at 24.11-pre 5.9 kB view raw
1{ options, config, pkgs, lib, ... }: 2 3let 4 inherit (lib) mkOption types mkIf; 5 6 opt = options.services.quicktun; 7 cfg = config.services.quicktun; 8in 9{ 10 options = { 11 services.quicktun = mkOption { 12 default = { }; 13 description = '' 14 QuickTun tunnels. 15 16 See <http://wiki.ucis.nl/QuickTun> for more information about available options. 17 ''; 18 type = types.attrsOf (types.submodule ({ name, ... }: let 19 qtcfg = cfg.${name}; 20 in { 21 options = { 22 tunMode = mkOption { 23 type = with types; coercedTo bool (b: if b then 1 else 0) (ints.between 0 1); 24 default = false; 25 example = true; 26 description = "Whether to operate in tun (IP) or tap (Ethernet) mode."; 27 }; 28 29 remoteAddress = mkOption { 30 type = types.str; 31 default = "0.0.0.0"; 32 example = "tunnel.example.com"; 33 description = '' 34 IP address or hostname of the remote end (use `0.0.0.0` for a floating/dynamic remote endpoint). 35 ''; 36 }; 37 38 localAddress = mkOption { 39 type = with types; nullOr str; 40 default = null; 41 example = "0.0.0.0"; 42 description = "IP address or hostname of the local end."; 43 }; 44 45 localPort = mkOption { 46 type = types.port; 47 default = 2998; 48 description = "Local UDP port."; 49 }; 50 51 remotePort = mkOption { 52 type = types.port; 53 default = qtcfg.localPort; 54 defaultText = lib.literalExpression "config.services.quicktun.<name>.localPort"; 55 description = " remote UDP port"; 56 }; 57 58 remoteFloat = mkOption { 59 type = with types; coercedTo bool (b: if b then 1 else 0) (ints.between 0 1); 60 default = false; 61 example = true; 62 description = '' 63 Whether to allow the remote address and port to change when properly encrypted packets are received. 64 ''; 65 }; 66 67 protocol = mkOption { 68 type = types.enum [ "raw" "nacl0" "nacltai" "salty" ]; 69 default = "nacltai"; 70 description = "Which protocol to use."; 71 }; 72 73 privateKey = mkOption { 74 type = with types; nullOr str; 75 default = null; 76 description = '' 77 Local secret key in hexadecimal form. 78 79 ::: {.warning} 80 This option is deprecated. Please use {var}`services.quicktun.<name>.privateKeyFile` instead. 81 ::: 82 83 ::: {.note} 84 Not needed when {var}`services.quicktun.<name>.protocol` is set to `raw`. 85 ::: 86 ''; 87 }; 88 89 privateKeyFile = mkOption { 90 type = with types; nullOr path; 91 # This is a hack to deprecate `privateKey` without using `mkChangedModuleOption` 92 default = if qtcfg.privateKey == null then null else pkgs.writeText "quickttun-key-${name}" qtcfg.privateKey; 93 defaultText = "null"; 94 description = '' 95 Path to file containing local secret key in binary or hexadecimal form. 96 97 ::: {.note} 98 Not needed when {var}`services.quicktun.<name>.protocol` is set to `raw`. 99 ::: 100 ''; 101 }; 102 103 publicKey = mkOption { 104 type = with types; nullOr str; 105 default = null; 106 description = '' 107 Remote public key in hexadecimal form. 108 109 ::: {.note} 110 Not needed when {var}`services.quicktun.<name>.protocol` is set to `raw`. 111 ::: 112 ''; 113 }; 114 115 timeWindow = mkOption { 116 type = types.ints.unsigned; 117 default = 5; 118 description = '' 119 Allowed time window for first received packet in seconds (positive number allows packets from history) 120 ''; 121 }; 122 123 upScript = mkOption { 124 type = with types; nullOr lines; 125 default = null; 126 description = '' 127 Run specified command or script after the tunnel device has been opened. 128 ''; 129 }; 130 }; 131 })); 132 }; 133 }; 134 135 config = { 136 warnings = lib.pipe cfg [ 137 (lib.mapAttrsToList (name: value: if value.privateKey != null then name else null)) 138 (builtins.filter (n: n != null)) 139 (map (n: " - services.quicktun.${n}.privateKey")) 140 (services: lib.optional (services != [ ]) '' 141 `services.quicktun.<name>.privateKey` is deprecated. 142 Please use `services.quicktun.<name>.privateKeyFile` instead. 143 144 Offending options: 145 ${lib.concatStringsSep "\n" services} 146 '') 147 ]; 148 149 systemd.services = lib.mkMerge ( 150 lib.mapAttrsToList (name: qtcfg: { 151 "quicktun-${name}" = { 152 wantedBy = [ "multi-user.target" ]; 153 after = [ "network.target" ]; 154 environment = { 155 INTERFACE = name; 156 TUN_MODE = toString qtcfg.tunMode; 157 REMOTE_ADDRESS = qtcfg.remoteAddress; 158 LOCAL_ADDRESS = mkIf (qtcfg.localAddress != null) (qtcfg.localAddress); 159 LOCAL_PORT = toString qtcfg.localPort; 160 REMOTE_PORT = toString qtcfg.remotePort; 161 REMOTE_FLOAT = toString qtcfg.remoteFloat; 162 PRIVATE_KEY_FILE = mkIf (qtcfg.privateKeyFile != null) qtcfg.privateKeyFile; 163 PUBLIC_KEY = mkIf (qtcfg.publicKey != null) qtcfg.publicKey; 164 TIME_WINDOW = toString qtcfg.timeWindow; 165 TUN_UP_SCRIPT = mkIf (qtcfg.upScript != null) (pkgs.writeScript "quicktun-${name}-up.sh" qtcfg.upScript); 166 SUID = "nobody"; 167 }; 168 serviceConfig = { 169 Type = "simple"; 170 ExecStart = "${pkgs.quicktun}/bin/quicktun.${qtcfg.protocol}"; 171 }; 172 }; 173 }) cfg 174 ); 175 }; 176}