Setting up a network firewall

Before you read this part of the chapter, note that we assume that you have already installed iptables as described in the previous section.

Introduction to Firewall Creation

The general purpose of a firewall is to protect a network against malicious access by using a single machine as a firewall. This does imply that the firewall is to be considered a single point of failure, but it can make the administrator's life a lot easier.

In a perfect world where you knew that every daemon or service on every machine was perfectly configured and was immune to, e.g., buffer-overflows and any other imaginable problem regarding its security, and where you trusted every user accessing your services to aim no harm, you wouldn't need to have a firewall! In the real world however, daemons may be misconfigured, exploits against essential services are freely available, you may wish to choose which services are accessible by certain machines, you may wish to limit which machines or applications are allowed to have Internet access, or you may simply not trust some of your apps or users. In these situations you might benefit by using a firewall.

Don't assume however, that having a firewall makes careful configuration redundant, or that it makes any negligent misconfiguration harmless. It also doesn't prevent anyone from exploiting a service you intentionally offer but haven't recently updated or patched after an exploit went public. Despite having a firewall, you need to keep applications and daemons on your system well-configured and up-to-date; a firewall is not a cure-all!

Meaning of the word firewall.

The word firewall can have several different meanings.

This is a setup or program, for Windows commercially sold by companies such as Symantec, of which they claim or pretend that it secures a home or desktop-pc with Internet access. This topic is highly relevant for users who do not know the methods their computers might be accessed via the Internet or how to disable them, especially if they are always online and connected via broadband links.

This is a box placed between the Internet and an intranet. To minimize the risk of compromising the firewall itself it should generally have only one role, that of protecting the intranet. Although not completely risk free, the tasks of doing the routing and eventually IP masquerading (rewriting IP-headers of the packets it routes from clients with private IP-addresses onto the Internet so that they seem to come from the firewall itself) are commonly considered harmless.

This is often an old box you may have retired and nearly forgotten, performing masquerading or routing functions, but offering a bunch of services, e.g., web-cache, mail, etc. This may be very commonly used for home networks, but can definitely not be considered as secure anymore because the combining of server and router on one machine raises the complexity of the setup.

Firewall with a demilitarized zone [not further described here]

This box performs masquerading or routing, but grants public access to some branch of your network which, because of public IP's and a physically separated structure, is neither considered to be part of the inter- nor intranet. These servers are those which must be easily accessible from both the inter- and intranet. The firewall protects them all.

Packetfilter / partly accessible net [partly described here, see BusyBox]

Doing routing or masquerading, but permitting only selected services to be accessible, sometimes only by selected internal users or boxes; mostly used in highly secure business contexts, sometimes by distrusting employers. This was the common configuration of a firewall at the time of the Linux 2.2 kernel. It's still possible to configure a firewall this way, but it makes the rules quite complex and lengthy.

Disclaimer

This document is meant as an introduction to how to setup a firewall. It is not a complete guide to securing systems. Firewalling is a complex issue that requires careful configuration. The scripts quoted here are simply intended to give examples as to how a firewall works, they are not intended to fit into any imaginable configuration and may not prevent any imaginable attack.

The purpose of this text is simply to give you a hint on how to get started with a firewall.

Customization of these scripts for your specific situation will be necessary for an optimal configuration, but you should make a serious study of the iptables documentation and creating firewalls in general before hacking away. Have a look at the list of Links for further reading at the end of this section for more details. Here you will find a list of URLs that contain quite comprehensive information about building your own firewall.

Getting a firewall enabled Kernel

If you want your Linux-Box to have a firewall, you must first ensure that your kernel has been compiled with the relevant options turned on.

How to configure your kernel, with enabling the options to be either compiled into the kernel or as modules, depends on your personal preferences and experience. Note, that for the quoted scripts it is assumed that the modules need to be loaded at first.

