--- chapter.sgml.ori Tue Nov 14 23:43:29 2006
+++ chapter.sgml Tue Nov 14 23:47:55 2006
@@ -399,6 +399,1441 @@
firewall. Do not forget to check the mailing list archives
before asking questions.
+
+ A PF rule sets and tools
+ This section walks you through some useful PF features and
+ PF related tools in a series of examples. A more thorough
+ tutorial is available at http://home.nuug.no/~peter/pf/.
+
+ The simplest rule set ever
+
+ The simplest possible setup is for a single machine
+ which will not run any services, and which will talk to one
+ network which may be the Internet. A minimal
+ /etc/pf.conf looks like this:
+
+
+ block in all
+ pass out all keep state
+
+
+ Here we deny any incoming traffic, allow traffic we make
+ ourselves to pass, and retain state information on our
+ connections. Keeping state information allows return traffic
+ for all connections we have initiated to pass back to us.
+ This is something you do if this is a machine you know you
+ can trust. If you are ready to use the rule set, you load
+ it with
+
+
+ $ sudo pfctl -e ; sudo pfctl -f /etc/pf.conf
+
+
+ Tighter and more elegant
+
+ For a slightly more structured and complete setup, we
+ start by denying everything and then allowing only those
+ things we know that we needYou may ask why
+ do I write the rule set to default deny? The short answer
+ is, it gives you better control at the expense of some
+ thinking. The point of packet filtering is to take
+ control, not to run catch-up with what the bad guys do.
+ Marcus Ranum has written a very entertaining and
+ informative article about this, The
+ Six Dumbest Ideas in Computer Security, and it's
+ well written too. . This gives us the
+ opportunity to introduce two of the features which make PF
+ such a wonderful tool - lists and macros.
+
+
+ We'll make some changes to /etc/pf.conf, starting with
+
+
+ block all
+
+
+ Then we back up a little. Macros need to be defined
+ before use, so at the very top of the file, we add:
+
+
+ tcp_services = "{ ssh, smtp, domain, www, pop3, auth, pop3s }"
+ udp_services = "{ domain }"
+
+
+ Now we've demonstrated several things at once - what
+ macros look like, we've shown that macros may be lists,
+ and that PF understands rules using port names equally
+ well as it does port numbers. The names are the ones
+ listed in /etc/services. This gives
+ us something to put in our rules, which we edit slightly
+ to look like this:
+
+
+ block all
+ pass out proto tcp to any port $tcp_services keep state
+ pass proto udp to any port $udp_services keep state
+
+
+ At this point some of us will point out that UDP is
+ stateless, but PF actually manages to maintain state
+ information despite this. Keeping state for a UDP
+ connection means that for example when you ask a name
+ server about a domain name, you will be able to receive
+ its answer.
+
+
+ Since we've made changes to our
+ pf.conf, we load the new rules:
+
+
+ $
+ sudo
+ pfctl -f
+ /etc/pf.conf
+
+
+ and the new rules apply. If there are no syntax errors,
+ pfctl will not output any
+ messages during the rule load. The -v flag will produce
+ more verbose pfctl output.
+
+
+ If you have made extensive changes to your rule set, you
+ may want to check the rules before attempting to load
+ them. The command to do this is,
+ pfctl -nf
+ /etc/pf.conf. The
+ -n option causes the rules to be
+ interpreted only without loading the rules. This gives
+ you an opportunity to correct any errors. Under any
+ circumstances the last valid rule set loaded will be in
+ force until you either disable PF or load a new rule set.
+
+
+
+
+ A simple gateway with NAT
+
+ To most users, a single machine setup will be of limited
+ interest, and at this point we move on to a more realistic
+ or at least more common setups, where we concentrate on a
+ machine which is running PF and aalso acts as a gateway for
+ at least one other machine.
+
+
+
+ Gateways and the pitfalls of in, out and on
+
+
+ In the single machine setup, life is relatively simple.
+ Traffic you create should either pass or not out to the rest
+ of the world, and you decide what you let in from elsewhere.
+
+
+ When you set up a gateway, your perspective changes. You go
+ from the "me versus the network out there" setting
+ to "I am the one who decides what to pass to or from
+ all the networks I am connected to". The machine has
+ several, or at least two, network interfaces, each connected
+ to a separate net.
+
+
+ Now it's very reasonable to think that if you want traffic
+ to pass from the network connected to
+ xl1 to hosts on the network connected
+ to xl0, you will need a rule like
+
+
+ pass in on xl1 from xl1:network to xl0:network \
+ port $ports keep state
+
+
+ which keeps track of states as well.
+
+
+ However, one of the most common and most complained-about
+ mistakes in firewall configuration is not realizing that the
+ "to" keyword does not in itself guarantee passage
+ all the way there. The rule we just wrote only lets the
+ traffic pass in to the gateway on the internal interface.
+ To let the packets get a bit further you would need a
+ matching rule which says
+
+
+ pass out on xl0 from xl1:network to xl0:network \
+ port $ports keep state
+
+
+ These rules will work, but they will not necessarily achieve what you want.
+
+
+ If there are good reasons why you need to have rules which
+ are this specific in your rule set, you know you need them
+ and why. For the basic gateway configurations we will be
+ dealing with here, what you really want to use is probably a
+ rule which says
+
+
+ pass from xl1:network to any port $ports keep state
+
+
+ to let your local net access the Internet and leave the
+ detective work to the antispoof and
+ scrub code. They are both pretty
+ good these days, and we will get back to them later. For
+ now we just accept the fact that for simple setups,
+ interface bound rules with in/out rules tend to add more
+ clutter than they are worth to your rule sets.
+
+
+ For a busy network admin, a readable rule set is a safer rule set.
+
+
+ For the remainder of this section, with some exceptions, we
+ will keep the rules as simple as possible for readability.
+
+
+
+
+ What is your local network, anyway?
+
+
+ Above we introduced the
+ interface:network notation. That
+ is a nice piece of shorthand, but you make your rule set
+ even more readable and maintainable by taking the macro
+ use a tiny bit further.
+
+
+ You could for example define a
+ $localnet macro, initially defined
+ as the network directly attached to your internal
+ interface ($xl1:network in the
+ examples above).
+
+
+ Alternatively, you could change the definition of
+ $localnet to an IP
+ address/netmask notation to denote a network,
+ such as 192.168.100.1/24 for a
+ subnet of private addresses.
+
+
+ If your network requires it, you could even define your
+ $localnet as a list of networks.
+ Whatever your specific needs, a sensible
+ $localnet definition and a typical
+ pass rule of the type
+
+
+ pass from $localnet to any port $ports keep state
+
+
+ could end up saving you a few headaches. We will stick to that convention from here on.
+
+
+
+
+ Setting up
+
+
+ We assume that the machine has acquired another network
+ card or at any rate you have set up a network connection
+ from your local network, via PPP or other means. We will
+ not consider the specific interface configurations.
+
+
+ For the discussion and examples below, only the interface
+ names will differ between a PPP setup and an Ethernet one,
+ and we will do our best to get rid of the actual interface
+ names as quickly as possible.
+
+
+ First, we need to turn on gatewaying in order to let the
+ machine forward the network traffic it receives on one
+ interface to other networks via a separate interface.
+ Initially we will do this on the command line with
+ sysctl, for traditional
+ IP version four
+
+
+ # sysctl net.inet.ip.forwarding=1
+
+
+ and if we need to forward IP version six traffic, the command is
+
+
+ # sysctl net.inet6.ip6.forwarding=1
+
+
+ In order for this to work once you reboot the computer at
+ some time in the future, you need to enter these settings
+ into your /etc/rc.conf file:
+
+
+ gateway_enable="YES" #for ipv4
+ ipv6_gateway_enable="YES" #for ipv6
+
+
+ Are both of the interfaces you intend to use up and running? Use
+ ifconfig -a, or ifconfig
+ interface_name to find out.
+
+
+ If you still intend to allow any traffic initiated by
+ machines on the inside, your
+ /etc/pf.conf could look roughly like
+ this For dialup users, the external
+ interface is the tun0 pseudo-device.
+ Broadband users such as ADSL subscribers tend to have an
+ Ethernet interface to play with, however for a significant
+ subset of ADSL users, specifically those using PPP over
+ Ethernet (PPPoE), the correct external interface will be
+ the tun0 pseudo-device, not the
+ physical Ethernet interface. :
+
+
+ ext_if = "xl0" # macro for external interface - use tun0 for PPPoE
+ int_if = "xl1" # macro for internal interface
+ localnet = $int_if:network
+ # ext_if IP address could be dynamic, hence ($ext_if)
+ nat on $ext_if from $localnet to any -> ($ext_if)
+ block all
+ pass from { lo0, $localnet } to any keep state
+
+
+ Note the use of macros to assign logical names to the
+ network interfaces. Here 3Com cards are used, but this is
+ the last time during this lecture we will find this of any
+ interest whatsoever. In truly simple setups like this one,
+ we may not gain very much by using macros like these, but
+ once the rule sets grow somewhat larger, you will learn to
+ appreciate the readability this adds to the rule sets
+
+
+ Also note the nat rule. This is where we handle the
+ network address translation from the non-routable address
+ inside your local net to the sole official address we
+ assume has been assigned to you.
+
+
+ The parentheses surrounding the last part of the nat rule
+ ($ext_if) are there to compensate
+ for the possibility that the IP address of the external
+ interface may be dynamically assigned. This detail will
+ ensure that your network traffic runs without serious
+ interruptions even if the external IP address changes.
+
+
+ On the other hand, this rule set probably allows more
+ traffic than what you actually want to pass out of your
+ network. One reasonable setup could contain the macro
+
+
+ client_out = "{ ftp-data, ftp, ssh, domain, pop3, auth, nntp, http,\
+ https, cvspserver, 2628, 5999, 8000, 8080 }"
+
+
+ and the main pass rule
+
+
+ pass inet proto tcp from $localnet to any port $client_out \
+ flags S/SA keep state
+
+
+ This may be a somewhat peculiar selection of ports, but it
+ is based on a real life example. Your needs probably
+ differ at least in some specifics, but this should cover
+ at least some of the more useful services.
+
+
+ In addition, we have a few other pass rules. We will be
+ returning to some of the more interesting ones rather
+ soon. One pass rule which is useful to those of us who
+ want the ability to administer our machines from elsewhere
+ is
+
+
+ pass in inet proto tcp from any to any port ssh
+
+
+ or for that matter
+
+
+ pass in inet proto tcp from any to $ext_if port ssh
+
+
+ whichever you like. Lastly we need to make the name service work for our clients
+
+
+ udp_services = "{ domain, ntp }"
+
+
+ supplemented with a rule which passes the traffic we want through our firewall:
+
+
+ pass quick inet proto { tcp, udp } to any port $udp_services keep state
+
+
+ Note the quick keyword in this rule.
+ We have started writing rule sets which consist of several
+ rules, and it is time to take a look at the relationships
+ between the rules in a rule set. The rules are evaluated
+ from top to bottom, in the sequence they are written in
+ the configuration file. For each packet or connection
+ evaluated by PF, the last matching
+ rule in the rule set is the one which is
+ applied. The quick keyword offers an
+ escape from the ordinary sequence. When a packet matches
+ a quick rule, the packet is treated according to the
+ present rule. The rule processing stops without
+ considering any further rules which might have matched the
+ packet. This is very useful when you need a few isolated
+ exceptions to your general rules.
+
+
+ This also takes care of ntp, which is used for time
+ synchronization. One thing common to both protocols is
+ that they may under certain circumstances communicate
+ alternately over TCP and UDP.
+
+
+
+
+
+ That sad old FTP thing
+
+
+ The short list of real life TCP ports above contained, among
+ other things, FTP. FTP is a sad old thing and a problem
+ child, emphatically so for anyone trying to combine FTP and
+ firewalls. FTP is an old and weird protocol, with a lot to
+ not like. The most common points against it, are
+
+
+
+
+ Passwords are transferred in the clear
+
+
+
+
+ The protocol demands the use of at least two TCP connections (control
+ and data) on separate ports
+
+
+
+
+ When a session is established, data is communicated via ports selected
+ at random
+
+
+
+
+ All of these points make for challenges security-wise, even
+ before considering any potential weaknesses in client or
+ server software which may lead to security issues. These
+ things have tended to happen.
+
+
+ Under any circumstances, other more modern and more secure
+ options for file transfer exist, such as
+ sftp or
+ scp, which feature both
+ authentication and data transfer via encrypted connections.
+ Competent IT professionals should have a preference for some
+ other form of file transfer than FTP.
+
+
+ Regardless of our professionalism and preferences, we are
+ all too aware that at times we will need to handle things we
+ would prefer not to. In the case of FTP through firewalls,
+ the main part of our handling consists of redirecting the
+ traffic to a small program which is written specifically for
+ this purpose.
+
+
+ Depending on your configuration, which operating system you
+ are using as the platform for your PF firewall and how you
+ count them, three or four different options are available
+ for this particular task.
+
+
+ We will present them in roughly chronological order
+ according to their ages. The original FTP proxy for PF is
+ described below in . We then move
+ on to two newer, solutions developed by Camiel
+ Dobbelaar in .
+
+
+
+ FTP through NAT: ftp-proxy
+
+
+ ftp-proxy is a part of the base
+ system on &os; and other systems which offer PF, and is
+ usually called via the inetd
+ "super server" via an appropriate
+ /etc/inetd.conf entry.
+
+
+ The line quoted here specifies that
+ ftp-proxy runs in NAT mode on
+ the loopback interface, lo0:
+
+
+ 127.0.0.1:8021 stream tcp nowait root /usr/libexec/ftp-proxy \
+ ftp-proxy -n
+
+
+ This line is by default in your
+ inetd.conf, commented out with a
+ # character at the beginning of the
+ line. To enable your change, you restart
+ inetd with the command
+
+
+ $ sudo /etc/rc.d/inetd restart
+
+
+ or equivalent. Consult man 8 inetd if you are unsure.
+
+
+ Now for the actual redirection. Redirection rules and NAT
+ rules fall into the same rule class. These rules may be
+ referenced directly by other rules, and filtering rules
+ may depend on these rules. Logically, rdr and nat rules
+ need to be defined before the filtering rules.
+
+
+ We insert our rdr rule immediately after the nat rule in our /etc/pf.conf
+
+
+ rdr on $int_if proto tcp from any to any port ftp -> 127.0.0.1 \
+ port 8021
+
+
+ In addition, the redirected traffic must be allowed to pass. We achive this with
+
+
+ pass in on $ext_if inet proto tcp from port ftp-data to ($ext_if) \
+ user proxy flags S/SA keep state
+
+
+ Save pf.conf, then load the new rules with
+
+
+ $ sudo pfctl -f /etc/pf.conf
+
+
+ At this point you will probably have users noticing that FTP works before
+ you get around to telling them what you've done.
+
+
+ This example assumes you are using NAT on a gateway with
+ non routable addresses on the inside.
+
+
+
+
+ FTP, PF and routable addresses: ftpsesame and pftpx
+
+
+ In cases where the local network uses official, routable
+ address inside the firewall, some users report
+ difficulties in making
+ ftp-proxy work properly. Two
+ alternative applications are available through the ports
+ system which may be appropriate in some
+ configurations.
+
+
+ ftpsesame, written by Camiel
+ Dobbelaar, is available through the ports system as
+ /usr/ports/ftp/ftpsesame.
+
+
+ Once installed and running,
+ ftpsesame hooks into your rule
+ set via an anchor, a named sub-ruleset. The documentation
+ consists of a man page with examples which you can more
+ likely than not simply copy and paste.
+
+
+ The other solution, also written by Camiel Dobbellar, is
+ pftpx, available through the
+ &os; ports system as
+ /usr/ports/ftp/pftpx.
+ pftpx comes with a fairly
+ complete and well written man page to get you
+ started.
+
+
+ A further developed version, suitably renamed as the new
+ ftp-proxy, is now part of
+ OpenBSD since release 3.9 as
+ /usr/sbin/ftp-proxy, and is likely to
+ make it into the &os; base system in the near future.
+
+
+
+ Easing Troubleshooting
+
+ Making your network troubleshooting friendly is a
+ potentially large subject. At most times, the debugging or
+ troubleshooting friendliness of your TCP/IP network depends
+ on how you treat the Internet protocol which was designed
+ specifically with debugging in mind, the Internet
+ Control Message Protocol, or
+ ICMP as it is usually abbreviated.
+
+
+ ICMP is the protocol for sending and receiving
+ control messages between hosts and
+ gateways, mainly to provide feedback to a sender about any
+ unusual or difficult conditions en route to the target host.
+
+
+ There is a lot of ICMP traffic which usually just happens in
+ the background while you are surfing the web, reading mail
+ or transferring files. Routers use ICMP to negotiate packet
+ sizes and other transmission parameters in a process often
+ referred to as path MTU discovery.
+
+
+ You may have heard admins referring to ICMP as either 'just
+ evil', or, if their understanding runs a little deeper, 'a
+ necessary evil'. The reason for this attitude is purely
+ historical. The reason can be found a few years back when it
+ was discovered that several operating systems contained code
+ in their networking stack which could make a machine running
+ one of the affected systems crash and fall over, or in some
+ cases just do really strange things, with a sufficiently
+ large ICMP request.
+
+
+ One of the companies which was hit hard by this was
+ Microsoft, and you can find rather a lot of material on the
+ 'ping of death' bug by using your favourite search engine.
+ This all happened in the second half of the 1990s, and all
+ modern operating systems, at least the ones we can read,
+ have thoroughly sanitized their network code since then. At
+ least that's what we are lead to believe.
+
+
+ One of the early workarounds was to simply block either all
+ ICMP traffic or at least ICMP ECHO, which is what ping uses.
+ Now these rule sets have been around for roughly ten years,
+ and the people who put them there are still scared.
+
+
+
+ Then, do we let it all through?
+
+
+ The obvious question then becomes, if ICMP is such a good
+ and useful thing, should we not let it all through, all
+ the time? The answer is, 'It depends'.
+
+
+ Letting diagnostic traffic pass unconditionally of course
+ makes debugging easier, but it also makes it relatively
+ easy for others to extract information about your network.
+ That means that a rule like
+
+
+ pass inet proto icmp from any to any
+
+
+ might not be optimal if you want to cloak the internal
+ workings of your network in a bit of mystery. In all
+ fairness it should also be said that you might find some
+ ICMP traffic quite harmlessly riding piggyback on your
+ keep state rules.
+
+
+
+
+ The easy way out: The buck stops here
+
+
+ The easiest solution could very well be to let all ICMP
+ traffic from your local net through and let probes from
+ elsewhere stop at your gateway:
+
+
+ pass inet proto icmp icmp-type $icmp_types from $localnet \
+ to any keep state
+ pass inet proto icmp icmp-type $icmp_types from any to $ext_if \
+ keep state
+
+
+ Stopping probes at the gateway might be an attractive
+ option anyway, but let us have a look at a few other
+ options which will show you some of PF's flexibility.
+
+
+
+
+
+ Letting ping through
+
+
+ The rule set we have developed so far has one clear
+ disadvantage: common troubleshooting commands such as
+ ping and
+ traceroute will not work. That
+ may not matter too much to your users, and since it was
+ the ping command which scared
+ people into filtering or blocking ICMP traffic in the
+ first place, there are apparently some people who feel we
+ are better off without it. If you are in my perceived
+ target audience, you will be rather fond of having those
+ troubleshooting tools avalable. With a couple of small
+ additions to the rule set, they will be.
+ ping uses ICMP, and in order to
+ keep our rule set tidy, we start by defining another
+ macro:
+
+
+ icmp_types = "echoreq"
+
+
+ and a rule which uses the definition,
+
+
+ pass inet proto icmp all icmp-type $icmp_types keep state
+
+
+ You may need more or other types of ICMP packets to go
+ through, and you can then expand
+ icmp_types to a list of those
+ packet types you want to allow.
+
+
+
+
+ Helping traceroute
+
+
+ traceroute is another command
+ which is quite useful when your users claim that the
+ Internet isn't working. By default, Unix
+ traceroute uses UDP connections
+ according to a set formula based on destination. The rule
+ below works with the traceroute
+ command on all unixes I've had access to, including
+ GNU/Linux:
+
+
+ # allow out the default range for traceroute(8):
+ # "base+nhops*nqueries-1" (33434+64*3-1)
+ pass out on $ext_if inet proto udp from any to any \
+ port 33433 >< 33626 keep state
+
+
+ Experience so far indicates that
+ traceroute implementations on
+ other operating systems work roughly the same. Except, of
+ course, Microsoft Windows. On that platform,
+ TRACERT.EXE uses ICMP ECHO for this
+ purpose. So if you want to let Windows traceroutes
+ through, you only need the first rule. Unix
+ traceroutes can be instructed
+ to use other protocols as well, and will behave remarkably
+ like its Microsoft counterpart if you use its
+ -I command line option. You can
+ check the traceroute man page
+ (or its source code, for that matter) for all the details.
+
+
+ Under any circumstances, this solution was lifted from an
+ openbsd-misc post. I've found that list, and the
+ searchable list archives (accessible among other places
+ from http://marc.theaimsgroup.com/),
+ to be a very valuable resource whenever you need OpenBSD
+ or PF related information.
+
+
+
+
+ Path MTU discovery
+
+
+ Internet protocols are designed to be device independent,
+ and one consequence of device independence is that you can
+ not always predict reliably what the optimal packet size
+ is for a given connection. The main constraint on your
+ packet size is called the Maximum Transmission
+ Unit, or MTU, which
+ sets the upper limit on the packet size for an interface.
+ The ifconfig command will show
+ you the MTU for your network interfaces.
+
+
+ The way modern TCP/IP implementations work, they expect to
+ be able to determine the right packet size for a
+ connection through a process which simply puts involves
+ sending packets of varying sizes with the 'Do not
+ fragment' flag set, expecting an ICMP return packet
+ indicating "type 3, code 4", when the upper limit has been
+ reached. Now you don't need to dive for the RFCs right
+ away. Type 3 means "destination unreachable", while code
+ 4 is short for "fragmentation needed, but the do not
+ fragment flag is set". So if your connections to networks
+ which may have other MTUs than your own seem sub-optimal,
+ and you do not need to be that specific, you could try
+ changing your list of ICMP types slightly to let the
+ Destination unreachable packets through, too:
+
+
+ icmp_types = "{ echoreq, unreach }"
+
+
+ as we can see, this means we do not need to change the pass rule itself:
+
+
+ pass inet proto icmp all icmp-type $icmp_types keep state
+
+
+ PF lets you filter on all variations of ICMP types and
+ codes, and if you want to delve into what to pass and not
+ of ICMP traffic, the list of possible types and codes are
+ documented in the icmp(4) and icmp6(4) man pages. The
+ background information is available in the RFCs
+
+ The main internet RFCs describing ICMP and some
+ related techhiques are RFC792, RFC950, RFC1191,
+ RFC1256, RFC2521, rfc2765, while necessary updates for
+ ICMP for IPv6 are found in RFC1885, RFC2463, RFC2466.
+ These documents are available in a number of places on
+ the net, such as the ietf.org and faqs.org web
+ sites.
+
+ .
+
+
+
+
+ Tables make your life easier
+
+ By this time you may be thinking that this gets awfully
+ static and rigid. There will after all be some kinds of
+ data which are relevant to filtering and redirection at a
+ given time, but do not deserve to be put into a
+ configuration file! Quite right, and PF offers mechanisms
+ for handling these situations as well. Tables are one such
+ feature, mainly useful as lists which can be manipulated
+ without needing to reload the entire rule set, and where
+ fast lookups are desirable. Table names are always enclosed
+ in < >, like this:
+
+
+ table <clients> { 192.168.2.0/24, !192.168.2.5 }
+
+
+ here, the network 192.168.2.0/24 is
+ part of the table, except the address
+ 192.168.2.5, which is excluded using
+ the ! operator (logical NOT). It is also possible to load
+ tables from files where each item is on a separate line,
+ such as the file /etc/clients
+
+
+ 192.168.2.0/24
+ !192.168.2.5
+
+
+ which in turn is used to initialize the table in /etc/pf.conf:
+
+
+ table <clients> persist file /etc/clients
+
+
+ Then, for example, you can change one of our earlier rules to read
+
+
+ pass inet proto tcp from <clients> to any port $client_out \
+ flags S/SA keep state
+
+
+ to manage outgoing traffic from your client computers. With
+ this in hand, you can manipulate the table's contents live,
+ such as
+
+
+ $ sudo pfctl -t clients -T add 192.168.1/16
+
+
+ Note that this changes the in-memory copy of the table only,
+ meaning that the change will not survive a power failure or
+ other reboot unless you arrange to store your changes.
+
+
+ You might opt to maintain the on-disk copy of the table
+ using a cron job which dumps the table content to disk at
+ regular intervals, using a command such as pfctl
+ -t clients -T show >/etc/clients.
+ Alternatively, you could edit the
+ /etc/clients file and replace the
+ in-memory table contents with the file data:
+
+
+ $ sudo pfctl -t clients -T replace -f /etc/clients
+
+
+ For operations you will be performing frequently, you will
+ sooner or later end up writing shell scripts for tasks such
+ as inserting or removing items or replacing table
+ contents. The only real limitations lie in your own needs
+ and your creativity.
+
+
+
+ Overload tables
+
+ If you run a Secure Shell login service anywhere which is
+ accessible from the Internet, you have probably seed something
+ like this in your authentication logs:
+
+
+
+ Sep 26 03:12:34 skapet sshd[25771]: Failed password for root from
+ 200.72.41.31 port 40992 ssh2
+ Sep 26 03:12:34 skapet sshd[5279]: Failed password for root from
+ 200.72.41.31 port 40992 ssh2
+ Sep 26 03:12:35 skapet sshd[5279]: Received disconnect from
+ 200.72.41.31: 11: Bye Bye
+ Sep 26 03:12:44 skapet sshd[29635]: Invalid user admin from
+ 200.72.41.31
+ Sep 26 03:12:44 skapet sshd[24703]: input_userauth_request:
+ invalid user admin
+ Sep 26 03:12:44 skapet sshd[24703]: Failed password for invalid user
+ admin from 200.72.41.31 port 41484 ssh2
+
+
+ And so on. This is what a brute force attack looks like.
+ Essentially somebody, or more likely, a cracked computer
+ somewhere, is trying by brute force to find a combination of
+ user name and password which will let them into your system.
+
+
+ The simplest response would be to write a
+ pf.conf rule which blocks all access.
+ This leads to another class of problems, including what you
+ do in order to let people with legitimate business on your
+ system access it anyway. You might consider moving the
+ service to some other port, but then again, the ones
+ flooding you on port 22 would probably be able to scan their
+ way to port 22222 for a repeat performance.
+
+
+ Since OpenBSD 3.7, and soon after in &os; version 6.0, PF
+ has offered a slightly more elegant solution. You can write
+ your pass rules so they maintain certain limits on what
+ connecting hosts can do. For good measure, you can banish
+ violators to a table of addresses which you deny some or all
+ access. You can even choose to drop all existing
+ connections from machines which overreach your limits, if
+ you like. Here's how it's done:
+
+
+ First, you set up the table. In your tables section, add
+
+
+ table <bruteforce> persist
+
+
+ Then somewhere fairly early in your rule set you set up to
+ block from the bruteforcers
+
+
+ block quick from <bruteforce>
+
+
+ And finally, your pass rule.
+
+
+ pass inet proto tcp from any to $localnet port $tcp_services \
+ flags S/SA keep state \
+ (max-src-conn 100, max-src-conn-rate 15/5, \
+ overload <bruteforce> flush global)
+
+
+ The first part here is identical to the main rule we
+ constructed earlier. The part in brackets is the new stuff
+ which will ease your network load even further.
+
+
+ max-src-conn is the number of
+ simultaneous connections you allow from one host. In this
+ example, I've set it at 100, in your setup you may want a
+ slightly higher or lower value.
+
+
+ max-src-conn-rate is the rate of new
+ connections allowed from any single host, here 15
+ connections per 5 seconds. Again, you are the one to judge
+ what suits your setup.
+
+
+ overload
+ <bruteforce> means
+ that any host which exceeds these limits gets its address
+ added to the table
+ bruteforce. Our rule set
+ blocks all traffic from addresses in the bruteforce table.
+
+
+ finally, flush
+ global says that when a host reaches
+ the limit, that host's connections will be terminated
+ (flushed). The global part says that for good measure, this
+ applies to connections which match other pass rules too.
+
+
+ The effect is dramatic. From here on, bruteforcers more
+ often than not will end up with "Fatal:
+ timeout before authentication"
+ messages, getting nowhere.
+
+
+ Once again, please keep in mind that this example rule is
+ intended mainly as an illustration. It is not unlikely that
+ your network's needs are better served by rather different
+ rules or combinations of rules.
+
+
+ If, for example, you want to allow a generous number of
+ connections in general, but would like to be a little more
+ tight fisted when it comes to
+ ssh, you could supplement the
+ rule above with something like the one below, early on in
+ your rule set:
+
+
+ pass quick proto { tcp, udp } from any to any port ssh \
+ flags S/SA keep state \
+ (max-src-conn 15, max-src-conn-rate 5/3, \
+ overload <bruteforce> flush global)
+
+
+ You should be able to find the set of parameters which is
+ just right for your situation by reading the relevant man
+ pages and the PF
+ User Guide, and perhaps a bit of experimentation.
+
+
+
+ You may not need to block all of your overloaders
+
+
+ It is probably worth noting at this point that the
+ overload mechanism is a general
+ technique which does not have to apply exclusively to the
+ ssh service, and it is not
+ necessarily always optimal to block all traffic from
+ offenders entirely.
+
+
+ You could for example use an overload rule to protect a
+ mail service or a web service, and you could use the
+ overload table in a rule to assign offenders to a queue
+ with a minimal bandwidth allocationor, in the web case, to
+ redirect to a specific web page.
+
+
+
+ The expiretable tool
+
+ At this point, we have tables which will be filled by our
+ overload rules, and since we could
+ reasonably expect our gateways to have months of uptime,
+ the tables will grow incrementally, taking up more memory
+ as time goes by.
+
+
+ You could also find that an IP address you blocked last
+ week due to a brute force attack was in fact a dynamically
+ assigned one, which is now assigned to a different ISP
+ customer who has a legitimate reason to try communicating
+ with hosts in your network.
+
+
+ Situations like these were what caused Henrik Gustafsson
+ to write expiretable, which
+ removes table entries which have not been accessed for a
+ specified period of time.
+
+
+ One useful example is to use the
+ expiretable program as a way of
+ removing outdated
+ <bruteforce> table entries.
+
+
+ You could for example let
+ expiretable remove
+ <bruteforce> table entries
+ older than 24 hours by adding an entry containing the
+ following to your /etc/rc.local file:
+
+
+ /usr/local/sbin/expiretable -v -d -t 24h bruteforce
+
+
+ expiretable is in the ports
+ tree on &os; as
+ /usr/ports/security/expiretable.
+
+
+
+
+
+ Other PF tools
+ Over time, a number of tools have been developed which interact with PF in various ways.
+
+ The pftop traffic viewer
+
+ If you are interested in keeping an eye on what passes in
+ to and out of your network, Can Erkin Acar's
+ pftop is a for you.
+ pftop is available through the
+ prots system as
+ /usr/ports/sysutils/pftop. The name
+ is a strong hint at what it does -
+ pftop shows a running snapshot
+ of your traffic in a format which is strongly inspired by
+ top(1).
+
+
+
+ The spamd spam deferral daemon
+
+ Not to be confused with the
+ spamd deamon which comes
+ bundled with spamassassin, the
+ PF companion spamd was designed
+ to run on your PF gateway to form part of your outer
+ defense against spam. spamd
+ hooks into your PF configuration via a set of redirections.
+
+
+ The main point underlying the
+ spamd design is the fact that
+ spammers send a large number of messages, and the
+ probability that you are the first person receiving a
+ particular message is incredibly small. In addition, spam
+ is mainly sent via a few spammer friendly networks and a
+ large number of hijacked machines. Both the individual
+ messages and the machines will be reported to blacklists
+ fairly quickly, and this is kind of data
+ spamd uses to our advantage via the use of blacklists.
+
+
+ What spamd does to SMTP
+ connections from addresses in the blacklist is to present
+ its banner and immediately switch to a mode where it
+ answers SMTP traffic 1 byte at the time. This technique,
+ which is intended to waste as much time as possible on the
+ sending end while costing the receiver pretty much
+ nothing, is called tarpitting. The
+ specific implementation with 1 byte SMTP replies is often
+ referred to as stuttering.
+
+
+ A basic blacklisting spamd
+
+ Here is the basic procedure for setting up
+ spamd with automatically
+ updated blacklists:
+
+
+
+
+ Install the
+ /usr/ports/mail/spamd/ port. In
+ particular, make sure you read the package message and
+ act upon what it says. Specifically, to use
+ spamd's greylisting
+ features, you need to have a file descriptor file
+ system (see fdescfs(5))
+ mounted at /dev/fd/. You do this
+ by adding the following line to your
+ /etc/fstab:
+
+ fdescfs /dev/fd fdescfs rw 0 0
+
+
+ and making sure the fdescfs code
+ is in your kernel, either compiled in or by loading
+ the module via the appropriate
+ kldload command.
+
+
+
+
+ Next, you edit your rule set to include
+
+
+ table <spamd> persist
+ table <spamd-white> persist
+ rdr pass on $ext_if inet proto tcp from <spamd> to \
+ { $ext_if, $localnet } port smtp -> 127.0.0.1 port 8025
+ rdr pass on $ext_if inet proto tcp from !<spamd-white> to \
+ { $ext_if, $localnet } port smtp -> 127.0.0.1 port 8025
+
+
+ The two tables <spamd> and <spamd-white>
+ are essential. SMTP traffic from the addresses in the
+ first table plus the ones which are not in the other
+ table are redirected to a daemon listening at port
+ 8025.
+
+
+
+
+ The next step is to set up
+ spamd's own configuration
+ in /usr/local/etc/spamd.confsupplemented by rc.conf parameters.
+
+
+ The supplied sample file offers quite a bit of
+ explanation, and the man page offers additional
+ information, but we will recap the essentials here.
+
+
+ One of the first lines without a
+ # comment sign at the start
+ contains the block which defines the
+ all list, which specifies the
+ lists you actually use:
+
+
+ all:\
+ :traplist:whitelist:
+
+
+ Here you add all black lists you want to use,
+ separated by colons (:). If you want to use
+ whitelists to subtract addresses from your blacklist,
+ you add the name of the whitelist immediately after
+ the name of each blacklist, ie
+ :blacklist:whitelist:.
+
+
+ Next up is a blacklist definition:
+
+
+ traplist:\
+ :black:\
+ :msg="SPAM. Your address %A has sent spam within the last 24 hours":\
+ :method=http:\
+ :file=www.openbsd.org/spamd/traplist.gz
+
+
+ Following the name, the first data field specifies the
+ list type, in this case black.
+ The msg field contains the
+ message to display to blacklisted senders during the
+ SMTP dialogue. The method
+ field specifies how spamd-setup fetches the list data,
+ here http. The other options
+ are fetching via ftp, from a
+ file in a mounted file system
+ or via exec of an external
+ program. Finally the file
+ field specifies the name of the file spamd expects to
+ receive.
+
+
+ The definition of a whitelist follows much the same pattern:
+
+
+ whitelist:\
+ :white:\
+ :method=file:\
+ :file=/var/mail/whitelist.txt
+
+
+ but omits the message parameters since a message is not needed.
+
+
+
+ Choose your data sources with care
+
+
+ If you use all the blacklists in the sample
+ spamd.conf you would end up
+ blacklisting large blocks of the Internet, including
+ several Asian nations. You will need to edit the
+ file to end up with an optimal configuration. You
+ are the judge of which data sources to use, and
+ using other lists than the ones suggested in the
+ sample file is possible.
+
+
+
+ Put the lines for spamd and any startup parameters you
+ want in your /etc/rc.conf, for example
+
+
+ spamd_flags="-v" # for normal use: "" and see spamd-setup(8)
+
+
+ When you are done with editing the setup, you reload
+ your rule set, start spamd
+ with the options you want (using the
+ /usr/local/etc/rc.d/pfspamd.sh
+ script, and complete the configuration using
+ spamd-setup. Finally, you
+ create a cron job which
+ calls spamd-setup to update
+ the tables at reasonable intervals.
+
+
+
+
+ On a typical gateway in front of a mail server, you will
+ soon see hosts getting trapped for anything from a few
+ seconds to several minutes.
+
+
+
+
+ Adding greylisting to your spamd setup
+
+
+ spamd also supports
+ greylisting, which works by
+ rejecting messages from unknown hosts temporarily with 45n
+ codes, letting messages from hosts which try again within
+ a reasonable time through. Traffic from well behaved
+ hosts, that is, senders which are set up to behave within
+ the limits set up in the relevant RFCsThe
+ relevant RFCs are mainly RFC1123 and
+ RFC2821., will be let through.
+
+
+ Greylisting as a technique was presented in a 2003 paper
+ by Evan HarrisThe original Harris paper
+ and a number of other useful articles and resources can
+ be found at the greylisting.org
+ web site., and a number of
+ implementations followed over the next few months.
+ OpenBSD's spamd aquired its
+ ability to greylist in version OpenBSD 3.5, which was
+ released in May 2004.
+
+
+ The most amazing thing about greylisting, apart from its
+ simplicity, is that it still works. Spammers and
+ malware writers have been very slow to adapt.
+
+
+ The basic procedure for adding greylisting to your setup
+ follows below.
+
+
+
+
+ If you have not done so already, make sure you have a file descriptor file
+ system (see fdescfs(5))
+ mounted at /dev/fd/. You do this
+ by adding the following line to your
+ /etc/fstab:
+
+ fdescfs /dev/fd fdescfs rw 0 0
+
+
+ and making sure the fdescfs code
+ is in your kernel, either compiled in or by loading
+ the module via the appropriate
+ kldload command.
+
+
+
+
+ To run spamd in greylisting
+ mode, you need to change your
+ /etc/rc.conf slightly. Mainly,
+ you need the setting
+
+
+ spamd_grey=YES # use spamd greylisting if YES
+
+
+ Note for that you can fine tune several of the
+ greylisting related parameters via
+ spamd command line
+ parameters and the corresponding
+ /etc/rc.conf settings. Check the
+ spamd man page to see
+ what the parameters mean.
+
+
+
+
+ To complete the greylisting setup, restart
+ spamd using the
+ /usr/local/etc/rc.d/pfspamd.sh
+ script.
+
+
+
+
+ Behind the scenes, rarely mentioned and barely
+ documented are two of spamd's
+ helpers, the spamdb database
+ tool and the spamlogd
+ whitelist updater, which both perform essential
+ functions for the greylisting feature. Of the two
+ spamlogd works quietly in the
+ background, while spamdb has
+ been developed to offer some interesting features.
+
+
+
+ Restart spamd to enable greylisting
+
+
+ If you followed all steps in the tutorial exactly up
+ to this point, spamlogd has
+ been started automatically already. However, if your
+ initial spamd configuration
+ did not include greylisting,
+ spamlogd may not have been
+ started, and you may experience strange symptoms, such
+ as your greylists and whitelist not getting updated
+ properly.
+
+
+ Under normal circumstances, you should not have to
+ start spamlogd by hand.
+ Restarting spamd after you
+ have enabled greylisting ensures
+ spamlogd is loaded and
+ available too.
+
+
+
+ spamdb is the administrator's
+ main interface to managing the black, grey and white
+ lists via the contents of the
+ /var/db/spamdb database.
+
+
+
+
+