Skip to content

/flags/iptables/iptables-m-conntrack-ctstate

iptables -m conntrack --ctstate ESTABLISHED,RELATED: allow reply traffic

The commands on this page have not been executed by our verification runner yet.updated
tool
iptables / nftables
command
iptables
flag
-m conntrack --ctstate STATES
default
none (without the match, rules do not look at the connection state)

iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT accepts every packet that belongs to, or is related to, a connection the kernel's connection tracker already knows. It is the rule that makes a firewall stateful: you open only the ports for new incoming connections, and replies to traffic your host started (DNS answers, HTTP responses, package downloads) are allowed automatically. -m conntrack loads the conntrack match, and --ctstate takes a comma-separated list of states.

A minimal stateful INPUT chain

bash
sudo iptables -A INPUT -i lo -j ACCEPT
sudo iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
sudo iptables -A INPUT -m conntrack --ctstate INVALID -j DROP
sudo iptables -A INPUT -p tcp --dport 22 -m conntrack --ctstate NEW -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 443 -m conntrack --ctstate NEW -j ACCEPT
sudo iptables -P INPUT DROP

The ESTABLISHED,RELATED rule comes first because it matches the vast majority of packets; order matters, see iptables -I vs -A. Set the DROP policy last, after the SSH rule exists, or a remote session is cut off.

States

The iptables-extensions manual defines these states for --ctstate:

StateMeaning
NEWThe packet starts a new connection, or belongs to one that has not seen packets in both directions
ESTABLISHEDThe packet belongs to a connection that has seen packets in both directions
RELATEDThe packet starts a new connection associated with an existing one, such as an FTP data channel or an ICMP error
INVALIDThe packet is associated with no known connection
UNTRACKEDThe packet is not tracked, because a raw-table rule used -j CT --notrack
SNAT / DNATVirtual states: the original source or destination differs from the reply (NAT was applied)

A ! before --ctstate negates the list, for example ! --ctstate NEW.

Other conntrack options

-m conntrack can also match --ctproto, --ctorigsrc/--ctorigdst, --ctreplsrc/--ctrepldst, the matching port options, --ctstatus (EXPECTED, SEEN_REPLY, ASSURED, CONFIRMED), --ctexpire and --ctdir ORIGINAL|REPLY. They are useful on NAT gateways, where the original and the translated addresses differ.

Pitfalls

  • Module not available. On kernels or containers without the conntrack modules, the rule fails with No chain/target/match by that name.
  • conntrack table full. Busy servers can exhaust nf_conntrack_max; the kernel then logs nf_conntrack: table full, dropping packet. Raise the limit or exempt high-volume traffic with -j CT --notrack in the raw table.
  • Rules are not persistent. Save them as described in save and restore rules.
  • nftables equivalent. ct state established,related accept does the same in nftables; see iptables vs nftables.

FAQ

What is the difference between -m state --state and -m conntrack --ctstate?

Both match the connection tracking state. The state match is the older, narrower module; conntrack is its superset and also matches original and reply addresses, ports and statuses. New rules should use -m conntrack --ctstate.

Why are replies to my outgoing connections dropped?

With a DROP policy on INPUT, reply packets need a rule that accepts them. Without an ESTABLISHED,RELATED accept, every reply is treated like unsolicited traffic and dropped, so DNS lookups and package downloads from the host fail.

Should I drop INVALID packets?

Usually yes: -m conntrack --ctstate INVALID -j DROP discards packets that belong to no known connection, such as stray TCP segments, before other rules see them.

Sources