A common problem for me when setting up SSH tunnels is that even though the ssh client process is running, data is not going through.
Steps to reproduce:
- Create a tunnel (ssh -D or ssh -L or ssh -R ) on some port
- Data is not going through, so we need to restart it
- The connection cannot be established because bind: Address already in use
- We have to kill the old client, ps aux | grep ssh , to find the right process and then kill -9 it
- Re-create the tunnel
Instead, we could leverage sockets when creating the connection, which allow communication with the SSH process (as opposed to searching for the pid ). This is enabled by the -S option:
ssh -NMfn -S /tmp/server1.local.socket -o ExitOnForwardFailure=yes -D 8080 server1.local # Additional flags: # -N Don't open a terminal # -M Master mode, necessary for socket commands # -f Go to background # -S Control socket
Once the socket is set up, we can send commands to it. For example, exit to close the connection (regardless of the state of the connection):
ssh -S /tmp/server1.local.socket -O exit server1.local
Finally, here is a script that will create SOCKS tunnels (proxies) to a list of hostnames. When the script is run again, it will attempt to close any existing tunnels and establish brand new connections:
#!/bin/bash # These are the servers that we will set up SOCKS tunnels to HOSTS="server1.local server2.remote" BASE_PORT=11000 # Some fancy output bold=$(tput bold) normal=$(tput sgr0) # Send exit to all existing sockets for HOST in $HOSTS; do if [ -e /tmp/$HOST.socket ]; then ssh -S /tmp/$HOST.socket -O exit $HOST fi done # Set up variables and nice output PORT=$BASE_PORT STATUS_LINE="%-35s%-15s${bold}%s${normal}" printf "${bold}$STATUS_LINE\n${normal}" "HOST" "SOCKS PORT" "STATUS" for HOST in $HOSTS; do printf "$STATUS_LINE" "$HOST" "$PORT" "CONNECTING" # Attempt to create tunnel ssh -NMfn -S /tmp/$HOST.socket -o ConnectTimeout=5 -o ExitOnForwardFailure=yes -D $PORT $HOST &> /dev/null # Report outcome if (( $? == 0 )); then printf "\r$STATUS_LINE\n" "$HOST" "$PORT" "DONE " else printf "\r$STATUS_LINE\n" "$HOST" "$PORT" "FAILED " fi # Increment port number PORT=$(expr $PORT + 1) done