10mn Guide to Netfilter

A little bit of theory

Netfilter is the latest firewalling feature available in Linux, following ipfwadm (Linux 2.0) and ipchains (2.2), and the first to be stateful. It is part of 2.4.x, and is also known under the name of IPTabs. Chains and rules are actually handled by a user-space application called IPtables. Netfilter also requires that you have the iproute package installed, along with a certain number of kernel options, including netlink. NetFilter is actually a set of hooks inside the Linux kernel so that modules are called every time a packet needs to be handled.

Improvements or additions include

Just like ipchains, NetFilter is based on sets of rules, called "chains". Each set belongs to a different state in which a packet can be: INPUT (incoming packet meant for the firewall itself), OUTPUT (outgoing packets leaving the firewall itself), FORWARD (packets en route to the network on the other side), PREROUTING (used for special applications, eg. Destination NAT), POSTROUTING (eg. Source NAT). A good explanation on how packets are routed through the different chains is here.


  1. If they are not already installed, Install the IPTabs and IPRoute applications (rpm -Uvh iptables iproute)
  2. Configure a 2.4 Linux kernel with NetFilter compiled in
    1. In the main menu, go to the "Networking options" section, and enable "Network packet filtering".
    2. An extra menu option pops up called "IP: NetFilter Configuration". Select this option.
    3. Enable "Connection tracking (required for masq/NAT)", followed by "FTP protocol support" and "IRC protocol support"
    4. Enable "IP tables support (required for filtering/masq/NAT)", and enable all the new options that pop up
  3. Compile and install this new kernel, and reboot. Once this new kernel is up and running, check that NetFilter is included by checking if you have processes called ip_conntrack and ip_tables_names under /proc/net/, followed by "iptables -L"

Basic functions

Chains can be handled with the following switches:

Rules can be handled with the following switches:

A basic configuration

To tell the firewall box to route/forward traffic, remember to run echo 1 > /proc/sys/net/ipv4/ip_forward

	 Generic IPTables script, accept all by default
	# path to your iptables executable
	# put your local network address below
	# the interface you want to secure here
	# ppp+ = any PPP interface if you're connected to the internet through a ppp modem link.
	# our reject lists
	# reject everything but ssh, + postgres squid apache linuxconf
	tcp="1:19 23:537 539:598 600:1022 3128 4100:4300 5432 7100 8080 10000"
	# reject everyting + nfs but named
	udp="1:52 54:1022 2049"
	# delete previous rules
	$IPT -F OUTPUT -t nat
	# disable ping reply and log incoming pings, so you'll get in /var/log/messages
	# IP addresses of little Hackers trying to check if your host is up.
	$IPT -A INPUT -i $iface -p icmp -s --icmp-type echo-request -j LOG
	$IPT -A INPUT -i $iface -p icmp -s --icmp-type echo-request -j DROP
	# improve throughput (0x08) and delays (0x10)
	$IPT -t mangle -A OUTPUT -p tcp -d --dport telnet -j TOS --set-tos 0x10
	$IPT -t mangle -A OUTPUT -p tcp -d --dport ssh -j TOS --set-tos 0x10
	$IPT -t mangle -A OUTPUT -p tcp -d --dport ftp -j TOS --set-tos 0x10
	$IPT -t mangle -A OUTPUT -p tcp -d --dport ftp-data -j TOS --set-tos 0x08
	# disable ip spoofing (and log)             
	$IPT -A INPUT -i $iface -s $mynet -j LOG
	$IPT -A INPUT -i $iface -s $mynet -j DROP
	# more blocking
	for p in $tcp ; do
	  $IPT -A INPUT -p tcp -i $iface -s 0/0 -d 0/0 --dport $p -j REJECT
	for p in $udp ; do
	  $IPT -A INPUT -p udp -i $iface -s 0/0 -d 0/0 --dport $p -j REJECT
	#Some environment variables
	#Set default policies
	iptables -t nat -P PREROUTING DROP
	iptables -t nat -P POSTROUTING DROP
	iptables -P FORWARD DROP
	iptables -P OUTPUT DROP
	iptables -P INPUT DROP
	#Add to INPUT set to block some well-known attacks
	#--tcp-flags <flags to inspect> <flags that should be set>
	iptables -A INPUT -p tcp --tcp-flags ALL ALL -j DROP
	iptables -A FORWARD -p tcp --tcp-flags ALL ALL -j DROP
	iptables -A INPUT -p tcp --tcp-flags ALL NONE -j DROP
	iptables -A FORWARD -p tcp --tcp-flags ALL NONE -j DROP

	#Allow SSH connections to the firewall from the inside network
	iptables -A INPUT -i $INSIDE_INT -s $INSIDE_NETWORK -p tcp --dport 22 -j ACCEPT
	#Allow outgoing PINGs and incoming PONGs
	iptables -A FORWARD -s $INSIDE_NETWORK -p icmp --icmp-type echo-requested -j ACCEPT
	iptables -A FORWARD -d $INSIDE_NETWORK -p icmp --icmp-type echo-reply -j ACCEPT
	iptables -A OUTPUT -i $OUTSIDE_INT -p icmp --icmp-type echo-requested -j ACCEPT
	iptables -A INPUT -i $OUTSIDE_INT -p icmp --icmp-type echo-reply -j ACCEPT
	#Block spoofed packets

	#Block non-routable addresses from the Interne	
	iptables -A FORWARD -i $OUTSIDE_INT -s -j DROP
	iptables -A FORWARD -i $OUTSIDE_INT -s -j DROP
	iptables -A FORWARD -i $OUTSIDE_INT -s -j DROP

	#Block SMB/CIFS	
	iptables -A FORWARD -p tcp --sport 137:139 -J DROP
	iptables -A FORWARD -p udp --sport 137:139 -J DROP

	#Block NFS and other dangerous apps	
	iptables -A FORWARD -p tcp --sport 635 -j DROP
	iptables -A FORWARD -p udp --sport 635 -j DROP
	iptables -A FORWARD -p tcp --sport 2049 -j DROP
	iptables -A FORWARD -p udp --sport 2049 -j DROP
	iptables -A FORWARD -p tcp --sport 111 -j DROP
	iptables -A FORWARD -p udp --sport 111 -j DROP
	iptables -A FORWARD -i $OUTSIDE_INT -p udp syslog -j DROP
	iptables -A FORWARD -i $OUTSIDE_INT -p tcp --dport 512 -j DROP
	iptables -A FORWARD -i $OUTSIDE_INT -p tcp --dport 514 -j DROP
	iptables -A FORWARD -i $OUTSIDE_INT -p tcp --dport 515 -j DROP

	#Route all outgoing WWW traffic to our proxy; -t nat required with PREROUTING/POSTROUTING
	iptables -t nat -A PREROUTING -i $INSIDE_INT -p tcp--dport 80 -j NAT --to $PROXY
	iptables -t nat -A PREROUTING -i $INSIDE_INT -p tcp --dport 443 -j NAT --to $PROXYSSL

	#Route all outgoing SMTP traffice to single host
	iptables -t nat -A PREROUTING -i $INSIDE_INT -p tcp --dport 25 -j NAT --to $SMTP

	#Stateful settings
	iptables -A FORWARD -m state --state NEW -i $INSIDE_INT -s$INSIDE_NETWORK -j ACCEPT

