IPFW is a stateful firewall written for FreeBSD which also provides a traffic shaper, packet scheduler, and in-kernel NAT.
FreeBSD provides a sample ruleset in
/etc/rc.firewall
. The sample ruleset
define several firewall types for common scenarios to assist
novice users in generating an appropriate ruleset.
ipfw(8) provides a powerful syntax which advanced users can
use to craft customized rulesets that meet the security
requirements of a given environment.
IPFW is composed of several components: the kernel firewall
filter rule processor and its integrated packet accounting
facility, the logging facility, the
divert
rule which triggers
NAT, the dummynet traffic shaper facilities,
the fwd rule
forward facility, the bridge
facility, and the ipstealth facility. IPFW supports both IPv4
and IPv6.
IPFW is included in the basic FreeBSD install as a run time
loadable module. The system will dynamically load the kernel
module when rc.conf
contains the
statement firewall_enable="YES"
. After
rebooting the system, the following white highlighted message
is displayed on the screen as part of the boot process:
The loadable module includes logging ability. To enable
logging and set the verbose logging limit, add these
statements to
/etc/sysctl.conf
before rebooting:
For those users who wish to statically compile kernel IPFW support, the following options are available for the custom kernel configuration file:
This option enables IPFW as part of the kernel.
This option enables logging of packets that pass through
IPFW and have the log
keyword specified in
the ruleset.
This option limits the number of packets logged through syslogd(8), on a per-entry basis. This option may be used in hostile environments, when firewall activity logging is desired. This will close a possible denial of service attack via syslog flooding.
This option allows everything to pass through the firewall by default, which is a good idea when the firewall is being set up for the first time.
This option enables the use of NAT functionality.
The firewall will block all incoming and outgoing
packets if either the
IPFIREWALL_DEFAULT_TO_ACCEPT
kernel
option or a rule to explicitly allow these connections is
missing.
Enables the firewall:
To select one of the default firewall types provided by
FreeBSD, select one by reading
/etc/rc.firewall
and specify it in
the following:
Available values for this setting are:
open
: passes all traffic.
client
: protects only this
machine.
simple
: protects the whole
network.
closed
: entirely disables IP
traffic except for the loopback interface.
UNKNOWN
: disables the loading of
firewall rules.
:
absolute path of the file containing the firewall
rules.filename
Two methods are available for loading custom
ipfw rules. One is to set the
firewall_type
variable to the absolute
path of the file which contains the firewall rules.
The other method is to set the
firewall_script
variable to the absolute
path of an executable script that includes
ipfw
commands. A ruleset script that
blocks all incoming and outgoing traffic would look like
this:
If firewall_type
is set to either
client
or simple
,
modify the default rules found in
/etc/rc.firewall
to fit the
configuration of the system. The examples used in this
section assume that the firewall_script
is set to /etc/ipfw.rules
.
Enable logging:
firewall_logging
sets the
net.inet.ip.fw.verbose
sysctl
variable to the value of 1
. There is no
rc.conf
variable to set log
limitations, but the desired value can be set using
sysctl
or by adding the following
variable and desired value to
/etc/sysctl.conf
:
If the machine is acting as a gateway providing
NAT using natd(8),
refer to Section 31.9, “Network Address Translation” for information
regarding the required /etc/rc.conf
options.
ipfw
can be used to make manual,
single rule additions or deletions to the active firewall
while it is running. The problem with using this method is
that all the changes are lost when the system reboots. It is
recommended to instead write all the rules in a file and to
use that file to load the rules at boot time and to replace
the currently running firewall rules whenever that file
changes.
ipfw
is a useful way to display the
running firewall rules to the console screen. The IPFW
accounting facility dynamically creates a counter for each
rule that counts each packet that matches the rule. During
the process of testing a rule, listing the rule with its
counter is one way to determine if the rule is
functioning as expected.
To list all the running rules in sequence:
#
ipfw list
To list all the running rules with a time stamp of when the last time the rule was matched:
#
ipfw -t list
The next example lists accounting information and the packet count for matched rules along with the rules themselves. The first column is the rule number, followed by the number of matched packets and bytes, followed by the rule itself.
#
ipfw -a list
To list dynamic rules in addition to static rules:
#
ipfw -d list
To also show the expired dynamic rules:
#
ipfw -d -e list
To zero the counters:
#
ipfw zero
To zero the counters for just the rule with number
NUM
:
#
ipfw zero NUM
When a packet enters the IPFW firewall,
it is compared against the first rule in the ruleset and
progresses one rule at a time, moving from top to bottom of
the set in ascending rule number sequence order. When the
packet matches the selection parameters of a rule, the rule's
action field value is executed and the search of the ruleset
terminates for that packet. This is referred to as
“first match wins”. If the packet does not match
any of the rules, it gets caught by the mandatory IPFW default
rule, number 65535, which denies all packets and silently
discards them. However, if the packet matches a rule that
contains the count
,
skipto
, or tee
keywords,
the search continues. Refer to ipfw(8) for details on
how these keywords affect rule processing.
The examples in this section create an inclusive type
firewall ruleset containing the stateful keep
state
, limit
,
in
, out
and
via
options. For a complete rule syntax
description, refer to ipfw(8).
Be careful when working with firewall rules, as it is easy to lock out even the administrator.
This section describes the keywords which comprise an
IPFW rule. Keywords must be written in
the following order. #
is used to mark
the start of a comment and may appear at the end of a rule
line or on its own line. Blank lines are ignored.
CMD RULE_NUMBER ACTION LOGGING SELECTION
STATEFUL
A rule can be associated with one of the following actions. The specified action will be executed when the packet matches the selection criterion of the rule.
allow | accept | pass |
permit
These keywords are equivalent as they allow packets that match the rule to exit the firewall rule processing. The search terminates at this rule.
check-state
Checks the packet against the dynamic rules table.
If a match is found, execute the action associated with
the rule which generated this dynamic rule, otherwise
move to the next rule. A check-state
rule does not have selection criterion. If no
check-state
rule is present in the
ruleset, the dynamic rules table is checked at the first
keep-state
or limit
rule.
deny | drop
Both words mean the same thing, which is to discard packets that match this rule. The search terminates.
When a packet matches a rule with the
log
keyword, a message will be logged
to syslogd(8) with a facility name of
SECURITY
. Logging only occurs if the
number of packets logged for that particular rule does not
exceed the logamount
parameter. If no
logamount
is specified, the limit is
taken from the sysctl
value of
net.inet.ip.fw.verbose_limit
. In both
cases, a value of zero removes the logging limit. Once
the limit is reached, logging can be re-enabled by
clearing the logging counter or the packet counter for
that rule, using ipfw reset log
.
Logging is done after all other packet matching conditions have been met, and before performing the final action on the packet. The administrator decides which rules to enable logging on.
The keywords described in this section are used to describe attributes of the packet to be checked when determining whether rules match the packet or not. The following general-purpose attributes are provided for matching, and must be used in this order:
udp | tcp | icmp
Any other protocol names found in
/etc/protocols
can be used. The
value specified is the protocol to be matched against.
This is a mandatory keyword.
from src to dst
The from
and to
keywords are used to match against IP addresses. Rules
must specify both source and
destination parameters. any
is a
special keyword that matches any IP address.
me
is a special keyword that matches
any IP address configured on an interface in the FreeBSD
system to represent the PC the firewall is running on.
Example usage includes from me to any
,
from any to me
, from 0.0.0.0/0
to any
, from any to
0.0.0.0/0
, from 0.0.0.0 to
any
. from any to 0.0.0.0
,
and from me to 0.0.0.0
. IP addresses
are specified in dotted IP address format followed by the
mask in CIDR notation, or as a single host in dotted IP
address format. This keyword is a mandatory requirement.
The net-mgmt/ipcalc
port may be used to assist the mask calculation.
port number
For protocols which support port numbers, such as
TCP and UDP, it
is mandatory to include the port number of the service
that will be matched. Service names from
/etc/services
may be used instead
of numeric port values.
in | out
Matches incoming or outgoing packets. It is mandatory that one or the other is included as part of the rule matching criterion.
via IF
Matches packets going through the interface specified
by device name. The via
keyword causes
the interface to always be checked as part of the match
process.
setup
This mandatory keyword identifies the session start request for TCP packets.
keep-state
This is a mandatory keyword. Upon a match, the firewall will create a dynamic rule, whose default behavior is to match bidirectional traffic between source and destination IP/port using the same protocol.
limit {src-addr | src-port | dst-addr |
dst-port}
The firewall will only allow
N
connections with the same
set of parameters as specified in the rule. One or more
of source and destination addresses and ports can be
specified. limit
and
keep-state
can not be used on the same
rule as they provide the same stateful function.
The check-state
option is used to
identify where in the IPFW ruleset the packet is to be
tested against the dynamic rules facility. On a match, the
packet exits the firewall to continue on its way and a new
rule is dynamically created for the next anticipated packet
being exchanged during this session. On a no match, the
packet advances to the next rule in the ruleset for
testing.
The dynamic rules facility is vulnerable to resource
depletion from a SYN-flood attack which would open a huge
number of dynamic rules. To counter this type of attack
with IPFW, use limit
.
This keyword limits the number of simultaneous sessions by
checking that rule's source or destinations fields and using
the packet's IP address in a search of the open dynamic
rules, counting the number of times this rule and IP address
combination occurred. If this count is greater than the
value specified by limit
, the packet is
discarded.
Even with the logging facility enabled, IPFW will not
generate any rule logging on its own. The firewall
administrator decides which rules in the ruleset will be
logged, and adds the log
keyword to those
rules. Normally only deny rules are logged. It is
customary to duplicate the “ipfw default deny
everything” rule with the log
keyword included as the last rule in the ruleset. This
way, it is possible to see all the packets that did not
match any of the rules in the ruleset.
Logging is a two edged sword. If one is not careful, an over abundance of log data or a DoS attack can fill the disk with log files. Log messages are not only written to syslogd, but also are displayed on the root console screen and soon become annoying.
The IPFIREWALL_VERBOSE_LIMIT=5
kernel option limits the number of consecutive messages
sent to syslogd(8), concerning the packet matching of a
given rule. When this option is enabled in the kernel, the
number of consecutive messages concerning a particular rule
is capped at the number specified. There is nothing to be
gained from 200 identical log messages. With this option
set to five,
five consecutive messages concerning a particular rule
would be logged to syslogd and
the remainder identical consecutive messages would be
counted and posted to syslogd
with a phrase like the following:
All logged packets messages are written by default to
/var/log/security
, which is
defined in /etc/syslog.conf
.
Most experienced IPFW users create a file containing the rules and code them in a manner compatible with running them as a script. The major benefit of doing this is the firewall rules can be refreshed in mass without the need of rebooting the system to activate them. This method is convenient in testing new rules as the procedure can be executed as many times as needed. Being a script, symbolic substitution can be used for frequently used values to be substituted into multiple rules.
This example script is compatible with the syntax used by the sh(1), csh(1), and tcsh(1) shells. Symbolic substitution fields are prefixed with a dollar sign ($). Symbolic fields do not have the $ prefix. The value to populate the symbolic field must be enclosed in double quotes ("").
Start the rules file like this:
The rules are not important as the focus of this example is how the symbolic substitution fields are populated.
If the above example was in
/etc/ipfw.rules
, the rules could be
reloaded by the following command:
#
sh /etc/ipfw.rules
/etc/ipfw.rules
can be located
anywhere and the file can have any name.
The same thing could be accomplished by running these commands by hand:
#
ipfw -q -f flush
#
ipfw -q add check-state
#
ipfw -q add deny all from any to any frag
#
ipfw -q add deny tcp from any to any established
#
ipfw -q add allow tcp from any to any 80 out via tun0 setup keep-state
#
ipfw -q add allow tcp from any to 192.0.2.11 53 out via tun0 setup keep-state
#
ipfw -q add 00611 allow udp from any to 192.0.2.11 53 out via tun0 keep-state
The following sample ruleset is a complete inclusive
type ruleset. Comment out any
pass
rules for services that are not
required. To avoid logging undesired messages, add a
deny
rule in the inbound section.
Change the dc0
in every rule to the
device name of the interface that connects the system to the
Internet.
There is a noticeable pattern in the usage of these rules.
All statements that are a request to start a session
to the Internet use
keep-state
.
All the authorized services that originate from
the Internet use limit
to prevent
flooding.
All rules use in
or
out
to clarify direction.
All rules use via
interface-name
to specify
the interface the packet is traveling over.
The following rules go into
/etc/ipfw.rules
:
There are some additional configuration statements that
need to be enabled to activate the NAT
function of IPFW. For a customized kernel, the kernel
configuration file needs
option IPDIVERT
added to the other
IPFIREWALL
options.
In addition to the normal IPFW options in
/etc/rc.conf
, the following are
needed:
Utilizing stateful rules with a
divert natd
rule complicates the ruleset
logic. The positioning of the
check-state
, and
divert natd
rules in the ruleset is
critical and a new action type is used, called
skipto
. When using
skipto
, it is mandatory that each rule is
numbered, so that the skipto
rule knows
which rule to jump to.
The following is an uncommented example of a ruleset which explains the sequence of the packet flow.
The processing flow starts with the first rule from the
top of the ruleset and progresses one rule at a time until
the end is reached or the packet matches and the packet is
released out of the firewall. Take note of the location of
rule numbers 100 101, 450, 500, and 510. These rules
control the translation of the outbound and inbound packets
so that their entries in the dynamic keep-state table always
register the private LAN IP address. All the allow and deny
rules specify the direction of the packet and the interface.
All start outbound session requests will
skipto rule 500
to undergo NAT.
Consider a web browser which initializes a new HTTP
session over port 80. When the first outbound packet enters
the firewall, it does not match rule 100 because it is
headed out rather than in. It passes rule 101 because this
is the first packet, and it has not been posted to the
dynamic keep-state table yet. The packet finally matches
rule 125 as it is outbound through the NIC facing the
Internet and has a source IP address as a private LAN IP
address. On matching this rule, two actions take place.
keep-state
adds this rule to the dynamic
keep-state rules table and the specified action is executed
and posted as part of the info in the dynamic table. In
this case, the action is skipto rule 500
.
Rule 500 NATs the packet IP address and
sends it out to the Internet. This packet makes its way to
the destination web server, where a response packet is
generated and sent back. This new packet enters the top of
the ruleset. It matches rule 100 and has it destination IP
address mapped back to the corresponding LAN IP address. It
then is processed by the check-state
rule, is found in the table as an existing session, and is
released to the LAN. It goes to the LAN system that sent it
and a new packet is sent requesting another segment of the
data from the remote server. This time it matches the
check-state
rule, its outbound entry is
found, and the associated action,
skipto 500
, is executed. The packet
jumps to rule 500, gets NATed, and is
released to the Internet.
On the inbound side, everything coming in that is part
of an existing session is automatically handled by the
check-state
rule and the properly placed
divert natd
rules. The ruleset only has
to deny bad packets and allow only authorized services.
Consider a web server running on the firewall where web
requests from the Internet should have access to the local
web site. An inbound start request packet will match rule
100 and its IP address will be mapped to the LAN IP address
of the firewall. The packet is then matched against all the
nasty things that need to be checked and finally matches
rule 425 where two actions occur. The packet rule is posted
to the dynamic keep-state table but this time, any new
session requests originating from that source IP address are
limited to 2. This defends against DoS attacks against the
service running on the specified port number. The action is
allow
, so the packet is released to the
LAN. The packet generated as a response is recognized by the
check-state
as belonging to an existing
session. It is then sent to rule 500 for
NATing and released to the outbound
interface.
Example Ruleset #1:
The next example is functionally equivalent, but uses descriptive comments to help the inexperienced IPFW rule writer to better understand what the rules are doing.
Example Ruleset #2:
All FreeBSD documents are available for download at http://ftp.FreeBSD.org/pub/FreeBSD/doc/
Questions that are not answered by the
documentation may be
sent to <freebsd-questions@FreeBSD.org>.
Send questions about this document to <freebsd-doc@FreeBSD.org>.