Connection Tracking TCP — Iptables

April 18, 2006 — Nikesh

A tcp connection is initiated via a three-way handshake involving a synchronization request from the client, a synchronization and an acknowledgement from the server, and finally an acknowledgement from the client. Subsequent traffic flowing between server and client is acknowledged in all cases. The sequence looks like:

ClientServer

SYN---->

SYN+ACK

ACK---->

ACK

you need a rule that looks something like this:

iptables -A INPUT -p tcp -m state –state ESTABLISHED -j ACCEPT

iptables -A OUTPUT -p tcp -m state –state NEW,ESTABLISHED -j ACCEPT

Walkthrough

What we are going to do now is walk and talk through the establishment of a normal tcp connection and look at the state table at each stage:

Once an initial SYN is sent in the OUTPUT chain, and accepted by out rule that allows the NEW connection, the connection table entry may look something like:

We are now waiting for the final part of the handshake, an ACK. When it is seen by the connection tracking module, we check that it’s sequence number matches the ACK of the SYN+ACK handshake from the server to the client. The tcp connection state now becomes ESTABLISHED and the state table entry is marked ASSURED (ASSURED connections are not dropped from the state table when the connection is under load). Here we see the ESTABLISHED connection:

Connection tracking’s perspective on the state table

We just talked a lot about tcp connection states. Now let’s think about this from the perspective of the connection tracking:

Connection tracking only knows about NEW,ESTABLISHED,RELATED and INVALID, classified as described above. To quote Joszef Kadlecsik, who helped me out with a confusion I had initially about this very subject:

When a packet with the SYN+ACK flags set arrrives in response to a packet with SYN set the connection tracking thinks: “I have been just seeing a packet with SYN+ACK which answers a SYN I had previously seen, so this is an ESTABLISHED connection.”

The important point here is that the conntrack states are not equivalent to tcp states. We have already seen that a connection doesn’t achieve the tcp connection status of ESTABLISHED until the ACK after the SYN+ACK has been seen by the connection tracking module.

The representation of the tcp connection states in the state table is purely for timeouts. You can prove this to yourself by sending an ACK packet through your firewall to a non-existent machine (so that you don’t get the RST back). It will create a state table entry no problem because it it is the first packet of a connection and so is treated as NEW (the entry will not be marked as ASSURED though). Checkpoint’s Firewall-1 version 4.1 SP1 allows connection initiation by ACK packets too .

In the light of the fact that ACK packets can create state table entries, the following contribution from Henrik Nordstrum is insightful: To make sure that NEW tcp connections are packets with SYN set, use the following rule:

iptables -A INPUT-p tcp ! –syn -m state –state NEW-j DROP

Note that doing this will prevent idle sessions from continuing once they have expired from the conntrack table. In the normal “relaxed” view such connections initiated from the correct direction (i.e. the direction you allow NEW packets through) can normally continue even if expired from conntrack, provided that the first data/ack packet that resumes the connection comes from the correct direction.

Timeouts

Something to note is that timeouts are reset to the maximum each time a connection sees traffic. Timeouts are set in the kernel at compile time.

Connection Termination

Connection termination occurs in two ways. Natural termination at the end of a session occurs when the client sends a packet with the FIN and ACK flags set. The closure proceeds as follows:

ClientServer

FIN+ACK---->

ACK

FIN+ACK

ACK---->

Sometime during, or at the end of this sequence the state table connection status changes to TIME_WAIT and the entry is removed after 2 minutes by default.

Another way for connection termination to occur is if either party sends a packet with the RST (reset) flag set. RST’s are not acknowledged. In this case the state table connection status changes to CLOSE and times out from the state table after 10 seconds. This often happens with http entries, where the server sends an RST after a period of inactivity.