This page looks best with JavaScript enabled

NAT with PF

 ·  🎃 kr0m

In the previous article, we saw the basic concepts about PF . This time we will quickly see how to NAT an internal network.

As we can see, the device has two network interfaces, em0(WAN) and em1(LAN):

ifconfig

em0: flags=8863<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> metric 0 mtu 1500
	options=481009b<RXCSUM,TXCSUM,VLAN_MTU,VLAN_HWTAGGING,VLAN_HWCSUM,VLAN_HWFILTER,NOMAP>
	ether 08:00:27:9d:dd:69
	inet 192.168.69.55 netmask 0xffffff00 broadcast 192.168.69.255
	media: Ethernet autoselect (1000baseT <full-duplex>)
	status: active
	nd6 options=29<PERFORMNUD,IFDISABLED,AUTO_LINKLOCAL>
em1: flags=8863<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> metric 0 mtu 1500
	options=481009b<RXCSUM,TXCSUM,VLAN_MTU,VLAN_HWTAGGING,VLAN_HWCSUM,VLAN_HWFILTER,NOMAP>
	ether 08:00:27:2f:97:97
	inet 192.168.1.1 netmask 0xffffff00 broadcast 192.168.1.255
	media: Ethernet autoselect (1000baseT <full-duplex>)
	status: active
	nd6 options=29<PERFORMNUD,IFDISABLED,AUTO_LINKLOCAL>
lo0: flags=8049<UP,LOOPBACK,RUNNING,MULTICAST> metric 0 mtu 16384
	options=680003<RXCSUM,TXCSUM,LINKSTATE,RXCSUM_IPV6,TXCSUM_IPV6>
	inet6 ::1 prefixlen 128
	inet6 fe80::1%lo0 prefixlen 64 scopeid 0x3
	inet 127.0.0.1 netmask 0xff000000
	groups: lo
	nd6 options=21<PERFORMNUD,AUTO_LINKLOCAL>
pflog0: flags=141<UP,RUNNING,PROMISC> metric 0 mtu 33160
	groups: pflog

We enable packet forwarding between networks:

sysctl net.inet.ip.forwarding=1
sysctl net.inet6.ip6.forwarding=1

For the configuration to persist, we must assign the following RC variables:

sysrc gateway_enable=YES
sysrc ipv6_gateway_enable=YES

The script is quite self-explanatory:

  • Only incoming ssh connections are allowed to the router.
  • All outgoing connections are allowed to the router.
  • The NATed network is allowed all traffic as long as it does not attempt to connect to the router on a port other than 22.
vi /etc/pf.conf
ext_if = "em0"
int_if = "em1"
localnet = $int_if:network

set block-policy return
scrub in on $ext_if all fragment reassemble
set skip on lo

nat on $ext_if from $localnet to any -> ($ext_if)

antispoof for $ext_if inet

block log all
pass from $localnet
block from $localnet to ($ext_if)
block from $localnet to ($int_if)
pass out
pass in proto tcp to any port 22

We enable PF at startup:

sysrc pf_enable=YES
sysrc pf_rules="/etc/pf.conf"

We enable PF-LOG at startup and configure the log file:

sysrc pflog_enable=YES
sysrc pflog_logfile="/var/log/pflog"

We reload the configuration:

pfctl -f /etc/pf.conf

If you liked the article, you can treat me to a RedBull here