How to restrict Internet access to known IP/MAC on OpenWRT?

I decided to restrict Internet access from my LAN to known IP/MAC pairs only. Primary to block Internet access from my PS3, virtual machines and computers that do not need it. Simplest way to achieve this on Linux: filter packet coming from LAN interface in FORWARD chain.

On OpenWRT custom firewall rules can be defined in /etc/firewall.user. Before creating rules we need some method to create and (easily) maintain IP/MAC pairs. I decided t use /etc/ethers and /etc/hosts that already contains MACs, hostnames nad IPs (used by dnsmasq).

On my router I have /etc/ethers in format:

00:11:11:11:11:12 stargate
00:22:22:22:22:23 techie
00:33:33:33:33:34 tortoise
...

And /etc/hosts:

127.0.0.1 localhost OpenWrt
...
10.0.0.2 stargate
10.0.0.5 techie
10.0.0.14 tortoise
...

The only problem I found is parsing all those information in a simple way (eg. in a one line of sh/awk/perl/whatever script). Perl is not available in default installation of OpenWRT. SH cannot easily handle text files. Finally awk with grep seems to be really simple and efficient:

(awk '{ printf "iptables -A forwarding_rule -i br0 -m mac --mac-source " $1 " -s " ; \
 cmd = "cat /etc/hosts | grep " $2 ; cmd | getline ; print $1 " -j ACCEPT" }'
/etc/ethers ; \
 echo "iptables -A forwarding_rule -i br0 -j DROP")

This command (script?) parses /etc/ethers and /etc/hosts and creates firewall rules on standard output:

iptables -A forwarding_rule -i br0 -m mac --mac-source 00:11:11:11:11:12 -s 10.0.0.2 -j ACCEPT
iptables -A forwarding_rule -i br0 -m mac --mac-source 00:22:22:22:22:23 -s 10.0.0.5 -j ACCEPT
iptables -A forwarding_rule -i br0 -m mac --mac-source 00:33:33:33:33:34 -s 10.0.0.14 -j ACCEPT
iptables -A forwarding_rule -i br0 -j DROP

Now it is easy to attach it to OpenWRT firewall in /etc/firewall.user. Just after flush rules insert:

# Forward only traffic from known clients

(awk '{ printf "iptables -A forwarding_rule -i br0 -m mac --mac-source " $1 " -s " ; \
 cmd = "cat /etc/hosts | grep " $2 ; cmd | getline ; print $1 " -j ACCEPT" }'
/etc/ethers ; \
 echo "iptables -A forwarding_rule -i br0 -j DROP") | sh

Note “| sh” at the end of command. This is needed to execute created rules.

Finally reload firewall rules:

/etc/init.d/S35firewall start

Try to access any Internet hosts from allowed and blocked (any not allowed) clients. Than check if it works:

iptables -vxL forwarding_rule

2 thoughts on “How to restrict Internet access to known IP/MAC on OpenWRT?”

  1. Great tip, thanks. I recycled it for the opposite purpose: blocking a few heavy freeloader from accessing my guest network (not password protected, but only for decent people).

    Openwrt Chaos Calmer r43143, in the firewall -> custom rules LuCI config page:

    # This file is interpreted as shell script.
    # Put your custom iptables rules here, they will
    # be executed with each firewall (re-)start.

    # block all mac addresses in /etc/roguemaclist.txt from the guest interface
    # disable by commenting the awk | sh command below

    # the file /etc/roguemaclist.txt has the format
    # symbolic-name1 mac-address1
    # symbolic-name2 mac-address2
    # ….

    (awk ‘{printf “iptables -A forwarding_rule -i br-guest -m mac –mac-source ” $2 ” -j DROP\n”}’ /etc/roguemaclist.txt) | sh

    Unfortunately, this iptables version won’t understand the –comment option, otherwise that could have been

    (awk ‘{printf “iptables -A forwarding_rule -i br-guest -m mac –mac-source ” $2 ” –comment \”Block ” $1 “\” -j DROP\n”}’ /etc/roguemaclist.txt) | sh

    Thanks again! :-)

  2. Instead of generating a script and pipe that to sh, you can also do:

    while read mac host; do
    iptables … –mac-source $mac;
    done < /etc/ethers

    which is a bit easier to parse for humans

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.