Defcon-1-Logo

           [Home]    [FBSD Articles]    [Scripts Corner]    [Contribute]    [Search]    [FBSD Links]    [Files]

About Us

FreeBSD Articles
  *Hardware
  *Networking
  *Security
  *Software
  *X Windows


Files / Scripts
Newbies Corner
Tech. Talk
Tips and Tricks


FreeBSD Links

Articles in other
Languages :
  *French Articles
  *Spanish Articles

Want to Help ?
 
   Click Here

Email Users5

Search:
 

 


FreeBSD Search:


 

 

Powered-By-Apache-Logo
Defcon1 Logo

IPFW How To

  If there are any questions or comments, please direct them to walt@erudition.net . The newest copy of this HowTo can always be retrieved from www.freebsd-howto.com. All rights for the reproduction of this document are reserved.


Summary.

    1.   General Introduction to Packet Filters
    2.   Enabling Ipfirewall(4)

    2.1.  rc.firewall and OPEN firewalls
    2.2.  Loading Rulesets

    2.2.1. Pre-defined Firewall Types
    2.2.2. Custom Firewall Types

    3.   Basic Ipfw(8) Rule Syntax
 
    3.1.  Listing Rules
    3.2.  Basic Commands and Actions
    3.3.  Specifying Protocols
    3.4.  Specifying the Source and Destination Addresses

    3.4.1. Introduction to Bitmasks and Netmasks
    3.4.2. Specifying Ports and Port Ranges

    4.   Advanced ipfw(8) Rule Syntax

    4.1.  "unreach" Action
    4.2.  Interface and Flow Control
    4.3.  Matching specific ICMP and TCP Packet Types

    4.3.1. icmptypes
    4.3.2. tcpflags, setup and established
    4.3.3. ipoptions

    4.4.  Catching Fragmented Packets
    4.5.  UID and GID Based Filtering

    5.   Logging

    5.1.  Logging Issues
    5.2.  System Logging Configuration

    5.2.1. Kernel Options
    5.2.2. Configuring syslog(8) for Logging
    5.2.3. Configuring newsyslog(8) for Log Rotation

    5.3.  Rule Logging Configuration

    6.  Introduction to Stateless and Stateful Filtering

    6.1.  Basic Stateful Configuration
    6.2.  Advanced Stateful Configuration
    6.3.  Anatomy of a Dynamic Rule

    7.   Traffic Shaping

    7.1.  Probability Matching
    7.2.  Dummynet

    7.2.1. Pipe Queues
    7.2.2. Pipe Masks
    7.2.3. Pipe Packet Reinjection

    8.   Traffic Flow

    Appendix A: Example Firewall Configurations

1.General Introduction to Packet Filters

