4

Here's the problem: I'm trying to SSH into a system that is accessible from at least 3 different networks—sometimes directly, sometimes via a proxy—at different times.

Connecting directly is far faster and more reliable than connecting via an intermediate host, which is again far faster and more reliable than connecting over the general internet, so I would like SSH to attempt to connect in 3 different ways in a prioritized fashion, picking the first that succeeds.

They're all the same machine, obviously, so I don't want to keep having to manually choose between 3 different aliases depending on where I'm connecting from.

However, I can't find any mechanism for solving this. Is it possible to do this at all, or no?

If not, what do people generally do in such a situation?

5

Do not use aliases for ssh connections! Use a proper ssh_config in ~/.ssh/config. It has some truly powerful features.

Lets say you can identify in which network you are. For example using your IP, which can be pulled for example using hostname -I. So lets write some configuration:

# in network1 I am getting ip from "10.168.*.*" and I need to connect through proxy
Match Host myalias Exec hostname -I | grep 10\.168\.
  Hostname real-host-IP
  ProxyCommand ssh -W %h:%p proxy-server

# in network2 I am getting IP from "192.168.*.*" and I do not need a proxy
Match Host myalias Exec hostname -I | grep 192\.168\.
  Hostname real-host-IP

# in network3 I am getting something else

I believe you got the point ...

  • YES! Thank you!! I'd lost hope but this is exactly what I needed! My line looks like Match Host myalias Exec "hostname | xargs nslookup | tail -n +5 | grep -q -e '^Address:\s*192\.168\.1\.'", for any readers wondering. – Mehrdad Aug 17 '17 at 11:39
3

You can store a shell alias or a function in your .bashrc or whatever else is your shell's config file. For example, for a Bash alias:

alias my_ssh="
ssh mehrdad@"IP1 ||
ssh tomas@IP2 ||
ssh tomas@IP3
"

Then call the alias:

 my_ssh

And if IP1 fails, || makes the second command execute. And so it goes again, now with the IP3.

I've not tested this, but it should be ok. Or at least shows a way.

For SSH options like proxies, see man ssh.

  • 1
    The problem here is dealing with the timeouts. – Rui F Ribeiro Aug 16 '17 at 20:49
  • Great point by @RuiFRibeiro. Also the other problem is that I'm not asking for a shell scripting tutorial. I'm asking if there's a way to make the ssh command do this. As in, I want to be able to SSH into this server the same way I SSH into any other server. A generic script that uses SSH will completely fail on this machine if it has to call a different command. – Mehrdad Aug 16 '17 at 21:16
  • 1
    BTW it's not enough to use || because ssh exits with the return value of the last remote command. You need to check for exit code 255 to be sure that there was a connection problem. – rudimeier Aug 16 '17 at 21:58
  • @rudimeier Actually in my testing it seems like exit code 255 isn't the only bad exit code ssh gives. Depending on why it was failing I was getting a few different codes. support2.microfocus.com/techdocs/2487.html – Jesse_b Aug 16 '17 at 22:03
  • 1
    @rush Yes I had tested this using openssh client: ssh localhost 'exit 123'; echo $? prints 123. It's documented in the man page: ssh exits with the exit status of the remote command or with 255 if an error occurred. – rudimeier Aug 16 '17 at 22:23
1

There can be several solutions, some better than other, and ignoring security implications, or infra-structure (unknown) limitations:

  • doing an SSH reverse tunnel (an ugly hack);
  • setting up anycast with the help of OSPF or BGP, and sshing to a anycast VIP;
  • the remote machine establishing an IPsec tunnel - without the proxy;
  • communicating via Tor
  • updating a site/page/Redis/MySQL server with the current address, and your ssh script fetching it;
  • using HAProxy;
  • dynamic DNS.
  • 1
    Some of these suggestions seem absolutely ridiculous... communicating via Tor? Using Redis? Makes me wonder if you've even understood the point of the question... – Mehrdad Aug 16 '17 at 21:13
  • 1
    I would advise some concepts of networks and what is anycast. I am not giving an extensive list of good solution, my point is more about showing there can be a lot solutions once you get creative. And I also find it absolutely an excellent policy using the word ridiculous with people helping you for free. – Rui F Ribeiro Aug 16 '17 at 21:42
  • 2
    Are you doing a bingo? I bet this is the first time on all the StackExchange sites that an answer uses OSPF, Redis and HAProxy in less that 500 lines. Add RS-485 and iSCSI and you get my vote ;-) – xhienne Aug 16 '17 at 22:46
1

This function may work, but if Tomas's alias works I think that's a better solution.

autossh () {

  publicip="11.11.11.11"
  privateip="10.10.10.100"
  proxyhost="10.10.10.10"
  proxyport="9001"
  ssh -o ConnectTimeout=10 $1@$privateip 2> /dev/null && exit 0
  if [ $? -ge 1 ]; then
    ssh -o ConnectTimeout=10 $1@$publicip -o "ProxyCommand=nc -X connect -x $proxyhost:$proxyport %h %p" 2> /dev/null && exit 0
    if [ $? -ge 1 ]; then
      ssh -o ConnectTimeout=10 $1@$publicip 2> /dev/null && exit 0
      if [ $? -ge 1 ]; then
        echo "I think your node is down"
      fi
    fi
  fi

}
  • Thanks but this misses the point of my question... see my comment under his answer. – Mehrdad Aug 16 '17 at 21:16
  • Alright well what you're asking is still vague then, but the way I understand it; the short answer is no. Long answer is rename my function or Tomas's alias to ssh. – Jesse_b Aug 16 '17 at 21:27
  • Your function might have an unexpected behaviour in case already established ssh session got accidental disconnect. – rush Aug 16 '17 at 22:10
  • What do you mean? The $? will only represent the last executed command so if an ssh session terminated before running the function it's exit code would be overwritten before the function tries to ssh. – Jesse_b Aug 16 '17 at 22:11
  • 2
    @Jesse_b I mean that if ssh connection to $1@$privateip will be successfully established but it will unexpectedly die afterwards, the exit status will be non-zero and the function will try to connect to public ip instead of simply dying. – rush Aug 16 '17 at 22:19

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.