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 else
27 return prng.randrange32(1, 512);
28}
29
30template <typename PKTSTREAM>
31static void do_test(const bool grow, const bool verbose)
32{
33#ifdef INSTRUMENTATION_SLOWDOWN
34 const int n_iter = 500;
35#else
36 const int n_iter = 250000;
37#endif
38
39 const Frame::Context fc(256, 512, 256, 0, sizeof(size_t), grow ? BufAllocFlags::GROW : BufAllocFlags::NO_FLAGS);
40 const Frame::Context fc_big(256, 4096, 256, 0, sizeof(size_t), grow ? BufAllocFlags::GROW : BufAllocFlags::NO_FLAGS);
41
42 if (verbose)
43 {
44 OPENVPN_LOG("FC " << fc.info());
45 OPENVPN_LOG("FC BIG " << fc_big.info());
46 }
47
48 MTRand::Ptr prng(new MTRand());
49
50 size_t count = 0;
51
52 for (int iter = 0; iter < n_iter; ++iter)
53 {
54 // build big
56 fc_big.prepare(big);
57 size_t nbig = 0;
58
59 {
61 while (true)
62 {
63 fc.prepare(src);
64 const size_t r = rand_size(*prng);
65 for (size_t i = 0; i < r; ++i)
66 src.push_back('a' + static_cast<unsigned char>(i % 26));
67 PKTSTREAM::prepend_size(src);
68 if (src.size() > fc_big.remaining_payload(big))
69 break;
70 big.write(src.data(), src.size());
71 ++nbig;
72 }
73 }
74
75 // save big
76 const Buffer bigorig(big);
77
78 // deconstruct big
79 BufferAllocated bigcmp;
80 fc_big.prepare(bigcmp);
81 size_t ncmp = 0;
82
83 {
84 PKTSTREAM pktstream;
86 while (big.size())
87 {
88 const size_t bytes = std::min(big.size(), rand_size(*prng));
89 fc.prepare(in);
90 in.write(big.data(), bytes);
91 big.advance(bytes);
93 while (in.size())
94 {
95 pktstream.put(in, fc);
96 while (pktstream.ready())
97 {
98 pktstream.get(out, fc);
99 PKTSTREAM::prepend_size(out);
100 bigcmp.write(out.data(), out.size());
101 ++ncmp;
102 }
103 }
104 }
105 }
106
107 // sum byte count
108 count += bigorig.size();
109
110 // check result
111 ASSERT_EQ(nbig, ncmp);
112 ASSERT_EQ(bigorig, bigcmp);
113 }
114
115 if (verbose)
116 OPENVPN_LOG("count=" << count);
117}
118
119TEST(pktstream, test_16)
120{
121 do_test<PacketStream<std::uint16_t>>(false, false);
122}
123
124TEST(pktstream, test_32)
125{
126 do_test<PacketStream<std::uint32_t>>(false, false);
127}
128
129TEST(pktstream, test_16_residual)
130{
131 do_test<PacketStreamResidual<std::uint16_t>>(true, false);
132}
133
134TEST(pktstream, test_32_residual)
135{
136 do_test<PacketStreamResidual<std::uint32_t>>(true, false);
137}
138
139template <typename PKTSTREAM>
140static void validate_size(const Frame::Context &fc, const size_t size, const bool expect_throw)
141{
142 bool actual_throw = false;
143 try
144 {
145 PKTSTREAM::validate_size(size, fc);
146 }
147 catch (typename PKTSTREAM::embedded_packet_size_error &)
148 {
149 actual_throw = true;
150 }
151 if (expect_throw != actual_throw)
152 THROW_FMT("validate_size: bad throw, expect=%s, actual=%s, FC=%s size=%s",
153 expect_throw,
154 actual_throw,
155 fc.info(),
156 size);
157}
158
159template <typename PKTSTREAM>
161{
162 const size_t payload = 2048;
163 const size_t headroom = 16;
164 const size_t tailroom = 0;
165 const size_t align_block = 16;
166 const Frame::Context fixed(headroom, payload, tailroom, 0, align_block, BufAllocFlags::NO_FLAGS);
167 const Frame::Context grow(headroom, payload, tailroom, 0, align_block, BufAllocFlags::GROW);
168 validate_size<PKTSTREAM>(fixed, 2048, false); // succeeds
169 validate_size<PKTSTREAM>(fixed, 2049, true); // exceeded payload, throw
170 validate_size<PKTSTREAM>(grow, 2048, false); // succeeds
171 validate_size<PKTSTREAM>(grow, 2049, false); // exceeded payload, but okay with growable buffer
172}
173
174TEST(pktstream, validate_size_16)
175{
176 validate_size_test<PacketStream<std::uint16_t>>();
177}
178
179TEST(pktstream, validate_size_32)
180{
181 validate_size_test<PacketStream<std::uint32_t>>();
182}
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 * data()
Get a mutable pointer to the start of the array.
Definition buffer.hpp:1450
void advance(const size_t delta)
Advances the buffer by the specified delta.
Definition buffer.hpp:1277
void write(const T *data, const size_t size)
Write data to the buffer.
Definition buffer.hpp:1563
std::string info() const
Definition frame.hpp:202
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:147
bool randbool()
Return a random boolean.
Definition randapi.hpp:186
#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)
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()
TEST(pktstream, test_16)