Firewalls are an area of increasing interest for people who are
connected to the Internet, and are even finding applications on private
networks to provide enhanced security. This section will hopefully
explain what firewalls are, how to use them, and how to use the
facilities provided in the FreeBSD kernel to implement them.

Note: People often think that having a firewall between your
internal network and the "Big Bad Internet" will solve all
your security problems. It may help, but a poorly setup firewall
system is more of a security risk than not having one at all. A
firewall can add another layer of security to your systems, but it
cannot stop a really determined cracker from penetrating your internal
network. If you let internal security lapse because you believe your
firewall to be impenetrable, you have just made the crackers job that
much easier.

There are currently two distinct types of firewalls in common use
on the Internet today. The first type is more properly called a
packet filtering router, where the kernel on a
multi-homed machine chooses whether to forward or block packets based
on a set of rules. The second type, known as a proxy
server, relies on daemons to provide authentication and to
forward packets, possibly on a multi-homed machine which has kernel
packet forwarding disabled.

Sometimes sites combine the two types of firewalls, so that only a
certain machine (known as a bastion host) is
allowed to send packets through a packet filtering router onto an
internal network. Proxy services are run on the bastion host, which
are generally more secure than normal authentication
mechanisms.

FreeBSD comes with a kernel packet filter (known as
IPFW), which is what the rest of this
section will concentrate on. Proxy servers can be built on FreeBSD
from third party software, but there is such a variety of proxy
servers available that it would be impossible to cover them in this
document.

A router is a machine which forwards packets between two or more
networks. A packet filtering router has an extra piece of code in
its kernel which compares each packet to a list of rules before
deciding if it should be forwarded or not. Most modern IP routing
software has packet filtering code within it that defaults to
forwarding all packets. To enable the filters, you need to define a
set of rules for the filtering code so it can decide if the
packet should be allowed to pass or not.

To decide whether a packet should be passed on, the code looks
through its set of rules for a rule which matches the contents of
this packets headers. Once a match is found, the rule action is
obeyed. The rule action could be to drop the packet, to forward the
packet, or even to send an ICMP message back to the originator.
Only the first match counts, as the rules are searched in order.
Hence, the list of rules can be referred to as a "rule
chain".

The packet matching criteria varies depending on the software
used, but typically you can specify rules which depend on the source
IP address of the packet, the destination IP address, the source
port number, the destination port number (for protocols which
support ports), or even the packet type (UDP, TCP, ICMP,
etc).

Proxy servers are machines which have had the normal system
daemons (telnetd, ftpd, etc) replaced with special servers. These
servers are called proxy servers as they
normally only allow onward connections to be made. This enables you
to run (for example) a proxy telnet server on your firewall host,
and people can telnet in to your firewall from the outside, go
through some authentication mechanism, and then gain access to the
internal network (alternatively, proxy servers can be used for
signals coming from the internal network and heading out).

Proxy servers are normally more secure than normal servers, and
often have a wider variety of authentication mechanisms available,
including "one-shot" password systems so that even if
someone manages to discover what password you used, they will not be
able to use it to gain access to your systems as the password
instantly expires. As they do not actually give users access to the
host machine, it becomes a lot more difficult for someone to install
backdoors around your security system.

Proxy servers often have ways of restricting access further, so
that only certain hosts can gain access to the servers, and often
they can be set up so that you can limit which users can talk to
which destination machine. Again, what facilities are available
depends largely on what proxy software you choose.

IPFW, the software supplied with
FreeBSD, is a packet filtering and accounting system which resides in
the kernel, and has a user-land control utility,
ipfw(8). Together, they allow you to define and query the
rules currently used by the kernel in its routing decisions.

There are two related parts to IPFW.
The firewall section allows you to perform packet filtering. There is
also an IP accounting section which allows you to track usage of your
router, based on similar rules to the firewall section. This allows
you to see (for example) how much traffic your router is getting from
a certain machine, or how much WWW (World Wide Web) traffic it is
forwarding.

As a result of the way that IPFW is
designed, you can use IPFW on non-router
machines to perform packet filtering on incoming and outgoing
connections. This is a special case of the more general use of
IPFW, and the same commands and techniques
should be used in this situation.

As the main part of the IPFW system
lives in the kernel, you will need to add one or more options to your
kernel configuration file, depending on what facilities you want, and
recompile your kernel. See reconfiguring
the kernel for more details on how to recompile your
kernel.

There are currently three kernel configuration options relevant to
IPFW:

options IPFIREWALL

Compiles into the kernel the code for packet
filtering.

options IPFIREWALL_VERBOSE

Enables code to allow logging of packets through
syslogd(8). Without this option, even if you specify
that packets should be logged in the filter rules, nothing will
happen.

options IPFIREWALL_VERBOSE_LIMIT=10

Limits the number of packets logged through
syslogd(8) on a per entry basis. You may wish to use
this option in hostile environments in which you want to log
firewall activity, but do not want to be open to a denial of
service attack via syslog flooding.

When a chain entry reaches the packet limit specified,
logging is turned off for that particular entry. To resume
logging, you will need to reset the associated counter using the
ipfw(8) utility:

#ipfw zero 4500

Where 4500 is the chain entry you wish to continue
logging.

Previous versions of FreeBSD contained an
IPFIREWALL_ACCT option. This is now obsolete as
the firewall code automatically includes accounting
facilities.

The configuration of the IPFW software
is done through the ipfw(8) utility. The syntax for this
command looks quite complicated, but it is relatively simple once you
understand its structure.

There are currently four different command categories used by the
utility: addition/deletion, listing, flushing, and clearing.
Addition/deletion is used to build the rules that control how packets
are accepted, rejected, and logged. Listing is used to examine the
contents of your rule set (otherwise known as the chain) and packet
counters (accounting). Flushing is used to remove all entries from
the chain. Clearing is used to zero out one or more accounting
entries.

The command given can be shortened to the
shortest unique form. The valid commands
are:

add

Add an entry to the firewall/accounting rule list

delete

Delete an entry from the firewall/accounting rule
list

Previous versions of IPFW used
separate firewall and accounting entries. The present version
provides packet accounting with each firewall entry.

If an index value is supplied, it used to
place the entry at a specific point in the chain. Otherwise, the
entry is placed at the end of the chain at an index 100 greater than
the last chain entry (this does not include the default policy, rule
65535, deny).

The log option causes matching rules to be
output to the system console if the kernel was compiled with
IPFIREWALL_VERBOSE.

Valid actions are:

reject

Drop the packet, and send an ICMP host or port unreachable
(as appropriate) packet to the source.

allow

Pass the packet on as normal. (aliases:
pass and
accept)

deny

Drop the packet. The source is not notified via an
ICMP message (thus it appears that the packet never
arrived at the destination).

count

Update packet counters but do not allow/deny the packet
based on this rule. The search continues with the next chain
entry.

Each action will be recognized by the
shortest unambiguous prefix.

The protocols which can be specified
are:

all

Matches any IP packet

icmp

Matches ICMP packets

tcp

Matches TCP packets

udp

Matches UDP packets

The address specification is:

from address/mask [port] to address/mask [port] [via interface]

You can only specify port in
conjunction with protocols which support ports
(UDP and TCP).

The via is optional and may specify the IP
address or domain name of a local IP interface, or an interface name
(e.g. ed0) to match only packets coming
through this interface. Interface unit numbers can be specified
with an optional wildcard. For example, ppp*
would match all kernel PPP interfaces.

The syntax used to specify an
address/mask is:

address

or

address/mask-bits

or

address:mask-pattern

A valid hostname may be specified in place of the IP address.
mask-bits is a decimal
number representing how many bits in the address mask should be set.
e.g. specifying 192.216.222.1/24 will create a
mask which will allow any address in a class C subnet (in this case,
192.216.222) to be matched.
mask-pattern is an IP
address which will be logically AND'ed with the address given. The
keyword any may be used to specify "any IP
address".

The port numbers to be blocked are specified as:

port [,port [,port [...]]]

to specify either a single port or a list of ports, or

port-port

to specify a range of ports. You may also combine a single range
with a list, but the range must always be specified first.

The options available are:

frag

Matches if the packet is not the first fragment of the
datagram.

in

Matches if the packet is on the way in.

out

Matches if the packet is on the way out.

ipoptions spec