Network options menu
  Network packet filtering:                         Y
  Unix domain sockets:                         Y or M
  TCP/IP networking:                                Y
  IP: advanced router:                              Y
  IP: verbose route monitoring:                     Y
  IP: TCP Explicit Congestion Notification support: Y
  IP: TCP syncookie support:                        Y
  IP: Netfilter Configuration menu
    Every option except:                       Y or M
      ipchains (2.2-style) support                  N
      ipfwadm (2.0-style) support                   N
  Fast switching:                                   N

Now you can start to build your Firewall

Personal Firewall

A Personal Firewall is supposed to let you access all the services offered on the Internet, but keep your box secure and your data private.

Below is a slightly modified version of Rusty Russell's recommendation from the Linux 2.4 Packet Filtering HOWTO:

cat > /etc/rc.d/init.d/firewall << "EOF"
#!/bin/sh

# Begin $rc_base/init.d/firewall

# Insert connection-tracking modules (not needed if built into the kernel).
modprobe ip_tables
modprobe iptable_filter
modprobe ip_conntrack
modprobe ip_conntrack_ftp
modprobe ipt_state
modprobe ipt_LOG

# allow local-only connections
iptables -A INPUT  -i lo -j ACCEPT
# free output on any interface to any ip for any service (equal to -P ACCEPT)
iptables -A OUTPUT -j ACCEPT

# permit answers on already established connections
# and permit new connections related to established ones (eg active-ftp)
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

# Log everything else:  What's Windows' latest exploitable vulnerability?
iptables -A INPUT -j LOG --log-prefix "FIREWALL:INPUT "

# set a sane policy:    everything not accepted > /dev/null
iptables -P INPUT    DROP
iptables -P FORWARD  DROP
iptables -P OUTPUT   DROP

# be verbose on dynamic ip-addresses     (not needed in case of static IP)
echo 2 > /proc/sys/net/ipv4/ip_dynaddr

# disable ExplicitCongestionNotification - too many routers are still ignorant
echo 0 > /proc/sys/net/ipv4/tcp_ecn

# End $rc_base/init.d/firewall
EOF

His script is quite simple, it drops all traffic coming in into your computer that wasn't initiated from your box, but as long as you are simply surfing the Internet you are unlikely to exceed its limits.

If you frequently encounter certain delays at accessing ftp-servers, please have a look at BusyBox - example no. 4.

Even if you have daemons or services running on your box, these should be inaccessible everywhere but from your box itself. If you want to allow access to services on your machine, such as ssh or pinging, take a look at BusyBox.

Masquerading Router

A true Firewall has two interfaces, one connected to an intranet, in this example, eth0, and one connected to the Internet, here, ppp0. To provide the maximum security against the box itself being broken into, make sure that there are no servers running on it, especially not X11 et al. And, as a general principle, the box itself should not access any untrusted service (Think of a name server giving answers that make your bind crash, or, even worse, that implement a worm via a buffer-overflow).

cat > /etc/rc.d/init.d/firewall << "EOF"
#!/bin/sh

# Begin $rc_base/init.d/firewall

echo
echo "You're using the example-config for a setup of a firewall"
echo "from the firewalling-hint written for LinuxFromScratch."
echo "This example is far from being complete, it is only meant"
echo "to be a reference."
echo "Firewall security is a complex issue, that exceeds the scope"
echo "of the quoted configuration rules."
echo "You can find some quite comprehensive information"
echo "about firewalls in Chapter 4 of the BLFS book."
echo "http://www.linuxfromscratch.org/blfs"
echo

# Insert iptables modules (not needed if built into the kernel).

modprobe ip_tables
modprobe iptable_filter
modprobe ip_conntrack
modprobe ip_conntrack_ftp
modprobe ipt_state
modprobe iptable_nat
modprobe ip_nat_ftp
modprobe ipt_MASQUERADE
modprobe ipt_LOG
modprobe ipt_REJECT

# allow local-only connections
iptables -A INPUT  -i lo -j ACCEPT
iptables -A OUTPUT -o lo -j ACCEPT

# allow forwarding
iptables -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A FORWARD -m state --state NEW -i ! ppp+       -j ACCEPT

# do masquerading    (not needed if intranet is not using private ip-addresses)
iptables -t nat -A POSTROUTING -o ppp+ -j MASQUERADE

# Log everything for debugging (last of all rules, but before DROP/REJECT)
iptables -A INPUT   -j LOG --log-prefix "FIREWALL:INPUT  "
iptables -A FORWARD -j LOG --log-prefix "FIREWALL:FORWARD"
iptables -A OUTPUT  -j LOG --log-prefix "FIREWALL:OUTPUT "

# set a sane policy
iptables -P INPUT   DROP
iptables -P FORWARD DROP
iptables -P OUTPUT  DROP

# be verbose on dynamic ip-addresses (not needed in case of static IP)
echo 2 > /proc/sys/net/ipv4/ip_dynaddr

# disable ExplicitCongestionNotification
echo 0 > /proc/sys/net/ipv4/tcp_ecn

# activate TCPsyncookies
echo 1 > /proc/sys/net/ipv4/tcp_syncookies

# activate Route-Verification = IP-Spoofing_protection
for f in /proc/sys/net/ipv4/conf/*/rp_filter; do
        echo 1 > $f
done

# activate IP-Forwarding 
echo 1 > /proc/sys/net/ipv4/ip_forward
EOF

With this script your intranet should be sufficiently secure against external attacks. No one should be able to setup a new connection to any internal service and, if it's masqueraded, it's even invisible. Furthermore, your firewall should be nearly immune because there are no services running that a cracker could attack.

Note: if the interface you're connecting to the Internet doesn't connect via ppp, you will need to change ppp+ to the name of the interface which you are using. If you are using the same interface type to connect to both your intranet and the Internet, you need to use the actual name of the interface such as eth0, on both interfaces.

If you need stronger security (e.g., against DOS, connection highjacking, spoofing, etc.), have a look at the list of Links for further reading at the end of this section.

BusyBox

This scenario isn't too different from (Masquerading Router), but in this case you want to offer some services to your intranet. Examples of this can be when you want to admin your box from another host on your intranet or use it as a proxy or a name server. Note: Outlining a true concept of how to protect a server that offers services on the Internet goes far beyond the scope of this document, see Disclaimer.

Be cautious. Every service you offer and have enabled makes your setup more complex and your box less secure. You induce the risks of misconfigured services or running a service with an exploitable bug. A firewall should generally not run any extra services. See the introduction to Masquerading Router for some more details.

If the services you'd like to offer do not need to access the Internet themselves, like internal-only samba- or name-servers, it's quite simple and should still be acceptable from a security standpoint. Just add the following lines before the logging-rules into the script.

iptables -A INPUT  -i ! ppp+  -j ACCEPT
iptables -A OUTPUT -o ! ppp+  -j ACCEPT

If your daemons have to access the web themselves, like squid would need to, you could open OUTPUT generally and restrict INPUT.

iptables -A INPUT -m state --state ESTABLISHED,RELATED   -j ACCEPT
iptables -A OUTPUT                                      -j ACCEPT

However, it is generally not advisable to leave OUTPUT unrestricted. You lose any control over trojans who'd like to "call home", and a bit of redundancy in case you've (mis-)configured a service so that it does broadcast its existence to the world.

If you prefer to have this protection, you may restrict INPUT and OUTPUT on all ports except those that it's absolutely necessary to have open. Which ports you have to open depends on your needs: mostly you will find them by looking for failed accesses in your log-files.

Have a look at the following examples:

  • Squid is caching the web:

    iptables -A OUTPUT -p tcp --dport 80                              -j ACCEPT
    iptables -A INPUT  -p tcp --sport 80 -m state --state ESTABLISHED -j ACCEPT
    
  • Your caching name server (e.g., dnscache) does its lookups via udp:

    iptables -A OUTPUT -p udp --dport 53                              -j ACCEPT
    iptables -A INPUT  -p udp --sport 53 -m state --state ESTABLISHED -j ACCEPT
    
  • Alternatively, if you want to be able to ping your box to ensure it's still alive:

    iptables -A INPUT  -p icmp -m icmp --icmp-type echo-request -j ACCEPT
    iptables -A OUTPUT -p icmp -m icmp --icmp-type echo-reply   -j ACCEPT
    
  • If you are frequently accessing ftp-servers or enjoy chatting, you might notice certain delays because some implementations of these daemons have the feature of querying an identd on your box for logging usernames. Although there's really no harm in this, having an identd running is not recommended because some implementations are known to be vulnerable.

    To avoid these delays you could reject the requests with a 'tcp-reset':

    iptables -A INPUT  -p tcp --dport 113 -j REJECT --reject-with tcp-reset
    iptables -A OUTPUT -p tcp --sport 113 -m state --state RELATED -j ACCEPT
    
  • To log and drop invalid packets (harmless packets that came in after netfilter's timeout or some types of network scans):

    iptables -I INPUT 1 -p tcp -m state --state INVALID -j LOG --log-prefix \ 
    "FIREWALL:INVALID"
    iptables -I INPUT 2 -p tcp -m state --state INVALID -j DROP
    
  • Anything coming from the outside should not have a private address, this is a common attack called IP-spoofing:

    iptables -t nat -A PREROUTING -i ppp+ -s 10.0.0.0/8     -j DROP
    iptables -t nat -A PREROUTING -i ppp+ -s 172.16.0.0/12  -j DROP
    iptables -t nat -A PREROUTING -i ppp+ -s 192.168.0.0/16 -j DROP
    
  • To simplify debugging and be fair to anyone who'd like to access a service you have disabled, purposely or by mistake, you should REJECT those packets that are dropped.

    Obviously this must be done directly after logging as the very last lines before the packets are dropped by policy:

    iptables -A INPUT                        -j REJECT
    iptables -A OUTPUT -p icmp --icmp-type 3 -j ACCEPT
    

These are only examples to show you some of the capabilities of the new firewall code in Linux-Kernel 2.4. Have a look at the man page of iptables. There you will find more of them. The port-numbers you'll need for this can be found in /etc/services, in case you didn't find them by trial and error in your log file.

If you add any of your offered or accessed services such as the above, maybe even in FORWARD and for intranet-communication, and delete the general clauses, you get an old fashioned packet filter.

Conclusion

Finally, I'd like to remind you of one fact we must not forget: The effort spent attacking a system corresponds to the value the cracker expects to gain from it. If you are responsible for such valuable assets that you expect great effort to be made by potential crackers, you hopefully won't be in the need of this hint!

Extra Information

firewall.status

If you'd like to have a look at the chains your firewall consists of and the order in which the rules take effect:

cat > /etc/rc.d/init.d/firewall.status << "EOF"
#!/bin/sh

# Begin $rc_base/init.d/firewall.status

echo "iptables.mangling:"
iptables -t mangle  -v -L -n --line-numbers

echo
echo "iptables.nat:"
iptables -t nat     -v -L -n --line-numbers

echo
echo "iptables.filter:"
iptables            -v -L -n --line-numbers
EOF

firewall.stop

If you need to turn the firewall off, this script will do it:

cat > /etc/rc.d/init.d/firewall.stop << "EOF"
#!/bin/sh

# Being $rc_base/init.d/firewall.stop

# deactivate IP-Forwarding 
echo 0 > /proc/sys/net/ipv4/ip_forward

iptables -Z
iptables -F
iptables -t nat         -F PREROUTING
iptables -t nat         -F OUTPUT
iptables -t nat         -F POSTROUTING
iptables -t mangle      -F PREROUTING
iptables -t mangle      -F OUTPUT
iptables -X
iptables -P INPUT       ACCEPT
iptables -P FORWARD     ACCEPT
iptables -P OUTPUT      ACCEPT
EOF