summaryrefslogtreecommitdiff
path: root/channels.c
diff options
context:
space:
mode:
authorDamien Miller <djm@mindrot.org>2011-09-22 21:38:52 +1000
committerDamien Miller <djm@mindrot.org>2011-09-22 21:38:52 +1000
commitf6dff7cd2ff5eba5cd63e3a9c7bf6ccf183cb056 (patch)
treeca2f37e390f5f26598341a09435dabed25648d46 /channels.c
parent9ee2c606c1d03ecb955aa8a2624b9db4aa9752a2 (diff)
- djm@cvs.openbsd.org 2011/09/09 22:46:44
[channels.c channels.h clientloop.h mux.c ssh.c] support for cancelling local and remote port forwards via the multiplex socket. Use ssh -O cancel -L xx:xx:xx -R yy:yy:yy user@host" to request the cancellation of the specified forwardings; ok markus@
Diffstat (limited to 'channels.c')
-rw-r--r--channels.c164
1 files changed, 109 insertions, 55 deletions
diff --git a/channels.c b/channels.c
index 24d4a9f42..0f7e1a872 100644
--- a/channels.c
+++ b/channels.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: channels.c,v 1.311 2011/06/22 22:08:42 djm Exp $ */ 1/* $OpenBSD: channels.c,v 1.312 2011/09/09 22:46:44 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
@@ -302,6 +302,8 @@ channel_new(char *ctype, int type, int rfd, int wfd, int efd,
302 buffer_init(&c->output); 302 buffer_init(&c->output);
303 buffer_init(&c->extended); 303 buffer_init(&c->extended);
304 c->path = NULL; 304 c->path = NULL;
305 c->listening_addr = NULL;
306 c->listening_port = 0;
305 c->ostate = CHAN_OUTPUT_OPEN; 307 c->ostate = CHAN_OUTPUT_OPEN;
306 c->istate = CHAN_INPUT_OPEN; 308 c->istate = CHAN_INPUT_OPEN;
307 c->flags = 0; 309 c->flags = 0;
@@ -411,6 +413,10 @@ channel_free(Channel *c)
411 xfree(c->path); 413 xfree(c->path);
412 c->path = NULL; 414 c->path = NULL;
413 } 415 }
416 if (c->listening_addr) {
417 xfree(c->listening_addr);
418 c->listening_addr = NULL;
419 }
414 while ((cc = TAILQ_FIRST(&c->status_confirms)) != NULL) { 420 while ((cc = TAILQ_FIRST(&c->status_confirms)) != NULL) {
415 if (cc->abandon_cb != NULL) 421 if (cc->abandon_cb != NULL)
416 cc->abandon_cb(c, cc->ctx); 422 cc->abandon_cb(c, cc->ctx);
@@ -2634,6 +2640,46 @@ channel_set_af(int af)
2634 IPv4or6 = af; 2640 IPv4or6 = af;
2635} 2641}
2636 2642
2643
2644/*
2645 * Determine whether or not a port forward listens to loopback, the
2646 * specified address or wildcard. On the client, a specified bind
2647 * address will always override gateway_ports. On the server, a
2648 * gateway_ports of 1 (``yes'') will override the client's specification
2649 * and force a wildcard bind, whereas a value of 2 (``clientspecified'')
2650 * will bind to whatever address the client asked for.
2651 *
2652 * Special-case listen_addrs are:
2653 *
2654 * "0.0.0.0" -> wildcard v4/v6 if SSH_OLD_FORWARD_ADDR
2655 * "" (empty string), "*" -> wildcard v4/v6
2656 * "localhost" -> loopback v4/v6
2657 */
2658static const char *
2659channel_fwd_bind_addr(const char *listen_addr, int *wildcardp,
2660 int is_client, int gateway_ports)
2661{
2662 const char *addr = NULL;
2663 int wildcard = 0;
2664
2665 if (listen_addr == NULL) {
2666 /* No address specified: default to gateway_ports setting */
2667 if (gateway_ports)
2668 wildcard = 1;
2669 } else if (gateway_ports || is_client) {
2670 if (((datafellows & SSH_OLD_FORWARD_ADDR) &&
2671 strcmp(listen_addr, "0.0.0.0") == 0 && is_client == 0) ||
2672 *listen_addr == '\0' || strcmp(listen_addr, "*") == 0 ||
2673 (!is_client && gateway_ports == 1))
2674 wildcard = 1;
2675 else if (strcmp(listen_addr, "localhost") != 0)
2676 addr = listen_addr;
2677 }
2678 if (wildcardp != NULL)
2679 *wildcardp = wildcard;
2680 return addr;
2681}
2682
2637static int 2683static int
2638channel_setup_fwd_listener(int type, const char *listen_addr, 2684channel_setup_fwd_listener(int type, const char *listen_addr,
2639 u_short listen_port, int *allocated_listen_port, 2685 u_short listen_port, int *allocated_listen_port,
@@ -2659,36 +2705,9 @@ channel_setup_fwd_listener(int type, const char *listen_addr,
2659 return 0; 2705 return 0;
2660 } 2706 }
2661 2707
2662 /* 2708 /* Determine the bind address, cf. channel_fwd_bind_addr() comment */
2663 * Determine whether or not a port forward listens to loopback, 2709 addr = channel_fwd_bind_addr(listen_addr, &wildcard,
2664 * specified address or wildcard. On the client, a specified bind 2710 is_client, gateway_ports);
2665 * address will always override gateway_ports. On the server, a
2666 * gateway_ports of 1 (``yes'') will override the client's
2667 * specification and force a wildcard bind, whereas a value of 2
2668 * (``clientspecified'') will bind to whatever address the client
2669 * asked for.
2670 *
2671 * Special-case listen_addrs are:
2672 *
2673 * "0.0.0.0" -> wildcard v4/v6 if SSH_OLD_FORWARD_ADDR
2674 * "" (empty string), "*" -> wildcard v4/v6
2675 * "localhost" -> loopback v4/v6
2676 */
2677 addr = NULL;
2678 if (listen_addr == NULL) {
2679 /* No address specified: default to gateway_ports setting */
2680 if (gateway_ports)
2681 wildcard = 1;
2682 } else if (gateway_ports || is_client) {
2683 if (((datafellows & SSH_OLD_FORWARD_ADDR) &&
2684 strcmp(listen_addr, "0.0.0.0") == 0 && is_client == 0) ||
2685 *listen_addr == '\0' || strcmp(listen_addr, "*") == 0 ||
2686 (!is_client && gateway_ports == 1))
2687 wildcard = 1;
2688 else if (strcmp(listen_addr, "localhost") != 0)
2689 addr = listen_addr;
2690 }
2691
2692 debug3("channel_setup_fwd_listener: type %d wildcard %d addr %s", 2711 debug3("channel_setup_fwd_listener: type %d wildcard %d addr %s",
2693 type, wildcard, (addr == NULL) ? "NULL" : addr); 2712 type, wildcard, (addr == NULL) ? "NULL" : addr);
2694 2713
@@ -2793,6 +2812,7 @@ channel_setup_fwd_listener(int type, const char *listen_addr,
2793 c->path = xstrdup(host); 2812 c->path = xstrdup(host);
2794 c->host_port = port_to_connect; 2813 c->host_port = port_to_connect;
2795 c->listening_port = listen_port; 2814 c->listening_port = listen_port;
2815 c->listening_addr = addr == NULL ? NULL : xstrdup(addr);
2796 success = 1; 2816 success = 1;
2797 } 2817 }
2798 if (success == 0) 2818 if (success == 0)
@@ -2810,9 +2830,36 @@ channel_cancel_rport_listener(const char *host, u_short port)
2810 2830
2811 for (i = 0; i < channels_alloc; i++) { 2831 for (i = 0; i < channels_alloc; i++) {
2812 Channel *c = channels[i]; 2832 Channel *c = channels[i];
2833 if (c == NULL || c->type != SSH_CHANNEL_RPORT_LISTENER)
2834 continue;
2835 if (strcmp(c->path, host) == 0 && c->listening_port == port) {
2836 debug2("%s: close channel %d", __func__, i);
2837 channel_free(c);
2838 found = 1;
2839 }
2840 }
2841
2842 return (found);
2843}
2844
2845int
2846channel_cancel_lport_listener(const char *lhost, u_short lport,
2847 u_short cport, int gateway_ports)
2848{
2849 u_int i;
2850 int found = 0;
2851 const char *addr = channel_fwd_bind_addr(lhost, NULL, 1, gateway_ports);
2813 2852
2814 if (c != NULL && c->type == SSH_CHANNEL_RPORT_LISTENER && 2853 for (i = 0; i < channels_alloc; i++) {
2815 strcmp(c->path, host) == 0 && c->listening_port == port) { 2854 Channel *c = channels[i];
2855 if (c == NULL || c->type != SSH_CHANNEL_PORT_LISTENER)
2856 continue;
2857 if (c->listening_port != lport || c->host_port != cport)
2858 continue;
2859 if ((c->listening_addr == NULL && addr != NULL) ||
2860 (c->listening_addr != NULL && addr == NULL))
2861 continue;
2862 if (addr == NULL || strcmp(c->listening_addr, addr) == 0) {
2816 debug2("%s: close channel %d", __func__, i); 2863 debug2("%s: close channel %d", __func__, i);
2817 channel_free(c); 2864 channel_free(c);
2818 found = 1; 2865 found = 1;
@@ -2843,10 +2890,30 @@ channel_setup_remote_fwd_listener(const char *listen_address,
2843} 2890}
2844 2891
2845/* 2892/*
2893 * Translate the requested rfwd listen host to something usable for
2894 * this server.
2895 */
2896static const char *
2897channel_rfwd_bind_host(const char *listen_host)
2898{
2899 if (listen_host == NULL) {
2900 if (datafellows & SSH_BUG_RFWD_ADDR)
2901 return "127.0.0.1";
2902 else
2903 return "localhost";
2904 } else if (*listen_host == '\0' || strcmp(listen_host, "*") == 0) {
2905 if (datafellows & SSH_BUG_RFWD_ADDR)
2906 return "0.0.0.0";
2907 else
2908 return "";
2909 } else
2910 return listen_host;
2911}
2912
2913/*
2846 * Initiate forwarding of connections to port "port" on remote host through 2914 * Initiate forwarding of connections to port "port" on remote host through
2847 * the secure channel to host:port from local side. 2915 * the secure channel to host:port from local side.
2848 */ 2916 */
2849
2850int 2917int
2851channel_request_remote_forwarding(const char *listen_host, u_short listen_port, 2918channel_request_remote_forwarding(const char *listen_host, u_short listen_port,
2852 const char *host_to_connect, u_short port_to_connect) 2919 const char *host_to_connect, u_short port_to_connect)
@@ -2855,25 +2922,10 @@ channel_request_remote_forwarding(const char *listen_host, u_short listen_port,
2855 2922
2856 /* Send the forward request to the remote side. */ 2923 /* Send the forward request to the remote side. */
2857 if (compat20) { 2924 if (compat20) {
2858 const char *address_to_bind;
2859 if (listen_host == NULL) {
2860 if (datafellows & SSH_BUG_RFWD_ADDR)
2861 address_to_bind = "127.0.0.1";
2862 else
2863 address_to_bind = "localhost";
2864 } else if (*listen_host == '\0' ||
2865 strcmp(listen_host, "*") == 0) {
2866 if (datafellows & SSH_BUG_RFWD_ADDR)
2867 address_to_bind = "0.0.0.0";
2868 else
2869 address_to_bind = "";
2870 } else
2871 address_to_bind = listen_host;
2872
2873 packet_start(SSH2_MSG_GLOBAL_REQUEST); 2925 packet_start(SSH2_MSG_GLOBAL_REQUEST);
2874 packet_put_cstring("tcpip-forward"); 2926 packet_put_cstring("tcpip-forward");
2875 packet_put_char(1); /* boolean: want reply */ 2927 packet_put_char(1); /* boolean: want reply */
2876 packet_put_cstring(address_to_bind); 2928 packet_put_cstring(channel_rfwd_bind_host(listen_host));
2877 packet_put_int(listen_port); 2929 packet_put_int(listen_port);
2878 packet_send(); 2930 packet_send();
2879 packet_write_wait(); 2931 packet_write_wait();
@@ -2917,13 +2969,13 @@ channel_request_remote_forwarding(const char *listen_host, u_short listen_port,
2917 * Request cancellation of remote forwarding of connection host:port from 2969 * Request cancellation of remote forwarding of connection host:port from
2918 * local side. 2970 * local side.
2919 */ 2971 */
2920void 2972int
2921channel_request_rforward_cancel(const char *host, u_short port) 2973channel_request_rforward_cancel(const char *host, u_short port)
2922{ 2974{
2923 int i; 2975 int i;
2924 2976
2925 if (!compat20) 2977 if (!compat20)
2926 return; 2978 return -1;
2927 2979
2928 for (i = 0; i < num_permitted_opens; i++) { 2980 for (i = 0; i < num_permitted_opens; i++) {
2929 if (permitted_opens[i].host_to_connect != NULL && 2981 if (permitted_opens[i].host_to_connect != NULL &&
@@ -2932,12 +2984,12 @@ channel_request_rforward_cancel(const char *host, u_short port)
2932 } 2984 }
2933 if (i >= num_permitted_opens) { 2985 if (i >= num_permitted_opens) {
2934 debug("%s: requested forward not found", __func__); 2986 debug("%s: requested forward not found", __func__);
2935 return; 2987 return -1;
2936 } 2988 }
2937 packet_start(SSH2_MSG_GLOBAL_REQUEST); 2989 packet_start(SSH2_MSG_GLOBAL_REQUEST);
2938 packet_put_cstring("cancel-tcpip-forward"); 2990 packet_put_cstring("cancel-tcpip-forward");
2939 packet_put_char(0); 2991 packet_put_char(0);
2940 packet_put_cstring(host == NULL ? "" : host); 2992 packet_put_cstring(channel_rfwd_bind_host(host));
2941 packet_put_int(port); 2993 packet_put_int(port);
2942 packet_send(); 2994 packet_send();
2943 2995
@@ -2945,6 +2997,8 @@ channel_request_rforward_cancel(const char *host, u_short port)
2945 permitted_opens[i].port_to_connect = 0; 2997 permitted_opens[i].port_to_connect = 0;
2946 xfree(permitted_opens[i].host_to_connect); 2998 xfree(permitted_opens[i].host_to_connect);
2947 permitted_opens[i].host_to_connect = NULL; 2999 permitted_opens[i].host_to_connect = NULL;
3000
3001 return 0;
2948} 3002}
2949 3003
2950/* 3004/*