Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

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 ]]
        then
        echo "franklin not available on local, so trying remote connection"
        ssh -p 22 remote.address.of.franklin
    else
        echo "franklin available on local network, so trying local connection"
        ssh username@franklin.local
    fi
}

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?

share|improve this question
    
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/10.1.2.3 –  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
add comment

3 Answers 3

up vote 4 down vote accepted

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).

share|improve this answer
    
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
add comment

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"
    else
        echo "Connecting remotely."
        ssh "remote.address.of.franklin"
    fi
}

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

share|improve this answer
add comment

I use nc instead of ping:

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

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

franklin uptime
share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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