When tailscaled.service starts up (after nftables.service), we end up with table ip filter, table ip6 filter, and table ip nat in addition to the existing table inet filter.
A chain in a table inet can have both ip (ipv4) and ip6 rules in it. I believe nftables is smart enough to not evaluate an ip or ip6 rule when processing a packet for the other type, so really doesn't add any extra overhead.
How should we solve this?
Check if there are existing table inet filter, table ip filter and table ip6 filter tables, and if there are table inet, but no table ip or table ip6, then only create/update chains in table inet.
Default to table inet instead of table ip
I think that'd look something like this:
table inet filter {
chain FORWARD {
type filter hook forward priority filter; policy accept;
counter jump ts-forward
}
chain INPUT {
type filter hook input priority filter; policy accept;
counter jump ts-input
}
chain ts-forward {
iifname "tailscale0*" counter meta mark set meta mark & 0xffff04ff | 0x00000400
meta mark & 0x0000ff00 == 0x00000400 counter accept
oifname "tailscale0*" ip saddr 100.64.0.0/10 counter drop
oifname "tailscale0*" counter accept
}
chain ts-input {
iifname "lo*" ip saddr 100.123.45.67 counter accept
iifname "lo*" ip6 saddr fd7a:115c:a1e0::1234:5678 counter accept
iifname != "tailscale0*" ip saddr 100.115.92.0/23 counter return
iifname != "tailscale0*" ip saddr 100.64.0.0/10 counter drop
iifname "tailscale0*" counter accept
udp dport 41641 counter accept
}
}
Since tailscaled adds table ip nat but not table ip6 nat, I'm assuming it makes sense to keep that as `table ip nat
What is the impact of not solving this?
Leaves our nftables list ruleset output confusing in a way where I'd have to carefully read nftables documentation to fully understand what's really happening to a packet going through our nftables.
Key fragments of the live nftables config on one of our servers with tailscaled running:
table inet filter {
chain INPUT {
type filter hook input priority filter; policy drop;
# various rules
}
}
table ip filter {
chain INPUT {
type filter hook input priority filter; policy accept;
counter jump ts-input
}
}
There's two chains with same hook, priority, and name, but different policy and family.
It's possible to give two base chains the same priority, but there is no guaranteed evaluation order of base chains with identical priority that are attached to the same hook location.
As best I can tell, it's basically random which INPUT chain is evaluated first. If our policy drop INPUT chain is evaluated first, then policy accept INPUT chain won't get hit at all. If tailscaled's policy accept INPUT chain is evaluated first, then this should all work ok (since policy accept will still evaluate for any other base chains with same or later priority value).
What are you trying to do?
On our servers, we have local firewall
nftables
firewall rules along the lines of:When tailscaled.service starts up (after nftables.service), we end up with
table ip filter
,table ip6 filter
, andtable ip nat
in addition to the existingtable inet filter
.A chain in a
table inet
can have bothip
(ipv4) andip6
rules in it. I believe nftables is smart enough to not evaluate anip
orip6
rule when processing a packet for the other type, so really doesn't add any extra overhead.How should we solve this?
table inet filter
,table ip filter
andtable ip6 filter
tables, and if there aretable inet
, but notable ip
ortable ip6
, then only create/update chains intable inet
.table inet
instead oftable ip
I think that'd look something like this:
Since tailscaled adds
table ip nat
but nottable ip6 nat
, I'm assuming it makes sense to keep that as `table ip natWhat is the impact of not solving this?
Leaves our
nftables list ruleset
output confusing in a way where I'd have to carefully read nftables documentation to fully understand what's really happening to a packet going through our nftables.Key fragments of the live nftables config on one of our servers with tailscaled running:
There's two chains with same hook, priority, and name, but different policy and family.
Docs here https://wiki.nftables.org/wiki-nftables/index.php/Configuring_chains#Adding_base_chains say
As best I can tell, it's basically random which
INPUT
chain is evaluated first. If ourpolicy drop
INPUT chain is evaluated first, thenpolicy accept
INPUT chain won't get hit at all. If tailscaled'spolicy accept
INPUT chain is evaluated first, then this should all work ok (sincepolicy accept
will still evaluate for any other base chains with same or later priority value).Anything else?
No response