Skip to content

FireRack Home

Sections
Personal tools
You are here: Home » Development » IPtables MAC-IP pair match

IPtables MAC-IP pair match

Document Actions
MAC/IP pair matching allows you to match packets based on a list of MAC and IP address pairs. You can use this to help prevent users from changing their IP address to conflict with or spoof other users, and from changing their MAC address (e.g. new network card, MAC spoofing or NAT).

Overview

MAC/IP pair matching allows you to match packets based on a list of MAC and IP address pairs. You can use this to help prevent users from:
  • Changing their IP address to conflict with or spoof other users
  • Changing their MAC address (e.g. new network card, MAC spoofing or NAT)
Note that users can change both their MAC and IP address in order to bypass this protection and spoof another user. You can prevent them from changing their MAC address by using Ethernet switches which support locking certain MAC addresses to certain ports.

By using such switches together with this module, you can lock particular MAC and IP addresses to particular ports on your LAN, detecting spoofing users or prevent them from accessing services through your firewall.

Download

You can download the source code, in the form of a Netfilter Patch-o-Matic patch set, by clicking on the link below:

Usage

To use the module, you must configure it with one or more triples of
<IP address, MAC address, source interface>
For example:
192.168.0.20    00:20:aa:bb:cc:dd    eth0
is such a triple. The module only accepts unique triples, and if you try to add a triple which exactly matches an existing one, the kernel will return an error.

On the other hand, you can add triples which have the same IP address, MAC address or device as an existing entry, as long as all three are not the same. This allows you to add two MAC addresses for a given IP, two IP addresses for a given MAC, or the same IP and MAC on more than one device.

The triple above is interpreted as follows: IP packets with the source IP address 192.168.0.20, and the source MAC address 00:20:aa:bb:cc:dd, received on device eth0, will successfully match with the IPtables match command "-m macmatch --mac --ip" (and also if either --mac or --ip is omitted).

In the case of packets received on a Linux bridge device (e.g. br0), the interface will normally be the name of the bridge device, and not the physical device, similarly to the iptables match "-i <device>". The exception is when the bridge device is configured using ebtables to route the packet rather than bridge it, when the physical device name
is required instead.

To add or remove triples from the module, you must use the /proc interface, by opening /proc/net/ipt_macmatch and writing commands to it. You can find out the current contents of the triple list by reading from the same file.

Commands are of the following forms (with double quotes omitted, and newline characters (0x0a) for "\n"):
"+<ip address> <mac address> <device>\n"
Adds a new triple to the list (the leading "+" is optional).
"-<ip address> <mac address> <device>\n"
Removes an existing triple from the list.
"clear\n"
Removes all existing entries from the list.

Multiple commands may be written without closing and reopening /proc/net/ipt_macmatch. Multiple commands may even be written in the same call to write(), but if one fails, the error will not help you very much to identify which one failed. Commands before the one which failed will have been processed, and commands afterwards will have been ignored.

IP addresses must be in the form of a dotted quad, e.g. 192.168.0.1. MAC addresses must be in the form of six hexadecimal octets, e.g. 00:20:aa:bb:cc:dd. Device names may only include upper and lower case letters, numbers, underscores and full stops.

The format of the commands is very strict. No extra white space is allowed. The three parts of the triple (IP, MAC and device name) must be separated by exactly one space (0x20), and the command must be terminated by exactly one newline (0x0A).

Having opened /proc/net/ipt_macmatch, the write() system call will return a status code which tells you whether the command succeeded. If the
command succeeds, write() will return the number of bytes written, just like a regular file. Otherwise, it may return one of the following errors:

  • EEXIST (file exists)
    The triple which you attempted to add is already in the list
  • ENOENT (no such file or directory)
    The triple which you attempted to remove is not in the list
  • EINVAL (invalid argument)
    The triple is badly formatted
  • EFAULT (bad address)
    The address of the buffer passed to write() is invalid

The /proc/net/ipt_macmatch interface file may only be opened once at a time. Attempting to open it again while it is already open will return the error EINTR (interrupted system call).

The maximum size of the list defaults to 10,000 entries. You can override this by loading the module with the extra parameter "max_entries=X", for example:

modprobe ipt_macmatch max_entries=20000

Entries are allocated one-by-one from the kmalloc() slab, which means that they occupy just over 64 bytes each. Thus the maximum memory usage in the
default configuration is just over 640 kB.

There is currently no support for wildcard IP addresses, MAC addresses or device names. All three must match exactly.

In order to use the list, you will need to use the "macmatch" match of IPtables, like this:

iptables -A FORWARD -m macmatch --mac --ip -j ACCEPT
You must specify one or both of the options "--mac" and "--ip":

--mac
    Match succeeds if the source MAC address of the incoming packet is
    present in the list, with any IP address, and the packet was
    received on any device listed against this MAC address.

--ip
    Match succeeds if the source IP address of the incoming packet is
    present in the list, with any MAC address, and the packet was
    received on any device listed against this IP address.

--mac --ip
    Match succeeds if the source IP, MAC address and device are
    present in the list as a single triple.

Bugs


Using this module on non-Ethernet packets doesn't make any sense, and may behave strangely or crash your machine. At the moment, I test incoming packets like this, in the iptables match function:
    eh = skb->mac.ethernet;
    if (!eh) {
        LOG_DEBUG("packet without ethernet header, skipped");
        return 0;
    }
Please could someone tell me whether this is the best way to check for an Ethernet header, and whether it guarantees that the address length is ETH_ALEN (i.e. six octets). Send e-mail to chris@netservers.co.uk. Thanks.

Enabling debugging mode, by supplying the parameter "debug=1" when loading the module, prints a lot of information in the kernel logs at the KERN_DEBUG level. This will significantly slow down the process of MAC matching, and has been observed to make the machine unstable (oopses, kernel panics). This seems to be related to printing lots of data via printk. If anybody knows what causes this, I'd be very interested to fix it.

The module has not been heavily tested yet, and caution is advised before deployment in production systems.

Credits

This module was developed by Chris Wilson of Netservers in the year 2004. You can reach me at chris@netservers.co.uk, and find this and other free software at  [http://www.firerack.com] and [http://www.netservers.co.uk/gpl].

The module is licensed under the GNU General Public License version 2, or any later version at your option.  This copyright does not cover user programs that use kernel services by normal system calls.

The code is based on ipt_recent.c, which is Copyright 2002-2003, Stephen Frost <sfrost@snowman.net>, and can be found at [http://snowman.net/projects/ipt_recent].

Contains portions of ebt_among.c by Grzegorz Borowiak <grzes@gnu.univ.gda.pl>, part of the ebtables distribution [http://ebtables.sourceforge.net].

Created by chris
Last modified 2005-09-23 10:37 AM