Subversion Repositories uuid_mac_utils

Rev

Rev 21 | Rev 23 | Go to most recent revision | Show entire file | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 21 Rev 22
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-04
6
 * Version 2023-05-05
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 110... Line 110...
110
 
110
 
111
                $x = explode("\n", $x);
111
                $x = explode("\n", $x);
112
 
112
 
113
                $ra_len = strlen(dechex($end-$beg));
113
                $ra_len = strlen(dechex($end-$beg));
114
 
114
 
115
                $out = sprintf("%-32s 0x%s\n", "IEEE $oui_name part:", substr($mac, 0, 12-$ra_len));
115
                $out = sprintf("%-32s 0x%s\n", "IEEE $oui_name:", substr($mac, 0, 12-$ra_len));
116
                $out .= sprintf("%-32s 0x%s\n", "NIC specific part:", substr($mac, 12-$ra_len));
116
                $out .= sprintf("%-32s 0x%s\n", "Vendor-specific part:", substr($mac, 12-$ra_len));
117
                $out .= sprintf("%-32s %s\n", "Registrant:", $x[0]);
117
                $out .= sprintf("%-32s %s\n", "Registrant:", $x[0]);
118
                foreach ($x as $n => $y) {
118
                foreach ($x as $n => $y) {
119
                        if ($n == 0) continue;
119
                        if ($n == 0) continue;
120
                        else if ($n == 1) $out .= sprintf("%-32s %s\n", "Address of registrant:", $y);
120
                        else if ($n == 1) $out .= sprintf("%-32s %s\n", "Address of registrant:", $y);
121
                        else if ($n >= 2) $out .= sprintf("%-32s %s\n", "", $y);
121
                        else if ($n >= 2) $out .= sprintf("%-32s %s\n", "", $y);
Line 265... Line 265...
265
 
265
 
266
        /**
266
        /**
267
         *
267
         *
268
         *      ZYXM
268
         *      ZYXM
269
         * 0    0000    EUI (OUI)
269
         * 0    0000    EUI (OUI)
270
         * 1    0001
270
         * 1    0001    [Multicast]
271
         * 2    0010    AAI
271
         * 2    0010    AAI
272
         * 3    0011
272
         * 3    0011    [Multicast]
273
         * 4    0100    EUI (OUI)
273
         * 4    0100    EUI (OUI)
274
         * 5    0101
274
         * 5    0101    [Multicast]
275
         * 6    0110    Reserved
275
         * 6    0110    Reserved
276
         * 7    0111
276
         * 7    0111    [Multicast]
277
         * 8    1000    EUI (OUI)
277
         * 8    1000    EUI (OUI)
278
         * 9    1001
278
         * 9    1001    [Multicast]
279
         * A    1010    ELI (CID)
279
         * A    1010    ELI (CID)
280
         * B    1011
280
         * B    1011    [Multicast]
281
         * C    1100    EUI (OUI)
281
         * C    1100    EUI (OUI)
282
         * D    1101
282
         * D    1101    [Multicast]
283
         * E    1110    SAI
283
         * E    1110    SAI
284
         * F    1111
284
         * F    1111    [Multicast]
285
         *
285
         *
286
         */
286
         */
287
 
287
 
288
        $type = '';
288
        $type = '';
289
        $tmp = ipv6linklocal_to_mac48($mac);
289
        $tmp = ipv6linklocal_to_mac48($mac);
Line 291... Line 291...
291
                $mac = $tmp;
291
                $mac = $tmp;
292
                $type = 'IPv6-Link-Local';
292
                $type = 'IPv6-Link-Local';
293
        }
293
        }
294
        if (!mac_valid($mac)) throw new Exception("Invalid MAC address");
294
        if (!mac_valid($mac)) throw new Exception("Invalid MAC address");
