0

I have a system with both a public (e.g server1.foo.bar) and privately-resolvable (e.g. server1.internal.foo.bar) DNS name. SSH connections are only possible via the private IP, but I always think of these hosts in terms of their public name.

I would like to:

  • connect to the right IP regardless of whether I remember to use the *.internal.bar pattern
  • save keystrokes

I'm aware of the substitution tokens such as %h that can be used to modify the hostname given at the commandline, e.g.

Host foo
    Hostname %h.some.other.domain

The behavior I'm looking for would be something like:

Host *.foo.bar
    Hostname %m.internal.foo.bar

Where %m gets substituted with just the portion of the given hostname up to the first dot. I've read man 5 ssh_config as well as https://man.openbsd.org/ssh_config and couldn't find the answer, if one even exists. I'm using macOS 10.15.4:

$ ssh -V
OpenSSH_8.1p1, LibreSSL 2.7.3
3
  • Why don't you add server1.foo.bar to your /etc/hosts with the address of server1.internal.foo.bar? Then the name will also work outside of ssh (ping, http, git...).
    – xenoid
    Apr 18, 2020 at 19:00
  • @xenoid because then I could not properly test anything else running on that server, this is specifically for SSH connections, not HTTP etc.
    – luckman212
    Apr 18, 2020 at 19:51
  • The Hostname thing in the SHH config works for single hosts, so I assume you have many servers? This is something I would solve with a small script or a loop that generates aliases. Or you just define 'serverX` in your /etc/hosts and use ssh serverX. On my Linux I get bash command completion of ssh with host names that are in /etc/hosts so in practice you would just enter the ends of the names.
    – xenoid
    Apr 18, 2020 at 21:05

2 Answers 2

0

I figured out a working method. It's a bit ugly, but it does work. This leverages the ProxyCommand directive (see manpage) combined with a small bash helper script.

  1. Add sections like this to ~/.ssh/config — one for each domain you want remapped:
Match final host="!*.corp.foo.com,*.foo.com"
    ProxyCommand ssh_ext2int %h %p

Match final host="*.quux.biz"
    ProxyCommand ssh_ext2int %h %p
  1. Save this in your $PATH somewhere as ssh_ext2int — and chmod u+x it:
#!/usr/bin/env bash

[ $# -eq 2 ] || exit 1
typeset -A dmap
dmap=(
  [foo.com]=corp.foo.com
  [quux.biz]=internal.qux.lan
)

d=${1#*.}
h=${1%%.*}
nd=${dmap[$d]:-$d}

/usr/bin/nc -w 120 $h.$nd $2 2>/dev/null

Now, ssh server158247.quux.biz should connect you to server158247.internal.qux.lan

0

This particular thing you ask for is not possible with OpenSSH. These constructs are really meant only for simple aliases and not for complex replacements such as you ask. If these servers have some specific format, you can make them aliases (without the domain name):

Host server*
    Hostname %h.internal.foo.bar

If you need some more complex matches for the aliases (lets say you have a file containing all your hosts. This can be either manually created or automatically updated from DNS), you can use something like this

Match exec "grep %h %d/.ssh/internal_hosts"
    Hostname %h.internal.foo.bar

The last resort is to generate the ssh_config from the above list/DNS, which will have the whole hardcoded items for all your hosts. It does not have to be the main configuration file, but just some included one. The configuration files are really just a text files.

2
  • But... the %m token does not exist! I made it up to illustrate the behavior I was seeking. So, the examples you posted don't work.
    – luckman212
    May 4, 2020 at 19:51
  • Well ... obviously I meant the %h. Fixed now.
    – Jakuje
    May 5, 2020 at 6:36

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.