# pf on FreeBSD # PF (packet filter) is one of the firewall technologies available on FreeBSD. PF originated from OpenBSD, although the two versions have since diverged significantly; FreeBSD uses the same version of PF as OpenBSD 4.5. PF is a last-matching-rule-wins firewall. (The "quick" keyword on a rule means to stop and _not_ evaluate subsequent rules.) See `pf.conf(5)` and `pfctl(8)` and `/usr/share/examples/pf/*`. Enable PF in `/etc/rc.conf` with: pf_enable="YES" pflog_enable="YES" By default, pf loads its rules from `/etc/pf.conf`. This is a very simple PF config file: block in all pass out all keep state Start PF (and PF logging): # service pf start # service pflog start The pfctl utility configures rulesets and parameters, and retrieves status info from PF. pfctl -e Enable PF. pfctl -d Disable PF. pfctl -F all -f /etc/pf.conf Flush all NAT, filter, state, and table rules and reload /etc/pf.conf. pfctl -s [ rules | nat | states ] Report on the filter rules, NAT rules, or state table. pfctl -vnf /etc/pf.conf Check /etc/pf.conf for errors, but do not load ruleset. pfctl -k host Kill all state entries originating from "host" pfctl -s states -vv Show state ID's, ages, and rule numbers pfctl -s rules -vv Show rules with stats and rule numbers pfctl -s Tables List tables pfctl -t foo -T show Show the contents of table "foo" pfctl -t foo -T delete xx.xx.xx.xx Delete address "xx.xx.xx.xx" from table "foo" ## Gateway Firewall Example ## First, set: # sysctl net.inet.ip.forwarding=1 # sysctl net.inet6.ip6.forwarding=1 Add to `/etc/rc.conf`: gateway_enable="YES" ipv6_gateway_enable="YES" And create the rules `/etc/pf.conf`: ######################## ## Macros ######################## ext_if = "em0" int_if = "em1" wifi_if = "wlan0" int_server = "10.0.1.10" int_nets = "{ 10.0.1.0/24, 10.0.2.0/24 }" tcp_pass_out = "{ bootpc, bootps, dhcpv6-client, dhcpv6-server, domain, https, ipp, nicname, ntp, ssh, www, 6667, 6697 }" udp_pass_out = "{ bootpc, bootps, dhcpv6-client, dhcpv6-server, domain, nicname, ntp }" icmp_ok_types = "{ echoreq, unreach }" ######################## ## Tables ######################## table { 192.0.2.17, 198.51.100.223, 203.0.113.110 } table persist ######################## ## Options ######################## set skip on lo ######################## ## Normalization ######################## scrub in ######################## ## Translation ######################## nat on $ext_if inet from !($ext_if) to any -> ($ext_if) rdr on $ext_if proto tcp from any to any port 8000 -> $int_server ######################## ## Filtering ######################## block in antispoof for $ext_if antispoof for $int_if antispoof for $wifi_if pass quick on $ext_if from keep state block quick from pass in inet proto tcp from any to $ext_if port ssh keep state (max-src-conn 5, max-src-conn-rate 3/5, overload flush global) pass proto tcp from $int_nets to any port $tcp_pass_out keep state pass proto udp from $int_nets to any port $udp_pass_out keep state pass proto tcp from $ext_if to any port $tcp_pass_out keep state pass proto udp from $ext_if to any port $udp_pass_out keep state pass inet6 proto tcp from fe80::/10 to any port $tcp_pass_out keep state pass inet6 proto udp from fe80::/10 to any port $udp_pass_out keep state pass inet6 proto icmp6 from any pass inet proto icmp icmp-type $icmp_ok_types keep state pass in from $int_nets to $int_if keep state # Anti-lockout rule Note the use of variables like `$ext_if`, macros like `udp_pass_out = "{ domain, ntp }"`, and tables like `table { 192.0.2.17, 198.51.100.223, 203.0.113.110 }`. Scrub before any NAT or redirection rules. Define NAT and redirection rules before filtering rules. ## Gotcha: DHCP External Interface ## If the external interface receives its address via DHCP, the PF rules may fail to load if FreeBSD tries before the interface gets its address. Edit `/etc/rc.conf`. Change `ifconfig_em0="DHCP"` to `ifconfig_em0="SYNCDHCP"`. ## Links ## - https://www.freebsd.org/cgi/man.cgi?query=pf.conf&sektion=5 - https://www.freebsd.org/doc/handbook/firewalls-pf.html - https://www.freebsd.org/cgi/man.cgi?query=pfctl&sektion=8&manpath=freebsd-release-ports - https://www.nostarch.com/pf3 (The Book of PF) - /usr/share/examples/pf/ - http://www.scottro.net/pf.html