295
        if ($tmp === false) {
295
        if ($tmp === false) {
296
                if ($mac[1] == '2') {
296
                if (($mac[1] == '2') || ($mac[1] == '3')) {
297
                        /*
297
                        /*
298
                         * AAI: Administratively Assigned Identifier
298
                         * AAI: Administratively Assigned Identifier
299
                         * Administrators who wish to assign local MAC addresses in an
299
                         * Administrators who wish to assign local MAC addresses in an
300
                         * arbitrary fashion (for example, randomly) and yet maintain
300
                         * arbitrary fashion (for example, randomly) and yet maintain
301
                         * compatibility with other assignment protocols operating under the
301
                         * compatibility with other assignment protocols operating under the
302
                         * SLAP on the same LAN may assign a local MAC address as AAI.
302
                         * SLAP on the same LAN may assign a local MAC address as AAI.
303
                         */
303
                         */
304
                        $type = 'AAI-' . eui_bits($mac).' (Administratively Assigned Identifier)';
304
                        $type = 'AAI-' . eui_bits($mac).' (Administratively Assigned Identifier)';
305
                } else if ($mac[1] == '6') {
305
                } else if (($mac[1] == '6') || ($mac[1] == '7')) {
306
                        /*
306
                        /*
307
                         * Reserved
307
                         * Reserved
308
                         * may be administratively used and assigned in accordance with the
308
                         * may be administratively used and assigned in accordance with the
309
                         * considerations specified for AAI usage, without effect on SLAP
309
                         * considerations specified for AAI usage, without effect on SLAP
310
                         * assignments. However, administrators should be cognizant of
310
                         * assignments. However, administrators should be cognizant of
311
                         * possible future specifications… that would render administrative
311
                         * possible future specifications… that would render administrative
312
                         * assignment incompatible with the SLAP.
312
                         * assignment incompatible with the SLAP.
313
                         */
313
                         */
314
                        $type = 'Reserved-' . eui_bits($mac);
314
                        $type = 'Reserved-' . eui_bits($mac);
315
                } else if ($mac[1] == 'A') {
315
                } else if (($mac[1] == 'A') || ($mac[1] == 'B')) {
316
                        /*
316
                        /*
317
                         * ELI: Extended Local Identifier
317
                         * ELI: Extended Local Identifier
318
                         * An ELI is based on a 24 bit CID
318
                         * An ELI is based on a 24 bit CID
319
                         * A CID has ZYXM bits set to 1010 (0b1010 = 0xA)
319
                         * A CID has ZYXM bits set to 1010 (0b1010 = 0xA)
320
                         * Since X=1 (U/L=1), the CID cannot be used to form a universal UAA MAC (only a local LAA MAC)
320
                         * Since X=1 (U/L=1), the CID cannot be used to form a universal UAA MAC (only a local LAA MAC)
321
                         */
321
                         */
322
                        $type = 'ELI-' . eui_bits($mac).' (Extended Local Identifier)';
322
                        $type = 'ELI-' . eui_bits($mac).' (Extended Local Identifier)';
323
                } else if ($mac[1] == 'E') {
323
                } else if (($mac[1] == 'E') || ($mac[1] == 'F')) {
324
                        /*
324
                        /*
325
                         * SAI: Standard Assigned Identifier
325
                         * SAI: Standard Assigned Identifier
326
                         * Specification of the use of the SAI quadrant for SLAP address
326
                         * Specification of the use of the SAI quadrant for SLAP address
327
                         * assignments is reserved for the standard forthcoming from IEEE
327
                         * assignments is reserved for the standard forthcoming from IEEE
328
                         * P802.1CQ.
328
                         * P802.1CQ.
Line 335... Line 335...
335
                         * and bridges that recognize the specific SAI assignment protocol, as
335
                         * and bridges that recognize the specific SAI assignment protocol, as
336
                         * identified by the subspace of the SAI. The functionality of receivers
336
                         * identified by the subspace of the SAI. The functionality of receivers
337
                         * and bridges that do not recognize the protocol is not affected.
337
                         * and bridges that do not recognize the protocol is not affected.
338
                         */
338
                         */
339
                        $type = 'SAI-' . eui_bits($mac).' (Standard Assigned Identifier)';
339
                        $type = 'SAI-' . eui_bits($mac).' (Standard Assigned Identifier)';
340
                } else if ((hexdec($mac[1])&1) == 1) {
340
                } else {
341
                        $type = 'Multicast MAC-'.eui_bits($mac);
-
 
342
                } else if (($mac[1] == '0') || ($mac[1] == '4') || ($mac[1] == '8') || ($mac[1] == 'C')) {
-
 
343
                        /*
341
                        /*
344
                         * Extended Unique Identifier
342
                         * Extended Unique Identifier
345
                         * Based on an OUI-24, OUI-28, or OUI-36
343
                         * Based on an OUI-24, OUI-28, or OUI-36
346
                         */
344
                         */
347
                        if (eui_bits($mac) == 48) {
345
                        if (eui_bits($mac) == 48) {
Line 363... Line 361...
363
                        } else {
361
                        } else {
364
                                assert(false); /** @phpstan-ignore-line */
362
                                assert(false); /** @phpstan-ignore-line */
365
                        }
363
                        }
366
                }
364
                }
367
        }
365
        }
-
 
366
 
-
 
367
        if ((hexdec($mac[1])&1) == 1) {
-
 
368
                // Question: 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
 
-
 
372
                /* 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
-
 
374
                 *   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
-
 
376
                 *   do not globally identify hardware instances, even though U/L=0.
-
 
377
                 * - 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
-
 
379
                 *   extended identifier is an ELI.
-
 
380
                 */
-
 
381
 
-
 
382
                // TODO: If "Multicast EUI" is not an EUI, how should we name it instead?!
-
 
383
                $type = "Multicast $type";
-
 
384
        }
-
 
385
 
368
        return $type;
386
        return $type;
369
}
387
}
370
 
388
 
371
/**
389
/**
372
 * Prints information about an IPv6-Link-Local address, MAC, EUI, ELI, AAI, or SAI.
390
 * Prints information about an IPv6-Link-Local address, MAC, EUI, ELI, AAI, or SAI.
Line 375... Line 393...
375
 * @throws Exception
393
 * @throws Exception
376
 */
