Improved IPtables Tutorial
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