LocalForward and RemoteForward bind patch

Jeff Hansen jeff at rubysoft.com
Fri Aug 6 05:12:16 EST 2004


FINALLY, it's here.

You can now tell SSH which address to bind to for every single port 
forwarding option!  This patch allows you to pass the following as ssh 
command line options:

ssh -L 192.168.1.55:1234:localhost:80 -R ::11:22:aa:bb/80/localhost/80
etc.

Or as normal config file options:

LocalForward ::11:22:33/1234 localhost/80
RemoteForward 1.2.3.4:80 localhost:80

It will also accept the old-style forwarding options just fine.

It would be cool if this could be put into the main branch some day so 
that everyone can enjoy this functionality.  If I'm mistaken, and OpenSSH 
already had this sort of functionality, please let me know as I don't 
subscribe to this list.  I knew people on this list would enjoy this 
patch, however.

The gateway ports options just don't cut it for me, so I wrote this patch.
It's backwards compatible with old ssh servers and clients, and I've 
tested it quite a bit.  Let me know if there are any problems with it.

-Jeff Hansen
jeff at rubysoft.com
-------------- next part --------------
diff -u -r openssh-3.8p1/channels.c openssh-3.8p1-localbind/channels.c
--- openssh-3.8p1/channels.c	2004-01-20 16:02:09.000000000 -0800
+++ openssh-3.8p1-localbind/channels.c	2004-08-05 12:55:16.101830360 -0700
@@ -86,6 +86,7 @@
  * network (which might be behind a firewall).
  */
 typedef struct {
+	char *listen_host;		/* Address to listen on */
 	char *host_to_connect;		/* Connect to 'host'. */
 	u_short port_to_connect;	/* Connect to 'port'. */
 	u_short listen_port;		/* Remote side should listen port number. */
@@ -2146,8 +2147,7 @@
 	char ntop[NI_MAXHOST], strport[NI_MAXSERV];
 
 	success = 0;
-	host = (type == SSH_CHANNEL_RPORT_LISTENER) ?
-	    listen_addr : host_to_connect;
+	host = host_to_connect;
 
 	if (host == NULL) {
 		error("No forward host name.");
@@ -2167,7 +2167,8 @@
 	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_addr==NULL?NULL:strlen(listen_addr)>0?listen_addr:NULL, 
+	    strport, &hints, &aitop) != 0)
 		packet_disconnect("getaddrinfo: fatal error");
 
 	for (ai = aitop; ai; ai = ai->ai_next) {
@@ -2222,28 +2223,28 @@
 		success = 1;
 	}
 	if (success == 0)
-		error("channel_setup_fwd_listener: cannot listen to port: %d",
-		    listen_port);
+		error("channel_setup_fwd_listener: cannot listen to port: %s/%d",
+		    listen_addr == NULL ? "0.0.0.0" : listen_addr, listen_port);
 	freeaddrinfo(aitop);
 	return success;
 }
 
 /* protocol local port fwd, used by ssh (and sshd in v1) */
 int
-channel_setup_local_fwd_listener(u_short listen_port,
+channel_setup_local_fwd_listener(const char *listen_host, u_short listen_port,
     const char *host_to_connect, u_short port_to_connect, int gateway_ports)
 {
 	return channel_setup_fwd_listener(SSH_CHANNEL_PORT_LISTENER,
-	    NULL, listen_port, host_to_connect, port_to_connect, gateway_ports);
+	    listen_host, listen_port, host_to_connect, port_to_connect, gateway_ports);
 }
 
 /* protocol v2 remote port fwd, used by sshd */
 int
 channel_setup_remote_fwd_listener(const char *listen_address,
-    u_short listen_port, int gateway_ports)
+    u_short listen_port, const char *bind_address, int gateway_ports)
 {
 	return channel_setup_fwd_listener(SSH_CHANNEL_RPORT_LISTENER,
-	    listen_address, listen_port, NULL, 0, gateway_ports);
+	    bind_address, listen_port, listen_address, 0, gateway_ports);
 }
 
 /*
@@ -2252,7 +2253,7 @@
  */
 
 void
