{ config, pkgs, lib, ... }: let cfg = config.services.quicktun; in with lib; { options = { services.quicktun = mkOption { default = { }; description = "QuickTun tunnels"; type = types.attrsOf (types.submodule { options = { tunMode = mkOption { type = types.int; default = 0; example = 1; description = ""; }; remoteAddress = mkOption { type = types.str; example = "tunnel.example.com"; description = ""; }; localAddress = mkOption { type = types.str; example = "0.0.0.0"; description = ""; }; localPort = mkOption { type = types.int; default = 2998; description = ""; }; remotePort = mkOption { type = types.int; default = 2998; description = ""; }; remoteFloat = mkOption { type = types.int; default = 0; description = ""; }; protocol = mkOption { type = types.str; default = "nacltai"; description = ""; }; privateKey = mkOption { type = types.str; description = ""; }; publicKey = mkOption { type = types.str; description = ""; }; timeWindow = mkOption { type = types.int; default = 5; description = ""; }; upScript = mkOption { type = types.lines; default = ""; description = ""; }; }; }); }; }; config = mkIf (cfg != []) { systemd.services = fold (a: b: a // b) {} ( mapAttrsToList (name: qtcfg: { "quicktun-${name}" = { wantedBy = [ "multi-user.target" ]; after = [ "network.target" ]; environment = { "INTERFACE" = name; "TUN_MODE" = toString qtcfg.tunMode; "REMOTE_ADDRESS" = qtcfg.remoteAddress; "LOCAL_ADDRESS" = 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; "TIME_WINDOW" = toString qtcfg.timeWindow; "TUN_UP_SCRIPT" = pkgs.writeScript "quicktun-${name}-up.sh" qtcfg.upScript; "SUID" = "nobody"; }; serviceConfig = { Type = "simple"; ExecStart = "${pkgs.quicktun}/bin/quicktun.${qtcfg.protocol}"; }; }; }) cfg ); }; }