Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

util/linuxfw: fix IPv6 availability check for nftables #12009

Merged
merged 3 commits into from May 14, 2024
Merged

Conversation

irbekrm
Copy link
Contributor

@irbekrm irbekrm commented May 5, 2024

See #11353 for context- this change fixes a firewall NAT availability check that was using the no-longer set ipv6NATAvailable field by removing the field and using a method that, for nftables, just checks that IPv6 is available.

When running firewall in nftables mode,
there is no need for a separate NAT availability check (unlike with iptables, there are no hosts that support nftables, but not IPv6 NAT - see #11353).

I have tested that with this change the IPv6 NAT table gets created as expected:

/ # nft list ruleset table ip filter { chain FORWARD { type filter hook forward priority filter; policy accept; counter packets 0 bytes 0 jump ts-forward }
    chain INPUT {
            type filter hook input priority filter; policy accept;
            counter packets 114 bytes 26380 jump ts-input
    }

    chain ts-forward {
            iifname "tailscale0*" counter packets 0 bytes 0 meta mark set meta mark & 0xffff04ff | 0x00000400
            meta mark & 0x0000ff00 == 0x00000400 counter packets 0 bytes 0 accept
            oifname "tailscale0*" ip saddr 100.64.0.0/10 counter packets 0 bytes 0 drop
            oifname "tailscale0*" counter packets 0 bytes 0 accept
    }

    chain ts-input {
            iifname "lo*" ip saddr 100.110.115.23 counter packets 0 bytes 0 accept
            iifname != "tailscale0*" ip saddr 100.115.92.0/23 counter packets 0 bytes 0 return
            iifname != "tailscale0*" ip saddr 100.64.0.0/10 counter packets 0 bytes 0 drop
            iifname "tailscale0*" counter packets 0 bytes 0 accept
            udp dport 35215 counter packets 79 bytes 8632 accept
    }

}
table ip nat {
chain POSTROUTING {
type nat hook postrouting priority srcnat; policy accept;
counter packets 46 bytes 6233 jump ts-postrouting
}

    chain ts-postrouting {
            meta mark & 0x0000ff00 == 0x00000400 counter packets 0 bytes 0 masquerade
    }

}
table ip6 filter {
chain FORWARD {
type filter hook forward priority filter; policy accept;
counter packets 28 bytes 23435 jump ts-forward
}

    chain INPUT {
            type filter hook input priority filter; policy accept;
            counter packets 224 bytes 2783585 jump ts-input
    }

    chain ts-forward {
            iifname "tailscale0*" counter packets 16 bytes 1318 meta mark set meta mark & 0xffff04ff | 0x00000400
            meta mark & 0x0000ff00 == 0x00000400 counter packets 16 bytes 1318 accept
            oifname "tailscale0*" counter packets 12 bytes 22117 accept
    }

    chain ts-input {
            iifname "lo*" ip6 saddr fd7a:115c:a1e0::df01:7317 counter packets 0 bytes 0 accept
            iifname "tailscale0*" counter packets 0 bytes 0 accept
            udp dport 57553 counter packets 52 bytes 5406 accept
    }

}
table ip6 nat {
chain POSTROUTING {
type nat hook postrouting priority srcnat; policy accept;
counter packets 28 bytes 2540 jump ts-postrouting
}

    chain ts-postrouting {
            meta mark & 0x0000ff00 == 0x00000400 counter packets 2 bytes 160 masquerade
    }

}

Also updated tests to test the amount of chains/tables created depending on whether the IPv6 check errors out or not- that would have caught this bug.

Updates #12008

@irbekrm irbekrm force-pushed the irbekrm/ipv6nat branch 2 times, most recently from 9dc13af to 1155420 Compare May 5, 2024 12:07
When running firewall in nftables mode,
there is no need for a separate NAT availability check
(unlike with iptables, there are no hosts that support nftables, but not IPv6 NAT - see #11353).
This change fixes a firewall NAT availability check that was using the no-longer set ipv6NATAvailable field
by removing the field and using a method that, for nftables, just checks that IPv6 is available.

Updates #12008

Signed-off-by: Irbe Krumina <irbe@tailscale.com>
@irbekrm irbekrm changed the title util/linuxfw: fix IPv6 NAT availability check for nftables util/linuxfw: fix IPv6 availability check for nftables May 5, 2024
func (n *nftablesRunner) getTables() []*nftable {
if n.v6Available {
if n.HasIPV6() {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For consistency, does not change anything functionally

@irbekrm irbekrm requested a review from raggi May 5, 2024 12:53
Test that the expected number of nftables
tables/chains are created depending on whether
the host supports IPv6 or not.

Signed-off-by: Irbe Krumina <irbe@tailscale.com>
@@ -109,7 +109,8 @@ func getTailscaleSubnetRouteMark() []byte {
// missing. It does not check that IPv6 is currently functional or
// that there's a global address, just that the system would support
// IPv6 if it were on an IPv6 network.
func CheckIPv6(logf logger.Logf) error {
// CheckIPv6 can be overridden in tests.
var CheckIPv6 = func(logf logger.Logf) error {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd prefer this signature remain unchanged and instead add a new unexported package-level func that, if non-nil, is used inside the body, like:

var checkIPv6ForTest func(logger.Logf) error // non-nil in some tests

func CheckIPv6(logf logger.Logf) error {
    if f := checkIPv6ForTest; f != nil {
        return f(logf)
    }
    ....

Then use tstest.Replace to set it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh that's really nice

Copy link
Collaborator

@maisem maisem left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM after addressing brads comment about using tstest.Replace in tests with a package private var.

Signed-off-by: Irbe Krumina <irbe@tailscale.com>
@irbekrm irbekrm merged commit 7ef2f72 into main May 14, 2024
48 checks passed
@irbekrm irbekrm deleted the irbekrm/ipv6nat branch May 14, 2024 07:51
irbekrm added a commit that referenced this pull request May 14, 2024
* util/linuxfw: fix IPv6 NAT availability check for nftables

When running firewall in nftables mode,
there is no need for a separate NAT availability check
(unlike with iptables, there are no hosts that support nftables, but not IPv6 NAT - see #11353).
This change fixes a firewall NAT availability check that was using the no-longer set ipv6NATAvailable field
by removing the field and using a method that, for nftables, just checks that IPv6 is available.

Updates #12008

Signed-off-by: Irbe Krumina <irbe@tailscale.com>
(cherry picked from commit 7ef2f72)
irbekrm added a commit that referenced this pull request May 14, 2024
* util/linuxfw: fix IPv6 NAT availability check for nftables

When running firewall in nftables mode,
there is no need for a separate NAT availability check
(unlike with iptables, there are no hosts that support nftables, but not IPv6 NAT - see #11353).
This change fixes a firewall NAT availability check that was using the no-longer set ipv6NATAvailable field
by removing the field and using a method that, for nftables, just checks that IPv6 is available.

Updates #12008

Signed-off-by: Irbe Krumina <irbe@tailscale.com>
(cherry picked from commit 7ef2f72)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants