OpenVPN 3 Core Library
Loading...
Searching...
No Matches
continuation_fragment.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// Server-side code to fragment an oversized options buffer
13// into multiple buffers using the push-continuation option.
14
15#pragma once
16
17#include <string>
18#include <vector>
19
24
25namespace openvpn {
26
27// Fragment a long PUSH_REPLY/PUSH_UPDATE buffer into
28// multiple buffers using the push-continuation option.
29class PushContinuationFragment : public std::vector<BufferPtr>
30{
31 public:
32 // maximum allowable fragment size (excluding null termination
33 // that will be appended by push_reply() in servproto.hpp).
34 static constexpr size_t FRAGMENT_SIZE = 1023;
35
36 OPENVPN_EXCEPTION(push_continuation_fragment_error);
37
38 static bool should_fragment(const ConstBuffer &buf)
39 {
40 return buf.size() > FRAGMENT_SIZE;
41 }
42
43 // prefix should be PUSH_REPLY or PUSH_UPDATE
44 PushContinuationFragment(const ConstBuffer &buf, const std::string &prefix)
45 {
46 // size of ",push-continuation n"
47 const size_t push_continuation_len = 20;
48
49 // loop over options
50 bool did_continuation = false;
51 PushLex lex(buf, true);
52 while (lex.defined())
53 {
54 // get escaped opt
55 const std::string escaped_opt = lex.next();
56
57 // create first buffer on loop startup
58 if (empty())
59 append_new_buffer(prefix);
60
61 // ready to finalize this outbut buffer and move on to next?
62 // (the +1 is for escaped_opt comma)
63 if (back()->size() + escaped_opt.size() + push_continuation_len + 1 > FRAGMENT_SIZE)
64 {
65 did_continuation = true;
66 append_push_continuation(*back(), false);
67 append_new_buffer(prefix);
68 }
69
70 back()->push_back(',');
71 buf_append_string(*back(), escaped_opt);
72 }
73
74 // push final push-continuation
75 if (!empty() && did_continuation)
76 append_push_continuation(*back(), true);
77 }
78
79 // prefix should be PUSH_REPLY or PUSH_UPDATE
80 static BufferPtr defragment(const std::vector<BufferPtr> &bv,
81 const std::string &prefix)
82 {
83 // exit cases where no need to defrag
84 if (bv.empty())
85 return BufferPtr();
86 if (bv.size() == 1)
87 return bv[0];
88
89 // compute length
90 size_t total_size = 0;
91 for (const auto &e : bv)
92 total_size += e->size();
93
94 // allocate return buffer
95 auto ret = BufferAllocatedRc::Create(total_size);
96 buf_append_string(*ret, prefix);
97
98 // terminators
99 static const char pc1[] = ",push-continuation 1";
100 static const char pc2[] = ",push-continuation 2";
101
102 // build return buffer
103 const std::string prefix_comma = prefix + ',';
104 const size_t size = bv.size();
105 for (size_t i = 0; i < size; ++i)
106 {
107 const Buffer &buf = *bv[i];
108 const char *pc = (i == size - 1) ? pc1 : pc2;
109 const auto strbuf = buf_to_string(buf);
110 if (strbuf.starts_with(prefix_comma) && strbuf.ends_with(pc))
111 {
112 Buffer b = buf;
113 b.advance(prefix.size()); // advance past prefix
114 b.set_size(b.size() - 20); // truncate ",push-continuation n"
115 ret->append(b);
116 }
117 else
118 throw push_continuation_fragment_error("badly formatted fragments");
119 }
120 return ret;
121 }
122
123 private:
124 // create a new PUSH_REPLY/PUSH_UPDATE buffer
125 void append_new_buffer(const std::string &prefix)
126 {
127 // include extra byte for null termination
129 buf_append_string(*bp, prefix);
130 push_back(std::move(bp));
131 }
132
133 // append a push-continuation directive to buffer
134 static void append_push_continuation(Buffer &buf, bool end)
135 {
136 buf_append_string(buf, ",push-continuation ");
137 buf.push_back(end ? '1' : '2');
138 }
139};
140} // namespace openvpn
void push_back(const T &value)
Append a T object to the end of the array, resizing the array if necessary.
Definition buffer.hpp:1479
size_t size() const
Returns the size of the buffer in T objects.
Definition buffer.hpp:1241
void advance(const size_t delta)
Advances the buffer by the specified delta.
Definition buffer.hpp:1276
void set_size(const size_t size)
After an external method, operating on the array as a mutable unsigned char buffer,...
Definition buffer.hpp:1381
static void append_push_continuation(Buffer &buf, bool end)
OPENVPN_EXCEPTION(push_continuation_fragment_error)
PushContinuationFragment(const ConstBuffer &buf, const std::string &prefix)
void append_new_buffer(const std::string &prefix)
static BufferPtr defragment(const std::vector< BufferPtr > &bv, const std::string &prefix)
static bool should_fragment(const ConstBuffer &buf)
bool defined() const
Definition pushlex.hpp:61
std::string next()
Definition pushlex.hpp:71
static Ptr Create(ArgsT &&...args)
Creates a new instance of RcEnable with the given arguments.
Definition make_rc.hpp:43
void buf_append_string(Buffer &buf, const std::string &str)
Definition bufstr.hpp:82
RCPtr< BufferAllocatedRc > BufferPtr
Definition buffer.hpp:1896
std::string buf_to_string(const Buffer &buf)
Definition bufstr.hpp:22
server addresses push_back(address)
std::string ret