Vous êtes sur la page 1sur 11

FreeBSD Network Tutorial/How-To Guide Page 1

A Network Tutorial/How-To Guide


for the FreeBSD OS
by Nick Rogness

FreeBSD Firewall
Nick Rogness nick@rogness.net

Introduction

This section deals with building a firewall. What is a firewall? A firewall (in this context) is a set of
rules that allows or denies certain types of network traffic (packets) from entering or leaving your
FreeBSD machine.

Firewall Concepts

There are several different types of firewalls you can run. Hardware firewalls, sometimes called
Firewall appliances, implement firewalling using hardware. Most of these 'hardware' firewalls are
proprietary and usually run an embedded OS like FreeBSD or Linux. Hardware firewalls usually cost
money and provide a nice graphical configuration tool to deploy your firewall. Some example
hardware firewalls you may have heard of are 'Cisco Systems PIX', 'SonicWall', Linkysys, and many
others.

Software firewalls, on the other hand, are usually a set of tools that run on a specific OS. They
interface with the OS's kernel packet processing system. Many different types of software firewalls
exist, some commercial and some free. Some free software firewall packages include IPFilter,
IPChains, IPTables, and IPFW. Several commercial software firewalls exist the most popular being
CheckPoint's Firewall-1. We will be focusing on FreeBSD's ipfw firewall package. One thing about
free software based firewalls is that they are usually difficult to setup and manage. FreeBSD provides
a nice interface to create, delete and manage your firewall. However, it takes a certain amount of
knowledge about IP packets and routing to understand completely. I recommend you first
understand these basics before you start reading. I will be expecting you understand some of these
basics.

FreeBSD Firewalling notes

As I mentioned earlier, we will be exploring the FreeBSD ipfw software firewall. This 'tool' is
included in the base system of FreeBSD so you will not need to download any 3rd party software.
You should be familiar with interfaces on FreeBSD. If you are not please read the Interfaces
Section. Interfaces are key to firewalling on any OS as they are the conduits for packets coming and
going on your machine. Also, you may have to build a kernel on your FreeBSD machine to turn on

http://freebsd.rogness.net/redirect.cgi?basic/firewall.html 06/23/2004 11:21:24 PM


FreeBSD Network Tutorial/How-To Guide Page 2
firewalling in the kernel. This is done with the 'options IPFIREWALL' line in the kernel config file.
See the Kernel section for more details on building a custom kernel. Another quick note: everything
in this "how-to" can be retrieved from the ipfw(8) manpage.

Quick note
If you want to be real efficient in management of your firewall(s), you should understand one very
important thing that most people miss: Packets flow symmetrically to and from your machine. A
common mistake made by begginers is over looking this fact. You must always look at packets like
with this in mind, i.e. you need to firewall both ways: in AND out. Keep this in mind when you are
reading this article.

Basic Firewall

We will start with a simple setup. One machine connected directly to the internet. We will progress
to a more advanced setup in the next section: Building a Gateway/Router. But for now, let's focus
on the basics: one machine and one interface.

First, lets conceptually look at how packets flow to/from your machine to/from the internet (or
network):
Image
Notice how packets flow both ways: in and out of your machine. This will be crucial in upcoming
paragraphs.

Next, lets enable firewalling on boot up. In order to do this we edit /etc/rc.conf and add:

firewall_enable="YES"
firewall_type="OPEN"

This does 2 things. First off the 'firewall_enable="YES" tells BSD to enable the firewall on bootup.
The firewall_type="OPEN" tells BSD to use a stock OPEN firewall configuration. There are several
different stock preconfiged setups you can choose from to go between the "" marks in te
firewall_type line within /etc/rc.conf:

open - will allow anyone in


client - will try to protect just this machine
simple - will try to protect a whole network
closed - totally disables IP services except via lo0 interface
UNKNOWN - disables the loading of firewall rules.
filename - will load the rules in the given filename (full path required)

These /etc/rc.conf options get processed by /etc/rc.firewall upon startup. For now lets focus on 2
different stock configurations we can play with: OPEN and filename. An OPEN firewall just allows
all traffic to and from your machine. By default, if you forget to add this firewall_type="OPEN" to /
etc/rc.conf all traffic will STOP! That is by IPFIREWALL has a default rule to deny traffic from any
to any. Don't do this remotely or you'll have to get to the console and reset it to get back in!! You
can change this behavior by adding an 'options DEFAULT_TO_ACCEPT' to the kernel config file
and rebuilding your kernel. The OPEN statement tells /etc/rc.firewall to add a pass rule to your

http://freebsd.rogness.net/redirect.cgi?basic/firewall.html 06/23/2004 11:21:24 PM


