Introduction
Firewalls make it possible to filter the incoming and outgoing traffic that flows
through a system. A firewall can use one or more sets of “rules” to inspect
network packets as they come in or go out of network connections and either allows the
traffic through or blocks it. The rules of a firewall can inspect one or more
characteristics of the packets such as the protocol type, source or destination host
address, and source or destination port.
Firewalls can enhance the security of a host or a network. They can be used to do one
or more of the following:
-
Protect and insulate the applications, services, and machines of an internal
network from unwanted traffic from the public Internet.
-
Limit or disable access from hosts of the internal network to services of the
public Internet.
-
Support network address translation (NAT), which allows an internal network to use private IP addresses and share a single connection to the
public Internet using either a single IP address or a shared pool of automatically assigned public
addresses.
After reading this chapter, you will know:
-
How to define packet filtering rules.
-
The differences between the firewalls built into FreeBSD.
-
How to use and configure the PF firewall.
-
How to use and configure the IPFILTER firewall.
-
How to use and configure the IPFW firewall.
Before reading this chapter, you should:
-
Understand basic FreeBSD and Internet concepts.
Firewall
Concepts
A firewall ruleset can be either “exclusive” or “inclusive”.
An exclusive firewall allows all traffic through except for the traffic matching the
ruleset. An inclusive firewall does the reverse as it only allows traffic matching the
rules through and blocks everything else.
An inclusive firewall offers better control of the outgoing traffic, making it a
better choice for systems that offer services to the public Internet. It also controls
the type of traffic originating from the public Internet that can gain access to a
private network. All traffic that does not match the rules is blocked and logged.
Inclusive firewalls are generally safer than exclusive firewalls because they
significantly reduce the risk of allowing unwanted traffic.
Note: Unless noted otherwise, all configuration and example rulesets in
this chapter create inclusive firewall rulesets.
Security can be tightened further using a “stateful firewall”. This
type of firewall keeps track of open connections and only allows traffic which either
matches an existing connection or opens a new, allowed connection. The disadvantage of a
stateful firewall is that it can be vulnerable to Denial of Service (DoS) attacks if a lot of new connections are opened very
fast. Most firewalls use a combination of stateful and non-stateful behavior.
Firewall
Packages
FreeBSD has three firewalls built into the base system: IPFILTER, also known as IPF, IPFIREWALL, also known as IPFW, and PF). FreeBSD also
provides two traffic shapers for controlling bandwidth usage: altq(4) and dummynet(4). Dummynet has
traditionally been closely tied with IPFW,
and ALTQ with PF. Each firewall uses rules to control the access of packets to and from a
FreeBSD system, although they go about it in different ways and each has a different rule
syntax.
FreeBSD provides multiple firewalls in order to meet the different requirements and
preferences for a wide variety of users. Each user should evaluate which firewall best
meets their needs.
Since all firewalls are based on inspecting the values of selected packet control
fields, the creator of the firewall ruleset must have an understanding of how
TCP/IP works, what the different values in
the packet control fields are, and how these values are used in a normal session
conversation. For a good introduction, refer to Daryl's TCP/IP Primer
.The IPFILTER (IPF)
Firewall
IPFILTER is a cross-platform, open source firewall which has been ported to FreeBSD,
NetBSD, OpenBSD, SunOS™, HP/UX, and Solaris™ operating systems.
IPFILTER is based on a kernel-side firewall and NAT mechanism that can be controlled and monitored by userland interface
programs. The firewall rules can be set or deleted using ipf(8). The NAT rules can be set or deleted using ipnat(8). Run-time
statistics for the kernel parts of IPFILTER can be printed using ipfstat(8). To log IPFILTER
actions to the system log files, use ipmon(8).
IPF was originally written using a rule processing logic of “the last matching
rule wins” and only used stateless rules. Over time, IPF has been enhanced to
include a “quick” option and a stateful “keep state” option which
modernized the rules processing logic. IPF's official documentation covers only the
legacy rule coding parameters and rule file processing logic and the modernized functions
are only included as additional options.
The instructions contained in this section are based on using rules that contain
“quick” and “keep state” as these provide the basic framework for
configuring an inclusive firewall ruleset.
For a detailed explanation of the legacy rules processing method, refer to http://www.munk.me.uk/ipf/ipf-howto.html and http://coombs.anu.edu.au/~avalon/ip-filter.html.
The IPF FAQ is at http://www.phildev.net/ipf/index.html.
A searchable archive of the IPFilter mailing list is available at http://marc.theaimsgroup.com/?l=ipfilter.
IPF is included in the basic FreeBSD install as a kernel loadable module. The
system will dynamically load this module at boot time when ipfilter_enable="YES"
is added to rc.conf. The module enables logging and default
pass all. To change the default to block all, add a
block all rule at the end of the ruleset.
For users who prefer to statically compile IPF support into a custom kernel, the
following IPF option statements, listed in /usr/src/sys/conf/NOTES, are available:
options IPFILTER
options IPFILTER_LOG
options IPFILTER_DEFAULT_BLOCK
options IPFILTER enables support for the
“IPFILTER” firewall.
options IPFILTER_LOG enables IPF logging using the
ipl packet logging pseudo—device for every rule
that has the log keyword.
options IPFILTER_DEFAULT_BLOCK changes the default
behavior so that any packet not matching a firewall pass
rule gets blocked.
These settings will take effect only after installing a kernel that has been
built with the above options set.
To activate IPF at boot time, the following statements need to be added to
/etc/rc.conf:
ipfilter_enable="YES" # Start ipf firewall
ipfilter_rules="/etc/ipf.rules" # loads rules definition text file
ipmon_enable="YES" # Start IP monitor log
ipmon_flags="-Ds" # D = start as daemon
# s = log to syslog
# v = log tcp window, ack, seq
# n = map IP & port to names
If there is a LAN behind the firewall that uses the reserved private IP address
ranges, the following lines have to be added to enable NAT functionality:
gateway_enable="YES" # Enable as LAN gateway
ipnat_enable="YES" # Start ipnat function
ipnat_rules="/etc/ipnat.rules" # rules definition file for ipnat
To load the ruleset file, use ipf(8). Custom rules
are normally placed in a file, and the following command can be used to replace
the currently running firewall rules:
# ipf -Fa -f /etc/ipf.rules
-Fa
flushes all the internal rules tables.
-f
specifies the file containing the rules to
load.
This provides the ability to make changes to a custom rules file, run the above
IPF command, and thus update the running firewall with a fresh copy of the rules
without having to reboot the system. This method is convenient for testing new
rules as the procedure can be executed as many times as needed.
Refer to ipf(8) for details on the
other flags available with this command.
ipf(8) expects the rules
file to be a standard text file. It will not accept a rules file written as a script
with symbolic substitution.
There is a way to build IPF rules that utilize the power of script symbolic
substitution. For more information, see .
The default behavior of ipfstat(8) is to retrieve
and display the totals of the accumulated statistics gathered by applying the
rules against packets going in and out of the firewall since it was last started, or
since the last time the accumulators were reset to zero using ipf -Z.
Refer to ipfstat(8) for details.
The default ipfstat(8) output will look
something like this:
input packets: blocked 99286 passed 1255609 nomatch 14686 counted 0
output packets: blocked 4200 passed 1284345 nomatch 14687 counted 0
input packets logged: blocked 99286 passed 0
output packets logged: blocked 0 passed 0
packets logged: input 0 output 0
log failures: input 3898 output 0
fragment state(in): kept 0 lost 0
fragment state(out): kept 0 lost 0
packet state(in): kept 169364 lost 0
packet state(out): kept 431395 lost 0
ICMP replies: 0 TCP RSTs sent: 0
Result cache hits(in): 1215208 (out): 1098963
IN Pullups succeeded: 2 failed: 0
OUT Pullups succeeded: 0 failed: 0
Fastroute successes: 0 failures: 0
TCP cksum fails(in): 0 (out): 0
Packet log flags set: (0)
When supplied with either -i
for inbound or
-o
for outbound, the command will retrieve and display
the appropriate list of filter rules currently installed and in use by the
kernel.
ipfstat -in displays the inbound internal rules table
with rule numbers.
ipfstat -on displays the outbound internal rules table
with rule numbers.
The output will look something like this:
@1 pass out on xl0 from any to any
@2 block out on dc0 from any to any
@3 pass out quick on dc0 proto tcp/udp from any to any keep state
ipfstat -ih displays the inbound internal rules table,
prefixing each rule with a count of how many times the rule was matched.
ipfstat -oh displays the outbound internal rules table,
prefixing each rule with a count of how many times the rule was matched.
The output will look something like this:
2451423 pass out on xl0 from any to any
354727 block out on dc0 from any to any
430918 pass out quick on dc0 proto tcp/udp from any to any keep state
One of the most important options of ipfstat is
-t
which displays the state table in a way similar to
how top(1) shows the
FreeBSD running process table. When a firewall is under attack, this function
provides the ability to identify and see the attacking packets. The optional
sub-flags give the ability to select the destination or source IP, port, or
protocol to be monitored in real time. Refer to ipfstat(8) for details.
In order for ipmon to work properly, the kernel option
IPFILTER_LOG must be turned on. This command has two
different modes. Native mode is the default mode when the command is used without
-D
.
Daemon mode provides a continuous system log file so that logging of past events
may be reviewed. FreeBSD has a built in facility to automatically rotate system
logs. This is why outputting the log information to syslogd(8) is better
than the default of outputting to a regular file. The default rc.conf ipmon_flags statement uses
-Ds
:
ipmon_flags="-Ds" # D = start as daemon
# s = log to syslog
# v = log tcp window, ack, seq
# n = map IP & port to names
Logging provides the ability to review, after the fact, information such as which
packets were dropped, what addresses they came from and where they were going. These
can all provide a significant edge in tracking down attackers.
Even with the logging facility enabled, IPF will not generate any rule logging by
default. The firewall administrator decides which rules in the ruleset should be
logged and adds the log keyword to those rules. Normally, only deny rules are
logged.
It is customary to include a “default deny everything” rule with the
log keyword included as the last rule in the ruleset. This makes it possible to see
all the packets that did not match any of the rules in the ruleset.
IPMON Logging
syslogd(8) uses its own
method for segregation of log data. It uses groupings called “facility”
and “level”. By default, IPMON in -Ds
mode uses local0 as the “facility” name. The
following levels can be used to further segregate the logged data:
LOG_INFO - packets logged using the "log" keyword as the action rather than pass or block.
LOG_NOTICE - packets logged which are also passed
LOG_WARNING - packets logged which are also blocked
LOG_ERR - packets which have been logged and which can be considered short
In order to setup IPFILTER to log all data to /var/log/ipfilter.log, first create the empty file:
# touch /var/log/ipfilter.log
syslogd(8) is controlled by
definition statements in /etc/syslog.conf. This file
offers considerable flexibility in how syslog will
deal with system messages issued by software applications like IPF.
To write all logged messages to the specified file, add the following statement
to /etc/syslog.conf:
local0.* /var/log/ipfilter.log
To activate the changes and instruct syslogd(8) to read the
modified /etc/syslog.conf, run service
syslogd reload.
Do not forget to change /etc/newsyslog.conf to rotate
the new log file.
Messages generated by ipmon consist of data fields
separated by white space. Fields common to all messages are:
-
The date of packet receipt.
-
The time of packet receipt. This is in the form HH:MM:SS.F, for hours, minutes,
seconds, and fractions of a second.
-
The name of the interface that processed the packet.
-
The group and rule number of the rule in the format @0:17.
These can be viewed with
ipfstat -in.
-
The action: p for passed, b
for blocked, S for a short packet, n did not match any rules, and L for a log
rule. The order of precedence in showing flags is: S,
p, b, n, L. A capital P
or B means that the packet has been logged due to a global
logging setting, not a particular rule.
-
The addresses written as three fields: the source address and port separated by
a comma, the -> symbol, and the destination address and port. For example:
209.53.17.22,80 -> 198.73.220.17,1722.
-
PR followed by the protocol name or number: for
example, PR tcp.
-
len followed by the header length and total length of
the packet: for example, len 20 40.
If the packet is a
TCP packet, there
will be an additional field starting with a hyphen followed by letters
corresponding to any flags that were set. Refer to
ipf(5) for a list of letters
and their flags.
If the packet is an ICMP packet, there will be two fields at the end: the first
always being “ICMP” and the next being the ICMP message and sub-message
type, separated by a slash. For example: ICMP 3/3 for a port unreachable
message.
Building the Rule Script with Symbolic
Substitution
Some experienced IPF users create a file containing the rules and code them in a
manner compatible with running them as a script with symbolic substitution. The
major benefit of doing this is that only the value associated with the symbolic
name needs to be changed, and when the script is run all the rules containing the
symbolic name will have the value substituted in the rules. Being a script, symbolic
substitution can be used to code frequently used values and substitute them in
multiple rules. This can be seen in the following example.
The script syntax used here is compatible with the
sh(1),
csh(1), and
tcsh(1) shells.
Symbolic substitution fields are prefixed with a
$.
Symbolic fields do not have the $ prefix.
The value to populate the symbolic field must be enclosed between double quotes
(
").
Start the rule file with something like this:
############# Start of IPF rules script ########################
oif="dc0" # name of the outbound interface
odns="192.0.2.11" # ISP's DNS server IP address
myip="192.0.2.7" # my static IP address from ISP
ks="keep state"
fks="flags S keep state"
# You can choose between building /etc/ipf.rules file
# from this script or running this script "as is".
#
# Uncomment only one line and comment out another.
#
# 1) This can be used for building /etc/ipf.rules:
#cat > /etc/ipf.rules << EOF
#
# 2) This can be used to run script "as is":
/sbin/ipf -Fa -f - << EOF
# Allow out access to my ISP's Domain name server.
pass out quick on $oif proto tcp from any to $odns port = 53 $fks
pass out quick on $oif proto udp from any to $odns port = 53 $ks
# Allow out non-secure standard www function
pass out quick on $oif proto tcp from $myip to any port = 80 $fks
# Allow out secure www function https over TLS SSL
pass out quick on $oif proto tcp from $myip to any port = 443 $fks
EOF
################## End of IPF rules script ########################
The rules are not important in this example as it instead focuses on how the
symbolic substitution fields are populated. If this example was in a file named
/etc/ipf.rules.script, these rules could be reloaded
by running:
# sh /etc/ipf.rules.script
There is one problem with using a rules file with embedded symbolics: IPF does
not understand symbolic substitution, and cannot read such scripts directly.
This script can be used in one of two ways:
Now, when the system boots, the IPF rules will be loaded.
IPF Rulesets
A ruleset contains a group of IPF rules which pass or block packets based on the
values contained in the packet. The bi-directional exchange of packets between hosts
comprises a session conversation. The firewall ruleset processes both the
packets arriving from the public Internet, as well as the packets produced by the
system as a response to them. Each
TCP/IP service is predefined by its protocol and listening port.
Packets destined for a specific service originate from the source address using an
unprivileged port and target the specific service port on the destination
address. All the above parameters can be used as selection criteria to create rules
which will pass or block services.
Warning: When working with the firewall rules, be very careful. Some configurations
can lock the administrator
out of the server. To be on the safe side, consider performing the
initial firewall configuration from the local console rather than doing it
remotely over ssh.
Rule Syntax
The rule syntax presented here has been simplified to only address the modern
stateful rule context and “first matching rule wins” logic. For the
complete legacy rule syntax, refer to
ipf(8).
A
# character 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.
Rules contain keywords which must be written in a specific order from left to
right on the line. Keywords are identified in bold type. Some keywords have
sub-options which may be keywords themselves and also include more sub-options. Each
of the headings in the below syntax has a bold section header which expands on
the content.
ACTION IN-OUT OPTIONS SELECTION STATEFUL PROTO
SRC_ADDR,DST_ADDR OBJECT PORT_NUM TCP_FLAG STATEFUL
ACTION = block | pass
IN-OUT = in | out
OPTIONS = log | quick | on interface-name
SELECTION = proto value | source/destination
IP | port = number | flags flag-value
PROTO = tcp/udp | udp | tcp | icmp
SRC_ADD,DST_ADDR = all | from object to
object
OBJECT = IP address | any
PORT_NUM = port number
TCP_FLAG = S
STATEFUL = keep state
ACTION
The action keyword indicates what to do with the packet if it matches the rest
of the filter rule. Each rule must have an action. The following actions are
recognized:
block indicates that the packet should be dropped if
the selection parameters match the packet.
pass indicates that the packet should exit the firewall
if the selection parameters match the packet.
IN-OUT
A mandatory requirement is that each filter rule explicitly state which side of
the I/O it is to be used on. The next keyword must be either in or out and one or the other has to be
included or the rule will not pass syntax checks.
in means this rule is being applied against an inbound
packet which has just been received on the interface facing the public
Internet.
out means this rule is being applied against an
outbound packet destined for the interface facing the public Internet.
OPTIONS
Note: These options must be used in the order shown here.
log indicates that the packet header will be written to
the
ipl(4) packet log
pseudo-device if the selection parameters match the packet.
quick indicates that if the selection parameters match
the packet, this rule will be the last rule checked, and no further processing of
any following rules will occur for this packet.
on indicates the interface name to be incorporated into
the selection parameters. Interface names are as displayed by
ifconfig(8). Using this
option, the rule will only match if the packet is going through that
interface in the specified direction.
When a packet is logged, the headers of the packet are written to the
ipl(4) packet logging
pseudo-device. Immediately following the
log keyword,
the following qualifiers may be used in this order:
body indicates that the first 128 bytes of the packet
contents will be logged after the headers.
first. If the
log keyword is
being used in conjunction with a
keep state option, this
option is recommended so that only the triggering packet is logged and not every
packet which matches the stateful connection.
SELECTION
The keywords described in this section are used to describe attributes of the
packet to be checked when determining whether or not rules match. There is a
keyword subject, and it has sub-option keywords, one of which has to be selected.
The following general-purpose attributes are provided for matching, and must be
used in this order:
PROTO
proto is the subject keyword which must include one of
its corresponding keyword sub-option values. The sub-option indicates a specific
protocol to be matched against.
tcp/udp | udp | tcp | icmp or any protocol names found
in
/etc/protocols are recognized and may be used. The
special protocol keyword
tcp/udp may be used to match
either a
TCP or a
UDP packet, and has been added as a convenience to
save duplication of otherwise identical rules.
SRC_ADDR/DST_ADDR
The all keyword is equivalent to “from any to
any” with no other match parameters.
from | to src to dst: the from
and to keywords are used to match against IP addresses.
Rules must specify both the
source and destination parameters. any is a special
keyword that matches any IP address. Examples include: from any
to any, from 0.0.0.0/0 to any, from any to 0.0.0.0/0, from 0.0.0.0 to
any, and from any to 0.0.0.0.
There is no way to match ranges of IP addresses which do not express themselves
easily using the dotted numeric form / mask-length notation. The net-mgmt/ipcalc port may be used to ease the calculation.
Additional information is available at the utility's web page: http://jodies.de/ipcalc.
PORT
If a port match is included, for either or both of source and destination, it is
only applied to
TCP and
UDP packets. When composing port comparisons, either
the service name from
/etc/services or an integer port
number may be used. When the port appears as part of the
from object, it matches the source port number. When it appears as
part of the
to object, it matches the destination
port number. An example usage is
from any to any port =
80
Single port comparisons may be done in a number of ways, using a number of
different comparison operators. Instead of the
= shown in
the example above, the following operators may be used:
!=,
<,
>,
<=,
>=,
eq,
ne,
lt,
gt,
le, and
ge.
To specify port ranges, place the two port numbers between
<> or
><
TCP_FLAG
Flags are only effective for
TCP
filtering. The letters represent one of the possible flags that can be matched
against the
TCP packet header.
The modernized rules processing logic uses the
flags S
parameter to identify the TCP session start request.
STATEFUL
keep state indicates that on a pass rule, any packets
that match the rules selection parameters should activate the stateful filtering
facility.
Stateful Filtering
Stateful filtering treats traffic as a bi-directional exchange of packets
comprising a session. When activated,
keep-state
dynamically generates internal rules for each anticipated packet being exchanged
during the session. It has sufficient matching capabilities to determine if a
packet is valid for a session. Any packets that do not properly fit the session
template are automatically rejected.
IPF stateful filtering will also allow
ICMP packets related to an existing
TCP or
UDP session. So, if
an
ICMP type 3 code 4 packet is a
response in a session started by a keep state rule, it will automatically be
allowed. Any packet that IPF can be certain is part of an active session, even if it
is a different protocol, will be allowed.
Packets destined to go out through the interface connected to the public Internet
are first checked against the dynamic state table. If the packet matches the next
expected packet comprising an active session conversation, it exits the
firewall and the state of the session conversation flow is updated in the
dynamic state table. Packets that do not belong to an already active session, are
checked against the outbound ruleset.
Packets coming in from the interface connected to the public Internet are first
checked against the dynamic state table. If the packet matches the next expected
packet comprising an active session, it exits the firewall and the state of the
session conversation flow is updated in the dynamic state table. Packets that do not
belong to an already active session, are checked against the inbound
ruleset.
When the session completes, it is removed from the dynamic state table.
Stateful filtering allows one to focus on blocking/passing new sessions. If the
new session is passed, all its subsequent packets are allowed automatically and any
impostor packets are automatically rejected. If a new session is blocked, none
of its subsequent packets are allowed. Stateful filtering provides advanced matching
abilities capable of defending against the flood of different attack methods
employed by attackers.
Inclusive Ruleset
Example
The following ruleset is an example of an inclusive type of firewall which only
allows services matching
pass rules and blocks all others
by default. Network firewalls intended to protect other machines should have at
least two interfaces, and are generally configured to trust the
LAN and to not trust the public Internet.
Alternatively, a host based firewall might be configured to protect only the system
it is running on, and is appropriate for servers on an untrusted network or a
desktop system not protected by firewall on the network.
FreeBSD uses interface
lo0 and IP address
127.0.0.1 for internal communication within the operating system. The
firewall rules must contain rules to allow free movement of these internally
used packets.
The interface which faces the public Internet is the one specified in the rules
that authorize and control access of the outbound and inbound connections.
In cases where one or more NICs are cabled to private network segments, those
interfaces may require rules to allow packets originating from those LAN interfaces
transit to each other or to the Internet.
The rules should be organized into three major sections: the trusted interfaces,
then the public interface outbound, and lastly, the public untrusted interface
inbound.
The rules in each of the public interface sections should have the most
frequently matched rules placed before less commonly matched rules, with the last
rule in the section blocking and logging all packets on that interface and
direction.
The outbound section in the following ruleset only contains
pass rules which uniquely identify the services that are authorized
for public Internet access. All the rules use
quick,
on,
proto,
port, and
keep state. The
proto tcp rules include
flag to identify the
session start request as the triggering packet to activate the stateful
facility.
The inbound section blocks undesirable packets first, for two different reasons.
The first is that malicious packets may be partial matches for legitimate traffic.
These packets have to be discarded rather than allowed, based on their partial
matches against the
allow rules. The second reason is that
known and uninteresting rejects may be blocked silently, rather than being logged by
the last rule in the section.
The ruleset should ensure that there is no response returned for any undesirable
traffic. Invalid packets should be silently dropped so that the attacker has no
knowledge if the packets reached the system. Rules that include a
log first option, will only log the event the first time they are
triggered. This option is included in the sample
nmap OS
fingerprint rule. The
security/nmap utility is commonly used by attackers who attempt
to identify the operating system of the server.
Any time there are logged messages on a rule with the
log
first option,
ipfstat -hio should be executed to
evaluate how many times the rule has been matched. A large number of matches usually
indicates that the system is being flooded or is under attack.
To lookup unknown port numbers, refer to
/etc/services.
Alternatively, visit http://en.wikipedia.org/wiki/List_of_TCP_and_UDP_port_numbers and do a
port number lookup to find the purpose of a particular port number.
Check out this link for port numbers used by Trojans http://www.sans.org/security-resources/idfaq/oddports.php.
The following ruleset creates an
inclusive firewall
ruleset which can be easily customized by commenting out
pass rules for services that should not be authorized.
To avoid logging unwanted messages, add a
block rule in
the inbound section.
Change the
dc0 interface name in every rule to the
interface name that connects the system to the public Internet.
The following statements were added to
/etc/ipf.rules:
#################################################################
# No restrictions on Inside LAN Interface for private network
# Not needed unless you have LAN
#################################################################
#pass out quick on xl0 all
#pass in quick on xl0 all
#################################################################
# No restrictions on Loopback Interface
#################################################################
pass in quick on lo0 all
pass out quick on lo0 all
#################################################################
# Interface facing Public Internet (Outbound Section)
# Match 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.
# xxx 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
pass out quick on dc0 proto tcp from any to xxx port = 53 flags S keep state
pass out quick on dc0 proto udp from any to xxx port = 53 keep state
# Allow out access to my ISP's DHCP server for cable or DSL networks.
# This rule is not needed for 'user ppp' type 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
pass out log quick on dc0 proto udp from any to any port = 67 keep state
#pass out quick on dc0 proto udp from any to z.z.z.z port = 67 keep state
# Allow out non-secure standard www function
pass out quick on dc0 proto tcp from any to any port = 80 flags S keep state
# Allow out secure www function https over TLS SSL
pass out quick on dc0 proto tcp from any to any port = 443 flags S keep state
# Allow out send & get email function
pass out quick on dc0 proto tcp from any to any port = 110 flags S keep state
pass out quick on dc0 proto tcp from any to any port = 25 flags S keep state
# Allow out Time
pass out quick on dc0 proto tcp from any to any port = 37 flags S keep state
# Allow out nntp news
pass out quick on dc0 proto tcp from any to any port = 119 flags S keep state
# Allow out gateway & LAN users' non-secure FTP ( both passive & active modes)
# This function uses the IPNAT built in FTP proxy function coded in
# the nat rules file to make this single rule function correctly.
# If you want to use the pkg_add command to install application packages
# on your gateway system you need this rule.
pass out quick on dc0 proto tcp from any to any port = 21 flags S keep state
# Allow out ssh/sftp/scp (telnet/rlogin/FTP replacements)
# This function is using SSH (secure shell)
pass out quick on dc0 proto tcp from any to any port = 22 flags S keep state
# Allow out insecure Telnet
pass out quick on dc0 proto tcp from any to any port = 23 flags S keep state
# Allow out FreeBSD CVSup
pass out quick on dc0 proto tcp from any to any port = 5999 flags S keep state
# Allow out ping to public Internet
pass out quick on dc0 proto icmp from any to any icmp-type 8 keep state
# Allow out whois from LAN to public Internet
pass out quick on dc0 proto tcp from any to any port = 43 flags S keep state
# Block and log only the first occurrence of everything
# else that's trying to get out.
# This rule implements the default block
block out log first quick on dc0 all
#################################################################
# Interface facing Public Internet (Inbound Section)
# Match packets originating from the public Internet
# destined for this gateway server or the private network.
#################################################################
# Block all inbound traffic from non-routable or reserved address spaces
block in quick on dc0 from 192.168.0.0/16 to any #RFC 1918 private IP
block in quick on dc0 from 172.16.0.0/12 to any #RFC 1918 private IP
block in quick on dc0 from 10.0.0.0/8 to any #RFC 1918 private IP
block in quick on dc0 from 127.0.0.0/8 to any #loopback
block in quick on dc0 from 0.0.0.0/8 to any #loopback
block in quick on dc0 from 169.254.0.0/16 to any #DHCP auto-config
block in quick on dc0 from 192.0.2.0/24 to any #reserved for docs
block in quick on dc0 from 204.152.64.0/23 to any #Sun cluster interconnect
block in quick on dc0 from 224.0.0.0/3 to any #Class D & E multicast
##### Block a bunch of different nasty things. ############
# That I do not want to see in the log
# Block frags
block in quick on dc0 all with frags
# Block short tcp packets
block in quick on dc0 proto tcp all with short
# block source routed packets
block in quick on dc0 all with opt lsrr
block in quick on dc0 all with opt ssrr
# Block nmap OS fingerprint attempts
# Log first occurrence of these so I can get their IP address
block in log first quick on dc0 proto tcp from any to any flags FUP
# Block anything with special options
block in quick on dc0 all with ipopts
# Block public pings
block in quick on dc0 proto icmp all icmp-type 8
# Block ident
block in quick on dc0 proto tcp from any to any port = 113
# Block all Netbios service. 137=name, 138=datagram, 139=session
# Netbios is MS/Windows sharing services.
# Block MS/Windows hosts2 name server requests 81
block in log first quick on dc0 proto tcp/udp from any to any port = 137
block in log first quick on dc0 proto tcp/udp from any to any port = 138
block in log first quick on dc0 proto tcp/udp from any to any port = 139
block in log first quick on dc0 proto tcp/udp from any to any port = 81
# 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.
pass in quick on dc0 proto udp from z.z.z.z to any port = 68 keep state
# Allow in standard www function because I have apache server
pass in quick on dc0 proto tcp from any to any port = 80 flags S keep state
# Allow in non-secure Telnet session from public Internet
# labeled non-secure because ID/PW passed over public Internet as clear text.
# Delete this sample group if you do not have telnet server enabled.
#pass in quick on dc0 proto tcp from any to any port = 23 flags S keep state
# Allow in secure FTP, Telnet, and SCP from public Internet
# This function is using SSH (secure shell)
pass in quick on dc0 proto tcp from any to any port = 22 flags S keep state
# Block and log only first occurrence of all remaining traffic
# coming into the firewall. The logging of only the first
# occurrence avoids filling up disk with Denial of Service logs.
# This rule implements the default block.
block in log first quick on dc0 all
################### End of rules file #####################################
NAT
NAT stands for
Network Address Translation. In
Linux®, NAT is called “IP
Masquerading”. The IPF
NAT
function enables the private LAN behind the firewall to share a single ISP-assigned
IP address, even if that address is dynamically assigned. NAT allows each
computer in the LAN to have Internet access, without having to pay the ISP for
multiple Internet accounts or IP addresses.
NAT will automatically translate the
private LAN IP address for each system on the LAN to the single public IP
address as packets exit the firewall bound for the public Internet. It also performs
the reverse translation for returning packets.
According to RFC 1918, the following IP address ranges are reserved for private
networks which will never be routed directly to the public Internet, and therefore
are available for use with NAT:
-
10.0.0.0/8.
-
172.16.0.0/12.
-
192.168.0.0/16.
IPNAT
NAT rules are loaded using
ipnat. Typically, the
NAT
rules are stored in
/etc/ipnat.rules. See
ipnat(8) for
details.
When the file containing the
NAT rules
is edited after
NAT has been started,
run
ipnat with
-CF
to delete
the internal in use
NAT rules and flush
the contents of the translation table of all active entries.
To reload the
NAT rules, issue a
command like this:
# ipnat -CF -f
/etc/ipnat.rules
To display some
NAT statistics, use
this command:
# ipnat -s
To list the
NAT table's current
mappings, use this command:
# ipnat -l
To turn verbose mode on and display information relating to rule processing and
active rules/table entries:
# ipnat -v
IPNAT Rules
NAT rules are flexible and can
accomplish many different things to fit the needs of commercial and home
users.
The rule syntax presented here has been simplified to what is most commonly used
in a non-commercial environment. For a complete rule syntax description, refer to
ipnat(5).
The syntax for a
NAT rule looks like
this:
map IF LAN_IP_RANGE -> PUBLIC_ADDRESS
The keyword
map starts the rule.
Replace
IF with the external interface.
The
LAN_IP_RANGE is used by the internal
clients use for IP Addressing. Usually, this is something like
192.168.1.0/24.
The
PUBLIC_ADDRESS can either be the static
external IP address or the special keyword
0/32 which uses
the IP address assigned to
IF.
How NAT Works
In IPF, when a packet arrives at the firewall from the LAN with a public
destination, it passes through the outbound filter rules.
NAT gets its turn at the packet and applies its rules top down,
where the first matching rule wins.
NAT
tests each of its rules against the packet's interface name and source IP
address. When a packet's interface name matches a
NAT rule, the packet's source IP address in the private LAN is
checked to see if it falls within the IP address range specified to the left of the
arrow symbol on the
NAT rule. On a
match, the packet has its source IP address rewritten with the public IP address
obtained by the
0/32 keyword.
NAT posts an entry in its internal
NAT table so when the packet returns from the public Internet it
can be mapped back to its original private IP address and then passed to the filter
rules for processing.
Enabling IPNAT
To enable IP
NAT, add these statements
to
/etc/rc.conf.
To enable the machine to route traffic between interfaces:
gateway_enable="YES"
To start IP
NAT automatically each
time:
ipnat_enable="YES"
To specify where to load the IP
NAT
rules from:
ipnat_rules="/etc/ipnat.rules"
NAT for a Large LAN
For networks that have large numbers of systems on the LAN or networks with more
than a single LAN, the process of funneling all those private IP addresses into a
single public IP address becomes a resource problem that may cause problems
with the same port numbers being used many times across many connections,
causing collisions. There are two ways to relieve this resource problem.
Assigning Ports to
Use
A normal NAT rule would look like:
map dc0 192.168.1.0/24 -> 0/32
In the above rule, the packet's source port is unchanged as the packet passes
through IP
NAT. By adding the
portmap keyword, IP
NAT
can be directed to only use source ports in the specified range. For example, the
following rule will tell IP
NAT to
modify the source port to be within the range shown:
map dc0 192.168.1.0/24 -> 0/32 portmap tcp/udp 20000:60000
Additionally, the
auto keyword tells IP
NAT to determine which ports are available for
use:
map dc0 192.168.1.0/24 -> 0/32 portmap tcp/udp auto
Using a Pool of Public
Addresses
In very large LANs there comes a point where there are just too many LAN
addresses to fit into a single public address. If a block of public IP addresses is
available, these addresses can be used as a “pool”, and
IP
NAT may pick one of the public IP
addresses as packet addresses are mapped on their way out.
For example, instead of mapping all packets through a single public IP
address:
map dc0 192.168.1.0/24 -> 204.134.75.1
A range of public IP addresses can be specified either with a netmask:
map dc0 192.168.1.0/24 -> 204.134.75.0/255.255.255.0
or using CIDR notation:
map dc0 192.168.1.0/24 -> 204.134.75.0/24
Port Redirection
A common practice is to have a web server, email server, database server, and DNS
server each segregated to a different system on the LAN. In this case, the traffic
from these servers still has to undergo
NAT, but there has to be some way to direct the inbound traffic to the
correct server. For example, a web server operating on LAN address
10.0.10.25 and using a single public IP address of
20.20.20.5, would use this rule:
rdr dc0 20.20.20.5/32 port 80 -> 10.0.10.25 port 80
or:
rdr dc0 0.0.0.0/0 port 80 -> 10.0.10.25 port 80
For a LAN DNS server on a private address of
10.0.10.33 that
needs to receive public DNS requests:
rdr dc0 20.20.20.5/32 port 53 -> 10.0.10.33 port 53 udp
FTP and NAT
FTP has two modes: active mode and passive mode. The difference is in how the
data channel is acquired. Passive mode is more secure as the data channel is
acquired by the ordinal ftp session requester. For a good explanation of FTP
and the different modes, see http://www.slacksite.com/other/ftp.html.
IPNAT Rules
IP
NAT has a built in FTP proxy option
which can be specified on the
NAT map
rule. It can monitor all outbound packet traffic for FTP active or passive
start session requests and dynamically create temporary filter rules containing the
port number being used by the data channel. This eliminates the security risk
FTP normally exposes the firewall to as it no longer needs to open large ranges of
high order ports for FTP connections.
This rule will handle all the traffic for the internal LAN:
map dc0 10.0.10.0/29 -> 0/32 proxy port 21 ftp/tcp
This rule handles the FTP traffic from the gateway:
map dc0 0.0.0.0/0 -> 0/32 proxy port 21 ftp/tcp
This rule handles all non-FTP traffic from the internal LAN:
map dc0 10.0.10.0/29 -> 0/32
The FTP
map rules go before the
NAT rule so that when a packet matches an FTP rule,
the FTP proxy creates temporary filter rules to let the FTP session packets pass
and undergo
NAT. All LAN packets that
are not FTP will not match the FTP rules but will undergo
NAT if they match the third rule.
IPNAT FTP Filter Rules
Only one filter rule is needed for FTP if the
NAT FTP proxy is used.
Without the FTP proxy, the following three rules will be needed:
# Allow out LAN PC client FTP to public Internet
# Active and passive modes
pass out quick on rl0 proto tcp from any to any port = 21 flags S keep state
# Allow out passive mode data channel high order port numbers
pass out quick on rl0 proto tcp from any to any port > 1024 flags S keep state
# Active mode let data channel in from FTP server
pass in quick on rl0 proto tcp from any to any port = 20 flags S keep state