Home > Articles > Introduction of IP CHAINS

Introduction of IP CHAINS

May 14th, 2003

The kernel starts with three lists of rules; these lists are called firewall chains or just chains. The three chains are called input, output and forward. When a packet comes in (say, through the Ethernet card) the kernel uses the input chain to decide its fate. If it survives that step, then the kernel decides where to send the packet next (this is called routing). If it is destined for another machine, it consults the forward chain. Finally, just before a packet is to go out, the kernel consults the output chain.

A chain is a checklist of rules. Each rule says `if the packet header looks like this, then here´s what to do with the packet´. If the rule doesn´t match the packet, then the next rule in the chain is consulted. Finally, if there are no more rules to consult, then the kernel looks at the chain policy to decide what to do. In a security-conscious system, this policy usually tells the kernel to reject or deny the packet.

Using ipchains

First, check that you have the version of ipchains that this document refers to:

[root@khanzada root]# ipchains –version

ipchains 1.3.10, 1-Sep-2000

Note that I recommend 1.3.4 (which has no long options, like `–sport´), or 1.3.8 or above; these are very stable.

There are several different things you can do with ipchains. First the operations to manage whole chains. You start with three built-in chains input, output and forward which you can´t delete.

1. Create a new chain (-N).

2. Delete an empty chain (-X).

3. Change the policy for a built-in chain. (-P).

4. List the rules in a chain (-L).

5. Flush the rules out of a chain (-F).

6. Zero the packet and byte counters on all rules in a chain (-Z).

There are several ways to manipulate rules inside a chain:

1. Append a new rule to a chain (-A).

2. Insert a new rule at some position in a chain (-I).

3. Replace a rule at some position in a chain (-R).

4. Delete a rule at some position in a chain (-D).

1. Delete the first rule that matches in a chain (-D).

[root@khanzada root]# ping -c 1 127.0.0.1

PING 127.0.0.1 (127.0.0.1) from 127.0.0.1 : 56(84) bytes of data.

64 bytes from 127.0.0.1: icmp_seq=0 ttl=255 time=516 usec

— 127.0.0.1 ping statistics —

1 packets transmitted, 1 packets received, 0% packet loss

round-trip min/avg/max/mdev = 1.189/1.189/1.189/0.000 ms

[root@khanzada /]# ipchains -A input -s 127.0.0.1 -p icmp -j DENY

[root@khanzada root]# ping -c 1 127.0.0.1

PING 127.0.0.1 (127.0.0.1) from 127.0.0.1 : 56(84) bytes of data.

— 127.0.0.1 ping statistics —

1 packets transmitted, 0 packets received, 100% packet loss

