Networking: Difference between revisions

From NixOS Wiki
imported>Onny
Add section on static ip configuration
0x4A6F (talk | contribs)
IPv6-mostly
 
(11 intermediate revisions by 7 users not shown)
Line 1: Line 1:
This site provides snippets for configuring your network ''just right'' for the use case you are looking for. All configuration is for <code>configuration.nix</code>
Networking config always goes in your system configuration. This can be done declaratively as shown in the following sections or through non-declarative tools such as [[NetworkManager]].


== Configuration ==
== Configuration ==
Line 5: Line 5:
=== Static IP for network adapter ===
=== Static IP for network adapter ===


The following example configures a static IPv6 address and a default gateway for the interface <code>ens3</code>
The following example configures a static IPv4 and IPv6 address and a default gateway for the interface <code>ens3</code>


<syntaxhighlight lang="nix">
<syntaxhighlight lang="nix">
networking = {
networking = {
   interfaces = {
   interfaces.ens3 = {
     ens3.ipv6.addresses = [{
     ipv6.addresses = [{
       address = "2a01:4f8:1c1b:16d0::";
       address = "2a01:4f8:1c1b:16d0::1";
       prefixLength = 64;
       prefixLength = 64;
    }];
    ipv4.addresses = [{
      address = "192.0.2.2";
      prefixLength = 24;
     }];
     }];
  };
  defaultGateway = {
    address = "192.0.2.1";
    interface = "ens3";
   };
   };
   defaultGateway6 = {
   defaultGateway6 = {
Line 26: Line 34:
To edit <code>/etc/hosts</code> just add something like this to your <code>configuration.nix</code>:
To edit <code>/etc/hosts</code> just add something like this to your <code>configuration.nix</code>:
<syntaxhighlight lang="nix">
<syntaxhighlight lang="nix">
networking.extraHosts = ''
networking.hosts = {
   127.0.0.2 other-localhost
   "127.0.0.2" = ["other-localhost"];
   10.0.0.1 server
   "192.0.2.1" = ["mail.example.com" "imap.example.com"];
'';
};
</syntaxhighlight>
</syntaxhighlight>


=== Port forwarding ===
=== Port forwarding ===


In this example we're going to forward the port <code>80</code> via NAT from our external network interface <code>ens3</code> to the host <code>10.100.0.3</code> on our internal interface <code>wg0</code>.
In this example we're going to forward the port <code>80</code> via NAT from our internal network interface <code>ens3</code> to the host <code>10.100.0.3</code> on our external interface <code>wg0</code>.


<syntaxhighlight lang="nix">
<syntaxhighlight lang="nix">
networking = {
networking = {
  nftables = {
    enable = true;
    ruleset = ''
        table ip nat {
          chain PREROUTING {
            type nat hook prerouting priority dstnat; policy accept;
            iifname "ens3" tcp dport 80 dnat to 10.100.0.3:80
          }
        }
    '';
  };
   firewall = {
   firewall = {
     enable = true;
     enable = true;
     allowedTCPPorts = [ 80 ];
     allowedTCPPorts = [ 80 ];
    extraCommands = "iptables -t nat -A POSTROUTING -d 10.100.0.3 -p tcp -m tcp --dport 80 -j MASQUERADE";
   };
   };
   nat = {
   nat = {
     enable = true;
     enable = true;
     internalInterfaces = [ "wg0" ];
     internalInterfaces = [ "ens3" ];
     externalInterface = "ens3";
     externalInterface = "wg0";
     forwardPorts = [
     forwardPorts = [
       {
       {
Line 52: Line 70:
         proto = "tcp";
         proto = "tcp";
         destination = "10.100.0.3:80";
         destination = "10.100.0.3:80";
      }
    ];
  };
};
</syntaxhighlight>
For IPv6 port forwarding, the example would look like this. Incoming connections on the address <code>2001:db8::</code> and port <code>80</code> will be forwarded to <code>[fe80::1234:5678:9abc:def0]:80</code>.
<syntaxhighlight lang="nix">
networking = {
  nftables = {
    enable = true;
    ruleset = ''
        table ip6 nat {
          chain PREROUTING {
            type nat hook prerouting priority dstnat; policy accept;
            iifname "ens3" ip6 daddr [2001:db8::] tcp dport 80 dnat to [fe80::1234:5678:9abc:def0]:80
          }
        }
    '';
  };
  firewall = {
    enable = true;
    allowedTCPPorts = [ 80 ];
  };
  nat = {
    enable = true;
    internalInterfaces = [ "ens3" ];
    externalInterface = "wg0";
    enableIPv6 = true;
    internalIPv6s = [ "2001:db8::/64" ];
    externalIPv6 = "fe80::1234:5678:9abc:def0";
    forwardPorts = [
      {
        sourcePort = 80;
        proto = "tcp";
        destination = "fe80::1234:5678:9abc:def0]:80";
       }
       }
     ];
     ];
Line 62: Line 117:
== Prefix delegation with fixed DUID ==
== Prefix delegation with fixed DUID ==


Sometimes the hosting provider manages ipv6 networks via a so-called ''DUID'' or ''clientid''. This snippet is required to make the network routable:
Sometimes the hosting provider manages IPv6 networks via a so-called ''DUID'' or ''clientid''. This snippet is required to make the network routable:


<syntaxhighlight lang="nix">
<syntaxhighlight lang="nix">
Line 100: Line 155:
</syntaxhighlight>
</syntaxhighlight>


== VLAN's ==
== IPv6-mostly ==


[https://nixos.org/manual/nixos/stable/options.html#opt-networking.vlans vlan information in the manual]
For IPv6 mostly networks the situation in Linux is a little bit dire.  
A 464XLAT CLAT implementation on the client device has to be running.


The below is a complete networking example, showing 2 interfaces, 1 with VLAN trunk tagging and 1 without.
For example run clatd:
<syntaxhighlight lang="nix">
{
  services.clatd.enable = true;
}
</syntaxhighlight>


eth1 is a normal network interface @ 192.168.1.2, with no VLAN information.
Caveats:
* disable IPv4 manually for DHCPv4 clients that do not accept Option 108 (IPv6-Only Preferred Option)
* set NAT64 prefix manually, if client doesn't support RA/PREF64 (RFC 8781) or DNS64 (RFC 7050):
<syntaxhighlight lang="nix">
{
  services.clatd.settings = {
    plat-prefix = "64:ff9b::/96";
  };
}
</syntaxhighlight>
* clatd needs to be restarted, if the network has changed


eth0 is the vlan trunk tagged, with 2 VLAN's tagged, vlan 100 and vlan 101.
Sources:
* https://labs.ripe.net/author/ondrej_caletka_1/deploying-ipv6-mostly-access-networks/
* https://ripe85.ripe.net/presentations/9-RIPE85-Deploying_IPv6_mostly.pdf
* https://github.com/systemd/systemd/issues/23674
* https://github.com/toreanderson/clatd
* https://gist.github.com/oskar456/d898bf2e11b642757800a5ccdc2415aa
* https://fosdem.org/2024/schedule/event/fosdem-2024-1798-improving-ipv6-only-experience-on-linux/
* https://nlnet.nl/project/IPv6-monostack/


vlan100 is in the 10.1.1.X network and vlan 101 is in the 10.10.10.X network.
= VLANs =


the hostID should be random data, derived from something like: <syntaxhighlight>head -c4 /dev/urandom | od -A none -t x4</syntaxhighlight> see [https://nixos.org/manual/nixos/stable/options.html#opt-networking.hostId the manual] for more information.
Refer to [https://nixos.org/manual/nixos/stable/options.html#opt-networking.vlans {{ic|networking.vlans}} in the manual].


Below is a complete networking example showing two interfaces, one with VLAN trunk tagging and one without.


{{ic|enp2s1}} is a normal network interface at {{ic|192.168.1.2}} with no VLAN information.
{{ic|enp2s0}} is the virtual LAN trunk with two tagged VLANs, {{ic|vlan100}} and {{ic|vlan101}}.
{{ic|vlan100}} is in the {{ic|10.1.1.X}} network and {{ic|vlan101}} is in the {{ic|10.10.10.X}} network.
The {{ic|hostID}} should be unique among your machines, [https://nixos.org/manual/nixos/stable/options.html#opt-networking.hostId as mentioned in the manual].


Complete networking section example:
Complete networking section example:
Line 124: Line 210:
       domain = "example.com";
       domain = "example.com";
       dhcpcd.enable = false;
       dhcpcd.enable = false;
      usePredictableInterfaceNames = false;
       interfaces.enp2s1.ipv4.addresses = [{
       interfaces.eth1.ipv4.addresses = [{
         address = "192.168.1.2";
         address = "192.168.1.2";
         prefixLength = 28;
         prefixLength = 28;
       }];
       }];
       vlans = {
       vlans = {
         vlan100 = { id=100; interface="eth0"; };
         vlan100 = { id=100; interface="enp2s0"; };
         vlan101 = { id=101; interface="eth0"; };
         vlan101 = { id=101; interface="enp2s0"; };
       };
       };
       interfaces.vlan100.ipv4.addresses = [{
       interfaces.vlan100.ipv4.addresses = [{
Line 145: Line 230:
     };
     };
</syntaxhighlight>
</syntaxhighlight>
[[Category:Networking]]

Latest revision as of 08:30, 22 May 2024

Networking config always goes in your system configuration. This can be done declaratively as shown in the following sections or through non-declarative tools such as NetworkManager.

Configuration

Static IP for network adapter

The following example configures a static IPv4 and IPv6 address and a default gateway for the interface ens3

networking = {
  interfaces.ens3 = {
    ipv6.addresses = [{
      address = "2a01:4f8:1c1b:16d0::1";
      prefixLength = 64;
    }];
    ipv4.addresses = [{
      address = "192.0.2.2";
      prefixLength = 24;
    }];
  };
  defaultGateway = {
    address = "192.0.2.1";
    interface = "ens3";
  };
  defaultGateway6 = {
    address = "fe80::1";
    interface = "ens3";
  };
};

Hosts file

To edit /etc/hosts just add something like this to your configuration.nix:

networking.hosts = {
  "127.0.0.2" = ["other-localhost"];
  "192.0.2.1" = ["mail.example.com" "imap.example.com"];
};

Port forwarding

In this example we're going to forward the port 80 via NAT from our internal network interface ens3 to the host 10.100.0.3 on our external interface wg0.

networking = {
  nftables = {
    enable = true;
    ruleset = ''
        table ip nat {
          chain PREROUTING {
            type nat hook prerouting priority dstnat; policy accept;
            iifname "ens3" tcp dport 80 dnat to 10.100.0.3:80
          }
        }
    '';
  };
  firewall = {
    enable = true;
    allowedTCPPorts = [ 80 ];
  };
  nat = {
    enable = true;
    internalInterfaces = [ "ens3" ];
    externalInterface = "wg0";
    forwardPorts = [
      {
        sourcePort = 80;
        proto = "tcp";
        destination = "10.100.0.3:80";
      }
    ];
  };
};

For IPv6 port forwarding, the example would look like this. Incoming connections on the address 2001:db8:: and port 80 will be forwarded to [fe80::1234:5678:9abc:def0]:80.

networking = {
  nftables = {
    enable = true;
    ruleset = ''
        table ip6 nat {
          chain PREROUTING {
            type nat hook prerouting priority dstnat; policy accept;
            iifname "ens3" ip6 daddr [2001:db8::] tcp dport 80 dnat to [fe80::1234:5678:9abc:def0]:80
          }
        }
    '';
  };
  firewall = {
    enable = true;
    allowedTCPPorts = [ 80 ];
  };
  nat = {
    enable = true;
    internalInterfaces = [ "ens3" ];
    externalInterface = "wg0";
    enableIPv6 = true;
    internalIPv6s = [ "2001:db8::/64" ];
    externalIPv6 = "fe80::1234:5678:9abc:def0";
    forwardPorts = [
      {
        sourcePort = 80;
        proto = "tcp";
        destination = "fe80::1234:5678:9abc:def0]:80";
      }
    ];
  };
};

IPv6

Prefix delegation with fixed DUID

Sometimes the hosting provider manages IPv6 networks via a so-called DUID or clientid. This snippet is required to make the network routable:

{ config, pkgs, ... }:

let
  # Get this from your hosting provider
  clientid = "00:11:22:33:44:55:66:77:88:99";
  interface = "enp2s0";
  subnet =  "56";
  network = "2001:bbb:3333:1111::/${subnet}";
  own_ip =  "2001:bbb:3333:1111::1/${subnet}";
in {
  # ... snip ...

  networking.enableIPv6 = true;
  networking.useDHCP = true;
  networking.dhcpcd.persistent = true;
  networking.dhcpcd.extraConfig = ''
    clientid "${clientid}"
    noipv6rs
    interface ${interface}
    ia_pd 1/${network} ${interface}
    static ip6_address=${own_ip}
  '';
  environment.etc."dhcpcd.duid".text = clientid;

}

Source: gleber gist for online.net IPv6 config in NixOS

Note: Recent versions of dhcpcd move the duid file to /var/db/dcpcd/duid. For that to work, you have to replace the above environment.etc line with something like:

systemd.services.dhcpcd.preStart = ''
  cp ${pkgs.writeText "duid" "<ID>"} /var/db/dhcpcd/duid
'';

IPv6-mostly

For IPv6 mostly networks the situation in Linux is a little bit dire. A 464XLAT CLAT implementation on the client device has to be running.

For example run clatd:

{
  services.clatd.enable = true;
}

Caveats:

  • disable IPv4 manually for DHCPv4 clients that do not accept Option 108 (IPv6-Only Preferred Option)
  • set NAT64 prefix manually, if client doesn't support RA/PREF64 (RFC 8781) or DNS64 (RFC 7050):
{
  services.clatd.settings = {
    plat-prefix = "64:ff9b::/96";
  };
}
  • clatd needs to be restarted, if the network has changed

Sources:

VLANs

Refer to networking.vlans in the manual.

Below is a complete networking example showing two interfaces, one with VLAN trunk tagging and one without.

enp2s1 is a normal network interface at 192.168.1.2 with no VLAN information.

enp2s0 is the virtual LAN trunk with two tagged VLANs, vlan100 and vlan101.

vlan100 is in the 10.1.1.X network and vlan101 is in the 10.10.10.X network.

The hostID should be unique among your machines, as mentioned in the manual.

Complete networking section example:

    networking = {
      hostId = "deadb33f";
      hostName = "nixos";
      domain = "example.com";
      dhcpcd.enable = false;
      interfaces.enp2s1.ipv4.addresses = [{
        address = "192.168.1.2";
        prefixLength = 28;
      }];
      vlans = {
        vlan100 = { id=100; interface="enp2s0"; };
        vlan101 = { id=101; interface="enp2s0"; };
      };
      interfaces.vlan100.ipv4.addresses = [{
        address = "10.1.1.2";
        prefixLength = 24;
      }];
      interfaces.vlan101.ipv4.addresses = [{
        address = "10.10.10.3";
        prefixLength = 24;
      }];
      defaultGateway = "192.168.1.1";
      nameservers = [ "1.1.1.1" "8.8.8.8" ];
    };