This article will detail how to configure an IPv4 only router and secure it with PF firewall.
In the examples provided re0
is the external and re1
is the internal interface.
Substitute them with your system's respective iface names.
Configure System Startup
Configure the network interfaces, enable routing, and enable PF firewall by adding the following to /etc/rc.conf
:
ifconfig_re0="SYNCDHCP" ifconfig_re1="inet 192.0.2.1 netmask 255.255.255.0" gateway_enable="YES" # PF pf_enable="YES" pf_rules="/etc/pf.conf" pflog_enable="YES" pflog_logfile="/var/log/pflog"
Configure the PF firewall rules
Edit /etc/pf.conf
#### Macros #### ext_if = re0 int_if = re1 # ICMP Types icmp_types = "{ echorep }" # Private and documentation example networks priv_nets = "{ 127.0.0.0/8, 192.168.0.0/16, 172.16.0.0/12, 10.0.0.0/8, 255.255.255.255/32 }" doc_example_nets = "{ 192.0.2.0/24, 198.51.100.0/24, 203.0.113.0/24 }" #### Options #### set block-policy drop set skip on lo0 # Scrub scrub on $ext_if all no-df random-id reassemble tcp # NAT nat on $ext_if from 192.0.2.0/24 -> ($ext_if) #### Block #### block log all # Antispoof antispoof quick log for $ext_if block in on $ext_if from { urpf-failed, no-route } block in quick log on $ext_if from { $priv_nets, $doc_example_nets } # Block ICMP Port Unreachable Messages to Prevent and Mitigate DDOS and Other Attacks i.e. SAD DNS block out quick log on $ext_if inet proto icmp icmp-type unreach code port-unr #### Allow #### # Allow all traffic on internal interface pass quick on $int_if flags any # Allow all traffic out via external interface pass out on $ext_if flags any # ICMP pass in on $ext_if proto icmp all icmp-type $icmp_types ### Inbound Services # pass in on $ext_if proto tcp to port http
Note: When PF loads the ruleset into memory it automatically appends keep state to all valid pass rules. If the rule is a TCP pass rule then flags S/SA keep state is appended instead. For example:
pass in on $ext_if proto tcp from any to any port http
is written into memory as:
pass in on re0 proto tcp from any to any port = http flags S/SA keep state
Reboot the system watching the console for any errors during startup.
Login and confirm that you can ping external Internet hosts.
When you make changes to /etc/pf.conf
execute the following command to load the new rule-set:
pfctl -f /etc/pf.conf
If there are errors then the rule-set will not be loaded and the affected line number(s) will be identified.
Existing states in the states table will be retained. This means that connected systems and devices on your LAN will not be interrupted when reloading the rule-set.
Another useful command is pfctl -s modifier
pfctl -s rules
will show the currently loaded filter rules.
There are several other useful modifiers
available, refer to pfctl(8) for more information.