Files
traberph dd1b847a05
build / image (push) Successful in 35s
cleanup
2026-09-27 09:52:12 +02:00

52 lines
2.3 KiB
Bash

#!/bin/sh
# Opens SSH reverse tunnels to a sish edge and reconnects forever. See README.md.
set -eu
set -f # no globbing: routes may contain wildcards (*.example.com)
die() { echo "sish-client: $*" >&2; exit 64; }
: "${SISH_HOST:?is required}" "${SISH_HOST_KEY:?is required}" "${SISH_ROUTES:?is required}"
SNI_PROXY=${SISH_SNI_PROXY:-true}
PROXY_PROTOCOL=${SISH_PROXY_PROTOCOL:-2}
KEY=${SISH_KEY_FILE:-/secrets/id_ed25519}
case $SNI_PROXY in true | false) ;; *) die "SISH_SNI_PROXY must be true or false" ;; esac
case $PROXY_PROTOCOL in 1 | 2 | off) ;; *) die "SISH_PROXY_PROTOCOL must be 1, 2 or off" ;; esac
[ -r "$KEY" ] || die "cannot read private key $KEY"
# Pin the edge host key: the only entry ssh will trust. A newline would allow
# extra known_hosts lines (e.g. a wildcard entry), so the key must be one line.
case $SISH_HOST_KEY in *'
'*) die "SISH_HOST_KEY must be a single line" ;; esac
KNOWN_HOSTS=$(mktemp) # private 0600 file with a random name, safe in a shared /tmp
printf 'sish-edge %s\n' "$SISH_HOST_KEY" > "$KNOWN_HOSTS"
# host:bind-port=target:port -> -R host:bind-port:target:port
# Each route stays a single argument to -R, so it cannot inject ssh options.
forwards=""
for r in $(printf '%s' "$SISH_ROUTES" | tr , ' '); do
case $r in *=*) ;; *) die "bad route '$r', expected host:port=target:port" ;; esac
forwards="$forwards -R ${r%%=*}:${r#*=}"
done
[ -n "$forwards" ] || die "SISH_ROUTES contains no routes"
# sish session options, sent as the remote command
opts=""
if [ "$SNI_PROXY" = true ]; then opts="sni-proxy=true"; fi
if [ "$PROXY_PROTOCOL" != off ]; then opts="$opts proxy-protocol=$PROXY_PROTOCOL"; fi
# -F /dev/null: ignore all ssh_config files, every option is set here.
# The server can only open channels for the forwards requested above; agent and
# X11 forwarding are off by default.
while :; do
# shellcheck disable=SC2086 # $forwards and $opts are split on purpose
ssh -F /dev/null -T -p "${SISH_PORT:-2222}" -i "$KEY" \
-o BatchMode=yes -o IdentitiesOnly=yes -o ExitOnForwardFailure=yes \
-o ServerAliveInterval=15 -o ServerAliveCountMax=3 \
-o HostKeyAlias=sish-edge -o StrictHostKeyChecking=yes \
-o UserKnownHostsFile="$KNOWN_HOSTS" -o GlobalKnownHostsFile=/dev/null \
$forwards "connector@$SISH_HOST" $opts \
|| echo "sish-client: ssh exited ($?), reconnecting in 5s" >&2
sleep 5
done