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