19

In the office, I can connect to internal machines without a proxy, but need a proxy for external connections. Outside of the office, I can connect to other external machines without a proxy, but need to use one of 2 proxies to connect to internal machines.

If I can figure out a way to autodetect what network I'm on, can I instruct ssh to load the appropriate config file?

If not, is there a more elegant solution than writing a shell script to symlink the appropriate config file to ~/.ssh/config (my best idea so far)?

Edit: I think @pcm and JonnyRo understood my question and I'll try what they suggest, but just to be clear, I want

|--------\    Dest   | abc.example.com | xyz.external.org |
| Source  \---------\|                 |                  |
|--------------------+-----------------+------------------|
| example.com office | No Proxy        | Proxy            |
| outside            | Proxy           | No Proxy         |

8 Answers 8

11

Depending on how your proxy is configured, you can simply build an SSH config entry that works in either situation. For example on one network I regularly use I have to ssh to an intermediate host before I can make an outbound connection. So basically I setup a configuration that looks like this.

# proxy ssh 
Host *%sshproxy
    ProxyCommand ssh [email protected] /bin/netcat -w 1 $(echo %h | cut -d%% -f1) 22

Host myhost.example.org
    HostName 172.16.24.1

Host otherhost.example.com
    HostName 192.168.57.12

So when I don't need to use a proxy, I can simply run a command like ssh myhost.example.org and get connected, but when I do need the proxy, I run the command ssh myhost.example.org%sshproxy.

I suspect you could probably setup some kind of alias or auto-complete setting that would automatically append the %proxy bit.

10

Old question, but some ideas in this thread helped me and this is a solution I came up with:

First, the proxy server ssh configuration.

Match Originalhost proxy Exec "ifconfig | grep 10.0.1"
     Hostname 10.0.1.2
Host proxy 
     Hostname external.hostname.com

Then, the Server B configuration:

Match Originalhost server-b Exec "ifconfig | grep 10.0.1"
     ProxyCommand none
Host server-b
     Hostname 10.0.1.3
     ProxyCommand ssh -W %h:%p server-a

The idea here is that the default case is connecting from an external site and the ProxyCommand initiates an ssh connection to proxy first and then connect to server-b. If, on the other hand, we are located on the local subnet already, the ProxyCommand is disabled and no proxy connection to server-a is made.

Regardless of where you are, you can always reach server-abc by this entry and this setup figures out where you are and sets up the connection accordingly. For server-xyz, just use the same idea.

I made a more thorough explanation here: http://blog.kihltech.com/2017/04/ssh-conditional-host-address-based-on-network-or-location/

7

You can use the -F option to select from different config files. for the two network cases. You can then either create aliases that use the different config files, based on which net you are on, or in your login script setup a single alias, based on your IP address.

2
  • Thanks! Aliases with -F will definitely be my fallback if I can't get a script working based on IP. Apr 25, 2012 at 6:29
  • This is awesome, I was just about to ask the same question. I already script some other options to set environment variables when I start a new terminal, I can easily create an alias or symlink the proper .ssh/config based on the environment.
    – newz2000
    May 23, 2013 at 18:12
1

Write a shell script that checks your IP against a pattern, then symlinks the appropriate shell script.

If for some reason your IP range is the same for home and work, try switching based on /etc/resolv.conf, which contains the DHCP configured DNS servers.

0

The "Host" option in .ssh/config lets you change the configuration based on the destination. I use that to adjust port forwarding and such based on where I'm going.

0

I have looked into this question in the past and one possible solution is to have such entry in the config file:

Host ENTRY_POINT
Hostname ENTRY_POINT_FQDN
User USERNAME

Host *.INSIDE_DOMAIN
ProxyCommand ssh ENTRY_POINT nc %h %p

This way, if you are outside, you can $ ssh machine.inside_domain. If you are inside and have dns resolving, you can $ ssh machine. That works well for me.

Maybe someone can improve upon this idea, maybe changing DNS configuration so it automatically resolves machine to machine.inside_domain if you are outside and use the SSH entry point.

0

