When I'm on a certain network (subnet is 10.10.11.x) I need to jump through an intermediate host to reach my destination because of destination port I can't change and limited ports on which I can exit the restricted network. I use a ssh config like the following with success:
Host web-direct web
HostName web.example.com
Port 1111
Host web-via-jump jweb
HostName web.example.com
Port 1111
ForwardAgent yes
ProxyCommand ssh -p 110 -q relay.example.com nc %h %p
Going through the jumpbox is a significant performance hit so I need to avoid it for the majority of times it is not needed. Switching the ssh/scp/rsync host nickname is fine for interactive use but there are some automated/scripted tasks which it is very painful.
My shell stays open across network transitions so startup (.zshrc) mechanisms don't help.
I've thought of running a script to poll for the restricted subnet and automate the switch by modifying the .ssh/config file but I'm not even sure there would be a caching issue. Before I implement that, I thought I would ask if there is a better approach.
What's the best approach for swapping out ssh config based on origin host subnet detection?
In pseudo-config, something like:
if <any-active-local-interface> is on 10.10.11.x:
Host web
HostName web.example.com
Port 1111
ForwardAgent yes
ProxyCommand ssh -p 110 -q relay.example.com nc %h %p
else:
Host web
HostName web.example.com
Port 1111
endif
There is possibility to use Match exec
option to execute particular commands so you can write something like this:
Match exec "hostname -I | grep -F 10.10.11." host web
ForwardAgent yes
ProxyCommand ssh -p 110 -q relay.example.com nc %h %p
Host web
HostName web.example.com
Port 1111
I'm using next function for that:
function ssh() {
network=`networksetup -getairportnetwork en0 | cut -d: -f2 | tr -d [:space:]`
if [ -n "$network" -a -f $HOME/.ssh/config.$network ]; then
/usr/bin/ssh -F $HOME/.ssh/config.$network "$@"
else
/usr/bin/ssh "$@"
fi
}
export -f ssh
So I must have separate configuration file for each WiFi network I want custom solution. It works for me right now but it's ugly so I could recommend it only as idea not as best solution.
Will be glad to know any solution better.
Based on the answer by Fedor Dikarev, Mike created a bash script named onsubnet
:
#!/usr/bin/env bash
if [[ "$1" == "--help" ]] || [[ "$1" == "-h" ]] || [[ "$1" == "" ]] ; then
printf "Usage:\n\tonsubnet [ --not ] partial-ip-address\n\n"
printf "Example:\n\tonsubnet 10.10.\n\tonsubnet --not 192.168.0.\n\n"
printf "Note:\n\tThe partial-ip-address must match starting at the first\n"
printf "\tcharacter of the ip-address, therefore the first example\n"
printf "\tabove will match 10.10.10.1 but not 110.10.10.1\n"
exit 0
fi
on=0
off=1
if [[ "$1" == "--not" ]] ; then
shift
on=1
off=0
fi
regexp="^$(sed 's/\./\\./g' <<<"$1")"
if [[ "$(uname)" == "Darwin" ]] ; then
ifconfig | fgrep 'inet ' | fgrep -v 127.0.0. | cut -d ' ' -f 2 | egrep "$regexp" >/dev/null
else
hostname -I | tr -s " " "\012" | fgrep -v 127.0.0. | egrep "$regexp" >/dev/null
fi
if [[ $? == 0 ]]; then
exit $on
else
exit $off
fi
Then in his .ssh/config file, he uses something like:
Match exec "onsubnet 10.10.1." host my-server
HostName web.example.com
Port 1111
ForwardAgent yes
ProxyCommand ssh -p 110 -q relay.example.com nc %h %p
Match exec "onsubnet --not 10.10.1." host my-server
HostName web.example.com
Port 1111