I have a home computer (let’s call it franklin because that’s what I call it) that I often ssh into from my work laptop. When I’m at home, I ssh to franklin.local, and when I’m at work or anywhere else, I ssh to remote.address.of.franklin.

I want to have a function in my profile that always connects in the correct way for the situation. My network conditions often change (wired vs. wireless, different SSIDs, etc), so I’d prefer not to do it by detecting the state of the network, but rather:

  1. If franklin is available locally, connect locally,
  2. else, connect remotely

Here’s what I use now:

function franklin () {
    ping -c 5 "franklin.local" > /dev/null
    if [[ $? != 0 ]]
        echo "franklin not available on local, so trying remote connection"
        ssh -p 22 remote.address.of.franklin
        echo "franklin available on local network, so trying local connection"
        ssh username@franklin.local

The problem is, the ping takes time. My question is: can I execute both ssh commands simultaneously, and then automatically use whichever one connects first?

  • Do you have the option to reconfigure your DNS (caching) server at home (e.g. in your router)? Tell it to have a static entry remote.address.of.franklin pointing to your local address. In dnsmasq for example, this can be configured using a line address=/remote.address.of.franklin/ – gertvdijk Dec 19 '12 at 15:57
  • Interesting idea, but I’d like something a little more reusable if possible. I have something I’m going to try; will answer my own question if it works. – Zev Eisenberg Dec 19 '12 at 16:05
  • Really, you want to use proper "split DNS" here. A host should have a single, fully qualified hostname. Makes life a lot easier. You're now creating a workaround for SSH, but you'll run into more later with accessing other servers or services. – gertvdijk Dec 19 '12 at 16:38

What about trying a simple OR from your shell?

ssh username@franklin.local || ssh -p 22 remote.address.of.franklin

I am not really familiar with ZSH, but I guess the evaluation logic would still be lazy, meaning that the second part is only evaluated if the first part fails. Of course the first command may stall for some time trying to figure out if franklin.local is available.

You could assign that command to an alias to shorten it up (like you did with the function).

  • Oh man, this totally works. Much nicer than the one I posted, and was going to accept as an answer until I saw this. – Zev Eisenberg Dec 19 '12 at 16:50
  • I am glad you like it (o: – Axel Knauf Dec 19 '12 at 16:51
  • adding '-o ConnectTimeout=5' to 'ssh username@franklin.local' will speed things up a little as well. – Stephen Paul Lesniewski Jan 6 '13 at 15:14

I use nc instead of ping:

franklin() {
    local host=franklin.local
    if nc -w1 $host 22 &>/dev/null; then
        echo "connecting locally"
        echo "connecting remotely"
    ssh username@$host "$@"

I added "$@" to the ssh call. That let's you quickly execute remote commands like

franklin uptime

Turns out I was closer to the solution than I thought. I had a faulty assumption about how the address lookup part of ping works. I thought that if I had a network hiccup, and franklin.local didn’t return the pings, then it would fail and connect remotely instead. Turns out, if franklin.local is on the network, ping -c 1 franklin.local returns 0, and if not, it returns 68, both pretty immediately. So the only change is the count of the ping from 5 to 1 (I've also tweaked the order of the script to make it make more sense):

function franklin
    ping -c 1 franklin.local &> /dev/null
    if [[ $? == 0 ]]; then
        echo "Connecting locally."
        ssh "username@franklin.local"
        echo "Connecting remotely."
        ssh "remote.address.of.franklin"

This is significantly faster than how I had it before, and not appreciably slower than just using the appropriate ssh command directly.

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.