Subversion Repositories uuid_mac_utils

Rev

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 = '';