FreeBSD Network Tutorial/How-To Guide Page 3
firewall on bootup. The 'filename' is exactly that, a filename that contains a set of custom built
firewall rules.

Firewall Rules

Firewall rules are just a list of sequentially searched 'rules' that EVERY packet gets compared to
when it leaves/enters an interface. Notice I didn't say machine, I said interface. What I mean by that
is every packet enters an interface and leaves an interface. Each time it passes across an interface,
the kernel compares these packets to these rules to determine whether it should be allowed or
blocked. The matching is done by comparing the packet header information to the rule criteria to
determine if it matches. If a match is encountered then the system looks at the 'action' for the rule to
determine if it should be passed or blocked. IP header information that the firewall can match against
are: source IP, destination IP, source PORT, destination PORT, protocol type, and protocol specific
flags. It is important to remember that the firewall can not inspect any further into a packet than the
header. Therefore, it can not determine payload contents, i.e. it's not a content firewall/proxy.

Let's now look at the syntax of these rules. For example let's say we have a machine with interface
setup:

# ifconfig -a
xl0: flags=8843 mtu 1500
options=3
inet 205.238.129.221 netmask 0xfffffffc broadcast 205.238.129.223
inet6 fe80::250:daff:fe77:cc77%xl0 prefixlen 64 scopeid 0x1
ether 00:50:da:77:cc:77
media: Ethernet autoselect (100baseTX )
status: active

A small ruleset may look something like:

# ipfw l
00100 allow ip from any to any via lo0
00200 deny ip from any to 127.0.0.0/8
00300 deny ip from 127.0.0.0/8 to any
65000 allow ip from any to any
65535 deny ip from any to any

Fairly intimidating. So lets step back for a moment at just adding one of these rules first. Then we'll
worry about the ruleset as a whole. Let's say we want to add a rule to allow all traffic to and from
this machine. We might add something like this:

# ipfw add 50 allow ip from any to any via xl0

WOW! What the hell is this? Let's examine it piece by piece. First the 'ipfw' command is the
command line interface tool to add and remove firewall rules from the system. Everything else is an
argument to ipfw. I used the 'l' argument to ipfw above to list the current ruleset. This is a failry
common way to inspect running rulesets.

http://freebsd.rogness.net/redirect.cgi?basic/firewall.html 06/23/2004 11:21:24 PM


FreeBSD Network Tutorial/How-To Guide Page 4
Next the 'add' argument to ipfw tells the system that this entry is to be added to the ruleset.

The number 50 is used as kind of a line number. I said earlier that these rules are sequentially
searched for matching packets. This number 50 just means it is rule number 50. Rule numbers have a
range from 1-65534. Rule number 65535 is always the default deny rule (Unless changed as
mentioned above). Rule numbers don't have to be concurrent added, i.e. you can add rule 100 then
add rule 200. The important thing to rememeber about rule numbers is that they are processed in
ascending order (1 to 65535).

The next argument is 'allow'. This is the action to be taken if a packet matches on this rule. Different
types of actions can be taken if a packet matches this rule. We will only be covering 'allow' and
'deny' in this section. The 'allow' action means that the kernel will let the packet go. The 'deny' action
means the kernel will throw the packet away.

When I said "if a packet matches" I meant exactly that. See, the kernel takes the packet and
compares it to the rest of the line: 'ip from any to any via xl0'. This is the match criteria. If the kernel
decides it matches the criteria then it performs 'action' (allow or deny) for the rule. If the kernel
doesn't match on this rule, it proceeds to compare the packet to the next rule in the firewall ruleset.
Eventually, if the firewall doesn't find a match for any rule number, it will get to the default 65536
rule, which will deny the packet (throw it away). If a match does occur, the action is taken and no
more rules are compared to the current packet, i.e. rule processing stops at that rule number.

The match criteria means exactly what it sounds like. You can think of the match criteria kind of like
an if-else programming statement. Therefore, you can analyze 'ip from any to any via xl0' like so:

// Analyzing: 'ip'
// Meaning: Is protocol type in packet header equal to ip?
if (protocol == ip) {

// Yes, protocol is IP

// Analyzing: 'from any'


// Meaning: Does source IP in packet header (from) equal any?
if (from == any) {

//Yes, source IP equals any

//Analyzing: 'to any'


//Meaning: Does destination IP in packet header (to) equal
if (to == any) {

//Yes, desintation IP equals any

//Analyzing: 'via xl0'


//Meaning: Did the packet leave or enter through
if (via eq xl0) {

//Yes, packet left or entered through the

//We have a match!!! now perform action

http://freebsd.rogness.net/redirect.cgi?basic/firewall.html 06/23/2004 11:21:24 PM


FreeBSD Network Tutorial/How-To Guide Page 5
// In this case action is 'allow' so that
// let it pass through the interface

} else {

// Packet didn't enter or leave through the


// So skip this rule and move to next rule
}

} else {
// No, destination IP doesn't equal 'any'
// So skip this rule and move to next rule number
}

} else {

//No, source IP doesn't equal 'any'


// So skip this rule and move to next rule number.
}

} else {

//No, protocol doesn't equal ip


// So skip this and rule move to next rule number.
}

