diff options
author | Damien Miller <djm@mindrot.org> | 2010-05-21 14:57:35 +1000 |
---|---|---|
committer | Damien Miller <djm@mindrot.org> | 2010-05-21 14:57:35 +1000 |
commit | 388f6fc48561851dcedd5433aff75f60af573fb2 (patch) | |
tree | 4ac7be863c3ba9be98df80c6d66953608cd77a6c /mux.c | |
parent | d530f5f471491b6be9edb58a063f2590e4dce48d (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@
Diffstat (limited to 'mux.c')
-rw-r--r-- | mux.c | 113 |
1 files changed, 105 insertions, 8 deletions
@@ -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 */ | ||
114 | struct 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 */ |
113 | int muxserver_sock = -1; | 121 | int 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 | ||
569 | static void | ||
570 | mux_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 | |||
560 | static int | 624 | static int |
561 | process_mux_open_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r) | 625 | process_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__); |