Firewalls, IP aliasing and proxies
Writing rules
The sequence in which rules are applied is not necessarily the sequence in which they are read. Instead, each rule can have a line number between 1 and 65534. Rules are applied from the lowest to the highest line number. If you enter a rule without a line number, however, it receives a number 100 higher than the previous rule.
The highest-numbered rule is number 65535, which is always present. Normally it has the form:
65535 deny all from any to any
In other words, if no other rules are present, or they don't match the packet, ipfw drops the packet. If you build a kernel with the option IPFIREWALL_DEFAULT_TO_ACCEPT, this rule changes to its opposite:
65535 allow all from any to any
These two rule sets implicitly illustrate two basic security strategies. You may note parallels to certain political systems:
- The first takes the attitude "everything is forbidden unless explicitly allowed."
- The second takes the attitude "everything is allowed unless explicitly forbidden."
It goes without saying that the first policy is safer. If you make a mistake with the first (more restrictive) rule set, you're more likely to lock people out of your system accidentally than you are to let them in when you don't want them.
Configuration files
The main configuration file is /etc/rc.firewall. It's unlikely to match your needs exactly. There are two possibilities:
- You can edit it to match your requirements.
- You can create your own configuration file with your rules.
Which do you choose? If you're making only minor modifications, it's easier to edit it. If you're taking things seriously, though, you'll end up with something that no longer bears much of a relationship with the original file. Upgrades are easier if you have your own file.
If you create your own file, you can tell /etc/rc.conf its name, and /etc/rc.firewall will read it. Either way, the rules are the same. In the following section we'll go through the default /etc/rc.firewall file. There's nothing stopping you from copying them to another file and editing them to match your requirements.
Reading the file is somewhat complicated by a number of environment variables that are set in the system startup scripts. We'll see the important ones below. It's also helpful to know that ${fwcmd} gets replaced by the name of the firewall program, /sbin/ipfw. The other ones are described in /etc/default/rc.conf:
firewall_enable="NO" # Set to YES to enable firewall functionality firewall_script="/etc/rc.firewall" # Which script to run to set up the firewall firewall_type="UNKNOWN" # Firewall type (see /etc/rc.firewall) firewall_quiet="NO" # Set to YES to suppress rule display firewall_logging="NO" # Set to YES to enable events logging firewall_flags="" # Flags passed to ipfw when type is a file
To set up the firewall, first decide the kind of profile you need and set the variable firewall_type accordingly. The current version of /etc/rc.firewall defines four kinds of usage profile:
- The open profile is effectively a disabled firewall. It allows all traffic. You might use this if you're having trouble setting up the firewall and need to disable it temporarily.
- The client profile is a good starting point for a system that does not provide many publicly accessible services to the Net. We'll look at it in the next section.
- The simple profile, despite its name, is intended for a system that does provide a number of publicly accessible services to the Net.
- The closed profile allows only local traffic via the loopback interface.
In addition, you can set firewall_type to the name of a file describing the firewall configuration.
All configurations start with a call to setup_loopback, which adds the following rules:
${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} add 300 deny ip from 127.0.0.0/8 to any
These rules allow all local traffic and stop traffic coming in with a fake local address.
The client profile
At the beginning of the client profile you'll find a number of variables you need to set. In the following example they're set to match http://freebie.example.org and our example network:
[Cc][Ll][Ii][Ee][Nn][Tt]) ############ #This is a prototype setup that will protect your system somewhat against #people from outside your own network. ############ #set these to your network and netmask and ip net="223.147.37.0" mask="255.255.255.0" ip="223.147.37.1" freebie.example.orgЛистинг 22_1. Client profile in /etc/rc.firewall
The first line matches the text client whether written in upper or lower case. Then we have:
setup_loopback #Allow any traffic to or from my own net. ${fwcmd} add pass all from ${ip} to ${net}:${mask} ${fwcmd} add pass all from ${net}:${mask} to ${ip}
These rules allow any traffic in the local network.
#Allow TCP through if setup succeeded ${fwcmd} add pass tcp from any to any established
If a TCP connection has already been established, allow it to continue. Establishing a TCP connection requires other rules, which we shall see below.
#Allow IP fragments to pass through ${fwcmd} add pass all from any to any frag
Fragmented packets are difficult to recognize, and if we block them, strange things might happen. They're usually not a significant security risk.
#Allow setup of incoming email ${fwcmd} add pass tcp from any to ${ip} 25 setup #Allow setup of outgoing TCP connections only ${fwcmd} add pass tcp from ${ip} to any setup #Disallow setup of all other TCP connections ${fwcmd} add deny tcp from any to any setup
The preceding three rules allow external systems to establish a TCP connection for delivering mail (first rule), but nothing else (third rule). The second rule allows setup of TCP connections to the outside world.
#Allow DNS queries out in the world ${fwcmd} add pass udp from ${ip} to any 53 keep-state #Allow NTP queries out in the world ${fwcmd} add pass udp from ${ip} to any 123 keep-state #Everything else is denied as default.
These two rules allow DNS and NTP queries. The keyword keep-state causes ipfw to build a short-lived dynamic rule matching this particular combination of end points and protocol. This means that we don't need to open traffic in the other direction. Previously, the rule set for DNS queries consisted of these two rules:
$fwcmd add pass udp from any 53 to ${ip} $fwcmd add pass udp from ${ip} to any 53
This allows all DNS traffic in both directions. By contrast, keep-state allows only the reply traffic for specific queries to pass the firewall. You don't need this for TCP—the established keyword does the same thing—but UDP doesn't have the concept of a connection, so the firewall needs to keep track of the traffic.
There are no more rules, so the default deny rule prevents any other kind of traffic.