Defcon1-Header
Tool-BarfreeBSD ArticlesSearch Our SiteHOMEfreeBSD LinksContribute to FreeBSD HelpFreeBSD FilesFreeBSD Script Corner

NATD How-To with FreeBSD

If there are any questions or comments, please direct them to walt@erudition.net. The newest copy of this HowTo can always be retrieved from www.freebsd-howto.com . All rights for the reproduction of this document are reserved.


Summary.

This HowTo describes the theory behind NAT, and the use of natd(8) to accomplish designing a network with NAT. It covers issues such as setting up the kernel and ipfw to enable natd(8), specifying alias addresses, port and address forwarding, setting up a configuration file, and setting up natd(8) to start at boot time. 


1.Background

1.1.What is NAT?
1.2.The Basic Theory
1.3.Internet / Registered & Unregistered IP Addresses
1.4.Overcoming Your Shortage of Internet Addresses

2.Deployment

2.1.Kernel Options
2.2.Enabling Packet Forwarding
2.3.ipfw(8) and divert(4)
2.4.natd(8) arguments

2.4.1. Basic Usage
2.4.2. More Complex Usage

2.4.2.1. Port & Address Redirection

2.4.3. Configuration File

2.5.Starting natd(8) at Boot Time

3.Appendix



1.Background.

1.1.What is NAT?

The basic goal of NAT (Network Address Translation), also known as IP Masquerading, is to allow a private network protected access to an outer network, such as the internet, such that no node in the private network can be directly accessed from the outside, but all nodes on the inside can have clear access to all nodes on the outside. This is accomplished through the use of addressing private IP addresses to the private network and then translating them to (masquerading them as) public IP addresses that the outer network can route. This is accomplished
through the use of natd(8).

1.2. The Basic Theory

To illustrate natd(8) in action, let us take the following sample 
network as an example:

Network A -------- PC #1 --------- PC #2


Let us assume that PC #1 has direct access to Network A, that is, it can send out data packets directly addressed to any PC in Network A and they will reach their destination, and the other way around as well. Now, let us assume that PC #2, which is connected to PC #1, also needs access to Network A, however, you do not wish any PC in Network A to be able to directly access PC #2, that is, you do not wish any PC in Network A to be able to send a data packet to PC #2's IP address and have it reach its destination. Alternatively, wishing to protect PC #2 from being able to be directly accessed by any PC in Network A, you do wish it to somehow retain access to any PC in Network A.

The solution is to translate IP addresses as they move between PC #1, hence the acronym 'Network Address Translation': NAT. As packets move from PC #2 to PC #1, you can translate them as if they were coming from a different address, remember which packets were translated, and when responces to these packets come back from Network A allow them to pass through to PC #2. In this fasion, packets from the outside when responding to packets from PC #2 do not aim their destination at PC #2's address, but at the proxy address that the outgoing packets were masked as. Let us illustrate this in more concrete terms taking the following enhanced sample network:

 192.168.0.3
  PC #3
|
|
|
|  192.168.0.5  192.168.0.1   10.0.0.1
----------- Gateway A -------- PC #1 --------- PC #2
|
|
|
|
  PC #4
 192.168.0.4


Let us assume that Network A consists of PC #3, PC #4 and Gateway A. PC #3 attempts to send some data packets to PC #1. The packets pass to Gateway A who in turn routes them to PC #1 - their destination is reached. Next PC #1 responds with its own data packets, and they reach PC #3. After this, you wish to send data packets from PC #2 to PC #3. The data packets first reach PC #1 who, running natd(8), translates the packets coming from PC #2 as if they were coming from itself - from PC #1. That is, the source address of all packets going from PC #2 is changed from 10.0.0.1 to 192.168.0.1, and then they are sent. A table is kept of all packets which were translated in this fashion, and when later PC #3 responds with his own packets, thinking his responce packets should be sent to 192.168.0.1, they come to PC #1, where the destination addresses of those packets are changed from 192.168.0.1 to 10.0.0.1 and they are sent to PC #2 accordingly. It is clear why this is also termed "IP Masquerading," as one PC's packets masquerade as that of another.

Clearly, a connexion between PC #2 and PC #3 can be easily facilitated when PC #2 sends out packets, first which, after being translated, sit in the NAT table in PC #1 awaiting responces, however, when PC #3 attempts to send data packets first to PC #2 (but addressing them to 192.168.0.1 as it had before, thinking this is the address for PC #2 as well) no corresponding entries in the NAT table exist, so the packets are not translated and sent to PC #2, but instead remain at PC #1, clearly missing their intended destination of PC #2.