Matches if the IP header contains the comma separated list
of options specified in spec. The
supported list of IP options are: ssrr
(strict source route), lsrr (loose source
route), rr (record packet route), and
ts (time stamp). The absence of a
particular option may be denoted with a leading
!.

established

Matches if the packet is part of an already established
TCP connection (i.e. it has the RST or ACK bits set). You can
optimize the performance of the firewall by placing
established rules early in the
chain.

setup

Matches if the packet is an attempt to establish a TCP
connection (the SYN bit set is set but the ACK bit is
not).

tcpflags flags

Matches if the TCP header contains the comma separated
list of flags. The supported flags
are fin, syn,
rst, psh,
ack, and urg. The
absence of a particular flag may be indicated by a leading
!.

icmptypes types

Matches if the ICMP type is present in the list
types. The list may be specified
as any combination of ranges and/or individual types separated
by commas. Commonly used ICMP types are: 0
echo reply (ping reply), 3 destination
unreachable, 5 redirect,
8 echo request (ping request), and
11 time exceeded (used to indicate TTL
expiration as with traceroute(8)).

This causes all entries in the firewall chain to be removed
except the fixed default policy enforced by the kernel (index
65535). Use caution when flushing rules, the default deny policy
will leave your system cut off from the network until allow entries
are added to the chain.

Note: The following suggestions are just that: suggestions. The
requirements of each firewall are different and we cannot tell you
how to build a firewall to meet your particular requirements.

When initially setting up your firewall, unless you have a test
bench setup where you can configure your firewall host in a controlled
environment, it is strongly recommend you use the logging version of the
commands and enable logging in the kernel. This will allow you to
quickly identify problem areas and cure them without too much
disruption. Even after the initial setup phase is complete, I
recommend using the logging for `deny' as it allows tracing of
possible attacks and also modification of the firewall rules if your
requirements alter.

Note: If you use the logging versions of the accept
command, it can generate large amounts of log
data as one log line will be generated for every packet that passes
through the firewall, so large ftp/http transfers, etc, will really
slow the system down. It also increases the latencies on those
packets as it requires more work to be done by the kernel before the
packet can be passed on. syslogd with also start using up a lot
more processor time as it logs all the extra data to disk, and it
could quite easily fill the partition /var/log
is located on.

You should enable your firewall from
/etc/rc.conf.local or
/etc/rc.conf. The associated man page explains
which knobs to fiddle and lists some preset firewall configurations.
If you do not use a preset configuration, ipfw list
will output the current ruleset into a file that you can
pass to rc.conf. If you do not use
/etc/rc.conf.local or
/etc/rc.conf to enable your firewall,
it is important to make sure your firewall is enabled before
any IP interfaces are configured.

The next problem is what your firewall should actually
do! This is largely dependent on what access to
your network you want to allow from the outside, and how much access
to the outside world you want to allow from the inside. Some general
rules are:

Block all incoming access to ports below 1024 for TCP. This is
where most of the security sensitive services are, like finger,
SMTP (mail) and telnet.

Block all incoming UDP traffic. There
are very few useful services that travel over UDP, and what useful
traffic there is normally a security threat (e.g. Suns RPC and
NFS protocols). This has its disadvantages also, since UDP is a
connectionless protocol, denying incoming UDP traffic also blocks
the replies to outgoing UDP traffic. This can cause a problem for
people (on the inside) using external archie (prospero) servers.
If you want to allow access to archie, you'll have to allow
packets coming from ports 191 and 1525 to any internal UDP port
through the firewall. ntp is another service you may consider
allowing through, which comes from port 123.

Block traffic to port 6000 from the outside. Port 6000 is the
port used for access to X11 servers, and can be a security threat
(especially if people are in the habit of doing xhost
+ on their workstations). X11 can actually use a
range of ports starting at 6000, the upper limit being how many X
displays you can run on the machine. The upper limit as defined
by RFC 1700 (Assigned Numbers) is 6063.

Check what ports any internal servers use (e.g. SQL servers,
etc). It is probably a good idea to block those as well, as they
normally fall outside the 1-1024 range specified above.

As stated above, these are only guidelines.
You will have to decide what filter rules you want to use on your
firewall yourself. We cannot accept ANY responsibility if someone
breaks into your network, even if you follow the advice given
above.