arptables is the ARP-layer counterpart of iptables: it
filters ARP frames instead of IP packets. There are very few examples of it online,
yet it is a solid way to protect a host's ARP cache from tampering and MAC hijacking
(the same ARP spoofing / MITM attacks described elsewhere on this blog). This post
shows a minimal arptables configuration for a proxy / gateway that is
exposed to the Internet and does not hide an internal network behind NAT.
arptables is provided
by the nftables backend (arptables-nft). The rules below
still work through that compatibility layer, but for new deployments consider writing
native nft rules in the arp family.
The idea
We deny every incoming ARP request by default, while still allowing our own ARP traffic out so the box can reach its upstream provider. Then we selectively allow ARP from the hosts we actually need to talk to: our LAN and our ISP's DNS/gateway addresses.
Default policy
arptables -P INPUT DROP
arptables -P OUTPUT ACCEPTAt this point the proxy can initiate ARP (so it keeps talking to the provider), but it ignores every ARP request coming in — including forged ones.
Sample topology
eth2 = Internet (dynamic IP via DHCP), public IP e.g. 200.37.113.152
eth1 = LAN 210.93.45.0/24, proxy LAN address 210.93.45.1Check which upstream address is actually serving you by looking at the current ARP cache (the entry on the Internet interface is the one that matters):
arp -v
# Address HWtype HWaddress Iface
# 200.37.113.1 ether 00:00:CA:FE:4C:0A eth2 <-- upstream gatewayAllow only the addresses you need
The first rule permits ARP between the LAN and the proxy's LAN IP. The remaining
rules permit ARP from the ISP gateway and the DNS servers listed in
/etc/resolv.conf:
arptables -A INPUT -i eth1 -s 210.93.45.0 -d 210.93.45.1 -j ACCEPT
arptables -A INPUT -i eth2 -s 200.60.37.2 -j ACCEPT
arptables -A INPUT -i eth2 -s 200.48.211.2 -j ACCEPT
arptables -A INPUT -i eth2 -s 208.67.222.222 -j ACCEPT # OpenDNS
arptables -A INPUT -i eth2 -s 200.37.113.1 -j ACCEPT # ISP gatewayThe LAN rule must set the proxy's static LAN IP as the destination — remember the
box has two IPs, so being explicit avoids surprises. Use whatever gateway IP shows up
in arp -v; the other addresses are secondary DNS servers.
Full script
#!/bin/bash
# Released under the GPL. You may copy, distribute and modify it as long
# as this license is preserved.
arptables -P INPUT DROP
arptables -P OUTPUT ACCEPT
arptables -A INPUT -i eth1 -s 210.93.45.0 -d 210.93.45.1 -j ACCEPT
arptables -A INPUT -i eth2 -s 200.60.37.2 -j ACCEPT
arptables -A INPUT -i eth2 -s 200.48.211.2 -j ACCEPT
arptables -A INPUT -i eth2 -s 208.67.222.222 -j ACCEPT
arptables -A INPUT -i eth2 -s 200.37.113.1 -j ACCEPTWhy bother?
By dropping unsolicited ARP and pinning the few peers you trust, a poisoning attacker on the same segment can no longer overwrite the proxy's cache to insert themselves as the gateway. On managed switches you would combine this with Dynamic ARP Inspection and DHCP snooping for defence in depth. See the arptables manual for the full rule syntax.
Comments