summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog6
-rw-r--r--PROTOCOL.mux13
-rw-r--r--clientloop.h3
-rw-r--r--mux.c113
-rw-r--r--readconf.c3
-rw-r--r--readconf.h3
-rw-r--r--ssh.111
-rw-r--r--ssh.c9
8 files changed, 141 insertions, 20 deletions
diff --git a/ChangeLog b/ChangeLog
index a485000a..fffbd727 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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
diff --git a/PROTOCOL.mux b/PROTOCOL.mux
index d22f7379..1d8c463a 100644
--- a/PROTOCOL.mux
+++ b/PROTOCOL.mux
@@ -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 $
diff --git a/clientloop.h b/clientloop.h
index 0b8257b9..a5bc246a 100644
--- a/clientloop.h
+++ b/clientloop.h
@@ -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 *);
diff --git a/mux.c b/mux.c
index 18dfd99f..3f5babcc 100644
--- a/mux.c
+++ b/mux.c
@@ -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__);
diff --git a/readconf.c b/readconf.c
index 8bdc8caf..4bc98b77 100644
--- a/readconf.c
+++ b/readconf.c
@@ -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
diff --git a/readconf.h b/readconf.h
index 4264751c..4fb29e2f 100644
--- a/readconf.h
+++ b/readconf.h
@@ -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. */
diff --git a/ssh.1 b/ssh.1
index 34bddbcb..2a0fd5dd 100644
--- a/ssh.1
+++ b/ssh.1
@@ -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
diff --git a/ssh.c b/ssh.c
index ee224e9f..228afecf 100644
--- a/ssh.c
+++ b/ssh.c
@@ -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) {