Using Stateful Inspection


You can now match particular sorts of packets, and allow them in or out. You can even set rules that will identify the first packet in a TCP/IP request. If you can identify the first packet of a permitted data stream, you can tell PF to not only allow that packet but to allow all packets related to that first packet.

For example, suppose a SYN (connection request) packet arrives at port 80 on your OpenBSD web server. If you have a rule allowing stateful inspection, PF will examine that packet and record the source IP, source port, and various other connection characteristics such as sequence number. This information is stored in a state table, or a list of existing permitted connections. When your web server replies, PF will run that packet through the state table. When it sees that a permitted connection exists between the web server and the client requesting access, and that this packet matches the information it has for this connection, it allows the packet to pass without running it through the rules table. If an ICMP message related to a particular TCP connection arrives, stateful inspection will match the message to the proper connection and let it through. If the connection is properly terminated, or if no traffic goes over it for a reasonable length of time, the entry in the state table is discarded.

You enable stateful inspection with the "keep state" keyword at the end of your rule.

 pass in proto tcp from any to 192.168.1.5 port 80 1 flags S/SA 2 keep state 

Not only can packets arrive at your web server now, but also with the addition of 2 stateful inspection your web server will be able to respond. Note that this rule only matches 1 initial TCP connection requests, so an intruder would not be able to send a packet that appeared to be part of an outgoing connection instead, or any of the other wide range of TCP/IP tricks that intruders have used through the years. (Without this flag, you could clear your state table and PF would automatically rebuild it from existing connections. We'll talk about that in "Managing Stateful Inspection.")

UDP State

UDP traffic is stateless, but in some cases you may well expect a response packet. As the firewall administrator, you must know if a particular application protocol that runs over UDP will send a response or not. If you are expecting a response, you can use stateful inspection to match based on hostname and port. Because UDP packets don't have any of TCP's fancy flags, that's the best any filter can do. For example, systems expect replies to DNS queries, and you should know that. In this example, we allow anyone within the firewall to access the ISP's nameserver and receive the replies.

 pass out proto udp from any to 10.0.0.5 port 53 keep state 

With all the caveats, UDP stateful inspection might seem to be risky. The risks are not as high as they might seem, however. To breach UDP stateful inspection, the intruder would have to send UDP packets to port 53 on a particular client that appeared to be from port 53 on the nameserver, and do this before the stateful inspection timed out, and be able to use that packet to compromise the client in some way. Can it be done? Yes. Is it very difficult? Absolutely.

In an ideal world, you would never permit UDP through your firewall. But that isn't very likely given the current design of the Internet.

ICMP States

While ICMP messages that are part of TCP connections are handled by stateful inspection in the TCP connection, ICMP messages used for connections such as ping(8) and traceroute(8) have separate stateful requirements. PF is aware of the most common of these and can use stateful inspection to allow the proper replies. We earlier saw how to allow ping requests into a packet filter; now, we can easily allow the replies:

 pass in inet proto icmp icmp-type 8 code 0 keep state 

State Modulation

State modulation is much like stateful inspection, but provides additional security enhancements for poor TCP/IP stacks. Every connection request contains an initial sequence number, or ISN, that the client and the server both use to track individual connections. If you can guess this ISN, you can hijack the connection and feed the client any information you like. This might sound unlikely, but the most common TCP/IP stack in the world chose astonishingly poor ISNs, making ISN hijacking a popular technique.

State modulation replaces the ISN sent by every machine involved in a connection by a highly random ISN, and translates that ISN as needed for each client. While it only works for TCP connections, it provides a much greater level of TCP protocol security than the naive TCP stack found in the most common desktop operating systems.

You enable state modulation with the "modulate state" keyword. This includes stateful inspection. Here, we enable state modulation for web browsing on every client behind our network:

 pass out from any to any port {80, 443} flags S/SA modulate state 

Inspection and Modulation Options

Stateful inspection and state modulation have two settings that can be tweaked: the number of states a particular rule will match and the timeouts for the state table. Each option should be given in parenthesis after the "keep state" or "modulate state" statements.

You can use the "max" keyword to limit the number of entries in the state table. You might be low on system resources and want to conserve memory, but this is also useful for connection rate limiting. If someone posts the script for the next Harry Potter movie on your web server, you could find your bandwidth devoured by hordes of rabid fans. The max keyword will restrict the state table to that many entries in the state table. Additional packets that would match the rule and keep state are rejected. When an existing connection times out or terminates, another connection may be opened. This example limits port 80 to 100 simultaneous connections:

 pass in proto tcp from any to 192.168.1.5 port 80 flags S/SA keep state (max 100) 

You can use this same technique to implement rate limits to any port, and it is much simpler than limiting rates via the program itself or by using bandwidth managers. I personally prefer to return requested information quickly for the users that are lucky enough to get in and get them off my server so I can serve other people, as opposed to making everyone's connections unbearably slow via bandwidth queues. Your preferences or requirements may be different, of course.

Timeouts can be adjusted on a per-rule basis, much as the global stateful inspection timeouts can be set (see OPTIONS). While I find the defaults perfectly sensible for almost all situations, there are occasional rules where adjusting them makes sense.

You can view the current timeout settings with "pfctl -s timeouts." This will spit out the stateful inspection timeouts for every state of a TCP connection. By default, idle TCP sessions time out after 24 hours. Here I tell TCP connections to port 80 on my web server to time out in only one hour, or 3,600 seconds:

 pass in proto tcp from any to 192.168.1.5 port 80 flags S/SA keep state (tcp. established 3600) 

This is generally not necessary, but you might have special circumstances.

Stateful inspection is absolutely necessary if you are using NAT (see "Network Address Translation"). Without stateful inspection, your packet filter will be unable to match translated addresses to real addresses.




Absolute Openbsd(c) Unix for the Practical Paranoid
Absolute OpenBSD: Unix for the Practical Paranoid
ISBN: 1886411999
EAN: 2147483647
Year: 2005
Pages: 298

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net