With Match and Exec you can check whether SSH port is accessible, and only use ProxyCommand if not. See my example here: https://stackoverflow.com/questions/40746463/how-to-automatically-switch-ssh-config-based-on-local-subnet/62924483#62924483

0

My answer is inspired by @Robert Kihlberg, but goes a bit further.

I have a home network with a machine called vorlon on it, and a gateway called luthor. Vorlon is behind a NAT, and is not visible on the internet, while luthor has a dyndns address and is accessible from anywhere in the world.

The following is present in ~/.ssh/config on all my machines. (The options LocalCommand and PermitLocalCommand are only there to simplify reconfiguration, or to help debugging if something goes wrong – note the redirection to STDERR in them though, >&2, without those rsync breaks!):

# For gateway machine.
# Coming from localhost.
Match originalhost luthor exec "[ %h = %L ]"
  LocalCommand echo "SSH %n: To localhost" >&2
# Coming from outside home network.
Match originalhost luthor !exec "[ %h = %L ]" !exec "{ ip neigh; ip link; }|grep -Fw 60:0e:56:36:c4:ca"
  LocalCommand echo "SSH %n: From outside network, to %h" >&2
  Hostname luthor.dyndns.org
# Coming from inside home network.
Host luthor
  PermitLocalCommand yes
  LocalCommand echo "SSH %n: From home network, to %h" >&2

First, in order to detect which network I'm on, I use the following command (as argument for the Match … exec "…" option):

{ ip neigh; ip link; }|grep -Fw 60:0e:56:36:c4:ca

This command returns true if the MAC address of my gateway machine can be found on the network. This will only happen if the machiche I'm using is currently connected to my home network. (The ip neigh command lists all the hosts on the network [including their MAC addresses] that is known to the machine I'm SSH:ing from. However this it's output does not include the machine I'm SSH:ing from itself, which is instead done by the ip link command. – The output formats of the two commands is slightly different, but it doesn't matter, as they both include the MAC addresses in the same format.)

There are three distict cases:

1. SSH:ing to localhost.

If we're SSH:ing to 'luthor' (originalhost luthor), and the host I'm coming from is the same as the destination ([ %h = %L ]) then we're SSH:ing to localhost, in which case no further logic is needed.

It may not look as such, but [ %h = %L ] is a shell command, which is percent-expanded by SSH, and which returns true if the local hostname (%L) is the same as the remote host (%h).

2. SSH:ing to the gateway machine from outside the home network.

If we're SSH:ing to 'luthor' (originalhost luthor), and the host that I'm coming from is not the same as the destination (!exec "[ %h = %L ]"), and the MAC address of my gateway server 'luthor' can't be found on the local network (!exec "{ ip neigh; ip link; }|grep -Fw 60:0e:56:36:c4:ca"). Then I'm outside my home network.

In this case Hostname is set to the address visible from the internet (in my example luthor.dyndns.org, but it could equally well have been an IP number).

3. SSH:ing from inside the home network.

If none of the above matches, then we just use the default profile which assume that we are on the home network. Any additional options added here like XForward, etc. will be applied in all three cases.

Entries for machines on my home network look kinda similar:

Match originalhost vorlon exec "[ %h = %L ]"
  LocalCommand echo "SSH %n: To localhost" >&2
Match originalhost vorlon !exec "[ %h = %L ]" !exec "{ ip neigh; ip link; }|grep -Fw 60:0e:56:36:c4:ca"
  LocalCommand echo "SSH %n: From outside network, via proxy luthor" >&2
  ProxyJump luthor
Host vorlon
  PermitLocalCommand yes
  LocalCommand echo "SSH %n: From home network" >&2

The only difference here is that instead of setting Hostname when we're SSH:ing in from the outside, we instead set ProxyJump (from what I gather the SSH option ProxyCommand can also be used for this, but I haven't tried it) so that we may tunnel through the gateway and into the home network.

Note: I initially tried to use the iwgetid -r|grep SSID command to detect when the computer I'm on is connected to my home wifi, but I wanted something that would work even if I hook up my computer with an Ethernet cable.

You must log in to answer this question.

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