diff --git a/cstp.c b/cstp.c index 048920f4..6fe87240 100644 --- a/cstp.c +++ b/cstp.c @@ -734,6 +734,56 @@ int decompress_and_queue_packet(struct openconnect_info *vpninfo, return 0; } +int compress_packet(struct openconnect_info *vpninfo, int compr_type, struct pkt *this) +{ + int ret; + if (compr_type == COMPR_DEFLATE) { + unsigned char *adler; + + vpninfo->deflate_strm.next_in = this->data; + vpninfo->deflate_strm.avail_in = this->len; + vpninfo->deflate_strm.next_out = (void *)vpninfo->deflate_pkt->data; + vpninfo->deflate_strm.avail_out = vpninfo->deflate_pkt_size - 4; + vpninfo->deflate_strm.total_out = 0; + + ret = deflate(&vpninfo->deflate_strm, Z_SYNC_FLUSH); + if (ret) { + vpn_progress(vpninfo, PRG_ERR, _("deflate failed %d\n"), ret); + /* Things are going to go horribly wrong if we try to do any + more compression. Give up entirely. */ + vpninfo->cstp_compr = 0; + return -EIO; + } + + /* Add ongoing adler32 to tail of compressed packet */ + vpninfo->deflate_adler32 = adler32(vpninfo->deflate_adler32, + this->data, this->len); + + adler = &vpninfo->deflate_pkt->data[vpninfo->deflate_strm.total_out]; + *(adler++) = vpninfo->deflate_adler32 >> 24; + *(adler++) = (vpninfo->deflate_adler32 >> 16) & 0xff; + *(adler++) = (vpninfo->deflate_adler32 >> 8) & 0xff; + *(adler) = vpninfo->deflate_adler32 & 0xff; + + vpninfo->deflate_pkt->len = vpninfo->deflate_strm.total_out + 4; + return 0; + } else if (vpninfo->cstp_compr == COMPR_LZS) { + if (this->len < 40) + return -EFBIG; + + ret = lzs_compress(vpninfo->deflate_pkt->data, this->len, + this->data, this->len); + if (ret < 0) + return ret; + + vpninfo->deflate_pkt->len = ret; + return 0; + } else + return -EINVAL; + + return 0; +} + #if defined(OPENCONNECT_OPENSSL) static int cstp_read(struct openconnect_info *vpninfo, void *buf, int maxlen) { @@ -1065,49 +1115,10 @@ int cstp_mainloop(struct openconnect_info *vpninfo, int *timeout) vpninfo->outgoing_queue = this->next; vpninfo->outgoing_qlen--; - if (vpninfo->cstp_compr == COMPR_DEFLATE) { - unsigned char *adler; - - vpninfo->deflate_strm.next_in = this->data; - vpninfo->deflate_strm.avail_in = this->len; - vpninfo->deflate_strm.next_out = (void *)vpninfo->deflate_pkt->data; - vpninfo->deflate_strm.avail_out = vpninfo->deflate_pkt_size - 4; - vpninfo->deflate_strm.total_out = 0; - - ret = deflate(&vpninfo->deflate_strm, Z_SYNC_FLUSH); - if (ret) { - vpn_progress(vpninfo, PRG_ERR, _("deflate failed %d\n"), ret); - goto uncompr; - } - - /* Add ongoing adler32 to tail of compressed packet */ - vpninfo->deflate_adler32 = adler32(vpninfo->deflate_adler32, - this->data, this->len); - - adler = &vpninfo->deflate_pkt->data[vpninfo->deflate_strm.total_out]; - *(adler++) = vpninfo->deflate_adler32 >> 24; - *(adler++) = (vpninfo->deflate_adler32 >> 16) & 0xff; - *(adler++) = (vpninfo->deflate_adler32 >> 8) & 0xff; - *(adler) = vpninfo->deflate_adler32 & 0xff; - - vpninfo->deflate_pkt->len = vpninfo->deflate_strm.total_out + 4; - - vpninfo->deflate_pkt->hdr[4] = (vpninfo->deflate_pkt->len) >> 8; - vpninfo->deflate_pkt->hdr[5] = (vpninfo->deflate_pkt->len) & 0xff; - - vpn_progress(vpninfo, PRG_TRACE, - _("Sending deflate compressed data packet of %d bytes (was %d)\n"), - vpninfo->deflate_pkt->len, this->len); - - vpninfo->pending_deflated_pkt = this; - vpninfo->current_ssl_pkt = vpninfo->deflate_pkt; - } else if (vpninfo->cstp_compr == COMPR_LZS) { - ret = lzs_compress(vpninfo->deflate_pkt->data, this->len, - this->data, this->len); + if (vpninfo->cstp_compr) { + ret = compress_packet(vpninfo, vpninfo->cstp_compr, this); if (ret < 0) - goto uncompr; /* It only ever returns -EFBIG */ - - vpninfo->deflate_pkt->len = ret; + goto uncompr; vpninfo->deflate_pkt->hdr[4] = (vpninfo->deflate_pkt->len) >> 8; vpninfo->deflate_pkt->hdr[5] = (vpninfo->deflate_pkt->len) & 0xff; @@ -1116,8 +1127,8 @@ int cstp_mainloop(struct openconnect_info *vpninfo, int *timeout) vpninfo->deflate_pkt->hdr[7] = 0; vpn_progress(vpninfo, PRG_TRACE, - _("Sending LZS compressed data packet of %d bytes (was %d)\n"), - ret, this->len); + _("Sending compressed data packet of %d bytes (was %d)\n"), + vpninfo->deflate_pkt->len, this->len); vpninfo->pending_deflated_pkt = this; vpninfo->current_ssl_pkt = vpninfo->deflate_pkt; diff --git a/dtls.c b/dtls.c index 8b58acc8..7c580bae 100644 --- a/dtls.c +++ b/dtls.c @@ -854,19 +854,14 @@ int dtls_mainloop(struct openconnect_info *vpninfo, int *timeout) /* One byte of header */ this->hdr[7] = AC_PKT_DATA; - /* We can just use vpninfo->deflate_pkt unless CSTP currently - * has a compressed packet pending — which it shouldn't if - * DTLS is active. */ - if (vpninfo->dtls_compr & COMPR_LZS && this->len > 0x40 && - vpninfo->current_ssl_pkt != vpninfo->deflate_pkt) { - - ret = lzs_compress(vpninfo->deflate_pkt->data, this->len, - this->data, this->len); - if (ret > 0) { + /* We can compress into vpninfo->deflate_pkt unless CSTP + * currently has a compressed packet pending — which it + * shouldn't if DTLS is active. */ + if (vpninfo->dtls_compr && + vpninfo->current_ssl_pkt != vpninfo->deflate_pkt && + !compress_packet(vpninfo, vpninfo->dtls_compr, this)) { send_pkt = vpninfo->deflate_pkt; send_pkt->hdr[7] = AC_PKT_COMPRESSED; - send_pkt->len = ret; - } } #if defined(DTLS_OPENSSL) diff --git a/openconnect-internal.h b/openconnect-internal.h index 1a3f31d2..95b5d6e4 100644 --- a/openconnect-internal.h +++ b/openconnect-internal.h @@ -633,6 +633,7 @@ int cstp_bye(struct openconnect_info *vpninfo, const char *reason); void cstp_free_splits(struct openconnect_info *vpninfo); int decompress_and_queue_packet(struct openconnect_info *vpninfo, unsigned char *buf, int len); +int compress_packet(struct openconnect_info *vpninfo, int compr_type, struct pkt *this); /* lzs.c */ int lzs_decompress(unsigned char *dst, int dstlen, const unsigned char *src, int srclen);