iptables

How iptables Works

iptables works by matching each packet that crosses the networking interface against a set of rules (grouped by chains) to decide what to do (called target).

rules

The iptables firewall operates by comparing network traffic against a set of rules. The rules define the characteristics that a packet must have to match the rule, and the action that should be taken for matching packets.

chains

These rules are organized into groups called chains. A chain is a set of rules that a packet is checked against sequentially. When the packet matches one of the rules, it executes the associated action and is not checked against the remaining rules in the chain.
A user can create chains as needed. There are three chains defined by default. They are:
· INPUT: This chain handles all packets that are addressed to your server.
· OUTPUT: This chain contains rules for traffic created by your server.
· FORWARD: This chain is used to deal with traffic destined for other servers that are not created on your server.

policy

Each chain can contain zero or more rules, and has a default policy. The policy determines what happens when a packet does not match any rule. So policy could also be treated as the last rule in chain.

target

When the defined pattern matches, the action that takes place is called a target.

  • A target can be a final policy decision for the packet, such as accept, or drop.
  • It can also be move the packet to a different chain for processing, or simply log the encounter.
  • There are many options.

IPv4 Versus IPv6

The netfilter firewall that is included in the Linux kernel keeps IPv4 and IPv6 traffic completely separate. For IPv6 traffic, a companion command called ip6tables is used.

Things to Keep in Mind

  • First, we need to make sure that we have rules to keep current connections active if we implement a default drop policy. This is especially important if you are connected to your server through SSH.
  • Another thing to keep in mind is that the order of the rules in each chain matter.
    • Rules near the top of a chain should have a higher level of specificity than rules at the bottom.
    • You should match specific cases first, and then provide more general rules to match broader patterns.
    • If a packet falls through the entire chain (doesn’t match any rules), it will hit the most general rule, the default policy.
    • For this reason, a chain’s default policy very strongly dictates the types of rules that will be included in the chain. A chain with the default policy of ACCEPT will contain rules that explicitly drop packets. A chain that defaults to DROP will contain exceptions for packets that should be specifically accepted.

List Rules

1
sudo iptables -S

Demo output:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
-P INPUT DROP
-P FORWARD DROP
-P OUTPUT ACCEPT
-N ICMP
-N TCP
-N UDP
-A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -m conntrack --ctstate INVALID -j DROP
-A INPUT -p udp -m conntrack --ctstate NEW -j UDP
-A INPUT -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -m conntrack --ctstate NEW -j TCP
-A INPUT -p icmp -m conntrack --ctstate NEW -j ICMP
-A INPUT -p udp -j REJECT --reject-with icmp-port-unreachable
-A INPUT -p tcp -j REJECT --reject-with tcp-reset
-A INPUT -j REJECT --reject-with icmp-proto-unreachable
-A TCP -p tcp -m tcp --dport 22 -j ACCEPT

List Specific Chain

Specify the chain name directly after the -S option.

1
sudo iptables -S INPUT

Demo output:

1
2
3
4
5
6
7
-P INPUT ACCEPT
-A INPUT -s 39.187.179.166/32 -j DROP
-A INPUT -i lo -j ACCEPT
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p tcp -m tcp --dport 22 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 80 -j ACCEPT
-A INPUT -p icmp -m icmp --icmp-type 8 -j ACCEPT

##List Rules as Tables
Listing the iptables rules in the table view can be useful for comparing different rules against each other.

1
sudo iptables -L

This will output all of current rules sorted by chain.

1
sudo iptables -L INPUT --line-numbers

Demo output:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Chain INPUT (policy ACCEPT)
num target prot opt source destination
1 f2b-shadowsocks tcp -- anywhere anywhere multiport dports 6000:6100
2 f2b-mysqld-auth tcp -- anywhere anywhere multiport dports mysql
3 f2b-php-url-fopen tcp -- anywhere anywhere multiport dports http,https
4 f2b-nginx-botsearch tcp -- anywhere anywhere multiport dports http,https
5 f2b-nginx-http-auth tcp -- anywhere anywhere multiport dports http,https
6 f2b-sshd-ddos tcp -- anywhere anywhere multiport dports 7022
7 f2b-sshd tcp -- anywhere anywhere multiport dports 7022
8 DROP all -- 39.187.179.166 anywhere
9 ACCEPT all -- anywhere anywhere
10 ACCEPT all -- anywhere anywhere state RELATED,ESTABLISHED
11 ACCEPT tcp -- anywhere anywhere tcp dpt:ssh
12 ACCEPT tcp -- anywhere anywhere tcp dpt:http
13 DROP tcp -- anywhere anywhere tcp dpt:mysql
14 ACCEPT icmp -- anywhere anywhere icmp echo-request

