29.6. IPFW

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.

29.6.1. Enabling IPFW

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:

ipfw2 initialized, divert disabled, rule-based forwarding disabled, default to deny, logging disabled

The loadable module includes logging ability. To enable logging and set the verbose logging limit, add these statements to /etc/sysctl.conf before rebooting:

net.inet.ip.fw.verbose=1
net.inet.ip.fw.verbose_limit=5

29.6.2. Kernel Options

For those users who wish to statically compile kernel IPFW support, the following options are available for the custom kernel configuration file:

options    IPFIREWALL

This option enables IPFW as part of the kernel.

options    IPFIREWALL_VERBOSE

This option enables logging of packets that pass through IPFW and have the log keyword specified in the ruleset.

options    IPFIREWALL_VERBOSE_LIMIT=5

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.

options    IPFIREWALL_DEFAULT_TO_ACCEPT

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.

options    IPDIVERT

This option enables the use of NAT functionality.

Note:

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.

29.6.3. /etc/rc.conf Options

Enables the firewall:

firewall_enable="YES"

To select one of the default firewall types provided by FreeBSD, select one by reading /etc/rc.firewall and specify it in the following:

firewall_type="open"

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.

  • filename: absolute path of the file containing the firewall rules.

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:

#!/bin/sh

ipfw -q flush

ipfw add deny in
ipfw add deny out

Note:

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="YES"

Warning:

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:

net.inet.ip.fw.verbose_limit=5

If the machine is acting as a gateway providing NAT using natd(8), refer to Section 30.9, “Network Address Translation” for information regarding the required /etc/rc.conf options.

29.6.4. The IPFW Command

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

29.6.5. IPFW Rulesets

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).

Warning:

Be careful when working with firewall rules, as it is easy to lock out even the administrator.

29.6.5.1. Rule Syntax

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

29.6.5.1.1. CMD

Each new rule has to be prefixed with add to add the rule to the internal table.

29.6.5.1.2. RULE_NUMBER

Each rule is associated with a rule_number in the range of 1 to 65535.

29.6.5.1.3. ACTION

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.

29.6.5.1.4. Logging

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.

Note:

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.

29.6.5.1.5. Selection

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.

29.6.5.2. Stateful Rule Option

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.

29.6.5.3. Logging Firewall Messages

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:

last message repeated 45 times

All logged packets messages are written by default to /var/log/security, which is defined in /etc/syslog.conf.

29.6.5.4. Building a Rule Script

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:

############### start of example ipfw rules script #############
#
ipfw -q -f flush       # Delete all rules
# Set defaults
oif="tun0"             # out interface
odns="192.0.2.11"      # ISP's DNS server IP address
cmd="ipfw -q add "     # build rule prefix
ks="keep-state"        # just too lazy to key this each time
$cmd 00500 check-state
$cmd 00502 deny all from any to any frag
$cmd 00501 deny tcp from any to any established
$cmd 00600 allow tcp from any to any 80 out via $oif setup $ks
$cmd 00610 allow tcp from any to $odns 53 out via $oif setup $ks
$cmd 00611 allow udp from any to $odns 53 out via $oif $ks
################### End of example ipfw rules script ############

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

29.6.5.5. An Example Stateful Ruleset

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:

################ Start of IPFW rules file ###############################
# Flush out the list before we begin.
ipfw -q -f flush

# Set rules command prefix
cmd="ipfw -q add"
pif="dc0"     # public interface name of NIC
              # facing the public Internet

#################################################################
# No restrictions on Inside LAN Interface for private network
# Not needed unless you have LAN.
# Change xl0 to your LAN NIC interface name
#################################################################
#$cmd 00005 allow all from any to any via xl0

#################################################################
# No restrictions on Loopback Interface
#################################################################
$cmd 00010 allow all from any to any via lo0

#################################################################
# Allow the packet through if it has previous been added to the
# the "dynamic" rules table by a allow keep-state statement.
#################################################################
$cmd 00015 check-state

#################################################################
# Interface facing Public Internet (Outbound Section)
# Interrogate session start requests originating from behind the
# firewall on the private network or from this gateway server
# destined for the public Internet.
#################################################################

# Allow out access to my ISP's Domain name server.
# x.x.x.x must be the IP address of your ISP.s DNS
# Dup these lines if your ISP has more than one DNS server
# Get the IP addresses from /etc/resolv.conf file
$cmd 00110 allow tcp from any to x.x.x.x 53 out via $pif setup keep-state
$cmd 00111 allow udp from any to x.x.x.x 53 out via $pif keep-state