Because PC #3 never sees packets coming from PC #2 whose source is addressed as 10.0.0.1 it does not know to send any packets to 10.0.0.1. If it does learn 10.0.0.1 is the address of PC #2, it can, however, in our simple network situation, reach its destination unless there is a firewall at PC #1 blocking all packets that are directly addressed as 10.0.0.1 for PC #2.

1.3 Internet / Registered & Unregistered IP Addresses

In the real world, however, particularly when Network A is the internet, there is a facility for private networks that does not have this added complication. There are three IP address ranges reserved for private use such that no packet from the internet addressed to them will reach it's intended destination.

These three private (unregistered) address ranges are:

192.168.0.0-> 192.168.255.255    (192.168.0.0/16)
172.16.0.0-> 172.16.255.255 (172.16.0.0/16)
10.0.0.1-> 10.255.255.255 (10.0.0.1/8)

They are intended solely for private networks and as such are not assigned as official IP addresses for internet connected computers, and are termed "unregistered". If data packets are sent to an IP address in one of these ranges and a computer in the immediate network is not assigned that number, once they are sent to an ISP or whatever upstream privider you have, they will either be blocked by a firewall or routed to a computer on another private network by that address, or perhaps routed into some other dead end. Simply put, only use them for private networks.

Let us now slightly adjust our sample network:

    201.160.20.83
  PC #3
|
|
|
|  208.1.56.3  208.1.53.45   10.0.0.1
----------- Gateway A -------- PC #1 --------- PC #2
|
|
|
|
  PC #4
30.10.87.132

In this example PC #3 is assigned a legitimate internet IP address and PC #2 is not. If PC #3 attempts to directly send data packets addressed to 10.0.0.1 on PC #2 they will never reach their destination; indeed, tens of thousands of PCs around the may be addressed 10.0.0.1 as an address on a private network. Data packes from PC #2 can, however, as illustrated earler, mask their source IP as PC #1's address of 209.1.53.45 and then successfully be routed across the internet and received responces from any node on the internet through NAT.

1.4Overcoming Your Shortage of Internet Addresses

This is an excellent solution when one wishes to have more PCs access the internet than they have internet IP addresses to assign them. It is also a solution, as was offered earlier, for securely protecting a PC from being directly accessed by some computer in an outer network, in this case the Internet. One shortcoming is that no PC behind NAT can act as a server to the outer network because no node from the outer network can initiate a connexion to make use of it. Connexions must be initiated by the PC behind NAT.

2. Deployment

2.1.Kernel Options

To successfully deploy natd(8) on FreeBSD one must be at least mildly familiar with ipfw(8) AND one must have root privileges. Kernel options and firewall rules can not be changed by anyone but root. To enable ipfw(8) the following option must be enabled in the kernel:

options IPFIREWALL

Because natd(8) also uses the divert(4) kernel packet diversion mechanism the following option must also be enabled in the kernel:

options IPDIVERT

