-The Big Bad Wolf
UNIX has traditionally been the platform of choice for users wanting robust yet flexible IP networking. In recent years IP masquerading has become very desirable as more people have multiple machines from which they wish to access the Internet while fewer of these people have the luxury of allocating subnets to their dial-up links.
The Portable UNIX Firewall (PUF) is a portable masquerading IP firewall. It provides a service previously only available through FreeBSD's PPP daemon, the Linux kernel-level masquerading firewall, or Sun's SunScreen product. Leveraging established technology such as Berkeley sockets and libpcap, PUF requires approximately 50 lines of code to port it to a new platform. Additionally, PUF resides entirely in userspace, requires no kernel modifications, and may be run on a machine also acting as a ``normal'' router. These things have simply been unavailable previously.
This paper describes, in some detail, the theory and operation of PUF and masquerading firewalls in general. It assumes that the reader has a grasp of the structure of the Internet. This paper should not be considered a technical guide, a functional specification, or anything more than an introduction to PUF and the subject of IP masquerading.
More and more people have small networks at home or in remote locations. Frequently these people are forced to share one dialup Internet link among all their machines. There are only a few ways to do this effectively.
The Internet Service Provider can provide the home network with an entire subnet. This allows one computer to act as a router and route traffic between the LAN and the Internet. There is no compromise in this case. Unfortunately, very few, if any, service providers will do this for free and in the case of corporate installations, using a subnet for each dialup link rapidly exahausts the available IP address pools.
Each machine on the remote network can dialup when it needs to use the Internet. While very effective and easy to implement, this means that there can also be no more than one machine on the Internet at one time.
One machine can run proxy servers and all the other machines can use those proxies. This is an excellent option in terms of performance. Frequently proxy servers will cache content as well, providing instant response when the data is accessed for a second time. Unfortunately, this requires that applications running on the clients understand how to use the proxy.
One machine can act as a masquerading firewall. This is probably the best solution if the dialup line only has one IP address rather than an IP subnet. Additionally, this method can be used in conjunction with proxy servers to increase performance for those applications capable of using them.
Figure 1 illustrates the concept behind IP masquerading. The firewall has two or more network interfaces, similar to a regular router. One interface is on the LAN side and one is on the WAN side. All hosts on the LAN side use host G as their default gateway. When a LAN host initiates a connection to a remote host, the firewall proxies the connection. In this way, it appears that all traffic is coming from host H, the only globally known address. It is then the responsibility of the firewall to maintain mappings between IP sessions established from address H and IP sessions established on the LAN.
This is similar to the operation of NAT or a SOCKS proxy server with the exception that a masquerading firewall requires only one IP address, as opposed to NAT, and is transparent to clients, as opposed to SOCKS.
The firewall takes a number of steps necessary to make the session established between H and a remote host appear, on the LAN, as if it were established between one of the LAN hosts and the remote host.
The user looking for IP masquerading previously had three options: they may use the masquerading firewall built into the Linux kernel, they may use the userland PPP daemon for FreeBSD, or they may use the SunScreen product from Sun. All of these solutions have advantages and disadvantages.
PUF resides entirely in userland meaning that it can be modified, improved, started, and stopped all without recompiling the kernel or even shutting down the system. Furthermore, it is, as the name implies, extremely portable. There are a great many UNIXes that may support PUF eventually. It already supports Linux and DEC ULTRIX. This means that the user's choice of one flavor of UNIX versus another isn't influenced by the lack of availability of masquerading support.
In all fairness though, all is not roses. There are some significant disadvantages to the PUF architecture. Perhaps the most notable of these is the performance drawback of executing outside the kernel. Kernel level firewalls have access to all the goodies inside the kernel and can be much more efficient with packet translation since they have all the information that may not be available to user level processes. The constant system calls can also impact performance negatively as costly switches between kernel and user mode are required. However, processor is cheap and tests have shown that, at least in the case of dialup Internet access, the performance impact is negligable.
The operation of PUF, while conceptually very simple, turns out to be a bit more difficult in practice. In the following sections, we'll examine the operation of PUF from interception of the hardware frame to establishing and managing a TCP connection.
Since PUF must act as a default gateway (Internet router), it is important that we understand the concept of the hardware frame. This is a topology specific frame that wraps up all network traffic. For simplicity's sake we'll use ethernet as it is the most common and most easily understood network topology.
Each ethernet frame consists of a header and data (see Figure 2). The header contains three fields:
If the protocol is IP, we strip off the ethernet headers, recording the data first, and continue on to the IP datagram processing.
Each piece of data on the Internet is wrapped up as an IP datagram (also known as an IP packet). The IP datagram consists of two important pieces: the header, and the payload. It is the header that presents us with the most immediate problem (see Figure 3).
While we are concerned with all the fields, the ones that are most important are as follows:
In the most basic operations, PUF strips off the IP headers, sends the data to the remote host, waits for a response, and spoofs the response data onto the LAN with the appropriate IP headers. It's usually not this easy.
Of all the protocols in the IP suite, UDP is probably the easiest protocol for us to handle. The packet header format is relatively simple (see Figure 4). After determining that the IP datagram is UDP, we strip off the IP headers and send the UDP packet on for processing.
On the whole, processing UDP is very simple. When receiving UDP traffic off the LAN, we simply take the data out of the packet, and send it, via UDP, to it's intended host from the WAN interface. All this is accomplished using standard Berkeley sockets. Since UDP ports do not have to be bound to use (unlike TCP), we don't need to trouble ourselves with changing the source or port. However, if the source port has been bound on the WAN interface, we may never hear the response.
Probably the most difficult thing about UDP is that many of the protocols that ride on UDP embed the address of the originating host within the data portion. An example of this would be talk. The BSD talk protocol contains the IP address and UDP port of the originating request within the data portion of the UDP packet. This must then be replaced with the IP address of our firewall's WAN interface. Other programs operate similarly.
After UDP, ICMP is the simplest protocol. However, lest you get the wrong idea, ICMP is a relatively complex protocol. The Internet Control Message Protocol (ICMP) provides last minute routing information, traffic management, network timing and health reports among other thigsn. There are eleven different ICMP messages. Each message has one of three sets of header fields. PUF currently supports only one of these three types and may never support the other two. This ICMP message format is detailed in Figure 5.
This message style is the one used by ICMP's echo, echo reply, information request, information reply, timestamp, and timestamp reply messages. These messages are commonly used by hosts to verify the status (speed, reliability) of the network.
The ICMP checksum is simply a checksum of the ICMP packet and does not rely on anything from the IP header, unlike UDP and TCP. For this reason, processing these messages is simply a matter of copying the entire ICMP message and retransmitting it from the WAN interface.
Without any question, TCP traffic is the most difficult to process. With a number of advanced features, TCP is very complex. In addition to this advanced feature set and unlike UDP and ICMP, the Berkeley sockets interface does not always provide low level access to TCP sessions (this feature was not present until 4.4BSD) . This means that while we have access to the raw TCP packet on the LAN side, on the WAN side we are simply given a file descriptor. That makes it the responsibility of PUF to manage the LAN side of the TCP session manually. Figure 6 shows the format of a TCP packet.
The following fields are of particular importance and difficulty to the firewall:
In essence, the firewall client establishes a TCP session with PUF which then manages that session while the connection to the remote host is managed by UNIX and thus is totally transparent to PUF.
So far, we've really only seen how PUF deals with traffic on the LAN in its role as a masquerading firewall. Very little attention has been given to how it handles traffic destined from the WAN to the LAN.
This is really quite simple. When a session (ICMP, UDP, TCP) has been established through the firewall, PUF makes a session entry indicating this. Simultaneously, it establishes a connection to the remote host. In the event of UDP or ICMP this has the effect of simply setting the destination for subsequent packets. In the case of TCP, a connection attempt is made. If this fails, a RESET packet is sent to the originating LAN host indicating failure. Otherwise, it proceeds with the establishment of the session by sending the appropriate SYN message. If in the course of the session the remote host closes the connection, it is the responsibility of PUF to instruct, with a series of TCP messages, the client side to close it's connection. All other data received from the WAN socket must be wrapped up with the appropriate IP and TCP headers, including proper sequence and acknowledgement numbers, and sent on its way.
WAN to LAN data transmission is generally easier than LAN to WAN transmission, especially in the case of TCP.
In this section, we will simply examine the current state of PUF. The things that work are as follows:
The things that don't work properly:
Despite its many shortcomings, PUF is impressive given that it implements a transparent masquerading firewall in a relatively platform independent fashion. It has been successfully used to establish connections of various protocols from multiple machines concurrently. It is in use on a daily basis and is extremely stable, requiring restarting only to put new code in place. In short, it works as advertised and there's no reason that it can not be a fully functional masquerading firewall as capable as any proprietary, non-portable, or kernel-based one.
The follow materials are good starting points for anyone who is interested in more technical examinations of the issues PUF must deal with:
J. Postel. RFC 768: User Datagram Protocol. USC/Information Sciences Institute, August 1980.
J. Postel. RFC 791: Internet Protocol. Defense Advanced Research Projects Agency, September 1981.
J. Postel. RFC 792: Internet Control Message Protocol. USC/Information Sciences Institute, September 1981.
J. Postel. RFC 793: Transmission Control Protocol. Defense Advanced Research Projects Agency, September 1981.
I P. Francis, K. Egevang. RFC 1631: The IP Network Address Translator (NAT). Cray Communications, NTT Software Lab; May 1994.
S. McCanne, V. Jacobson. The BSD Packet Filter: A New Architecture for User-level Packet Capture. Lawrence Berkeley Laboratory, December 1992.