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);