Ipfw(8), the command frontend to ipfirewall(4), is the most common IP filtering and traffic shaping facility in FreeBSD, and the one for which FreeBSD is ready to handle by default (although the firewall itself is disabled by default in the kernel). The logical operation if its rules is similar to many other packet filters, with the exception of IPFilter, whose default operation in handling rules is rather less efficient and requires greater care to tune it (if you're familiar with it, note the 'quick' keyword required for ipf(8) not to traverse the entire ruleset every time, etc). This is not to minimize the power of ipf(8), which has its own advantages. The ultimate decision as to which packet filtering facility one uses is a personal choice, unless one requires particular functionality not available in one or the other, although, we will delve into a rough comparison of the two later on.

As indicated above, ipfirewall(4) is a packeting filtering
firewall, which means that it acts by inspecting connexions on a
packet-by-packet basis, and as of FreeBSD 4.0, can also perform
rudimentary connexion oriented (stateful) filtering. On either count, it
acts by filtering packets through one or more network interfaces. This
behaviour is always transparent, that is, one will probably not be aware
that a firewall is present until something is blocked.

Firewall designs take on many shapes, but all can be broken down
into two general policies: open and closed. The open firewall approach
lets all packets through by default and only blocks that which is NOT
desired, while on the other hand, the closed approach blocks all packets
by default, and only lets through was IS desired. The latter allows for a
much tighter firewall configuration, but is much trickier to setup because
one can easily block out traffic that one's net requires, but one isn't
aware of.

2.Enabling Ipfirewall(4)

Ipfirewall(4) can be enabled in two ways: add the appropriate
options into your kernel configuration file and rebuild the kernel, or use
kldload(8) to dynamically load the basic ipfw.ko module into the kernel.
Either approach works well for enabling basic ipfirewall(4) operations,
however, only the former allows you to add additional configuration
options, such as logging.

To dynamically load ipfw one can simply issue the following
command:

(root@nu)~># kldload ipfw
(root@nu)~>#

Enabling ipfirewall(4) statically, the equivalent would be to add
the following line into your kernel configuration file:

optionsIPFIREWALL

Then, rebuilding and rebooting would enable ipfirewall(4) in the
kernel statically.

However, things are not as simple as they may seem; one can only
do things exactly as above when one is in front of the console. Additional
options are necessary to make the box usable. If you recall the discussion
above concerning firewall policies (open and closed), you will understand
why things can get very messy when you realize that the default firewall
policy is closed. As such, if you simply enable ipfirewall(4) without any
further actions, all network traffic will be blocked. This can become a
nightmare when enabling ipfirewall(4) remotely. Diasaster can be avoided,
although, it is never recommened to remotely enable ipfirewall(4), either
dynamically or statically.

If you wish to dynamically load ipfirewall(4) remotely, anyhow,
the follow command is recommended:

    (root@nu)~># kldload ipfw && \
ipfw -q add 65000 allow all from any to any
    (root@nu)~>#

This will automatically set a rule to allow all traffic instead of
blocking it, so you don't cut yourself off from your remote box. Likewise,
this is recommended on local boxes as well if they are connected to a
network and you don't want to lose your connexion.

Enabling ipfirewall(4) in the kernel statically in a remote box
takes a little extra work. Once one has added the kernel option specified
earlier, in the kernel configuration file, and rebuilt the kernel, one has
to then set at least two ipfirewall(4) options in rc.conf so that when the
box reboots, it will not be locked out by its own firewall with the
default-to-close policy.

firewall_enable="YES"
firewall_type="OPEN"

There are other firewall types defined in /etc/rc.firewall, but we
will concern ourselves with those later. For now, a default open policy is
good practice for the beginner. Alternatively, one can enable a default
open policy for ipfw(8) in the kernel, instead, by also adding the
following option into the kernel configuration file:

optionsIPFIREWALL_DEFAULT_TO_ACCEPT

In this case, the rc.conf options noted above will not be
*necessary* as we will not *need* to use /etc/rc.firewall to enable an
open policy because it will be enabled by default in the kernel. However,
even if one chooses to enable this in the kernel, it is good practice to
enable the /etc/rc.conf options anyhow, because later we will be using
/etc/rc.firewall to load custom rulesets. This also applies if one loads
the kernel dynamically, because eventually one will reboot, and the kernel
ipfw.ko module will not be automatically loaded. The /etc/rc.conf firewall
enabling functions allow for a convenient place to load the ipfw.ko
module.

With the additional options for ipfirewall(4) that are available
for enabling statically in the kernel, one soon realizes this is the
better method for enabling ipfirewall(4), at least as FreeBSD is designed
currently. Aside from IPFIREWALL_DEFAULT_TO_ACCEPT, we also have:

options     IPFIREWALL_VERBOSE   
options     IPFIREWALL_FORWARD   
options     IPFIREWALL_VERBOSE_LIMIT=#

IPFIREWALL_VERBOSE allows one to log traffic with ipfirewall(4) by
verbosely printing packet activity to syslogd(8) for every rule that has
the "log" keyword. This will be more clearly explained later.

IPFIREWALL_FORWARD allows one to forward packets to other hosts
with the 'fwd' command for ipfirewall(4), which will be dealt with in more
depth later.

IPFIREWALL_VERBOSE_LIMIT=# specifies a limit to logging packets
from a particular rule. With this, syslogd(8) and one's console (unless
disabled in /etc/syslog.conf, as will be shown later) will not be
overwhelmed with messages from ipfirewall(4) activity. The "#" is
replaced with the number of consecutive times one wishes to log a given
rule being activated.

If one has IPv6 enabled, then the following rules will apply to
the corresponding firewall actions on IPv6 packets:

options     IPV6FIREWALL
options     IPV6FIREWALL_VERBOSE
options     IPV6FIREWALL_VERBOSE_LIMIT=100
options     IPV6FIREWALL_DEFAULT_TO_ACCEPT

In addition, there are four more options associated with
ipfirewall(4) that can be enabled in the kernel, but will not be discussed
at this moment as they are not necessary for the basic firewall
activities, and involve more complex routing situations.


