1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
|
#ifndef BOOST_TEST_DYN_LINK
#define BOOST_TEST_DYN_LINK
#endif
#define BOOST_TEST_NO_MAIN
#include <boost/test/unit_test.hpp>
#include "dnsdist-svc.hh"
#include "svc-records.hh"
#include "dnsparser.hh"
BOOST_AUTO_TEST_SUITE(dnsdistsvc_cc)
BOOST_AUTO_TEST_CASE(test_Basic)
{
DNSName target("powerdns.com.");
{
// invalid priority of 0 + parameters
std::vector<uint8_t> payload;
const uint16_t priority = 0;
BOOST_CHECK(!generateSVCPayload(payload, priority, target, {SvcParam::SvcParamKey::port}, {"dot"}, false, 853, std::string(), {ComboAddress("192.0.2.1")}, {ComboAddress("2001:db8::1")}, {}));
}
{
std::vector<uint8_t> payload;
const uint16_t priority = 1;
BOOST_CHECK(generateSVCPayload(payload, priority, target, {SvcParam::SvcParamKey::port}, {"dot"}, false, 853, std::string(), {ComboAddress("192.0.2.1")}, {ComboAddress("2001:db8::1")}, {}));
/* 2 octet field for SvcPriority as an integer in network byte order */
/* uncompressed, fully-qualified TargetName */
/* list of SvcParams as:
- 2 octet field containing the SvcParamKey as an integer in network byte order
- 2 octet field containing the length of the SvcParamValue as an integer between 0 and 65535 in network byte order (but constrained by the RDATA and DNS message sizes)
- an octet string of this length whose contents are in a format determined by the SvcParamKey
SvcParamKeys SHALL appear in increasing numeric order
*/
size_t expectedSize = (/* priority */ 2) + target.wirelength() + (/* mandatory */ 2 + 2 + 2) + (/* alpns with 1-byte length field for each value */ 2 + 2 + 4) + (/* no-alpn-default is false */ 0) + (/* port */ 2 + 2 + 2) + (/* ech */ 0) + (/* v4 hints */ 2 + 2 + 9) + (/* v6 hints */ 2 + 2 + 11);
BOOST_CHECK_EQUAL(payload.size(), expectedSize);
std::set<SvcParam> params;
PacketReader pr(std::string_view(reinterpret_cast<const char*>(payload.data()), payload.size()), 0);
BOOST_CHECK_EQUAL(pr.get16BitInt(), priority);
/* we can't use getName() directly because it assumes that there has to be a dnsheader before the name */
DNSName parsedTarget(reinterpret_cast<const char*>(payload.data()), payload.size(), pr.getPosition(), false /* uncompress */, nullptr /* qtype */, nullptr /* qclass */, nullptr /* consumed */, 0);
pr.skip(parsedTarget.wirelength());
BOOST_CHECK_EQUAL(target.toString(), parsedTarget.toString());
pr.xfrSvcParamKeyVals(params);
BOOST_REQUIRE_EQUAL(params.size(), 5U);
auto param = params.begin();
BOOST_CHECK(param->getKey() == SvcParam::SvcParamKey::mandatory);
++param;
BOOST_CHECK(param->getKey() == SvcParam::SvcParamKey::alpn);
++param;
BOOST_CHECK(param->getKey() == SvcParam::SvcParamKey::port);
++param;
BOOST_CHECK(param->getKey() == SvcParam::SvcParamKey::ipv4hint);
++param;
BOOST_CHECK(param->getKey() == SvcParam::SvcParamKey::ipv6hint);
}
{
std::vector<uint8_t> payload;
const uint16_t priority = 2;
const std::string ech("whatever");
const std::string dohParam("/dns-query{?dns}");
BOOST_CHECK(generateSVCPayload(payload, priority, target, {SvcParam::SvcParamKey::port}, {"h2"}, true, 443, ech, {ComboAddress("192.0.2.2")}, {ComboAddress("2001:db8::2")}, {std::pair<uint16_t, std::string>(42, dohParam)}));
size_t expectedSize = (/* priority */ 2) + target.wirelength() + (/* mandatory */ 2 + 2 + 2) + (/* alpns */ 2 + 2 + 3) + (/* no-alpn-default is true */ 2 + 2) + (/* port */ 2 + 2 + 2) + (/* ech */ 2 + 2 + ech.size()) + (/* v4 hints */ 2 + 2 + 9) + (/* v6 hints */ 2 + 2 + 11) + (/* doh parameter */ 2 + 2 + dohParam.size());
BOOST_CHECK_EQUAL(payload.size(), expectedSize);
std::set<SvcParam> params;
PacketReader pr(std::string_view(reinterpret_cast<const char*>(payload.data()), payload.size()), 0);
BOOST_CHECK_EQUAL(pr.get16BitInt(), priority);
/* we can't use getName() directly because it assumes that there has to be a dnsheader before the name */
DNSName parsedTarget(reinterpret_cast<const char*>(payload.data()), payload.size(), pr.getPosition(), false /* uncompress */, nullptr /* qtype */, nullptr /* qclass */, nullptr /* consumed */, 0);
pr.skip(parsedTarget.wirelength());
BOOST_CHECK_EQUAL(target.toString(), parsedTarget.toString());
pr.xfrSvcParamKeyVals(params);
BOOST_REQUIRE_EQUAL(params.size(), 8U);
auto param = params.begin();
BOOST_CHECK(param->getKey() == SvcParam::SvcParamKey::mandatory);
++param;
BOOST_CHECK(param->getKey() == SvcParam::SvcParamKey::alpn);
++param;
BOOST_CHECK(param->getKey() == SvcParam::SvcParamKey::no_default_alpn);
++param;
BOOST_CHECK(param->getKey() == SvcParam::SvcParamKey::port);
++param;
BOOST_CHECK(param->getKey() == SvcParam::SvcParamKey::ipv4hint);
++param;
BOOST_CHECK(param->getKey() == SvcParam::SvcParamKey::ech);
++param;
BOOST_CHECK(param->getKey() == SvcParam::SvcParamKey::ipv6hint);
++param;
BOOST_CHECK_EQUAL(static_cast<uint16_t>(param->getKey()), 42U);
}
}
BOOST_AUTO_TEST_CASE(test_Parsing)
{
svcParamsLua_t params;
params["mandatory"] = std::vector<std::pair<int, std::string>>({
{1, "port"},
});
params["alpn"] = std::vector<std::pair<int, std::string>>({
{1, "h2"},
});
params["noDefaultAlpn"] = static_cast<bool>(true);
params["port"] = static_cast<uint16_t>(443);
params["ipv4hint"] = std::vector<std::pair<int, std::string>>({
{1, "192.0.2.1"},
});
params["ipv6hint"] = std::vector<std::pair<int, std::string>>({
{1, "2001:db8::1"},
});
params["ech"] = std::string("test");
auto parsed = parseSVCParameters(params);
BOOST_CHECK(parsed.mandatoryParams == std::set<uint16_t>{SvcParam::SvcParamKey::port});
BOOST_CHECK(parsed.alpns == std::vector<std::string>{"h2"});
BOOST_CHECK(parsed.ipv4hints == std::vector<ComboAddress>{ComboAddress("192.0.2.1")});
BOOST_CHECK(parsed.ipv6hints == std::vector<ComboAddress>{ComboAddress("2001:db8::1")});
BOOST_CHECK_EQUAL(parsed.ech, "test");
BOOST_CHECK_EQUAL(*parsed.port, 443);
BOOST_CHECK_EQUAL(parsed.noDefaultAlpn, true);
}
BOOST_AUTO_TEST_SUITE_END()
|