summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDamien Miller <djm@mindrot.org>2010-05-21 14:57:35 +1000
committerDamien Miller <djm@mindrot.org>2010-05-21 14:57:35 +1000
commit388f6fc48561851dcedd5433aff75f60af573fb2 (patch)
tree4ac7be863c3ba9be98df80c6d66953608cd77a6c
parentd530f5f471491b6be9edb58a063f2590e4dce48d (diff)
- 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@
-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 a485000a8..fffbd727e 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -23,6 +23,12 @@
23 the server. 23 the server.
24 24
25 motivated by and with feedback from markus@ 25 motivated by and with feedback from markus@
26 - markus@cvs.openbsd.org 2010/05/16 12:55:51
27 [PROTOCOL.mux clientloop.h mux.c readconf.c readconf.h ssh.1 ssh.c]
28 mux support for remote forwarding with dynamic port allocation,
29 use with
30 LPORT=`ssh -S muxsocket -R0:localhost:25 -O forward somehost`
31 feedback and ok djm@
26 32
2720100511 3320100511
28 - (dtucker) [Makefile.in] Bug #1770: Link libopenbsd-compat twice to solve 34 - (dtucker) [Makefile.in] Bug #1770: Link libopenbsd-compat twice to solve
diff --git a/PROTOCOL.mux b/PROTOCOL.mux
index d22f7379c..1d8c463a7 100644
--- a/PROTOCOL.mux
+++ b/PROTOCOL.mux
@@ -109,8 +109,14 @@ A client may request the master to establish a port forward:
109 109
110forwarding type may be MUX_FWD_LOCAL, MUX_FWD_REMOTE, MUX_FWD_DYNAMIC. 110forwarding type may be MUX_FWD_LOCAL, MUX_FWD_REMOTE, MUX_FWD_DYNAMIC.
111 111
112A server may reply with a MUX_S_OK, a MUX_S_PERMISSION_DENIED or a 112A server may reply with a MUX_S_OK, a MUX_S_REMOTE_PORT, a
113MUX_S_FAILURE. 113MUX_S_PERMISSION_DENIED or a MUX_S_FAILURE.
114
115For dynamically allocated listen port the server replies with
116
117 uint32 MUX_S_REMOTE_PORT
118 uint32 client request id
119 uint32 allocated remote listen port
114 120
1155. Requesting closure of port forwards 1215. Requesting closure of port forwards
116 122
@@ -178,6 +184,7 @@ The MUX_S_PERMISSION_DENIED and MUX_S_FAILURE include a reason:
178#define MUX_S_EXIT_MESSAGE 0x80000004 184#define MUX_S_EXIT_MESSAGE 0x80000004
179#define MUX_S_ALIVE 0x80000005 185#define MUX_S_ALIVE 0x80000005
180#define MUX_S_SESSION_OPENED 0x80000006 186#define MUX_S_SESSION_OPENED 0x80000006
187#define MUX_S_REMOTE_PORT 0x80000007
181 188
182#define MUX_FWD_LOCAL 1 189#define MUX_FWD_LOCAL 1
183#define MUX_FWD_REMOTE 2 190#define MUX_FWD_REMOTE 2
@@ -193,4 +200,4 @@ XXX server->client error/warning notifications
193XXX port0 rfwd (need custom response message) 200XXX port0 rfwd (need custom response message)
194XXX send signals via mux 201XXX send signals via mux
195 202
196$OpenBSD: PROTOCOL.mux,v 1.1 2010/01/26 01:28:35 djm Exp $ 203$OpenBSD: PROTOCOL.mux,v 1.2 2010/05/16 12:55:51 markus Exp $
diff --git a/clientloop.h b/clientloop.h
index 0b8257b99..a5bc246a3 100644
--- a/clientloop.h
+++ b/clientloop.h
@@ -1,4 +1,4 @@
1/* $OpenBSD: clientloop.h,v 1.23 2010/01/26 01:28:35 djm Exp $ */ 1/* $OpenBSD: clientloop.h,v 1.24 2010/05/16 12:55:51 markus Exp $ */
2 2
3/* 3/*
4 * Author: Tatu Ylonen <ylo@cs.hut.fi> 4 * Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -63,6 +63,7 @@ void client_register_global_confirm(global_confirm_cb *, void *);
63#define SSHMUX_COMMAND_ALIVE_CHECK 2 /* Check master is alive */ 63#define SSHMUX_COMMAND_ALIVE_CHECK 2 /* Check master is alive */
64#define SSHMUX_COMMAND_TERMINATE 3 /* Ask master to exit */ 64#define SSHMUX_COMMAND_TERMINATE 3 /* Ask master to exit */
65#define SSHMUX_COMMAND_STDIO_FWD 4 /* Open stdio fwd (ssh -W) */ 65#define SSHMUX_COMMAND_STDIO_FWD 4 /* Open stdio fwd (ssh -W) */
66#define SSHMUX_COMMAND_FORWARD 5 /* Forward only, no command */
66 67
67void muxserver_listen(void); 68void muxserver_listen(void);
68void muxclient(const char *); 69void muxclient(const char *);
diff --git a/mux.c b/mux.c
index 18dfd99f3..3f5babccc 100644
--- a/mux.c
+++ b/mux.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: mux.c,v 1.17 2010/05/14 23:29:23 djm Exp $ */ 1/* $OpenBSD: mux.c,v 1.18 2010/05/16 12:55:51 markus Exp $ */
2/* 2/*
3 * Copyright (c) 2002-2008 Damien Miller <djm@openbsd.org> 3 * Copyright (c) 2002-2008 Damien Miller <djm@openbsd.org>
4 * 4 *
@@ -71,6 +71,7 @@
71#include "xmalloc.h" 71#include "xmalloc.h"
72#include "log.h" 72#include "log.h"
73#include "ssh.h" 73#include "ssh.h"
74#include "ssh2.h"
74#include "pathnames.h" 75#include "pathnames.h"
75#include "misc.h" 76#include "misc.h"
76#include "match.h" 77#include "match.h"
@@ -109,6 +110,13 @@ struct mux_session_confirm_ctx {
109 u_int rid; 110 u_int rid;
110}; 111};
111 112
113/* Context for global channel callback */
114struct mux_channel_confirm_ctx {
115 u_int cid; /* channel id */
116 u_int rid; /* request id */
117 int fid; /* forward id */
118};
119
112/* fd to control socket */ 120/* fd to control socket */
113int muxserver_sock = -1; 121int muxserver_sock = -1;
114 122
@@ -144,6 +152,7 @@ struct mux_master_state {
144#define MUX_S_EXIT_MESSAGE 0x80000004 152#define MUX_S_EXIT_MESSAGE 0x80000004
145#define MUX_S_ALIVE 0x80000005 153#define MUX_S_ALIVE 0x80000005
146#define MUX_S_SESSION_OPENED 0x80000006 154#define MUX_S_SESSION_OPENED 0x80000006
155#define MUX_S_REMOTE_PORT 0x80000007
147 156
148/* type codes for MUX_C_OPEN_FWD and MUX_C_CLOSE_FWD */ 157/* type codes for MUX_C_OPEN_FWD and MUX_C_CLOSE_FWD */
149#define MUX_FWD_LOCAL 1 158#define MUX_FWD_LOCAL 1
@@ -557,6 +566,61 @@ compare_forward(Forward *a, Forward *b)
557 return 1; 566 return 1;
558} 567}
559 568
569static void
570mux_confirm_remote_forward(int type, u_int32_t seq, void *ctxt)
571{
572 struct mux_channel_confirm_ctx *fctx = ctxt;
573 char *failmsg = NULL;
574 Forward *rfwd;
575 Channel *c;
576 Buffer out;
577
578 if ((c = channel_by_id(fctx->cid)) == NULL) {
579 /* no channel for reply */
580 error("%s: unknown channel", __func__);
581 return;
582 }
583 buffer_init(&out);
584 if (fctx->fid >= options.num_remote_forwards) {
585 xasprintf(&failmsg, "unknown forwarding id %d", fctx->fid);
586 goto fail;
587 }
588 rfwd = &options.remote_forwards[fctx->fid];
589 debug("%s: %s for: listen %d, connect %s:%d", __func__,
590 type == SSH2_MSG_REQUEST_SUCCESS ? "success" : "failure",
591 rfwd->listen_port, rfwd->connect_host, rfwd->connect_port);
592 if (type == SSH2_MSG_REQUEST_SUCCESS) {
593 if (rfwd->listen_port == 0) {
594 rfwd->allocated_port = packet_get_int();
595 logit("Allocated port %u for mux remote forward"
596 " to %s:%d", rfwd->allocated_port,
597 rfwd->connect_host, rfwd->connect_port);
598 buffer_put_int(&out, MUX_S_REMOTE_PORT);
599 buffer_put_int(&out, fctx->rid);
600 buffer_put_int(&out, rfwd->allocated_port);
601 } else {
602 buffer_put_int(&out, MUX_S_OK);
603 buffer_put_int(&out, fctx->rid);
604 }
605 goto out;
606 } else {
607 xasprintf(&failmsg, "remote port forwarding failed for "
608 "listen port %d", rfwd->listen_port);
609 }
610 fail:
611 error("%s: %s", __func__, failmsg);
612 buffer_put_int(&out, MUX_S_FAILURE);
613 buffer_put_int(&out, fctx->rid);
614 buffer_put_cstring(&out, failmsg);
615 xfree(failmsg);
616 out:
617 buffer_put_string(&c->output, buffer_ptr(&out), buffer_len(&out));
618 buffer_free(&out);
619 if (c->mux_pause <= 0)
620 fatal("%s: mux_pause %d", __func__, c->mux_pause);
621 c->mux_pause = 0; /* start processing messages again */
622}
623
560static int 624static int
561process_mux_open_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r) 625process_mux_open_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r)
562{ 626{
@@ -592,15 +656,16 @@ process_mux_open_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r)
592 ftype != MUX_FWD_DYNAMIC) { 656 ftype != MUX_FWD_DYNAMIC) {
593 logit("%s: invalid forwarding type %u", __func__, ftype); 657 logit("%s: invalid forwarding type %u", __func__, ftype);
594 invalid: 658 invalid:
595 xfree(fwd.listen_host); 659 if (fwd.listen_host)
596 xfree(fwd.connect_host); 660 xfree(fwd.listen_host);
661 if (fwd.connect_host)
662 xfree(fwd.connect_host);
597 buffer_put_int(r, MUX_S_FAILURE); 663 buffer_put_int(r, MUX_S_FAILURE);
598 buffer_put_int(r, rid); 664 buffer_put_int(r, rid);
599 buffer_put_cstring(r, "Invalid forwarding request"); 665 buffer_put_cstring(r, "Invalid forwarding request");
600 return 0; 666 return 0;
601 } 667 }
602 /* XXX support rport0 forwarding with reply of port assigned */ 668 if (fwd.listen_port >= 65536) {
603 if (fwd.listen_port == 0 || fwd.listen_port >= 65536) {
604 logit("%s: invalid listen port %u", __func__, 669 logit("%s: invalid listen port %u", __func__,
605 fwd.listen_port); 670 fwd.listen_port);
606 goto invalid; 671 goto invalid;
@@ -635,8 +700,17 @@ process_mux_open_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r)
635 case MUX_FWD_REMOTE: 700 case MUX_FWD_REMOTE:
636 for (i = 0; i < options.num_remote_forwards; i++) { 701 for (i = 0; i < options.num_remote_forwards; i++) {
637 if (compare_forward(&fwd, 702 if (compare_forward(&fwd,
638 options.remote_forwards + i)) 703 options.remote_forwards + i)) {
639 goto exists; 704 if (fwd.listen_port != 0)
705 goto exists;
706 debug2("%s: found allocated port",
707 __func__);
708 buffer_put_int(r, MUX_S_REMOTE_PORT);
709 buffer_put_int(r, rid);
710 buffer_put_int(r,
711 options.remote_forwards[i].allocated_port);
712 goto out;
713 }
640 } 714 }
641 break; 715 break;
642 } 716 }
@@ -668,14 +742,24 @@ process_mux_open_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r)
668 add_local_forward(&options, &fwd); 742 add_local_forward(&options, &fwd);
669 freefwd = 0; 743 freefwd = 0;
670 } else { 744 } else {
671 /* XXX wait for remote to confirm */ 745 struct mux_channel_confirm_ctx *fctx;
746
672 if (options.num_remote_forwards + 1 >= 747 if (options.num_remote_forwards + 1 >=
673 SSH_MAX_FORWARDS_PER_DIRECTION || 748 SSH_MAX_FORWARDS_PER_DIRECTION ||
674 channel_request_remote_forwarding(fwd.listen_host, 749 channel_request_remote_forwarding(fwd.listen_host,
675 fwd.listen_port, fwd.connect_host, fwd.connect_port) < 0) 750 fwd.listen_port, fwd.connect_host, fwd.connect_port) < 0)
676 goto fail; 751 goto fail;
677 add_remote_forward(&options, &fwd); 752 add_remote_forward(&options, &fwd);
753 fctx = xcalloc(1, sizeof(*fctx));
754 fctx->cid = c->self;
755 fctx->rid = rid;
756 fctx->fid = options.num_remote_forwards-1;
757 client_register_global_confirm(mux_confirm_remote_forward,
758 fctx);
678 freefwd = 0; 759 freefwd = 0;
760 c->mux_pause = 1; /* wait for mux_confirm_remote_forward */
761 /* delayed reply in mux_confirm_remote_forward */
762 goto out;
679 } 763 }
680 buffer_put_int(r, MUX_S_OK); 764 buffer_put_int(r, MUX_S_OK);
681 buffer_put_int(r, rid); 765 buffer_put_int(r, rid);
@@ -1392,6 +1476,15 @@ mux_client_request_forward(int fd, u_int ftype, Forward *fwd)
1392 switch (type) { 1476 switch (type) {
1393 case MUX_S_OK: 1477 case MUX_S_OK:
1394 break; 1478 break;
1479 case MUX_S_REMOTE_PORT:
1480 fwd->allocated_port = buffer_get_int(&m);
1481 logit("Allocated port %u for remote forward to %s:%d",
1482 fwd->allocated_port,
1483 fwd->connect_host ? fwd->connect_host : "",
1484 fwd->connect_port);
1485 if (muxclient_command == SSHMUX_COMMAND_FORWARD)
1486 fprintf(stdout, "%u\n", fwd->allocated_port);
1487 break;
1395 case MUX_S_PERMISSION_DENIED: 1488 case MUX_S_PERMISSION_DENIED:
1396 e = buffer_get_string(&m, NULL); 1489 e = buffer_get_string(&m, NULL);
1397 buffer_free(&m); 1490 buffer_free(&m);
@@ -1758,6 +1851,10 @@ muxclient(const char *path)
1758 mux_client_request_terminate(sock); 1851 mux_client_request_terminate(sock);
1759 fprintf(stderr, "Exit request sent.\r\n"); 1852 fprintf(stderr, "Exit request sent.\r\n");
1760 exit(0); 1853 exit(0);
1854 case SSHMUX_COMMAND_FORWARD:
1855 if (mux_client_request_forwards(sock) != 0)
1856 fatal("%s: master forward request failed", __func__);
1857 exit(0);
1761 case SSHMUX_COMMAND_OPEN: 1858 case SSHMUX_COMMAND_OPEN:
1762 if (mux_client_request_forwards(sock) != 0) { 1859 if (mux_client_request_forwards(sock) != 0) {
1763 error("%s: master forward request failed", __func__); 1860 error("%s: master forward request failed", __func__);
diff --git a/readconf.c b/readconf.c
index 8bdc8caf1..4bc98b77e 100644
--- a/readconf.c
+++ b/readconf.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: readconf.c,v 1.183 2010/02/08 10:50:20 markus Exp $ */ 1/* $OpenBSD: readconf.c,v 1.184 2010/05/16 12:55:51 markus 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
@@ -283,6 +283,7 @@ add_remote_forward(Options *options, const Forward *newfwd)
283 fwd->listen_port = newfwd->listen_port; 283 fwd->listen_port = newfwd->listen_port;
284 fwd->connect_host = newfwd->connect_host; 284 fwd->connect_host = newfwd->connect_host;
285 fwd->connect_port = newfwd->connect_port; 285 fwd->connect_port = newfwd->connect_port;
286 fwd->allocated_port = 0;
286} 287}
287 288
288static void 289static void
diff --git a/readconf.h b/readconf.h
index 4264751c5..4fb29e2fa 100644
--- a/readconf.h
+++ b/readconf.h
@@ -1,4 +1,4 @@
1/* $OpenBSD: readconf.h,v 1.82 2010/02/08 10:50:20 markus Exp $ */ 1/* $OpenBSD: readconf.h,v 1.83 2010/05/16 12:55:51 markus Exp $ */
2 2
3/* 3/*
4 * Author: Tatu Ylonen <ylo@cs.hut.fi> 4 * Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -23,6 +23,7 @@ typedef struct {
23 int listen_port; /* Port to forward. */ 23 int listen_port; /* Port to forward. */
24 char *connect_host; /* Host to connect. */ 24 char *connect_host; /* Host to connect. */
25 int connect_port; /* Port to connect on connect_host. */ 25 int connect_port; /* Port to connect on connect_host. */
26 int allocated_port; /* Dynamically allocated listen port */
26} Forward; 27} Forward;
27/* Data structure for representing option data. */ 28/* Data structure for representing option data. */
28 29
diff --git a/ssh.1 b/ssh.1
index 34bddbcbc..2a0fd5ddd 100644
--- a/ssh.1
+++ b/ssh.1
@@ -34,8 +34,8 @@
34.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 34.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
35.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36.\" 36.\"
37.\" $OpenBSD: ssh.1,v 1.304 2010/03/26 06:54:36 jmc Exp $ 37.\" $OpenBSD: ssh.1,v 1.305 2010/05/16 12:55:51 markus Exp $
38.Dd $Mdocdate: March 26 2010 $ 38.Dd $Mdocdate: May 16 2010 $
39.Dt SSH 1 39.Dt SSH 1
40.Os 40.Os
41.Sh NAME 41.Sh NAME
@@ -421,7 +421,9 @@ option is specified, the
421argument is interpreted and passed to the master process. 421argument is interpreted and passed to the master process.
422Valid commands are: 422Valid commands are:
423.Dq check 423.Dq check
424(check that the master process is running) and 424(check that the master process is running),
425.Dq forward
426(request forwardings without command execution) and
425.Dq exit 427.Dq exit
426(request the master to exit). 428(request the master to exit).
427.It Fl o Ar option 429.It Fl o Ar option
@@ -557,6 +559,9 @@ argument is
557.Ql 0 , 559.Ql 0 ,
558the listen port will be dynamically allocated on the server and reported 560the listen port will be dynamically allocated on the server and reported
559to the client at run time. 561to the client at run time.
562When used together with
563.Ic -O forward
564the allocated port will be printed to the standard output.
560.It Fl S Ar ctl_path 565.It Fl S Ar ctl_path
561Specifies the location of a control socket for connection sharing, 566Specifies the location of a control socket for connection sharing,
562or the string 567or the string
diff --git a/ssh.c b/ssh.c
index ee224e9ff..228afecf4 100644
--- a/ssh.c
+++ b/ssh.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: ssh.c,v 1.337 2010/05/14 23:29:23 djm Exp $ */ 1/* $OpenBSD: ssh.c,v 1.338 2010/05/16 12:55:51 markus 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
@@ -327,6 +327,8 @@ main(int ac, char **av)
327 fatal("Multiplexing command already specified"); 327 fatal("Multiplexing command already specified");
328 if (strcmp(optarg, "check") == 0) 328 if (strcmp(optarg, "check") == 0)
329 muxclient_command = SSHMUX_COMMAND_ALIVE_CHECK; 329 muxclient_command = SSHMUX_COMMAND_ALIVE_CHECK;
330 else if (strcmp(optarg, "forward") == 0)
331 muxclient_command = SSHMUX_COMMAND_FORWARD;
330 else if (strcmp(optarg, "exit") == 0) 332 else if (strcmp(optarg, "exit") == 0)
331 muxclient_command = SSHMUX_COMMAND_TERMINATE; 333 muxclient_command = SSHMUX_COMMAND_TERMINATE;
332 else 334 else
@@ -877,9 +879,10 @@ ssh_confirm_remote_forward(int type, u_int32_t seq, void *ctxt)
877 type == SSH2_MSG_REQUEST_SUCCESS ? "success" : "failure", 879 type == SSH2_MSG_REQUEST_SUCCESS ? "success" : "failure",
878 rfwd->listen_port, rfwd->connect_host, rfwd->connect_port); 880 rfwd->listen_port, rfwd->connect_host, rfwd->connect_port);
879 if (type == SSH2_MSG_REQUEST_SUCCESS && rfwd->listen_port == 0) { 881 if (type == SSH2_MSG_REQUEST_SUCCESS && rfwd->listen_port == 0) {
882 rfwd->allocated_port = packet_get_int();
880 logit("Allocated port %u for remote forward to %s:%d", 883 logit("Allocated port %u for remote forward to %s:%d",
881 packet_get_int(), 884 rfwd->allocated_port,
882 rfwd->connect_host, rfwd->connect_port); 885 rfwd->connect_host, rfwd->connect_port);
883 } 886 }
884 887
885 if (type == SSH2_MSG_REQUEST_FAILURE) { 888 if (type == SSH2_MSG_REQUEST_FAILURE) {