banner Debian GNU/Linux

Linux Router

Internet Connection Sharing, Network Address Translation, Routing, and Firewall

Setting up Linux as a router and firewall is an excellent exercise to get some hands-on experience with system administration on Linux and gain some insight in routing and networking. It's also rather easy.

In today's world of broadband internet connections, the word "router" is usually associated with a device that connects you to the internet and allows you to connect multiple computers on a simple ISP account (possibly a 'one computer' account). Those devices combine functionality of several devices : an ADSL modem or cable modem, a router, Network Address Translation, some firewall functionality, and a switch. We will limit ourselves to the router with NAT, and a firewall. A switch v-can be connected separately, as it only servers to physically connect multiple PC's. It is possible to build in an ADSL board in a PC, but it's probably easier to just use a dedicated ADSL or Cable modem.

What I'll explain here is how to turn a basic Linux system into a router, and add firewall functionality with iptables (netfilter). It's based on a Debian 3.0 installation, but should apply to other distributions as well. If you get confused about Debian Linux, About Debian has a very good collection of beginner's guides.

Tux Router

Getting started

You need some hardware : a personal computer that will become the router. It will need 2 network cards, 1 to connect to the modem and through that to the internet, and 1 to connect to your local network, be it 1 other computer or a switch with several computers attached to it.

