MAC Address Filtering with iptables

Source and destination MAC addresses are included in the header of every Ethernet (and by extension, WiFi) frame. As the name implies, iptables is generally intended for use with Layer 3 protocols and as such has limited support for dealing with MAC addresses. Layer 2 filtering is more properly the domain of arptables and ebtables. That being said, iptables does have a limited 'mac' module that lets us filter by --mac-source which lets us do some neat things to local packets received on Ethernet/WiFi interfaces.

For example, you may wish to ignore all traffic from a particular MAC on your network:
iptables -A INPUT -m mac --mac-source 12:34:56:78:9a:bc -j DROP

Or flip it around with the ! operator and discard all traffic from any device on your local network other than your upstream gateway:
iptables -A INPUT -m mac ! --mac-source 12:34:56:78:9a:bc -j DROP

You might find it handy to allow SSH access only to one device on a particular interface, avoiding having to specify any IP addresses which may be ideal on a DHCP-configured or frequently changing LAN:
iptables -A INPUT -i eth0 --dport 22 -m mac ! --mac-source 12:34:56:78:9a:bc -j REJECT

If you want to set up an ACL similar to a hotspot whitelist/blacklist it may be easier to maintain a list of addresses in a text file:
for MAC in `cat /path/to/whitelist.txt`; do iptables -A FORWARD -i eth0 -o eth1 -m mac --mac-source $MAC -j ACCEPT done iptables -P FORWARD DROP
It is possible to defend against ARP poisoning/spoofing by taking this one step further and dropping all traffic coming from IPs that don't match their proper MAC address if you maintain a table of every device you wish to communicate with, statically configured their IP addresses or set up static leases in your DHCP server.

It should be noted that since the only filter available to us is the MAC source address we can only create useful filters in the INPUT, FORWARD and PREROUTING chains.

You can find a device's MAC address locally using ifconfig:
# ifconfig eth0 eth0: flags=4163 mtu 1500 inet netmask broadcast ether 12:34:56:78:9a:bc txqueuelen 1000 (Ethernet) RX packets 1035457 bytes 733963916 (699.9 MiB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 1183022 bytes 909429182 (867.2 MiB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

...or ip:
# ip addr show eth0 2: eth0: mtu 1500 qdisc mq state UP group default qlen 1000 link/ether 12:34:56:78:9a:bc brd ff:ff:ff:ff:ff:ff

...or ethtool:
# ethtool -P eth0 Permanent address: 12:34:56:78:9a:bc

You can find a remote device's MAC address by running arping:
# arping ARPING 60 bytes from 12:34:56:78:9a:bc ( index=0 time=775.829 usec ...

Alternatively, since arping is not always available (or you may be using a Windows machine...) you can send a conventional ICMP echo request to the device to ensure a record is entered into your local ARP table and obtain its address there:
# ping PING ( 56(84) bytes of data. 64 bytes from icmp_seq=1 ttl=255 time=1.95 ms ^C --- ping statistics --- 1 packets transmitted, 1 received, 0% packet loss, time 0ms rtt min/avg/max/mdev = 1.947/1.947/1.947/0.000 ms # arp -a | grep ? ( at 12:34:56:78:9a:bc [ether] on eth0


There are no comments for this item.