Skip to content

Commit

Permalink
fixed arp table mac address parsing
Browse files Browse the repository at this point in the history
- Added ARPEntry.Flags field related to entry flags
- Added ARPEntry.IsComplete() to check if entry is complete
- Fixed mac address parsing and error handling
- Test improved with incomplete entry information
Closes #413.

Signed-off-by: Serhii Zasenko <sergii@zasenko.name>
  • Loading branch information
und3f committed Sep 19, 2021
1 parent 59a4b3a commit 8cc7622
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 8 deletions.
40 changes: 35 additions & 5 deletions arp.go
Expand Up @@ -17,9 +17,26 @@ import (
"fmt"
"io/ioutil"
"net"
"strconv"
"strings"
)

// Learned from include/uapi/linux/if_arp.h
const (
// completed entry (ha valid)
ATF_Complete = 0x02
// permanent entry
ATF_Permanent = 0x04
// Publish entry
ATF_Publish = 0x08
// Has requested trailers
ATF_UseTrailers = 0x10
// Obsoleted: Want to use a netmask (only for proxy entries)
ATF_Netmask = 0x20
// Don't answer this addresses
ATF_DontPublish = 0x40
)

// ARPEntry contains a single row of the columnar data represented in
// /proc/net/arp.
type ARPEntry struct {
Expand All @@ -29,6 +46,8 @@ type ARPEntry struct {
HWAddr net.HardwareAddr
// Name of the device
Device string
// Flags
Flags byte
}

// GatherARPEntries retrieves all the ARP entries, parse the relevant columns,
Expand Down Expand Up @@ -72,14 +91,25 @@ func parseARPEntries(data []byte) ([]ARPEntry, error) {
}

func parseARPEntry(columns []string) (ARPEntry, error) {
entry := ARPEntry{Device: columns[5]}
ip := net.ParseIP(columns[0])
mac := net.HardwareAddr(columns[3])
entry.IPAddr = ip

if mac, err := net.ParseMAC(columns[3]); err == nil {
entry.HWAddr = mac
} else {
return ARPEntry{}, err
}

entry := ARPEntry{
IPAddr: ip,
HWAddr: mac,
Device: columns[5],
if flags, err := strconv.ParseUint(columns[2], 0, 8); err == nil {
entry.Flags = byte(flags)
} else {
return ARPEntry{}, err
}

return entry, nil
}

func (entry *ARPEntry) IsComplete() bool {
return entry.Flags&ATF_Complete != 0
}
28 changes: 26 additions & 2 deletions arp_test.go
Expand Up @@ -33,11 +33,35 @@ func TestARP(t *testing.T) {
t.Errorf("want 192.168.224.1, got %s", got)
}

if want, got := net.HardwareAddr("00:50:56:c0:00:08").String(), arpFile[0].HWAddr.String(); want != got {
t.Errorf("want 00:50:56:c0:00:08, got %s", got)
if want, got := "00:50:56:c0:00:08", arpFile[0].HWAddr.String(); want != got {
t.Errorf("want %s, got %s", want, got)
}

if want, got := "ens33", arpFile[0].Device; want != got {
t.Errorf("want ens33, got %s", got)
}

if want, got := true, arpFile[0].IsComplete(); want != got {
t.Errorf("want %t, got %t", want, got)
}

if want, got := "192.168.224.2", arpFile[1].IPAddr.String(); want != got {
t.Errorf("want 192.168.224.2, got %s", got)
}

if want, got := make(net.HardwareAddr, 6).String(), arpFile[1].HWAddr.String(); want != got {
t.Errorf("expected empty MAC, got %s", got)
}

if want, got := "ens33", arpFile[1].Device; want != got {
t.Errorf("want %s, got %s", want, got)
}

if want, got := byte(0x0), arpFile[1].Flags; want != got {
t.Errorf("want %b, got %b", want, got)
}

if want, got := false, arpFile[1].IsComplete(); want != got {
t.Errorf("want %t, got %t", want, got)
}
}
3 changes: 2 additions & 1 deletion fixtures.ttar
Expand Up @@ -2084,9 +2084,10 @@ Directory: fixtures/proc/net
Mode: 755
# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Path: fixtures/proc/net/arp
Lines: 2
Lines: 3
IP address HW type Flags HW address Mask Device
192.168.224.1 0x1 0x2 00:50:56:c0:00:08 * ens33
192.168.224.2 0x1 0x0 00:00:00:00:00:00 * ens33
Mode: 664
# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Path: fixtures/proc/net/dev
Expand Down

0 comments on commit 8cc7622

Please sign in to comment.