You can see here that the first ping succeeds (the `-c 1´ tells ping to only send a single packet).

Then we append (-A) to the `input´ chain, a rule specifying that for packets from 127.0.0.1 (`-s 127.0.0.1´) with protocol ICMP (`-p ICMP´) we should jump to DENY (`-j DENY´).

Then we test our rule, using the second ping. There will be a pause before the program gives up waiting for a response that will never come.

We can delete the rule in one of two ways. Firstly, since we know that it is the only rule in the input chain, we can use a numbered delete, as in:

To delete rule number 1 in the input chain.

The second way is to mirror the -A command, but replacing the -A with -D. This is useful when you have a complex chain of rules and you don´t want to have to count them to figure out that it´s rule 37 that you want to get rid of. In this case, we would use:

[root@khanzada /]# ipchains -D input -s 127.0.0.1 -p icmp -j DENY

Filtering Specifications

We have seen the use of `-p´ to specify protocol, and `-s´ to specify source address, but there are other options we can use to specify packet characteristics. What follows is an exhaustive compendium.

Specifying Source and Destination IP Addresses

Source (-s) and destination (-d) IP addresses can be specified in four ways. The most common way is to use the full name, such as `localhost´ or `www.linuxhq.com´. The second way is to specify the IP address such as `127.0.0.1´.

The third and fourth ways allow specification of a group of IP addresses, such as `199.95.207.0/24´ or `199.95.207.0/255.255.255.0´. These both specify any IP address from 199.95.207.0 to 199.95.207.255 inclusive; the digits after the `/´ tell which parts of the IP address are significant. `/32´ or `/255.255.255.255´ is the default (match all of the IP address). To specify any IP address at all `/0´ can be used, like so:

[root@khanzada /]# ipchains -A input -s 0/0 -j DENY

Specifying Protocol

The protocol can be specified with the `-p´ flag. Protocol can be a number (if you know the numeric protocol values for IP) or a name for the special cases of `TCP´, `UDP´ or `ICMP´. Case doesn´t matter, so `tcp´ works as well as `TCP´

Specifying Inversion

Many flags, including the `-s´ and `-d´ flags can have their arguments preceded by `!´ (pronounced `not´) to match addresses NOT equal to the ones given. For example. `-s ! localhost´ matches any packet not coming from localhost.

Don´t forget the spaces around the `!´: they really are needed.

Logging Packets

This is a side effect that matching a rule can have; you can have the matching packet logged using the `-l´ flag. You will usually not want this for routine packets, but it is a useful feature if you want to look for exceptional events.

The kernel logs this information looking like:

I apply that command for icmp ping block

[root@khanzada root]# ipchains -A input -p icmp -j DENY -l

May 27 16:18:27 khanzada kernel: Packet log: input DENY eth0 PROTO=1 192.168.1.2:8 192.168.1.1:0 L=60 S=0x00 I=59680 F=0x0000 T=32 (#1)

This log message is designed to be terse, and contain technical information useful only to networking gurus, but it can be useful to the rest of us. It breaks down like so:

1- May 27 16:18:27 is the Month-Date-Time

2- Khanzada is the hostname

3- `input´ is the chain which contained the rule which matched the packet, causing the log message

4- `DENY´ is what the rule said to do to the packet. If this is `-´ then the rule didn´t effect the packet at all (an accounting rule).

5- `eth0´ is the interface name. Because this was the input chain, it means that the packet came in `eth0´.

6- `PROTO=1´ means that the packet was protocol 17. A list of protocol numbers is given in `/etc/protocols´. The most common are 1 (ICMP), 6 (TCP) and 17 (UDP).

7- 192.168.1.2 means that the packet´s source IP address was 192.168.1.2.

8- `:8´ means that the source port was port 8. Looking in `/etc/services´ shows that this is the `domain´ port (ie. this is probably an DNS reply). For UDP and TCP, this number is the source port. For ICMP, it´s the ICMP type. For others, it will be 65535.

9- 192.168.1.1´ is the destination IP address.

10- `:0´ means that the destination port was 0. For UDP and TCP, this number is the destination port. For ICMP, it´s the ICMP code. For others, it will be 65535.

11- L=36´ means that packet was a total of 34 bytes long.

12- S=0x00´ means the Type of Service field (divide by 4 to get the Type of Service as used by ipchains).

13- `I=59680´ is the IP ID.

14- ‘F=0x0000’ is the 16-bit fragment offset plus flags. A value starting with `0x4´ or `0x5´ means that the Don´t Fragment bit is set. `0x2´ or `0x3´ means the `More Fragments´ bit is set; expect more fragments after this. The rest of the number is the offset of this fragment, divided by 8.

15- `T=32´ is the Time To Live of the packet. One is subtracted from this value for every hop, and it usually starts at 15 or 255.

16- `(#1)´ there may be a final number in brackets on more recent kernels (perhaps after 2.2.9). This is the rule number which caused the packet log.

Manipulating the Type Of Service

There are four seldom-used bits in the IP header, called the Type of Service (TOS) bits. They effect the way packets are treated; the four bits are “Minimum Delay”, “Maximum Throughput”, “Maximum Reliability” and “Minimum Cost”. Only one of these bits is allowed to be set. Rob van Nieuwkerk, the author of the TOS-mangling code, puts it as follows:

Especially the “Minimum Delay” is important for me. I switch it on for “interactive” packets in my upstream (Linux) router. I´m behind a 33k6 modem link. Linux prioritizes packets in 3 queues. This way I get acceptable interactive performance while doing bulk downloads at the same time. (It could even be better if there wasn´t such a big queue in the serial driver, but latency is kept down 1.5 seconds now).

The most common use is to set telnet & ftp control connections to “Minimum Delay” and FTP data to “Maximum Throughput”. This would be done as follows:

[root@khanzada root]# ipchains -A output -p tcp -d 0.0.0.0/0 telnet -t 0x01 0x10

[root@khanzada root]# ipchains -A output -p tcp -d 0.0.0.0/0 ftp -t 0x01 0x10

[root@khanzada root]# ipchains -A output -p tcp -d 0.0.0.0/0 ftp-data -t 0x01 0x18

The `-t´ flag takes two extra parameters, both in hexadecimal. These allow complex twiddling of the TOS bits: the first mask is ANDed with the packet´s current TOS, and then the second mask is XORed with it. If this is too confusing, just use the following table:

TOS Name Value Typical Uses

Minimum Delay 0x01 0x10 ftp, telnet

Maximum Throughput 0x01 0x08 ftp-data

Maximum Reliability 0x01 0x04 snmp

Minimum Cost 0x01 0x02 nntp

Creating a New Chain

Let´s create a new chain. Because I am such an imaginative fellow, I´ll call it test.

[root@khanzada root]# ipchains -N test

Deleting a Chain

Deleting a chain is simple as well.

[root@khanzada root]# ipchains -X test

Why `-X´? Well, all the good letters were taken.

There are a couple of restrictions to deleting chains: they must be empty (see Flushing a Chain below) and they must not be the target of any rule. You can´t delete any of the three built-in chains.

Flushing a Chain

There is a simple way of emptying all rules out of a chain, using the `-F´ command.

[root@khanzada root]# ipchains -F

If you don´t specify a chain, then all chains will be flushed.

Listing a Chain

You can list all the rules in a chain by using the `-L´ command

[root@khanzada root]# ipchains -L input

Chain input (policy ACCEPT):

target prot opt source destination ports

ACCEPT tcp —— anywhere anywhere any -> any

There are three options which can accompany `-L´. The `-n´ (numeric) option is very useful as it prevents ipchains from trying to lookup the IP addresses, which (if you are using DNS like most people) will cause large delays if your DNS is not set up properly, or you have filtered out DNS requests. It also causes ports to be printed out as numbers rather than names.

The `-v´ options shows you all the details of the rules, such as the the packet and byte counters, the TOS masks, the interface, and the packet mark. Otherwise these values are omitted. For example:

[root@khanzada root]# ipchains -v -L input

Chain input (policy ACCEPT: 8691 packets, 512549 bytes):

pkts bytes target prot opt tosa tosx ifname mark outsize source destination ports

266 13712 ACCEPT tcp —— 0xFF 0x00 any anywhere anywhere any -> any

Note that the packet and byte counters are printed out using the suffixes `K´, `M´ or `G´ for 1000, 1,000,000 and 1,000,000,000 respectively. Using the `-x´ (expand numbers) flag as well prints the full numbers, no matter how large they are.

Resetting (Zeroing) Counters

It is useful to be able to reset the counters. This can be done with the `-Z´ (zero counters) option. For example

[root@khanzada root]# ipchains -v -L input

pkts bytes target prot opt tosa tosx ifname mark outsize source destination ports

266 13712 ACCEPT tcp —— 0xFF 0x00 any anywhere anywhere any -> any

[root@khanzada root]# ipchains -Z input

[root@khanzada root]# ipchains -v -L input

pkts bytes target prot opt tosa tosx ifname mark outsize source destination ports

0 0 ACCEPT tcp —— 0xFF 0x00 any anywhere anywhere any -> any

Multiple Rules at Once and Watching What Happens

Sometimes a single command line can result in multiple rules being effected. This is done in two ways. Firstly, if you specify a hostname which resolves (using DNS) to multiple IP addresses, ipchains will act as if you had typed multiple commands with each combination of addresses.

So if the hostname `www.foo.com´ resolves to three IP addresses, and the hostname `www.bar.com´ resolves to two IP addresses, then the command `ipchains -A input -j reject -s www.bar.com -d www.foo.com´ would append six rules to the input chain.

The other way to have ipchains perform multiple actions is to use the bidirectional flag (`-b´). This flag makes ipchains behave as if you had typed the command twice, the second time with the `-s´ and `-d´ arguments reversed. So, to avoid forwarding either to or from 192.168.1.1, you could do the following:

[root@khanzada /]# ipchains -b -A forward -s 192.168.1.1 -j REJECT

Useful Examples

I have a dialup PPP connection (-i ppp0). I grab news (-p TCP -s news.fascom.com nntp) and mail (-p TCP -s mail.fascom.com pop-3) every time I dial up. use Red Hat´s FTP method to update my machine regularly (-p TCP -y -s ftp.redhat.com ftp-data). I surf the web through my ISP´s proxy while this is going on (-p TCP -d proxy.fascom.com 8080), but hate the ads from doubleclick.net on the Dilbert Archive (-p TCP -y -d 199.95.207.0/24 and -p TCP -y -d 199.95.208.0/24).

Minimum Delay and got good response from Your ISP Proxy & Telnet

[root@khanzada /]# ipchains -N ppp-out

[root@khanzada /]# ipchains -A output -i ppp0 -j ppp-out

[root@khanzada /]# ipchains -A ppp-out -p TCP -d Proxy-OF-ISP 8080 -t 0x01 0x10

[root@khanzada /]# ipchains -A ppp-out -p TCP -d 0.0.0.0/0 telnet -t 0x01 0x10

Masquerading/Forwarding Doesn´t Work!

Make sure that packet forwarding is enabled (in recent kernels it is disabled by default, meaning that packets never even try to traverse the `forward´ chain). You can override this (as root) by typing

[root@khanzada /]# echo 1 > /proc/sys/net/ipv4/ip_forward

If this works for you, you can put this somewhere in your bootup scripts so it is enabled every time; you´ll want to set up your firewalling before this command runs though, otherwise there´s an opportunity for packets to slip through.

Anti-Spoofing

for f in /proc/sys/net/ipv4/conf/*/rp_filter; do echo 1 > $f; done

Articles

Comments are closed.