new feature w/ patch

Scott Bolte listS+openssh-unix-dev at niss.com
Sun Jan 6 09:09:17 EST 2002


I've attached a patch to OpenSSH 3.0.2p1 that will allow the client
side of local port forwarding to be bound to a single address. For
my purposes, binding to 127.0.0.1 or (via GatewayPorts) all addresses
would not work. I overloaded the "-b local_host" option so that
it's address will be used when "-L port:remote_host:remote_port"
is also specified.

Today is the first day I played with OpenSSH 3.x or port forwarding.
Therefore I am not sure if my use of -b with -L will break any
existing use cases. If it does, please speak up. 

In case you are curious, here is the scenario I have...

	On FreeBSD there is the idea of a jail. A jail takes the
	old idea of chroot and extends it quite a bit. Aside from
	limiting the privileges of root in a jail, each jail can
	also have its own IP address. Therefore, one host can easily
	have two instances of (for example) Apache, each bound to
	port 80. (Yes, this can be done simply by multi-homing the
	host, but there are other reasons for a jail.)

	On one host on my LAN, I have two jails. Call them jail_1
	(127.74.0.1) and jail_2 (127.74.0.2).  I want to provide
	a remote friend access to those jails even though they are
	not routable addresses for him.

	With my patch, my friend can add two IP aliases on a host
	on his LAN.  Let's call them mirror_1 (127.77.0.1) and
	mirror_2 (127.77.0.2).  If "remote" is in root's ~/.ssh/config
	file pointing to my system, then the following two commands
	will provide two unique tunnels linking each mirror with
	its corresponding jail:

		root# ssh -b mirror_1 -N -f -L 80:jail_1:80 remote
		root# ssh -b mirror_2 -N -f -L 80:jail_2:80 remote

	Either the jails or the mirrors could use 10.* instead of
	127.* if it is safe to allow general access on the LAN.

	Using the use case of Apache, my friend can then use
	http://mirror_1:80/ and http://mirror_2:80/ and reach my
	jails transparently. If we both then aliased mirror_1 and
	jail_1 to be virtual_1, we could even use the same host
	names.

The commands below show my local test case.

	:
	: Set up two aliases, one representing a FreeBSD jail and the
	: other a remote mirror.
	:
	root# grep 127.7 /etc/hosts
	127.74.0.1              localjail_1
	127.77.0.1              localmirror_1

	root# ifconfig lo0 inet localjail_1   netmask 0xffffffff alias
	root# ifconfig lo0 inet localmirror_1 netmask 0xffffffff alias

	:
	: Make sure (ssh remote) is a login into localhost.
	:
	user% tail -4 ~/.ssh/config
	Host remote
	 Protocol       2
	 IdentityFile   /home/scott/.ssh/id_dsa
	 HostName       127.0.0.1

	:
	: Start the tunnel so that it is locally bound to the host
	: address of localmirror_1. The 'remote' end happens to be local
	: for this example, but it easily could be half way around the
	: world.
	:
	user% ssh -b localmirror_1 -N -f -L 1111:localjail_1:2222 remote

	:
	: Run a test script that listens on a host:port and prints out
	: what it sees. Note the last line below was actually printed
	: after portsend was called.
	:
	user% portlisten.pl -a localjail_1 -p 2222 -w 600 &
	[Server ./portlisten.pl accepting clients on port 2222.]
	[Connect from 127.74.0.1:3521]
	read "in the mirror, out the jail"

	:
	: Now send a test message in one port of the mirror and see it
	: come out the other port in the jail.
	:
	user% ~/WIP-perl/portsend.pl -a localmirror_1 -p 1111 in the mirror, out the jail

	:
	: Verify that the client side of the tunnel is bound to a single
	: address.
	:
	root# netstat -a
	Active Internet connections (including servers)
	Proto Recv-Q Send-Q  Local Address       Foreign Address     (state)
	tcp4       0      0  localjail_1.3521    localjail_1.2222    TIME_WAIT
	tcp4       0      0  localmirror_1.3520  localmirror_1.1111  TIME_WAIT
	tcp4       0      0  localjail_1.2222    *.*                 LISTEN
	tcp4       0      0  localmirror_1.1111  *.*                 LISTEN
	tcp4       0      0  localhost.ssh       localmirror_1.3517  ESTABLISHED
	tcp4       0      0  localmirror_1.3517  localhost.ssh       ESTABLISHED
		...

So folks, what do I need to do to have this feature added to the
mainline of OpenSSH?

	Thanks,

	   Scott



