Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Connection Tracking (conntrack)

Overview

Connection tracking (conntrack) is the netfilter subsystem that monitors and tracks the state of all network connections passing through the Linux kernel. It examines every packet to determine which connection it belongs to and what state that connection is in. conntrack is the foundation for stateful firewalls (nftables, iptables), NAT, and ALG (Application Layer Gateways).

conntrack tracks connections for TCP, UDP, ICMP, and other protocols by maintaining a hash table of connection entries (nf_conn). Each entry records the source/destination addresses, ports, protocol state, and timestamps.

Source: net/netfilter/nf_conntrack_core.c
Module: nf_conntrack
Key structures: struct nf_conn, struct nf_conntrack_tuple


Architecture

flowchart TD
    subgraph Netfilter["Netfilter Hooks"]
        PRE["PREROUTING"]
        IN["INPUT"]
        FWD["FORWARD"]
        OUT["OUTPUT"]
        POST["POSTROUTING"]
    end

    subgraph Conntrack["conntrack"]
        CT_IN["conntrack_in<br>(NEW/ESTABLISHED detection)"]
        CT_CONFIRM["conntrack_confirm<br>(confirm entry)"]
        CT_HELPER["conntrack_helper<br>(ALG support)"]
        CT_NAT["NAT integration<br>(SNAT/DNAT)"]
    end

    subgraph HashTable["nf_conn Hash Table"]
        ENTRY1["nf_conn: TCP 192.168.1.1:1234 → 10.0.0.1:80 ESTABLISHED"]
        ENTRY2["nf_conn: UDP 192.168.1.1:5678 → 8.8.8.8:53 ASSURED"]
        ENTRY3["nf_conn: ICMP 192.168.1.1 → 10.0.0.1 echo/reply"]
    end

    PRE --> CT_IN
    CT_IN --> IN
    IN --> FWD
    FWD --> POST
    POST --> CT_CONFIRM
    CT_IN --> HashTable
    CT_CONFIRM --> HashTable
    CT_HELPER --> CT_IN
    CT_NAT --> CT_IN

Connection States

Generic States (All Protocols)

StateMeaning
NEWFirst packet seen, no reply yet
ESTABLISHEDReply packet seen (bidirectional traffic confirmed)
RELATEDNew connection related to an existing one (e.g., FTP data channel)
INVALIDPacket doesn’t belong to any known connection

TCP-Specific States

TCP tracking is more granular, following the TCP state machine:

stateDiagram-v2
    [*] --> SYN_SENT: SYN
    SYN_SENT --> SYN_RECV: SYN+ACK
    SYN_RECV --> ESTABLISHED: ACK
    ESTABLISHED --> FIN_WAIT: FIN
    FIN_WAIT --> CLOSE_WAIT: FIN
    CLOSE_WAIT --> LAST_ACK: FIN
    LAST_ACK --> TIME_WAIT: ACK
    TIME_WAIT --> [*]: timeout
    ESTABLISHED --> [*]: RST
conntrack TCP StateTCP FlagMeaning
SYN_SENTSYNConnection initiated
SYN_RECVSYN+ACKSYN acknowledged
ESTABLISHEDACKConnection established
FIN_WAITFINClosing initiated
CLOSE_WAITFIN receivedRemote closing
LAST_ACKFIN+ACKFinal close
TIME_WAITACKWaiting for stray packets
NONEUnknown state

Key Data Structures

struct nf_conn

Each tracked connection is represented by:

/* include/net/netfilter/nf_conntrack.h */
struct nf_conn {
    struct nf_conntrack ct_general;    /* Refcount, extension list */

    /* Tuple hash entries (reply and original direction) */
    struct nf_conntrack_tuple_hash tuplehash[IP_CT_DIR_MAX];

    /* Connection status (IPS_*) */
    unsigned long status;

    /* Timeout in jiffies */
    unsigned long timeout;

    /* Protocol-specific data (TCP state, etc.) */
    union nf_conntrack_proto proto;

    /* NAT manipulation data */
    struct nf_conn_nat __rcu *nat;

    /* Helper (ALG) */
    struct nf_conn_help __rcu *helper;

    /* Mark and labels */
    u32 mark;
    u32 secmark;

    /* Extension list (labels, timeout, acct, etc.) */
    struct nf_ct_ext *ext;
};

Connection Status Bits (IPS_*)

/* include/uapi/linux/netfilter/nf_conntrack_common.h */
enum ip_conntrack_info {
    IP_CT_NEW,            /* New connection */
    IP_CT_RELATED,        /* Related to existing connection */
    IP_CT_ESTABLISHED,    /* Established connection */
    IP_CT_IS_REPLY,       /* Reply direction */
    /* ... */
};

