6

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?

4 Answers 4

11

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
3
  • 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.
    – user541686
    Aug 17, 2017 at 11:39
  • 1
    Maybe something changed but I had to double-quote the command: Exec "hostname -I...". See also here.
    – spawn
    Dec 20, 2022 at 21:23
  • @spawn probably yes. I think I wrote it mostly as a pseudocode to give the point. I will fix it.
    – Jakuje
    Dec 21, 2022 at 12:26
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.

8
  • 1
    The problem here is dealing with the timeouts. Aug 16, 2017 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.
    – user541686
    Aug 16, 2017 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, 2017 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, 2017 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, 2017 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.
3
  • 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...
    – user541686
    Aug 16, 2017 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. Aug 16, 2017 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, 2017 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

}
8
  • Thanks but this misses the point of my question... see my comment under his answer.
    – user541686
    Aug 16, 2017 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, 2017 at 21:27
  • Your function might have an unexpected behaviour in case already established ssh session got accidental disconnect.
    – rush
    Aug 16, 2017 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, 2017 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, 2017 at 22:19

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .