7

I'm trying to figure out how NAT and iptables work. While I'm in the trial-and-error phase of learning about it, I found two somewhat conflicting howtos.

One howto uses a script to call iptables rules one after another. The script seems to be named and stored such that it is executed early during system boot, and I think a problem may be that other scripts may be called after it and undo its intentions. I even think I did this once by accident when I saved and renamed the original script (00-firewall) using a backup (00-firewall-old). The example script form the howto is:

#!/bin/sh

PATH=/usr/sbin:/sbin:/bin:/usr/bin

#
# delete all existing rules.
#
iptables -F
iptables -t nat -F
iptables -t mangle -F
iptables -X

# Always accept loopback traffic
iptables -A INPUT -i lo -j ACCEPT


# Allow established connections, and those not coming from the outside
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A INPUT -m state --state NEW -i ! eth1 -j ACCEPT
iptables -A FORWARD -i eth1 -o eth0 -m state --state ESTABLISHED,RELATED -j ACCEPT

# Allow outgoing connections from the LAN side.
iptables -A FORWARD -i eth0 -o eth1 -j ACCEPT

# Masquerade.
iptables -t nat -A POSTROUTING -o eth1 -j MASQUERADE

# Don't forward from the outside to the inside.
iptables -A FORWARD -i eth1 -o eth1 -j REJECT

# Enable routing.
echo 1 > /proc/sys/net/ipv4/ip_forward

Another howto does not use a script but a file where some filter rules are defined. It looks like this:

*filter

# Allows all loopback (lo0) traffic and drop all traffic to 127/8 that doesn't use lo0
-A INPUT -i lo -j ACCEPT
-A INPUT ! -i lo -d 127.0.0.0/8 -j REJECT

# Accepts all established inbound connections
-A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

# Allows all outbound traffic
# You could modify this to only allow certain traffic
-A OUTPUT -j ACCEPT

# Allows HTTP and HTTPS connections from anywhere (the normal ports for websites)
-A INPUT -p tcp --dport 80 -j ACCEPT
-A INPUT -p tcp --dport 443 -j ACCEPT

# Allows SSH connections 
# THE -dport NUMBER IS THE SAME ONE YOU SET UP IN THE SSHD_CONFIG FILE
-A INPUT -p tcp -m state --state NEW --dport 30000 -j ACCEPT

# Now you should read up on iptables rules and consider whether ssh access 
# for everyone is really desired. Most likely you will only allow access from certain IPs.

# Allow ping
-A INPUT -p icmp -m icmp --icmp-type 8 -j ACCEPT

# log iptables denied calls (access via 'dmesg' command)
-A INPUT -m limit --limit 5/min -j LOG --log-prefix "iptables denied: " --log-level 7

# Reject all other inbound - default deny unless explicitly allowed policy:
-A INPUT -j REJECT
-A FORWARD -j REJECT

COMMIT

What are the pros and cons of both ways of setting up iptables? Background info is much appreciated because I'm quite new to the whole thing. For example, I don't get who is reading the file from the latter howto, and how it is processed. My feeling tells me the second howto suggests a better solution, but why exactly?

3 Answers 3

5

I've used both techniques in the past. These days, I'm gravitating towards a hybrid of the two.

If your ruleset has five or six simple rules, either method is fine. Things start to become interesting when you have big rulesets: large installations, your firewalling box does a bit of routing, etc.

Just remember, you can shoot yourself in the foot no matter how you load your rulesets. :)

Script-Based

You make a bash script, a Perl script, a Python script — hell, write a Lisp or Befunge program for all anyone cares! In the script, you create all the Netfilter rules you want.

