1 { config, lib, pkgs, ... }:
5 cfg = config.services.tayga;
7 # Converts an address set to a string
8 strAddr = addr: "${addr.address}/${toString addr.prefixLength}";
10 configFile = pkgs.writeText "tayga.conf" ''
11 tun-device ${cfg.tunDevice}
13 ipv4-addr ${cfg.ipv4.address}
14 ${optionalString (cfg.ipv6.address != null) "ipv6-addr ${cfg.ipv6.address}"}
16 prefix ${strAddr cfg.ipv6.pool}
17 dynamic-pool ${strAddr cfg.ipv4.pool}
18 data-dir ${cfg.dataDir}
20 ${concatStringsSep "\n" (mapAttrsToList (ipv4: ipv6: "map " + ipv4 + " " + ipv6) cfg.mappings)}
24 assert v == 4 || v == 6;
29 description = "IPv${toString v} address.";
32 prefixLength = mkOption {
33 type = types.addCheck types.int (n: n >= 0 && n <= (if v == 4 then 32 else 128));
35 Subnet mask of the interface, specified as the number of
36 bits in the prefix ("${if v == 4 then "24" else "64"}").
47 description = "The IPv${toString v} address of the router.";
52 type = types.nullOr types.str;
54 description = "The source IPv${toString v} address of the TAYGA server.";
58 type = with types; nullOr (submodule (addrOpts v));
59 description = "The pool of IPv${toString v} addresses which are used for translation.";
67 enable = mkEnableOption "Tayga";
69 package = mkPackageOption pkgs "tayga" { };
72 type = types.submodule (versionOpts 4);
73 description = "IPv4-specific configuration.";
74 example = literalExpression ''
76 address = "192.0.2.0";
78 address = "192.0.2.1";
81 address = "192.0.2.1";
89 type = types.submodule (versionOpts 6);
90 description = "IPv6-specific configuration.";
91 example = literalExpression ''
93 address = "2001:db8::1";
95 address = "64:ff9b::1";
98 address = "64:ff9b::";
107 default = "/var/lib/tayga";
108 description = "Directory for persistent data.";
111 tunDevice = mkOption {
114 description = "Name of the nat64 tun device.";
117 mappings = mkOption {
118 type = types.attrsOf types.str;
120 description = "Static IPv4 -> IPv6 host mappings.";
121 example = literalExpression ''
123 "192.168.5.42" = "2001:db8:1:4444::1";
124 "192.168.5.43" = "2001:db8:1:4444::2";
125 "192.168.255.2" = "2001:db8:1:569::143";
132 config = mkIf cfg.enable {
135 assertion = allUnique (attrValues cfg.mappings);
136 message = "Neither the IPv4 nor the IPv6 addresses must be entered twice in the mappings.";
140 networking.interfaces."${cfg.tunDevice}" = {
143 virtualOwner = mkIf config.networking.useNetworkd "";
146 { address = cfg.ipv4.router.address; prefixLength = 32; }
154 { address = cfg.ipv6.router.address; prefixLength = 128; }
162 systemd.services.tayga = {
163 description = "Stateless NAT64 implementation";
164 wantedBy = [ "multi-user.target" ];
165 after = [ "network.target" ];
168 ExecStart = "${cfg.package}/bin/tayga -d --nodetach --config ${configFile}";
169 ExecReload = "${pkgs.coreutils}/bin/kill -SIGHUP $MAINPID";
173 # - nixos-scripts: 2.1
174 # - systemd-networkd: 1.6
182 ProtectKernelLogs = true;
183 AmbientCapabilities = [
186 CapabilityBoundingSet = "";
187 RestrictAddressFamilies = [
192 StateDirectory = "tayga";
193 DynamicUser = mkIf config.networking.useNetworkd true;
194 MemoryDenyWriteExecute = true;
195 RestrictRealtime = true;
196 RestrictSUIDSGID = true;
197 ProtectHostname = true;
198 ProtectKernelModules = true;
199 ProtectKernelTunables = true;
200 RestrictNamespaces = true;
201 NoNewPrivileges = true;
202 ProtectControlGroups = true;
203 SystemCallArchitectures = "native";
205 LockPersonality = true;
206 ProtectSystem = true;
208 ProtectProc = "invisible";