RemoteForward and dynamically allocated listen port

Andrew Pimlott andrew at
Tue Aug 6 05:04:44 EST 2013

Specifying a RemoteForward of dynamically allocates
the listen port on the server, and then reports it to ... the client!
Where it is practically useless.  Was this someone's idea of a joke?

Presumably not--there are some technical obstacles to reporting it to
the remote process.  I'd like to help solve that problem.

The natural way to me would be to extend the syntax of RemoteForward to
allow  This would set $ENV_VAR to the
dynamically alocated port in the remote process.  However, the protocol
passes the listen port as a u_int.  A hack might be to pack the env var
name into the listen address and set the listen port to a special value
to indicate this, but I don't know if this is playing too fast and
loose.  A cleaner solution would be to add a new request type.  I
imagine that ssh protocol changes are made conservatively, so I don't
know how viable these options are.

Without changing the protocol, we could at least set an environment
variable for each dynamically allocated port, numbered by the order of
the RemoteForward requests, eg. SSH_REMOTE_FORWARD_PORT_1,
SSH_REMOTE_FORWARD_PORT_2, ....  I was able to wedge a proof of concept
into session.c:do_setup_env (patch below).  It's a hack because there
doesn't seem to be an API to iterate channels outside of channels.c.
Would it be agreeable to export channels and channels_alloc?  Also,
struct Channel doesn't let you tell which forwards were dynamically
allocated, so an environment variable is set for all RemoteForwards.
This could be changed by extending struct Channel, though it isn't a
show-stopper for me.

Last thought: if a new protocol request type were added, it should make
it easy to add support for forwarding unix sockets, which I have missed
for a long time.

Would any of these approaches be acceptable?  Any other ideas?


--- session.c.orig	2013-08-03 13:22:10.354171156 -0700
+++ session.c	2013-08-05 09:58:00.017397667 -0700
@@ -1307,6 +1307,17 @@
 		child_set_env(&env, &envsize, SSH_AUTHSOCKET_ENV_NAME,
+	char name[256];
+	u_int n = 0;
+	for (i = 0; i < 100; i++) {
+		Channel *c = channel_by_id(i);
+		if (c == NULL || c->type != SSH_CHANNEL_RPORT_LISTENER)
+			continue;
+		snprintf(name, sizeof name, "SSH_REMOTE_FORWARD_PORT_%d", n);
+		snprintf(buf, sizeof buf, "%d", c->listening_port);
+		child_set_env(&env, &envsize, name, buf);
+	}
 	/* read $HOME/.ssh/environment. */
 	if (options.permit_user_env && !options.use_login) {
 		snprintf(buf, sizeof buf, "%.200s/.ssh/environment",

More information about the openssh-unix-dev mailing list