Rate this page

Flattr this

Block unsolicited inbound network traffic using iptables

Tested on

Debian (Lenny)
Ubuntu (Precise, Trusty)

Objective

To block unsolicited inbound network traffic using iptables, without blocking return traffic associated with outbound connections

Background

Most machines that are connected to the Internet have no need to act as a server. This provides the opportunity for a large class of undesirable network traffic to be blocked using a firewall without interfering with the normal operation of the machine. To do that, the firewall must be able to distinguish between solicited and unsolicited inbound traffic.

For TCP-based protocols there are two types of inbound packet that need to be let through:

The first case is handled generically by the IPv4 connection tracking module. The second case requires the use of a helper module that understands the specific protocol in question (for example, nf_conntrack_ftp for FTP).

UDP is a connectionless protocol, therefore deterministic connection tracking like that done for TCP is not possible. What the connection tracking module does instead is assume that datagrams are related to each other if they use the same addresses and port numbers within a defined time interval (typically 30 seconds). This avoids the need for every UDP-based protocol to be explicitly supported by a helper module.

ICMP is a special case because it is an integral part of the Internet Protocol which all hosts are supposed to support. It can be argued that blocking ICMP provides some minor security benefits, however in most situations this is likely to cause more inconvenience to legitimate users and administrators than it would to a potential attacker. For this reason, the method described here allows inbound ICMP traffic even if it is unsolicited.

Scenario

Suppose that you wish to firewall a machine that is used only as a workstation. It is not required to provide any network services to other machines.

(For machines that are intended to act as servers the firewall described here cannot be used as it stands, but it can be used as a starting point if further rules are added to open specific inbound ports.)

Prerequisities

These instructions assume that you have a working installation of iptables and some means of persisting the ruleset. They also assume that the INPUT chain of the filter table is initially empty. If this is not already the case then it can be emptied by flushing that particular chain:

iptables -t filter -F INPUT

or by flushing the whole of the filter table:

iptables -t filter -F

Method

Configure iptables

The required effect can be achieved using the following ruleset:

iptables -t filter -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -t filter -A INPUT -p icmp -j ACCEPT
iptables -t filter -A INPUT -i lo -j ACCEPT
iptables -t filter -A INPUT -j REJECT

The first rule accepts solicited inbound traffic by inspecting the state assigned by the connection tracking module. Packets are accepted when the state is:

Packets are not accepted by this particular rule if they have a state of:

The second rule accepts all ICMP traffic, including unsolicited inbound traffic, for the reason given above.

The third rule accepts all traffic from the loopback interface. In this case that has been done by filtering on the interface name, but it would be equally acceptable to filter on the IP address (127.0.0.1). Although this is implemented as a special case, it is not an exception to the stated policy: any traffic received through the loopback interface must have originated on the local machine, therefore (by one means or another) it must have been solicited by the local machine.

The fourth rule blocks all traffic that has not already been accepted by one of the first three rules. There is a choice to be made here between the REJECT target and the DROP target:

Load any required connection tracking modules

If you wish to use any protocols that require a helper module for connection tracking then the relevant modules will need to be loaded. This can be done non-persistently using the modprobe command, for example:

modprobe nf_conntrack_ftp

You should also arrange for the modules to be re-loaded at boot time. On Debian-based systems this can be done by listing them in the file /etc/modules.

The module names are of the form nf_conntrack_ftp from version 2.6.20 of the kernel onwards. Prior to this they are of the form ip_conntrack_ftp.

Testing

The firewall configuration can be tested by attempting to make connections from another machine. An easy way to do this is by using the network scanning tool nmap:

nmap -sS -sU -p 0-65535 workstation1.example.com

This will check all TCP and UDP ports. Be warned that this can be quite time-consuming if you have chosen to drop unwanted traffic (as opposed to rejecting it).

To ensure that the traffic is being blocked by the machine under test (and not by any intermediate device) it may be useful to scan with the firewall both enabled and disabled. If necessary you could temporarily open a port using netcat to provide something for the scan to find. Do not do this when connected to the public Internet unless you are confident that the machine will survive unscathed.

Where practicable it is a good idea to check that the new configuration survives a reboot, otherwise there is a risk that when the machine does reboot it will return to operation in an unprotected state.

Variations

Allowing inbound connections on specific ports

The firewall described here is not directly suitable for use on a server, but as noted above it can be used as a starting point. You should add an ACCEPT rule for each port that needs to be left open, placing it prior to the final REJECT or DROP rule. For example, if you were running a DNS server then you could enable TCP and UDP connections to port 53 by adding the following pair of rules:

iptables -t filter -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -t filter -A INPUT -p icmp -j ACCEPT
iptables -t filter -A INPUT -i lo -j ACCEPT
iptables -t filter -A INPUT -p tcp --dport 53 -j ACCEPT
iptables -t filter -A INPUT -p udp --dport 53 -j ACCEPT
iptables -t filter -A INPUT -j REJECT

Alternatives

Avoid running unnecessary services

By far the most effective way to prevent unwanted connections is to avoid running unnecessary network services in the first place. If there is no process listening on a given TCP port then the network stack will unceremoniously reject any inbound connection attempts (typically by issuing an RST). Inbound UDP datagrams will be similarly rebuffed (typically with an ICMP destination port unreachable message).

The main drawback of using this policy as the sole line of defence is the difficulty of enforcing it on a long-term basis. You can determine what ports are open at a given moment in time using the netstat command:

netstat -lntu

However this does nothing to prevent ports from being opened in the future. A firewall provides a single point of control, and cannot normally be changed by unprivileged users.

Avoid binding to the external network interface

Most network services provide a method for configuring which address they bind to when listening for connections. Normally this would be either:

If you choose the second option then the effect, so far as external connections are concerned, is as if the service were not running.

Avoid giving the machine a public IP address

From a security perspective, the use of network address translation (NAT) has an almost identical effect to the firewall described here. It has the added benefits of failing safe (without NAT all traffic is blocked) and conserving public IP addresses.

Tags: firewall | iptables