1. EL PROBLEMA: “LA CONVIVENCIA EN UN AMBIENTE CARENTE DE ARMONÍA”
4.2 MARCO DE REFERENCIA CONCEPTUAL
4.2.1 Comportamiento Social
The first rule set was an extremely simple example, and even though we could use it to demonstrate some basics about how networks and packet filtering work, it is probably too simplistic for practical use. For a slightly more structured and complete setup, we can construct a slightly more realistic example. However, this rule set is still based on the single, stand-alone system that connects to one network.
In this configuration, we’ll start by denying everything and then allowing only those things we know that we need.3 This gives us the opportunity to introduce two of the features that make PF such a wonderful tool: lists and macros.
We’ll make some changes to /etc/pf.conf, starting with
block all
This is a little more restrictive than the first rule set we used. The new rule blocks all traffic in both directions, incoming and outgoing. This is the sensible default and one you will get used to seeing. In all complete rule sets we develop over the next few chapters, this is the baseline filtering rule. Sub- sequent rules will cut your traffic some slack, but before we get to the actual rules, we need to make a few more changes at the very top of the configuration file. We need to define some macros so we can use them later in the rule set:
tcp_services = "{ ssh, smtp, domain, www, pop3, auth, https, pop3s }" udp_services = "{ domain }"
Here we’ve demonstrated several things. You now know what macros look like, and we’ve shown that macros may be lists. You probably also expected to see port numbers by now, but as we have shown here, PF understands rules using service names as well as port numbers. The names are the ones listed in your /etc/services file.
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 pass proto udp to any port $udp_services
NOTE Please remember to add keep state to these rules if your system has a PF version older than OpenBSD 4.1.
3 You may ask why I write the rule set to default deny. The short answer is that it gives you better
control at the expense of some thinking. The point of packet filtering is to take control, not to play catch-up with what the bad guys do. Marcus Ranum has written a very entertaining and informative article about this called “The Six Dumbest Ideas in Computer Security,” which comes highly recommended. It is available at http://www.ranum.com/security/computer_security/
The strings $tcp_services and $udp_services are macro references. Macros are expanded in place when the rule set loads, and the running rule set will have the full lists inserted where the macros are referenced. Macros are extremely good for readability. Even in a small rule set like this, the rules are easier to grasp and maintain than if we had dealt with the full list or port numbers.
This is the point where you pick up the habit of always looking for parts of your rule set that could reasonably be written as macros to help readability. As your rule sets expand, you will be happy that you did.
You may be thinking about how UDP is stateless and connectionless, but PF creates and maintains data equivalent to state information for UDP traffic in order to ensure that UDP return traffic is allowed back in. One common example where state information for UDP is useful is for handling name reso- lution. When you ask a nameserver to resolve a domain name to an IP address or to resolve an IP address back to a hostname, it is quite reasonable to assume that you want to receive the answer. Retaining state information or the func- tional equivalent about your UDP traffic makes this possible.
Since we’ve made changes to our pf.conf file, we must load the new rules:
$ sudo pfctl -f /etc/pf.conf
If there are no syntax errors, pfctl will not output any messages during the rule load.
It is worth noting that you can use the -v flag to produce more verbose pfctl output:
$ sudo pfctl -vf /etc/pf.conf
In this specific case it probably will not make a difference, however. If there are no errors in your rule set, pfctl will not produce any output before returning you to the command-line prompt.
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. If pfctl finds any syntax errors in your rule set, it will exit with an error message that points out the line number where the error occurred.
Under any circumstances, unless you flushed your rules (using pfctl -F and some specifier) before attempting to load new rules from your config- uration file, the last valid rule set loaded will be in force until you either disable PF or load a new rule set. The way rule set loading works, pfctl syntax checks and then loads your new rule set completely before switching over to the new one. With a valid rule set loaded, there is no intermediate state with a partial rule set or no rules loaded. The upshot of this is that flushing the rule set is rarely a good idea, since it effectively puts your packet filter in a pass all mode.