2.1.rc.firewall and OPEN firewalls

Whether one specifies a firewall type or not, once
firewall_enable="YES" is put into rc.conf and the system reboots,
/etc/rc.firewall is started from rc.conf, and the following two commands
are issued to ipfw(8) from within it:

${fwcmd} add 100 pass all from any to any via lo0
${fwcmd} add 200 deny all from any to 127.0.0.0/8

{fwcmd} is defined early on in the rc.firewall script, depending
on whether one specified that ipfw(8) run quietly (with the -q option) or
not. The first rule allows all traffic via the loopback device (lo0) to
pass, and the second rule blocks all traffic aimed at the localhost
(127.0.0.0) network. The first rule is necessary to allow local IPC
(inter-process communication) traffic, and the second rule is necessary so
that no external packets can ever be allowed to reach the localhost
address, which is the address on the loopback device, thus protecting
one's local traffic. If these rules are missing, and the firewall defaults
to a closed policy, you will see RPC(3) services break during startup,
among other things.

Next, when one specifies a firewall type of "OPEN" in rc.conf, the
following line in rc.firewall is activated:

    ${fwcmd} add 65000 pass all from any to any

This allows all external traffic in (except to the localhost), and
all internal traffic out. It fulfills the same task as enabling the
IPFIREWALL_DEFAULT_TO_ACCEPT in the kernel. If the open policy is enabled
in the kernel, then rule # 65535 will be automatically set to "allow ip
from any to any" instead of "deny ip from any to any," thus making rule #
65000 as set in rc.firewall for the open policy redundant. As such, it is
more apropos to indicate firewall type "UNKNOWN" if one enables an open
policy in the kernel, and does not wish to enable any other rules. For one
wishes to, for instance, simply enable the firewall to play with and see
how it work,s or simply block packets from a single host, then leaving the
firewall type open like this is sufficient and one can safely skip to
section 3.

However, if one wishes to use one of the pre-built rulesets in
rc.firewall, or create one's own custom rulesets, then neither options
(OPEN or UNKNOWN) are sufficient.


2.2.Loading Rulesets

There are two generally different things that can be done
concerning rulesets: use one of the pre-built ones in rc.firewall, or
create your own. The author recommends the latter for two reasons:

- You can customize the firewall rules to your liking and needs
without touching rc.firewall, which can be kept as a general reference.

- You will be forced harder to become familiarized with
ipfw(8) syntax, and as such, will become more comfortable with using
ipfw(8).


2.2.1.Pre-defined Firewall Types

Of course, the final decision is the administrator's. If one
wishes to use one of the pre-built rulesets, then one should read through
each of them in rc.firewall to become familiar with them before activating
any of them. Which ruleset is loaded is controlled by the
firewall_type="" option in rc.conf. Aside from the "OPEN" type, there are
three more predefined types available:

"CLIENT" This ruleset enables some basic rules. It allows all
traffic from the local network (which could be a private network behind
NAT) to itself. It blocks fragmented packets. It allows mail, DNS and NTP
packets in and out of the network, and does not allow any host outside the
private network to initiate TCP connexions with internal hosts. This would
already be impossible if the network was behind a vanilla NAT
configuration without any special proxies. This configuration will work
with both a default open or closed policy.


