Score:1

nftables chain priority not working

id flag

So I have two input chains, input and dyn which is dynamically generated.

However the rules of dyn just don't work because of input. I've tried setting the priority of input to 1, and the dyn to 0 even -200. Still nothing.

When I flush the input rules, then dyn works.

What am I doing wrong here?

sudo nft list ruleset
table inet filter {
chain input {
    type filter hook input priority filter + 1; policy accept;
    iif "lo" accept
    ct state established,related accept
    tcp dport 299 ip saddr 3x.xx.xx.xx accept
    icmpv6 type { destination-unreachable, packet-too-big, time-exceeded, parameter-problem, echo-request, echo-reply, nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert, 148, 149 } accept
    ip6 saddr fe80::/10 icmpv6 type { mld-listener-query, mld-listener-report, mld-listener-done, mld2-listener-report, 151, 152, 153 } accept
    counter packets 10 bytes 5255 drop
}

chain dyn {
    type filter hook input priority filter; policy accept;
    iif "lo" accept
    ct state established,related accept
    ip saddr 2x.xx.xx.xx udp dport 8999 log prefix "dyn" accept
    ip6 saddr xxx:xxxx:xxxx:xxxx::9999 udp dport 8999 log prefix "dyn" accept
    ip saddr 2x.xx.xx.xx tcp dport 7999 log prefix "dyn" accept
    ip6 saddr xxx:xxxx:xxxx:xxxx::9999 tcp dport 7999 log prefix "dyn" accept
    ip saddr 2x.xx.xx.xx icmp type echo-request log prefix "dyn" accept
    ip6 saddr xxx:xxxx:xxxx:xxxx::9999 icmp type echo-request log prefix "dyn"
    ip saddr 2x.xx.xx.xx tcp dport 6999 log prefix "dyn" accept
    ip6 saddr xxx:xxxx:xxxx:xxxx::aaaa tcp dport 6999 log prefix "dyn" accept
}
}
Score:1
cl flag
A.B

Each chain hooks into Netfilter: as long as a packet exists, Netfilter will call all chains hooking in the current phase (eg: input).

What this means is that each chain provides a chance to get the packet dropped. Once the packet is dropped, it doesn't exist anymore: remaining chains won't be called for traversal since there's nothing to be used for traversal: the packet already disappeared.

So whatever the priority order of the two chains, when each chain has its own rule to accept or drop a packet, independently from the other chain, the final outcome is a logical AND between each outcome, where drop means false and accept means true:

drop   AND drop   = drop
drop   AND accept = drop
accept AND drop   = drop
accept AND accept = accept

This is reminded in nft(8) in the VERDICT STATEMENT section:

accept

Terminate ruleset evaluation and accept the packet. The packet can still be dropped later by another hook, for instance accept in the forward hook still allows one to drop the packet later in the postrouting hook, or another forward base chain that has a higher priority number and is evaluated afterwards in the processing pipeline.

drop

Terminate ruleset evaluation and drop the packet. The drop occurs instantly, no further chains or hooks are evaluated. It is not possible to accept the packet in a later chain again, as those are not evaluated anymore for the packet.

If you want to avoid this, then the evaluation must not be independent. For example you can pass a message between the first chain and the 2nd chain (in order of hook and hook's priority) using a firewall mark to be interpreted as "decision already made, accept this packet". This requires cooperation from both sides, so can't be slapped on an unaware tool (eg: can't add this to a ruleset handled by firewalld without modifying firewalld to account for this, either as the message creator or as the message consumer.

For your case, you could replace your ruleset with a variation of this:

table inet filter {

chain markandaccept {
    meta mark set 0x900d accept
}

chain input {
    type filter hook input priority filter + 1; policy accept;
    meta mark 0x900d accept
    iif "lo" accept
    ct state established,related accept
    tcp dport 299 ip saddr 3x.xx.xx.xx accept
    icmpv6 type { destination-unreachable, packet-too-big, time-exceeded, parameter-problem, echo-request, echo-reply, nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert, 148, 149 } accept
    ip6 saddr fe80::/10 icmpv6 type { mld-listener-query, mld-listener-report, mld-listener-done, mld2-listener-report, 151, 152, 153 } accept
    counter drop
}

chain dyn {
    type filter hook input priority filter; policy accept;
    iif "lo" goto markandaccept
    ct state established,related goto markandaccept
    ip saddr 2x.xx.xx.xx udp dport 8999 log prefix "dyn" goto markandaccept
    ip6 saddr xxx:xxxx:xxxx:xxxx::9999 udp dport 8999 log prefix "dyn" goto markandaccept
    ip saddr 2x.xx.xx.xx tcp dport 7999 log prefix "dyn" goto markandaccept
    ip6 saddr xxx:xxxx:xxxx:xxxx::9999 tcp dport 7999 log prefix "dyn" goto markandaccept
    ip saddr 2x.xx.xx.xx icmp type echo-request log prefix "dyn" goto markandaccept
    ip6 saddr xxx:xxxx:xxxx:xxxx::9999 icmp type echo-request log prefix "dyn"
    ip saddr 2x.xx.xx.xx tcp dport 6999 log prefix "dyn" goto markandaccept
    ip6 saddr xxx:xxxx:xxxx:xxxx::aaaa tcp dport 6999 log prefix "dyn" goto markandaccept
}
}

This is an example made without any simplification, I'm sure better can be done.

So whenever the dyn chain deems a packet should stay accepted, the packet is tagged (internally, in the current network stack only) with a mark. The first test in the altered input chain is to check for this mark: if present, the packet is immediately accepted without further processing: the decision made in the first chain is honored in the 2nd chain.

Nikk avatar
id flag
Very interesting. Thank you.
I sit in a Tesla and translated this thread with Ai:

mangohost

Post an answer

Most people don’t grasp that asking a lot of questions unlocks learning and improves interpersonal bonding. In Alison’s studies, for example, though people could accurately recall how many questions had been asked in their conversations, they didn’t intuit the link between questions and liking. Across four studies, in which participants were engaged in conversations themselves or read transcripts of others’ conversations, people tended not to realize that question asking would influence—or had influenced—the level of amity between the conversationalists.