Dev Notes

Various Cheat Sheets and Resources by David Egan/Carawebs.

iptables Ubuntu Firewall

Linux, Security, Ubuntu
David Egan

iptables is a firewall programme that allows you to control server traffic on a Linux system.

By default, iptables allows all traffic.

Note: UFW is the default firewall configuration tool for Ubuntu - UFW (disabled by default) can simplify firewall setup.

Display iptables Info

# Quick list
sudo iptables -S

# iptables list with numbered lines
iptables -nL --line-numbers

Add Rules

The -A flag denotes that the rule will be appended - added as the last rule in the chain.

The -I flag denotes that the rule will be inserted - the precise line-number for insertion can also be controlled.

# Allow connection on post 80 by appending a rule
sudo iptables -A INPUT -p tcp -m tcp --dport 80 -j ACCEPT

# Allow incoming traffic on the default SSH port(22):
sudo iptables -A INPUT -p tcp --dport ssh -j ACCEPT

# Allow SSH connection on a non-standard port (1234)
sudo iptables -A INPUT -p tcp -m state --state NEW -m tcp --dport 1234 -j ACCEPT

# Allow ping from a specified IP address, inserted at a specific line in the chain:
sudo iptables -I INPUT 9 -s x.x.x.x -p ICMP --icmp-type 8 -j ACCEPT

# Insert a rule as the first rule in the INPUT chain
# This rule allows already established (and related) connections
iptables -I INPUT 1 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT

Delete Rules

Delete a rule in a chain using the -D option. You need to specify the chain, and the rule. The rule is either specified by entering the whole rule to match, or the line number of the rule to delete. Rules are numbered from the top of each chain, starting with 1.

# Delete by specifying rule
sudo iptables -D INPUT -p tcp -m tcp --dport 80 -j ACCEPT

# Delete by specifying the line number in the INPUT chain - deletes the 9th rule in the chain
sudo iptables -D INPUT 9

View iptables Log

Logs are generated by the kernel, so they go to the file that receives kernel logs: /var/log/kern.log.

To view iptables denial in real time, run:

tail -f /var/log/kern.log

Blocking an IP

To block an attackers ip address (e.g. enter:

iptables -A INPUT -s -j DROP
iptables -A INPUT -s -j DROP

Make iptables Rules Persistent

The iptables rulesets are held in memory, which means that they are not persistent across system reboots.

The easiest way to persist rules on Ubuntu is probably the iptables-persistent package.

To install:

sudo apt-get install iptables-persistent

# Start the service!
sudo service iptables-persistent start

After starting, new ruleset files will be created: /etc/iptables/rules.v4 and /etc/iptables/rules.v6. These contain IPv4 and IPv6 rules respectively.

After amending iptables (or ip6tables), save changes to those files:

sudo iptables-save | sudo tee /etc/iptables/rules.v4
sudo ip6tables-save | sudo tee /etc/iptables/rules.v6

# Restart service to read the changes in:
sudo service iptables-persistent start


Import or Restore a Ruleset

# Save ruleset
sudo iptables-save > /tmp/ruleset-v4
sudo ip6tables-save > /tmp/ruleset-v6

# Restore ruleset
sudo iptables-restore < /tmp/ruleset-v4
sudo ip6tables-restore < /tmp/ruleset-v6

There is a good basic ruleset from Linode here.

Sample iptables Ruleset

Restoring this ruleset may provide a decent starting point. The default policy is DROP - this means that the rules contain exceptions - if the specific condition is met, the packet is accepted.

The ruleset below allows:

  • Loopback traffic
  • Inbound traffic from established connections
  • HTTP & HTTPS connections (internet)
  • SSH connection on a custom port number
# Allow all loopback traffic (lo0)
-A INPUT -i lo -j ACCEPT
# Reject traffic to localhost that doesn't originate from lo0
-A INPUT ! -i lo -s -j REJECT

# Allow inbound from established connections
-A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT

# Allow HTTP and HTTPS connections from anywhere
-A INPUT -p tcp -m tcp --dport 80 -j ACCEPT
-A INPUT -p tcp --dport 443 -m state --state NEW -j ACCEPT

# Allow ping from the home server only
-A INPUT -s -p icmp -m icmp --icmp-type 8 -j ACCEPT

# Allow SSH traffic on custom port 4321
-A INPUT -p tcp -m state --state NEW -m tcp --dport 4321 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 4321 -j ACCEPT

# If the packet has made it this far without being accepted, it's going to be
# dropped. The logging chain will record some data about the packet first.
# The relevant log file is `/var/log/kern.log`.
-A LOGGING -p icmp -m limit --limit 5/min -j LOG --log-prefix "iptables-denied ICMP: " --log-level 7
-A LOGGING -p udp -m limit --limit 5/min -j LOG --log-prefix "iptables-denied UDP: " --log-level 7
-A LOGGING -p tcp -m limit --limit 5/min -j LOG --log-prefix "iptables-denied TCP: " --log-level 7

Notes Re iptables and UFW

If iptables rules have been added, they will appear before the UFW rules - and the first rules will take precedence.

Packets drop through a chain of rules. If the iptables INPUT chain rule has a default drop policy, it matches every remaining packet that reaches it. With iptables, order is important. The first rule that natches a packet of data is the one that will be applied.

Once a decision is made to accept a packet, no more rules affect it. As our rules allowing ssh and web traffic come first, as long as our rule to block all traffic comes after them, we can still accept the traffic we want. All we need to do is put the rule to block all traffic at the end.

Ubuntu Community iptables HowTo

Procedure to Flush Rules

If you need to flush firewall rules, first ensure that the remote connection can be maintained:

# Set default policies to "ACCEPT"
sudo iptables -P INPUT ACCEPT
sudo iptables -P FORWARD ACCEPT
sudo iptables -P OUTPUT ACCEPT

# Flush the `nat` and `mangle` tables:
sudo iptables -t nat -F
sudo iptables -t mangle -F

# Flush all chains
sudo iptables -F

# Delete all non-default chains
sudo iptables -X

If you’ve been trying UFW, you may end up with a number of extraneous statements prepended “ufw-“. To remove these:

# Remove ufw rules from iptables
sudo iptables -D ufw-after-forward
sudo iptables -X ufw-after-forward
sudo iptables -X ufw-after-input
sudo iptables -X ufw-after-logging-forward
sudo iptables -X ufw-after-logging-input
sudo iptables -X ufw-after-logging-output
sudo iptables -X ufw-after-output
sudo iptables -X ufw-before-forward
sudo iptables -X ufw-before-input
sudo iptables -X ufw-before-logging-forward
sudo iptables -X ufw-before-logging-input
sudo iptables -X ufw-before-logging-output
sudo iptables -X ufw-before-output
sudo iptables -X ufw-reject-forward
sudo iptables -X ufw-reject-input
sudo iptables -X ufw-reject-output
sudo iptables -X ufw-track-forward
sudo iptables -X ufw-track-input
sudo iptables -X ufw-track-output

You might need to do something similar for ip6tables. Bash script for this procedure.


comments powered by Disqus