FreeBSD Router/Gateway/Firewall HOW-TO

Prolog

Yes, you can replace your Cisco, or other Router/Gateway/Firewall device with something better. As a long-time network administrator, I have worked with many Routers, Gateways, and Firewalls. Cisco, Juniper, 3Com, and many other known or unknown manufacturers. While I was working with those, I was often frustrated with the management tools, and management interfaces provided on those devices. Who the hell designed the software that runs on these devices? Were they from another planet? There seemed little logical flow, or coherency, and the names of the commands were more often-than-not, unintuitive.

I had been working with, and using FreeBSD for quite some time, and decided enough is enough. I'm going to create my own.

The OpenBSD Packet Filter was merged into the FreeBSD base system, some time ago. So this task should prove to be very effective, and relatively easy.

If you don't know anything about pf, I can tell you that this firewall was made by real UNIX hackers—no kidding. They stand behind one of the most secure operating systems; OpenBSD. On security events like Defcon and BlackHat, hackers don't even try to mess with OpenBSD. So what to expect from it's Firewall? A lot! There's even a written poem describing the firewall.

So let's get started...

Welcome to FreeBSD! Release Notes, Errata: https://www.FreeBSD.org/releases/ Security Advisories: https://www.FreeBSD.org/security/ FreeBSD Handbook: https://www.FreeBSD.org/handbook/ FreeBSD FAQ: https://www.FreeBSD.org/faq/ Questions List: https://lists.FreeBSD.org/mailman/listinfo/freebsd-questions/ FreeBSD Forums: https://forums.FreeBSD.org/ Documents installed with the system are in the /usr/local/share/doc/freebsd/ directory, or can be installed later with: pkg install en-freebsd-doc For other languages, replace "en" with a language code like de or fr. Show the version of FreeBSD installed: freebsd-version ; uname -a Please include that output and any error messages when posting questions. Introduction to manual pages: man man FreeBSD directory layout: man hier Edit /etc/motd to change this login announcement.
~ 6:06am Fri, 23 devbox#

The possibilities...

If someone tries to break into our company server, redirect them to the dummy machine, log all their activities, while enjoying my cup of coffee.

or, just for fun...

If that cute girl from the customer service department ever goes to that popular online dating site, redirect her to my profile first ;-)

The possibilities are endless!

There are many reasons to choose pf over some of the other possibilities. Here are just a few:

The steps to perform...

Let's get to it!

I'll now describe how you can replace your Cisco/Linksys/Netgear/whatever router/gateway/firewall with FreeBSD.

So what will our server do?

  1. Act as a router to your connection to the Internet. (routing, NAT)
  2. Blocking, redirecting, and logging of traffic
  3. DHCP server for your internal network

You will need a server with two network cards. In this example the two network cards will be the re0, and nfe0.
For this example, let's assume that your ISP gave you a block of 8 IP addresses for your organization. The range (in CIDR notation) is 24.0.0.0/29. One IP address is reserved for their router, and that IP address is 24.0.0.1, with a netmask of 255.255.255.248. That will be our gateway. So delegate the next IP address in the range to be our WAN IP. We will assign this IP to the re0 interface. Next we'll need an interface that will be connected to our local network. We will use the nfe0 interface with the IP 192.168.1.1/24 for this example. In our local network, we will have three more servers that we need to allow traffic to; One is our DNS server, the next is our MAIL server, and the last, our dummy server with intrusion detection tools, so that we can see what sort of attacks are popular today, or if there's someone we may know of. Also I would like to access my web server on the inside from my mobile phone when I'm not in the office. We didn't want them to be on an outside IP address range, so we put them in our local LAN. (Best solution is to put your servers in a DMZ. It's more secure, and standard proceedure in this sort of arrangement).

Open your /etc/rc.conf file on your FreeBSD, and add this to that file

# # # NETWORK # # # defaultrouter="24.0.0.1" # My ISP Gateway IP hostname="bsd-router.yourdomain.com" ifconfig_re0="inet 24.0.0.2 netmask 255.255.255.248" # My WAN IP ifconfig_nfe0="inet 192.168.1.1 netmask 255.255.255.0" # My LAN IP # # # # # # # # # #
# # # FIREWALL and NAT # # # gateway_enable="YES" # Yes we will forward some traffic pf_enable="YES" # enable The Firewall pf_rules="/etc/firewall" # configuration file pf_flags="" pflog_enable="YES" # start pflogd(8) pflog_logfile="/var/log/pflog" # where pflogd should store the logfile pflog_flags="" ftpproxy_enable="YES" # don't ask now, we need that ftp-proxy(8) ftpproxy_flags="-b 192.168.1.1 -D 6" # bind it to 192.168.1.1 with debug level 6 # # # # # # # # # # # # # # #

We will need lists of networks that we can trust. For example, your company network, or your ISP. Later we'll import this list in a table. So create the file /etc/PERMIT_NETWORKS, and put your desired networks in that file like this

# My Mobile network provider 212.91.96.0/19 212.15.160.0/19 # My company network 8.8.8.0/24

Now create the file /etc/firewall

touch /etc/firewall
and open it. Then add the following