Yes, matching criteria can get quite complicated with many different combinations to match on.
Although confusing, this complexity gives us extreme amounts of power and flexibility in building
rules.

Now that you have added a rule lets look at it in the firewall within the kernel using the ipfw
command line utility with the 'l' argument (meaning list):

# ipfw l
00050 allow ip from any to any via xl0

I mentioned earlier that you should be aware that packets traverse your interfaces in both directions.
So our single add rule: 'ipfw add 50 allow ip from any to any via xl0' could be added by 2 different
ipfw add statements. Let's take a look:

# ipfw add 50 allow ip from any to any in via xl0


# ipfw add 60 allow ip from any to any out via xl0
# ipfw l
00050 allow ip from any to any in recv xl0
00060 allow ip from any to any out xmit xl0

Notice how I changed the 'via' to 'in via' and 'out via'. The 'in via xl0' means 'Is this packet coming in
through the xl0 interface'. The 'out via xl0' means 'Is this packet leaving out the xl0 interface?'. Also
take note that the rule numbers are 50 and 60. That means EVERY packet coming or leaving first
gets compared to rule number 50, then rule number 60.

http://freebsd.rogness.net/redirect.cgi?basic/firewall.html 06/23/2004 11:21:24 PM


FreeBSD Network Tutorial/How-To Guide Page 6
You can even get more specific if you want. Since I know what my IP address is (205.238.129.221),
I can add that to the ruleset to get even more specific:

# ipfw add 50 allow ip from any to 205.238.129.221 in via xl0


# ipfw add 60 allow ip from 205.238.129.221 to any out via xl0
# ipfw l
00050 allow ip from any to 205.238.129.221 in recv xl0
00060 allow ip from 205.238.129.221 to any out xmit xl0

SO how do you delete a rule once it's added. That's simple. You delete it by rule number like so:

# ipfw delete 50

You just deleted rule number 50!

Rules Processing

Now that you are an expert at rule syntax (hehe) let's look at the firewall ruleset as a whole as we did
earlier. Using a sample ruleset:

# ipfw l

00100 allow ip from any to any via lo0


00200 deny ip from any to 127.0.0.0/8
00300 deny ip from 127.0.0.0/8 to any
65000 allow ip from any to any
65535 deny ip from any to any

The idea here is to reinforce the rule processing of how packets are inspected and leave/enter the
machine. This is a key concept of understanding firewalls in general. Lets take you through a quick
example with this ruleset above. Suppose my machine (205.238.129.221) receives a telnet packet
from the internet, i.e. Someone (1.2.3.4) is trying to telnet to my machine from the internet. So a
sample packet would have attributes that look similar to:

Source_IP Source_PORT Destination_IP Destination_PORT


1.2.3.4 3333 205.238.129.221 23

Steps involved in processing this packet:


1) Kernel receives packet on interface xl0
2) Kernel compares packet to this rule (100):

=====> 00100 allow ip from any to any via lo0


00200 deny ip from any to 127.0.0.0/8
00300 deny ip from 127.0.0.0/8 to any
65000 allow ip from any to any
65535 deny ip from any to any

3) Kernel doesn't match, so proceeds to compare to next rule (200):

http://freebsd.rogness.net/redirect.cgi?basic/firewall.html 06/23/2004 11:21:24 PM


FreeBSD Network Tutorial/How-To Guide Page 7

00100 allow ip from any to any via lo0


======> 00200 deny ip from any to 127.0.0.0/8
00300 deny ip from 127.0.0.0/8 to any
65000 allow ip from any to any
65535 deny ip from any to any

4) Kernel doesn't match, so proceeds to compare to next rule (300):

00100 allow ip from any to any via lo0


00200 deny ip from any to 127.0.0.0/8
======> 00300 deny ip from 127.0.0.0/8 to any
65000 allow ip from any to any
65535 deny ip from any to any

5) Kernel doesn't match, so proceeds to compare to next rule (65000):

00100 allow ip from any to any via lo0


