From 5672d3d8b835b510a72b4280c97e8db0765ebef4 Mon Sep 17 00:00:00 2001 From: h7x4 Date: Wed, 1 Nov 2023 19:47:51 +0100 Subject: [PATCH] nixos/quicktun: clean up module --- .../modules/services/networking/quicktun.nix | 146 ++++++++++++------ 1 file changed, 102 insertions(+), 44 deletions(-) diff --git a/nixos/modules/services/networking/quicktun.nix b/nixos/modules/services/networking/quicktun.nix index 7aed972adc88..2d44659f2080 100644 --- a/nixos/modules/services/networking/quicktun.nix +++ b/nixos/modules/services/networking/quicktun.nix @@ -1,94 +1,153 @@ -{ config, pkgs, lib, ... }: +{ options, config, pkgs, lib, ... }: let + inherit (lib) mkOption mdDoc types mkIf; + opt = options.services.quicktun; cfg = config.services.quicktun; - in - -with lib; - { options = { - services.quicktun = mkOption { default = { }; - description = lib.mdDoc "QuickTun tunnels"; - type = types.attrsOf (types.submodule { + description = mdDoc '' + QuickTun tunnels. + + See for more information about available options. + ''; + type = types.attrsOf (types.submodule ({ name, ... }: let + qtcfg = cfg.${name}; + in { options = { tunMode = mkOption { - type = types.int; - default = 0; - example = 1; - description = lib.mdDoc ""; + type = with types; coercedTo bool (b: if b then 1 else 0) (ints.between 0 1); + default = false; + example = true; + description = mdDoc "Whether to operate in tun (IP) or tap (Ethernet) mode."; }; remoteAddress = mkOption { type = types.str; + default = "0.0.0.0"; example = "tunnel.example.com"; - description = lib.mdDoc ""; + description = mdDoc '' + IP address or hostname of the remote end (use `0.0.0.0` for a floating/dynamic remote endpoint). + ''; }; localAddress = mkOption { - type = types.str; + type = with types; nullOr str; + default = null; example = "0.0.0.0"; - description = lib.mdDoc ""; + description = mdDoc "IP address or hostname of the local end."; }; localPort = mkOption { - type = types.int; + type = types.port; default = 2998; - description = lib.mdDoc ""; + description = mdDoc "Local UDP port."; }; remotePort = mkOption { - type = types.int; - default = 2998; - description = lib.mdDoc ""; + type = types.port; + default = qtcfg.localPort; + defaultText = lib.literalExpression "config.services.quicktun..localPort"; + description = mdDoc " remote UDP port"; }; remoteFloat = mkOption { - type = types.int; - default = 0; - description = lib.mdDoc ""; + type = with types; coercedTo bool (b: if b then 1 else 0) (ints.between 0 1); + default = false; + example = true; + description = mdDoc '' + Whether to allow the remote address and port to change when properly encrypted packets are received. + ''; }; protocol = mkOption { - type = types.str; + type = types.enum [ "raw" "nacl0" "nacltai" "salty" ]; default = "nacltai"; - description = lib.mdDoc ""; + description = mdDoc "Which protocol to use."; }; privateKey = mkOption { - type = types.str; - description = lib.mdDoc ""; + type = with types; nullOr str; + default = null; + description = mdDoc '' + Local secret key in hexadecimal form. + + ::: {.warning} + This option is deprecated. Please use {var}`services.quicktun..privateKeyFile` instead. + ::: + + ::: {.note} + Not needed when {var}`services.quicktun..protocol` is set to `raw`. + ::: + ''; + }; + + privateKeyFile = mkOption { + type = with types; nullOr path; + # This is a hack to deprecate `privateKey` without using `mkChangedModuleOption` + default = if qtcfg.privateKey == null then null else pkgs.writeText "quickttun-key-${name}" qtcfg.privateKey; + defaultText = "null"; + description = mdDoc '' + Path to file containing local secret key in binary or hexadecimal form. + + ::: {.note} + Not needed when {var}`services.quicktun..protocol` is set to `raw`. + ::: + ''; }; publicKey = mkOption { - type = types.str; - description = lib.mdDoc ""; + type = with types; nullOr str; + default = null; + description = mdDoc '' + Remote public key in hexadecimal form. + + ::: {.note} + Not needed when {var}`services.quicktun..protocol` is set to `raw`. + ::: + ''; }; timeWindow = mkOption { - type = types.int; + type = types.ints.unsigned; default = 5; - description = lib.mdDoc ""; + description = mdDoc '' + Allowed time window for first received packet in seconds (positive number allows packets from history) + ''; }; upScript = mkOption { - type = types.lines; - default = ""; - description = lib.mdDoc ""; + type = with types; nullOr lines; + default = null; + description = mdDoc '' + Run specified command or script after the tunnel device has been opened. + ''; }; }; - }); + })); }; - }; - config = mkIf (cfg != []) { - systemd.services = foldr (a: b: a // b) {} ( - mapAttrsToList (name: qtcfg: { + config = { + warnings = lib.pipe cfg [ + (lib.mapAttrsToList (name: value: if value.privateKey != null then name else null)) + (builtins.filter (n: n != null)) + (map (n: " - services.quicktun.${n}.privateKey")) + (services: lib.optional (services != [ ]) '' + `services.quicktun..privateKey` is deprecated. + Please use `services.quicktun..privateKeyFile` instead. + + Offending options: + ${lib.concatStringsSep "\n" services} + '') + ]; + + systemd.services = lib.mkMerge ( + lib.mapAttrsToList (name: qtcfg: { "quicktun-${name}" = { wantedBy = [ "multi-user.target" ]; after = [ "network.target" ]; @@ -96,14 +155,14 @@ with lib; INTERFACE = name; TUN_MODE = toString qtcfg.tunMode; REMOTE_ADDRESS = qtcfg.remoteAddress; - LOCAL_ADDRESS = qtcfg.localAddress; + LOCAL_ADDRESS = mkIf (qtcfg.localAddress != null) (qtcfg.localAddress); LOCAL_PORT = toString qtcfg.localPort; REMOTE_PORT = toString qtcfg.remotePort; REMOTE_FLOAT = toString qtcfg.remoteFloat; - PRIVATE_KEY = qtcfg.privateKey; - PUBLIC_KEY = qtcfg.publicKey; + PRIVATE_KEY_FILE = mkIf (qtcfg.privateKeyFile != null) qtcfg.privateKeyFile; + PUBLIC_KEY = mkIf (qtcfg.publicKey != null) qtcfg.publicKey; TIME_WINDOW = toString qtcfg.timeWindow; - TUN_UP_SCRIPT = pkgs.writeScript "quicktun-${name}-up.sh" qtcfg.upScript; + TUN_UP_SCRIPT = mkIf (qtcfg.upScript != null) (pkgs.writeScript "quicktun-${name}-up.sh" qtcfg.upScript); SUID = "nobody"; }; serviceConfig = { @@ -114,5 +173,4 @@ with lib; }) cfg ); }; - }