OpenVPN 3 Core Library
Loading...
Searching...
No Matches
test_pktstream.cpp
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
13#include "test_common.hpp"
14
17
18using namespace openvpn;
19
20// Return a random value in the range [1,512] but with
21// the subrange [1, 16] having elevated probability.
22static size_t rand_size(RandomAPI &prng)
23{
24 if (prng.randbool())
25 return prng.randrange32(1, 16);
26 return prng.randrange32(1, 512);
27}
28
29template <typename PKTSTREAM>
30static void do_test(const bool grow, const bool verbose)
31{
32#ifdef INSTRUMENTATION_SLOWDOWN
33 const int n_iter = 500;
34#else
35 const int n_iter = 250000;
36#endif
37
38 const Frame::Context fc(256, 512, 256, 0, sizeof(size_t), grow ? BufAllocFlags::GROW : BufAllocFlags::NO_FLAGS);
39 const Frame::Context fc_big(256, 4096, 256, 0, sizeof(size_t), grow ? BufAllocFlags::GROW : BufAllocFlags::NO_FLAGS);
40
41 if (verbose)
42 {
43 OPENVPN_LOG("FC " << fc.info());
44 OPENVPN_LOG("FC BIG " << fc_big.info());
45 }
46
47 MTRand::Ptr prng(new MTRand());
48
49 size_t count = 0;
50
51 for (int iter = 0; iter < n_iter; ++iter)
52 {
53 // build big
55 fc_big.prepare(big);
56 size_t nbig = 0;
57
58 {
60 while (true)
61 {
62 fc.prepare(src);
63 const size_t r = rand_size(*prng);
64 for (size_t i = 0; i < r; ++i)
65 src.push_back('a' + static_cast<unsigned char>(i % 26));
66 PKTSTREAM::prepend_size(src);
67 if (src.size() > fc_big.remaining_payload(big))
68 break;
69 big.write(src.data(), src.size());
70 ++nbig;
71 }
72 }
73
74 // save big
75 const Buffer bigorig(big);
76
77 // deconstruct big
78 BufferAllocated bigcmp;
79 fc_big.prepare(bigcmp);
80 size_t ncmp = 0;
81
82 {
83 PKTSTREAM pktstream;
85 while (!big.empty())
86 {
87 const size_t bytes = std::min(big.size(), rand_size(*prng));
88 fc.prepare(in);
89 in.write(big.data(), bytes);
90 big.advance(bytes);
92 while (!in.empty())
93 {
94 pktstream.put(in, fc);
95 while (pktstream.ready())
96 {
97 pktstream.get(out, fc);
98 PKTSTREAM::prepend_size(out);
99 bigcmp.write(out.data(), out.size());
100 ++ncmp;
101 }
102 }
103 }
104 }
105
106 // sum byte count
107 count += bigorig.size();
108
109 // check result
110 ASSERT_EQ(nbig, ncmp);
111 ASSERT_EQ(bigorig, bigcmp);
112 }
113
114 if (verbose)
115 OPENVPN_LOG("count=" << count);
116}
117
118TEST(Pktstream, Test16)
119{
120 do_test<PacketStream<std::uint16_t>>(false, false);
121}
122
123TEST(Pktstream, Test32)
124{
125 do_test<PacketStream<std::uint32_t>>(false, false);
126}
127
128TEST(Pktstream, Test16Residual)
129{
130 do_test<PacketStreamResidual<std::uint16_t>>(true, false);
131}
132
133TEST(Pktstream, Test32Residual)
134{
135 do_test<PacketStreamResidual<std::uint32_t>>(true, false);
136}
137
138template <typename PKTSTREAM>
139static void validate_size(const Frame::Context &fc, const size_t size, const bool expect_throw)
140{
141 bool actual_throw = false;
142 try
143 {
144 PKTSTREAM::validate_size(size, fc);
145 }
146 catch (typename PKTSTREAM::embedded_packet_size_error &)
147 {
148 actual_throw = true;
149 }
150 if (expect_throw != actual_throw)
151 THROW_FMT("validate_size: bad throw, expect=%s, actual=%s, FC=%s size=%s",
152 expect_throw,
153 actual_throw,
154 fc.info(),
155 size);
156}
157
158template <typename PKTSTREAM>
160{
161 const size_t payload = 2048;
162 const size_t headroom = 16;
163 const size_t tailroom = 0;
164 const size_t align_block = 16;
165 const Frame::Context fixed(headroom, payload, tailroom, 0, align_block, BufAllocFlags::NO_FLAGS);
166 const Frame::Context grow(headroom, payload, tailroom, 0, align_block, BufAllocFlags::GROW);
167 validate_size<PKTSTREAM>(fixed, 2048, false); // succeeds
168 validate_size<PKTSTREAM>(fixed, 2049, true); // exceeded payload, throw
169 validate_size<PKTSTREAM>(grow, 2048, false); // succeeds
170 validate_size<PKTSTREAM>(grow, 2049, false); // exceeded payload, but okay with growable buffer
171}
172
173TEST(Pktstream, ValidateSize16)
174{
175 validate_size_test<PacketStream<std::uint16_t>>();
176}
177
178TEST(Pktstream, ValidateSize32)
179{
180 validate_size_test<PacketStream<std::uint32_t>>();
181}
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
T * data()
Get a mutable pointer to the start of the array.
Definition buffer.hpp:1447
void advance(const size_t delta)
Advances the buffer by the specified delta.
Definition buffer.hpp:1276
bool empty() const
Returns true if the buffer is empty.
Definition buffer.hpp:1235
void write(const T *data, const size_t size)
Write data to the buffer.
Definition buffer.hpp:1560
std::string info() const
Definition frame.hpp:201
size_t prepare(Buffer &buf) const
Definition frame.hpp:116
The smart pointer class.
Definition rc.hpp:119
Abstract base class for random number generators.
Definition randapi.hpp:39
std::uint32_t randrange32(const std::uint32_t end)
Return a uniformly distributed random number in the range [0, end)
Definition randapi.hpp:146
bool randbool()
Return a random boolean.
Definition randapi.hpp:184
#define OPENVPN_LOG(args)
constexpr BufferFlags GROW(1U<< 2)
if enabled, buffer will grow (otherwise buffer_full exception will be thrown)
constexpr BufferFlags NO_FLAGS(0U)
no flags set
#define THROW_FMT(...)
static bool verbose
Definition test_ip.cpp:31
static std::stringstream out
Definition test_path.cpp:10
static size_t rand_size(RandomAPI &prng)
TEST(Pktstream, Test16)
static void do_test(const bool grow, const bool verbose)
static void validate_size(const Frame::Context &fc, const size_t size, const bool expect_throw)
static void validate_size_test()