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
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
# ip addr show eth0
# ethtool -P eth0
Permanent address: 12:34:56:78:9a:bc
You can find a remote device's MAC address by running arping:
# arping 192.168.0.1
60 bytes from 12:34:56:78:9a:bc (192.168.0.1): 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 192.168.0.1
PING 192.168.0.1 (192.168.0.1) 56(84) bytes of data.
64 bytes from 192.168.0.1: icmp_seq=1 ttl=255 time=1.95 ms
--- 192.168.0.1 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 192.168.0.1
? (192.168.0.1) at 12:34:56:78:9a:bc [ether] on eth0