Rev 17 | Rev 19 | Go to most recent revision | Show entire file | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 17 | Rev 18 | ||
---|---|---|---|
Line 16... | Line 16... | ||
16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
17 | * See the License for the specific language governing permissions and |
17 | * See the License for the specific language governing permissions and |
18 | * limitations under the License. |
18 | * limitations under the License. |
19 | */ |
19 | */ |
20 | 20 | ||
- | 21 | // Very good resources for information about OUI, EUI, MAC, ... |
|
- | 22 | // - https://mac-address.alldatafeeds.com/faq#how-to-recognise-mac-address-application |
|
- | 23 | // - https://standards.ieee.org/wp-content/uploads/import/documents/tutorials/eui.pdf |
|
- | 24 | // - https://en.m.wikipedia.org/wiki/Organizationally_unique_identifier |
|
- | 25 | ||
21 | const IEEE_MAC_REGISTRY = __DIR__ . '/../web-data'; |
26 | const IEEE_MAC_REGISTRY = __DIR__ . '/../web-data'; |
22 | 27 | ||
23 | /** |
28 | /** |
24 | * Checks if a MAC, EUI, or IPv6-LinkLocal address is valid |
29 | * Checks if a MAC, EUI, ELI, or IPv6-LinkLocal address is valid |
25 | * @param string $mac MAC, EUI, or IPv6-LinkLocal Address |
30 | * @param string $mac MAC, EUI, or IPv6-LinkLocal Address |
26 | * @return bool True if it is valid |
31 | * @return bool True if it is valid |
27 | */ |
32 | */ |
28 | function mac_valid(string $mac): bool { |
33 | function mac_valid(string $mac): bool { |
29 | $tmp = ipv6linklocal_to_mac48($mac); |
34 | $tmp = ipv6linklocal_to_mac48($mac); |
Line 38... | Line 43... | ||
38 | 43 | ||
39 | return ($mac === ''); |
44 | return ($mac === ''); |
40 | } |
45 | } |
41 | 46 | ||
42 | /** |
47 | /** |
43 | * Returns the amount of bits of a MAC or EUI |
48 | * Returns the amount of bits of a MAC, EUI, or ELI |
44 | * @param string $mac |
49 | * @param string $mac |
45 | * @return false|int |
50 | * @return false|int |
46 | */ |
51 | */ |
47 | function eui_bits(string $mac) { |
52 | function eui_bits(string $mac) { |
48 | if (!mac_valid($mac)) return false; |
53 | if (!mac_valid($mac)) return false; |
49 | $mac = mac_canonize($mac, ''); |
54 | $mac = mac_canonize($mac, ''); |
50 | return (int)(strlen($mac)*4); |
55 | return (int)(strlen($mac)*4); |
51 | } |
56 | } |
52 | 57 | ||
53 | /** |
58 | /** |
54 | * Canonizes a MAC, EUI, or IPv6-LinkLocal address |
59 | * Canonizes a MAC, EUI, ELI, or IPv6-LinkLocal address |
55 | * @param string $mac MAC, EUI, or IPv6-LinkLocal Address |
60 | * @param string $mac MAC, EUI, ELI, or IPv6-LinkLocal Address |
56 | * @param string $delimiter Desired delimiter for inserting between each octet |
61 | * @param string $delimiter Desired delimiter for inserting between each octet |
57 | * @return string|false The canonized address (Note: IPv6-Linklocal becomes EUI-64) |
62 | * @return string|false The canonized address (Note: IPv6-Linklocal becomes EUI-64) |
58 | */ |
63 | */ |
59 | function mac_canonize(string $mac, string $delimiter="-") { |
64 | function mac_canonize(string $mac, string $delimiter="-") { |
60 | if (!mac_valid($mac)) return false; |
65 | if (!mac_valid($mac)) return false; |
Line 131... | Line 136... | ||
131 | */ |
136 | */ |
132 | function eui64_to_eui48(string $eui64) { |
137 | function eui64_to_eui48(string $eui64) { |
133 | if (!mac_valid($eui64)) return false; |
138 | if (!mac_valid($eui64)) return false; |
134 | $eui64 = mac_canonize($eui64, ''); |
139 | $eui64 = mac_canonize($eui64, ''); |
135 | if (eui_bits($eui64) == 48) return mac_canonize($eui64); |
140 | if (eui_bits($eui64) == 48) return mac_canonize($eui64); |
- | 141 | if ($eui64[1] == 'A') return false; // do not allow ELI-64 |
|
136 | 142 | ||
137 | if (substr($eui64, 6, 4) == 'FFFF') { |
143 | if (substr($eui64, 6, 4) == 'FFFF') { |
138 | // EUI-64 to MAC-48 |
144 | // EUI-64 to MAC-48 |
139 | return mac_canonize(substr($eui64, 0, 6).substr($eui64, 10, 6)); |
145 | return mac_canonize(substr($eui64, 0, 6).substr($eui64, 10, 6)); |
140 | } else if (substr($eui64, 6, 4) == 'FFFE') { |
146 | } else if (substr($eui64, 6, 4) == 'FFFE') { |
Line 160... | Line 166... | ||
160 | // Note: MAC-48 is used for network hardware; EUI-48 is used to identify other devices and software. |
166 | // Note: MAC-48 is used for network hardware; EUI-48 is used to identify other devices and software. |
161 | // MAC48-to-EUI64 Encapsulation uses 0xFFFF middle part |
167 | // MAC48-to-EUI64 Encapsulation uses 0xFFFF middle part |
162 | if (!mac_valid($mac48)) return false; |
168 | if (!mac_valid($mac48)) return false; |
163 | $mac48 = mac_canonize($mac48, ''); |
169 | $mac48 = mac_canonize($mac48, ''); |
164 | if (eui_bits($mac48) == 64) return mac_canonize($mac48); |
170 | if (eui_bits($mac48) == 64) return mac_canonize($mac48); |
- | 171 | if ($mac48[1] == 'A') return false; // do not allow ELI-48 |
|
165 | 172 | ||
166 | $eui64 = substr($mac48, 0, 6).'FFFF'.substr($mac48, 6, 6); |
173 | $eui64 = substr($mac48, 0, 6).'FFFF'.substr($mac48, 6, 6); |
167 | return mac_canonize($eui64); |
174 | return mac_canonize($eui64); |
168 | } |
175 | } |
169 | 176 | ||
Line 176... | Line 183... | ||
176 | // Note: MAC-48 is used for network hardware; EUI-48 is used to identify other devices and software. |
183 | // Note: MAC-48 is used for network hardware; EUI-48 is used to identify other devices and software. |
177 | // EUI48-to-EUI64 Encapsulation uses 0xFFFF middle part |
184 | // EUI48-to-EUI64 Encapsulation uses 0xFFFF middle part |
178 | if (!mac_valid($eui48)) return false; |
185 | if (!mac_valid($eui48)) return false; |
179 | $eui48 = mac_canonize($eui48, ''); |
186 | $eui48 = mac_canonize($eui48, ''); |
180 | if (eui_bits($eui48) == 64) return mac_canonize($eui48); |
187 | if (eui_bits($eui48) == 64) return mac_canonize($eui48); |
- | 188 | if ($eui48[1] == 'A') return false; // do not allow ELI-48 |
|
181 | 189 | ||
182 | $eui64 = substr($eui48, 0, 6).'FFFE'.substr($eui48, 6, 6); |
190 | $eui64 = substr($eui48, 0, 6).'FFFE'.substr($eui48, 6, 6); |
183 | return mac_canonize($eui64); |
191 | return mac_canonize($eui64); |
184 | } |
192 | } |
185 | 193 | ||
Line 192... | Line 200... | ||
192 | // Note: MAC-48 is used for network hardware; EUI-48 is used to identify other devices and software. |
200 | // Note: MAC-48 is used for network hardware; EUI-48 is used to identify other devices and software. |
193 | // EUI48-to-ModifiedEUI64 Encapsulation uses 0xFFFE middle part (SIC! This was a mistake by IETF, since it should actually be 0xFFFF!) |
201 | // EUI48-to-ModifiedEUI64 Encapsulation uses 0xFFFE middle part (SIC! This was a mistake by IETF, since it should actually be 0xFFFF!) |
194 | if (!mac_valid($eui48)) return false; |
202 | if (!mac_valid($eui48)) return false; |
195 | $eui48 = mac_canonize($eui48, ''); |
203 | $eui48 = mac_canonize($eui48, ''); |
196 | if (eui_bits($eui48) == 64) return mac_canonize($eui48); |
204 | if (eui_bits($eui48) == 64) return mac_canonize($eui48); |
- | 205 | if ($eui48[1] == 'A') return false; // do not allow ELI-48 |
|
197 | 206 | ||
198 | $eui64 = substr($eui48, 0, 6).'FFFE'.substr($eui48, 6, 6); |
207 | $eui64 = substr($eui48, 0, 6).'FFFE'.substr($eui48, 6, 6); |
199 | 208 | ||
200 | $eui64[1] = dechex(hexdec($eui64[1]) | 2); // flip seventh bit |
209 | $eui64[1] = dechex(hexdec($eui64[1]) | 2); // flip seventh bit |
201 | 210 | ||
Line 246... | Line 255... | ||
246 | $mac = str_pad($mac, 16, '0', STR_PAD_LEFT); |
255 | $mac = str_pad($mac, 16, '0', STR_PAD_LEFT); |
247 | 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)); |
248 | } |
257 | } |
249 | 258 | ||
250 | /** |
259 | /** |
251 | * Prints information about an IPv6-LinkLocal address, MAC, or EUI. |
260 | * Prints information about an IPv6-LinkLocal address, MAC, EUI, or ELI. |
252 | * @param string $mac IPv6-LinkLocal address, MAC, or EUI |
261 | * @param string $mac IPv6-LinkLocal address, MAC, EUI, or ELI |
253 | * @return void |
262 | * @return void |
254 | * @throws Exception |
263 | * @throws Exception |
255 | */ |
264 | */ |
256 | function decode_mac(string $mac) { |
265 | function decode_mac(string $mac) { |
257 | // Amazing website about MAC addresses: https://mac-address.alldatafeeds.com/faq#how-to-recognise-mac-address-application |
- | |
258 | - | ||
259 | echo sprintf("%-32s %s\n", "Input:", $mac); |
266 | echo sprintf("%-32s %s\n", "Input:", $mac); |
260 | 267 | ||
261 | // Format MAC for machine readability |
268 | // Format MAC for machine readability |
262 | $mac = mac_canonize($mac, ''); |
269 | $mac = mac_canonize($mac, ''); |
263 | 270 | ||
264 | $type = ''; |
271 | $type = ''; |
- | 272 | if ($mac[1] == 'A') { |
|
- | 273 | // An ELI is based on a CID-24 |
|
- | 274 | // A CID has ZYXM bits set to 1010 (0b1010 = 0xA) |
|
- | 275 | // Since X=1 (U/L=1), the CID cannot be used to form a universal UAA MAC (only a local LAA MAC) |
|
- | 276 | $type = 'ELI-'.eui_bits($mac);; |
|
- | 277 | } else { |
|
265 | $tmp = ipv6linklocal_to_mac48($mac); |
278 | $tmp = ipv6linklocal_to_mac48($mac); |
266 | if ($tmp !== false) { |
279 | if ($tmp !== false) { |
267 | $mac = $tmp; |
280 | $mac = $tmp; |
268 | $type = 'IPv6-Link-Local'; |
281 | $type = 'IPv6-Link-Local'; |
269 | } |
282 | } |
Line 285... | Line 298... | ||
285 | } |
298 | } |
286 | } else { |
299 | } else { |
287 | assert(false); /** @phpstan-ignore-line */ |
300 | assert(false); /** @phpstan-ignore-line */ |
288 | } |
301 | } |
289 | } |
302 | } |
- | 303 | } |
|
290 | echo sprintf("%-32s %s\n", "Type:", $type); |
304 | echo sprintf("%-32s %s\n", "Type:", $type); |
291 | 305 | ||
292 | echo "\n"; |
306 | echo "\n"; |
293 | 307 | ||
294 | // Show various representations |
308 | // Show various representations |
- | 309 | if ($mac[1] == 'A') { |
|
- | 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)); |
|
- | 312 | } else { |
|
295 | $eui48 = eui64_to_eui48($mac); |
313 | $eui48 = eui64_to_eui48($mac); |
296 | echo sprintf("%-32s %s\n", "EUI-48:", (eui_bits($eui48) != 48) ? 'Not available' : $eui48); |
314 | echo sprintf("%-32s %s\n", "EUI-48:", (eui_bits($eui48) != 48) ? 'Not available' : $eui48); |
297 | if (eui_bits($mac) == 48) { |
315 | if (eui_bits($mac) == 48) { |
298 | $eui64 = mac48_to_eui64($mac); |
316 | $eui64 = mac48_to_eui64($mac); |
299 | echo sprintf("%-32s %s\n", "EUI-64:", ((eui_bits($eui64) != 64) ? 'Not available' : $eui64).' (MAC-48 to EUI-64 Encapsulation)'); |
317 | echo sprintf("%-32s %s\n", "EUI-64:", ((eui_bits($eui64) != 64) ? 'Not available' : $eui64).' (MAC-48 to EUI-64 Encapsulation)'); |
Line 305... | Line 323... | ||
305 | echo sprintf("%-32s %s\n", "IPv6 link local address:", $ipv6); |
323 | echo sprintf("%-32s %s\n", "IPv6 link local address:", $ipv6); |
306 | } else { |
324 | } else { |
307 | $eui64 = mac_canonize($mac); |
325 | $eui64 = mac_canonize($mac); |
308 | echo sprintf("%-32s %s\n", "EUI-64:", $eui64); |
326 | echo sprintf("%-32s %s\n", "EUI-64:", $eui64); |
309 | } |
327 | } |
- | 328 | } |
|
310 | 329 | ||
311 | // Vergabestelle |
330 | // Vergabestelle |
312 | $ul = hexdec($mac[1]) & 2; // Bit #LSB+1 of Byte 1 |
331 | $ul = hexdec($mac[1]) & 2; // Bit #LSB+1 of Byte 1 |
313 | $ul_ = ($ul == 0) ? '[0] Universally Administered Address (UAA)' : '[1] Locally Administered Address (LAA)'; |
332 | $ul_ = ($ul == 0) ? '[0] Universally Administered Address (UAA)' : '[1] Locally Administered Address (LAA)'; |
314 | echo sprintf("%-32s %s\n", "Administration type (U/L flag):", $ul_); |
333 | echo sprintf("%-32s %s\n", "Administration type (U/L flag):", $ul_); |
315 | 334 | ||
316 | // Empfaengergruppe |
335 | // Empfaengergruppe |
317 | $ig = hexdec($mac[1]) & 1; // Bit #LSB+0 of Byte 1 |
336 | $ig = hexdec($mac[1]) & 1; // Bit #LSB+0 of Byte 1 |
318 | $ig_ = ($ig == 0) ? '[0] Individual (Unicast)' : '[1] Group (Multicast)'; |
337 | $ig_ = ($ig == 0) ? '[0] Unicast (Individual)' : '[1] Multicast (Group)'; |
319 | echo sprintf("%-32s %s\n", "Transmission type (I/G flag):", $ig_); |
338 | echo sprintf("%-32s %s\n", "Transmission type (I/G flag):", $ig_); |
320 | 339 | ||
321 | // Query IEEE registries |
340 | // Query IEEE registries |
322 | // TODO: gilt OUI nur bei Individual UAA? For LAA, should we convert to UAA and then query the registry? |
- | |
323 | if (count(glob(IEEE_MAC_REGISTRY.DIRECTORY_SEPARATOR.'*.txt')) > 0) { |
341 | if (count(glob(IEEE_MAC_REGISTRY.DIRECTORY_SEPARATOR.'*.txt')) > 0) { |
- | 342 | if ($mac[1] == 'A') { |
|
- | 343 | // Query the CID registry |
|
- | 344 | if ( |
|
- | 345 | ($x = _lookup_ieee_registry(IEEE_MAC_REGISTRY . DIRECTORY_SEPARATOR . 'cid.txt', 'CID', $mac)) |
|
- | 346 | ) { |
|
- | 347 | echo $x; |
|
- | 348 | } |
|
- | 349 | } else { |
|
- | 350 | // Query the OUI registries |
|
- | 351 | // TODO: Should we try to convert Unicast<=>Multicast if one of them can't be found? |
|
324 | if ( |
352 | if ( |
325 | # 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] |
353 | # 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] |
326 | # 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. |
354 | # 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. |
327 | ($x = _lookup_ieee_registry(IEEE_MAC_REGISTRY . DIRECTORY_SEPARATOR . 'iab.txt', 'IAB', $mac)) || |
355 | ($x = _lookup_ieee_registry(IEEE_MAC_REGISTRY . DIRECTORY_SEPARATOR . 'iab.txt', 'IAB', $mac)) || |
328 | ($x = _lookup_ieee_registry(IEEE_MAC_REGISTRY . DIRECTORY_SEPARATOR . 'oui36.txt', 'OUI-36 (MA-S)', $mac)) || |
356 | ($x = _lookup_ieee_registry(IEEE_MAC_REGISTRY . DIRECTORY_SEPARATOR . 'oui36.txt', 'OUI-36 (MA-S)', $mac)) || |
Line 330... | Line 358... | ||
330 | ($x = _lookup_ieee_registry(IEEE_MAC_REGISTRY . DIRECTORY_SEPARATOR . 'oui.txt', 'OUI-24 (MA-L)', $mac)) |
358 | ($x = _lookup_ieee_registry(IEEE_MAC_REGISTRY . DIRECTORY_SEPARATOR . 'oui.txt', 'OUI-24 (MA-L)', $mac)) |
331 | ) { |
359 | ) { |
332 | echo $x; |
360 | echo $x; |
333 | } |
361 | } |
334 | } |
362 | } |
- | 363 | } |
|
335 | 364 | ||
336 | $vm = ''; |
365 | $vm = ''; |
337 | // === FAQ "Detection rules which don't have their dedicated page yet" === |
366 | // === FAQ "Detection rules which don't have their dedicated page yet" === |
338 | // https://wiki.xenproject.org/wiki/Xen_Networking |
367 | // https://wiki.xenproject.org/wiki/Xen_Networking |
339 | // https://mcpmag.com/articles/2007/11/27/hey-vm-whats-your-hypervisor.aspx |
368 | // https://mcpmag.com/articles/2007/11/27/hey-vm-whats-your-hypervisor.aspx |
Line 769... | Line 798... | ||
769 | $hightest = eui64_to_eui48($high); |
798 | $hightest = eui64_to_eui48($high); |
770 | if ($hightest === false) return false; |
799 | if ($hightest === false) return false; |
771 | 800 | ||
772 | if ((eui_bits($mactest) != eui_bits($lowtest)) || (eui_bits($lowtest) != eui_bits($hightest))) { |
801 | if ((eui_bits($mactest) != eui_bits($lowtest)) || (eui_bits($lowtest) != eui_bits($hightest))) { |
773 | $mactest = eui48_to_eui64($mac); |
802 | $mactest = eui48_to_eui64($mac); |
- | 803 | if ($mactest === false) return false; // e.g. trying ELI-48 to ELI-64 |
|
774 | $lowtest = eui48_to_eui64($low); |
804 | $lowtest = eui48_to_eui64($low); |
- | 805 | if ($lowtest === false) return false; // e.g. trying ELI-48 to ELI-64 |
|
775 | $hightest = eui48_to_eui64($high); |
806 | $hightest = eui48_to_eui64($high); |
- | 807 | if ($hightest === false) return false; // e.g. trying ELI-48 to ELI-64 |
|
776 | } |
808 | } |
777 | 809 | ||
778 | $mactest = strtoupper(preg_replace('@[^0-9A-F]@', '', $mactest)); |
810 | $mactest = strtoupper(preg_replace('@[^0-9A-F]@', '', $mactest)); |
779 | $lowtest = strtoupper(preg_replace('@[^0-9A-F]@', '', $lowtest)); |
811 | $lowtest = strtoupper(preg_replace('@[^0-9A-F]@', '', $lowtest)); |
780 | $hightest = strtoupper(preg_replace('@[^0-9A-F]@', '', $hightest)); |
812 | $hightest = strtoupper(preg_replace('@[^0-9A-F]@', '', $hightest)); |