diff options
author | Ryan Lahfa <masterancpp@gmail.com> | 2022-12-01 21:14:50 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-12-01 21:14:50 +0100 |
commit | 5d87a1b9b8dd88ac213244aa9ce6094b68d44433 (patch) | |
tree | c438b1af8f490e3e6801c6f698d6d6cc4313ce40 | |
parent | 831b9b4c3628f1c2858b4ec82e1de4a2ecba2c9c (diff) | |
parent | 3e534cfde55bfd5a2e1348d25bd27bfe9c615746 (diff) | |
download | nixpkgs-5d87a1b9b8dd88ac213244aa9ce6094b68d44433.tar nixpkgs-5d87a1b9b8dd88ac213244aa9ce6094b68d44433.tar.gz nixpkgs-5d87a1b9b8dd88ac213244aa9ce6094b68d44433.tar.bz2 nixpkgs-5d87a1b9b8dd88ac213244aa9ce6094b68d44433.tar.lz nixpkgs-5d87a1b9b8dd88ac213244aa9ce6094b68d44433.tar.xz nixpkgs-5d87a1b9b8dd88ac213244aa9ce6094b68d44433.tar.zst nixpkgs-5d87a1b9b8dd88ac213244aa9ce6094b68d44433.zip |
Merge pull request #195735 from hax404/tayga_init
nixos/tayga: init
-rw-r--r-- | nixos/doc/manual/from_md/release-notes/rl-2211.section.xml | 7 | ||||
-rw-r--r-- | nixos/doc/manual/release-notes/rl-2211.section.md | 2 | ||||
-rw-r--r-- | nixos/modules/module-list.nix | 1 | ||||
-rw-r--r-- | nixos/modules/services/networking/tayga.nix | 195 | ||||
-rw-r--r-- | nixos/tests/all-tests.nix | 1 | ||||
-rw-r--r-- | nixos/tests/tayga.nix | 235 | ||||
-rw-r--r-- | pkgs/tools/networking/tayga/default.nix | 6 |
7 files changed, 445 insertions, 2 deletions
diff --git a/nixos/doc/manual/from_md/release-notes/rl-2211.section.xml b/nixos/doc/manual/from_md/release-notes/rl-2211.section.xml index f912c467c7e..1fe25e7be78 100644 --- a/nixos/doc/manual/from_md/release-notes/rl-2211.section.xml +++ b/nixos/doc/manual/from_md/release-notes/rl-2211.section.xml @@ -1811,6 +1811,13 @@ services.github-runner.serviceOverrides.SupplementaryGroups = [ </listitem> <listitem> <para> + <link xlink:href="http://www.litech.org/tayga/">TAYGA</link>, + an out-of-kernel stateless NAT64 implementation. Available as + <link linkend="opt-services.tayga.enable">services.tayga</link>. + </para> + </listitem> + <listitem> + <para> <link xlink:href="https://github.com/tmate-io/tmate-ssh-server">tmate-ssh-server</link>, server side part of <link xlink:href="https://tmate.io/">tmate</link>. Available diff --git a/nixos/doc/manual/release-notes/rl-2211.section.md b/nixos/doc/manual/release-notes/rl-2211.section.md index d427597cc7b..b6e0824f8b4 100644 --- a/nixos/doc/manual/release-notes/rl-2211.section.md +++ b/nixos/doc/manual/release-notes/rl-2211.section.md @@ -526,6 +526,8 @@ In addition to numerous new and upgraded packages, this release includes the fol - [Tandoor Recipes](https://tandoor.dev), a self-hosted multi-tenant recipe collection. Available as [services.tandoor-recipes](options.html#opt-services.tandoor-recipes.enable). +- [TAYGA](http://www.litech.org/tayga/), an out-of-kernel stateless NAT64 implementation. Available as [services.tayga](#opt-services.tayga.enable). + - [tmate-ssh-server](https://github.com/tmate-io/tmate-ssh-server), server side part of [tmate](https://tmate.io/). Available as [services.tmate-ssh-server](#opt-services.tmate-ssh-server.enable). - [Uptime Kuma](https://uptime.kuma.pet/), a fancy self-hosted monitoring tool. Available as [services.uptime-kuma](#opt-services.uptime-kuma.enable). diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index d5550cd878e..18ce9e8a151 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -967,6 +967,7 @@ ./services/networking/syncthing-relay.nix ./services/networking/syncplay.nix ./services/networking/tailscale.nix + ./services/networking/tayga.nix ./services/networking/tcpcrypt.nix ./services/networking/teamspeak3.nix ./services/networking/tedicross.nix diff --git a/nixos/modules/services/networking/tayga.nix b/nixos/modules/services/networking/tayga.nix new file mode 100644 index 00000000000..299ae2777f7 --- /dev/null +++ b/nixos/modules/services/networking/tayga.nix @@ -0,0 +1,195 @@ +{ config, lib, pkgs, ... }: + +with lib; +let + cfg = config.services.tayga; + + # Converts an address set to a string + strAddr = addr: "${addr.address}/${toString addr.prefixLength}"; + + configFile = pkgs.writeText "tayga.conf" '' + tun-device ${cfg.tunDevice} + + ipv4-addr ${cfg.ipv4.address} + ${optionalString (cfg.ipv6.address != null) "ipv6-addr ${cfg.ipv6.address}"} + + prefix ${strAddr cfg.ipv6.pool} + dynamic-pool ${strAddr cfg.ipv4.pool} + data-dir ${cfg.dataDir} + ''; + + addrOpts = v: + assert v == 4 || v == 6; + { + options = { + address = mkOption { + type = types.str; + description = lib.mdDoc "IPv${toString v} address."; + }; + + prefixLength = mkOption { + type = types.addCheck types.int (n: n >= 0 && n <= (if v == 4 then 32 else 128)); + description = lib.mdDoc '' + Subnet mask of the interface, specified as the number of + bits in the prefix ("${if v == 4 then "24" else "64"}"). + ''; + }; + }; + }; + + versionOpts = v: { + options = { + router = { + address = mkOption { + type = types.str; + description = lib.mdDoc "The IPv${toString v} address of the router."; + }; + }; + + address = mkOption { + type = types.nullOr types.str; + default = null; + description = lib.mdDoc "The source IPv${toString v} address of the TAYGA server."; + }; + + pool = mkOption { + type = with types; nullOr (submodule (addrOpts v)); + description = lib.mdDoc "The pool of IPv${toString v} addresses which are used for translation."; + }; + }; + }; +in +{ + options = { + services.tayga = { + enable = mkEnableOption (lib.mdDoc "Tayga"); + + package = mkOption { + type = types.package; + default = pkgs.tayga; + defaultText = lib.literalMD "pkgs.tayga"; + description = lib.mdDoc "This option specifies the TAYGA package to use."; + }; + + ipv4 = mkOption { + type = types.submodule (versionOpts 4); + description = lib.mdDoc "IPv4-specific configuration."; + example = literalExpression '' + { + address = "192.0.2.0"; + router = { + address = "192.0.2.1"; + }; + pool = { + address = "192.0.2.1"; + prefixLength = 24; + }; + } + ''; + }; + + ipv6 = mkOption { + type = types.submodule (versionOpts 6); + description = lib.mdDoc "IPv6-specific configuration."; + example = literalExpression '' + { + address = "2001:db8::1"; + router = { + address = "64:ff9b::1"; + }; + pool = { + address = "64:ff9b::"; + prefixLength = 96; + }; + } + ''; + }; + + dataDir = mkOption { + type = types.path; + default = "/var/lib/tayga"; + description = lib.mdDoc "Directory for persistent data"; + }; + + tunDevice = mkOption { + type = types.str; + default = "nat64"; + description = lib.mdDoc "Name of the nat64 tun device"; + }; + }; + }; + + config = mkIf cfg.enable { + networking.interfaces."${cfg.tunDevice}" = { + virtual = true; + virtualType = "tun"; + virtualOwner = mkIf config.networking.useNetworkd ""; + ipv4 = { + addresses = [ + { address = cfg.ipv4.router.address; prefixLength = 32; } + ]; + routes = [ + cfg.ipv4.pool + ]; + }; + ipv6 = { + addresses = [ + { address = cfg.ipv6.router.address; prefixLength = 128; } + ]; + routes = [ + cfg.ipv6.pool + ]; + }; + }; + + systemd.services.tayga = { + description = "Stateless NAT64 implementation"; + wantedBy = [ "multi-user.target" ]; + after = [ "network.target" ]; + + serviceConfig = { + ExecStart = "${cfg.package}/bin/tayga -d --nodetach --config ${configFile}"; + ExecReload = "${pkgs.coreutils}/bin/kill -SIGHUP $MAINPID"; + Restart = "always"; + + # Hardening Score: + # - nixos-scripts: 2.1 + # - systemd-networkd: 1.6 + ProtectHome = true; + SystemCallFilter = [ + "@network-io" + "@system-service" + "~@privileged" + "~@resources" + ]; + ProtectKernelLogs = true; + AmbientCapabilities = [ + "CAP_NET_ADMIN" + ]; + CapabilityBoundingSet = ""; + RestrictAddressFamilies = [ + "AF_INET" + "AF_INET6" + "AF_NETLINK" + ]; + StateDirectory = "tayga"; + DynamicUser = mkIf config.networking.useNetworkd true; + MemoryDenyWriteExecute = true; + RestrictRealtime = true; + RestrictSUIDSGID = true; + ProtectHostname = true; + ProtectKernelModules = true; + ProtectKernelTunables = true; + RestrictNamespaces = true; + NoNewPrivileges = true; + ProtectControlGroups = true; + SystemCallArchitectures = "native"; + PrivateTmp = true; + LockPersonality = true; + ProtectSystem = true; + PrivateUsers = true; + ProtectProc = "invisible"; + }; + }; + }; +} diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix index f97d7b184af..895cbe4290d 100644 --- a/nixos/tests/all-tests.nix +++ b/nixos/tests/all-tests.nix @@ -638,6 +638,7 @@ in { systemd-misc = handleTest ./systemd-misc.nix {}; tandoor-recipes = handleTest ./tandoor-recipes.nix {}; taskserver = handleTest ./taskserver.nix {}; + tayga = handleTest ./tayga.nix {}; teeworlds = handleTest ./teeworlds.nix {}; telegraf = handleTest ./telegraf.nix {}; teleport = handleTest ./teleport.nix {}; diff --git a/nixos/tests/tayga.nix b/nixos/tests/tayga.nix new file mode 100644 index 00000000000..44974f6efea --- /dev/null +++ b/nixos/tests/tayga.nix @@ -0,0 +1,235 @@ +# This test verifies that we can ping an IPv4-only server from an IPv6-only +# client via a NAT64 router. The hosts and networks are configured as follows: +# +# +------ +# Client | eth1 Address: 2001:db8::2/64 +# | | Route: 64:ff9b::/96 via 2001:db8::1 +# +--|--- +# | VLAN 3 +# +--|--- +# | eth2 Address: 2001:db8::1/64 +# Router | +# | nat64 Address: 64:ff9b::1/128 +# | Route: 64:ff9b::/96 +# | Address: 192.0.2.0/32 +# | Route: 192.0.2.0/24 +# | +# | eth1 Address: 100.64.0.1/24 +# +--|--- +# | VLAN 2 +# +--|--- +# Server | eth1 Address: 100.64.0.2/24 +# | Route: 192.0.2.0/24 via 100.64.0.1 +# +------ + +import ./make-test-python.nix ({ pkgs, lib, ... }: + +{ + name = "tayga"; + meta = with pkgs.lib.maintainers; { + maintainers = [ hax404 ]; + }; + + nodes = { + # The server is configured with static IPv4 addresses. RFC 6052 Section 3.1 + # disallows the mapping of non-global IPv4 addresses like RFC 1918 into the + # Well-Known Prefix 64:ff9b::/96. TAYGA also does not allow the mapping of + # documentation space (RFC 5737). To circumvent this, 100.64.0.2/24 from + # RFC 6589 (Carrier Grade NAT) is used here. + # To reach the IPv4 address pool of the NAT64 gateway, there is a static + # route configured. In normal cases, where the router would also source NAT + # the pool addresses to one IPv4 addresses, this would not be needed. + server = { + virtualisation.vlans = [ + 2 # towards router + ]; + networking = { + useDHCP = false; + interfaces.eth1 = lib.mkForce {}; + }; + systemd.network = { + enable = true; + networks."vlan1" = { + matchConfig.Name = "eth1"; + address = [ + "100.64.0.2/24" + ]; + routes = [ + { routeConfig = { Destination = "192.0.2.0/24"; Gateway = "100.64.0.1"; }; } + ]; + }; + }; + }; + + # The router is configured with static IPv4 addresses towards the server + # and IPv6 addresses towards the client. For NAT64, the Well-Known prefix + # 64:ff9b::/96 is used. NAT64 is done with TAYGA which provides the + # tun-interface nat64 and does the translation over it. The IPv6 packets + # are sent to this interfaces and received as IPv4 packets and vice versa. + # As TAYGA only translates IPv6 addresses to dedicated IPv4 addresses, it + # needs a pool of IPv4 addresses which must be at least as big as the + # expected amount of clients. In this test, the packets from the pool are + # directly routed towards the client. In normal cases, there would be a + # second source NAT44 to map all clients behind one IPv4 address. + router_systemd = { + boot.kernel.sysctl = { + "net.ipv4.ip_forward" = 1; + "net.ipv6.conf.all.forwarding" = 1; + }; + + virtualisation.vlans = [ + 2 # towards server + 3 # towards client + ]; + + networking = { + useDHCP = false; + useNetworkd = true; + firewall.enable = false; + interfaces.eth1 = lib.mkForce { + ipv4 = { + addresses = [ { address = "100.64.0.1"; prefixLength = 24; } ]; + }; + }; + interfaces.eth2 = lib.mkForce { + ipv6 = { + addresses = [ { address = "2001:db8::1"; prefixLength = 64; } ]; + }; + }; + }; + + services.tayga = { + enable = true; + ipv4 = { + address = "192.0.2.0"; + router = { + address = "192.0.2.1"; + }; + pool = { + address = "192.0.2.0"; + prefixLength = 24; + }; + }; + ipv6 = { + address = "2001:db8::1"; + router = { + address = "64:ff9b::1"; + }; + pool = { + address = "64:ff9b::"; + prefixLength = 96; + }; + }; + }; + }; + + router_nixos = { + boot.kernel.sysctl = { + "net.ipv4.ip_forward" = 1; + "net.ipv6.conf.all.forwarding" = 1; + }; + + virtualisation.vlans = [ + 2 # towards server + 3 # towards client + ]; + + networking = { + useDHCP = false; + firewall.enable = false; + interfaces.eth1 = lib.mkForce { + ipv4 = { + addresses = [ { address = "100.64.0.1"; prefixLength = 24; } ]; + }; + }; + interfaces.eth2 = lib.mkForce { + ipv6 = { + addresses = [ { address = "2001:db8::1"; prefixLength = 64; } ]; + }; + }; + }; + + services.tayga = { + enable = true; + ipv4 = { + address = "192.0.2.0"; + router = { + address = "192.0.2.1"; + }; + pool = { + address = "192.0.2.0"; + prefixLength = 24; + }; + }; + ipv6 = { + address = "2001:db8::1"; + router = { + address = "64:ff9b::1"; + }; + pool = { + address = "64:ff9b::"; + prefixLength = 96; + }; + }; + }; + }; + + # The client is configured with static IPv6 addresses. It has also a static + # route for the NAT64 IP space where the IPv4 addresses are mapped in. In + # normal cases, there would be only a default route. + client = { + virtualisation.vlans = [ + 3 # towards router + ]; + + networking = { + useDHCP = false; + interfaces.eth1 = lib.mkForce {}; + }; + + systemd.network = { + enable = true; + networks."vlan1" = { + matchConfig.Name = "eth1"; + address = [ + "2001:db8::2/64" + ]; + routes = [ + { routeConfig = { Destination = "64:ff9b::/96"; Gateway = "2001:db8::1"; }; } + ]; + }; + }; + environment.systemPackages = [ pkgs.mtr ]; + }; + }; + + testScript = '' + # start client and server + for machine in client, server: + machine.wait_for_unit("network-online.target") + machine.log(machine.execute("ip addr")[1]) + machine.log(machine.execute("ip route")[1]) + machine.log(machine.execute("ip -6 route")[1]) + + # test systemd-networkd and nixos-scripts based router + for router in router_systemd, router_nixos: + router.start() + router.wait_for_unit("network-online.target") + router.wait_for_unit("tayga.service") + router.log(machine.execute("ip addr")[1]) + router.log(machine.execute("ip route")[1]) + router.log(machine.execute("ip -6 route")[1]) + + with subtest("Wait for tayga"): + router.wait_for_unit("tayga.service") + + with subtest("Test ICMP"): + client.wait_until_succeeds("ping -c 3 64:ff9b::100.64.0.2 >&2") + + with subtest("Test ICMP and show a traceroute"): + client.wait_until_succeeds("mtr --show-ips --report-wide 64:ff9b::100.64.0.2 >&2") + + router.log(router.execute("systemd-analyze security tayga.service")[1]) + router.shutdown() + ''; +}) diff --git a/pkgs/tools/networking/tayga/default.nix b/pkgs/tools/networking/tayga/default.nix index 8d0de6a6c18..ef393f5bb15 100644 --- a/pkgs/tools/networking/tayga/default.nix +++ b/pkgs/tools/networking/tayga/default.nix @@ -1,4 +1,4 @@ -{ lib, stdenv, fetchurl }: +{ lib, stdenv, fetchurl, nixosTests }: stdenv.mkDerivation rec { version = "0.9.2"; @@ -9,6 +9,8 @@ stdenv.mkDerivation rec { sha256 = "1700y121lhvpna49bjpssb7jq1abj9qw5wxgjn8gzp6jm4kpj7rb"; }; + passthru.tests.tayga = nixosTests.tayga; + meta = with lib; { description = "Userland stateless NAT64 daemon"; longDescription = '' @@ -19,7 +21,7 @@ stdenv.mkDerivation rec { for networks where dedicated NAT64 hardware would be overkill. ''; homepage = "http://www.litech.org/tayga"; - license = licenses.gpl2; + license = licenses.gpl2Plus; maintainers = with maintainers; [ _0x4A6F ]; platforms = platforms.linux; }; |