NAT daemon, natd(8)
, works in conjunction with
IPFW to provide network address translation.
This can be used to provide an Internet Connection Sharing solution so that several internal computers can connect to the Internet using a single
To do this, the FreeBSD machine connected to the Internet must act as a gateway.
This system must have two
NICs, where one is connected to the Internet and the other is connected to the internal
Each machine connected to the
LAN should be assigned an
IP address in the private network space, as defined by RFC
1918, and have the default gateway set to the natd(8)
Some additional configuration is needed in order to activate the
NAT function of
If the system has a custom kernel, the kernel configuration file needs to include
option IPDIVERT along with the other
IPFIREWALL options described in Enabling IPFW.
NAT support at boot time, the following must be in
gateway_enable="YES" # enables the gateway
natd_enable="YES" # enables NAT
natd_interface="rl0" # specify interface name of NIC attached to Internet
natd_flags="-dynamic -m" # -m = preserve port numbers; additional options are listed in natd8
It is also possible to specify a configuration file which contains the options to pass to natd(8)
The specified file must contain a list of configuration options, one per line.
redirect_port tcp 192.168.0.2:6667 6667
redirect_port tcp 192.168.0.3:80 80
For more information about this configuration file, consult natd(8)
Next, add the
NAT rules to the firewall ruleset.
When the rulest contains stateful rules, the positioning of the
NAT rules is critical and the
skipto action is used.
skipto action requires a rule number so that it knows which rule to jump to.
The following example builds upon the firewall ruleset shown in the previous section.
It adds some additional entries and modifies some existing rules in order to configure the firewall for
It starts by adding some additional variables which represent the rule number to skip to, the
keep-state option, and a list of
TCP ports which will be used to reduce the number of rules:
ipfw -q -f flush
cmd="ipfw -q add"
NAT rule is inserted after the two rules which allow all traffic on the trusted internal interface and on the loopback interface and before the
It is important that the rule number selected for this
NAT rule, in this example
100, is higher than the first two rules and lower than the
$cmd 005 allow all from any to any via xl0 # exclude LAN traffic
$cmd 010 allow all from any to any via lo0 # exclude loopback traffic
$cmd 100 divert natd ip from any to any in via $pif # NAT any inbound packets
# Allow the packet through if it has an existing entry in the dynamic rules table
$cmd 101 check-state
The outbound rules are modified to replace the
allow action with the
$skip variable, indicating that rule processing will continue at rule
tcp rules have been replaced by rule
125 as the
$good_tcpo variable contains the seven allowed outbound ports.
# Authorized outbound packets
$cmd 120 $skip udp from any to x.x.x.x 53 out via $pif $ks
$cmd 121 $skip udp from any to x.x.x.x 67 out via $pif $ks
$cmd 125 $skip tcp from any to any $good_tcpo out via $pif setup $ks
$cmd 130 $skip icmp from any to any out via $pif $ks
The inbound rules remain the same, except for the very last rule which removes the
via $pif in order to catch both inbound and outbound rules.
NAT rule must follow this last outbound rule, must have a higher number than that last rule, and the rule number must be referenced by the
In this ruleset, rule number
500 diverts all packets which match the outbound rules to natd(8)
The next rule allows any packet which has undergone
NAT processing to pass.
$cmd 499 deny log all from any to any
$cmd 500 divert natd ip from any to any out via $pif # skipto location for outbound stateful rules
$cmd 510 allow ip from any to any
In this example, rules
510 control the address translation of the outbound and inbound packets so that the entries in the dynamic state table always register the private
Consider an internal web browser which initializes a new outbound
HTTP session over port 80.
When the first outbound packet enters the firewall, it does not match rule
100 because it is headed out rather than in.
It passes rule
101 because this is the first packet and it has not been posted to the dynamic state table yet.
The packet finally matches rule
125 as it is outbound on an allowed port and has a source
IP address from the internal
On matching this rule, two actions take place.
keep-state action adds an entry to the dynamic state table and the specified action,
skipto rule 500, is executed.
Next, the packet undergoes
NAT and is sent out to the Internet.
This packet makes its way to the destination web server, where a response packet is generated and sent back.
This new packet enters the top of the ruleset.
It matches rule
100 and has its destination
IP address mapped back to the original internal address.
It then is processed by the
check-state rule, is found in the table as an existing session, and is released to the
On the inbound side, the ruleset has to deny bad packets and allow only authorized services.
A packet which matches an inbound rule is posted to the dynamic state table and the packet is released to the
The packet generated as a response is recognized by the
check-state rule as belonging to an existing session.
It is then sent to rule
500 to undergo
NAT before being released to the outbound interface.