OpenVPN 3 Core Library
Loading...
Searching...
No Matches
compress.hpp
Go to the documentation of this file.
1// OpenVPN -- An application to securely tunnel IP networks
2// over a single port, with support for SSL/TLS-based
3// session authentication and key exchange,
4// packet encryption, packet authentication, and
5// packet compression.
6//
7// Copyright (C) 2012- OpenVPN Inc.
8//
9// SPDX-License-Identifier: MPL-2.0 OR AGPL-3.0-only WITH openvpn3-openssl-exception
10//
11
12// Base class and factory for compression/decompression objects.
13// Currently we support LZO, Snappy, and LZ4 implementations.
14
15#ifndef OPENVPN_COMPRESS_COMPRESS_H
16#define OPENVPN_COMPRESS_COMPRESS_H
17
20#include <openvpn/common/rc.hpp>
26
27namespace openvpn {
28
30#if !defined(OPENVPN_DEBUG_COMPRESS)
31#define OPENVPN_DEBUG_COMPRESS 1
32#endif
33
34class Compress : public RC<thread_unsafe_refcount>,
35 public logging::LoggingMixin<OPENVPN_DEBUG_COMPRESS, logging::LOG_LEVEL_TRACE, Compress>
36{
37 public:
39
40 // Compressor name
41 virtual const char *name() const = 0;
42
43 // Compression method implemented by underlying compression class.
44 // hint should normally be true to compress the data. If hint is
45 // false, the data may be uncompressible or already compressed,
46 // so method shouldn't attempt compression.
47 virtual void compress(BufferAllocated &buf, const bool hint) = 0;
48
49 // Decompression method implemented by underlying compression class.
50 virtual void decompress(BufferAllocated &buf) = 0;
51
52 protected:
53 // magic numbers to indicate no compression
54 enum
55 {
57 NO_COMPRESS_SWAP = 0xFB, // for better alignment handling, replace this byte with last byte of packet
58 };
59
60 // Compress V2 constants
61 enum
62 {
64
65 // Compression algs
68 };
69
70 Compress(const Frame::Ptr &frame_arg,
71 const SessionStats::Ptr &stats_arg)
72 : frame(frame_arg), stats(stats_arg)
73 {
74 }
75
77 {
79 buf.reset_size();
80 }
81
82 void do_swap(Buffer &buf, unsigned char op)
83 {
84 if (buf.size())
85 {
86 buf.push_back(buf[0]);
87 buf[0] = op;
88 }
89 else
90 buf.push_back(op);
91 }
92
93 void do_unswap(Buffer &buf)
94 {
95 if (buf.size() >= 2)
96 {
97 const unsigned char first = buf.pop_back();
98 buf.push_front(first);
99 }
100 }
101
102 // Push a COMPRESS_V2 header byte (value).
103 // Pass value == 0 to omit push.
104 void v2_push(Buffer &buf, unsigned char value)
105 {
106 unsigned char uc = buf[0];
107 if (value == 0 && uc != COMPRESS_V2_ESCAPE)
108 return;
109 unsigned char *esc = buf.prepend_alloc(2);
110 esc[0] = COMPRESS_V2_ESCAPE;
111 esc[1] = value;
112 }
113
114 // Pull a COMPRESS_V2 header byte.
115 // Returns the compress op (> 0) on success.
116 // Returns 0 if no compress op.
117 int v2_pull(Buffer &buf)
118 {
119 unsigned char uc = buf[0];
120 if (uc != COMPRESS_V2_ESCAPE)
121 return 0;
122 uc = buf[1];
123 buf.advance(2);
124 return uc;
125 }
126
129};
130} // namespace openvpn
131
132// include compressor implementations here
135
136#ifndef NO_LZO
138#endif
139#ifdef HAVE_LZ4
141#endif
142#ifdef HAVE_SNAPPY
144#endif
145
146namespace openvpn {
148{
149 public:
150 enum Type
151 {
153 COMP_STUB, // generic compression stub
154 COMP_STUBv2, // generic compression stub using v2 protocol
155 ANY, // placeholder for any method on client, before server assigns it
156 ANY_LZO, // placeholder for LZO or LZO_STUB methods on client, before server assigns it
163 };
164
165 OPENVPN_SIMPLE_EXCEPTION(compressor_unavailable);
166
168 {
169 }
170
171 CompressContext(const Type t, const bool asym)
172 : asym_(asym) // asym indicates asymmetrical compression where only downlink is compressed
173 {
174 if (!compressor_available(t))
175 throw compressor_unavailable();
176 type_ = t;
177 }
178
179 Type type() const
180 {
181 return type_;
182 }
183 bool asym() const
184 {
185 return asym_;
186 }
187
188 unsigned int extra_payload_bytes() const
189 {
190 switch (type_)
191 {
192 case NONE:
193 return 0;
194 case COMP_STUBv2:
195 case LZ4v2:
196 return 2; // worst case
197 default:
198 return 1;
199 }
200 }
201
203 {
204 switch (type_)
205 {
206 case NONE:
207 return new CompressNull(frame, stats);
208 case ANY_LZO:
209 case LZO_STUB:
210 return new CompressStub(frame, stats, false);
211 case ANY:
212 case COMP_STUB:
213 return new CompressStub(frame, stats, true);
214 case COMP_STUBv2:
215 return new CompressStubV2(frame, stats);
216#ifndef NO_LZO
217 case LZO:
218 return new CompressLZO(frame, stats, false, asym_);
219 case LZO_SWAP:
220 return new CompressLZO(frame, stats, true, asym_);
221#endif
222#ifdef HAVE_LZ4
223 case LZ4:
224 return new CompressLZ4(frame, stats, asym_);
225 case LZ4v2:
226 return new CompressLZ4v2(frame, stats, asym_);
227#endif
228#ifdef HAVE_SNAPPY
229 case SNAPPY:
230 return new CompressSnappy(frame, stats, asym_);
231#endif
232 default:
233 throw compressor_unavailable();
234 }
235 }
236
237 static bool compressor_available(const Type t)
238 {
239 switch (t)
240 {
241 case NONE:
242 case ANY:
243 case ANY_LZO:
244 case LZO_STUB:
245 case COMP_STUB:
246 case COMP_STUBv2:
247 return true;
248 case LZO:
249 case LZO_SWAP:
250#ifndef NO_LZO
251 return true;
252#else
253 return false;
254#endif
255 case LZ4:
256#ifdef HAVE_LZ4
257 return true;
258#else
259 return false;
260#endif
261 case LZ4v2:
262#ifdef HAVE_LZ4
263 return true;
264#else
265 return false;
266#endif
267 case SNAPPY:
268#ifdef HAVE_SNAPPY
269 return true;
270#else
271 return false;
272#endif
273 default:
274 return false;
275 }
276 }
277
278 // On the client, used to tell server which compression methods we support.
279 // Includes compression V1 and V2 methods.
280 const char *peer_info_string() const
281 {
282 switch (type_)
283 {
284#ifndef NO_LZO
285 case LZO:
286 return "IV_LZO=1\n";
287 case LZO_SWAP:
288 return "IV_LZO_SWAP=1\n";
289#endif
290#ifdef HAVE_LZ4
291 case LZ4:
292 return "IV_LZ4=1\n";
293#endif
294#ifdef HAVE_LZ4
295 case LZ4v2:
296 return "IV_LZ4v2=1\n";
297#endif
298#ifdef HAVE_SNAPPY
299 case SNAPPY:
300 return "IV_SNAPPY=1\n";
301#endif
302 case LZO_STUB:
303 case COMP_STUB:
304 case COMP_STUBv2:
305 return "IV_LZO_STUB=1\n"
306 "IV_COMP_STUB=1\n"
307 "IV_COMP_STUBv2=1\n";
308 case ANY:
309 return
310#ifdef HAVE_SNAPPY
311 "IV_SNAPPY=1\n"
312#endif
313#ifndef NO_LZO
314 "IV_LZO=1\n"
315 "IV_LZO_SWAP=1\n"
316#else
317 "IV_LZO_STUB=1\n"
318#endif
319#ifdef HAVE_LZ4
320 "IV_LZ4=1\n"
321 "IV_LZ4v2=1\n"
322#endif
323 "IV_COMP_STUB=1\n"
324 "IV_COMP_STUBv2=1\n";
325 case ANY_LZO:
326 return
327#ifndef NO_LZO
328 "IV_LZO=1\n"
329 "IV_LZO_SWAP=1\n"
330#else
331 "IV_LZO_STUB=1\n"
332#endif
333 "IV_COMP_STUB=1\n"
334 "IV_COMP_STUBv2=1\n";
335 default:
336 return nullptr;
337 }
338 }
339
340 // On the client, used to tell server which compression methods we support.
341 // Limited only to compression V1 methods.
342 const char *peer_info_string_v1() const
343 {
344 switch (type_)
345 {
346#ifndef NO_LZO
347 case LZO:
348 return "IV_LZO=1\n";
349 case LZO_SWAP:
350 return "IV_LZO_SWAP=1\n";
351#endif
352#ifdef HAVE_LZ4
353 case LZ4:
354 return "IV_LZ4=1\n";
355#endif
356#ifdef HAVE_SNAPPY
357 case SNAPPY:
358 return "IV_SNAPPY=1\n";
359#endif
360 case LZO_STUB:
361 case COMP_STUB:
362 return "IV_LZO_STUB=1\n"
363 "IV_COMP_STUB=1\n";
364 case ANY:
365 return
366#ifdef HAVE_SNAPPY
367 "IV_SNAPPY=1\n"
368#endif
369#ifndef NO_LZO
370 "IV_LZO=1\n"
371 "IV_LZO_SWAP=1\n"
372#else
373 "IV_LZO_STUB=1\n"
374#endif
375#ifdef HAVE_LZ4
376 "IV_LZ4=1\n"
377#endif
378 "IV_COMP_STUB=1\n";
379 case ANY_LZO:
380 return
381#ifndef NO_LZO
382 "IV_LZO=1\n"
383 "IV_LZO_SWAP=1\n"
384#else
385 "IV_LZO_STUB=1\n"
386#endif
387 "IV_COMP_STUB=1\n";
388 default:
389 return nullptr;
390 }
391 }
392
393 const char *options_string() const
394 {
395 switch (type_)
396 {
397 case LZO:
398 case LZO_STUB:
399 case SNAPPY:
400 case LZ4:
401 case LZ4v2:
402 case LZO_SWAP:
403 case COMP_STUB:
404 case COMP_STUBv2:
405 case ANY:
406 case ANY_LZO:
407 return "comp-lzo";
408 default:
409 return nullptr;
410 }
411 }
412
413 const char *str() const
414 {
415 switch (type_)
416 {
417 case LZO:
418 return "LZO";
419 case LZO_SWAP:
420 return "LZO_SWAP";
421 case LZ4:
422 return "LZ4";
423 case LZ4v2:
424 return "LZ4v2";
425 case SNAPPY:
426 return "SNAPPY";
427 case LZO_STUB:
428 return "LZO_STUB";
429 case COMP_STUB:
430 return "COMP_STUB";
431 case COMP_STUBv2:
432 return "COMP_STUBv2";
433 case ANY:
434 return "ANY";
435 case ANY_LZO:
436 return "ANY_LZO";
437 default:
438 return "NONE";
439 }
440 }
441
442 /* This function returns a parseable string representation of the compress
443 * method. NOTE: returns nullptr if no mapping is possible */
444 const char *method_to_string() const
445 {
446 switch (type_)
447 {
448 case LZO:
449 return "lzo";
450 case LZO_SWAP:
451 return "lzo-swap";
452 case LZO_STUB:
453 return "lzo-stub";
454 case LZ4:
455 return "lz4";
456 case LZ4v2:
457 return "lz4v2";
458 case SNAPPY:
459 return "snappy";
460 case COMP_STUB:
461 return "stub";
462 case COMP_STUBv2:
463 return "stub-v2";
464 default:
465 return nullptr;
466 }
467 }
468
469 static Type parse_method(const std::string &method)
470 {
471 if (method == "stub-v2")
472 return COMP_STUBv2;
473 else if (method == "lz4-v2")
474 return LZ4v2;
475 else if (method == "lz4")
476 return LZ4;
477 else if (method == "lzo")
478 return LZO;
479 else if (method == "lzo-swap")
480 return LZO_SWAP;
481 else if (method == "lzo-stub")
482 return LZO_STUB;
483 else if (method == "snappy")
484 return SNAPPY;
485 else if (method == "stub")
486 return COMP_STUB;
487 else
488 return NONE;
489 }
490
491 static Type stub(const Type t)
492 {
493 switch (t)
494 {
495 case COMP_STUBv2:
496 case LZ4v2:
497 return COMP_STUBv2;
498 default:
499 return COMP_STUB;
500 }
501 }
502
510 static bool is_any_stub(const Type t)
511 {
512 switch (t)
513 {
514 case LZO_STUB:
515 case COMP_STUB:
516 case COMP_STUBv2:
517 return true;
518 default:
519 return false;
520 }
521 }
522
523 static void init_static()
524 {
525#ifndef NO_LZO
527#endif
528 }
529
530 private:
532 bool asym_ = false;
533};
534
535} // namespace openvpn
536
537#endif // OPENVPN_COMPRESS_COMPRESS_H
static Type parse_method(const std::string &method)
Definition compress.hpp:469
const char * options_string() const
Definition compress.hpp:393
unsigned int extra_payload_bytes() const
Definition compress.hpp:188
const char * str() const
Definition compress.hpp:413
static Type stub(const Type t)
Definition compress.hpp:491
const char * method_to_string() const
Definition compress.hpp:444
Compress::Ptr new_compressor(const Frame::Ptr &frame, const SessionStats::Ptr &stats)
Definition compress.hpp:202
const char * peer_info_string() const
Definition compress.hpp:280
static bool is_any_stub(const Type t)
Definition compress.hpp:510
OPENVPN_SIMPLE_EXCEPTION(compressor_unavailable)
const char * peer_info_string_v1() const
Definition compress.hpp:342
static void init_static()
Definition compress.hpp:523
static bool compressor_available(const Type t)
Definition compress.hpp:237
CompressContext(const Type t, const bool asym)
Definition compress.hpp:171
static void init_static()
Definition lzoasym.hpp:45
void do_swap(Buffer &buf, unsigned char op)
Definition compress.hpp:82
virtual void decompress(BufferAllocated &buf)=0
void error(BufferAllocated &buf)
Definition compress.hpp:76
virtual const char * name() const =0
void do_unswap(Buffer &buf)
Definition compress.hpp:93
void v2_push(Buffer &buf, unsigned char value)
Definition compress.hpp:104
Frame::Ptr frame
Definition compress.hpp:127
virtual void compress(BufferAllocated &buf, const bool hint)=0
RCPtr< Compress > Ptr
Definition compress.hpp:38
SessionStats::Ptr stats
Definition compress.hpp:128
Compress(const Frame::Ptr &frame_arg, const SessionStats::Ptr &stats_arg)
Definition compress.hpp:70
int v2_pull(Buffer &buf)
Definition compress.hpp:117
T * prepend_alloc(const size_t size)
Allocate space for prepending data to the buffer.
Definition buffer.hpp:1597
void push_back(const T &value)
Append a T object to the end of the array, resizing the array if necessary.
Definition buffer.hpp:1482
size_t size() const
Returns the size of the buffer in T objects.
Definition buffer.hpp:1242
T pop_back()
Removes and returns the last element from the buffer.
Definition buffer.hpp:1248
void advance(const size_t delta)
Advances the buffer by the specified delta.
Definition buffer.hpp:1277
void push_front(const T &value)
Append a T object to the array, with possible resize.
Definition buffer.hpp:1490
void reset_size()
Resets the size of the buffer to zero.
Definition buffer.hpp:1170
The smart pointer class.
Definition rc.hpp:119
Reference count base class for objects tracked by RCPtr. Disallows copying and assignment.
Definition rc.hpp:912
virtual void error(const size_t type, const std::string *text=nullptr)