From fb653292612eddca5b088ed88466c546d1597107 Mon Sep 17 00:00:00 2001 From: Elizabeth Alexander Hunt Date: Sat, 20 Jun 2026 09:40:07 -0700 Subject: Initial commit --- adapters/arp/arp.go | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 adapters/arp/arp.go (limited to 'adapters/arp/arp.go') diff --git a/adapters/arp/arp.go b/adapters/arp/arp.go new file mode 100644 index 0000000..19d7632 --- /dev/null +++ b/adapters/arp/arp.go @@ -0,0 +1,63 @@ +package arp + +import ( + "os/exec" + "regexp" + "strings" + + "penguins.lan/utils" +) + +type ArpTable struct { + AddrToMac map[utils.INet4]utils.Mac +} + +// Lookup returns the canonical MAC for an IPv4 string, false if it isn't in the +// table or isn't parseable IPv4 (e.g. an IPv6 peer). +func (t *ArpTable) Lookup(ip string) (string, bool) { + addr, err := utils.ParseINet4(ip) + if err != nil { + return "", false + } + mac, ok := t.AddrToMac[*addr] + if !ok { + return "", false + } + return mac.Format(), true +} + +type TableProvider interface { + Fetch() (*ArpTable, error) +} + +var arpLine = regexp.MustCompile(`\((\d{1,3}(?:\.\d{1,3}){3})\) at ([0-9a-fA-F]{1,2}(?::[0-9a-fA-F]{1,2}){5})`) + +type SystemProvider struct{} + +func (SystemProvider) Fetch() (*ArpTable, error) { + out, err := exec.Command("arp", "-an").Output() + if err != nil { + return nil, err + } + return parseTable(string(out)), nil +} + +func parseTable(out string) *ArpTable { + table := &ArpTable{AddrToMac: make(map[utils.INet4]utils.Mac)} + for _, line := range strings.Split(out, "\n") { + m := arpLine.FindStringSubmatch(line) + if m == nil { + continue + } + addr, err := utils.ParseINet4(m[1]) + if err != nil { + continue + } + mac, err := utils.ParseMac(m[2]) + if err != nil { + continue + } + table.AddrToMac[*addr] = *mac + } + return table +} -- cgit v1.3