FreeBSD Firewall Configuration
FreeBSD Firewall Configuration
FreeBSD makes it very easy to set up a rule-based packet filtering firewall. You can
protect just one host, or an entire network. You can easily add Network Address
Translation too, so that you can connect up your whole internal network via only one IP
address from the outside.
There are three parts to this.
1. First, you have to make a few changes to your kernel. This isn't as hard as it
sounds. Su to root, cd /usr/src/sys/i386/conf, and copy GENERIC to a new file.
Let's call it ACME. This will be your new kernel config. Here are the changes
you need to make:
2. *** GENERIC
Sun Apr 27 20:41:46 2003
3. --- ACME
Sun May 9 12:47:24 2004
4. ***************
5. *** 22,29 ****
6.
cpu
I486_CPU
7.
cpu
I586_CPU
8.
cpu
I686_CPU
9. ! ident
GENERIC
10.
maxusers
0
11.
12.
#makeoptions DEBUG=-g
#Build kernel with
gdb(1) debug symbols
13.
14. --- 22,40 ---15.
cpu
I486_CPU
16.
cpu
I586_CPU
17.
cpu
I686_CPU
18. ! ident
ACME
19.
maxusers
0
20. +
21. + # Enable ipfw.
22. + options
IPFIREWALL
23. + options
IPFIREWALL_VERBOSE
24. +
25. + # Enable ip6fw too.
26. + options
IPV6FIREWALL
27. + options
IPV6FIREWALL_VERBOSE
28. +
29. + # Enable NAT.
30. + options
IPDIVERT
31.
32.
#makeoptions DEBUG=-g
#Build kernel with
gdb(1) debug symbols
33.
In other words, change the ident and add the firewall options. Adding the
IPV6FIREWALL options to the kernel doesn't actually enable IPv6; to do that,
you have to add ipv6_enable="YES" to your /etc/rc.conf. However, if you have
IPv6 enabled and you are setting up an IPv4 firewall, you must enable the IPv6
firewall as well. If you were to set up a v4 firewall and not a v6 firewall, all v6
packets would be allowed through, which would be bad.
After setting up the config, build and install the new kernel:
#
#
#
#
#
/usr/sbin/config ACME
cd ../../compile/ACME
make depend
make
make install
34. Second, edit /etc/rc.conf and add these defines to the end:
35. # Enable ipfw.
36. firewall_enable="YES"
37. firewall_type="type"
goes here
38. firewall_quiet="NO"
39.
40. # Enable ip6fw.
41. ipv6_firewall_enable="YES"
42. ipv6_firewall_type="type"
goes here
43. ipv6_firewall_quiet="NO"
44. Third, you have to make a few edits in rc.firewall and rc.firewall6. The
comments there explain what is needed, it's real easy. Look for the section with
rules for your firewall type, either "client" or "simple". At the beginning of the
section there will be a few defines for your IP numbers, network interfaces, etc.;
fill these in.
That's it, for a starter setup anyway. Reboot and you should be up and running.
Important Troubleshooting Note
FreeBSD's firewall facility is designed so that it's secure by default. If you enable it and
then don't add any rules, it drops ALL packets. This means if you mess something up in
your firewall setup, you may find that you can't get to your machine through the
network to fix it. You will have to log in via the system console.
This happened to me once during debugging. It's no big deal as long as you understand
what's going on. It's easy to recover from if you have access to the console; just edit
/etc/rc.conf, change firewall_type to "open" or just comment out the firewall lines, and
boot again. But do be careful if you're tweaking your firewall setup over the net.
FTP Note
Firewall setups like this prevent regular FTP from working. This is really FTP's fault.
It's an old-fashioned and over-complicated protocol, which requires the server to initiate
a callback connection to the client. Since firewalls prevent new connections from the
outside (except for a few protocols such as email), FTP fails.
There is a workaround - use FTP's "passive" mode, which basically tells it to stick to a
regular client-server protocol. Every time you run ftp, just give the "passive" command.
With recent versions of FTP clients, you can make this the default by setting the
environment variable FTP_PASSIVE_MODE to "yes".
The other workaround, of course, is to avoid FTP and just use HTTP or scp instead.
More Advanced Topics
Once you have a firewall set up, you may find you don't like the canned rule sets. If so,
it's easy to make your own. The first thing you might do is allow ssh connections
through. (ssh is a secure replacement for telnet/rlogin; you can fetch it from
http://www.openssh.org/.) Where your ruleset says "Allow setup of incoming email",
add a similar rule for ssh by changing the port number 25 to a 22.
Or, you can go whole hog and make an entirely new ruleset. I ended up making two new
ones, called acme-solo and acme-net, which are souped-up versions of the default client
and simple rulesets. Here's the code:
[Aa][Cc][Mm][Ee]-[Ss][Oo][Ll][Oo])
############
# ACME single-machine custom firewall setup.
somewhat
# against the outside world.
############
Protects
imaps,
tcp
tcp
tcp
tcp
tcp
tcp
from
from
from
from
from
from
any
any
any
any
any
any
to
to
to
to
to
to
${ip}
${ip}
${ip}
${ip}
${ip}
${ip}
21 setup
22 setup
25 setup
53 setup
80 setup
443 setup
${fwcmd}
${fwcmd}
${fwcmd}
${fwcmd}
add
add
add
add
allow
allow
allow
allow
tcp
tcp
tcp
tcp
from
from
from
from
any
any
any
any
to
to
to
to
${ip}
${ip}
${ip}
${ip}
143
993
110
995
setup
setup
setup
setup
protocol
# without logging.
${fwcmd} add reset
${fwcmd} add reset
${fwcmd} add reset
${fwcmd} add reset
tcp
tcp
tcp
tcp
from
from
from
from
any
any
any
any
to
to
to
to
${ip}
${ip}
${ip}
${ip}
113
139
389
445
setup
setup
setup
setup
This is somewhat of a
quench,
[Aa][Cc][Mm][Ee]-[Nn][Ee][Tt])
############
# ACME network custom firewall setup. The assumption here is
that
# the internal hosts are trusted, and can do almost anything
they want.
# The only thing we have to be careful about is what comes in
over
# the outside interface. So, you'll see a lot of "in via $
{oif}"
# clauses here.
############
ip.
oif="fxp0"
onet="216.27.1234.0"
omask="255.255.255.0"
oip="216.27.1234.1"
# Set these to your inside interface network and netmask and
ip.
iif="fxp1"
inet="192.100.666.0"
imask="255.255.255.0"
iip="192.100.666.1"
setup_loopback
{oif}
# Stop spoofing.
${fwcmd} add deny all from ${inet}:${imask} to any in via $
${fwcmd} add deny all from ${onet}:${omask} to any in via $
{iif}
outside interface.
any to 10.0.0.0/8 via ${oif}
any to 172.16.0.0/12 via ${oif}
any to 192.168.0.0/16 via ${oif}
slow.
# ftp
# ssh
${fwcmd} add allow tcp from ${oip} 21 to any out via ${oif}
${fwcmd} add allow tcp from any to ${oip} 22 in via ${oif}
${fwcmd} add allow tcp from ${oip} 22 to any out via ${oif}
${fwcmd} add allow tcp from any to ${oip} 25 in via ${oif}
# smtp
${fwcmd} add allow tcp from ${oip} 25 to any out via ${oif}
${fwcmd} add allow tcp from any to ${oip} 53 in via ${oif}
# tcpdns
${fwcmd} add allow tcp from ${oip} 53 to any out via ${oif}
${fwcmd} add allow tcp from any to ${oip} 80 in via ${oif}
# http
# https
${fwcmd} add allow tcp from ${oip} 80 to any out via ${oif}
${fwcmd} add allow tcp from any to ${oip} 443 in via ${oif}
${fwcmd} add allow tcp from ${oip} 443 to any out via ${oif}
${fwcmd} add allow tcp from any to ${oip} 143 in via ${oif}
# imap
${fwcmd} add allow tcp from ${oip} 143 to any out via ${oif}
${fwcmd} add allow tcp from any to ${oip} 993 in via ${oif}
# imaps
# pop3
${fwcmd} add allow tcp from ${oip} 993 to any out via ${oif}
${fwcmd} add allow tcp from any to ${oip} 110 in via ${oif}
${fwcmd} add allow tcp from ${oip} 110 to any out via ${oif}
${fwcmd} add allow tcp from any to ${oip} 995 in via ${oif}
# pop3s
${fwcmd} add allow tcp from ${oip} 995 to any out via ${oif}
outside interface.
10.0.0.0/8 to any via ${oif}
172.16.0.0/12 to any via ${oif}
192.168.0.0/16 to any via ${oif}
separate
# without logging.
${fwcmd} add reset tcp from any to ${oip} 113 setup in via $
${fwcmd} add reset tcp from any to ${oip} 139 setup in via $
${fwcmd} add reset tcp from any to ${oip} 389 setup in via $
${fwcmd} add reset tcp from any to ${oip} 445 setup in via $
# Deny some chatty UDP broadcast protocols without logging.
${fwcmd} add deny udp from any 137 to any in via ${oif}
${fwcmd} add deny udp from any to any 137 in via ${oif}
${fwcmd} add deny udp from any 138 to any in via ${oif}
${fwcmd} add deny udp from any 513 to any in via ${oif}
${fwcmd} add deny udp from any 525 to any in via ${oif}
hole,
be
This is somewhat of a