src/openvpn/comp.c
38d96bd7
 /*
  *  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.
  *
49979459
  *  Copyright (C) 2002-2018 OpenVPN Inc <sales@openvpn.net>
38d96bd7
  *
  *  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.
  *
caa54ac3
  *  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.
38d96bd7
  */
 
 #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)
 {
81d882d5
     struct compress_context *compctx = NULL;
     switch (opt->alg)
38d96bd7
     {
81d882d5
         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;
 
38d96bd7
 #ifdef ENABLE_LZO
81d882d5
         case COMP_ALG_LZO:
             ALLOC_OBJ_CLEAR(compctx, struct compress_context);
             compctx->flags = opt->flags;
             compctx->alg = lzo_alg;
             break;
 
38d96bd7
 #endif
40efb635
 #ifdef ENABLE_LZ4
81d882d5
         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;
40efb635
 #endif
38d96bd7
     }
81d882d5
     if (compctx)
     {
         (*compctx->alg.compress_init)(compctx);
     }
67b3de98
 
81d882d5
     return compctx;
38d96bd7
 }
 
a75bb2e4
 /* 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
81d882d5
 compv2_escape_data_ifneeded(struct buffer *buf)
a75bb2e4
 {
81d882d5
     uint8_t *head = BPTR(buf);
a75bb2e4
     if (head[0] != COMP_ALGV2_INDICATOR_BYTE)
81d882d5
     {
         return;
     }
a75bb2e4
 
     /* Header is 0x50 */
     ASSERT(buf_prepend(buf, 2));
 
81d882d5
     head = BPTR(buf);
a75bb2e4
     head[0] = COMP_ALGV2_INDICATOR_BYTE;
     head[1] = COMP_ALGV2_UNCOMPRESSED;
 }
 
 
38d96bd7
 void
 comp_uninit(struct compress_context *compctx)
 {
81d882d5
     if (compctx)
38d96bd7
     {
81d882d5
         (*compctx->alg.compress_uninit)(compctx);
         free(compctx);
38d96bd7
     }
 }
 
 void
 comp_add_to_extra_frame(struct frame *frame)
 {
81d882d5
     /* Leave room for our one-byte compressed/didn't-compress prefix byte. */
     frame_add_to_extra_frame(frame, COMP_PREFIX_LEN);
38d96bd7
 }
 
 void
 comp_add_to_extra_buffer(struct frame *frame)
 {
81d882d5
     /* 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)));
38d96bd7
 }
 
 void
81d882d5
 comp_print_stats(const struct compress_context *compctx, struct status_output *so)
38d96bd7
 {
81d882d5
     if (compctx)
38d96bd7
     {
81d882d5
         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);
38d96bd7
     }
 }
 
 /*
  * Tell our peer which compression algorithms we support.
  */
 void
 comp_generate_peer_info_string(const struct compress_options *opt, struct buffer *out)
 {
81d882d5
     if (opt)
38d96bd7
     {
81d882d5
         bool lzo_avail = false;
         if (!(opt->flags & COMP_F_ADVERTISE_STUBS_ONLY))
         {
40efb635
 #if defined(ENABLE_LZ4)
81d882d5
             buf_printf(out, "IV_LZ4=1\n");
             buf_printf(out, "IV_LZ4v2=1\n");
40efb635
 #endif
38d96bd7
 #if defined(ENABLE_LZO)
81d882d5
             buf_printf(out, "IV_LZO=1\n");
             lzo_avail = true;
38d96bd7
 #endif
81d882d5
         }
         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");
38d96bd7
     }
 }
 
 #endif /* USE_COMP */