5.4. Stateless NAT and Packet Filtering

Because NAT rewrites the packet as it passes through the IP stack, packet filtering can become complex. With attentiveness to the addressing of the packet at each stage in its journey through the packet filtering code, you can ease the burden of writing a packet filter.

All of the below requirements can be deduced from an understanding of NAT and the path a packet takes through the kernel. Consult also the ipchains packet path as illustrated in the ipchains HOWTO to understand the packet path when using ipchains. Keep in mind when viewing the ASCII diagram that stateless NAT will always occur in the routing stage. Also consult the kernel packet traveling diagram for a good picture of a 2.4 kernel packet path.

Table 5.1, “Filtering an iproute2 NAT packet with ipchains identifies the IP addresses on a packet traversing each of the input, forward and output chains in an ipchains installation.

Table 5.1. Filtering an iproute2 NAT packet with ipchains

Inbound to the NAT IP
ChainSource IPDestination IP
Routing Stage
Outbound from the real IP
ChainSource IPDestination IP
Routing Stage

A firewall implementing a tight policy (deny all, selectively allow) will require a large number of individual rules to allow the NAT packets to traverse the firewall packet filter. Assuming the configuration detailed in Example 5.1, “ Stateless NAT Packet Capture ”, the following set of chains is required and will restrict access to only port 25 [33].

Example 5.4. Using an ipchains packet filter with stateless NAT

[root@masq-gw]# ipchains -I input  -i eth1 -p tcp -l -y -s 0/0 1024:65535    -d 25 -j ACCEPT
[root@masq-gw]# ipchains -I input  -i eth1 -p tcp  ! -y -s 0/0 1024:65535    -d 25 -j ACCEPT
[root@masq-gw]# ipchains -I forward        -p tcp       -s 0/0 1024:65535    -d 25 -j ACCEPT
[root@masq-gw]# ipchains -I output -i eth0 -p tcp       -s 0/0 1024:65535    -d 25 -j ACCEPT
[root@masq-gw]# ipchains -I input  -i eth0 -p tcp  ! -y -s 25 -d 0/0 1024:65535    -j ACCEPT
[root@masq-gw]# ipchains -I forward        -p tcp       -s 25 -d 0/0 1024:65535    -j ACCEPT
[root@masq-gw]# ipchains -I output -i eth1 -p tcp       -s 25 -d 0/0 1024:65535    -j ACCEPT
[root@masq-gw]# for icmptype in \
> destination-unreachable source-quench time-exceeded parameter-problem; do
> ipchains -I input  -i eth1 -p icmp -s 0/0 $icmptype            -d -j ACCEPT
> ipchains -I forward        -p icmp -s 0/0 $icmptype            -d -j ACCEPT
> ipchains -I output -i eth0 -p icmp -s 0/0 $icmptype            -d -j ACCEPT
> ipchains -I input  -i eth0 -p icmp -s $icmptype -d 0/0            -j ACCEPT
> ipchains -I forward        -p icmp -s $icmptype -d 0/0            -j ACCEPT
> ipchains -I output -i eth1 -p icmp -s $icmptype -d 0/0            -j ACCEPT
> done

Please note that the formatting of the commands is simply for display purposes, and to allow for easier reading of a complex set of commands. The above set of rules is 31 individual chains. This is most certainly a complex set of rules. For further details on how to use ipchains please see the ipchains HOWTO. The salient detail you should notice from the above set of rules is the difference between the IPs used in the input and forward chains. Since packets are rewritten by the stateless NAT code in the routing stage, the transformation of the packet will by complete before the forward chain is traversed.

The first two lines cover all inbound TCP packets, the first line as a special case of the second, indicating (-l) that we want to log the packet. After successfully traversing the input chain, the packet is routed, at which point the destination address of the packet has changed. Now, we need to forward the packet from the public source address to the private (or real) internal IP address. Finally, we need to allow the packet out on the internal interface.

The next set of rules handles all of the TCP return packets. On the input rule, we are careful to match only non-SYN packets from our internal server bound for the world. Once again, the packet is rewritten during the routing stage. Now in the forward chain, the packet's source IP is the public IP of the service. Finally, we need to let the packet out on our external interface.

The next series of lines are required ICMP rules to prevent network traffic from breaking terribly. These types of ICMP, particularly destination unreachable (ICMP 3) and source quench (ICMP 4) help to ensure that TCP sessions run with optimized characteristics.

These rules are the minimum set of ipchains rules needed to support a NAT'd TCP service. This concludes our discussion of publishing a service to the world with iproute2 based NAT and protecting the service with ipchains. As you can see, the complexity of supporting NAT with iproute2 can be substantial, which is why we'll examine the benefits of inbound NAT (DNAT) with netfilter in the next section.

[33] I assume here that the user has a restrictive default policy on the firewalling device. I suggest a policy of DENY on each of the built in ipchains chains.