Rev 65 | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 65 | Rev 97 | ||
---|---|---|---|
1 | <?php |
1 | <?php |
2 | 2 | ||
3 | /* |
3 | /* |
4 | * IPv4 functions for PHP |
4 | * IPv4 functions for PHP |
5 | * Copyright 2012-2021 Daniel Marschall, ViaThinkSoft |
5 | * Copyright 2012-2022 Daniel Marschall, ViaThinkSoft |
6 | * Version 2021-05-21 |
6 | * Version 2022-09-22 |
7 | * |
7 | * |
8 | * Licensed under the Apache License, Version 2.0 (the "License"); |
8 | * Licensed under the Apache License, Version 2.0 (the "License"); |
9 | * you may not use this file except in compliance with the License. |
9 | * you may not use this file except in compliance with the License. |
10 | * You may obtain a copy of the License at |
10 | * You may obtain a copy of the License at |
11 | * |
11 | * |
12 | * http://www.apache.org/licenses/LICENSE-2.0 |
12 | * http://www.apache.org/licenses/LICENSE-2.0 |
13 | * |
13 | * |
14 | * Unless required by applicable law or agreed to in writing, software |
14 | * Unless required by applicable law or agreed to in writing, software |
15 | * distributed under the License is distributed on an "AS IS" BASIS, |
15 | * distributed under the License is distributed on an "AS IS" BASIS, |
16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
17 | * See the License for the specific language governing permissions and |
17 | * See the License for the specific language governing permissions and |
18 | * limitations under the License. |
18 | * limitations under the License. |
19 | */ |
19 | */ |
20 | 20 | ||
21 | // TODO: oop, exceptions? |
21 | // TODO: oop, exceptions? |
22 | 22 | ||
23 | // Very small self-test: |
23 | // Very small self-test: |
24 | /* |
24 | /* |
25 | function ipv4_selftest() { |
25 | function ipv4_selftest() { |
26 | $iv_b = ipv4_complete('1.2'); |
26 | $iv_b = ipv4_complete('1.2'); |
27 | $iv_m = 20; |
27 | $iv_m = 20; |
28 | $r = ipv4_cidr2range($iv_b, $iv_m); |
28 | $r = ipv4_cidr2range($iv_b, $iv_m); |
29 | echo "$iv_b/$iv_m => $r[0] - $r[1]\n"; |
29 | echo "$iv_b/$iv_m => $r[0] - $r[1]\n"; |
30 | 30 | ||
31 | $rev = ipv4_range2cidr($r[0], $r[1]); |
31 | $rev = ipv4_range2cidr($r[0], $r[1]); |
32 | $rev = implode("\n", $rev); |
32 | $rev = implode("\n", $rev); |
33 | echo "$r[0] - $r[1] => $rev ["; |
33 | echo "$r[0] - $r[1] => $rev ["; |
34 | $ok = $rev == "$iv_b/$iv_m"; |
34 | $ok = $rev == "$iv_b/$iv_m"; |
35 | echo $ok ? 'OK' : 'Mismatch'; |
35 | echo $ok ? 'OK' : 'Mismatch'; |
36 | echo "]\n"; |
36 | echo "]\n"; |
37 | echo "In-CIDR-Test: "; |
37 | echo "In-CIDR-Test: "; |
38 | echo ipv4_in_cidr("$iv_b/$iv_m", "$iv_b/$iv_m") ? 'OK' : 'Fail'; |
38 | echo ipv4_in_cidr("$iv_b/$iv_m", "$iv_b/$iv_m") ? 'OK' : 'Fail'; |
39 | echo "\n"; |
39 | echo "\n"; |
40 | } |
40 | } |
41 | ipv4_selftest(); |
41 | ipv4_selftest(); |
42 | */ |
42 | */ |
43 | 43 | ||
44 | function ipv4_cidr2range($baseip_or_cidr, $subnet='') { |
44 | function ipv4_cidr2range($baseip_or_cidr, $subnet='') { |
45 | # (C) 2012 ViaThinkSoft |
45 | # (C) 2012 ViaThinkSoft |
46 | # Version 1.1 |
46 | # Version 1.1 |
47 | # This function converts an CIDR notation <baseip>/<subnet> into an IPv4 address block array($low_ip, $high_ip) |
47 | # This function converts an CIDR notation <baseip>/<subnet> into an IPv4 address block array($low_ip, $high_ip) |
48 | 48 | ||
49 | if (strpos($baseip_or_cidr, '/') !== false) { |
49 | if (strpos($baseip_or_cidr, '/') !== false) { |
50 | $tmp = explode('/', $baseip_or_cidr, 2); |
50 | $tmp = explode('/', $baseip_or_cidr, 2); |
51 | $baseip_or_cidr = $tmp[0]; |
51 | $baseip_or_cidr = $tmp[0]; |
52 | $subnet = $tmp[1]; |
52 | $subnet = $tmp[1]; |
53 | unset($tmp); |
53 | unset($tmp); |
54 | } |
54 | } |
55 | 55 | ||
56 | if (($subnet < 0) || ($subnet > 32)) return false; |
56 | if (($subnet < 0) || ($subnet > 32)) return false; |
57 | 57 | ||
58 | $maxint32 = 0xFFFFFFFF; |
58 | $maxint32 = 0xFFFFFFFF; |
59 | $netmask = $maxint32 << (32-$subnet); |
59 | $netmask = $maxint32 << (32-$subnet); |
60 | $netmask = $netmask & $maxint32; // crop to 32 bits |
60 | $netmask = $netmask & $maxint32; // crop to 32 bits |
61 | $wildcard = $maxint32 ^ $netmask; // ~$netmask; |
61 | $wildcard = $maxint32 ^ $netmask; // ~$netmask; |
62 | 62 | ||
63 | $x = ipv4_incomplete_ip2long($baseip_or_cidr) & $netmask; |
63 | $x = ipv4_incomplete_ip2long($baseip_or_cidr) & $netmask; |
64 | $nums = $wildcard; |
64 | $nums = $wildcard; |
65 | $low = long2ip($x); |
65 | $low = long2ip($x); |
66 | $high = long2ip($x + $nums); |
66 | $high = long2ip($x + $nums); |
67 | 67 | ||
68 | return array($low, $high); |
68 | return array($low, $high); |
69 | } |
69 | } |
70 | 70 | ||
71 | function ipv4_range2cidr($baseip, $topip, $shortening=false) { |
71 | function ipv4_range2cidr($baseip, $topip, $shortening=false) { |
72 | # (C) 2012 ViaThinkSoft |
72 | # (C) 2012 ViaThinkSoft |
73 | # Version 1.0 |
73 | # Version 1.0 |
74 | # This function converts an IPv4 address block into valid CIDR blocks (There may be multiple blocks!) |
74 | # This function converts an IPv4 address block into valid CIDR blocks (There may be multiple blocks!) |
75 | 75 | ||
76 | $out = array(); |
76 | $out = array(); |
77 | if (ipv4_cmp($baseip, $topip) > 0) return false; |
77 | if (ipv4_cmp($baseip, $topip) > 0) return false; |
78 | while (ipv4_incomplete_ip2long($baseip)-1 != ipv4_incomplete_ip2long($topip)) { |
78 | while (ipv4_incomplete_ip2long($baseip)-1 != ipv4_incomplete_ip2long($topip)) { |
79 | $i = -1; |
79 | $i = -1; |
80 | do { |
80 | do { |
81 | $i++; |
81 | $i++; |
82 | $range = ipv4_cidr2range($baseip, $i); |
82 | $range = ipv4_cidr2range($baseip, $i); |
83 | $l = $range[0]; |
83 | $l = $range[0]; |
84 | $t = $range[1]; |
84 | $t = $range[1]; |
85 | } while ((ipv4_cmp($l, $baseip) != 0) || (ipv4_cmp($t, $topip) > 0)); |
85 | } while ((ipv4_cmp($l, $baseip) != 0) || (ipv4_cmp($t, $topip) > 0)); |
86 | 86 | ||
87 | # Shortening: Stroke ".0" at the end |
87 | # Shortening: Stroke ".0" at the end |
88 | if ($shortening) $baseip = ipv4_shortening($baseip); |
88 | if ($shortening) $baseip = ipv4_shortening($baseip); |
89 | 89 | ||
90 | $out[] = "$baseip/$i"; |
90 | $out[] = "$baseip/$i"; |
91 | $baseip = ipv4_add($t, 1); |
91 | $baseip = ipv4_add($t, 1); |
92 | } |
92 | } |
93 | return $out; |
93 | return $out; |
94 | } |
94 | } |
95 | 95 | ||
96 | function ipv4_shortening($ip) { |
96 | function ipv4_shortening($ip) { |
97 | # (C) 2012 ViaThinkSoft |
97 | # (C) 2012 ViaThinkSoft |
98 | # Version 1.0 |
98 | # Version 1.0 |
99 | 99 | ||
100 | return preg_replace("|(\\.0{1,3}){0,3}\$|ismU", '', $ip); |
100 | return preg_replace("|(\\.0{1,3}){0,3}\$|ismU", '', $ip); |
101 | } |
101 | } |
102 | 102 | ||
103 | function ipv4_add($baseip, $num) { |
103 | function ipv4_add($baseip, $num) { |
104 | # (C) 2012 ViaThinkSoft |
104 | # (C) 2012 ViaThinkSoft |
105 | # Version 1.0 |
105 | # Version 1.0 |
106 | 106 | ||
107 | return long2ip(ipv4_incomplete_ip2long($baseip) + $num); |
107 | return long2ip(ipv4_incomplete_ip2long($baseip) + $num); |
108 | } |
108 | } |
109 | 109 | ||
110 | function ipv4_sub($baseip, $num) { |
110 | function ipv4_sub($baseip, $num) { |
111 | # (C) 2012 ViaThinkSoft |
111 | # (C) 2012 ViaThinkSoft |
112 | # Version 1.0 |
112 | # Version 1.0 |
113 | 113 | ||
114 | return long2ip(ipv4_incomplete_ip2long($baseip) - $num); |
114 | return long2ip(ipv4_incomplete_ip2long($baseip) - $num); |
115 | } |
115 | } |
116 | 116 | ||
117 | function ipv4_cmp($a, $b) { |
117 | function ipv4_cmp($a, $b) { |
118 | # (C) 2012 ViaThinkSoft |
118 | # (C) 2012 ViaThinkSoft |
119 | # Version 1.0 |
119 | # Version 1.0 |
120 | 120 | ||
121 | $a = ipv4_incomplete_ip2long($a); |
121 | $a = ipv4_incomplete_ip2long($a); |
122 | $b = ipv4_incomplete_ip2long($b); |
122 | $b = ipv4_incomplete_ip2long($b); |
123 | 123 | ||
124 | if ($a == $b) return 0; |
124 | if ($a == $b) return 0; |
125 | if ($a < $b) return -1; |
125 | if ($a < $b) return -1; |
126 | if ($a > $b) return 1; |
126 | if ($a > $b) return 1; |
127 | } |
127 | } |
128 | 128 | ||
129 | function ipv4_in_cidr($haystack, $needle) { |
129 | function ipv4_in_cidr($haystack, $needle) { |
130 | # (C) 2012 ViaThinkSoft |
130 | # (C) 2012 ViaThinkSoft |
131 | # Version 1.1 |
131 | # Version 1.1 |
132 | 132 | ||
133 | $x = explode('/', $haystack); |
133 | $x = explode('/', $haystack); |
134 | $ha = ipv4_cidr2range($x[0], $x[1]); |
134 | $ha = ipv4_cidr2range($x[0], $x[1]); |
135 | 135 | ||
136 | $x = explode('/', $needle); |
136 | $x = explode('/', $needle); |
137 | if (!isset($x[1])) $x[1] = '32'; // single IP |
137 | if (!isset($x[1])) $x[1] = '32'; // single IP |
138 | $ne = ipv4_cidr2range($x[0], $x[1]); |
138 | $ne = ipv4_cidr2range($x[0], $x[1]); |
139 | 139 | ||
140 | $ha_low = ipv4_incomplete_ip2long($ha[0]); |
140 | $ha_low = ipv4_incomplete_ip2long($ha[0]); |
141 | $ha_hig = ipv4_incomplete_ip2long($ha[1]); |
141 | $ha_hig = ipv4_incomplete_ip2long($ha[1]); |
142 | $ne_low = ipv4_incomplete_ip2long($ne[0]); |
142 | $ne_low = ipv4_incomplete_ip2long($ne[0]); |
143 | $ne_hig = ipv4_incomplete_ip2long($ne[1]); |
143 | $ne_hig = ipv4_incomplete_ip2long($ne[1]); |
144 | 144 | ||
145 | # HA: low[ ]high |
145 | # HA: low[ ]high |
146 | # NE: low[ ]high |
146 | # NE: low[ ]high |
147 | 147 | ||
148 | return ($ne_low >= $ha_low) && ($ne_hig <= $ha_hig); |
148 | return ($ne_low >= $ha_low) && ($ne_hig <= $ha_hig); |
149 | } |
149 | } |
150 | 150 | ||
151 | function ipv4_complete($short_form) { |
151 | function ipv4_complete($short_form) { |
152 | # (C) 2012 ViaThinkSoft |
152 | # (C) 2012 ViaThinkSoft |
153 | # Version 1.0 |
153 | # Version 1.0 |
154 | 154 | ||
155 | $short_form = trim($short_form); |
155 | $short_form = trim($short_form); |
156 | if ($short_form == '') return '0.0.0.0'; |
156 | if ($short_form == '') return '0.0.0.0'; |
157 | $c = substr_count($short_form, '.'); |
157 | $c = substr_count($short_form, '.'); |
158 | if ($c > 3) return false; |
158 | if ($c > 3) return false; |
159 | if ($c == 3) return $short_form; |
159 | if ($c == 3) return $short_form; |
160 | $c = substr_count($short_form, '.'); |
160 | $c = substr_count($short_form, '.'); |
161 | $short_form .= str_repeat('.0', 3-$c); |
161 | $short_form .= str_repeat('.0', 3-$c); |
162 | return $short_form; |
162 | return $short_form; |
163 | } |
163 | } |
164 | 164 | ||
165 | function ipv4_incomplete_ip2long($ip) { |
165 | function ipv4_incomplete_ip2long($ip) { |
166 | # (C) 2012-2014 ViaThinkSoft |
166 | # (C) 2012-2014 ViaThinkSoft |
167 | # Version 1.2 |
167 | # Version 1.2 |
168 | 168 | ||
169 | # return sprintf('%u', ip2long(ipv4_complete($ip))); |
169 | # return sprintf('%u', ip2long(ipv4_complete($ip))); |
170 | return sprintf('%u', ip2long(ipv4_normalize($ip))); |
170 | return sprintf('%u', ip2long(ipv4_normalize($ip))); |
171 | } |
171 | } |
172 | 172 | ||
173 | // IMPORTANT! $cmp_ary[x]=y MUST HAVE x<=y ! |
173 | // IMPORTANT! $cmp_ary[x]=y MUST HAVE x<=y ! |
174 | function ipv4_merge_address_blocks($data, $debug = false, $shortening = false) { |
174 | function ipv4_merge_address_blocks($data, $debug = false, $shortening = false) { |
175 | # (C) 2012-2013 ViaThinkSoft |
175 | # (C) 2012-2013 ViaThinkSoft |
176 | # Version 2.2 |
176 | # Version 2.2 |
177 | 177 | ||
178 | if ($debug !== false) $STARTZEIT = time(); |
178 | if ($debug !== false) $STARTZEIT = time(); |
179 | 179 | ||
180 | // 1. Convert IPs to numbers |
180 | // 1. Convert IPs to numbers |
181 | 181 | ||
182 | $cmp_ary = array(); |
182 | $cmp_ary = array(); |
183 | foreach ($data as $a => &$b) { |
183 | foreach ($data as $a => &$b) { |
184 | $a = ipv4_incomplete_ip2long($a); |
184 | $a = ipv4_incomplete_ip2long($a); |
185 | $b = ipv4_incomplete_ip2long($b); |
185 | $b = ipv4_incomplete_ip2long($b); |
186 | 186 | ||
187 | $cmp_ary[$a] = $b; |
187 | $cmp_ary[$a] = $b; |
188 | unset($a); |
188 | unset($a); |
189 | unset($b); |
189 | unset($b); |
190 | } |
190 | } |
191 | 191 | ||
192 | // 2. Sort array |
192 | // 2. Sort array |
193 | 193 | ||
194 | ksort($cmp_ary); |
194 | ksort($cmp_ary); |
195 | 195 | ||
196 | // 3. Merge the blocks in an intelligent way (and remove redundant blocks) |
196 | // 3. Merge the blocks in an intelligent way (and remove redundant blocks) |
197 | 197 | ||
198 | # Merge overlapping blocks |
198 | # Merge overlapping blocks |
199 | # [ ] |
199 | # [ ] |
200 | # [ ] -> [ ] |
200 | # [ ] -> [ ] |
201 | 201 | ||
202 | # Merge neighbor blocks |
202 | # Merge neighbor blocks |
203 | # [ ][ ] -> [ ] |
203 | # [ ][ ] -> [ ] |
204 | 204 | ||
205 | # Remove redundant blocks |
205 | # Remove redundant blocks |
206 | # [ ] -> [ ] |
206 | # [ ] -> [ ] |
207 | # [ ] |
207 | # [ ] |
208 | 208 | ||
209 | $merge_count = 0; |
209 | $merge_count = 0; |
210 | $redundant_deleted_count = 0; |
210 | $redundant_deleted_count = 0; |
211 | $round_count = 0; |
211 | $round_count = 0; |
212 | do { |
212 | do { |
213 | if ($debug !== false) { |
213 | if ($debug !== false) { |
214 | $LAUFZEIT = time() - $STARTZEIT; |
214 | $LAUFZEIT = time() - $STARTZEIT; |
215 | echo $debug."Merging... $round_count rounds; merged $merge_count blocks; deleted $redundant_deleted_count redundant blocks; time: $LAUFZEIT seconds\r"; |
215 | echo $debug."Merging... $round_count rounds; merged $merge_count blocks; deleted $redundant_deleted_count redundant blocks; time: $LAUFZEIT seconds\r"; |
216 | } |
216 | } |
217 | 217 | ||
218 | $round_count++; |
218 | $round_count++; |
219 | 219 | ||
220 | $clean = true; |
220 | $clean = true; |
221 | 221 | ||
222 | foreach ($cmp_ary as $a => &$b) { |
222 | foreach ($cmp_ary as $a => &$b) { |
223 | foreach ($cmp_ary as $x => &$y) { |
223 | foreach ($cmp_ary as $x => &$y) { |
224 | // x in range [a+1..b+1] ? |
224 | // x in range [a+1..b+1] ? |
225 | if ($x<=$a) continue; |
225 | if ($x<=$a) continue; |
226 | if ($x>$b+1) break; |
226 | if ($x>$b+1) break; |
227 | 227 | ||
228 | // Merge |
228 | // Merge |
229 | $clean = false; |
229 | $clean = false; |
230 | if ($y>$b) { |
230 | if ($y>$b) { |
231 | $merge_count++; |
231 | $merge_count++; |
232 | $b = $y; |
232 | $b = $y; |
233 | unset($cmp_ary[$x]); |
233 | unset($cmp_ary[$x]); |
234 | } else { |
234 | } else { |
235 | $redundant_deleted_count++; |
235 | $redundant_deleted_count++; |
236 | unset($cmp_ary[$x]); |
236 | unset($cmp_ary[$x]); |
237 | } |
237 | } |
238 | } |
238 | } |
239 | } |
239 | } |
240 | } while (!$clean); |
240 | } while (!$clean); |
241 | 241 | ||
242 | if ($debug !== false) { |
242 | if ($debug !== false) { |
243 | $LAUFZEIT = time() - $STARTZEIT; |
243 | $LAUFZEIT = time() - $STARTZEIT; |
244 | echo $debug."Merge completed. $round_count rounds; merged $merge_count blocks; deleted $redundant_deleted_count redundant blocks; time: $LAUFZEIT seconds\n"; |
244 | echo $debug."Merge completed. $round_count rounds; merged $merge_count blocks; deleted $redundant_deleted_count redundant blocks; time: $LAUFZEIT seconds\n"; |
245 | } |
245 | } |
246 | 246 | ||
247 | // 4. Convert back to IPs |
247 | // 4. Convert back to IPs |
248 | 248 | ||
249 | $out_ary = array(); |
249 | $out_ary = array(); |
250 | foreach ($cmp_ary as $a => &$b) { |
250 | foreach ($cmp_ary as $a => &$b) { |
251 | $a = long2ip($a); |
251 | $a = long2ip($a); |
252 | $b = long2ip($b); |
252 | $b = long2ip($b); |
253 | if ($shortening) { |
253 | if ($shortening) { |
254 | $a = ipv4_shortening($a); |
254 | $a = ipv4_shortening($a); |
255 | $b = ipv4_shortening($b); |
255 | $b = ipv4_shortening($b); |
256 | } |
256 | } |
257 | $out_ary[$a] = $b; |
257 | $out_ary[$a] = $b; |
258 | } |
258 | } |
259 | 259 | ||
260 | return $out_ary; |
260 | return $out_ary; |
261 | } |
261 | } |
262 | 262 | ||
263 | function ipv4_merge_arrays($data_a, $data_b) { |
263 | function ipv4_merge_arrays($data_a, $data_b) { |
264 | # (C) 2012 ViaThinkSoft |
264 | # (C) 2012 ViaThinkSoft |
265 | # Version 1.2 |
265 | # Version 1.2 |
266 | 266 | ||
267 | $normalized_data_a = array(); |
267 | $normalized_data_a = array(); |
268 | foreach ($data_a as $from => &$to) { |
268 | foreach ($data_a as $from => &$to) { |
269 | $normalized_data_a[ipv4_normalize($from)] = ipv4_normalize($to); |
269 | $normalized_data_a[ipv4_normalize($from)] = ipv4_normalize($to); |
270 | } |
270 | } |
271 | 271 | ||
272 | $normalized_data_b = array(); |
272 | $normalized_data_b = array(); |
273 | foreach ($data_b as $from => &$to) { |
273 | foreach ($data_b as $from => &$to) { |
274 | $normalized_data_b[ipv4_normalize($from)] = ipv4_normalize($to); |
274 | $normalized_data_b[ipv4_normalize($from)] = ipv4_normalize($to); |
275 | } |
275 | } |
276 | 276 | ||
277 | $data = array(); |
277 | $data = array(); |
278 | 278 | ||
279 | foreach ($normalized_data_a as $from => &$to) { |
279 | foreach ($normalized_data_a as $from => &$to) { |
280 | if (isset($normalized_data_b[$from])) { |
280 | if (isset($normalized_data_b[$from])) { |
281 | $data[$from] = ipv4_max($to, $normalized_data_b[$from]); |
281 | $data[$from] = ipv4_max($to, $normalized_data_b[$from]); |
282 | } else { |
282 | } else { |
283 | $data[$from] = $to; |
283 | $data[$from] = $to; |
284 | } |
284 | } |
285 | } |
285 | } |
286 | 286 | ||
287 | foreach ($normalized_data_b as $from => &$to) { |
287 | foreach ($normalized_data_b as $from => &$to) { |
288 | if (!isset($normalized_data_a[$from])) { |
288 | if (!isset($normalized_data_a[$from])) { |
289 | $data[$from] = $to; |
289 | $data[$from] = $to; |
290 | } |
290 | } |
291 | } |
291 | } |
292 | 292 | ||
293 | return $data; |
293 | return $data; |
294 | } |
294 | } |
295 | 295 | ||
296 | function ipv4_valid($ip) { |
296 | function ipv4_valid($ip) { |
297 | # (C) 2012 ViaThinkSoft |
297 | # (C) 2012 ViaThinkSoft |
298 | # Version 1.0 |
298 | # Version 1.0 |
299 | 299 | ||
300 | # return ipv4_incomplete_ip2long($ip) !== false; |
300 | # return ipv4_incomplete_ip2long($ip) !== false; |
301 | return ip2long($ip) !== false; |
301 | return ip2long($ip) !== false; |
302 | } |
302 | } |
303 | 303 | ||
304 | function ipv4_normalize($ip) { |
304 | function ipv4_normalize($ip) { |
305 | # (C) 2012-2013 ViaThinkSoft |
305 | # (C) 2012-2013 ViaThinkSoft |
306 | # Version 1.1.1 |
306 | # Version 1.1.1 |
307 | 307 | ||
308 | # Example: |
308 | # Example: |
309 | # 100.010.001.000 -> 100.10.1.0 |
309 | # 100.010.001.000 -> 100.10.1.0 |
310 | 310 | ||
311 | $ip = ipv4_complete($ip); |
311 | $ip = ipv4_complete($ip); |
312 | if (!$ip) return false; |
312 | if (!$ip) return false; |
313 | 313 | ||
314 | # ip2long buggy: 001.0.0.0 is not accepted |
314 | # ip2long buggy: 001.0.0.0 is not accepted |
315 | ## $cry = explode('.', $ip); |
315 | ## $cry = explode('.', $ip); |
316 | ## $cry[0] = preg_replace('@^0+@', '', $cry[0]); if ($cry[0] == '') $cry[0] = '0'; |
316 | ## $cry[0] = preg_replace('@^0+@', '', $cry[0]); if ($cry[0] == '') $cry[0] = '0'; |
317 | ## $cry[1] = preg_replace('@^0+@', '', $cry[1]); if ($cry[1] == '') $cry[1] = '0'; |
317 | ## $cry[1] = preg_replace('@^0+@', '', $cry[1]); if ($cry[1] == '') $cry[1] = '0'; |
318 | ## $cry[2] = preg_replace('@^0+@', '', $cry[2]); if ($cry[2] == '') $cry[2] = '0'; |
318 | ## $cry[2] = preg_replace('@^0+@', '', $cry[2]); if ($cry[2] == '') $cry[2] = '0'; |
319 | ## $cry[3] = preg_replace('@^0+@', '', $cry[3]); if ($cry[3] == '') $cry[3] = '0'; |
319 | ## $cry[3] = preg_replace('@^0+@', '', $cry[3]); if ($cry[3] == '') $cry[3] = '0'; |
320 | ## $ip = implode('.', $cry); |
320 | ## $ip = implode('.', $cry); |
321 | ## return $ip; |
321 | ## return $ip; |
322 | 322 | ||
323 | return preg_replace('@^0{0,2}([0-9]{1,3})\.0{0,2}([0-9]{1,3})\.0{0,2}([0-9]{1,3})\.0{0,2}([0-9]{1,3})$@', '\\1.\\2.\\3.\\4', $ip); |
323 | return preg_replace('@^0{0,2}([0-9]{1,3})\.0{0,2}([0-9]{1,3})\.0{0,2}([0-9]{1,3})\.0{0,2}([0-9]{1,3})$@', '\\1.\\2.\\3.\\4', $ip); |
324 | } |
324 | } |
325 | 325 | ||
326 | function ipv4_expand($ip) { |
326 | function ipv4_expand($ip) { |
327 | # (C) 2012 ViaThinkSoft |
327 | # (C) 2012 ViaThinkSoft |
328 | # Version 1.0 |
328 | # Version 1.0 |
329 | 329 | ||
330 | # Example: |
330 | # Example: |
331 | # 100.10.1.0 -> 100.010.001.000 |
331 | # 100.10.1.0 -> 100.010.001.000 |
332 | 332 | ||
333 | $ip = ipv4_complete($ip); |
333 | $ip = ipv4_complete($ip); |
334 | if (!$ip) return false; |
334 | if (!$ip) return false; |
335 | 335 | ||
336 | $cry = explode('.', $ip); |
336 | $cry = explode('.', $ip); |
337 | $cry[0] = str_pad($cry[0], 3, '0', STR_PAD_LEFT); |
337 | $cry[0] = str_pad($cry[0], 3, '0', STR_PAD_LEFT); |
338 | $cry[1] = str_pad($cry[1], 3, '0', STR_PAD_LEFT); |
338 | $cry[1] = str_pad($cry[1], 3, '0', STR_PAD_LEFT); |
339 | $cry[2] = str_pad($cry[2], 3, '0', STR_PAD_LEFT); |
339 | $cry[2] = str_pad($cry[2], 3, '0', STR_PAD_LEFT); |
340 | $cry[3] = str_pad($cry[3], 3, '0', STR_PAD_LEFT); |
340 | $cry[3] = str_pad($cry[3], 3, '0', STR_PAD_LEFT); |
341 | return implode('.', $cry); |
341 | return implode('.', $cry); |
342 | } |
342 | } |
343 | 343 | ||
344 | function ipv4_min($ip_a, $ip_b) { |
344 | function ipv4_min($ip_a, $ip_b) { |
345 | # (C) 2012 ViaThinkSoft |
345 | # (C) 2012 ViaThinkSoft |
346 | # Version 1.0 |
346 | # Version 1.0 |
347 | 347 | ||
348 | if (ipv4_cmp($ip_a, $ip_b) == -1) { |
348 | if (ipv4_cmp($ip_a, $ip_b) == -1) { |
349 | return $ip_a; |
349 | return $ip_a; |
350 | } else { |
350 | } else { |
351 | return $ip_b; |
351 | return $ip_b; |
352 | } |
352 | } |
353 | } |
353 | } |
354 | 354 | ||
355 | function ipv4_max($ip_a, $ip_b) { |
355 | function ipv4_max($ip_a, $ip_b) { |
356 | # (C) 2012 ViaThinkSoft |
356 | # (C) 2012 ViaThinkSoft |
357 | # Version 1.0 |
357 | # Version 1.0 |
358 | 358 | ||
359 | if (ipv4_cmp($ip_a, $ip_b) == 1) { |
359 | if (ipv4_cmp($ip_a, $ip_b) == 1) { |
360 | return $ip_a; |
360 | return $ip_a; |
361 | } else { |
361 | } else { |
362 | return $ip_b; |
362 | return $ip_b; |
363 | } |
363 | } |
364 | } |
364 | } |
365 | 365 | ||
366 | function ipv4_ipcount($data) { |
366 | function ipv4_ipcount($data) { |
367 | # (C) 2012 ViaThinkSoft |
367 | # (C) 2012 ViaThinkSoft |
368 | # Version 1.0 |
368 | # Version 1.0 |
369 | 369 | ||
370 | $cnt = 0; |
370 | $cnt = 0; |
371 | 371 | ||
372 | foreach ($data as $from => &$to) { |
372 | foreach ($data as $from => &$to) { |
373 | $cnt += ipv4_incomplete_ip2long($to) - ipv4_incomplete_ip2long($from); |
373 | $cnt += ipv4_incomplete_ip2long($to) - ipv4_incomplete_ip2long($from); |
374 | } |
374 | } |
375 | 375 | ||
376 | return $cnt; |
376 | return $cnt; |
377 | } |
377 | } |
378 | 378 | ||
379 | function ipv4_read_file($file) { |
379 | function ipv4_read_file($file) { |
380 | # (C) 2012 ViaThinkSoft |
380 | # (C) 2012 ViaThinkSoft |
381 | # Version 1.0 |
381 | # Version 1.0 |
382 | 382 | ||
383 | $data = array(); |
383 | $data = array(); |
384 | 384 | ||
385 | $lines = file($file); |
385 | $lines = file($file); |
386 | foreach ($lines as &$line) { |
386 | foreach ($lines as &$line) { |
387 | $rng = ipv4_line2range($line); |
387 | $rng = ipv4_line2range($line); |
388 | $data[$rng[0]] = $rng[1]; |
388 | $data[$rng[0]] = $rng[1]; |
389 | } |
389 | } |
390 | 390 | ||
391 | return $data; |
391 | return $data; |
392 | } |
392 | } |
393 | 393 | ||
394 | function ipv4_line2range($line) { |
394 | function ipv4_line2range($line) { |
395 | # (C) 2012 ViaThinkSoft |
395 | # (C) 2012 ViaThinkSoft |
396 | # Version 1.0 |
396 | # Version 1.0 |
397 | 397 | ||
398 | $line = trim($line); |
398 | $line = trim($line); |
399 | 399 | ||
400 | if (strpos($line, '/') !== false) { |
400 | if (strpos($line, '/') !== false) { |
401 | $rng = ipv4_cidr2range($line); |
401 | $rng = ipv4_cidr2range($line); |
402 | } else { |
402 | } else { |
403 | $rng = explode('-', $line); |
403 | $rng = explode('-', $line); |
404 | $rng[0] = trim($rng[0]); |
- | |
405 | $rng[1] = trim($rng[1]); |
- | |
406 | $rng[0] = ipv4_normalize($rng[0]); |
404 | $rng[0] = ipv4_normalize(trim($rng[0])); |
407 | if (!isset($rng[1])) $rng[1] = $rng[0]; |
405 | $rng[1] = isset($rng[1]) ? ipv4_normalize(trim($rng[1])) : $rng[0]; |
408 | $rng[1] = ipv4_normalize($rng[1]); |
- | |
409 | } |
406 | } |
410 | 407 | ||
411 | return $rng; |
408 | return $rng; |
412 | } |
409 | } |
413 | 410 | ||
414 | # --- New 16,12,12 |
411 | # --- New 16,12,12 |
415 | 412 | ||
416 | define('IPV4_BITS', 32); |
413 | define('IPV4_BITS', 32); |
417 | 414 | ||
418 | function ipv4_distance($ipOrCIDR_Searchterm, $ipOrCIDR_Candidate) { |
415 | function ipv4_distance($ipOrCIDR_Searchterm, $ipOrCIDR_Candidate) { |
419 | $ary = ipv4_cidr_split($ipOrCIDR_Searchterm); |
416 | $ary = ipv4_cidr_split($ipOrCIDR_Searchterm); |
420 | $ip = $ary[0]; |
417 | $ip = $ary[0]; |
421 | 418 | ||
422 | if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) === false) { |
419 | if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) === false) { |
423 | return false; |
420 | return false; |
424 | } |
421 | } |
425 | 422 | ||
426 | $ary = ipv4_cidr_split($ipOrCIDR_Candidate); |
423 | $ary = ipv4_cidr_split($ipOrCIDR_Candidate); |
427 | $ip = $ary[0]; |
424 | $ip = $ary[0]; |
428 | $cidr_bits = $ary[1]; |
425 | $cidr_bits = $ary[1]; |
429 | if ($cidr_bits > IPV4_BITS) return false; // throw new Exception('CIDR bits > '.IPV4_BITS); |
426 | if ($cidr_bits > IPV4_BITS) return false; // throw new Exception('CIDR bits > '.IPV4_BITS); |
430 | if (!is_numeric($cidr_bits)) return false; |
427 | if (!is_numeric($cidr_bits)) return false; |
431 | 428 | ||
432 | if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) === false) { |
429 | if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) === false) { |
433 | return false; |
430 | return false; |
434 | } |
431 | } |
435 | 432 | ||
436 | $x = ipv4_trackdown($ipOrCIDR_Searchterm); |
433 | $x = ipv4_trackdown($ipOrCIDR_Searchterm); |
437 | 434 | ||
438 | if (ipv4_in_cidr($x[0], $ip.'/'.$cidr_bits)) { |
435 | if (ipv4_in_cidr($x[0], $ip.'/'.$cidr_bits)) { |
439 | $ary = ipv4_cidr_split($x[0]); |
436 | $ary = ipv4_cidr_split($x[0]); |
440 | $cidr_bits2 = $ary[1]; |
437 | $cidr_bits2 = $ary[1]; |
441 | if ($cidr_bits2 > IPV4_BITS) return false; // throw new Exception('CIDR bits > '.IPV4_BITS); |
438 | if ($cidr_bits2 > IPV4_BITS) return false; // throw new Exception('CIDR bits > '.IPV4_BITS); |
442 | return $cidr_bits2-$cidr_bits; |
439 | return $cidr_bits2-$cidr_bits; |
443 | } |
440 | } |
444 | 441 | ||
445 | $i = 0; |
442 | $i = 0; |
446 | $max = false; |
443 | $max = false; |
447 | foreach ($x as &$y) { |
444 | foreach ($x as &$y) { |
448 | if (ipv4_in_cidr($ip.'/'.$cidr_bits, $y)) { |
445 | if (ipv4_in_cidr($ip.'/'.$cidr_bits, $y)) { |
449 | $max = $i; |
446 | $max = $i; |
450 | } |
447 | } |
451 | $i++; |
448 | $i++; |
452 | } |
449 | } |
453 | 450 | ||
454 | return $max; |
451 | return $max; |
455 | } |
452 | } |
456 | 453 | ||
457 | function ipv4_cidr_split($ipOrCIDR) { |
454 | function ipv4_cidr_split($ipOrCIDR) { |
458 | $ary = explode('/', $ipOrCIDR, 2); |
455 | $ary = explode('/', $ipOrCIDR, 2); |
459 | $cidr_bits = isset($ary[1]) ? $ary[1] : IPV4_BITS; |
456 | $cidr_bits = isset($ary[1]) ? $ary[1] : IPV4_BITS; |
460 | if ($cidr_bits > IPV4_BITS) return false; // throw new Exception('CIDR bits > '.IPV4_BITS); |
457 | if ($cidr_bits > IPV4_BITS) return false; // throw new Exception('CIDR bits > '.IPV4_BITS); |
461 | if (!is_numeric($cidr_bits)) return false; |
458 | if (!is_numeric($cidr_bits)) return false; |
462 | $ip = $ary[0]; |
459 | $ip = $ary[0]; |
463 | return array($ip, $cidr_bits); |
460 | return array($ip, $cidr_bits); |
464 | } |
461 | } |
465 | 462 | ||
466 | function ipv4_equals($ipOrCIDRA, $ipOrCIDRB) { |
463 | function ipv4_equals($ipOrCIDRA, $ipOrCIDRB) { |
467 | return ipv4_normalize_range($ipOrCIDRA) == ipv4_normalize_range($ipOrCIDRB); |
464 | return ipv4_normalize_range($ipOrCIDRA) == ipv4_normalize_range($ipOrCIDRB); |
468 | } |
465 | } |
469 | 466 | ||
470 | function ipv4_cidr_min_ip($ipOrCIDR) { |
467 | function ipv4_cidr_min_ip($ipOrCIDR) { |
471 | $ary = ipv4_cidr_split($ipOrCIDR); |
468 | $ary = ipv4_cidr_split($ipOrCIDR); |
472 | $ipOrCIDR = $ary[0]; |
469 | $ipOrCIDR = $ary[0]; |
473 | $cidr_bits = $ary[1]; |
470 | $cidr_bits = $ary[1]; |
474 | if ($cidr_bits > IPV4_BITS) return false; // throw new Exception('CIDR bits > '.IPV4_BITS); |
471 | if ($cidr_bits > IPV4_BITS) return false; // throw new Exception('CIDR bits > '.IPV4_BITS); |
475 | if (!is_numeric($cidr_bits)) return false; |
472 | if (!is_numeric($cidr_bits)) return false; |
476 | 473 | ||
477 | $m = ip2bin($ipOrCIDR); |
474 | $m = ip2bin($ipOrCIDR); |
478 | $m = substr($m, 0, $cidr_bits) . str_repeat('0', IPV4_BITS-$cidr_bits); |
475 | $m = substr($m, 0, $cidr_bits) . str_repeat('0', IPV4_BITS-$cidr_bits); |
479 | 476 | ||
480 | return bin2ip($m); |
477 | return bin2ip($m); |
481 | } |
478 | } |
482 | 479 | ||
483 | function ipv4_cidr_max_ip($ipOrCIDR) { |
480 | function ipv4_cidr_max_ip($ipOrCIDR) { |
484 | $ary = ipv4_cidr_split($ipOrCIDR); |
481 | $ary = ipv4_cidr_split($ipOrCIDR); |
485 | $ipOrCIDR = $ary[0]; |
482 | $ipOrCIDR = $ary[0]; |
486 | $cidr_bits = $ary[1]; |
483 | $cidr_bits = $ary[1]; |
487 | if ($cidr_bits > IPV4_BITS) return false; // throw new Exception('CIDR bits > '.IPV4_BITS); |
484 | if ($cidr_bits > IPV4_BITS) return false; // throw new Exception('CIDR bits > '.IPV4_BITS); |
488 | if (!is_numeric($cidr_bits)) return false; |
485 | if (!is_numeric($cidr_bits)) return false; |
489 | 486 | ||
490 | $m = ip2bin($ipOrCIDR); |
487 | $m = ip2bin($ipOrCIDR); |
491 | $m = substr($m, 0, $cidr_bits) . str_repeat('1', IPV4_BITS-$cidr_bits); |
488 | $m = substr($m, 0, $cidr_bits) . str_repeat('1', IPV4_BITS-$cidr_bits); |
492 | 489 | ||
493 | return bin2ip($m); |
490 | return bin2ip($m); |
494 | } |
491 | } |
495 | 492 | ||
496 | function ipv4_normalize_range($ipOrCIDR) { |
493 | function ipv4_normalize_range($ipOrCIDR) { |
497 | $ary = ipv4_cidr_split($ipOrCIDR); |
494 | $ary = ipv4_cidr_split($ipOrCIDR); |
498 | $ipOrCIDR = $ary[0]; |
495 | $ipOrCIDR = $ary[0]; |
499 | $cidr_bits = $ary[1]; |
496 | $cidr_bits = $ary[1]; |
500 | if ($cidr_bits > IPV4_BITS) return false; // throw new Exception('CIDR bits > '.IPV4_BITS); |
497 | if ($cidr_bits > IPV4_BITS) return false; // throw new Exception('CIDR bits > '.IPV4_BITS); |
501 | if (!is_numeric($cidr_bits)) return false; |
498 | if (!is_numeric($cidr_bits)) return false; |
502 | 499 | ||
503 | $m = ip2bin($ipOrCIDR); |
500 | $m = ip2bin($ipOrCIDR); |
504 | $m = substr($m, 0, $cidr_bits) . str_repeat('0', IPV4_BITS-$cidr_bits); |
501 | $m = substr($m, 0, $cidr_bits) . str_repeat('0', IPV4_BITS-$cidr_bits); |
505 | 502 | ||
506 | return bin2ip($m) . '/' . $cidr_bits; |
503 | return bin2ip($m) . '/' . $cidr_bits; |
507 | } |
504 | } |
508 | 505 | ||
509 | function ipv4_trackdown($ipOrCIDR) { |
506 | function ipv4_trackdown($ipOrCIDR) { |
510 | $ary = ipv4_cidr_split($ipOrCIDR); |
507 | $ary = ipv4_cidr_split($ipOrCIDR); |
511 | $ipOrCIDR = $ary[0]; |
508 | $ipOrCIDR = $ary[0]; |
512 | $cidr_bits = $ary[1]; |
509 | $cidr_bits = $ary[1]; |
513 | if ($cidr_bits > IPV4_BITS) return false; // throw new Exception('CIDR bits > '.IPV4_BITS); |
510 | if ($cidr_bits > IPV4_BITS) return false; // throw new Exception('CIDR bits > '.IPV4_BITS); |
514 | if (!is_numeric($cidr_bits)) return false; |
511 | if (!is_numeric($cidr_bits)) return false; |
515 | 512 | ||
516 | $out = array(); |
513 | $out = array(); |
517 | $m = ip2bin($ipOrCIDR); |
514 | $m = ip2bin($ipOrCIDR); |
518 | 515 | ||
519 | for ($i=$cidr_bits; $i>=0; $i--) { |
516 | for ($i=$cidr_bits; $i>=0; $i--) { |
520 | $m = substr($m, 0, $i) . str_repeat('0', IPV4_BITS-$i); |
517 | $m = substr($m, 0, $i) . str_repeat('0', IPV4_BITS-$i); |
521 | $out[] = bin2ip($m) . '/' . $i; |
518 | $out[] = bin2ip($m) . '/' . $i; |
522 | } |
519 | } |
523 | 520 | ||
524 | return $out; |
521 | return $out; |
525 | } |
522 | } |
526 | 523 | ||
527 | # --- |
524 | # --- |
528 | 525 | ||
529 | if (!function_exists('ip2bin')) { |
526 | if (!function_exists('ip2bin')) { |
530 | function ip2bin($ip) { |
527 | function ip2bin($ip) { |
531 | # Source: http://php.net/manual/en/function.ip2long.php#104163 |
528 | # Source: http://php.net/manual/en/function.ip2long.php#104163 |
532 | # modified by VTS |
529 | # modified by VTS |
533 | 530 | ||
534 | if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) !== false) { |
531 | if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) !== false) { |
535 | $iplong = ip2long($ip); |
532 | $iplong = ip2long($ip); |
536 | assert($iplong !== false); |
533 | assert($iplong !== false); |
537 | return base_convert((string)$iplong, 10, 2); |
534 | return base_convert((string)$iplong, 10, 2); |
538 | } |
535 | } |
539 | if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) === false) { |
536 | if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) === false) { |
540 | return false; |
537 | return false; |
541 | } |
538 | } |
542 | if (($ip_n = inet_pton($ip)) === false) { |
539 | if (($ip_n = inet_pton($ip)) === false) { |
543 | return false; |
540 | return false; |
544 | } |
541 | } |
545 | $bits = 15; // 16 x 8 bit = 128bit (ipv6) |
542 | $bits = 15; // 16 x 8 bit = 128bit (ipv6) |
546 | $ipbin = ''; # added by vts to avoid warning |
543 | $ipbin = ''; # added by vts to avoid warning |
547 | while ($bits >= 0) { |
544 | while ($bits >= 0) { |
548 | $bin = sprintf('%08b', (ord($ip_n[$bits]))); |
545 | $bin = sprintf('%08b', (ord($ip_n[$bits]))); |
549 | $ipbin = $bin.$ipbin; |
546 | $ipbin = $bin.$ipbin; |
550 | $bits--; |
547 | $bits--; |
551 | } |
548 | } |
552 | return $ipbin; |
549 | return $ipbin; |
553 | } |
550 | } |
554 | } |
551 | } |
555 | 552 | ||
556 | if (!function_exists('bin2ip')) { |
553 | if (!function_exists('bin2ip')) { |
557 | function bin2ip($bin) { |
554 | function bin2ip($bin) { |
558 | # Source: http://php.net/manual/en/function.ip2long.php#104163 |
555 | # Source: http://php.net/manual/en/function.ip2long.php#104163 |
559 | # modified by VTS |
556 | # modified by VTS |
560 | 557 | ||
561 | if (strlen($bin) <= 32) { // 32bits (ipv4) |
558 | if (strlen($bin) <= 32) { // 32bits (ipv4) |
562 | $iplong = base_convert($bin, 2, 10); |
559 | $iplong = base_convert($bin, 2, 10); |
563 | return long2ip(intval($iplong)); |
560 | return long2ip(intval($iplong)); |
564 | } |
561 | } |
565 | if (strlen($bin) != 128) { |
562 | if (strlen($bin) != 128) { |
566 | return false; |
563 | return false; |
567 | } |
564 | } |
568 | $pad = 128 - strlen($bin); |
565 | //$bin = str_pad($bin, 128, '0', STR_PAD_LEFT); |
569 | for ($i = 1; $i <= $pad; $i++) { |
- | |
570 | $bin = '0'.$bin; |
- | |
571 | } |
- | |
572 | $bits = 0; |
566 | $bits = 0; |
573 | $ipv6 = ''; # added by vts to avoid warning |
567 | $ipv6 = ''; # added by vts to avoid warning |
574 | while ($bits <= 7) { |
568 | while ($bits <= 7) { |
575 | $bin_part = substr($bin,($bits*16),16); |
569 | $bin_part = substr($bin,($bits*16),16); |
576 | $ipv6 .= dechex(bindec($bin_part)) . ':'; |
570 | $ipv6 .= dechex(bindec($bin_part)) . ':'; |
577 | $bits++; |
571 | $bits++; |
578 | } |
572 | } |
579 | return inet_ntop(inet_pton(substr($ipv6, 0, -1))); |
573 | return inet_ntop(inet_pton(substr($ipv6, 0, -1))); |
580 | } |
574 | } |
581 | } |
575 | } |
582 | 576 | ||
583 | # --- TEST |
577 | # --- TEST |
584 | 578 | ||
585 | /* |
579 | /* |
586 | assert(ipv4_normalize('100.010.001.000') == '100.10.1.0'); |
580 | assert(ipv4_normalize('100.010.001.000') == '100.10.1.0'); |
587 | assert(ipv4_normalize('100.010.01.000') == '100.10.1.0'); |
581 | assert(ipv4_normalize('100.010.01.000') == '100.10.1.0'); |
588 | assert(ipv4_normalize('100.10.001.000') == '100.10.1.0'); |
582 | assert(ipv4_normalize('100.10.001.000') == '100.10.1.0'); |
589 | assert(ipv4_normalize('1.010.001.000') == '1.10.1.0'); |
583 | assert(ipv4_normalize('1.010.001.000') == '1.10.1.0'); |
590 | assert(ipv4_normalize('1.10.001.000') == '1.10.1.0'); |
584 | assert(ipv4_normalize('1.10.001.000') == '1.10.1.0'); |
591 | 585 | ||
592 | assert(ipv4_distance('192.168.0.0/16', '192.168.64.0/18') == -2); |
586 | assert(ipv4_distance('192.168.0.0/16', '192.168.64.0/18') == -2); |
593 | assert(ipv4_distance('192.168.0.0/17', '192.168.64.0/18') == -1); |
587 | assert(ipv4_distance('192.168.0.0/17', '192.168.64.0/18') == -1); |
594 | assert(ipv4_distance('192.168.64.0/18', '192.168.64.0/18') == 0); |
588 | assert(ipv4_distance('192.168.64.0/18', '192.168.64.0/18') == 0); |
595 | assert(ipv4_distance('192.168.64.0/19', '192.168.64.0/18') == 1); |
589 | assert(ipv4_distance('192.168.64.0/19', '192.168.64.0/18') == 1); |
596 | assert(ipv4_distance('192.168.64.0/20', '192.168.64.0/18') == 2); |
590 | assert(ipv4_distance('192.168.64.0/20', '192.168.64.0/18') == 2); |
597 | 591 | ||
598 | assert(ipv4_distance('192.168.69.202/31', '192.168.69.200/31') === false); |
592 | assert(ipv4_distance('192.168.69.202/31', '192.168.69.200/31') === false); |
599 | assert(ipv4_distance('192.168.69.201/32', '192.168.69.200/32') === false); |
593 | assert(ipv4_distance('192.168.69.201/32', '192.168.69.200/32') === false); |
600 | assert(ipv4_distance('192.168.69.201', '192.168.69.200') === false); |
594 | assert(ipv4_distance('192.168.69.201', '192.168.69.200') === false); |
601 | */ |
595 | */ |
602 | 596 | ||
603 | /* |
597 | /* |
604 | $test = '192.168.69.123'; |
598 | $test = '192.168.69.123'; |
605 | $x = ipv4_trackdown($test); |
599 | $x = ipv4_trackdown($test); |
606 | foreach ($x as &$cidr) { |
600 | foreach ($x as &$cidr) { |
607 | $min = ipv4_cidr_min_ip($cidr); |
601 | $min = ipv4_cidr_min_ip($cidr); |
608 | $max = ipv4_cidr_max_ip($cidr); |
602 | $max = ipv4_cidr_max_ip($cidr); |
609 | echo "$cidr ($min - $max)\n"; |
603 | echo "$cidr ($min - $max)\n"; |
610 | } |
604 | } |
611 | */ |
605 | */ |
612 | 606 | ||
613 | 607 | ||
614 | 608 | ||
615 | 609 | ||
616 | function ipv4_sort($ary) { |
610 | function ipv4_sort($ary) { |
617 | $f = array(); |
611 | $f = array(); |
618 | foreach ($ary as $c) { |
612 | foreach ($ary as $c) { |
619 | $a = explode('/', $c); |
613 | $a = explode('/', $c); |
620 | $ip = $a[0]; |
614 | $ip = $a[0]; |
621 | $bits = isset($a[1]) ? $a[1] : 32; |
615 | $bits = isset($a[1]) ? $a[1] : 32; |
622 | 616 | ||
623 | $d = ip2bin($ip); |
617 | $d = ip2bin($ip); |
624 | 618 | ||
625 | # ord('*') must be smaller than ord('0') |
619 | # ord('*') must be smaller than ord('0') |
626 | $d = substr($d, 0, $bits).str_repeat('*', 32-$bits); |
620 | $d = substr($d, 0, $bits).str_repeat('*', 32-$bits); |
627 | 621 | ||
628 | $f[$d] = $c; |
622 | $f[$d] = $c; |
629 | } |
623 | } |
630 | 624 | ||
631 | return $f; |
625 | return $f; |
632 | } |
626 | } |
633 | 627 | ||
634 | function ipv4_make_tree($ary) { |
628 | function ipv4_make_tree($ary) { |
635 | $ary = ipv4_sort($ary); |
629 | $ary = ipv4_sort($ary); |
636 | 630 | ||
637 | if (count($ary) == 0) return array(); |
631 | if (count($ary) == 0) return array(); |
638 | 632 | ||
639 | $sub_begin = ''; |
633 | $sub_begin = ''; |
640 | $sub_begin_ip = ''; |
634 | $sub_begin_ip = ''; |
641 | foreach ($ary as $n => $d) { |
635 | foreach ($ary as $n => $d) { |
642 | $sub_begin = substr($n, 0, strpos($n, '*')); |
636 | $sub_begin = substr($n, 0, strpos($n, '*')); |
643 | $sub_begin_ip = $d; |
637 | $sub_begin_ip = $d; |
644 | unset($ary[$n]); |
638 | unset($ary[$n]); |
645 | break; |
639 | break; |
646 | } |
640 | } |
647 | 641 | ||
648 | $sub = array(); |
642 | $sub = array(); |
649 | $nonsub = array(); |
643 | $nonsub = array(); |
650 | foreach ($ary as $n => $d) { |
644 | foreach ($ary as $n => $d) { |
651 | if (substr($n, 0, strlen($sub_begin)) == $sub_begin) { |
645 | if (substr($n, 0, strlen($sub_begin)) == $sub_begin) { |
652 | $sub[$n] = $d; |
646 | $sub[$n] = $d; |
653 | } else { |
647 | } else { |
654 | $nonsub[$n] = $d; |
648 | $nonsub[$n] = $d; |
655 | } |
649 | } |
656 | } |
650 | } |
657 | 651 | ||
658 | $out = array(); |
652 | $out = array(); |
659 | $out[$sub_begin_ip] = ipv4_make_tree($sub); |
653 | $out[$sub_begin_ip] = ipv4_make_tree($sub); |
660 | 654 | ||
661 | $a = ipv4_make_tree($nonsub); |
655 | $a = ipv4_make_tree($nonsub); |
662 | 656 | ||
663 | $out = array_merge($out, $a); |
657 | $out = array_merge($out, $a); |
664 | 658 | ||
665 | return $out; |
659 | return $out; |
666 | } |
660 | } |
667 | 661 | ||
668 | 662 |