--- 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: <application>ftp-proxy</application> + + + 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: <application>ftpsesame</application> and <application>pftpx</application> + + + 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 <application>ping</application> 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 <application>traceroute</application> + + + 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 <userinput>block</userinput> all of your <userinput>overload</userinput>ers + + + 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 <application>expiretable</application> 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 <application>pftop</application> 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 <application>spamd</application> 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 <application>spamd</application> + + 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 <application>spamd</application> 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 <application>spamd</application> 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. + + + + +