OpenVPN 3 Core Library
Loading...
Searching...
No Matches
test_generators.hpp
Go to the documentation of this file.
1#ifndef TEST_GENERATORS_HPP
2#define TEST_GENERATORS_HPP
3#ifdef __GNUC__
4#pragma GCC diagnostic push
5#pragma GCC diagnostic ignored "-Wconversion" // turn off warning for rapidcheck
6#endif
7#include <rapidcheck/gtest.h>
8#ifdef __GNUC__
9#pragma GCC diagnostic pop
10#endif
11
12#include <algorithm>
13#include <cstdint>
14#include <limits>
15#include <optional>
16#include <utility>
17#include <string>
18#include <tuple>
19#include <array>
20#include <string_view>
21#include <bitset>
22#include <sstream>
23#include <vector>
24
25#include "openvpn/addr/ip.hpp"
28
29namespace rc {
30
43template <size_t N>
44auto atLeastOneFalse() -> Gen<std::array<bool, N>>
45{
46 static_assert(N > 0, "N must be greater than 0");
47
48 return gen::suchThat(
49 gen::container<std::array<bool, N>>(gen::arbitrary<bool>()),
50 [](const auto &booleans)
51 {
52 return std::any_of(booleans.begin(), booleans.end(), [](const bool b)
53 { return !b; });
54 });
55}
56
77template <size_t N>
78auto generateValidityFlags(const bool all_valid = true) -> Gen<std::array<bool, N>>
79{
80 if (all_valid)
81 {
82 return gen::container<std::array<bool, N>>(gen::just(true));
83 }
84 return atLeastOneFalse<N>();
85}
86
100inline auto IPv4Octet(const bool valid = true) -> Gen<int>
101{
102 static constexpr int min_ipv4_octet = 0;
103 static constexpr int max_ipv4_octet = 255;
104
105 if (valid)
106 {
107 return gen::inRange(min_ipv4_octet, max_ipv4_octet + 1);
108 }
109 return gen::suchThat(gen::arbitrary<int>(), [](const auto &i)
110 { return i < min_ipv4_octet || i > max_ipv4_octet; });
111}
112
129inline auto IPv4Address(const bool valid = true) -> Gen<std::string>
130{
131 static constexpr int octets_number = 4;
132 static constexpr std::array<bool, octets_number> all_true = {true, true, true, true};
133 const auto octet_validity = valid ? all_true : *atLeastOneFalse<octets_number>().as("first,second,third,fourth octet valid");
134
135 return gen::map(
136 gen::tuple(IPv4Octet(octet_validity[0]),
137 IPv4Octet(octet_validity[1]),
138 IPv4Octet(octet_validity[2]),
139 IPv4Octet(octet_validity[3])),
140 [](const auto &octets)
141 {
142 return std::to_string(std::get<0>(octets)) + "." + std::to_string(std::get<1>(octets)) + "."
143 + std::to_string(std::get<2>(octets)) + "." + std::to_string(std::get<3>(octets));
144 });
145}
146
159inline auto asciiPrintableCode() -> Gen<int>
160{
161 static constexpr int ASCII_range_start_code = 32; // ASCII code for space character
162 static constexpr int ASCII_range_end_code = 127; // ASCII code for DEL (not included)
163 static constexpr int ASCII_percent_sign_code = 37; // ASCII code for percent sign
164
165 // Due to IPv6 Scoped Address Architecture (RFC 4007) anything after '%' is not part of IPv6 address but zone_id
166 // Therefore generating '% breaks assumption on validity of generated IPv6 addresses
167 return gen::distinctFrom(gen::inRange(ASCII_range_start_code, ASCII_range_end_code), ASCII_percent_sign_code);
168}
169
185inline auto hexChar(const bool valid = true) -> Gen<std::string>
186{
187 if (valid)
188 {
189 const auto alphapositives = gen::elementOf(std::string("abcdefABCDEF123456789"));
190
191 static constexpr int probability_weight_of_0 = 23;
192 static constexpr int probability_weight_of_alphapositives = 1;
193
194 // "0" should be generated <probability_weight_of_0> times more often
195 return gen::map(gen::weightedOneOf<char>({{probability_weight_of_0, gen::just<char>('0')},
196 {probability_weight_of_alphapositives, alphapositives}}),
197 [](const auto &c)
198 {
199 return std::string{static_cast<char>(c)};
200 });
201 }
202
203 // Generate invalid hexadecimal characters
204 return gen::map(gen::suchThat(asciiPrintableCode(), [](const auto &c)
205 { return isxdigit(c) == 0; }),
206 [](const auto &c)
207 {
208 return std::string{static_cast<char>(c)};
209 });
210}
211
226inline auto IPv6HextetValue(const bool valid = true) -> Gen<std::string>
227{
228 static constexpr int hexchars_number = 4;
229 static constexpr std::array<bool, hexchars_number> all_true = {true, true, true, true};
230 const auto hexchar_validity = valid ? all_true : *atLeastOneFalse<hexchars_number>().as("first,second,third,fourth hexchar in hextet valid");
231
232 return gen::map(
233 gen::tuple(hexChar(hexchar_validity[0]),
234 hexChar(hexchar_validity[1]),
235 hexChar(hexchar_validity[2]),
236 hexChar(hexchar_validity[3])),
237 [](const auto &hexchars)
238 {
239 const auto &[first_hexchar, second_hexchar, third_hexchar, fourth_hexchar] = hexchars;
240 return first_hexchar + second_hexchar + third_hexchar + fourth_hexchar;
241 });
242}
243
251inline std::string removeLeadingZerosFromHextet(const std::string &hextet)
252{
253 const auto first_nonzero = hextet.find_first_not_of('0');
254 return first_nonzero == std::string::npos ? "0" : hextet.substr(first_nonzero);
255}
256
265inline void removeLeadingZerosFromHextets(std::vector<std::string> &hextets)
266{
267 std::transform(hextets.begin(), hextets.end(), hextets.begin(), removeLeadingZerosFromHextet);
268}
269
278inline void replaceSequenceOfZerosWithDoubleColon(std::vector<std::string> &hextets)
279{
280 for (auto longest_zero_sequence = hextets.size(); longest_zero_sequence > 1; --longest_zero_sequence)
281 {
282 auto position = std::search_n(hextets.begin(), hextets.end(), longest_zero_sequence, std::string{"0"});
283 if (position != hextets.end())
284 {
285 const auto it = hextets.insert(position, "::");
286 hextets.erase(it + 1, std::next(it + 1, longest_zero_sequence));
287 return;
288 }
289 }
290}
291
302inline std::string stringifyHextetsToAddressWithColons(const std::vector<std::string> &hextets)
303{
304 std::string result;
305 for (size_t i = 0; i < hextets.size(); ++i)
306 {
307 if (i > 0 && hextets[i] != "::" && hextets[i - 1] != "::")
308 {
309 result += ":";
310 }
311 result += hextets[i];
312 }
313 return result;
314}
315
325inline std::string compressIPv6Address(std::vector<std::string> hextets)
326{
330}
331
349inline auto IPv6Address(const bool valid = true) -> Gen<std::string>
350{
351 static constexpr int number_of_hextets = 8;
352 static constexpr std::array<bool, number_of_hextets> all_true = {true, true, true, true, true, true, true, true};
353 const auto hextet_validity = valid ? all_true : *atLeastOneFalse<number_of_hextets>().as("first,second,third,fourth,fifth,sixth,seventh,eighth hextet valid");
354
355 auto convert_hextets_to_compressed_address = [](std::string first_hextet,
356 std::string second_hextet,
357 std::string third_hextet,
358 std::string fourth_hextet,
359 std::string fifth_hextet,
360 std::string sixth_hextet,
361 std::string seventh_hextet,
362 std::string eighth_hextet)
363 {
364 return compressIPv6Address({std::move(first_hextet),
365 std::move(second_hextet),
366 std::move(third_hextet),
367 std::move(fourth_hextet),
368 std::move(fifth_hextet),
369 std::move(sixth_hextet),
370 std::move(seventh_hextet),
371 std::move(eighth_hextet)});
372 };
373
374 if (valid)
375 {
376 return gen::apply(convert_hextets_to_compressed_address,
377 IPv6HextetValue(hextet_validity[0]),
378 IPv6HextetValue(hextet_validity[1]),
379 IPv6HextetValue(hextet_validity[2]),
380 IPv6HextetValue(hextet_validity[3]),
381 IPv6HextetValue(hextet_validity[4]),
382 IPv6HextetValue(hextet_validity[5]),
383 IPv6HextetValue(hextet_validity[6]),
384 IPv6HextetValue(hextet_validity[7]));
385 }
386 return gen::map(gen::tuple(
387 IPv6HextetValue(hextet_validity[0]),
388 IPv6HextetValue(hextet_validity[1]),
389 IPv6HextetValue(hextet_validity[2]),
390 IPv6HextetValue(hextet_validity[3]),
391 IPv6HextetValue(hextet_validity[4]),
392 IPv6HextetValue(hextet_validity[5]),
393 IPv6HextetValue(hextet_validity[6]),
394 IPv6HextetValue(hextet_validity[7])),
395 [](const auto &hextets)
396 {
397 const auto [first_hextet, second_hextet, third_hextet, fourth_hextet, fifth_hextet, sixth_hextet, seventh_hextet, eighth_hextet] = hextets;
398 return first_hextet + ":" + second_hextet + ":" + third_hextet + ":" + fourth_hextet + ":" + fifth_hextet + ":" + sixth_hextet + ":" + seventh_hextet + ":" + eighth_hextet;
399 });
400}
401
403
409template <>
411{
419 static Gen<RedirectGatewayFlagsValues> arbitrary()
420 {
421 static constexpr int number_of_flags = 9;
422 return gen::map(
423 gen::container<std::vector<int>>(gen::inRange(0, number_of_flags + 1)),
424 [](const auto &bit_positions)
425 {
426 auto flags = static_cast<RedirectGatewayFlagsValues>(0);
427 for (const auto &pos : bit_positions)
428 {
429 flags = static_cast<RedirectGatewayFlagsValues>(flags | (1 << pos));
430 }
431 return flags;
432 });
433 }
434};
435
442template <>
444{
451 static auto arbitrary() -> Gen<openvpn::TunBuilderCapture::RouteBase>
452 {
453 return gen::just(openvpn::TunBuilderCapture::RouteBase{});
454 }
455};
456
465template <>
467{
474 static auto arbitrary() -> Gen<openvpn::TunBuilderCapture::Route>
475 {
476 return gen::just(openvpn::TunBuilderCapture::Route{});
477 }
478};
479
485template <>
487{
494 static auto arbitrary() -> Gen<openvpn::TunBuilderCapture::RouteAddress>
495 {
497 }
498};
499
509
519template <typename T, typename... Ts>
520struct Arbitrary<std::variant<T, Ts...>>
521{
530 static auto arbitrary() -> Gen<std::variant<T, Ts...>>
531 {
532 return gen::oneOf(
533 gen::cast<std::variant<T, Ts...>>(gen::arbitrary<T>()),
534 gen::cast<std::variant<T, Ts...>>(gen::arbitrary<Ts>())...);
535 }
536};
537
538static const std::string ALPHA_CHARACTERS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
539static const std::string DIGITS = "1234567890";
540
556inline auto alpha(const bool valid = true) -> Gen<char>
557{
558 if (valid)
559 {
560 return gen::elementOf(std::string_view{ALPHA_CHARACTERS});
561 }
562 return gen::suchThat(gen::character<char>(),
563 [](const char character)
564 { return !std::isalpha(character); });
565}
566
581inline auto from_allowed_chars(const std::string_view &allowed_chars, const bool valid = true) -> Gen<char>
582{
583 if (valid)
584 {
585 return gen::elementOf(allowed_chars);
586 }
587 return gen::suchThat(gen::character<char>(),
588 [allowed_chars](const char character)
589 { return allowed_chars.find(character) == std::string::npos; });
590}
591
609inline auto string_from_allowed_chars(const std::string_view &allowed_chars, const bool valid = true) -> Gen<std::string>
610{
611 if (valid)
612 {
613 return gen::container<std::string>(from_allowed_chars(allowed_chars));
614 }
615 return gen::suchThat(gen::string<std::string>(), [allowed_chars](const auto &string)
616 { return std::any_of(string.begin(), string.end(), [allowed_chars](const auto &character)
617 { return allowed_chars.find(character) == std::string::npos; }); });
618}
619
630inline auto port(const bool valid = true) -> Gen<int>
631{
632 static constexpr int port_upper_bound = 65535;
633 static constexpr int port_lower_bound = 0;
634 if (valid)
635 return gen::inRange(port_lower_bound, port_upper_bound + 1);
636 return gen::suchThat<int>(
637 [](const auto port_number)
638 { return port_number < port_lower_bound || port_number > port_upper_bound; });
639}
640
658inline auto calculateIPPrefixRange(const std::string &ipAddress) -> std::tuple<int, int>
659{
660 std::array<unsigned int, 4> addressParts{};
661 std::istringstream addressStream(ipAddress);
662 std::string part;
663 size_t partIndex = 0;
664
665 while (std::getline(addressStream, part, '.'))
666 {
667 addressParts[partIndex++] = std::stoi(part);
668 }
669
670 const uint32_t addressInteger = (addressParts[0] << 24) | (addressParts[1] << 16) | (addressParts[2] << 8) | addressParts[3];
671
672 auto minimumPrefix = 32;
673 for (auto bitPosition = 0; bitPosition < 32; ++bitPosition)
674 {
675 if (addressInteger & (1U << bitPosition))
676 {
677 minimumPrefix = 32 - bitPosition;
678 break;
679 }
680 }
681
682 return {minimumPrefix, openvpn::IPv4::Addr::SIZE};
683}
684
685namespace helpers {
686
701inline auto genHost(const bool valid = true) -> Gen<std::string>
702{
703 static constexpr size_t HOST_MAX_LENGTH = 256;
704 static constexpr size_t HOST_MIN_LENGTH = 1;
705 static constexpr size_t INVALID_MAX_LENGTH_LIMIT = 8192;
706
707 static const std::string allowed_chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-:";
708
709 auto [valid_chars, valid_length] = valid ? *generateValidityFlags<2>() : *generateValidityFlags<2>(false);
710 const auto length = valid_length ? *gen::inRange(HOST_MIN_LENGTH, HOST_MAX_LENGTH + 1) : *gen::inRange(HOST_MAX_LENGTH + 1, INVALID_MAX_LENGTH_LIMIT);
711
712 return gen::container<std::string>(length, from_allowed_chars(allowed_chars, valid_chars));
713}
714
721inline auto genDnsServerSecurity() -> Gen<openvpn::DnsServer::Security>
722{
723 return gen::element(
728}
729
736inline auto genDnsServerTransport() -> Gen<openvpn::DnsServer::Transport>
737{
738 return gen::element(
743}
744
750
752inline auto singleBit(const openvpn::IP::Addr::Version version, const unsigned int bit) -> openvpn::IP::Addr
753{
754 using openvpn::IP::Addr;
755 const auto size = Addr::version_size(version);
756 return Addr::netmask_from_prefix_len(version, size - bit) & ~Addr::netmask_from_prefix_len(version, size - bit - 1);
757}
758
765inline auto nonContiguousNetmask(const openvpn::IP::Addr::Version version, const unsigned int cleared_bit) -> openvpn::IP::Addr
766{
767 return ~singleBit(version, cleared_bit);
768}
769
771template <typename Parse>
772std::optional<std::string> rejectionMessageOf(Parse &&parse)
773{
774 try
775 {
776 parse();
777 }
778 catch (const openvpn::IP::AddrMaskPair::addr_pair_mask_parse_error &e)
779 {
780 return e.what();
781 }
782 return std::nullopt;
783}
784
785inline std::optional<std::string> rejectionMessage(const std::string &input, const char *title = nullptr)
786{
787 return rejectionMessageOf([&]
789}
790
792inline std::optional<std::string> rejectionMessageForTerms(const std::string &address, const std::string &mask)
793{
794 return rejectionMessageOf([&]
795 { openvpn::IP::AddrMaskPair::from_string(address, mask); });
796}
797
798inline std::optional<std::string> rejectionMessage(const openvpn::IP::AddrMaskPair::StringPair &pair)
799{
800 return rejectionMessageOf([&]
802}
803
804} // namespace helpers
805
826inline auto genDnsDomain(const bool valid = true) -> Gen<openvpn::DnsDomain>
827{
828 return gen::build(
829 gen::construct<openvpn::DnsDomain>(),
831}
832
855inline auto genDnsAddress(const bool valid = true) -> Gen<openvpn::DnsAddress>
856{
857 return gen::map(
858 gen::tuple(
859 gen::oneOf(IPv4Address(valid), IPv6Address(valid)),
860 gen::maybe(port(*rc::gen::arbitrary<bool>()))), // port is not checked during DnsAddress validation
861 [](const auto &params) -> openvpn::DnsAddress
862 {
863 const auto &[address, maybe_port] = params;
864 openvpn::DnsAddress result;
865 result.address = address;
866 if (maybe_port)
867 {
868 result.port = *maybe_port;
869 }
870 return result;
871 });
872}
873
884inline auto genDnsAddressAsStr(const bool valid = true) -> Gen<std::string>
885{
886 return gen::map(
887 gen::tuple(
888 gen::oneOf(IPv4Address(valid), IPv6Address(valid)),
889 gen::maybe(port(valid))),
890 [](const auto &params) -> std::string
891 {
892 const auto &[address, maybe_port] = params;
893 openvpn::DnsAddress result;
894 result.address = address;
895 if (maybe_port)
896 {
897 result.port = *maybe_port;
898 }
899 return result.to_string();
900 });
901}
902
917inline auto genDnsServer() -> Gen<openvpn::DnsServer>
918{
919 static constexpr auto MAX_VECTOR_SIZE = 100;
920 return gen::build(
921 gen::construct<openvpn::DnsServer>(),
923 gen::container<std::vector<openvpn::DnsAddress>>(
924 *gen::inRange<size_t>(0, MAX_VECTOR_SIZE),
925 genDnsAddress())),
927 gen::container<std::vector<openvpn::DnsDomain>>(
928 *gen::inRange<size_t>(0, MAX_VECTOR_SIZE),
929 genDnsDomain())),
932 gen::set(&openvpn::DnsServer::sni, gen::string<std::string>()));
933}
934
948inline auto genDNSOptions() -> Gen<openvpn::DnsOptions>
949{
950 static constexpr auto MAX_CONTAINER_SIZE = 100;
951 auto generateDnsServerMap = []() -> Gen<std::map<int, openvpn::DnsServer>>
952 {
953 return gen::map(
954 gen::tuple(
955 gen::container<std::vector<openvpn::DnsServer>>(
956 *gen::inRange<size_t>(0, MAX_CONTAINER_SIZE),
957 genDnsServer()),
958 gen::unique<std::vector<int>>(*gen::inRange<size_t>(0, MAX_CONTAINER_SIZE), gen::nonNegative<int>())),
959 [](const auto &params) -> std::map<int, openvpn::DnsServer>
960 {
961 const auto &[servers, priorities] = params;
962 std::map<int, openvpn::DnsServer> result;
963
964 for (size_t i = 0; i < std::min(servers.size(), priorities.size()); ++i)
965 {
966 result[priorities[i]] = servers[i];
967 }
968
969 return result;
970 });
971 };
972
973 return gen::build(
974 gen::construct<openvpn::DnsOptions>(),
975 gen::set(&openvpn::DnsOptions::from_dhcp_options, gen::arbitrary<bool>()),
977 gen::container<std::vector<openvpn::DnsDomain>>(
978 *gen::inRange<size_t>(0, MAX_CONTAINER_SIZE),
979 genDnsDomain())),
980 gen::set(&openvpn::DnsOptions::servers, generateDnsServerMap()));
981}
982
988template <>
989struct Arbitrary<openvpn::IP::Addr::Version>
990{
991 static auto arbitrary() -> Gen<openvpn::IP::Addr::Version>
992 {
993 return gen::element(openvpn::IP::Addr::V4, openvpn::IP::Addr::V6);
994 }
995};
996
998inline auto genIPAddressString(const openvpn::IP::Addr::Version version, const bool valid = true) -> Gen<std::string>
999{
1000 if (version == openvpn::IP::Addr::V4)
1001 {
1002 return IPv4Address(valid);
1003 }
1004 return IPv6Address(valid);
1005}
1006
1007inline auto genIPAddr(const openvpn::IP::Addr::Version version) -> Gen<openvpn::IP::Addr>
1008{
1009 return gen::map(genIPAddressString(version),
1010 [](const std::string &address)
1011 { return openvpn::IP::Addr::from_string(address); });
1012}
1013
1014inline auto genIPAddr() -> Gen<openvpn::IP::Addr>
1015{
1016 return gen::mapcat(gen::arbitrary<openvpn::IP::Addr::Version>(),
1017 [](const auto version)
1018 { return genIPAddr(version); });
1019}
1020
1030inline auto genPrefixLength(const openvpn::IP::Addr::Version version, const bool valid = true) -> Gen<unsigned int>
1031{
1032 const auto address_size = openvpn::IP::Addr::version_size(version);
1033
1034 if (valid)
1035 {
1036 static constexpr int bound_weight = 1;
1037 static constexpr int interior_weight = 6;
1038 return gen::weightedOneOf<unsigned int>({{bound_weight, gen::just(0U)},
1039 {bound_weight, gen::just(address_size)},
1040 {interior_weight, gen::inRange(0U, address_size + 1U)}});
1041 }
1042 static constexpr unsigned int illegal_prefix_upper_bound = std::numeric_limits<unsigned int>::max();
1043 return gen::inRange(address_size + 1U, illegal_prefix_upper_bound);
1044}
1045
1052inline auto genAddrMaskPair(const openvpn::IP::Addr::Version version) -> Gen<openvpn::IP::AddrMaskPair>
1053{
1054 return gen::apply(
1055 [version](openvpn::IP::Addr addr, const unsigned int prefix_len)
1056 {
1057 return openvpn::IP::AddrMaskPair{.addr = std::move(addr),
1059 },
1060 genIPAddr(version),
1061 genPrefixLength(version));
1062}
1063
1065template <>
1066struct Arbitrary<openvpn::IP::AddrMaskPair>
1067{
1068 static auto arbitrary() -> Gen<openvpn::IP::AddrMaskPair>
1069 {
1070 return gen::mapcat(gen::arbitrary<openvpn::IP::Addr::Version>(),
1071 [](const auto version)
1072 { return genAddrMaskPair(version); });
1073 }
1074};
1075
1081inline auto genNonCanonicalAddrMaskPair(const openvpn::IP::Addr::Version version) -> Gen<openvpn::IP::AddrMaskPair>
1082{
1083 using openvpn::IP::Addr;
1084 const auto size = Addr::version_size(version);
1085 return gen::mapcat(gen::inRange(0U, size),
1086 [version, size](const unsigned int prefix_len)
1087 {
1088 return gen::apply(
1089 [version, prefix_len](const Addr &addr, const unsigned int host_bit)
1090 {
1091 return openvpn::IP::AddrMaskPair{.addr = addr | helpers::singleBit(version, host_bit),
1092 .netmask = Addr::netmask_from_prefix_len(version, prefix_len)};
1093 },
1094 genIPAddr(version),
1095 gen::inRange(0U, size - prefix_len));
1096 });
1097}
1098
1105inline auto genNetmaskString(const openvpn::IP::Addr::Version version, const bool valid = true) -> Gen<std::string>
1106{
1107 if (valid)
1108 {
1109 return gen::map(genPrefixLength(version),
1110 [version](const unsigned int prefix_len)
1112 }
1113 return gen::map(gen::inRange(1U, openvpn::IP::Addr::version_size(version)),
1114 [version](const unsigned int cleared_bit)
1115 { return helpers::nonContiguousNetmask(version, cleared_bit).to_string(); });
1116}
1117
1126inline auto genMaskToken(const openvpn::IP::Addr::Version version, const bool valid = true) -> Gen<std::string>
1127{
1128 const auto asToken = [](Gen<unsigned int> prefix_length)
1129 {
1130 return gen::map(std::move(prefix_length),
1131 [](const unsigned int prefix_len)
1132 { return std::to_string(prefix_len); });
1133 };
1134
1135 if (valid)
1136 {
1137 return gen::oneOf(asToken(genPrefixLength(version)),
1138 genNetmaskString(version),
1139 gen::just(std::string{}));
1140 }
1141 return gen::oneOf(asToken(genPrefixLength(version, false)),
1142 genNetmaskString(version, false),
1144}
1145
1153inline auto genAddrMaskPairString(const openvpn::IP::Addr::Version version, const bool valid = true) -> Gen<std::string>
1154{
1155 static constexpr int bare_address_weight = 1;
1156 static constexpr int mask_term_weight = 3;
1157 static constexpr int shape_weight = 1;
1158
1159 const auto joined = [](const std::string &address, const std::string &mask)
1160 { return address + "/" + mask; };
1161
1162 if (valid)
1163 {
1164 return gen::weightedOneOf<std::string>({{bare_address_weight, genIPAddressString(version)},
1165 {mask_term_weight, gen::apply(joined, genIPAddressString(version), genMaskToken(version))}});
1166 }
1167
1168 const auto three_terms = [](const std::string &address, const unsigned int first, const unsigned int second)
1169 { return address + "/" + std::to_string(first) + "/" + std::to_string(second); };
1170
1171 // Addr::from_string accepts both families, so a string malformed as one is filtered against the other too
1172 const auto malformed_address = gen::suchThat(genIPAddressString(version, false),
1173 [](const std::string &address)
1174 { return !openvpn::IP::Addr::is_valid(address); });
1175
1176 return gen::weightedOneOf<std::string>({{shape_weight, malformed_address},
1177 {mask_term_weight, gen::apply(joined, genIPAddressString(version), genMaskToken(version, false))},
1178 {shape_weight, gen::apply(three_terms, genIPAddressString(version), genPrefixLength(version), genPrefixLength(version))},
1179 {shape_weight, gen::just(std::string{})},
1180 {shape_weight, gen::nonEmpty(string_from_allowed_chars(ALPHA_CHARACTERS))}});
1181}
1182} // namespace rc
1183#endif // TEST_GENERATORS_HPP
static Addr from_string(const std::string &ipstr, const TITLE &title, const Version required_version)
Definition ip.hpp:105
std::string to_string() const
Definition ip.hpp:528
static bool is_valid(const std::string &ipstr)
Definition ip.hpp:232
static Addr netmask_from_prefix_len(Version v, const unsigned int prefix_len)
Definition ip.hpp:502
static unsigned int version_size(Version v)
Definition ip.hpp:1028
static constexpr unsigned int SIZE
Definition ipv4.hpp:43
Route address class that may use non-canonical form.
Definition capture.hpp:295
Base class for route-related functionality representing a network route.
Definition capture.hpp:197
Route class that must use canonical form.
Definition capture.hpp:313
auto nonContiguousNetmask(const openvpn::IP::Addr::Version version, const unsigned int cleared_bit) -> openvpn::IP::Addr
A mask of version with every bit set except cleared_bit.
constexpr auto otherVersion(const openvpn::IP::Addr::Version version) -> openvpn::IP::Addr::Version
The address version that is not version; UNSPEC maps to V4.
std::optional< std::string > rejectionMessageOf(Parse &&parse)
The diagnostic AddrMaskPair::from_string throws when parse calls it, or nullopt when it accepts.
auto genDnsServerTransport() -> Gen< openvpn::DnsServer::Transport >
Generates random DNS server transport.
auto genHost(const bool valid=true) -> Gen< std::string >
Generates a host string.
auto singleBit(const openvpn::IP::Addr::Version version, const unsigned int bit) -> openvpn::IP::Addr
The address of version with only bit set; bit 0 is the least significant.
auto genDnsServerSecurity() -> Gen< openvpn::DnsServer::Security >
Generates random DNS server security settings.
std::optional< std::string > rejectionMessageForTerms(const std::string &address, const std::string &mask)
Named apart from rejectionMessage: a literal "" second argument would otherwise bind to the title par...
std::optional< std::string > rejectionMessage(const std::string &input, const char *title=nullptr)
auto genIPAddressString(const openvpn::IP::Addr::Version version, const bool valid=true) -> Gen< std::string >
Generates an address string of version; valid is IPv4Address()/IPv6Address()'s.
auto calculateIPPrefixRange(const std::string &ipAddress) -> std::tuple< int, int >
Calculates the valid IP prefix range for a given IP address.
auto string_from_allowed_chars(const std::string_view &allowed_chars, const bool valid=true) -> Gen< std::string >
Generates strings based on allowed characters.
auto from_allowed_chars(const std::string_view &allowed_chars, const bool valid=true) -> Gen< char >
Generates characters based on an allowed character set.
std::string stringifyHextetsToAddressWithColons(const std::vector< std::string > &hextets)
Converts a vector of hextets to an IPv6 address string with colons.
auto IPv4Octet(const bool valid=true) -> Gen< int >
Generates a valid or invalid IPv4 octet value.
auto genDnsAddressAsStr(const bool valid=true) -> Gen< std::string >
Generates a DNS address as a string.
auto genAddrMaskPair(const openvpn::IP::Addr::Version version) -> Gen< openvpn::IP::AddrMaskPair >
Generates a well-formed AddrMaskPair of version: an address and a contiguous netmask.
auto genMaskToken(const openvpn::IP::Addr::Version version, const bool valid=true) -> Gen< std::string >
Generates the netmask term of an AddrMaskPair input for an address of version.
void replaceSequenceOfZerosWithDoubleColon(std::vector< std::string > &hextets)
Replaces the longest sequence of consecutive "0" strings in a vector with "::".
std::variant< openvpn::TunBuilderCapture::Route, openvpn::TunBuilderCapture::RouteAddress, openvpn::TunBuilderCapture::RouteBase > RouteBased
Alias representing a route-based variant type.
auto genNetmaskString(const openvpn::IP::Addr::Version version, const bool valid=true) -> Gen< std::string >
Generates a netmask of version rendered as an address string.
auto genNonCanonicalAddrMaskPair(const openvpn::IP::Addr::Version version) -> Gen< openvpn::IP::AddrMaskPair >
Generates a pair of version whose address has a host bit set, so is_canonical() is false.
std::string compressIPv6Address(std::vector< std::string > hextets)
Compress an IPv6 address by simplifying its representation.
auto genDNSOptions() -> Gen< openvpn::DnsOptions >
Generates random DNS options.
static const std::string ALPHA_CHARACTERS
std::string removeLeadingZerosFromHextet(const std::string &hextet)
Removes leading zeros from a hextet (IPv6 segment).
auto port(const bool valid=true) -> Gen< int >
Generates a port number value.
static const std::string DIGITS
void removeLeadingZerosFromHextets(std::vector< std::string > &hextets)
Removes leading zeros from a vector of hextets.
auto genDnsAddress(const bool valid=true) -> Gen< openvpn::DnsAddress >
Generates a DNS address.
auto genIPAddr() -> Gen< openvpn::IP::Addr >
auto hexChar(const bool valid=true) -> Gen< std::string >
Generates a valid or invalid hexadecimal character.
auto genDnsServer() -> Gen< openvpn::DnsServer >
Generates a DNS server.
auto genPrefixLength(const openvpn::IP::Addr::Version version, const bool valid=true) -> Gen< unsigned int >
Generates a prefix length for an address of version.
auto genAddrMaskPairString(const openvpn::IP::Addr::Version version, const bool valid=true) -> Gen< std::string >
Generates an AddrMaskPair::from_string input for an address of version.
auto atLeastOneFalse() -> Gen< std::array< bool, N > >
Generates an array of booleans that contains at least one false.
auto asciiPrintableCode() -> Gen< int >
Generates a random printable ASCII character code.
auto genDnsDomain(const bool valid=true) -> Gen< openvpn::DnsDomain >
Generates a DnsDomain.
auto generateValidityFlags(const bool all_valid=true) -> Gen< std::array< bool, N > >
Generates an array of validity flags for component testing.
auto IPv6HextetValue(const bool valid=true) -> Gen< std::string >
Generates a hextet value of an IPv6 address.
auto IPv4Address(const bool valid=true) -> Gen< std::string >
Generates a random IPv4 address.
auto IPv6Address(const bool valid=true) -> Gen< std::string >
Generates a random IPv6 address.
auto alpha(const bool valid=true) -> Gen< char >
Generates alphabetic or non-alphabetic characters.
A name server address and optional port.
std::string to_string() const
Return string representation of the IP address and port stored in the DnsAddress object.
std::map< int, DnsServer > servers
List of DNS servers to use, according to the list of priority.
std::vector< DnsDomain > search_domains
List of global DNS search domains to use.
bool from_dhcp_options
Set to true if the DNS options comes from –dhcp-option options.
std::vector< DnsAddress > addresses
Parsed from –dns server n address ADDRESS[:PORT] [...] or –dhcp-option DNS/DNS6.
std::vector< DnsDomain > domains
Parsed from –dns server n resolve-domains DOMAIN [...] or –dhcp-option DOMAIN/DOMAIN-SEARCH if use_se...
std::string sni
Parsed from –dns server n sni.
Security dnssec
Parsed from –dns server n dnssec {yes,optional,no}.
@ Yes
Enforce using DNSSEC.
@ No
Do not use DNSSEC.
@ Unset
Undefined setting; default value when not set.
@ Optional
Try to use DNSSEC opportunistically. If it fails, the DNS resolver may ignore DNSSEC.
@ TLS
Use DNS-over-TLS (DoT)
@ HTTPS
Use DNS-over-HTTPS (DoH)
@ Plain
Use the classic unencrypted DNS protocol.
@ Unset
Undefined setting; default value when not set.
Transport transport
Parsed from –dns server n transport {plain,DoT,DoH}.
static AddrMaskPair from_string(const std::string &s1, const std::string &s2, const char *title=nullptr)
Definition addrpair.hpp:102
static Gen< RedirectGatewayFlagsValues > arbitrary()
Generates an arbitrary RedirectGatewayFlagsValues.
static auto arbitrary() -> Gen< openvpn::IP::AddrMaskPair >
static auto arbitrary() -> Gen< openvpn::IP::Addr::Version >
static auto arbitrary() -> Gen< openvpn::TunBuilderCapture::RouteAddress >
Generates an arbitrary RouteAddress instance.
static auto arbitrary() -> Gen< openvpn::TunBuilderCapture::RouteBase >
Generates a value of type RouteBase.
static auto arbitrary() -> Gen< openvpn::TunBuilderCapture::Route >
Generates an arbitrary instance of TunBuilderCapture::Route.
static auto arbitrary() -> Gen< std::variant< T, Ts... > >
Generates an arbitrary std::variant containing one of the specified types.
static const char * input[]
int prefix_len(const IPv4::Addr::base_type mask)