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

wgengine/router: add auto selection heuristic for iptables/nftables #8762

Conversation

KevinLiang10
Copy link
Contributor

@KevinLiang10 KevinLiang10 commented Aug 1, 2023

Summary:

This change implements chooseFireWallMode that decides which one of iptables/nftables will be used.

Issue related

Updates: #391
Fix: #8111 #8733

Changes made

  1. Added chooseFireWallMode that automatically decides which one of iptables ornftables should be used.
  2. Replaced the TS_DEBUG_USE_NETLINK_NFTABLES envknob with TS_DEBUG_FIREWALL_MODE that should be set to either 'iptables' or 'nftables' to select firewall mode manually.
  3. Reimplemented DetectIptables that detects iptables binary and returns number of rules in iptables in current network namespace.

Thought Process

  1. It is a very edge case when iptables binary is not available, nft is also not available and iptables is in use. So we are not supporting this case for now.
  2. It is a very edge case when nftables is only available throught nft binary but not netlinkAPI, so we will skip this case for now also. This is usually due to system configuration.
  3. We always prioritize nftables ahead of iptables due to it's excellence in performance, and less likely to fail in containerized environment.
  4. When In a container, if there was other app in the same container using iptables, we use iptables since if iptables wouldn't work the container would fail anyways. Otherwise we tend to use nftables since netlinkAPI is less likely to run into incompatibility issues.

Expected Result

  1. If either 'iptables' or 'nftables' is set for TS_DEBUG_FIREWALL_MODE use the tool respectively.
  2. If nftables is in use already use nftables.
  3. if iptables is already in use user iptables, notice that since iptables-nft would write to nftables subsystem, iptables here refer to iptables-legacy.
  4. Otherwise if nftables is available throught netlink API, use nftables. This case includes both ipt, nft are in use, neither is used or iptables-nft was used.
  5. If only iptables binary is available, use iptables.
  6. If neither iptables or nftables is available, return error.

How to test

On linux environment do the following:

  1. Bring up tailscaled by running sudo TS_DEBUG_FIREWALL_MODE=iptables ./tool/go run ./cmd/tailscaled
  2. Start tailscale by running sudo ./tool/go run ./cmd/tailscale up.
  3. Run sudo iptables -L to view the rules added. In log of tailscaled, there should be a line router: router: envknob TS_DEBUG_NETFILTER_MODE=iptables set.
  4. Turn everything down.
  5. Bring up tailscaled by running sudo TS_DEBUG_FIREWALL_MODE=nftables ./tool/go run ./cmd/tailscaled
  6. Start tailscale by running sudo ./tool/go run ./cmd/tailscale up.
  7. Run sudo nft list ruleset to view the rules added. In the output log of tailscaled, it should say router: envknob TS_DEBUG_NETFILTER_MODE=nftables set.
  8. Turn everything down.
  9. Buring up tailscaled by running sudo ./tool/go run ./cmd/tailscaled
  10. Start tailscale
  11. You should see the count of iptables rules and nftables rule currently in system from the log in the form
router: router: iptables rule count: {number}
router: router: nftables rule count: {number}

if iptables is associated with iptables-nft, or nftables is used, it's likely that bother number are non zero depending on system implementation.
12. Your tailscale should be working, with which ever mode is selected.

Copy link
Member

@andrew-d andrew-d left a comment

Choose a reason for hiding this comment

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

Looking good! I did a preliminary review, and I'd appreciate if @raggi and/or @catzkorn could do one as well since they're more familiar with this than I am.

wgengine/router/router_linux.go Outdated Show resolved Hide resolved
wgengine/router/router_linux.go Outdated Show resolved Hide resolved
wgengine/router/router_linux.go Outdated Show resolved Hide resolved
wgengine/router/router_linux.go Show resolved Hide resolved
wgengine/router/router_linux_test.go Outdated Show resolved Hide resolved
util/linuxfw/iptables.go Outdated Show resolved Hide resolved
util/linuxfw/iptables.go Outdated Show resolved Hide resolved
Copy link
Member

@raggi raggi left a comment

Choose a reason for hiding this comment

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

Looks good overall, but please adjust the logic so that we can still detect and function correctly on systems that only have iptables and are missing ip6tables, as we are able to function on those configurations today.

This commit replaces the TS_DEBUG_USE_NETLINK_NFTABLES envknob with
a TS_DEBUG_FIREWALL_MODE that should be set to either 'iptables' or
'nftables' to select firewall mode manually, other wise tailscaled
will automatically choose between iptables and nftables depending on
environment and system availability.

updates: #319
Signed-off-by: KevinLiang10 <kevinliang@tailscale.com>
@KevinLiang10 KevinLiang10 force-pushed the KevinLiang10/Netfilter_selection_autoadapt_to_system_environments branch from 1d231a0 to be3372a Compare August 8, 2023 18:27
@KevinLiang10 KevinLiang10 merged commit ae63c51 into main Aug 8, 2023
36 checks passed
@KevinLiang10 KevinLiang10 deleted the KevinLiang10/Netfilter_selection_autoadapt_to_system_environments branch August 8, 2023 18:59
@joesankey
Copy link

I was getting the following error while trying these changes with the Kubernetes operator to expose a service on a tailnet:

│ modprobe: can't change directory to '/lib/modules': No such file or directory                                                                                               │
│ modprobe: can't change directory to '/lib/modules': No such file or directory                                                                                               │
│ modprobe: can't change directory to '/lib/modules': No such file or directory                                                                                               │
│ iptables v1.8.8 (legacy): can't initialize iptables table `nat': Table does not exist (do you need to insmod?)                                                              │
│ Perhaps iptables or your kernel needs to be upgraded.                                                                                                                       │
│ boot: 2023/08/11 01:42:37 installing proxy rules: executing iptables failed: exit status 3

Looks like containerboot needs to be updated to use iptables/nftables autoselection this PR introduced. When in nftable mode, the nat table no longer exists for container boot to add rules to.

I added this commit to my fork to fix the issue, at least for nftables.

maisem added a commit that referenced this pull request Oct 17, 2023
We were previously using the netlink API to see if there
are chains/rules that already exist. This works fine in
environments where there is either full nftable support
or no support at all. However, we have identified certain
environments which have partial nftable support and the only
feasible way of detecting such an environment is to try
to create some of the chains that we need.

This adds a check to create a dummy postrouting chain which
is immediately deleted. The goal of the check is to ensure
we are able to use nftables and that it won't error out later.
This check is only done in the path where we detected that
the system has no nftable rules.

Updates #5621
Updates #8555
Updates #8762

Signed-off-by: Maisem Ali <maisem@tailscale.com>
maisem added a commit that referenced this pull request Oct 17, 2023
We were previously using the netlink API to see if there
are chains/rules that already exist. This works fine in
environments where there is either full nftable support
or no support at all. However, we have identified certain
environments which have partial nftable support and the only
feasible way of detecting such an environment is to try
to create some of the chains that we need.

This adds a check to create a dummy postrouting chain which
is immediately deleted. The goal of the check is to ensure
we are able to use nftables and that it won't error out later.
This check is only done in the path where we detected that
the system has no nftable rules.

Updates #5621
Updates #8555
Updates #8762

Signed-off-by: Maisem Ali <maisem@tailscale.com>
maisem added a commit that referenced this pull request Oct 17, 2023
We were previously using the netlink API to see if there
are chains/rules that already exist. This works fine in
environments where there is either full nftable support
or no support at all. However, we have identified certain
environments which have partial nftable support and the only
feasible way of detecting such an environment is to try
to create some of the chains that we need.

This adds a check to create a dummy postrouting chain which
is immediately deleted. The goal of the check is to ensure
we are able to use nftables and that it won't error out later.
This check is only done in the path where we detected that
the system has no nftable rules.

Updates #5621
Updates #8555
Updates #8762

Signed-off-by: Maisem Ali <maisem@tailscale.com>
maisem added a commit that referenced this pull request Oct 17, 2023
These tests were broken at HEAD. CI currently does not run these
as root, will figure out how to do that in a followup.

Updates #5621
Updates #8555
Updates #8762

Signed-off-by: Maisem Ali <maisem@tailscale.com>
maisem added a commit that referenced this pull request Oct 17, 2023
We were previously using the netlink API to see if there are chains/rules that
already exist. This works fine in environments where there is either full
nftable support or no support at all. However, we have identified certain
environments which have partial nftable support and the only feasible way of
detecting such an environment is to try to create some of the chains that we
need.

This adds a check to create a dummy postrouting chain which is immediately
deleted. The goal of the check is to ensure we are able to use nftables and
that it won't error out later. This check is only done in the path where we
detected that the system has no preexisting nftable rules.

Updates #5621
Updates #8555
Updates #8762
maisem added a commit that referenced this pull request Oct 17, 2023
These tests were broken at HEAD. CI currently does not run these
as root, will figure out how to do that in a followup.

Updates #5621
Updates #8555
Updates #8762

Signed-off-by: Maisem Ali <maisem@tailscale.com>
maisem added a commit that referenced this pull request Oct 17, 2023
We were previously using the netlink API to see if there are chains/rules that
already exist. This works fine in environments where there is either full
nftable support or no support at all. However, we have identified certain
environments which have partial nftable support and the only feasible way of
detecting such an environment is to try to create some of the chains that we
need.

This adds a check to create a dummy postrouting chain which is immediately
deleted. The goal of the check is to ensure we are able to use nftables and
that it won't error out later. This check is only done in the path where we
detected that the system has no preexisting nftable rules.

Updates #5621
Updates #8555
Updates #8762

Signed-off-by: Maisem Ali <maisem@tailscale.com>
maisem added a commit that referenced this pull request Oct 17, 2023
We were previously using the netlink API to see if there are chains/rules that
already exist. This works fine in environments where there is either full
nftable support or no support at all. However, we have identified certain
environments which have partial nftable support and the only feasible way of
detecting such an environment is to try to create some of the chains that we
need.

