FreeBSD as NAT gateway

FreeBSD can be easily configured as NAT (NAPT precisely) gateway with built-in pf module. This page provides a way to setup FreeBSD as NAT gateway.

Custom Search

FreeBSD as NAT gateway

Enable gateway function

To enable gateway function on FreeBSD, add the following line to /etc/rc.conf:


This line enables IP forwarding (i.e., sysctl net.inet.ip.forwarding=1).

Enable NAT with pf

The NAT function is in pf (packet filter). To use pf, add the following lines to /etc/rc.conf:


The first line enables pf on boot, and the second one specifies the configuration of rules for pf. The third line enables logging and the last one specifies the path to log file.

Then create /etc/pf.rules as follows.

# ls -l /etc/pf.rules
-rw-r--r--  1 root  wheel     0 Mar  3 18:30 /etc/pf.rules

The content of the file is like following:

### Options ###
set limit states 100000

### Macros ###
ext_if = "em0"               # External network interface for IPv4
ext_if6 = "em0"              # External network interface for IPv6
ext_addr = ""       # External IPv4 address (i.e., global)
int_if = "em1"               # Internal network interface for IPv4
int_if6 = "em1"              # Internal network interface for IPv6
int_addr = ""        # Internal IPv4 address (i.e., gateway for private network)
int_network = ""  # Internal IPv4 network

### Tables ###
# Host local address
table <local> const { }
# IPv4 private address ranges
table <private> const { 10/8, 172.16/12, 192.168/16 }
# Special-use IPv4 addresses defined in RFC3330
table <special> const { 0/8, 14/8, 24/8, 39/8, 127/8, 128.0/16, 169.254/16, 192.0.0/24, 192.0.2/24, 192.88.99/24, 198.18/15, 240/4 }

### Scrub: Packet normalization ###
# Scrub for all incoming packets
scrub in all
# Randomize the ID field for all outgoing packets
scrub out all random-id
# If you have MTU problem or something like that
#scrub out all random-id  max-mss 1400

### NAT ###
nat on $ext_if from $int_network to ! <private> -> $ext_addr

### Filters ###
# Permit keep-state packets for UDP and TCP on external interfaces
pass out quick on $ext_if proto udp all keep state
pass out quick on $ext_if6 proto udp all keep state
pass out quick on $ext_if proto tcp all modulate state flags S/SA
pass out quick on $ext_if6 proto tcp all modulate state flags S/SA

# Permit any packets from internal network to this host
pass in quick on $int_if inet from $int_network to $int_addr

# Permit established sessions from internal network to any (incl. the Internet)
pass in quick on $int_if inet from $int_network to any keep state
# If you want to limit the number of sessions per NAT, nodes per NAT (simultaneously), and sessions per source IP
# Please refer to <> for greater detailed information
#pass in quick on $int_if inet from $int_network to any keep state (max 30000, source-track rule, max-src-nodes 100, max-src-states 500 )

# Permit and log all packets from clients in private network through NAT
pass in quick log on $int_if all

# Pass any other packets
pass in all
pass out all

Note that this file also defines filter rules which is useful or mandatory to provide the network to users. If you do not provide this network to others, you can eliminate filter section just by writing following:

pass in all
pass out all

Here, we note that file /var/log/pflog would be automatically created as follows.

# ls -l /var/log/pflog
-rw-------  1 root  wheel  3832 Jul 13 17:45 /var/log/pflog

Setup snort as an intrusion detection system (IDS)

If you provide your network to others, you have responsibility for it. Snort (security/snort in ports-tree) may help you a lot in case you meet troubles with your network users.

Before setting up snort, you have to install two packages; snort (security/snort), and oinkmaster (security/oinkmaster). Package oinkmaster is used to update the rule database of snort.

After you have installed snort and oinkmaster, you will configure these softwares. To enable snort and to start it up on boot, add the following line to /etc/rc.conf:


If you want to specify interface to monitor, also add the following line to /etc/rc.conf:

snort_interface="em0"  # Change em0 to your desired interface name

To download/update the snort rule file via oinkmaster, you need to register and get oinkcode from snort Web site. N.B., you can also get the file from web site without oinkmaster, but we recommend you to use oinkmaster to enable periodical update.

After you get an oinkcode, add the following line to /usr/local/etc/oinkmaster.conf:

url =<your-oinkcode>/snortrules-snapshot-<4-digit-version>.tar.gz

Then, execute the following command to update the rules:

# oinkmaster -o /usr/local/etc/snort/rules/

Additionally, you should edit (normally comment out/uncomment) file /usr/local/etc/snort/snort.conf. Finally, start daemon with script /usr/local/etc/rc.d/snort or just reboot.

Solve an error with oinkmaster about CA certificate (if you meet)

You may meet the following error about CA certificate when you update the database.

# oinkmaster -o /usr/local/etc/snort/rules/
Loading /usr/local/etc/oinkmaster.conf
Downloading file from*oinkcode*/snortrules-snapshot-2853.tar.gz... 
/usr/local/bin/oinkmaster: Error: could not download from*oinkcode*/snortrules-snapshot-2853.tar.gz. Output from wget follows:*oinkcode*/snortrules-snapshot-2853.tar.gzResolving
Connecting to||:80... connected.
HTTP request sent, awaiting response... 302 Found
Location: [following]
--2010-07-13 21:54:10--
Connecting to||:443... connected.
ERROR: cannot verify's certificate, issued by `/C=US/O=VeriSign, Inc./OU=VeriSign Trust Network/OU=Terms of use at (c)09/CN=VeriSign Class 3 Secure Server CA - G2':
  Unable to locally verify the issuer's authority.
To connect to insecurely, use `--no-check-certificate'.
Unable to establish SSL connection.

Oink, oink. Exiting...

Please get/export CA certificate Class 3 Public Primary Certification Authority - G2 with PEM format from your Web browser, and then put it at /usr/local/etc/class3_public_primary_certification_authority_g2.pem edit /root/.wgetrc as follows.