summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDamien Miller <djm@cvs.openbsd.org>2009-02-12 03:00:57 +0000
committerDamien Miller <djm@cvs.openbsd.org>2009-02-12 03:00:57 +0000
commitb408bf990ab866324abffed8e86f5c4aebb6a2ea (patch)
tree483da191cd7e6ea927350e8fe96b55bddb347e6a
parent922a2c5cb32a2e9e2113325186745a11e2d6fb89 (diff)
support remote port forwarding with a zero listen port (-R0:...) to
dyamically allocate a listen port at runtime (this is actually specified in rfc4254); bz#1003 ok markus@
-rw-r--r--usr.bin/ssh/canohost.c4
-rw-r--r--usr.bin/ssh/canohost.h4
-rw-r--r--usr.bin/ssh/channels.c52
-rw-r--r--usr.bin/ssh/channels.h4
-rw-r--r--usr.bin/ssh/clientloop.c4
-rw-r--r--usr.bin/ssh/readconf.c13
-rw-r--r--usr.bin/ssh/readconf.h4
-rw-r--r--usr.bin/ssh/serverloop.c12
-rw-r--r--usr.bin/ssh/ssh.c15
9 files changed, 83 insertions, 29 deletions
diff --git a/usr.bin/ssh/canohost.c b/usr.bin/ssh/canohost.c
index 1d4696ddb24..0b37e7a5db1 100644
--- a/usr.bin/ssh/canohost.c
+++ b/usr.bin/ssh/canohost.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: canohost.c,v 1.63 2008/06/12 00:03:49 dtucker Exp $ */
+/* $OpenBSD: canohost.c,v 1.64 2009/02/12 03:00:56 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -300,7 +300,7 @@ get_remote_name_or_ip(u_int utmp_len, int use_dns)
/* Returns the local/remote port for the socket. */
-static int
+int
get_sock_port(int sock, int local)
{
struct sockaddr_storage from;
diff --git a/usr.bin/ssh/canohost.h b/usr.bin/ssh/canohost.h
index acc77c00e34..cdd7b46826c 100644
--- a/usr.bin/ssh/canohost.h
+++ b/usr.bin/ssh/canohost.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: canohost.h,v 1.9 2006/03/25 22:22:42 djm Exp $ */
+/* $OpenBSD: canohost.h,v 1.10 2009/02/12 03:00:56 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -23,3 +23,5 @@ char *get_local_name(int);
int get_remote_port(void);
int get_local_port(void);
+int get_sock_port(int, int);
+
diff --git a/usr.bin/ssh/channels.c b/usr.bin/ssh/channels.c
index 1791f478c8b..b1dc7b9fde5 100644
--- a/usr.bin/ssh/channels.c
+++ b/usr.bin/ssh/channels.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: channels.c,v 1.294 2009/01/22 09:49:57 djm Exp $ */
+/* $OpenBSD: channels.c,v 1.295 2009/02/12 03:00:56 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -2438,7 +2438,8 @@ channel_set_af(int af)
}
static int
-channel_setup_fwd_listener(int type, const char *listen_addr, u_short listen_port,
+channel_setup_fwd_listener(int type, const char *listen_addr,
+ u_short listen_port, int *allocated_listen_port,
const char *host_to_connect, u_short port_to_connect, int gateway_ports)
{
Channel *c;
@@ -2446,6 +2447,7 @@ channel_setup_fwd_listener(int type, const char *listen_addr, u_short listen_por
struct addrinfo hints, *ai, *aitop;
const char *host, *addr;
char ntop[NI_MAXHOST], strport[NI_MAXSERV];
+ in_port_t *lport_p;
host = (type == SSH_CHANNEL_RPORT_LISTENER) ?
listen_addr : host_to_connect;
@@ -2514,10 +2516,29 @@ channel_setup_fwd_listener(int type, const char *listen_addr, u_short listen_por
}
return 0;
}
-
+ if (allocated_listen_port != NULL)
+ *allocated_listen_port = 0;
for (ai = aitop; ai; ai = ai->ai_next) {
- if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6)
+ switch (ai->ai_family) {
+ case AF_INET:
+ lport_p = &((struct sockaddr_in *)ai->ai_addr)->
+ sin_port;
+ break;
+ case AF_INET6:
+ lport_p = &((struct sockaddr_in6 *)ai->ai_addr)->
+ sin6_port;
+ break;
+ default:
continue;
+ }
+ /*
+ * If allocating a port for -R forwards, then use the
+ * same port for all address families.
+ */
+ if (type == SSH_CHANNEL_RPORT_LISTENER && listen_port == 0 &&
+ allocated_listen_port != NULL && *allocated_listen_port > 0)
+ *lport_p = htons(*allocated_listen_port);
+
if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop, sizeof(ntop),
strport, sizeof(strport), NI_NUMERICHOST|NI_NUMERICSERV) != 0) {
error("channel_setup_fwd_listener: getnameinfo failed");
@@ -2533,7 +2554,8 @@ channel_setup_fwd_listener(int type, const char *listen_addr, u_short listen_por
channel_set_reuseaddr(sock);
- debug("Local forwarding listening on %s port %s.", ntop, strport);
+ debug("Local forwarding listening on %s port %s.",
+ ntop, strport);
/* Bind the socket to the address. */
if (bind(sock, ai->ai_addr, ai->ai_addrlen) < 0) {
@@ -2548,6 +2570,19 @@ channel_setup_fwd_listener(int type, const char *listen_addr, u_short listen_por
close(sock);
continue;
}
+
+ /*
+ * listen_port == 0 requests a dynamically allocated port -
+ * record what we got.
+ */
+ if (type == SSH_CHANNEL_RPORT_LISTENER && listen_port == 0 &&
+ allocated_listen_port != NULL &&
+ *allocated_listen_port == 0) {
+ *allocated_listen_port = get_sock_port(sock, 1);
+ debug("Allocated listen port %d",
+ *allocated_listen_port);
+ }
+
/* Allocate a channel number for the socket. */
c = channel_new("port listener", type, sock, sock, -1,
CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT,
@@ -2590,17 +2625,18 @@ 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,
- listen_host, listen_port, host_to_connect, port_to_connect,
+ listen_host, listen_port, NULL, 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, int *allocated_listen_port, int gateway_ports)
{
return channel_setup_fwd_listener(SSH_CHANNEL_RPORT_LISTENER,
- listen_address, listen_port, NULL, 0, gateway_ports);
+ listen_address, listen_port, allocated_listen_port,
+ NULL, 0, gateway_ports);
}
/*
diff --git a/usr.bin/ssh/channels.h b/usr.bin/ssh/channels.h
index 185b477b014..10b0c075a94 100644
--- a/usr.bin/ssh/channels.h
+++ b/usr.bin/ssh/channels.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: channels.h,v 1.97 2009/01/22 09:46:01 djm Exp $ */
+/* $OpenBSD: channels.h,v 1.98 2009/02/12 03:00:56 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -244,7 +244,7 @@ int channel_request_remote_forwarding(const char *, u_short,
int channel_setup_local_fwd_listener(const char *, u_short,
const char *, u_short, int);
void channel_request_rforward_cancel(const char *host, u_short port);
-int channel_setup_remote_fwd_listener(const char *, u_short, int);
+int channel_setup_remote_fwd_listener(const char *, u_short, int *, int);
int channel_cancel_rport_listener(const char *, u_short);
/* x11 forwarding */
diff --git a/usr.bin/ssh/clientloop.c b/usr.bin/ssh/clientloop.c
index eeaba5274f5..23b2dea58bb 100644
--- a/usr.bin/ssh/clientloop.c
+++ b/usr.bin/ssh/clientloop.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: clientloop.c,v 1.208 2009/01/22 10:02:34 djm Exp $ */
+/* $OpenBSD: clientloop.c,v 1.209 2009/02/12 03:00:56 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -840,7 +840,7 @@ process_cmdline(void)
}
channel_request_rforward_cancel(cancel_host, cancel_port);
} else {
- if (!parse_forward(&fwd, s, dynamic ? 1 : 0)) {
+ if (!parse_forward(&fwd, s, dynamic, remote)) {
logit("Bad forwarding specification.");
goto out;
}
diff --git a/usr.bin/ssh/readconf.c b/usr.bin/ssh/readconf.c
index 963709e729f..9aee3ecc6c8 100644
--- a/usr.bin/ssh/readconf.c
+++ b/usr.bin/ssh/readconf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: readconf.c,v 1.175 2009/01/22 10:02:34 djm Exp $ */
+/* $OpenBSD: readconf.c,v 1.176 2009/02/12 03:00:56 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -730,7 +730,8 @@ parse_int:
}
if (parse_forward(&fwd, fwdarg,
- opcode == oDynamicForward ? 1 : 0) == 0)
+ opcode == oDynamicForward ? 1 : 0,
+ opcode == oRemoteForward ? 1 : 0) == 0)
fatal("%.200s line %d: Bad forwarding specification.",
filename, linenum);
@@ -1215,7 +1216,7 @@ fill_default_options(Options * options)
* returns number of arguments parsed or zero on error
*/
int
-parse_forward(Forward *fwd, const char *fwdspec, int dynamicfwd)
+parse_forward(Forward *fwd, const char *fwdspec, int dynamicfwd, int remotefwd)
{
int i;
char *p, *cp, *fwdarg[4];
@@ -1278,12 +1279,16 @@ parse_forward(Forward *fwd, const char *fwdspec, int dynamicfwd)
goto fail_free;
}
- if (fwd->listen_port <= 0)
+ if (fwd->listen_port < 0 || (!remotefwd && fwd->listen_port == 0))
goto fail_free;
if (fwd->connect_host != NULL &&
strlen(fwd->connect_host) >= NI_MAXHOST)
goto fail_free;
+ if (fwd->listen_host != NULL &&
+ strlen(fwd->listen_host) >= NI_MAXHOST)
+ goto fail_free;
+
return (i);
diff --git a/usr.bin/ssh/readconf.h b/usr.bin/ssh/readconf.h
index d94d65890d2..8fb3a852816 100644
--- a/usr.bin/ssh/readconf.h
+++ b/usr.bin/ssh/readconf.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: readconf.h,v 1.77 2009/01/22 10:02:34 djm Exp $ */
+/* $OpenBSD: readconf.h,v 1.78 2009/02/12 03:00:56 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -134,7 +134,7 @@ typedef struct {
void initialize_options(Options *);
void fill_default_options(Options *);
int read_config_file(const char *, const char *, Options *, int);
-int parse_forward(Forward *, const char *, int);
+int parse_forward(Forward *, const char *, int, int);
int
process_config_line(Options *, const char *, char *, const char *, int, int *);
diff --git a/usr.bin/ssh/serverloop.c b/usr.bin/ssh/serverloop.c
index 86ee4ae31d4..999e5be8a49 100644
--- a/usr.bin/ssh/serverloop.c
+++ b/usr.bin/ssh/serverloop.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: serverloop.c,v 1.155 2009/01/22 10:02:34 djm Exp $ */
+/* $OpenBSD: serverloop.c,v 1.156 2009/02/12 03:00:56 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -1058,7 +1058,7 @@ server_input_global_request(int type, u_int32_t seq, void *ctxt)
{
char *rtype;
int want_reply;
- int success = 0;
+ int success = 0, allocated_listen_port = 0;
rtype = packet_get_string(NULL);
want_reply = packet_get_char();
@@ -1081,13 +1081,15 @@ server_input_global_request(int type, u_int32_t seq, void *ctxt)
/* check permissions */
if (!options.allow_tcp_forwarding ||
no_port_forwarding_flag ||
- (listen_port < IPPORT_RESERVED && pw->pw_uid != 0)) {
+ (listen_port != 0 && listen_port < IPPORT_RESERVED &&
+ pw->pw_uid != 0)) {
success = 0;
packet_send_debug("Server has disabled port forwarding.");
} else {
/* Start listening on the port */
success = channel_setup_remote_fwd_listener(
- listen_address, listen_port, options.gateway_ports);
+ listen_address, listen_port,
+ &allocated_listen_port, options.gateway_ports);
}
xfree(listen_address);
} else if (strcmp(rtype, "cancel-tcpip-forward") == 0) {
@@ -1109,6 +1111,8 @@ server_input_global_request(int type, u_int32_t seq, void *ctxt)
if (want_reply) {
packet_start(success ?
SSH2_MSG_REQUEST_SUCCESS : SSH2_MSG_REQUEST_FAILURE);
+ if (success && allocated_listen_port > 0)
+ packet_put_int(allocated_listen_port);
packet_send();
packet_write_wait();
}
diff --git a/usr.bin/ssh/ssh.c b/usr.bin/ssh/ssh.c
index 912ff5e54dd..49cdfed145a 100644
--- a/usr.bin/ssh/ssh.c
+++ b/usr.bin/ssh/ssh.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssh.c,v 1.323 2009/01/22 10:02:34 djm Exp $ */
+/* $OpenBSD: ssh.c,v 1.324 2009/02/12 03:00:56 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -440,7 +440,7 @@ main(int ac, char **av)
break;
case 'L':
- if (parse_forward(&fwd, optarg, 0))
+ if (parse_forward(&fwd, optarg, 0, 0))
add_local_forward(&options, &fwd);
else {
fprintf(stderr,
@@ -451,7 +451,7 @@ main(int ac, char **av)
break;
case 'R':
- if (parse_forward(&fwd, optarg, 0)) {
+ if (parse_forward(&fwd, optarg, 0, 1)) {
add_remote_forward(&options, &fwd);
} else {
fprintf(stderr,
@@ -462,7 +462,7 @@ main(int ac, char **av)
break;
case 'D':
- if (parse_forward(&fwd, optarg, 1)) {
+ if (parse_forward(&fwd, optarg, 1, 0)) {
add_local_forward(&options, &fwd);
} else {
fprintf(stderr,
@@ -818,9 +818,16 @@ ssh_confirm_remote_forward(int type, u_int32_t seq, void *ctxt)
{
Forward *rfwd = (Forward *)ctxt;
+ /* XXX verbose() on failure? */
debug("remote forward %s for: listen %d, connect %s:%d",
type == SSH2_MSG_REQUEST_SUCCESS ? "success" : "failure",
rfwd->listen_port, rfwd->connect_host, rfwd->connect_port);
+ if (type == SSH2_MSG_REQUEST_SUCCESS && rfwd->listen_port == 0) {
+ logit("Allocated port %u for remote forward to %s:%d",
+ packet_get_int(),
+ rfwd->connect_host, rfwd->connect_port);
+ }
+
if (type == SSH2_MSG_REQUEST_FAILURE) {
if (options.exit_on_forward_failure)
fatal("Error: remote port forwarding failed for "