Intro

iptables (ipt) is a packet filter for Linux. A packet filter inspects parameters of traffic against a list of well-defined rule in order to decide whether to allow traffic through a network interface

Chains

  • INPUT: Protects listening sockets/services from receiving undesired traffic from external sources
  • OUTPUT:
    Prevents local processes/users from initiating unwanted communication
  • FORWARD: Provides a set of rules for routing traffic where our host is neither the src nor dst

Logic

IPT inspects each packet one by one, examining various parameters and checking for matches against a list of rules, sequentially. A final decision is made on the first match. Each examination adds a certain amount of latency due to the processing power required by the system. This becomes relevant on low performance systems or those processing large volumes of traffic.

Stateful rules

IPT is a stateful firewall. This means it keeps a table of active connections and can identify traffic that is part of an existing session compared with traffic that is unsolicited.

We need to begin our rules with an "allow state established" statement.
This example demonstrates why:

iptables -A FORWARD -i $inside -o $outside \
-p icmp --icmp-type echo-request -j ACCEPT

iptables -A FORWARD -i $outside -o $inside -j DROP

Although our pings were actually sent out, we don't see any replies.
This is because the replies entering via the outside interface and are therefore being blocked.

For illustration, lets create an explict stateful rule

iptables -I FORWARD -i $outside -o $inside \
-p icmp --icmp-type echo-reply \
-m state --state ESTABLISHED,RELATED -j ACCEPT

By making the rules stateful, the system knows the echo-replies being received on eth1 are to be allowed because they are associated with an active session. We do this by inserting the following

Rather than creating a bunch of rules like the one above, we instead add a single rule at the top of the chain to catch established traffic

iptables -I INPUT   -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -I FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT

Host examples

These are rules pertaining to a standard workstation/desktop rather than a gateway or router

Quickly secure a new system

If I'm on a freshly installed server, this is the very first command I run. This immediately stops any traffic from being received on eth0 that doesn't originate from my home IP.

iptables --append INPUT -i $external -m state --state NEW ! --src $trusted-j DROP

Nb: If you don't know your home ip, ${SSH_CLIENT%% *} stores the src address of the active session (assuming you're connected on ssh)

Allow the host to respond to ping

iptables --append INPUT -p icmp --icmp-type echo-request -j ACCEPT

Prevent two way communication with a specific IP

This is based on the stateful firewall theory talked about earlier.
Almost all communication on the internet is two way in nature; a request and response. This will DROP any unsolicited requests from the target. Connections from our local machine to our target will TIMEOUT because the connecting process won't see the target's replies.

iptables --insert INPUT --src malware-cac.example.com -j DROP

For this to work, you must use -I rather than -A because we want it to supersede the rules accepting ESTABLISHED state traffic

Gateway/Router/Firewall Examples

Allow a subset of ICMP types to be forwarded

for type in echo-request echo-reply destination-unreachable parameter-problem time-exceeded source-quench; do sudo iptables -I FORWARD -p icmp --icmp-type $type -j ACCEPT; done

Drop traffic from internal hosts to a particular IP

iptables --append FORWARD -i $internal --dst oca.telemetry.microsoft.com -j DROP

Nb: This is not sufficient to completely block windows telemtry

Accept traffic from anywhere to an endpoint on the DMZ

iptables --append FORWRD -o $dmz --dst webserver.dmz.lan -p tcp --dport 80 -j ACCEPT

Accept traffic from DMZ only to a whitelisted IP

iptables --append FORWARD -i $dmz ! --dst syslog.example.lan  -j DROP

Tips

Don't be a fool :)

A fool SSH's into an active system and writes firewall rules on the fly, accidently locks themselves out while leaving the system exposed with an incomplete firewall policy. Taking this approach can be forgiven on a personal box but not on live business assets.

Keep templates and use a testing vm to experiment with policies. Once your policy is working as expected during testing, create a template for later use on your systems.

Doing this saves you a lot of time and reduces errors.

It's only one piece of the security puzzle

Firewalls are a useful and important component of network security but other controls should be present too.

These include things like ensuring ensuring that SSH uses only PubKeyAuthentication and respecting the rule of least privilege.

Pay attention to the sequential order of rules:

Due to the sequential nature of iptables, the line number of the rules matters. Later in this document we will show commands for adding and inserting rules

Understand Default targets:

Each one of the three default chains have a default option of ACCEPT/DROP which applies to packets that do not match any rules. As long as your logic is sound, both DROP/ACCEPT are good options for iptables -P. On my systems, I usually have a default target of ACCEPT but write rules that are effectively deny by default

They have trade-offs. A default policy of DROP may encourage creating overly liberal rules to ACCEPT traffic while a default policy of ACCEPT makes accidental omissions more likely.

Lastly, a default policy of DROP can lead to a less concise rule set because you have to add many specific exemptions.

Negative statements are useful:

IPT are based on simple logic and for every rule has logically equivalent contrapositive. Negative statements take practice but can sometimes be very clear and are best suited for creating DROP rules when you have a default policy of ACCEPT

iptables -A FORWARD --src 10.4.20.1 ! --dst 10.3.14.1 -j DROP