This adds a check to create a dummy postrouting chain which is immediately
deleted. The goal of the check is to ensure we are able to use nftables and
that it won't error out later. This check is only done in the path where we
detected that the system has no preexisting nftable rules.

Updates #5621
Updates #8555
Updates #8762

Signed-off-by: Maisem Ali <maisem@tailscale.com>
maisem added a commit that referenced this pull request Oct 18, 2023
We were previously using the netlink API to see if there are chains/rules that
already exist. This works fine in environments where there is either full
nftable support or no support at all. However, we have identified certain
environments which have partial nftable support and the only feasible way of
detecting such an environment is to try to create some of the chains that we
need.

This adds a check to create a dummy postrouting chain which is immediately
deleted. The goal of the check is to ensure we are able to use nftables and
that it won't error out later. This check is only done in the path where we
detected that the system has no preexisting nftable rules.

Updates #5621
Updates #8555
Updates #8762

Signed-off-by: Maisem Ali <maisem@tailscale.com>
maisem added a commit that referenced this pull request Oct 18, 2023
These tests were broken at HEAD. CI currently does not run these
as root, will figure out how to do that in a followup.

Updates #5621
Updates #8555
Updates #8762

Signed-off-by: Maisem Ali <maisem@tailscale.com>
maisem added a commit that referenced this pull request Oct 18, 2023
We were previously using the netlink API to see if there are chains/rules that
already exist. This works fine in environments where there is either full
nftable support or no support at all. However, we have identified certain
environments which have partial nftable support and the only feasible way of
detecting such an environment is to try to create some of the chains that we
need.

This adds a check to create a dummy postrouting chain which is immediately
deleted. The goal of the check is to ensure we are able to use nftables and
that it won't error out later. This check is only done in the path where we
detected that the system has no preexisting nftable rules.

Updates #5621
Updates #8555
Updates #8762

Signed-off-by: Maisem Ali <maisem@tailscale.com>
maisem added a commit that referenced this pull request Oct 18, 2023
We were previously using the netlink API to see if there are chains/rules that
already exist. This works fine in environments where there is either full
nftable support or no support at all. However, we have identified certain
environments which have partial nftable support and the only feasible way of
detecting such an environment is to try to create some of the chains that we
need.

This adds a check to create a dummy postrouting chain which is immediately
deleted. The goal of the check is to ensure we are able to use nftables and
that it won't error out later. This check is only done in the path where we
detected that the system has no preexisting nftable rules.

Updates #5621
Updates #8555
Updates #8762

Signed-off-by: Maisem Ali <maisem@tailscale.com>
maisem added a commit that referenced this pull request Oct 18, 2023
These tests were broken at HEAD. CI currently does not run these
as root, will figure out how to do that in a followup.

Updates #5621
Updates #8555
Updates #8762

Signed-off-by: Maisem Ali <maisem@tailscale.com>
maisem added a commit that referenced this pull request Oct 18, 2023
We were previously using the netlink API to see if there are chains/rules that
already exist. This works fine in environments where there is either full
nftable support or no support at all. However, we have identified certain
environments which have partial nftable support and the only feasible way of
detecting such an environment is to try to create some of the chains that we
need.

This adds a check to create a dummy postrouting chain which is immediately
deleted. The goal of the check is to ensure we are able to use nftables and
that it won't error out later. This check is only done in the path where we
detected that the system has no preexisting nftable rules.

Updates #5621
Updates #8555
Updates #8762

Signed-off-by: Maisem Ali <maisem@tailscale.com>
alexelisenko pushed a commit to Control-D-Inc/tailscale that referenced this pull request Feb 15, 2024
These tests were broken at HEAD. CI currently does not run these
as root, will figure out how to do that in a followup.

Updates tailscale#5621
Updates tailscale#8555
Updates tailscale#8762

Signed-off-by: Maisem Ali <maisem@tailscale.com>
Signed-off-by: Alex Paguis <alex@windscribe.com>
alexelisenko pushed a commit to Control-D-Inc/tailscale that referenced this pull request Feb 15, 2024
We were previously using the netlink API to see if there are chains/rules that
already exist. This works fine in environments where there is either full
nftable support or no support at all. However, we have identified certain
environments which have partial nftable support and the only feasible way of
detecting such an environment is to try to create some of the chains that we
need.

This adds a check to create a dummy postrouting chain which is immediately
deleted. The goal of the check is to ensure we are able to use nftables and
that it won't error out later. This check is only done in the path where we
detected that the system has no preexisting nftable rules.

Updates tailscale#5621
Updates tailscale#8555
Updates tailscale#8762

Signed-off-by: Maisem Ali <maisem@tailscale.com>
Signed-off-by: Alex Paguis <alex@windscribe.com>
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.

tailscale-operator not working on AKS
4 participants