Prepare the PC if it is not yet in working order. Put in 2 Network cards (labeled eth0, eth1). If the network cards are not PCI cards (i.e. you're working with truly old material) you may need to configure them so that the 2 of them use different IRQ's and I/O addresses. You'll need to search for a configuration tool or set jumpers. Write down which card has what IRQ and I/O base address : you'll need that. You don't need to do that with PCI cards, they will configure themselves at system boot and report their settings to the operating system so you don't need to know the settings.

Install Linux. Choose a custom setup so that you can limit the installation to a basic system. You only need text mode, no graphical desktop and all that. You can always add stuff later if you left them out in the original installation. For help with old hardware (no CD-rom, ISA network cards, ...) : Install Linux on old hardware

installing the network cards

Setting up the network adaptors is described in detail in How to Set up a Linux Network at About Debian. This paper also covers, in detail many other aspects of TCP/IP networking, and is recommended reading if all this is new to you.

When installing Debian, you have the opportunity to load modules (drivers) for the network cards. Modules can also be added with the modconf command. This will bring up the module selection routine you know from the initial installation.

If every NIC requires a different module, the order in which the modules are loaded will define the interface names (eth0, eth1 etc). This order can be checked in /etc/modules.conf file. However, when 2 or more NIC's use the same driver, this does not work. Still, it is important to know which NIC is eth1, which one is eth2, and to make sure this will be the same every time the system boots. If not, it will completely mess up the routing tables.

The Linux Ethernet Howto has a list of NIC hardware, and the corresponding drivers. 3Com is one of the companies that offer Linux modules for their network cards. The 3com 3C509 cards are well supported under Linux, you'll easily find information on how to use them.

When more than 1 NIC uses the same driver, it only needs to be loaded once. Interface aliases (eth1, eth2, ...) will be assigned in the order that the cards are detected by the system. PCI cards will be detected in the order of their PCI slots. ISA cards will be detected by their IRQ. So by setting the IRQ on an ISA card, or by choosing a PCI slot where to insert the PCI card(s), you can define the order in which the network cards will be named by the system. With a mix of PCI and ISA cards, you may have to check what IRQ the system assigns to the PCI card, and set the IRQ of the ISA card to a higher or lower IRQ to control the order.

As a last resort, you can map hardware (MAC) addresses to interface names with the ifconfig command, as explained in the Linux Cable Modem Howto :

		# ifconfig ethX hw ether 00:D0:09:DE:D4:6F up 

With some modules, you can give irq and I/O base address as parameters and thus (try to) control the interfaces. See also this SUSE setup.

Network interfaces are configured in the /etc/network/interfaces file. For our internet gateway, we will have eth0 as the external interface. It will have to get its network settings from the internet provider, through dhcp. The other interfaces will have a static IP address from our private ranges. So the interfaces file will look something like this

	#loopback interface
	auto lo iface lo inet loopback

	# interface external network (internet), configured through dhcp 
	auto eth0
	iface eth0 inet dhcp

	#interface network 1
	auto eth1
	iface eth1 inet static

	#interface network 2
	auto eth2
	iface eth2 inet static

use DHCP

remember that you have to have a dhcp client running for this to work (for eth0). In Debian, the dhcp-client package is automatically installed as a part of the base packages, as /sbin/dhclient. You can check if it is with one of the following commands :

To install or update : # apt-get install dhcp3-client.
dhclient also works.

For troubleshooting dhcp, check the Linux DHCP Howto. One particular problem for cable modems can be that these modems 'remember' the hardware address of the network interface card of the system that was connected to them. If you try to connect a different machine or a machine with a different NIC, they won't connect, and your DHCP will fail. Usually it helps to turn the cable modem of completely (pull the power plug), connect the (new) computer and boot it, then bring on the cable modem again. Reboot the computer or run dhclient to get DHCP.

check configuration

you may want to have a look at the following files :

Have a cup of coffee ...

You now have a working Linux system configured for multiple network cards. All that's left to do is tell it to route :-)

Make it route

execute echo 1 > /proc/sys/net/ipv4/ip_forward. This will instruct the kernel to allow IP packets to pass between the network cards. Your computer is now a router. Run the command route -n to show the routing table. Linux updates the routing table as part of the network configuration, so it is possible you already have a couple of routes there. E.g. /etc/dhclient-script will add a route after you've received network configuration (including IP address) from a DHCP server.

If need be, the routing table is can be modified with the route command, like this (re. man route) :
adding a route to each network (using for any network, the internet) - the final 'route' command (without parameters) will show the routing table after it has been modified.

	route add -net -n netmask dev eth1
	route add -net -n netmask dev eth2
	route add -net -n dev eth0

Note that routes that you add manually, are not permanent, i.e. you'll loose them on system reboot, unless there is a script or a config file that sets them again during the boot process. I'm still confused as to where exactly this is done. It may also depend on the distribution. If all else fails, you can just add these commands to a startup script - it will work just fine.

You will also need to add the "echo 1 > /proc/sys/net/ipv4/ip_forward" to a startup script so that it is re-enabled after a system reboot. Startup scripts are kept in /etc/init.d, with symbolic links in the /etc/rcX.d for the corresponding runlevels. You can use the rc-update command to create them, or create them by hand with ln.

Network Address Translation

If we are routing between private networks and the public internet, the private IP addresses will need to be translated in to a public address. As we're connecting multiple hosts through this gateway, we'll need translation from multiple private addresses to the 1 public address assigned to eth0 by our internet provider. We need NAT : Network Address Translation.

The type of NAT described here is called 'MASQUERADING4 and is a specific form of 'SOURCE NAT' : when the hosts on the private networks connect to a host on th internet, their source address will be translated into the public address of the NAT router, thus eth0 's IP address. This NAT is executed POST-ROUTING, so the routing decision will be taken first, then the address will be translated. There is thus no need to modify the routing table when applying NAT. Keeps it simple and straightforward, no ?

If connections initiated from the internet need to be forwarded to a server on your private networks, the destination address (and sometimes port) will need to be changed by the NAT router. This is called 'DESTINATION NAT' and is executed PRE-ROUTING, so that the router can use the real (private) address to take a routing decision. Again the NAT and the routing go together without any trouble.

In this case study, we will focus on the 'source' NAT. The associated Destination NAT is handled automatically.

What we want is that all addresses from network /24 are translated into eth0 's IP address when they connect to the internet. And idem dito for all addresses from network /24. This is done with a startup script. Startup scripts belong in /etc/init.d directory and are called by symbolic links from the appropriate runlevel directories (eg /etc/rc2.d if you use runlevel 2 as default runlevel for this system). The script could be called and would look like this :

	# delete old configuration, if any
	#Flush all the rules in filter and nat tables
   	iptables --flush           		
   	iptables --table nat --flush
	# delete all chains that are not in default filter and nat table, if any
   	iptables --delete-chain     
   	iptables --table nat --delete-chain

	# Set up IP FORWARDing and Masquerading (NAT)
   	iptables --table nat --append POSTROUTING --out-interface eth0 -j MASQUERADE
   	iptables --append FORWARD --in-interface eth1 -j ACCEPT

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

Don't forget this script has to be executable : chmod 700 <name_of_script> .

You have now a basic router with NAT capability, allowing multiple computers on a private network to access the internet (or whatever network on the other side of the router. The NAT provides also a basic form of firewall, because it automatically blocks incoming connections to the private network - incoming connections to the router itself are not filtered but if you haven't installed any additional services, there's nothing there to connect to.

Details :

remote administration with secure shell

For remote control, it's best to use secure shell. You can install the package with # apt-get install ssh. This includes the sshd (secure shell daemon) that will allow you to secure login to the router. You don't want anyone else to try that, so you only allow this for connections coming from the local network. Add an appropriate rule to the firewall. See Linux Firewall.

Points for style

Some other details to take care of :

These contain the messages users will see when they log on to your router / firewall. Ideally, that would be only you.

If everything is working fine ...

Finally, you can, if the BIOS of the router PC allows it, disconnect the monitor and key board from the PC (You'll have to adjust some BIOS settings to avoid boot error messages), and put the router somewhere out of the way. It can be left on at all times (Linux systems hardly ever crash), and you can access it remotely if you need to configure anything.

Koen Noens
October 2004