Subversion Repositories uuid_mac_utils

Rev

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