Embed the IEEE OUI registry (~1MB pre-processed text file) and resolve the vendor for every station MAC. Locally administered MACs (U/L bit set, used by iOS/Android private addresses and virtual interfaces) are skipped so we don't return spurious matches against randomized prefixes. The vendor name shows up in the device card as a secondary line, and falls back to the title position when no DHCP hostname is available — "Apple" with the IP and MAC is far more useful than "Sans nom". The lookup table loads lazily (sync.Once) on the first call so the ~40k-entry parse only runs when the station discovery code is exercised.
57 lines
1.6 KiB
Go
57 lines
1.6 KiB
Go
package backend
|
|
|
|
import "testing"
|
|
|
|
func TestLookupVendor(t *testing.T) {
|
|
cases := []struct {
|
|
mac string
|
|
want string
|
|
exact bool // when true, want must match exactly; otherwise non-empty is enough
|
|
comment string
|
|
}{
|
|
{"00:1c:b3:11:22:33", "Apple", true, "Apple OUI"},
|
|
{"f4:0f:24:11:22:33", "Apple", true, "Apple OUI uppercase"},
|
|
{"B8:27:EB:AA:BB:CC", "", false, "Raspberry Pi Foundation"},
|
|
{"dc:a6:32:11:22:33", "", false, "Raspberry Pi Trading"},
|
|
{"02:11:22:33:44:55", "", true, "locally administered (U/L bit set)"},
|
|
{"aa:bb:cc:dd:ee:ff", "", true, "locally administered randomized"},
|
|
{"", "", true, "empty mac"},
|
|
{"not a mac", "", true, "garbage"},
|
|
}
|
|
|
|
for _, tc := range cases {
|
|
got := LookupVendor(tc.mac)
|
|
if tc.exact {
|
|
if got != tc.want {
|
|
t.Errorf("%s: LookupVendor(%q) = %q, want %q", tc.comment, tc.mac, got, tc.want)
|
|
}
|
|
continue
|
|
}
|
|
if got == "" {
|
|
t.Errorf("%s: LookupVendor(%q) returned empty, expected non-empty", tc.comment, tc.mac)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestNormalizeOUI(t *testing.T) {
|
|
cases := []struct {
|
|
in string
|
|
want string
|
|
}{
|
|
{"00:1c:b3:11:22:33", "001CB3"},
|
|
{"00-1c-b3-11-22-33", "001CB3"},
|
|
{"001c.b311.2233", "001CB3"},
|
|
{"001cb3112233", "001CB3"},
|
|
{"02:11:22:33:44:55", ""}, // U/L bit set
|
|
{"03:11:22:33:44:55", ""}, // U/L bit set
|
|
{"06:11:22:33:44:55", ""}, // U/L bit set
|
|
{"01:00:5e:00:00:00", "01005E"}, // bit 0 (multicast) is fine, only bit 1 matters
|
|
{"abcd", ""}, // too short
|
|
}
|
|
|
|
for _, tc := range cases {
|
|
if got := normalizeOUI(tc.in); got != tc.want {
|
|
t.Errorf("normalizeOUI(%q) = %q, want %q", tc.in, got, tc.want)
|
|
}
|
|
}
|
|
}
|