[PROTOCOL.mux clientloop.h mux.c readconf.c readconf.h ssh.1 ssh.c]
     mux support for remote forwarding with dynamic port allocation,
     use with
        LPORT=`ssh -S muxsocket -R0:localhost:25 -O forward somehost`
     feedback and ok djm@
This commit is contained in:
Damien Miller 2010-05-21 14:57:35 +10:00
parent d530f5f471
commit 388f6fc485
8 changed files with 141 additions and 20 deletions

View File

@ -23,6 +23,12 @@
the server.
motivated by and with feedback from markus@
- markus@cvs.openbsd.org 2010/05/16 12:55:51
[PROTOCOL.mux clientloop.h mux.c readconf.c readconf.h ssh.1 ssh.c]
mux support for remote forwarding with dynamic port allocation,
use with
LPORT=`ssh -S muxsocket -R0:localhost:25 -O forward somehost`
feedback and ok djm@
20100511
- (dtucker) [Makefile.in] Bug #1770: Link libopenbsd-compat twice to solve

View File

@ -109,8 +109,14 @@ A client may request the master to establish a port forward:
forwarding type may be MUX_FWD_LOCAL, MUX_FWD_REMOTE, MUX_FWD_DYNAMIC.
A server may reply with a MUX_S_OK, a MUX_S_PERMISSION_DENIED or a
MUX_S_FAILURE.
A server may reply with a MUX_S_OK, a MUX_S_REMOTE_PORT, a
MUX_S_PERMISSION_DENIED or a MUX_S_FAILURE.
For dynamically allocated listen port the server replies with
uint32 MUX_S_REMOTE_PORT
uint32 client request id
uint32 allocated remote listen port
5. Requesting closure of port forwards
@ -178,6 +184,7 @@ The MUX_S_PERMISSION_DENIED and MUX_S_FAILURE include a reason:
#define MUX_S_EXIT_MESSAGE 0x80000004
#define MUX_S_ALIVE 0x80000005
#define MUX_S_SESSION_OPENED 0x80000006
#define MUX_S_REMOTE_PORT 0x80000007
#define MUX_FWD_LOCAL 1
#define MUX_FWD_REMOTE 2
@ -193,4 +200,4 @@ XXX server->client error/warning notifications
XXX port0 rfwd (need custom response message)
XXX send signals via mux
$OpenBSD: PROTOCOL.mux,v 1.1 2010/01/26 01:28:35 djm Exp $
$OpenBSD: PROTOCOL.mux,v 1.2 2010/05/16 12:55:51 markus Exp $

View File

@ -1,4 +1,4 @@
/* $OpenBSD: clientloop.h,v 1.23 2010/01/26 01:28:35 djm Exp $ */
/* $OpenBSD: clientloop.h,v 1.24 2010/05/16 12:55:51 markus Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
@ -63,6 +63,7 @@ void client_register_global_confirm(global_confirm_cb *, void *);
#define SSHMUX_COMMAND_ALIVE_CHECK 2 /* Check master is alive */
#define SSHMUX_COMMAND_TERMINATE 3 /* Ask master to exit */
#define SSHMUX_COMMAND_STDIO_FWD 4 /* Open stdio fwd (ssh -W) */
#define SSHMUX_COMMAND_FORWARD 5 /* Forward only, no command */
void muxserver_listen(void);
void muxclient(const char *);

113
mux.c
View File

