Skip to content
Go to file
Cannot retrieve contributors at this time
executable file 106 lines (95 sloc) 4.41 KB
# This script takes care of:
# - Creating an SSH connection to a remote server
# - Running a remote command to attach to an existing tmux session
# (though any other interactive command is fine too).
# - Enable SSH agent forwarding (handled by SSH natively), GPG agent
# forwarding (this script figures out the paths to use using gpgconf)
# and auxiliary TCP forwarding (See $FORWARD_OPTIONS below).
# - Kill any previous session that is still running serverside, to
# prevent the port forwards failing because ports are still in use.
# - Remove the previous GPG forwarding socket serverside, since sshd
# does not appear to do so when it quits.
# - When the connection breaks or the remote command does not return
# success, you can reconnect by just pressing enter.
# To do this, a single SSH ControlMaster session is started, over which
# multiple commands are run in turn. Multiple commands are needed, since
# any previous sessions must be cleaned up *before* trying to set up new
# port forwards, which could otherwise fail. By using ControlMaster,
# SSH only needs a single TCP connection and needs to authenticate only
# once.
# If this script is invoked multiple times, each invocation uses its own
# ControlPath, so they should not interfere with each other client-side
# (but the latter will kill the former server-side, of course).
# Work around
if [ "$TERM" = "stterm-256color" ]; then
# Hostname or entry in .ssh/config to connect to
# Any options to be passed to the final, forwarding ssh connection
FORWARD_OPTIONS="-R 2220:localhost:22"
# Remoet command to be passed to the final, forwarding ssh connection
# SSH ControlMaster path for connection sharing. Includes the current
# PID to make sure it is unique, even if an existing session is already
# running.
# PIDFile to be created remotely to allow killing lingering older
# sessions, to cleanup any listening ports
# SSH command to use
SSH="ssh $HOST -o ControlPath=$CONTROLPATH -o ControlMaster=auto"
# Make sure the controlpath directory exists
mkdir -p "$(dirname $CONTROLPATH)"
cleanup() {
$SSH -q -O exit
trap cleanup EXIT
# Run cleanup, just in case the control socket wasn't cleaned up
# properly and we end up re-using the same name
while true; do
# Start a new control master, that does not execute any commands
# (-N) and goes to the background after authentication (-f). All
# subsequent ssh commands reuse this same connection. It autoquits
# after some seconds idle time (ControlPersist=10).
if $SSH -A -N -f -o ControlMaster=yes -o ControlPersist=10; then
echo "Connected"
# Figure out local and remote GPG socket paths
LOCAL_GPG_SOCKET=$(gpgconf --list-dir agent-extra-socket)
REMOTE_GPG_SOCKET=$($SSH gpgconf --list-dir agent-socket)
echo "Got socket info"
# Kill any previous sshd control master still running
# remotely, to clean up forwarded listening ports, and
# remove any forwarded gpg socket (which sshd does not).
# While we're there, prepare the pidfile directory
$SSH [ -f "$REMOTE_PIDFILE" ] \&\& \
pkill -F "$REMOTE_PIDFILE" \; \
rm -f "$REMOTE_PIDFILE" \; \
rm -f "$REMOTE_GPG_SOCKET" \; \
mkdir -p "\$(dirname \"$REMOTE_PIDFILE\")"
echo "Killed old sessions"
# Store the PID of the new control master connection and run the
# actual command. This also sets up all port forwardings. Note
# that the -A option must be passed to both this connection and
# the original master connection for it to work somehow, see
-o ExitOnForwardFailure=yes \
echo "\$PPID" \> "$REMOTE_PIDFILE" \; \
# On a normal exit, break out of the reply loop
echo "Press enter to reconnect"
if ! read; then # Wait for an enter so error can be read
echo "Read returned $?. Exiting"
exit 1;
You can’t perform that action at this time.