Linux also provides a facility comparable (to some extend) with transparent proxies (not requiring any changes for users or application software), which is implemented as part of the IP firewall module and can be configured using a similar set of rules.
Network security, and more specifically the use of Internet firewalls, is one of today's hottest topics in the computer business. Every private network that is going to be connected to the Internet needs an appropriate firewall, being some combination of hardware, software, and procedures, to protect it. Most commercial firewall products are quite expensive, especially for small companies.
An alternative is to use Linux, a freely available operating system. We will focus on one aspect of Linux, the IP packet screening facilities, being one of the components for building firewalls based on Linux. A good firewall certainly needs more than packet filters. At the end you'll find some recommendations for using Linux systems as a complete firewall solution.
This paper is based on release 1.3.88 of the Linux kernel and version 2.0 of the ipfwadm utility. Be aware of the fact that some details might have changed in the next production release of Linux.
Copyright © 1996 by X/OS Experts in Open Systems BV. All rights reserved.
Before describing the Linux implementation of IP packet filtering, we will briefly introduce the underlying general concepts.
IP packet filters inspect network datagrams (IP packets) and decide whether these packets are allowed to pass the filter or not. These inspections may take place at several stages, like the moment packets arrive on the system or when they are about to be forwarded to another system.
The decision to let a filter block certain packets is usually based on several criteria, being checked against the contents of the IP packet and some environmental parameters:
An IP packet filter can react in different ways to packets, depending on the filters and the capabilities of the filtering system. The most obvious actions are: let the packet pass the filter normally or drop the packet silently. Some filters also offer the possibility to send some notification (like an ICMP Destination Unreachable message) back to the sender, in case a packet is blocked by the filter. Besides that, filters often include some logging facility, to facilitate the network administrator in detecting if someone is trying to break in.
There are several ways to implement packet filters in a UNIX system. The most efficient way is to implement it in the kernel. One of the disadvantages of this method is that it is not very flexible. Another method is to let some user-level process do the filtering. Such a daemon process has to get the relevant information of all IP packets (at least part of the IP and TCP/UDP headers, possibly even the data part) via some system call, apply its filter rules, and pass the answer back to the kernel. The (freely available) screend package behaves like this. The major drawback of these implementations is the considerable overhead generated by the system calls and process scheduling.
The Linux kernel provides native support for IP packet filtering at several stages: when a packet is received, when packet is sent, and when a packet is being forwarded (see figure 1).
Each of the three filters consists of a default policy and a list of filter rules. Every filter rule defines some packet characteristics, like IP addresses, an optional network device, and several other options. Furthermore, each rule has a policy associated with it, defining what to do when a packet matches with the rule.
The algorithm used in the filters can be described as follows:
There are currently three policies supported in Linux:
Filter rules in Linux contain the following items:
Now that we have seen the basic concepts of the Linux firewall filters, we will show how to manage the filter rules from an administrator point of view.
The interface for managing the kernel-level filter rules at user-level mainly consists of two parts:
/proc/net/ip_input /proc/net/ip_output /proc/net/ip_forward
Each of these files lists the default policy, followed by the details of all rules (if any) belonging to that filter, in a compact format.
The ipfwadm command provides a command-level interface for managing the Linux firewall facilities: it can be used to change or inspect all aspects of the kernel filters. Let's start with a simple example:
ipfwadm -I -a deny -S 192.168.22.0/24 -D 0.0.0.0/0
This command basically means ``refuse all incoming packets originally coming from network 192.168.22.0''. It appends (-a) a new rule to the list of filter rules belonging to the input firewall (-I). The output and forward filters can be changed by using the -O and -F options, respectively. After the append command the rule's policy is specified. Valid keywords are accept, deny, and reject (refuse the packet, but return an ICMP message). The source (-S) and destination (-D) addresses both include a mask: the suffixes /24 and /0 are equivalent to /255.255.255.0 and /0.0.0.0, respectively. Every IP address will match the specified destination, because the mask only contains 0's (we could also have written something like 22.214.171.124/0).
ipfwadm -I -a accept -k -P tcp -S 0.0.0.0/0 telnet \ -D 192.168.37.1 1024:65535 ipfwadm -O -a accept -P tcp -S 192.168.37.1 1024:65535 \ -D 0.0.0.0/0 telnet
The command creates two rules (one for the input firewall, one for the output firewall) that accepts all packets belonging to an outgoing telnet connection (here it is assumed that our local IP address is 192.168.37.1). The protocol is specified via the -P option and after the IP address a service name (telnet, specifying port 23) and a port range (in this case all unpriviliged ports) are specified. The -k option makes the input rule only match with packets having the TCP ACK flag set. This prevents someone from trying to initiate a connection from the outside (using source port 23) to some unpriviliged port on our system.
Unfortunately, enabling a service is not as easy for all services. The ftp protocol, for example, uses a separate, incoming connection to transfer the data. So, using ftp (unless used in ``passive mode'') requires to allow a connection being initiated from outside your own network. Setting up a set of firewall rules for ftp would look like:
ipfwadm -I -a accept -k -P tcp -S 0.0.0.0/0 ftp \ -D 192.168.37.1 1024:65535 ipfwadm -O -a accept -P tcp -S 192.168.37.1 1024:65535 \ -D 0.0.0.0/0 ftp ipfwadm -I -a accept -P tcp -S 0.0.0.0/0 ftp-data \ -D 192.168.37.1 1024:65535 ipfwadm -O -a accept -k -P tcp -S 192.168.37.1 1024:65535 \ -D 0.0.0.0/0 ftp-data
Here it is assumed that ftp-data is a valid service name for TCP port 20.
With the -p (set policy) command a default policy is specified.
ipfwadm -F -p deny
In this case, all forwarding is disabled, unless packets match with one of the forward rules, explicitly allowing them to pass the filter. Filters can be listed using the -l command, like in:
ipfwadm -I -l
This command would produce the following result, after issuing the above ipfwadm commands for the input firewall:
IP firewall input rules, default policy: accept
typ prot source destination ports
den all 192.168.22.0/24 anywhere n/a
acc tcp anywhere gw.foo.com telnet -> 1024:65535
acc tcp anywhere gw.foo.com ftp -> 1024:65535
acc tcp anywhere gw.foo.com ftp-data -> 1024:65535
The printed hostname, gw.foo.com, corresponds to the local system, having IP address 192.168.37.1. There are several options to change or extend the given output of ipfwadm. The above example show the most simple format.
Some more hints for managing firewall filters:
This ensures that you don't have any time intervals, during which network traffic is not controlled by the firewall.
See the ipfwadm(8) manual page for more details and other options.
The Linux kernel provides an additional mechanism to use in firewall solutions: masquerading of IP packets. This means that some or all packets being forwarded by a Linux system can be changed as if there were sent from the local system. So, the source IP address is replaced by the local IP address and the source port is replaced by a locally generated port (e.g., 60005). Because an administration is kept of masqueraded sessions, incoming packets for that port will automatically be ``demasqueraded'' and forwarded to the system that originally initiated the session.
The next table summarizes the masquerading function, given a telnet session from an internal host (192.168.37.15) to an external host (10.42.17.8), passing a Linux system doing masquerading (192.168.37.1):
|IP address||port||IP address||port|
Masquerading takes place after passing the forward firewall filter. Demasquerading is done after receiving a packet and demasqueraded packets bypass the forwarding filter. Figure 2 shows the kernel flow diagram including (de)masquerading.
Masquerading is not as easy as it seems: some protocols need special care. One of the problem areas is found in the widely used ftp protocol, because this protocol uses a second session (normally initiated by the remote site) for transferring the actual data. A similar problem arises with the IRC protocol. The Linux IP masquerading implementation deals with such protocol-specific features in separately loadable modules. Another problem is that a transparent proxy should operate on transport level connections, whereas masquerading is implemented in the network layer. The current implementation tries to address this with a limited session administration, but there are still some weaknesses to work on.
Masquerading can be enabled by specifying a special policy for a forward filter rule. The next command creates a rule that makes every outgoing telnet session being masqueraded (given that our local network has address 192.168.37.0):
ipfwadm -F -a masquerade -P tcp -S 192.168.37.0/24 \ 1024:65535 -D 0.0.0.0/0 telnet
The masquerade policy is in fact a variant of the accept policy: the packet is accepted (that is, allowed to be forwarded), but it gets masqueraded before being sent out. Because the masquerading mechanism depends on port numbers, it only works for TCP or UDP packets. So, be careful when using commands like:
ipfwadm -F -a masquerade -S 192.168.37.0/24 -D 0.0.0.0/0
This command creates a rule that will cause all outgoing TCP and UDP traffic to be masqueraded. But it will also let all other packets (like ICMP messages) be forwarded unchanged, because they will also match with this rule! So, it's probably better to explicitly handle those cases, like with:
ipfwadm -F -p deny ipfwadm -F -a masquerade -P tcp -S 192.168.37.0/24 \ -D 0.0.0.0/0 ipfwadm -F -a masquerade -P udp -S 192.168.37.0/24 \ -D 0.0.0.0/0
Especially when using unregistered IP addresses on your internal network (like the addresses defined in RFC1597 or, even worse, illegally used addresses), no packets should ever be forwarded directly.
Please note that there are no ``masquerading rules'', but only forwarding rules with a special policy. So, you can list the rules with a command like:
ipfwadm -F -l
which will (given the above example) result in something like:
IP firewall forward rules, default policy: deny
typ prot source destination ports
msq tcp 192.168.37.0/24 anywhere any -> any
msq udp 192.168.37.0/24 anywhere any -> any
Besides this static information, the list of sessions currently being masqueraded can be inspected. This is dynamic information, changing every moment, which can be used to keep track of the external connections being active. The command
ipfwadm -M -l
might for example produce the following output:
IP masquerading entries
prot expire source destination ports
tcp 13:00.15 int1.foo.com ext2.bar.com 1017 (60001) -> login
tcp 14:15.60 int2.foo.com ext1.bar.com 1346 (60010) -> telnet
tcp 14:52.82 int1.foo.com ext1.bar.com 1348 (60015) -> ftp
The above table shows three sessions being masqueraded. The information is read from the pseudo-file /proc/net/ip_masquerade, which is converted to a human-readable format by ipfwadm.
In Linux, IP traffic can be counted using accounting rules, defined by the same characteristics as the firewall rules. Accounting is done at two places: when a packet is received and when a packet is sent out (see figure 3).
So, a packet being forwarded is counted twice: the first time just after its arrival, the second time when it is being sent out again. There is one single list of accounting rules, that is being used for both incoming and outgoing traffic. For every packet, all rules in this list are checked and the packet and byte counters of every matching rule are incremented. Note the difference with the firewall lists: scanning a list there stops at the first match.
The following ipfwadm command counts all http traffic related to people using your WWW-server from the outside:
ipfwadm -A -a -b -W eth1 -P tcp -S 0.0.0.0/0 \ -D 192.168.37.1 www
Here it is assumed that the local system, hosting the WWW-server, has IP address 192.168.37.1. We see some new options in this command. The -b option means ``bidirectional'', and makes that also packets coming from 192.168.37.1 (port 80) are counted. The -W option has an interface name as parameter, so that only traffic via that particular interface is taken into account. Packets passing another interface (e.g., an interface eth0 connected to your internal network) are not counted here.
Some suggestions to use accounting most effectively:
When listing the accounting rules (and the associated values) with ipfwadm, the pseudo-file /proc/net/ip_acct is read.
This section lists a complete example for a set of firewall filters on a Linux system acting as a gateway between the Internet and a private network. Note that this example is only included for illustrative purposes. Although it will protect the internal network to some extend, we strongly discourage to consider this to be a complete, robust firewall solution.
The example applies to a gateway system (gw.foo.com) connected to the Internet using interface 192.168.22.15 and to an internal network (192.168.37.0) via interface 192.168.37.1. The system is as a public WWW and ftp server, it can send and receive mail, it acts as a mail relay host for the internal network, and it is the primary DNS server for the foo.com domain.
Hosts on the private network can directly use telnet, WWW, ftp, gopher and WAIS services on the Internet (which is not a recommended firewall architecture). Also, ICMP traffic is allowed without any restrictions (e.g., to enable ping). Note that traceroute will not work, because this is using UDP packets to some unpriviliged ports.
# Some definitions for easy maintenance. LOCALHOST="gw.foo.com" IFEXTERN="192.168.22.15" IFINTERN="192.168.37.1" LOCALNET="192.168.37.0/24" ANYWHERE="0.0.0.0/0" UNPRIVPORTS="1024:65535" # ====== Basic rules. # Sure we're paranoid, but are we paranoid enough? ipfwadm -I -p deny ipfwadm -O -p deny ipfwadm -F -p deny # Handle spoofed packets. ipfwadm -I -a deny -V $IFEXTERN -S $LOCALNET -D ANYWHERE ipfwadm -I -a deny -V $IFEXTERN -S $IFEXTERN -D ANYWHERE # Unlimited traffic within the local network. ipfwadm -I -a accept -V $IFINTERN -S $ANYWHERE -D $ANYWHERE ipfwadm -O -a accept -V $IFINTERN -S $ANYWHERE -D $ANYWHERE # Unlimited ICMP traffic (not recommended). ipfwadm -I -a accept -P icmp -S $ANYWHERE -D $ANYWHERE ipfwadm -O -a accept -P icmp -S $ANYWHERE -D $ANYWHERE ipfwadm -F -a accept -P icmp -S $ANYWHERE -D $ANYWHERE # ====== External use of our system. # Public access for e-mail, ftp, WWW, and DNS. ipfwadm -I -a accept -P tcp \ -S $ANYWHERE -D $LOCALHOST smtp ftp www domain ipfwadm -I -a accept -P udp \ -S $ANYWHERE -D $LOCALHOST domain ipfwadm -I -a accept -k -P tcp \ -S $ANYWHERE -D $LOCALHOST ftp-data ipfwadm -O -a accept -P tcp -S $LOCALHOST smtp ftp \ ftp-data www domain -D $ANYWHERE ipfwadm -O -a accept -P udp \ -S $LOCALHOST domain -D $ANYWHERE # ====== Internal use of the Internet. # Outgoing packets. ipfwadm -O -a accept -P tcp -S $LOCALNET $UNPRIVPORTS \ -D $ANYWHERE smtp ftp ftp-data www telnet gopher \ z3950 domain ipfwadm -O -a accept -P tcp -S $IFEXTERN $UNPRIVPORTS \ -D $ANYWHERE smtp ftp ftp-data www telnet gopher \ z3950 domain ipfwadm -O -a accept -P udp -S $LOCALNET $UNPRIVPORTS \ -D $ANYWHERE z3950 ipfwadm -O -a accept -P udp -S $LOCALHOST $UNPRIVPORTS \ -D $ANYWHERE z3950 domain ipfwadm -F -a accept -P tcp -S $LOCALNET $UNPRIVPORTS \ -D $ANYWHERE ftp ftp-data www telnet gopher z3950 ipfwadm -F -a accept -P udp -S $LOCALNET $UNPRIVPORTS \ -D $ANYWHERE z3950 # Incoming packets. ipfwadm -I -a accept -k -P tcp \ -S $ANYWHERE ftp www telnet gopher z3950 domain \ -D $LOCALNET $UNPRIVPORTS ipfwadm -I -a accept -k -P tcp \ -S $ANYWHERE ftp www telnet gopher z3950 domain \ -D $IFEXTERN $UNPRIVPORTS ipfwadm -I -a accept -P tcp \ -S $ANYWHERE ftp-data -D $LOCALNET $UNPRIVPORTS ipfwadm -I -a accept -P tcp \ -S $ANYWHERE ftp-data -D $IFEXTERN $UNPRIVPORTS ipfwadm -I -a accept -P udp \ -S $ANYWHERE z3950 -D $LOCALNET $UNPRIVPORTS ipfwadm -I -a accept -P udp -S $ANYWHERE z3950 domain \ -D $LOCALHOST $UNPRIVPORTS ipfwadm -F -a accept -k -P tcp \ -S $ANYWHERE ftp www telnet gopher z3950 \ -D $LOCALNET $UNPRIVPORTS ipfwadm -F -a accept -P tcp \ -S $ANYWHERE ftp-data -D $LOCALNET $UNPRIVPORTS ipfwadm -F -a accept -P udp \ -S $ANYWHERE z3950 -D $LOCALNET $UNPRIVPORTS
Some further remarks about the above example:
Although the current Linux firewall facilities are very useful, there are still some weaknesses and missing features. Therefore, possible areas for improvement in future Linux versions might be:
In general, most of the optimal firewall solutions are some mixture of IP filters and application-level proxies, although the detailed architecture highly depends on the target environment. Proxies are mostly used for enabling extra authentication methods and advanced logging facilities. Linux systems can be used as a complete firewall solution, when using additional packages like the Firewall Toolkit of Trusted Information Systems, Inc. (TIS), S/Key or one of its derivatives like OPIE (One-time Passwords In Everything), SOCKS, etc. These packages are freely available and are known to work on Linux. But keep in mind that the use of a single bastion host without a filtering router is not recommended practice.
The pro's en con's of using free software for mission-critical applications like a firewall often focus on the black box versus crystal box debate. A commercial product usually doesn't come with source code, so nobody can study that code to find security leaks and try to misuse them. This is the black box concept, sometimes called ``security by obscurity''. On the other hand, when using freely available software, everybody, including the user, can look for possible bugs or weaknesses. The source code is available, so this approach is often referred to as a crystal box (of course, configuration details, local enhancements, etc., are not known publically). This usually will make bugs be found earlier, and fixes are just made available via the Internet, often within hours after detecting a bug.
The costs of a Linux firewall solution are relatively low. Given today's decreasing prices of PC's, a single Linux PC acting as a filtering router might cost less than Dfl. 1,500. A more advanced Linux system, also hosting several proxy services, a WWW-server, etc., will cost no more than Dfl. 3,000. Of course, these prices do not include consulting services to configure a customized firewall solution. But, be aware of the fact that you'll also have additional costs when buying a commercial firewall product. The quality of a total firewall solution highly depends on a well-designed configuration scheme, no matter whether it's based on commercial or free components.
The newest Linux kernel is available from:
The home page of ipfwadm on the World Wide Web:
The ipfwadm package can be obtained via:
Some recommended books about firewalls:
Copyright © 1996 by X/OS Experts in Open Systems BV. All rights reserved.
Last-modified: Wed, 06 Aug 1997 18:51:24 GMT