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

NAT module: allow hot rules replace after nixos-rebuild switch #15815

Closed
wants to merge 1 commit into from

Conversation

danbst
Copy link
Contributor

@danbst danbst commented May 29, 2016

I was playing with NAT module and suddenly realized, that nothing changes whatever options I set. Port forwarding didn't work. I checked iptables -t nat -L --- it was empty for this configuration:

   networking.nat.enable = true;
   networking.nat.forwardPorts = [
     { destination = "127.0.0.1:22"; sourcePort = 1022; }
   ];

After a bit of struggle and couple of lost hours I added locally this line:

systemd.services.nat.wantedBy = [ "default.target" ];

Now I can change nat rules in configuration.nix and they are correctly applied after switch.

Without "default.target" your NAT settings won't be applied on normal `nixos-rebuild switch`, you have to manually restart nat service.
@mention-bot
Copy link

By analyzing the blame information on this pull request, we identified @wkennington, @edolstra and @lethalman to be potential reviewers

@edolstra
Copy link
Member

The real question is why do we have a nat.service to begin with, rather than a generic iptables.service. (The NAT rules do get reloaded properly when the firewall is enabled.)

@danbst
Copy link
Contributor Author

danbst commented May 30, 2016

@edolstra I cannot confirm that reloading is working when firewall enabled. I'm using this declarative container for test:

{ config, pkgs, lib, ... }:
{
   networking.enableIPv6 = lib.mkForce false;

   containers.testnat2 =
     { privateNetwork = true;
       hostAddress = "192.168.101.1";
       localAddress = "192.168.101.12";

       config = 
         { networking.firewall.enable = true;
           networking.enableIPv6 = false;
           networking.nat.enable = true;
           networking.nat.forwardPorts = [
             { destination = "192.168.101.12:22"; sourcePort = 2023; }
           ];
           networking.nat.internalInterfaces = ["eth0"];
           networking.nat.externalInterface = "eth0";

           services.openssh.enable = true;
       };
     };
}

After I change sourcePort = 2023; to sourcePort = 2025; and run nixos-rebuild switch && nixos-container update, I see this in iptables:

[root@testnat2:~]# iptables -n -t nat -L
Chain PREROUTING (policy ACCEPT)
target     prot opt source               destination
nixos-nat-pre  all  --  0.0.0.0/0            0.0.0.0/0

Chain INPUT (policy ACCEPT)
target     prot opt source               destination

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination

Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination
nixos-nat-post  all  --  0.0.0.0/0            0.0.0.0/0

Chain nixos-nat-post (1 references)
target     prot opt source               destination
MASQUERADE  all  --  0.0.0.0/0            0.0.0.0/0            mark match 0x1

Chain nixos-nat-pre (1 references)
target     prot opt source               destination
MARK       all  --  0.0.0.0/0            0.0.0.0/0            MARK set 0x1
DNAT       tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:2023 to:192.168.101.12:22

This can be fixed by systemd.services.firewall.wantedBy = [ "default.target" ]; too

generic iptables.service

+1, it is kind of confusing for newbies that nat and firewall are same thing. Also, it would simplify switch to nftables. But I can't do that in nearest future, hence this PR

@edolstra
Copy link
Member

Is that on master or 16.03? I tried on 16.03 and it seemed to work.

@danbst
Copy link
Contributor Author

danbst commented May 30, 2016

I'm on 16.03 too

@danbst
Copy link
Contributor Author

danbst commented May 30, 2016

Unfortunately I am not able to write test that involves nixos-rebuild. I've looked at installer.nix test, but couldn't extract the essentials (SSL CA cert errors, nixpkgs not found errors, curl errors), so I can't currently prove my point.

@danbst
Copy link
Contributor Author

danbst commented May 31, 2016

@edolstra I have more information on this subject, wrt firewall.

When I change option networking.firewall.allowedTCPPorts, firewall service does reload, so here I confirm you that reload works.

When I disable firewall with networking.firewall.enable = lib.mkForce false;, it is stopped.

But when I enable firewall again with networking.firewall.enable = lib.mkForce true;, it doesn't start. Actually, this is the same as with NAT - no changes are applied because nat service didn't start with networking.nat.enable = true;.

After I manually sudo start firewall reloading on config changes works again.

All tests I'm doing in container.

@danbst
Copy link
Contributor Author

danbst commented May 31, 2016

Seems like default.target is not the correct one, but multi-user.target. Here is how I've fixed firewall:

         systemd.services.firewall = lib.mkIf config.networking.firewall.enable {
           wantedBy = [ "multi-user.target" ];
         };

I think, I should review my PR once more and better understand the difference between default and multi-user.

@groxxda
Copy link
Contributor

groxxda commented May 31, 2016

default.target is a symlink to multi-user.target

@danbst
Copy link
Contributor Author

danbst commented Aug 1, 2016

Closing this PR because now I think it's too hackish solution. The root problem is somewhat related to network.target, because nat, firewall, bridges and default gateway config all suffer from this problem. Hope someone will fix #16230 properly and that will fix my issue too.

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.

4 participants