# Allow out access to my ISP's DHCP server for cable/DSL configurations.
# This rule is not needed for .user ppp. connection to the public Internet.
# so you can delete this whole group.
# Use the following rule and check log for IP address.
# Then put IP address in commented out rule & delete first rule
$cmd 00120 allow log udp from any to any 67 out via $pif keep-state
#$cmd 00120 allow udp from any to x.x.x.x 67 out via $pif keep-state

# Allow out non-secure standard www function
$cmd 00200 allow tcp from any to any 80 out via $pif setup keep-state

# Allow out secure www function https over TLS SSL
$cmd 00220 allow tcp from any to any 443 out via $pif setup keep-state

# Allow out send & get email function
$cmd 00230 allow tcp from any to any 25 out via $pif setup keep-state
$cmd 00231 allow tcp from any to any 110 out via $pif setup keep-state

# Allow out FBSD (make install & CVSUP) functions
# Basically give user root "GOD" privileges.
$cmd 00240 allow tcp from me to any out via $pif setup keep-state uid root

# Allow out ping
$cmd 00250 allow icmp from any to any out via $pif keep-state

# Allow out Time
$cmd 00260 allow tcp from any to any 37 out via $pif setup keep-state

# Allow out nntp news (i.e., news groups)
$cmd 00270 allow tcp from any to any 119 out via $pif setup keep-state

# Allow out secure FTP, Telnet, and SCP
# This function is using SSH (secure shell)
$cmd 00280 allow tcp from any to any 22 out via $pif setup keep-state

# Allow out whois
$cmd 00290 allow tcp from any to any 43 out via $pif setup keep-state

# deny and log everything else that.s trying to get out.
# This rule enforces the block all by default logic.
$cmd 00299 deny log all from any to any out via $pif

#################################################################
# Interface facing Public Internet (Inbound Section)
# Check packets originating from the public Internet
# destined for this gateway server or the private network.
#################################################################

# Deny all inbound traffic from non-routable reserved address spaces
$cmd 00300 deny all from 192.168.0.0/16 to any in via $pif  #RFC 1918 private IP
$cmd 00301 deny all from 172.16.0.0/12 to any in via $pif     #RFC 1918 private IP
$cmd 00302 deny all from 10.0.0.0/8 to any in via $pif          #RFC 1918 private IP
$cmd 00303 deny all from 127.0.0.0/8 to any in via $pif        #loopback
$cmd 00304 deny all from 0.0.0.0/8 to any in via $pif            #loopback
$cmd 00305 deny all from 169.254.0.0/16 to any in via $pif   #DHCP auto-config
$cmd 00306 deny all from 192.0.2.0/24 to any in via $pif       #reserved for docs
$cmd 00307 deny all from 204.152.64.0/23 to any in via $pif  #Sun cluster interconnect
$cmd 00308 deny all from 224.0.0.0/3 to any in via $pif         #Class D & E multicast

# Deny public pings
$cmd 00310 deny icmp from any to any in via $pif

# Deny ident
$cmd 00315 deny tcp from any to any 113 in via $pif

# Deny all Netbios service. 137=name, 138=datagram, 139=session
# Netbios is MS/Windows sharing services.
# Block MS/Windows hosts2 name server requests 81
$cmd 00320 deny tcp from any to any 137 in via $pif
$cmd 00321 deny tcp from any to any 138 in via $pif
$cmd 00322 deny tcp from any to any 139 in via $pif
$cmd 00323 deny tcp from any to any 81 in via $pif

# Deny any late arriving packets
$cmd 00330 deny all from any to any frag in via $pif

# Deny ACK packets that did not match the dynamic rule table
$cmd 00332 deny tcp from any to any established in via $pif

# Allow traffic in from ISP's DHCP server. This rule must contain
# the IP address of your ISP.s DHCP server as it.s the only
# authorized source to send this packet type.
# Only necessary for cable or DSL configurations.
# This rule is not needed for .user ppp. type connection to
# the public Internet. This is the same IP address you captured
# and used in the outbound section.
#$cmd 00360 allow udp from any to x.x.x.x 67 in via $pif keep-state

# Allow in standard www function because I have apache server
$cmd 00400 allow tcp from any to me 80 in via $pif setup limit src-addr 2

# Allow in secure FTP, Telnet, and SCP from public Internet
$cmd 00410 allow tcp from any to me 22 in via $pif setup limit src-addr 2

