Firewall and Advanced Routing Under Linux

Introduction

This page content was cloned from http://ornellas.apanela.com/dokuwiki/pub:firewall_and_adv_routing for safe keeping. — Nathan Martin 2011/10/04 14:57

Objective

To present different tools and functionalities present on Linux systems to implement firewall and routers. Specific usage of each tool will not be covered by this article and it is up to the reader to learn more about them by reading the manuals.

Requirements

It is assumed that the author has basic knowledge about GNU / Linux systems and TCP / IP networking (including firewall and routing).

It is recommended that the reader follow the article together with each tool´s manual in hand for reference.

Firewall: IP Tables

The current tool for firewall under Linux is iptables. IP Tables is composed of a series of userland tools that interact with netfilter, which is Linux firewall implementation in kernel space.

IP Tables behavior is based on pairs of rules and actions. Rules define in which packets (eg. packets from a certain network) a certain action (eg. to drop the packets) will be executed. Netfilter will process all rules sequentially for each package. When it finds one that matches a certain rule, it will act by calling the defined action for that rule. Actions taken can be either terminative or not. For example, an action which asks netfilter to ignore a certain packet will be called and no other rules will be applied. This is a terminative action. However, if the action specifies to only log the existence of the package, it will do its job and let netfilter process the following rules. This is a non terminative action.

The main tool is the command iptables, which manual can be accessed via:

# man iptables

The next sections will explain how the explained behavior works inside iptables and how to configure it.

Tables

The name iptables comes from the fact that internally iptables works based on tables, each one specialized on a certain type of packets treatment. These are the tables existent on a Linux 2.6.8 (different kernel versions can have different tables):

Table Meaning
raw Low level alteration of packets.
nat Changes on packets headers (where NAT takes place).
mangle Used to make specialized packet alterations.
filter Packet filtering.

Thus, depending on what you wish to do with a certain packet, there is an adequate table for that.

Chains

In IP Tables, there are several chains glued to each table and each one associated a certain kind of traffic. Here they are:

Chain Meaning
PREROUTING Incoming traffic to the machine (including local generated traffic destined to the machine itself) before routing takes place (can be either local or passing traffic).
INPUT Traffic destined to the machine itself.
FORWARD Matches passing traffic (remote generated, remote destination).
OUTPUT Locally generated traffic (either local or remote destination).
POSTROUTING Outgoing traffic (including locally generating traffic, destined to the machine itself).

It is also possible to create personalized chains, topic that will not be covered on this article.

The FORWARD chain has a special treatment inside Linux kernel. It comes with a lock that blocks traffic through this chain by default. To allow such traffic, it is needed to change the following kernel parameter:

net.ipv4.ip_forward=1

to allow IPv4 traffic (there is a similar switch to IPv6 traffic). This parameter can be changed using sysctl(8) command:

# sysctl -w net.ipv4.ip_forward=1

This can be automated by adding the following line to sysctl.conf(5) (usually /etc/sysctl.conf) and should be set up at boot time:

net.ipv4.ip_forward=1

Note: Debian versions previous (and including) Sarge have a file named /etc/network/options that can also be used to set up this parameter. This is wrong and is not present any more in future releases.

Data Flow Diagram

The data flow inside each table / chain inside the Linux kernel is described by the graph below. In each box, it is labeled the acting chain and the names of the valid tables for each chain. Traffic flows through each one of the tables in series for each chain. For example, at PREROUTING chain, there are the tables raw, mangle e nat. Traffic flowing through this chain will pass by each one of the three tables sequentially.

      Incoming
       Traffic
          |
          |
          V
     +----------+
     |PREROUTING|
     +----------+
     |   raw    |  <--------------+
     |  mangle  |                 |
     |   nat    |                 |
     +----------+                 |
          |                       |
          |                       |
       Routing                    |
    +- Decision -+                |
    |            |                |
    |            |                |
    V            V                |
  Local        Remote             |
Destination   Destination         |
    |            |                |
    |            |                |
    V            V                |
