FREEWARE FIREWALLS

Many Unix systems, including Linux, FreeBSD, OpenBSD, and the like, come with packet filtering packages. They require special kernel options and modules to be built in, but because security has become so important, these options and modules are almost always built into the default system install. First, we'll discuss Linux's ipchains and iptables software. Then we'll take a look at FreeBSD's IPFW tool kit.

Note 

It's important to note that ipchains, iptables, and IPFW are all "userspace" programs. That means that the programs run and reside in memory designated for programs run by the users as opposed to those run by the system kernel. The actual packet filtering is done by the system kernel itself. These programs should be thought of as user interfaces to the kernel's packet filtering capabilities.

Ipchains

Ipchains is the first packet filter we'll discuss. Ipchains was originally based on a tool called ipfwadm, a Linux spawn of BSD's IPFW, which we'll discuss shortly. The idea behind ipchains was to create chains of rules for a packet to traverse. At any point in a chain, the packet could be passed on or denied . Ipchains has all but been replaced by iptables for Linux kernels running the 2.6 series; however, it may be included in most Linux distributions along with iptables. It is a good starting point for our first look at firewall packages, and it also gives us an example of a stateless firewall.

To use ipchains, all you need is a Linux box with the proper options compiled into the kernel. You can tell if your kernel has ipchains support if the file /proc/net/ip_fwchains exists. Most current Linux installs will have these options built in, but earlier Linux installs may need to be modified. Unfortunately, we can't go into detail here about how to build a Linux kernel; numerous Internet resources are available on building kernels for firewall support. You can check out the ipchains man page or visit the following web pages for more details: http://www.tldp.org/HOWTO/IPCHAINS-HOWTO.html.

Tip 

You'll also need to make sure that the file /proc/sys/net/ipv4/ip_forward contains the value 1 if you want to be able to forward packets from one network to the other. You can type echo 1 > /proc/sys/ net/ipv4/ip_forward as root to make sure that your firewall is ready to forward packets.

Ipchains is a user interface to the kernel's packet filtering capabilities. All of the actual packet examination gets done in the kernel's memory space. The ipchains program simply dictates the rules to the kernel. Unfortunately, this means the kernel will forget your rules any time the system is rebooted. Thankfully, you can use the tools ipchains-save and ipchains-restore to make a dump of the current ipchains rules in use and restore them after a reboot.

Implementation

If your Linux box has ipchains support, the first thing you can do is list the current set of rules:

 [root@originix /root]# ipchains -L Chain input (policy ACCEPT): Chain forward (policy ACCEPT): Chain output (policy ACCEPT): 

This command lists the current packet filtering rules in use. As you can see, ipchains defines three chains by default: input, forward, and output. The default policy for each chain is that packets are accepted. This means that if a packet passes through the entire chain and doesn't match any of the rules, it is considered acceptable and passed through the interface. You can choose from six common built-in targets:

ACCEPT

Accepts the packet.

REJECT

Blocks the packet and informs the sender of the rejection , usually by sending a special ICMP packet.

DENY

Drops the packet altogether, with no information sent to the packet's origin.

MASQ

Performs network address translation on the packet.

REDIRECT

Sends the packet to a local port on the system, much like basic port forwarding.

RETURN

Skips to the end of the chain. This is usually done for performance reasons as it's not necessarily a good idea to explicitly bypass other rules.

It's important that you understand how each of the default chains is used. Any packets coming into a system's interface first go to the input chain defined for that interface. Packets that aren't destined for the firewall itself will need to pass through the forward chain before continuing to their destination. Finally, any packets going out of the system must pass through the output chain. This means that any traffic passing between a system on the private network (connected to interface eth0) and a system on the public network (connected to interface eth1) will have to pass through all three chains. It's also important to note that input and output are not necessarily synonymous as inbound or outbound. Packets hit the input chain first whether they're coming from the internal network to eth0 or from the external network to eth1. This means we'll need to make sure we specify network interfaces in our chain rules to avoid any ambiguity between inbound and outbound traffic.

Using Ipchains Rules Ipchains doesn't do us much good unless we can define rules on each of our chains. Here we'll discuss the ipchains commands that are used to manipulate rules as well as the rule syntax.

First, let's take a look at the basic commands that allow you to add, remove, and modify rules and chains in Table 13-1.

Table 13-1: Ipchains Commands

Command

Description

ipchains A <chain> <rule>

Adds the specified rule at the end of the specified chain.

ipchains I <chain> <rulenum> <rule>

Inserts the specified rule at position <rulenum> of the specified chain.

ipchains R <chain> <rulenum> <rule>

Replaces the rule at position <rulenum> with the new specified rule.

ipchains D <chain> <rulenum>

Deletes the rule at position <rulenum> of the specified chain.

ipchains D <chain> <rule>

Deletes the first rule that matches the specified rule in the specified chain.

ipchains P <chain> <target>

Changes the default policy for a chain:
ACCEPT
REJECT
DENY
MASQ
REDIRECT
RETURN

ipchains L <chain>

Lists all the rules in the specified chain.

ipchains F <chain>

Deletes all the rules in the specified chain.

ipchains Z <chain>

Resets the byte counters on all rules in the specified chain. Byte counters provide a measure of traffic that has passed through the chain.

ipchains N <chain>

Creates a new chain.

ipchains X <chain>

Deletes an empty chain. You can't delete the default input , output , and forward chains.