/* Connection status flags */
IPS_SEEN_REPLY_BIT      /* Reply packet seen */
IPS_ASSURED_BIT         /* Connection is assured (won't be evicted) */
IPS_CONFIRMED_BIT       /* Entry is in the hash table */
IPS_SRC_NAT_BIT         /* Source NAT applied */
IPS_DST_NAT_BIT         /* Destination NAT applied */
IPS_DYING_BIT           /* Entry is being destroyed */
IPS_FIXED_TIMEOUT_BIT   /* Timeout is fixed (not refreshed) */

Conntrack Tuple

A tuple uniquely identifies a packet’s 5-tuple:

/* include/net/netfilter/nf_conntrack_tuple.h */
struct nf_conntrack_tuple {
    struct nf_conntrack_man src;    /* Source: addr + port + ID */
    struct {
        union nf_inet_addr u3;     /* Destination IP */
        union {
            __be16 tcp;             /* TCP port */
            __be16 udp;             /* UDP port */
            struct {
                __be16 id;          /* ICMP ID */
                u8 type;            /* ICMP type */
                u8 code;            /* ICMP code */
            } icmp;
            /* ... */
        } u;
        u8 protonum;                /* Protocol number */
    } dst;                          /* Destination */
};

Hash Table

conntrack uses a hash table for fast tuple lookup:

/* net/netfilter/nf_conntrack_core.c */
static struct nf_conntrack_hash nf_conntrack_hash;

/* Hash function: based on source/dest IP, ports, protocol */
static u32 hash_conntrack(const struct net *net,
                          const struct nf_conntrack_tuple *tuple)
{
    /* ... */
    return reciprocal_scale(hash, nf_conntrack_hash_size);
}

Conntrack Lifecycle

1. First Packet (NEW)

sequenceDiagram
    participant Pkt as Packet
    participant CT as conntrack_in()
    participant Hash as Hash Table
    participant HLP as Helper

    Pkt->>CT: Packet arrives at PREROUTING
    CT->>Hash: Lookup tuple in hash table
    Hash-->>CT: Not found (NEW connection)
    CT->>CT: Create new nf_conn entry
    CT->>CT: Set timeout (tcp: 120s, udp: 30s)
    CT->>HLP: Call helper if protocol matches
    CT->>Hash: Insert into hash table (unconfirmed)
    CT-->>Pkt: Return NF_ACCEPT

2. Confirmed (at POSTROUTING or LOCAL_IN)

/* net/netfilter/nf_conntrack_core.c */
int nf_conntrack_confirm(struct sk_buff *skb)
{
    struct nf_conn *ct = (struct nf_conn *)skb_nfct(skb);

    /* Mark as confirmed */
    if (!nf_ct_is_confirmed(ct)) {
        nf_ct_del_from_dying_unconfirmed_list(ct);
        __nf_conntrack_hash_insert(ct, hash, reply_hash);
        set_bit(IPS_CONFIRMED_BIT, &ct->status);
    }
    return NF_ACCEPT;
}

3. Subsequent Packets (ESTABLISHED)

sequenceDiagram
    participant Pkt as Reply Packet
    participant CT as conntrack_in()
    participant Hash as Hash Table

    Pkt->>CT: Reply packet arrives
    CT->>Hash: Lookup reply tuple
    Hash-->>CT: Found! (existing connection)
    CT->>CT: Set IPS_SEEN_REPLY
    CT->>CT: Refresh timeout
    CT->>CT: Mark ESTABLISHED
    CT-->>Pkt: Return NF_ACCEPT

4. Timeout and Cleanup

Each connection entry has a timeout. If no packets are seen within the timeout, the entry is evicted:

ProtocolDefault Timeout
TCP established5 days (432000s)
TCP SYN_SENT120s
TCP SYN_RECV60s
TCP TIME_WAIT120s
UDP30s
ICMP30s
Generic120s

Conntrack Helpers (ALG)

Helpers track related connections that can’t be determined from the packet header alone:

FTP Helper

/* net/netfilter/nf_conntrack_ftp.c */
static struct nf_conntrack_helper ftp[MAX_PORTS] = {
    {
        .name = "ftp",
        .me = THIS_MODULE,
        .tuple.src.l3num = NFPROTO_IPV4,
        .tuple.dst.protonum = IPPROTO_TCP,
        .tuple.src.u.tcp.port = htons(21),
        .help = ftp_help,          /* Parse PORT/PASV commands */
        .expect_policy = &ftp_exp_policy,
    },
};

Supported Helpers