00200 deny ip from any to 127.0.0.0/8
00300 deny ip from 127.0.0.0/8 to any
======> 65000 allow ip from any to any
65535 deny ip from any to any

6) Kernel FOUND A MATCH! Action is taken which is 'allow' so


7) Packet gets handed to the telnet daemon (listening on port 23 tcp) for processing
8) The telnet daemon now responds back to the sender.

This is what I mentioned earlier about packets being symmetrical. Most people forget that the
response packet gets sent back to the sender. Its attributes look similar to this:

Source_IP Source_PORT Destination_IP Destination


205.238.129.221 23 1.2.3.4 3333

So now we repeat the process for the outgoing packet: 1) Kernel compares packet to this rule (100):

=====> 00100 allow ip from any to any via lo0


00200 deny ip from any to 127.0.0.0/8
00300 deny ip from 127.0.0.0/8 to any
65000 allow ip from any to any
65535 deny ip from any to any

2) Kernel doesn't match, so proceeds to compare to next rule (200):

00100 allow ip from any to any via lo0


======> 00200 deny ip from any to 127.0.0.0/8
00300 deny ip from 127.0.0.0/8 to any
65000 allow ip from any to any
65535 deny ip from any to any

3) Kernel doesn't match, so proceeds to compare to next rule (300):

http://freebsd.rogness.net/redirect.cgi?basic/firewall.html 06/23/2004 11:21:24 PM


FreeBSD Network Tutorial/How-To Guide Page 8

00100 allow ip from any to any via lo0


00200 deny ip from any to 127.0.0.0/8
======> 00300 deny ip from 127.0.0.0/8 to any
65000 allow ip from any to any
65535 deny ip from any to any

5) Kernel doesn't match, so proceeds to compare to next rule (65000):

00100 allow ip from any to any via lo0


00200 deny ip from any to 127.0.0.0/8
00300 deny ip from 127.0.0.0/8 to any
======> 65000 allow ip from any to any
65535 deny ip from any to any

6) Kernel MATCHES! So packet gets transmitted out interface xl0

Notice in the above steps that if we wouldn't have matched on rule number 65000, then we would
have hit the default rule of 65536 which would 'deny' or drop the packet!

There are several different ways to write rules as mentioned above. We could have matched on that
telnet example above by using several different rules. The first 7 steps which was when the kernel
was processing a packet that was inbound would have matched by any of these rules (which i'll show
you how to add):

# ipfw add 55 allow ip from any to any via xl0


OR
# ipfw add 55 allow ip from any to 205.238.129.221 via xl0
OR
# ipfw add 55 allow ip from 1.2.3.4 to any via xl0
OR
# ipfw add 55 allow ip from any to any in via xl0
OR
# ipfw add 55 allow ip from any to 205.238.129.221 in via xl0
OR
# ipfw add 55 allow ip from 1.2.3.4 to any in via xl0
OR
# ipfw add 55 allow ip from 1.2.3.4 to 205.238.129.221 in via xl0
OR
# ipfw add 55 allow ip from 1.2.3.4 to 205.238.129.221 in via xl0
OR
# ipfw add 55 allow tcp from any to 205.238.129.221 23
OR
# ipfw add 55 allow tcp from any to any 23 via xl0
OR
# ipfw add 55 allow tcp from any to any 23 in via xl0
OR
# ipfw add 55 allow tcp from any to 205.238.129.221 23 in via xl0
OR
# ipfw add 55 allow tcp from 1.2.3.4 to 205.238.129.221 23 in via xl0
OR
# ipfw add 55 allow tcp from 1.2.3.4 3333 to 205.238.129.221 23 in via xl

http://freebsd.rogness.net/redirect.cgi?basic/firewall.html 06/23/2004 11:21:24 PM


FreeBSD Network Tutorial/How-To Guide Page 9
As you can see, there are a lot of different combinations which would've matched JUST THE
INBOUND PACKET! Same goes for the outbound (response) packet, except for the the from and
to order would be swapped and in replaced with out:

# ipfw add 65 allow ip from any to any via xl0


OR
# ipfw add 65 allow ip from 205.238.129.221 to any via xl0
OR
# ipfw add 65 allow ip from any to 1.2.3.4 via xl0
OR
# ipfw add 65 allow ip from any to any out via xl0
OR
# ipfw add 65 allow ip from 205.238.129.221 to any out via xl0
OR
# ipfw add 65 allow ip from any to 1.2.3.4 out via xl0
OR
# ipfw add 65 allow ip from 205.238.129.221 to 1.2.3.4 out via xl0
OR
# ipfw add 65 allow ip from 205.238.129.221 to 1.2.3.4 out via xl0
OR
# ipfw add 65 allow tcp from 205.238.129.221 23 to any
OR
# ipfw add 65 allow tcp from any 23 to any via xl0
OR
# ipfw add 65 allow tcp from any 23 to any out via xl0
OR
# ipfw add 65 allow tcp from 205.238.129.221 23 to any out via xl0
OR
# ipfw add 65 allow tcp from 205.238.129.221 23 to 1.2.3.4 out via xl0
OR
# ipfw add 65 allow tcp from 205.238.129.221 23 to 1.2.3.4 3333 out via xl

