How to build a NAT firewall

First

OK, first you need to install the box. Just choose a default installation, choose kernel-developer (Full sources but no X-windows), answer no when prompted to install the "Ports Collection".

I rely on the fact that you are no newbie, that is - you can install the box and configure networking support, so both network interfaces have proper connectivity.

Optimize kernel configuration file

After installation go to the /usr/src/sys/i386/conf directory and copy the GENERIC kernel configuration file to a file with another name, mostly to avoid changing the default kernel configuration file.

Let's just take it that the name (hostname) of the firewall are "gw", so copy the GENERIC file to GW (cp GENERIC GW).

Now, edit the GW file to remove devices you don't need in the firewall. This is a highly individual process, as some might need support for RAID controllers and others may want to have PCMCIA support.

If you are not sure of this, then just leave the default devices in there, as this process is mainly for optimizing speed and reducing memory usage..

Changes to the default kernel configuration

In order for the kernel to have firewall support, which are not in the default kernel, add this:

options IPFIREWALL
options IPFIREWALL_VERBOSE
options IPFIREWALL_VERBOSE_LIMIT=0

RANDOM IP ID causes the ID field in IP packets to be randomized instead of incremented by 1 with each packet generated. This option closes a minor information leak which allows remote observers to determine the rate of packet generation on the machine by watching the counter.

So add:

options RANDOM_IP_ID

To have NAT support, add this to the kernel configuration:

options IPDIVERT

The IPFireWall software have another feature, that feature are bandwith throttle - or bandwith control. This way, the amount of bandwidth used to/from specific sites or networks can be limited, so the entire internet connection doesn't go to netradio or movie downloads.
Add to the kernel configuration file:

options DUMMYNET

Recompile the kernel

This is no different than the usual compile-dance, go to (or stay in) the /usr/src/sys/i386/conf directory.

Type "/usr/sbin/config GW"

Go to ../../compile/GW

Type "make depend"

After finished making all dependencies, type "make" to make it start compiling.

Now it's time to go for a cup of coffee, as recompilation of the kernel are something that usually takes quite some time, a fast processor and addequate amounts of RAM usually speeds tings up - but even on a very fast machine it still takes some time..

After finished compiling, type "make install" to install the new kernel. If this step fails, please change the kernel_securelevel_enable="YES" in /etc/rc.conf to kernel_securelevel_enable="NO" and reboot the machine and try "make install" again..

Disable services

Disabling services not needed on the firewall will contribute in minimizing the risk of intrusion and remote exploits.

The portmapper should be desabled as per default in FreeBSD 4.4, but...
In /etc/rc.conf:

inetd_enable="NO"
portmap_enable="NO"
sendmail_enable="NO"
inetd_enable="NO"

Gateway

In order for the machine to act as a network gateway, the gateway option must be enabled - this is pretty important, unless you plan on making it a proxy-firewall, using Squid or Apache.

In /etc/rc.conf:

gateway_enable="YES"

Enable Firewall and NAT
The firewall must be enabled, this is also done in /etc/rc.conf.

Add this:
firewall_enable="YES"
firewall_type="simple"

To enable the NAT feature, add this to /etc/rc.conf:

natd_enable="YES"
natd_interface="fxp0"
natd_flags=""

The fxp0 in natd_interface must be changed to match the NIC on the outside, so if you have a 3Com 509B network card and it is found as the first 509B card, the line would be natd_interface="ep0".

Kernel securelevel

This part is pretty damn important, so read carefully:

The kernel runs with four different levels of security. Any super-user process can raise the security level, but no process can lower it.

The security levels are:
  • -1
    Permanently insecure mode - always run the system in level 0 mode.
    This is the default initial value.

  • 0
    Insecure mode - immutable and append-only flags may be turned off.
    All devices may be read or written subject to their permissions.

  • 1
    Secure mode - the system immutable and system append-only flags may not be turned off; disks for mounted filesystems, /dev/mem, and /dev/kmem may not be opened for writing; kernel modules may not be loaded or unloaded.

  • 2
    Highly secure mode - same as secure mode, plus disks may not be opened for writing (except by mount) whether mounted or not.
    This level precludes tampering with filesystems by unmounting them, but also inhibits running newfs while the system is multi-user mode.

    In addition, kernel time changes are restricted to less than or equal to one second. Attempts to change the time by more than this will log the message "Time adjustment clamped to +1 second".

  • 3
    Network secure mode - same as highly secure mode, plus IP packet filter rules (see ipfw and ipfirewall) cannot be changed and dummynet configuration cannot be adjusted.
