The unofficial Linux ipchains-HOWTO (beta)


By Adam McKenna (adam@flounder.net)

This (unofficial) HOWTO was written in order to help clarify the use of the new ipchains program, which is used for IP firewalling/packet filtering under Linux 2.1 and 2.2. I found the official HOWTO very theoretical, giving few concrete examples. This HOWTO will not focus on theory, it will instead focus on getting things done.

Table of Contents:

i.  Introduction
1.  Compiling IP filtering into your kernel
2.  Simple IP filtering
3.  Filtering by IP address
4.  Filtering by port
5.  Filtering by interface
6.  Setting up IP Accounting
7.  Enabling IP Forwarding
8.  Setting up IP Masquerading (NAT)
9.  Port redirection (transparent proxying)
10. Acknowledgements

Introduction

ipchains is an extremely powerful program that allows the user to set up complex IP filtering and accounting rules. Support for ipchains is compiled directly into the Linux kernel. This HOWTO will give specific examples of how to set up commonly used filtering rules using ipchains.

Compiling IP filtering into your kernel

The following list is a chart of all the options in the kernel configuration you need to say [Y] to in order to support IP firewalling and/or IP masquerading (NAT).

[!] Packet socket (CONFIG_PACKET)
[*] Kernel/User netlink socket (CONFIG_NETLINK)
[.] Routing messages (CONFIG_RTNETLINK)
[!] Network firewalls (CONFIG_FIREWALL)
[.] Network aliasing (CONFIG_NET_ALIAS)
[.] Socket Filtering (CONFIG_FILTER)
[!] TCP/IP networking (CONFIG_INET)
[.] IP: advanced router (CONFIG_IP_ADVANCED_ROUTER)
[!] IP: firewalling (CONFIG_IP_FIREWALL)
[.] IP: firewall packet netlink device (CONFIG_IP_FIREWALL_NETLINK)
[@] IP: always defragment (required for masquerading) (CONFIG_IP_ALWAYS_DEFRAG)
[@] IP: transparent proxy support (CONFIG_IP_TRANSPARENT_PROXY)
[@] IP: masquerading (CONFIG_IP_MASQUERADE)
[.] IP: ICMP masquerading (CONFIG_IP_MASQUERADE_ICMP)
[.] IP: masquerading special modules support (CONFIG_IP_MASQUERADE_MOD)
[.] IP: ipautofw masq support (EXPERIMENTAL) (CONFIG_IP_MASQUERADE_IPAUTOFW)
[.] IP: ipportfw masq support (EXPERIMENTAL) (CONFIG_IP_MASQUERADE_IPPORTFW)
[.] IP: ip fwmark masq-forwarding support (EXPERIMENTAL) (CONFIG_IP_MASQUERADE_MFW)
[.] IP: optimize as router not host (CONFIG_IP_ROUTER)

[!] Required for IP filtering
[@] Required for IP masquerading (NAT)
[*] Recommended
[.] Optional (RTFM!)

Simple IP filtering

After you've recompiled your kernel with IP filtering support, you can use the ipchains utility to add rules. Some of the rules you'll want to add as soon as possible:

# ipchains -A input -j DENY -p all -l -s 127.0.0.0/8 -i eth0 -d 0.0.0.0/0
# ipchains -A input -j DENY -p all -l -s 127.0.0.0/8 -i ppp0 -d 0.0.0.0/0 # if you are on dialup

This rule prevents packets that have addresses beginning with 127. from entering your machine. The reason for this is that any IP address starting with 127. is a loopback address, and only used internally. That means that any packet coming into your ppp or ethernet device matching this rule is spoofed.

In the above example, input refers to the chain. There are three built-in chains: input, output and forward.

The input chain refers to packets that are coming into your machine. These packets can be coming from a variety of sources. The local network, a foreign network, a ppp connection, or even the local loopback device.

The output chain refers to packets that are leaving your machine. Again, these packets can be leaving in any number of ways, through any interface which connects your computer to any network.

The forward chain refers to packets that are received that are not destined for your machine. These packets are being routed through your machine. Note that each packet that passes through the forward chain also passes through both the input and output chains.

A more complete description of each chain can be found at http://www.rustcorp.com/linux/ipchains/HOWTO-4.html.

You should always use the -l switch to log matches for your important chains. If this switch is specified on the command line, then a message will be printed to your kernel log each time your computer detects a packet matching the rule.

Filtering by IP address

Allowing or denying a connection based on IP address is very straightforward. As in the line above, you would just use something like this:

