. * --------------------------------------------------------------------- * */ if (!defined('GLPI_ROOT')) { die("Sorry. You can't access this file directly"); } /// Class IPNetwork : Represent an IPv4 or an IPv6 network. /// It fully use IPAddress and IPNetmask to check validity and change representation from binary /// to textual values. /// \anchor parameterType Moreover, attributes of checking and retrieving functions allways allows /// both binary (ie: array of 4 bytes) or IPAddress Object. As such, $version is only use (and /// checked) with binary format of parameters. /// \anchor ipAddressToNetwork We have to notice that checking regarding an IP address is the same /// thing than checking regarding a network with all bits of the netmask set to 1 /// @since 0.84 class IPNetwork extends CommonImplicitTreeDropdown { public $dohistory = true; static $rightname = 'internet'; static function getTypeName($nb = 0) { return _n('IP network', 'IP networks', $nb); } function rawSearchOptions() { $tab = parent::rawSearchOptions(); $tab[] = [ 'id' => '10', 'table' => $this->getTable(), 'field' => 'version', 'name' => __('IP version'), 'massiveaction' => false, 'datatype' => 'number' ]; $tab[] = [ 'id' => '11', 'table' => $this->getTable(), 'field' => 'address', 'name' => IPAddress::getTypeName(1), 'massiveaction' => false, 'datatype' => 'string' ]; $tab[] = [ 'id' => '12', 'table' => $this->getTable(), 'field' => 'netmask', 'name' => IPNetmask::getTypeName(1), 'massiveaction' => false, 'datatype' => 'string' ]; $tab[] = [ 'id' => '17', 'table' => $this->getTable(), 'field' => 'gateway', 'name' => __('Gateway'), 'massiveaction' => false, 'datatype' => 'string', 'autocomplete' => true, ]; $tab[] = [ 'id' => '18', 'table' => $this->getTable(), 'field' => 'addressable', 'name' => __('Addressable network'), 'datatype' => 'bool' ]; return $tab; } function getAddress() { if (!isset($this->address)) { $this->address = new IPAddress(); if (!$this->address->setAddressFromArray($this->fields, "version", "address", "address")) { return false; } } return $this->address; } function getNetmask() { if (!isset($this->netmask)) { $this->netmask = new IPNetmask(); if (!$this->netmask->setAddressFromArray($this->fields, "version", "netmask", "netmask")) { return false; } } return $this->netmask; } function getGateway() { if (!isset($this->gateway)) { $this->gateway = new IPAddress(); if (!$this->gateway->setAddressFromArray($this->fields, "version", "gateway", "gateway")) { return false; } } return $this->gateway; } /** * When we load the object, we fill the "network" field with the correct address/netmask values **/ function post_getFromDB () { // Be sure to remove addresses, otherwise reusing will provide old objects for getAddress, ... unset($this->address); unset($this->netmask); unset($this->gateway); if (isset($this->fields["address"]) && isset($this->fields["netmask"])) { if ($this->fields["version"] == 4) { $this->fields["network"] = sprintf(__('%1$s / %2$s'), $this->fields["address"], $this->fields["netmask"]); } else { // IPv6 $this->fields["network"] = sprintf(__('%1$s / %2$s'), $this->fields["address"], $this->fields["netmask"]); } } } function getAdditionalFields() { return [['name' => 'network', 'label' => self::getTypeName(1), 'type' => 'text', 'list' => true, 'comment' => __('Set the network using notation address/mask')], ['name' => 'gateway', 'label' => __('Gateway'), 'type' => 'text', 'list' => true], ['name' => 'addressable', 'label' => __('Addressable network'), 'comment' => __('An addressable network is a network defined on an equipment'), 'type' => 'bool']]; } function getNewAncestor() { if (isset($this->data_for_implicit_update)) { $params = ["address" => $this->data_for_implicit_update['address'], "netmask" => $this->data_for_implicit_update['netmask']]; if (isset($this->fields['id'])) { $params['exclude IDs'] = $this->fields['id']; } $parents = self::searchNetworks("contains", $params, $this->data_for_implicit_update['entities_id']); if ((is_array($parents)) && (count($parents) > 0)) { return $parents[0]; } } return 0; } /** * @param $input **/ function prepareInput($input) { // In case of entity transfer, $input['network'] is not defined if (!isset($input['network']) && isset($this->fields['network'])) { $input['network'] = $this->fields['network']; } // In case of entity transfer, $input['gateway'] is not defined if (!isset($input['gateway']) && isset($this->fields['gateway'])) { $input['gateway'] = $this->fields['gateway']; } // If $this->fields["id"] is not set then, we are adding a new network // Or if $this->fields["network"] != $input["network"] we a updating the network $address = new IPAddress(); $netmask = new IPNetmask(); // Don't validate an empty network if (empty($input["network"])) { return ['error' => __('Invalid network address'), 'input' => false]; } if (!isset($this->fields["id"]) || !isset($this->fields["network"]) || ($input["network"] != $this->fields["network"])) { $network = explode ("/", $input["network"]); if (count($network) != 2) { return ['error' => __('Invalid input format for the network'), 'input' => false]; } if (!$address->setAddressFromString(trim($network[0]))) { return ['error' => __('Invalid network address'), 'input' => false]; } if (!$netmask->setNetmaskFromString(trim($network[1]), $address->getVersion())) { return ['error' => __('Invalid subnet mask'), 'input' => false]; } // After checking that address and netmask are valid, modify the address to be the "real" // network address : the first address of the network. This is not required for SQL, but // that looks better for the human self::computeNetworkRangeFromAdressAndNetmask($address, $netmask, $address); // Now, we look for already existing same network inside the database $params = ["address" => $address, "netmask" => $netmask]; if (isset($this->fields["id"])) { $params["exclude IDs"] = $this->fields["id"]; } if (isset($this->fields["entities_id"])) { $entities_id = $this->fields["entities_id"]; } else if (isset($input["entities_id"])) { $entities_id = $input["entities_id"]; } else { $entities_id = -1; } // TODO : what is the best way ? recursive or not ? $sameNetworks = self::searchNetworks("equals", $params, $entities_id, false); // Check unicity ! if ($sameNetworks && (count($sameNetworks) > 0)) { return ['error' => __('Network already defined in visible entities'), 'input' => false]; } // Then, update $input to reflect the network and the netmask $input = $address->setArrayFromAddress($input, "version", "address", "address"); $input = $netmask->setArrayFromAddress($input, "", "netmask", "netmask"); // We check to see if the network is modified $previousAddress = new IPAddress(); $previousAddress->setAddressFromArray($this->fields, "version", "address", "address"); $previousNetmask = new IPNetmask(); $previousNetmask->setAddressFromArray($this->fields, "version", "netmask", "netmask"); if ($previousAddress->equals($address) && $previousNetmask->equals($netmask)) { $this->networkUpdate = false; } else { $this->networkUpdate = true; } } else { // If netmask and address are not modified, then, load them from DB to check the validity // of the gateway $this->networkUpdate = false; $address->setAddressFromArray($this->fields, "version", "address", "address"); $netmask->setAddressFromArray($this->fields, "version", "netmask", "netmask"); $entities_id = $this->fields['entities_id']; } // Update class for the CommonImplicitTree update ... $this->data_for_implicit_update = ['address' => $address, 'netmask' => $netmask, 'entities_id' => $entities_id]; $returnValue = []; // If the gateway has been altered, or the network information (address or netmask) changed, // then, we must revalidate the gateway ! if (!isset($this->fields["gateway"]) || ($input["gateway"] != $this->fields["gateway"]) || $this->networkUpdate) { $gateway = new IPAddress(); if (!empty($input["gateway"])) { if (!$gateway->setAddressFromString($input["gateway"]) || !self::checkIPFromNetwork($gateway, $address, $netmask)) { $returnValue['error'] = __('Invalid gateway address'); if (!empty($this->fields["gateway"])) { if (!$gateway->setAddressFromString($this->fields["gateway"]) || !self::checkIPFromNetwork($gateway, $address, $netmask)) { $gateway->disableAddress(); } } else { $gateway->disableAddress(); } } } $input = $gateway->setArrayFromAddress($input, "", "gateway", "gateway"); } $returnValue['input'] = $input; return $returnValue; } function prepareInputForAdd($input) { $preparedInput = $this->prepareInput($input); if (isset($preparedInput['error'])) { Session::addMessageAfterRedirect($preparedInput['error'], false, ERROR); } $input = $preparedInput['input']; if (is_array($input)) { return parent::prepareInputForAdd($input); } return false; } function prepareInputForUpdate($input) { $preparedInput = $this->prepareInput($input); if (isset($preparedInput['error'])) { Session::addMessageAfterRedirect($preparedInput['error'], false, ERROR); } $input = $preparedInput['input']; if (is_array($input)) { return parent::prepareInputForUpdate($input); } return false; } function post_addItem() { if ($this->networkUpdate) { IPAddress_IPNetwork::linkIPAddressFromIPNetwork($this); } unset($this->networkUpdate); parent::post_addItem(); } function post_updateItem($history = 1) { if ($this->networkUpdate) { IPAddress_IPNetwork::linkIPAddressFromIPNetwork($this); } unset($this->networkUpdate); parent::post_updateItem($history); } function cleanDBonPurge() { $this->deleteChildrenAndRelationsFromDb( [ IPAddress_IPNetwork::class, IPNetwork_Vlan::class, ] ); } function getPotentialSons() { if (isset($this->data_for_implicit_update)) { $params = ["address" => $this->data_for_implicit_update['address'], "netmask" => $this->data_for_implicit_update['netmask'], "exclude IDs" => $this->getID()]; $mysons = self::searchNetworks("is contained by", $params, $this->data_for_implicit_update['entities_id']); if (is_array($mysons)) { return $mysons; } } return []; } /** * \brief Search any networks that contains the given IP * \ref ipAddressToNetwork * * @param IPAddress|string|integer[] $IP (see \ref parameterType) given IP * @param integer $entityID scope of the search (parents and childrens are check) * @param boolean $recursive set to false to only search in current entity, * otherwise, all visible entities will be search * @param string|array $fields list of fields to return in the result (default : only ID of the networks) * @param string $where search criteria * * @return array|false list of networks (see searchNetworks()) **/ static function searchNetworksContainingIP($IP, $entityID = -1, $recursive = true, $fields = "", $where = "") { return self::searchNetworks('contains', ['address' => $IP, 'netmask' => [0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff], 'fields' => $fields, 'where' => $where], $entityID, $recursive); } /** * Search networks relative to a given network * * @param string $relation type of relation ("is contained by", "equals" or "contains") * regarding the networks given as parameter * @param array $condition array of elements to select the good arrays (see Parameters above) * - fields : the fields of the network we wish to retrieve (single field or array of * fields). This parameter will impact the result of the function * - address (see \ref parameterType) : the address for the query * - netmask (see \ref parameterType) : the netmask for the query * - exclude IDs : the IDs to exclude from the query (for instance, $this->getID()) * - where : filters to add to the SQL request * * @param integer $entityID the entity on which the selection should occur (-1 => the current active * entity) (default -1) * @param boolean $recursive set to false to only search in current entity, otherwise, all visible * entities will be search (true by default) * @param integer $version version of IP to look (only use when using arrays or string as input for * address or netmask n(default 0) * * @return array of networks found. If we want request several field, the return value will be * an array of array * * \warning The order of the elements inside the result are ordered from the nearest one to the * further. (ie. 0.0.0.0 is the further of whatever network if you lool for ones that * contains the current network. **/ static function searchNetworks($relation, $condition, $entityID = -1, $recursive = true, $version = 0) { global $DB; if (empty($relation)) { return false; } if (empty($condition["fields"])) { $fields = 'id'; } else { $fields = $condition["fields"]; } if (!is_array($fields)) { $fields = [$fields]; } $startIndex = (($version == 4) ? 3 : 1); $addressDB = ['address_0', 'address_1', 'address_2', 'address_3']; $netmaskDB = ['netmask_0', 'netmask_1', 'netmask_2', 'netmask_3']; $WHERE = []; if (isset($condition["address"]) && isset($condition["netmask"])) { $addressPa = new IPAddress($condition["address"]); // Check version equality ... if ($version != $addressPa->getVersion()) { if ($version != 0) { return false; } $version = $addressPa->getVersion(); } $netmaskPa = new IPNetmask($condition["netmask"], $version); // Get the array of the adresses $addressPa = $addressPa->getBinary(); $netmaskPa = $netmaskPa->getBinary(); // Check the binary is valid if (!is_array($addressPa) || (count($addressPa) != 4)) { return false; } if (!is_array($netmaskPa) || (count($netmaskPa) != 4)) { return false; } $startIndex = (($version == 4) ? 3 : 0); if ($relation == "equals") { for ($i = $startIndex; $i < 4; ++$i) { $WHERE = [ new \QueryExpression("(".$DB->quoteName($addressDB[$i]) . " & " . $DB->quoteValue($netmaskPa[$i]) . ") = (".$DB->quoteValue($addressPa[$i])." & ".$DB->quoteValue($netmaskPa[$i]).")"), $netmaskDB[$i] => $netmaskPa[$i] ]; } } else { for ($i = $startIndex; $i < 4; ++$i) { if ($relation == "is contained by") { $globalNetmask = $DB->quoteValue($netmaskPa[$i]); } else { $globalNetmask = $DB->quoteName($netmaskDB[$i]); } $WHERE = [ new \QueryExpression("(".$DB->quoteName($addressDB[$i])." & $globalNetmask) = (".$DB->quoteValue($addressPa[$i])." & $globalNetmask)"), new \QueryExpression("(".$DB->quoteValue($netmaskPa[$i])." & ".$DB->quoteName($netmaskDB[$i]).")=$globalNetmask") ]; } } } if ($entityID < 0) { $entityID = $_SESSION['glpiactive_entity']; } $entitiesID = []; switch ($relation) { case "is contained by" : $ORDER_ORIENTATION = 'ASC'; if ($recursive) { $entitiesID = getSonsOf('glpi_entities', $entityID); } break; case "contains" : $ORDER_ORIENTATION = 'DESC'; if ($recursive) { $entitiesID = getAncestorsOf('glpi_entities', $entityID); } break; case "equals" : $ORDER_ORIENTATION = ''; if ($recursive) { $entitiesID = getSonsAndAncestorsOf('glpi_entities', $entityID); } break; } $entitiesID[] = $entityID; $WHERE['entities_id'] = $entitiesID; $WHERE['version'] = $version; if (!empty($condition["exclude IDs"])) { if (is_array($condition["exclude IDs"])) { if (count($condition["exclude IDs"]) > 1) { $WHERE['NOT'] = ['id' => $condition['exclude IDs']]; } else { $WHERE['id'] = ['<>', $condition['exclude IDs'][0]]; } } else { $WHERE['id'] = ['<>', $condition['exclude IDs']]; } } $ORDER = []; // By ordering on the netmask, we ensure that the first element is the nearest one (ie: // the last should be 0.0.0.0/0.0.0.0 of x.y.z.a/255.255.255.255 regarding the interested // element) for ($i = $startIndex; $i < 4; ++$i) { $ORDER[] = new \QueryExpression("BIT_COUNT(".$DB->quoteName($netmaskDB[$i]).") $ORDER_ORIENTATION"); } if (!empty($condition["where"])) { $WHERE .= " AND " . $condition["where"]; } $iterator = $DB->request([ 'SELECT' => $fields, 'FROM' => self::getTable(), 'WHERE' => $WHERE, 'ORDER' => $ORDER ]); $returnValues = []; while ($data = $iterator->next()) { if (count($fields) > 1) { $returnValue = []; foreach ($fields as $field) { $returnValue[$field] = $data[$field]; } } else { $returnValue = $data[$fields[0]]; } $returnValues[] = $returnValue; } return $returnValues; } function defineTabs($options = []) { $ong = []; $this->addDefaultFormTab($ong); $this->addStandardTab('IPNetwork_Vlan', $ong, $options); $this->addStandardTab('IPAddress', $ong, $options); $this->addStandardTab('Log', $ong, $options); return $ong; } /** * Get SQL WHERE criteria for requesting elements that are contained inside the current network * * @since 9.5.0 * * @param string $tableName name of the table containing the element * (for instance : glpi_ipaddresses) * @param string $binaryFieldPrefix prefix of the binary version of IP address * (binary for glpi ipaddresses) * @param string $versionField the name of the field containing the version inside the database * * @return array **/ function getCriteriaForMatchingElement($tableName, $binaryFieldPrefix, $versionField) { global $DB; $version = $this->fields["version"]; $start = null; $this->computeNetworkRange($start); $result = []; for ($i = ($version == 4 ? 3 : 0); $i < 4; ++$i) { $result[] = new \QueryExpression( "({$DB->quoteName($tableName.'.'.$binaryFieldPrefix.'_'.$i)} & " . $this->fields["netmask_$i"] . ") = ({$start[$i]})" ); } $result["$tableName.version"] = $version; return $result; } /** * Check to see if an IP is inside a given network * See : \ref ipAddressToNetwork * * @param IPAddress|integer[] $address (see \ref parameterType) the IP address to check * @param IPAddress|integer[] $networkAddress (see \ref parameterType) the address of the network * @param IPAddress|integer[] $networkNetmask (see \ref parameterType) the netmask of the network * @param integer $version of IP : only usefull for binary array as input (default 0) * * @return true if the network owns the IP address **/ static function checkIPFromNetwork($address, $networkAddress, $networkNetmask, $version = 0) { $IPNetmask = [0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff]; $relativity = self::checkNetworkRelativity($address, $IPNetmask, $networkAddress, $networkNetmask, $version); return ($relativity == "equals") || ($relativity == "second contains first"); } /** * \brief Check network relativity * Check how networks are relative (fully different, equals, first contains second, ...) * * @param IPAddress|integer[] $firstAddress (see \ref parameterType) address of the first network * @param IPAddress|integer[] $firstNetmask (see \ref parameterType) netmask of the first network * @param IPAddress|integer[] $secondAddress (see \ref parameterType) address of the second network * @param IPAddress|integer[] $secondNetmask (see \ref parameterType) netmask of the second network * @param integer $version of IP : only usefull for binary array as input (default 0) * * @return string : * - "different version" : there is different versions between elements * - "?" : There is holes inside the netmask and both networks can partially intersect * - "different" : the networks are fully different; * - "equals" : both networks are equals * - "first contains second" "second contains first" : one include the other */ static function checkNetworkRelativity($firstAddress, $firstNetmask, $secondAddress, $secondNetmask, $version = 0) { if ($firstAddress instanceof IPAddress) { if ($version == 0) { $version = $firstAddress->getVersion(); } if ($version != $firstAddress->getVersion()) { return "different version"; } $firstAddress = $firstAddress->getBinary(); } if ($firstNetmask instanceof IPAddress) { if ($version != $firstNetmask->getVersion()) { return "different version"; } $firstNetmask = $firstNetmask->getBinary(); } if ($secondAddress instanceof IPAddress) { if ($version != $secondAddress->getVersion()) { return "different version"; } $secondAddress = $secondAddress->getBinary(); } if ($secondNetmask instanceof IPAddress) { if ($version != $secondNetmask->getVersion()) { return "different version"; } $secondNetmask = $secondNetmask->getBinary(); } $startIndex = (($version == 4) ? 3 : 0); $first = true; $second = true; for ($i = $startIndex; $i < 4; ++$i) { $and = ($firstNetmask[$i] & $secondNetmask[$i]); // Be carefull : php integers are 32 bits SIGNED. // Thus, checking equality must be done by XOR ... $first &= (($and ^ $firstNetmask[$i]) == 0); $second &= (($and ^ $secondNetmask[$i]) == 0); } if (!$first && !$second) { return "?"; } if ($first && $second) { $result = "equals"; $mask = &$firstNetmask; } else if ($first) { $result = "first contains second"; $mask = &$firstNetmask; } else { // $second == true $result = "second contains first"; $mask = &$secondNetmask; } for ($i = $startIndex; $i < 4; ++$i) { if ((($firstAddress[$i] & $mask[$i]) ^ ($secondAddress[$i] & $mask[$i])) != 0) { return "different"; } } return $result; } /** * Compute the first and the last address of $this * \see computeNetworkRangeFromAdressAndNetmask() * * @param $start * @param $end (default NULL) * @param $excludeBroadcastAndNetwork Don't provide extremties addresses * ($this->fields['addressable'] by default) * (default '') **/ function computeNetworkRange(&$start, &$end = null, $excludeBroadcastAndNetwork = '') { if (!is_bool($excludeBroadcastAndNetwork)) { if (isset($this->fields['addressable'])) { $excludeBroadcastAndNetwork = ($this->fields['addressable'] == 1); } else { $excludeBroadcastAndNetwork = false; } } self::computeNetworkRangeFromAdressAndNetmask($this->getAddress(), $this->getNetmask(), $start, $end, $excludeBroadcastAndNetwork); } /** * \brief Compute the first and the last address of a network. * That is usefull, for instance, to compute the "real" network address (the first address) * or the broadcast address of the network * * @param $address (see \ref parameterType) the address of the network * @param $netmask (see \ref parameterType) its netmask * @param $firstAddress (see \ref parameterType - in/out) * the first address (ie real address of the network) * @param $lastAddress (see \ref parameterType - in/out) * the lastAddress of the network * (ie. : the broadcast address) (default NULL) * @param $excludeBroadcastAndNetwork boolean exclude broadcast and network address from the * result (false by default) **/ static function computeNetworkRangeFromAdressAndNetmask($address, $netmask, &$firstAddress, &$lastAddress = null, $excludeBroadcastAndNetwork = false) { if ($address instanceof IPAddress) { $address = $address->getBinary(); } if ($netmask instanceof IPNetmask) { $netmask = $netmask->getBinary(); } $start = []; $end = []; for ($i = 0; $i < 4; ++$i) { $start[$i] = IPAddress::convertNegativeIntegerToPositiveFloat($address[$i] & $netmask[$i]); $end[$i] = IPAddress::convertNegativeIntegerToPositiveFloat($address[$i] | ~$netmask[$i]); } if ($excludeBroadcastAndNetwork) { IPAddress::addValueToAddress($start, 1); IPAddress::addValueToAddress($end, -1); } if ($firstAddress instanceof IPAddress) { $firstAddress->setAddressFromBinary($start); } else { $firstAddress = $start; } if ($lastAddress instanceof IPAddress) { $lastAddress->setAddressFromBinary($end); } else { $lastAddress = $end; } } /** * \brief Recreate network tree * Among others, the migration create plan tree network. This method allows to recreate the tree. * You can also use it if you suspect the network tree to be corrupted. * * First, reset the tree, then, update each network by its own field, letting * CommonImplicitTreeDropdown working such as it would in case of standard update * * @return void **/ static function recreateTree() { global $DB; // Reset the tree $DB->update( 'glpi_ipnetworks', [ 'ipnetworks_id' => 0, 'level' => 1, 'completename' => new \QueryExpression($DB->quoteName('name')) ], [true] ); // Foreach IPNetwork ... $iterator = $DB->request([ 'SELECT' => 'id', 'FROM' => self::getTable() ]); $network = new self(); while ($network_entry = $iterator->next()) { if ($network->getFromDB($network_entry['id'])) { $input = $network->fields; // ... update it by its own entries $network->update($input); } } } /** * @since 0.84 * * @param $itemtype * @param $base HTMLTableBase object * @param $super HTMLTableSuperHeader object (default NULL) * @param $father HTMLTableHeader object (default NULL) * @param $options array **/ static function getHTMLTableHeader($itemtype, HTMLTableBase $base, HTMLTableSuperHeader $super = null, HTMLTableHeader $father = null, array $options = []) { if ($itemtype != 'IPAddress') { return; } $column_name = __CLASS__; if (isset($options['dont_display'][$column_name])) { return; } $content = self::getTypeName(); $this_header = $base->addHeader($column_name, $content, $super, $father); $this_header->setItemType(__CLASS__); } /** * @since 0.84 * * @param $row HTMLTableRow object (default NULL) * @param $item CommonDBTM object (default NULL) * @param $father HTMLTableCell object (default NULL) * @param $options array **/ static function getHTMLTableCellsForItem(HTMLTableRow $row = null, CommonDBTM $item = null, HTMLTableCell $father = null, array $options = []) { if (empty($item)) { if (empty($father)) { return; } $item = $father->getItem(); } if ($item->getType() != 'IPAddress') { return; } $column_name = __CLASS__; if (isset($options['dont_display'][$column_name])) { return; } $header= $row->getGroup()->getHeaderByName('Internet', __CLASS__); if (!$header) { return; } $createRow = (isset($options['createRow']) && $options['createRow']); $options['createRow'] = false; $network = new self(); foreach (self::searchNetworksContainingIP($item) as $networks_id) { if ($network->getFromDB($networks_id)) { $address = $network->getAddress(); $netmask = $network->getNetmask(); // Stop if we failed to retrieve address or netmask if (!$address || !$netmask) { continue; } if ($createRow) { $row = $row->createRow(); } //TRANS: %1$s is address, %2$s is netmask $content = sprintf( __('%1$s / %2$s'), $address->getTextual(), $netmask->getTextual() ); if ($network->fields['addressable'] == 1) { $content = "".$content.""; } $content = sprintf(__('%1$s - %2$s'), $content, $network->getLink()); $row->addCell($header, $content, $father, $network); } } } /** * Show all available IPNetwork for a given entity * * @param $entities_id entity of the IPNetworks (-1 for all entities) * (default -1) **/ static function showIPNetworkProperties($entities_id = -1) { global $CFG_GLPI; $rand = mt_rand(); self::dropdown(['entity' => $entities_id, 'rand' => $rand]); $params = ['ipnetworks_id' => '__VALUE__']; Ajax::updateItemOnSelectEvent("dropdown_ipnetworks_id$rand", "show_ipnetwork_$rand", $CFG_GLPI["root_doc"]. "/ajax/dropdownShowIPNetwork.php", $params); echo " \n"; } /** * Override title function to display the link to reinitialisation of the network tree **/ function title() { parent::title(); if (Session::haveRight('internet', UPDATE) && Session::canViewAllEntities()) { echo "
"; echo ""; echo ""; echo "
"; Html::showSimpleForm(IPNetwork::getFormURL(), 'reinit_network', __('Reinit the network topology')); echo "
"; echo "
"; } } }