Current File : /home/escuelai/public_html/it/src/IPNetwork.php |
<?php
/**
* ---------------------------------------------------------------------
*
* GLPI - Gestionnaire Libre de Parc Informatique
*
* http://glpi-project.org
*
* @copyright 2015-2022 Teclib' and contributors.
* @copyright 2003-2014 by the INDEPNET Development Team.
* @licence https://www.gnu.org/licenses/gpl-3.0.html
*
* ---------------------------------------------------------------------
*
* LICENSE
*
* This file is part of GLPI.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* ---------------------------------------------------------------------
*/
/// 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;
public static $rightname = 'internet';
/**
* Data used during add/update process to handle CommonImplicitTreeDropdown ancestors/sons.
* @var array
*/
private $data_for_implicit_update;
/**
* Computed address.
* Used for caching purpose.
* @var IPAddress
*/
private $address;
/**
* Computed netmask.
* Used for caching purpose.
* @var IPNetmask
*/
private $netmask;
/**
* Computed gateway.
* Used for caching purpose.
* @var IPAddress
*/
private $gateway;
/**
* Indicates whether the IPAddress or the IPNetmask has been updated during add/update process.
* Variable will be set during add/update process and unset after it.
* @var bool
*/
private $networkUpdate;
public function __get(string $property)
{
// TODO Deprecate read access to all variables in GLPI 10.1.
$value = null;
switch ($property) {
case 'address':
case 'data_for_implicit_update':
case 'gateway':
case 'netmask':
case 'networkUpdate':
$value = $this->$property;
break;
default:
$trace = debug_backtrace();
trigger_error(
sprintf('Undefined property: %s::%s in %s on line %d', __CLASS__, $property, $trace[0]['file'], $trace[0]['line']),
E_USER_WARNING
);
break;
}
return $value;
}
public function __set(string $property, $value)
{
switch ($property) {
case 'address':
case 'data_for_implicit_update':
case 'gateway':
case 'netmask':
Toolbox::deprecated(sprintf('Writing private property %s::%s is deprecated', __CLASS__, $property));
// no break is intentionnal
case 'networkUpdate':
// TODO Deprecate write access to variable in GLPI 10.1.
$this->$property = $value;
break;
default:
$trace = debug_backtrace();
trigger_error(
sprintf('Undefined property: %s::%s in %s on line %d', __CLASS__, $property, $trace[0]['file'], $trace[0]['line']),
E_USER_WARNING
);
break;
}
}
public static function getTypeName($nb = 0)
{
return _n('IP network', 'IP networks', $nb);
}
public 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',
];
$tab[] = [
'id' => '18',
'table' => $this->getTable(),
'field' => 'addressable',
'name' => __('Addressable network'),
'datatype' => 'bool'
];
return $tab;
}
public function getAddress()
{
if ($this->address === null) {
$this->address = new IPAddress();
if (!$this->address->setAddressFromArray($this->fields, "version", "address", "address")) {
return false;
}
}
return $this->address;
}
public function getNetmask()
{
if ($this->netmask === null) {
$this->netmask = new IPNetmask();
if (!$this->netmask->setAddressFromArray($this->fields, "version", "netmask", "netmask")) {
return false;
}
}
return $this->netmask;
}
public function getGateway()
{
if ($this->gateway === null) {
$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
**/
public function post_getFromDB()
{
// Be sure to remove addresses, otherwise reusing will provide old objects for getAddress, ...
$this->address = null;
$this->netmask = null;
$this->gateway = null;
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"]
);
}
}
}
public 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'
]
];
}
public function getNewAncestor()
{
if ($this->data_for_implicit_update !== null) {
$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
**/
public 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' => __('Missing network property (In CIDR notation. Ex: 192.168.1.1/24)'),
'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;
}
public 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;
}
public 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;
}
public function post_addItem()
{
if ($this->networkUpdate) {
IPAddress_IPNetwork::linkIPAddressFromIPNetwork($this);
}
parent::post_addItem();
$this->networkUpdate = null;
$this->data_for_implicit_update = null;
}
public function post_updateItem($history = 1)
{
if ($this->networkUpdate) {
IPAddress_IPNetwork::linkIPAddressFromIPNetwork($this);
}
unset($this->networkUpdate);
parent::post_updateItem($history);
}
public function cleanDBonPurge()
{
$this->deleteChildrenAndRelationsFromDb(
[
IPAddress_IPNetwork::class,
IPNetwork_Vlan::class,
]
);
}
public function getPotentialSons()
{
if ($this->data_for_implicit_update !== null) {
$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())
**/
public 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.
**/
public 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 = [];
foreach ($iterator as $data) {
if (count($fields) > 1) {
$returnValue = [];
foreach ($fields as $field) {
$returnValue[$field] = $data[$field];
}
} else {
$returnValue = $data[$fields[0]];
}
$returnValues[] = $returnValue;
}
return $returnValues;
}
public 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
**/
public 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
**/
public 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
*/
public 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 '')
**/
public 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)
**/
public 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
**/
public 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();
foreach ($iterator as $network_entry) {
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
**/
public 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
**/
public 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 = "<span class='b'>" . $content . "</span>";
}
$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)
**/
public static function showIPNetworkProperties($entities_id = -1, $value = 0)
{
global $CFG_GLPI;
$rand = mt_rand();
self::dropdown(['entity' => $entities_id,
'rand' => $rand,
'value' => $value
]);
$params = ['ipnetworks_id' => '__VALUE__'];
Ajax::updateItemOnSelectEvent(
"dropdown_ipnetworks_id$rand",
"show_ipnetwork_$rand",
$CFG_GLPI["root_doc"] . "/ajax/dropdownShowIPNetwork.php",
$params
);
echo "<span id='show_ipnetwork_$rand'> </span>\n";
if ($value > 0) {
$params = ["ipnetworks_id" => $value];
Ajax::updateItem(
"show_ipnetwork_$rand",
$CFG_GLPI["root_doc"] . "/ajax/dropdownShowIPNetwork.php",
$params
);
}
}
/**
* Override title function to display the link to reinitialisation of the network tree
**/
public function title()
{
parent::title();
if (
Session::haveRight('internet', UPDATE)
&& Session::canViewAllEntities()
) {
echo "<div class='spaced' id='tabsbody'>";
echo "<table class='tab_cadre_fixe'>";
echo "<tr><td class='center'>";
Html::showSimpleForm(
IPNetwork::getFormURL(),
'reinit_network',
__('Reinit the network topology')
);
echo "</td></tr>";
echo "</table>";
echo "</div>";
}
}
}