+--------+  +---------+           |
| INPUT  |  | FORWARD |           |
+--------+  +---------+           |
| mangle |  | mangle  |           |
| filter |  | filter  |           |
+--------+  +---------+           |
    |            |                |
    |            |                |
    V            |                |
  Local          |                |
 Machine         |                |
    |            |                |
    |            |                |
    V            |                |
 Routing         |                |
 Decision        |                |
    |            |                |
    |            |                |
    V            |                |
+--------+       |                |
| OUTPUT |       |                |
+--------+       |                |
|  raw   |       |                |
| mangle |       |                |
|  nat   |       |                |
| filter |       |                |
+--------+       |                |
    |            |                |
    |      +-------------+        |
    |      | POSTROUTING |      Local
    +----> +-------------+ --> Traffic
           |   mangle    |
           |     nat     |
           +-------------+
                 |
                 |
                 V
              Outgoing
              Traffic

Let´s take as an example an access from the machine to itself. Traffic will flow sequentially by each one of the following chains / tables:

  1. Packet generated by a local process / kernel
  2. Routing decision
  3. OUTPUT: raw
  4. OUTPUT: mangle
  5. OUTPUT: nat
  6. OUTPUT: filter
  7. POSTROUTING: mangle
  8. POSTROUTING: nat
  9. PREROUTING: raw
  10. PREROUTING: mangle
  11. PREROUTING: nat
  12. Routing decision
  13. INPUT: mangle
  14. INPUT: filter
  15. Packet delivered to a local process / kernel

Thus, if one wish to allow such traffic, there must have no rule / action pair prohibiting the traffic in any of the above cases.

Rules

Given a certain chain / table, it is necessary to use rules to select in which packets a certain action will take place. Not all rules applies to all chains. For example, a rule specifying the outgoing interface of a packet does not apply to the chain PREROUTING, since routing decision has not been taken at that point.

There are general rules (referred as PARAMETERS on the manual iptables(8)) and extensions (see MATCH EXTENSIONS on the same manual). General rules are usually the same across different kernel versions. Match extensions depends on the running kernel and IP Tables version (remember that IP Tables is only a userland tool to interface with netfilter). It is possible to have the case where a certain rule exists in IP Tables but it's corresponding implementation is missing in the running kernel. In this case, trying to use such rule will fail.

General rules are:

Rule Description
-p PROTOCOL Specify an IP protocol (eg. TCP or UDP).
-s ADDRESS Specify a source address.
-d ADDRESS Specify a destination address.
-i INTERFACE Specify a local interface of incoming traffic.
-o INTERFACE Specify a local interface of outgoing traffic.

Match extensions will be treated to follow.

Target

A target specify the action to be taken when a certain packet match a certain rule. This target can be one of the default (should be available on all kernels) or one target extension (refer to TARGET EXTENSIONS at iptables(8)).

The default targets are:

Target Meaning
ACCEPT Allow the packet through.
DROP Instruct netfilter to ignore the packet.
QUEUE Pass the packet to userspace.
RETURN From the manual: “stop traversing this chain and resume at the next rule in the previous (calling) chain. If the end of a built-in chain is reached or a rule in a built-in chain with target RETURN is matched, the target specified by the chain policy determines the fate of the packet.”

In practice, most times you will be using either ACCEPT or DROP.

Writing rules

According to iptables(8), there are many ways to add / remove rules. All add rule actions, are discrete operation. This suggests the creation of a shell script containing all iptables(8) calls that compose the whole firewall. Remember to clean all pre-existing rules at the beginning of the script.

To add a single rule (at the end of the existing ones), follow this general form:

# iptables -t [TABLE] -A [CHAIN] [RULES] -j [TARGET]

Where:

Variable Meaning
TABLE Specify the table.
CHAIN Specify the chain.
RULES Packet selection rules.
TARGET Action to take place.

For example, to allow the network 192.168.0.0/24 connected through the network interface named eth0 to send traffic to the network 192.168.1.0/24, connected to the network interface eth1, one can write the following rule:

# iptables -t filter -A FORWARD -s 192.168.0.0/24 -d 192.168.1.0/24 -i eth0 -o eth1 -j ACCEPT

Follow the data flow on the above data flow graph to note that this rule would not be enough, since the packet flows through many other table / chains.

