summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormarkus@openbsd.org <markus@openbsd.org>2016-09-30 09:19:13 +0000
committerDamien Miller <djm@mindrot.org>2016-10-01 02:45:10 +1000
commit8d0578478586e283e751ca51e7b0690631da139a (patch)
tree3621da2b97213f8ff0b434f5fd239dfd4f50d83d
parentb7689155f3f5c4999846c07a852b1c7a43b09cec (diff)
upstream commit
ssh proxy mux mode (-O proxy; idea from Simon Tatham): - mux client speaks the ssh-packet protocol directly over unix-domain socket. - mux server acts as a proxy, translates channel IDs and relays to the server. - no filedescriptor passing necessary. - combined with unix-domain forwarding it's even possible to run mux client and server on different machines. feedback & ok djm@ Upstream-ID: 666a2fb79f58e5c50e246265fb2b9251e505c25b
-rw-r--r--channels.c392
-rw-r--r--channels.h12
-rw-r--r--clientloop.c45
-rw-r--r--clientloop.h5
-rw-r--r--mux.c69
-rw-r--r--opacket.h4
-rw-r--r--packet.c93
-rw-r--r--packet.h6
-rw-r--r--ssh.c27
9 files changed, 612 insertions, 41 deletions
diff --git a/channels.c b/channels.c
index 5d8c2a0c0..ae248414b 100644
--- a/channels.c
+++ b/channels.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: channels.c,v 1.353 2016/09/19 07:52:42 natano Exp $ */ 1/* $OpenBSD: channels.c,v 1.354 2016/09/30 09:19:13 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
@@ -71,6 +71,7 @@
71#include "ssh.h" 71#include "ssh.h"
72#include "ssh1.h" 72#include "ssh1.h"
73#include "ssh2.h" 73#include "ssh2.h"
74#include "ssherr.h"
74#include "packet.h" 75#include "packet.h"
75#include "log.h" 76#include "log.h"
76#include "misc.h" 77#include "misc.h"
@@ -120,6 +121,7 @@ typedef struct {
120 char *listen_host; /* Remote side should listen address. */ 121 char *listen_host; /* Remote side should listen address. */
121 char *listen_path; /* Remote side should listen path. */ 122 char *listen_path; /* Remote side should listen path. */
122 int listen_port; /* Remote side should listen port. */ 123 int listen_port; /* Remote side should listen port. */
124 Channel *downstream; /* Downstream mux*/
123} ForwardPermission; 125} ForwardPermission;
124 126
125/* List of all permitted host/port pairs to connect by the user. */ 127/* List of all permitted host/port pairs to connect by the user. */
@@ -183,6 +185,7 @@ static int IPv4or6 = AF_UNSPEC;
183 185
184/* helper */ 186/* helper */
185static void port_open_helper(Channel *c, char *rtype); 187static void port_open_helper(Channel *c, char *rtype);
188static const char *channel_rfwd_bind_host(const char *listen_host);
186 189
187/* non-blocking connect helpers */ 190/* non-blocking connect helpers */
188static int connect_next(struct channel_connect *); 191static int connect_next(struct channel_connect *);
@@ -207,6 +210,20 @@ channel_by_id(int id)
207 return c; 210 return c;
208} 211}
209 212
213Channel *
214channel_by_remote_id(int remote_id)
215{
216 Channel *c;
217 u_int i;
218
219 for (i = 0; i < channels_alloc; i++) {
220 c = channels[i];
221 if (c != NULL && c->remote_id == remote_id)
222 return c;
223 }
224 return NULL;
225}
226
210/* 227/*
211 * Returns the channel if it is allowed to receive protocol messages. 228 * Returns the channel if it is allowed to receive protocol messages.
212 * Private channels, like listening sockets, may not receive messages. 229 * Private channels, like listening sockets, may not receive messages.
@@ -229,6 +246,7 @@ channel_lookup(int id)
229 case SSH_CHANNEL_INPUT_DRAINING: 246 case SSH_CHANNEL_INPUT_DRAINING:
230 case SSH_CHANNEL_OUTPUT_DRAINING: 247 case SSH_CHANNEL_OUTPUT_DRAINING:
231 case SSH_CHANNEL_ABANDONED: 248 case SSH_CHANNEL_ABANDONED:
249 case SSH_CHANNEL_MUX_PROXY:
232 return (c); 250 return (c);
233 } 251 }
234 logit("Non-public channel %d, type %d.", id, c->type); 252 logit("Non-public channel %d, type %d.", id, c->type);
@@ -410,14 +428,56 @@ channel_free(Channel *c)
410{ 428{
411 char *s; 429 char *s;
412 u_int i, n; 430 u_int i, n;
431 Channel *other;
413 struct channel_confirm *cc; 432 struct channel_confirm *cc;
414 433
415 for (n = 0, i = 0; i < channels_alloc; i++) 434 for (n = 0, i = 0; i < channels_alloc; i++) {
416 if (channels[i]) 435 if ((other = channels[i]) != NULL) {
417 n++; 436 n++;
437
438 /* detach from mux client and prepare for closing */
439 if (c->type == SSH_CHANNEL_MUX_CLIENT &&
440 other->type == SSH_CHANNEL_MUX_PROXY &&
441 other->mux_ctx == c) {
442 other->mux_ctx = NULL;
443 other->type = SSH_CHANNEL_OPEN;
444 other->istate = CHAN_INPUT_CLOSED;
445 other->ostate = CHAN_OUTPUT_CLOSED;
446 }
447 }
448 }
418 debug("channel %d: free: %s, nchannels %u", c->self, 449 debug("channel %d: free: %s, nchannels %u", c->self,
419 c->remote_name ? c->remote_name : "???", n); 450 c->remote_name ? c->remote_name : "???", n);
420 451
452 /* XXX more MUX cleanup: remove remote forwardings */
453 if (c->type == SSH_CHANNEL_MUX_CLIENT) {
454 for (i = 0; i < (u_int)num_permitted_opens; i++) {
455 if (permitted_opens[i].downstream != c)
456 continue;
457 /* cancel on the server, since mux client is gone */
458 debug("channel %d: cleanup remote forward for %s:%u",
459 c->self,
460 permitted_opens[i].listen_host,
461 permitted_opens[i].listen_port);
462 packet_start(SSH2_MSG_GLOBAL_REQUEST);
463 packet_put_cstring("cancel-tcpip-forward");
464 packet_put_char(0);
465 packet_put_cstring(channel_rfwd_bind_host(
466 permitted_opens[i].listen_host));
467 packet_put_int(permitted_opens[i].listen_port);
468 packet_send();
469 /* unregister */
470 permitted_opens[i].listen_port = 0;
471 permitted_opens[i].port_to_connect = 0;
472 free(permitted_opens[i].host_to_connect);
473 permitted_opens[i].host_to_connect = NULL;
474 free(permitted_opens[i].listen_host);
475 permitted_opens[i].listen_host = NULL;
476 permitted_opens[i].listen_path = NULL;
477 permitted_opens[i].downstream = NULL;
478 }
479 }
480
421 s = channel_open_message(); 481 s = channel_open_message();
422 debug3("channel %d: status: %s", c->self, s); 482 debug3("channel %d: status: %s", c->self, s);
423 free(s); 483 free(s);
@@ -563,6 +623,7 @@ channel_still_open(void)
563 case SSH_CHANNEL_OPEN: 623 case SSH_CHANNEL_OPEN:
564 case SSH_CHANNEL_X11_OPEN: 624 case SSH_CHANNEL_X11_OPEN:
565 case SSH_CHANNEL_MUX_CLIENT: 625 case SSH_CHANNEL_MUX_CLIENT:
626 case SSH_CHANNEL_MUX_PROXY:
566 return 1; 627 return 1;
567 case SSH_CHANNEL_INPUT_DRAINING: 628 case SSH_CHANNEL_INPUT_DRAINING:
568 case SSH_CHANNEL_OUTPUT_DRAINING: 629 case SSH_CHANNEL_OUTPUT_DRAINING:
@@ -596,6 +657,7 @@ channel_find_open(void)
596 case SSH_CHANNEL_RPORT_LISTENER: 657 case SSH_CHANNEL_RPORT_LISTENER:
597 case SSH_CHANNEL_MUX_LISTENER: 658 case SSH_CHANNEL_MUX_LISTENER:
598 case SSH_CHANNEL_MUX_CLIENT: 659 case SSH_CHANNEL_MUX_CLIENT:
660 case SSH_CHANNEL_MUX_PROXY:
599 case SSH_CHANNEL_OPENING: 661 case SSH_CHANNEL_OPENING:
600 case SSH_CHANNEL_CONNECTING: 662 case SSH_CHANNEL_CONNECTING:
601 case SSH_CHANNEL_ZOMBIE: 663 case SSH_CHANNEL_ZOMBIE:
@@ -621,7 +683,6 @@ channel_find_open(void)
621 return -1; 683 return -1;
622} 684}
623 685
624
625/* 686/*
626 * Returns a message describing the currently open forwarded connections, 687 * Returns a message describing the currently open forwarded connections,
627 * suitable for sending to the client. The message contains crlf pairs for 688 * suitable for sending to the client. The message contains crlf pairs for
@@ -650,7 +711,6 @@ channel_open_message(void)
650 case SSH_CHANNEL_AUTH_SOCKET: 711 case SSH_CHANNEL_AUTH_SOCKET:
651 case SSH_CHANNEL_ZOMBIE: 712 case SSH_CHANNEL_ZOMBIE:
652 case SSH_CHANNEL_ABANDONED: 713 case SSH_CHANNEL_ABANDONED:
653 case SSH_CHANNEL_MUX_CLIENT:
654 case SSH_CHANNEL_MUX_LISTENER: 714 case SSH_CHANNEL_MUX_LISTENER:
655 case SSH_CHANNEL_UNIX_LISTENER: 715 case SSH_CHANNEL_UNIX_LISTENER:
656 case SSH_CHANNEL_RUNIX_LISTENER: 716 case SSH_CHANNEL_RUNIX_LISTENER:
@@ -663,6 +723,8 @@ channel_open_message(void)
663 case SSH_CHANNEL_X11_OPEN: 723 case SSH_CHANNEL_X11_OPEN:
664 case SSH_CHANNEL_INPUT_DRAINING: 724 case SSH_CHANNEL_INPUT_DRAINING:
665 case SSH_CHANNEL_OUTPUT_DRAINING: 725 case SSH_CHANNEL_OUTPUT_DRAINING:
726 case SSH_CHANNEL_MUX_PROXY:
727 case SSH_CHANNEL_MUX_CLIENT:
666 snprintf(buf, sizeof buf, 728 snprintf(buf, sizeof buf,
667 " #%d %.300s (t%d r%d i%u/%d o%u/%d fd %d/%d cc %d)\r\n", 729 " #%d %.300s (t%d r%d i%u/%d o%u/%d fd %d/%d cc %d)\r\n",
668 c->self, c->remote_name, 730 c->self, c->remote_name,
@@ -2360,6 +2422,278 @@ channel_output_poll(void)
2360 } 2422 }
2361} 2423}
2362 2424
2425/* -- mux proxy support */
2426
2427/*
2428 * When multiplexing channel messages for mux clients we have to deal
2429 * with downstream messages from the mux client and upstream messages
2430 * from the ssh server:
2431 * 1) Handling downstream messages is straightforward and happens
2432 * in channel_proxy_downstream():
2433 * - We forward all messages (mostly) unmodified to the server.
2434 * - However, in order to route messages from upstream to the correct
2435 * downstream client, we have to replace the channel IDs used by the
2436 * mux clients with a unique channel ID because the mux clients might
2437 * use conflicting channel IDs.
2438 * - so we inspect and change both SSH2_MSG_CHANNEL_OPEN and
2439 * SSH2_MSG_CHANNEL_OPEN_CONFIRMATION messages, create a local
2440 * SSH_CHANNEL_MUX_PROXY channel and replace the mux clients ID
2441 * with the newly allocated channel ID.
2442 * 2) Upstream messages are received by matching SSH_CHANNEL_MUX_PROXY
2443 * channels and procesed by channel_proxy_upstream(). The local channel ID
2444 * is then translated back to the original mux client ID.
2445 * 3) In both cases we need to keep track of matching SSH2_MSG_CHANNEL_CLOSE
2446 * messages so we can clean up SSH_CHANNEL_MUX_PROXY channels.
2447 * 4) The SSH_CHANNEL_MUX_PROXY channels also need to closed when the
2448 * downstream mux client are removed.
2449 * 5) Handling SSH2_MSG_CHANNEL_OPEN messages from the upstream server
2450 * requires more work, because they are not addressed to a specific
2451 * channel. E.g. client_request_forwarded_tcpip() needs to figure
2452 * out whether the request is addressed to the local client or a
2453 * specific downstream client based on the listen-address/port.
2454 * 6) Agent and X11-Forwarding have a similar problem and are currenly
2455 * not supported as the matching session/channel cannot be identified
2456 * easily.
2457 */
2458
2459/*
2460 * receive packets from downstream mux clients:
2461 * channel callback fired on read from mux client, creates
2462 * SSH_CHANNEL_MUX_PROXY channels and translates channel IDs
2463 * on channel creation.
2464 */
2465int
2466channel_proxy_downstream(Channel *downstream)
2467{
2468 Channel *c = NULL;
2469 struct ssh *ssh = active_state;
2470 struct sshbuf *original = NULL, *modified = NULL;
2471 const u_char *cp;
2472 char *ctype = NULL, *listen_host = NULL;
2473 u_char type;
2474 size_t have;
2475 int ret = -1, r, id, remote_id, listen_port, idx;
2476
2477 /* sshbuf_dump(&downstream->input, stderr); */
2478 if ((r = sshbuf_get_string_direct(&downstream->input, &cp, &have))
2479 != 0) {
2480 error("%s: malformed message: %s", __func__, ssh_err(r));
2481 return -1;
2482 }
2483 if (have < 2) {
2484 error("%s: short message", __func__);
2485 return -1;
2486 }
2487 type = cp[1];
2488 /* skip padlen + type */
2489 cp += 2;
2490 have -= 2;
2491 if (ssh_packet_log_type(type))
2492 debug3("%s: channel %u: down->up: type %u", __func__,
2493 downstream->self, type);
2494
2495 switch (type) {
2496 case SSH2_MSG_CHANNEL_OPEN:
2497 if ((original = sshbuf_from(cp, have)) == NULL ||
2498 (modified = sshbuf_new()) == NULL) {
2499 error("%s: alloc", __func__);
2500 goto out;
2501 }
2502 if ((r = sshbuf_get_cstring(original, &ctype, NULL)) != 0 ||
2503 (r = sshbuf_get_u32(original, &id)) != 0) {
2504 error("%s: parse error %s", __func__, ssh_err(r));
2505 goto out;
2506 }
2507 c = channel_new("mux proxy", SSH_CHANNEL_MUX_PROXY,
2508 -1, -1, -1, 0, 0, 0, ctype, 1);
2509 c->mux_ctx = downstream; /* point to mux client */
2510 c->mux_downstream_id = id; /* original downstream id */
2511 if ((r = sshbuf_put_cstring(modified, ctype)) != 0 ||
2512 (r = sshbuf_put_u32(modified, c->self)) != 0 ||
2513 (r = sshbuf_putb(modified, original)) != 0) {
2514 error("%s: compose error %s", __func__, ssh_err(r));
2515 channel_free(c);
2516 goto out;
2517 }
2518 break;
2519 case SSH2_MSG_CHANNEL_OPEN_CONFIRMATION:
2520 /*
2521 * Almost the same as SSH2_MSG_CHANNEL_OPEN, except then we
2522 * need to parse 'remote_id' instead of 'ctype'.
2523 */
2524 if ((original = sshbuf_from(cp, have)) == NULL ||
2525 (modified = sshbuf_new()) == NULL) {
2526 error("%s: alloc", __func__);
2527 goto out;
2528 }
2529 if ((r = sshbuf_get_u32(original, &remote_id)) != 0 ||
2530 (r = sshbuf_get_u32(original, &id)) != 0) {
2531 error("%s: parse error %s", __func__, ssh_err(r));
2532 goto out;
2533 }
2534 c = channel_new("mux proxy", SSH_CHANNEL_MUX_PROXY,
2535 -1, -1, -1, 0, 0, 0, "mux-down-connect", 1);
2536 c->mux_ctx = downstream; /* point to mux client */
2537 c->mux_downstream_id = id;
2538 c->remote_id = remote_id;
2539 if ((r = sshbuf_put_u32(modified, remote_id)) != 0 ||
2540 (r = sshbuf_put_u32(modified, c->self)) != 0 ||
2541 (r = sshbuf_putb(modified, original)) != 0) {
2542 error("%s: compose error %s", __func__, ssh_err(r));
2543 channel_free(c);
2544 goto out;
2545 }
2546 break;
2547 case SSH2_MSG_GLOBAL_REQUEST:
2548 if ((original = sshbuf_from(cp, have)) == NULL) {
2549 error("%s: alloc", __func__);
2550 goto out;
2551 }
2552 if ((r = sshbuf_get_cstring(original, &ctype, NULL)) != 0) {
2553 error("%s: parse error %s", __func__, ssh_err(r));
2554 goto out;
2555 }
2556 if (strcmp(ctype, "tcpip-forward") != 0) {
2557 error("%s: unsupported request %s", __func__, ctype);
2558 goto out;
2559 }
2560 if ((r = sshbuf_get_u8(original, NULL)) != 0 ||
2561 (r = sshbuf_get_cstring(original, &listen_host, NULL)) != 0 ||
2562 (r = sshbuf_get_u32(original, &listen_port)) != 0) {
2563 error("%s: parse error %s", __func__, ssh_err(r));
2564 goto out;
2565 }
2566 /* Record that connection to this host/port is permitted. */
2567 permitted_opens = xreallocarray(permitted_opens,
2568 num_permitted_opens + 1, sizeof(*permitted_opens));
2569 idx = num_permitted_opens++;
2570 permitted_opens[idx].host_to_connect = xstrdup("<mux>");
2571 permitted_opens[idx].port_to_connect = -1;
2572 permitted_opens[idx].listen_host = listen_host;
2573 permitted_opens[idx].listen_port = listen_port;
2574 permitted_opens[idx].downstream = downstream;
2575 listen_host = NULL;
2576 break;
2577 case SSH2_MSG_CHANNEL_CLOSE:
2578 if (have < 4)
2579 break;
2580 remote_id = PEEK_U32(cp);
2581 if ((c = channel_by_remote_id(remote_id)) != NULL) {
2582 if (c->flags & CHAN_CLOSE_RCVD)
2583 channel_free(c);
2584 else
2585 c->flags |= CHAN_CLOSE_SENT;
2586 }
2587 break;
2588 }
2589 if (modified) {
2590 if ((r = sshpkt_start(ssh, type)) != 0 ||
2591 (r = sshpkt_putb(ssh, modified)) != 0 ||
2592 (r = sshpkt_send(ssh)) != 0) {
2593 error("%s: send %s", __func__, ssh_err(r));
2594 goto out;
2595 }
2596 } else {
2597 if ((r = sshpkt_start(ssh, type)) != 0 ||
2598 (r = sshpkt_put(ssh, cp, have)) != 0 ||
2599 (r = sshpkt_send(ssh)) != 0) {
2600 error("%s: send %s", __func__, ssh_err(r));
2601 goto out;
2602 }
2603 }
2604 ret = 0;
2605 out:
2606 free(ctype);
2607 free(listen_host);
2608 sshbuf_free(original);
2609 sshbuf_free(modified);
2610 return ret;
2611}
2612
2613/*
2614 * receive packets from upstream server and de-multiplex packets
2615 * to correct downstream:
2616 * implemented as a helper for channel input handlers,
2617 * replaces local (proxy) channel ID with downstream channel ID.
2618 */
2619int
2620channel_proxy_upstream(Channel *c, int type, u_int32_t seq, void *ctxt)
2621{
2622 struct ssh *ssh = active_state;
2623 struct sshbuf *b = NULL;
2624 Channel *downstream;
2625 const u_char *cp = NULL;
2626 size_t len;
2627 int r;
2628
2629 /*
2630 * When receiving packets from the peer we need to check whether we
2631 * need to forward the packets to the mux client. In this case we
2632 * restore the orignal channel id and keep track of CLOSE messages,
2633 * so we can cleanup the channel.
2634 */
2635 if (c == NULL || c->type != SSH_CHANNEL_MUX_PROXY)
2636 return 0;
2637 if ((downstream = c->mux_ctx) == NULL)
2638 return 0;
2639 switch (type) {
2640 case SSH2_MSG_CHANNEL_CLOSE:
2641 case SSH2_MSG_CHANNEL_DATA:
2642 case SSH2_MSG_CHANNEL_EOF:
2643 case SSH2_MSG_CHANNEL_EXTENDED_DATA:
2644 case SSH2_MSG_CHANNEL_OPEN_CONFIRMATION:
2645 case SSH2_MSG_CHANNEL_OPEN_FAILURE:
2646 case SSH2_MSG_CHANNEL_WINDOW_ADJUST:
2647 case SSH2_MSG_CHANNEL_SUCCESS:
2648 case SSH2_MSG_CHANNEL_FAILURE:
2649 case SSH2_MSG_CHANNEL_REQUEST:
2650 break;
2651 default:
2652 debug2("%s: channel %u: unsupported type %u", __func__,
2653 c->self, type);
2654 return 0;
2655 }
2656 if ((b = sshbuf_new()) == NULL) {
2657 error("%s: alloc reply", __func__);
2658 goto out;
2659 }
2660 /* get remaining payload (after id) */
2661 cp = sshpkt_ptr(ssh, &len);
2662 if (cp == NULL) {
2663 error("%s: no packet", __func__);
2664 goto out;
2665 }
2666 /* translate id and send to muxclient */
2667 if ((r = sshbuf_put_u8(b, 0)) != 0 || /* padlen */
2668 (r = sshbuf_put_u8(b, type)) != 0 ||
2669 (r = sshbuf_put_u32(b, c->mux_downstream_id)) != 0 ||
2670 (r = sshbuf_put(b, cp, len)) != 0 ||
2671 (r = sshbuf_put_stringb(&downstream->output, b)) != 0) {
2672 error("%s: compose for muxclient %s", __func__, ssh_err(r));
2673 goto out;
2674 }
2675 /* sshbuf_dump(b, stderr); */
2676 if (ssh_packet_log_type(type))
2677 debug3("%s: channel %u: up->down: type %u", __func__, c->self,
2678 type);
2679 out:
2680 /* update state */
2681 switch (type) {
2682 case SSH2_MSG_CHANNEL_OPEN_CONFIRMATION:
2683 /* record remote_id for SSH2_MSG_CHANNEL_CLOSE */
2684 if (cp && len > 4)
2685 c->remote_id = PEEK_U32(cp);
2686 break;
2687 case SSH2_MSG_CHANNEL_CLOSE:
2688 if (c->flags & CHAN_CLOSE_SENT)
2689 channel_free(c);
2690 else
2691 c->flags |= CHAN_CLOSE_RCVD;
2692 break;
2693 }
2694 sshbuf_free(b);
2695 return 1;
2696}
2363 2697
2364/* -- protocol input */ 2698/* -- protocol input */
2365 2699
@@ -2377,6 +2711,8 @@ channel_input_data(int type, u_int32_t seq, void *ctxt)
2377 c = channel_lookup(id); 2711 c = channel_lookup(id);
2378 if (c == NULL) 2712 if (c == NULL)
2379 packet_disconnect("Received data for nonexistent channel %d.", id); 2713 packet_disconnect("Received data for nonexistent channel %d.", id);
2714 if (channel_proxy_upstream(c, type, seq, ctxt))
2715 return 0;
2380 2716
2381 /* Ignore any data for non-open channels (might happen on close) */ 2717 /* Ignore any data for non-open channels (might happen on close) */
2382 if (c->type != SSH_CHANNEL_OPEN && 2718 if (c->type != SSH_CHANNEL_OPEN &&
@@ -2439,6 +2775,8 @@ channel_input_extended_data(int type, u_int32_t seq, void *ctxt)
2439 2775
2440 if (c == NULL) 2776 if (c == NULL)
2441 packet_disconnect("Received extended_data for bad channel %d.", id); 2777 packet_disconnect("Received extended_data for bad channel %d.", id);
2778 if (channel_proxy_upstream(c, type, seq, ctxt))
2779 return 0;
2442 if (c->type != SSH_CHANNEL_OPEN) { 2780 if (c->type != SSH_CHANNEL_OPEN) {
2443 logit("channel %d: ext data for non open", id); 2781 logit("channel %d: ext data for non open", id);
2444 return 0; 2782 return 0;
@@ -2484,6 +2822,8 @@ channel_input_ieof(int type, u_int32_t seq, void *ctxt)
2484 c = channel_lookup(id); 2822 c = channel_lookup(id);
2485 if (c == NULL) 2823 if (c == NULL)
2486 packet_disconnect("Received ieof for nonexistent channel %d.", id); 2824 packet_disconnect("Received ieof for nonexistent channel %d.", id);
2825 if (channel_proxy_upstream(c, type, seq, ctxt))
2826 return 0;
2487 chan_rcvd_ieof(c); 2827 chan_rcvd_ieof(c);
2488 2828
2489 /* XXX force input close */ 2829 /* XXX force input close */
@@ -2508,7 +2848,8 @@ channel_input_close(int type, u_int32_t seq, void *ctxt)
2508 c = channel_lookup(id); 2848 c = channel_lookup(id);
2509 if (c == NULL) 2849 if (c == NULL)
2510 packet_disconnect("Received close for nonexistent channel %d.", id); 2850 packet_disconnect("Received close for nonexistent channel %d.", id);
2511 2851 if (channel_proxy_upstream(c, type, seq, ctxt))
2852 return 0;
2512 /* 2853 /*
2513 * Send a confirmation that we have closed the channel and no more 2854 * Send a confirmation that we have closed the channel and no more
2514 * data is coming for it. 2855 * data is coming for it.
@@ -2543,9 +2884,11 @@ channel_input_oclose(int type, u_int32_t seq, void *ctxt)
2543 int id = packet_get_int(); 2884 int id = packet_get_int();
2544 Channel *c = channel_lookup(id); 2885 Channel *c = channel_lookup(id);
2545 2886
2546 packet_check_eom();
2547 if (c == NULL) 2887 if (c == NULL)
2548 packet_disconnect("Received oclose for nonexistent channel %d.", id); 2888 packet_disconnect("Received oclose for nonexistent channel %d.", id);
2889 if (channel_proxy_upstream(c, type, seq, ctxt))
2890 return 0;
2891 packet_check_eom();
2549 chan_rcvd_oclose(c); 2892 chan_rcvd_oclose(c);
2550 return 0; 2893 return 0;
2551} 2894}
@@ -2557,10 +2900,12 @@ channel_input_close_confirmation(int type, u_int32_t seq, void *ctxt)
2557 int id = packet_get_int(); 2900 int id = packet_get_int();
2558 Channel *c = channel_lookup(id); 2901 Channel *c = channel_lookup(id);
2559 2902
2560 packet_check_eom();
2561 if (c == NULL) 2903 if (c == NULL)
2562 packet_disconnect("Received close confirmation for " 2904 packet_disconnect("Received close confirmation for "
2563 "out-of-range channel %d.", id); 2905 "out-of-range channel %d.", id);
2906 if (channel_proxy_upstream(c, type, seq, ctxt))
2907 return 0;
2908 packet_check_eom();
2564 if (c->type != SSH_CHANNEL_CLOSED && c->type != SSH_CHANNEL_ABANDONED) 2909 if (c->type != SSH_CHANNEL_CLOSED && c->type != SSH_CHANNEL_ABANDONED)
2565 packet_disconnect("Received close confirmation for " 2910 packet_disconnect("Received close confirmation for "
2566 "non-closed channel %d (type %d).", id, c->type); 2911 "non-closed channel %d (type %d).", id, c->type);
@@ -2578,7 +2923,12 @@ channel_input_open_confirmation(int type, u_int32_t seq, void *ctxt)
2578 id = packet_get_int(); 2923 id = packet_get_int();
2579 c = channel_lookup(id); 2924 c = channel_lookup(id);
2580 2925
2581 if (c==NULL || c->type != SSH_CHANNEL_OPENING) 2926 if (c==NULL)
2927 packet_disconnect("Received open confirmation for "
2928 "unknown channel %d.", id);
2929 if (channel_proxy_upstream(c, type, seq, ctxt))
2930 return 0;
2931 if (c->type != SSH_CHANNEL_OPENING)
2582 packet_disconnect("Received open confirmation for " 2932 packet_disconnect("Received open confirmation for "
2583 "non-opening channel %d.", id); 2933 "non-opening channel %d.", id);
2584 remote_id = packet_get_int(); 2934 remote_id = packet_get_int();
@@ -2628,7 +2978,12 @@ channel_input_open_failure(int type, u_int32_t seq, void *ctxt)
2628 id = packet_get_int(); 2978 id = packet_get_int();
2629 c = channel_lookup(id); 2979 c = channel_lookup(id);
2630 2980
2631 if (c==NULL || c->type != SSH_CHANNEL_OPENING) 2981 if (c==NULL)
2982 packet_disconnect("Received open failure for "
2983 "unknown channel %d.", id);
2984 if (channel_proxy_upstream(c, type, seq, ctxt))
2985 return 0;
2986 if (c->type != SSH_CHANNEL_OPENING)
2632 packet_disconnect("Received open failure for " 2987 packet_disconnect("Received open failure for "
2633 "non-opening channel %d.", id); 2988 "non-opening channel %d.", id);
2634 if (compat20) { 2989 if (compat20) {
@@ -2672,6 +3027,8 @@ channel_input_window_adjust(int type, u_int32_t seq, void *ctxt)
2672 logit("Received window adjust for non-open channel %d.", id); 3027 logit("Received window adjust for non-open channel %d.", id);
2673 return 0; 3028 return 0;
2674 } 3029 }
3030 if (channel_proxy_upstream(c, type, seq, ctxt))
3031 return 0;
2675 adjust = packet_get_int(); 3032 adjust = packet_get_int();
2676 packet_check_eom(); 3033 packet_check_eom();
2677 debug2("channel %d: rcvd adjust %u", id, adjust); 3034 debug2("channel %d: rcvd adjust %u", id, adjust);
@@ -2726,14 +3083,15 @@ channel_input_status_confirm(int type, u_int32_t seq, void *ctxt)
2726 packet_set_alive_timeouts(0); 3083 packet_set_alive_timeouts(0);
2727 3084
2728 id = packet_get_int(); 3085 id = packet_get_int();
2729 packet_check_eom();
2730
2731 debug2("channel_input_status_confirm: type %d id %d", type, id); 3086 debug2("channel_input_status_confirm: type %d id %d", type, id);
2732 3087
2733 if ((c = channel_lookup(id)) == NULL) { 3088 if ((c = channel_lookup(id)) == NULL) {
2734 logit("channel_input_status_confirm: %d: unknown", id); 3089 logit("channel_input_status_confirm: %d: unknown", id);
2735 return 0; 3090 return 0;
2736 } 3091 }
3092 if (channel_proxy_upstream(c, type, seq, ctxt))
3093 return 0;
3094 packet_check_eom();
2737 if ((cc = TAILQ_FIRST(&c->status_confirms)) == NULL) 3095 if ((cc = TAILQ_FIRST(&c->status_confirms)) == NULL)
2738 return 0; 3096 return 0;
2739 cc->cb(type, c, cc->ctx); 3097 cc->cb(type, c, cc->ctx);
@@ -3287,6 +3645,7 @@ channel_request_remote_forwarding(struct Forward *fwd)
3287 permitted_opens[idx].listen_path = NULL; 3645 permitted_opens[idx].listen_path = NULL;
3288 permitted_opens[idx].listen_port = fwd->listen_port; 3646 permitted_opens[idx].listen_port = fwd->listen_port;
3289 } 3647 }
3648 permitted_opens[idx].downstream = NULL;
3290 } 3649 }
3291 return (idx); 3650 return (idx);
3292} 3651}
@@ -3382,6 +3741,7 @@ channel_request_rforward_cancel_tcpip(const char *host, u_short port)
3382 free(permitted_opens[i].listen_host); 3741 free(permitted_opens[i].listen_host);
3383 permitted_opens[i].listen_host = NULL; 3742 permitted_opens[i].listen_host = NULL;
3384 permitted_opens[i].listen_path = NULL; 3743 permitted_opens[i].listen_path = NULL;
3744 permitted_opens[i].downstream = NULL;
3385 3745
3386 return 0; 3746 return 0;
3387} 3747}
@@ -3419,6 +3779,7 @@ channel_request_rforward_cancel_streamlocal(const char *path)
3419 permitted_opens[i].listen_host = NULL; 3779 permitted_opens[i].listen_host = NULL;
3420 free(permitted_opens[i].listen_path); 3780 free(permitted_opens[i].listen_path);
3421 permitted_opens[i].listen_path = NULL; 3781 permitted_opens[i].listen_path = NULL;
3782 permitted_opens[i].downstream = NULL;
3422 3783
3423 return 0; 3784 return 0;
3424} 3785}
@@ -3501,6 +3862,7 @@ channel_add_permitted_opens(char *host, int port)
3501 permitted_opens[num_permitted_opens].listen_host = NULL; 3862 permitted_opens[num_permitted_opens].listen_host = NULL;
3502 permitted_opens[num_permitted_opens].listen_path = NULL; 3863 permitted_opens[num_permitted_opens].listen_path = NULL;
3503 permitted_opens[num_permitted_opens].listen_port = 0; 3864 permitted_opens[num_permitted_opens].listen_port = 0;
3865 permitted_opens[num_permitted_opens].downstream = NULL;
3504 num_permitted_opens++; 3866 num_permitted_opens++;
3505 3867
3506 all_opens_permitted = 0; 3868 all_opens_permitted = 0;
@@ -3763,6 +4125,10 @@ connect_to(const char *name, int port, char *ctype, char *rname)
3763 return c; 4125 return c;
3764} 4126}
3765 4127
4128/*
4129 * returns either the newly connected channel or the downstream channel
4130 * that needs to deal with this connection.
4131 */
3766Channel * 4132Channel *
3767channel_connect_by_listen_address(const char *listen_host, 4133channel_connect_by_listen_address(const char *listen_host,
3768 u_short listen_port, char *ctype, char *rname) 4134 u_short listen_port, char *ctype, char *rname)
@@ -3772,6 +4138,8 @@ channel_connect_by_listen_address(const char *listen_host,
3772 for (i = 0; i < num_permitted_opens; i++) { 4138 for (i = 0; i < num_permitted_opens; i++) {
3773 if (open_listen_match_tcpip(&permitted_opens[i], listen_host, 4139 if (open_listen_match_tcpip(&permitted_opens[i], listen_host,
3774 listen_port, 1)) { 4140 listen_port, 1)) {
4141 if (permitted_opens[i].downstream)
4142 return permitted_opens[i].downstream;
3775 return connect_to( 4143 return connect_to(
3776 permitted_opens[i].host_to_connect, 4144 permitted_opens[i].host_to_connect,
3777 permitted_opens[i].port_to_connect, ctype, rname); 4145 permitted_opens[i].port_to_connect, ctype, rname);
diff --git a/channels.h b/channels.h
index 9d76c9d2a..95363e98a 100644
--- a/channels.h
+++ b/channels.h
@@ -1,4 +1,4 @@
1/* $OpenBSD: channels.h,v 1.118 2015/07/01 02:26:31 djm Exp $ */ 1/* $OpenBSD: channels.h,v 1.119 2016/09/30 09:19:13 markus Exp $ */
2 2
3/* 3/*
4 * Author: Tatu Ylonen <ylo@cs.hut.fi> 4 * Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -58,7 +58,8 @@
58#define SSH_CHANNEL_ABANDONED 17 /* Abandoned session, eg mux */ 58#define SSH_CHANNEL_ABANDONED 17 /* Abandoned session, eg mux */
59#define SSH_CHANNEL_UNIX_LISTENER 18 /* Listening on a domain socket. */ 59#define SSH_CHANNEL_UNIX_LISTENER 18 /* Listening on a domain socket. */
60#define SSH_CHANNEL_RUNIX_LISTENER 19 /* Listening to a R-style domain socket. */ 60#define SSH_CHANNEL_RUNIX_LISTENER 19 /* Listening to a R-style domain socket. */
61#define SSH_CHANNEL_MAX_TYPE 20 61#define SSH_CHANNEL_MUX_PROXY 20 /* proxy channel for mux-slave */
62#define SSH_CHANNEL_MAX_TYPE 21
62 63
63#define CHANNEL_CANCEL_PORT_STATIC -1 64#define CHANNEL_CANCEL_PORT_STATIC -1
64 65
@@ -162,6 +163,7 @@ struct Channel {
162 mux_callback_fn *mux_rcb; 163 mux_callback_fn *mux_rcb;
163 void *mux_ctx; 164 void *mux_ctx;
164 int mux_pause; 165 int mux_pause;
166 int mux_downstream_id;
165}; 167};
166 168
167#define CHAN_EXTENDED_IGNORE 0 169#define CHAN_EXTENDED_IGNORE 0
@@ -209,6 +211,7 @@ struct Channel {
209/* channel management */ 211/* channel management */
210 212
211Channel *channel_by_id(int); 213Channel *channel_by_id(int);
214Channel *channel_by_remote_id(int);
212Channel *channel_lookup(int); 215Channel *channel_lookup(int);
213Channel *channel_new(char *, int, int, int, int, u_int, u_int, int, char *, int); 216Channel *channel_new(char *, int, int, int, int, u_int, u_int, int, char *, int);
214void channel_set_fds(int, int, int, int, int, int, int, u_int); 217void channel_set_fds(int, int, int, int, int, int, int, u_int);
@@ -228,6 +231,11 @@ void channel_cancel_cleanup(int);
228int channel_close_fd(int *); 231int channel_close_fd(int *);
229void channel_send_window_changes(void); 232void channel_send_window_changes(void);
230 233
234/* mux proxy support */
235
236int channel_proxy_downstream(Channel *mc);
237int channel_proxy_upstream(Channel *, int, u_int32_t, void *);
238
231/* protocol handler */ 239/* protocol handler */
232 240
233int channel_input_close(int, u_int32_t, void *); 241int channel_input_close(int, u_int32_t, void *);
diff --git a/clientloop.c b/clientloop.c
index 58e712241..4289a4081 100644
--- a/clientloop.c
+++ b/clientloop.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: clientloop.c,v 1.288 2016/09/17 18:00:27 tedu Exp $ */ 1/* $OpenBSD: clientloop.c,v 1.289 2016/09/30 09:19:13 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
@@ -1883,11 +1883,14 @@ client_input_agent_open(int type, u_int32_t seq, void *ctxt)
1883} 1883}
1884 1884
1885static Channel * 1885static Channel *
1886client_request_forwarded_tcpip(const char *request_type, int rchan) 1886client_request_forwarded_tcpip(const char *request_type, int rchan,
1887 u_int rwindow, u_int rmaxpack)
1887{ 1888{
1888 Channel *c = NULL; 1889 Channel *c = NULL;
1890 struct sshbuf *b = NULL;
1889 char *listen_address, *originator_address; 1891 char *listen_address, *originator_address;
1890 u_short listen_port, originator_port; 1892 u_short listen_port, originator_port;
1893 int r;
1891 1894
1892 /* Get rest of the packet */ 1895 /* Get rest of the packet */
1893 listen_address = packet_get_string(NULL); 1896 listen_address = packet_get_string(NULL);
@@ -1902,6 +1905,31 @@ client_request_forwarded_tcpip(const char *request_type, int rchan)
1902 c = channel_connect_by_listen_address(listen_address, listen_port, 1905 c = channel_connect_by_listen_address(listen_address, listen_port,
1903 "forwarded-tcpip", originator_address); 1906 "forwarded-tcpip", originator_address);
1904 1907
1908 if (c != NULL && c->type == SSH_CHANNEL_MUX_CLIENT) {
1909 if ((b = sshbuf_new()) == NULL) {
1910 error("%s: alloc reply", __func__);
1911 goto out;
1912 }
1913 /* reconstruct and send to muxclient */
1914 if ((r = sshbuf_put_u8(b, 0)) != 0 || /* padlen */
1915 (r = sshbuf_put_u8(b, SSH2_MSG_CHANNEL_OPEN)) != 0 ||
1916 (r = sshbuf_put_cstring(b, request_type)) != 0 ||
1917 (r = sshbuf_put_u32(b, rchan)) != 0 ||
1918 (r = sshbuf_put_u32(b, rwindow)) != 0 ||
1919 (r = sshbuf_put_u32(b, rmaxpack)) != 0 ||
1920 (r = sshbuf_put_cstring(b, listen_address)) != 0 ||
1921 (r = sshbuf_put_u32(b, listen_port)) != 0 ||
1922 (r = sshbuf_put_cstring(b, originator_address)) != 0 ||
1923 (r = sshbuf_put_u32(b, originator_port)) != 0 ||
1924 (r = sshbuf_put_stringb(&c->output, b)) != 0) {
1925 error("%s: compose for muxclient %s", __func__,
1926 ssh_err(r));
1927 goto out;
1928 }
1929 }
1930
1931 out:
1932 sshbuf_free(b);
1905 free(originator_address); 1933 free(originator_address);
1906 free(listen_address); 1934 free(listen_address);
1907 return c; 1935 return c;
@@ -2057,7 +2085,8 @@ client_input_channel_open(int type, u_int32_t seq, void *ctxt)
2057 ctype, rchan, rwindow, rmaxpack); 2085 ctype, rchan, rwindow, rmaxpack);
2058 2086
2059 if (strcmp(ctype, "forwarded-tcpip") == 0) { 2087 if (strcmp(ctype, "forwarded-tcpip") == 0) {
2060 c = client_request_forwarded_tcpip(ctype, rchan); 2088 c = client_request_forwarded_tcpip(ctype, rchan, rwindow,
2089 rmaxpack);
2061 } else if (strcmp(ctype, "forwarded-streamlocal@openssh.com") == 0) { 2090 } else if (strcmp(ctype, "forwarded-streamlocal@openssh.com") == 0) {
2062 c = client_request_forwarded_streamlocal(ctype, rchan); 2091 c = client_request_forwarded_streamlocal(ctype, rchan);
2063 } else if (strcmp(ctype, "x11") == 0) { 2092 } else if (strcmp(ctype, "x11") == 0) {
@@ -2065,8 +2094,9 @@ client_input_channel_open(int type, u_int32_t seq, void *ctxt)
2065 } else if (strcmp(ctype, "auth-agent@openssh.com") == 0) { 2094 } else if (strcmp(ctype, "auth-agent@openssh.com") == 0) {
2066 c = client_request_agent(ctype, rchan); 2095 c = client_request_agent(ctype, rchan);
2067 } 2096 }
2068/* XXX duplicate : */ 2097 if (c != NULL && c->type == SSH_CHANNEL_MUX_CLIENT) {
2069 if (c != NULL) { 2098 debug3("proxied to downstream: %s", ctype);
2099 } else if (c != NULL) {
2070 debug("confirm %s", ctype); 2100 debug("confirm %s", ctype);
2071 c->remote_id = rchan; 2101 c->remote_id = rchan;
2072 c->remote_window = rwindow; 2102 c->remote_window = rwindow;
@@ -2102,6 +2132,9 @@ client_input_channel_req(int type, u_int32_t seq, void *ctxt)
2102 char *rtype; 2132 char *rtype;
2103 2133
2104 id = packet_get_int(); 2134 id = packet_get_int();
2135 c = channel_lookup(id);
2136 if (channel_proxy_upstream(c, type, seq, ctxt))
2137 return 0;
2105 rtype = packet_get_string(NULL); 2138 rtype = packet_get_string(NULL);
2106 reply = packet_get_char(); 2139 reply = packet_get_char();
2107 2140
@@ -2110,7 +2143,7 @@ client_input_channel_req(int type, u_int32_t seq, void *ctxt)
2110 2143
2111 if (id == -1) { 2144 if (id == -1) {
2112 error("client_input_channel_req: request for channel -1"); 2145 error("client_input_channel_req: request for channel -1");
2113 } else if ((c = channel_lookup(id)) == NULL) { 2146 } else if (c == NULL) {
2114 error("client_input_channel_req: channel %d: " 2147 error("client_input_channel_req: channel %d: "
2115 "unknown channel", id); 2148 "unknown channel", id);
2116 } else if (strcmp(rtype, "eow@openssh.com") == 0) { 2149 } else if (strcmp(rtype, "eow@openssh.com") == 0) {
diff --git a/clientloop.h b/clientloop.h
index f4d4c69b7..ae83aa8cf 100644
--- a/clientloop.h
+++ b/clientloop.h
@@ -1,4 +1,4 @@
1/* $OpenBSD: clientloop.h,v 1.32 2016/01/13 23:04:47 djm Exp $ */ 1/* $OpenBSD: clientloop.h,v 1.33 2016/09/30 09:19:13 markus Exp $ */
2 2
3/* 3/*
4 * Author: Tatu Ylonen <ylo@cs.hut.fi> 4 * Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -71,9 +71,10 @@ void client_expect_confirm(int, const char *, enum confirm_action);
71#define SSHMUX_COMMAND_FORWARD 5 /* Forward only, no command */ 71#define SSHMUX_COMMAND_FORWARD 5 /* Forward only, no command */
72#define SSHMUX_COMMAND_STOP 6 /* Disable mux but not conn */ 72#define SSHMUX_COMMAND_STOP 6 /* Disable mux but not conn */
73#define SSHMUX_COMMAND_CANCEL_FWD 7 /* Cancel forwarding(s) */ 73#define SSHMUX_COMMAND_CANCEL_FWD 7 /* Cancel forwarding(s) */
74#define SSHMUX_COMMAND_PROXY 8 /* Open new connection */
74 75
75void muxserver_listen(void); 76void muxserver_listen(void);
76void muxclient(const char *); 77int muxclient(const char *);
77void mux_exit_message(Channel *, int); 78void mux_exit_message(Channel *, int);
78void mux_tty_alloc_failed(Channel *); 79void mux_tty_alloc_failed(Channel *);
79 80
diff --git a/mux.c b/mux.c
index a8a753b54..ec42bf520 100644
--- a/mux.c
+++ b/mux.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: mux.c,v 1.61 2016/08/08 22:40:57 dtucker Exp $ */ 1/* $OpenBSD: mux.c,v 1.62 2016/09/30 09:19:13 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 *
@@ -79,6 +79,7 @@
79#include "key.h" 79#include "key.h"
80#include "readconf.h" 80#include "readconf.h"
81#include "clientloop.h" 81#include "clientloop.h"
82#include "ssherr.h"
82 83
83/* from ssh.c */ 84/* from ssh.c */
84extern int tty_flag; 85extern int tty_flag;
@@ -144,6 +145,7 @@ struct mux_master_state {
144#define MUX_C_CLOSE_FWD 0x10000007 145#define MUX_C_CLOSE_FWD 0x10000007
145#define MUX_C_NEW_STDIO_FWD 0x10000008 146#define MUX_C_NEW_STDIO_FWD 0x10000008
146#define MUX_C_STOP_LISTENING 0x10000009 147#define MUX_C_STOP_LISTENING 0x10000009
148#define MUX_C_PROXY 0x1000000f
147#define MUX_S_OK 0x80000001 149#define MUX_S_OK 0x80000001
148#define MUX_S_PERMISSION_DENIED 0x80000002 150#define MUX_S_PERMISSION_DENIED 0x80000002
149#define MUX_S_FAILURE 0x80000003 151#define MUX_S_FAILURE 0x80000003
@@ -152,6 +154,7 @@ struct mux_master_state {
152#define MUX_S_SESSION_OPENED 0x80000006 154#define MUX_S_SESSION_OPENED 0x80000006
153#define MUX_S_REMOTE_PORT 0x80000007 155#define MUX_S_REMOTE_PORT 0x80000007
154#define MUX_S_TTY_ALLOC_FAIL 0x80000008 156#define MUX_S_TTY_ALLOC_FAIL 0x80000008
157#define MUX_S_PROXY 0x8000000f
155 158
156/* type codes for MUX_C_OPEN_FWD and MUX_C_CLOSE_FWD */ 159/* type codes for MUX_C_OPEN_FWD and MUX_C_CLOSE_FWD */
157#define MUX_FWD_LOCAL 1 160#define MUX_FWD_LOCAL 1
@@ -169,6 +172,7 @@ static int process_mux_open_fwd(u_int, Channel *, Buffer *, Buffer *);
169static int process_mux_close_fwd(u_int, Channel *, Buffer *, Buffer *); 172static int process_mux_close_fwd(u_int, Channel *, Buffer *, Buffer *);
170static int process_mux_stdio_fwd(u_int, Channel *, Buffer *, Buffer *); 173static int process_mux_stdio_fwd(u_int, Channel *, Buffer *, Buffer *);
171static int process_mux_stop_listening(u_int, Channel *, Buffer *, Buffer *); 174static int process_mux_stop_listening(u_int, Channel *, Buffer *, Buffer *);
175static int process_mux_proxy(u_int, Channel *, Buffer *, Buffer *);
172 176
173static const struct { 177static const struct {
174 u_int type; 178 u_int type;
@@ -182,6 +186,7 @@ static const struct {
182 { MUX_C_CLOSE_FWD, process_mux_close_fwd }, 186 { MUX_C_CLOSE_FWD, process_mux_close_fwd },
183 { MUX_C_NEW_STDIO_FWD, process_mux_stdio_fwd }, 187 { MUX_C_NEW_STDIO_FWD, process_mux_stdio_fwd },
184 { MUX_C_STOP_LISTENING, process_mux_stop_listening }, 188 { MUX_C_STOP_LISTENING, process_mux_stop_listening },
189 { MUX_C_PROXY, process_mux_proxy },
185 { 0, NULL } 190 { 0, NULL }
186}; 191};
187 192
@@ -1110,6 +1115,18 @@ process_mux_stop_listening(u_int rid, Channel *c, Buffer *m, Buffer *r)
1110 return 0; 1115 return 0;
1111} 1116}
1112 1117
1118static int
1119process_mux_proxy(u_int rid, Channel *c, Buffer *m, Buffer *r)
1120{
1121 debug("%s: channel %d: proxy request", __func__, c->self);
1122
1123 c->mux_rcb = channel_proxy_downstream;
1124 buffer_put_int(r, MUX_S_PROXY);
1125 buffer_put_int(r, rid);
1126
1127 return 0;
1128}
1129
1113/* Channel callbacks fired on read/write from mux slave fd */ 1130/* Channel callbacks fired on read/write from mux slave fd */
1114static int 1131static int
1115mux_master_read_cb(Channel *c) 1132mux_master_read_cb(Channel *c)
@@ -1960,6 +1977,41 @@ mux_client_request_session(int fd)
1960} 1977}
1961 1978
1962static int 1979static int
1980mux_client_proxy(int fd)
1981{
1982 Buffer m;
1983 char *e;
1984 u_int type, rid;
1985
1986 buffer_init(&m);
1987 buffer_put_int(&m, MUX_C_PROXY);
1988 buffer_put_int(&m, muxclient_request_id);
1989 if (mux_client_write_packet(fd, &m) != 0)
1990 fatal("%s: write packet: %s", __func__, strerror(errno));
1991
1992 buffer_clear(&m);
1993
1994 /* Read their reply */
1995 if (mux_client_read_packet(fd, &m) != 0) {
1996 buffer_free(&m);
1997 return 0;
1998 }
1999 type = buffer_get_int(&m);
2000 if (type != MUX_S_PROXY) {
2001 e = buffer_get_string(&m, NULL);
2002 fatal("%s: master returned error: %s", __func__, e);
2003 }
2004 if ((rid = buffer_get_int(&m)) != muxclient_request_id)
2005 fatal("%s: out of sequence reply: my id %u theirs %u",
2006 __func__, muxclient_request_id, rid);
2007 buffer_free(&m);
2008
2009 debug3("%s: done", __func__);
2010 muxclient_request_id++;
2011 return 0;
2012}
2013
2014static int
1963mux_client_request_stdio_fwd(int fd) 2015mux_client_request_stdio_fwd(int fd)
1964{ 2016{
1965 Buffer m; 2017 Buffer m;
@@ -2105,7 +2157,7 @@ mux_client_request_stop_listening(int fd)
2105} 2157}
2106 2158
2107/* Multiplex client main loop. */ 2159/* Multiplex client main loop. */
2108void 2160int
2109muxclient(const char *path) 2161muxclient(const char *path)
2110{ 2162{
2111 struct sockaddr_un addr; 2163 struct sockaddr_un addr;
@@ -2128,7 +2180,7 @@ muxclient(const char *path)
2128 case SSHCTL_MASTER_NO: 2180 case SSHCTL_MASTER_NO:
2129 break; 2181 break;
2130 default: 2182 default:
2131 return; 2183 return -1;
2132 } 2184 }
2133 2185
2134 memset(&addr, '\0', sizeof(addr)); 2186 memset(&addr, '\0', sizeof(addr));
@@ -2164,14 +2216,14 @@ muxclient(const char *path)
2164 strerror(errno)); 2216 strerror(errno));
2165 } 2217 }
2166 close(sock); 2218 close(sock);
2167 return; 2219 return -1;
2168 } 2220 }
2169 set_nonblock(sock); 2221 set_nonblock(sock);
2170 2222
2171 if (mux_client_hello_exchange(sock) != 0) { 2223 if (mux_client_hello_exchange(sock) != 0) {
2172 error("%s: master hello exchange failed", __func__); 2224 error("%s: master hello exchange failed", __func__);
2173 close(sock); 2225 close(sock);
2174 return; 2226 return -1;
2175 } 2227 }
2176 2228
2177 switch (muxclient_command) { 2229 switch (muxclient_command) {
@@ -2191,10 +2243,10 @@ muxclient(const char *path)
2191 case SSHMUX_COMMAND_OPEN: 2243 case SSHMUX_COMMAND_OPEN:
2192 if (mux_client_forwards(sock, 0) != 0) { 2244 if (mux_client_forwards(sock, 0) != 0) {
2193 error("%s: master forward request failed", __func__); 2245 error("%s: master forward request failed", __func__);
2194 return; 2246 return -1;
2195 } 2247 }
2196 mux_client_request_session(sock); 2248 mux_client_request_session(sock);
2197 return; 2249 return -1;
2198 case SSHMUX_COMMAND_STDIO_FWD: 2250 case SSHMUX_COMMAND_STDIO_FWD:
2199 mux_client_request_stdio_fwd(sock); 2251 mux_client_request_stdio_fwd(sock);
2200 exit(0); 2252 exit(0);
@@ -2207,6 +2259,9 @@ muxclient(const char *path)
2207 error("%s: master cancel forward request failed", 2259 error("%s: master cancel forward request failed",
2208 __func__); 2260 __func__);
2209 exit(0); 2261 exit(0);
2262 case SSHMUX_COMMAND_PROXY:
2263 mux_client_proxy(sock);
2264 return (sock);
2210 default: 2265 default:
2211 fatal("unrecognised muxclient_command %d", muxclient_command); 2266 fatal("unrecognised muxclient_command %d", muxclient_command);
2212 } 2267 }
diff --git a/opacket.h b/opacket.h
index d2a63a355..c487f4f40 100644
--- a/opacket.h
+++ b/opacket.h
@@ -153,5 +153,9 @@ void packet_disconnect(const char *, ...)
153 ssh_packet_set_rekey_limits(active_state, x, y) 153 ssh_packet_set_rekey_limits(active_state, x, y)
154#define packet_get_bytes(x,y) \ 154#define packet_get_bytes(x,y) \
155 ssh_packet_get_bytes(active_state, x, y) 155 ssh_packet_get_bytes(active_state, x, y)
156#define packet_set_mux() \
157 ssh_packet_set_mux(active_state)
158#define packet_get_mux() \
159 ssh_packet_get_mux(active_state)
156 160
157#endif /* _OPACKET_H */ 161#endif /* _OPACKET_H */
diff --git a/packet.c b/packet.c
index 50de0267a..783ae5bd4 100644
--- a/packet.c
+++ b/packet.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: packet.c,v 1.241 2016/09/28 21:44:52 djm Exp $ */ 1/* $OpenBSD: packet.c,v 1.242 2016/09/30 09:19:13 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
@@ -204,6 +204,9 @@ struct session_state {
204 /* Used in packet_send2 */ 204 /* Used in packet_send2 */
205 int rekeying; 205 int rekeying;
206 206
207 /* Used in ssh_packet_send_mux() */
208 int mux;
209
207 /* Used in packet_set_interactive */ 210 /* Used in packet_set_interactive */
208 int set_interactive_called; 211 int set_interactive_called;
209 212
@@ -325,6 +328,19 @@ ssh_packet_set_timeout(struct ssh *ssh, int timeout, int count)
325 state->packet_timeout_ms = timeout * count * 1000; 328 state->packet_timeout_ms = timeout * count * 1000;
326} 329}
327 330
331void
332ssh_packet_set_mux(struct ssh *ssh)
333{
334 ssh->state->mux = 1;
335 ssh->state->rekeying = 0;
336}
337
338int
339ssh_packet_get_mux(struct ssh *ssh)
340{
341 return ssh->state->mux;
342}
343
328int 344int
329ssh_packet_stop_discard(struct ssh *ssh) 345ssh_packet_stop_discard(struct ssh *ssh)
330{ 346{
@@ -1078,7 +1094,7 @@ ssh_packet_enable_delayed_compress(struct ssh *ssh)
1078} 1094}
1079 1095
1080/* Used to mute debug logging for noisy packet types */ 1096/* Used to mute debug logging for noisy packet types */
1081static int 1097int
1082ssh_packet_log_type(u_char type) 1098ssh_packet_log_type(u_char type)
1083{ 1099{
1084 switch (type) { 1100 switch (type) {
@@ -1623,6 +1639,44 @@ ssh_packet_read_poll1(struct ssh *ssh, u_char *typep)
1623 return r; 1639 return r;
1624} 1640}
1625 1641
1642static int
1643ssh_packet_read_poll2_mux(struct ssh *ssh, u_char *typep, u_int32_t *seqnr_p)
1644{
1645 struct session_state *state = ssh->state;
1646 const u_char *cp;
1647 size_t need;
1648 int r;
1649
1650 if (ssh->kex)
1651 return SSH_ERR_INTERNAL_ERROR;
1652 *typep = SSH_MSG_NONE;
1653 cp = sshbuf_ptr(state->input);
1654 if (state->packlen == 0) {
1655 if (sshbuf_len(state->input) < 4 + 1)
1656 return 0; /* packet is incomplete */
1657 state->packlen = PEEK_U32(cp);
1658 if (state->packlen < 4 + 1 ||
1659 state->packlen > PACKET_MAX_SIZE)
1660 return SSH_ERR_MESSAGE_INCOMPLETE;
1661 }
1662 need = state->packlen + 4;
1663 if (sshbuf_len(state->input) < need)
1664 return 0; /* packet is incomplete */
1665 sshbuf_reset(state->incoming_packet);
1666 if ((r = sshbuf_put(state->incoming_packet, cp + 4,
1667 state->packlen)) != 0 ||
1668 (r = sshbuf_consume(state->input, need)) != 0 ||
1669 (r = sshbuf_get_u8(state->incoming_packet, NULL)) != 0 ||
1670 (r = sshbuf_get_u8(state->incoming_packet, typep)) != 0)
1671 return r;
1672 if (ssh_packet_log_type(*typep))
1673 debug3("%s: type %u", __func__, *typep);
1674 /* sshbuf_dump(state->incoming_packet, stderr); */
1675 /* reset for next packet */
1676 state->packlen = 0;
1677 return r;
1678}
1679
1626int 1680int
1627ssh_packet_read_poll2(struct ssh *ssh, u_char *typep, u_int32_t *seqnr_p) 1681ssh_packet_read_poll2(struct ssh *ssh, u_char *typep, u_int32_t *seqnr_p)
1628{ 1682{
@@ -1635,6 +1689,9 @@ ssh_packet_read_poll2(struct ssh *ssh, u_char *typep, u_int32_t *seqnr_p)
1635 struct sshcomp *comp = NULL; 1689 struct sshcomp *comp = NULL;
1636 int r; 1690 int r;
1637 1691
1692 if (state->mux)
1693 return ssh_packet_read_poll2_mux(ssh, typep, seqnr_p);
1694
1638 *typep = SSH_MSG_NONE; 1695 *typep = SSH_MSG_NONE;
1639 1696
1640 if (state->packet_discard) 1697 if (state->packet_discard)
@@ -2875,11 +2932,43 @@ sshpkt_start(struct ssh *ssh, u_char type)
2875 return sshbuf_put(ssh->state->outgoing_packet, buf, len); 2932 return sshbuf_put(ssh->state->outgoing_packet, buf, len);
2876} 2933}
2877 2934
2935static int
2936ssh_packet_send_mux(struct ssh *ssh)
2937{
2938 struct session_state *state = ssh->state;
2939 u_char type, *cp;
2940 size_t len;
2941 int r;
2942
2943 if (ssh->kex)
2944 return SSH_ERR_INTERNAL_ERROR;
2945 len = sshbuf_len(state->outgoing_packet);
2946 if (len < 6)
2947 return SSH_ERR_INTERNAL_ERROR;
2948 cp = sshbuf_mutable_ptr(state->outgoing_packet);
2949 type = cp[5];
2950 if (ssh_packet_log_type(type))
2951 debug3("%s: type %u", __func__, type);
2952 /* drop everything, but the connection protocol */
2953 if (type >= SSH2_MSG_CONNECTION_MIN &&
2954 type <= SSH2_MSG_CONNECTION_MAX) {
2955 POKE_U32(cp, len - 4);
2956 if ((r = sshbuf_putb(state->output,
2957 state->outgoing_packet)) != 0)
2958 return r;
2959 /* sshbuf_dump(state->output, stderr); */
2960 }
2961 sshbuf_reset(state->outgoing_packet);
2962 return 0;
2963}
2964
2878/* send it */ 2965/* send it */
2879 2966
2880int 2967int
2881sshpkt_send(struct ssh *ssh) 2968sshpkt_send(struct ssh *ssh)
2882{ 2969{
2970 if (ssh->state && ssh->state->mux)
2971 return ssh_packet_send_mux(ssh);
2883 if (compat20) 2972 if (compat20)
2884 return ssh_packet_send2(ssh); 2973 return ssh_packet_send2(ssh);
2885 else 2974 else
diff --git a/packet.h b/packet.h
index 690f2ec7e..0a64eb2a5 100644
--- a/packet.h
+++ b/packet.h
@@ -1,4 +1,4 @@
1/* $OpenBSD: packet.h,v 1.72 2016/09/28 16:33:07 djm Exp $ */ 1/* $OpenBSD: packet.h,v 1.73 2016/09/30 09:19:13 markus Exp $ */
2 2
3/* 3/*
4 * Author: Tatu Ylonen <ylo@cs.hut.fi> 4 * Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -97,6 +97,10 @@ void ssh_packet_set_interactive(struct ssh *, int, int, int);
97int ssh_packet_is_interactive(struct ssh *); 97int ssh_packet_is_interactive(struct ssh *);
98void ssh_packet_set_server(struct ssh *); 98void ssh_packet_set_server(struct ssh *);
99void ssh_packet_set_authenticated(struct ssh *); 99void ssh_packet_set_authenticated(struct ssh *);
100void ssh_packet_set_mux(struct ssh *);
101int ssh_packet_get_mux(struct ssh *);
102
103int ssh_packet_log_type(u_char);
100 104
101int ssh_packet_send1(struct ssh *); 105int ssh_packet_send1(struct ssh *);
102int ssh_packet_send2_wrapped(struct ssh *); 106int ssh_packet_send2_wrapped(struct ssh *);
diff --git a/ssh.c b/ssh.c
index 5095baf06..5e50fa02a 100644
--- a/ssh.c
+++ b/ssh.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: ssh.c,v 1.446 2016/09/12 23:31:27 djm Exp $ */ 1/* $OpenBSD: ssh.c,v 1.447 2016/09/30 09:19:13 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
@@ -213,10 +213,6 @@ static int ssh_session2(void);
213static void load_public_identity_files(void); 213static void load_public_identity_files(void);
214static void main_sigchld_handler(int); 214static void main_sigchld_handler(int);
215 215
216/* from muxclient.c */
217void muxclient(const char *);
218void muxserver_listen(void);
219
220/* ~/ expand a list of paths. NB. assumes path[n] is heap-allocated. */ 216/* ~/ expand a list of paths. NB. assumes path[n] is heap-allocated. */
221static void 217static void
222tilde_expand_paths(char **paths, u_int num_paths) 218tilde_expand_paths(char **paths, u_int num_paths)
@@ -668,6 +664,8 @@ main(int ac, char **av)
668 muxclient_command = SSHMUX_COMMAND_STOP; 664 muxclient_command = SSHMUX_COMMAND_STOP;
669 else if (strcmp(optarg, "cancel") == 0) 665 else if (strcmp(optarg, "cancel") == 0)
670 muxclient_command = SSHMUX_COMMAND_CANCEL_FWD; 666 muxclient_command = SSHMUX_COMMAND_CANCEL_FWD;
667 else if (strcmp(optarg, "proxy") == 0)
668 muxclient_command = SSHMUX_COMMAND_PROXY;
671 else 669 else
672 fatal("Invalid multiplex command."); 670 fatal("Invalid multiplex command.");
673 break; 671 break;
@@ -1162,7 +1160,8 @@ main(int ac, char **av)
1162 tty_flag = options.request_tty != REQUEST_TTY_NO; 1160 tty_flag = options.request_tty != REQUEST_TTY_NO;
1163 1161
1164 /* Force no tty */ 1162 /* Force no tty */
1165 if (options.request_tty == REQUEST_TTY_NO || muxclient_command != 0) 1163 if (options.request_tty == REQUEST_TTY_NO ||
1164 (muxclient_command && muxclient_command != SSHMUX_COMMAND_PROXY))
1166 tty_flag = 0; 1165 tty_flag = 0;
1167 /* Do not allocate a tty if stdin is not a tty. */ 1166 /* Do not allocate a tty if stdin is not a tty. */
1168 if ((!isatty(fileno(stdin)) || stdin_null_flag) && 1167 if ((!isatty(fileno(stdin)) || stdin_null_flag) &&
@@ -1239,8 +1238,16 @@ main(int ac, char **av)
1239 1238
1240 if (muxclient_command != 0 && options.control_path == NULL) 1239 if (muxclient_command != 0 && options.control_path == NULL)
1241 fatal("No ControlPath specified for \"-O\" command"); 1240 fatal("No ControlPath specified for \"-O\" command");
1242 if (options.control_path != NULL) 1241 if (options.control_path != NULL) {
1243 muxclient(options.control_path); 1242 int sock;
1243 if ((sock = muxclient(options.control_path)) >= 0) {
1244 packet_set_connection(sock, sock);
1245 ssh = active_state; /* XXX */
1246 enable_compat20(); /* XXX */
1247 packet_set_mux();
1248 goto skip_connect;
1249 }
1250 }
1244 1251
1245 /* 1252 /*
1246 * If hostname canonicalisation was not enabled, then we may not 1253 * If hostname canonicalisation was not enabled, then we may not
@@ -1443,6 +1450,7 @@ main(int ac, char **av)
1443 options.certificate_files[i] = NULL; 1450 options.certificate_files[i] = NULL;
1444 } 1451 }
1445 1452
1453 skip_connect:
1446 exit_status = compat20 ? ssh_session2() : ssh_session(); 1454 exit_status = compat20 ? ssh_session2() : ssh_session();
1447 packet_close(); 1455 packet_close();
1448 1456
@@ -1953,7 +1961,8 @@ ssh_session2(void)
1953 ssh_init_forwarding(); 1961 ssh_init_forwarding();
1954 1962
1955 /* Start listening for multiplex clients */ 1963 /* Start listening for multiplex clients */
1956 muxserver_listen(); 1964 if (!packet_get_mux())
1965 muxserver_listen();
1957 1966
1958 /* 1967 /*
1959 * If we are in control persist mode and have a working mux listen 1968 * If we are in control persist mode and have a working mux listen