summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog9
-rw-r--r--channels.c167
-rw-r--r--channels.h21
-rw-r--r--clientloop.c21
-rw-r--r--serverloop.c19
5 files changed, 149 insertions, 88 deletions
diff --git a/ChangeLog b/ChangeLog
index bd6b640b1..9e683143a 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -104,6 +104,13 @@
104 client stderr (subject to LogLevel in the mux master) - better than 104 client stderr (subject to LogLevel in the mux master) - better than
105 silently failing. 105 silently failing.
106 most bits ok markus@ (as part of a larger diff) 106 most bits ok markus@ (as part of a larger diff)
107 - djm@cvs.openbsd.org 2008/05/09 04:55:56
108 [channels.c channels.h clientloop.c serverloop.c]
109 Try additional addresses when connecting to a port forward destination
110 whose DNS name resolves to more than one address. The previous behaviour
111 was to try the first address and give up.
112 Reported by stig AT venaas.com in bz#343
113 great feedback and ok markus@
107 114
10820080403 11520080403
109 - (djm) [openbsd-compat/bsd-poll.c] Include stdlib.h to avoid compile- 116 - (djm) [openbsd-compat/bsd-poll.c] Include stdlib.h to avoid compile-
@@ -3964,4 +3971,4 @@
3964 OpenServer 6 and add osr5bigcrypt support so when someone migrates 3971 OpenServer 6 and add osr5bigcrypt support so when someone migrates
3965 passwords between UnixWare and OpenServer they will still work. OK dtucker@ 3972 passwords between UnixWare and OpenServer they will still work. OK dtucker@
3966 3973
3967$Id: ChangeLog,v 1.4924 2008/05/19 05:36:08 djm Exp $ 3974$Id: ChangeLog,v 1.4925 2008/05/19 05:37:09 djm Exp $
diff --git a/channels.c b/channels.c
index b5e28dabf..1e57951dc 100644
--- a/channels.c
+++ b/channels.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: channels.c,v 1.275 2008/05/08 12:02:23 djm Exp $ */ 1/* $OpenBSD: channels.c,v 1.276 2008/05/09 04:55:56 djm Exp $ */
2/* 2/*
3 * Author: Tatu Ylonen <ylo@cs.hut.fi> 3 * Author: Tatu Ylonen <ylo@cs.hut.fi>
4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -165,6 +165,10 @@ static int IPv4or6 = AF_UNSPEC;
165/* helper */ 165/* helper */
166static void port_open_helper(Channel *c, char *rtype); 166static void port_open_helper(Channel *c, char *rtype);
167 167
168/* non-blocking connect helpers */
169static int connect_next(struct channel_connect *);
170static void channel_connect_ctx_free(struct channel_connect *);
171
168/* -- channel core */ 172/* -- channel core */
169 173
170Channel * 174Channel *
@@ -1425,7 +1429,7 @@ channel_post_auth_listener(Channel *c, fd_set *readset, fd_set *writeset)
1425static void 1429static void
1426channel_post_connecting(Channel *c, fd_set *readset, fd_set *writeset) 1430channel_post_connecting(Channel *c, fd_set *readset, fd_set *writeset)
1427{ 1431{
1428 int err = 0; 1432 int err = 0, sock;
1429 socklen_t sz = sizeof(err); 1433 socklen_t sz = sizeof(err);
1430 1434
1431 if (FD_ISSET(c->sock, writeset)) { 1435 if (FD_ISSET(c->sock, writeset)) {
@@ -1434,7 +1438,9 @@ channel_post_connecting(Channel *c, fd_set *readset, fd_set *writeset)
1434 error("getsockopt SO_ERROR failed"); 1438 error("getsockopt SO_ERROR failed");
1435 } 1439 }
1436 if (err == 0) { 1440 if (err == 0) {
1437 debug("channel %d: connected", c->self); 1441 debug("channel %d: connected to %s port %d",
1442 c->self, c->connect_ctx.host, c->connect_ctx.port);
1443 channel_connect_ctx_free(&c->connect_ctx);
1438 c->type = SSH_CHANNEL_OPEN; 1444 c->type = SSH_CHANNEL_OPEN;
1439 if (compat20) { 1445 if (compat20) {
1440 packet_start(SSH2_MSG_CHANNEL_OPEN_CONFIRMATION); 1446 packet_start(SSH2_MSG_CHANNEL_OPEN_CONFIRMATION);
@@ -1448,8 +1454,19 @@ channel_post_connecting(Channel *c, fd_set *readset, fd_set *writeset)
1448 packet_put_int(c->self); 1454 packet_put_int(c->self);
1449 } 1455 }
1450 } else { 1456 } else {
1451 debug("channel %d: not connected: %s", 1457 debug("channel %d: connection failed: %s",
1452 c->self, strerror(err)); 1458 c->self, strerror(err));
1459 /* Try next address, if any */
1460 if ((sock = connect_next(&c->connect_ctx)) > 0) {
1461 close(c->sock);
1462 c->sock = c->rfd = c->wfd = sock;
1463 channel_max_fd = channel_find_maxfd();
1464 return;
1465 }
1466 /* Exhausted all addresses */
1467 error("connect_to %.100s port %d: failed.",
1468 c->connect_ctx.host, c->connect_ctx.port);
1469 channel_connect_ctx_free(&c->connect_ctx);
1453 if (compat20) { 1470 if (compat20) {
1454 packet_start(SSH2_MSG_CHANNEL_OPEN_FAILURE); 1471 packet_start(SSH2_MSG_CHANNEL_OPEN_FAILURE);
1455 packet_put_int(c->remote_id); 1472 packet_put_int(c->remote_id);
@@ -2327,7 +2344,7 @@ channel_input_port_open(int type, u_int32_t seq, void *ctxt)
2327 Channel *c = NULL; 2344 Channel *c = NULL;
2328 u_short host_port; 2345 u_short host_port;
2329 char *host, *originator_string; 2346 char *host, *originator_string;
2330 int remote_id, sock = -1; 2347 int remote_id;
2331 2348
2332 remote_id = packet_get_int(); 2349 remote_id = packet_get_int();
2333 host = packet_get_string(NULL); 2350 host = packet_get_string(NULL);
@@ -2339,20 +2356,16 @@ channel_input_port_open(int type, u_int32_t seq, void *ctxt)
2339 originator_string = xstrdup("unknown (remote did not supply name)"); 2356 originator_string = xstrdup("unknown (remote did not supply name)");
2340 } 2357 }
2341 packet_check_eom(); 2358 packet_check_eom();
2342 sock = channel_connect_to(host, host_port); 2359 c = channel_connect_to(host, host_port,
2343 if (sock != -1) { 2360 "connected socket", originator_string);
2344 c = channel_new("connected socket",
2345 SSH_CHANNEL_CONNECTING, sock, sock, -1, 0, 0, 0,
2346 originator_string, 1);
2347 c->remote_id = remote_id;
2348 }
2349 xfree(originator_string); 2361 xfree(originator_string);
2362 xfree(host);
2350 if (c == NULL) { 2363 if (c == NULL) {
2351 packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE); 2364 packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE);
2352 packet_put_int(remote_id); 2365 packet_put_int(remote_id);
2353 packet_send(); 2366 packet_send();
2354 } 2367 } else
2355 xfree(host); 2368 c->remote_id = remote_id;
2356} 2369}
2357 2370
2358/* ARGSUSED */ 2371/* ARGSUSED */
@@ -2770,35 +2783,26 @@ channel_clear_adm_permitted_opens(void)
2770 num_adm_permitted_opens = 0; 2783 num_adm_permitted_opens = 0;
2771} 2784}
2772 2785
2773/* return socket to remote host, port */ 2786/* Try to start non-blocking connect to next host in cctx list */
2774static int 2787static int
2775connect_to(const char *host, u_short port) 2788connect_next(struct channel_connect *cctx)
2776{ 2789{
2777 struct addrinfo hints, *ai, *aitop; 2790 int sock, saved_errno;
2778 char ntop[NI_MAXHOST], strport[NI_MAXSERV]; 2791 char ntop[NI_MAXHOST], strport[NI_MAXSERV];
2779 int gaierr;
2780 int sock = -1;
2781 2792
2782 memset(&hints, 0, sizeof(hints)); 2793 for (; cctx->ai; cctx->ai = cctx->ai->ai_next) {
2783 hints.ai_family = IPv4or6; 2794 if (cctx->ai->ai_family != AF_INET &&
2784 hints.ai_socktype = SOCK_STREAM; 2795 cctx->ai->ai_family != AF_INET6)
2785 snprintf(strport, sizeof strport, "%d", port);
2786 if ((gaierr = getaddrinfo(host, strport, &hints, &aitop)) != 0) {
2787 error("connect_to %.100s: unknown host (%s)", host,
2788 ssh_gai_strerror(gaierr));
2789 return -1;
2790 }
2791 for (ai = aitop; ai; ai = ai->ai_next) {
2792 if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6)
2793 continue; 2796 continue;
2794 if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop, sizeof(ntop), 2797 if (getnameinfo(cctx->ai->ai_addr, cctx->ai->ai_addrlen,
2795 strport, sizeof(strport), NI_NUMERICHOST|NI_NUMERICSERV) != 0) { 2798 ntop, sizeof(ntop), strport, sizeof(strport),
2796 error("connect_to: getnameinfo failed"); 2799 NI_NUMERICHOST|NI_NUMERICSERV) != 0) {
2800 error("connect_next: getnameinfo failed");
2797 continue; 2801 continue;
2798 } 2802 }
2799 sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); 2803 if ((sock = socket(cctx->ai->ai_family, cctx->ai->ai_socktype,
2800 if (sock < 0) { 2804 cctx->ai->ai_protocol)) == -1) {
2801 if (ai->ai_next == NULL) 2805 if (cctx->ai->ai_next == NULL)
2802 error("socket: %.100s", strerror(errno)); 2806 error("socket: %.100s", strerror(errno));
2803 else 2807 else
2804 verbose("socket: %.100s", strerror(errno)); 2808 verbose("socket: %.100s", strerror(errno));
@@ -2806,45 +2810,94 @@ connect_to(const char *host, u_short port)
2806 } 2810 }
2807 if (set_nonblock(sock) == -1) 2811 if (set_nonblock(sock) == -1)
2808 fatal("%s: set_nonblock(%d)", __func__, sock); 2812 fatal("%s: set_nonblock(%d)", __func__, sock);
2809 if (connect(sock, ai->ai_addr, ai->ai_addrlen) < 0 && 2813 if (connect(sock, cctx->ai->ai_addr,
2810 errno != EINPROGRESS) { 2814 cctx->ai->ai_addrlen) == -1 && errno != EINPROGRESS) {
2811 error("connect_to %.100s port %s: %.100s", ntop, strport, 2815 debug("connect_next: host %.100s ([%.100s]:%s): "
2816 "%.100s", cctx->host, ntop, strport,
2812 strerror(errno)); 2817 strerror(errno));
2818 saved_errno = errno;
2813 close(sock); 2819 close(sock);
2820 errno = saved_errno;
2814 continue; /* fail -- try next */ 2821 continue; /* fail -- try next */
2815 } 2822 }
2816 break; /* success */ 2823 debug("connect_next: host %.100s ([%.100s]:%s) "
2824 "in progress, fd=%d", cctx->host, ntop, strport, sock);
2825 cctx->ai = cctx->ai->ai_next;
2826 set_nodelay(sock);
2827 return sock;
2828 }
2829 return -1;
2830}
2831
2832static void
2833channel_connect_ctx_free(struct channel_connect *cctx)
2834{
2835 xfree(cctx->host);
2836 if (cctx->aitop)
2837 freeaddrinfo(cctx->aitop);
2838 bzero(cctx, sizeof(*cctx));
2839 cctx->host = NULL;
2840 cctx->ai = cctx->aitop = NULL;
2841}
2817 2842
2843/* Return CONNECTING channel to remote host, port */
2844static Channel *
2845connect_to(const char *host, u_short port, char *ctype, char *rname)
2846{
2847 struct addrinfo hints;
2848 int gaierr;
2849 int sock = -1;
2850 char strport[NI_MAXSERV];
2851 struct channel_connect cctx;
2852 Channel *c;
2853
2854 memset(&hints, 0, sizeof(hints));
2855 hints.ai_family = IPv4or6;
2856 hints.ai_socktype = SOCK_STREAM;
2857 snprintf(strport, sizeof strport, "%d", port);
2858 if ((gaierr = getaddrinfo(host, strport, &hints, &cctx.aitop)) != 0) {
2859 error("connect_to %.100s: unknown host (%s)", host,
2860 ssh_gai_strerror(gaierr));
2861 return NULL;
2818 } 2862 }
2819 freeaddrinfo(aitop); 2863
2820 if (!ai) { 2864 cctx.host = xstrdup(host);
2821 error("connect_to %.100s port %d: failed.", host, port); 2865 cctx.port = port;
2822 return -1; 2866 cctx.ai = cctx.aitop;
2867
2868 if ((sock = connect_next(&cctx)) == -1) {
2869 error("connect to %.100s port %d failed: %s",
2870 host, port, strerror(errno));
2871 channel_connect_ctx_free(&cctx);
2872 return NULL;
2823 } 2873 }
2824 /* success */ 2874 c = channel_new(ctype, SSH_CHANNEL_CONNECTING, sock, sock, -1,
2825 set_nodelay(sock); 2875 CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 0, rname, 1);
2826 return sock; 2876 c->connect_ctx = cctx;
2877 return c;
2827} 2878}
2828 2879
2829int 2880Channel *
2830channel_connect_by_listen_address(u_short listen_port) 2881channel_connect_by_listen_address(u_short listen_port, char *ctype, char *rname)
2831{ 2882{
2832 int i; 2883 int i;
2833 2884
2834 for (i = 0; i < num_permitted_opens; i++) 2885 for (i = 0; i < num_permitted_opens; i++) {
2835 if (permitted_opens[i].host_to_connect != NULL && 2886 if (permitted_opens[i].host_to_connect != NULL &&
2836 permitted_opens[i].listen_port == listen_port) 2887 permitted_opens[i].listen_port == listen_port) {
2837 return connect_to( 2888 return connect_to(
2838 permitted_opens[i].host_to_connect, 2889 permitted_opens[i].host_to_connect,
2839 permitted_opens[i].port_to_connect); 2890 permitted_opens[i].port_to_connect, ctype, rname);
2891 }
2892 }
2840 error("WARNING: Server requests forwarding for unknown listen_port %d", 2893 error("WARNING: Server requests forwarding for unknown listen_port %d",
2841 listen_port); 2894 listen_port);
2842 return -1; 2895 return NULL;
2843} 2896}
2844 2897
2845/* Check if connecting to that port is permitted and connect. */ 2898/* Check if connecting to that port is permitted and connect. */
2846int 2899Channel *
2847channel_connect_to(const char *host, u_short port) 2900channel_connect_to(const char *host, u_short port, char *ctype, char *rname)
2848{ 2901{
2849 int i, permit, permit_adm = 1; 2902 int i, permit, permit_adm = 1;
2850 2903
@@ -2870,9 +2923,9 @@ channel_connect_to(const char *host, u_short port)
2870 if (!permit || !permit_adm) { 2923 if (!permit || !permit_adm) {
2871 logit("Received request to connect to host %.100s port %d, " 2924 logit("Received request to connect to host %.100s port %d, "
2872 "but the request was denied.", host, port); 2925 "but the request was denied.", host, port);
2873 return -1; 2926 return NULL;
2874 } 2927 }
2875 return connect_to(host, port); 2928 return connect_to(host, port, ctype, rname);
2876} 2929}
2877 2930
2878void 2931void
diff --git a/channels.h b/channels.h
index 46cde0309..d4ac24a51 100644
--- a/channels.h
+++ b/channels.h
@@ -1,4 +1,4 @@
1/* $OpenBSD: channels.h,v 1.90 2008/05/08 12:02:23 djm Exp $ */ 1/* $OpenBSD: channels.h,v 1.91 2008/05/09 04:55:56 djm Exp $ */
2 2
3/* 3/*
4 * Author: Tatu Ylonen <ylo@cs.hut.fi> 4 * Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -75,6 +75,13 @@ struct channel_confirm {
75}; 75};
76TAILQ_HEAD(channel_confirms, channel_confirm); 76TAILQ_HEAD(channel_confirms, channel_confirm);
77 77
78/* Context for non-blocking connects */
79struct channel_connect {
80 char *host;
81 int port;
82 struct addrinfo *ai, *aitop;
83};
84
78struct Channel { 85struct Channel {
79 int type; /* channel type/state */ 86 int type; /* channel type/state */
80 int self; /* my own channel identifier */ 87 int self; /* my own channel identifier */
@@ -125,7 +132,11 @@ struct Channel {
125 channel_infilter_fn *input_filter; 132 channel_infilter_fn *input_filter;
126 channel_outfilter_fn *output_filter; 133 channel_outfilter_fn *output_filter;
127 134
128 int datagram; /* keep boundaries */ 135 /* keep boundaries */
136 int datagram;
137
138 /* non-blocking connect */
139 struct channel_connect connect_ctx;
129}; 140};
130 141
131#define CHAN_EXTENDED_IGNORE 0 142#define CHAN_EXTENDED_IGNORE 0
@@ -225,8 +236,8 @@ int channel_add_adm_permitted_opens(char *, int);
225void channel_clear_permitted_opens(void); 236void channel_clear_permitted_opens(void);
226void channel_clear_adm_permitted_opens(void); 237void channel_clear_adm_permitted_opens(void);
227int channel_input_port_forward_request(int, int); 238int channel_input_port_forward_request(int, int);
228int channel_connect_to(const char *, u_short); 239Channel *channel_connect_to(const char *, u_short, char *, char *);
229int channel_connect_by_listen_address(u_short); 240Channel *channel_connect_by_listen_address(u_short, char *, char *);
230int channel_request_remote_forwarding(const char *, u_short, 241int channel_request_remote_forwarding(const char *, u_short,
231 const char *, u_short); 242 const char *, u_short);
232int channel_setup_local_fwd_listener(const char *, u_short, 243int channel_setup_local_fwd_listener(const char *, u_short,
@@ -241,7 +252,7 @@ int x11_connect_display(void);
241int x11_create_display_inet(int, int, int, u_int *, int **); 252int x11_create_display_inet(int, int, int, u_int *, int **);
242void x11_input_open(int, u_int32_t, void *); 253void x11_input_open(int, u_int32_t, void *);
243void x11_request_forwarding_with_spoofing(int, const char *, const char *, 254void x11_request_forwarding_with_spoofing(int, const char *, const char *,
244 const char *); 255 const char *);
245void deny_input_open(int, u_int32_t, void *); 256void deny_input_open(int, u_int32_t, void *);
246 257
247/* agent forwarding */ 258/* agent forwarding */
diff --git a/clientloop.c b/clientloop.c
index c40f2c303..7bd1af60c 100644
--- a/clientloop.c
+++ b/clientloop.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: clientloop.c,v 1.190 2008/05/08 13:06:10 djm Exp $ */ 1/* $OpenBSD: clientloop.c,v 1.191 2008/05/09 04:55:56 djm Exp $ */
2/* 2/*
3 * Author: Tatu Ylonen <ylo@cs.hut.fi> 3 * Author: Tatu Ylonen <ylo@cs.hut.fi>
4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -1762,7 +1762,6 @@ client_request_forwarded_tcpip(const char *request_type, int rchan)
1762 Channel *c = NULL; 1762 Channel *c = NULL;
1763 char *listen_address, *originator_address; 1763 char *listen_address, *originator_address;
1764 int listen_port, originator_port; 1764 int listen_port, originator_port;
1765 int sock;
1766 1765
1767 /* Get rest of the packet */ 1766 /* Get rest of the packet */
1768 listen_address = packet_get_string(NULL); 1767 listen_address = packet_get_string(NULL);
@@ -1771,19 +1770,13 @@ client_request_forwarded_tcpip(const char *request_type, int rchan)
1771 originator_port = packet_get_int(); 1770 originator_port = packet_get_int();
1772 packet_check_eom(); 1771 packet_check_eom();
1773 1772
1774 debug("client_request_forwarded_tcpip: listen %s port %d, originator %s port %d", 1773 debug("client_request_forwarded_tcpip: listen %s port %d, "
1775 listen_address, listen_port, originator_address, originator_port); 1774 "originator %s port %d", listen_address, listen_port,
1775 originator_address, originator_port);
1776
1777 c = channel_connect_by_listen_address(listen_port,
1778 "forwarded-tcpip", originator_address);
1776 1779
1777 sock = channel_connect_by_listen_address(listen_port);
1778 if (sock < 0) {
1779 xfree(originator_address);
1780 xfree(listen_address);
1781 return NULL;
1782 }
1783 c = channel_new("forwarded-tcpip",
1784 SSH_CHANNEL_CONNECTING, sock, sock, -1,
1785 CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 0,
1786 originator_address, 1);
1787 xfree(originator_address); 1780 xfree(originator_address);
1788 xfree(listen_address); 1781 xfree(listen_address);
1789 return c; 1782 return c;
diff --git a/serverloop.c b/serverloop.c
index 20991c3ce..2142f3809 100644
--- a/serverloop.c
+++ b/serverloop.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: serverloop.c,v 1.149 2008/05/08 12:02:23 djm Exp $ */ 1/* $OpenBSD: serverloop.c,v 1.150 2008/05/09 04:55:56 djm Exp $ */
2/* 2/*
3 * Author: Tatu Ylonen <ylo@cs.hut.fi> 3 * Author: Tatu Ylonen <ylo@cs.hut.fi>
4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -938,7 +938,6 @@ static Channel *
938server_request_direct_tcpip(void) 938server_request_direct_tcpip(void)
939{ 939{
940 Channel *c; 940 Channel *c;
941 int sock;
942 char *target, *originator; 941 char *target, *originator;
943 int target_port, originator_port; 942 int target_port, originator_port;
944 943
@@ -948,18 +947,16 @@ server_request_direct_tcpip(void)
948 originator_port = packet_get_int(); 947 originator_port = packet_get_int();
949 packet_check_eom(); 948 packet_check_eom();
950 949
951 debug("server_request_direct_tcpip: originator %s port %d, target %s port %d", 950 debug("server_request_direct_tcpip: originator %s port %d, target %s "
952 originator, originator_port, target, target_port); 951 "port %d", originator, originator_port, target, target_port);
953 952
954 /* XXX check permission */ 953 /* XXX check permission */
955 sock = channel_connect_to(target, target_port); 954 c = channel_connect_to(target, target_port,
956 xfree(target); 955 "direct-tcpip", "direct-tcpip");
956
957 xfree(originator); 957 xfree(originator);
958 if (sock < 0) 958 xfree(target);
959 return NULL; 959
960 c = channel_new("direct-tcpip", SSH_CHANNEL_CONNECTING,
961 sock, sock, -1, CHAN_TCP_WINDOW_DEFAULT,
962 CHAN_TCP_PACKET_DEFAULT, 0, "direct-tcpip", 1);
963 return c; 960 return c;
964} 961}
965 962