FreeBSD IPFW rules for WireGuard

Usage


You've installed WireGuard on FreeBSD EC2 server - now we need to configure IPFW rules correctly.

Scripts


/etc/rc.conf

Make sure the following is present in /etc/rc.conf

firewall_enable="YES"
firewall_nat_enable="YES"
firewall_script="/usr/local/etc/IPFW.rules"
firewall_logging="YES"

We can use the following commands to make sure /etc/rc.conf has all of the required parameters:

sed -i -E 's/firewall_enable=.*//g' /etc/rc.conf
sed -i -E 's/firewall_nat_enable=.*//g' /etc/rc.conf
sed -i -E 's/firewall_script=.*//g' /etc/rc.conf
sed -i -E 's/firewall_logging=.*//g' /etc/rc.conf
sed -i -E 's/gateway_enable=.*//g' /etc/rc.conf
printf %b\\n "gateway_enable=\"YES\"
firewall_enable=\"YES\"
firewall_nat_enable=\"YES\"
firewall_script=\"/usr/local/etc/IPFW.rules\"
firewall_logging=\"YES\"" | tee -a /etc/rc.conf >/dev/null

sysctl

We need the following options set

# Disable TCP segmentation offloading to use in-kernel NAT
# See 30.4.4. In-kernel NAT in https://www.freebsd.org/doc/handbook/firewalls-ipfw.html
$ sudo sed -i -E 's/net.inet.tcp.tso=.*//g' /etc/sysctl.conf
$ sudo printf %b\\n "net.inet.tcp.tso=0" | tee -a /etc/sysctl.conf >/dev/null
$ sudo sysctl net.inet.tcp.tso="0"
#Enable IP forwarding
$ sudo sysctl net.inet.ip.forwarding="1"

/usr/local/etc/IPFW.rules

Use the following for a firewall config template. Pay attention to vif, ssh_port, pub_dns, wg_port and wg_subnet varibles, they will be unique to your setup.

#!/bin/sh
# ipfw config/rules
# from FBSD Handbook, rc.firewall, et. al.
# Flush all rules before we begin.
ipfw -q -f flush
# Set rules command prefix
cmd="ipfw -q add "
# Internet-facing iface
vif="xn0"
# Used for outboud NAT rules
skip="skipto 1000"
# sshd port
ssh_port="22"
#### WG-specific Options ####
# DNS Server
pub_dns="1.1.1.1"
# Listen Port
wg_port="9201"
# Subnet
wg_subnet="10.10.0.0/24"
# Wireguard interface, matching the name in /etc/wireguard/*.conf
wg_iface="wg0"
# Allow NAT
ipfw disable one_pass
ipfw -q nat 1 config if $vif same_ports unreg_only reset
# allow all for localhost
$cmd 00010 allow ip from any to any via lo0
$cmd 00011 allow ip from any to any via $wg_iface
# NAT-specifig rules
$cmd 00099 reass all from any to any in # reassamble inbound packets
$cmd 00100 nat 1 ip from any to any in via $vif # NAT any inbound packets
# checks stateful rules. If marked as "keep-state" the packet has
# already passed through filters and is "OK" without futher
# rule matching
$cmd 00101 check-state
# allow DNS out
$cmd 00110 $skip tcp from any to $pub_dns dst-port 53 out via $vif setup keep-state
$cmd 00111 $skip udp from any to $pub_dns dst-port 53 out via $vif keep-state
# allow dhclient connection out (port numbers are important)
$cmd 00120 $skip udp from me 68 to any dst-port 67 out via $vif keep-state
# allow HTTP HTTPS replies
$cmd 00200 $skip tcp from any to any dst-port 80 out via $vif setup keep-state
$cmd 00220 $skip tcp from any to any dst-port 443 out via $vif setup keep-state
# allow outbound mail
$cmd 00230 $skip tcp from any to any dst-port 25 out via $vif setup keep-state
$cmd 00231 $skip tcp from any to any dst-port 465 out via $vif setup keep-state
$cmd 00232 $skip tcp from any to any dst-port 587 out via $vif setup keep-state
# allow WG
$cmd 00233 $skip udp from any to any src-port $wg_port out via $vif keep-state
$cmd 00234 $skip udp from $wg_subnet to any out via $vif keep-state
$cmd 00235 $skip tcp from $wg_subnet to any out via $vif setup keep-state
# allow icmp re: ping, et. al.
# comment this out to disable ping, et.al.
$cmd 00250 $skip icmp from any to any out via $vif keep-state
# alllow timeserver out
$cmd 00260 $skip tcp from any to any dst-port 37 out via $vif setup keep-state
# allow ntp out
$cmd 00270 $skip udp from any to any dst-port 123 out via $vif keep-state
# allow outbound SSH traffic
$cmd 00280 $skip tcp from any to any dst-port 22 out via $vif setup keep-state
# otherwise deny outbound packets
# outbound catchall.
$cmd 00299 deny log ip from any to any out via $vif
# inbound rules
# deny inbound traffic to restricted addresses
$cmd 00300 deny ip from 192.168.0.0/16 to any in via $vif
$cmd 00301 deny all from 172.16.0.0/12 to any in via $vif #RFC 1918 private IP
$cmd 00302 deny ip from 10.0.0.0/8 to any in via $vif
$cmd 00303 deny ip from 127.0.0.0/8 to any in via $vif
$cmd 00304 deny ip from 0.0.0.0/8 to any in via $vif
$cmd 00305 deny ip from 169.254.0.0/16 to any in via $vif
$cmd 00306 deny ip from 192.0.2.0/24 to any in via $vif
$cmd 00307 deny ip from 204.152.64.0/23 to any in via $vif
$cmd 00308 deny ip from 224.0.0.0/3 to any in via $vif
# deny inbound packets on these ports
# auth 113, netbios (services) 137/138/139, hosts-nameserver 81
$cmd 00315 deny tcp from any to any dst-port 113 in via $vif
$cmd 00320 deny tcp from any to any dst-port 137 in via $vif
$cmd 00321 deny tcp from any to any dst-port 138 in via $vif
$cmd 00322 deny tcp from any to any dst-port 139 in via $vif
$cmd 00323 deny tcp from any to any dst-port 81 in via $vif
# deny partial packets
$cmd 00330 deny ip from any to any frag in via $vif
$cmd 00332 deny tcp from any to any established in via $vif
# allowing icmp re: ping, etc.
$cmd 00310 allow icmp from any to any in via $vif
# allowing inbound mail, dhcp, http, https
$cmd 00370 allow udp from any 67 to me dst-port 68 in via $vif keep-state
# allow inbound ssh, mail. PROTECTED SERVICES: numbered ABOVE sshguard blacklist range
$cmd 700 allow tcp from any to me dst-port $ssh_port in via $vif setup limit src-addr 2
$cmd 702 allow udp from any to any dst-port $wg_port in via $vif keep-state
# deny everything else, and log it
# inbound catchall
$cmd 999 deny log ip from any to any in via $vif
# NAT
$cmd 1000 nat 1 ip from any to any out via $vif # skipto location for outbound stateful rules
$cmd 1001 allow ip from any to any
# ipfw built-in default, don't uncomment
# $cmd 65535 deny ip from any to any

Enable IPFW

$ sudo service ipfw start