ProtocolModuleWhat it Tracks
FTPnf_conntrack_ftpData channel (PORT/PASV)
SIPnf_conntrack_sipRTP media streams
TFTPnf_conntrack_tftpData transfers
H.323nf_conntrack_h323Call signaling + media
PPTPnf_conntrack_pptpGRE tunnels
NFSnf_conntrack_nfsRPC callbacks

Helper Loading

# Load FTP helper
modprobe nf_conntrack_ftp

# Check loaded helpers
lsmod | grep nf_conntrack_

# Enable helper for a connection (nftables)
nft add rule ip filter input tcp dport 21 ct helper set "ftp"

Conntrack Marks (connmark)

conntrack marks allow labeling connections for routing or policy decisions:

# Mark a connection (iptables)
iptables -t mangle -A PREROUTING -p tcp --dport 80 -j CONNMARK --set-mark 1

# Restore connection mark to packet
iptables -t mangle -A PREROUTING -j CONNMARK --restore-mark

# Save packet mark to connection
iptables -t mangle -A POSTROUTING -j CONNMARK --save-mark

# nftables equivalent
nft add rule ip mangle prerouting tcp dport 80 ct mark set 1

Monitoring and Debugging

conntrack Tool

# List all tracked connections
conntrack -L

# Count connections
conntrack -C

# Watch real-time connection events
conntrack -E

# Filter by state
conntrack -L -p tcp --state ESTABLISHED

# Filter by source IP
conntrack -L -s 192.168.1.1

# Show specific connection
conntrack -L -p tcp --dport 80

/proc/net/nf_conntrack

# Raw conntrack table
cat /proc/net/nf_conntrack

# Example entry:
# tcp  6 431998 ESTABLISHED src=192.168.1.1 dst=10.0.0.1 sport=12345 dport=80
#   src=10.0.0.1 dst=192.168.1.1 sport=80 dport=12345 [ASSURED] mark=0 use=1

# Conntrack statistics
cat /proc/net/stat/nf_conntrack
# entries  found  new  invalid  ignore  delete  delete_list  insert  insert_failed  drop  early_drop  error  search_restart
# 1234     56789  123  5        67      89      90           123     0              0     0           0      45

sysfs Conntrack Parameters

# Maximum tracked connections
cat /proc/sys/net/netfilter/nf_conntrack_max
# Default: 65536 (auto-scaled on high-mem systems)
echo 262144 > /proc/sys/net/netfilter/nf_conntrack_max

# Hash table size
cat /proc/sys/net/netfilter/nf_conntrack_buckets
# Default: nf_conntrack_max / 4
echo 65536 > /proc/sys/net/netfilter/nf_conntrack_buckets

# Timeout per protocol
cat /proc/sys/net/netfilter/nf_conntrack_tcp_timeout_established
# Default: 432000 (5 days)
echo 3600 > /proc/sys/net/netfilter/nf_conntrack_tcp_timeout_established

# UDP timeout
cat /proc/sys/net/netfilter/nf_conntrack_udp_timeout
# Default: 30

Conntrack Timeout Sysctls

# TCP timeouts
/proc/sys/net/netfilter/nf_conntrack_tcp_timeout_syn_sent        # 120
/proc/sys/net/netfilter/nf_conntrack_tcp_timeout_syn_recv        # 60
/proc/sys/net/netfilter/nf_conntrack_tcp_timeout_established     # 432000
/proc/sys/net/netfilter/nf_conntrack_tcp_timeout_fin_wait        # 120
/proc/sys/net/netfilter/nf_conntrack_tcp_timeout_close_wait      # 60
/proc/sys/net/netfilter/nf_conntrack_tcp_timeout_last_ack        # 30
/proc/sys/net/netfilter/nf_conntrack_tcp_timeout_time_wait       # 120
/proc/sys/net/netfilter/nf_conntrack_tcp_timeout_close           # 10

# Other protocol timeouts
/proc/sys/net/netfilter/nf_conntrack_udp_timeout                 # 30
/proc/sys/net/netfilter/nf_conntrack_udp_timeout_stream          # 120
/proc/sys/net/netfilter/nf_conntrack_icmp_timeout                # 30
/proc/sys/net/netfilter/nf_conntrack_generic_timeout             # 120

Tuning for High-Connection-Rate Environments

Web Servers / Load Balancers

# Increase max connections
echo 1048576 > /proc/sys/net/netfilter/nf_conntrack_max

# Increase hash table size (must be set before loading module)
echo 262144 > /sys/module/nf_conntrack/parameters/hashsize
# Or at module load:
modprobe nf_conntrack hashsize=262144

# Reduce TCP established timeout (don't keep stale entries for 5 days)
echo 3600 > /proc/sys/net/netfilter/nf_conntrack_tcp_timeout_established

