13

I have my ~/.ssh/config configured with various hosts that are accessible either while on our company VPN, or via a SSH proxy server.

At the moment I just have

Host internal-server
    ProxyCommand ssh -W internal.ip:22 external-server

However if I'm in the internal network I can directly access the internal ip, so proxying through the external server just adds a delay to connecting.

Is there a way I can provisionally proxy if the internal ip isn't reachable, and connect directly otherwise?

8

I usually setup something like this. It assumes the intermediate host will be able to resolve the name.

Host *%homeproxy
    ProxyCommand ssh user@proxyhost /bin/netcat -w 1 $(echo %h | cut -d%% -f1) 22

So I would connect to like ssh blah%homeproxy.

  • My google-fu is failing me. Can you explain this more? I've never seen this *% syntax before. – fukawi2 Sep 4 '13 at 1:41
  • 3
    There is nothing special about the % character. You could use anything really. The percent is used since it isn't valid in a hostname, or username. The cut command withing the ProxyCommand uses the % as a delimiter to pull out the hostname. – Zoredache Sep 4 '13 at 1:44
  • 1
    This is good, however it does mean that I have to spell out the full hostname rather than the ssh alias. – alt Sep 5 '13 at 0:22
  • @mobiusnz It actually means simply that you need a different name for each different means of connecting. In my case, for example, if I'm at home, I use ssh targetH, meaning target from home. If in a local network to target, simply ssh target. It'd've been nice to have this stated more straightforwardly in the answer though. – Rubens Jan 8 '15 at 16:53
2

A decade ago I wrote a proxy command for this kind of scenario. In your usage case my proxy command could be used like this:

Host internal-server
    ProxyCommand ssh-multipath-proxy %h:%p -- ssh -W %h:%p external-server

A couple of caveats: I am a bit embarrassed to admit, that it doesn't handle IPv6, and that it will only try a single IP address per hostname. Also, it won't transfer the client banner to the server before the server banner has been sent. But that is unlikely to cause problems.

2

Thanks for @till's Answer, it inspired me a lot.

I found that you can forcely redirect your connection with ProxyCommand nc dst dst-port.

For example, You will in fact connect to B.com if you use

ssh A.com -o ProxyCommand="nc B.com 22"

But UserKnownHostsFile will still record as A.com

So you could add a domain "auto" to your ssh_config

Host auto.internal-server
  Hostname {internal-server ip or domain}
  ProxyCommand bash -c '(timeout 0.1 nc -z %h %p) && nc %h %p || ssh -W %h:%p external-server'

I replaced nc -w 1 %h %p with (timeout 0.1 nc -z %h %p) && nc %h %p , it will be more quick if you could reach internal-server less then 100ms.

Or you can replaced by ping, but it might indicate bad information if you use a TCP based proxy like proxychains, or server doesn't allow a ICMP echo.

Host auto.internal-server
  Hostname {internal-server ip or domain}
  ProxyCommand bash -c '(ping %h &>/dev/null) && nc %h %p || ssh -W %h:%p external-server'

You can replace (timeout 0.1 nc -z %h %p) with anything which detects whether you are in internal-server.

If you has multiple candidate IPs, even you can use this:

Host auto.internal-server
  Hostname {internal-server ip or domain}
  ProxyCommand bash -c 'f(){(timeout 0.1 ping -c 1 $1 &>/dev/null) && nc $1 %p;}; f 1.1.1.1 || f 2.2.2.2 || f 3.3.3.3'

It will try to connect 1.1.1.1, if fail try to connect 2.2.2.2, and then 3.3.3.3.

2

I use a different method using Match. In my case, I want to use a local proxy if its running, or not, if it isn't. The following directive accomplishes this nicely:

Match Exec "nc -z 127.0.0.1 1086"
    ProxyCommand nc -X 5 -x 127.0.0.1:1086 %h %p

It matches every ssh attempt, and execute a quick check using nc to see if my proxy is up and running on 1086. If it is, it sets the ProxyCommand.

0

This works a little bit more automagically with a tiny additional 1sec delay if you are not behind the firewall and the firewall does not reject:

Host proxyhost.example.com
ProxyCommand none

Host *.example.com
ProxyCommand sh -c "nc -w 1 %h %p || ssh -W  %h:%p proxyhost.example.com"
0

I would typically create another entry something like this --

Host myVM
    ProxyCommand ssh -W internal.ip:22 external-server
    User ubuntu

Host myVM-np
    User ubuntu

Then just invoke the one you want, depending on your current proxy environment..

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.