The ARP table maps every IPv4 address you talk to into a MAC address β and an attacker who can poison it sees, modifies, or drops your traffic. ARP spoofing is one of the oldest attacks in networking and remains effective on flat Layer 2 networks because the protocol has no authentication. Linux exposes the ARP cache through several tools; this guide walks through the audit techniques that detect spoofing, duplicate IPs, and rogue devices on a network segment.
The modern ARP commands
arp is deprecated; ip neigh from iproute2 is the supported replacement:
ip neigh show # current ARP/NDP table
ip neigh show dev eth0 # one interface
ip -s neigh # with statistics
arp -an # legacy form, still works
ip neigh flush all # nuke the cache (forces re-learn)
Each entry shows IP, device, MAC, and a state: REACHABLE, STALE, DELAY, PROBE, FAILED. Healthy hosts have most entries reachable; many FAILED entries indicate aggressive scanning or a broken peer.
Detecting duplicate IPs
Two devices with the same IP cause ARP to flap between MACs β the symptom is intermittent connectivity blamed on "the network":
arping -c 5 -D -I eth0 192.0.2.10 # duplicate-address detection
ip neigh | awk '{print $1}' | sort | uniq -d
sudo arpwatch -i eth0 -d # live monitoring of address changes
arping -D sends an ARP request specifically asking "does anyone else claim this IP?" β the standard way to verify a static IP is unused before assigning it.
Detecting MAC spoofing
The classic ARP-spoofing pattern: an attacker sends gratuitous ARP replies claiming the gateway's IP belongs to their MAC. Symptoms in your ARP table:
- The gateway's MAC suddenly changes.
- The same MAC appears for multiple IPs.
- A new MAC OUI you do not recognise becomes the gateway.
ip neigh | awk '{print $5}' | sort | uniq -c | sort -rn | head
ip neigh | awk '{print $5}' | sort -u | wc -l # unique MACs seen
sudo arpwatch -f /var/lib/arpwatch/eth0.dat -i eth0 # log every change
Continuous monitoring with arpwatch
arpwatch is the dedicated tool for this. It maintains a database of (IP, MAC) pairings and emails when one changes:
sudo apt install arpwatch
sudo systemctl enable --now arpwatch
sudo journalctl -u arpwatch --since today
sudo cat /var/lib/arpwatch/arp.dat | head
Configure the recipient address in /etc/arpwatch/eth0.iface or via systemd unit override. Every "new station" or "changed ethernet address" event becomes an email β perfect for small networks; pipe to your SIEM for larger fleets.
Static ARP entries for critical peers
The most effective defence: hard-code the gateway and database server MACs so spoofed replies are ignored:
sudo ip neigh add 192.0.2.1 lladdr aa:bb:cc:dd:ee:ff dev eth0 nud permanent
ip neigh show 192.0.2.1
# Persist via /etc/network/interfaces post-up or NetworkManager dispatcher
Drawback: if the gateway hardware is replaced, you must update every host. For data-centre environments where MACs do not change unexpectedly, the trade-off is worth it for the most critical peers.
Sysctl hardening
# /etc/sysctl.d/99-arp.conf
net.ipv4.conf.all.arp_ignore = 1
net.ipv4.conf.default.arp_ignore = 1
net.ipv4.conf.all.arp_announce = 2
net.ipv4.conf.default.arp_announce = 2
net.ipv4.conf.all.drop_gratuitous_arp = 1
net.ipv4.conf.default.drop_gratuitous_arp = 1
arp_ignore=1 only answers ARP requests for an IP actually configured on the receiving interface. arp_announce=2 uses the best-matching source IP. drop_gratuitous_arp=1 ignores unsolicited ARP replies β the primary spoofing vector.
Switch-side dynamic ARP inspection
The strongest mitigation lives on the switch, not the host: managed switches support DHCP snooping plus Dynamic ARP Inspection (DAI), which validates every ARP packet against the snooping binding table. Coordinate with your network team β this single feature defeats most ARP attacks regardless of host configuration.
Audit script
#!/bin/bash
echo "== ARP table summary =="
total=$(ip neigh | wc -l)
unique_macs=$(ip neigh | awk '{print $5}' | sort -u | wc -l)
failed=$(ip neigh | grep -c FAILED)
echo " total entries: $total"
echo " unique MACs: $unique_macs"
echo " failed: $failed"
echo
echo "== Duplicate IPs =="
ip neigh | awk '{print $1}' | sort | uniq -d
echo
echo "== Macs claiming multiple IPs =="
ip neigh | awk '{print $5, $1}' | sort -u | awk '{m[$1]++} END {for (k in m) if (m[k]>1) print m[k], k}' | sort -rn | head
echo
echo "== Gateway MAC =="
gw=$(ip route | awk '/^default/ {print $3}')
ip neigh show "$gw"
echo
echo "== Recent arpwatch events =="
journalctl -u arpwatch --since '24 hours ago' | grep -E 'new (station|activity)|changed' | tail -10
Wireless caveats
Wi-Fi has additional MAC-layer protection (WPA2/3 4-way handshake) but the kernel ARP cache still operates the same. Captive portals and open Wi-Fi remain vulnerable. Avoid sensitive operations on untrusted networks regardless of host hardening.
Common pitfalls
- Trusting that "we have a switch with port security" without enabling DAI β port security alone does not stop ARP spoofing.
- Setting all gateway entries to permanent then forgetting about them when hardware refreshes.
- Running arpwatch but not actually reading the email β the alert is only useful if someone investigates.
- Disabling gratuitous ARP entirely and breaking VRRP, keepalived, or container-runtime IP failover.
ARP is unauthenticated, ancient, and on every Layer 2 network you connect to. Five minutes setting up arpwatch, hardening sysctls, and pinning critical MAC entries closes a class of MitM attacks that pen testers love and defenders rarely look at. Make it part of your network hardening baseline.