Hack 39 MAC Filtering with Netfilter

figs/moderate.gif figs/hack39.gif

Keep unwanted machines off your network with MAC address whitelisting

Media Access Control (MAC) address filtering is a well-known method for protecting wireless networks. This type of filtering works on the default deny principle: you specify the hosts that are allowed to connect, while leaving unknown ones behind. MAC addresses are unique 48-bit numbers that have been assigned to every Ethernet device that has ever been manufactured, including 802.11 devices, and are usually written as six 8-bit hexadecimal digits separated by colons.

In addition to Linux's native IP packet filtering system, Netfilter also contains MAC address filtering functionality. While many of the wireless access points on the market today already support this, there are many older ones that do not. MAC filtering is also important if your access point is actually the Linux machine itself, using a wireless card. If you have a Linux-based firewall already set up, it's a trivial modification to enable it to filter at the MAC level. MAC address filtering with iptables is very much like IP-based filtering, and is just as easy to do.

This example demonstrates how to allow a particular MAC address if your firewall policy is set to DROP [Hack #33] :

iptables -A FORWARD -m state --state NEW \

  -m mac --mac-source 00:DE:AD:BE:EF:00 -j ACCEPT

This command will allow any traffic sent from the network interface with the address 00:DE:AD:BE:EF:00. Using rules like this one along with a default deny policy enables you to create a whitelist of the MAC addresses that you want to allow through your gateway. To create a blacklist, you can employ a default accept policy and change the MAC address matching rule's target to DENY.

This is all pretty straightforward if you already know the MAC addresses for which you want to create rules, but what if you don't? If you have access to the system, you can find out the MAC address of an interface by using the ifconfig command:

$ ifconfig eth0

eth0      Link encap:Ethernet  HWaddr 00:0C:29:E2:2B:C1  

          inet addr:  Bcast:  Mask:


          RX packets:132893 errors:0 dropped:0 overruns:0 frame:0

          TX packets:17007 errors:0 dropped:0 overruns:0 carrier:0

          collisions:0 txqueuelen:100 

          RX bytes:46050011 (43.9 Mb)  TX bytes:1601488 (1.5 Mb)

          Interrupt:10 Base address:0x10e0

Here you can see that the MAC address for this interface is 00:0C:29:E2:2B:C1. The output of ifconfig is somewhat different on other operating systems, but they are all similar to some degree (this output was from a Linux system).

Finding the MAC address of a system remotely is slightly more involved and can be done by using the arp and ping commands. By pinging the remote system, its IP address will be resolved to a MAC address, which can then be looked up using the arp command.

For example, to look up the MAC address that corresponds to the IP address, you could run the following commands:

$ ping -c 1

$ /sbin/arp | awk '{print $3}'

Or you could use this very small and handy shell script:


ping -c $1 >/dev/null && /sbin/arp $1 | awk '{print $3}' \

  | grep -v Hwaddress

When implementing MAC address filtering, please be aware that it is not foolproof. Under many circumstances, it is quite trivial to change the MAC address that an interface uses by simply instructing the driver to do so. It is also possible to send out link-layer frames with forged MAC addresses by using raw link-layer sockets. Thus, MAC address filtering should only be considered as an additional measure that you can use to protect your network. Treat MAC filtering more as a "Keep Out" sign, rather than a good deadbolt.