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
This commit is contained in:
parent
b7689155f3
commit
8d05784785
392
channels.c
392
channels.c
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: channels.c,v 1.353 2016/09/19 07:52:42 natano Exp $ */
|
||||
/* $OpenBSD: channels.c,v 1.354 2016/09/30 09:19:13 markus Exp $ */
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
|
@ -71,6 +71,7 @@
|
|||
#include "ssh.h"
|
||||
#include "ssh1.h"
|
||||
#include "ssh2.h"
|
||||
#include "ssherr.h"
|
||||
#include "packet.h"
|
||||
#include "log.h"
|
||||
#include "misc.h"
|
||||
|
@ -120,6 +121,7 @@ typedef struct {
|
|||
char *listen_host; /* Remote side should listen address. */
|
||||
char *listen_path; /* Remote side should listen path. */
|
||||
int listen_port; /* Remote side should listen port. */
|
||||
Channel *downstream; /* Downstream mux*/
|
||||
} ForwardPermission;
|
||||
|
||||
/* List of all permitted host/port pairs to connect by the user. */
|
||||
|
@ -183,6 +185,7 @@ static int IPv4or6 = AF_UNSPEC;
|
|||
|
||||
/* helper */
|
||||
static void port_open_helper(Channel *c, char *rtype);
|
||||
static const char *channel_rfwd_bind_host(const char *listen_host);
|
||||
|
||||
/* non-blocking connect helpers */
|
||||
static int connect_next(struct channel_connect *);
|
||||
|
@ -207,6 +210,20 @@ channel_by_id(int id)
|
|||
return c;
|
||||
}
|
||||
|
||||
Channel *
|
||||
channel_by_remote_id(int remote_id)
|
||||
{
|
||||
Channel *c;
|
||||
u_int i;
|
||||
|
||||
for (i = 0; i < channels_alloc; i++) {
|
||||
c = channels[i];
|
||||
if (c != NULL && c->remote_id == remote_id)
|
||||
return c;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the channel if it is allowed to receive protocol messages.
|
||||
* Private channels, like listening sockets, may not receive messages.
|
||||
|
@ -229,6 +246,7 @@ channel_lookup(int id)
|
|||
case SSH_CHANNEL_INPUT_DRAINING:
|
||||
case SSH_CHANNEL_OUTPUT_DRAINING:
|
||||
case SSH_CHANNEL_ABANDONED:
|
||||
case SSH_CHANNEL_MUX_PROXY:
|
||||
return (c);
|
||||
}
|
||||
logit("Non-public channel %d, type %d.", id, c->type);
|
||||
|
@ -410,14 +428,56 @@ channel_free(Channel *c)
|
|||
{
|
||||
char *s;
|
||||
u_int i, n;
|
||||
Channel *other;
|
||||
struct channel_confirm *cc;
|
||||
|
||||
for (n = 0, i = 0; i < channels_alloc; i++)
|
||||
if (channels[i])
|
||||
for (n = 0, i = 0; i < channels_alloc; i++) {
|
||||
if ((other = channels[i]) != NULL) {
|
||||
n++;
|
||||
|
||||
/* detach from mux client and prepare for closing */
|
||||
if (c->type == SSH_CHANNEL_MUX_CLIENT &&
|
||||
other->type == SSH_CHANNEL_MUX_PROXY &&
|
||||
other->mux_ctx == c) {
|
||||
other->mux_ctx = NULL;
|
||||
other->type = SSH_CHANNEL_OPEN;
|
||||
other->istate = CHAN_INPUT_CLOSED;
|
||||
other->ostate = CHAN_OUTPUT_CLOSED;
|
||||
}
|
||||
}
|
||||
}
|
||||
debug("channel %d: free: %s, nchannels %u", c->self,
|
||||
c->remote_name ? c->remote_name : "???", n);
|
||||
|
||||
/* XXX more MUX cleanup: remove remote forwardings */
|
||||
if (c->type == SSH_CHANNEL_MUX_CLIENT) {
|
||||
for (i = 0; i < (u_int)num_permitted_opens; i++) {
|
||||
if (permitted_opens[i].downstream != c)
|
||||
continue;
|
||||
/* cancel on the server, since mux client is gone */
|
||||
debug("channel %d: cleanup remote forward for %s:%u",
|
||||
c->self,
|
||||
permitted_opens[i].listen_host,
|
||||
permitted_opens[i].listen_port);
|
||||
packet_start(SSH2_MSG_GLOBAL_REQUEST);
|
||||
packet_put_cstring("cancel-tcpip-forward");
|
||||
packet_put_char(0);
|
||||
packet_put_cstring(channel_rfwd_bind_host(
|
||||
permitted_opens[i].listen_host));
|
||||
packet_put_int(permitted_opens[i].listen_port);
|
||||
packet_send();
|
||||
/* unregister */
|
||||
permitted_opens[i].listen_port = 0;
|
||||
permitted_opens[i].port_to_connect = 0;
|
||||
free(permitted_opens[i].host_to_connect);
|
||||
permitted_opens[i].host_to_connect = NULL;
|
||||
free(permitted_opens[i].listen_host);
|
||||
permitted_opens[i].listen_host = NULL;
|
||||
permitted_opens[i].listen_path = NULL;
|
||||
permitted_opens[i].downstream = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
s = channel_open_message();
|
||||
debug3("channel %d: status: %s", c->self, s);
|
||||
free(s);
|
||||
|
@ -563,6 +623,7 @@ channel_still_open(void)
|
|||
case SSH_CHANNEL_OPEN:
|
||||
case SSH_CHANNEL_X11_OPEN:
|
||||
case SSH_CHANNEL_MUX_CLIENT:
|
||||
case SSH_CHANNEL_MUX_PROXY:
|
||||
return 1;
|
||||
case SSH_CHANNEL_INPUT_DRAINING:
|
||||
case SSH_CHANNEL_OUTPUT_DRAINING:
|
||||
|
@ -596,6 +657,7 @@ channel_find_open(void)
|
|||
case SSH_CHANNEL_RPORT_LISTENER:
|
||||
case SSH_CHANNEL_MUX_LISTENER:
|
||||
case SSH_CHANNEL_MUX_CLIENT:
|
||||
case SSH_CHANNEL_MUX_PROXY:
|
||||
case SSH_CHANNEL_OPENING:
|
||||
case SSH_CHANNEL_CONNECTING:
|
||||
case SSH_CHANNEL_ZOMBIE:
|
||||
|
@ -621,7 +683,6 @@ channel_find_open(void)
|
|||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Returns a message describing the currently open forwarded connections,
|
||||
* suitable for sending to the client. The message contains crlf pairs for
|
||||
|
@ -650,7 +711,6 @@ channel_open_message(void)
|
|||
case SSH_CHANNEL_AUTH_SOCKET:
|
||||
case SSH_CHANNEL_ZOMBIE:
|
||||
case SSH_CHANNEL_ABANDONED:
|
||||
case SSH_CHANNEL_MUX_CLIENT:
|
||||
case SSH_CHANNEL_MUX_LISTENER:
|
||||
case SSH_CHANNEL_UNIX_LISTENER:
|
||||
case SSH_CHANNEL_RUNIX_LISTENER:
|
||||
|
@ -663,6 +723,8 @@ channel_open_message(void)
|
|||
case SSH_CHANNEL_X11_OPEN:
|
||||
case SSH_CHANNEL_INPUT_DRAINING:
|
||||
case SSH_CHANNEL_OUTPUT_DRAINING:
|
||||
case SSH_CHANNEL_MUX_PROXY:
|
||||
case SSH_CHANNEL_MUX_CLIENT:
|
||||
snprintf(buf, sizeof buf,
|
||||
" #%d %.300s (t%d r%d i%u/%d o%u/%d fd %d/%d cc %d)\r\n",
|
||||
c->self, c->remote_name,
|
||||
|
@ -2360,6 +2422,278 @@ channel_output_poll(void)
|
|||
}
|
||||
}
|
||||
|
||||
/* -- mux proxy support */
|
||||
|
||||
/*
|
||||
* When multiplexing channel messages for mux clients we have to deal
|
||||
* with downstream messages from the mux client and upstream messages
|
||||
* from the ssh server:
|
||||
* 1) Handling downstream messages is straightforward and happens
|
||||
* in channel_proxy_downstream():
|
||||
* - We forward all messages (mostly) unmodified to the server.
|
||||
* - However, in order to route messages from upstream to the correct
|
||||
* downstream client, we have to replace the channel IDs used by the
|
||||
* mux clients with a unique channel ID because the mux clients might
|
||||
* use conflicting channel IDs.
|
||||
* - so we inspect and change both SSH2_MSG_CHANNEL_OPEN and
|
||||
* SSH2_MSG_CHANNEL_OPEN_CONFIRMATION messages, create a local
|
||||
* SSH_CHANNEL_MUX_PROXY channel and replace the mux clients ID
|
||||
* with the newly allocated channel ID.
|
||||
* 2) Upstream messages are received by matching SSH_CHANNEL_MUX_PROXY
|
||||
* channels and procesed by channel_proxy_upstream(). The local channel ID
|
||||
* is then translated back to the original mux client ID.
|
||||
* 3) In both cases we need to keep track of matching SSH2_MSG_CHANNEL_CLOSE
|
||||
* messages so we can clean up SSH_CHANNEL_MUX_PROXY channels.
|
||||
* 4) The SSH_CHANNEL_MUX_PROXY channels also need to closed when the
|
||||
* downstream mux client are removed.
|
||||
* 5) Handling SSH2_MSG_CHANNEL_OPEN messages from the upstream server
|
||||
* requires more work, because they are not addressed to a specific
|
||||
* channel. E.g. client_request_forwarded_tcpip() needs to figure
|
||||
* out whether the request is addressed to the local client or a
|
||||
* specific downstream client based on the listen-address/port.
|
||||
* 6) Agent and X11-Forwarding have a similar problem and are currenly
|
||||
* not supported as the matching session/channel cannot be identified
|
||||
* easily.
|
||||
*/
|
||||
|
||||
/*
|
||||
* receive packets from downstream mux clients:
|
||||
* channel callback fired on read from mux client, creates
|
||||
* SSH_CHANNEL_MUX_PROXY channels and translates channel IDs
|
||||
* on channel creation.
|
||||
*/
|
||||
int
|
||||
channel_proxy_downstream(Channel *downstream)
|
||||
{
|
||||
Channel *c = NULL;
|
||||
struct ssh *ssh = active_state;
|
||||
struct sshbuf *original = NULL, *modified = NULL;
|
||||
const u_char *cp;
|
||||
char *ctype = NULL, *listen_host = NULL;
|
||||
u_char type;
|
||||
size_t have;
|
||||
int ret = -1, r, id, remote_id, listen_port, idx;
|
||||
|
||||
/* sshbuf_dump(&downstream->input, stderr); */
|
||||
if ((r = sshbuf_get_string_direct(&downstream->input, &cp, &have))
|
||||
!= 0) {
|
||||
error("%s: malformed message: %s", __func__, ssh_err(r));
|
||||
return -1;
|
||||
}
|
||||
if (have < 2) {
|
||||
error("%s: short message", __func__);
|
||||
return -1;
|
||||
}
|
||||
type = cp[1];
|
||||
/* skip padlen + type */
|
||||
cp += 2;
|
||||
have -= 2;
|
||||
if (ssh_packet_log_type(type))
|
||||
debug3("%s: channel %u: down->up: type %u", __func__,
|
||||
downstream->self, type);
|
||||
|
||||
switch (type) {
|
||||
case SSH2_MSG_CHANNEL_OPEN:
|
||||
if ((original = sshbuf_from(cp, have)) == NULL ||
|
||||
(modified = sshbuf_new()) == NULL) {
|
||||
error("%s: alloc", __func__);
|
||||
goto out;
|
||||
}
|
||||
if ((r = sshbuf_get_cstring(original, &ctype, NULL)) != 0 ||
|
||||
(r = sshbuf_get_u32(original, &id)) != 0) {
|
||||
error("%s: parse error %s", __func__, ssh_err(r));
|
||||
goto out;
|
||||
}
|
||||
c = channel_new("mux proxy", SSH_CHANNEL_MUX_PROXY,
|
||||
-1, -1, -1, 0, 0, 0, ctype, 1);
|
||||
c->mux_ctx = downstream; /* point to mux client */
|
||||
c->mux_downstream_id = id; /* original downstream id */
|
||||
if ((r = sshbuf_put_cstring(modified, ctype)) != 0 ||
|
||||
(r = sshbuf_put_u32(modified, c->self)) != 0 ||
|
||||
(r = sshbuf_putb(modified, original)) != 0) {
|
||||
error("%s: compose error %s", __func__, ssh_err(r));
|
||||
channel_free(c);
|
||||
goto out;
|
||||
}
|
||||
break;
|
||||
case SSH2_MSG_CHANNEL_OPEN_CONFIRMATION:
|
||||
/*
|
||||
* Almost the same as SSH2_MSG_CHANNEL_OPEN, except then we
|
||||
* need to parse 'remote_id' instead of 'ctype'.
|
||||
*/
|
||||
if ((original = sshbuf_from(cp, have)) == NULL ||
|
||||
(modified = sshbuf_new()) == NULL) {
|
||||
error("%s: alloc", __func__);
|
||||
goto out;
|
||||
}
|
||||
if ((r = sshbuf_get_u32(original, &remote_id)) != 0 ||
|
||||
(r = sshbuf_get_u32(original, &id)) != 0) {
|
||||
error("%s: parse error %s", __func__, ssh_err(r));
|
||||
goto out;
|
||||
}
|
||||
c = channel_new("mux proxy", SSH_CHANNEL_MUX_PROXY,
|
||||
-1, -1, -1, 0, 0, 0, "mux-down-connect", 1);
|
||||
c->mux_ctx = downstream; /* point to mux client */
|
||||
c->mux_downstream_id = id;
|
||||
c->remote_id = remote_id;
|
||||
if ((r = sshbuf_put_u32(modified, remote_id)) != 0 ||
|
||||
(r = sshbuf_put_u32(modified, c->self)) != 0 ||
|
||||
(r = sshbuf_putb(modified, original)) != 0) {
|
||||
error("%s: compose error %s", __func__, ssh_err(r));
|
||||
channel_free(c);
|
||||
goto out;
|
||||
}
|
||||
break;
|
||||
case SSH2_MSG_GLOBAL_REQUEST:
|
||||
if ((original = sshbuf_from(cp, have)) == NULL) {
|
||||
error("%s: alloc", __func__);
|
||||
goto out;
|
||||
}
|
||||
if ((r = sshbuf_get_cstring(original, &ctype, NULL)) != 0) {
|
||||
error("%s: parse error %s", __func__, ssh_err(r));
|
||||
goto out;
|
||||
}
|
||||
if (strcmp(ctype, "tcpip-forward") != 0) {
|
||||
error("%s: unsupported request %s", __func__, ctype);
|
||||
goto out;
|
||||
}
|
||||
if ((r = sshbuf_get_u8(original, NULL)) != 0 ||
|
||||
(r = sshbuf_get_cstring(original, &listen_host, NULL)) != 0 ||
|
||||
(r = sshbuf_get_u32(original, &listen_port)) != 0) {
|
||||
error("%s: parse error %s", __func__, ssh_err(r));
|
||||
goto out;
|
||||
}
|
||||
/* Record that connection to this host/port is permitted. */
|
||||
permitted_opens = xreallocarray(permitted_opens,
|
||||
num_permitted_opens + 1, sizeof(*permitted_opens));
|
||||
idx = num_permitted_opens++;
|
||||
permitted_opens[idx].host_to_connect = xstrdup("<mux>");
|
||||
permitted_opens[idx].port_to_connect = -1;
|
||||
permitted_opens[idx].listen_host = listen_host;
|
||||
permitted_opens[idx].listen_port = listen_port;
|
||||
permitted_opens[idx].downstream = downstream;
|
||||
listen_host = NULL;
|
||||
break;
|
||||
case SSH2_MSG_CHANNEL_CLOSE:
|
||||
if (have < 4)
|
||||
break;
|
||||
remote_id = PEEK_U32(cp);
|
||||
if ((c = channel_by_remote_id(remote_id)) != NULL) {
|
||||
if (c->flags & CHAN_CLOSE_RCVD)
|
||||
channel_free(c);
|
||||
else
|
||||
c->flags |= CHAN_CLOSE_SENT;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (modified) {
|
||||
if ((r = sshpkt_start(ssh, type)) != 0 ||
|
||||
(r = sshpkt_putb(ssh, modified)) != 0 ||
|
||||
(r = sshpkt_send(ssh)) != 0) {
|
||||
error("%s: send %s", __func__, ssh_err(r));
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
if ((r = sshpkt_start(ssh, type)) != 0 ||
|
||||
(r = sshpkt_put(ssh, cp, have)) != 0 ||
|
||||
(r = sshpkt_send(ssh)) != 0) {
|
||||
error("%s: send %s", __func__, ssh_err(r));
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
ret = 0;
|
||||
out:
|
||||
free(ctype);
|
||||
free(listen_host);
|
||||
sshbuf_free(original);
|
||||
sshbuf_free(modified);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* receive packets from upstream server and de-multiplex packets
|
||||
* to correct downstream:
|
||||
* implemented as a helper for channel input handlers,
|
||||
* replaces local (proxy) channel ID with downstream channel ID.
|
||||
*/
|
||||
int
|
||||
channel_proxy_upstream(Channel *c, int type, u_int32_t seq, void *ctxt)
|
||||
{
|
||||
struct ssh *ssh = active_state;
|
||||
struct sshbuf *b = NULL;
|
||||
Channel *downstream;
|
||||
const u_char *cp = NULL;
|
||||
size_t len;
|
||||
int r;
|
||||
|
||||
/*
|
||||
* When receiving packets from the peer we need to check whether we
|
||||
* need to forward the packets to the mux client. In this case we
|
||||
* restore the orignal channel id and keep track of CLOSE messages,
|
||||
* so we can cleanup the channel.
|
||||
*/
|
||||
if (c == NULL || c->type != SSH_CHANNEL_MUX_PROXY)
|
||||
return 0;
|
||||
if ((downstream = c->mux_ctx) == NULL)
|
||||
return 0;
|
||||
switch (type) {
|
||||
case SSH2_MSG_CHANNEL_CLOSE:
|
||||
case SSH2_MSG_CHANNEL_DATA:
|
||||
case SSH2_MSG_CHANNEL_EOF:
|
||||
case SSH2_MSG_CHANNEL_EXTENDED_DATA:
|
||||
case SSH2_MSG_CHANNEL_OPEN_CONFIRMATION:
|
||||
case SSH2_MSG_CHANNEL_OPEN_FAILURE:
|
||||
case SSH2_MSG_CHANNEL_WINDOW_ADJUST:
|
||||
case SSH2_MSG_CHANNEL_SUCCESS:
|
||||
case SSH2_MSG_CHANNEL_FAILURE:
|
||||
case SSH2_MSG_CHANNEL_REQUEST:
|
||||
break;
|
||||
default:
|
||||
debug2("%s: channel %u: unsupported type %u", __func__,
|
||||
c->self, type);
|
||||
return 0;
|
||||
}
|
||||
if ((b = sshbuf_new()) == NULL) {
|
||||
error("%s: alloc reply", __func__);
|
||||
goto out;
|
||||
}
|
||||
/* get remaining payload (after id) */
|
||||
cp = sshpkt_ptr(ssh, &len);
|
||||
if (cp == NULL) {
|
||||
error("%s: no packet", __func__);
|
||||
goto out;
|
||||
}
|
||||
/* translate id and send to muxclient */
|
||||
if ((r = sshbuf_put_u8(b, 0)) != 0 || /* padlen */
|
||||
(r = sshbuf_put_u8(b, type)) != 0 ||
|
||||
(r = sshbuf_put_u32(b, c->mux_downstream_id)) != 0 ||
|
||||
(r = sshbuf_put(b, cp, len)) != 0 ||
|
||||
(r = sshbuf_put_stringb(&downstream->output, b)) != 0) {
|
||||
error("%s: compose for muxclient %s", __func__, ssh_err(r));
|
||||
goto out;
|
||||
}
|
||||
/* sshbuf_dump(b, stderr); */
|
||||
if (ssh_packet_log_type(type))
|
||||
debug3("%s: channel %u: up->down: type %u", __func__, c->self,
|
||||
type);
|
||||
out:
|
||||
/* update state */
|
||||
switch (type) {
|
||||
case SSH2_MSG_CHANNEL_OPEN_CONFIRMATION:
|
||||
/* record remote_id for SSH2_MSG_CHANNEL_CLOSE */
|
||||
if (cp && len > 4)
|
||||
c->remote_id = PEEK_U32(cp);
|
||||
break;
|
||||
case SSH2_MSG_CHANNEL_CLOSE:
|
||||
if (c->flags & CHAN_CLOSE_SENT)
|
||||
channel_free(c);
|
||||
else
|
||||
c->flags |= CHAN_CLOSE_RCVD;
|
||||
break;
|
||||
}
|
||||
sshbuf_free(b);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* -- protocol input */
|
||||
|
||||
|
@ -2377,6 +2711,8 @@ channel_input_data(int type, u_int32_t seq, void *ctxt)
|
|||
c = channel_lookup(id);
|
||||
if (c == NULL)
|
||||
packet_disconnect("Received data for nonexistent channel %d.", id);
|
||||
if (channel_proxy_upstream(c, type, seq, ctxt))
|
||||
return 0;
|
||||
|
||||
/* Ignore any data for non-open channels (might happen on close) */
|
||||
if (c->type != SSH_CHANNEL_OPEN &&
|
||||
|
@ -2439,6 +2775,8 @@ channel_input_extended_data(int type, u_int32_t seq, void *ctxt)
|
|||
|
||||
if (c == NULL)
|
||||
packet_disconnect("Received extended_data for bad channel %d.", id);
|
||||
if (channel_proxy_upstream(c, type, seq, ctxt))
|
||||
return 0;
|
||||
if (c->type != SSH_CHANNEL_OPEN) {
|
||||
logit("channel %d: ext data for non open", id);
|
||||
return 0;
|
||||
|
@ -2484,6 +2822,8 @@ channel_input_ieof(int type, u_int32_t seq, void *ctxt)
|
|||
c = channel_lookup(id);
|
||||
if (c == NULL)
|
||||
packet_disconnect("Received ieof for nonexistent channel %d.", id);
|
||||
if (channel_proxy_upstream(c, type, seq, ctxt))
|
||||
return 0;
|
||||
chan_rcvd_ieof(c);
|
||||
|
||||
/* XXX force input close */
|
||||
|
@ -2508,7 +2848,8 @@ channel_input_close(int type, u_int32_t seq, void *ctxt)
|
|||
c = channel_lookup(id);
|
||||
if (c == NULL)
|
||||
packet_disconnect("Received close for nonexistent channel %d.", id);
|
||||
|
||||
if (channel_proxy_upstream(c, type, seq, ctxt))
|
||||
return 0;
|
||||
/*
|
||||
* Send a confirmation that we have closed the channel and no more
|
||||
* data is coming for it.
|
||||
|
@ -2543,9 +2884,11 @@ channel_input_oclose(int type, u_int32_t seq, void *ctxt)
|
|||
int id = packet_get_int();
|
||||
Channel *c = channel_lookup(id);
|
||||
|
||||
packet_check_eom();
|
||||
if (c == NULL)
|
||||
packet_disconnect("Received oclose for nonexistent channel %d.", id);
|
||||
if (channel_proxy_upstream(c, type, seq, ctxt))
|
||||
return 0;
|
||||
packet_check_eom();
|
||||
chan_rcvd_oclose(c);
|
||||
return 0;
|
||||
}
|
||||
|
@ -2557,10 +2900,12 @@ channel_input_close_confirmation(int type, u_int32_t seq, void *ctxt)
|
|||
int id = packet_get_int();
|
||||
Channel *c = channel_lookup(id);
|
||||
|
||||
packet_check_eom();
|
||||
if (c == NULL)
|
||||
packet_disconnect("Received close confirmation for "
|
||||
"out-of-range channel %d.", id);
|
||||
if (channel_proxy_upstream(c, type, seq, ctxt))
|
||||
return 0;
|
||||
packet_check_eom();
|
||||
if (c->type != SSH_CHANNEL_CLOSED && c->type != SSH_CHANNEL_ABANDONED)
|
||||
packet_disconnect("Received close confirmation for "
|
||||
"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)
|
|||
id = packet_get_int();
|
||||
c = channel_lookup(id);
|
||||
|
||||
if (c==NULL || c->type != SSH_CHANNEL_OPENING)
|
||||
if (c==NULL)
|
||||
packet_disconnect("Received open confirmation for "
|
||||
"unknown channel %d.", id);
|
||||
if (channel_proxy_upstream(c, type, seq, ctxt))
|
||||
return 0;
|
||||
if (c->type != SSH_CHANNEL_OPENING)
|
||||
packet_disconnect("Received open confirmation for "
|
||||
"non-opening channel %d.", id);
|
||||
remote_id = packet_get_int();
|
||||
|
@ -2628,7 +2978,12 @@ channel_input_open_failure(int type, u_int32_t seq, void *ctxt)
|
|||
id = packet_get_int();
|
||||
c = channel_lookup(id);
|
||||
|
||||
if (c==NULL || c->type != SSH_CHANNEL_OPENING)
|
||||
if (c==NULL)
|
||||
packet_disconnect("Received open failure for "
|
||||
"unknown channel %d.", id);
|
||||
if (channel_proxy_upstream(c, type, seq, ctxt))
|
||||
return 0;
|
||||
if (c->type != SSH_CHANNEL_OPENING)
|
||||
packet_disconnect("Received open failure for "
|
||||
"non-opening channel %d.", id);
|
||||
if (compat20) {
|
||||
|
@ -2672,6 +3027,8 @@ channel_input_window_adjust(int type, u_int32_t seq, void *ctxt)
|
|||
logit("Received window adjust for non-open channel %d.", id);
|
||||
return 0;
|
||||
}
|
||||
if (channel_proxy_upstream(c, type, seq, ctxt))
|
||||
return 0;
|
||||
adjust = packet_get_int();
|
||||
packet_check_eom();
|
||||
debug2("channel %d: rcvd adjust %u", id, adjust);
|
||||
|
@ -2726,14 +3083,15 @@ channel_input_status_confirm(int type, u_int32_t seq, void *ctxt)
|
|||
packet_set_alive_timeouts(0);
|
||||
|
||||
id = packet_get_int();
|
||||
packet_check_eom();
|
||||
|
||||
debug2("channel_input_status_confirm: type %d id %d", type, id);
|
||||
|
||||
if ((c = channel_lookup(id)) == NULL) {
|
||||
logit("channel_input_status_confirm: %d: unknown", id);
|
||||
return 0;
|
||||
}
|
||||
if (channel_proxy_upstream(c, type, seq, ctxt))
|
||||
return 0;
|
||||
packet_check_eom();
|
||||
if ((cc = TAILQ_FIRST(&c->status_confirms)) == NULL)
|
||||
return 0;
|
||||
cc->cb(type, c, cc->ctx);
|
||||
|
@ -3287,6 +3645,7 @@ channel_request_remote_forwarding(struct Forward *fwd)
|
|||
permitted_opens[idx].listen_path = NULL;
|
||||
permitted_opens[idx].listen_port = fwd->listen_port;
|
||||
}
|
||||
permitted_opens[idx].downstream = NULL;
|
||||
}
|
||||
return (idx);
|
||||
}
|
||||
|
@ -3382,6 +3741,7 @@ channel_request_rforward_cancel_tcpip(const char *host, u_short port)
|
|||
free(permitted_opens[i].listen_host);
|
||||
permitted_opens[i].listen_host = NULL;
|
||||
permitted_opens[i].listen_path = NULL;
|
||||
permitted_opens[i].downstream = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -3419,6 +3779,7 @@ channel_request_rforward_cancel_streamlocal(const char *path)
|
|||
permitted_opens[i].listen_host = NULL;
|
||||
free(permitted_opens[i].listen_path);
|
||||
permitted_opens[i].listen_path = NULL;
|
||||
permitted_opens[i].downstream = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -3501,6 +3862,7 @@ channel_add_permitted_opens(char *host, int port)
|
|||
permitted_opens[num_permitted_opens].listen_host = NULL;
|
||||
permitted_opens[num_permitted_opens].listen_path = NULL;
|
||||
permitted_opens[num_permitted_opens].listen_port = 0;
|
||||
permitted_opens[num_permitted_opens].downstream = NULL;
|
||||
num_permitted_opens++;
|
||||
|
||||
all_opens_permitted = 0;
|
||||
|
@ -3763,6 +4125,10 @@ connect_to(const char *name, int port, char *ctype, char *rname)
|
|||
return c;
|
||||
}
|
||||
|
||||
/*
|
||||
* returns either the newly connected channel or the downstream channel
|
||||
* that needs to deal with this connection.
|
||||
*/
|
||||
Channel *
|
||||
channel_connect_by_listen_address(const char *listen_host,
|
||||
u_short listen_port, char *ctype, char *rname)
|
||||
|
@ -3772,6 +4138,8 @@ channel_connect_by_listen_address(const char *listen_host,
|
|||
for (i = 0; i < num_permitted_opens; i++) {
|
||||
if (open_listen_match_tcpip(&permitted_opens[i], listen_host,
|
||||
listen_port, 1)) {
|
||||
if (permitted_opens[i].downstream)
|
||||
return permitted_opens[i].downstream;
|
||||
return connect_to(
|
||||
permitted_opens[i].host_to_connect,
|
||||
permitted_opens[i].port_to_connect, ctype, rname);
|
||||
|
|
12
channels.h
12
channels.h
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: channels.h,v 1.118 2015/07/01 02:26:31 djm Exp $ */
|
||||
/* $OpenBSD: channels.h,v 1.119 2016/09/30 09:19:13 markus Exp $ */
|
||||
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
|
@ -58,7 +58,8 @@
|
|||
#define SSH_CHANNEL_ABANDONED 17 /* Abandoned session, eg mux */
|
||||
#define SSH_CHANNEL_UNIX_LISTENER 18 /* Listening on a domain socket. */
|
||||
#define SSH_CHANNEL_RUNIX_LISTENER 19 /* Listening to a R-style domain socket. */
|
||||
#define SSH_CHANNEL_MAX_TYPE 20
|
||||
#define SSH_CHANNEL_MUX_PROXY 20 /* proxy channel for mux-slave */
|
||||
#define SSH_CHANNEL_MAX_TYPE 21
|
||||
|
||||
#define CHANNEL_CANCEL_PORT_STATIC -1
|
||||
|
||||
|
@ -162,6 +163,7 @@ struct Channel {
|
|||
mux_callback_fn *mux_rcb;
|
||||
void *mux_ctx;
|
||||
int mux_pause;
|
||||
int mux_downstream_id;
|
||||
};
|
||||
|
||||
#define CHAN_EXTENDED_IGNORE 0
|
||||
|
@ -209,6 +211,7 @@ struct Channel {
|
|||
/* channel management */
|
||||
|
||||
Channel *channel_by_id(int);
|
||||
Channel *channel_by_remote_id(int);
|
||||
Channel *channel_lookup(int);
|
||||
Channel *channel_new(char *, int, int, int, int, u_int, u_int, int, char *, int);
|
||||
void channel_set_fds(int, int, int, int, int, int, int, u_int);
|
||||
|
@ -228,6 +231,11 @@ void channel_cancel_cleanup(int);
|
|||
int channel_close_fd(int *);
|
||||
void channel_send_window_changes(void);
|
||||
|
||||
/* mux proxy support */
|
||||
|
||||
int channel_proxy_downstream(Channel *mc);
|
||||
int channel_proxy_upstream(Channel *, int, u_int32_t, void *);
|
||||
|
||||
/* protocol handler */
|
||||
|
||||
int channel_input_close(int, u_int32_t, void *);
|
||||
|
|
45
clientloop.c
45
clientloop.c
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: clientloop.c,v 1.288 2016/09/17 18:00:27 tedu Exp $ */
|
||||
/* $OpenBSD: clientloop.c,v 1.289 2016/09/30 09:19:13 markus Exp $ */
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* 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)
|
|||
}
|
||||
|
||||
static Channel *
|
||||
client_request_forwarded_tcpip(const char *request_type, int rchan)
|
||||
client_request_forwarded_tcpip(const char *request_type, int rchan,
|
||||
u_int rwindow, u_int rmaxpack)
|
||||
{
|
||||
Channel *c = NULL;
|
||||
struct sshbuf *b = NULL;
|
||||
char *listen_address, *originator_address;
|
||||
u_short listen_port, originator_port;
|
||||
int r;
|
||||
|
||||
/* Get rest of the packet */
|
||||
listen_address = packet_get_string(NULL);
|
||||
|
@ -1902,6 +1905,31 @@ client_request_forwarded_tcpip(const char *request_type, int rchan)
|
|||
c = channel_connect_by_listen_address(listen_address, listen_port,
|
||||
"forwarded-tcpip", originator_address);
|
||||
|
||||
if (c != NULL && c->type == SSH_CHANNEL_MUX_CLIENT) {
|
||||
if ((b = sshbuf_new()) == NULL) {
|
||||
error("%s: alloc reply", __func__);
|
||||
goto out;
|
||||
}
|
||||
/* reconstruct and send to muxclient */
|
||||
if ((r = sshbuf_put_u8(b, 0)) != 0 || /* padlen */
|
||||
(r = sshbuf_put_u8(b, SSH2_MSG_CHANNEL_OPEN)) != 0 ||
|
||||
(r = sshbuf_put_cstring(b, request_type)) != 0 ||
|
||||
(r = sshbuf_put_u32(b, rchan)) != 0 ||
|
||||
(r = sshbuf_put_u32(b, rwindow)) != 0 ||
|
||||
(r = sshbuf_put_u32(b, rmaxpack)) != 0 ||
|
||||
(r = sshbuf_put_cstring(b, listen_address)) != 0 ||
|
||||
(r = sshbuf_put_u32(b, listen_port)) != 0 ||
|
||||
(r = sshbuf_put_cstring(b, originator_address)) != 0 ||
|
||||
(r = sshbuf_put_u32(b, originator_port)) != 0 ||
|
||||
(r = sshbuf_put_stringb(&c->output, b)) != 0) {
|
||||
error("%s: compose for muxclient %s", __func__,
|
||||
ssh_err(r));
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
sshbuf_free(b);
|
||||
free(originator_address);
|
||||
free(listen_address);
|
||||
return c;
|
||||
|
@ -2057,7 +2085,8 @@ client_input_channel_open(int type, u_int32_t seq, void *ctxt)
|
|||
ctype, rchan, rwindow, rmaxpack);
|
||||
|
||||
if (strcmp(ctype, "forwarded-tcpip") == 0) {
|
||||
c = client_request_forwarded_tcpip(ctype, rchan);
|
||||
c = client_request_forwarded_tcpip(ctype, rchan, rwindow,
|
||||
rmaxpack);
|
||||
} else if (strcmp(ctype, "forwarded-streamlocal@openssh.com") == 0) {
|
||||
c = client_request_forwarded_streamlocal(ctype, rchan);
|
||||
} else if (strcmp(ctype, "x11") == 0) {
|
||||
|
@ -2065,8 +2094,9 @@ client_input_channel_open(int type, u_int32_t seq, void *ctxt)
|
|||
} else if (strcmp(ctype, "auth-agent@openssh.com") == 0) {
|
||||
c = client_request_agent(ctype, rchan);
|
||||
}
|
||||
/* XXX duplicate : */
|
||||
if (c != NULL) {
|
||||
if (c != NULL && c->type == SSH_CHANNEL_MUX_CLIENT) {
|
||||
debug3("proxied to downstream: %s", ctype);
|
||||
} else if (c != NULL) {
|
||||
debug("confirm %s", ctype);
|
||||
c->remote_id = rchan;
|
||||
c->remote_window = rwindow;
|
||||
|
@ -2102,6 +2132,9 @@ client_input_channel_req(int type, u_int32_t seq, void *ctxt)
|
|||
char *rtype;
|
||||
|
||||
id = packet_get_int();
|
||||
c = channel_lookup(id);
|
||||
if (channel_proxy_upstream(c, type, seq, ctxt))
|
||||
return 0;
|
||||
rtype = packet_get_string(NULL);
|
||||
reply = packet_get_char();
|
||||
|
||||
|
@ -2110,7 +2143,7 @@ client_input_channel_req(int type, u_int32_t seq, void *ctxt)
|
|||
|
||||
if (id == -1) {
|
||||
error("client_input_channel_req: request for channel -1");
|
||||
} else if ((c = channel_lookup(id)) == NULL) {
|
||||
} else if (c == NULL) {
|
||||
error("client_input_channel_req: channel %d: "
|
||||
"unknown channel", id);
|
||||
} else if (strcmp(rtype, "eow@openssh.com") == 0) {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: clientloop.h,v 1.32 2016/01/13 23:04:47 djm Exp $ */
|
||||
/* $OpenBSD: clientloop.h,v 1.33 2016/09/30 09:19:13 markus Exp $ */
|
||||
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
|
@ -71,9 +71,10 @@ void client_expect_confirm(int, const char *, enum confirm_action);
|
|||
#define SSHMUX_COMMAND_FORWARD 5 /* Forward only, no command */
|
||||
#define SSHMUX_COMMAND_STOP 6 /* Disable mux but not conn */
|
||||
#define SSHMUX_COMMAND_CANCEL_FWD 7 /* Cancel forwarding(s) */
|
||||
#define SSHMUX_COMMAND_PROXY 8 /* Open new connection */
|
||||
|
||||
void muxserver_listen(void);
|
||||
void muxclient(const char *);
|
||||
int muxclient(const char *);
|
||||
void mux_exit_message(Channel *, int);
|
||||
void mux_tty_alloc_failed(Channel *);
|
||||
|
||||
|
|
69
mux.c
69
mux.c
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: mux.c,v 1.61 2016/08/08 22:40:57 dtucker Exp $ */
|
||||
/* $OpenBSD: mux.c,v 1.62 2016/09/30 09:19:13 markus Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2002-2008 Damien Miller <djm@openbsd.org>
|
||||
*
|
||||
|
@ -79,6 +79,7 @@
|
|||
#include "key.h"
|
||||
#include "readconf.h"
|
||||
#include "clientloop.h"
|
||||
#include "ssherr.h"
|
||||
|
||||
/* from ssh.c */
|
||||
extern int tty_flag;
|
||||
|
@ -144,6 +145,7 @@ struct mux_master_state {
|
|||
#define MUX_C_CLOSE_FWD 0x10000007
|
||||
#define MUX_C_NEW_STDIO_FWD 0x10000008
|
||||
#define MUX_C_STOP_LISTENING 0x10000009
|
||||
#define MUX_C_PROXY 0x1000000f
|
||||
#define MUX_S_OK 0x80000001
|
||||
#define MUX_S_PERMISSION_DENIED 0x80000002
|
||||
#define MUX_S_FAILURE 0x80000003
|
||||
|
@ -152,6 +154,7 @@ struct mux_master_state {
|
|||
#define MUX_S_SESSION_OPENED 0x80000006
|
||||
#define MUX_S_REMOTE_PORT 0x80000007
|
||||
#define MUX_S_TTY_ALLOC_FAIL 0x80000008
|
||||
#define MUX_S_PROXY 0x8000000f
|
||||
|
||||
/* type codes for MUX_C_OPEN_FWD and MUX_C_CLOSE_FWD */
|
||||
#define MUX_FWD_LOCAL 1
|
||||
|
@ -169,6 +172,7 @@ static int process_mux_open_fwd(u_int, Channel *, Buffer *, Buffer *);
|
|||
static int process_mux_close_fwd(u_int, Channel *, Buffer *, Buffer *);
|
||||
static int process_mux_stdio_fwd(u_int, Channel *, Buffer *, Buffer *);
|
||||
static int process_mux_stop_listening(u_int, Channel *, Buffer *, Buffer *);
|
||||
static int process_mux_proxy(u_int, Channel *, Buffer *, Buffer *);
|
||||
|
||||
static const struct {
|
||||
u_int type;
|
||||
|
@ -182,6 +186,7 @@ static const struct {
|
|||
{ MUX_C_CLOSE_FWD, process_mux_close_fwd },
|
||||
{ MUX_C_NEW_STDIO_FWD, process_mux_stdio_fwd },
|
||||
{ MUX_C_STOP_LISTENING, process_mux_stop_listening },
|
||||
{ MUX_C_PROXY, process_mux_proxy },
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
|
@ -1110,6 +1115,18 @@ process_mux_stop_listening(u_int rid, Channel *c, Buffer *m, Buffer *r)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
process_mux_proxy(u_int rid, Channel *c, Buffer *m, Buffer *r)
|
||||
{
|
||||
debug("%s: channel %d: proxy request", __func__, c->self);
|
||||
|
||||
c->mux_rcb = channel_proxy_downstream;
|
||||
buffer_put_int(r, MUX_S_PROXY);
|
||||
buffer_put_int(r, rid);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Channel callbacks fired on read/write from mux slave fd */
|
||||
static int
|
||||
mux_master_read_cb(Channel *c)
|
||||
|
@ -1959,6 +1976,41 @@ mux_client_request_session(int fd)
|
|||
exit(exitval);
|
||||
}
|
||||
|
||||
static int
|
||||
mux_client_proxy(int fd)
|
||||
{
|
||||
Buffer m;
|
||||
char *e;
|
||||
u_int type, rid;
|
||||
|
||||
buffer_init(&m);
|
||||
buffer_put_int(&m, MUX_C_PROXY);
|
||||
buffer_put_int(&m, muxclient_request_id);
|
||||
if (mux_client_write_packet(fd, &m) != 0)
|
||||
fatal("%s: write packet: %s", __func__, strerror(errno));
|
||||
|
||||
buffer_clear(&m);
|
||||
|
||||
/* Read their reply */
|
||||
if (mux_client_read_packet(fd, &m) != 0) {
|
||||
buffer_free(&m);
|
||||
return 0;
|
||||
}
|
||||
type = buffer_get_int(&m);
|
||||
if (type != MUX_S_PROXY) {
|
||||
e = buffer_get_string(&m, NULL);
|
||||
fatal("%s: master returned error: %s", __func__, e);
|
||||
}
|
||||
if ((rid = buffer_get_int(&m)) != muxclient_request_id)
|
||||
fatal("%s: out of sequence reply: my id %u theirs %u",
|
||||
__func__, muxclient_request_id, rid);
|
||||
buffer_free(&m);
|
||||
|
||||
debug3("%s: done", __func__);
|
||||
muxclient_request_id++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
mux_client_request_stdio_fwd(int fd)
|
||||
{
|
||||
|
@ -2105,7 +2157,7 @@ mux_client_request_stop_listening(int fd)
|
|||
}
|
||||
|
||||
/* Multiplex client main loop. */
|
||||
void
|
||||
int
|
||||
muxclient(const char *path)
|
||||
{
|
||||
struct sockaddr_un addr;
|
||||
|
@ -2128,7 +2180,7 @@ muxclient(const char *path)
|
|||
case SSHCTL_MASTER_NO:
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(&addr, '\0', sizeof(addr));
|
||||
|
@ -2164,14 +2216,14 @@ muxclient(const char *path)
|
|||
strerror(errno));
|
||||
}
|
||||
close(sock);
|
||||
return;
|
||||
return -1;
|
||||
}
|
||||
set_nonblock(sock);
|
||||
|
||||
if (mux_client_hello_exchange(sock) != 0) {
|
||||
error("%s: master hello exchange failed", __func__);
|
||||
close(sock);
|
||||
return;
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (muxclient_command) {
|
||||
|
@ -2191,10 +2243,10 @@ muxclient(const char *path)
|
|||
case SSHMUX_COMMAND_OPEN:
|
||||
if (mux_client_forwards(sock, 0) != 0) {
|
||||
error("%s: master forward request failed", __func__);
|
||||
return;
|
||||
return -1;
|
||||
}
|
||||
mux_client_request_session(sock);
|
||||
return;
|
||||
return -1;
|
||||
case SSHMUX_COMMAND_STDIO_FWD:
|
||||
mux_client_request_stdio_fwd(sock);
|
||||
exit(0);
|
||||
|
@ -2207,6 +2259,9 @@ muxclient(const char *path)
|
|||
error("%s: master cancel forward request failed",
|
||||
__func__);
|
||||
exit(0);
|
||||
case SSHMUX_COMMAND_PROXY:
|
||||
mux_client_proxy(sock);
|
||||
return (sock);
|
||||
default:
|
||||
fatal("unrecognised muxclient_command %d", muxclient_command);
|
||||
}
|
||||
|
|
|
@ -153,5 +153,9 @@ void packet_disconnect(const char *, ...)
|
|||
ssh_packet_set_rekey_limits(active_state, x, y)
|
||||
#define packet_get_bytes(x,y) \
|
||||
ssh_packet_get_bytes(active_state, x, y)
|
||||
#define packet_set_mux() \
|
||||
ssh_packet_set_mux(active_state)
|
||||
#define packet_get_mux() \
|
||||
ssh_packet_get_mux(active_state)
|
||||
|
||||
#endif /* _OPACKET_H */
|
||||
|
|
93
packet.c
93
packet.c
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: packet.c,v 1.241 2016/09/28 21:44:52 djm Exp $ */
|
||||
/* $OpenBSD: packet.c,v 1.242 2016/09/30 09:19:13 markus Exp $ */
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
|
@ -204,6 +204,9 @@ struct session_state {
|
|||
/* Used in packet_send2 */
|
||||
int rekeying;
|
||||
|
||||
/* Used in ssh_packet_send_mux() */
|
||||
int mux;
|
||||
|
||||
/* Used in packet_set_interactive */
|
||||
int set_interactive_called;
|
||||
|
||||
|
@ -325,6 +328,19 @@ ssh_packet_set_timeout(struct ssh *ssh, int timeout, int count)
|
|||
state->packet_timeout_ms = timeout * count * 1000;
|
||||
}
|
||||
|
||||
void
|
||||
ssh_packet_set_mux(struct ssh *ssh)
|
||||
{
|
||||
ssh->state->mux = 1;
|
||||
ssh->state->rekeying = 0;
|
||||
}
|
||||
|
||||
int
|
||||
ssh_packet_get_mux(struct ssh *ssh)
|
||||
{
|
||||
return ssh->state->mux;
|
||||
}
|
||||
|
||||
int
|
||||
ssh_packet_stop_discard(struct ssh *ssh)
|
||||
{
|
||||
|
@ -1078,7 +1094,7 @@ ssh_packet_enable_delayed_compress(struct ssh *ssh)
|
|||
}
|
||||
|
||||
/* Used to mute debug logging for noisy packet types */
|
||||
static int
|
||||
int
|
||||
ssh_packet_log_type(u_char type)
|
||||
{
|
||||
switch (type) {
|
||||
|
@ -1623,6 +1639,44 @@ ssh_packet_read_poll1(struct ssh *ssh, u_char *typep)
|
|||
return r;
|
||||
}
|
||||
|
||||
static int
|
||||
ssh_packet_read_poll2_mux(struct ssh *ssh, u_char *typep, u_int32_t *seqnr_p)
|
||||
{
|
||||
struct session_state *state = ssh->state;
|
||||
const u_char *cp;
|
||||
size_t need;
|
||||
int r;
|
||||
|
||||
if (ssh->kex)
|
||||
return SSH_ERR_INTERNAL_ERROR;
|
||||
*typep = SSH_MSG_NONE;
|
||||
cp = sshbuf_ptr(state->input);
|
||||
if (state->packlen == 0) {
|
||||
if (sshbuf_len(state->input) < 4 + 1)
|
||||
return 0; /* packet is incomplete */
|
||||
state->packlen = PEEK_U32(cp);
|
||||
if (state->packlen < 4 + 1 ||
|
||||
state->packlen > PACKET_MAX_SIZE)
|
||||
return SSH_ERR_MESSAGE_INCOMPLETE;
|
||||
}
|
||||
need = state->packlen + 4;
|
||||
if (sshbuf_len(state->input) < need)
|
||||
return 0; /* packet is incomplete */
|
||||
sshbuf_reset(state->incoming_packet);
|
||||
if ((r = sshbuf_put(state->incoming_packet, cp + 4,
|
||||
state->packlen)) != 0 ||
|
||||
(r = sshbuf_consume(state->input, need)) != 0 ||
|
||||
(r = sshbuf_get_u8(state->incoming_packet, NULL)) != 0 ||
|
||||
(r = sshbuf_get_u8(state->incoming_packet, typep)) != 0)
|
||||
return r;
|
||||
if (ssh_packet_log_type(*typep))
|
||||
debug3("%s: type %u", __func__, *typep);
|
||||
/* sshbuf_dump(state->incoming_packet, stderr); */
|
||||
/* reset for next packet */
|
||||
state->packlen = 0;
|
||||
return r;
|
||||
}
|
||||
|
||||
int
|
||||
ssh_packet_read_poll2(struct ssh *ssh, u_char *typep, u_int32_t *seqnr_p)
|
||||
{
|
||||
|
@ -1635,6 +1689,9 @@ ssh_packet_read_poll2(struct ssh *ssh, u_char *typep, u_int32_t *seqnr_p)
|
|||
struct sshcomp *comp = NULL;
|
||||
int r;
|
||||
|
||||
if (state->mux)
|
||||
return ssh_packet_read_poll2_mux(ssh, typep, seqnr_p);
|
||||
|
||||
*typep = SSH_MSG_NONE;
|
||||
|
||||
if (state->packet_discard)
|
||||
|
@ -2875,11 +2932,43 @@ sshpkt_start(struct ssh *ssh, u_char type)
|
|||
return sshbuf_put(ssh->state->outgoing_packet, buf, len);
|
||||
}
|
||||
|
||||
static int
|
||||
ssh_packet_send_mux(struct ssh *ssh)
|
||||
{
|
||||
struct session_state *state = ssh->state;
|
||||
u_char type, *cp;
|
||||
size_t len;
|
||||
int r;
|
||||
|
||||
if (ssh->kex)
|
||||
return SSH_ERR_INTERNAL_ERROR;
|
||||
len = sshbuf_len(state->outgoing_packet);
|
||||
if (len < 6)
|
||||
return SSH_ERR_INTERNAL_ERROR;
|
||||
cp = sshbuf_mutable_ptr(state->outgoing_packet);
|
||||
type = cp[5];
|
||||
if (ssh_packet_log_type(type))
|
||||
debug3("%s: type %u", __func__, type);
|
||||
/* drop everything, but the connection protocol */
|
||||
if (type >= SSH2_MSG_CONNECTION_MIN &&
|
||||
type <= SSH2_MSG_CONNECTION_MAX) {
|
||||
POKE_U32(cp, len - 4);
|
||||
if ((r = sshbuf_putb(state->output,
|
||||
state->outgoing_packet)) != 0)
|
||||
return r;
|
||||
/* sshbuf_dump(state->output, stderr); */
|
||||
}
|
||||
sshbuf_reset(state->outgoing_packet);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* send it */
|
||||
|
||||
int
|
||||
sshpkt_send(struct ssh *ssh)
|
||||
{
|
||||
if (ssh->state && ssh->state->mux)
|
||||
return ssh_packet_send_mux(ssh);
|
||||
if (compat20)
|
||||
return ssh_packet_send2(ssh);
|
||||
else
|
||||
|
|
6
packet.h
6
packet.h
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: packet.h,v 1.72 2016/09/28 16:33:07 djm Exp $ */
|
||||
/* $OpenBSD: packet.h,v 1.73 2016/09/30 09:19:13 markus Exp $ */
|
||||
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
|
@ -97,6 +97,10 @@ void ssh_packet_set_interactive(struct ssh *, int, int, int);
|
|||
int ssh_packet_is_interactive(struct ssh *);
|
||||
void ssh_packet_set_server(struct ssh *);
|
||||
void ssh_packet_set_authenticated(struct ssh *);
|
||||
void ssh_packet_set_mux(struct ssh *);
|
||||
int ssh_packet_get_mux(struct ssh *);
|
||||
|
||||
int ssh_packet_log_type(u_char);
|
||||
|
||||
int ssh_packet_send1(struct ssh *);
|
||||
int ssh_packet_send2_wrapped(struct ssh *);
|
||||
|
|
27
ssh.c
27
ssh.c
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: ssh.c,v 1.446 2016/09/12 23:31:27 djm Exp $ */
|
||||
/* $OpenBSD: ssh.c,v 1.447 2016/09/30 09:19:13 markus Exp $ */
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
|
@ -213,10 +213,6 @@ static int ssh_session2(void);
|
|||
static void load_public_identity_files(void);
|
||||
static void main_sigchld_handler(int);
|
||||
|
||||
/* from muxclient.c */
|
||||
void muxclient(const char *);
|
||||
void muxserver_listen(void);
|
||||
|
||||
/* ~/ expand a list of paths. NB. assumes path[n] is heap-allocated. */
|
||||
static void
|
||||
tilde_expand_paths(char **paths, u_int num_paths)
|
||||
|
@ -668,6 +664,8 @@ main(int ac, char **av)
|
|||
muxclient_command = SSHMUX_COMMAND_STOP;
|
||||
else if (strcmp(optarg, "cancel") == 0)
|
||||
muxclient_command = SSHMUX_COMMAND_CANCEL_FWD;
|
||||
else if (strcmp(optarg, "proxy") == 0)
|
||||
muxclient_command = SSHMUX_COMMAND_PROXY;
|
||||
else
|
||||
fatal("Invalid multiplex command.");
|
||||
break;
|
||||
|
@ -1162,7 +1160,8 @@ main(int ac, char **av)
|
|||
tty_flag = options.request_tty != REQUEST_TTY_NO;
|
||||
|
||||
/* Force no tty */
|
||||
if (options.request_tty == REQUEST_TTY_NO || muxclient_command != 0)
|
||||
if (options.request_tty == REQUEST_TTY_NO ||
|
||||
(muxclient_command && muxclient_command != SSHMUX_COMMAND_PROXY))
|
||||
tty_flag = 0;
|
||||
/* Do not allocate a tty if stdin is not a tty. */
|
||||
if ((!isatty(fileno(stdin)) || stdin_null_flag) &&
|
||||
|
@ -1239,8 +1238,16 @@ main(int ac, char **av)
|
|||
|
||||
if (muxclient_command != 0 && options.control_path == NULL)
|
||||
fatal("No ControlPath specified for \"-O\" command");
|
||||
if (options.control_path != NULL)
|
||||
muxclient(options.control_path);
|
||||
if (options.control_path != NULL) {
|
||||
int sock;
|
||||
if ((sock = muxclient(options.control_path)) >= 0) {
|
||||
packet_set_connection(sock, sock);
|
||||
ssh = active_state; /* XXX */
|
||||
enable_compat20(); /* XXX */
|
||||
packet_set_mux();
|
||||
goto skip_connect;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If hostname canonicalisation was not enabled, then we may not
|
||||
|
@ -1443,6 +1450,7 @@ main(int ac, char **av)
|
|||
options.certificate_files[i] = NULL;
|
||||
}
|
||||
|
||||
skip_connect:
|
||||
exit_status = compat20 ? ssh_session2() : ssh_session();
|
||||
packet_close();
|
||||
|
||||
|
@ -1953,7 +1961,8 @@ ssh_session2(void)
|
|||
ssh_init_forwarding();
|
||||
|
||||
/* Start listening for multiplex clients */
|
||||
muxserver_listen();
|
||||
if (!packet_get_mux())
|
||||
muxserver_listen();
|
||||
|
||||
/*
|
||||
* If we are in control persist mode and have a working mux listen
|
||||
|
|
Loading…
Reference in New Issue