Two different kinds of filtering must occur on a boundary machine that is offering services to the Internet on behalf of the protected network behind it, and at the same time forwarding traffic to machines on the protected network. The first set of filtering rules protect the boundary machine from unwanted interference, and the second set protect the machines on the private network. For this reason, some security wizards recommend that the boundary machine that provides the firewalling service be dedicated to that task, and that all other services be provided by separate machines.
The earlier toolset (ipfwadm) required you to consider all of the sorts of filtering at once, and to construct rules accordingly. One of the great improvements that ipchains has made is simplicity of rule specification. It is fairly straightforward to break the two cases above into separate chains of rules that do not interact, so that you can specify separately the rules for traffic that may flow through the boundary machine onto the protected network, and the rules for traffic that may flow onto the boundary machine. This simplification makes it much safer to use the boundary machine not only for firewalling, but also for a variety of other services. A useful set of such services is described here.
The ipchains program constructs a set of rule lists (chains) that are then used by the kernel to examine each packet as it arrives, is forwarded, and departs the boundary machine. For this purpose, ipchains starts out with three predeclared lists (chains): input, forward, and output. As it seems convenient, you can define other lists of rules, and refer to them from the primary rule lists.
Before actually constructing the rules, let us see how they are used to qualify a packet as it is handled by the boundary machine. As an example, here is a fragment of the configuration script that we will examine in detail below. The purpose of this fragment is to restrict the kinds of packets that will be allowed to flow onto the boundary machine.
/sbin/ipchains -A input -i eth1 -p tcp -d 126.96.36.199 --dport 1024:65535 -j ACCEPT /sbin/ipchains -A input -i eth1 -p tcp -d 188.8.131.52 -j wellk /sbin/ipchains -A input -i eth1 -p udp -d 184.108.40.206 -j udpsocks /sbin/ipchains -A input -i eth1 -p udp -d 220.127.116.11 --sport domain --dport 1024:65535 -j ACCEPT /sbin/ipchains -A input -i eth1 -p icmp -d 18.104.22.168 -j icmptypes /sbin/ipchains -A input -l -j DENY
These commands define a list of input checking rules that will be applied to each packet that arrives on the interface eth1, and is addressed to some socket on the boundary machine. The first two rules handle TCP traffic; the third and fourth handle UDP traffic, and the fifth takes care of ICMP traffic. No other packet types are expected for this machine, so anything that is not acceptable is thrown out, after a note is made in the logfile.
In more detail, the first rule says that if the protocol-type is tcp and the destination port number is in the unprivileged range (1024:65535), the packet is accepted without further examination. Otherwise, we go on to the second rule: if the protocol is tcp, we jump to a ruleset named wellk for further checking.
If the protocol is udp, the packet is checked against a set of rules in the ruleset titled udpsocks. If this ruleset does not either ACCEPT or DENY (or REJECT) the packet, checking continues at the next line of this ruleset, where both the source port and the destination port are required to match the conditions specified. (This rule permits DNS traffic to flow.)
If the incoming packet is neither TCP nor UDP, the only other protocol that we will allow is ICMP. For this protocol, we check the packet type field, according to the ruleset named icmptypes.
Finally, if the packet doesn't match any of the rules so far, the last rule causes a log entry to be recorded, and the packet to be dumped on the ash-heap.
This example illustrates several points. First, we can break rulesets into manageable parts, so that we don't have to consider all protocols, all interfaces, and all combinations of traffic at once. We do this by creating secondary rulesets, each with its own name. These rulesets behave like subroutines; if no rule matches the packet being checked, then control returns to the next rule in the list that invoked ths secondary ruleset.
Second, rules are processed in order from the top; as soon as the pattern-matching code can decide what to do with a packet, it stops applying rules, and takes the indicated action for that packet. Third, there are really only two actions we can take with a packet: ACCEPT or refuse passage to it. If we refuse a packet, we can either DENY it (drop it silently on the ash-heap), or REJECT it (complain to the sender before dropping it on the ash-heap).
(Another action we can take only in the forward ruleset is MASQ, masquerading or translating the packet headers, as described in the section on Private Networking. We will describe how to set this up later, when we discuss the details of an actual firewall configuration script.)
To construct a useful set of rules, then, we need to know which services are offered on the boundary machine, and which kinds of traffic should be allowed to flow through the boundary machine (firewall) onto the protected network. A useful set of services that may be offered on a boundary machine is described in the section on Other Services; deciding what sorts of traffic should be allowed to flow through the firewall is left to you, the firewall manager.