Sample configuration file

This script must be made executable with chmod 700 myscript. You can stop it by running "iptables -F".



#Load the module.
#If compiled as module.... modprobe ip_tables

#Flush old rules, delete the firewall chain if it exists
$IPT -F -t nat
$IPT -X firewall

#Setup Masquerading. Change the IP to your internal network and uncomment
#this in order to enable it.
#echo 1 > /proc/sys/net/ipv4/ip_forward

#Set up the firewall chain
$IPT -N firewall
$IPT -A firewall -j LOG --log-level info --log-prefix "Firewall:"
$IPT -A firewall -j DROP #Accept ourselves

#If you're using IP Masquerading, change this IP to whatever your internl
#IP addres is and uncomment it
#$IPT -A INPUT -s -d 0/0 -j ACCEPT

#Accept DNS, 'cause it's warm and friendly
$IPT -A INPUT -p udp --source-port 53 -j ACCEPT
$IPT -A INPUT -p tcp --source-port 113 -j ACCEPT
$IPT -A INPUT -p tcp --destination-port 113 -j ACCEPT

#Allow ftp to send data back and forth.
$IPT -A INPUT -p tcp ! --syn --source-port 20 --destination-port 1024:65535 -j ACCEPT

#Accept SSH. Duh.
#$IPT -A INPUT -p tcp --destination-port 22 -j ACCEPT

#Send everything else ot the firewall.
$IPT -A INPUT -p icmp -j firewall
$IPT -A INPUT -p tcp --syn -j firewall
$IPT -A INPUT -p udp -j firewall


ip address show ip route show ip neigh show //arp ip neigh delete dev eth0 ip link list ip rule list ip route list table local ip route list table main


If you have a large router, you may well cater for the needs of different people, who should be served differently. The routing policy database allows you to do this by having multiple sets of routing tables. If you want to use this feature, make sure that your kernel is compiled with the "IP: advanced router" and "IP: policy routing" features. When the kernel needs to make a routing decision, it finds out which table needs to be consulted. By default, there are three tables. The old 'route' tool modifies the main and local tables, as does the ip tool (by default).




Why the extra -t nat?

Shouldn't the -A [PRE | POST ]ROUTING token be sufficient to tell iptables that we want NAT?

Why doesn't the LOG target work?

Ripped off from the Web: iptables -A INPUT -i eth0 -s -j LOG iptables: No chain/target/match by that name