View Single Post
  #8   (View Single Post)  
Old 29th October 2008
J65nko J65nko is offline
Join Date: May 2008
Location: Budel - the Netherlands
Posts: 3,506

If you don't show the complete ruleset it is very difficult to diagnose the problem.
There probably is some other rule that is blocking the smtp traffic. Remember: in pf the last matching rule wins.

These rules are still not correct
# pass smtp
pass in quick on $ext_if proto tcp from any to $ext_if port 25 keep state
pass out quick on $ext_if proto tcp from any to any port 25 keep state
You have two options to do it correctly:
  1. Use no keep state at all
    pass in quick on $ext_if proto tcp from any to $ext_if port 25
    pass out quick on $ext_if proto tcp from any to any port 25
    In this case the FBSD 7.0 pf will add automatically flags S/A keep state
  2. Use flags S/A keep state yourself:
    pass in quick on $ext_if proto tcp from any to $ext_if port 25 flags S/SA keep state
    pass out quick on $ext_if proto tcp from any to any port 25 flags S/SA keep state
Daniel Hartmeier, one of the pf architects explains it as follows in

Create TCP states on the initial SYN packet

Ideally, TCP state entries are created when the first packet of the connection, the initial SYN is seen. You can enforce this by following a simple principle:
Use 'flags S/SA' on all 'pass proto tcp keep state' rules!
All initial SYN packets (and only those packets) have flag SYN set but flag ACK not set. When all your 'keep state' rules that can apply to TCP packets are restricted these packet, only initial SYN packets can create states. Therefore, any TCP state created is created based on an initial SYN packet.

The reason for creating state only on initial SYN packets is a TCP extention called 'window scaling' defined in RFC 1323. The field of the TCP header used to advertise accepted windows became too small for today's fast links. Modern TCP/IP stacks would like to use larger window values than can be stored in the existing header field. Window scaling means that all window values advertised by one peer are to be multiplied by a certain factor by the receipient, instead of be taken literally. In order for this scheme to work, both peers must understand the extention and advertise their ability to support it during the handshake using TCP options. The TCP options are only present in the initial SYN and SYN+ACK packets of the handshake. If and only if both of those packets contain the TCP option, the negotiation is successful, and all further packets' window values are meant to be multiplied.

If pf didn't know about window scaling being used, it would take all advertised window values seen literally, and calculate its windows of acceptable sequence number ranges incorrectly. Typically, peers start to advertise smaller windows and gradually advertise larger windows during the course of a connection. Unaware of the window scaling factors, pf would at some point start to block packets because it would think one peer is overflowing the other's advertised window. The effects would be more or less subtle. Sometimes, the peers will react to the loss of the packets by going into a loss recovery mode and advertise smaller windows. When pf then passes subsequent retransmissions again, advertised windows grow again, up to the point where pf blocks packets. The effect is that connections temporarily stall and throughput is poor. It's also possible that connections stall completely and time out.

pf does know about window scaling and supports it. However, the prerequisite is that you create state on the initial SYN, so pf can associate the first two packets of the handshake with the state entry. Since the entire negotiation of the window scaling factors takes place only in these two packets, there is no reliable way to deduce the factors after the handshake.

Window scaling wasn't widely used in the past, but this is changing rapidly. Just recently, Linux started using window scaling by default. If you experience stalling connections, especially when problems are limited to certain combinations of hosts, and you see 'BAD state' messages related to these connections logged, verify that you're really creating states on the initial packet of a connection.
You don't need to be a genius to debug a pf.conf firewall ruleset, you just need the guts to run tcpdump
Reply With Quote