Using TrueOS as a IPFW based home router

Status
Not open for further replies.
K

Kris Moore

Guest
Setting up a FreeBSD / TrueOS home router with IPFW

Over the Christmas holidays I had some spare time and was ready to take the plunge and retire an old Asus router. It had begun getting rather slow, due to the increasing number of devices connected to our network, and of course I wanted peace of mind using a FreeBSD system I could be sure was up to date with security fixes. I used PC-BSD’s server release, TrueOS 10.1, because I wanted to use ZFS with boot-environments to ensure upgrading and replacing disks would be risk-free down the road. The following details how I setup TrueOS on the new box.




* Disclaimer *

This is by no means a comprehensive IPFW or NATd tutorial, but hopefully it can serve as a good reference for other users trying to do similar things.



The Hardware:

To replace it, I had an old AMD 64 x2 Dual-Core system which hadn’t been used in a while.

CPU: AMD Athlon™ 64 X2 Dual Core Processor 5200+ (2719.21-MHz K8-class CPU)
real memory = 4966055936 (4736 MB)
avail memory = 3974365184 (3790 MB)
80GB IDE disk drives (2x)
Intel PWLA83911GTBLK PRO/1000 GT network adapter (2x) — (Amazon Link)

This box is easily overkill, with more than enough horsepower to handle our internet traffic, which is currently 100Mb/s down, 10MB/s up, however it was something I had on hand which means I was only out the cost of a couple network cards. Also, I expect it will be able to keep up with future speed increases, since 200Mb/s down and 20MB/s up is supposed to be coming to our area in the near future.

The Installation:

To get started, I grabbed a copy of the CD-sized installer for TrueOS from PC-BSD’s website:
http://www.pcbsd.org/en/download.html

The installation was very straight forward. I picked the defaults to use ZFS on root, with GRUB so that boot-environments work properly. The only major change was to go to advanced disk setup and attach the second 80GB disk drive as a mirror of the primary (ada0). Since these disks aren’t super new I wanted the ability to easily replace them when they begin to fail down the road.

Post Install Configuration:

With the installation finished, the first thing I did was to edit /etc/rc.conf with the following lines:

# Disable some PC-BSD / TrueOS services we don’t need to run on a router
syscache_enable=“NO“
php_fpm_enable=“NO“
appcafe_enable=“NO”

This disabled the AppCafe / Warden web-interface, since I don’t plan on running any applications or jails on this box, only using it purely as a router. Of course if you plan on running jails or doing other package work, the web-interface could be useful and you can skip these lines.

Next I started the configuration of the network interfaces:

# Network configuration
hostname=“interdictor“
ifconfig_em0=“inet 192.168.1.1 netmask 255.255.255.0″ # LAN IP / Bottom NIC
ifconfig_em1=“inet XXX.XXX.XXX.XXX netmask XXX.XXX.XXX.XXX” # WAN IP / Top NIC
defaultrouter=“XXX.XXX.XXX.XXX”

# Enable gateway mode
gateway_enable=“YES”

A couple of comments help me keep straight which ports on the back of the system are the WAN / LAN. Of course I replaced the XXX lines with the static IP / gateway from my ISP.

Next, I was going to be using this router to assign local IP’s with DHCP, so I first installed the DHCP server from PC-BSD’s package repo:

# pkg install net/isc-dhcp43-server

Next, I configured my DHCP information in /usr/local/etc/dhcpd.conf

# option definitions common to all supported networks…
option domain-name “XXXXXXXXX”;
option domain-name-servers 8.8.8.8, 8.8.4.4;
default-lease-time 86400;
max-lease-time 90000;

# Use this to enble / disable dynamic dns updates globally.
#ddns-update-style none;

# If this DHCP server is the official DHCP server for the local
# network, the authoritative directive should be uncommented.
authoritative;

# Use this to send dhcp log messages to a different log file (you also
# have to hack syslog.conf to complete the redirection).
log-facility local7;

# Home Network
subnet 192.168.1.0 netmask 255.255.255.0 {
range 192.168.1.100 192.168.1.254;
option domain-name-servers 8.8.8.8, 8.8.4.4;
option broadcast-address 192.168.1.255;
option routers 192.168.1.1;
default-lease-time 86400;
max-lease-time 90000;
}

And finally enable the service in /etc/rc.conf

# DHCPD config
dhcpd_enable=“YES“
dhdpd_ifaces=“em0”

With DHCPD now enabled, I next went and created /etc/natd.conf with the following:

interface em1
use_sockets yes
same_ports yes
dynamic yes
log_denied yes
log yes

