openssh-unix-dev Digest, Vol 205, Issue 26

Peter Stuge peter at
Mon May 25 01:01:31 AEST 2020

Hi Christof,

Warlich, Christof wrote:
> > My point is that neither ProxyJump nor ProxyCommand describe a command that executes
> > remotely, they both result in an extra command being executed locally, on the initial client.
> > That command (ssh -W) instructs the jumphost sshd to connect to the given destination by
> > way of a "direct-tcpip" channel, and the destination sent in that CHANNEL_OPEN request is
> > either what the user typed in the original client command or a configured HostName.
> Thanks for the clarification: As I understand, ProxyCommand (and thus, ProxyJump) may
> not be "misused" to do some hidden extra functionality that is just only needed for the
> particular use case that I'm interested in.

Yes and no. I wanted to make a few points, two are:

1. ProxyCommand (and thus ProxyJump) runs a command on client, not jumphost
2. ProxyJump always only runs one particular, hard-coded command (ssh -W)

So you are correct that ProxyJump can not be used to gain extra functionality.

But if you can create a command which does what you want when run *on client*
then you can certainly hook it into ssh through ProxyCommand.

> a new option, e.g. something like CanonicalProxy, that may be set to a
> jumphost and that allows to test the resolvability of a host from that
> jumphost.

Another point I wanted to make is that the SSH protocol fundamentally
supports TCP port forwarding within SSH connections, and this is what
ssh -W (ie. ProxyJump) uses.

Note that with this proxying the local client always communicates directly
with every jumphost (there can be many) as well as with the final destination.

Another way to think about it is authenticated source- or onion-routing.

The SSH protocol does however *not* have fundamental support for "test
the resolvability of a host", so there's no basis to implement exactly
what you describe.

The closest there is would indeed be the very TCP port forwarding that
is used by ssh -W, since it accepts both numerical addresses and names,
and any names are only ever resolved by jumphosts.

You can, for example, experiment with this:

Host !*.* *
  ProxyCommand ssh -W %h.internal.sub.domain:%p jumphost

Note that this results in no name resolution attempts for unqualified
names on the client, using the client system resolver. This may or
may not be desirable.

Note that this suggestion only makes sense when *every* unqualified name
used on your client is always destined for the internal network behind jumphost.

If you try to use unqualified names on your client e.g. for systems in the
same local network then this configuration still tries to connect to that
system through the jumphost. Probably wrong.

> And finally, I'm _really_ curious w.r.t.  the difference in functionality
> of "CanonicalizeHostname yes" and "CanonicalizeHostname always".  As the
> documentation is quite unspecific on that,

--8<-- ssh_config.5
If set to yes then, for connections that do not use a ProxyCommand or ProxyJump,
ssh(1) will attempt to canonicalize the hostname specified on the command line
using the CanonicalDomains suffixes and CanonicalizePermittedCNAMEs rules.

If CanonicalizeHostname is set to always, then canonicalization is applied
to proxied connections too.

I find this well described, but maybe it changed recently.

> latter was  _intended_ to switch on the hidden extra functionality that
> I was suggesting for ProxyJump (and ProxyCommand).

CanonicalizeHostname controls canonicalization done by the client according
only to the client's CanonicalDomains list and taking place before any
connection is attempted. Think of it as an ssh-local version of "search"
in /etc/resolv.conf.

Note that the canonicalized name is only accepted if the system resolver
on the client finds an address for it; the opposite of the previous example.

If you want to experiment with this functionality and the resolver on
your client knows all internal.sub.domain names then you could try:

CanonicalDomains internal.sub.domain
CanonicalizeHostname yes # I believe "always" is unneccessary in this case

Host *.internal.sub.domain
  ProxyCommand ssh -W %h:%p jumphost

If the system resolver on the client can resolve *.internal.sub.domain then
the effect is similar as for the previous "Host !*.* *" variant.

If it can't resolve then this will never work.

I believe that CanonicalizeHostname "yes" works here because proxying is
enabled *after* canonicalization, in the second processing pass of Host
and Match blocks.

As I understand the man page and the code, yes vs. always only matters when
proxying is enabled before canonicalization, e.g.:

CanonicalDomains internal.sub.domain
CanonicalizeHostname always # here it must be always

Host blah
  ProxyCommand ssh -W %h:%p jumphost # or simply: ProxyJump jumphost

When running ssh blah on the client this is different from the previous
variant in that the Host block is processed before canonicalization because
it matches the name given on the command line, so proxying is enabled before
canonicalization and thus "always" is required.

The idea is that names likely shouldn't be resolved by the client when
proxying, but likely only by the proxy.

If you want to use canonicalization then you have to also configure
the resolver on your client such that it can resolve names behind the
jumphost. This can make sense but requires configuration beyond OpenSSH.

In your case I would probably settle on something like:

Host *.i
  ProxyCommand ssh -W %hnternal.sub.domain:%p jumphost

Which allows running "ssh blah.i" to access blah.internal.sub.domain
behind jumphost and "ssh blah" to access blah on the local client network.

I hope this helps.


More information about the openssh-unix-dev mailing list