If you’re using Linux, you either already have a Linux firewall or are planning to set one up. If you’re planning to migrate to the 2.4 kernel and you currently use ipchains, you might want to take the time to learn the ins and outs of iptables.
The iptables utility is a new, soon-to-be-standard utility for firewall architecture in the Linux community. In this Daily Drill Down, Vincent Danen explains how to migrate from ipchains to iptables.
From kernel to kernel
Well, it's that time again. You’re about to migrate to the new 2.4 kernel, which boasts the newer iptables, but you’re using (and understand) the older ipchains utility. We saw the same type of migration happen when people went from kernel 2.0.x to kernel 2.2.x and the firewall rules changed from those based on ipfwadm to those based on ipchains. The conversion was made painless for some because ipchains could understand ipfwadm rules. That way, you weren't forced to rewrite your rules when you upgraded your kernel.
Now that kernel 2.4.3 was recently released, people are seeing the 2.4 kernels as stable enough for a production environment. Many of these production systems are firewall machines or systems that provide their own firewalls using ipchains rules. With kernel 2.4.x, we are once again migrating from one program to another. This time, we go from ipchains to iptables.
To be backwards compatible, an ipchains module can be loaded to use your existing ipchains rules. However, the benefits of using iptables and Netfilter are worth the time invested in converting your firewall rules.
What is the iptables firewall tool?
Iptables is a firewalling subsystem for your Linux machine. It is based on two components: kernel modules and the user interface application. For iptables to work, you must have support compiled into your kernel or the modules must be loadable by the kernel. There are also several components that handle different tasks, such as masquerading, port forwarding, and packet filtering.
With iptables, the modules handle the filtering and management of incoming and outgoing IP packets. So that you know, iptables is a part of the Netfilter framework, which is a part of the 2.4 kernel. Netfilter is a series of hooks in the network protocol stacks that allows modules (iptables) to work with network packets.
Perhaps the most exciting thing about iptables is that it performs network address translation (NAT), which is more commonly known as IP masquerading. This is useful primarily for routers and firewalls, and as such wouldn't often be used on a desktop machine. However, NAT is only a small part of what iptables does, so it will definitely have a home on your system, regardless of what your system is used for.
I hope you won't have to go through the chore of compiling your own kernel to obtain iptables support. A few vendors have made 2.4 kernels for their distribution available. Currently only SuSE has a distribution that ships the 2.4 kernel; however, in the next few weeks, Linux-Mandrake 8.0 will be available, which ships both the 2.4 and 2.2 kernels. A new version of Red Hat that should provide the 2.4 kernel is also in beta.
If you don't want to wait for a vendor-supplied kernel and are not afraid to compile your own, grab the latest version of the 2.4 kernel from one of the mirror sites listed at Kernel.org. For this Daily Drill Down, I’ll assume that you already know how to compile your kernel, and I’ll direct you to areas you need to know above and beyond the other modules or performance issues you’ll need in your kernel. For more information on kernel compilation, take a look at this quick Daily Feature by Jack Wallen, Jr.
Finally, you will need to download the iptables userspace program, which is available from the Netfilter Project homepage. This is a very simple build. You will also need the 2.4 kernel source available prior to building iptables. Once you have the 2.4 kernel sources available, you can build iptables. (You do not necessarily need to have the 2.4 kernel built prior to doing this.) Untar the iptables-1.2.1a.tar.bz2 file into /usr/src/ like this:
tar xvjf iptables-1.2.1a.tar.bz2
make install KERNEL_DIR=/usr/src/linux
Of course, replace the path specified in KERNEL_DIR with the directory that contains your 2.4 kernel. By default, make will look in /usr/src/linux for the source to the kernel. Once this is done, you will have the userspace iptables program available and can either begin to use iptables or compile your kernel to enable iptables and Netfilter support.
You will need to enable Netfilter and the iptables support directly in the kernel. This can be located in the Networking Options menu when you use make xconfig or make menuconfig from within the kernel source directory. You will want to select Network Packet Filtering (Replaces Ipchains) to enable Netfilter. Next, select the IP Netfilter Configuration menu option. You will then see the Netfilter Configuration menu. Enable the IP Tables Support option, and then select the iptables subsystems that you want to use. If you're not sure of a particular subystem, compile it as a module, because you may want to use it later. Making each subsystem available as loadable modules does not increase the size or overhead of your kernel. The method that seems to work best is compiling Netfilter and iptables support as part of the kernel and then compiling the various iptables components as loadable modules.
Before you are able to use iptables, you must load the modules. This can be done by executing:
You can also load more modules, such as those used to enable stateful firewalls:
To preserve the loading of these modules across reboots, you may want to insert those commands into your /etc/rc.d/rc.local file so they are loaded at each boot.
If you're familiar with ipchains rules, using iptables should be very simple. The syntax is almost identical to ipchains with some minor variations and additions. The syntax for using iptables is:
iptables command rule-specification extensions
There are a number of commands you can use. These commands (shown in Table A) act in an identical manner as those in ipchains. In fact, the commands use the exact same parameters:
|-A chain||This command appends one or more rules to the end of the nominated chain. If a hostname is supplied as either source or destination and it resolves to more than one IP address, a rule will be added for each address.|
|-I chain rulenum||Use this command to insert one or more rules to the start of the nominated chain. Like the -A command, if a hostname is supplied in the rule specification, a rule will be added for each of the addresses to which it resolves.|
|-D chain [rulenum]||To delete one or more rules from the specified chain and match the rule specification, use this command. If rulenum is specified, it will delete the rule residing at that position in the specified chain. Rule positions start at 1 for the first rule in the chain.|
|-R chain rulenum||This replaces the rule residing at position rulenum in the specified chain with the supplied rule.|
|-C chain||Use this command to check the datagram described by the rule specification against the specified rule. It will return a message describing how the chain processed the datagram. (This is very useful for testing your firewall configuration.)|
|-L [chain]||This command lists the rules of the specified chain or all chains if no chain is specified.|
|-F [chain]||Use this command to flush the rules of the specified chain or all chains if no chain is specified.|
|-Z [chain]||To zero the datagram and byte counters for all rules of the specified chain, or all chains if no chain is specified, use this command.|
|-N chain||To create a new chain with the specified name, use this command. (A chain of the same name must not already exist.) Also, use this to create user-defined chains.|
|-X [chain]||Use this command to delete the specified user-defined chain or all user-defined chains if no chain is specified.|
|-P chain policy||To set the default policy of the specified chain to the specified policy, use this command. Valid policies you may select are ACCEPT, DROP, QUEUE, and RETURN.|
These commands are identical to those used in ipchains. The policies are similar, as well: The ACCEPT policy allows the datagram to pass, while the DROP policy causes the datagram to be discarded. The QUEUE policy causes the datagram to be passed to userspace for further processing. Finally, the RETURN policy causes the firewall code to exit and return to the original calling chain. Once focus has shifted back to the original calling chain, the process picks up at the rule after the one containing the return policy.
Iptables rule specifications
There are also rule specification parameters that can be used. Whenever a rule specification is required, one of these parameters must be supplied or the default will be assumed.
The -p command is used to specify the protocol of the datagram. Valid protocol names are tcp, udp, icmp, or a number (if you know the IP protocol number). You can also prefix the protocol with the exclamation mark character (!), which makes it match anything but the specified protocol.
The -s command is used to specify the source address of the datagram that will match this rule. The address can be specified as a hostname, network name, or IP address. You can optionally supply a netmask to use in the traditional form (/255.255.255.0) or the modern form (/24). For example:
will match any packets originating from the IP address 192.168.1.28 with a subnet mask of 255.255.255.0. You can also use the exclamation point (!) to negate a source address.
The -d command is used to specify the destination address and follows the same syntax as the -s command.
The -j command is used to specify a target, which is any one of the policies described previously. You can also specify a user-defined chain that will be used to continue processing. You can think of the-j specification as a jump to parameter.
The -i command specifies the interface on which the datagram was received (the incoming interface). You can use the exclamation point (!) to negate it, just as with the other commands. You can also end the interface name with the plus symbol (+), which will match any interface that begins with the supplied string. For instance, using eth+ will match against eth0, eth1, etc.
The -o command specifies the outgoing interface and follows the same syntax as the -i command.
Finally, the -f command specifies that the rule applies only to the second and subsequent fragments of a fragmented packet, but not to the first fragment.
These commands are similar to the ipchains commands of the same names, with some minor differences. For instance, with the -s and -d commands under ipchains, you were also able to specify ports. With iptables, you aren’t allowed to do this with those same commands. By using some new extensions, which I will explain, you can still specify ports.
The extensions that can be used are called by using the -m command with a protocol name. This should coincide with the protocol specified by using the -p command. For instance, you will most likely be using -m tcp -p tcp instead of just -p tcp when you want to make use of these extensions.
The —sport command specifies the port that the datagram source must use to match this rule. Ports may be specified as a range using the colon (:) as a delimiter. For example, specifying 139:141 will specify ports 139 through 141. Also, you can use the exclamation point (!) to negate the values.
The —dport command specifies the destination port that the datagram must use to match this rule. It follows the same arguments as the —sport option.
Both of these commands can be used using the TCP or UDP protocols; i.e. -m tcp -p tcp or -m udp -p udp respectively. The following two commands (—tcp-flags mask comp, and —syn)can only be used with the TCP protocol.
The —tcp-flags mask comp command specifies that this rule should match when the TCP flags in the datagram match those specified by mask and comp. The mask is a comma-separated list of flags that should be examined when making the test. The comp is a comma-separated list of flags that must be set for the rule to match. The valid flags that can be specified are: SYN, ACK, FIN, RST, URG, PSH, ALL, or NONE.
The —syn command tells the rule to match only datagrams with the SYN bit set and the ACK and FIN bits cleared. Packets with these options are used to open TCP connections, so this option can be used to manage connection requests. This option is identical to using —tcp-flags SYN,RST,ACK SYN. If you use the exclamation point (!) with this command, the rule will match all datagrams that do not have both the SYN and ACK bits set.
You can also use an extension for ICMP message types by specifying -m icmp -p icmp. The command is —icmp-type type where type is an ICMP message type that may be specified by a number or name. Some valid names are echo-request, echo-reply, time-exceeded, host-unreachable, and port-unreachable, among others.
The final extension you can use is for MAC addresses by using -m mac. The —mac-source command is used to specify a host's Ethernet hardware address that was used to transmit the datagram.
A few comparisons
To allow SMTP connections on the first external interface (eth0) to the IP address 192.168.1.112 in ipchains, you would have used the following:
ipchains -A input -p tcp -s 0/0 -d 192.168.1.112 25 -j ACCEPT
Click here to view the command for using iptables.
To flush and set some defaults to deny everything incoming and allow unrestricted outgoing traffic in ipchains, you may use the following:
ipchains -F input
ipchains -P input DENY
ipchains -F output
ipchains -P output ACCEPT
And in iptables:
iptables -F INPUT
iptables -P INPUT DENY
iptables -F OUTPUT
iptables -P OUTPUT ACCEPT
As you can see, the two are nearly identical, except that in iptables, you use uppercase letters when specifying the chain. You will notice many similarities like this when rewriting your old ipchains rules.
While this is not an exhaustive look at the differences between ipchains and iptables, it’s sufficient to show you that it should be a relatively painless migration. Of course, if you still want to use the rules written for ipchains, you can do so by loading the ipchains module. You will not obtain all of the flexibility that comes with using iptables and Netfilter, but your firewall will still work properly until you are able to rewrite your rules.
I recall that converting from ipfwadm to ipchains was a lot more painful than converting from ipchains to iptables. The firewalling capabilities in iptables are also a lot more mature and advanced, and the syntax is very similar. The time spent converting rules that took so long in our migration from ipfwadm to ipchains should be minimal in comparison, and the time spent doing so is well worth the benefits that using iptables provides.
Vincent Danen works on the Red Hat Security Response Team and lives in Canada. He has been writing about and developing on Linux for over 10 years and is a veteran Mac user.