=================================================================== RCS file: /cvsrepo/anoncvs/cvs/src/usr.bin/ssh/packet.c,v retrieving revision 1.241 retrieving revision 1.242 diff -u -r1.241 -r1.242 --- src/usr.bin/ssh/packet.c 2016/09/28 21:44:52 1.241 +++ src/usr.bin/ssh/packet.c 2016/09/30 09:19:13 1.242 @@ -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 * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -198,6 +198,9 @@ /* Used in packet_send2 */ int rekeying; + /* Used in ssh_packet_send_mux() */ + int mux; + /* Used in packet_set_interactive */ int set_interactive_called; @@ -319,7 +322,20 @@ 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) { struct session_state *state = ssh->state; @@ -1067,7 +1083,7 @@ } /* Used to mute debug logging for noisy packet types */ -static int +int ssh_packet_log_type(u_char type) { switch (type) { @@ -1611,6 +1627,44 @@ 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) { @@ -1623,6 +1677,9 @@ 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) @@ -2851,11 +2908,43 @@ 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