|
Lines 2443-2602
Link Here
|
| 2443 |
const char *host_to_connect, u_short port_to_connect, int gateway_ports) |
2443 |
const char *host_to_connect, u_short port_to_connect, int gateway_ports) |
| 2444 |
{ |
2444 |
{ |
| 2445 |
Channel *c; |
2445 |
Channel *c; |
| 2446 |
int sock, r, success = 0, wildcard = 0, is_client; |
2446 |
int sock, r, success = 0, wildcard = 0, is_client, is_unix; |
| 2447 |
struct addrinfo hints, *ai, *aitop; |
2447 |
struct addrinfo hints, *ai, *aitop; |
| 2448 |
const char *host, *addr; |
2448 |
const char *host, *path, *addr; |
| 2449 |
char ntop[NI_MAXHOST], strport[NI_MAXSERV]; |
2449 |
char ntop[NI_MAXHOST], strport[NI_MAXSERV]; |
| 2450 |
in_port_t *lport_p; |
2450 |
in_port_t *lport_p; |
|
|
2451 |
struct sockaddr_un sun; |
| 2451 |
|
2452 |
|
| 2452 |
host = (type == SSH_CHANNEL_RPORT_LISTENER) ? |
|
|
| 2453 |
listen_addr : host_to_connect; |
| 2454 |
is_client = (type == SSH_CHANNEL_PORT_LISTENER); |
2453 |
is_client = (type == SSH_CHANNEL_PORT_LISTENER); |
|
|
2454 |
is_unix = (is_client && listen_port == 0); |
| 2455 |
|
2455 |
|
| 2456 |
if (host == NULL) { |
2456 |
if (is_unix) { |
| 2457 |
error("No forward host name."); |
2457 |
path = listen_addr; |
| 2458 |
return 0; |
2458 |
if (strlen(path) >= sizeof(sun.sun_path)) { |
| 2459 |
} |
2459 |
error("Forward path too long."); |
| 2460 |
if (strlen(host) >= NI_MAXHOST) { |
2460 |
return 0; |
| 2461 |
error("Forward host name too long."); |
2461 |
} |
| 2462 |
return 0; |
|
|
| 2463 |
} |
| 2464 |
|
2462 |
|
| 2465 |
/* |
2463 |
memset(&sun, '\0', sizeof(sun)); |
| 2466 |
* Determine whether or not a port forward listens to loopback, |
2464 |
sun.sun_len = sizeof(sun); |
| 2467 |
* specified address or wildcard. On the client, a specified bind |
2465 |
sun.sun_family = AF_UNIX; |
| 2468 |
* address will always override gateway_ports. On the server, a |
2466 |
strlcpy(sun.sun_path, path, sizeof(sun.sun_path)); |
| 2469 |
* gateway_ports of 1 (``yes'') will override the client's |
|
|
| 2470 |
* specification and force a wildcard bind, whereas a value of 2 |
| 2471 |
* (``clientspecified'') will bind to whatever address the client |
| 2472 |
* asked for. |
| 2473 |
* |
| 2474 |
* Special-case listen_addrs are: |
| 2475 |
* |
| 2476 |
* "0.0.0.0" -> wildcard v4/v6 if SSH_OLD_FORWARD_ADDR |
| 2477 |
* "" (empty string), "*" -> wildcard v4/v6 |
| 2478 |
* "localhost" -> loopback v4/v6 |
| 2479 |
*/ |
| 2480 |
addr = NULL; |
| 2481 |
if (listen_addr == NULL) { |
| 2482 |
/* No address specified: default to gateway_ports setting */ |
| 2483 |
if (gateway_ports) |
| 2484 |
wildcard = 1; |
| 2485 |
} else if (gateway_ports || is_client) { |
| 2486 |
if (((datafellows & SSH_OLD_FORWARD_ADDR) && |
| 2487 |
strcmp(listen_addr, "0.0.0.0") == 0 && is_client == 0) || |
| 2488 |
*listen_addr == '\0' || strcmp(listen_addr, "*") == 0 || |
| 2489 |
(!is_client && gateway_ports == 1)) |
| 2490 |
wildcard = 1; |
| 2491 |
else if (strcmp(listen_addr, "localhost") != 0) |
| 2492 |
addr = listen_addr; |
| 2493 |
} |
| 2494 |
|
2467 |
|
| 2495 |
debug3("channel_setup_fwd_listener: type %d wildcard %d addr %s", |
2468 |
if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) |
| 2496 |
type, wildcard, (addr == NULL) ? "NULL" : addr); |
2469 |
goto unix_error; |
| 2497 |
|
2470 |
|
| 2498 |
/* |
2471 |
if (bind(sock, (struct sockaddr *)&sun, sizeof(sun)) < 0) |
| 2499 |
* getaddrinfo returns a loopback address if the hostname is |
2472 |
goto unix_error; |
| 2500 |
* set to NULL and hints.ai_flags is not AI_PASSIVE |
2473 |
|
| 2501 |
*/ |
2474 |
if (listen(sock, SSH_LISTEN_BACKLOG) < 0) |
| 2502 |
memset(&hints, 0, sizeof(hints)); |
2475 |
goto unix_error; |
| 2503 |
hints.ai_family = IPv4or6; |
2476 |
|
| 2504 |
hints.ai_flags = wildcard ? AI_PASSIVE : 0; |
2477 |
c = channel_new("unix listener", type, sock, sock, -1, |
| 2505 |
hints.ai_socktype = SOCK_STREAM; |
2478 |
CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, |
| 2506 |
snprintf(strport, sizeof strport, "%d", listen_port); |
2479 |
0, "unix listener", 1); |
| 2507 |
if ((r = getaddrinfo(addr, strport, &hints, &aitop)) != 0) { |
2480 |
c->path = xstrdup(host_to_connect); |
| 2508 |
if (addr == NULL) { |
2481 |
c->host_port = port_to_connect; |
| 2509 |
/* This really shouldn't happen */ |
2482 |
c->listening_port = 0; |
| 2510 |
packet_disconnect("getaddrinfo: fatal error: %s", |
2483 |
|
| 2511 |
ssh_gai_strerror(r)); |
2484 |
return 1; |
| 2512 |
} else { |
2485 |
|
| 2513 |
error("channel_setup_fwd_listener: " |
2486 |
unix_error: |
| 2514 |
"getaddrinfo(%.64s): %s", addr, |
2487 |
error("channel_setup_fwd_listener: unable to create listener " |
| 2515 |
ssh_gai_strerror(r)); |
2488 |
"unix:%.200s, %s", path, strerror(errno)); |
| 2516 |
} |
2489 |
if (sock >= 0) |
|
|
2490 |
close(sock); |
| 2517 |
return 0; |
2491 |
return 0; |
| 2518 |
} |
2492 |
} |
| 2519 |
if (allocated_listen_port != NULL) |
2493 |
else { |
| 2520 |
*allocated_listen_port = 0; |
2494 |
host = (is_client ? host_to_connect : listen_addr); |
| 2521 |
for (ai = aitop; ai; ai = ai->ai_next) { |
2495 |
|
| 2522 |
switch (ai->ai_family) { |
2496 |
if (host == NULL) { |
| 2523 |
case AF_INET: |
2497 |
error("No forward host name."); |
| 2524 |
lport_p = &((struct sockaddr_in *)ai->ai_addr)-> |
2498 |
return 0; |
| 2525 |
sin_port; |
2499 |
} |
| 2526 |
break; |
2500 |
if (strlen(host) >= NI_MAXHOST) { |
| 2527 |
case AF_INET6: |
2501 |
error("Forward host name too long."); |
| 2528 |
lport_p = &((struct sockaddr_in6 *)ai->ai_addr)-> |
2502 |
return 0; |
| 2529 |
sin6_port; |
|
|
| 2530 |
break; |
| 2531 |
default: |
| 2532 |
continue; |
| 2533 |
} |
2503 |
} |
|
|
2504 |
|
| 2534 |
/* |
2505 |
/* |
| 2535 |
* If allocating a port for -R forwards, then use the |
2506 |
* Determine whether or not a port forward listens to loopback, |
| 2536 |
* same port for all address families. |
2507 |
* specified address or wildcard. On the client, a specified bind |
|
|
2508 |
* address will always override gateway_ports. On the server, a |
| 2509 |
* gateway_ports of 1 (``yes'') will override the client's |
| 2510 |
* specification and force a wildcard bind, whereas a value of 2 |
| 2511 |
* (``clientspecified'') will bind to whatever address the client |
| 2512 |
* asked for. |
| 2513 |
* |
| 2514 |
* Special-case listen_addrs are: |
| 2515 |
* |
| 2516 |
* "0.0.0.0" -> wildcard v4/v6 if SSH_OLD_FORWARD_ADDR |
| 2517 |
* "" (empty string), "*" -> wildcard v4/v6 |
| 2518 |
* "localhost" -> loopback v4/v6 |
| 2537 |
*/ |
2519 |
*/ |
| 2538 |
if (type == SSH_CHANNEL_RPORT_LISTENER && listen_port == 0 && |
2520 |
addr = NULL; |
| 2539 |
allocated_listen_port != NULL && *allocated_listen_port > 0) |
2521 |
if (listen_addr == NULL) { |
| 2540 |
*lport_p = htons(*allocated_listen_port); |
2522 |
/* No address specified: default to gateway_ports setting */ |
| 2541 |
|
2523 |
if (gateway_ports) |
| 2542 |
if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop, sizeof(ntop), |
2524 |
wildcard = 1; |
| 2543 |
strport, sizeof(strport), NI_NUMERICHOST|NI_NUMERICSERV) != 0) { |
2525 |
} else if (gateway_ports || is_client) { |
| 2544 |
error("channel_setup_fwd_listener: getnameinfo failed"); |
2526 |
if (((datafellows & SSH_OLD_FORWARD_ADDR) && |
| 2545 |
continue; |
2527 |
strcmp(listen_addr, "0.0.0.0") == 0 && is_client == 0) || |
| 2546 |
} |
2528 |
*listen_addr == '\0' || strcmp(listen_addr, "*") == 0 || |
| 2547 |
/* Create a port to listen for the host. */ |
2529 |
(!is_client && gateway_ports == 1)) |
| 2548 |
sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); |
2530 |
wildcard = 1; |
| 2549 |
if (sock < 0) { |
2531 |
else if (strcmp(listen_addr, "localhost") != 0) |
| 2550 |
/* this is no error since kernel may not support ipv6 */ |
2532 |
addr = listen_addr; |
| 2551 |
verbose("socket: %.100s", strerror(errno)); |
|
|
| 2552 |
continue; |
| 2553 |
} |
| 2554 |
|
| 2555 |
channel_set_reuseaddr(sock); |
| 2556 |
|
| 2557 |
debug("Local forwarding listening on %s port %s.", |
| 2558 |
ntop, strport); |
| 2559 |
|
| 2560 |
/* Bind the socket to the address. */ |
| 2561 |
if (bind(sock, ai->ai_addr, ai->ai_addrlen) < 0) { |
| 2562 |
/* address can be in use ipv6 address is already bound */ |
| 2563 |
verbose("bind: %.100s", strerror(errno)); |
| 2564 |
close(sock); |
| 2565 |
continue; |
| 2566 |
} |
| 2567 |
/* Start listening for connections on the socket. */ |
| 2568 |
if (listen(sock, SSH_LISTEN_BACKLOG) < 0) { |
| 2569 |
error("listen: %.100s", strerror(errno)); |
| 2570 |
close(sock); |
| 2571 |
continue; |
| 2572 |
} |
2533 |
} |
| 2573 |
|
2534 |
|
|
|
2535 |
debug3("channel_setup_fwd_listener: type %d wildcard %d addr %s", |
| 2536 |
type, wildcard, (addr == NULL) ? "NULL" : addr); |
| 2537 |
|
| 2574 |
/* |
2538 |
/* |
| 2575 |
* listen_port == 0 requests a dynamically allocated port - |
2539 |
* getaddrinfo returns a loopback address if the hostname is |
| 2576 |
* record what we got. |
2540 |
* set to NULL and hints.ai_flags is not AI_PASSIVE |
| 2577 |
*/ |
2541 |
*/ |
| 2578 |
if (type == SSH_CHANNEL_RPORT_LISTENER && listen_port == 0 && |
2542 |
memset(&hints, 0, sizeof(hints)); |
| 2579 |
allocated_listen_port != NULL && |
2543 |
hints.ai_family = IPv4or6; |
| 2580 |
*allocated_listen_port == 0) { |
2544 |
hints.ai_flags = wildcard ? AI_PASSIVE : 0; |
| 2581 |
*allocated_listen_port = get_sock_port(sock, 1); |
2545 |
hints.ai_socktype = SOCK_STREAM; |
| 2582 |
debug("Allocated listen port %d", |
2546 |
snprintf(strport, sizeof strport, "%d", listen_port); |
| 2583 |
*allocated_listen_port); |
2547 |
if ((r = getaddrinfo(addr, strport, &hints, &aitop)) != 0) { |
| 2584 |
} |
2548 |
if (addr == NULL) { |
|
|
2549 |
/* This really shouldn't happen */ |
| 2550 |
packet_disconnect("getaddrinfo: fatal error: %s", |
| 2551 |
ssh_gai_strerror(r)); |
| 2552 |
} else { |
| 2553 |
error("channel_setup_fwd_listener: " |
| 2554 |
"getaddrinfo(%.64s): %s", addr, |
| 2555 |
ssh_gai_strerror(r)); |
| 2556 |
} |
| 2557 |
return 0; |
| 2558 |
} |
| 2559 |
if (allocated_listen_port != NULL) |
| 2560 |
*allocated_listen_port = 0; |
| 2561 |
for (ai = aitop; ai; ai = ai->ai_next) { |
| 2562 |
switch (ai->ai_family) { |
| 2563 |
case AF_INET: |
| 2564 |
lport_p = &((struct sockaddr_in *)ai->ai_addr)-> |
| 2565 |
sin_port; |
| 2566 |
break; |
| 2567 |
case AF_INET6: |
| 2568 |
lport_p = &((struct sockaddr_in6 *)ai->ai_addr)-> |
| 2569 |
sin6_port; |
| 2570 |
break; |
| 2571 |
default: |
| 2572 |
continue; |
| 2573 |
} |
| 2574 |
/* |
| 2575 |
* If allocating a port for -R forwards, then use the |
| 2576 |
* same port for all address families. |
| 2577 |
*/ |
| 2578 |
if (type == SSH_CHANNEL_RPORT_LISTENER && listen_port == 0 && |
| 2579 |
allocated_listen_port != NULL && *allocated_listen_port > 0) |
| 2580 |
*lport_p = htons(*allocated_listen_port); |
| 2581 |
|
| 2582 |
if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop, sizeof(ntop), |
| 2583 |
strport, sizeof(strport), NI_NUMERICHOST|NI_NUMERICSERV) != 0) { |
| 2584 |
error("channel_setup_fwd_listener: getnameinfo failed"); |
| 2585 |
continue; |
| 2586 |
} |
| 2587 |
/* Create a port to listen for the host. */ |
| 2588 |
sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); |
| 2589 |
if (sock < 0) { |
| 2590 |
/* this is no error since kernel may not support ipv6 */ |
| 2591 |
verbose("socket: %.100s", strerror(errno)); |
| 2592 |
continue; |
| 2593 |
} |
| 2594 |
|
| 2595 |
channel_set_reuseaddr(sock); |
| 2596 |
|
| 2597 |
debug("Local forwarding listening on %s port %s.", |
| 2598 |
ntop, strport); |
| 2599 |
|
| 2600 |
/* Bind the socket to the address. */ |
| 2601 |
if (bind(sock, ai->ai_addr, ai->ai_addrlen) < 0) { |
| 2602 |
/* address can be in use ipv6 address is already bound */ |
| 2603 |
verbose("bind: %.100s", strerror(errno)); |
| 2604 |
close(sock); |
| 2605 |
continue; |
| 2606 |
} |
| 2607 |
/* Start listening for connections on the socket. */ |
| 2608 |
if (listen(sock, SSH_LISTEN_BACKLOG) < 0) { |
| 2609 |
error("listen: %.100s", strerror(errno)); |
| 2610 |
close(sock); |
| 2611 |
continue; |
| 2612 |
} |
| 2613 |
|
| 2614 |
/* |
| 2615 |
* listen_port == 0 requests a dynamically allocated port - |
| 2616 |
* record what we got. |
| 2617 |
*/ |
| 2618 |
if (type == SSH_CHANNEL_RPORT_LISTENER && listen_port == 0 && |
| 2619 |
allocated_listen_port != NULL && |
| 2620 |
*allocated_listen_port == 0) { |
| 2621 |
*allocated_listen_port = get_sock_port(sock, 1); |
| 2622 |
debug("Allocated listen port %d", |
| 2623 |
*allocated_listen_port); |
| 2624 |
} |
| 2625 |
|
| 2626 |
/* Allocate a channel number for the socket. */ |
| 2627 |
c = channel_new("port listener", type, sock, sock, -1, |
| 2628 |
CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, |
| 2629 |
0, "port listener", 1); |
| 2630 |
c->path = xstrdup(host); |
| 2631 |
c->host_port = port_to_connect; |
| 2632 |
c->listening_port = listen_port; |
| 2633 |
success = 1; |
| 2634 |
} |
| 2635 |
|
| 2636 |
if (success == 0) |
| 2637 |
error("channel_setup_fwd_listener: cannot listen to port: %d", |
| 2638 |
listen_port); |
| 2639 |
freeaddrinfo(aitop); |
| 2585 |
|
2640 |
|
| 2586 |
/* Allocate a channel number for the socket. */ |
2641 |
return success; |
| 2587 |
c = channel_new("port listener", type, sock, sock, -1, |
|
|
| 2588 |
CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, |
| 2589 |
0, "port listener", 1); |
| 2590 |
c->path = xstrdup(host); |
| 2591 |
c->host_port = port_to_connect; |
| 2592 |
c->listening_port = listen_port; |
| 2593 |
success = 1; |
| 2594 |
} |
2642 |
} |
| 2595 |
if (success == 0) |
|
|
| 2596 |
error("channel_setup_fwd_listener: cannot listen to port: %d", |
| 2597 |
listen_port); |
| 2598 |
freeaddrinfo(aitop); |
| 2599 |
return success; |
| 2600 |
} |
2643 |
} |
| 2601 |
|
2644 |
|
| 2602 |
int |
2645 |
int |
|
Lines 2621-2631
Link Here
|
| 2621 |
|
2664 |
|
| 2622 |
/* protocol local port fwd, used by ssh (and sshd in v1) */ |
2665 |
/* protocol local port fwd, used by ssh (and sshd in v1) */ |
| 2623 |
int |
2666 |
int |
| 2624 |
channel_setup_local_fwd_listener(const char *listen_host, u_short listen_port, |
2667 |
channel_setup_local_fwd_listener(const char *listen_host_or_path, u_short listen_port, |
| 2625 |
const char *host_to_connect, u_short port_to_connect, int gateway_ports) |
2668 |
const char *host_to_connect, u_short port_to_connect, int gateway_ports) |
| 2626 |
{ |
2669 |
{ |
| 2627 |
return channel_setup_fwd_listener(SSH_CHANNEL_PORT_LISTENER, |
2670 |
return channel_setup_fwd_listener(SSH_CHANNEL_PORT_LISTENER, |
| 2628 |
listen_host, listen_port, NULL, host_to_connect, port_to_connect, |
2671 |
listen_host_or_path, listen_port, NULL, host_to_connect, port_to_connect, |
| 2629 |
gateway_ports); |
2672 |
gateway_ports); |
| 2630 |
} |
2673 |
} |
| 2631 |
|
2674 |
|