Working with IPFire

Nov 1, 2015 18:00 ipfire

Deciding upon an open source firewall to secure your network can be difficult. This is partly because there are so many great options to choose from. I personally like to change it up every now and then: sometimes I’m running IPFW on FreeBSD, other times VyOS and I used to run m0n0wall a lot before the project shutdown. One of the reasons I keep coming back to IPFire though, is because it seems to have the fewest abstractions compared to some other firewall distros. In some instances abstractions are great. Very often they can save you from making silly mistakes or having to learn the ugly internals of how different kernel APIs work. However, they sometimes just get in your way when all you want to do is hack.

IPFire ships with a web UI which is typically used to configure the system. But, unlike some other tools out there it also gives you (relatively easy) access to the underlying Linux that you know and love. Sometimes I’m OK with using the web UI but other times, like when I’m configuring a massive rule set, I can work more quickly and efficiently by going straight to the command line. Knowing that this is a fairly popular sentiment, the project’s maintainers included a simple way to do just that. The maintainers included several custom chains (CUSTOMINPUT, CUSTOMOUTPUT, CUSTOMFORWARD, CUSTOMPREROUTING and CUSTOMPOSTROUTING) which are positioned at just the right places to make sure that they are the first chains to be traversed by packets. Equally important is the file located at /etc/sysconfig/firewall.local where one can add their own custom firewall rules without needing to use the web UI. The file looks similar to an init script with its start, stop and reload actions. Everytime the firewall comes up (or goes down), this script will be called and your rules processed. Careful though: there are no abstractions here so you’d better be handy with writing IPTables rules and have a solid hold on shell scripting before hacking this file up.

I’ll go over the following scenarios as they pertain to firewall.local :

  • Allowing traffic between the different networks on the firewall
  • Exposing a service publicly
  • Filtering egress packets

Allowing traffic between the different networks on the firewall

Let’s say we want to allow tcp traffic over port 443 from the blue network to a host on the green network:

...
case "$1" in
  start)
    iptables -A CUSTOMINPUT -i blue0 -p tcp --dport 443 -s <HOST-ON-BLUE-IP> -d <HOST-ON-GREEN-IP> \
	  -j ACCEPT -m comment --comment "Allow HTTPS access from foo.blue to bar.green"
...

Exposing a service publicly

Suppose we’d like to expose a Jabber server running on a host on the orange network to the world. This time, we’ll need to create both a source NAT (SNAT) and a forwarding rule which allows traffic to reach it’s desired destination:

...
case "$1" in
  start)
    iptables -t nat -A CUSTOMPREROUTING -i red0 -p tcp --dport 5222 -j DNAT --to <HOST-ON-ORANGE-IP>
    iptables -A CUSTOMFORWARD -p tcp --dport 5222 -d <HOST-ON-ORANGE-IP> \
	  -j ACCEPT -m comment --comment "Expose Jabber to the world"
...

Filtering egress packets

In this example, we’ll prevent hosts on the orange network from using any DNS servers other than Level3’s public DNS servers:

...
case "$1" in
  start)
    for p in tcp udp; do
      iptables -A CUSTOMFORWARD -i orange0 -p $p --dport 53 -m iprange ! --dst-range 209.244.0.3-209.244.0.4 \
	    -j REJECT -m comment --comment "Hosts on orange net can only use Level3 for DNS"
    done
...

‘stop’ rules

Making sure that your custom chains get cleaned up when the firewall stops, starts or reloads will save you a lot of headache when trying to troubleshoot your rules. This should suffice:

...
  stop)
    for c in CUSTOMINPUT CUSTOMOUTPUT CUSTOMFORWARD; do
      iptables -F $c
      iptables -Z $c
    done
    for c in CUSTOMPREROUTING CUSTOMPOSTROUTING; do
      iptables -t nat -F $c
      iptables -t nat -Z $c
    done
...