Using ssh_config Match to connect to a host using
multiple IP or Hostnames
This commit is contained in:
Felipe M 2022-08-12 13:28:13 +02:00
parent f647625361
commit cb7b2f1d06
Signed by: fmartingr
GPG Key ID: 716BC147715E716F
1 changed files with 78 additions and 0 deletions

View File

@ -0,0 +1,78 @@
title: Using ssh_config Match to connect to a host using multiple IP or Hostnames
---
pub_date: 2022-08-12
---
_discoverable: yes
---
body:
My main computer is a MacBook Pro from 2017, but I have some servers laying around and one other laptop connected at home
with ArchLinux installed that I use mainly for development. I connect to it remotely either directly using a
SSH/Mosh + Tmux + Emacs/Vim combination, or using the pretty convenient VSCode Remote Extensions when I'm not feeling
much of a _hacker_.
Thing is, I may access this computer either from my home network directly if I'm at home or via a SDN if I am not (at the office,
coffeeshop, visiting family, etc).
My approach was to setup the hosts directly on my `~/.ssh/ssh_config` as you would with different machines:
``` bash
# .ssh/config
Host laptop.lan
HostName 192.168.1.2 # Internal network IP
Host laptop.sdn
Hostname 10.0.0.2 # SDN IP
```
That way, I would connect to each one of them depending on the situation. Using tmux and ssh is not that much of a problem
since I could just detach from home, go away, then connect via SDN an everything would be there (though I had to remember
which alias to use instead of just `ssh laptop`). For VSCode is not that convenient since I would need to close the connection,
made a new one to the new host and so on. Surely we could made this simpler, right?
In my home network, my main router is also my DNS server (with Ad Blocking, rules and all kind of fancy things), and that
server resolves my local domain (`*.lan`) to LAN IP Addresses, so I can start with a simple config as I had previously:
``` bash
# .ssh/config
Host laptop
HostName laptop.lan
```
Now, what happens if I'm not at home? I could solve this in several ways:
- I could `ping` my router, but that could collide with other networks out there.
- I could check if my Wifi BSSID is one of the APs at home, but I could also connect via Ethernet.
- I could check if I can resolve the `laptop.lan` address, though this requires network access, but in the end is the one I ended
up using.
``` bash
$ dig +short laptop.lan
192.168.1.2 # At home
$ dig +short laptop.lan
# Empty result when away from home
```
Now, here comes the [`Match`](https://man7.org/linux/man-pages/man5/ssh_config.5.html) magic:
``` bash
# .ssh/config
Host laptop
HostName laptop.lan
Match originalhost laptop exec "[[ $(/usr/bin/dig +short laptop.lan) == '' ]]"
HostName laptop.sdn
```
Using `Match` we can replace properties for a defined host using matches. In this ad-hoc example what I did is:
- `Match originalhost laptop`: The connection host need to match `laptop`
- `exec "[[ $(/usr/bin/dig +short laptop.lan) == '' ]]"`: Execute `dig` and try to resolve my LAN's laptop domain name.
This needs to be a successful command for it to match, in this case we compare `dig`s output to an empty string to evaluate
if we can resolve the `laptop.lan` domain name (check the `[[ ]]`).
- `HostName laptop.sdn` If both rules match, replace the `HostName` property with the laptop's SDN domain name.
This is a pretty easy way to just `ssh laptop` wherever I am. I didn't knew about this particular
keyword until today, and it's pretty powerful!
Documentation: [ssh_config(5) manpage](https://man7.org/linux/man-pages/man5/ssh_config.5.html)