In the case that no rule matches a certain traffic, there is a way to set up a default policy to a certain table / chain. This default policy configure a target to be executed in the case no other terminative rule on the same target / table match the traffic. To define a default policy try:

# iptables -t [TABLE] -P [CHAIN] [TARGET]

For example:

# iptables -t raw -P OUTPUT ACCEPT

This rule will allow free traffic by default on the table raw, chain OUTPUT

Up to here, resources to control traffic are limited. The neTABELAxt topic will cover some extensions that give much more control / power over the firewall.

Match extensions

As said previously, there are match extensions that allow to better select packets. The general form is:

... -m [NAME] [OPTIONS]

where

Variable Meaning
NAME Name of the match extension in use.
OPTIONS Match extension options.

Please reffer to the topic MATCH EXTENSIONS of iptables(8) to get more information on available match extensions and its options.

Examples

Here are presented some common match extensions, that will be used most of the times.

tcp

Allow to specify a certain source / destination TCP port:

... -m tcp --dport www

This will match TCP connections which destination port is www (number 80, please reffer to /etc/services).

udp

Allow to specify a certain source / destination UDP port:

... -m udp --dport www

Connection tracking

IP Tables is a so called stateful firewall. This means it is possible to match all packets related to a certain connection, having no need to make a rule to allow packets going and another to allow packets coming from the same connection. This is direct for TCP connections, but there are extensions to allow UDP traffic windows, thus defining an “UDP connection”. Example:

# iptables -t filter -A FORWARD -d [WEB_SERVER] -i [EXTERNAL_INTERFACE] -o [INTERNAL_INTERFACE] -j ACCEPT
# iptables -t filter -A FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT

The first rule allows external traffic coming via EXTERNAL_INTERFACE to reach WEB_SERVER on INTERNAL_INTERFACE. The second rule says that any forwarding traffic related to an existing connection, will be allowed (eg. traffic coming from WEB_SERVER to EXTERNAL_INTERFACE). The match extension state tracks the connections, and matches the respective traffic. Note that in this case, all forwarding traffic related to a pre-existing connection will be allowed, not only the traffic from the first rule.

The connection tracking system from netfilter has many different modules, being able to track specific protocols, such as FTP, to allow related (data) connections to work with no additional rule or the need of a proxy server. In the case where no connection is defined (eg. UDP or ICMP) after the traffic goes, a window is opened to allow its return. Thus, everything works like if there was actually an “UDP connection”.

It is recommended to let a rule similar to the above second one. It is better to have a generic rule “catch all” than writing an specific connection rule for each traffic. Since this rule will not allow traffic if it was not allowed before, it is not security problem to do this. It is also recommended to allow ICMP traffic to flow freely.

Please refer to iptables manual to find out more about connection tracking and more uses of this tool.

Target Extensions

Target extensions allow some specialized actions and packet treatment to be done, such as NAT or load balancing. Please refer to iptables manual to know more about available target extensions. Here are some important ones:

  • LOG

This one allow to log (via kernel logging, you can see using the command dmesg) any message you wish when a certain packet matches. A good rule is to include a logging rule right before any rejected traffic. This way, finding out problems with your firewall is easy, as you can see what and when it is dropping something. This target accepts an option –log-prefix, that allow to prefix a text to each log message.

  • MASQUERADE, SNAT, DNAT

Those are three possibilities of implementing NAT (RFC1631). This way, it is possible to integrate a private network (RFC1918) to the internet with no problems. Please refer to the manual on the use of each target.

Advanced Routing

Linux has a different approach for routing than other UNIX. The way things are implemented on Linux is more flexible and powerful than traditional ways. Legacy utilities such as ifconfig and route are still valid, but incomplete. This is because they do not give access to the advanced routing layer present on Linux. The utility ip (part of iproute2) is the current tool for networking related stuff under Linux. This tool will be the focus of this section.

Linux advanced routing is implemented in two parts:

  1. Rules

It is possible to have multiple routing tables under Linux and the rules indicate when to use each one of them.

Rules

To list existing routing rules, one can try:

# ip rule list
0:	from all lookup local 
32766:	from all lookup main 
32767:	from all lookup default

Rules are processed in increasing priority (1st) column). In the above case, priority 0 rule instruct the kernel to look for a routing decision inside table named local for traffic comming from any origin. The content of this table can be accessed via:

# ip route list table local
local 192.168.1.1 dev eth3  proto kernel  scope host  src 192.168.1.1 
local 200.170.111.237 dev eth0  proto kernel  scope host  src 200.170.111.233 
broadcast 192.168.1.0 dev eth3  proto kernel  scope link  src 192.168.1.1 
broadcast 192.168.2.255 dev eth1  proto kernel  scope link  src 192.168.2.1 
local 200.170.111.236 dev eth0  proto kernel  scope host  src 200.170.111.233 
broadcast 127.255.255.255 dev lo  proto kernel  scope link  src 127.0.0.1 
broadcast 200.170.111.239 dev eth0  proto kernel  scope link  src 200.170.111.233 
local 200.170.111.239 dev eth0  proto kernel  scope host  src 200.170.111.233 
local 200.170.111.238 dev eth0  proto kernel  scope host  src 200.170.111.233 
local 200.170.111.233 dev eth0  proto kernel  scope host  src 200.170.111.233 
broadcast 200.170.111.232 dev eth0  proto kernel  scope link  src 200.170.111.233 
local 200.170.111.235 dev eth0  proto kernel  scope host  src 200.170.111.233 
local 201.20.202.11 dev eth0  proto kernel  scope host  src 201.20.202.11 
broadcast 201.6.149.0 dev eth2  proto kernel  scope link  src 201.6.149.41 
local 200.170.111.234 dev eth0  proto kernel  scope host  src 200.170.111.233 
local 192.168.2.1 dev eth1  proto kernel  scope host  src 192.168.2.1 
broadcast 192.168.1.255 dev eth3  proto kernel  scope link  src 192.168.1.1 
broadcast 192.168.2.0 dev eth1  proto kernel  scope link  src 192.168.2.1 
broadcast 201.20.207.255 dev eth0  proto kernel  scope link  src 201.20.202.11 
broadcast 201.20.200.0 dev eth0  proto kernel  scope link  src 201.20.202.11 
broadcast 127.0.0.0 dev lo  proto kernel  scope link  src 127.0.0.1 
broadcast 201.6.149.255 dev eth2  proto kernel  scope link  src 201.6.149.41 
local 201.6.149.41 dev eth2  proto kernel  scope host  src 201.6.149.41 
local 127.0.0.1 dev lo  proto kernel  scope host  src 127.0.0.1 
local 127.0.0.0/8 dev lo  proto kernel  scope host  src 127.0.0.1

This table is long, but is managed by the kernel itself, thus, do not worry about it. This table contains information regarding local addresses (the ones associated with network interfaces), informing that they are resolved locally.

In the case the table does not solve a certain destination address (eg. traffic to another machine in this case), Linux kernel look for the next rule with lower priority (higher priority number) to find out a routing solution. In this case, the next rule is the one with priority 32766, which says to go to table main:

# ip route list table main
200.170.111.232/29 dev eth0  proto kernel  scope link  src 200.170.111.233 
192.168.2.0/24 dev eth1  proto kernel  scope link  src 192.168.2.1 
192.168.1.0/24 dev eth3  proto kernel  scope link  src 192.168.1.1 
201.6.149.0/24 dev eth2  proto kernel  scope link  src 201.6.149.41 
201.20.200.0/21 dev eth0  proto kernel  scope link  src 201.20.202.11 
default via 201.6.149.1 dev eth2 

This table contain exactly the same information displayed by the route command:

# route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
200.170.111.232 0.0.0.0         255.255.255.248 U     0      0        0 eth0
192.168.2.0     0.0.0.0         255.255.255.0   U     0      0        0 eth1
192.168.1.0     0.0.0.0         255.255.255.0   U     0      0        0 eth3
201.6.149.0     0.0.0.0         255.255.255.0   U     0      0        0 eth2
201.20.200.0    0.0.0.0         255.255.248.0   U     0      0        0 eth0
0.0.0.0         201.6.149.1     0.0.0.0         UG    0      0        0 eth2

So, this table contains the traditional routing information. The last table named default comes empty (try it).

The rules and tables described here contain all the traditional routing information. It is possible however to insert new rules and new tables to fit demands of a more complex environment.

Custom Rules

One can for example, add a rule specifying that traffic from a certain source must be routed using a specific routing table:

# ip rule add type unicast from 192.168.4.0/24 priority 55 table 55

This will instruct the kernel to when it finds traffic coming from 192.168.4.0/24 network, look for a routing solution inside table number 55, with priority 55. The table 55 must be created containing routing information regarding only to the source network in question. In this case:

# ip rule list
0:	from all lookup local 
55:    from 192.168.4.0/24 lookup 55
32766:	from all lookup main 
32767:	from all lookup default

Note that priority number 55 and table number 55 are absolutely arbitrary and have no need to be the same number. These numbers must only make sense to fit your routing needs.

Please look at ip manual to obtain more information on how to add or remove rules and all possible parameters.

Tables

Routing tables are identified by numbers from 0 to 255. Tables local and main have the numbers 255 and 254 associated with it. There is a configuration file that one can associate a name to each table number (as for local and main) that will not be covered by this article.

The existence of a table containing routing rules inside does not imply that it is in use. A table will only be used if there is a rule pointing to it.

Please consult ip manual on how to add routing rules inside tables. It should not be a problem, since its operation is similar to classic routing utility route.

Note

Linux kernel comes with an anti-spoof protection apart from firewall. This protection protects an internal network against external attacks. Depending on the routing situation you need (specially when connected to multiple ISPs) this setting must be disable in order for your routing rules to work.

This option is accessible vis sysctl

net.ipv4.conf.all.rp_filter 

which changes configuration for all network interfaces. There is also the possibility to enable / disable by interface (substituting .all by .eth0 for example, to change only interface eth0).

The line:

net.ipv4.conf.all.rp_filter=0

at /etc/sysctl.conf, should disable this feature at boot time. Please refer to distribution specific settings.

Integrating Firewall and Routing

One possible routing rule matching filter is fwmark. This option makes packets marked by the firewall to be matched and fall into desired table.

# ip rule list
0:	from all lookup local 
33:	from all fwmark 0x1 lookup 33 
32766:	from all lookup main 
32767:	from all lookup default 

In this case, packets marked as 0x1 by the firewall (0x1 is 1 noted in hexa-decimal) to be solved by the table numbered 33. The number 0x1 is absolutely arbitrary.

It is important to know that this mark is local and internal to the Linux kernel and in any way alters the packets.

Marking packets

To mark a packet with iptables, use the target MARK:

# iptables -t mangle -A PREROUTING -i eth0 -j MARK --set-mark 1

In this example, all traffic coming through interface eth0 will be marked as 1 (an arbitrary number). After this, it is possible to include a routing rule matching these packets, as explained on the previous topic. Thus, this iptables rule and the routing rule will make specific routing for packets coming by interface eth0.

Note by the above iptables fluxogram that the mark is being done before routing table. In this case, traffic is entering the machine, thus the PREROUTING. In the case you wish to mark traffic generated locally, you should use the OUTPUT chain.

Connections

It is also possible to mark all packets related to a connection. The target CONNMARK allows marking of a connection (referred as connection mark, internal to the firewall), that is not the same marking seen by routing (referred as netfilter mark, accessible by routing rules), do not confuse them. Thus, one can make the following to mark packets of a connection to the routing rules:

# iptables -t mangle -A OUTPUT -d SERVER -j CONNMARK --set-mark 1
# iptables -t mangle -A OUTPUT -m connmark --mark 1 -j MARK --set-mark 1

The first rule mark all desired connections. The second rule uses the match extension -m connmark to identify those connection marks and create netfilter marks by using the target MARK (to be saved by routing rules).

linux/networking/firewall_and_routing.txt · Last modified: 2011/10/04 21:58 by Nathan Martin
 
Except where otherwise noted, content on this wiki is licensed under the following license: CC Attribution-Noncommercial-Share Alike 4.0 International
Recent changes RSS feed Donate Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki