summaryrefslogtreecommitdiff
path: root/home-modules/autossh-proxy.nix
diff options
context:
space:
mode:
Diffstat (limited to 'home-modules/autossh-proxy.nix')
-rw-r--r--home-modules/autossh-proxy.nix120
1 files changed, 120 insertions, 0 deletions
diff --git a/home-modules/autossh-proxy.nix b/home-modules/autossh-proxy.nix
new file mode 100644
index 00000000..46cf1838
--- /dev/null
+++ b/home-modules/autossh-proxy.nix
@@ -0,0 +1,120 @@
1{ lib, sysConfig, config, pkgs, ... }:
2
3let
4 cfg = config.programs.ssh.autosshProxies;
5in {
6 options = {
7 programs.ssh.autosshProxies = lib.mkOption {
8 type = lib.types.attrsOf (lib.types.submodule ({ name, config, ... }: {
9 options = {
10 port = lib.mkOption {
11 type = lib.types.port;
12 };
13
14 socksPort = lib.mkOption {
15 type = lib.types.port;
16 default = config.port - 1;
17 };
18
19 host = lib.mkOption {
20 type = lib.types.str;
21 default = name;
22 };
23
24 sshpassSecret = lib.mkOption {
25 type = lib.types.nullOr lib.types.str;
26 };
27
28 ProxyCommand = lib.mkOption {
29 type = lib.types.str;
30 readOnly = true;
31 default = "${lib.getExe pkgs.socat} - SOCKS4A:127.0.0.1:%h:%p,socksport=${toString config.port}";
32 };
33 };
34 }));
35 };
36 };
37
38 config = {
39 assertions = [
40 {
41 assertion = builtins.length (lib.unique (lib.concatMap (cfg: [cfg.port cfg.socksPort]) (builtins.attrValues cfg))) == builtins.length (builtins.attrValues cfg) * 2;
42 message = "autosshProxy ports are not unique";
43 }
44 ];
45
46 systemd.user.services = lib.mkMerge (map (cfg: {
47 "autossh-socks@${cfg.host}:${toString cfg.socksPort}" = {
48 Service = {
49 Type = "notify";
50 NotifyAccess = "all";
51 WorkingDirectory = "~";
52 Restart = "always";
53 RestartSec = "23s";
54 ExecStart = "${pkgs.writeScript "autossh" ''
55 #!${lib.getExe config.programs.zsh.package} -xe
56
57 host="''${1%:*}"
58 port="''${1#*:}"
59
60 typeset -a cmd
61 cmd=()
62
63 if [[ -n "''${SSHPASS_SECRET}" ]]; then
64 cmd+=(${lib.getExe' pkgs.sshpassSecret "sshpass-secret"})
65 cmd+=("''${(@s/:/)SSHPASS_SECRET}")
66 cmd+=(--)
67 fi
68
69 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}")
70
71 ( exec -a "''${cmd[1]}" -- ''${cmd} ) &
72 pid=$!
73
74 newpid=""
75 i=200
76 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
77 if ! kill -0 "''${pid}"; then
78 wait "''${pid}"
79 exit $?
80 fi
81 [[ "''${i}" -gt 0 ]] || exit 1
82 i=$((''${i} - 1))
83 ${lib.getExe' pkgs.coreutils "sleep"} 0.1
84 done
85
86 ${lib.getExe' sysConfig.systemd.package "systemd-notify"} --pid=''${newpid} --ready
87 ''} \"%I\"";
88 Environment = lib.optional (cfg.sshpassSecret != null) "SSHPASS_SECRET=${cfg.sshpassSecret}";
89 };
90 Unit = {
91 StopWhenUnneeded = true;
92 StartLimitInterval = "180s";
93 StartLimitBurst = 7;
94 };
95 };
96 "proxy-to-autossh-socks@${toString cfg.port}" = {
97 Unit = {
98 BindsTo = ["autossh-socks@${cfg.host}:${toString cfg.socksPort}.service" "proxy-to-autossh-socks@${toString cfg.port}.socket"];
99 After = ["autossh-socks@${cfg.host}:${toString cfg.socksPort}.service" "proxy-to-autossh-socks@${toString cfg.port}.socket"];
100 };
101 Service = {
102 ExecStart = "${sysConfig.systemd.package}/lib/systemd/systemd-socket-proxyd --exit-idle-time=60s 127.0.0.1:${toString cfg.socksPort}";
103 Restart = "always";
104 RestartSec = "23s";
105 };
106 };
107 }) (builtins.attrValues cfg));
108 systemd.user.sockets = builtins.listToAttrs (map (cfg: lib.nameValuePair "proxy-to-autossh-socks@${toString cfg.port}" {
109 Socket = {
110 ListenStream = "%I";
111 TriggerLimitIntervalSec = 0;
112 PollLimitIntervalSec = "180s";
113 PollLimitBurst = 6;
114 };
115 Install = {
116 WantedBy = ["sockets.target"];
117 };
118 }) (builtins.attrValues cfg));
119 };
120}