Optionally if you run services behind NAT and need to forward ports, you can do so with syntax like the following:
# Sample redirect port
# redirect_port tcp 192.168.1.20:80 80

Where 192.168.1.20 is the local IP of your system hosting a service, and “:80 80” being the local server port, and port on your router to open.

For our last config, we now need to setup our firewall rules, which we will do by creating the file /etc/ipfw.rules with a setup something like this:

#!/bin/sh
# Flush out the list before we begin.
ipfw –q –f flush

# Set rules command prefix
cmd=“ipfw –q add“
pif=“em1” # interface name of NIC attached to Internet
iif=“em0” # interface name of NIC attached to LAN
server=“192.168.1.1″
inside=“192.168.1.0/24″
me=“XXX.XXX.XXX.XXX” # Public WAN address
ks=“keep-state” # Laziness
skip=“skipto 600″

# Allow everything through the local NIC
######################################
$cmd 00020 allow all from any to any via em0

######################################
# No restrictions on Loopback Interface
######################################
$cmd 00025 allow all from any to any via lo0

# NAT the inbound stuff
######################################
$cmd 00100 divert natd ip from any to any in via $pif # NAT any inbound packets

######################################
# Allow packet through if it matches existing entry in dynamic rules

######################################
$cmd 00105 check-state

######################################
# Allow all outgoing packets
######################################
$cmd 00110 $skip all from any to any out via $pif $ks

# Deny all inbound traffic from non-routable reserved address spaces
######################################
$cmd 00300 deny all from 192.168.0.0/16 to any in via $pif #RFC 1918 private IP
$cmd 00301 deny all from 172.16.0.0/12 to any in via $pif #RFC 1918 private IP
$cmd 00302 deny all from 10.0.0.0/8 to any in via $pif #RFC 1918 private IP
$cmd 00303 deny all from 127.0.0.0/8 to any in via $pif #loopback
$cmd 00304 deny all from 0.0.0.0/8 to any in via $pif #loopback
$cmd 00305 deny all from 169.254.0.0/16 to any in via $pif #DHCP auto-config
$cmd 00306 deny all from 192.0.2.0/24 to any in via $pif #reserved for doc’s
$cmd 00307 deny all from 204.152.64.0/23 to any in via $pif #Sun cluster interconnect
$cmd 00308 deny all from 224.0.0.0/3 to any in via $pif #Class D & E multicast
######################################

# Deny public pings
######################################
$cmd 00310 deny icmp from any to any in via $pif

# Log all the other troublemakers
$cmd 00550 deny log all from any to any

# Skip location for NATD
$cmd 600 divert natd ip from any to any out via $pif # skipto location for outbound stateful rules
$cmd 610 allow ip from any to any


Now that NATD / IPFW are setup, we can set them to run at boot with the following /etc/rc.conf entries:

# IPFW
firewall_enable=“YES“
firewall_logging=“YES“
firewall_script=”/etc/ipfw.rules”

# NATD
natd_enable=“YES“
natd_interface=“em1“
natd_flags=”-m –f /etc/natd.conf”

If you don’t want to reboot the server you can start the services with the following commands:

# service natd start
# service isc-dhcpd start
# service ipfw start

Also, the ipfw.rules file is just a shell-script, so you can always re-apply the firewall rules with “sh /etc/ipfw.rules”.

That’s it! At this point you should be able to replace your consumer router with the new system, and it’ll begin handling NAT traffic, assigning DHCP addresses, etc. Even during my network’s peak usage, I’ve yet to see the system drop below 95% idle.





Bonus content!

Some users may want to do NAT reflection for public facing services. This basically means you can have clients, such as your phone, connect to the same public address, regardless of being on the local LAN, or roaming outside the home. OpenBSD has a great explanation of this, along with the methods of solving it. I was able to easily do this with IPFW and TCP proxying. To get started, install tcpproxy:

# pkg install tcpproxy

Next, we have to create our /usr/local/etc/tcpproxy.conf file:

listen * 50080
{
remote: 192.168.1.20 80;
remote-resolv: ipv4;
};

In the example above, we are going to listen on port 50080 on the local router machine, and proxy this to the remote machine on the LAN: 192.168.1.20 on port 80. Next we will need to add a firewall rule to /etc/ipfw.rules causing it to redirect traffic coming from the LAN NIC to this service:

# Setup NAT reflection
$cmd 00002 fwd 127.0.0.1,50080 tcp from 192.168.1.0/24 to $me 80 in via em0

With those entries complete, you can now start the tcpproxy service, and restart IPFW to enable them.


sZiPd48HQv4


Continue reading...
 
  • Thanks
Reactions: Oko
Status
Not open for further replies.
Back
Top