"SIMPLE" This ruleset is somewhat of any oxymoron - it is more
complex than the CLIENT configuration and requires some knowledge of
internet RFCs to make sense of at first glance. It will attempt to stop
spoofing by not allowing in external packets that have return addresses
the same as that of any internal host. It will block all
private-net-addressesed packets as defined by RFC 1918 from leaking in or
out, and will block all additional non-routable networks as defined in the
Manning internet draft
( http://www.ietf.org/internet-drafts/draft-manning-dsua-03.txt ). It will
allow mail, www, DNS, NTP traffic and fragmented packets to pass through,
and will not only block attempts for connexions to be initiated by outside
hosts, like CLIENT, but will also log these attempts.

"CLOSED" This is technically not a rulest, because it does not
enable any rules. In fact, it does everything we've been warning not to
do: allow the default closed policy to take hold over all traffic (except
for traffic via lo0 as controlled by the rules explained earlier). It will
essentially disable all IP services, unless, one enabled the default open
policy in the kernel. Don't do this.


2.2.2.Custom Firewall Types

If one has decided to instead load one's oen ruleset(s), then one
should specify a file instead of one of the above types in the
firewall_type option in rc.conf. For instance, one might have the
following in their rc.conf:

firewall_enable="YES"
firewall_type="/etc/rc.firewall.rules"

This will allow one to define one's custom ipfirewall(4) ruleset
in /etc/rc.firewall.rules and have it run everytime during bootup.
Furthermore, if one wanted to have the rules start quietly, one could also
include the following in rc.conf:

firewall_quiet="YES"

The format of the ruleset in this file will be slightly different
from that which is encountered in rc.firewall. This is because rc.firewall
is an sh(1) script designed to run on its own. The ipfirewall(4) rule file
is there solely to be processed by ipfw(8). The primary difference will be
that where the shell variable {fwcmd} is invoked in rc.firewall, you will
see nothing corresponding to it invoked in the ipfirewall(4) rule file -
simply the rules on their own. Later on, when we construct a sample rule
file, we will go through this step by step.


3.Basic Ipfw(8) Rule Syntax

The rule syntax for ipfw(8) is pretty simple. Any rule can be
enabled from the console with the ipfw(8) command. Before we delve into
the rule syntax, however, we will quickly overview how to list the
ipfirewall(4) rules that have been activated.


3.1.Listing Rules

In its simplest form, we can list the rules with:

ipfw list

This will list all of the rules ordered by their rule number. To
also list the timestamp of the last moment a packet was matched on a
specific rule, the following command will accomplish this:

ipfw -t list


Finally, if we wish to list the packet count for matched rules
along with the rules themselves, we can issue the following:

ipfw -a list

OR

ipfw show

Both will display the same information in the same way. The first
column is the rule number, followed by the number of outgoing matched
packets, followed by the number of incoming matched packets, and finally
followed by the rule itself.


3.2.Basic Commands and Actions

We will now gradually go through the various options available for
the construction of a stateless filtering ruleset. In our examples we will
only state the rule not including the firewall control utility
(/sbin/ipfw) which must precede each one if we're manually setting these
rules from the command prompt; otherwise, if we're construction a rule
file to be passed to ipfw(8) we can use the sample lines as-is.

add 1000 allow all from any to any

This is the most benign example of a rule. We have already
encountered the same rule, except for the rule #, in section 2.1 when
discussing the OPEN firewall type. Note: the "pass" parameter used in that
rule, as written in rc.firewall, is synonym for "allow" and "permit" -
they are interchangable. In this rule, "all" packets from "any" source to
"any" destination are allowed to pass.

With ipfirewall(4), under most circumstances, the moment a rule
matches a particular packet, then ruleset examination halts there.

As we see, the simplest syntax for ipfw(4) is:

<command> [<rule #>] <action> <proto> from <source> to
<destination>

The important commands are "add" and "delete." They are
self-explanatory. Rule numbers start count at 0 and end at 65535. The last
rule number is always defined by the default firewall policy in the
kernel. Even if you have an open policy defined in rc.conf, the last rule
will always reflect the kernel policy. This is fine because ruleset search
halts at the first matching rule (usually), so if the penultimate (second
to last) rule is number 65000 and defined by rc.firewall to allow all
packets, all packets will be allowed by default even if the last rule
(65535) defines a closed kernel firewall policy, because the last rule
will never be reached.

"action" can be one of a number of things:

"allow" | "pass" | "permit" - Any packets matching a rule with
this action are allowed to pass through the firewall, and search of
ruleset terminates.

"deny" | "drop" - Any packets matching a rule with this action are
silently blocked by the firewall and search of ruleset terminates.

add 1100 deny all from any to any

This would deny all packets from anywhere to anywhere.

"reset" - Any packets matching a rule with this action are blocked
and the ipfirewall(4) attempts to send a TCP reset (RST) notice to the
source. The ruleset search is terminated. Naturally, because this only
applies for TCP packets, the protocol must be "tcp," which matches only
TCP packets, and not "all," which matches all IP packets.

This action is sometimes useful for fooling network scanners that
would otherwise be able to detect a service behind a filtered port. On the
other hand, it can become a liability if one is flooded at a particular IP
and port for which ipfirewall(4) is set to reply with a RST packet, thus
doubling the usage of your bandwidth.

add 1200 reset tcp from any to any

This would deny all TCP packets from any to anywhere, and sent a
TCP RST responce packet to the source for each.

"count" - Any packets matching a rule with this action will prompt
ipfirewall(4) to increment its packet counter. Search through the ruleset
continues.

add 1300 count all from any to any

This would increment the packet counter for this rule, which
matches all packets coming from anywhere and going anywhere.

"skipto <number>" - Any packets matching a rule with this action
will prompt ipfirewall(4) to continue its search through the ruleset
starting with the rule number equal to or greater than that which is
indicated by <number>.

add 1400 skipto 1800 all from any to any

This would skip ruleset search to rule 1800 for any packets that
matched this rule in the first place.


3.3.Specifying Protocols

The "proto" is the protocol that is desired to be matched. The
keywords "ip" or "all" are catch-alls that match all protocols. The
commonly matched packet procotols are icmp, udp, and tcp, although, that
is by no means an exhaustive list. For the complete list of possible
protocols one can match, 'more /etc/protocols'.

3.4.Specifying the Source and Destination Addresses

The "source" and "destination" both take on the same format. They
can be a name, as defined in /etc/hosts or through DNS, an IP address, a
network address with bitmask (or netmask), and can be optionally followed
by one or more ports numbers if the protocol is udp or tcp. Using names or
IPs is straightforward, for instance:

add 1000 allow all from myhost to hishost
add 1100 deny all from 10.0.0.5 to any

The first rule will allow all traffic from "myhost" to "hishost,"
and the second rule will deny all traffic from 10.0.0.5 to any host. Once
a packet matches one of these, ruleset examination for that packet ceases,
and it is either passed or dropped, according to the action specified in
the rule it matched. This is a simple example of host-based filtering;
that is, of filtering according to which hosts a packet is destined for,
or arriving from. Network-based filtering works similarly, and the network
notation there utilizes either bitmasks or netmasks, for instance:

add 2000 allow all from 192.168.0.0/16 to any
add 2100 deny all from any to 10.0.0.0:255.0.0.0

The first rule allows all traffic from the network whose IP range
is 192.168.0.0-192.168.255.255. It uses a bitmask to indicate this. A
bitmask specifies how many bits from the network address (192.168.0.0)
should remain the same for matching packets. In this instance, the first
16 bits out of the 32 bit address will remain the same, and as the first
16 bits happen to be the first two octets, 192.168, all addresses whose
source addresses have the first two octets as 192.168 will be matched by
this rule. The second rule accomplishes a similar thing using netmasks.
The netmask indicate how many bits from the indicated network address
should be used for rule matching. In the above example, for rule two, the
netmask is 255.0.0.0. Its first octet is set with high bits; in other
words, the first 8 bits are set high. This indicates to ipfw(8) that only
packets with the first 8 bits of the network address (10.0.0.0) should be
matched. As the first 8 bits of the network address equal 10, then all
packets whose destination address have a 10 for the first octet (all
addresses between 10.0.0.0 and 10.255.255.255) will be matched by this
rule, and then dropped, as indicated by the action.

Rule matches can also be inverted with the "not" keyword. For
instance, in the following ipfw(8) commands, all packets not from
192.168.0.3 are dropped:

add 1000 deny all from not 192.168.0.3


3.4.1.Introduction to Bitmasks and Netmasks

The principle behind bitmasks and netmasks is simple, but often
confusing to new users, as it requires knowledge of binary numbers. It
makes far more sense if one worked with IP addresses in their binary form,
however, the confounding of decimal and binary concepts easily throws
newcomers off. For a quick reference, the following table illustrates what
network ranges are indicated by the corresponding bitmasks/netmasks up to
a default class C netmask and a couple quick examples of additional
bitmask/netmask entries for larger networks:

BitmaskNetmaskTotal IPs / Usable IPs

32255.255.255.25511
31255.255.255.25421
30255.255.255.25242
29255.255.255.24886
28255.255.255.2401614
27255.255.255.2243230
26255.255.255.1926462
25255.255.255.128128126
24255.255.255.0256254

...

22255.255.192.01632016318
20255.255.128.03276832766
16255.255.0.06553665534
12255.128.0.08.388608+e6  8.388606+e6
8255.0.0.0256^3(256^3)-2
00.0.0.0(all IPs)256^4(256^4)-2

As you can see, there is a definite pattern. The number if total
IPs always doubles, and the number of usable IPs is always total - 2. This
is because for every IP network/subnet there are two IPs reserved for the
network and broadcast addresses. The netmask's last octet starts at 255
and constantly decreases by multiples of 2, while the bitmask decreases by
multiples of 1, because in binary, each shift over to the left halves the
number, not divides by ten, like in the decimal number system. This same
pattern goes for all possible netmasks and bitmasks.

For a quick example in using the above table/pattern, let us
figure out the IP range for the subnet indicated by:

172.16.100.32/28

First we notice that the network address is 172.16.100.32, so we
know that the subnet begins with this address. Second, we notice that the
bitmask of 28 indicates that the last 4 bits (32-28) are set low and 28
bits set high. Because there are far less bits set low, it'll be easier to
compute this using them. Because each bit has two possible values, 2^4
indicates how many hosts are referenced by this bitmask. In this case, 16.
172.16.100.32 + 16 = 172.16.100.48, so the IP range is 172.16.100.32 -
172.16.100.48. Looking at the table, we see that 16 IPs correspond to a
bitmask of 28, so we could've used that to add to our network address and
avoided the other math, but it's so much better to know how to do it all
on your own - learn once and use always.


3.4.2.Specifying Ports and Port Ranges

One can also do port-based filtering along with host and
network-based filtering. Ports can be simply specified following the
address of either a source of destination. Port ranges can be specified
with a dash, be comma-separated, or use a bitmask to specify a range. Most
importantly, one can not use the "all" protocol when specifying ports
because not all protocols are port-sensitive.

add 1000 allow tcp from any to 172.16.0.5 25
add 1100 allow tcp from any to 172.16.0.5 1021-1023 
add 1200 allow tcp from any to 172.16.0.5 21,22,23
add 1300 deny udp from any to 192.168.0.5 1024:8

In the first rule all TCP packets which are destined for port 25
on 172.16.0.5 are matched. In the second rule, all TCP packets which are
destined for ports 1021 through 1023, inclusive, on host 172.16.0.5 are
matched. In the third rule, all TCP packets which are destined for ports
21, 22 or 23 on host 172.15.0.5 are matched; and finally, in the fourth
rule, all UDP packets which are destined for ports 1024 through 1028 on
host 172.16.0.5 are matched. The last rule can be tricky as it uses a
bitmask on the port to make matches. The port 1024 contains 10 bits. The
bitmask indicates that all hosts matching the last 8 bits on that port,
destined for host 192.168.0.5, are matched. 10 - 8 gives one 2 bits which
can be anything. 2^2 = 4, so we have 4 port numbers, starting with 1024,
that can be the destination ports for packets aiming for that host, and
will result in a match.

Bitmasks for ports are rarely used and are even trickier than
bitmasks or netmasks for IP addresses, because the number of bits in a
port varies depending on the port specified before the mask. As such, it
is recommended that one stick to specifying port ranges with a dash ( -
) or separate the list of ports with commas.


4.Advanced ipfw(8) Rule Syntax

Although the above overview of ipfw(8) rule creation will cover
many of the simple scenarios, it sorely falls short for many more complex
situations, such as when a system has more than one network interface, one
wishes to make special responces to certain matches, or one wants more
control over the direction of traffic flow. We will first expand the
template for the ipfw(8) syntax to the follow:

<command> [<rule #>] <action> [log [logamount <number>]] <proto>
from <source> to <destination> [<interface-spec>] [<options>]

Everything in brackets comprises new functionality we will discuss
in this section. We will also cover an additional "action" that was not
covered earlier. The syntax may suddenly seem daunting, but we will take
it slowly, and add each part as we go along, so as not to overwhelm you.


4.1."unreach" Action

Firstly, we will introduce a new "action:"

"unreach <code>" - Any packet which matches a rule with this
action will reply with an ICMP unreach code, after which time the ruleset
search will terminate. The possible unreach codes can be indicated by
number or name. The following is a quick list of ICMP unreach codes and
corresponding names. If you don't know what these are used for, you won't
have a reason to use them:

net0net-prohib9
host1host-prohib10
protocol2tosnet11
port3toshost12
needfrag4filter-prohib13
srcfail5host-precedence14
net-unknown6precedence-cutoff15
host-unknown7
isolated8


4.2.Interface and Flow Control

One important functionality missing from the basic description of
ipfw(8) syntax in part 3 was interface and flow control; that is, the
ability to match packets according to which interface (if you have a
multihomed system) packets are moving through, and in which direction
they're moving. Up until now, direction was only loosely gauged by using
the source and destination addresses, but using just them to guesstimate
whether a packet is really coming or going when it moves through the
firewall is unreliable. If you wish to match packets only coming in or
going out, the keywords "in" and "out" can be used. Both correspond to the
"interface-spec" area of the syntax template given earlier, and therefore,
are placed near the end of every rule, prior to any posible options. For
instance, if we wish to match all packets coming in from anywhere and
going anywhere, we could have:

add 1000 allow all from any to any in

To match packets going through a particular interface, use the
"via" option followed by the interface name. For instance, if you are
using a PCI 3Com 3c59x, then your interface device will be xl0. To match
all packets coming in through that interface specifically, sourced from
anywhere and destined anywhere, the following would suffice:

add 1100 allow all from any to any in via xl0

Or, perhaps, if one has a multihomed system and wishes to match
any packets coming from anywhere and going anywhere at least moving
outside through *some* interface, he can do the following:

add 1200 allow all from any to any out via any

One will notice, when listing firewall rules, that when using
either "in" or "out" in combination with "via" the rule as it actually
looks does not contain a "via" but either "recv" or "xmit," depending on
whether an "in" or "out" was specified, respectively. For instance:

(root@nu)~># ipfw add 7000 allow all from any to any out via xl0
(root@nu)~># ipfw list | grep 7000
07000 allow ip from any to any out xmit xl0
(root@nu)~>#

Indeed, one can use either "recv" or "xmit" in place of "via" when using
"in" or "out," however, doing so is not required, and can add to some
confusion for the newcomer.

In all, these options allow a lot more control over network
traffic on a multihomed system and any system in general, by allowing one
to filter packets specifically coming into the firewall, exiting it, and
moving through a specified interface.


4.3.Matching specific ICMP and TCP Packet Types

ICMP, TCP, and IP packets come in various types. These types are
defined by the various flags that each of those packets sets. We can match
each of those types by using one of the following ipfw(8) options at the
end of our rules.


4.3.1.icmptypes

"icmptypes <type>" - This will match the specified ICMP packet
<type>, and conversely, if a '!' is put before the <type> then all ICMP
packets that are not of this type are match. There are currently 15
different ICMP packet types that can be matched; each is specified by the
correct number. Ranges can be specified with dashes or be comma-separated.
The 15 possible ICMP types are:

0-Echo Reply
3-Destination Unreachable
4-Source Quench
5-Redirect
8-Echo Request
9-Router Advertisement
10-Router Silicitation
11-Time-to-Live Exceeded
12-IP header bad
13-Timestamp Request
14-Timestamp Reply
15-Information Request
16-Information Reply
17-Address Mask Request
18-Address Mask Reply

If one is curious how these ICMP type, specifically type 3,
correspond with the Unreach codes that can be generated with the "unreach"
action, then, simply type 3 matches any of those Unreach codes. Filtering
ICMP packet types can be very useful for controlling ping; specifically,
for allowing internal hosts to ping out while blocking outside hosts from
pinging the gateway or any other host. The following three rules can
accomplish this easily:

1000 allow icmp from any to any out icmptypes 8
1100 allow icmp from any to any in icmptypes 0
1200 deny icmp from any to any in icmptypes 8

The first rule allows all icmp packets of type 8 (echo request) to
go out. The second rule allows all icmp packets of type 0 (echo reply) in,
and the final rule blocks all icmp packets of type 8 from entering. In
short, it allows echo requests to go out and echo replies to come in, but
blocks echo requests from coming in. As such, hosts behind the firewall
can ping anyone on the outside, while hosts on the outside can't ping
anyone behind the firewall. Naturally, this option can only be specified
when the indicated procotol is "icmp."


4.3.2.tcpflags, setup and established

"tcpflags <flag>" - This will match any TCP packet whose header
contains one of the following flags, or conversely, if '!' is presented
before the <flag>, match all TCP packets that do not have the <flag> set:

fin-Request for connexion termination
syn-Request for connexion initiation
rst-Reset Connexion
psh-Push Flag
ack-Acknowledgement
urg-Indicate Urgent OOB data

The SYN flag is of most interest as it is sent for initiation of
TCP connecions. Because it is so important, there is a separate
ipfw(8) option dedicated specifically for matching TCP packets with the
SYN flag set. This is called "setup." Naturally, this option can only be
specified when the indicated protocol is "tcp."

"setup" - Any rule containing this option will match any TCP
packet with the SYN flag set. For instance, if we wished to deny all
incoming TCP SYN packets, we coul issue the following:

add deny tcp from any to any in tcpflags syn

OR

add deny tcp from any to any in setup

On either count, the same action is performed: all TCP SYN packets
from "any" destined to "any" will be matched, and denied. As stated above
for "tcpflags", this option can only be used for rules when the indicated
protocol is "tcp."

"established" - Just as there is a special option for indicating
the request for TCP connexion initiation ("setup") there is a special
option for matching an already established TCP connexion. Because it is of
paramount important to easily control TCP connexions, "established" and
"setup" are available for quick rule formation. Given these options (or
their corresponding "tcpflags" incarnations) we can have some simplistic
control of TCP connexion activity. This is the very base of stateful
firewall functionality, which shall be dealt with in more detail later.


4.3.3.ipoptions

"ipoptions <flag>" - Finally, we can match for some specific IP
packet flags, namely, for SSRR (Strict Source Route), LSRR Loose Source
Route, RR Record Packet Route, and TS (Timestamp) flags. If you do not
know what any of these IP options do then you will not need to match for
them specifically.


4.4.Catching Fragmented Packets

Fragmented packets are matched with the "frag" ipfw(8) option.
Under most circumstances fragmented packets should be blocked. Receiving
many fragmented packets may indicate a DoS (Denial of Service) attack,
although FreeBSD and most other UNIX and UNIX-like systems will not be
phased by such attacks, Windows systems are often quite vulnerable. As
such, if one has one or more Windows systems on their network behind the
firewall, it is avisable to block fragmented packets.

When using the "frag" option to match [and block] fragmented
packets, there are a couple guidelines that must be followed. Firstly, one
can not use the "frag" option when also specifying "tcpflags." Secondly,
one can not use "frag" if also specifying any TCP or UDP ports. Given
these guidelines, we can easily issue a rule to block all incoming
fragmented packets:

add deny all from any to any in frag


4.5.UID and GID Based Filtering

One powerful function that IPFilter does not have is UID/GID-based
filtering. Ipfirewall(4) is able to filter packets according to the UID
and/or the GID of the process from which they are arriving. Naturally,
this can only be used to match packets which originate from processes on
the local host, however, it still offers a powerful functionality. The
options to be used are "uid" and "gid" followed by the UID/GID or name of
the user or group by which we will be filtering.

One potential use is to restrict the use of IP vhosts on a shell
server. If one wants to ensure that one or more vhosts can not be used by
anyone else, one can easily use UID-based filtering to block everyone's
but one's own traffic from that vhost:

add allow tcp from any to 172.16.0.10 in
add allow tcp from 172.16.0.10 to any out uid george
add deny tcp from 172.168.0.10 to any

With the above rules, only user george would be able to use the
aliased IP (IP vhost) 172.168.0.10 to establish TCP connexions to the
outside. No one else would be able to bind bots, IRC chat clients, or what
have you, to that IP and establish connexions with anything that required
TCP (most things). Likewise, the UDP protocol can be used with
UID/GID-based filtering, however, no other protocol can be.

Another possible use of UID/GID-based filtering would be to enable
bandwidth limiting on a per-user basis, as opposed to per-host or
per-network basis. As such, one could, for example, have a group of users
that all have fast FTP accounts, and only moderately limit their GID,
while on the other hand, have another group of shell users, who don't
require much bandwidth, and therefore significantly cap the bandwidth on
the GID they all belong to. Such GID-based bandwidth capping will be
illustrated later, once we cover the traffic shaping facilities of
ipfirewall(8).

For security purposes, one may wish to log the traffic of a
particular user, and here too UID-based filtering would come in handy. In
short, whenever one would wish to conduct firewall behaviour differently
for one or more users, UID/GID-based filtering would come in
handy. Because, in general, once a rule is matched, search through the
ruleset stops, UID/GID matching rules must be invoked before other
sweeping rules can match the traffic. So, when creating one's ruleset, one
must take this into careful account if one wishes to enable UID/GID-based
filtering.

For the next Sections :
  5 - 8  Click Here

Email Us

ghostrdr@defcon1.org

This site cannot be duplicated without permission

© 1998 - 2010 Defcon1, www.defcon1.org. Copyrights for all materials on this web site are held by the individual authors, artists, photographers or creators. Materials may not be reproduced or otherwise distributed without permission of www.defcon1.org and the content's original author.