Published: Mon 07 September 2020

In content.

- "blog-posts"

iptables for GNU/Linux client machine

Note: This article is written for fully patched Ubuntu 18.04 LTS GNU/Linux machine running latest kernel. The ruleset that comes with this article should work with other GNU/Linux derivatives.

This article assumes reader has some knowledge in Firewalls and it’s concepts, OSI Model, TCP/IP stack, and network related tools such as Wireshark and tcpdump.

iptables Introduction

The iptables firewall was developed by the Netfilter Project1 and has been available to the masses as part of GNU/Linux since the release of the Linux 2.4 kernel in January 2001. Over the years, iptables has evolved into a formidable firewall with functionalities typically found in proprietary commercial firewalls. iptables provide comprehensive protocol state tracking, packet application layer inspection, rate limiting, and powerful mechanism to specify a filtering policy(Rash, M., 2007).

For more information on iptables, read page 10 in Linux Firewalls by No Starch Press.

Packet Filtering with iptables

iptables can be a a powerful tool if understood well. A powerful policy can be implemented within iptables and not a single packet will be left checked unless a targeted attack happens to your machine/server.

An iptables policy is built from ordered set of rules, which tells the kernel what to do with the packet. Each iptables rule is then applied to a chain within a table. An iptables chain is a collection of rules that are compared(Rash, M., 2007).


A table is an iptables construct that outline broad categories of functionality, such as packet filtering or NAT (Network Address Translation). There are 4 tables: filter,nat,mangle and raw. Filtering rules are applied to the filter table, NAT rules are applied to the nat table, special rules that alter packet data are applied to mangle table and rules that are independent of the Netfilter connection-tracking subsystem are applied to the raw table(Rash, M., 2007).


Each table has its own set of built-in chains, and user-defined chains can also be added. This can be expended with common tags such as DMZ_NETWORK. The most important built-in chains are the INPUT, OUTPUT and FORWARD chains.

  • INPUT chain is crossed by packets that are destined for the local Linux System.
  • OUTPUT chain is reserved for packets that goes out of the Linux system.
  • FORWARD chain determine packets that are routed through the Linux system. For example, when the iptables firewall is used to connect one network to another and packets between the two networks must flow through the firewall.

There are two additional chains that are important for any serious iptables deployment. They are PREROUTING & POSTROUTING, found in nat table, which used to modify packet headers before and after IP routing calculation is made within the kernel.

Image below illustrates how a packet passes through the nat and filter tables within the kernel.