There are quite a few combinations I didn't get to either. Not to menton several things which I'm not
covering in this section, which would add even more combinations. So, that poses a good question:
Which rule should I use? The answer is not an easy one. Different people like different techniques. I
can advise one general rule of thumb. The more specific a rule is the more secure you will be (or at
least feel). That is, the rule:

# ipfw add 65 allow tcp from 205.238.129.221 23 to 1.2.3.4 out via xl0

Is better (more tightly secured) than a more general rule such as:

# ipfw add 65 allow ip from any to any via xl0

This isn't always the case but when you get to refining your ruleset being more specific about rules
can help you better monitor your machine/network. In a later section, Fun with Firewalling, I will be
covering fine tuning your rulesets and such refinements will be covered.

Firewall Options

http://freebsd.rogness.net/redirect.cgi?basic/firewall.html 06/23/2004 11:21:24 PM


FreeBSD Network Tutorial/How-To Guide Page 10
Now that you can build firewalls via the command line, let's add them so they come up when the
system boots. As mentioned above, firewall rules are loaded by a special startup script called /etc/
rc.firewall. Many people add their rules to this file manually. I believe this is a terrible idea. This is a
system file and shold not be modified directly. It causes problems with mergemaster and makes
upgrading other things difficult. The approach I recommend is to create your own file and put your
rules in it to be loaded at boot time.

So create a file, e.g. /etc/firewall.local, and add your rules to it line by line:

# Allow bob.rogness.net to talk to me and me to talk to bob.rogness.net


add 100 allow ip from bob.rogness.net to any in via xl0
add 105 allow ip from any to bob.rogness.net out via xl0

# Allow this machine to make DNS queries


add 5000 allow udp from me to any 53 out via xl0
add 5005 allow udp from any 50 to me in via xl0

# Allow anyone to ssh to me and allow me to respond


add 10000 allow tcp from any to 205.238.129.221 22 via xl0
add 15673 allow tcp from 205.238.129.221 22 to any via xl0

# Allow and log everything else to look for


add 20000 allow log ip from any to any

Save the file. You can now add it to the /etc/rc.conf file and when you reboot it will automagically
load your firewall:

firewall_type="/etc/firewall.local"

You can also invoke it from the command like manually if you are too impatient for a reboot by:

# ipfw /etc/firewall.local

The above firewall ruleset also showed a few more details I left out earlier. One being the use of
hostnames (bob.rogness.net) as source or destination address (rule 100). When added like this ipfw
will look up the name 'bob.rogness.net' and replace 'bob.rogness.net' by the IP it resolves to. Beware
that this is not dynamic, if bob.rogness.net changes IPs, ipfw will not automagically change it for
you!

Another trick I used was the keywork 'me' (rule 5000). This referes to any IP referenced on your
machine. This is a great trick for use in DHCP or when your machines interface IPs change
frequently. This 'me' keywork is dynamic, i.e. your IP can change and the rule will still match.

The last trick I used was the keyword 'log' (rule 20000). This tells the firewall to log the packet (in
abbreviated form) to syslog. You must enable this in the kernel before usage with 'options
IPFIREWALL_VERBOSE' and rebuild your kernel. The reason I showed you this is because it is

http://freebsd.rogness.net/redirect.cgi?basic/firewall.html 06/23/2004 11:21:24 PM


FreeBSD Network Tutorial/How-To Guide Page 11
crutial to troubleshooting. If you are having problems because packets are being denied or allowed
or not being matched, etc. Turn on the 'log' option on your questionable rule(s). This will dump the
packet header matches to syslog for your inspection. It is very convient without having to use a
packet sniffer. Just remember the log keywork will save your butt!

Well, that's it! Firewalling can be very complex. The only way to get good at such an unbearable act
is practice. Checkout the next firewalling section Fun with Firewalling to go over some more
advanced things you can do with ipfw. Any questions, just email me. Oh and, you the ipfw man
page. It is a very indepth and helpful tool when you hit a roadblock.

http://freebsd.rogness.net/redirect.cgi?basic/firewall.html 06/23/2004 11:21:24 PM

Vous aimerez peut-être aussi