One of the most common things to do with FreeBSD is to use it as a gateway to
the internet. Most internet connections have 1 IP assigned to them (via dialup,
dhcp, or PPPoE) and have to serve that connection to the whole network.
So how does this work? Let's take a look at our network (it's animated so be
A machine on the Local Ethernet wants to go to the internet, it must traverse
the FreeBSD machine (via their default gateway). It is the job of the FreeBSD
machine to route them to the right place. However, you can see that the IP
address of Workstation-1 is 192.168.0.10. The BSD machine must change that
address before it sends the packets out to the internet. In fact, he must change
the source address to an address that is routeable across the internet. Once the
FreeBSD machine changes the address, the packets get sent out on the internet.
When the packet returns, the same thing happens, but instead of changing the
source address in the pakcet headers, it changes the destination address back to
192.168.0.10 and the packet gets sent back to your local workstation-1.
This process is called NAT or sometimes referred to as IP Maquerading. The point
is that the client workstation does not have to know that this process is
So How does natd change the packets? Well, that is where ipfw comes in.
Through the ipfw `divert` command packets are sent to natd first, natd changes
the packet header information, then the packets get reinjected back into the "IP
packet processing system" and away they go. (See figure 1.1 above).
natd comes default with system so you do not need to install it. However, the
default kernel does not have support for "diverting" packets. You have to
rebuild the kernel with this support. To do this :
Your system will reboot and should come up with natd running. To verify lets
see if everythings setup:
First let's check that the firewall has the proper ruleset running:
# ipfw -a l
00050 1566423 901667271 divert 8668 ip from any to any via xl0
00100 116714 10731910 allow ip from any to any via lo0
00200 0 0 deny ip from any to 127.0.0.0/8
65000 3342945 1813053300 allow ip from any to any
65535 0 0 deny ip from any to any
OK, looks as if the firewall is working. Let's look at what rule 50 above
(first line) is doing. It basically says, "Send any packet incoming or outgoing
on interface xl0 to port 8668 on the local machine".
Luckily natd is running on port 8668, so natd will get the packets from this
line. After natd is done with the packets, they get reinjected at the next
rule...in this case, it happens to be rule 100.
Now let's see if natd is running:
# ps -auxw |grep nat
root 182 0.0 1.4 528 180 ?? Rs 20Apr01 28:23.03 /sbin/natd -n xl0
WOW! it looks as if its running! The "-n" option tells natd to use the IP
assigned to xl0 as the address to alias packets to. So when packets leave the
local network their source address will be the address assigned to interface
xl0. You added this option when you specified "natd_interface=xl0" in /etc/rc.conf
Let's test it out to see if we can get to the internet:
# ping ftp.freebsd.org
PING ftp.freebsd.org (18.104.22.168): 56 data bytes
64 bytes from 22.214.171.124: icmp_seq=0 ttl=240 time=81.597 ms
64 bytes from 126.96.36.199: icmp_seq=1 ttl=240 time=115.910 ms
64 bytes from 188.8.131.52: icmp_seq=2 ttl=240 time=50.444 ms
--- ftp.freebsd.org ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max/stddev = 50.444/82.650/115.910/26.737 ms
OMFG! It works...
OK, so natd is up and running, but what if we have a web server or dns server
on the inside network. How can we extend service through the firewall to an
internal machine on incoming requests from the internet? The answer is to supply
options to natd to "point" to the right machine and service". For example,
another diagram (hehe):
Since web server traffic runs on port 80 tcp we need to add the following
option to nat:
natd -n xl0 -redirect_port tcp 192.168.0.10:80 80
The redirect_port option given to natd says "send any tcp traffic
destined for port 80 to 192.168.0.10 on port 80".
Another option is to send all traffic destined for your outside IP (from the
internet) to an internal machine. This option is called redirect_address. So the
natd -n xl0 -redirect_address 192.168.0.10 184.108.40.206
The redirect_address option given to natd says "send ALL traffic destined
for 220.127.116.11 (my outside IP) to 192.168.0.10". This option is sometimes
called static nat, whereas normal nat operation is sometimes called
PAT (Port Address Translation or Overloaded NAT).
Another point of interest for static nat is that internal machines that have
a redirect_address option assigned to them will keep their public IP out on the
internet. ie, They will appear to be coming from the public IP assigned to them
by redirect_address when that machine is out on the internet. It's symmetrical!
These options can be added to /etc/rc.conf so they will stay in effect even
after a reboot:
natd_flags="-redirect_address 192.168.0.10 18.104.22.168"
There are several options that can be given to natd to make it do really cool
stuff. See the natd man page for more info.
If you look at these options they can be quite long. So I like to put them
into a seperate config file...so let's do it