Freebsd: pf firewall doesn’t work on restart

firewallfreebsdjailspf

I'm running FreeBSD 10.3 p4 and observed some strange behavior

When restarting the machine pf starts due to /etc/rc.conf entry

# JAILS
cloned_interfaces="${cloned_interfaces} lo1"
gateway_enable="YES"
ipv6_gateway_enable="YES"

# OPENVPN -> jails
cloned_interfaces="${cloned_interfaces} tun0"

# FIREWALL
pf_enable="YES"
pf_rules="/etc/pf.conf"
fail2ban_enable="YES"

# ... other services ...

# load ezjail
ezjail_enable="YES"

but ignores all rules concerning jails. So I have to reload rules manually to get it started by

sudo pfctl -f /etc/pf.conf

My pf.conf reads:

#external interface
ext_if = "bge0"
myserver_v4 = "xxx.xxx.xxx.xxx"

# internal interfaces
set skip on lo0
set skip on lo1

# nat all jails
jails_net = "127.0.1.1/24"
nat on $ext_if inet from $jails_net to any -> $ext_if

# nat and redirect openvpn
vpn_if = "tun0"
vpn_jail = "127.0.1.2"
vpn_ports = "{8080}"
vpn_proto = "{tcp}"
vpn_network = "10.8.0.0/24"
vpn_network_v6 = "fe80:dead:beef::1/64"
nat on $ext_if inet from $vpn_network to any -> $ext_if
rdr pass on $ext_if proto $vpn_proto from any to $myserver_v4 port $vpn_ports -> $vpn_jail

# nsupdate jail
nsupdate_jail="127.0.1.3"
nsupdate_ports="{http, https}"
rdr pass on $ext_if proto {tcp} from any to $myserver_v4 port $nsupdate_ports -> $nsupdate_jail

# ... other yails ...

# block all incoming traffic
#block in

# pass out 
pass out

# block fail2ban
table <fail2ban> persist
block quick proto tcp from <fail2ban> to any port ssh

# ssh
pass in on $ext_if proto tcp from any to any port ssh keep state

I had to disable blocking all incoming traffic as ssh via ipv6 stopped working.

Any suggestions how to fix the problem?

Best Answer

The problem here is that /etc/rc.d/pf runs before /usr/local/etc/rc.d/ezjail, so the kernel hasn't configured the jailed network by the time it tries to load the firewall rules. You might be tempted to alter the pf script to start after ezjail, but that's not a good idea - you want your firewall to start early in the boot process, but jails get started quite late on. service -r shows what order your rc scripts will run.

You don't show any of your pf.conf rules, but my guess is that they use static interface configuration. Normally, hostname lookups and interface name to address translations are carried out when the rules are loaded. If a hostname or IP address changes, the rules need to be reloaded to update the kernel. However, you can change this behaviour by surrounding interface names (and any optional modifiers) in parentheses, which will cause the rules to update automatically if the interface's address changes. As a simple (and not very useful) example:

ext_if="em0"
pass in log on $ext_if to ($ext_if) keep state

The pf.conf manpage is very thorough. In particular, the "PARAMETERS" section is relevant here.

Related Question