From 0fbdb0cd87a55ac26df54694386953281850d0a9 Mon Sep 17 00:00:00 2001 From: Gregor Kleen Date: Mon, 28 Sep 2026 10:12:04 +0200 Subject: ... --- home-modules/autossh-proxy.nix | 114 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 114 insertions(+) create mode 100644 home-modules/autossh-proxy.nix (limited to 'home-modules/autossh-proxy.nix') diff --git a/home-modules/autossh-proxy.nix b/home-modules/autossh-proxy.nix new file mode 100644 index 00000000..e3179096 --- /dev/null +++ b/home-modules/autossh-proxy.nix @@ -0,0 +1,114 @@ +{ lib, sysConfig, config, pkgs, ... }: + +let + cfg = config.services.autosshProxy; +in { + options = { + services.autosshProxy = lib.mkOption { + type = lib.types.attrsOf (lib.types.submodule ({ name, config, ... }: { + options = { + port = lib.mkOption { + type = lib.types.port; + }; + + socksPort = lib.mkOption { + type = lib.types.port; + default = config.port - 1; + }; + + host = lib.mkOption { + type = lib.types.str; + default = name; + }; + + sshpassSecret = lib.mkOption { + type = lib.types.nullOr lib.types.str; + }; + }; + })); + }; + }; + + config = { + assertions = [ + { + assertion = builtins.length (lib.unique (lib.concatMap (cfg: [cfg.port cfg.socksPort]) (builtins.attrValues cfg))) == builtins.length (builtins.attrValues cfg) * 2; + message = "autosshProxy ports are not unique"; + } + ]; + + systemd.user.services = lib.mkMerge (map (cfg: { + "autossh-socks@${cfg.host}:${toString cfg.socksPort}" = { + Service = { + Type = "notify"; + NotifyAccess = "all"; + WorkingDirectory = "~"; + Restart = "always"; + RestartSec = "23s"; + ExecStart = "${pkgs.writeScript "autossh" '' + #!${lib.getExe config.programs.zsh.package} -xe + + host="''${1%:*}" + port="''${1#*:}" + + typeset -a cmd + cmd=() + + if [[ -n "''${SSHPASS_SECRET}" ]]; then + cmd+=(${lib.getExe' pkgs.sshpassSecret "sshpass-secret"}) + cmd+=("''${(@s/:/)SSHPASS_SECRET}") + cmd+=(--) + fi + + cmd+=(${lib.getExe' pkgs.openssh "ssh"} -vN -D 127.0.0.1:''${port} -o ControlPath=none -o ExitOnForwardFailure=yes -o ServerAliveCountMax=15 -o ServerAliveInterval=2 "''${host}") + + ( exec -a "''${cmd[1]}" -- ''${cmd} ) & + pid=$! + + newpid="" + i=200 + while ! { newpid=$(${lib.getExe' pkgs.iproute2 "ss"} -HO -pln "src localhost sport ''${port}" | ${lib.getExe pkgs.gnused} -r 's/^.*pid=([0-9]+).*$/\1/'); [[ -n $newpid ]] }; do + if ! kill -0 "''${pid}"; then + wait "''${pid}" + exit $? + fi + [[ "''${i}" -gt 0 ]] || exit 1 + i=$((''${i} - 1)) + ${lib.getExe' pkgs.coreutils "sleep"} 0.1 + done + + ${lib.getExe' sysConfig.systemd.package "systemd-notify"} --pid=''${newpid} --ready + ''} \"%I\""; + Environment = lib.optional (cfg.sshpassSecret != null) "SSHPASS_SECRET=${cfg.sshpassSecret}"; + }; + Unit = { + StopWhenUnneeded = true; + StartLimitInterval = "180s"; + StartLimitBurst = 7; + }; + }; + "proxy-to-autossh-socks@${toString cfg.port}" = { + Unit = { + BindsTo = ["autossh-socks@${cfg.host}:${toString cfg.socksPort}.service" "proxy-to-autossh-socks@${toString cfg.port}.socket"]; + After = ["autossh-socks@${cfg.host}:${toString cfg.socksPort}.service" "proxy-to-autossh-socks@${toString cfg.port}.socket"]; + }; + Service = { + ExecStart = "${sysConfig.systemd.package}/lib/systemd/systemd-socket-proxyd --exit-idle-time=60s 127.0.0.1:${toString cfg.socksPort}"; + Restart = "always"; + RestartSec = "23s"; + }; + }; + }) (builtins.attrValues cfg)); + systemd.user.sockets = builtins.listToAttrs (map (cfg: lib.nameValuePair "proxy-to-autossh-socks@${toString cfg.port}" { + Socket = { + ListenStream = "%I"; + TriggerLimitIntervalSec = 0; + PollLimitIntervalSec = "180s"; + PollLimitBurst = 6; + }; + Install = { + WantedBy = ["sockets.target"]; + }; + }) (builtins.attrValues cfg)); + }; +} -- cgit v1.2.3