1 /*
2 * OpenVPN -- An application to securely tunnel IP networks
3 * over a single UDP port, with support for SSL/TLS-based
4 * session authentication and key exchange,
5 * packet encryption, packet authentication, and
6 * packet compression.
7 *
8 * Copyright (C) 2002-2018 OpenVPN Inc <sales@openvpn.net>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2
12 * as published by the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 */
23
24 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #elif defined(_MSC_VER)
27 #include "config-msvc.h"
28 #endif
29
30 #include "syshead.h"
31
32 #ifdef USE_COMP
33
34 #include "comp.h"
35 #include "error.h"
36 #include "otime.h"
37
38 #include "memdbg.h"
39
40 struct compress_context *
comp_init(const struct compress_options * opt)41 comp_init(const struct compress_options *opt)
42 {
43 struct compress_context *compctx = NULL;
44 switch (opt->alg)
45 {
46 case COMP_ALG_STUB:
47 ALLOC_OBJ_CLEAR(compctx, struct compress_context);
48 compctx->flags = opt->flags;
49 compctx->alg = comp_stub_alg;
50 break;
51
52 case COMP_ALGV2_UNCOMPRESSED:
53 ALLOC_OBJ_CLEAR(compctx, struct compress_context);
54 compctx->flags = opt->flags;
55 compctx->alg = compv2_stub_alg;
56 break;
57
58 #ifdef ENABLE_LZO
59 case COMP_ALG_LZO:
60 ALLOC_OBJ_CLEAR(compctx, struct compress_context);
61 compctx->flags = opt->flags;
62 compctx->alg = lzo_alg;
63 break;
64
65 #endif
66 #ifdef ENABLE_LZ4
67 case COMP_ALG_LZ4:
68 ALLOC_OBJ_CLEAR(compctx, struct compress_context);
69 compctx->flags = opt->flags;
70 compctx->alg = lz4_alg;
71 break;
72
73 case COMP_ALGV2_LZ4:
74 ALLOC_OBJ_CLEAR(compctx, struct compress_context);
75 compctx->flags = opt->flags;
76 compctx->alg = lz4v2_alg;
77 break;
78 #endif
79 }
80 if (compctx)
81 {
82 (*compctx->alg.compress_init)(compctx);
83 }
84
85 return compctx;
86 }
87
88 /* In the v2 compression schemes, an uncompressed packet has
89 * has no opcode in front, unless the first byte is 0x50. In this
90 * case the packet needs to be escaped */
91 void
compv2_escape_data_ifneeded(struct buffer * buf)92 compv2_escape_data_ifneeded(struct buffer *buf)
93 {
94 uint8_t *head = BPTR(buf);
95 if (head[0] != COMP_ALGV2_INDICATOR_BYTE)
96 {
97 return;
98 }
99
100 /* Header is 0x50 */
101 ASSERT(buf_prepend(buf, 2));
102
103 head = BPTR(buf);
104 head[0] = COMP_ALGV2_INDICATOR_BYTE;
105 head[1] = COMP_ALGV2_UNCOMPRESSED;
106 }
107
108
109 void
comp_uninit(struct compress_context * compctx)110 comp_uninit(struct compress_context *compctx)
111 {
112 if (compctx)
113 {
114 (*compctx->alg.compress_uninit)(compctx);
115 free(compctx);
116 }
117 }
118
119 void
comp_add_to_extra_frame(struct frame * frame)120 comp_add_to_extra_frame(struct frame *frame)
121 {
122 /* Leave room for our one-byte compressed/didn't-compress prefix byte. */
123 frame_add_to_extra_frame(frame, COMP_PREFIX_LEN);
124 }
125
126 void
comp_add_to_extra_buffer(struct frame * frame)127 comp_add_to_extra_buffer(struct frame *frame)
128 {
129 /* Leave room for compression buffer to expand in worst case scenario
130 * where data is totally incompressible */
131 frame_add_to_extra_buffer(frame, COMP_EXTRA_BUFFER(EXPANDED_SIZE(frame)));
132 }
133
134 void
comp_print_stats(const struct compress_context * compctx,struct status_output * so)135 comp_print_stats(const struct compress_context *compctx, struct status_output *so)
136 {
137 if (compctx)
138 {
139 status_printf(so, "pre-compress bytes," counter_format, compctx->pre_compress);
140 status_printf(so, "post-compress bytes," counter_format, compctx->post_compress);
141 status_printf(so, "pre-decompress bytes," counter_format, compctx->pre_decompress);
142 status_printf(so, "post-decompress bytes," counter_format, compctx->post_decompress);
143 }
144 }
145
146 /*
147 * Tell our peer which compression algorithms we support.
148 */
149 void
comp_generate_peer_info_string(const struct compress_options * opt,struct buffer * out)150 comp_generate_peer_info_string(const struct compress_options *opt, struct buffer *out)
151 {
152 if (opt)
153 {
154 bool lzo_avail = false;
155 if (!(opt->flags & COMP_F_ADVERTISE_STUBS_ONLY))
156 {
157 #if defined(ENABLE_LZ4)
158 buf_printf(out, "IV_LZ4=1\n");
159 buf_printf(out, "IV_LZ4v2=1\n");
160 #endif
161 #if defined(ENABLE_LZO)
162 buf_printf(out, "IV_LZO=1\n");
163 lzo_avail = true;
164 #endif
165 }
166 if (!lzo_avail)
167 {
168 buf_printf(out, "IV_LZO_STUB=1\n");
169 }
170 buf_printf(out, "IV_COMP_STUB=1\n");
171 buf_printf(out, "IV_COMP_STUBv2=1\n");
172 buf_printf(out, "IV_TCPNL=1\n");
173 }
174 }
175
176 #endif /* USE_COMP */
177