# Reduce TIME_WAIT timeout
echo 30 > /proc/sys/net/netfilter/nf_conntrack_tcp_timeout_time_wait

# Reduce UDP timeout for DNS
echo 10 > /proc/sys/net/netfilter/nf_conntrack_udp_timeout

DDoS Mitigation

# Reduce SYN_RECV timeout (detect SYN floods faster)
echo 15 > /proc/sys/net/netfilter/nf_conntrack_tcp_timeout_syn_recv

# Enable conntrack accounting
echo 1 > /proc/sys/net/netfilter/nf_conntrack_log_invalid

# Consider using raw table to bypass conntrack for trusted traffic
iptables -t raw -A PREROUTING -s 10.0.0.0/8 -j NOTRACK
iptables -t raw -A OUTPUT -d 10.0.0.0/8 -j NOTRACK

Monitoring Conntrack Usage

# Current entries vs max
echo "Entries: $(conntrack -C) / $(cat /proc/sys/net/netfilter/nf_conntrack_max)"

# Monitor for table full
dmesg | grep "nf_conntrack: table full"
# This means packets are being dropped!

# Conntrack events (real-time monitoring)
conntrack -E | head -20

Conntrack and NAT

conntrack is required for NAT. Each NAT rule must be associated with a conntrack entry:

# SNAT (source NAT)
iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE

# DNAT (destination NAT)
iptables -t nat -A PREROUTING -p tcp --dport 8080 -j DNAT --to-destination 10.0.0.1:80

# nftables NAT
nft add rule ip nat prerouting tcp dport 8080 dnat to 10.0.0.1:80
nft add rule ip nat postrouting oifname "eth0" masquerade

NAT and conntrack Flow

sequenceDiagram
    participant Client as Client
    participant CT as conntrack
    participant NAT as NAT
    participant Server as Server

    Client->>CT: SYN 192.168.1.1:1234 → 10.0.0.1:80
    CT->>CT: Create conntrack entry (NEW)
    NAT->>NAT: SNAT: rewrite src to 203.0.113.1:54321
    NAT->>Server: SYN 203.0.113.1:54321 → 10.0.0.1:80

    Server->>CT: SYN+ACK 10.0.0.1:80 → 203.0.113.1:54321
    CT->>CT: Match reply tuple (ESTABLISHED)
    NAT->>NAT: Reverse NAT: rewrite dst to 192.168.1.1:1234
    NAT->>Client: SYN+ACK 10.0.0.1:80 → 192.168.1.1:1234

Conntrack in Containers

In container environments (Docker, Kubernetes), conntrack is heavily used for:

  • Container-to-container networking
  • Service load balancing (kube-proxy)
  • NAT for pod networking

Kubernetes conntrack Tuning

# Kubernetes recommends:
echo 131072 > /proc/sys/net/netfilter/nf_conntrack_max
echo 32768 > /sys/module/nf_conntrack/parameters/hashsize

# For high-traffic clusters:
echo 524288 > /proc/sys/net/netfilter/nf_conntrack_max
echo 131072 > /sys/module/nf_conntrack/parameters/hashsize

# Reduce timeouts for ephemeral connections
echo 300 > /proc/sys/net/netfilter/nf_conntrack_tcp_timeout_established
echo 30 > /proc/sys/net/netfilter/nf_conntrack_tcp_timeout_time_wait

Common Issues

“nf_conntrack: table full” Drops

Symptom: dmesg shows “nf_conntrack: table full, dropping packet”.

Cause: Too many connections for the configured max.

Solutions:

  • Increase nf_conntrack_max
  • Increase hash table size
  • Reduce timeout values
  • Use NOTRACK for trusted/internal traffic

Conntrack Hash Contention

Symptom: High CPU usage in softirq, lock contention on conntrack hash.

Cause: Too many connections for the hash table size.

Solutions:

  • Increase hashsize parameter
  • Use per-CPU conntrack (enabled by default in modern kernels)

Connection Tracking Overhead

Symptom: Packet processing overhead from conntrack.

Solutions:

  • Disable conntrack for internal/trusted traffic using NOTRACK
  • Use raw table to bypass conntrack
  • Consider nftables flow offload for hardware-accelerated tracking

Source Files

FileContents
net/netfilter/nf_conntrack_core.cCore conntrack logic
net/netfilter/nf_conntrack_proto_tcp.cTCP state tracking
net/netfilter/nf_conntrack_proto_udp.cUDP tracking
net/netfilter/nf_conntrack_helper.cALG helpers
net/netfilter/nf_conntrack_netlink.cNetlink interface
include/net/netfilter/nf_conntrack.hCore data structures
net/netfilter/nf_conntrack_standalone.cproc/sysfs interfaces

Further Reading


See Also