New Media has a number of development servers located in-house where we get stuff done before releasing it out into the wild. Until last week these were protected by an aging OpenBSD firewall running packet filter and all was well until midweek when the motherboard failed. Not having a spare on hand, I was scrambling for a solution.
Being familiar with the dd-wrt project, I was pretty sure I could build a firewall out of a Linksys router. We went with the WRT54GL, currently as cheap as $50 on Amazon. (We bought local so we’d have it sooner, and it was a bit more).
The first step after flashing the firmware with the latest dd-wrt build (v24-sp2) was to take off the antennas and turn off the radio. The last thing I want for the firewall is to be broadcasting an SSID and allow wireless associations. This actually requires a startup script on the router, with a line to remove the wireless module so it won’t try to reenable itself:
wl radio off wl down rmmod wl
Good start. Next I needed to bridge the WAN port with the LAN ports, which ended up being a struggle until I found the easy options in the dd-wrt GUI. First, set the LAN to use a static IP and make sure you can connect via another machine to configure it. You’ll also need to enable SSH access and remote configuration – but be sure to lock this down once the firewall is running!
Once you have the LAN configured, you need to set the WAN connection type to “disabled”. This will give you a checkbox to bridge the LAN and WAN: “Assign WAN port to switch”. Lastly, under Advanced Routing set the Operating Mode to “Router” so it stops trying to do NAT. Apply these settings, and you’ll basically have an expensive dumb switch – all traffic shows up on every port, and there’s no logic at all. We’re halfway there.
Being unfamiliar with iptables (we use OpenBSD and pf for firewalls around here), I was under the impression that iptables rules would work in a bridging environment. This is not the case: bridged packets don’t reach iptables at all! The best I could do was block everything (manual restart needed), or otherwise blow up the configuration (manual restart needed) as I tried to mess with the bridge. This was an incredibly frustrating learning curve as everything I could find made it sound like this was the way to configure a firewall in Linux, but it just wasn’t working.
Note to keep you sane: don’t do any of this testing in the startup scripts or you’ll brick your router, guaranteed. Do it all from the command line with a known-good startup. That way it’s a simple (but annoying) power cycle to get things back up.
The trick, it turns out, is a kernel module called ebtables. Luckily, this is included in the dd-wrt build, but it’s not turned on by default! Add this to your startup script:
insmod ebtables insmod ebtable_filter insmod ebt_ip.o
And, ta-da, all your iptables rules will start impacting packets! Now it’s just a matter of configuring the firewall rules. We’re using something like this: (vlan0 represents the LAN ports, and vlan1 is the WAN port)
# drop everything by default: iptables -P FORWARD DROP # clear the old rules: iptables -F FORWARD # forward stuff that's established already iptables -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT # let connections out: iptables -A FORWARD -i vlan0 -m state --state NEW -j ACCEPT # firewall access rules iptables -F INPUT # WAC ips can get to fw: iptables -A INPUT -p tcp -d 220.127.116.11 -s 18.104.22.168/24 -j ACCEPT # drop everything else! iptables -A INPUT -p tcp -d 22.214.171.124 -j DROP # ... snipped all the actual access rules and packet flood protection ...
The only trick here is the last few lines which limit access to the firewall machine itself. We can’t use the FORWARD rules since these packets are destined for the internal hardware and not forwarded, but we do need to limit access via the INPUT chain. In this example the firewall has IP 126.96.36.199 and the network I want to access it from has 4.3.2.x. That way I can leave the firewall’s remote access turned on and limit it to our network. (because there’s no terminal access you can’t make it a truly transparent bridge or you’d never be able to change the config!)
I admit I’m a bit nervous posting some of this in case there’s a glaring security hole, but it seems good to me. Anyone see anything they’d like to warn me about before we get hacked?
And there you have it! For the cost of a cheap router and some time (not much, since you can just follow these notes!) you have a full-featured bridging firewall running on dedicated hardware. With a little extra work it would be easy to get VPN running and much more… I’m hoping for years of service from this little guy!
( Hat tip another DIY firewall solution that I’d really like to try someday. )