394
 */
377
function decode_mac(string $mac) {
395
function decode_mac(string $mac) {
378
       
396
 
379
        // TODO: Should we decode Multicast MAC to its IP (see https://ipcisco.com/lesson/multicast-mac-addresses/)?
397
        // TODO: Should we decode Multicast MAC to its IP (see https://ipcisco.com/lesson/multicast-mac-addresses/)?
380
        // TODO: Is an ELI with M=1 a Multicast-ELI, or isn't it an ELI anymore? Same question for SAI and AAI
-
 
381
       
398
 
382
        echo sprintf("%-32s %s\n", "Input:", $mac);
399
        echo sprintf("%-32s %s\n", "Input:", $mac);
383
 
400
 
384
        // Format MAC for machine readability
401
        // Format MAC for machine readability
385
        $mac = mac_canonize($mac, '');
402
        $mac = mac_canonize($mac, '');
Line 423... Line 440...
423
        $ig_ = ($ig == 0) ? '[0] Unicast (Individual)' : '[1] Multicast (Group)';
440
        $ig_ = ($ig == 0) ? '[0] Unicast (Individual)' : '[1] Multicast (Group)';
424
        echo sprintf("%-32s %s\n", "Transmission type (I/G flag):", $ig_);
441
        echo sprintf("%-32s %s\n", "Transmission type (I/G flag):", $ig_);
425
 
442
 
426
        // Query IEEE registries
443
        // Query IEEE registries
427
        if (count(glob(IEEE_MAC_REGISTRY.DIRECTORY_SEPARATOR.'*.txt')) > 0) {
444
        if (count(glob(IEEE_MAC_REGISTRY.DIRECTORY_SEPARATOR.'*.txt')) > 0) {
-
 
445
                $alt_mac = $mac;
-
 
446
                $alt_mac[1] = dechex(hexdec($alt_mac[1])^1); // switch Unicat<=>Multicast in order to find the vendor
-
 
447
 
428
                if ($mac[1] == 'A') {
448
                if ($mac[1] == 'A') {
429
                        // Query the CID registry
449
                        // Query the CID registry
430
                        if (
450
                        if (
431
                                ($x = _lookup_ieee_registry(IEEE_MAC_REGISTRY . DIRECTORY_SEPARATOR . 'cid.txt', 'CID', $mac))
451
                                ($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))
432
                        ) {
453
                        ) {
433
                                echo $x;
454
                                echo $x;
434
                        }
455
                        }
435
                } else {
456
                } else {
436
                        // Query the OUI registries
457
                        // Query the OUI registries
437
                        // TODO: Should we try to convert Unicast<=>Multicast if one of them can't be found?
-
 
438
                        if (
458
                        if (
439
                                # 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]
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]
440
                                # 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.
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.
441
                                ($x = _lookup_ieee_registry(IEEE_MAC_REGISTRY . DIRECTORY_SEPARATOR . 'iab.txt', 'IAB', $mac)) ||
461
                                ($x = _lookup_ieee_registry(IEEE_MAC_REGISTRY . DIRECTORY_SEPARATOR . 'iab.txt', 'IAB', $mac)) ||
442
                                ($x = _lookup_ieee_registry(IEEE_MAC_REGISTRY . DIRECTORY_SEPARATOR . 'oui36.txt', 'OUI-36 (MA-S)', $mac)) ||
462
                                ($x = _lookup_ieee_registry(IEEE_MAC_REGISTRY . DIRECTORY_SEPARATOR . 'oui36.txt', 'OUI-36 (MA-S)', $mac)) ||
-
 
463
                                ($x = _lookup_ieee_registry(IEEE_MAC_REGISTRY . DIRECTORY_SEPARATOR . 'mam.txt', '28 bit identifier (MA-M)', $mac)) ||
443
                                ($x = _lookup_ieee_registry(IEEE_MAC_REGISTRY . DIRECTORY_SEPARATOR . 'mam.txt', 'OUI-28 (MA-M)', $mac)) ||
464
                                ($x = _lookup_ieee_registry(IEEE_MAC_REGISTRY . DIRECTORY_SEPARATOR . 'oui.txt', 'OUI (MA-L)', $mac)) ||
-
 
465
                                ($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)) ||
-
 
467
                                ($x = _lookup_ieee_registry(IEEE_MAC_REGISTRY . DIRECTORY_SEPARATOR . 'mam.txt', '28 bit identifier (MA-M)', $alt_mac)) ||
444
                                ($x = _lookup_ieee_registry(IEEE_MAC_REGISTRY . DIRECTORY_SEPARATOR . 'oui.txt', 'OUI-24 (MA-L)', $mac))
468
                                ($x = _lookup_ieee_registry(IEEE_MAC_REGISTRY . DIRECTORY_SEPARATOR . 'oui.txt', 'OUI (MA-L)', $alt_mac))
445
                        ) {
469
                        ) {
446
                                echo $x;
470
                                echo $x;
447
                        }
471
                        }
448
                }
472
                }
449
        }
473
        }