Rev 18 | Rev 20 | Go to most recent revision | Show entire file | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 18 | Rev 19 | ||
---|---|---|---|
Line 24... | Line 24... | ||
24 | // - https://en.m.wikipedia.org/wiki/Organizationally_unique_identifier |
24 | // - https://en.m.wikipedia.org/wiki/Organizationally_unique_identifier |
25 | 25 | ||
26 | const IEEE_MAC_REGISTRY = __DIR__ . '/../web-data'; |
26 | const IEEE_MAC_REGISTRY = __DIR__ . '/../web-data'; |
27 | 27 | ||
28 | /** |
28 | /** |
29 | * Checks if a MAC, EUI, ELI, or IPv6-LinkLocal address is valid |
29 | * Checks if a MAC, EUI, ELI, or IPv6-Link-Local address is valid |
30 | * @param string $mac MAC, EUI, or IPv6-LinkLocal Address |
30 | * @param string $mac MAC, EUI, or IPv6-Link-Local Address |
31 | * @return bool True if it is valid |
31 | * @return bool True if it is valid |
32 | */ |
32 | */ |
33 | function mac_valid(string $mac): bool { |
33 | function mac_valid(string $mac): bool { |
34 | $tmp = ipv6linklocal_to_mac48($mac); |
34 | $tmp = ipv6linklocal_to_mac48($mac); |
35 | if ($tmp !== false) $mac = $tmp; |
35 | if ($tmp !== false) $mac = $tmp; |
Line 54... | Line 54... | ||
54 | $mac = mac_canonize($mac, ''); |
54 | $mac = mac_canonize($mac, ''); |
55 | return (int)(strlen($mac)*4); |
55 | return (int)(strlen($mac)*4); |
56 | } |
56 | } |
57 | 57 | ||
58 | /** |
58 | /** |
59 | * Canonizes a MAC, EUI, ELI, or IPv6-LinkLocal address |
59 | * Canonizes a MAC, EUI, ELI, or IPv6-Link-Local address |
60 | * @param string $mac MAC, EUI, ELI, or IPv6-LinkLocal Address |
60 | * @param string $mac MAC, EUI, ELI, or IPv6-Link-Local Address |
61 | * @param string $delimiter Desired delimiter for inserting between each octet |
61 | * @param string $delimiter Desired delimiter for inserting between each octet |
62 | * @return string|false The canonized address (Note: IPv6-Linklocal becomes EUI-64) |
62 | * @return string|false The canonized address (Note: IPv6-Link-Local becomes EUI-64) |
63 | */ |
63 | */ |
64 | function mac_canonize(string $mac, string $delimiter="-") { |
64 | function mac_canonize(string $mac, string $delimiter="-") { |
65 | if (!mac_valid($mac)) return false; |
65 | if (!mac_valid($mac)) return false; |
66 | 66 | ||
67 | $tmp = ipv6linklocal_to_mac48($mac); |
67 | $tmp = ipv6linklocal_to_mac48($mac); |
Line 210... | Line 210... | ||
210 | 210 | ||
211 | return mac_canonize($eui64); |
211 | return mac_canonize($eui64); |
212 | } |
212 | } |
213 | 213 | ||
214 | /** |
214 | /** |
215 | * Try to convert IPv6-LinkLocal address to MAC-48 |
215 | * Try to convert IPv6-Link-Local address to MAC-48 |
216 | * @param string $ipv6 IPv6-LinkLocal address |
216 | * @param string $ipv6 IPv6-Link-Local address |
217 | * @return false|string MAC-48 (or IPv6 if it was no LinkLocal address, or Modified EUI-64 if it decapsulation failed) |
217 | * @return false|string MAC-48 (or IPv6 if it was no LinkLocal address, or Modified EUI-64 if it decapsulation failed) |
218 | */ |
218 | */ |
219 | function ipv6linklocal_to_mac48(string $ipv6) { |
219 | function ipv6linklocal_to_mac48(string $ipv6) { |
220 | // https://stackoverflow.com/questions/12095835/quick-way-of-expanding-ipv6-addresses-with-php (modified) |
220 | // https://stackoverflow.com/questions/12095835/quick-way-of-expanding-ipv6-addresses-with-php (modified) |
221 | $tmp = inet_pton($ipv6); |
221 | $tmp = inet_pton($ipv6); |
222 | if ($tmp === false) return false; |
222 | if ($tmp === false) return false; |
223 | $hex = unpack("H*hex", $tmp); |
223 | $hex = unpack("H*hex", $tmp); |
224 | $ipv6 = substr(preg_replace("/([A-f0-9]{4})/", "$1:", $hex['hex']), 0, -1); |
224 | $ipv6 = substr(preg_replace("/([A-f0-9]{4})/", "$1:", $hex['hex']), 0, -1); |
225 | 225 | ||
226 | // Remove "fe80::" to convert IPv6 Link Local address back to EUI-64 |
226 | // Remove "fe80::" to convert IPv6-Link-Local address back to EUI-64 |
227 | // see https://support.lenovo.com/de/de/solutions/ht509925-how-to-convert-a-mac-address-into-an-ipv6-link-local-address-eui-64 |
227 | // see https://support.lenovo.com/de/de/solutions/ht509925-how-to-convert-a-mac-address-into-an-ipv6-link-local-address-eui-64 |
228 | $cnt = 0; |
228 | $cnt = 0; |
229 | $mac = preg_replace('@^fe80:0000:0000:0000:@i', '', $ipv6, -1, $cnt); |
229 | $mac = preg_replace('@^fe80:0000:0000:0000:@i', '', $ipv6, -1, $cnt); |
230 | if ($cnt == 0) return false; |
230 | if ($cnt == 0) return false; |
231 | 231 | ||
Line 240... | Line 240... | ||
240 | return $mac; // Failed decapsulation; output Modified EUI-64 instead |
240 | return $mac; // Failed decapsulation; output Modified EUI-64 instead |
241 | } |
241 | } |
242 | } |
242 | } |
243 | 243 | ||
244 | /** |
244 | /** |
245 | * Converts MAC-48 or EUI-48 to IPv6-LinkLocal (based on Modified EUI-64) |
245 | * Converts MAC-48 or EUI-48 to IPv6-Link-Local (based on Modified EUI-64) |
246 | * @param string $mac |
246 | * @param string $mac |
247 | * @return false|string |
247 | * @return false|string |
248 | */ |
248 | */ |
249 | function maceui_to_ipv6linklocal(string $mac) { |
249 | function maceui_to_ipv6linklocal(string $mac) { |
250 | if (!mac_valid($mac)) return false; |
250 | if (!mac_valid($mac)) return false; |
Line 255... | Line 255... | ||
255 | $mac = str_pad($mac, 16, '0', STR_PAD_LEFT); |
255 | $mac = str_pad($mac, 16, '0', STR_PAD_LEFT); |
256 | return strtolower('fe80::'.substr($mac,0, 4).':'.substr($mac,4, 4).':'.substr($mac,8, 4).':'.substr($mac,12, 4)); |
256 | return strtolower('fe80::'.substr($mac,0, 4).':'.substr($mac,4, 4).':'.substr($mac,8, 4).':'.substr($mac,12, 4)); |
257 | } |
257 | } |
258 | 258 | ||
259 | /** |
259 | /** |
260 | * Prints information about an IPv6-LinkLocal address, MAC, EUI, or ELI. |
260 | * Prints information about an IPv6-Link-Local address, MAC, EUI, or ELI. |
261 | * @param string $mac IPv6-LinkLocal address, MAC, EUI, or ELI |
261 | * @param string $mac IPv6-Link-Local address, MAC, EUI, or ELI |
262 | * @return void |
262 | * @return void |
263 | * @throws Exception |
263 | * @throws Exception |
264 | */ |
264 | */ |
265 | function decode_mac(string $mac) { |
265 | function decode_mac(string $mac) { |
266 | echo sprintf("%-32s %s\n", "Input:", $mac); |
266 | echo sprintf("%-32s %s\n", "Input:", $mac); |
Line 307... | Line 307... | ||
307 | 307 | ||
308 | // Show various representations |
308 | // Show various representations |
309 | if ($mac[1] == 'A') { |
309 | if ($mac[1] == 'A') { |
310 | // Note: There does not seem to exist an algorithm for converting ELI-48 <=> ELI-64 |
310 | // Note: There does not seem to exist an algorithm for converting ELI-48 <=> ELI-64 |
311 | echo sprintf("%-32s %s\n", "ELI-".eui_bits($mac).":", mac_canonize($mac)); |
311 | echo sprintf("%-32s %s\n", "ELI-".eui_bits($mac).":", mac_canonize($mac)); |
- | 312 | $mac48 = eui64_to_eui48($mac); |
|
- | 313 | echo sprintf("%-32s %s\n", "MAC-48 (Local):", (eui_bits($mac48) != 48) ? 'Not available' : $mac48); |
|
312 | } else { |
314 | } else { |
313 | $eui48 = eui64_to_eui48($mac); |
315 | $eui48 = eui64_to_eui48($mac); |
314 | echo sprintf("%-32s %s\n", "EUI-48:", (eui_bits($eui48) != 48) ? 'Not available' : $eui48); |
316 | echo sprintf("%-32s %s\n", "EUI-48 or MAC-48:", (eui_bits($eui48) != 48) ? 'Not available' : $eui48); |
315 | if (eui_bits($mac) == 48) { |
317 | if (eui_bits($mac) == 48) { |
316 | $eui64 = mac48_to_eui64($mac); |
318 | $eui64 = mac48_to_eui64($mac); |
317 | echo sprintf("%-32s %s\n", "EUI-64:", ((eui_bits($eui64) != 64) ? 'Not available' : $eui64).' (MAC-48 to EUI-64 Encapsulation)'); |
319 | echo sprintf("%-32s %s\n", "EUI-64:", ((eui_bits($eui64) != 64) ? 'Not available' : $eui64).' (MAC-48 to EUI-64 Encapsulation)'); |
318 | $eui64 = eui48_to_eui64($mac); |
320 | $eui64 = eui48_to_eui64($mac); |
319 | echo sprintf("%-32s %s\n", "", ((eui_bits($eui64) != 64) ? 'Not available' : $eui64).' (EUI-48 to EUI-64 Encapsulation)'); |
321 | echo sprintf("%-32s %s\n", "", ((eui_bits($eui64) != 64) ? 'Not available' : $eui64).' (EUI-48 to EUI-64 Encapsulation)'); |
320 | $eui64 = maceui48_to_modeui64($mac); |
322 | $eui64 = maceui48_to_modeui64($mac); |
321 | echo sprintf("%-32s %s\n", "", ((eui_bits($eui64) != 64) ? 'Not available' : $eui64).' (MAC/EUI-48 to Modified EUI-64 Encapsulation)'); |
323 | echo sprintf("%-32s %s\n", "", ((eui_bits($eui64) != 64) ? 'Not available' : $eui64).' (MAC/EUI-48 to Modified EUI-64 Encapsulation)'); |
322 | $ipv6 = maceui_to_ipv6linklocal($mac); |
324 | $ipv6 = maceui_to_ipv6linklocal($mac); |
323 | echo sprintf("%-32s %s\n", "IPv6 link local address:", $ipv6); |
325 | echo sprintf("%-32s %s\n", "IPv6-Link-Local address:", $ipv6); |
324 | } else { |
326 | } else { |
325 | $eui64 = mac_canonize($mac); |
327 | $eui64 = mac_canonize($mac); |
326 | echo sprintf("%-32s %s\n", "EUI-64:", $eui64); |
328 | echo sprintf("%-32s %s\n", "EUI-64:", $eui64); |
327 | } |
329 | } |
328 | } |
330 | } |
Line 476... | Line 478... | ||
476 | // https://tools.ietf.org/html/rfc7042#section-2.3.2 |
478 | // https://tools.ietf.org/html/rfc7042#section-2.3.2 |
477 | if (mac_between($mac, 'CF:00:00:00:00:00', 'CF:00:00:FF:FF:FF')) $app = 'Reserved'; |
479 | if (mac_between($mac, 'CF:00:00:00:00:00', 'CF:00:00:FF:FF:FF')) $app = 'Reserved'; |
478 | if (mac_equals($mac, 'CF:00:00:00:00:00')) $app = 'Used for Ethernet loopback tests'; |
480 | if (mac_equals($mac, 'CF:00:00:00:00:00')) $app = 'Used for Ethernet loopback tests'; |
479 | 481 | ||
480 | // === FAQ "How to recognise a Broadcast MAC address application?" === |
482 | // === FAQ "How to recognise a Broadcast MAC address application?" === |
- | 483 | // According to https://standards.ieee.org/wp-content/uploads/import/documents/tutorials/eui.pdf FFFFFFFFFFFF can be used as NULL EUI |
|
481 | if (mac_equals($mac, 'FF:FF:FF:FF:FF:FF')) echo sprintf("%-32s %s\n", "Special use:", "Broadcast messaging"); |
484 | if (mac_equals($mac, 'FF:FF:FF:FF:FF:FF')) echo sprintf("%-32s %s\n", "Special use:", "Broadcast messaging or Null-EUI"); |
482 | 485 | ||
483 | // === FAQ "How to recognise a Virtual Router ID by MAC address?" === |
486 | // === FAQ "How to recognise a Virtual Router ID by MAC address?" === |
484 | // https://tools.ietf.org/html/rfc7042#section-5.1 |
487 | // https://tools.ietf.org/html/rfc7042#section-5.1 |
485 | // https://tools.ietf.org/html/rfc5798 |
488 | // https://tools.ietf.org/html/rfc5798 |
486 | if (mac_between($mac, '00:00:5E:00:01:00', '00:00:5E:00:01:FF')) $app = 'IPv4 Virtual Router Redundancy Protocol (VRRP)'; |
489 | if (mac_between($mac, '00:00:5E:00:01:00', '00:00:5E:00:01:FF')) $app = 'IPv4 Virtual Router Redundancy Protocol (VRRP)'; |