-channel_request_remote_forwarding(u_short listen_port,
+channel_request_remote_forwarding(const char *listen_host, u_short listen_port,
     const char *host_to_connect, u_short port_to_connect)
 {
 	int type, success = 0;
@@ -2263,7 +2264,8 @@
 
 	/* Send the forward request to the remote side. */
 	if (compat20) {
-		const char *address_to_bind = "0.0.0.0";
+		const char *address_to_bind =
+			listen_host == NULL ? "0.0.0.0" : listen_host;
 		packet_start(SSH2_MSG_GLOBAL_REQUEST);
 		packet_put_cstring("tcpip-forward");
 		packet_put_char(1);			/* boolean: want reply */
@@ -2297,6 +2299,7 @@
 		}
 	}
 	if (success) {
+		permitted_opens[num_permitted_opens].listen_host = listen_host == NULL ? NULL : xstrdup(listen_host);
 		permitted_opens[num_permitted_opens].host_to_connect = xstrdup(host_to_connect);
 		permitted_opens[num_permitted_opens].port_to_connect = port_to_connect;
 		permitted_opens[num_permitted_opens].listen_port = listen_port;
@@ -2335,7 +2338,7 @@
 #endif
 
 	/* Initiate forwarding */
-	channel_setup_local_fwd_listener(port, hostname, host_port, gateway_ports);
+	channel_setup_local_fwd_listener(NULL, port, hostname, host_port, gateway_ports);
 
 	/* Free the argument string. */
 	xfree(hostname);
diff -u -r openssh-3.8p1/channels.h openssh-3.8p1-localbind/channels.h
--- openssh-3.8p1/channels.h	2003-10-01 23:17:00.000000000 -0700
+++ openssh-3.8p1-localbind/channels.h	2004-08-05 09:44:22.159094328 -0700
@@ -199,9 +199,9 @@
 void     channel_input_port_forward_request(int, int);
 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_setup_local_fwd_listener(u_short, const char *, u_short, int);
-int	 channel_setup_remote_fwd_listener(const char *, u_short, int);
+void	 channel_request_remote_forwarding(const char *, u_short, const char *, u_short);
+int	 channel_setup_local_fwd_listener(const char *, u_short, const char *, u_short, int);
+int	 channel_setup_remote_fwd_listener(const char *, u_short, const char *, int);
 
 /* x11 forwarding */
 
diff -u -r openssh-3.8p1/clientloop.c openssh-3.8p1-localbind/clientloop.c
--- openssh-3.8p1/clientloop.c	2004-08-05 08:59:57.478187000 -0700
+++ openssh-3.8p1-localbind/clientloop.c	2004-08-05 09:44:51.134689368 -0700
@@ -549,13 +549,13 @@
 		goto out;
 	}
 	if (local) {
-		if (channel_setup_local_fwd_listener(fwd_port, buf,
+		if (channel_setup_local_fwd_listener(NULL, fwd_port, buf,
 		    fwd_host_port, options.gateway_ports) < 0) {
 			logit("Port forwarding failed.");
 			goto out;
 		}
 	} else
-		channel_request_remote_forwarding(fwd_port, buf,
+		channel_request_remote_forwarding(NULL, fwd_port, buf,
 		    fwd_host_port);
 	logit("Forwarding port.");
 out:
diff -u -r openssh-3.8p1/misc.c openssh-3.8p1-localbind/misc.c
--- openssh-3.8p1/misc.c	2003-11-03 01:07:14.000000000 -0800
+++ openssh-3.8p1-localbind/misc.c	2004-08-05 11:49:12.019462480 -0700
@@ -141,6 +141,19 @@
 	return (old);
 }
 
+int strcount( char *str, char c )
+{
+	int count = 0;
+
+	if( str == NULL )
+		return -1;
+
+	while( *str != 0 && *str != ' ' && *str != '\t' )
+		if( *(str++) == c )
+			count++;
+	return count;
+}
+
 struct passwd *
 pwcopy(struct passwd *pw)
 {
diff -u -r openssh-3.8p1/misc.h openssh-3.8p1-localbind/misc.h
--- openssh-3.8p1/misc.h	2003-08-24 18:16:21.000000000 -0700
+++ openssh-3.8p1-localbind/misc.h	2004-08-05 11:02:08.916639344 -0700
@@ -14,6 +14,7 @@
 
 char	*chop(char *);
 char	*strdelim(char **);
+int	 strcount( char *, char );
 void	 set_nonblock(int);
 void	 unset_nonblock(int);
 void	 set_nodelay(int);
diff -u -r openssh-3.8p1/readconf.c openssh-3.8p1-localbind/readconf.c
--- openssh-3.8p1/readconf.c	2004-08-05 08:59:24.775159000 -0700
+++ openssh-3.8p1-localbind/readconf.c	2004-08-05 12:53:24.203841440 -0700
@@ -203,8 +203,8 @@
  */
 
 void
-add_local_forward(Options *options, u_short port, const char *host,
-		  u_short host_port)
+add_local_forward(Options *options, const char *listen_host, u_short port, 
+		  const char *host, u_short host_port)
 {
 	Forward *fwd;
 #ifndef NO_IPPORT_RESERVED_CONCEPT
@@ -215,6 +215,7 @@
 	if (options->num_local_forwards >= SSH_MAX_FORWARDS_PER_DIRECTION)
 		fatal("Too many local forwards (max %d).", SSH_MAX_FORWARDS_PER_DIRECTION);
 	fwd = &options->local_forwards[options->num_local_forwards++];
+	fwd->listen_host = listen_host == NULL ? NULL : xstrdup(listen_host);
 	fwd->port = port;
 	fwd->host = xstrdup(host);
 	fwd->host_port = host_port;
@@ -226,14 +227,15 @@
  */
 
 void
-add_remote_forward(Options *options, u_short port, const char *host,
-		   u_short host_port)
+add_remote_forward(Options *options, const char *listen_host, u_short port, 
+		   const char *host, u_short host_port)
 {
 	Forward *fwd;
 	if (options->num_remote_forwards >= SSH_MAX_FORWARDS_PER_DIRECTION)
 		fatal("Too many remote forwards (max %d).",
 		    SSH_MAX_FORWARDS_PER_DIRECTION);
 	fwd = &options->remote_forwards[options->num_remote_forwards++];
+	fwd->listen_host = listen_host == NULL ? NULL : xstrdup(listen_host);
 	fwd->port = port;
 	fwd->host = xstrdup(host);
 	fwd->host_port = host_port;
@@ -281,11 +283,12 @@
 		    char *line, const char *filename, int linenum,
 		    int *activep)
 {
-	char buf[256], *s, **charptr, *endofnumber, *keyword, *arg;
+	char buf[256], buf2[256], *s, **charptr, *endofnumber, *keyword, *arg;
 	int opcode, *intptr, value;
 	size_t len;
 	u_short fwd_port, fwd_host_port;
 	char sfwd_host_port[6];
+	char sfwd_port[6];
 
 	/* Strip trailing whitespace */
 	for(len = strlen(line) - 1; len > 0; len--) {
@@ -645,13 +648,32 @@
 
 	case oLocalForward:
 	case oRemoteForward:
+		buf[0] = '\0';
+
 		arg = strdelim(&s);
 		if (!arg || *arg == '\0')
 			fatal("%.200s line %d: Missing port argument.",
 			    filename, linenum);
-		if ((fwd_port = a2port(arg)) == 0)
-			fatal("%.200s line %d: Bad listen port.",
-			    filename, linenum);
+
+		int slash_count = strcount( arg, '/' );
+		int colon_count = strcount( arg, ':' );
+
+		if( slash_count == 1 || colon_count == 1 )
+		{
+			if (sscanf(arg, "%255[^:]:%5[0-9]", buf2, sfwd_port) != 2 &&
+			    sscanf(arg, "%255[^/]/%5[0-9]", buf2, sfwd_port) != 2)
+				fatal("%.200s line %d: Bad bind_address forwarding specification.",
+				    filename, linenum);
+			if ((fwd_port = a2port(sfwd_port)) == 0)
+				fatal("%.200s line %d: Bad forwarding port.",
+				    filename, linenum);
+		} else
+		{
+			buf2[0] = '\0';
+			if ((fwd_port = a2port(arg)) == 0)
+				fatal("%.200s line %d: Bad listen port.",
+				    filename, linenum);
+		}
 		arg = strdelim(&s);
 		if (!arg || *arg == '\0')
 			fatal("%.200s line %d: Missing second argument.",
@@ -665,10 +687,10 @@
 			    filename, linenum);
 		if (*activep) {
 			if (opcode == oLocalForward)
-				add_local_forward(options, fwd_port, buf,
+				add_local_forward(options, strlen(buf2) > 0 ? buf2 : NULL, fwd_port, buf,
 				    fwd_host_port);
 			else if (opcode == oRemoteForward)
-				add_remote_forward(options, fwd_port, buf,
+				add_remote_forward(options, strlen(buf2) > 0 ? buf2 : NULL, fwd_port, buf,
 				    fwd_host_port);
 		}
 		break;
@@ -683,7 +705,7 @@
 			fatal("%.200s line %d: Badly formatted port number.",
 			    filename, linenum);
 		if (*activep)
-			add_local_forward(options, fwd_port, "socks", 0);
+			add_local_forward(options, NULL, fwd_port, "socks", 0);
 		break;
 
 	case oClearAllForwardings:
diff -u -r openssh-3.8p1/readconf.h openssh-3.8p1-localbind/readconf.h
--- openssh-3.8p1/readconf.h	2004-08-05 08:59:24.776158000 -0700
+++ openssh-3.8p1-localbind/readconf.h	2004-08-05 09:56:20.538884000 -0700
@@ -21,6 +21,7 @@
 /* Data structure for representing a forwarding request. */
 
 typedef struct {
+	char	 *listen_host;	/* Host to forward. */
 	u_short	  port;		/* Port to forward. */
 	char	 *host;		/* Host to connect. */
 	u_short	  host_port;	/* Port to connect on host. */
@@ -113,7 +114,7 @@
 int
 process_config_line(Options *, const char *, char *, const char *, int, int *);
 
-void	 add_local_forward(Options *, u_short, const char *, u_short);
-void	 add_remote_forward(Options *, u_short, const char *, u_short);
+void	 add_local_forward(Options *, const char *, u_short, const char *, u_short);
+void	 add_remote_forward(Options *, const char *, u_short, const char *, u_short);
 
 #endif				/* READCONF_H */
diff -u -r openssh-3.8p1/serverloop.c openssh-3.8p1-localbind/serverloop.c
--- openssh-3.8p1/serverloop.c	2004-01-20 16:02:50.000000000 -0800
+++ openssh-3.8p1-localbind/serverloop.c	2004-08-05 12:27:29.649169672 -0700
@@ -988,7 +988,7 @@
 		} else {
 			/* Start listening on the port */
 			success = channel_setup_remote_fwd_listener(
-			    listen_address, listen_port, options.gateway_ports);
+			    listen_address, listen_port, !strcmp(listen_address,"0.0.0.0")?NULL:listen_address, options.gateway_ports);
 		}
 		xfree(listen_address);
 	}
diff -u -r openssh-3.8p1/ssh.c openssh-3.8p1-localbind/ssh.c
--- openssh-3.8p1/ssh.c	2003-12-16 21:33:11.000000000 -0800
+++ openssh-3.8p1-localbind/ssh.c	2004-08-05 12:58:46.419857160 -0700
@@ -174,8 +174,8 @@
 	fprintf(stderr, "  -c cipher   Select encryption algorithm\n");
 	fprintf(stderr, "  -m macs     Specify MAC algorithms for protocol version 2.\n");
 	fprintf(stderr, "  -p port     Connect to this port.  Server must be on the same port.\n");
-	fprintf(stderr, "  -L listen-port:host:port   Forward local port to remote address\n");
-	fprintf(stderr, "  -R listen-port:host:port   Forward remote port to local address\n");
+	fprintf(stderr, "  -L [listen-host:]listen-port:host:port   Forward local port to remote address\n");
+	fprintf(stderr, "  -R [listen-host:]listen-port:host:port   Forward remote port to local address\n");
 	fprintf(stderr, "              These cause %s to listen for connections on a port, and\n", __progname);
 	fprintf(stderr, "              forward them to the other side by connecting to host:port.\n");
 	fprintf(stderr, "  -D port     Enable dynamic application-level port forwarding.\n");
@@ -202,10 +202,10 @@
 int
 main(int ac, char **av)
 {
-	int i, opt, exit_status;
+	int i, opt, exit_status, localbind = 0;
 	u_short fwd_port, fwd_host_port;
 	char sfwd_port[6], sfwd_host_port[6];
-	char *p, *cp, *line, buf[256];
+	char *p, *cp, *line, buf[256], buf2[256];
 	struct stat st;
 	struct passwd *pw;
 	int dummy;
@@ -418,10 +418,16 @@
 
 		case 'L':
 		case 'R':
+			buf[0] = 0;
 			if (sscanf(optarg, "%5[0123456789]:%255[^:]:%5[0123456789]",
 			    sfwd_port, buf, sfwd_host_port) != 3 &&
 			    sscanf(optarg, "%5[0123456789]/%255[^/]/%5[0123456789]",
-			    sfwd_port, buf, sfwd_host_port) != 3) {
+			    sfwd_port, buf, sfwd_host_port) != 3 &&
+			    (localbind = 1) &&	// Set localbind to TRUE
+			    sscanf(optarg, "%255[^:]:%5[0123456789]:%255[^:]:%5[0123456789]",
+			    buf2, sfwd_port, buf, sfwd_host_port) != 4 &&
+			    sscanf(optarg, "%255[^/]/%5[0123456789]/%255[^/]/%5[0123456789]",
+			    buf2, sfwd_port, buf, sfwd_host_port) != 4) {
 				fprintf(stderr,
 				    "Bad forwarding specification '%s'\n",
 				    optarg);
@@ -435,11 +441,11 @@
 				exit(1);
 			}
 			if (opt == 'L')
-				add_local_forward(&options, fwd_port, buf,
-				    fwd_host_port);
+				add_local_forward(&options, localbind ? buf2 : NULL,
+				    fwd_port, buf, fwd_host_port);
 			else if (opt == 'R')
-				add_remote_forward(&options, fwd_port, buf,
-				    fwd_host_port);
+				add_remote_forward(&options, localbind ? buf2 : NULL,
+				    fwd_port, buf, fwd_host_port);
 			break;
 
 		case 'D':
@@ -449,7 +455,7 @@
 				    optarg);
 				exit(1);
 			}
-			add_local_forward(&options, fwd_port, "socks", 0);
+			add_local_forward(&options, NULL, fwd_port, "socks", 0);
 			break;
 
 		case 'C':
@@ -840,11 +846,13 @@
 
 	/* 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",
+		    options.local_forwards[i].listen_host,
 		    options.local_forwards[i].port,
 		    options.local_forwards[i].host,
 		    options.local_forwards[i].host_port);
 		success += channel_setup_local_fwd_listener(
+		    options.local_forwards[i].listen_host,
 		    options.local_forwards[i].port,
 		    options.local_forwards[i].host,
 		    options.local_forwards[i].host_port,
@@ -855,11 +863,13 @@
 
 	/* Initiate remote TCP/IP port forwardings. */
 	for (i = 0; i < options.num_remote_forwards; i++) {
-		debug("Connections to remote port %d forwarded to local address %.200s:%d",
+		debug("Connections to remote port %.200s:%d forwarded to local address %.200s:%d",
+		    options.remote_forwards[i].listen_host,
 		    options.remote_forwards[i].port,
 		    options.remote_forwards[i].host,
 		    options.remote_forwards[i].host_port);
 		channel_request_remote_forwarding(
+		    options.remote_forwards[i].listen_host,
 		    options.remote_forwards[i].port,
 		    options.remote_forwards[i].host,
 		    options.remote_forwards[i].host_port);


More information about the openssh-unix-dev mailing list