This page looks best with JavaScript enabled

NAT with IPFW

 ·  🎃 kr0m

One of the most common tasks a router can perform is address masking, commonly known as NAT. With IPFW, NAT can be done in two different ways: through natd and through the code integrated into the kernel itself. The former provides greater flexibility while the latter provides better performance.

In FreeBSD, NAT can be done in two different ways: in user-space through the natd daemon or in the kernel-space itself.

The choice between one option or the other will be based on our needs. For example, natd allows us to insert dynamic rules for ftp, while kernel-space mode is faster.

We will build our firewall script based on this one .

In this example, we will have two networks:

  • LAN: 192.168.61.0/24
  • WAN: 192.168.55.0/24

The first step would be to enable traffic routing between networks:

sysrc gateway_enable="yes"
service routing restart


NATD:

We enable the natd service, indicate the WAN interface, and the -m parameter to try to keep the same ports of the original packet in the masked packet. This way, it is more likely that RPC services will work correctly.

sysrc natd_enable="yes"
sysrc natd_interface=“em0”
sysrc natd_flags="-m"

We edit the firewall script to divert to the natd process when necessary:

vim /etc/ipfw.rules

#!/bin/sh
# Flush out the list before we begin.
ipfw -q -f flush

# Set rules command prefix
cmd="ipfw -q add"

wanif="em0"
lanif="em1"

lannet="192.168.55.0/24"

# No restrictions on Loopback Interface
$cmd 00001 allow all from any to any via lo0

# Allow all LAN traffic
$cmd 00002 allow all from $lannet to any in via $lanif

# Check inbound traffic for redirections
$cmd 00003 divert natd ip from any to me in via $wanif

# Allow dynamic rules table connections
$cmd 00101 check-state

# NAT Lan traffic:
$cmd 00102 skipto 1000 tcp from $lannet to any out via $wanif setup keep-state
$cmd 00103 skipto 1000 udp from $lannet to any out via $wanif keep-state
$cmd 00104 skipto 1000 icmp from $lannet to any out via $wanif keep-state

# -- Host Traffic --
# Allow access to public DNS
# DNS TCP
$cmd 00201 allow tcp from me to 8.8.8.8 53 out via $wanif setup keep-state
$cmd 00202 allow tcp from me to 8.8.4.4 53 out via $wanif setup keep-state
# DNS UDP
$cmd 00203 allow udp from me to 8.8.8.8 53 out via $wanif keep-state
$cmd 00204 allow udp from me to 8.8.4.4 53 out via $wanif keep-state

# Allow outbound HTTP and HTTPS connections
$cmd 00300 allow tcp from me to any 80 out via $wanif setup keep-state
$cmd 00301 allow tcp from me to any 443 out via $wanif setup keep-state

# Allow outbound email connections
$cmd 00400 allow tcp from me to any 25 out via $wanif setup keep-state
$cmd 00401 allow tcp from me to any 110 out via $wanif setup keep-state

# Allow outbound ping
$cmd 00500 allow icmp from me to any out via $wanif keep-state

# Allow outbound NTP
$cmd 00501 allow udp from me to any 123 out via $wanif keep-state

# Allow outbound SSH
$cmd 00680 allow tcp from me to any 22 out setup keep-state

# Allow inbound public pings
$cmd 00700 allow icmp from any to me in via $wanif

# Allow inbound SSH
# With stateless rules we dont break our ssh connection each time we restart ipfw service
$cmd 00711 allow tcp from any to me 22 in
$cmd 00712 allow tcp from me 22 to any out
# ------------------

# Deny and log all other outbound connections
$cmd 00900 deny log all from any to any out

# NAT outbound traffic
$cmd 01000 divert natd ip from any to any out via $wanif
$cmd 01001 allow ip from any to any

KERNEL-SPACE:

We enable nat at the kernel level and indicate the WAN interface:

sysrc firewall_nat_enable="yes"
sysrc firewall_nat_interface=“em0”

We perform a similar configuration but this time we don’t make any divert, we directly make a nat:

vim /etc/ipfw.rules

#!/bin/sh
# Flush out the list before we begin.
ipfw -q -f flush

# Set rules command prefix
cmd="ipfw -q add"

wanif="em0"
lanif="em1"

lannet="192.168.55.0/24"

# No restrictions on Loopback Interface
$cmd 00001 allow all from any to any via lo0

# Allow all LAN traffic
$cmd 00002 allow all from $lannet to any in via $lanif

# Configure NAT-WAN interface
ipfw -q nat 1 config same_ports if $wanif

# Check inbound traffic for redirections
$cmd 00004 nat 1 ip from any to me in via $wanif

# Allow dynamic rules table connections
$cmd 00101 check-state

# NAT Lan traffic:
$cmd 00102 skipto 1000 tcp from $lannet to any out via $wanif setup keep-state
$cmd 00103 skipto 1000 udp from $lannet to any out via $wanif keep-state
$cmd 00104 skipto 1000 icmp from $lannet to any out via $wanif keep-state

# -- Host Traffic --
# Allow access to public DNS
# DNS TCP
$cmd 00201 allow tcp from me to 8.8.8.8 53 out via $wanif setup keep-state
$cmd 00202 allow tcp from me to 8.8.4.4 53 out via $wanif setup keep-state
# DNS UDP
$cmd 00203 allow udp from me to 8.8.8.8 53 out via $wanif keep-state
$cmd 00204 allow udp from me to 8.8.4.4 53 out via $wanif keep-state

# Allow outbound HTTP and HTTPS connections
$cmd 00300 allow tcp from me to any 80 out via $wanif setup keep-state
$cmd 00301 allow tcp from me to any 443 out via $wanif setup keep-state

# Allow outbound email connections
$cmd 00400 allow tcp from me to any 25 out via $wanif setup keep-state
$cmd 00401 allow tcp from me to any 110 out via $wanif setup keep-state

# Allow outbound ping
$cmd 00500 allow icmp from me to any out via $wanif keep-state

# Allow outbound NTP
$cmd 00501 allow udp from me to any 123 out via $wanif keep-state

# Allow outbound SSH
$cmd 00680 allow tcp from me to any 22 out setup keep-state

# Allow inbound public pings
$cmd 00700 allow icmp from any to me in via $wanif

# Allow inbound SSH
# $cmd 00711 allow tcp from any to me 22 in setup keep-state
# With stateless rules we dont break our ssh connection each time we restart ipfw service
$cmd 00711 allow tcp from any to me 22 in
$cmd 00712 allow tcp from me 22 to any out
# ------------------

# Deny and log all other outbound connections
$cmd 00900 deny log all from any to any out

# NAT outbound traffiC
$cmd 01000 nat 1 ip from any to any out via $wanif
$cmd 01001 allow ip from any to any
If you liked the article, you can treat me to a RedBull here