The upsides:

  • Directness. You're experimenting with rules, and you just copy and paste the ones that work from the command line straight to the script.
  • Dynamic firewalling. One client of mine runs OpenVPN setups for their own clients, and each client gets their own instance of OpenVPN for security, firewalling and accounting reasons. The first-line-of-defence firewall needs to open the OpenVPN ports dynamically for each (IP,port) tuple. So the firewalling script parses the manifest of OpenVPN configs and dynamically pokes the required holes. Another one stores web server details on LDAP; the iptables script queries the LDAP server, and automatically allows ingress to the web servers. On large installations, this is a great boon.
  • Cleverness. My firewall scripts allow remote administration, even without lights out management: after the ruleset is loaded, if the operator doesn't respond within a couple of minutes, the ruleset is rolled back to the last one known to work. If for some reason that fails too, there's a third (and fourth) failback of decreasing security.
  • More cleverness: you can open up SSH access to your netblock at the beginning of the script, then rescind it at the end of the script (and let filtered SSH sessions in). So, if your script fails, you can still get in there.
  • Online examples. For some reason, most of the examples I've seen online used invocations of iptables (this may be influenced by the fact my first few firewall setups predated iptables-save, and also Netfilter — but that's another story)

The downsides:

  • One syntax error in the script and you're locked out of your firewall. Some of the cleverness above is down to painful experiences. :)
  • Speed. On embedded Linux boxen, a bash (or even dash) script will be a slow, slow thing to run. Slow enough that, depending on your security policy, you may need to consider the order of rule addition — you could have a short-lived hole in your defences, and that's enough. Ruleset loading is nowhere near atomic.
  • Complexity. Yes, you can do amazing things, but yes, you can also make the script too complex to understand or maintain.

Ruleset-Based

Add your rules to a ruleset file, then use iptables-restore to load it (or just save your existing ruleset using iptables-save). This is what Debian does by default.

The pros:

  • Speed. iptables-restore is a C program, and it's deliciously fast compared to shell scripts. The difference is obvious even on decent machines, but it's orders of magnitude faster on more modest hardware.
  • Regularity. The format is easier to understand, it's essentially self-documenting (once you get used to Netfilter's peculiarities).
  • It's the Standard Tool, if you care about that.
  • It saves all the Netfilter tables. Too many Netfilter tools (including iptables) only operate on the filter table, and you could forget you have others ones at your disposal (with possibly harmful rules in them). This way, you get to see all the tables.

The cons:

  • Lack of flexibility.
  • With a lack of templating/parametrisation/dynamic features, repetition can lead to less maintainable rulesets, and to huge ruleset bugs. You don't want those.

A Hybrid Solution — Best of Both Worlds

I've been developing this one for a while in my Copious Free Time. I'm planning on using the same script-based setup I have now, but once the ruleset is loaded, it saves it with iptables-save and then caches it for later. You can have a dynamic ruleset with all its benefits, but it can be loaded really quickly when, e.g., the firewall box reboots.

1

One looks like the output of iptables-save and consequently the input for iptables-restore which are used to save and restore (eg at system boot) the current state of the netfilter firewall.

The iptables command manipulates the netfilter firewall. It can be used to make a single change in the live firewall configuration, eg the addition of a single rule, but also modify or delete rules.

so you create the configuration you desire with iptables, then save the resulting config with iptables-save. And do a restore of that configuration after reboot.

Or script the iptables commands you used to make that firewall: The -F switch clears the firewall creating a blank slate and subsequently adding rules in a script is an alternative to using the iptables-restore command with should result in a similar end state.

1

I agree with @zebonaut in that you need to consider carefully to ensure that your firewall/router is adequately protected during startup, and also during loading the rules. I ended up building my own firewall creation scripts, and when I've tested it I copy to a firewall.working script, if the two differ then a cron job runs the working one. So if I get locked out I can get back in. This is very rare now since the first rules permit established/related traffic. I have a different sub chain for each interface for forwarding and input, it makes debugging easier.

I have a separate settings file which enables/disables certain accesses, the settings file is flipped between day and night mode by cron to lock my children out of the internet when they should be in bed sleeping! Naturally I can also override and lock them out anytime I want :-)

The same script handles ipv4 and ipv6. If I use a hostname, I put it in /etc/hosts or the settings file rather than rely on DNS, because if DNS breaks the firewall config would break.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .