Netfilter Connmark

Introduction

CONNMARK is a cool feature of Netfilter. It provides a way to have a mark which is linked to the a connection tracking entry. Once a connmark is set, it also apply for RELATED connection entry. So, if you add a connmark to an FTP connection, the same connmark will be put of connections from ftp-data.

All Linux tools (for QoS or routing) are only able to use a mark put on packet. Thus, to be really useful, CONNMARK has the capability to transfer the connection mark to the packet mark (and reverse). This can be used to established connection persistent decision for QoS or routing.

More information is available on the netfilter site. It is available in all Linux kernel since 2.6.12.

Prerequisites

Code examples

A simple example

First here’s the code :

iptables -A POSTROUTING -t mangle -j CONNMARK --restore-mark
iptables -A POSTROUTING -t mangle -m mark ! --mark 0 -j ACCEPT
iptables -A POSTROUTING -p tcp --dport 21 -t mangle -j MARK --set-mark 1
iptables -A POSTROUTING -p tcp --dport 80 -t mangle -j MARK --set-mark 2
iptables -A POSTROUTING -t mangle -j CONNMARK --save-mark

The process is the following :

  1. We restore the mark following the CONNMARK mark. In fact, it does a simple MARK=CONNMARK where MARK is the standard mark (usable by tc)
  2. If we’ve got a mark no need to get further[1].
  3. We mark tcp packets with destination port 21 with MARK 1.
  4. We mark tcp packet with destination port 80.
  5. We set the mark of the initial packet as value of the conntrack mark for all the packets of the connection. This mark will be restore for the other packets by the first rule of POSTROUTING (–restore-mark).

A complete example

If you want to do a garbage (or use imbricated filters), you can do so by sorting rule from the more specific to the less specific :

iptables -A POSTROUTING -t mangle -j CONNMARK --restore-mark
iptables -A POSTROUTING -t mangle -m mark ! --mark 0 -j ACCEPT
iptables -A POSTROUTING -m mark --mark 0 -p tcp --dport 21 -t mangle -j MARK --set-mark 1
iptables -A POSTROUTING -m mark --mark 0 -p tcp --dport 80 -t mangle -j MARK --set-mark 2
iptables -A POSTROUTING -m mark --mark 0 -t mangle -p tcp -j MARK --set-mark 3
iptables -A POSTROUTING -t mangle -j CONNMARK --save-mark

We use -m mark –mark 0 to prevent an already put mark to be overwritten by a more generic filter.

The second line is optional but it’s a shortcut because all packets relative to an established connection are only tested once.

Related Tips

Connmark and ingress

If you use an ingress policy you can take advantage of CONNMARK by restoring the mark in the PREROUTING chain. So you can use :

iptables -A PREROUTING -t mangle -j CONNMARK --restore-mark

A modified ip_conntrack file

After loading of the connmark module, the file /proc/net/ip_conntrack contains the indication of the connmark :

tcp      6 432000 ESTABLISHED src=62.212.98.117 dst=XXX.XXX.XXX.XXX sport=35027 dport=22 \\
src=217.15.82.6 dst=62.212.98.117 sport=22 dport=35027 [ASSURED] use=1 mark=0
udp      17 24 src=127.0.0.1 dst=127.0.0.1 sport=1024 dport=53 [UNREPLIED] src=127.0.0.1 \\
dst=127.0.0.1 sport=53 dport=1024 use=1 mark=0

Accounting with ip_conntrack

It is easy to replace iptables -A POSTROUTING -t mangle -m mark ! –mark 0 -j ACCEPT by

iptables -A POSTROUTING -t mangle -m mark  --mark 1 -j ACCEPT
iptables -A POSTROUTING -t mangle -m mark  --mark 2 -j ACCEPT
...

With that, a simple iptables -L POSTROUTING -t mangle -v gives you a perfect counter for each flow. And as mentioned before it does also account the traffic of RELATED connections in the category of the parent connection.

There is still a problem since we loose the first packet of each connections. Thus it is necessary to add the counters of the –set-mark and of the related ACCEPT lines.