at 25.11-pre 5.7 kB view raw
1{ 2 config, 3 lib, 4 pkgs, 5 ... 6}: 7 8with lib; 9let 10 cfg = config.services.tayga; 11 12 # Converts an address set to a string 13 strAddr = addr: "${addr.address}/${toString addr.prefixLength}"; 14 15 configFile = pkgs.writeText "tayga.conf" '' 16 tun-device ${cfg.tunDevice} 17 18 ipv4-addr ${cfg.ipv4.address} 19 ${optionalString (cfg.ipv6.address != null) "ipv6-addr ${cfg.ipv6.address}"} 20 21 prefix ${strAddr cfg.ipv6.pool} 22 dynamic-pool ${strAddr cfg.ipv4.pool} 23 data-dir ${cfg.dataDir} 24 25 ${concatStringsSep "\n" (mapAttrsToList (ipv4: ipv6: "map " + ipv4 + " " + ipv6) cfg.mappings)} 26 ''; 27 28 addrOpts = 29 v: 30 assert v == 4 || v == 6; 31 { 32 options = { 33 address = mkOption { 34 type = types.str; 35 description = "IPv${toString v} address."; 36 }; 37 38 prefixLength = mkOption { 39 type = types.addCheck types.int (n: n >= 0 && n <= (if v == 4 then 32 else 128)); 40 description = '' 41 Subnet mask of the interface, specified as the number of 42 bits in the prefix ("${if v == 4 then "24" else "64"}"). 43 ''; 44 }; 45 }; 46 }; 47 48 versionOpts = v: { 49 options = { 50 router = { 51 address = mkOption { 52 type = types.str; 53 description = "The IPv${toString v} address of the router."; 54 }; 55 }; 56 57 address = mkOption { 58 type = types.nullOr types.str; 59 default = null; 60 description = "The source IPv${toString v} address of the TAYGA server."; 61 }; 62 63 pool = mkOption { 64 type = with types; nullOr (submodule (addrOpts v)); 65 description = "The pool of IPv${toString v} addresses which are used for translation."; 66 }; 67 }; 68 }; 69in 70{ 71 options = { 72 services.tayga = { 73 enable = mkEnableOption "Tayga"; 74 75 package = mkPackageOption pkgs "tayga" { }; 76 77 ipv4 = mkOption { 78 type = types.submodule (versionOpts 4); 79 description = "IPv4-specific configuration."; 80 example = literalExpression '' 81 { 82 address = "192.0.2.0"; 83 router = { 84 address = "192.0.2.1"; 85 }; 86 pool = { 87 address = "192.0.2.1"; 88 prefixLength = 24; 89 }; 90 } 91 ''; 92 }; 93 94 ipv6 = mkOption { 95 type = types.submodule (versionOpts 6); 96 description = "IPv6-specific configuration."; 97 example = literalExpression '' 98 { 99 address = "2001:db8::1"; 100 router = { 101 address = "64:ff9b::1"; 102 }; 103 pool = { 104 address = "64:ff9b::"; 105 prefixLength = 96; 106 }; 107 } 108 ''; 109 }; 110 111 dataDir = mkOption { 112 type = types.path; 113 default = "/var/lib/tayga"; 114 description = "Directory for persistent data."; 115 }; 116 117 tunDevice = mkOption { 118 type = types.str; 119 default = "nat64"; 120 description = "Name of the nat64 tun device."; 121 }; 122 123 mappings = mkOption { 124 type = types.attrsOf types.str; 125 default = { }; 126 description = "Static IPv4 -> IPv6 host mappings."; 127 example = literalExpression '' 128 { 129 "192.168.5.42" = "2001:db8:1:4444::1"; 130 "192.168.5.43" = "2001:db8:1:4444::2"; 131 "192.168.255.2" = "2001:db8:1:569::143"; 132 } 133 ''; 134 }; 135 }; 136 }; 137 138 config = mkIf cfg.enable { 139 assertions = [ 140 { 141 assertion = allUnique (attrValues cfg.mappings); 142 message = "Neither the IPv4 nor the IPv6 addresses must be entered twice in the mappings."; 143 } 144 ]; 145 146 networking.interfaces."${cfg.tunDevice}" = { 147 virtual = true; 148 virtualType = "tun"; 149 virtualOwner = mkIf config.networking.useNetworkd ""; 150 ipv4 = { 151 addresses = [ 152 { 153 address = cfg.ipv4.router.address; 154 prefixLength = 32; 155 } 156 ]; 157 routes = [ 158 cfg.ipv4.pool 159 ]; 160 }; 161 ipv6 = { 162 addresses = [ 163 { 164 address = cfg.ipv6.router.address; 165 prefixLength = 128; 166 } 167 ]; 168 routes = [ 169 cfg.ipv6.pool 170 ]; 171 }; 172 }; 173 174 systemd.services.tayga = { 175 description = "Stateless NAT64 implementation"; 176 wantedBy = [ "multi-user.target" ]; 177 after = [ "network.target" ]; 178 179 serviceConfig = { 180 ExecStart = "${cfg.package}/bin/tayga -d --nodetach --config ${configFile}"; 181 ExecReload = "${pkgs.coreutils}/bin/kill -SIGHUP $MAINPID"; 182 Restart = "always"; 183 184 # Hardening Score: 185 # - nixos-scripts: 2.1 186 # - systemd-networkd: 1.6 187 ProtectHome = true; 188 SystemCallFilter = [ 189 "@network-io" 190 "@system-service" 191 "~@privileged" 192 "~@resources" 193 ]; 194 ProtectKernelLogs = true; 195 AmbientCapabilities = [ 196 "CAP_NET_ADMIN" 197 ]; 198 CapabilityBoundingSet = ""; 199 RestrictAddressFamilies = [ 200 "AF_INET" 201 "AF_INET6" 202 "AF_NETLINK" 203 ]; 204 StateDirectory = "tayga"; 205 DynamicUser = mkIf config.networking.useNetworkd true; 206 MemoryDenyWriteExecute = true; 207 RestrictRealtime = true; 208 RestrictSUIDSGID = true; 209 ProtectHostname = true; 210 ProtectKernelModules = true; 211 ProtectKernelTunables = true; 212 RestrictNamespaces = true; 213 NoNewPrivileges = true; 214 ProtectControlGroups = true; 215 SystemCallArchitectures = "native"; 216 PrivateTmp = true; 217 LockPersonality = true; 218 ProtectSystem = true; 219 PrivateUsers = true; 220 ProtectProc = "invisible"; 221 }; 222 }; 223 }; 224}