To learn how to compile a custom kernel with these options if they are not already enabled, please refer to the FreeBSD Handbook
(http://www.freebsd.org/handbook/).

2.2.Enabling Packet Forwarding

Now, one must enable packet forwarding so that the PC can forward packets coming to it from the private LAN out into the Internet. To ensure that packet forwarding is automatically enabled when you boot the system, enable make sure the following line is set properly in /etc/rc.conf :

gateway_enable=YES

Once this is done, one can reboot the system, however, this is wholly unnecessary as packet forward can now be set during run-time by issuing the following command:

sysctl -w net.inet.ip.forwarding=1

2.3.ipfw(8) and divert(4)

Once this is accomplished, a rule must be added to your ipfw filtering rules that diverts packets to natd(8) so they can be translated. To view your ipfw(8) rules, issue the command: "ipfw list". A possible simple ipfw(8) rule set may appear thusly:

(root@box)~># ipfw list
01000 allow ip from any to any via lo0
65000 allow ip from any to any
65535 deny ip from any to any
(root@box)~>#

As you may later add addition rules, you want the rule that diverts packets to natd(8) to be activated as early as possible, otherwise, if you, for instance, filter ICMP packets destined for the gateway on which natd(8) is running, and the filter rule comes before the divert rule to natd(8) those IMCP packets will be filtered out even if they had actually been destined for a PC on the private network because natd(8) would not have had an opportunity to translate the destination address from that of the gateway to that of the other PC. In this instance, if the PC on the private network were to send ICMP packets trying to ping a host on the internet, the responces would never return. As such, packets should first be diverted to natd(8) for translation, unless there are certain firewall rules that you wish to apply to all computers on your network.

To divert packets to natd(8) the following rule can be applied:

ipfw add 500 divert natd all from any to any via tun0

This rule assumes that tun0 is your network interface that connects you to the outside network. This assumption clearly may be wrong. As you can see, rule number 500 is given this particular rule so that it is pretty early in the rule set - in the case of the example rule set suppled earlier, it is the very first rule.

So that ipfw(8) knows on what port to look for natd(8) make sure that a corresponding entry for natd(8) is found in /etc/services. To quickly verify that an entry exists for natd(8) in the services file, issue the following command:

(root@box)~># cat /etc/services | grep natd
natd      8668/divert   #Network Address Translation Socket
(root@box)~>#

In our case the entry exists. In most cases it should, unless the
/etc/services file has been tampered with. The default socket that natd(8)
binds to is 8668, as such, our ipfw rule can also have been issued thusly:

ipfw add 500 divert 8668 all from any to any via tun0

"natd" is an alias for port "8668" insolong as an entry defining
this relationship is found in /etc/services.

For the divert rule to become enabled during every startup, and to
ensure that the firewall doesn't block ALL traffic, the firewall rules
must be adjusted in /etc/rc.firewall after firewall_enable=YES and
firewall_type=OPEN are set in /etc/rc.conf.

For our example network adding the following line into
/etc/rc.firewall should be sufficient:

 /sbin/ipfw add 500 divert 8668 all from any to any via tun0

This will create a very "OPEN" firewall upon reboot. It is
strongly recommended that one learns how to further configure the
firewall.

2.4.natd(8) arguments

Once the divert rule has been issued, all packets coming and going
through tun0 (or the network device by which you are connected to the
outside) will be filtered through natd(8).

2.4.1. Basic Usage

In the simplest situation, we want all packets coming through
natd(8) to be translated into your gateway PC's IP address. To run natd(8)
such that it would supply this basic service we would activate it with the
following arguments:

/usr/sbin/natd -interface tun0

natd(8) would run in the background as a daemon, translating all
packets that are diverted through it to have a source IP address that of
the gateway. In our example network, this would be the IP address of:
208.1.53.45 .

2.4.2. More Complex Usage

However, let us take the following slightly more complex network
example:

Let us now slightly adjust our sample network:

           208.1.53.4510.0.0.1
Internet -------- PC #1 --------- PC #2
  |
  |
  |
  |
  |
 PC #3
    208.1.53.46

In this instance, there are two PCs on the private of which only
one has a private IP address and the other an official internet IP
address. If you do not wish natd(8) to translate packets coming from PC #3
but only those of PC #2, running natd(8) with the following arguments
would accomplish this:

/usr/sbin/natd -unregistered_only -interface tun0

Here, only the unregistered addresses would be translated. In this
instance, there is only one, that of PC #2. PC #3 would retain normal
access to the interent, using its own IP address.

Now, instead of supplying the interface which natd(8) should
monitor for incoming and outgoing packets to translate, the actual IP
address to translate the packets to/from can be given. This would be
particularly useful if one does not wish to translate address to the IP
address of the gateway, but of some other PC, which may be needed in more
complex networking scenarios. Giving natd(8) the specific IP to translate
packets to/from can be accomplished with issuing the following:

/usr/sbin/natd -unregistered_only -alias_address 208.1.53.45

Here, all packets from unregistered IP addresses going out will be
translated as having originated from 208.1.53.45.

If the arguments given natd(8) seem to be verbose, they are. In
fact, there are shortened version for each argument that can be given. The
list of shorter versions for the three arguments we have seen so far, and
three additional arguments we will cover in a moment, are:

Long Version  Short Version
-------------------------------------

-alias_address-a
-config-f
-log-l
-interface-n
-port-p
-unregistered_only-u

The -port argument allows natd(8) to bind to a different port than
its default one of 8668. Once this is used, the ipfw(8) divert(4) rule
will need to be adjusted so that packets are diverted to the correct
"-port"-specified port to which natd(8) has bound. An example of this
argument in action would be:

/usr/sbin/natd -port 8667 -unregistered_only -interface pe0

The -log argument simply specifies to take logs of natd(8)
activity. The log file is /var/log/alias.log . Am example of its usage
would be:

/usr/sbin/natd -log -unregistered_only -interface pe0

2.4.2.1Port & Address Redirection

Port and Address are some of the most complex issues with NAT,
yet, often become a necessity for either lack of registered IPs and the
desire to run servers from behind NAT, or for security reasons, utilizing
NAT as a poor man's firewall.

Let us presume that one has a three box LAN. The gateway is
running ipfw(8) and natd(8), and the first box behind NAT is to be used as
an ftp server and the second is to be used as a telnet server. Because of
the nature of NAT, as described in the first section of this Howto, direct
connexions to either the internal ftp or telnet servers from outside NAT
are not possible. All packets will terminate at the gateway. To circumvent
this, the packets can then, at the gateway, be forwarded to either the ftp
or telnet server. How will the gateway know to do this? All packets
reaching port 20 (data port for FTP) or 21 (control port for FTP) can be
forwarded to the internal FTP server. Likewise, all packets reaching port
23 on the gateway can be forwarded to the internal telnet server. This is
called port forwarding. The primary shortcoming of this setup is that the
gateway itself will be unable to server either telnet or ftp on their
regular ports. In short, the gateway can not offer any services which
require ports that are being forwarded to internal boxes in the LAN. The
following diagram illustrates the above Internal FTP and Telnet network
topology clearly.

    201.160.20.83
    Remote PC #1
       |
       |
       | 
      _/\/\_     208.1.56.3    10.0.0.1    10.0.0.2
  /  \   20,21,23    20,21 23
     |INTERNET|------- Gateway A ----- FTP Server ------ Telnet -O
      \_  _/
       \/\/
       |
       |
   |
    Remote PC #2
    30.10.87.132

The syntax for the port forwarding option, -redirect_port, in the
natd(8) man page initially looks daunting, but it really isn't. In the
most simple usage, to enable the port forwarding for the Telnet server,
the following will suffice presuming the alias interface is pe0:

/usr/sbin/natd -redirect_port tcp 10.0.0.2:23 23 -interface pe0

If the gateway has numerous alias IPs on the external interface,
then it can be specified packets directed to which of those IPs - in our
example, 208.1.56.4 - will be forwarded to the internal Telnet server:

/usr/sbin/natd -redirect_port tcp 10.0.0.2:23 208.1.56.4:23
-interface pe0

Finally, if one wishes to specify the remote IPs whose packets
will be allowed to be forwarded to the internal Telnet server, the
following would accomplish this, if the remote IP is 30.10.87.132 and the
gateway, unlike in the previous example, has no aliases:

/usr/sbin/natd -redirect_port tcp 10.0.0.2:23 23 30.10.87.132
-interface pe0

Finally, if one wishes to specify the remote IPs *and* range of
ports whose packets will be allowed to be forwarded to the internal Telnet
server, the following would accomplish this:

/usr/sbin/natd -redirect_port tcp 10.0.0.2:23 23 30.10.87.132:100-110
-interface pe0

In this example, only telnet requests originating from ports 100
through 110 on the remote IP 30.10.87.132 will be forwarded to port 23 on
the internal Telnet server 10.0.0.2. This is a very peculiar specification
and is only presented here as a hypothetical usage of the controlling the
remote IP and ports with the -redirect_port option.

Keep in mind, that single ports and range of ports can be
specified following any IP and ':'. To specify a range, a '-' is used,
like in the above example. Single ports can be specified by simply
following the ':' on their own. Only the IP of the internal server to whom
the ports are being forwarded is necessary. Remote IPs need not be
specified if it's not required to control what remote IPs packets will
be forwarded from, and the alias IP on the gateway need not be specified
if there is only one registered IP on the external interface. In short,
the first form for port redirection is the one that will suffice for the
vast majority of circumstances.

If an IP is not specified for the internal server to whom to
forward the ports, then natd(8) will assume ports are being forwarded on
the local box, i.e. the gateway. That is the most minimalistic usage of
the -redirect_port option, as shown below:

/usr/sbin/natd -redirect_port tcp 23 6666 -interface pe0

In this example, all telnet requests to port 6666 on the gateway
will be forwarded to port 23 on the gateway. To complete the initial
example, to forward FTP to the internal FTP server along with Telnet to
the internal Telnet server, the following natd(8) usage would accomplish
this, presuming the external interface on the gateway is pe0:

/usr/sbin/natd -redirect_port tcp 10.0.0.1:20-21 20-21
-redirect_port tcp 10.0.0.2:23 23 -interface pe0

The parameters to natd(8) can get lengthy and cumbersome such that using a configuration file instead, as explained in section 2.4.3, is recommended. In addition, UDP packets are also supported for forwarding. To do this, simply specify "udp" instead of "tcp" in the prototype section directly following the option "-redirect_port." Most services are tcp, such as FTP, Telnet, Finger, SSH, etc.

Address redirection with natd(8) is very similar. In short, it allows the gateway to redirect all packets destined for one IP to an internal IP address. This is also called as "Static NAT." It is most useful where one has multiple registered IPs, such that all packets to one will get redirected to an internal server behind NAT whilst packets to another IP would be served by the gateway itself, or another internal server. This clearly presumes that the external interface on the gateway has multiple IPs aliased on it.

The syntax for address redirection is simple. Presuming the we
wish to redirect all packets destined for the IP address 208.1.56.4 on the
gateway to an internal server 10.0.0.3, the following usage would
accomplish this:

/usr/sbin/natd -redirect_address 10.0.0.3 208.1.56.4 -interface
pe0

The usage is far more simple as one needs not specify packet types
(UDP, TCP) or ports to be specifically forwarded.

2.4.3. Configuration File

Finally, if there are too many arguments to pass to natd(8) to make it deemed practical, the -config argument can be passed to natd(8) followed by the configuration file that would hold all of the arguments that would normally be passed in on the command line.

Let us say we wished to store the following list of arguments to
be passed to natd(8) in /etc/natd.cf :

-unregistered_only
-alias_address 208.1.53.45
-log

We could do the following:

(root@box)~># echo "unregistered_only" > /etc/natd.cf
(root@box)~># echo "alias_address 208.1.53.45" >> /etc/natd.cf
(root@box)~># echo "log" >> /etc/natd.cf

And our new configuration file /etc/natd.cf would contain:

(root@box)~># cat /etc/natd.cf
unregistered_only
alias_address 208.1.53.45
log
(root@box)~>#

Now, we would only need to start natd(8) thusly:

(root@box)~># /usr/sbin/natd -f /etc/natd.cf
(root@box)~>#

And all of the configuration options in /etc/natd.cf would take hold.


    2.5.  Starting natd(8) at Boot Time

FreeBSD 3.x offers extra options to simplify starting natd(8) at boot time, however, it is just as doable with FreeBSD 2.2.x. The process with both versions is simple.

For the following examples, we will presume the external interface on your gateway is pe0 and that you are using a configuration file as described in section 2.4.3.

With FreeBSD 3.x, open /etc/rc.conf and add the following lines:

natd_enable="YES"
natd_interface=""
natd_flags="-f /etc/natd.cf"

In section 3.4.3 where configuration files were explained, we specified the natd(8) interface inside /etc/natd.cf so it would not have to be specified again here, however, if one wishes, one can remove the line specifying the alias IP or interface in the /etc/natd.cf and instead do the following:

    natd_enable="YES"
    natd_interface="pe0"
    natd_flags="-f /etc/natd.cf"

In addition, if one wishes to specify the alias IP address instead
of the interface, one can do the following, presuming the alias IP is
208.1.53.45:

    natd_enable="YES"
    natd_interface="208.1.53.45"
    natd_flags="-f /etc/natd.cf"

With FreeBSD 2.2.x, open /etc/rc.local and add the following
line:

/usr/sbin/natd -f /etc/natd.cf && echo -n ' natd'

This will initialize natd with all options in /etc/natd.cf, and unlike with FreeBSD 3.x, where the alias IP or address can be specified separately in /etc/rc.conf, the alias IP or address must be specified in /etc/natd.cf with FreeBSD 2.2.x.

Note, this FreeBSD 2.2.x method for initializing natd(8) can be used on a FreeBSD 3.x system instead of the method outlined for FreeBSD 3.x previously.

3.Appendix

Manual Page resources:

8 natd
4 divert

 

By: Lasker

© 1997 - 20013 Defcon1, www.defcon1.org , Copyrights for all materials on this web site are held by the individual authors, artists, photographers or creators. Materials may not be reproduced or otherwise distributed without permission of www.defcon1.org and the content's original author.

Defcon1-Header2
Tool-Bar-2Defcon1  Webmail