What I'll explain here is how to turn a base Linux system into a router, and add firewall functionality with iptables and netfilter. It's based on a Debian 3.0 installation, but should apply to other distributions as well. See also Linux as a router and Linux as a simple firewall ; we will build on a configuration describes on those pages.
we assume the network will look something like this :
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. You'll need 3 NICs, 1 for every connected network.
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 (ISP), also acts as default gateway
auto eth0
iface eth0 inet dhcp
#interface network 1
auto eth1
iface eth1 inet static
address 192.168.10.254
netmask 255.255.255.0
network 192.168.10.0
broadcast 192.168.10.255
#interface network 2
auto eth2
iface eth2 inet static
address 192.168.20.254
netmask 255.255.0.0
network 192.168.20.0
broadcast 192.168.20.255
First, execute the command 'route' to show the routing table, if any. Debian Linux runs scripts that update 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.
The routing table is modified with the route command, like this (re. man route) :
adding a route to each network (using 0.0.0.0. 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 192.168.10.0 netmask 255.255.255.0 dev eth1 route add -net -n 192.168.20.0 netmask 255.255.255.0 dev eth2 route add -net -n 0.0.0.0 dev eth0 route
As 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.
What we want is that all addresses from network 192.168.10.0 /24 are translated into eth0 's IP address when they connect to the internet. And idem dito for all addresses from network 192.168.20.0 /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 firewall.sh 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 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 iptables --append FORWARD --in-interface eth2 -j ACCEPT #enable forwarding echo 1 > /proc/sys/net/ipv4/ip_forward
The network address translation protects your local networks against any connection from outside, because the addresses on the LAN can not be routed without translation, and because in the outside world, only the public address of eth0 is visible.
The make it a real firewall, you may want to add rules about what kind of connections / traffic / communication will be allowed, be it between the LANs and the internet, or between the LANs themselves. A special case is a 'DMZ', a Demilitarized Zone. The DMZ sits between your secured network and the untrusted network (internet), and in principle, you only allow traffic between either the internet and the DMZ, or the secure network and the DMZ, so there is no direct communication between the secure net and the internet (see further). You'll need to design iptables rules to implement this.
Also : your LAN is invisible to the outside world, but your router is not. So you will need additional rules that govern the circumstances under which a connection to and from this machine will be allowed.
some sample rules:
#router : default = DROP iptables -P INPUT DROP iptables -P OUTPUT DROP #allow DHCP from and to the router on its external interface iptables -A OUTPUT -s 0/0 -i eth0 -p udp --sport 67:68 --dport 67:68 -j ACCEPT iptables -A INPUT -s 0/0 -i eth0 -p udp --sport 67:68 --dport 67:68 -j ACCEPT #allow remote login from LAN1, and allow router to respond iptables -A INPUT -s 192.168.10.0/24 -i eth1p tcp --sport 22 -j ACCEPT iptables -A OUTPUT -d 192.168.10.0/24 -o eth1 -m state --state ESTABLISHED,RELATED -j ACCEPT #allow troubleshouting etc if done from LAN1 iptables -A INPUT -s 192.168.10.0/24 -p icmp -j ACCEPT iptables -A OUTPUT -d 192.168.10.0/24 -p icmp -j ACCEPT
...
# connections from LAN to DMZ are allowed
iptables -A FORWARD -s $LAN1 -d $LAN2 -j ACCEPT
iptables -A FORWARD -s $LAN2 -d $LAN1 -m state --state ESTABLISHED,RELATED -j ACCEPT
### port forwarding from WAN to DMZ
## bittorent: range is 3881-3999
## bittorrent client runs on DMZ host, downloaded files are copied after downloads and seeding is stopped
for P in $(seq 3881 1 3889); do
iptables -t nat -A PREROUTING -i $IF_WAN -p tcp --dport $P -j DNAT --to-destination 192.168.20.115
done
With 3 or more networks, especially in DMZ configurations, it may be convenient to set up rules based on host or network addresses rather than the router in- and -out- interfaces. You can simplify this by using variables to hold the addresses, and possibly get dynamic addresses in real time. Here are some pointers.
Allowing access from an untrusted network (the internet) to your servers is like punching holes in your firewall. Therefore, it is common practice to group machines that need to allow public access together on a separate subnet. This subnet is often called the 'Demilitarized Zone' or DMZ. This only works well if you also block traffic from the DMZ to your secure net, so that if a host in the DMZ gets compromised, it will be blocked when trying to access the secure net.
Alternately, traffic from the secure net to the DMZ can be allowed, eg for remote administration of the servers.
It is also common to have hosts in the DMZ act as proxies for the hosts on the secure net. This way, you avoid direct connections between the secure net and the internet, even if the connection is initiated by a host on the secure net. Proxies can be a http and ftp proxy, a mail relay, a dns forwarder, ...
(More)
When using proxies, these in turn can be configured to add additional security to your firewall, e.g.
A combination of packet filtering, stateful inspection, a DMZ configuration, and some application level access control and filtering constitutes an excellent firewall (provided the router/firewall itself is sufficiently protected against attacks). Open source (free software) applications such as Squid http proxy and one of the many mail servers offer excellent solutions for this type of setup. This allows you to extend your Linux iptables firewall into a real firewall that can easily compete with commercial offerings.
You can see that there's two types of hosts in the DMZ : public servers (eg a web server), and hosts that are proxies for LAN hosts. Firewall rules may differ between the two kinds (public servers need to accept incoming connections, proxies need only allow replies to connections they initiated), so you could elaborate the concept of DMZ (eg. separate subnets), or implement rules to control which DNZ hosts can talk to each other (if any), etc, or logically group the hosts and apply different rules to each group, ...
A Bastion host is a host (usually a firewall system) that is exposed to the internet (or an other untrusted network), but hardenend to protect it against exploits or attacks. Such a host can then also host the proxies / application-level gateways that you'd otherwise have in a separate DMZ (the http and ftp proxy, a mail relay,...)
Bastille is a script that can help create such a bastion firewall. It creates an iptables firewall and sets additional security (allowed and denied hosts, users, ....) for services running on the host.
Even if you're firewall only does only IP-level packet and state filtering, Bastille is worth a look to secure your firewall so it won't get compromised easily.
For simple firewalls, a clean and well organized set of iptables rules is sufficient to create a secure and manageable firewall solution. As your network grows and your requirements become more complex (e.g. very elaborate rule sets for specific groups of hosts, multiple networks with specific requirements about which networks can talk to each other and how, ...), a graphical representation and a mechanism to logically group hosts or applications or networks, may help to keep it manageable, and reduce the chances for human error that may result in unexpected holes in the firewall.
There exist many GUI front-ends to iptables, but most of them are intended to simplify matters for an untrained user, so they tend to hide complexity rather than reduce it. If you want a GUI that deals with complexity without hiding information from you as a system administrator, fwbuilder is an excellent choice (fwbuilder screenshot). It's not strictly a front-end, but rather a GUI tool to design a firewall configuration. When you're done designing, the design is 'compiled' into a set of statements to implement the design, and the resulting file(s) can be installed on a firewall device.
This means you can run fwbuilder on a linux desktop to create a firewall configuration that you then copy and run on the actual firewall device or machine. If this machine is a linux box with iptables, you'll have fwbuilder generate an iptables script that you can put in /etc/init.d as a startup script. If your firewall is a FreeBSD machine or a Cisco device, you can let fwbuilder generate scripts or configs for those as well. You do no need to have fwbuilder installed on the target machine.
By modifying routes and/or firewall allow or deny rules based on time (time of day, day of week, ...), you can arrange for scheduled internet connections, e.g. to allow your children (or corporate end users) internet access only at given times. Here's a concept: firewall/router with scheduled internet access.