Every iptables rule has a set of matches along with a target that tells iptables what to do with the packet that obey to the rule. An iptables match is a condition that must be met by any packet in order for iptables to process the packet according to the step specified by the rule target. For example, to apply a rule only to TCP packets, you can use the --protocol match. Each match is specified on the iptables command line. The most important iptables matches are listed below. For more matches, refer to the man page or read Linux Firewalls by Michael Rash.

  • --source (-s) - Match on a source IP Address or network
  • `–destination (-d) - Match on a destination IP Address or network
  • --protocol (-p) - Match on an IP protocol such as TCP or UDP
  • --in-interface (-i) - Input interface
  • --out-interface (-o) - Output interface
  • --state - Match on a set of connection states


Finally, iptables takes care of a set of targets that trigger an action when a packet matches a rule. The most important targets are as follows:

  • ACCEPT - Allows a packet to continue on its way
  • DROP - Drops a packet
  • LOG - Logs a packet to syslog
  • REJECT - Drops a packet and at the same time sends an appropriate response packet.
  • RETURN - Continues processing a packet within the calling chain.

Author Note

Following sh script is built by using rules from the book Linux Firewall by Michael Rash and 3 additional rules pertaining to DHCP DORA cycle request by the author of this article. Bear in mind that this rule works for a GNU/Linux client machine having DHCP address set.

Reader of this article encouraged to put in his/her effort to google the parameters used besides the one explained earlier.

#!/usr/bin/env sh  

### Variable initialization  

### Flushing existing rules and setting DROP on chain policies ###  
echo "[+] Flushing existing iptables rules"  
$IPTABLES -F -t nat  

### this policy does not handle IPv6 traffic except to drop it.  
echo "[+] Disabling IPv6 traffic"  

### load connection-tracking modules  
$MODPROBE ip_conntrack  
$MODPROBE iptable_nat  
$MODPROBE ip_conntrack_ftp  
$MODPROBE ip_nat_ftp  

###### INPUT chain ######  
echo "[+] Setting up INPUT chain"  

### state tracking rules  
$IPTABLES -A INPUT -m conntrack --ctstate INVALID -j LOG --log-prefix "DROP INVALID " --log-ip-opt  
ions --log-tcp-options  
$IPTABLES -A INPUT -m conntrack --ctstate INVALID -j DROP  

### anti-spoofing rules  
$IPTABLES -A INPUT -i $INTF ! -s $INTNET -j LOG --log-prefix "SPOOFED PKT "  

### ACCEPT rules  
$IPTABLES -A INPUT -i $INTF -p tcp -s $INTNET --dport 22 -m conntrack --ctstate NEW -j ACCEPT  
#### DHCPOFFER rule  
$IPTABLES -t filter -A INPUT -i $INTF -p udp -s --sport 68 -d --dport 67 - 
$IPTABLES -t filter -A INPUT -i $INTF -p udp -s --sport 67 -d --dport 68 - 

#Allow ICMP echo request  
$IPTABLES -A INPUT -p icmp --icmp-type echo-request -j ACCEPT  

### default INPUT LOG rule  
$IPTABLES -A INPUT ! -i lo -j LOG --log-prefix "DROP " --log-ip-options --log-tcp-options  

### make sure that loopback traffic is accepted  

###### OUTPUT chain ######  
echo "[+] Setting up OUTPUT chain"  

### state tracking rules  
$IPTABLES -A OUTPUT -m conntrack --ctstate INVALID -j LOG --log-prefix "DROP INVALID " --log-ip-op  
tions --log-tcp-options  
$IPTABLES -A OUTPUT -m conntrack --ctstate INVALID -j DROP  

### ACCEPT rules for allowing connections out  
$IPTABLES -A OUTPUT -p tcp --dport 21 -m conntrack --ctstate NEW -j ACCEPT  
$IPTABLES -A OUTPUT -p tcp --dport 22 -m conntrack --ctstate NEW -j ACCEPT  
$IPTABLES -A OUTPUT -p tcp --dport 25 -m conntrack --ctstate NEW -j ACCEPT  
$IPTABLES -A OUTPUT -p tcp --dport 43 -m conntrack --ctstate NEW -j ACCEPT  
$IPTABLES -A OUTPUT -p tcp --dport 80 -m conntrack --ctstate NEW -j ACCEPT  
## To allow outbound connection to gateway for DHCP request  
$IPTABLES -t filter -A OUTPUT -p udp --sport 68 -d $GATEWAY --dport 67 -j ACCEPT  

$IPTABLES -A OUTPUT -p tcp --dport 443 -m conntrack --ctstate NEW -j ACCEPT  
$IPTABLES -A OUTPUT -p tcp --dport 4321 -m conntrack --ctstate NEW -j ACCEPT  
$IPTABLES -A OUTPUT -p tcp --dport 53 -m conntrack --ctstate NEW -j ACCEPT  
$IPTABLES -A OUTPUT -p udp --dport 53 -m conntrack --ctstate NEW -j ACCEPT  
$IPTABLES -A OUTPUT -p icmp --icmp-type echo-request -j ACCEPT  

### default OUTPUT LOG rule  
$IPTABLES -A OUTPUT ! -o lo -j LOG --log-prefix "DROP " --log-ip-options --log-tcp-options  

### make sure that loopback traffic is accepted  

###### FORWARD chain ######  
echo "[+] Setting up FORWARD chain"  

### state tracking rules  
$IPTABLES -A FORWARD -m conntrack --ctstate INVALID -j LOG --log-prefix "DROP INVALID " --log-ip-o  
ptions --log-tcp-options  
$IPTABLES -A FORWARD -m conntrack --ctstate INVALID -j DROP  

### anti-spoofing rules  
$IPTABLES -A FORWARD -i $INTF ! -s $INTNET -j LOG --log-prefix "SPOOFED PKT "  

### ACCEPT rules  
$IPTABLES -A FORWARD -p tcp -i $INTF -s $INTNET --dport 21 -m conntrack --ctstate NEW -j ACCEPT  
$IPTABLES -A FORWARD -p tcp -i $INTF -s $INTNET --dport 22 -m conntrack --ctstate NEW -j ACCEPT  
$IPTABLES -A FORWARD -p tcp -i $INTF -s $INTNET --dport 25 -m conntrack --ctstate NEW -j ACCEPT  
$IPTABLES -A FORWARD -p tcp -i $INTF -s $INTNET --dport 43 -m conntrack --ctstate NEW -j ACCEPT  
$IPTABLES -A FORWARD -p tcp --dport 80 -m conntrack --ctstate NEW -j ACCEPT  
$IPTABLES -A FORWARD -p tcp --dport 443 -m conntrack --ctstate NEW -j ACCEPT  
$IPTABLES -A FORWARD -p tcp -i $INTF -s $INTNET --dport 4321 -m conntrack --ctstate NEW -j ACCEPT  
$IPTABLES -A FORWARD -p tcp --dport 53 -m conntrack --ctstate NEW -j ACCEPT  
$IPTABLES -A FORWARD -p udp --dport 53 -m conntrack --ctstate NEW -j ACCEPT  
$IPTABLES -A FORWARD -p icmp --icmp-type echo-request -j ACCEPT  

### default LOG rule  
$IPTABLES -A FORWARD ! -i lo -j LOG --log-prefix "DROP " --log-ip-options --log-tcp-options  

###### forwarding ######  
echo "[+] Enabling IP forwarding"  
echo 1 > /proc/sys/net/ipv4/ip_forward

Read through the rules and add/remove the ones you think important and save it in a file that ends in .sh. Make sure the variables are changed accordingly. Also make sure the file containing the rule is executable.

Execute the file in a local session on your GNU/Linux machine, and the rules should be applied successfully. After applying the rule, you can remotely access your GNU/Linux machine from your network.

To test it out, issue nc -v <TARGET_HOST> 5500 and grep port 5500 from /var/log/kern.log for Ubuntu machines and /var/log/messages for RHEL/CentOS like machines. You can also test various other protocols.

As the author is still reading the book Linux Firewalls by Michael Rash, this article will be updated periodically.


Rash, M., 2007. Linux Firewalls: Attack Detection And Response With Iptables, Psad, And Fwsnort. 1st ed. San Francisco, California: No Starch Press, p.10.

Written with StackEdit.

  1. NetFilter Project ↩︎