The commands you will use most often are for adding rules to a chain, listing rules on a chain, and changing the policy on a chain. Additionally, you can create user-defined chains that can be used as targets. For example, if you want to test a particular packet against a certain set of rules but only if it first matches some initial criteria, you can have the packet jump to the user-defined chain. User-defined chains have no default policy, unlike the three default chains. If a packet reaches the end of a user-defined chain, it " falls off" that chain and lands back on the chain from whence it came.

First, let's look at an example rule. Imagine we wanted to block any incoming pings (ICMP echo requests ) at our external interface. How would we do this?

 ipchains -A input -p 1 -i eth1 -s 0.0.0.0/0 8 -d 0.0.0.0/0 -j DENY 

Let's break this down. First, we can see that we're adding this rule ( -A )tothe input chain. The p flag specifies the type of IP protocol. In this case, we're looking at IP protocol number 1, which is ICMP. The i flag allows us to define which network interface we're examining. In this case, we're concerned with incoming pings on the external interface, so we specify eth1. The s and d flags are used to specify the source and destination of the packet. In this case, the 0.0.0.0/0 will match all IP addresses, so we're actually saying "from any to any." The 8 at the end of the source address refers to the particular ICMP code for echo requests. Finally, the j flag says that any packets matching these criteria should be sent to the specified target. The target could be another chain or one of the built-in targets. In this case, we've said that any packets matching this rule should be denied.

Tip 

Ipchains will let you use symbolic names for protocols such as "icmp" and "tcp" and ports such as "www" and "telnet," as well as ICMP codes. We use the numbers here simply for educational purposes.

That wasn't so bad. Let's examine a rule that involves TCP. Let's say we wanted to allow web traffic only to our web server at 192.168.1.50 and deny everything else. How would we do it?

 ipchains -A input -p 6 -i eth1 -d 192.168.1.50 80 -j ACCEPT ipchains -P input DENY 

We've taken a bit of a shortcut here. Notice that we didn't specify a source address. In this case, it's unnecessary because we want to accept any traffic that destined for 192.168.1.50 on port 80, regardless of its source. The second line locks down the input chain so that any packet not matching this rule will be dropped.

Do you see any problems with this example? If that rule is the only rule we have on our input chain, the web server will never be able to respond to anyone who talks to it! We're saying that we allow only traffic inbound on eth1 to 192.168.1.50 on port 80. When 192.168.1.50 tries to talk back, it will be sending traffic inbound on eth0 (which becomes outbound on eth1, for those of you still with us). Since no matching rule exists and the default policy will DENY traffic, all responses are blocked. Let's add this rule:

 ipchains -A input -p 6 -i eth0 -s 192.168.1.50 80 -j ACCEPT 

That's better. This rule allows inbound responses from 192.168.1.50's web server on the eth0 interface. Assuming the packet makes it through the forward and output chains, the external web client would receive the response.

You can use an exclamation mark to invert nearly any possible value. For example, let's say you wanted everyone to have access to this web server except users on the 192.168.69.0 class C network. You could use inversion to rewrite the first rule.

 ipchains -R 1 input -p 6 -i eth1 -s ! 192.168.69.0/24 -d 192.168.1.50 80 -j ACCEPT 

This command replaces the first rule so that only traffic not coming from the 192.168.69.0 network to our web server will be accepted. We don't need to rewrite other rules because this one prevents 192.168.1.50 from ever receiving a packet from a system on the 192.168.69.0 network. Inversion is a handy feature, as you can use it with protocols, ports, addresses, interfaces, and even TCP flags.

Tip 

If you're dealing with a single host or IP address, you can simply use the hostname or IP. When you're dealing with a network or subnet, you need to be familiar with CIDR (Classless Inter Domain Routing) notation. For example, the class C network in the preceding example contained IP addresses from 192.168.69.0 to 192.168.69.255. The subnet mask for that address range is 255.255.255.0. That means that for all addresses on that subnet, the first 24 bits (or three octets) of the 32-bit IP address remain static. Therefore, to specify a class C 192.168.69.0 network as a source or destination for ipchains, you can specify the network number followed by a slash and either the subnet mask (192.168.69.0/255.255.255.0) or the number of network bits (192.168.69.0/24).

TCP and UDP ports can also be specified in a number of ways. You can use symbolic names for the ports, which are defined in the /etc/services file, or the port's number. You can specify a range of ports (such as 6000:6010) or an open range of ports ( :1023 specifies all ports under 1024). Ports can be preceded with the inversion operator (!) to negate the value.

Table 13-2 shows some of the different command-line flags you can use in your rules and what they do.

Table 13-2: Common Command-line Options

Characteristic

Example Command

Description

IP protocol

-p <proto>

Matches packets with the specified IP protocol. <proto> can be a protocol number or a symbolic name for the protocol number defined in /etc/protocols. The most popular symbolic names include TCP and UDP.

Source

-s <address> <port>

Matches packets with the specified source address and port. For ICMP, <port> is interpreted as ICMP type number. If <port> is omitted, any packet with a matching source address will match regardless of the port.

Destination

-d <address> <port>

Matches packets with the specified destination address and port. For ICMP, <port> is interpreted as ICMP code number. If <port> is omitted, any packet with a matching destination address will match regardless of the port.

Network interface

-i <interface>

Matches packets that are passing on the specified network interface. On Linux systems, you can type ifconfig to determine the interface names for your internal and external interfaces.

TCP SYN flag

-y

Matches TCP packets with only the SYN flag set. Because ipchains has no stateful capabilities, you'll often need to allow most return TCP traffic in, but use this rule to deny any incoming connections (those with only the SYN flag set).

Fragments

-f

Matches fragmented packets that also match the rest of the rule.

Logging

-l

By adding l at the end of a rule, any packets matching the rule will be logged to syslog using the kernel. info facility and level.

Now that you're familiar with the rule syntax, let's interpret a set of rules for a new system. The following is taken from an ipchains rules file generated using the ipchains-save utility. It could be loaded back into the kernel using the ipchains-restore utility.

  1)  :input DENY  2)  :forward DENY  3)  :output ACCEPT  4)  :unkwn-in --  5)  -A input -s 0.0.0.0/0.0.0.0 -d 0.0.0.0/0.0.0.0 -i eth1 -j unkwn-in  6)  -A input -s 0.0.0.0/0.0.0.0 -d 0.0.0.0/0.0.0.0 -i eth0 -j ACCEPT  7)  -A input -s 0.0.0.0/0.0.0.0 -d 0.0.0.0/0.0.0.0 -i lo -j ACCEPT  8)  -A forward -s 192.168.1.0/255.255.255.0 -d 0.0.0.0/0.0.0.0 -i eth1 -j MASQ  9)  -A unkwn-in -s 192.168.1.0/255.255.255.0 -d 0.0.0.0/0.0.0.0 -j DENY  10)  -A unkwn-in -s 0.0.0.0/0.0.0.0 -d 0.0.0.0/0.0.0.0 22:22 -p 6 -j ACCEPT  11)  -A unkwn-in -s 0.0.0.0/0.0.0.0 -d 0.0.0.0/0.0.0.0 80:80 -p 6 -j ACCEPT  12)  -A unkwn-in -s 0.0.0.0/0.0.0.0 20:20 -d 0.0.0.0/0.0.0.0 1024:5999 -p 6 -j ACCEPT  13)  -A unkwn-in -s 0.0.0.0/0.0.0.0 20:20 -d 0.0.0.0/0.0.0.0 6010:65535 -p 6 -j ACCEPT  14)  -A unkwn-in -s 0.0.0.0/0.0.0.0 0:0 -d 0.0.0.0/0.0.0.0 -p 1 -j ACCEPT  15)  -A unkwn-in -s 0.0.0.0/0.0.0.0 3:3 -d 0.0.0.0/0.0.0.0 -p 1 -j ACCEPT  16)  -A unkwn-in -s 10.3.0.6/255.255.255.255 53:53 -d 0.0.0.0/0.0.0.0 -p 17 -j ACCEPT  17)  -A unkwn-in -s 10.3.0.7/255.255.255.255 53:53 -d 0.0.0.0/0.0.0.0 -p 17 -j ACCEPT  18)  -A unkwn-in -s 0.0.0.0/0.0.0.0 -d 0.0.0.0/0.0.0.0 -p 6 -j ACCEPT ! -y  19)  -A unkwn-in -s 0.0.0.0/0.0.0.0 -d 0.0.0.0/0.0.0.0 -j DENY -l 
Note 

The line numbers in the preceding example are not part of the ruleset; they are merely for reference during the remainder of this section.

Let's see if we can make sense of this. The first three lines indicate the default policies for each of the built-in chains. The input and forward chains will drop any packets that don't match a rule while the output chain will accept any packets that don't match a rule. No rules have been defined for the output chain, so we can immediately determine that this firewall will pass all outgoing traffic.

The fourth line creates a chain called unkwn-in . Because user-defined chains cannot have a default policy, it is followed by a dash. The fifth line tells us that any packet coming in on eth1 (the external interface) should immediately jump to the unkwn-in chain for examination. The following two lines tell us that any traffic coming in on eth0 (the internal, trusted interface) and lo (the loopback interface) should be accepted. Although every packet that comes in to the firewall should match one of these three rules, the policy for the input chain is to deny anything else.

Line 8 begins the rule definitions for the forward chain. It says that any traffic with a source address on the 192.168.1.0 network in transit to the external interface eth1 should jump to the built-in MASQ target. This is how ipchains handles Network Address Translation (discussed in depth in the "Firewalls and Packet Filtersthe Basics" section). Any traffic from our internal network destined for the Internet will eventually get forwarded to the external interface eth1, putting it on the forward chain. The MASQ target will perform NAT on the packet and send it on to the output chain. Any other traffic that comes in on the forward chain will be denied.

Tip 

When a packet gets "de-masqueraded" by ipchains, it skips the forward chain and goes straight to the output chain. Since our firewall is doing NAT and no traffic from the external network should ever be forwarded to the internal network without having to be de-masqueraded first, we can safely deny all other traffic on the forward chain.

The remaining lines all define rules for our unkwn-in chain. Remember that for a packet to reach this chain in the first place, it had to arrive inbound on the eth1 interface. For that reason, it's not necessary to provide the i interface modifier on any of these rulesjust remember that it's implied .

The first rule on the unkwn-in chain protects our network from IP spoofing on the external interface. There's no reason that a packet from our private 192.168.1.0 network should be inbound on the external interface, so we explicitly deny it before it has a chance to match any of our ACCEPT rules. This illustrates an important point when designing any firewall ruleset. Even though we've made a default DENY policy for the input chain (and by consequence the unkwn-in chain), the packet won't hit that default action until it's passed through all the ACCEPT rules. This means we explicitly need to deny some things up front before we start accepting anything. Other firewalls deal with this differently.

