Learning iptables Basics

When a new server is stood up, one of the first things that it undergoes is the formidable process of ‘becoming secure’. During this process, the firewall often becomes the centre of attention for a while – and understandably so. The firewall dictates what traffic is allowed in and out of the server, as well as where the traffic can come in and out from. Kind of like a police officer (the firewall) only allowing a specific type of car (the protocol) to enter the city (the server) on the M2 highway (the port), but denies entry if it’s a different car or the wrong highway. That’s a very simple way of describing it, as you can configure a firewall to do a bunch of stuff. There’s multiple ways to administer a firewall, and I decided to learn some basics using iptables.

Important Note: iptables itself isn’t a firewall. It’s a front end for the Netfilter framework, which is used as a firewall. Put simply, iptables is used to administer Netfilter.

Just quickly, ‘iptables’ is made up of a few tables, the tables are made up of a few chains, and the chains are made up of one or more rules. You can add tables, chains, and rules. As a result, you can get very specific with the configuration – but that’s outside of our scope. We’re dealing with the default table called the Filter Table, which has the default chains INPUT(Inbound packets), OUTPUT (Outbound packets), and FORWARD (Passing through packets). I’ll show you some simple rules that we can use to populate the necessary chains.

A standard default table without any comments or formatting (Please always comment and format your stuff) looks like this:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
*filter
-A INPUT -i lo -j ACCEPT
-A INPUT ! -i lo -s 127.0.0.0/8 -j REJECT
-A INPUT -p icmp -m state --state NEW --icmp-type 8 -j ACCEPT
-A INPUT -p tcp --dport 22 -m state --state NEW -j ACCEPT
-A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
-A INPUT -m limit --limit 5/min -j LOG --log-prefix "iptables_INPUT_denied: " --log-level 7
-A INPUT -j REJECT
-A FORWARD -j REJECT
COMMIT

First up is *filter. This indicates we’re dealing with the Filter table (Which is our default table).

Down the very bottom is COMMIT. This applies everything above it to the table we named at the top. It’s worth noting that these firewall rules get lost on reboot – we just reapply them on start up.

Now for the rules. Each rule follows this system: The parameter, and then the parameters value. This can be repeated as many times as needed. They look like -p value, or --parameter value.
*Note: It’s not a standard, but generally if the parameter name is a single character, it gets a single dash. If it’s at least two characters, it gets two dashes.*

First we need to say which chain we’re appending the rule to. Our parameter is -A (A for Append), and our value is the chain. Lines 2 through 8 are -A INPUT because we’re appending the rule to theINPUT chain. Just like line 9 is -A FORWARD because we’re appending it to the FORWARD chain.

This is where things don’t really look the same, but it’s still just a parameter and then the value. The parameter will be in (round brackets), and the parameter value will be in [square brackets].
*Note: ! means ‘not’. So if it’s not the interface named, for example.*

1
2
3
! (-i) [lo] (-s) [127.0.0.0/8] (-j) [REJECT]
(-p) [icmp] (-m) [state] (--state) [NEW] (--icmp-type) [8] (-j) [ACCEPT]
(-m) [limit] (--limit) [5/min] (-j) [LOG] (--log-prefix) ["iptables_INPUT_denied: "] (--log-level) [7]

Now that you can read it, the next part is figuring out what each piece does. There’s not much point in me rehashing what each parameter accepts and does, as it’s already documented thoroughly. If you are interested, two good resources are the iptables manual page and the netfilter iptables page.

Here’s a quick description of some common parameters:

  • -i specifies the name of an interface in which a packet was received.
  • -j specifies what happens if a packet matches. (jump – this is always at the end of the rule)
  • -s specifies a source address.
  • -p specifies a protocol.
  • -m specifies a match to use.

To bring everything together, below is what a useful, tidy, and strict Filter table looks like. Feel free to use it. It’s modified from the Debian iptables page. As with all things, make sure you know what it does before you use it.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
*filter

# Allow all loopback (lo0) traffic and reject traffic
# to localhost that does not originate from lo0.
-A INPUT -i lo -j ACCEPT
-A INPUT ! -i lo -s 127.0.0.0/8 -j REJECT

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

# Allow SSH connections.
-A INPUT -p tcp --dport 22 -m state --state NEW -j ACCEPT

# Allow inbound traffic from established connections.
# This includes ICMP error returns.
-A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

# Log what was incoming but denied (optional but useful).
-A INPUT -m limit --limit 5/min -j LOG --log-prefix "iptables_INPUT_denied: " --log-level 7

# Reject all other inbound.
-A INPUT -j REJECT

# Reject all traffic forwarding.
-A FORWARD -j REJECT

COMMIT