Skip to content

Commit 12086bd

Browse files
author
Jean-François Hivert
committed
Fix for IPv6
1 parent 57a8eab commit 12086bd

6 files changed

Lines changed: 152 additions & 45 deletions

File tree

ipam/api/subnet.php

Lines changed: 12 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -131,30 +131,24 @@ public function getNetMask()
131131
return false;
132132
}
133133

134+
public function getFirstIp()
135+
{
136+
return IPAM_Tools::firstSubnetIp($this->getNetwork(), $this->getNetMask());
137+
}
138+
139+
public function getLastIp()
140+
{
141+
return IPAM_Tools::lastSubnetIp($this->getNetwork(), $this->getNetMask());
142+
}
143+
134144
public function getNetworkIp()
135145
{
136-
if($this->isIPv4()) {
137-
return IPAM_Tools::networkIp($this->getNetwork(), $this->getNetMask());
138-
}
139-
elseif($this->isIPv6()) {
140-
// @todo a coder
141-
}
142-
else {
143-
return false;
144-
}
146+
return IPAM_Tools::networkIp($this->getNetwork(), $this->getNetMask());
145147
}
146148

147149
public function getBroadcastIp()
148150
{
149-
if($this->isIPv4()) {
150-
return IPAM_Tools::broadcastIp($this->getNetwork(), $this->getNetMask());
151-
}
152-
elseif($this->isIPv6()) {
153-
// @todo a coder
154-
}
155-
else {
156-
return false;
157-
}
151+
return IPAM_Tools::broadcastIp($this->getNetwork(), $this->getNetMask());
158152
}
159153

160154
public function getGateway()

ipam/api/subnet/abstract.php

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,9 @@ public static function isIPv4Subnet($subnet)
160160
}
161161

162162
if($subnet !== false) {
163-
return (strpos($subnet, '.') !== false);
163+
// Be careful ::ffff:127.0.0.1 notation is valid
164+
//return (substr_count($subnet, '.') === 3 && strpos($subnet, ':') === false);
165+
return Tools::is('ipv4', $subnet);
164166
}
165167
else {
166168
return false;
@@ -174,7 +176,8 @@ public static function isIPv6Subnet($subnet)
174176
}
175177

176178
if($subnet !== false) {
177-
return (strpos($subnet, ':') !== false);
179+
//return (strpos($subnet, ':') !== false);
180+
return Tools::is('ipv6', $subnet);
178181
}
179182
else {
180183
return false;

ipam/tools.php

Lines changed: 102 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -67,39 +67,130 @@ public static function cidrMaskToNetMask($cidrMask)
6767
return long2ip(-1 << (32 - (int) $cidrMask));
6868
}
6969

70+
public static function cidrMaskToBinary($cidrMask, $IPv)
71+
{
72+
if($IPv === 4) {
73+
return (~((1 << (32 - $cidrMask)) - 1));
74+
}
75+
elseif($IPv === 6)
76+
{
77+
$netMask = str_repeat("f", $cidrMask / 4);
78+
79+
switch($cidrMask % 4)
80+
{
81+
case 0:
82+
break;
83+
case 1:
84+
$netMask .= "8";
85+
break;
86+
case 2:
87+
$netMask .= "c";
88+
break;
89+
case 3:
90+
$netMask .= "e";
91+
break;
92+
}
93+
94+
$netMask = str_pad($netMask, 32, '0');
95+
$binMask = pack("H*", $netMask);
96+
97+
return $binMask;
98+
}
99+
100+
return false;
101+
}
102+
70103
public static function netMaskToCidr($netMask)
71104
{
72105
$longMask = ip2long($netMask);
73106
$longBase = ip2long('255.255.255.255');
74107
return 32 - log(($longMask ^ $longBase)+1, 2);
75108
}
76109

77-
public static function networkIp($ip, $mask)
110+
public static function firstSubnetIp($ip, $mask)
78111
{
79-
if(Tools::is('int&&>0', $mask)) {
80-
$mask = self::cidrMaskToNetMask($mask);
112+
if(($isIPv4 = Tools::is('ipv4', $ip)) === true || ($isIPv6 = Tools::is('ipv6', $ip)) === true)
113+
{
114+
if(Tools::is('int&&>0', $mask)) {
115+
$IPv = ($isIPv4) ? (4) : (6);
116+
$mask = self::cidrMaskToBinary($mask, $IPv);
117+
}
118+
elseif(defined('AF_INET6')) {
119+
$mask = inet_pton($mask);
120+
}
121+
else {
122+
return false;
123+
}
124+
125+
// IPv4 & IPv6 compatible
126+
if(defined('AF_INET6')) {
127+
$ip = inet_pton($ip);
128+
return inet_ntop($ip & $mask);
129+
}
130+
// IPv4 only
131+
elseif($isIPv4) {
132+
$netIp = (ip2long($ip) & $mask);
133+
return long2ip($netIp);
134+
}
81135
}
82136

83-
$netIp = (ip2long($ip) & ip2long($mask));
84-
return long2ip($netIp);
137+
return false;
85138
}
86139

87-
public static function broadcastIp($ip, $mask)
140+
public static function lastSubnetIp($ip, $mask)
88141
{
89-
if(Tools::is('int&&>0', $mask)) {
90-
$mask = self::cidrMaskToNetMask($mask);
142+
if(($isIPv4 = Tools::is('ipv4', $ip)) === true || ($isIPv6 = Tools::is('ipv6', $ip)) === true)
143+
{
144+
if(Tools::is('int&&>0', $mask)) {
145+
$IPv = ($isIPv4) ? (4) : (6);
146+
$mask = self::cidrMaskToBinary($mask, $IPv);
147+
}
148+
elseif(defined('AF_INET6')) {
149+
$mask = inet_pton($mask);
150+
}
151+
else {
152+
return false;
153+
}
154+
155+
// IPv4 et IPv6 compatible
156+
if(defined('AF_INET6')) {
157+
$ip = inet_pton($ip);
158+
return inet_ntop($ip | ~ $mask);
159+
}
160+
// IPv4 only
161+
elseif($isIPv4) {
162+
$bcIp = (ip2long($ip) | (~ $mask));
163+
return long2ip($bcIp);
164+
}
91165
}
92166

93-
$bcIp = (ip2long($ip) | (~ ip2long($mask)));
94-
return long2ip($bcIp);
167+
return false;
168+
}
169+
170+
public static function networkIp($ip, $mask)
171+
{
172+
return self::firstSubnetIp($ip, $mask);
173+
}
174+
175+
public static function broadcastIp($ip, $mask)
176+
{
177+
if(Tools::is('ipv4', $ip)) {
178+
return self::lastSubnetIp($ip, $mask);
179+
}
180+
elseif(Tools::is('ipv6', $ip)) {
181+
return 'ff02::1';
182+
}
183+
else {
184+
return false;
185+
}
95186
}
96187

97188
public static function networkSubnet($cidrSubnet)
98189
{
99190
$subnetPart = explode('/', $cidrSubnet);
100191

101192
if(count($subnetPart) === 2) {
102-
$networkIp = self::networkIp($subnetPart[0], $subnetPart[1]);
193+
$networkIp = self::firstSubnetIp($subnetPart[0], $subnetPart[1]);
103194
return $networkIp.'/'.$subnetPart[1];
104195
}
105196
else {

services/ipam.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ class Service_Ipam extends Service_Abstract
3030
'show' => array(
3131
'section', 'subnet', 'vlan', 'address',
3232
),
33+
'phpipam',
3334
);
3435

3536
/**
@@ -59,7 +60,6 @@ class Service_Ipam extends Service_Abstract
5960
'list address' => "#^\"?(([0-9]{1,3}\.){3}[0-9]{1,3})|([a-z0-9\-_.:* ]+)\"?$#i",
6061
'show address' => "#^\"?(([0-9]{1,3}\.){3}[0-9]{1,3})|([a-z0-9\-_.:* ]+)\"?$#i",
6162
// @todo regexp ipv6
62-
'phpipam',
6363
);
6464

6565
/**

services/shell/abstract.php

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,13 @@ protected function _printObjectInfos(array $cases, array $args, $fromCurrentPath
105105
}
106106
}
107107

108-
return (isset($objectType)) ? ($this->_printInformations($objectType, $infos)) : (false);
108+
if(isset($objectType)) {
109+
$status = $this->_printInformations($objectType, $infos);
110+
return array($status, $objectType, $infos);
111+
}
112+
else {
113+
return false;
114+
}
109115
}
110116
else {
111117
return false;
@@ -134,11 +140,6 @@ protected function _printInformations($type, $items)
134140
if(array_key_exists($key, $item))
135141
{
136142
$field = $item[$key];
137-
138-
if(Tools::is('array', $field)) {
139-
$field = implode(PHP_EOL, $field);
140-
}
141-
142143
$field = vsprintf($format, $field);
143144

144145
switch($key)

services/shell/ipam.php

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,8 @@ class Service_Shell_Ipam extends Service_Shell_Abstract
7272
'netMask' => 'NET mask: %s',
7373
'networkIP' => 'Network IP: %s',
7474
'broadcastIP' => 'Broadcast IP: %s',
75+
'firstIP' => 'First IP: %s',
76+
'lastIP' => 'Last IP: %s',
7577
'gateway' => 'Gateway: %s',
7678
'vlanNumber' => 'VLAN ID: %d',
7779
'vlanName' => 'VLAN Name: %s',
@@ -266,7 +268,15 @@ public function printObjectInfos(array $args, $fromCurrentPath = true)
266268
'address' => '_getAddressInfos'
267269
);
268270

269-
return $this->_printObjectInfos($cases, $args, $fromCurrentPath);
271+
$result = $this->_printObjectInfos($cases, $args, $fromCurrentPath);
272+
273+
if($result !== false) {
274+
list($status, $objectType, $infos) = $result;
275+
return $status;
276+
}
277+
else {
278+
return false;
279+
}
270280
}
271281

272282
public function printSectionInfos(array $args, $fromCurrentPath = true)
@@ -497,24 +507,32 @@ protected function _getSubnetInfos($subnet, $fromCurrentPath, $path = null)
497507
foreach($subnets as $subnet)
498508
{
499509
$Ipam_Api_Subnet = new Ipam_Api_Subnet($subnet['id']);
510+
511+
if($IPv !== false && !$Ipam_Api_Subnet->{'isIPv'.$IPv}()) {
512+
continue;
513+
}
514+
500515
$Ipam_Api_Vlan = $Ipam_Api_Subnet->vlanApi;
501516

502517
$network = $Ipam_Api_Subnet->getNetwork();
503518
$cidrMask = $Ipam_Api_Subnet->getCidrMask();
504519

505-
if($IPv !== false && !Ipam_Api_Subnet::{'isIPv'.$IPv.'Subnet'}($network)) {
506-
continue;
507-
}
508-
509520
$item = array();
510521
$item['header'] = $network.'/'.$cidrMask;
511522
$item['name'] = $Ipam_Api_Subnet->getSubnetLabel();
512523
$item['network'] = $network;
513524
$item['cidrMask'] = $cidrMask;
514525
$item['netMask'] = $Ipam_Api_Subnet->getNetMask();
515526
$item['gateway'] = $Ipam_Api_Subnet->getGateway();
516-
$item['networkIP'] = $Ipam_Api_Subnet->getNetworkIp();
517-
$item['broadcastIP'] = $Ipam_Api_Subnet->getBroadcastIp();
527+
528+
if($Ipam_Api_Subnet->isIPv4()) {
529+
$item['networkIP'] = $Ipam_Api_Subnet->getNetworkIp();
530+
$item['broadcastIP'] = $Ipam_Api_Subnet->getBroadcastIp();
531+
}
532+
elseif($Ipam_Api_Subnet->isIPv6()) {
533+
$item['firstIP'] = $Ipam_Api_Subnet->getFirstIp();
534+
$item['lastIP'] = $Ipam_Api_Subnet->getLastIp();
535+
}
518536

519537
// Un subnet n'a pas forcément de VLAN
520538
if($Ipam_Api_Vlan !== false) {

0 commit comments

Comments
 (0)