The rules on lines 10 and 11 accept traffic coming in on TCP ports 80 and 22 (web and secure shell). This allows machines on the Internet to communicate with the web server and SSH server running on the firewall. Remember, even though we've specified a source and destination of any, an Internet system wouldn't be able to view any web servers or secure shells running on our private network due to NAT.

Note 

When the ipchains-save utility generates a rules file using the rules currently in the system, it writes the rules in great detail, specifying source and destination even when it isn't actually necessary.

The rules on lines 12 and 13 are for accepting FTP data connections. These rules are a good example of a terrible idea. They are accepting traffic from anywhere with a source port of 20 and a destination port that is not in the reserved port range (11023) or in the range commonly used by X servers (60006009). The reason we need to do this is because active mode FTP has the server make a separate connection back to the client using a source port of 20. In a NAT environment, this won't work at all unless the kernel has a special way of handling active mode FTP traffic. (Linux has an ip_masq_ftp kernel module that you can load at startup.) Even so, allowing any TCP traffic with a source port of 20 through your firewall is a bad idea. While discussing the difference between stateless and stateful firewalls in the "Firewalls and Packet Filtersthe Basics" section, we showed that port redirection (Chapter 15) could be used to tunnel a user's TCP traffic through a particular source port. In this case, the firewall rule provides some protection for reserved ports and X servers. But services like databases don't run in these ranges, so anyone who sends traffic with a source port of 20 will be able to access those ports because the firewall assumes it's FTP data traffic! Use passive mode FTP, which doesn't require a return connection from the server, to avoid such problems with FTP and firewall configuration.

The rules on lines 14 and 15 deal with ICMP traffic. Only ICMP echo replies (type 0) and destination unreachable messages (type 3) are allowed. All other ICMP traffic will eventually be denied when it hits the end of the chain. This allows machines on the internal network to ping external machines and get a response, but it keeps external machines from pinging our firewall.

Lines 16 and 17 deal with DNS traffic to servers on the external network. If we don't pass this traffic inbound from the DNS servers with a UDP source port of 53, we won't be able to make any DNS queries.

Line 18 is extremely important. Remember the distinction of ipchains as a stateless firewall? That means ipchains can judge only one packet at a time. Let's take the following simplified example. Let's say the machine 192.168.1.50 fires up its telnet client to an external machine. The source port is chosen by the telnet client at random from an available, nonreserved port. Let's say it chose a source port of 1029. Ignoring NAT for this example, the connection might look something like this:

The problem is that when the telnet server on the external machine responds, the source port is now 23 and the destination port is 1029. Our firewall isn't going to allow inbound traffic with a destination port of 1029. And we can't possibly open up holes for every possible choice of client source port without creating a ruleset nightmare. One option, as mentioned in the "Firewall and Packet Filtersthe Basics" section, would be to allow all incoming traffic with a source port of 23. However, now we've opened ourselves up to the same problem we encountered with the previous FTP data example. What else can we do? Use the y flag to examine the SYN flag on TCP packets. The SYN flag is set on any TCP packets that are used to initiate a connection. The rule on line 18 accepts all TCP packets that do not have only the SYN flag set. With this rule, our return packet from the external telnet server will be passed because the SYN flag will not be set without other flags, such as ACK, also being set. This is still dangerous because it allows some tricky port scanning, but it's probably the safest option. By accepting only non-SYN TCP packets, we ensure that no TCP connection can be established to any services running on our firewall (except for ports 22 and 80, for which we explicitly allowed access on lines 10 and 11). TCP connections are established with an initial SYN packet. The danger here is that we're assuming that inbound TCP packets that don't have the SYN flag set are part of a previously established outgoing connection. In reality, we've seen tools (such as the port scanners in Chapter 4 and hping in Chapter 14) that use non-SYN packets to gather information about open ports. Since our firewall will pass any non-SYN packets, it does not prevent these types of scans . Clearly, it would be better if ipchains could remember that we made this outgoing telnet connection using a source port of 1029, and then be smart enough to let response traffic from that connection through until the connection's termination. Iptables, discussed later in this chapter, will allow us to do this.

