|
Lines 161-166
static int IPv4or6 = AF_UNSPEC;
Link Here
|
| 161 |
/* helper */ |
161 |
/* helper */ |
| 162 |
static void port_open_helper(Channel *c, char *rtype); |
162 |
static void port_open_helper(Channel *c, char *rtype); |
| 163 |
|
163 |
|
|
|
164 |
static int connect_next(struct addrinfo **, const char *, int); |
| 165 |
|
| 164 |
/* -- channel core */ |
166 |
/* -- channel core */ |
| 165 |
|
167 |
|
| 166 |
Channel * |
168 |
Channel * |
|
Lines 1420-1426
channel_post_auth_listener(Channel *c, f
Link Here
|
| 1420 |
static void |
1422 |
static void |
| 1421 |
channel_post_connecting(Channel *c, fd_set *readset, fd_set *writeset) |
1423 |
channel_post_connecting(Channel *c, fd_set *readset, fd_set *writeset) |
| 1422 |
{ |
1424 |
{ |
| 1423 |
int err = 0; |
1425 |
int err = 0, sock; |
| 1424 |
socklen_t sz = sizeof(err); |
1426 |
socklen_t sz = sizeof(err); |
| 1425 |
|
1427 |
|
| 1426 |
if (FD_ISSET(c->sock, writeset)) { |
1428 |
if (FD_ISSET(c->sock, writeset)) { |
|
Lines 1429-1435
channel_post_connecting(Channel *c, fd_s
Link Here
|
| 1429 |
error("getsockopt SO_ERROR failed"); |
1431 |
error("getsockopt SO_ERROR failed"); |
| 1430 |
} |
1432 |
} |
| 1431 |
if (err == 0) { |
1433 |
if (err == 0) { |
| 1432 |
debug("channel %d: connected", c->self); |
1434 |
debug("channel %d: connected to %s port %d", |
|
|
1435 |
c->self, c->connect_ctx.host, c->connect_ctx.port); |
| 1436 |
xfree(c->connect_ctx.host); |
| 1437 |
c->connect_ctx.host = NULL; |
| 1438 |
freeaddrinfo(c->connect_ctx.aitop); |
| 1439 |
c->connect_ctx.ai = c->connect_ctx.aitop = NULL; |
| 1433 |
c->type = SSH_CHANNEL_OPEN; |
1440 |
c->type = SSH_CHANNEL_OPEN; |
| 1434 |
if (compat20) { |
1441 |
if (compat20) { |
| 1435 |
packet_start(SSH2_MSG_CHANNEL_OPEN_CONFIRMATION); |
1442 |
packet_start(SSH2_MSG_CHANNEL_OPEN_CONFIRMATION); |
|
Lines 1443-1450
channel_post_connecting(Channel *c, fd_s
Link Here
|
| 1443 |
packet_put_int(c->self); |
1450 |
packet_put_int(c->self); |
| 1444 |
} |
1451 |
} |
| 1445 |
} else { |
1452 |
} else { |
| 1446 |
debug("channel %d: not connected: %s", |
1453 |
debug("channel %d: connection failed: %s", |
| 1447 |
c->self, strerror(err)); |
1454 |
c->self, strerror(err)); |
|
|
1455 |
/* Try next address, if any */ |
| 1456 |
if ((sock = connect_next(&c->connect_ctx.ai, |
| 1457 |
c->connect_ctx.host, c->connect_ctx.port)) > 0) { |
| 1458 |
close(c->sock); |
| 1459 |
c->sock = c->rfd = c->wfd = sock; |
| 1460 |
channel_max_fd = channel_find_maxfd(); |
| 1461 |
return; |
| 1462 |
} |
| 1463 |
/* Exhausted all addresses */ |
| 1464 |
error("connect_to %.100s port %d: failed.", |
| 1465 |
c->connect_ctx.host, c->connect_ctx.port); |
| 1466 |
xfree(c->connect_ctx.host); |
| 1467 |
c->connect_ctx.host = NULL; |
| 1468 |
freeaddrinfo(c->connect_ctx.aitop); |
| 1469 |
c->connect_ctx.ai = c->connect_ctx.aitop = NULL; |
| 1448 |
if (compat20) { |
1470 |
if (compat20) { |
| 1449 |
packet_start(SSH2_MSG_CHANNEL_OPEN_FAILURE); |
1471 |
packet_start(SSH2_MSG_CHANNEL_OPEN_FAILURE); |
| 1450 |
packet_put_int(c->remote_id); |
1472 |
packet_put_int(c->remote_id); |
|
Lines 2311-2316
channel_input_port_open(int type, u_int3
Link Here
|
| 2311 |
u_short host_port; |
2333 |
u_short host_port; |
| 2312 |
char *host, *originator_string; |
2334 |
char *host, *originator_string; |
| 2313 |
int remote_id, sock = -1; |
2335 |
int remote_id, sock = -1; |
|
|
2336 |
struct addrinfo *ai, *aitop; |
| 2314 |
|
2337 |
|
| 2315 |
remote_id = packet_get_int(); |
2338 |
remote_id = packet_get_int(); |
| 2316 |
host = packet_get_string(NULL); |
2339 |
host = packet_get_string(NULL); |
|
Lines 2322-2333
channel_input_port_open(int type, u_int3
Link Here
|
| 2322 |
originator_string = xstrdup("unknown (remote did not supply name)"); |
2345 |
originator_string = xstrdup("unknown (remote did not supply name)"); |
| 2323 |
} |
2346 |
} |
| 2324 |
packet_check_eom(); |
2347 |
packet_check_eom(); |
| 2325 |
sock = channel_connect_to(host, host_port); |
2348 |
sock = channel_connect_to(host, host_port, &ai, &aitop); |
| 2326 |
if (sock != -1) { |
2349 |
if (sock != -1) { |
| 2327 |
c = channel_new("connected socket", |
2350 |
c = channel_new("connected socket", |
| 2328 |
SSH_CHANNEL_CONNECTING, sock, sock, -1, 0, 0, 0, |
2351 |
SSH_CHANNEL_CONNECTING, sock, sock, -1, 0, 0, 0, |
| 2329 |
originator_string, 1); |
2352 |
originator_string, 1); |
| 2330 |
c->remote_id = remote_id; |
2353 |
c->remote_id = remote_id; |
|
|
2354 |
c->connect_ctx.host = xstrdup(host); |
| 2355 |
c->connect_ctx.port = host_port; |
| 2356 |
c->connect_ctx.ai = ai; |
| 2357 |
c->connect_ctx.aitop = aitop; |
| 2331 |
} |
2358 |
} |
| 2332 |
xfree(originator_string); |
2359 |
xfree(originator_string); |
| 2333 |
if (c == NULL) { |
2360 |
if (c == NULL) { |
|
Lines 2747-2776
channel_clear_adm_permitted_opens(void)
Link Here
|
| 2747 |
num_adm_permitted_opens = 0; |
2774 |
num_adm_permitted_opens = 0; |
| 2748 |
} |
2775 |
} |
| 2749 |
|
2776 |
|
| 2750 |
/* return socket to remote host, port */ |
2777 |
/* |
|
|
2778 |
* Attempt non-blocking connect to next host on addrinfo list at *aip. |
| 2779 |
* Returns in-progress socket and updates *aip to next host in list, |
| 2780 |
* allowing continuation in cases where the connection ends up failing. |
| 2781 |
*/ |
| 2751 |
static int |
2782 |
static int |
| 2752 |
connect_to(const char *host, u_short port) |
2783 |
connect_next(struct addrinfo **aip, const char *host, int port) |
| 2753 |
{ |
2784 |
{ |
| 2754 |
struct addrinfo hints, *ai, *aitop; |
2785 |
struct addrinfo *ai = *aip; |
|
|
2786 |
int sock, saved_errno; |
| 2755 |
char ntop[NI_MAXHOST], strport[NI_MAXSERV]; |
2787 |
char ntop[NI_MAXHOST], strport[NI_MAXSERV]; |
| 2756 |
int gaierr; |
|
|
| 2757 |
int sock = -1; |
| 2758 |
|
2788 |
|
| 2759 |
memset(&hints, 0, sizeof(hints)); |
2789 |
for (; ai; ai = ai->ai_next) { |
| 2760 |
hints.ai_family = IPv4or6; |
|
|
| 2761 |
hints.ai_socktype = SOCK_STREAM; |
| 2762 |
snprintf(strport, sizeof strport, "%d", port); |
| 2763 |
if ((gaierr = getaddrinfo(host, strport, &hints, &aitop)) != 0) { |
| 2764 |
error("connect_to %.100s: unknown host (%s)", host, |
| 2765 |
ssh_gai_strerror(gaierr)); |
| 2766 |
return -1; |
| 2767 |
} |
| 2768 |
for (ai = aitop; ai; ai = ai->ai_next) { |
| 2769 |
if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) |
2790 |
if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) |
| 2770 |
continue; |
2791 |
continue; |
| 2771 |
if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop, sizeof(ntop), |
2792 |
if (getnameinfo(ai->ai_addr, ai->ai_addrlen, |
| 2772 |
strport, sizeof(strport), NI_NUMERICHOST|NI_NUMERICSERV) != 0) { |
2793 |
ntop, sizeof(ntop), |
| 2773 |
error("connect_to: getnameinfo failed"); |
2794 |
strport, sizeof(strport), |
|
|
2795 |
NI_NUMERICHOST|NI_NUMERICSERV) != 0) { |
| 2796 |
error("connect_next: getnameinfo failed"); |
| 2774 |
continue; |
2797 |
continue; |
| 2775 |
} |
2798 |
} |
| 2776 |
sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); |
2799 |
sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); |
|
Lines 2785-2819
connect_to(const char *host, u_short por
Link Here
|
| 2785 |
fatal("%s: set_nonblock(%d)", __func__, sock); |
2808 |
fatal("%s: set_nonblock(%d)", __func__, sock); |
| 2786 |
if (connect(sock, ai->ai_addr, ai->ai_addrlen) < 0 && |
2809 |
if (connect(sock, ai->ai_addr, ai->ai_addrlen) < 0 && |
| 2787 |
errno != EINPROGRESS) { |
2810 |
errno != EINPROGRESS) { |
| 2788 |
error("connect_to %.100s port %s: %.100s", ntop, strport, |
2811 |
debug("connect_next: host %.100s ([%.100s]:%s): " |
| 2789 |
strerror(errno)); |
2812 |
"%.100s", host, ntop, strport, strerror(errno)); |
|
|
2813 |
saved_errno = errno; |
| 2790 |
close(sock); |
2814 |
close(sock); |
|
|
2815 |
errno = saved_errno; |
| 2791 |
continue; /* fail -- try next */ |
2816 |
continue; /* fail -- try next */ |
| 2792 |
} |
2817 |
} |
| 2793 |
break; /* success */ |
2818 |
debug("connect_next: host %.100s ([%.100s]:%s) " |
|
|
2819 |
"in progress, fd=%d", host, ntop, strport, sock); |
| 2820 |
*aip = ai->ai_next; |
| 2821 |
set_nodelay(sock); |
| 2822 |
return sock; |
| 2823 |
} |
| 2824 |
*aip = NULL; |
| 2825 |
return -1; |
| 2826 |
} |
| 2827 |
|
| 2828 |
/* return socket to remote host, port */ |
| 2829 |
static int |
| 2830 |
connect_to(const char *host, u_short port, struct addrinfo **aip, |
| 2831 |
struct addrinfo **aitopp) |
| 2832 |
{ |
| 2833 |
struct addrinfo hints, *ai, *aitop; |
| 2834 |
int gaierr; |
| 2835 |
int sock = -1; |
| 2836 |
char strport[NI_MAXSERV]; |
| 2794 |
|
2837 |
|
|
|
2838 |
memset(&hints, 0, sizeof(hints)); |
| 2839 |
hints.ai_family = IPv4or6; |
| 2840 |
hints.ai_socktype = SOCK_STREAM; |
| 2841 |
snprintf(strport, sizeof strport, "%d", port); |
| 2842 |
if ((gaierr = getaddrinfo(host, strport, &hints, &aitop)) != 0) { |
| 2843 |
error("connect_to %.100s: unknown host (%s)", host, |
| 2844 |
ssh_gai_strerror(gaierr)); |
| 2845 |
return -1; |
| 2795 |
} |
2846 |
} |
| 2796 |
freeaddrinfo(aitop); |
2847 |
|
| 2797 |
if (!ai) { |
2848 |
ai = aitop; |
| 2798 |
error("connect_to %.100s port %d: failed.", host, port); |
2849 |
if ((sock = connect_next(&ai, host, port)) == -1) { |
|
|
2850 |
error("connect to %.100s port %d failed: %s", |
| 2851 |
host, port, strerror(errno)); |
| 2852 |
freeaddrinfo(aitop); |
| 2853 |
*aip = NULL; |
| 2854 |
*aitopp = NULL; |
| 2799 |
return -1; |
2855 |
return -1; |
| 2800 |
} |
2856 |
} |
|
|
2857 |
|
| 2801 |
/* success */ |
2858 |
/* success */ |
| 2802 |
set_nodelay(sock); |
2859 |
*aip = ai; |
|
|
2860 |
*aitopp = aitop; |
| 2803 |
return sock; |
2861 |
return sock; |
| 2804 |
} |
2862 |
} |
| 2805 |
|
2863 |
|
| 2806 |
int |
2864 |
int |
| 2807 |
channel_connect_by_listen_address(u_short listen_port) |
2865 |
channel_connect_by_listen_address(u_short listen_port, |
|
|
2866 |
char **dhost, int *dport, struct addrinfo **aip, struct addrinfo **aitopp) |
| 2808 |
{ |
2867 |
{ |
| 2809 |
int i; |
2868 |
int i, r; |
| 2810 |
|
2869 |
|
| 2811 |
for (i = 0; i < num_permitted_opens; i++) |
2870 |
for (i = 0; i < num_permitted_opens; i++) { |
| 2812 |
if (permitted_opens[i].host_to_connect != NULL && |
2871 |
if (permitted_opens[i].host_to_connect != NULL && |
| 2813 |
permitted_opens[i].listen_port == listen_port) |
2872 |
permitted_opens[i].listen_port == listen_port) { |
| 2814 |
return connect_to( |
2873 |
if ((r = connect_to( |
| 2815 |
permitted_opens[i].host_to_connect, |
2874 |
permitted_opens[i].host_to_connect, |
| 2816 |
permitted_opens[i].port_to_connect); |
2875 |
permitted_opens[i].port_to_connect, |
|
|
2876 |
aip, aitopp)) != -1) { |
| 2877 |
*dhost = xstrdup( |
| 2878 |
permitted_opens[i].host_to_connect); |
| 2879 |
*dport = permitted_opens[i].port_to_connect; |
| 2880 |
} |
| 2881 |
return r; |
| 2882 |
} |
| 2883 |
} |
| 2817 |
error("WARNING: Server requests forwarding for unknown listen_port %d", |
2884 |
error("WARNING: Server requests forwarding for unknown listen_port %d", |
| 2818 |
listen_port); |
2885 |
listen_port); |
| 2819 |
return -1; |
2886 |
return -1; |
|
Lines 2821-2827
channel_connect_by_listen_address(u_shor
Link Here
|
| 2821 |
|
2888 |
|
| 2822 |
/* Check if connecting to that port is permitted and connect. */ |
2889 |
/* Check if connecting to that port is permitted and connect. */ |
| 2823 |
int |
2890 |
int |
| 2824 |
channel_connect_to(const char *host, u_short port) |
2891 |
channel_connect_to(const char *host, u_short port, struct addrinfo **aip, |
|
|
2892 |
struct addrinfo **aitopp) |
| 2825 |
{ |
2893 |
{ |
| 2826 |
int i, permit, permit_adm = 1; |
2894 |
int i, permit, permit_adm = 1; |
| 2827 |
|
2895 |
|
|
Lines 2849-2855
channel_connect_to(const char *host, u_s
Link Here
|
| 2849 |
"but the request was denied.", host, port); |
2917 |
"but the request was denied.", host, port); |
| 2850 |
return -1; |
2918 |
return -1; |
| 2851 |
} |
2919 |
} |
| 2852 |
return connect_to(host, port); |
2920 |
return connect_to(host, port, aip, aitopp); |
| 2853 |
} |
2921 |
} |
| 2854 |
|
2922 |
|
| 2855 |
void |
2923 |
void |