The packet filter is responsible for detecting whether an incoming packet is actually a response to a prior outbound request. This task is difficult, however, because packet-filtering hardware is usually stateless; it must decide whether to drop or pass a packet based only on the physical port on which the packet arrives, the port on which it will be forwarded, and data in the packet itself. Packet filters do not, in general, have access to either previous packets or any internal host state. Furthermore, caching information about previous packets in a packet filter is equivalent to writing an application-level proxy and is impractical because it would increase the latency of all incoming packets.
TCP Request-Response: Filtering at Internal Hosts: Packet filtering is best suited to handle TCP-based services that establish explicit connections. In terms of our request-response policy, we treat connection establishment as a ``request'' and data transmission on an established TCP connection as a ``response.'' Intuitively, the fact that an internal host decides to establish a TCP connection to an external host is, in itself, implicit permission for that external host to send packets back through our firewall on that TCP connection.
In other words, the request-response policy implies that our firewall should allow external hosts to participate in TCP connections established by any host inside our firewall, but external hosts may not initiate such connections themselves. We achieve this by filtering incoming connection requests and relying on our internal hosts to drop extraneous TCP segments.
We filter incoming connection requests using standard SYN filtering. The TCP connection-establishment phase is the three-way handshake: SYN, SYN+ACK, ACK. Our filtering policy for TCP admits all inbound TCP packets, except packets attempting to initiate the three-way handshake---that is have SYN set but not ACK.
External hosts can therefore inject arbitrary TCP packets into our secure network except connection-request packets. We rely on the TCP module on all of our hosts to function correctly and discard TCP segments that do not match an established connection. Because an external host cannot initiate a TCP connection, TCP packets constructed by a would-be intruder should always be dropped by the destination host.
Thus, the combination of filtering external SYN packets, admitting all other TCP segments, and a working TCP implementation achieves precisely the desired request-response policy. This implementation does leave us vulnerable to denial-of-service and hijacking attacks, which are discussed in Section 6.2.
Connection-Based UDP Services: A few UDP-based application protocols, such as AFS, use well-known kernel ports at both the client and server hosts. We treat such protocols much like TCP connections by deploying a heuristic filter (based on source and destination addresses and port numbers and packet contents) and trusting internal hosts to further filter inappropriate responses.
NFS-client filtering at hosts: NFS  is a request-response protocol: the NFS client sends RPC  requests to the NFS server, and the server returns the results. The request-response rule of our security policy implies that NFS clients protected by our firewall should be permitted to NFS-mount filesystems from NFS-servers outside our firewall if group members behind the firewall choose to do so. We have found this to be a useful way to access resources such as campus software archives and Linux slackware distributions. This policy decision is markedly different from traditional network firewall policies.
As with TCP, we support a request-response policy for NFS by using a coarse-grain filter and trusting internal hosts to safely ignore and drop unexpected response packets. Our packet filter allows any packets out, including NFS requests. It also allows in any packets with a source port of 2049, with an SunRPC type of RPC_REPLY, and with the SunRPC program number set to RPCPROG_NFS.
The process of performing an NFS mount actually requires an exchange with a ``mount daemon'' on the remote NFS server to obtain an initial NFS ``file handle.'' The mount daemon is, in turn, located via an RPC request to the remote server's portmapper. To avoid problems with UDP port mapping, we use a modified NFS-mount utility, that performs these RPC transactions over TCP instead of UDP.
Our heuristic test for NFS response packets is currently the biggest hole in our firewall: A would-be intruder could generate UDP packets with all of the attributes of a valid response and send them to an arbitrary machine behind our firewall. We trust that each host's NFS client software correctly drops packets that are not valid responses to an outstanding NFS request and that our heuristic is strong enough to prevent forged responses from affecting other UDP clients. The risks that our policy entails in our environment are further discussed in Section 6.2. Modern NFS clients and servers are configurable to run entirely over TCP, which fits entirely within our TCP request-response implementation. Unfortunately, because our internal workstations run Unix with NFS implemented inside the kernel, using these newer implementations would require kernel modifications, compromising our goal of easy firewall installation.