Rev 2 | Rev 15 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
2 | daniel-mar | 1 | <?php |
2 | |||
3 | /* |
||
4 | * MAC utils for PHP |
||
5 | * Copyright 2017 Daniel Marschall, ViaThinkSoft |
||
6 | * Version 19 August 2017 |
||
7 | * |
||
8 | * Licensed under the Apache License, Version 2.0 (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 |
||
11 | * |
||
12 | * http://www.apache.org/licenses/LICENSE-2.0 |
||
13 | * |
||
14 | * Unless required by applicable law or agreed to in writing, software |
||
15 | * distributed under the License is distributed on an "AS IS" BASIS, |
||
16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||
17 | * See the License for the specific language governing permissions and |
||
18 | * limitations under the License. |
||
19 | */ |
||
20 | |||
21 | define('IEEE_MAC_REGISTRY', __DIR__ . '/../web-data'); |
||
22 | |||
23 | function mac_valid($mac) { |
||
24 | $mac = str_replace(array('-', ':'), '', $mac); |
||
25 | $mac = strtoupper($mac); |
||
26 | |||
27 | if (strlen($mac) != 12) return false; |
||
28 | |||
29 | $mac = preg_replace('@[0-9A-F]@', '', $mac); |
||
30 | |||
31 | return ($mac == ''); |
||
32 | } |
||
33 | |||
34 | function _lookup_ieee_registry($file, $oui_name, $mac) { |
||
35 | $begin = substr($mac, 0, 2).'-'.substr($mac, 2, 2).'-'.substr($mac, 4, 2); |
||
36 | $f = file_get_contents($file); |
||
37 | |||
38 | $f = str_replace("\r", '', $f); |
||
39 | |||
40 | # We are using a positive-lookahead because entries like the MA-M references have a blank line between organization and address |
||
41 | preg_match_all('@^\s*'.preg_quote($begin, '@').'\s+\(hex\)\s+(\S+)\s+(.*)\n\n\s*(?=[0-9A-F])@ismU', "$f\n\nA", $m, PREG_SET_ORDER); |
||
42 | foreach ($m as $n) { |
||
43 | preg_match('@(\S+)\s+\(base 16\)(.*)$@ism', $n[2], $m); |
||
44 | |||
45 | if (preg_match('@(.+)\-(.+)@ism', $m[1], $o)) { |
||
46 | $z = hexdec(substr($mac, 6, 6)); |
||
47 | $beg = hexdec($o[1]); |
||
48 | $end = hexdec($o[2]); |
||
49 | if (($z < $beg) || ($z > $end)) continue; |
||
50 | } else { |
||
51 | $beg = 0x000000; |
||
52 | $end = 0xFFFFFF; |
||
53 | } |
||
54 | |||
55 | $x = trim(preg_replace('@^\s+@ism', '', $m[2])); |
||
56 | |||
57 | # "PRIVATE" entries are only marked at the "(hex)" line, but not at the "(base16)" line |
||
58 | if ($x == '') $x = trim($n[1]); |
||
59 | |||
60 | $x = explode("\n", $x); |
||
61 | |||
62 | $ra_len = strlen(dechex($end-$beg)); |
||
63 | |||
64 | $out = ''; |
||
65 | $out .= sprintf("%-24s 0x%s\n", "IEEE $oui_name part:", substr($mac, 0, 12-$ra_len)); |
||
66 | $out .= sprintf("%-24s 0x%s\n", "NIC specific part:", substr($mac, 12-$ra_len)); |
||
67 | $out .= sprintf("%-24s %s\n", "Registrant:", $x[0]); |
||
68 | foreach ($x as $n => $y) { |
||
69 | if ($n == 0) continue; |
||
70 | else if ($n == 1) $out .= sprintf("%-24s %s\n", "Address of registrant:", $y); |
||
71 | else if ($n >= 2) $out .= sprintf("%-24s %s\n", "", $y); |
||
72 | } |
||
73 | |||
74 | // TODO: also print the date of last update of the OUI files |
||
75 | |||
76 | return $out; |
||
77 | } |
||
78 | |||
79 | return false; |
||
80 | } |
||
81 | |||
82 | function decode_mac($mac) { |
||
83 | if (!mac_valid($mac)) return false; |
||
84 | |||
85 | // Format MAC |
||
86 | $mac = strtoupper($mac); |
||
87 | $mac = preg_replace('@[^0-9A-F]@', '', $mac); |
||
88 | if (strlen($mac) != 12) { |
||
89 | # echo "Invalid MAC address\n"; |
||
90 | return false; |
||
91 | } |
||
92 | $mac_ = preg_replace('@^(..)(..)(..)(..)(..)(..)$@', '\\1-\\2-\\3-\\4-\\5-\\6', $mac); |
||
93 | echo sprintf("%-24s %s\n", "MAC address:", $mac_); |
||
94 | |||
95 | // Empfaengergruppe |
||
96 | $ig = hexdec($mac[1]) & 1; // Bit #LSB+0 of Byte 1 |
||
97 | $ig_ = ($ig == 0) ? '[0] Individual' : '[1] Group'; |
||
98 | echo sprintf("%-24s %s\n", "I/G flag:", $ig_); |
||
99 | |||
100 | // Vergabestelle |
||
101 | $ul = hexdec($mac[1]) & 2; // Bit #LSB+1 of Byte 1 |
||
102 | $ul_ = ($ul == 0) ? '[0] Universally Administered Address (UAA)' : '[1] Locally Administered Address (LAA)'; |
||
103 | echo sprintf("%-24s %s\n", "U/L flag:", $ul_); |
||
104 | |||
105 | // Query IEEE registries |
||
106 | // TODO: gilt OUI nur bei Individual UAA? |
||
107 | if ( |
||
108 | ($x = _lookup_ieee_registry(IEEE_MAC_REGISTRY.'/mam.txt', 'OUI-28 (MA-M)', $mac)) || |
||
109 | ($x = _lookup_ieee_registry(IEEE_MAC_REGISTRY.'/oui36.txt', 'OUI-36 (MA-S)', $mac)) || |
||
110 | # 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] |
||
111 | # 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. |
||
112 | ($x = _lookup_ieee_registry(IEEE_MAC_REGISTRY.'/iab.txt', 'IAB', $mac)) |
||
113 | ) { |
||
114 | return $x; |
||
115 | } else { |
||
116 | return _lookup_ieee_registry(IEEE_MAC_REGISTRY.'/oui.txt', 'OUI-24 (MA-L)', $mac); |
||
117 | } |
||
118 | |||
119 | // TODO |
||
120 | // FF-FF-FF-FF-FF-FF = Broadcast-Adresse |
||
121 | |||
122 | // TODO |
||
123 | // IP-Multicast |
||
124 | // 01-00-5E-00-00-00 bis 01-00-5E-7F-FF-FF (unterste 23 bit der MAC = unterste 23 Bit der IP) ... |
||
125 | // 224.0.0.1 -> 01-00-5e-00-00-01 |
||
126 | // erste 4 Bits durch Class D konvention belegt. 5 bits sind unbekannt |
||
127 | |||
128 | // TODO: VRRP |
||
129 | // 00-00-5E-00-01-ID |
||
130 | } |