Ben's FreeBSD Firewall HOWTO ============================ Goal ---- Create a FreeBSD machine that acts as a "bridge" to the internet for an entire LAN. The machine has one ethernet interface attached to a broadband connection, and a second interface attached to the LAN. When a computer connects to the LAN, it is automatically handed a DHCP address by the server. The server provides NAT for the whole LAN. The server also provides some (varying) degree of firewall protection by blocking incoming traffic from the internet. If you didn't understand all those acronyms, you probably shouldn't be reading this doc. :-) Target Audience --------------- People who have a spare box lying around, and would rather set it up as a firewall/router, rather than buy one of those $250 "NAT in a box" gizmos. Not only is this alternative cheaper, but you get more control. And you could even make your machine into an email server, web server, file server, etc. There's also an assumption here that you've chosen to do this with BSD instead of Linux. Maybe you've heard (or experienced) nightmare stories about how difficult it is to make ipchains work on Linux, or whatever. Anyway, congratulations on your choice of FreeBSD and welcome to the cathedral. You'll be surprised how easy this is. After all, BSD invented the TCP/IP stack! Prerequisites ------------- I am assuming that you have: * A computer with 2 ethernet interfaces in it. * FreeBSD 4.2 (or later) installed. * A working net connection on at least one interface. * Some kind of comfort with Unix I'll occasionally make references and comparisons to Linux, for those who are "making the transition". :-) STEP-BY-STEP ------------ 1. Build a firewall-enabled kernel. This might mean learning how to build a FreeBSD kernel. No biggie. Here's the nutshell: * cd /usr/src/sys/i386/conf * cp GENERIC MYKERNEL * edit MYKERNEL * add these lines near the beginning: options IPFIREWALL options IPFIREWALL_VERBOSE_LIMIT=10 options IPDIVERT * /usr/sbin/config MYKERNEL * cd ../../compile/MYKERNEL * make depend * make * make install 2. Verify your ethernet drivers. Make sure that the FreeBSD kernel recognized two distinct ethernet cards on bootup. Use 'dmesg | more' to examine boot messages. Unlike Linux, where every ethernet card is named "eth?", BSD has specific names for each driver, like "xl0", "dc0", etc. It will be obvious when the kernel finds an ethernet interface: it always prints the MAC address. Write down the names of your two cards. For this example, we'll assume they're called "xl0" and "sis0". 3. Make sure you have necessary binaries. You'll need * natd (the NAT daemon) * ipfw (the firewall shaper) * dhcpd (the dhcp server daemon) The first two utilities probably came auto-installed in /sbin. The third program you'll probably have to install out of /usr/ports. (Translation: FreeBSD rarely uses binary RPMs or the like. Instead, all 3rd party add-ons are built from source. If you haven't read about the `ports' tree, now would be a good time to go take 10 minutes and look it up in the FreeBSD Handbook.) I believe /usr/ports/net has two isc-dhcp servers; cd into one and run `make install`. You'll have to have a net connection to fetch the tarball. 4. Edit /etc/rc.conf While Linux uses a SysV-style startup system (lots of rc.N/ directories and scripts), BSD has a single file for you to edit. The file `/etc/rc.conf' contains nothing but variables that *you* set to determine your system's behavior. These variables happen to override about a zillion default variables in /etc/defaults/rc.conf -- which you can read if you want to see all the things you can tweak. Chances are, the BSD installation system (which, by the way, you can always run from /stand/sysinstall) probably auto-generated one for you based on its questioning. Don't be afraid to hack on it or change it around. Also, because you're setting variables, the ordering doesn't matter one whit. I'm only going to show the variables you need to get a firewall going -- ones specific to networking. Here they are: -------------------------------------------------------------- network_interfaces="xl0 sis0 lo0" ### The main Broadband interface hostname="piggy.red-bean.com" ifconfig_xl0="inet 64.193.94.49 netmask 255.255.255.252" defaultrouter="64.193.94.50" ### The secondary LAN interface ifconfig_sis0="inet 192.168.0.1 netmask 255.255.255.0" ### Loopback interface (needed by samba, if you ever run it) ifconfig_lo0="127.0.0.1 netmask 255.255.255.0" ### Firewall stuff gateway_enable="YES" firewall_enable="YES" firewall_type="simple" natd_enable="YES" natd_interface="xl0" # broadband interface here dhcpd_enable="YES" ---------------------------------------------------- .... that's all there is to it. Most of the variables are self-explanatory, and cause great magic to happen behind the scenes. :) 5. Edit /etc/rc.firewall Destroy any default garbage in this file (or just back it up.) Here's a real simple firewall config: ------------------------------------------ ### Firewall initialization/configuration # Flush out all the old rules /sbin/ipfw -f flush # "Divert" traffic through natd /sbin/ipfw add divert natd all from any to any via xl0 # For now, allow all traffic to pass between interfaces: /sbin/ipfw add pass all from any to any # Add more restrictions later... ------------------------------------------- 6. Edit /etc/dhcpd.conf Depending on which version of dhcpd you install, this file *might* need to exist in /usr/local/etc instead. You can be paranoid and put it in both places. Again, this file describes how DHCP addresses. If you're lazy, skip the whole "group" section -- that's only if you want to assign static DHCP addresses. --------------------------------------------- # Global settings for all DHCP clients option domain-name "red-bean.com"; option routers 192.168.0.1; option subnet-mask 255.255.255.0; option domain-name-servers 207.200.73.80; # General IP pool to use for unmatched MAC addresses: subnet 192.168.0.0 netmask 255.255.255.0 { range 192.168.0.10 192.168.0.100; } # Specific MAC addresses get specific IPs: group { # Ben's notebook, landline: host newt_landline { hardware ethernet 08:00:46:08:90:C2; fixed-address 192.168.0.17; } # Ben's notebook, wireless: host newt { hardware ethernet 00:02:2d:1d:05:38; fixed-address 192.168.0.17; } # Benbox, the Win2K Desktop: host benbox { hardware ethernet 00:a0:cc:53:51:79; fixed-address 192.168.0.33; } } ---------------------------------------------------- 7. Edit /etc/rc.local This is where you manually run things at boot time. Either create the file, or add to it this one line: /usr/sbin/dhcpd sis0 ...which will cause dhcpd to listen on your LAN interface after booting up. 8. Edit /etc/hosts After assigning an address, dhcpd will often make annoying complaints that it can't do a reverse DNS lookup of the IP addresses it's handing out. My solution is to simply put them into /etc/hosts: # Local DHCP boxes 192.168.0.17 newt newt.red-bean.com 192.168.0.33 benbox benbox.red-bean.com 9. Reboot! Upon reboot, you should see both ethernet interfaces configured, and see a bunch of messages about ipfw and natd starting up. Troubleshooting --------------- dhcpd is often the big complainer. It will complain if it can't find the dhcpd.conf in the right place, or if the file has a syntax error. You can examine your list of firewall "rules" by running `ipfw show`: piggy# ipfw show 00100 84 6617 allow ip from any to any 65535 0 0 deny ip from any to any Rules can be added; man ipfw or read its own HOWTO. VARIANT: modem ppp ------------------- You can do all the above using a *modem* (ppp link) as your primary net connection, instead of an ethernet interface. I'm assuming that first you're able to get ppp working on your own. There's a HOWTO for that already. In the end, you'll probably just have to tweak /etc/ppp/ppp.conf and then run 'ppp -auto provider'. I'm certainly not an expert on this, but I managed to get ppp working with the firewall. Here are the changes I made to the configuration above: * /etc/rc.conf: "network_interfaces": replace xl0 with ppp0 "natd_interface": replace xl0 with tun0 * /etc/rc.local: add a line to start ppp with the "nat" option: /usr/sbin/ppp -auto -nat provider * /etc/rc.firewall: comment out the "divert" line; the 'ppp -nat' is already doing diversion.