Første skann hos en ny kunde ga 45 svarende verter og 44 enheter i basen. 52 av 57 enheter sto som «ukjent type». På mitt eget nett hadde 32 av 36 enheter produsent, men 13 hadde ingen type. Det er ikke skanneren som er dårlig. Det er to helt konkrete ting som ryker: MAC-adresser som ikke er ekte, og et produsentoppslag som bare ser på de første 24 bitene.
Randomisert MAC er standard, ikke støy
iOS 14 og Android 10 slo på privat WiFi-adresse som standard. Windows har funksjonen, men den er avslått med mindre noen har skrudd den på. En stor del av klientene på et vanlig kontornett oppgir derfor en adresse som aldri har vært innom IEEE. Du kjenner dem igjen på to bit i første oktett, og begge må sjekkes.
bit 1 (0x02) U/L 1 = lokalt administrert
bit 0 (0x01) I/G 1 = multicast, 0 = unicast
randomisert = (b & 0x02) != 0 OG (b & 0x01) == 0
Den vanlige feilen er å sjekke bare & 0x02. Da flagges multicast-adresser med odde første oktett, altså 03:00:00:...-familien, som «randomisert klient». Utslaget er lite i praksis fordi multicast sjelden står i en ARP-tabell, men det koster ingenting å gjøre riktig.

Snarveien i hodet: se på andre hex-tegn i adressen. Er det 2, 6, A eller E, er adressen lokalt administrert og unicast.
def er_randomisert(mac: str) -> bool:
b = int(mac.replace(":", "").replace("-", "")[:2], 16)
return bool(b & 0x02) and not (b & 0x01)
>>> er_randomisert("a6:3f:1c:8d:42:07")
True
>>> er_randomisert("03:00:5e:00:00:01") # multicast, ikke klient
False
De churner mindre enn du tror
Randomiserte adresser er per SSID og stabile. Enheten lager én adresse første gang den ser et nettverk og beholder den ved gjentilkobling, ofte i måneder. De er altså brukbare nøkler i praksis, bare ikke koblet til produsent. Unntaket er MDM-styrte enheter som kan rotere daglig.
Konsekvensen for et inventar er ikke å kaste dem, men å behandle dem annerledes: aldri varsle om at de er borte, aldri gjette type på dem, og aldri la dem telle med i «nye ukjente enheter». Vil du faktisk ha ekte MAC-adresser på firmanettet, er eneste reelle løsning å slå av privat adresse via Intune eller Jamf for det SSID-et.
Produsentoppslaget må gå fra lengste prefiks og nedover
Her ligger den andre halvparten av problemet. IEEE deler ikke bare ut 24-bits blokker. Det finnes tre størrelser, og de ligger i hver sin fil.
| Blokk | Prefiks | Fil i ieee-data | Oppføringer |
|---|---|---|---|
| MA-L | 24 bit | oui.txt | 35 813 |
| MA-M | 28 bit | mam.txt | 5 418 |
| MA-S | 36 bit | oui36.txt | 6 079 |
Slår du opp 24 bit alene, treffer du blokka som IEEE selv har delt videre. Da får du navnet på registeret i stedet for navnet på produsenten. Det gjelder 358 av 24-bits-blokkene.
$ apt-get install ieee-data
$ ls /usr/share/ieee-data/
iab.txt mam.txt oui36.txt oui.txt
$ grep "70B3D5" /usr/share/ieee-data/oui.txt
70B3D5 (base 16) IEEE Registration Authority
$ grep -c "^70-B3-D5" /usr/share/ieee-data/oui36.txt
4092
Fire tusen produsenter deler altså den ene 24-bits blokka. Riktig rekkefølge er 36 bit, så 28, så 24, og første treff vinner.

