From 17525a708a3f00074f1423aa8d11b661a90e7778 Mon Sep 17 00:00:00 2001 From: djm Date: Sat, 14 Feb 2009 05:28:21 +0000 Subject: [PATCH] - djm@cvs.openbsd.org 2009/02/12 03:00:56 [canohost.c canohost.h channels.c channels.h clientloop.c readconf.c] [readconf.h serverloop.c ssh.c] 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@ --- ChangeLog | 6 ++++++ canohost.c | 4 ++-- canohost.h | 4 +++- channels.c | 52 ++++++++++++++++++++++++++++++++++++++++++++-------- channels.h | 4 ++-- clientloop.c | 4 ++-- readconf.c | 13 +++++++++---- readconf.h | 4 ++-- serverloop.c | 9 ++++++--- ssh.c | 15 +++++++++++---- 10 files changed, 87 insertions(+), 28 deletions(-) diff --git a/ChangeLog b/ChangeLog index daa8194f..b1b5c644 100644 --- a/ChangeLog +++ b/ChangeLog @@ -4,6 +4,12 @@ [sftp.c] Initialize a few variables to prevent spurious "may be used uninitialized" warnings from newer gcc's. ok djm@ + - djm@cvs.openbsd.org 2009/02/12 03:00:56 + [canohost.c canohost.h channels.c channels.h clientloop.c readconf.c] + [readconf.h serverloop.c ssh.c] + 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@ 20090212 - (djm) [sshpty.c] bz#1419: OSX uses cloning ptys that automagically diff --git a/canohost.c b/canohost.c index 42011fd0..7138f48d 100644 --- a/canohost.c +++ b/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 * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -342,7 +342,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/canohost.h b/canohost.h index e33e8941..d9b41ffe 100644 --- a/canohost.h +++ b/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 @@ -23,5 +23,7 @@ char *get_local_name(int); int get_remote_port(void); int get_local_port(void); +int get_sock_port(int, int); + void ipv64_normalise_mapped(struct sockaddr_storage *, socklen_t *); diff --git a/channels.c b/channels.c index 0b1c34c8..dea60ba2 100644 --- a/channels.c +++ b/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 * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -2460,7 +2460,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; @@ -2468,6 +2469,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; @@ -2536,10 +2538,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"); @@ -2555,7 +2576,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) { @@ -2574,6 +2596,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, @@ -2616,17 +2651,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/channels.h b/channels.h index 19fee769..1488ed7e 100644 --- a/channels.h +++ b/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 @@ -245,7 +245,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/clientloop.c b/clientloop.c index 1b5badb7..a2d2d1d0 100644 --- a/clientloop.c +++ b/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 * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -849,7 +849,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/readconf.c b/readconf.c index 0a8be140..53fc6c7b 100644 --- a/readconf.c +++ b/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 * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -735,7 +735,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); @@ -1220,7 +1221,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]; @@ -1283,12 +1284,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/readconf.h b/readconf.h index d94d6589..8fb3a852 100644 --- a/readconf.h +++ b/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 @@ -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/serverloop.c b/serverloop.c index 931779e3..6244ad71 100644 --- a/serverloop.c +++ b/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 * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -1095,7 +1095,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(); @@ -1119,7 +1119,8 @@ server_input_global_request(int type, u_int32_t seq, void *ctxt) if (!options.allow_tcp_forwarding || no_port_forwarding_flag #ifndef NO_IPPORT_RESERVED_CONCEPT - || (listen_port < IPPORT_RESERVED && pw->pw_uid != 0) + || (listen_port != 0 && + listen_port < IPPORT_RESERVED && pw->pw_uid != 0) #endif ) { success = 0; @@ -1149,6 +1150,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/ssh.c b/ssh.c index 26f070f3..9d43bb74 100644 --- a/ssh.c +++ b/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 * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -453,7 +453,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, @@ -464,7 +464,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, @@ -475,7 +475,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, @@ -837,9 +837,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 " -- 2.45.1