Stateful Firewall and Masquerading on Linux
www.puschitz.com
This article describes how I've setup stateful firewall and masquerading on Linux. For basic Linux
security, see my other article
Securing Linux Production Systems - A Practical Guide to Basic Security in Linux Production Environments.
I welcome emails from any readers with comments, suggestions, or corrections. You can find my email address at the bottom of this website.
The Netfilter in the Linux kernel is able to keep track of network packet's state and context. This means that Netfilter
can distinguish packets associated with an established connection from packets that are not.
For example, if you connect to a web server with your browser, the web server answers your browser's request
and Netfilter knows that these incoming network packets are the response to the request you initiated with your
browser.
Using this feature allows you to instruct Netfilter to only accept network packets that are part of an established
or related connection initiated by you but to ignore all other network packets.
To accept packets that are part of an established connection you can define the following rule:
# /sbin/iptables -A INPUT -m state --state ESTABLISHED -j ACCEPT
The option '-A' is for append which indicates that the rule should be appended to the
INPUT chain of the filter table ("INPUT" must be in capital letters!).
The INPUT chain is a built-in chain which is a filtering point for handling packets
that are destined for the local system where you are defining these rules.
Since the stateful firewall filter is not a built-in feature, a so called "match extension" must be invoked.
The option '-m' tells Netfilter to use a match extension. In the above example I invoked the state
match extension or state match module which is loaded automatically with the '-m' option.
The state match module ipt_state also loads a few other kernel modules as well:
# lsmod | grep ip
ipt_state 1857 1
ip_conntrack 41369 1 ipt_state
iptable_filter 2881 1
ip_tables 19521 2 ipt_state,iptable_filter
By defining the above rule you may soon realize that it will not work for all applications. For example, in
Active Mode FTP
the FTP server makes a connection back to the data port on the client side (your node or firewall).
This is a new connection which is related to the connection that you initiated by connecting
to port 21 on the FTP server.
To instruct Netfilter to also accept packets that are not part of an established connection but part of a related connection,
you can define the following rule:
# /sbin/iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
In the following stateful firewall example below I will create a custom chain called "block" which will handle
INPUT, and a FORWARD chain. The FORWARD chain handles packets that are being routed through the local system.
The FORWARD chain allows other nodes on your local network to use the system as a firewall and router.
To create the "block" custom chain, use the option '-N':
# /sbin/iptables -N block
It may also be useful to always flush all rules before setting up
a new set of rules. You can do this with the option '-F':
# /sbin/iptables -F
Basic Stateful Firewall Example
To summarize what has been covered in the introduction, the first iptables commands for building a
stateful firewall would look as follows:
/sbin/iptables -F
/sbin/iptables -N block
/sbin/iptables -A block -m state --state ESTABLISHED,RELATED -j ACCEPT
So far we have specified that all established and related network packets should pass the first
filter rule. To use the system as a firewall and gateway for other servers on the local network,
Netfilter needs to be told to accept all new network packets coming from the local network. An easy way
of doing this is to accept all new network packets that are NOT coming from the DSL line "ppp0",
i.e. all network packets that come from the local network through any other interfaces should be accepted:
/sbin/iptables -F
/sbin/iptables -N block
/sbin/iptables -A block -m state --state ESTABLISHED,RELATED -j ACCEPT
/sbin/iptables -A block -m state --state NEW -i ! ppp0 -j ACCEPT
If you have a cable modem connected to the interface "eth0", you need to replace "ppp0" with "eth0".
The option '-i' specifies the incoming interface. Since the system should be protected from
the Internet, the above rule only accepts new network packets (-m state --state NEW)
that are not coming via the DSL line (-i ! ppp0).
To log all network packets that don't pass the above rules, Netfilter can be told to create logs.
In the following example LOG connects to the syslogger kernel facility:
/sbin/iptables -F
/sbin/iptables -N block
/sbin/iptables -A block -m state --state ESTABLISHED,RELATED -j ACCEPT
/sbin/iptables -A block -m state --state NEW -i ! ppp0 -j ACCEPT
/sbin/iptables -A block -j LOG
The logs can be found on Red Hat in /var/log/messages and on SUSE in /var/log/firewall, respectively.
To drop all network packets that don't pass the rules that have been defined so far, the base target "DROP" can be specified.
This will cause all network connections to time out. If you want to send back ICMP error packets
as response, replace the base target "DROP" with "REJECT".
/sbin/iptables -F
/sbin/iptables -N block
/sbin/iptables -A block -m state --state ESTABLISHED,RELATED -j ACCEPT
/sbin/iptables -A block -m state --state NEW -i ! ppp0 -j ACCEPT
/sbin/iptables -A block -j LOG
/sbin/iptables -A block -j DROP
Now Netfilter just needs to be told to jump to the custom chain "block" from the INPUT chain:
/sbin/iptables -F
/sbin/iptables -N block
/sbin/iptables -A block -m state --state ESTABLISHED,RELATED -j ACCEPT
/sbin/iptables -A block -m state --state NEW -i ! ppp0 -j ACCEPT
/sbin/iptables -A block -j LOG
/sbin/iptables -A block -j DROP
/sbin/iptables -A INPUT -j block
Now test the stateful firewall and ensure it's working.
To list the rules, run:
# iptables -L
Chain INPUT (policy ACCEPT)
target prot opt source destination
block all -- anywhere anywhere
Chain FORWARD (policy ACCEPT)
target prot opt source destination
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
Chain block (1 references)
target prot opt source destination
ACCEPT all -- anywhere anywhere state RELATED,ESTABLISHED
ACCEPT all -- anywhere anywhere state NEW
LOG all -- anywhere anywhere LOG level warning
DROP all -- anywhere anywhere
#
Giving an IP Address Access to the Stateful Firewall
To give an IP address access to the stateful firewall server, you can add the following rule:
/sbin/iptables -F
/sbin/iptables -N block
/sbin/iptables -A block -m state --state ESTABLISHED,RELATED -j ACCEPT
/sbin/iptables -A block -m state --state NEW -i ! ppp0 -j ACCEPT
/sbin/iptables -A block -s xx.xx.xx.xx/32 -j ACCEPT
/sbin/iptables -A block -j LOG
/sbin/iptables -A block -j DROP
/sbin/iptables -A INPUT -j block
Stateful Firewall and IP Masquerading
IP Masquerading can be used to give all servers on a local network access to the Internet.
There is a subtle difference between Source NAT (SNAT) and Masquerading. SNAT requires a specific address to refer packets,
whereas Masquerading can also be used with source addresses that are assigned dynamically by DHCP. Also, with Masquerading,
connections are forgotten if the interface goes down.
To enable IP Masquerading, add the following rule to the Stateful Firewall example:
/sbin/iptables -F
/sbin/iptables -N block
/sbin/iptables -A block -m state --state ESTABLISHED,RELATED -j ACCEPT
/sbin/iptables -A block -m state --state NEW -i ! ppp0 -j ACCEPT
/sbin/iptables -A block -j LOG
/sbin/iptables -A block -j DROP
/sbin/iptables -A INPUT -j block
/sbin/iptables -t nat -A POSTROUTING -o ppp0 -j MASQUERADE
This rule specifies that all packets that are going out through the "ppp0" interface should change the source IP address
to the IP address of the firewall server. The POSTROUTING chain handles all packets immediately prior to
leaving the firewall system.
To enable IP masquerading you also need to activate it in the kernel by setting ip_forward to 1.
You can do this by adding the following entry to the /etc/sysctl.conf file:
net.ipv4.ip_forward=1
To have this setting become effective immediately, execute the following command:
# sysctl -p
NOTE: If you have a DSL line and you do masquerading, it is recommended to add the following additional rule:
/sbin/iptables -F
/sbin/iptables -N block
/sbin/iptables -A block -m state --state ESTABLISHED,RELATED -j ACCEPT
/sbin/iptables -A block -m state --state NEW -i ! ppp0 -j ACCEPT
/sbin/iptables -A block -j LOG
/sbin/iptables -A block -j DROP
/sbin/iptables -A INPUT -j block
/sbin/iptables -A FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu
/sbin/iptables -t nat -A POSTROUTING -o ppp0 -j MASQUERADE
For more information on this rule, see
http://en.tldp.org/HOWTO/IP-Masquerade-HOWTO/mtu-issues.html.
Here is an example of a Netfilter log entry in the /var/log/messages file:
Aug 18 06:05:04 localhost kernel: IN=ppp0 OUT= MAC= SRC=xx.xx.xx.xx DST=yy.yy.yy.yy LEN=78 TOS=0x00 PREC=0x00 TTL=120 ID=22337 PROTO=UDP SPT=137 DPT=137 LEN=58
SRC is the IP address where the request came from.
DST is the target IP address, in this case the IP address of the firewall.
SPT is the port number on SRC where the request came from.
DPT is the port number on the firewall where the request was sent to. In this example the port number is 137.
For various port numbers, see also /etc/services.
The netfilter/iptables project
IPTABLES Firewall Examples
RH253 Course Material
Copyright © 2007 PUSCHITZ.COM
The information provided on this website comes without warranty of any kind and is distributed AS IS.
Every effort has been made to provide the information as accurate as possible, but no warranty or fitness is implied.
The information may be incomplete, may contain errors or may have become out of date.
The use of this information described herein is your responsibility, and to use it in your own
environments do so at your own risk.