/* * OpenVPN -- An application to securely tunnel IP networks * over a single UDP port, with support for SSL/TLS-based * session authentication and key exchange, * packet encryption, packet authentication, and * packet compression. * * Copyright (C) 2002-2018 OpenVPN Inc * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifdef HAVE_CONFIG_H #include "config.h" #elif defined(_MSC_VER) #include "config-msvc.h" #endif #include "syshead.h" #ifdef USE_COMP #include "comp.h" #include "error.h" #include "otime.h" #include "memdbg.h" struct compress_context * comp_init(const struct compress_options *opt) { struct compress_context *compctx = NULL; switch (opt->alg) { case COMP_ALG_STUB: ALLOC_OBJ_CLEAR(compctx, struct compress_context); compctx->flags = opt->flags; compctx->alg = comp_stub_alg; break; case COMP_ALGV2_UNCOMPRESSED: ALLOC_OBJ_CLEAR(compctx, struct compress_context); compctx->flags = opt->flags; compctx->alg = compv2_stub_alg; break; #ifdef ENABLE_LZO case COMP_ALG_LZO: ALLOC_OBJ_CLEAR(compctx, struct compress_context); compctx->flags = opt->flags; compctx->alg = lzo_alg; break; #endif #ifdef ENABLE_LZ4 case COMP_ALG_LZ4: ALLOC_OBJ_CLEAR(compctx, struct compress_context); compctx->flags = opt->flags; compctx->alg = lz4_alg; break; case COMP_ALGV2_LZ4: ALLOC_OBJ_CLEAR(compctx, struct compress_context); compctx->flags = opt->flags; compctx->alg = lz4v2_alg; break; #endif } if (compctx) { (*compctx->alg.compress_init)(compctx); } return compctx; } /* In the v2 compression schemes, an uncompressed packet has * has no opcode in front, unless the first byte is 0x50. In this * case the packet needs to be escaped */ void compv2_escape_data_ifneeded(struct buffer *buf) { uint8_t *head = BPTR(buf); if (head[0] != COMP_ALGV2_INDICATOR_BYTE) { return; } /* Header is 0x50 */ ASSERT(buf_prepend(buf, 2)); head = BPTR(buf); head[0] = COMP_ALGV2_INDICATOR_BYTE; head[1] = COMP_ALGV2_UNCOMPRESSED; } void comp_uninit(struct compress_context *compctx) { if (compctx) { (*compctx->alg.compress_uninit)(compctx); free(compctx); } } void comp_add_to_extra_frame(struct frame *frame) { /* Leave room for our one-byte compressed/didn't-compress prefix byte. */ frame_add_to_extra_frame(frame, COMP_PREFIX_LEN); } void comp_add_to_extra_buffer(struct frame *frame) { /* Leave room for compression buffer to expand in worst case scenario * where data is totally uncompressible */ frame_add_to_extra_buffer(frame, COMP_EXTRA_BUFFER(EXPANDED_SIZE(frame))); } void comp_print_stats(const struct compress_context *compctx, struct status_output *so) { if (compctx) { status_printf(so, "pre-compress bytes," counter_format, compctx->pre_compress); status_printf(so, "post-compress bytes," counter_format, compctx->post_compress); status_printf(so, "pre-decompress bytes," counter_format, compctx->pre_decompress); status_printf(so, "post-decompress bytes," counter_format, compctx->post_decompress); } } /* * Tell our peer which compression algorithms we support. */ void comp_generate_peer_info_string(const struct compress_options *opt, struct buffer *out) { if (opt) { bool lzo_avail = false; if (!(opt->flags & COMP_F_ADVERTISE_STUBS_ONLY)) { #if defined(ENABLE_LZ4) buf_printf(out, "IV_LZ4=1\n"); buf_printf(out, "IV_LZ4v2=1\n"); #endif #if defined(ENABLE_LZO) buf_printf(out, "IV_LZO=1\n"); lzo_avail = true; #endif } if (!lzo_avail) { buf_printf(out, "IV_LZO_STUB=1\n"); } buf_printf(out, "IV_COMP_STUB=1\n"); buf_printf(out, "IV_COMP_STUBv2=1\n"); buf_printf(out, "IV_TCPNL=1\n"); } } #endif /* USE_COMP */