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