Finally, the last rule tells us to drop any packet that made it this far down the chain. Why do we need to do this? If we omit this rule, a packet reaching this point would fall off the end of the unkwn-in chain back to the input chain, where it would hit the input chain's default DENY policy. This last rule isn't redundant. If you look closely, you'll notice a l at the end of the rule. This tells ipchains not only to drop the packet, but to log the details of the packet to the syslog facility. This allows us to see who's been getting blocked at our firewall. Here's a snippet from a logfile showing someone trying to telnet into our firewall.

 Dec 25 14:49:54 cc94653-a kernel: Packet log: unkwn-in DENY eth1 PROTO=6 10.252.214.178:1776 10.180.192.229:23 L=48 S=0x00 I=5170 F=0x4000 T=108 SYN (#12) Dec 25 14:50:00 cc94653-a kernel: Packet log: unkwn-in DENY eth1 PROTO=6 10.252.214.178:1776 10.180.192.229:23 L=48 S=0x00 I=5791 F=0x4000 T=108 SYN (#12) 

We can see the date and time of the attempt, which chain the packet matched, the interface, the protocol, the source and destination information, packet details (length, type of service, IP ID, fragment offset, and time to live), and the rule number (#12) on the chain that matched the packet.

Debugging Ipchains One of the hardest things to do is to get your firewall rules doing exactly what you want them to do. Many times you'll find that a rule doesn't perform as intended. If you're trying to set up your firewall remotely instead of from the system console, you may even find that you occasionally block yourself from the system (don't worry, we've all done it). Ipchains provides a logging feature that lets you see which rule packets are matching against. When debugging your firewall during its initial setup, you can temporarily put the l flag at the end of every rule to see where packets are running into problems. Also, ipchains provides a C command-line option that you can use to check whether a particular packet would be accepted by the firewall chains currently in the system. For example, the following command would tell us what would happen if someone initiated (SYN flag set) a telnet connection to our firewall (10.180.192.229):

 # ipchains -C input -p 6 -y -i eth1 -d 10.180.192.229 23 denied 

Network Address Translation and Port Forwarding As mentioned in the previous section, NAT with ipchains is pretty easy. Simply set up the MASQ target in the forward chain on the external interface and you're good to go. What about port forwarding? You might think that the REDIRECT target we mentioned earlier would give us this capability, but it doesn't quite work like that. The REDIRECT target can only redirect traffic to a port on the localhost. This is useful if you want to set up a transparent proxy, such as forcing any web traffic destined for the Internet to instead go through a proxy server you have running on port 3128 of the firewall. Port forwarding to a different system actually requires a utility separate from ipchains.

The utility you're looking for is called ipmasqadm, and it requires another set of kernel options to be compiled in. If you don't have the ipmasqadm utility on our system, you can probably download it (as well as instructions on how to rebuild the kernel) from your Linux distribution's web site.

Just like ipchains, ipmasqadm is an interface to the actual kernel components that do the port forwarding. To allow a connection to port 443 on your firewall to pass through to an internal web server of 192.168.1.50 on port 443, you would issue this command:

 # ipmasqadm portfw -a -P tcp -L 10.180.192.229 443 -R 192.168.1.50 443 

Of course, we would also need to make sure that ipchains would allow inbound traffic with a destination port of 443 on our external interface.

Summarizing Ipchains

Now that we've spent all this time on ipchains, let us make a suggestion: don't use it. Ipchains is an excellent primer for getting your hands dirty with firewalling concepts, but it simply has a major limitation: lack of statefulness. As we mentioned earlier, most Linux systems will come with both ipchains and iptables. Now it's time to graduate you from the former to the latter.

Iptables (Netfilter)

The Netfilter/Iptables project (referred to simply as iptables from here on out) is the successor to Linux's ipchains. It has become the de facto packet filtering package for Linux kernel versions 2.4 and 2.6. Although most Linux distributions will come with their own prebuilt iptables packages, you can find out more information and download the iptables source at http://www.netfilter.org/.

As with ipchains, iptables requires that your kernel have the necessary capabilities before you can use the tool. Check out http://iptables-tutorial.frozentux.net/iptables-tutorial.html#KERNELSETUP for details on how to get your kernel ready for iptables.

If you haven't already read through the ipchains section, you probably should do so. Due to the similarities between iptables and ipchains, we make several references to the ipchains section when discussing some of the details that are similar between the two.

Implementation

Iptables does many things similarly to ipchains. In iptables, the concepts of firewall chains still exist, but chains are now part of logical groupings called tables . There are three different tables of chains.

The filter table is the main table and consists of an INPUT, OUTPUT, and FORWARD chain, just like ipchains. However, how the packets get passed to these chains is different. With ipchains, traffic coming directly to the firewall would hit the input chain, traffic leaving the firewall would hit the output chain, and traffic passing through the firewall would hit all three chains (starting with input ,to forward , and then to output ). In iptables, traffic passing through the firewall hits only the FORWARD chain. Only traffic that is originating from or destined to the firewall device itself will hit the OUTPUT and INPUT chains. The filter table is the heart of iptables; if you don't specify a table on the command line when manipulating rules and chains, it defaults to the filter table.

Another important table is the nat table, which also consists of three different chains: PREROUTING, POSTROUTING, and OUTPUT. The PREROUTING and POSTROUTING chains are encountered as packets first enter and just leave the firewall, respectively. They are encountered only by packets that pass through the firewall from one network to another or from one interface to another. The OUTPUT chain is for packets that come directly from the firewall. The nat table is meant to perform network address translation (NAT). No filter rules should be placed on any chains in this table.

The last table is the mangle table. The main use of the mangle table is to mark packets of interest for grouping as well as changing Time to Live and Type of Service options.

As with ipchains, when a packet matches a rule in iptables, it is sent to a target. Possible targets in the filter table are as follows :

ACCEPT

Allows the packet to pass through the interface.

REJECT

Blocks the packet and informs the sender of the rejection, usually by sending a special ICMP packet.

DROP

Drops the packet altogether, with no information send to the packet's origin.

LOG

Logs the packet to a syslog daemon. Continues down the chain.

RETURN

Skips to the end of the chain. This is usually done for performance reasons as it's not necessarily a good idea to explicitly bypass other rules.

There are four possible targets for the nat table:

DNAT

NAT for a specific destination, basically port forwarding.

MASQUERADE

Performs NAT on the packet.

REDIRECT

Sends the packet to a local port on the system, much like basic port forwarding.

SNAT

Explicit NAT for a specific IP range.

The MASQUERADE and SNAT targets are nearly identical except that the MASQUERADE target doesn't require you to specify a replacement source address when rewriting the packet header. The MASQUERADE target automatically uses the IP address on your external interface. The mangle table, which we won't spend much time on in this chapter, uses targets to adjust network performance or help create more complex rules. Some targets are

MARK

Marks packets for future matching.

TOS

Manipulates the Type of Service field in the IP header.

TTL

Modifies the packet's Time to Live.

Now that we've talked about the tables, chains, and targets, let's see how we write rules with iptables.

Using Iptables Rules The basic iptables commands for manipulating rules and chains are identical to those used by ipchains from Table 13-1. Remember that unless you specify an alternative table on the command line using the t option, iptables will assume you want to modify rules and chains in the filter table by default.

Let's take a look at an example iptables rule that protects our firewall from incoming Ping requests:

 iptables -A INPUT -i eth1 -p 1 -s 0.0.0.0/0 -d 0.0.0.0/0          --icmp-type 8 -j DROP 

If you refer back to the "Using Ipchains Rules" section, you'll notice that this rule looks similar to the rule for ipchains: Drop any packet that arrives on the external interface (eth1) of IP protocol number 1 (ICMP) with an ICMP type of 8 (echo request). The big difference between this rule and the ipchains rule is the way the ICMP type number is specified. You'll notice that iptables has separate flags for specifying ICMP numbers and TCP/UDP ports. Again, we've specified the source and destination here just for clarity's sake. The rule is intended to apply to traffic from any IP address to any IP address so we could have omitted the s and d options.

Tip 

Remember that the preceding rule protects only the firewall from external Pings. If we weren't using NAT and needed to protect an accessible network sitting on our internal interface, we'd want to append this rule to our FORWARD chain as well.

If we wanted to allow web traffic through to our internal web server (192.168.1.50) but block everything else, we would write this:

 iptables -A FORWARD -p 6 -i eth1 -o eth0 -d 192.168.1.50          --dport 80 -j ACCEPT iptables -P FORWARD DROP 

Pay close attention to this rule. Notice that we're filtering traffic coming through the firewall so we must use the FORWARD chain. Any packet with IP protocol number 6 (TCP) arriving on the external interface (-i eth1) and going out the internal interface (-o eth0) that is destined for port 80 on 192.168.1.50 is accepted. All other traffic is dropped.

We've intentionally made the same mistake in this rule that we did in the ipchains section. If this rule is the only rule on the FORWARD chain with a policy of DROP, no other traffic will ever pass through the firewall, including the web server's response to a web connection! One way to remedy this problem is simply to allow the web traffic on the FORWARD chain going the other way:

 iptables -A FORWARD -p 6 -i eth0 -o eth1 -s 192.168.1.50          --sport 80 -j ACCEPT 

This new rule simply reverses the direction of the traffic on the interfaces and swaps the destination information to source information. Iptables offers a better solution to this problem, connection tracking, that we'll discuss further in the upcoming sections.

Just like ipchains, you can use the inversion operator (!) to invert practically any value. We can modify the first rule so that anyone except users on the 192.168.69.0 network can talk to our web server:

 iptables -R FORWARD 1 -p 6 -i eth1 -o eth0 -s ! 192.168.69.0/24          -d 192.168.1.50 --dport 80 -j ACCEPT 

Use CIDR notation for IP address and network specifications. See the "Using Ipchains Rules" section or use your favorite search engine for more information on CIDR notation.

In ipchains, TCP and UDP ports can be specified after the source or destination IP address. In the interest of clarity, iptables requires a flag for port arguments: -sport and -dport . When specifying a port, you can use symbolic names for the ports as defined in the /etc/services file or the port's number. You can specify a closed range of ports (such as 6000:6010), an open range of ports (:1023 specifies all ports under 1024), or an inverse (! :1023 specifies ports 1024 and above). Iptables also has special capabilities for multiport matching. By specifying m multiport first on the command line, you can use a comma-separated list of up to 15 ports in the -sport and -dport options. It also allows you to use a special -port option that requires that both source and destination ports match ports in the comma-separated list. The multiport capabilities are simply a convenience, allowing you potentially to combine several similar rules into one. We'll talk more about other matching m options in the "Explicit Matching" section a little later.

Table 13-3 details the basic available rule options you can use in iptables.

Table 13-3: Iptables Options

Characteristic

Example Command

Description

IP protocol

-p <proto>

Matches packets with the specified IP protocol number. <proto> can be a protocol number or a symbolic name for the protocol number defined in /etc/protocols.

Source

-s <address>

Matches packets with the specified source address or range.

Destination

-d <address>

Matches packets with the specified destination address or range.

Source port (TCP, UDP)

sport <port>

Matches packets with the specified source port or range.

Destination port (TCP, UDP)

dport <port>

Matches packets with the specified destination port or range.

TCP flags (TCP only)

tcp-flags <flagmask>
<setflags>

Matches packets with certain TCP flags set. <flagmask> is a comma-separated list of flags that should be examined; <setflags> is a comma-separated list of the flags from <flagmask> that should be turned on (the other flags in <flagmask> should be off).

TCP SYN flag

syn

Matches packets with only the TCP SYN flag set. Same as specifying -tcpflags SYN,RST,ACK SYN .

ICMP type

icmp-type <type>

Matches ICMP packets with the specified type number.

Inbound network interface

-i <interface>

Matches packets that are inbound on the specified network interface. On Linux systems, you can type ifconfig to determine the interface numbers for your internal and external interfaces.

Outbound network interface

-o <interface>

Matches packets that are outbound on the specified network interface.

Fragments

-f

Matches fragmented packets that also match the rest of the rule.

In the "Using Ipchains Rules" section, we took a look at a set of sample rules. Let's see how these same rules might look in iptables.

One of the first things we did in working with ipchains earlier in the chapter was create a chain called unkwn-in to deal with any traffic coming in to the firewall on eth1. Before we write this rule in iptables, we need to consider which chain it should be applied to. Since we're using NAT in this setup, all inbound traffic on eth1 will have the firewall's external IP address as a destination anyway, so the INPUT chain is appropriate instead of the FORWARD or OUTPUT chains.

 iptables -N unkwn-in iptables -A INPUT -i eth1 -j unkwn-in 

Next, we want to make sure that our internal network can talk to (and through) the firewall, and that the firewall can talk to itself (on the loopback interface):

 iptables -A INPUT -i eth0 -j ACCEPT iptables -A FORWARD -i eth0 -o eth1 -j ACCEPT iptables -A INPUT -i lo -j ACCEPT 

Now we're ready to set up masquerading. Remember that all this time we've been operating on chains in the filter table. To set up masquerading, we need to use the nat table.

 iptables -t nat -A POSTROUTING -o eth1 -s 192.168.1.0/24 -j MASQUERADE 

Another nice feature with iptables is that many of the targets (such as MASQUERADE) can take arguments. If we append -to-ports 1024-4999 to the end of the previous rule, we can force the firewall to use only source ports from that range when performing IP masquerading or NAT.

Now we're ready to deal with our unkwn-in chain that will catch all traffic coming in from the external network to our firewall. First, there shouldn't be any traffic from our private range (192.168.1.0/24) hitting this chain. This is the anti-spoofing rule.

 iptables -A unkwn-in -s 192.168.1.0/24 -j DROP 

Next, we want to allow incoming web and secure shell connections. For this, we're going to use some of iptables' stateful connection-tracking features:

 iptables -A unkwn-in -p tcp ---dport 80 -m state ---state NEW -j ACCEPT iptables -A unkwn-in -p tcp ---dport 22 -m state ---state NEW -j ACCEPT 

This new syntax may be confusing because there's no corollary in ipchains. First, notice that we're using that tricky m option again. This flag is used for matching a packet against an extended characteristic, meaning something that isn't part of the packet header. In this case, we're using the state extension to gain access to the kernel's connection-tracking (or stateful) capabilities. The connection-tracking system has the ability to watch and remember packets, grouping them into connections or conversations for other rules in the chain. In this case, we're specifying a state of NEW, meaning that we'll accept packets inbound on these ports that aren't already part of an existing connection. In other words, we'll accept initial connections to our web server and secure shell ports.

Remember the last time we used the m option? We used it to do multiport comparisons. We could use multiport here to combine the two rules into one.

 iptables -R unkwn-in 2 -p tcp -m multiport ---dport 22,80 -m state         --state NEW -j ACCEPT iptables -D unkwn-in 3 

We've combined rules 2 and 3 into rule 2 and deleted rule 3. Now, if we think about this rule for a moment, we realize it will allow only NEW traffic to these ports. We also want packets that are part of an existing, valid connection to be passed. Add this rule:

 iptables -A unkwn-in -p tcp -m state ---state ESTABLISHED -j ACCEPT 

At first glance, you might not realize the power of this rule. Remember in ipchains how you would have to make considerations for passing response traffic from outgoing connections through the firewall? You had to either allow all packets with the SYN flag turned off or allow all traffic using source ports of the services you wanted to access (such as 22, 23, 80 and so on). Here we rely on iptables' connection-tracking capabilities to recognize packets that are part of a previously established connection and permit them to traverse the firewall. This is more convenient and secure than anything we could do with ipchains. With this rule, we've not only allowed incoming established traffic for our web server and secure shell server, but we've also allowed incoming established traffic for any outgoing connections our private machines may make.

Unfortunately, there remains one caveat: Due to the way connection tracking was implemented, it is possible for a packet without the SYN flag set to be labeled as part of a NEW connection. Therefore, our rule that allows only NEW inbound packets on ports 22 and 80 could still allow people to perform ACK scans against our firewall. We can combat this by adding a -syn flag to our rule or inserting an explicit drop instruction just before our rule, such as this:

 iptables -I unkwn-in 2 -p tcp ! ---syn -m state ---state NEW -j DROP 

This places an explicit drop instruction in position 2, moving our other two rules back. This will make certain that non-SYN packets labeled as NEW by the connection-tracking machine will never get through.

What about UDP and ICMP traffic? Both UDP and ICMP are connectionless protocols. Nevertheless, the connection-tracking system can still monitor particular characteristics of the protocols to determine implicit connections or conversations. We don't want any incoming UDP or ICMP traffic heading for our firewall, but we probably want to allow ESTABLISHED UDP and ICMP traffic in so that our private hosts can still Ping out and use UDP services such as DNS.

 iptables -A unkwn-in -p udp -m state ---state ESTABLISHED -j ACCEPT iptables -A unkwn-in -p icmp -m state ---state ESTABLISHED -j ACCEPT 

If we still want to receive ICMP unreachable messages (type 3), we'll have to add an explicit rule for that:

 iptables -A unkwn-in -p icmp ---icmp-type 3 -j ACCEPT 

That covers nearly everything that we had in our firewall rules when we used the ipchains tool. However, we still haven't dealt with active FTP. Do we need to open a load of port ranges to incoming packets with a source port of 20? Although the answer is yes, the ruleset is nowhere near as ugly as it was under ipchains.

 iptables -A unkwn-in -p tcp ---sport 20 -m state ---state ESTABLISHED,RELATED          -j ACCEPT 

We've used a new state keyword: RELATED . Connection tracking is able to recognize the separate reverse FTP data connection from port 20 as related to the outgoing FTP control connection on port 21. It does this using a separate kernel module called ip_conntrack_ftp. This module will have to be loaded into your kernel for this rule to allow active FTP traffic to pass.

We're almost finished. The last thing is make sure that we log and drop any packets that haven't matched any of the ACCEPT rules on this chain.

 iptables -A unkwn-in -j LOG iptables -P INPUT DROP 

This does what we want. The packet gets logged to syslog if it reaches the end of the unkwn-in chain. At that point, the packet falls off the unkwn-in chain back to the input chain. It will eventually reach the end of the input chain and be dropped.

Explicit Matching Explicit matches are made using that handy m option we've already discussed. Its most common use is for accessing the connection-tracking capabilities using the state extension; however, it can also be used with other extensions to make other matches. The following list explains some of these extensions in detail:

  • -m limit This match allows you to limit the validity of a rule based on the number of matches you receive over a certain period of time. Use the -limit-burst option to specify the maximum number of packets you can receive before this match is no longer valid. Use the -limit option to specify the ideal amount of matches over a period of time. For example, -m limit -limit-burst 20 -limit 10/minute would indicate that once we receive up to 20 matches in less than a minute, we stop matching until we go at least 6 seconds (1 minute divided by 10 seconds) without receiving another match. At this point, matches will be valid again until the burst value is reached. It's a bit complicated, but it can be useful for several things such as limiting the amount of logging you do on certain packets.

  • -m mac This match attempts to match the MAC address of the internal source, which is specified using -mac-source followed by a valid MAC address in XX:XX:XX:XX:XX:XX format.

  • -m mark This match is used to match packets that have been previously " marked " using iptables' MARK target in the mangle table. The mark must be a positive integer and can be specified using the -mark option.

  • -m multiport This match is used to match source and/or destination ports against a comma-separated list of ports, not just a single port or port range. Use -sport , dport , and -port to specify the port lists.

  • -m owner This match can be used for matching packets from processes with particular PIDs or owned by particular users. This match is useful only on the OUTPUT chain. Use -uid-owner , gid-owner , pid-owner ,and -sid-owner to specify the user ID, group ID, process ID, and session ID, respectively.

  • -m state This match is used for interfacing with the connection-tracking machine in the kernel. Using the state option, you can match packets that are not part of an existing connection (NEW), part of an established connection (ESTABLISHED), related to an existing connection (RELATED), or packets with invalid data or headers (INVALID).

Connection Tracking We don't want to get into a whole lot of gritty detail here, so we'll keep this as brief as possible. The connection-tracking module ip_conntrack (also referred to as the state machine) can keep track of packets and group them together into connections and conversations. It can track both connection-based protocols such as TCP as well as connectionless protocols such as UDP and ICMP. It does this by watching for responses with similar source and destination information and grouping them together. You can then access the state machine's classification of each packet using the m state explicit matching option discussed in the previous section. This makes iptables a stateful firewall, giving it an extreme advantage over the stateless ipchains.

Network Address Translation and Port Forwarding We've already discussed how you can use the nat table and the MASQUERADE target in the POSTROUTING chain to replace the source IP address of the private machine with the IP address of the firewall's public interface just before it goes out to the external network.

 iptables -t nat -A POSTROUTING -o eth1 -j MASQUERADE 

What do we do about port forwarding? With ipchains, we had to use a separate tool to configure port forwarding. With iptables, we can use the DNAT target in the PREROUTING chain of the nat table to handle port forwarding. If you think about it, port forwarding is just like NAT except in the reverse direction from how we've been using it. Instead of rewriting the source address of an outbound packet before it goes out to the Internet, we're rewriting the destination address of an inbound packet just as it comes in from the Internet.

 iptables -t nat -A PREROUTING -p tcp ---dport 443 -i eth1 -j DNAT          ---to-destination 192.168.1.50:443 

Here we've redirected port 443 on the firewall to port 443 on 192.168.1.50, our internal web server.

And just like ipchains, we can use the REDIRECT target to set up a transparent proxy server and force all outbound web traffic to get redirected to the proxy server running on port 3128 of our firewall. Keep in mind, however, that since redirecting has to be done in the PREROUTING chain, it will get done as the outbound packet first arrives on the internal interface, eth0.

 iptables -t nat -A PREROUTING -i eth0 -p tcp ---dport 80 -j REDIRECT          ---to-port 3128 

Summarizing Iptables

Iptables is a big step up from ipchains, one that gives you many new packet-filtering capabilities (primarily stateful packet inspection). Believe it or not, we haven't even covered all of the capabilities iptables has to offer. And developers are working on new features every day. We encourage you to visit http://www.netfilter.org/, where you can find things like tutorials, sample startup firewall scripts that do most of the hard work for you, and other packet-filtering resources.



Anti-Hacker Tool Kit
Anti-Hacker Tool Kit, Third Edition
ISBN: 0072262877
EAN: 2147483647
Year: 2006
Pages: 175

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net