[nftables] conntrack behavior wondering

Mathias Dufresne
2026-03-02T19:57:55Z

Hi everyone,

I don't understand conntrack behavior while forwarding packets. For me a
packet kept its status of being new, related or established all the way,
until it reached the target.

Below is the configuration I tested. In that configuration input,
forward and output are:

- accepting related and established packets

- jumping to service chain

- dropping everything after logging the drop.

This configuration allows SSH connection correctly but in a strange manner:

- SSH to the firewall (10.91.62.172/32) works well and generates only
one log, the on from chain ip_log_svc_administrative_services/ssh which
logs NEW packet from input hook.

- SSH through the firewall works (the connection works) but logs are
strange (to me at least) as :

- no logs from chain ip_log_svc_administrative_services/ssh which
logs NEW packet from input hook.

- no logs for output hook which shall see a new packet and shall not
match established/related rule and then shall throw the packet to chain
svc-ssh-out, but no log from there.

- there logs from forward once the packet has been passed to chain
svc-ssh-fwd but the logs which are generated are always the logs of
rules without ct state. Both previous pairs of rules using ct state are
ignored.

If packets are supposed to keep the CT status along all three hooks, I'd
expect one log from input as new, two others logs for new from forward
then from output and finally logs from forward as related/established.

Sorry about all noise I'm producing on your list but I'm puzzled...

Cheers,

mathias

PS : except for my misunderstanding of CT, service chains are working
magnificently, thank you again ; )

--------------------------------------------------------------------------

table ip filter_them_all {
chain ip_log_svc_administrative_services/ssh {
counter packets 0 bytes 0 log prefix "Accept ip SVC for
'administrative services/ssh': " group 2
counter packets 0 bytes 0 accept
}
chain svc-ssh-inp {
iif vdi-lan             ip daddr 10.91.62.172/32 ct state new jump
ip_log_svc_administrative_services/ssh
iif vdi-lan oif svc-web ip daddr 10.207.184.0/24 ct state new jump
ip_log_svc_administrative_services/ssh
counter packets 0 bytes 0 log prefix "SSH INP KO." group 2
counter packets 0 bytes 0 drop
}
chain svc-ssh-fwd {
# these don't seem to work. YET!
iif vdi-lan oif svc-web ip daddr 10.207.184.0/24 ct state new
log prefix "ACCEPT NEW FORWARD for ssh" group 2
iif vdi-lan oif svc-web ip daddr 10.207.184.0/24 ct state new
accept
iif vdi-lan oif svc-web ip daddr 10.207.184.0/24 ct state
{established, related} log prefix "ACCEPT REL/EST FORWARD for ssh" group 2
iif vdi-lan oif svc-web ip daddr 10.207.184.0/24 ct state
{established, related} accept
# these two are working and STILL can't be omitted
iif vdi-lan oif svc-web ip daddr 10.207.184.0/24 log prefix "ACCEPT
FORWARD for ssh" group 2
iif vdi-lan oif svc-web ip daddr 10.207.184.0/24 accept
counter packets 0 bytes 0 log prefix "SSH FWD KO." group 2
counter packets 0 bytes 0 drop
}
chain svc-ssh-out {
# these are never used
iif vdi-lan oif svc-web ip daddr 10.207.184.0/24 ct state new log
prefix "ACCEPT NEW OUTPUT for ssh" group 2
iif vdi-lan oif svc-web ip daddr 10.207.184.0/24 ct state new accept
counter packets 0 bytes 0 log prefix "SSH OUT KO." group 2
counter packets 0 bytes 0 drop
}
chain svc-dns-req {
ip daddr 10.195.171.240/32 accept
}
chain svc-dns-res {
ip saddr 10.195.171.240/32 accept
}
chain input {
type filter hook input priority filter; policy drop;
ct state {established,related} accept
tcp dport 22 jump svc-ssh-inp
udp dport 53 jump svc-dns-req
counter packets 0 bytes 0 log prefix "REFUSED INPUT packet as it
reached the end of filtering rules stack." group 2
counter packets 0 bytes 0 drop
}
chain forward {
type filter hook forward priority filter; policy drop;
ct state {established,related} accept
tcp dport 22 jump svc-ssh-fwd
udp dport 53 jump svc-dns-req
counter packets 0 bytes 0 log prefix "REFUSED FORWARD packet as it
reached the end of filtering rules stack." group 2
counter packets 0 bytes 0 drop
}
chain output {
type filter hook output priority filter; policy drop;
ct state {established,related} accept
tcp dport 22 jump svc-ssh-out
udp sport 53 jump svc-dns-res
counter packets 0 bytes 0 log prefix "REFUSED OUTPUT packet as it
reached the end of filtering rules stack." group 2
counter packets 0 bytes 0 drop
}
}

--------------------------------------------------------------------------