Skip to content

Instantly share code, notes, and snippets.

@Mister-Meeseeks
Last active October 27, 2019 05:02
Show Gist options
  • Save Mister-Meeseeks/8a52e3eb253e5f78f5d841530f4b95eb to your computer and use it in GitHub Desktop.
Save Mister-Meeseeks/8a52e3eb253e5f78f5d841530f4b95eb to your computer and use it in GitHub Desktop.
Use SSH socks tunnels to bypass firewall that blocks outbound Internet
#!/bin/bash -eu
# Script is designed to build an SSH proxy for external Internet access on a
# host, which sits behind a NAT/firewall that doesn't allow outbound traffic.
# (Common in exchange data centers).
#
# Call this from a bridge with access to the Intrent and inbound access to the
# host. On success it will make available on host both a Socks5 proxy deamon
# (at localhost:8080) and a tunnel to the bridge machine's http proxy (at
# Elocalhost:8118).
#
# Requires local/bridge machine to have ssh, bash, and whoami. For HTTP
# proxy functionality the bridge machine must have an HTTP proxy (e.g. privoxy)
# running at the HTTP proxy port. If not, Socks5 proxy will still work.
#
# Requires remote/destination machine to have ssh, nc, and socks5 capable
# client. (proxychains suggested)
destAuthArg=""
localAuthArg=""
while getopts i:j:P opt ; do
case "$opt" in
i) destAuthArg="-i $OPTARG";; # Must exist on local machine, if used
j) localAuthArg="-i $OPTARG";; # Must exst on destination machine
esac
done
shift $(($OPTIND - 1))
destAddr=$1 # Use user@host if different user on destination machine
reverseTunnelPort=19999
reverseTunnelDest=localhost:22
socksProxyPort=8080
httpProxyPort=8118
# Before each tunnel step, check if the port is already built, in which case
# we don't need to run the command again. This avoids spurious errors when
# the script is re-run.
function testRemotePort() {
local portNum=$1
! isRemotePortOpen $portNum
}
function isRemotePortOpen() {
local portNum=$1
local portTestCmd="nc -z localhost $portNum"
ssh $destAuthArg $destAddr "$portTestCmd"
}
# First build a reverse tunnel to allow an outbound path on the remote.
if testRemotePort $reverseTunnelPort ; then
ssh $destAuthArg -f -C -N -R $reverseTunnelPort:$reverseTunnelDest $destAddr
fi
# These commands get called on the remote destination...
socksProxyCmd="ssh $localAuthArg -f -D $socksProxyPort -C -N \
-p $reverseTunnelPort $(whoami)@localhost"
# ...with these remote calls
if testRemotePort $socksProxyPort ; then
ssh $destAuthArg -f $destAddr "$socksProxyCmd"
fi
# Now do the same with the HTTP proxy
httpTunnel=$httpProxyPort:localhost:$httpProxyPort
httpProxyCmd="ssh $localAuthArg -f -L $httpTunnel -C -N \
-p $reverseTunnelPort $(whoami)@localhost"
if testRemotePort $httpProxyPort ; then
ssh $destAuthArg -f $destAddr "$httpProxyCmd"
fi
# This spawns two SSH daemons on the localmachine and one on the remote host,
# all of which survive after the script finishes running. If you want to kill
# the daemons, use ps/pkill.
# To acccess outbound internet on destination configure proxychains config with
# proxy_dns
# socks5 127.0.0.1 8080
#
# Then run any outbound-accessing internet command as
# $ proxychains [command]
# e.g.
# $ proxychains curl google.com
#
# HTTP proxy access will be available on the remote machine at 8081. However
# for any requests to work, it requires the bridge machine to have an actual
# HTTP proxy (like privoxy) listening at localhost on 8081
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment