PF PF how to not drop existing connections when service starts

Hi, looking for help. Whenever I start/restart the PF service ( sudo service pf start), my SSH tunnel disconnects (and hangs locally). I have to kill the process locally or let it timeout, and reconnect in order to continue.

Though I don't interfere with pf service often, this dropping of connection disrupts my workflow. Is there any way to avoid it and keep my deny-by-default configuration? Basically, intention is to allow existing connections to continue after PF service starts?

I was thinking of something similar to ipfw's $cmd 00010 check-state (as an example), which would check the current connection for matching state rather than flushing everything on startup.

Current setup looks something like this (ext_if is my only local network interface):
Code:
ext_if = "{{ pf_ext_if }}"
block all
set skip on lo0
pass in quick on $ext_if proto tcp from any to any port ssh keep state
 
pf always tracks state, unless explicitly told not to.

This will always be an issue on the first start of pf, because it won't have state for your existing connections. There's not really anything you can do about that.
On reload (service pf reload) pf will keep states and your connection will not drop. If you explicitly restart (service pf restart / service pf stop ; service pf start) states will get flushed and you will lose your existing connection.
 
From pf.conf(5): (emphasis mine)

Because flags S/SA is applied by default (unless no state is specified), only the initial SYN packet of a TCP handshake will create a state for a TCP connection. It is possible to be less restrictive, and allow state creation from intermediate (non-SYN) packets, by specifying flags any. This will cause pf(4) to synchronize to existing connections, for instance if one flushes the state table. However, states created from such intermediate packets may be missing connection details such as the TCP window scaling factor. States which modify the packet flow, such as those affected by nat, binat or rdr rules, modulate or synproxy state options, or scrubbed with reassemble tcp will also not be recoverable from intermediate packets. Such connections will stall and time out.

TL;DR: you can use flags any to allow synchronization with existing connections, but rules that modify packet flow will break them. (If you’re using them.)
 
Thanks, unfortunately flags any has not made much of a difference, SSH connections drop upon starting service (but it did appear to not make it hang - so at least I was able to recover quicker). My testing is done over a LAN, with the FreeBSD vm being bridged - so there was no NAT involved, but it seems that flags any may be too brittle for my intentions. I appreciate the suggestion, perhaps I'm using it wrong?

My change:
Code:
pass in quick on $ext_if proto tcp from any to any port ssh flags any keep state

It would be nice if PF could interpret or ignore existing connections upon start (per configuration of course, not by default).

I tried to stagger my deployment by doing sudo pfctl -e, reconnect, then sudo pfctl -f /etc/pf.conf - but it still drops the connection as long as block all is part of my config.

I was able to get something going by doing the following:

Code:
#File: ~/pf-default.conf
pass in quick on $ext_if proto tcp from any to any port ssh keep state

sudo pf -ef ~/pf-default.conf

Now voluntarily close SSH session, reconnect, and:

sudo pf -f /etc/pf.conf (or service pf reload, thank you Kristof, this is more convenient in ansible)

Now the new SSH connection(s) remain functional, but the benefit is that you are never implicitly and involuntarily kicked from the session. This forces me to stagger my deployment process, but it's better than hanging it midway.

Sure wish there was a better way to do this.

@Eric A. Borisch - I only have the rules I listed in original post, do you know if there is a way to clean them up to allow "flags any" to do it's job?
 
You’ve got a block all statement, so by default you allow no outgoing packets other than those matching a previously established state. Either change that to only apply to inbound or try adding a (typically not needed because of stateful behavior) rule like pass out on $ext_if from port 22 to any flags any rule.
 
Eric, that totally did it, I owe you an enormous thank you.

I opted for the alternative, "typically not needed" rule:
Code:
pass out on $ext_if proto tcp from port 22 to any flags any

With this, the session from which I call service pf start remains active (though other sessions hang up/disconnect, which is completely fine for me but adding here for informational purposes).

Thanks again!
 
Back
Top