From 872de4e07609d8dae7660e467a73fc6f4061956a Mon Sep 17 00:00:00 2001 From: Simon Rettberg Date: Thu, 16 Jun 2016 16:14:42 +0200 Subject: [locations] Handle machine UUID param to determine location --- modules-available/baseconfig/api.inc.php | 14 ++++-- .../locations/baseconfig/getconfig.inc.php | 6 +-- modules-available/locations/inc/location.inc.php | 54 ++++++++++++++++++++++ 3 files changed, 66 insertions(+), 8 deletions(-) diff --git a/modules-available/baseconfig/api.inc.php b/modules-available/baseconfig/api.inc.php index 000015f5..877ff4a7 100644 --- a/modules-available/baseconfig/api.inc.php +++ b/modules-available/baseconfig/api.inc.php @@ -5,10 +5,9 @@ if (substr($ip, 0, 7) === '::ffff:') { $ip = substr($ip, 7); } -// TODO: Handle UUID in appropriate modules (optional) -$uuid = Request::post('uuid', '', 'string'); -if (strlen($uuid) !== 36) { - // Probably invalid UUID. What to do? Set empty or ignore? +$uuid = Request::any('uuid', false, 'string'); +if ($uuid !== false && strlen($uuid) !== 36) { + $uuid = false; } /** @@ -31,6 +30,11 @@ function escape($string) */ $configVars = array(); +function handleModule($file, $ip, $uuid) // Pass ip and uuid instead of global to make them read only +{ + global $configVars; + include $file; +} // Handle any hooks by other modules first // other modules should generally only populate $configVars @@ -38,7 +42,7 @@ foreach (glob('modules/*/baseconfig/getconfig.inc.php') as $file) { preg_match('#^modules/([^/]+)/#', $file, $out); if (!Module::isAvailable($out[1])) continue; - include $file; + handleModule($file, $ip, $uuid); } // Rest is handled by module diff --git a/modules-available/locations/baseconfig/getconfig.inc.php b/modules-available/locations/baseconfig/getconfig.inc.php index 2cf5495d..3a0c918f 100644 --- a/modules-available/locations/baseconfig/getconfig.inc.php +++ b/modules-available/locations/baseconfig/getconfig.inc.php @@ -8,11 +8,11 @@ if (Request::any('force', 0, 'int') === 1 && Request::any('module', false, 'stri $locationId = Request::any('value', 0, 'int'); } } -// TODO: machine specific mapping + if ($locationId === false) { - // Fallback to subnets - $locationId = Location::getFromIp($ip); + $locationId = Location::getFromIpAndUuid($ip, $uuid); } + $matchingLocations = array(); if ($locationId !== false) { // Get all parents diff --git a/modules-available/locations/inc/location.inc.php b/modules-available/locations/inc/location.inc.php index 3a282df1..bd642a57 100644 --- a/modules-available/locations/inc/location.inc.php +++ b/modules-available/locations/inc/location.inc.php @@ -153,6 +153,22 @@ class Location return $ids; } + /** + * Get location id for given machine (by uuid) + * @param $uuid machine uuid + * @return bool|int locationid, false if no match + */ + public static function getFromMachineUuid($uuid) + { + // Only if we have the statistics module which supplies the machine table + if (Module::get('statistics') === false) + return false; + $ret = Database::queryFirst("SELECT locationid FROM machine WHERE machineuuid = :uuid", compact('uuid')); + if ($ret === false) + return false; + return (int)$ret['locationid']; + } + /** * Get closest location by matching subnets. Deepest match in tree wins. * @@ -177,6 +193,44 @@ class Location return $locationId; } + /** + * Combined "intelligent" fetching of locationId by IP and UUID of + * client. We can't trust the UUID too much as it is provided by the + * client, so if it seems too fishy, the UUID will be ignored. + * + * @param $ip IP address of client + * @param $uuid System-UUID of client + * @return int|bool location id, or false if none matches + */ + public static function getFromIpAndUuid($ip, $uuid) + { + $locationId = false; + $ipLoc = self::getFromIp($ip); + if ($ipLoc !== false && $uuid !== false) { + // Machine ip maps to a location, and we have a client supplied uuid + $uuidLoc = self::getFromMachineUuid($uuid); + if ($uuidLoc !== false) { + // Validate that the location the IP maps to is in the chain we get using the + // location determined by the uuid + $uuidLocations = self::getLocationRootChain($uuidLoc); + $ipLocations = self::getLocationRootChain($ipLoc); + if (in_array($uuidLoc, $ipLocations) + || (in_array($ipLoc, $uuidLocations) && count($ipLocations) + 1 >= count($uuidLocations)) + ) { + // Close enough, allow + $locationId = $uuidLoc; + } else { + // UUID and IP disagree too much, play safe and ignore the UUID + $locationId = $ipLoc; + } + } + } else if ($ipLoc !== false) { + // No uuid, but ip maps to location; use that + $locationId = $ipLoc; + } + return $locationId; + } + /** * Get all location IDs from the given location up to the root. * -- cgit v1.2.3-55-g7522