├── LICENSE ├── README.md └── ssh-proxy /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2005-2015 Eric Engstrom, All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are met: 5 | 6 | 1. Redistributions of source code must retain the above copyright notice, this 7 | list of conditions and the following disclaimer. 8 | 9 | 2. Redistributions in binary form must reproduce the above copyright notice, 10 | this list of conditions and the following disclaimer in the documentation 11 | and/or other materials provided with the distribution. 12 | 13 | 3. All materials mentioning features or use of this software must credit the 14 | copyright holder(s). 15 | 16 | 4. Neither the name of the copyright holder nor the names of its contributors 17 | may be used to endorse or promote products derived from this software 18 | without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY COPYRIGHT HOLDER "AS IS" AND ANY EXPRESS OR 21 | IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 22 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 23 | EVENT SHALL COPYRIGHT HOLDER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 25 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 26 | BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 27 | IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 | POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ssh-proxy 2 | ssh ProxyCommand script to smartly proxy only when necessary. 3 | 4 | Simple shell wrapper to proxy or tunnel or hop through intermediate 5 | `ssh` servers, SOCKS proxies, or HTTP proxies (e.g. `corkscrew`), when 6 | `ssh` would be unable to connect directly. 7 | 8 | Most often useful on portable clients (e.g. laptops or tablets), 9 | especially when only SOMETIMES behind a draconian firewall or outside 10 | a network with limited `ssh` connections inbound. In all cases, if you 11 | have a VPN option, that will probably be better, but even in those 12 | cases, this script should not interfere and allows you to be "lazy" in 13 | your VPN usage. 14 | 15 | Intended for use inside your `~/.ssh/config` file, like these examples: 16 | 17 | Outbound http proxy (e.g., behind a restrictive outbound firewall): 18 | 19 | Host * 20 | ProxyCommand $HOME/.ssh/proxy -p httpproxy.foo.com:8080 %h %p 21 | 22 | If not specified on the command line, the proxy will default to the 23 | first non-empty evironment variables, in order: 24 | * `http_proxy` 25 | * `HTTP_PROXY` 26 | * `https_proxy` 27 | * `HTTPS_PROXY` 28 | 29 | Inbound hop, when limited inbound ssh connections allowed: 30 | 31 | Host * 32 | ProxyCommand $HOME/.ssh/proxy -h ssh-hop.foo.com:8080 %h %p 33 | 34 | In either case, the script will first attempt a direct connection, 35 | avoiding any overhead. 36 | 37 | Another feature enables you to setup "pseudo" hostnames in your 38 | `~/.ssh/config` file and use a `sed` regexp to modify the destination 39 | hostname before attempting a connection. For example: 40 | 41 | Host prefix-* 42 | ProxyCommand $HOME/.ssh/proxy -S 's/^prefix-//' -h subnet-bastion %h %p 43 | 44 | In those cases, the destiation hostname would have the `prefix-` 45 | removed before attempting to connect to the destiation server. This 46 | can be helpful if an entire subnet of hosts is behind a special 47 | bastion server, and you need or want rather just have hostname resolution 48 | happen on the bastion. Side-effect: your `~/.ssh/known_hosts` file 49 | will be populated with keys that still **include** the `prefix-`. 50 | 51 | In general, this script assumes `ssh`, `netcat` (`nc`) and `corkscrew` 52 | (an http-proxy available from http://www.agroman.net/corkscrew). As 53 | an alternative to corkscrew, some people have repoted success using 54 | `desproxy` (http://sourceforge.net/projects/desproxy/). 55 | 56 | Netcat is used both to detect the availablility of the destination or 57 | proxy hosts as well as for direct connections. Both are assumed to be 58 | resident in your `PATH`. If not, you may specify a different 59 | http-proxy or alternate location for netcat on the command line (in 60 | your ssh config) OR, of course, "use the source, Luke"... 61 | 62 | Comments, suggestions, questions welcome. 63 | -------------------------------------------------------------------------------- /ssh-proxy: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # Copyright (c) 2005 Eric Engstrom 4 | # See LICENSE for copying permissions and restrictions. 5 | # Author: Eric Engstrom (first(-DOT-)last(-AT-)g m a i l(-DOT-)c o m) 6 | # 7 | # See README.md for usage instructions and examples. 8 | # 9 | # Usage: 10 | # ssh-proxy [optional-args] [-p [:]] \ 11 | # [-h [:]] 12 | # with optional args: 13 | # [-n ] - path of netcat/direct-connect program 14 | # [-s ] - path of ssh client 15 | # [-t ] - path of http-tunnel program 16 | # [-w ] - timeout (seconds) to test connection to proxy server 17 | # [-S ] - regexp to pass to sed to modify destination hostname 18 | # 19 | # To Do: 20 | # * Should accept multiple hop or proxy and construct chained command 21 | # * sometimes re-times out over and over, queing multiple nc/ssh, but not sure why. 22 | # * evaulate use of `-X connect` option to nc for http proxy 23 | # (http://www.perkin.org.uk/posts/ssh-via-http-proxy-in-osx.html) 24 | ## 25 | 26 | # set to "echo" to debug; use -v option to ssh to see output 27 | DEBUG= 28 | 29 | # defaults 30 | ssh=ssh 31 | agent="-A" # forward agent 32 | tunnel=corkscrew 33 | timeout=8 34 | 35 | # Allow default proxy host to come from environment 36 | proxy=${http_proxy-${HTTP_PROXY-${https_proxy-$HTTPS_PROXY}}} 37 | # strip off http[s]:// and anything after first slash 38 | proxy=${proxy#http?://} 39 | proxy=${proxy%%/*} 40 | 41 | # if "nc" not found, try "netcat"; check later 42 | # should look also for ncat, but what preference order? 43 | netcat=nc 44 | if ! type -p ${netcat} >/dev/null 2>&1; then 45 | netcat="netcat" 46 | fi 47 | 48 | # parse args - can specify -n and/or -t 49 | while getopts "n:h:p:s:t:w:S:" OPT; do 50 | #echo "$OPT $OPTARG $OPTIND" 51 | case $OPT in 52 | h) arr=(${OPTARG//:/ }); hophost="${arr[0]}"; hopport=${arr[1]:+ -p ${arr[1]}} ;; 53 | p) proxy=$OPTARG ;; 54 | n) netcat=$OPTARG ;; 55 | s) ssh=$OPTARG ;; 56 | t) tunnel=$OPTARG ;; 57 | w) timeout=$OPTARG ;; 58 | S) sedregexp=$OPTARG ;; 59 | esac 60 | done 61 | shift $(($OPTIND - 1)) 62 | 63 | # Separate proxy var into host and (optional) port 64 | if [ -n "${proxy}" ]; then 65 | arr=(${proxy//:/ }); proxyhost="${arr[0]}"; proxyport=${arr[1]} 66 | fi 67 | #echo "Proxy: $proxyhost -- $proxyport"; exit 68 | 69 | # At this point $1 and $2 should be destination host and port, if specified. 70 | desthost="$(echo "$1" | sed -e "${sedregexp}")" 71 | destport=${2:-22} # default to port 22 72 | #echo "Dest: $desthost -- $destport"; exit 73 | 74 | # Check ability to use netcat now, after user specifies it 75 | if ! type -p ${netcat} >/dev/null 2>&1; then 76 | echo "Cannot find netcat - failing..." 1>&2 77 | exit 1; 78 | fi 79 | 80 | # test connection to host directly; go direct if possible, else tunnel or hop 81 | if ${netcat} -w ${timeout} -z ${desthost} ${destport} >/dev/null 2>&1; then 82 | $DEBUG exec ${netcat} ${desthost} ${destport} 83 | 84 | # else, if hop defined, then try that 85 | elif [ -n "${hophost}" ]; then 86 | #echo "Connecting through ${hophost} to ${desthost}" 1>&2 87 | # This can recurse through your config file, which is OK sometimes, 88 | # but can also go badly if you try to hop through your to your hop host. 89 | # Break that cycle: 90 | if [ "${hophost}" == "${desthost}" ]; then 91 | echo "Trying to hop through ${hophost} to itself - failing..." 1>&2 92 | exit 1; 93 | # elif ping -q -t ${timeout} -no ${hophost}; then 94 | # echo "Cannot ping ${hophost} - failing..." 1>&2 95 | # exit 1; 96 | fi 97 | # Hop through hophost, using netcat to direct to real destination 98 | #$DEBUG exec ${ssh} ${agent} ${hophost} ${hopport} ${netcat} ${desthost} ${destport} 99 | # But, have had issues with above use of `exec` failing with error... 100 | #$DEBUG ${ssh} ${agent} ${hophost} ${hopport} ${netcat} ${desthost} ${destport} 101 | # Better yet, since OpenSSH 5.3 includes a -W option, which implements netcat-like directly. 102 | $DEBUG exec ${ssh} ${agent} ${hophost} ${hopport} -W ${desthost}:${destport} 103 | 104 | # else, if proxy defined, then try that 105 | elif [ -n "${proxyhost}" ]; then 106 | $DEBUG exec ${tunnel} ${proxyhost} ${proxyport} ${desthost} ${destport} 107 | 108 | # otherwise, we got SUEd... 109 | else 110 | echo "No proxy or hop host specified - failing..." 1>&2 111 | exit 1; 112 | fi 113 | 114 | ## 115 | --------------------------------------------------------------------------------