My recommendation are setting securelevel to 2 or 3, where I myself would set it to securelevel 3 - but be aware that this will mean rebooting the firewall every time you made changes to ipfw filter rules.

Hardening features

The following should be added to /etc/sysctl.conf:

To defending against sequence number attacks based on rfc1948 by randomize initial sequence number, add:

net.inet.tcp.strict_rfc1948=1

To verify that an incoming packet arrives on an interface that has an address matching the packet's destination address, add:

net.inet.ip.check_interface=1

To drop SYN packets destine to non-listening tcp/udp port.
This will create a blackhole and protect somewhat against stealth port scans:

net.inet.tcp.blackhole=2
net.inet.udp.blackhole=1

And finally, to log all those packets desited for non-listening ports:

net.inet.tcp.log_in_vain=1
net.inet.udp.log_in_vain=1


Configuration of the firewall

The firewall configuration are located in the /etc/rc.firewall file.

Since we told the firewall software that we are using it as a "simple" firewall, the active configuration are the one in the "simple" section. Usually the default configuration are enough, especially since we just buld a NAT firewall.

For a comprehensive description on the fetaures of IPFW, please consult the man pages (man ipfw).

Port redirection

Normally, a firewall setup would include a DMZ, a third network interface, where publicly accesible servers should be located. One of these servers could be a mail-relay server, to handle and sort incoming mail before it reaches the central mail system - such as MS Exchange (known for it's non-existing features for relay control).

Many corporate installations would include something for scanning, filtering and validating the inbound and outbound mail, like MailSweeper.

This server would live on the DMZ..

There are two different approaches into solving this, one is port redirection - the other are address redirection.

So, how is this done..?

Peace of cake - really..

Let's just for arguments sake assume that the DMZ network have the address-space of 10.0.0.0 with a C-Class network (netmask 255.255.255.0), the DMZ interface is 10.0.0.1 and the MailSweeper machine are 10.0.0.2.

The easiest are port-redirection, change in /etc/rc.conf:

natd_flags=""

Should be changed to:

natd_flags="-redirect_port tcp 10.0.0.2:25 25"


This would redirect port 25 from the natd_interface to port 25 on 10.0.0.2.

Similar, for redirecting all traffic to an outside IP address (also known as "static NAT"):

natd_flags=""

Should be changed to;

natd_flags="-redirect_address 10.0.0.2 80.80.80.80"


Where the 80.80.80.80 address are really the address on the natd_interface or any public address available on the natd_interface (the "outside" interface).

More advanced stuff and facilites are available through the man pages.

Bandwidth limiting

FreeBSD comes with a bandwidth management in dummynet.
dummynet can be extremely useful to slow down a potential fast link DoS another slower link.

Lets assume that a lot of bandwith goes to downloading movies from servers at the 1.1.1.1 network.

Add to your configuration in /etc/rc.firewall:

First construct the pipe:
add pipe 1 ip from any to 1.1.1.0/24

Then configure the pipe:
pipe 1 config bw 256Kbit/s


This limits bandwith for the 1.1.1.0/24 network to 256 Kbit/s.

More realisticly, the bandwith used for mail transactions can be limited, so large mails doesn't chew up the entire internet connetion:

First construct the pipe:
add pipe 1 ip from any to 10.0.0.2

Then configure the pipe:
pipe 1 config bw 256Kbit/s


This limits mail transactions to 256 Kbit/s.

More information regarding other features, such as packet delay, forced random packetloss etc. can be found in the man pages ("man ipfw" or "man dummynet").

References

FreeBSD homepage: http://www.freebsd.org/

FreeBSD Manual: http://www.freebsd.org/handbook/

Address Allocation for Private Internets: http://www.muine.org/rfc/rfc1918.txt

The IP Network Address Translator (NAT): http://www.muine.org/rfc/rfc1631.txt

Traditional IP Network Address Translator (Traditional NAT): http://www.muine.org/rfc/rfc3022.txt

Bandwidth management: http://www.iet.unipi.it/~luigi/ip_dummynet/

The Twenty Most Critical Internet Security Vulnerabilities (Updated): http://66.129.1.101/top20.htm

Credits

This content are in part inspired from Hoang Q. Tran's "FreeBSD firewall using IP filter".