The first line of output indicates the chain name (INPUT, in this case), followed by its default policy (DROP). The next line consists of the headers of each column in the table, and is followed by the chain’s rules.

  • target: If a packet matches the rule, the target specifies what should be done with it. For example, a packet can be accepted, dropped, logged, or sent to another chain to be compared against more rules
  • prot: The protocol, such as tcp, udp, icmp, or all
  • opt: Rarely used, this column indicates IP options
  • source: The source IP address or subnet of the traffic, or anywhere
  • destination: The destination IP address or subnet of the traffic, or anywhere

The last column, which is not labeled, indicates the options of a rule.

Add Rules

Accept connection on port 22 for ssh:

1
sudo iptables -A INPUT -p tcp --dport 22 -j ACCEPT
  • -A INPUT: The -A flag appends a rule to the end of a chain (here the chain is INPUT). In another side -I INPUT 2 means insert to the 2nd rule of INPUT chain.
  • -p tcp: This option matches packets if the protocol being used is TCP.
  • --dport: This option is available if the -p tcp flag is given. It gives a further requirement of matching the destination port for the matching packet.
  • -j ACCEPT: This specifies the target of matching packets.

Delete Rules

Delete Rule by Specification

For example, if you want to delete the rule that drops invalid incoming packets (-A INPUT -m conntrack –ctstate INVALID -j DROP), you could run this command:

1
sudo iptables -D INPUT -m conntrack --ctstate INVALID -j DROP

Note that the -A option, which is used to indicate the rule position at creation time, should be excluded here.

Delete Rule by Chain and Number

To determine a rule’s line number, list the rules in the table format and add the –line-numbers option:

1
sudo iptables -L --line-numbers

Then run theiptables -D command followed by the chain and rule number.

1
sudo iptables -D INPUT 3

Drop Rules

There’re 2 ways for drop:

  • Set the default policy for chain as ACCEPT. Then if a connection doesn’t march any rules in the chain, it will be accepted.
    • If using this way, need to set drop rule one by one. If missed on, it will be security hole.
  • Set the default policy for chain as DROP. Then if a connection doesn’t march any rules in the chain, it will be dropped.
    • If using this way, only need to set accept rules. All others will be dropped by default. It’s strict but safe.

Set policy of chain to ACCEPT or DROP:

1
2
sudo iptables -P INPUT ACCEPT
sudo iptables -P INPUT DROP

Add a DROP rule in INPUT chain:

1
sudo iptables -A INPUT -j DROP

Block an IP Address

To block network connections that originate from a specific IP address, 15.15.15.51 for example, run this command:

1
sudo iptables -A INPUT -s 15.15.15.51 -j DROP

If you want to reject the connection instead, which will respond to the connection request with a “connection refused” error, replace “DROP” with “REJECT” like this:

1
sudo iptables -A INPUT -s 15.15.15.51 -j REJECT

Show Packet Counts and Aggregate Size

This is often useful when trying to get a rough idea of which rules are matching against packets. For example, let’s look at the INPUT chain again, with the -v option:

1
sudo iptables -L INPUT -v

Example: Verbose Listing