Fella er at filene ikke er en nøkkel-verdi-tabell på 7 eller 9 hex-tegn, slik man intuitivt antar. mam.txt og oui36.txt bruker fortsatt det samme 24-bits OUI-et som nøkkel, og angir så et intervall over de siste 24 bitene:
$ head -6 /usr/share/ieee-data/oui36.txt
OUI Organization
OUI-36/MA-S Range Organization
Address
8C-1F-64 (hex) ALISONIC SRL
C16000-C16FFF (base 16) ALISONIC SRL
Et oppslag må derfor slå opp OUI-et og sjekke om resten av adressen faller innenfor intervallet. Det er noen linjer mer kode, men det er forskjellen på riktig og feil svar.
ENTRY = re.compile(r"^([0-9A-F-]{8})\s+\(hex\)\s+(.+?)\s*$")
RANGE = re.compile(r"^([0-9A-F]{6})-([0-9A-F]{6})\s+\(base 16\)")
def vendor(mac, mas, mam, mal):
h = re.sub(r"[^0-9A-Fa-f]", "", mac).upper()
oui, rest = h[:6], int(h[6:12], 16)
for tabell in (mas, mam): # 36 bit, så 28 bit
for o, lo, hi, navn in tabell:
if o == oui and lo <= rest <= hi:
return navn
return mal.get(oui) # 24 bit til slutt
Kjørt mot de fire filene:
70:B3:D5:06:00:1A -> RCH SPA (MA-S, 36 bit)
C8:5C:E2:71:23:45 -> SYNERGY SYSTEMS AND SOLUTIONS (MA-M, 28 bit)
00:1B:21:00:00:01 -> Intel Corporate (MA-L, 24 bit)
Databasen er eldre enn utstyret ditt
Debian-pakka ieee-data har versjon 20240722. Tildelinger gjort etter 22. juli 2024 finnes ikke i noen av filene. To eksempler fra eget nett: 90:74:ae og 30:76:f5 gir null treff i alle fire filer.
Det er greit. Tom produsent er et ærlig svar. Alternativet, å falle tilbake på nærmeste prefiks, gir feil navn på ny maskinvare, og feil navn er verre enn ingenting i et inventar som styrer varsling. Vil du ha ferske data, må du hente registrene direkte fra IEEE i stedet for fra pakkebrønnen.
Hva du klassifiserer på når MAC ikke holder
Et vanlig discovery-skann har ingen portdata i det hele tatt. Uten produsent blir da alt «ukjent», og det var akkurat det som skjedde med de 52 enhetene. Signalene som faktisk skiller enheter fra hverandre, rangert etter treffsikkerhet:
- DHCP option 55, altså parameterlista klienten ber om. Antall og rekkefølge er svært diskriminerende. Option 60 er derimot upålitelig.
- mDNS-tjenestetyper. Gratis å hente og undervurdert.
- Portsett. Krever et dypere skann, men er entydig for infrastruktur.
- Produsent fra OUI.
- Vertsnavn med regex, som siste utvei.
$ avahi-browse -art | grep -E "_ipp|_googlecast|_hap|_esphomelib"
+ eth0 IPv4 skriver-kontor _ipp._tcp
+ eth0 IPv4 stue-tv _googlecast._tcp
+ eth0 IPv4 garasje-sensor _esphomelib._tcp
Bruk kun de entydige tjenestetypene til å sette type. _ipp._tcp er printer, _googlecast._tcp er mediespiller, _hap._tcp er husautomasjon, _esphomelib._tcp er IoT, _afpovertcp._tcp er lagring. Generiske typer som _workstation._tcp sier for lite. Og _services._dns-sd._udp alene sier ingenting.
Portsignaturene som har holdt i praksis:
9100 + 515 + 631 printer (9100/JetDirect er sterkeste enkeltsignal)
554 + 80 + 8000, TTL 64 IP-kamera
62078 iOS-enhet
161 managed infrastruktur, prøv SNMP
445 + 139 uten 3389 NAS eller filserver
22 + 3389 server eller arbeidsstasjon
8006 hypervisor
8123 husautomasjon
To fallgruver verdt å nevne. Vertsnavn må sjekkes før produsent, ellers blir en elbillader klassifisert som «Espressif» fordi den har en ESP-brikke. Og enkelte produsenter bør holdes helt utenfor fallbacken. Apple og Intel sier ingenting om hva enheten er, og feil type er verre enn ukjent når fraværsvarslingen behandler mobil annerledes enn infrastruktur.
IP er aldri identitet
Dette er den klassiske fella i inventarverktøy: DHCP gjenbruker adresser, og enheter som ble kastet for to år siden ser fortsatt «levende» ut. Vertsnavn er nesten like ustabilt. MAC er eneste brukbare nøkkel, men den er ikke tilstrekkelig alene, av grunner som ikke har noe med randomisering å gjøre.
- Dokkingstasjoner og USB-Ethernet. MAC-en følger docken, ikke maskinen. To ansatte som bytter plass ser ut som at samme enhet byttet eier. Den mest oversette feilkilden i kontornett.
- Verter med flere nettkort svarer på samme IP fra flere adresser.
- Utenfor eget broadcast-domene får du kun IP, ingen MAC. Der kollapser identiteten helt, og enheter «flytter» seg mellom kunder med like IP-planer hvis du ikke merker slike observasjoner som svakere.
Matching med rangert tillit fungerer: eksakt MAC gir høy, vertsnavn kombinert med samme produsent og samme L2-segment gir middels, og en fingeravtrykk-hash av portsett, mDNS og produsent gir lav. Den siste skal aldri brukes som primærnøkkel. To like printere gir identisk hash.
Fingerbank, som lenge var standardsvaret på klassifisering, er ikke lenger åpent. Det eies av Akamai og er API-gated. Det finnes speil av gamle PacketFence-dumper på GitHub. Å bygge maskinlæring på dette er heller ikke veien: publisert nivå ligger rundt 81 prosent på 27 enheter med 276 features, altså ikke bedre enn et gjennomtenkt regelsett, og langt dyrere å drifte.
Det som avgjør om et inventar overlever er derimot enkelt: manuell overstyring må feste seg. Setter noen type på en enhet, skal neste skann aldri overskrive den. Forskjellen på et system folk retter opp i og ett de gir opp er ett låst felt.


