Using Netfilter to Create a Masquerading Router

T-Å Fransson   Wed Jun 14 22:07:55 CEST 2000
Plain text version

TOC:

  1. About this document
  2. Requirements
  3. Understanding iptables
  4. Example network

1. About this document

This document is not maintained. This is the latest version of it. If you do not understand what masquerading is, and if you never heard of Netfilter, I suggest you stop reading here.

The reason I wrote this document was that I could not find a masquerading-HOWTO that was updated to use Netfilter (Linux kernel version 2.0 used a thing called ipfwadm, and v2.2 used something called ipchains).

1.1. License

You are hereby granted to copy and distribute this document, in parts or as a whole, provided T-Å Fransson is recognized as the author.

2. Requirements

2.1 Configuring your kernel for Netfilter

The kernel modules responsible for the actual work are: Netfilter also has a possibility to pass packets to user-space programs (not covered here), therefor you need the Kernel/User netlink socket.

This is how I configured my 2.4.0-test1 kernel:

under Networking Options (make menuconfig)...

     ...

     [*] Kernel/User netlink socket
     [ ]   Routing messages
     <*>   Netlink device emulation
     [*] Network packet filtering (replaces ipchains)
     [ ]   Network packet filtering debugging
     [ ] Socket Filtering

     ...
...and under IP: Netfilter Configuration:
     ...

     <M> Connection tracking (required for masq/NAT)
     <M>   FTP protocol support
     < > Userspace queueing via NETLINK (EXPERIMENTAL)
     <M> IP tables support (required for filtering/masq/NAT)
     < >   limit match support
     <M>   MAC address match support
     < >   netfilter MARK match support
     <M>   Multiple port match support
     < >   TOS match support
     < >   Connection state match support
     < >   Unclean match support (EXPERIMENTAL)
     < >   Owner match support (EXPERIMENTAL)
     <M>   Packet filtering
     <M>     REJECT target support
     <M>     MIRROR target support (EXPERIMENTAL)
     <M>   Full NAT
     <M>     MASQUERADE target support
     <M>     REDIRECT target support
     <M>   Packet mangling
     <M>     TOS target support                                     
     <M>     MARK target support
     <M>   LOG target support
     <M> ipchains (2.2-style) support
     <M> ipfwadm (2.0-style) support
     ...
obviously, i made some arbitrary choices on what to include, but it compiled ok. YMMV.

2.2 Installing iptables-1.1.10

Simple, really. Just read the INSTALL file in the tarball.

3. Understanding iptables

What Netfilter gives you, is a number of tables, which contains chains where you can set targets. A target decides the destiny of a packet. Example of targets are: The default table is called filter and contains the chains INPUT, FORWARD and OUTPUT. INPUT is typically where you want to set up DROP targets for packets coming from 'evil' hosts.

Example:

 iptables -A INPUT -s 138.106.24.12 -j ACCEPT
 iptables -A INPUT -s 138.106.0.0/16 -j DROP
This adds a DROP target in the chain INPUT. '-s' stands for 'source', so the above commands will make your host throw away packets coming from the network 138.106.*.*, _except_ packets from 138.106.24.12, which are let through (chains are evaluated top-down). To list the chain INPUT, use:
 iptables -L INPUT
The FORWARD chain is used if your host is acting as router, i.e you have multiple interfaces and are forwarding traffic between them, this is used in section 4.

If you want to make sure applications on your host do not contact certain other hosts, use the OUTPUT chain.

Example:

 iptables -A OUTPUT -d 130.236.2.0/24 -p icmp -j DROP 
This rule stops icmp packets (ping) destined for the 130.236.2.x network, from leaving your host.

When you insert the module iptable_nat, you get an extra table with three chains, PREROUTING, POSTROUTING and OUTPUT. These chains correspond to the chains in the default table, but are used for network adress translation. You also get some extra targets, most notably DNAT, SNAT and MASQUERADE. DNAT is for altering destination adress, SNAT is for altering the source adress.

Example:

 iptables -t nat -A OUTPUT -p tcp -j DNAT --to-destination 205.188.146.23:80
 iptables -t nat -A PREROUTING -p tcp \
	  -j DNAT --to-destination 207.46.131.137:80
Hosts, for which your host is routing, will always surf on www.microsoft.com, and users on your local host will always be directed to www.aol.com, no matter what URL they are typing >:)

To delete a rule, you just replace the '-A' for add, with a '-D' for delete. To remove all rules in a chain, use '-F', so to remove the above added rules, the following is good:

 iptables -t nat -D OUTPUT -p tcp -j DNAT --to-destination 205.188.146.23:80
 iptables -t nat -D PREROUTING -p tcp \
	  -j DNAT --to-destination 207.46.131.137:80
or, you can flush the chains completely with:
 iptables -t nat -F OUTPUT
 iptables -t nat -F PREROUTING 
