Skip to content

Commit

Permalink
- djm@cvs.openbsd.org 2011/09/09 22:46:44
Browse files Browse the repository at this point in the history
     [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@
  • Loading branch information
djmdjm committed Sep 22, 2011
1 parent 9ee2c60 commit f6dff7c
Show file tree
Hide file tree
Showing 6 changed files with 206 additions and 80 deletions.
5 changes: 5 additions & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,11 @@
[sshd.c]
kill the preauth privsep child on fatal errors in the monitor;
ok markus@
- 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@

20110909
- (dtucker) [entropy.h] Bug #1932: remove old definition of init_rng. From
Expand Down
164 changes: 109 additions & 55 deletions channels.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* $OpenBSD: channels.c,v 1.311 2011/06/22 22:08:42 djm Exp $ */
/* $OpenBSD: channels.c,v 1.312 2011/09/09 22:46:44 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
Expand Down Expand Up @@ -302,6 +302,8 @@ channel_new(char *ctype, int type, int rfd, int wfd, int efd,
buffer_init(&c->output);
buffer_init(&c->extended);
c->path = NULL;
c->listening_addr = NULL;
c->listening_port = 0;
c->ostate = CHAN_OUTPUT_OPEN;
c->istate = CHAN_INPUT_OPEN;
c->flags = 0;
Expand Down Expand Up @@ -411,6 +413,10 @@ channel_free(Channel *c)
xfree(c->path);
c->path = NULL;
}
if (c->listening_addr) {
xfree(c->listening_addr);
c->listening_addr = NULL;
}
while ((cc = TAILQ_FIRST(&c->status_confirms)) != NULL) {
if (cc->abandon_cb != NULL)
cc->abandon_cb(c, cc->ctx);
Expand Down Expand Up @@ -2634,6 +2640,46 @@ channel_set_af(int af)
IPv4or6 = af;
}


/*
* Determine whether or not a port forward listens to loopback, the
* specified address or wildcard. On the client, a specified bind
* address will always override gateway_ports. On the server, a
* gateway_ports of 1 (``yes'') will override the client's specification
* and force a wildcard bind, whereas a value of 2 (``clientspecified'')
* will bind to whatever address the client asked for.
*
* Special-case listen_addrs are:
*
* "0.0.0.0" -> wildcard v4/v6 if SSH_OLD_FORWARD_ADDR
* "" (empty string), "*" -> wildcard v4/v6
* "localhost" -> loopback v4/v6
*/
static const char *
channel_fwd_bind_addr(const char *listen_addr, int *wildcardp,
int is_client, int gateway_ports)
{
const char *addr = NULL;
int wildcard = 0;

if (listen_addr == NULL) {
/* No address specified: default to gateway_ports setting */
if (gateway_ports)
wildcard = 1;
} else if (gateway_ports || is_client) {
if (((datafellows & SSH_OLD_FORWARD_ADDR) &&
strcmp(listen_addr, "0.0.0.0") == 0 && is_client == 0) ||
*listen_addr == '\0' || strcmp(listen_addr, "*") == 0 ||
(!is_client && gateway_ports == 1))
wildcard = 1;
else if (strcmp(listen_addr, "localhost") != 0)
addr = listen_addr;
}
if (wildcardp != NULL)
*wildcardp = wildcard;
return addr;
}

static int
channel_setup_fwd_listener(int type, const char *listen_addr,
u_short listen_port, int *allocated_listen_port,
Expand All @@ -2659,36 +2705,9 @@ channel_setup_fwd_listener(int type, const char *listen_addr,
return 0;
}

/*
* Determine whether or not a port forward listens to loopback,
* specified address or wildcard. On the client, a specified bind
* address will always override gateway_ports. On the server, a
* gateway_ports of 1 (``yes'') will override the client's
* specification and force a wildcard bind, whereas a value of 2
* (``clientspecified'') will bind to whatever address the client
* asked for.
*
* Special-case listen_addrs are:
*
* "0.0.0.0" -> wildcard v4/v6 if SSH_OLD_FORWARD_ADDR
* "" (empty string), "*" -> wildcard v4/v6
* "localhost" -> loopback v4/v6
*/
addr = NULL;
if (listen_addr == NULL) {
/* No address specified: default to gateway_ports setting */
if (gateway_ports)
wildcard = 1;
} else if (gateway_ports || is_client) {
if (((datafellows & SSH_OLD_FORWARD_ADDR) &&
strcmp(listen_addr, "0.0.0.0") == 0 && is_client == 0) ||
*listen_addr == '\0' || strcmp(listen_addr, "*") == 0 ||
(!is_client && gateway_ports == 1))
wildcard = 1;
else if (strcmp(listen_addr, "localhost") != 0)
addr = listen_addr;
}

/* Determine the bind address, cf. channel_fwd_bind_addr() comment */
addr = channel_fwd_bind_addr(listen_addr, &wildcard,
is_client, gateway_ports);
debug3("channel_setup_fwd_listener: type %d wildcard %d addr %s",
type, wildcard, (addr == NULL) ? "NULL" : addr);

Expand Down Expand Up @@ -2793,6 +2812,7 @@ channel_setup_fwd_listener(int type, const char *listen_addr,
c->path = xstrdup(host);
c->host_port = port_to_connect;
c->listening_port = listen_port;
c->listening_addr = addr == NULL ? NULL : xstrdup(addr);
success = 1;
}
if (success == 0)
Expand All @@ -2810,9 +2830,36 @@ channel_cancel_rport_listener(const char *host, u_short port)

for (i = 0; i < channels_alloc; i++) {
Channel *c = channels[i];
if (c == NULL || c->type != SSH_CHANNEL_RPORT_LISTENER)
continue;
if (strcmp(c->path, host) == 0 && c->listening_port == port) {
debug2("%s: close channel %d", __func__, i);
channel_free(c);
found = 1;
}
}

return (found);
}

int
channel_cancel_lport_listener(const char *lhost, u_short lport,
u_short cport, int gateway_ports)
{
u_int i;
int found = 0;
const char *addr = channel_fwd_bind_addr(lhost, NULL, 1, gateway_ports);

if (c != NULL && c->type == SSH_CHANNEL_RPORT_LISTENER &&
strcmp(c->path, host) == 0 && c->listening_port == port) {
for (i = 0; i < channels_alloc; i++) {
Channel *c = channels[i];
if (c == NULL || c->type != SSH_CHANNEL_PORT_LISTENER)
continue;
if (c->listening_port != lport || c->host_port != cport)
continue;
if ((c->listening_addr == NULL && addr != NULL) ||
(c->listening_addr != NULL && addr == NULL))
continue;
if (addr == NULL || strcmp(c->listening_addr, addr) == 0) {
debug2("%s: close channel %d", __func__, i);
channel_free(c);
found = 1;
Expand Down Expand Up @@ -2842,11 +2889,31 @@ channel_setup_remote_fwd_listener(const char *listen_address,
NULL, 0, gateway_ports);
}

/*
* Translate the requested rfwd listen host to something usable for
* this server.
*/
static const char *
channel_rfwd_bind_host(const char *listen_host)
{
if (listen_host == NULL) {
if (datafellows & SSH_BUG_RFWD_ADDR)
return "127.0.0.1";
else
return "localhost";
} else if (*listen_host == '\0' || strcmp(listen_host, "*") == 0) {
if (datafellows & SSH_BUG_RFWD_ADDR)
return "0.0.0.0";
else
return "";
} else
return listen_host;
}

/*
* Initiate forwarding of connections to port "port" on remote host through
* the secure channel to host:port from local side.
*/

int
channel_request_remote_forwarding(const char *listen_host, u_short listen_port,
const char *host_to_connect, u_short port_to_connect)
Expand All @@ -2855,25 +2922,10 @@ channel_request_remote_forwarding(const char *listen_host, u_short listen_port,

/* Send the forward request to the remote side. */
if (compat20) {
const char *address_to_bind;
if (listen_host == NULL) {
if (datafellows & SSH_BUG_RFWD_ADDR)
address_to_bind = "127.0.0.1";
else
address_to_bind = "localhost";
} else if (*listen_host == '\0' ||
strcmp(listen_host, "*") == 0) {
if (datafellows & SSH_BUG_RFWD_ADDR)
address_to_bind = "0.0.0.0";
else
address_to_bind = "";
} else
address_to_bind = listen_host;

packet_start(SSH2_MSG_GLOBAL_REQUEST);
packet_put_cstring("tcpip-forward");
packet_put_char(1); /* boolean: want reply */
packet_put_cstring(address_to_bind);
packet_put_char(1); /* boolean: want reply */
packet_put_cstring(channel_rfwd_bind_host(listen_host));
packet_put_int(listen_port);
packet_send();
packet_write_wait();
Expand Down Expand Up @@ -2917,13 +2969,13 @@ channel_request_remote_forwarding(const char *listen_host, u_short listen_port,
* Request cancellation of remote forwarding of connection host:port from
* local side.
*/
void
int
channel_request_rforward_cancel(const char *host, u_short port)
{
int i;

if (!compat20)
return;
return -1;

for (i = 0; i < num_permitted_opens; i++) {
if (permitted_opens[i].host_to_connect != NULL &&
Expand All @@ -2932,19 +2984,21 @@ channel_request_rforward_cancel(const char *host, u_short port)
}
if (i >= num_permitted_opens) {
debug("%s: requested forward not found", __func__);
return;
return -1;
}
packet_start(SSH2_MSG_GLOBAL_REQUEST);
packet_put_cstring("cancel-tcpip-forward");
packet_put_char(0);
packet_put_cstring(host == NULL ? "" : host);
packet_put_cstring(channel_rfwd_bind_host(host));
packet_put_int(port);
packet_send();

permitted_opens[i].listen_port = 0;
permitted_opens[i].port_to_connect = 0;
xfree(permitted_opens[i].host_to_connect);
permitted_opens[i].host_to_connect = NULL;

return 0;
}

/*
Expand Down
6 changes: 4 additions & 2 deletions channels.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* $OpenBSD: channels.h,v 1.105 2011/06/22 22:08:42 djm Exp $ */
/* $OpenBSD: channels.h,v 1.106 2011/09/09 22:46:44 djm Exp $ */

/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
Expand Down Expand Up @@ -116,6 +116,7 @@ struct Channel {
char *path;
/* path for unix domain sockets, or host name for forwards */
int listening_port; /* port being listened for forwards */
char *listening_addr; /* addr being listened for forwards */
int host_port; /* remote port to connect for forwards */
char *remote_name; /* remote hostname */

Expand Down Expand Up @@ -261,9 +262,10 @@ int channel_request_remote_forwarding(const char *, u_short,
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_request_rforward_cancel(const char *host, u_short port);
int channel_setup_remote_fwd_listener(const char *, u_short, int *, int);
int channel_cancel_rport_listener(const char *, u_short);
int channel_cancel_lport_listener(const char *, u_short, u_short, int);

/* x11 forwarding */

Expand Down
3 changes: 2 additions & 1 deletion clientloop.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* $OpenBSD: clientloop.h,v 1.28 2011/06/22 22:08:42 djm Exp $ */
/* $OpenBSD: clientloop.h,v 1.29 2011/09/09 22:46:44 djm Exp $ */

/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
Expand Down Expand Up @@ -70,6 +70,7 @@ void client_expect_confirm(int, const char *, enum confirm_action);
#define SSHMUX_COMMAND_STDIO_FWD 4 /* Open stdio fwd (ssh -W) */
#define SSHMUX_COMMAND_FORWARD 5 /* Forward only, no command */
#define SSHMUX_COMMAND_STOP 6 /* Disable mux but not conn */
#define SSHMUX_COMMAND_CANCEL_FWD 7 /* Cancel forwarding(s) */

void muxserver_listen(void);
void muxclient(const char *);
Expand Down
Loading

0 comments on commit f6dff7c

Please sign in to comment.