Tutorial 11 · FreeBSD

PF firewall starter ruleset

Enable PF with a simple default-deny ruleset that allows SSH and ping, and learn to test it safely.

Last updated

PF is a powerful packet filter included in the base system. This starter ruleset blocks unsolicited incoming traffic, allows SSH and essential ICMP, and lets all outgoing traffic out.

1Write /etc/pf.conf

ext_if = "em0"
tcp_in = "{ ssh }"
icmp_types = "{ echoreq unreach }"

table <sshguard> persist

set skip on lo0
set block-policy return
scrub in all

block in log all
pass out quick keep state

block in quick on $ext_if from <sshguard>
antispoof quick for $ext_if

pass in on $ext_if inet proto icmp icmp-type $icmp_types
pass in on $ext_if inet6 proto icmp6
pass in on $ext_if proto tcp to port $tcp_in keep state

Allowing ICMPv6 is essential: IPv6 neighbour discovery and path MTU discovery depend on it. The <sshguard> table is used by the SSH hardening tutorial.

2Check the syntax

pfctl -nf /etc/pf.conf

3Enable and start PF

Starting PF over SSH can drop your session if the ruleset is wrong. Do it from the console if you can. Over SSH, a safety timer that disables PF after two minutes gives you a way back.

sysrc pf_enable=YES pflog_enable=YES
service pflog start
(sleep 120 && pfctl -d) &   # safety net
service pf start
# still connected? cancel the safety net:
kill %1

4Day-to-day commands

pfctl -sr            # show loaded rules
pfctl -ss            # show the state table
pfctl -si            # statistics
pfctl -f /etc/pf.conf   # reload after editing
tcpdump -n -e -ttt -i pflog0   # watch blocked packets

5Opening another port

Add the service name or port number to tcp_in, for example tcp_in = "{ ssh 8080 }", then check and reload.

← All FreeBSD tutorials