Ssh – Determine the target of an SSH connection at runtime

ssh

I want to determine the target address of an SSH connection with a function call that generate the address to connect to. All of the examples using ProxyCommand that I can find online use the -W flag to hop to a second machine. I tried that with localhost for the second machine, and that worked but required SSH authentication twice which I didn't like.

I am trying to call ssh inside of the ProxyCommand without forwarding to second hop. Right now, I have in my .ssh/config file:

Host test
    ProxyCommand ssh user@address

When I do ssh test, it seems to connect okay but after connecting there is a blank prompt that does not respond to input, so it seems stdin/stdout must not be directed properly.

Related questions:

Use a dynamically obtained hostname with an ssh config entry

How to get HostName from executable script in SSH config file?

Dynamically generate SSH Host entries in ~/.ssh/config

Best Answer

Since you don't pass a command to ssh, it runs a shell, which expects commands on its standard input. But you aren't passing it shell commands, you're passing it SSH traffic. Hilarity ensues.

Tunnelling is the whole point of ProxyCommand. This example tunnels an SSH connection inside an SSH connection. If you don't want to tunnel, ProxyCommand is not what you're looking for.

Since OpenSSH 6.4, you can use a Match directive with the exec keyword to include blocks conditionally based on a run-time directive. A typical use case is to have different actual host names or proxy commands depending on where your laptop is. Each Match block replaces a Host block, and you can't use the output of the command to determine the host name, only the fact that it exited with status 0.

# Connection inside ACME network
Match host foo exec on-acme-network
HostName foo.acme.local

# Connection from outside ACME
Host foo
HostName foo.example.com

Proxying is another option. To make a connection to a host name and port that are determined at connection time, you can use netcat to set up the TCP connection.

Host foo
ProxyCommand nc $(determine-target-host-name) 22

If you want a fully dynamic .ssh/config, you can make it a named pipe and ensure that a process is always writing to it. Or put it on scriptfs.

Related Question