1
2
3
4
5
6
7
8
9
10
11
Chain INPUT (policy DROP 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
284K 42M ACCEPT all -- any any anywhere anywhere ctstate RELATED,ESTABLISHED
0 0 ACCEPT all -- lo any anywhere anywhere
0 0 DROP all -- any any anywhere anywhere ctstate INVALID
396 63275 UDP udp -- any any anywhere anywhere ctstate NEW
17067 1005K TCP tcp -- any any anywhere anywhere tcp flags:FIN,SYN,RST,ACK/SYN ctstate NEW
2410 154K ICMP icmp -- any any anywhere anywhere ctstate NEW
396 63275 REJECT udp -- any any anywhere anywhere reject-with icmp-port-unreachable
2916 179K REJECT all -- any any anywhere anywhere reject-with icmp-proto-unreachable
0 0 ACCEPT tcp -- any any anywhere anywhere tcp dpt:ssh ctstate NEW,ESTABLISHED

Reset Packet Counts and Aggregate Size

They also reset if a reboot occurs. This is useful if you want to see if your server is receiving new traffic that matches your existing rules.

To clear the counters for all chains and rules, use the -Z option by itself:

1
2
3
sudo iptables -Z
sudo iptables -Z INPUT
sudo iptables -Z INPUT 1

Save iptables Configuration

By default, the rules that you add to iptables are ephemeral. This means that when you restart your server, your iptables rules will be gone. The easiest way to save is with the iptables-persistent package.

1
2
sudo apt-get update
sudo apt-get install iptables-persistent

Once the installation is complete, you will have a new service called iptables-persistent that is configured to run at boot. This service will load in your rules and apply them when the server is started.

If you ever update your firewall and want to preserve the changes, you must save your iptables rules for them to be persistent.

1
sudo service netfilter-persistent save

This will overwrite your /etc/iptables/rules.v4 and /etc/iptables/rules.v6 files with the policies you crafted on the command line.

1
2
3
/etc/iptables.rules
/etc/iptables/rules.v4
/etc/iptables/rules.v6

Create Your Own Firewall by iptables

Pre-condititions:

  • Backup existing iptables. Could just copy output of sudo iptables -S, or copy rules saved by iptables-persistent as mentioned above.
  • If you lock yourself from accessing using ssh, make sure you have other ways to access it.

Create Protocol-Specific Chains

1
2
3
sudo iptables -N UDP
sudo iptables -N TCP
sudo iptables -N ICMP

Enable ssh, http, https:

1
2
sudo iptables -A TCP -p tcp --dport 22 -j ACCEPT
sudo iptables -A TCP -p tcp --dport 80,443 -j ACCEPT

Enable other custom service:

1
2
sudo iptables -A TCP -p tcp --dport 8000:8010 -j ACCEPT
sudo iptables -A UDP -p udp --dport 8000:8010 -j ACCEPT

Create General Purpose Accept and Deny Rules

First, we will create an exception to accept all traffic that is part of an established connection or is related to an established connection:

1
sudo iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

Allow all traffic originating on the local loopback interface.

1
sudo iptables -A INPUT -i lo -j ACCEPT

Finally, we want to deny all invalid packets.

1
sudo iptables -A INPUT -m conntrack --ctstate INVALID -j DROP

Creating the Jump Rules to the Protocol-Specific Chains

Direct traffic in the INPUT chain into the appropriate protocol-specific chains.

1
2
3
sudo iptables -A INPUT -p udp -m conntrack --ctstate NEW -j UDP
sudo iptables -A INPUT -p tcp --syn -m conntrack --ctstate NEW -j TCP
sudo iptables -A INPUT -p icmp -m conntrack --ctstate NEW -j ICMP

Reject All Remaining Traffic

If a packet that was passed to a protocol-specific chain did not match any of the rules within, control will be passed back to the INPUT chain. Anything that reaches this point should not be allowed by our firewall. We will deny the traffic using the REJECT target, which sends a response message to the client.

Attempting to reach a closed UDP port will result in an ICMP “port unreachable” message.

1
sudo iptables -A INPUT -p udp -j REJECT --reject-with icmp-port-unreachable

Attempting to establish a TCP connection on a closed port results in a TCP RST response:

1
sudo iptables -A INPUT -p tcp -j REJECT --reject-with tcp-reset

For all other packets, we can send an ICMP “protocol unreachable” message to indicate that the server doesn’t respond to packets of that type:

1
sudo iptables -A INPUT -j REJECT --reject-with icmp-proto-unreachable

Adjusting Default Policies

Set the default policy to DROP as a precaution.

1
2
3
sudo iptables -P INPUT DROP
sudo iptables -P FORWARD DROP
sudo iptables -P OUTPUT ACCEPT

Saving iptables Rules

1
2
3
sudo service netfilter-persistent save
or
sudo /etc/init.d/iptables-persistent save

This will overwrite your /etc/iptables/rules.v4 and /etc/iptables/rules.v6 files with the policies you crafted on the command line.

Test your Firewall Configuration with Nmap and Tcpdump

https://www.digitalocean.com/community/tutorials/how-to-test-your-firewall-configuration-with-nmap-and-tcpdump

Preconditions:

  • Install tcpdump build-essential libssl-dev, nmap

Scan your Target for Open TCP Ports

Setting Up the Packet Capture

1
sudo tcpdump host target_ip_addr -w ~/scan_results/syn_scan/packets

With tcpdump recording our traffic to the target machine, we are ready to run the SYN scan using nmap.

1
sudo nmap -sS -Pn -p- -T4 -vv --reason -oN ~/scan_results/syn_scan/nmap.results target_ip_addr

The results are saved in ~/scan_results/syn_scan/nmap.results.

Scan your Target for Open UDP Ports

Setting Up the Packet Capture

1
sudo tcpdump host target_ip_addr -w ~/scan_results/udp_scan/packets

Run the UDP Scan

1
sudo nmap -sU -Pn -p- -T4 -vv --reason -oN ~/scan_results/udp_scan/nmap.results target_ip_addr

The results are saved in ~/scan_results/syn_scan/nmap.results.

Host and Service Discovery

Discovering the Versions of Services on the Server

1
sudo nmap -sV -Pn -p 22,80 -vv --reason -oN ~/scan_results/versions/service_versions.nmap target_ip_addr

Discovering the Host Operating System

1
sudo nmap -O -Pn -vv --reason -oN ~/scan_results/versions/os_version.nmap target_ip_addr

References