#  ipchains -A input -j DENY -p all -l -s x.x.x.x/x -d 0.0.0.0/0

Where x.x.x.x is the IP address you want to block. Also, you can define an optional subnet mask. If you want to block an entire class C network, you would use x.x.x.x/24, if you wanted to block a class B, you would use x.x.x.x/16. The number after the slash refers to the number of bits in the subnet mask.

You can also specify the protocol you want to filter by using the -p switch. In this example, we are blocking "all" protocols. Valid protocols are tcp, udp, icmp, or all. You can also use a protocol from /etc/protocols, if this file exists on your machine.

Filtering by port

A situation may arise where you need to control access to a particular port. The most common situation for this type of blocking is when an insecure or suspect service is being run on a certain port. For instance, rlogin. rlogin only does a check based on the hostname of the remote machine. If the hostname matches what's in a person's .rhosts file, the attacker would be able to login. To limit rlogin access to a certain class C address, we would add:

# ipchains -A input -j DENY -p tcp -l -s 0.0.0.0/0 -d y.y.y.y/32 513
# ipchains -A input -j ACCEPT -p tcp -s x.x.x.x/24 -d y.y.y.y/32 513

Where y.y.y.y is the IP address of the machine you want to protect, and x.x.x.x is the (Class C) subnet you want to allow access from. For services that are listed in /etc/services, you could specify the service name instead of the port number, i.e.:

# ipchains -A input -j DENY -p tcp -l -s 0.0.0.0/0 -d y.y.y.y/32 rlogin

You can also use a range of ports. The following would block and log packets destined for ports 10-100 on your local machine.

# ipchains -A input -j DENY -p tcp -l -s x.x.x.x/x -d y.y.y.y/32 10:100

Filtering by interface

It's possible to block all packets coming in on a particular interface. This would be useful if there was a service that you wanted to make available to users on your ethernet, but not to users on the other end of your ppp connection (i.e. the Internet). For instance, maybe you are running a web server that only local clients should access. You would therefore limit access to port 80 thusly:

# ipchains -A input -j DENY -p tcp -l -s 0.0.0.0/0 -i ppp0 -d y.y.y.y/32 80
Where as usual, y.y.y.y is your local IP address.

Setting up IP Accounting

With ipchains, IP accounting is built directly into the input and output chains. If you want to view IP accounting info, issue the following command:
# ipchains -L chain -v

Alternatively, special user-defined chains can be created in order to separate accounting rules from your input and output chains. To create these chains, and assign basic input/output rules to them, use the following commands:

# ipchains -N acctin
# ipchains -N acctout
# ipchains -N acctio
# ipchains -I input -j acctio
# ipchains -I input -j acctin
# ipchains -I output -j acctio
# ipchains -I output -j acctout

Enabling IP Forwarding

The rest of this document deals with situations in which your Linux server is being used as a router. If you want to use your Linux server as a router, you must enable IP forwarding. The command to do this is:

# echo "1" > /proc/sys/net/ipv4/ip_forward

*** NOTE: When you reboot your server, this value will be reset to zero! Remember to put the above command into your init scripts!

Setting up IP Masquerading (NAT)

If you're running a Linux server which has more than one external interface, it is possible to use your Linux server as a NAT Firewall. The commands to do this are:

# ipchains -P forward DENY
# ipchains -A forward -j MASQ -s y.y.y.y/24 -d 0.0.0.0/0

In this example, y.y.y.y is a local Class C subnet that you are proxying through your Linux server.

Port redirection (transparent proxying)

Ever wonder how transparent proxies work? Well, you can set one up yourself in the comfort of your own home! (or office). First of all, the only way this will ever work is if your Linux server is being used as a router; That is, it is forwarding packets between network interfaces that are connected to different networks.

In order for this to work, you need to have transparent proxy support compiled into your kernel.

Suppose you wanted to funnel all http requests to a web proxy running on port 8080 on the firewall. You would enter:

# ipchains -A input -j REDIRECT 8080 -p tcp -s 0.0.0.0/0 -d 0.0.0.0/0 80

It's really that easy! Now, all you need to do is set up your web proxy to run on local port 8080, and all of the machines that send packets through your Linux router will automatically have their HTTP requests proxied! (Note: It may be a bad idea to do this without telling your users as they may become testy.)

*** IMPORTANT: You must run a web proxy that is capable of transparent proxying. Most web proxies are not configured to do this by default. ***

Acknowledgements

I'd like to thank the following people: