diff options
Diffstat (limited to 'packet.c')
-rw-r--r-- | packet.c | 124 |
1 files changed, 87 insertions, 37 deletions
@@ -42,7 +42,7 @@ static void make_mac(unsigned int seqno, const struct key_context_directional * static int checkmac(); #define ZLIB_COMPRESS_INCR 100 -#define ZLIB_DECOMPRESS_INCR 100 +#define ZLIB_DECOMPRESS_INCR 1024 #ifndef DISABLE_ZLIB static buffer* buf_decompress(buffer* buf, unsigned int len); static void buf_compress(buffer * dest, buffer * src, unsigned int len); @@ -55,10 +55,62 @@ void write_packet() { buffer * writebuf = NULL; time_t now; unsigned packet_type; + int all_ignore = 1; +#ifdef HAVE_WRITEV + struct iovec *iov = NULL; + int i; + struct Link *l; +#endif - TRACE(("enter write_packet")) + TRACE2(("enter write_packet")) dropbear_assert(!isempty(&ses.writequeue)); +#ifdef HAVE_WRITEV + iov = m_malloc(sizeof(*iov) * ses.writequeue.count); + for (l = ses.writequeue.head, i = 0; l; l = l->link, i++) + { + writebuf = (buffer*)l->item; + packet_type = writebuf->data[writebuf->len-1]; + len = writebuf->len - 1 - writebuf->pos; + dropbear_assert(len > 0); + all_ignore &= (packet_type == SSH_MSG_IGNORE); + TRACE2(("write_packet writev #%d type %d len %d/%d", i, packet_type, + len, writebuf->len-1)) + iov[i].iov_base = buf_getptr(writebuf, len); + iov[i].iov_len = len; + } + written = writev(ses.sock_out, iov, ses.writequeue.count); + if (written < 0) { + if (errno == EINTR) { + m_free(iov); + TRACE2(("leave writepacket: EINTR")) + return; + } else { + dropbear_exit("Error writing"); + } + } + + if (written == 0) { + ses.remoteclosed(); + } + + while (written > 0) { + writebuf = (buffer*)examine(&ses.writequeue); + len = writebuf->len - 1 - writebuf->pos; + if (len > written) { + // partial buffer write + buf_incrpos(writebuf, written); + written = 0; + } else { + written -= len; + dequeue(&ses.writequeue); + buf_free(writebuf); + } + } + + m_free(iov); + +#else /* Get the next buffer in the queue of encrypted packets to write*/ writebuf = (buffer*)examine(&ses.writequeue); @@ -72,19 +124,13 @@ void write_packet() { if (written < 0) { if (errno == EINTR) { - TRACE(("leave writepacket: EINTR")) + TRACE2(("leave writepacket: EINTR")) return; } else { dropbear_exit("Error writing"); } } - - now = time(NULL); - ses.last_trx_packet_time = now; - - if (packet_type != SSH_MSG_IGNORE) { - ses.last_packet_time = now; - } + all_ignore = (packet_type == SSH_MSG_IGNORE); if (written == 0) { ses.remoteclosed(); @@ -100,7 +146,15 @@ void write_packet() { buf_incrpos(writebuf, written); } - TRACE(("leave write_packet")) +#endif + now = time(NULL); + ses.last_trx_packet_time = now; + + if (!all_ignore) { + ses.last_packet_time = now; + } + + TRACE2(("leave write_packet")) } /* Non-blocking function reading available portion of a packet into the @@ -112,7 +166,7 @@ void read_packet() { unsigned int maxlen; unsigned char blocksize; - TRACE(("enter read_packet")) + TRACE2(("enter read_packet")) blocksize = ses.keys->recv.algo_crypt->blocksize; if (ses.readbuf == NULL || ses.readbuf->len < blocksize) { @@ -125,7 +179,7 @@ void read_packet() { if (ret == DROPBEAR_FAILURE) { /* didn't read enough to determine the length */ - TRACE(("leave read_packet: packetinit done")) + TRACE2(("leave read_packet: packetinit done")) return; } } @@ -147,7 +201,7 @@ void read_packet() { if (len < 0) { if (errno == EINTR || errno == EAGAIN) { - TRACE(("leave read_packet: EINTR or EAGAIN")) + TRACE2(("leave read_packet: EINTR or EAGAIN")) return; } else { dropbear_exit("Error reading: %s", strerror(errno)); @@ -163,7 +217,7 @@ void read_packet() { /* The main select() loop process_packet() to * handle the packet contents... */ } - TRACE(("leave read_packet")) + TRACE2(("leave read_packet")) } /* Function used to read the initial portion of a packet, and determine the @@ -197,7 +251,7 @@ static int read_packet_init() { } if (slen < 0) { if (errno == EINTR) { - TRACE(("leave read_packet_init: EINTR")) + TRACE2(("leave read_packet_init: EINTR")) return DROPBEAR_FAILURE; } dropbear_exit("Error reading: %s", strerror(errno)); @@ -221,7 +275,7 @@ static int read_packet_init() { } len = buf_getint(ses.readbuf) + 4 + macsize; - TRACE(("packet size is %d, block %d mac %d", len, blocksize, macsize)) + TRACE2(("packet size is %d, block %d mac %d", len, blocksize, macsize)) /* check packet length */ @@ -247,7 +301,7 @@ void decrypt_packet() { unsigned int padlen; unsigned int len; - TRACE(("enter decrypt_packet")) + TRACE2(("enter decrypt_packet")) blocksize = ses.keys->recv.algo_crypt->blocksize; macsize = ses.keys->recv.algo_mac->hashsize; @@ -304,7 +358,7 @@ void decrypt_packet() { ses.recvseq++; - TRACE(("leave decrypt_packet")) + TRACE2(("leave decrypt_packet")) } /* Checks the mac at the end of a decrypted readbuf. @@ -314,7 +368,7 @@ static int checkmac() { unsigned char mac_bytes[MAX_MAC_LEN]; unsigned int mac_size, contents_len; - mac_size = ses.keys->trans.algo_mac->hashsize; + mac_size = ses.keys->recv.algo_mac->hashsize; contents_len = ses.readbuf->len - mac_size; buf_setpos(ses.readbuf, 0); @@ -366,7 +420,12 @@ static buffer* buf_decompress(buffer* buf, unsigned int len) { } if (zstream->avail_out == 0) { - buf_resize(ret, ret->size + ZLIB_DECOMPRESS_INCR); + int new_size = 0; + if (ret->size >= RECV_MAX_PAYLOAD_LEN) { + dropbear_exit("bad packet, oversized decompressed"); + } + new_size = MIN(RECV_MAX_PAYLOAD_LEN, ret->size + ZLIB_DECOMPRESS_INCR); + buf_resize(ret, new_size); } } } @@ -403,7 +462,6 @@ static void enqueue_reply_packet() { ses.reply_queue_head = new_item; } ses.reply_queue_tail = new_item; - TRACE(("leave enqueue_reply_packet")) } void maybe_flush_reply_queue() { @@ -440,24 +498,18 @@ void encrypt_packet() { unsigned int len, encrypt_buf_size; unsigned char mac_bytes[MAX_MAC_LEN]; - TRACE(("enter encrypt_packet()")) + TRACE2(("enter encrypt_packet()")) buf_setpos(ses.writepayload, 0); packet_type = buf_getbyte(ses.writepayload); buf_setpos(ses.writepayload, 0); - TRACE(("encrypt_packet type is %d", packet_type)) + TRACE2(("encrypt_packet type is %d", packet_type)) - if ((!ses.dataallowed && !packet_is_okay_kex(packet_type)) - || ses.kexstate.sentnewkeys) { + if ((!ses.dataallowed && !packet_is_okay_kex(packet_type))) { /* During key exchange only particular packets are allowed. Since this packet_type isn't OK we just enqueue it to send after the KEX, see maybe_flush_reply_queue */ - - /* We also enqueue packets here when we have sent a MSG_NEWKEYS - * packet but are yet to received one. For simplicity we just switch - * over all the keys at once. This is the 'ses.kexstate.sentnewkeys' - * case. */ enqueue_reply_packet(); return; } @@ -559,7 +611,7 @@ void encrypt_packet() { ses.kexstate.datatrans += writebuf->len; ses.transseq++; - TRACE(("leave encrypt_packet()")) + TRACE2(("leave encrypt_packet()")) } @@ -572,8 +624,6 @@ static void make_mac(unsigned int seqno, const struct key_context_directional * unsigned long bufsize; hmac_state hmac; - TRACE(("enter writemac")) - if (key_state->algo_mac->hashsize > 0) { /* calculate the mac */ if (hmac_init(&hmac, @@ -602,7 +652,7 @@ static void make_mac(unsigned int seqno, const struct key_context_directional * dropbear_exit("HMAC error"); } } - TRACE(("leave writemac")) + TRACE2(("leave writemac")) } #ifndef DISABLE_ZLIB @@ -613,7 +663,7 @@ static void buf_compress(buffer * dest, buffer * src, unsigned int len) { unsigned int endpos = src->pos + len; int result; - TRACE(("enter buf_compress")) + TRACE2(("enter buf_compress")) while (1) { @@ -647,6 +697,6 @@ static void buf_compress(buffer * dest, buffer * src, unsigned int len) { buf_resize(dest, dest->size + ZLIB_COMPRESS_INCR); } - TRACE(("leave buf_compress")) + TRACE2(("leave buf_compress")) } #endif |