diff -ru openssh-3.0.2p1/channels.c openssh-3.0.2p1-NewFeature/channels.c
--- openssh-3.0.2p1/channels.c	Thu Oct 11 20:35:05 2001
+++ openssh-3.0.2p1-NewFeature/channels.c	Sat Jan  5 15:36:10 2002
@@ -2057,11 +2057,11 @@
  * channel to host:port from remote side.
  */
 int
-channel_request_local_forwarding(u_short listen_port, const char *host_to_connect,
-    u_short port_to_connect, int gateway_ports)
+channel_request_local_forwarding(const char *listen_host, u_short listen_port,
+    const char *host_to_connect, u_short port_to_connect, int gateway_ports)
 {
 	return channel_request_forwarding(
-	    NULL, listen_port,
+	    listen_host, listen_port,
 	    host_to_connect, port_to_connect,
 	    gateway_ports, /*remote_fwd*/ 0);
 }
@@ -2080,7 +2080,7 @@
 	int success, sock, on = 1, type;
 	struct addrinfo hints, *ai, *aitop;
 	char ntop[NI_MAXHOST], strport[NI_MAXSERV];
-	const char *host;
+	const char *host, *listen_host = NULL;
 	struct linger linger;
 
 	success = 0;
@@ -2089,6 +2089,7 @@
 		host = listen_address;
 		type = SSH_CHANNEL_RPORT_LISTENER;
 	} else {
+		listen_host = listen_address;
 		host = host_to_connect;
 		type = SSH_CHANNEL_PORT_LISTENER;
 	}
@@ -2108,7 +2109,7 @@
 	hints.ai_flags = gateway_ports ? AI_PASSIVE : 0;
 	hints.ai_socktype = SOCK_STREAM;
 	snprintf(strport, sizeof strport, "%d", listen_port);
-	if (getaddrinfo(NULL, strport, &hints, &aitop) != 0)
+	if (getaddrinfo(listen_host, strport, &hints, &aitop) != 0)
 		packet_disconnect("getaddrinfo: fatal error");
 
 	for (ai = aitop; ai; ai = ai->ai_next) {
@@ -2259,7 +2260,7 @@
 				  port);
 #endif
 	/* Initiate forwarding */
-	channel_request_local_forwarding(port, hostname, host_port, gateway_ports);
+	channel_request_local_forwarding(NULL, port, hostname, host_port, gateway_ports);
 
 	/* Free the argument string. */
 	xfree(hostname);
diff -ru openssh-3.0.2p1/channels.h openssh-3.0.2p1-NewFeature/channels.h
--- openssh-3.0.2p1/channels.h	Sun Nov 11 18:04:55 2001
+++ openssh-3.0.2p1-NewFeature/channels.h	Sat Jan  5 14:34:05 2002
@@ -189,7 +189,7 @@
 int	 channel_connect_to(const char *, u_short);
 int	 channel_connect_by_listen_address(u_short);
 void	 channel_request_remote_forwarding(u_short, const char *, u_short);
-int	 channel_request_local_forwarding(u_short, const char *, u_short, int);
+int	 channel_request_local_forwarding(const char *, u_short, const char *, u_short, int);
 int
 channel_request_forwarding(const char *, u_short, const char *, u_short, int,
     int);
diff -ru openssh-3.0.2p1/ssh.c openssh-3.0.2p1-NewFeature/ssh.c
--- openssh-3.0.2p1/ssh.c	Sun Nov 11 17:52:04 2001
+++ openssh-3.0.2p1-NewFeature/ssh.c	Sat Jan  5 14:37:50 2002
@@ -830,14 +830,27 @@
 {
 	int success = 0;
 	int i;
+	char *local_host;
+
+	if (options.bind_address == NULL) {
+		if (options.gateway_ports == 0) {
+			local_host = "localhost";
+		} else {
+			local_host = "{ANY}";
+		}
+	} else {
+		local_host = options.bind_address;
+	}
 
 	/* Initiate local TCP/IP port forwardings. */
 	for (i = 0; i < options.num_local_forwards; i++) {
-		debug("Connections to local port %d forwarded to remote address %.200s:%d",
+		debug("Connections to local port %.200s:%d forwarded to remote address %.200s:%d",
+		    local_host,
 		    options.local_forwards[i].port,
 		    options.local_forwards[i].host,
 		    options.local_forwards[i].host_port);
 		success += channel_request_local_forwarding(
+		    options.bind_address,
 		    options.local_forwards[i].port,
 		    options.local_forwards[i].host,
 		    options.local_forwards[i].host_port,




More information about the openssh-unix-dev mailing list