The target MASQUERADE can be used in the POSTROUTING chain. This is a special form of SNAT, which makes packets beeing routed through your host look like they originate from your host. This is especially useful when your LAN is sharing a dynamic ip link (typically ppp over modem). In section 4, this is covered more throughly.

With Netfilter, you can do lots of other things. You can create your own chains, and have packets pass through them. User created chains are ('-j') jumped to just as other targets. Also, you can pass the packets to userspace programs and process them there (that is why you need Netlink, mentioned above). All of this is way beyond the scope of this document. Read the manual for iptables(8), and the various documents on netfilter.kernelnotes.org

4. Example Network

Consider the following network:
                              inet
                                |               
                                |                           
                                |212.130.17.23               
                      *-----------------*                  
           192.168.1.1|       ppp0      |192.168.2.1      
                 /----|eth0         eth1|------\     
                 |    |      XXX        |      |            
                 |    *-----------------*      |            
                 |    192.168.1/24  eth0       |
                 |    192.168.2/24  eth1       |
                 |    default       ppp0       |
                 |                             |
                 |                             |
                 |                             |
                 | 192.168.1.2                 | 192.168.2.2
            *-----------------*            *-----------------*       
            |   eth0          |            |   eth0          |        
            |       YYY       |            |       ZZZ       |        
            *-----------------*            *-----------------*        
            192.168.1/24  eth0             192.168.2/24  eth0                  
            default       192.168.1.1      default       192.168.2.1     
                                                           

                                                           
    - The text under each box indicates the routing table
    - xxx.xxx.xxx.xxx/24 means netmask 255.255.255.0 (/16 means 255.255.0.0
      and /22 means 255.255.252.0)
This particular setup involves three computers, XXX, YYY and ZZZ, four network adapters (two in XXX, one each in YYY and ZZZ) and a modem, through which XXX connects to an ISP. Since the ISP only provides one IP address, simple forwarding won't work, should YYY and ZZZ want to open a connection to the outside world. Instead, XXX is masquerading for the other hosts. At the same time, XXX, YYY and ZZZ should be able to talk to eachother, and their true identity should be revealed, unless connections are made to the outside world.

Note that YYY and ZZZ need not be Linux machines, since they are not performing any forwarding or NAT.

To fulfill these needs, a rule in the POSTROUTING chain of the nat table on XXX is added:

 iptables -t nat -A POSTROUTING -d ! 192.168.0.0/22 -j MASQUERADE
Elaborated, this means:
"If the destination of a packet, beeing routed through this node, is not one of 192.168.0.*, 192.168.1.*,192.168.2.* or 192.168.3.*, give the packet a source adress of the interface, through which the package is leaving the node."
192.168.1.* and 192.168.2.* are the networks for YYY and ZZZ, so in other words, packets to YYY and ZZZ (and to XXX itself, ofcourse) are not masqueraded, while packets to other places are given the source adress of XXX's ppp0 interface (212.130.17.23).

This ofcourse has the unwanted side effect that _anyone_ can use XXX as a masquerading gateway, and that is bad. To make sure XXX does not perform masquerading, or forwarding at all, for hosts other than those on the internal segment, add the following rules:

 iptables -A FORWARD -s 192.168.0.0/22 -j ACCEPT
 iptables -A FORWARD -d 192.168.0.0/22 -j ACCEPT
 iptables -A FORWARD -j DROP
Packets coming from, or going to, the two (four, actually) internal segments are accepted for forwarding by XXX, all others are thrown away.

The resulting chains are:

(filtering table)

[root@XXX /]#  iptables -L
Chain INPUT (policy ACCEPT)
target     prot opt source               destination         

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination         
ACCEPT     all  --  192.168.0.0/22       anywhere           
ACCEPT     all  --  anywhere             192.168.0.0/22     
DROP       all  --  anywhere             anywhere           

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination   
(nat table)
[root@XXX /]#  iptables -t nat -L
Chain PREROUTING (policy ACCEPT)
target     prot opt source               destination         

Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination         
MASQUERADE  all  --  anywhere            !192.168.0.0/22     

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination         
Also, don't forget to enable ipv4 forwarding by echoing "1" to /proc/sys/net/ipv4/ip_forward

Below is an example script to perform everything (call this from rc.local or equiv)


#!/bin/bash

# insert modules
insmod ip_tables
insmod ip_conntrack
insmod iptable_nat
insmod ipt_MASQUERADE

# set up masquerading for everything not destined to the localnets
iptables -t nat -A POSTROUTING -d ! 192.168.0.0/22 -j MASQUERADE

# only forward packages for our subnets
iptables -A FORWARD -s 192.168.0.0/22 -j ACCEPT
iptables -A FORWARD -d 192.168.0.0/22 -j ACCEPT
iptables -A FORWARD -j DROP

# enable forwarding
echo "1" > /proc/sys/net/ipv4/ip_forward

//T-Å <torkel@spam.lysator.liu.se> (kill the 'spam')