Rev 23 | Rev 41 | Go to most recent revision | Show entire file | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 23 | Rev 25 | ||
---|---|---|---|
Line 1... | Line 1... | ||
1 | <?php |
1 | <?php |
2 | 2 | ||
3 | /* |
3 | /* |
4 | * MAC (EUI-48 and EUI-64) utils for PHP |
4 | * MAC (EUI-48 and EUI-64) utils for PHP |
5 | * Copyright 2017 - 2023 Daniel Marschall, ViaThinkSoft |
5 | * Copyright 2017 - 2023 Daniel Marschall, ViaThinkSoft |
6 | * Version 2023-05-06 |
6 | * Version 2023-07-11 |
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 | * |
Line 74... | Line 74... | ||
74 | return preg_replace('@^(..)(..)(..)(..)(..)(..)$@', '\\1'.$delimiter.'\\2'.$delimiter.'\\3'.$delimiter.'\\4'.$delimiter.'\\5'.$delimiter.'\\6', $mac); |
74 | return preg_replace('@^(..)(..)(..)(..)(..)(..)$@', '\\1'.$delimiter.'\\2'.$delimiter.'\\3'.$delimiter.'\\4'.$delimiter.'\\5'.$delimiter.'\\6', $mac); |
75 | } |
75 | } |
76 | 76 | ||
77 | /** |
77 | /** |
78 | * @param string $file |
78 | * @param string $file |
79 | * @param string $oui_name |
79 | * @param string $registry_name |
80 | * @param string $mac |
80 | * @param string $mac |
81 | * @return false|string |
81 | * @return false|string |
82 | */ |
82 | */ |
83 | function _lookup_ieee_registry(string $file, string $oui_name, string $mac) { |
83 | function _lookup_ieee_registry(string $file, string $registry_name, string $mac) { |
84 | $mac = mac_canonize($mac, ''); |
84 | $mac = mac_canonize($mac, ''); |
85 | if ($mac === false) return false; |
85 | if ($mac === false) return false; |
86 | $begin = substr($mac, 0, 2).'-'.substr($mac, 2, 2).'-'.substr($mac, 4, 2); |
86 | $begin = substr($mac, 0, 2).'-'.substr($mac, 2, 2).'-'.substr($mac, 4, 2); |
87 | $f = file_get_contents($file); |
87 | $f = file_get_contents($file); |
88 | 88 | ||
Line 108... | Line 108... | ||
108 | # "PRIVATE" entries are only marked at the "(hex)" line, but not at the "(base16)" line |
108 | # "PRIVATE" entries are only marked at the "(hex)" line, but not at the "(base16)" line |
109 | if ($x == '') $x = trim($n[1]); |
109 | if ($x == '') $x = trim($n[1]); |
110 | 110 | ||
111 | $x = explode("\n", $x); |
111 | $x = explode("\n", $x); |
112 | 112 | ||
- | 113 | // The 12 is hardcoded and is valid for MAC-48 and MAC-64! |
|
- | 114 | // Reason: The length of the prefix is calculated from MAC-48. MAC-64 just extends the vendor-specific part |
|
- | 115 | // end-beg (= range) OUI24 0xFFFFFF len=6 12-6 = 6 nibbles prefix |
|
- | 116 | // OUI28 0xFFFFF len=5 12-5 = 7 nibbles prefix |
|
- | 117 | // OUI36 0xFFF len=3 12-3 = 9 nibbles prefix |
|
113 | $ra_len = strlen(dechex($end-$beg)); |
118 | $prefix_len = 12-strlen(dechex($end-$beg)); |
114 | 119 | ||
115 | $out = sprintf("%-32s 0x%s\n", "IEEE $oui_name:", substr($mac, 0, 12-$ra_len)); |
120 | $out = sprintf("%-32s 0x%s\n", "IEEE $registry_name:", substr($mac, 0, $prefix_len)); |
116 | $out .= sprintf("%-32s 0x%s\n", "Vendor-specific part:", substr($mac, 12-$ra_len)); |
121 | $out .= sprintf("%-32s 0x%s\n", "Vendor-specific part:", substr($mac, $prefix_len)); |
117 | $out .= sprintf("%-32s %s\n", "Registrant:", $x[0]); |
122 | $out .= sprintf("%-32s %s\n", "Registrant:", $x[0]); |
- | 123 | ||
118 | foreach ($x as $n => $y) { |
124 | foreach ($x as $n => $y) { |
119 | if ($n == 0) continue; |
125 | if ($n == 0) continue; |
120 | else if ($n == 1) $out .= sprintf("%-32s %s\n", "Address of registrant:", $y); |
126 | else if ($n == 1) $out .= sprintf("%-32s %s\n", "Address of registrant:", $y); |
121 | else if ($n >= 2) $out .= sprintf("%-32s %s\n", "", $y); |
127 | else if ($n >= 2) $out .= sprintf("%-32s %s\n", "", $y); |
122 | } |
128 | } |
Line 261... | Line 267... | ||
261 | */ |
267 | */ |
262 | function mac_type(string $mac): string { |
268 | function mac_type(string $mac): string { |
263 | // Format MAC for machine readability |
269 | // Format MAC for machine readability |
264 | $mac = mac_canonize($mac, ''); |
270 | $mac = mac_canonize($mac, ''); |
265 | 271 | ||
266 | /** |
272 | /* |
267 | * |
273 | * |
268 | * ZYXM |
274 | * ZYXM |
269 | * 0 0000 EUI (OUI) |
275 | * 0 0000 EUI (OUI) |
270 | * 1 0001 [Multicast] |
276 | * 1 0001 [Multicast] |
271 | * 2 0010 AAI |
277 | * 2 0010 AAI |
Line 363... | Line 369... | ||
363 | } |
369 | } |
364 | } |
370 | } |
365 | } |
371 | } |
366 | 372 | ||
367 | if ((hexdec($mac[1])&1) == 1) { |
373 | if ((hexdec($mac[1])&1) == 1) { |
368 | // Question: https://networkengineering.stackexchange.com/questions/83121/can-eli-aai-sai-addresses-be-multicast |
374 | // see also https://networkengineering.stackexchange.com/questions/83121/can-eli-aai-sai-addresses-be-multicast |
369 | // Are there "Multicast ELI", "Multicast AAI", "Multicast SAI"? |
- | |
370 | // Some documents of IEEE suggest this, but I am not 100% sure! |
- | |
371 | 375 | ||
372 | /* https://standards.ieee.org/wp-content/uploads/import/documents/tutorials/eui.pdf writes: |
376 | /* https://standards.ieee.org/wp-content/uploads/import/documents/tutorials/eui.pdf writes: |
373 | * - The assignee of an OUI or OUI-36 is exclusively authorized to assign group |
377 | * - The assignee of an OUI or OUI-36 is exclusively authorized to assign group |
374 | * MAC addresses, with I/G=1, by extending a modified version of the assigned |
378 | * MAC addresses, with I/G=1, by extending a modified version of the assigned |
375 | * OUI or OUI-36 in which the M bit is set to 1. Such addresses are not EUIs and |
379 | * OUI or OUI-36 in which the M bit is set to 1. Such addresses are not EUIs and |
Line 377... | Line 381... | ||
377 | * - The assignee of a CID may assign local group MAC addresses by extending a modified version of |
381 | * - The assignee of a CID may assign local group MAC addresses by extending a modified version of |
378 | * the assigned CID by setting the M bit to 1 (so that I/G=1). The resulting |
382 | * the assigned CID by setting the M bit to 1 (so that I/G=1). The resulting |
379 | * extended identifier is an ELI. |
383 | * extended identifier is an ELI. |
380 | */ |
384 | */ |
381 | 385 | ||
382 | // TODO: If "Multicast EUI" is not an EUI, how should we name it instead?! |
386 | // TODO: If "Multicast EUI" is not an EUI (as tutorials/eui.pdf states), how should we name it instead?! |
383 | $type = "Multicast $type"; |
387 | $type = "Multicast $type"; |
384 | } |
388 | } |
385 | 389 | ||
386 | return $type; |
390 | return $type; |
387 | } |
391 | } |
Line 404... | Line 408... | ||
404 | $type = mac_type($mac); |
408 | $type = mac_type($mac); |
405 | echo sprintf("%-32s %s\n", "Type:", $type); |
409 | echo sprintf("%-32s %s\n", "Type:", $type); |
406 | 410 | ||
407 | echo "\n"; |
411 | echo "\n"; |
408 | 412 | ||
- | 413 | $is_eli_unicast = (hexdec($mac[1]) & 0xF) == 0xA; // ELI = 1010 (unicast) |
|
- | 414 | $is_eli = (hexdec($mac[1]) & 0xE) == 0xA; // ELI = 101x (unicast and multicast) |
|
- | 415 | ||
- | 416 | $is_eui_unicast = (hexdec($mac[1]) & 0x3) == 0x0; // EUI = xx00 (unicast) |
|
- | 417 | $is_eui = (hexdec($mac[1]) & 0x2) == 0x0; // EUI = xx0x (unicast and multicast) |
|
- | 418 | ||
409 | // Show various representations |
419 | // Show various representations |
410 | if ($mac[1] == 'A') { |
420 | if ($is_eli) { |
411 | // Note: There does not seem to exist an algorithm for encapsulating/converting ELI-48 <=> ELI-64 |
421 | // Note: There does not seem to exist an algorithm for encapsulating/converting ELI-48 <=> ELI-64 |
412 | echo sprintf("%-32s %s\n", "ELI-".eui_bits($mac).":", mac_canonize($mac)); |
422 | echo sprintf("%-32s %s\n", "ELI-".eui_bits($mac).":", mac_canonize($mac)); |
413 | $mac48 = eui64_to_eui48($mac); |
423 | $mac48 = eui64_to_eui48($mac); |
414 | echo sprintf("%-32s %s\n", "MAC-48 (Local):", (eui_bits($mac48) != 48) ? 'Not available' : $mac48); |
424 | echo sprintf("%-32s %s\n", "MAC-48 (Local):", (eui_bits($mac48) != 48) ? 'Not available' : $mac48); |
415 | } else if (($mac[1] == '0') || ($mac[1] == '4') || ($mac[1] == '8') || ($mac[1] == 'C')) { |
425 | } else if ($is_eui) { |
416 | $eui48 = eui64_to_eui48($mac); |
426 | $eui48 = eui64_to_eui48($mac); |
417 | echo sprintf("%-32s %s\n", "EUI-48 or MAC-48:", (eui_bits($eui48) != 48) ? 'Not available' : $eui48); |
427 | echo sprintf("%-32s %s\n", "EUI-48 or MAC-48:", (eui_bits($eui48) != 48) ? 'Not available' : $eui48); |
418 | if (eui_bits($mac) == 48) { |
428 | if (eui_bits($mac) == 48) { |
419 | $eui64 = mac48_to_eui64($mac); |
429 | $eui64 = mac48_to_eui64($mac); |
420 | echo sprintf("%-32s %s\n", "EUI-64:", ((eui_bits($eui64) != 64) ? 'Not available' : $eui64).' (MAC-48 to EUI-64 Encapsulation)'); |
430 | echo sprintf("%-32s %s\n", "EUI-64:", ((eui_bits($eui64) != 64) ? 'Not available' : $eui64).' (MAC-48 to EUI-64 Encapsulation)'); |
Line 441... | Line 451... | ||
441 | echo sprintf("%-32s %s\n", "Transmission type (I/G flag):", $ig_); |
451 | echo sprintf("%-32s %s\n", "Transmission type (I/G flag):", $ig_); |
442 | 452 | ||
443 | // Query IEEE registries |
453 | // Query IEEE registries |
444 | if (count(glob(IEEE_MAC_REGISTRY.DIRECTORY_SEPARATOR.'*.txt')) > 0) { |
454 | if (count(glob(IEEE_MAC_REGISTRY.DIRECTORY_SEPARATOR.'*.txt')) > 0) { |
445 | $alt_mac = $mac; |
455 | $alt_mac = $mac; |
446 | $alt_mac[1] = dechex(hexdec($alt_mac[1])^1); // switch Unicat<=>Multicast in order to find the vendor |
456 | $alt_mac[1] = dechex(hexdec($alt_mac[1])^1); // switch Unicast<=>Multicast in order to find the vendor |
447 | 457 | ||
- | 458 | if (is_dir(IEEE_MAC_REGISTRY)) { |
|
448 | if ($mac[1] == 'A') { |
459 | if ($is_eli) { |
449 | // Query the CID registry |
460 | // Query the CID registry |
450 | if ( |
461 | if ( |
451 | ($x = _lookup_ieee_registry(IEEE_MAC_REGISTRY . DIRECTORY_SEPARATOR . 'cid.txt', 'CID', $mac)) || |
462 | ($x = _lookup_ieee_registry(IEEE_MAC_REGISTRY . DIRECTORY_SEPARATOR . 'cid.txt', 'CID', $mac)) || |
452 | ($x = _lookup_ieee_registry(IEEE_MAC_REGISTRY . DIRECTORY_SEPARATOR . 'cid.txt', 'CID', $alt_mac)) |
463 | ($x = _lookup_ieee_registry(IEEE_MAC_REGISTRY . DIRECTORY_SEPARATOR . 'cid.txt', 'CID', $alt_mac)) |
453 | ) { |
464 | ) { |
- | 465 | echo "\n"; |
|
454 | echo $x; |
466 | echo $x; |
455 | } |
- | |
456 | } else { |
467 | } else { |
- | 468 | $registry_name = 'CID'; |
|
- | 469 | echo "\n"; |
|
- | 470 | echo sprintf("%-32s 0x%s\n", "IEEE $registry_name:", substr($mac, 0, 6)); |
|
- | 471 | echo sprintf("%-32s 0x%s\n", "Vendor-specific part:", substr($mac, 6)); |
|
- | 472 | echo sprintf("%-32s %s\n", "Registrant:", "$registry_name not found in database"); |
|
- | 473 | } |
|
- | 474 | } else if ($is_eui) { |
|
457 | // Query the OUI registries |
475 | // Query the OUI registries |
458 | if ( |
476 | if ( |
459 | # The IEEE Registration Authority distinguishes between IABs and OUI-36 values. Both are 36-bit values which may be used to generate EUI-48 values, but IABs may not be used to generate EUI-64 values.[6] |
477 | # The IEEE Registration Authority distinguishes between IABs and OUI-36 values. Both are 36-bit values which may be used to generate EUI-48 values, but IABs may not be used to generate EUI-64 values.[6] |
460 | # Note: The Individual Address Block (IAB) is an inactive registry activity, which has been replaced by the MA-S registry product as of January 1, 2014. |
478 | # Note: The Individual Address Block (IAB) is an inactive registry activity, which has been replaced by the MA-S registry product as of January 1, 2014. |
461 | ($x = _lookup_ieee_registry(IEEE_MAC_REGISTRY . DIRECTORY_SEPARATOR . 'iab.txt', 'IAB', $mac)) || |
479 | ($x = _lookup_ieee_registry(IEEE_MAC_REGISTRY . DIRECTORY_SEPARATOR . 'iab.txt', 'IAB', $mac)) || |
Line 465... | Line 483... | ||
465 | ($x = _lookup_ieee_registry(IEEE_MAC_REGISTRY . DIRECTORY_SEPARATOR . 'iab.txt', 'IAB', $alt_mac)) || |
483 | ($x = _lookup_ieee_registry(IEEE_MAC_REGISTRY . DIRECTORY_SEPARATOR . 'iab.txt', 'IAB', $alt_mac)) || |
466 | ($x = _lookup_ieee_registry(IEEE_MAC_REGISTRY . DIRECTORY_SEPARATOR . 'oui36.txt', 'OUI-36 (MA-S)', $alt_mac)) || |
484 | ($x = _lookup_ieee_registry(IEEE_MAC_REGISTRY . DIRECTORY_SEPARATOR . 'oui36.txt', 'OUI-36 (MA-S)', $alt_mac)) || |
467 | ($x = _lookup_ieee_registry(IEEE_MAC_REGISTRY . DIRECTORY_SEPARATOR . 'mam.txt', '28 bit identifier (MA-M)', $alt_mac)) || |
485 | ($x = _lookup_ieee_registry(IEEE_MAC_REGISTRY . DIRECTORY_SEPARATOR . 'mam.txt', '28 bit identifier (MA-M)', $alt_mac)) || |
468 | ($x = _lookup_ieee_registry(IEEE_MAC_REGISTRY . DIRECTORY_SEPARATOR . 'oui.txt', 'OUI (MA-L)', $alt_mac)) |
486 | ($x = _lookup_ieee_registry(IEEE_MAC_REGISTRY . DIRECTORY_SEPARATOR . 'oui.txt', 'OUI (MA-L)', $alt_mac)) |
469 | ) { |
487 | ) { |
- | 488 | echo "\n"; |
|
470 | echo $x; |
489 | echo $x; |
- | 490 | } else { |
|
- | 491 | $registry_name = 'OUI (MA-L)?'; |
|
- | 492 | echo "\n"; |
|
- | 493 | echo sprintf("%-32s 0x%s\n", "IEEE $registry_name:", substr($mac, 0, 6)); |
|
- | 494 | echo sprintf("%-32s 0x%s\n", "Vendor-specific part:", substr($mac, 6)); |
|
- | 495 | echo sprintf("%-32s %s\n", "Registrant:", "$registry_name not found in database"); |
|
- | 496 | ||
- | 497 | $registry_name = '28 bit identifier (MA-M)?'; |
|
- | 498 | echo "\n"; |
|
- | 499 | echo sprintf("%-32s 0x%s\n", "IEEE $registry_name:", substr($mac, 0, 7)); |
|
- | 500 | echo sprintf("%-32s 0x%s\n", "Vendor-specific part:", substr($mac, 7)); |
|
- | 501 | echo sprintf("%-32s %s\n", "Registrant:", "$registry_name not found in database"); |
|
- | 502 | ||
- | 503 | $registry_name = 'OUI-36 (MA-S)?'; |
|
- | 504 | echo "\n"; |
|
- | 505 | echo sprintf("%-32s 0x%s\n", "IEEE $registry_name:", substr($mac, 0, 9)); |
|
- | 506 | echo sprintf("%-32s 0x%s\n", "Vendor-specific part:", substr($mac, 9)); |
|
- | 507 | echo sprintf("%-32s %s\n", "Registrant:", "$registry_name not found in database"); |
|
- | 508 | } |
|
471 | } |
509 | } |
472 | } |
510 | } |
473 | } |
511 | } |
474 | 512 | ||
475 | $vm = ''; |
513 | $vm = ''; |