Skip to content

Instantly share code, notes, and snippets.

@rany2
Last active November 2, 2022 11:21
Show Gist options
  • Save rany2/07562f62c97350fb08ccd6c0f8771724 to your computer and use it in GitHub Desktop.
Save rany2/07562f62c97350fb08ccd6c0f8771724 to your computer and use it in GitHub Desktop.
Start mosh-server, but first create a port redirection in the NAT router (with UPnP) and delete that redirection again just before mosh-server exits.
#!/usr/bin/env bash
#
# Start mosh-server, but first create a port redirection in the NAT
# router (with UPnP) and delete that redirection again just before
# mosh-server exits.
# die -- print error on stderr and exit
function die {
echo "$@" >&2
exit 1
}
declare -i port=0 n
# Check if we have been given a port via the -p option.
#
for ((n = 1; n <= "$#"; n++)); do
if [[ "${!n}" = "-p" ]]; then
n=$((n + 1))
port="${!n}"
fi
done
# If we don't have a valid port yet, find one that is not in
# use. Check that there is no server on this machine listening on the
# port and that it is not already redirected on the NAT box.
#
if [[ "${port}" -ne 0 ]]; then
fixed_port=true
else
for ((port = 61000; port > 0; port--)); do
ss_output=$(ss -4 -l -n -u) || die "Error: Calling ss failed."
if ! printf '%s\n' "${ss_output}" | grep -E -q '^[^ ]* * [^ ]* * [^ ]* * (([0-9]|[0-9]{2}|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[0-9]{2}|1[0-9]{2}|2[0-4][0-9]|25[0-5]):'"${port} "; then
upnpc_output=$(upnpc -l) || die "Error: Calling upnpc failed."
if ! printf '%s\n' "${upnpc_output}" | grep -E -q "^ *[0-9]+ UDP ${port}->"; then
break # Found one!
fi
fi
done
fi
# If we still don't have a port, we're in trouble
#
[[ "${port}" -ne 0 ]] || die "Error: Could not find a free port!?"
# Redirect the port in the NAT router
#
upnpc -e "mosh-server" -r "${port}" udp >/dev/null ||
echo "Failed to redirect port ${port}. Continuing anyway..." >&2
# Make a program that executes a shell, removes the port direction
# when the shell exits, and finally removes itself.
#
UPNP_SHELL=$(mktemp) || die "Error: Cannot create temporary file."
cat >"${UPNP_SHELL}" <<-EOF
#!/usr/bin/env bash
trap 'rm -f -- "${UPNP_SHELL}"' EXIT
ret=1
if command -v getent &> /dev/null; then
"\$(getent passwd "${USER}" | awk -F: '{print \$NF}')"
ret=\$?
elif command -v perl &> /dev/null; then
"\$(perl -e '@x=getpwuid(\$<); print \$x[8]')"
ret=\$?
elif command -v python3 &> /dev/null; then
"\$(python3 -c 'import pwd, os; print(pwd.getpwuid(os.getuid())[6])')"
ret=\$?
elif command -v python2 &> /dev/null; then
"\$(python2 -c 'import pwd, os; print(pwd.getpwuid(os.getuid())[6])')"
ret=\$?
elif command -v python &> /dev/null; then
"\$(python -c 'import pwd, os; print(pwd.getpwuid(os.getuid())[6])')"
ret=\$?
else
"\$(grep -E "^${USER}:" /etc/passwd | cut -d: -f7)"
ret=\$?
fi
upnpc -d "${port}" udp >/dev/null
exit "\${ret}"
EOF
chmod +x "${UPNP_SHELL}"
# Start mosh-server
#
if [[ -n "${fixed_port}" ]]; then
exec mosh-server "$@" -- "${UPNP_SHELL}"
else
exec mosh-server "$@" -p "${port}" -- "${UPNP_SHELL}"
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment