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

nixos/nat: Match iptables behavior with nftables, add externalIP check #277016

Merged
merged 5 commits into from
Dec 2, 2024

Conversation

JustTNE
Copy link
Contributor

@JustTNE JustTNE commented Dec 27, 2023

Description of changes

Previously, the behavior of the iptables and nftables NAT implementations had some differences. This PR addresses these differences by matching iptable nat's functionality with that of nftables. Additionally, this PR implements updated tests based on #279629. Finally, a relatively minor change mentioned in #279629 section 3 was implemented as well.

1. Previously, all requests arriving from outside NAT would still have their "source address" adjusted on iptables.

The following diagram describes the setup I've experienced the issue in:

1.2.3.4 - Example client
101.101.101.101 - Server's public address
10.0.0.5 - nixos nspawn container (via containers.*) address behind NAT

+--------------+   +----------------+   +-----+   +------------+
|    Client    |   |     Server     |   |     |   | Container  |
|   1.2.3.4    +---> 101.101.101.101+---> NAT +--->  10.0.0.5  |
|              |   |                |   |     |   |            |
+--------------+   +----------------+   +-----+   +------------+

If we introduce this example configuration:

networking.nat.forwardPorts = [
  {
    destination = "10.0.0.5:443";
    loopbackIPs = [ "101.101.101.101" ];
    proto = "tcp";
    sourcePort = 443;
  }
];

Any request previously targeted at 10.0.0.5, even from outside the NAT (outside of where NAT reflection is supposed to act), would have its source address rewritten to 101.101.101.101.

An application, like nginx, behind this NAT would then see the following:

101.101.101.101 - - [27/Dec/2023:02:00:04 +0100] "GET / HTTP/2.0" 200 11 "-" "curl/7.58.0"

The changes in this PR prevent the outside client's IP address from being overwritten by limiting the source address change to behind the NAT, matching the behavior with nftables. Test

2. NAT now supports default forward drop iptables rules.

Behaviors allowed by the NAT are now explicitly whitelisted in the forward ruleset on iptables, which allows behavior similar to nftables with the firewall filterForward setting enabled. Test

3. Only connections made to the nat.externalIP will be port forwarded

This is the one new addition to both nftables and iptables. This means that an interface that has multiple IP addresses can now correctly use only one of those IP addresses as the IP address used for NAT port forwarding, allowing the rest of the IP addresses on the interface to be used however else desired without interference. Test

Things done

  • Built on platform(s)
    • x86_64-linux
    • aarch64-linux
    • x86_64-darwin
    • aarch64-darwin
  • For non-Linux: Is sandboxing enabled in nix.conf? (See Nix manual)
    • sandbox = relaxed
    • sandbox = true
  • Tested, as applicable:
  • Tested compilation of all packages that depend on this change using nix-shell -p nixpkgs-review --run "nixpkgs-review rev HEAD". Note: all changes have to be committed, also see nixpkgs-review usage
  • Tested basic functionality of all binary files (usually in ./result/bin/)
  • 24.05 Release Notes (or backporting 23.05 and 23.11 Release notes)
    • (Package updates) Added a release notes entry if the change is major or breaking
    • (Module updates) Added a release notes entry if the change is significant
    • (Module addition) Added a release notes entry if adding a new NixOS module
  • Fits CONTRIBUTING.md.

@ofborg test nat


Add a 👍 reaction to pull requests you find important.

@github-actions github-actions bot added 6.topic: nixos Issues or PRs affecting NixOS modules, or package usability issues specific to NixOS 8.has: module (update) This PR changes an existing module in `nixos/` labels Dec 27, 2023
@JustTNE
Copy link
Contributor Author

JustTNE commented Dec 27, 2023

The user that originally implemented nat reflection seems to have deleted their GitHub account or it's inaccessible for another reason. That's unfortunate.

@ofborg ofborg bot added 10.rebuild-darwin: 0 This PR does not cause any packages to rebuild on Darwin 10.rebuild-linux: 1-10 labels Dec 27, 2023
@nixos-discourse
Copy link

This pull request has been mentioned on NixOS Discourse. There might be relevant details there:

https://discourse.nixos.org/t/prs-ready-for-review/3032/3789

@Luflosi
Copy link
Contributor

Luflosi commented Apr 20, 2024

What about the nftables implementation at nixos/modules/services/networking/nat-nftables.nix? Does that have the same problem?
Also I think it would be nice to have a NixOS test which fails without the required changes and passes with your changes.

@JustTNE
Copy link
Contributor Author

JustTNE commented Apr 21, 2024

What about the nftables implementation

@Luflosi We do not use nftables in production (I believe we tried to in the past), so I can't speak for how well the nftables code works (and I do not have any experience with nftables either)

About writing tests, it doesn't seem like there are nat reflection tests as is and I am not sure how to write some as of right now either. One would have to emulate a network environment where an "outside" and "inside" network exists I suppose?

@wegank wegank added the 12.approvals: 1 This PR was reviewed and approved by one reputable person label Apr 22, 2024
@JustTNE
Copy link
Contributor Author

JustTNE commented May 17, 2024

Is there still any interest in getting this pull request merged?

@wegank wegank added the 2.status: stale https://github.com/NixOS/nixpkgs/blob/master/.github/STALE-BOT.md label Jul 4, 2024
Copy link
Member

@fpletz fpletz left a comment

Choose a reason for hiding this comment

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

Code looks good to me. The nftables implementation looks like its has the same issue. We have to fix the nftables implementation for feature parity since both use the same options. Having a test for this would be awesome.

@stale stale bot removed the 2.status: stale https://github.com/NixOS/nixpkgs/blob/master/.github/STALE-BOT.md label Jul 4, 2024
@Luflosi
Copy link
Contributor

Luflosi commented Jul 10, 2024

I think #279629 is relevant.

@JustTNE
Copy link
Contributor Author

JustTNE commented Jul 11, 2024

I think #279629 is relevant.

Oh yes! I would be willing to port that test to this pull request and try my luck at implementing it for nftables as well. Excellent!

@Luflosi
Copy link
Contributor

Luflosi commented Jul 11, 2024

That would be awesome!

@JustTNE
Copy link
Contributor Author

JustTNE commented Jul 20, 2024

So... Trying to write these tests has me a little stuck with some unexpected behavior.

I wrote up a minimal test case where two machines in separate networks seem to be able to talk to each other completely without any iptables statements allowing them to do so.

This assumes a disabled firewall, but to me, it seems rather odd that the Linux kernel just goes "yeah that checks out"
when two unconnected networks try to talk to each other while forwarding is enabled? Is this expected?
This test is from #279629, so at least someone put some thought into it being there for what I assume is a good reason?

Test file here:
custom.txt
Run with: nix-build ./custom.txt

@JustTNE
Copy link
Contributor Author

JustTNE commented Jul 20, 2024

I was able to replicate this with the firewall enabled on the router as well:
custom.txt

This means a device from outside the network is indeed able to access any other network connected to the router it seems, unless I'm missing something?? I would appreciate some pointers for sure.

For now, for the purposes of this pull request, I'm going to solve the one issue this pull request is supposed to solve and put solving the other issues on the to-do list...

Edit:
I found this rather detailed discussion on the moby/docker GitHub discussing this issue, seems like it is only relevant if a malicious actor has L2 access to the machine used as a NAT router, which isn't ideal, but nowhere near as big of a deal as I thought it was. I'm going to ignore this issue in the tests.

@JustTNE JustTNE marked this pull request as draft July 21, 2024 06:19
@JustTNE JustTNE force-pushed the nat-reflection-fix branch from 4cc52c6 to 4955a9a Compare July 21, 2024 06:20
@github-actions github-actions bot added 8.has: documentation This PR adds or changes documentation 8.has: changelog 8.has: maintainer-list (update) This PR changes `maintainers/maintainer-list.nix` labels Jul 21, 2024
@JustTNE JustTNE changed the title nixos/nat: Prevent NAT reflection on connections not coming from behind the NAT nixos/nat: Match iptables behavior with nftables, add externalIP check Jul 21, 2024
@JustTNE JustTNE marked this pull request as ready for review July 21, 2024 06:40
@JustTNE
Copy link
Contributor Author

JustTNE commented Jul 21, 2024

This PR has been majorly updated with all the changes necessary to make this work. Iptables's behavior now matches the behavior of nftables in the new tests, iptables can now be configured for forward default drop and externalIP actually matters for port forwarding now.

This should also address all the concerns @gray-heron had in #279629 in general.

@Luflosi @fpletz @stalkerhumanoid

@ofborg test nat

@ofborg ofborg bot added 10.rebuild-darwin: 1-10 and removed 10.rebuild-darwin: 0 This PR does not cause any packages to rebuild on Darwin labels Jul 21, 2024
@JustTNE
Copy link
Contributor Author

JustTNE commented Sep 25, 2024

I've rebased this pull request to fix the merge conflicts it had. It would be great if the reviewers could review this pull request again so that we can finally get this merged! (Thanks for the help by the way!)

I've decided against implementing @TRPB request number 1 because this neither works on nftables nor iptables as of right now as far as I can tell, so it should be a separate PR I'd say. I've made some progress on implementing that, however I don't plan on finishing it. A diff is attached to this comment:
WIP.diff.txt

@stalkerhumanoid @fpletz (mentioning previous reviewers)
@ofborg test nat

@ofborg ofborg bot removed the 2.status: merge conflict This PR has merge conflicts with the target branch label Sep 25, 2024
@nixos-discourse
Copy link

This pull request has been mentioned on NixOS Discourse. There might be relevant details there:

https://discourse.nixos.org/t/prs-ready-for-review/3032/4648

@gray-heron
Copy link

gray-heron commented Oct 9, 2024

Great job! Thank you very much for picking this up.

I would suggest adding a note to networking.nat.enable that it assumes trusted L2 on all interfaces.

Other than that, I have checked the new behavior extensively and I found the issues preventing me from using the NixOS NAT resolved. I hope this gets reviewed and merged soon.

nixos/tests/nat.nix Outdated Show resolved Hide resolved
@JustTNE JustTNE force-pushed the nat-reflection-fix branch from dc41e81 to 7452818 Compare October 11, 2024 00:13
@JustTNE
Copy link
Contributor Author

JustTNE commented Oct 11, 2024

Rebased and addressed the review concerns! Thank you for the review and extensive testing. I've been running this in production since day 1 of this pull request existing, but the extra eyes and extra testing gives me some extra peace of mind for sure!

@ofborg test nat

@JustTNE JustTNE force-pushed the nat-reflection-fix branch from 7452818 to 4c3c348 Compare October 16, 2024 00:54
@JustTNE
Copy link
Contributor Author

JustTNE commented Oct 16, 2024

Rebased to fix the merge conflict in the docs.
@ofborg test nat

@JustTNE
Copy link
Contributor Author

JustTNE commented Oct 17, 2024

May I ask anyone with write access what could be done to unblock this pull request? This PR has been open since 2023 after all, and the 24.11 breaking changes freeze is coming up very soon according to #339153.

@PedroHLC PedroHLC requested review from vcunat, NickCao and stalkerhumanoid and removed request for stalkerhumanoid October 17, 2024 11:23
@nixos-discourse
Copy link

This pull request has been mentioned on NixOS Discourse. There might be relevant details there:

https://discourse.nixos.org/t/prs-ready-for-review/3032/4705

…tables rule is in effect.

This allows feature parity with the nftables "filterForward" firewall option when adding a ip forwarding default drop iptables rule.
This code is mostly from NixOS#279629, the uninvoled client checks were removed (since they are the same as the direct connection to the client test) and the tests were adjusted to work as intended as well as bugs fixed.
In some cases, some tests are skipped when they do not make sense for the specific configuration that is being tested.
@JustTNE JustTNE force-pushed the nat-reflection-fix branch from f3a9edf to 12f0948 Compare December 1, 2024 08:36
@JustTNE
Copy link
Contributor Author

JustTNE commented Dec 1, 2024

Rebased and release notes updated to 25.05! I'd still really like to get this merged some time! It's been almost a full year now!

@misuzu
Copy link
Contributor

misuzu commented Dec 1, 2024

@ofborg test nat

Copy link
Contributor

@misuzu misuzu left a comment

Choose a reason for hiding this comment

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

Unless there are any objections I'll merge this tomorrow.

@wegank wegank added the 12.approvals: 2 This PR was reviewed and approved by two reputable people label Dec 1, 2024
@misuzu misuzu merged commit dd9a2e2 into NixOS:master Dec 2, 2024
35 of 36 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
6.topic: nixos Issues or PRs affecting NixOS modules, or package usability issues specific to NixOS 8.has: changelog 8.has: documentation This PR adds or changes documentation 8.has: maintainer-list (update) This PR changes `maintainers/maintainer-list.nix` 8.has: module (update) This PR changes an existing module in `nixos/` 10.rebuild-darwin: 1-10 10.rebuild-linux: 1-10 12.approvals: 2 This PR was reviewed and approved by two reputable people
Projects
None yet
Development

Successfully merging this pull request may close these issues.

10 participants