# Allow in non-secure Telnet session from public Internet
# labeled non-secure because ID & PW are passed over public
# Internet as clear text.
# Delete this sample group if you do not have telnet server enabled.
$cmd 00420 allow tcp from any to me 23 in via $pif setup limit src-addr 2

# Reject & Log all incoming connections from the outside
$cmd 00499 deny log all from any to any in via $pif

# Everything else is denied by default
# deny and log all packets that fell through to see what they are
$cmd 00999 deny log all from any to any
################ End of IPFW rules file ###############################

29.6.5.6. An Example NAT and Stateful Ruleset

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:

natd_enable="YES"                   # Enable NATD function
natd_interface="rl0"                # interface name of public Internet NIC
natd_flags="-dynamic -m"            # -m = preserve port numbers if possible

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:

#!/bin/sh
cmd="ipfw -q add"
skip="skipto 500"
pif=rl0
ks="keep-state"
good_tcpo="22,25,37,43,53,80,443,110,119"

ipfw -q -f flush

$cmd 002 allow all from any to any via xl0  # exclude LAN traffic
$cmd 003 allow all from any to any via lo0  # exclude loopback traffic

$cmd 100 divert natd ip from any to any in via $pif
$cmd 101 check-state

# Authorized outbound packets
$cmd 120 $skip udp from any to xx.168.240.2 53 out via $pif $ks
$cmd 121 $skip udp from any to xx.168.240.5 53 out via $pif $ks
$cmd 125 $skip tcp from any to any $good_tcpo out via $pif setup $ks
$cmd 130 $skip icmp from any to any out via $pif $ks
$cmd 135 $skip udp from any to any 123 out via $pif $ks


# Deny all inbound traffic from non-routable reserved address spaces
$cmd 300 deny all from 192.168.0.0/16  to any in via $pif  #RFC 1918 private IP
$cmd 301 deny all from 172.16.0.0/12   to any in via $pif  #RFC 1918 private IP
$cmd 302 deny all from 10.0.0.0/8      to any in via $pif  #RFC 1918 private IP
$cmd 303 deny all from 127.0.0.0/8     to any in via $pif  #loopback
$cmd 304 deny all from 0.0.0.0/8       to any in via $pif  #loopback
$cmd 305 deny all from 169.254.0.0/16  to any in via $pif  #DHCP auto-config
$cmd 306 deny all from 192.0.2.0/24    to any in via $pif  #reserved for docs
$cmd 307 deny all from 204.152.64.0/23 to any in via $pif  #Sun cluster
$cmd 308 deny all from 224.0.0.0/3     to any in via $pif  #Class D & E multicast

# Authorized inbound packets
$cmd 400 allow udp from xx.70.207.54 to any 68 in $ks
$cmd 420 allow tcp from any to me 80 in via $pif setup limit src-addr 1


$cmd 450 deny log ip from any to any

# This is skipto location for outbound stateful rules
$cmd 500 divert natd ip from any to any out via $pif
$cmd 510 allow ip from any to any

######################## end of rules  ##################

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:

#!/bin/sh
################ Start of IPFW rules file ###############################
# Flush out the list before we begin.
ipfw -q -f flush

# Set rules command prefix
cmd="ipfw -q add"
skip="skipto 800"
pif="rl0"     # public interface name of NIC
              # facing the public Internet

#################################################################
# No restrictions on Inside LAN Interface for private network
# Change xl0 to your LAN NIC interface name
#################################################################
$cmd 005 allow all from any to any via xl0

#################################################################
# No restrictions on Loopback Interface
#################################################################
$cmd 010 allow all from any to any via lo0

#################################################################
# check if packet is inbound and nat address if it is
#################################################################
$cmd 014 divert natd ip from any to any in via $pif

#################################################################
# Allow the packet through if it has previous been added to the
# the "dynamic" rules table by a allow keep-state statement.
#################################################################
$cmd 015 check-state

#################################################################
# Interface facing Public Internet (Outbound Section)
# Check session start requests originating from behind the
# firewall on the private network or from this gateway server
# destined for the public Internet.
#################################################################

# Allow out access to my ISP's Domain name server.
# x.x.x.x must be the IP address of your ISP's DNS
# Dup these lines if your ISP has more than one DNS server
# Get the IP addresses from /etc/resolv.conf file
$cmd 020 $skip tcp from any to x.x.x.x 53 out via $pif setup keep-state


# Allow out access to my ISP's DHCP server for cable/DSL configurations.
$cmd 030 $skip udp from any to x.x.x.x 67 out via $pif keep-state

# Allow out non-secure standard www function
$cmd 040 $skip tcp from any to any 80 out via $pif setup keep-state

# Allow out secure www function https over TLS SSL
$cmd 050 $skip tcp from any to any 443 out via $pif setup keep-state

# Allow out send & get email function
$cmd 060 $skip tcp from any to any 25 out via $pif setup keep-state
$cmd 061 $skip tcp from any to any 110 out via $pif setup keep-state

# Allow out FreeBSD (make install & CVSUP) functions
# Basically give user root "GOD" privileges.
$cmd 070 $skip tcp from me to any out via $pif setup keep-state uid root

# Allow out ping
$cmd 080 $skip icmp from any to any out via $pif keep-state

# Allow out Time
$cmd 090 $skip tcp from any to any 37 out via $pif setup keep-state

# Allow out nntp news (i.e., news groups)
$cmd 100 $skip tcp from any to any 119 out via $pif setup keep-state

# Allow out secure FTP, Telnet, and SCP
# This function is using SSH (secure shell)
$cmd 110 $skip tcp from any to any 22 out via $pif setup keep-state

# Allow out whois
$cmd 120 $skip tcp from any to any 43 out via $pif setup keep-state

# Allow ntp time server
$cmd 130 $skip udp from any to any 123 out via $pif keep-state

#################################################################
# Interface facing Public Internet (Inbound Section)
# Check packets originating from the public Internet
# destined for this gateway server or the private network.
#################################################################

# Deny all inbound traffic from non-routable reserved address spaces
$cmd 300 deny all from 192.168.0.0/16  to any in via $pif  #RFC 1918 private IP
$cmd 301 deny all from 172.16.0.0/12   to any in via $pif  #RFC 1918 private IP
$cmd 302 deny all from 10.0.0.0/8      to any in via $pif  #RFC 1918 private IP
$cmd 303 deny all from 127.0.0.0/8     to any in via $pif  #loopback
$cmd 304 deny all from 0.0.0.0/8       to any in via $pif  #loopback
$cmd 305 deny all from 169.254.0.0/16  to any in via $pif  #DHCP auto-config
$cmd 306 deny all from 192.0.2.0/24    to any in via $pif  #reserved for docs
$cmd 307 deny all from 204.152.64.0/23 to any in via $pif  #Sun cluster
$cmd 308 deny all from 224.0.0.0/3     to any in via $pif  #Class D & E multicast

# Deny ident
$cmd 315 deny tcp from any to any 113 in via $pif

# Deny all Netbios service. 137=name, 138=datagram, 139=session
# Netbios is MS/Windows sharing services.
# Block MS/Windows hosts2 name server requests 81
$cmd 320 deny tcp from any to any 137 in via $pif
$cmd 321 deny tcp from any to any 138 in via $pif
$cmd 322 deny tcp from any to any 139 in via $pif
$cmd 323 deny tcp from any to any 81  in via $pif

# Deny any late arriving packets
$cmd 330 deny all from any to any frag in via $pif

# Deny ACK packets that did not match the dynamic rule table
$cmd 332 deny tcp from any to any established in via $pif

# Allow traffic in from ISP's DHCP server. This rule must contain
# the IP address of your ISP's DHCP server as it is the only
# authorized source to send this packet type.
# Only necessary for cable or DSL configurations.
# This rule is not needed for 'user ppp' type connection to
# the public Internet. This is the same IP address you captured
# and used in the outbound section.
$cmd 360 allow udp from x.x.x.x to any 68 in via $pif keep-state

# Allow in standard www function because I have Apache server
$cmd 370 allow tcp from any to me 80 in via $pif setup limit src-addr 2

# Allow in secure FTP, Telnet, and SCP from public Internet
$cmd 380 allow tcp from any to me 22 in via $pif setup limit src-addr 2

# Allow in non-secure Telnet session from public Internet
# labeled non-secure because ID & PW are passed over public
# Internet as clear text.
# Delete this sample group if you do not have telnet server enabled.
$cmd 390 allow tcp from any to me 23 in via $pif setup limit src-addr 2

# Reject & Log all unauthorized incoming connections from the public Internet
$cmd 400 deny log all from any to any in via $pif

# Reject & Log all unauthorized out going connections to the public Internet
$cmd 450 deny log all from any to any out via $pif

# This is skipto location for outbound stateful rules
$cmd 800 divert natd ip from any to any out via $pif
$cmd 801 allow ip from any to any

# Everything else is denied by default
# deny and log all packets that fell through to see what they are
$cmd 999 deny log all from any to any
################ End of IPFW rules file ###############################

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>.