@ -1,4 +1,4 @@
/* $OpenBSD: mux.c,v 1.17 2010/05/14 23:29:23 djm Exp $ */
/* $OpenBSD: mux.c,v 1.18 2010/05/16 12:55:51 markus Exp $ */
/*
* Copyright (c) 2002-2008 Damien Miller <djm@openbsd.org>
*
@ -71,6 +71,7 @@
#include "xmalloc.h"
#include "log.h"
#include "ssh.h"
#include "ssh2.h"
#include "pathnames.h"
#include "misc.h"
#include "match.h"
@ -109,6 +110,13 @@ struct mux_session_confirm_ctx {
u_int rid;
};
/* Context for global channel callback */
struct mux_channel_confirm_ctx {
u_int cid; /* channel id */
u_int rid; /* request id */
int fid; /* forward id */
};
/* fd to control socket */
int muxserver_sock = -1;
@ -144,6 +152,7 @@ struct mux_master_state {
#define MUX_S_EXIT_MESSAGE 0x80000004
#define MUX_S_ALIVE 0x80000005
#define MUX_S_SESSION_OPENED 0x80000006
#define MUX_S_REMOTE_PORT 0x80000007
/* type codes for MUX_C_OPEN_FWD and MUX_C_CLOSE_FWD */
#define MUX_FWD_LOCAL 1
@ -557,6 +566,61 @@ compare_forward(Forward *a, Forward *b)
return 1;
}
static void
mux_confirm_remote_forward(int type, u_int32_t seq, void *ctxt)
{
struct mux_channel_confirm_ctx *fctx = ctxt;
char *failmsg = NULL;
Forward *rfwd;
Channel *c;
Buffer out;
if ((c = channel_by_id(fctx->cid)) == NULL) {
/* no channel for reply */
error("%s: unknown channel", __func__);
return;
}
buffer_init(&out);
if (fctx->fid >= options.num_remote_forwards) {
xasprintf(&failmsg, "unknown forwarding id %d", fctx->fid);
goto fail;
}
rfwd = &options.remote_forwards[fctx->fid];
debug("%s: %s for: listen %d, connect %s:%d", __func__,
type == SSH2_MSG_REQUEST_SUCCESS ? "success" : "failure",
rfwd->listen_port, rfwd->connect_host, rfwd->connect_port);
if (type == SSH2_MSG_REQUEST_SUCCESS) {
if (rfwd->listen_port == 0) {
rfwd->allocated_port = packet_get_int();
logit("Allocated port %u for mux remote forward"
" to %s:%d", rfwd->allocated_port,
rfwd->connect_host, rfwd->connect_port);
buffer_put_int(&out, MUX_S_REMOTE_PORT);
buffer_put_int(&out, fctx->rid);
buffer_put_int(&out, rfwd->allocated_port);
} else {
buffer_put_int(&out, MUX_S_OK);
buffer_put_int(&out, fctx->rid);
}
goto out;
} else {
xasprintf(&failmsg, "remote port forwarding failed for "
"listen port %d", rfwd->listen_port);
}
fail:
error("%s: %s", __func__, failmsg);
buffer_put_int(&out, MUX_S_FAILURE);
buffer_put_int(&out, fctx->rid);
buffer_put_cstring(&out, failmsg);
xfree(failmsg);
out:
buffer_put_string(&c->output, buffer_ptr(&out), buffer_len(&out));
buffer_free(&out);
if (c->mux_pause <= 0)
fatal("%s: mux_pause %d", __func__, c->mux_pause);
c->mux_pause = 0; /* start processing messages again */
}
static int
process_mux_open_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r)
{
@ -592,15 +656,16 @@ process_mux_open_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r)
ftype != MUX_FWD_DYNAMIC) {
logit("%s: invalid forwarding type %u", __func__, ftype);
invalid:
xfree(fwd.listen_host);
xfree(fwd.connect_host);
if (fwd.listen_host)
xfree(fwd.listen_host);
if (fwd.connect_host)
xfree(fwd.connect_host);
buffer_put_int(r, MUX_S_FAILURE);
buffer_put_int(r, rid);
buffer_put_cstring(r, "Invalid forwarding request");
return 0;
}
/* XXX support rport0 forwarding with reply of port assigned */
if (fwd.listen_port == 0 || fwd.listen_port >= 65536) {
if (fwd.listen_port >= 65536) {
logit("%s: invalid listen port %u", __func__,
fwd.listen_port);
goto invalid;
@ -635,8 +700,17 @@ process_mux_open_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r)
case MUX_FWD_REMOTE:
for (i = 0; i < options.num_remote_forwards; i++) {
if (compare_forward(&fwd,
options.remote_forwards + i))
goto exists;
options.remote_forwards + i)) {
if (fwd.listen_port != 0)
goto exists;
debug2("%s: found allocated port",
__func__);
buffer_put_int(r, MUX_S_REMOTE_PORT);
buffer_put_int(r, rid);
buffer_put_int(r,
options.remote_forwards[i].allocated_port);
goto out;
}
}
break;
}
@ -668,14 +742,24 @@ process_mux_open_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r)
add_local_forward(&options, &fwd);
freefwd = 0;
} else {
/* XXX wait for remote to confirm */
struct mux_channel_confirm_ctx *fctx;
if (options.num_remote_forwards + 1 >=
SSH_MAX_FORWARDS_PER_DIRECTION ||
channel_request_remote_forwarding(fwd.listen_host,
fwd.listen_port, fwd.connect_host, fwd.connect_port) < 0)
goto fail;
add_remote_forward(&options, &fwd);
fctx = xcalloc(1, sizeof(*fctx));
fctx->cid = c->self;
fctx->rid = rid;
fctx->fid = options.num_remote_forwards-1;
client_register_global_confirm(mux_confirm_remote_forward,
fctx);
freefwd = 0;
c->mux_pause = 1; /* wait for mux_confirm_remote_forward */
/* delayed reply in mux_confirm_remote_forward */
goto out;
}
buffer_put_int(r, MUX_S_OK);
buffer_put_int(r, rid);
@ -1392,6 +1476,15 @@ mux_client_request_forward(int fd, u_int ftype, Forward *fwd)
switch (type) {
case MUX_S_OK:
break;
case MUX_S_REMOTE_PORT:
fwd->allocated_port = buffer_get_int(&m);
logit("Allocated port %u for remote forward to %s:%d",
fwd->allocated_port,
fwd->connect_host ? fwd->connect_host : "",
fwd->connect_port);
if (muxclient_command == SSHMUX_COMMAND_FORWARD)
fprintf(stdout, "%u\n", fwd->allocated_port);
break;
case MUX_S_PERMISSION_DENIED:
e = buffer_get_string(&m, NULL);
buffer_free(&m);
@ -1758,6 +1851,10 @@ muxclient(const char *path)
mux_client_request_terminate(sock);
fprintf(stderr, "Exit request sent.\r\n");
exit(0);
case SSHMUX_COMMAND_FORWARD:
if (mux_client_request_forwards(sock) != 0)
fatal("%s: master forward request failed", __func__);
exit(0);
case SSHMUX_COMMAND_OPEN:
if (mux_client_request_forwards(sock) != 0) {
error("%s: master forward request failed", __func__);

View File

@ -1,4 +1,4 @@
/* $OpenBSD: readconf.c,v 1.183 2010/02/08 10:50:20 markus Exp $ */
/* $OpenBSD: readconf.c,v 1.184 2010/05/16 12:55:51 markus Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -283,6 +283,7 @@ add_remote_forward(Options *options, const Forward *newfwd)
fwd->listen_port = newfwd->listen_port;
fwd->connect_host = newfwd->connect_host;
fwd->connect_port = newfwd->connect_port;
fwd->allocated_port = 0;
}
static void

View File

@ -1,4 +1,4 @@
/* $OpenBSD: readconf.h,v 1.82 2010/02/08 10:50:20 markus Exp $ */
/* $OpenBSD: readconf.h,v 1.83 2010/05/16 12:55:51 markus Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
@ -23,6 +23,7 @@ typedef struct {
int listen_port; /* Port to forward. */
char *connect_host; /* Host to connect. */
int connect_port; /* Port to connect on connect_host. */
int allocated_port; /* Dynamically allocated listen port */
} Forward;
/* Data structure for representing option data. */

11
ssh.1
View File

@ -34,8 +34,8 @@
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
.\" $OpenBSD: ssh.1,v 1.304 2010/03/26 06:54:36 jmc Exp $
.Dd $Mdocdate: March 26 2010 $
.\" $OpenBSD: ssh.1,v 1.305 2010/05/16 12:55:51 markus Exp $
.Dd $Mdocdate: May 16 2010 $
.Dt SSH 1
.Os
.Sh NAME
@ -421,7 +421,9 @@ option is specified, the
argument is interpreted and passed to the master process.
Valid commands are:
.Dq check
(check that the master process is running) and
(check that the master process is running),
.Dq forward
(request forwardings without command execution) and
.Dq exit
(request the master to exit).
.It Fl o Ar option
@ -557,6 +559,9 @@ argument is
.Ql 0 ,
the listen port will be dynamically allocated on the server and reported
to the client at run time.
When used together with
.Ic -O forward
the allocated port will be printed to the standard output.
.It Fl S Ar ctl_path
Specifies the location of a control socket for connection sharing,
or the string

9
ssh.c
View File

@ -1,4 +1,4 @@
/* $OpenBSD: ssh.c,v 1.337 2010/05/14 23:29:23 djm Exp $ */
/* $OpenBSD: ssh.c,v 1.338 2010/05/16 12:55:51 markus Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -327,6 +327,8 @@ main(int ac, char **av)
fatal("Multiplexing command already specified");
if (strcmp(optarg, "check") == 0)
muxclient_command = SSHMUX_COMMAND_ALIVE_CHECK;
else if (strcmp(optarg, "forward") == 0)
muxclient_command = SSHMUX_COMMAND_FORWARD;
else if (strcmp(optarg, "exit") == 0)
muxclient_command = SSHMUX_COMMAND_TERMINATE;
else
@ -877,9 +879,10 @@ ssh_confirm_remote_forward(int type, u_int32_t seq, void *ctxt)
type == SSH2_MSG_REQUEST_SUCCESS ? "success" : "failure",
rfwd->listen_port, rfwd->connect_host, rfwd->connect_port);
if (type == SSH2_MSG_REQUEST_SUCCESS && rfwd->listen_port == 0) {
rfwd->allocated_port = packet_get_int();
logit("Allocated port %u for remote forward to %s:%d",
packet_get_int(),
rfwd->connect_host, rfwd->connect_port);
rfwd->allocated_port,
rfwd->connect_host, rfwd->connect_port);
}
if (type == SSH2_MSG_REQUEST_FAILURE) {