# # # ext_if="re0" int_if="nfe0" localnet = $int_if:network # For NAT purposes me="24.0.0.2" me_in="192.168.1.1" lan="192.168.1.0/24" dns="192.168.1.5" mail="192.168.1.6" webserver="192.168.1.7" dummy="192.168.1.8" icmp_types = "echoreq" table <dummies> persist table <permit_networks> file "/etc/PERMIT_NETWORKS" set loginterface $ext_if # scrub on $ext_if reassemble tcp no-df random-id scrub in all # Do NAT. nat on $ext_if from $localnet to any -> ($ext_if) # Deal with the FTP. rdr commands must come before filtering nat-anchor "ftp-proxy/*" rdr-anchor "ftp-proxy/*" rdr pass proto tcp from any to any port ftp -> 192.168.1.1 port 8021 # Redirect this traffic to our internal servers rdr proto tcp from any to $me port 53 -> 192.168.1.5 port 53 rdr proto tcp from any to $me port 25 -> 192.168.1.6 port 25 rdr proto tcp from any to $me port 465 -> 192.168.1.6 port 465 rdr proto tcp from any to $me port 993 -> 192.168.1.6 port 993 # Redirect port 8080 to the internal webserver, so I can access it from my mobile phone rdr proto tcp from <permit_networks> to $me port 8080 -> $webserver port 80 # Redirect dummies to the dummy server rdr pass proto tcp from <dummies> to $me -> $dummy # Default values. Do NOT change these! pass in all pass out all antispoof for $ext_if antispoof for $int_if pass quick on lo0 all # First rule - allow all traffic from this server pass from { lo0, $me, $me_in } to any keep state # # # INCOMING TRAFFIC # # # block in log all # Pass redirected DNS queries to our internal dns server pass quick proto { tcp, udp } from any to $dns port 53 flags S/SA synproxy state # Pass redirected mail traffic to our internal mail-server pass quick proto tcp from any to $mail port { 25, 465, 993 } flags S/SA keep state # Give myself access to the web server from my mobile phone pass quick proto tcp from <permit_networks> to $webserver port 80 flags S/SA keep state # Allow ssh to this machine from table <permit_networks>, but be careful. If someone # tries to connect more than five times in 60 seconds, or with more than 3 concurrent # connections from the same IP, they must be attempting to crack this ssh account. # Put them in the <dummies> table, and redirect their traffic to the dummy server ;-) pass quick proto tcp from <permit_networks> to $me port ssh flags S/SA keep state (max-src-conn 3, max-src-conn-rate 5/60, overload <dummies> flush global) # Allow LAN users to go out without restriction pass inet proto { tcp, udp } from $lan to any flags S/SA keep state # Enable all on local network pass inet proto { tcp, udp } from $lan to $me_in keep state pass inet proto { tcp, udp } from $localnet to $localnet keep state # enabling ping may be necessary, at least initially # We can easily prevent it later, if need be pass in inet proto icmp all icmp-type $icmp_types keep state pass out inet proto icmp all icmp-type $icmp_types keep state # # # End of firewall configuration # # #

That's it. You can now start your firewall with:

# /etc/rc.d/pf start # /etc/rc.d/pflog start

Try to ping 8.8.178.110 (www.freebsd.org) from some LAN IP address, and see if it's working.

Now we'll need to install a DHCP server, so your network can assign IP addresses to all those hosts.

via the FreeBSD ports system

# cd /usr/ports/net/isc-dhcp43-server # make install clean

or, via the FreeBSD pkg system

# package install isc-dhcp43-server

When finished, open the file /usr/local/etc/dhcpd.conf, and edit as required

# dhcpd.conf # # Sample configuration file for ISC dhcpd # # option definitions common to all supported networks... option domain-name "yourdomain.com"; option domain-name-servers dns1.yourdomain.com, dns2.yourdomain.com; default-lease-time 43200; max-lease-time 50000; # 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; # Configuration for your local network. Leave first 10 addresses for your LAN servers subnet 192.168.1.0 netmask 255.255.255.0 { range 192.168.1.10 192.168.1.254; option domain-name-servers 192.168.1.5; option domain-name "yourdomain.com"; option routers 192.168.1.1; option broadcast-address 192.168.1.255; default-lease-time 43200; max-lease-time 50000; } # If you want that your PC have a fixed IP address, find it's MAC address with # the ifconfig command host mypc { hardware ethernet 00:26:18:b0:73:81; server-name "bsd-router.yourdomain.com"; fixed-address 192.168.1.2; } # that cute girl from customer service department host hot-chick { hardware ethernet 00:26:18:b0:73:82; server-name "bsd-router.yourdomain.com"; fixed-address 192.168.1.9; }

Then add this to /etc/rc.conf

dhcpd_enable="YES"

Start the DHCP server

# /usr/local/etc/rc.d/isc-dhcpd start

So that's pretty much it. You can see what users are in your dummies table with this command:

# pfctl -t dummies -T show

If you don't want to redirect <dummies> users, and want to block them, you can simply add this line:

# Redirect dummies to dummy server rdr pass proto tcp from <dummies> to $me -> $dummy

and add this before block in log all

block quick from <dummies>

In another article we'll show you how to configure VPN with FreeBSD. VPN is a popular choice by many.

Things to think about:
Do not leave port 25 open to the outside. Many viruses attack windows machines to send SPAM. If your firewall IP address sends a large quantity of SPAM, your IP address will be put in one of the many blacklists. If you have a mailserver inside, allow port 25 to outside only from this machine. (And yours, if you are using Gnus, Mutt or some other geek MUA with sendmail/qmail/postfix as a transport agent)

It is better that you put your servers in a DMZ, and separate them from the local LAN. That way the network is far more secured.

WARNING!
If you are using jails, don't assign another IP address on the external interface. The outside interface should have only one IP address. If you do that, your NAT will FAIL.

Additional FreeBSD related Articles, and man pages.

See also:
BSD forge
Damn Small BSD
Man Pages