Subversion Repositories oidplus

Rev

Blame | Last modification | View Log | RSS feed

  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. }
  131.