../../pdns/nameserver.cc \
../../pdns/rcpgenerator.cc \
../../pdns/unix_utility.cc \
+ ../../pdns/svc-records.cc ../../pdns/svc-records.hh \
../../pdns/json.hh ../../pdns/json.cc \
../../pdns/shuffle.hh ../../pdns/shuffle.cc \
httpconnector.cc \
qtype.cc qtype.hh \
query-local-address.hh query-local-address.cc \
rcpgenerator.cc \
+ svc-records.cc svc-records.hh \
receiver.cc \
resolver.cc resolver.hh \
axfr-retriever.cc axfr-retriever.hh \
pdnsutil.cc \
qtype.cc \
rcpgenerator.cc rcpgenerator.hh \
+ svc-records.cc svc-records.hh \
serialtweaker.cc \
shuffle.cc shuffle.hh \
signingpipe.cc \
nsecrecords.cc \
qtype.cc \
rcpgenerator.cc \
+ svc-records.cc svc-records.hh \
sillyrecords.cc \
statbag.cc \
unix_utility.cc \
nsecrecords.cc \
qtype.cc \
rcpgenerator.cc \
+ svc-records.cc svc-records.hh \
sillyrecords.cc \
statbag.cc \
unix_utility.cc \
nsecrecords.cc \
qtype.cc \
rcpgenerator.cc \
+ svc-records.cc svc-records.hh \
sillyrecords.cc \
statbag.cc \
unix_utility.cc \
proxy-protocol.cc proxy-protocol.hh \
qtype.cc \
rcpgenerator.cc rcpgenerator.hh \
+ svc-records.cc svc-records.hh \
sdig.cc \
sillyrecords.cc \
sstuff.hh \
nsecrecords.cc \
qtype.cc \
rcpgenerator.cc rcpgenerator.hh \
+ svc-records.cc svc-records.hh \
sillyrecords.cc \
sstuff.hh \
statbag.cc \
nsecrecords.cc \
qtype.cc \
rcpgenerator.cc \
+ svc-records.cc svc-records.hh \
sillyrecords.cc \
statbag.cc \
stubresolver.cc stubresolver.hh \
nsecrecords.cc \
qtype.cc \
rcpgenerator.cc rcpgenerator.hh \
+ svc-records.cc svc-records.hh \
saxfr.cc \
sillyrecords.cc \
sstuff.hh \
query-local-address.hh query-local-address.cc \
qtype.cc \
rcpgenerator.cc rcpgenerator.hh \
+ svc-records.cc svc-records.hh \
resolver.cc \
axfr-retriever.cc \
pollmplexer.cc \
query-local-address.hh query-local-address.cc \
qtype.cc \
rcpgenerator.cc rcpgenerator.hh \
+ svc-records.cc svc-records.hh \
resolver.cc \
axfr-retriever.cc \
ixfr.cc ixfr.hh \
nsecrecords.cc \
qtype.cc \
rcpgenerator.cc rcpgenerator.hh \
+ svc-records.cc svc-records.hh \
sillyrecords.cc \
sstuff.hh \
statbag.cc \
nsecrecords.cc \
qtype.cc \
rcpgenerator.cc rcpgenerator.hh \
+ svc-records.cc svc-records.hh \
sillyrecords.cc \
sstuff.hh \
statbag.cc \
qtype.cc \
root-dnssec.hh \
rcpgenerator.cc rcpgenerator.hh \
+ svc-records.cc svc-records.hh \
rec-lua-conf.hh \
recursor_cache.hh \
sholder.hh \
query-local-address.cc \
qtype.cc \
rcpgenerator.cc rcpgenerator.hh \
+ svc-records.cc svc-records.hh \
resolver.cc \
sillyrecords.cc \
sstuff.hh \
nsecrecords.cc \
qtype.cc \
rcpgenerator.cc rcpgenerator.hh \
+ svc-records.cc svc-records.hh \
sillyrecords.cc \
speedtest.cc \
statbag.cc \
nsecrecords.cc \
qtype.cc \
rcpgenerator.cc \
+ svc-records.cc svc-records.hh \
sillyrecords.cc \
statbag.cc \
unix_utility.cc \
nsecrecords.cc \
qtype.cc \
rcpgenerator.cc \
+ svc-records.cc svc-records.hh \
sillyrecords.cc \
statbag.cc \
unix_utility.cc \
nsecrecords.cc \
qtype.cc \
rcpgenerator.cc rcpgenerator.hh \
+ svc-records.cc svc-records.hh \
sillyrecords.cc \
statbag.cc \
unix_utility.cc \
nsecrecords.cc \
qtype.cc \
rcpgenerator.cc rcpgenerator.hh \
+ svc-records.cc svc-records.hh \
sillyrecords.cc \
statbag.cc \
unix_utility.cc \
pollmplexer.cc \
qtype.cc \
rcpgenerator.cc rcpgenerator.hh \
+ svc-records.cc svc-records.hh \
sillyrecords.cc \
statbag.cc \
unix_utility.cc
pollmplexer.cc \
qtype.cc \
rcpgenerator.cc rcpgenerator.hh \
+ svc-records.cc svc-records.hh \
sillyrecords.cc \
statbag.cc \
unix_utility.cc \
nsecrecords.cc \
qtype.cc \
rcpgenerator.cc rcpgenerator.hh \
+ svc-records.cc svc-records.hh \
sillyrecords.cc \
statbag.cc \
statnode.cc statnode.hh \
nsecrecords.cc \
qtype.cc \
rcpgenerator.cc rcpgenerator.hh \
+ svc-records.cc svc-records.hh \
sillyrecords.cc \
statbag.cc \
unix_utility.cc \
nsecrecords.cc \
qtype.cc \
rcpgenerator.cc rcpgenerator.hh \
+ svc-records.cc svc-records.hh \
sillyrecords.cc \
statbag.cc \
unix_utility.cc \
nsecrecords.cc \
qtype.cc \
rcpgenerator.cc rcpgenerator.hh \
+ svc-records.cc svc-records.hh \
sillyrecords.cc \
statbag.cc \
unix_utility.cc \
protobuf.cc protobuf.hh \
qtype.cc \
rcpgenerator.cc rcpgenerator.hh \
+ svc-records.cc svc-records.hh \
sillyrecords.cc \
statbag.cc \
unix_utility.cc \
proxy-protocol.cc proxy-protocol.hh \
qtype.cc \
rcpgenerator.cc \
- svc-records.cc \
+ svc-records.cc svc-records.hh \
responsestats.cc \
responsestats-auth.cc \
shuffle.cc shuffle.hh \
nsecrecords.cc \
qtype.cc qtype.hh \
rcpgenerator.cc rcpgenerator.hh \
+ svc-records.cc svc-records.hh \
sillyrecords.cc \
statbag.cc statbag.hh \
unix_utility.cc \
dnsname.cc dnsname.hh \
ednsoptions.cc ednsoptions.hh \
misc.cc misc.hh \
+ svc-records.cc svc-records.hh \
packetcache.hh \
qtype.cc qtype.hh \
statbag.cc statbag.hh
iputils.cc iputils.hh \
misc.cc misc.hh \
packetcache.hh \
- qtype.cc qtype.hh
+ qtype.cc qtype.hh \
+ svc-records.cc svc-records.hh
fuzz_target_dnsdistcache_DEPENDENCIES = $(fuzz_targets_deps)
fuzz_target_dnsdistcache_LDFLAGS = $(fuzz_targets_ldflags)
nsecrecords.cc \
qtype.cc qtype.hh \
rcpgenerator.cc rcpgenerator.hh \
+ svc-records.cc svc-records.hh \
sillyrecords.cc \
statbag.cc statbag.hh \
unix_utility.cc \
snmp-agent.cc snmp-agent.hh \
sodcrypto.cc sodcrypto.hh \
sstuff.hh \
+ svc-records.cc svc-records.hh \
statnode.cc statnode.hh \
tcpiohandler.cc tcpiohandler.hh \
threadname.hh threadname.cc \
sodcrypto.cc \
sstuff.hh \
statnode.cc statnode.hh \
+ svc-records.cc svc-records.hh \
threadname.hh threadname.cc \
testrunner.cc \
uuid-utils.hh uuid-utils.cc \
--- /dev/null
+../svc-records.cc
\ No newline at end of file
--- /dev/null
+../svc-records.hh
\ No newline at end of file
}
}
+void PacketReader::xfrSvcParamKeyVals(set<SvcParam> &kvs) {
+ while (d_pos < (d_startrecordpos + d_recordlen)) {
+ if (d_pos + 2 > (d_startrecordpos + d_recordlen)) {
+ throw std::out_of_range("incomplete key");
+ }
+ uint16_t keyInt;
+ xfr16BitInt(keyInt);
+ auto key = static_cast<SvcParam::SvcParamKey>(keyInt);
+ uint16_t len;
+ xfr16BitInt(len);
+
+ if (d_pos + len > (d_startrecordpos + d_recordlen)) {
+ throw std::out_of_range("record is shorter than SVCB lengthfield implies");
+ }
+
+ switch (key)
+ {
+ case SvcParam::mandatory: {
+ if (len % 2 != 0) {
+ throw std::out_of_range("mandatory SvcParam has invalid length");
+ }
+ if (len == 0) {
+ throw std::out_of_range("empty 'mandatory' values");
+ }
+ std::set<SvcParam::SvcParamKey> paramKeys;
+ size_t stop = d_pos + len;
+ while (d_pos < stop) {
+ uint16_t keyval;
+ xfr16BitInt(keyval);
+ paramKeys.insert(static_cast<SvcParam::SvcParamKey>(keyval));
+ }
+ kvs.insert(SvcParam(key, paramKeys));
+ break;
+ }
+ case SvcParam::alpn: {
+ size_t stop = d_pos + len;
+ std::vector<string> alpns;
+ while (d_pos < stop) {
+ string alpn;
+ uint8_t alpnLen = 0;
+ xfr8BitInt(alpnLen);
+ if (alpnLen == 0) {
+ throw std::out_of_range("alpn length of 0");
+ }
+ xfrBlob(alpn, alpnLen);
+ alpns.push_back(alpn);
+ }
+ kvs.insert(SvcParam(key, alpns));
+ break;
+ }
+ case SvcParam::no_default_alpn: {
+ if (len != 0) {
+ throw std::out_of_range("invalid length for no-default-alpn");
+ }
+ kvs.insert(SvcParam(key));
+ break;
+ }
+ case SvcParam::port: {
+ if (len != 2) {
+ throw std::out_of_range("invalid length for port");
+ }
+ uint16_t port;
+ xfr16BitInt(port);
+ kvs.insert(SvcParam(key, port));
+ break;
+ }
+ case SvcParam::ipv4hint: /* fall-through */
+ case SvcParam::ipv6hint: {
+ size_t addrLen = (key == SvcParam::ipv4hint ? 4 : 16);
+ if (len % addrLen != 0) {
+ throw std::out_of_range("invalid length for " + SvcParam::keyToString(key));
+ }
+ vector<ComboAddress> addresses;
+ auto stop = d_pos + len;
+ while (d_pos < stop)
+ {
+ ComboAddress addr;
+ xfrCAWithoutPort(key, addr);
+ addresses.push_back(addr);
+ }
+ kvs.insert(SvcParam(key, addresses));
+ break;
+ }
+ case SvcParam::echconfig: {
+ std::string blob;
+ blob.reserve(len);
+ xfrBlobNoSpaces(blob, len);
+ kvs.insert(SvcParam(key, blob));
+ break;
+ }
+ default: {
+ std::string blob;
+ blob.reserve(len);
+ xfrBlob(blob, len);
+ kvs.insert(SvcParam(key, blob));
+ break;
+ }
+ }
+ }
+}
+
void PacketReader::xfrHexBlob(string& blob, bool keepReading)
{
#include "dnsname.hh"
#include "pdnsexception.hh"
#include "iputils.hh"
+#include "svc-records.hh"
/** DNS records have three representations:
1) in the packet
void xfrBlobNoSpaces(string& blob, int len);
void xfrBlob(string& blob, int length);
void xfrHexBlob(string& blob, bool keepReading=false);
+ void xfrSvcParamKeyVals(set<SvcParam> &kvs);
void getDnsrecordheader(struct dnsrecordheader &ah);
void copyRecord(vector<unsigned char>& dest, uint16_t len);
conv.xfrBlob(d_keyring);
)
+boilerplate_conv(SVCB, 64,
+ conv.xfr16BitInt(d_priority);
+ conv.xfrName(d_target, false, true);
+ if (d_priority != 0) {
+ conv.xfrSvcParamKeyVals(d_params);
+ }
+ )
+
+boilerplate_conv(HTTPS, 65,
+ conv.xfr16BitInt(d_priority);
+ conv.xfrName(d_target, false, true);
+ if (d_priority != 0) {
+ conv.xfrSvcParamKeyVals(d_params);
+ }
+ )
+
boilerplate_conv(SMIMEA, 53,
conv.xfr8BitInt(d_certusage);
conv.xfr8BitInt(d_selector);
TLSARecordContent::report();
SMIMEARecordContent::report();
OPENPGPKEYRecordContent::report();
+ SVCBRecordContent::report();
+ HTTPSRecordContent::report();
DLVRecordContent::report();
DNSRecordContent::regist(QClass::ANY, QType::TSIG, &TSIGRecordContent::make, &TSIGRecordContent::make, "TSIG");
DNSRecordContent::regist(QClass::ANY, QType::TKEY, &TKEYRecordContent::make, &TKEYRecordContent::make, "TKEY");
#include <bitset>
#include "namespaces.hh"
#include "iputils.hh"
+#include "svc-records.hh"
#define includeboilerplate(RNAME) RNAME##RecordContent(const DNSRecord& dr, PacketReader& pr); \
RNAME##RecordContent(const string& zoneData); \
string d_keyring;
};
+class SVCBRecordContent : public DNSRecordContent
+{
+public:
+ includeboilerplate(SVCB)
+
+private:
+ uint16_t d_priority;
+ DNSName d_target;
+ set<SvcParam> d_params;
+};
+
+class HTTPSRecordContent : public DNSRecordContent
+{
+public:
+ includeboilerplate(HTTPS)
+
+private:
+ uint16_t d_priority;
+ DNSName d_target;
+ set<SvcParam> d_params;
+};
class RRSIGRecordContent : public DNSRecordContent
{
xfrBlob(blob);
}
+void DNSPacketWriter::xfrSvcParamKeyVals(const std::set<SvcParam> &kvs)
+{
+ for (auto const ¶m : kvs) {
+ // Key first!
+ xfr16BitInt(param.getKey());
+
+ switch (param.getKey())
+ {
+ case SvcParam::mandatory:
+ xfr16BitInt(2 * param.getMandatory().size());
+ for (auto const &m: param.getMandatory()) {
+ xfr16BitInt(m);
+ }
+ break;
+ case SvcParam::alpn:
+ {
+ uint16_t totalSize = param.getALPN().size(); // All 1 octet size headers for each value
+ for (auto const &a : param.getALPN()) {
+ totalSize += a.length();
+ }
+ xfr16BitInt(totalSize);
+ for (auto const &a : param.getALPN()) {
+ xfrUnquotedText(a, true); // will add the 1-byte length field
+ }
+ break;
+ }
+ case SvcParam::no_default_alpn:
+ xfr16BitInt(0); // no size :)
+ break;
+ case SvcParam::port:
+ xfr16BitInt(2); // size
+ xfr16BitInt(param.getPort());
+ break;
+ case SvcParam::ipv4hint:
+ xfr16BitInt(param.getIPHints().size() * 4); // size
+ for (auto a: param.getIPHints()) {
+ xfrCAWithoutPort(param.getKey(), a);
+ }
+ break;
+ case SvcParam::ipv6hint:
+ xfr16BitInt(param.getIPHints().size() * 16); // size
+ for (auto a: param.getIPHints()) {
+ xfrCAWithoutPort(param.getKey(), a);
+ }
+ break;
+ case SvcParam::echconfig:
+ xfr16BitInt(param.getEchConfig().size()); // size
+ xfrBlobNoSpaces(param.getEchConfig());
+ break;
+ default:
+ xfr16BitInt(param.getValue().size());
+ xfrUnquotedText(param.getValue(), false);
+ break;
+ }
+ }
+}
+
// call __before commit__
void DNSPacketWriter::getRecordPayload(string& records)
{
#include "dnsname.hh"
#include "namespaces.hh"
#include "iputils.hh"
+#include "svc-records.hh"
#include <arpa/inet.h>
void xfrText(const string& text, bool multi=false, bool lenField=true);
void xfrUnquotedText(const string& text, bool lenField);
void xfrBlob(const string& blob, int len=-1);
+ void xfrSvcParamKeyVals(const set<SvcParam>& kvs);
void xfrBlobNoSpaces(const string& blob, int len=-1);
void xfrHexBlob(const string& blob, bool keepReading=false);
CDS=59,
CDNSKEY=60,
OPENPGPKEY=61,
+ SVCB=64,
+ HTTPS=65,
SPF=99,
EUI48=108,
EUI64=109,
qtype_insert("CDS", 59);
qtype_insert("CDNSKEY", 60);
qtype_insert("OPENPGPKEY", 61);
+ qtype_insert("SVCB", 64);
+ qtype_insert("HTTPS", 65);
qtype_insert("SPF", 99);
qtype_insert("EUI48", 108);
qtype_insert("EUI64", 109);
if(octet > 255)
throw RecordTextException("unable to parse IP address");
}
- else if(dns_isspace(d_string.at(d_pos)))
+ else if(dns_isspace(d_string.at(d_pos)) || d_string.at(d_pos) == ',')
break;
else {
throw RecordTextException(string("unable to parse IP address, strange character: ")+d_string.at(d_pos));
B64Decode(tmp, val);
}
+void RecordTextReader::xfrSvcParamKeyVals(set<SvcParam>& val)
+{
+ while (d_pos != d_end) {
+ skipSpaces();
+ if (d_pos == d_end)
+ return;
+
+ // Find the SvcParamKey
+ size_t pos = d_pos;
+ while (d_pos != d_end) {
+ if (d_string.at(d_pos) == '=' || d_string.at(d_pos) == ' ') {
+ break;
+ }
+ d_pos++;
+ }
+
+ // We've reached a space or equals-sign or the end of the string (d_pos is at this char)
+ string k = d_string.substr(pos, d_pos - pos);
+ SvcParam::SvcParamKey key;
+ try {
+ key = SvcParam::keyFromString(k);
+ } catch (const std::invalid_argument &e) {
+ throw RecordTextException(e.what());
+ }
+
+ if (key != SvcParam::no_default_alpn) {
+ if (d_pos == d_end || d_string.at(d_pos) != '=') {
+ throw RecordTextException("expected '=' after " + k);
+ }
+ d_pos++; // Now on the first character after '='
+ if (d_pos == d_end || d_string.at(d_pos) == ' ') {
+ throw RecordTextException("expected value after " + k + "=");
+ }
+ }
+
+ switch (key) {
+ case SvcParam::no_default_alpn:
+ if (d_pos != d_end && d_string.at(d_pos) == '=') {
+ throw RecordTextException(k + " key can not have values");
+ }
+ val.insert(SvcParam(key));
+ break;
+ case SvcParam::ipv4hint: /* fall-through */
+ case SvcParam::ipv6hint: {
+ vector<ComboAddress> hints;
+ do {
+ ComboAddress address;
+ xfrCAWithoutPort(key, address); // The SVBC authors chose 4 and 6 to represent v4hint and v6hint :)
+ hints.push_back(address);
+ if (d_pos < d_end && d_string.at(d_pos) == ',') {
+ d_pos++; // Go to the next address
+ }
+ } while (d_pos != d_end && d_string.at(d_pos) != ' ');
+ try {
+ val.insert(SvcParam(key, hints));
+ }
+ catch (const std::invalid_argument& e) {
+ throw RecordTextException(e.what());
+ }
+ break;
+ }
+ case SvcParam::alpn: {
+ string value;
+ xfrUnquotedText(value, false);
+ vector<string> parts;
+ stringtok(parts, value, ",");
+ val.insert(SvcParam(key, parts));
+ break;
+ }
+ case SvcParam::mandatory: {
+ string value;
+ xfrUnquotedText(value, false);
+ vector<string> parts;
+ stringtok(parts, value, ",");
+ set<string> values(parts.begin(), parts.end());
+ val.insert(SvcParam(key, values));
+ break;
+ }
+ case SvcParam::port: {
+ uint16_t port;
+ xfr16BitInt(port);
+ val.insert(SvcParam(key, port));
+ break;
+ }
+ case SvcParam::echconfig: {
+ bool haveQuote = d_string.at(d_pos) == '"';
+ if (haveQuote) {
+ d_pos++;
+ }
+ string value;
+ xfrBlobNoSpaces(value);
+ if (haveQuote) {
+ d_pos++;
+ }
+ val.insert(SvcParam(key, value));
+ break;
+ }
+ default: {
+ string value;
+ if (d_string.at(d_pos) == '"') {
+ xfrText(value);
+ }
+ else {
+ xfrUnquotedText(value);
+ }
+ val.insert(SvcParam(key, value));
+ break;
+ }
+ }
+ }
+}
static inline uint8_t hextodec(uint8_t val)
{
}
}
+void RecordTextWriter::xfrSvcParamKeyVals(const set<SvcParam>& val) {
+ for (auto const ¶m : val) {
+ if (!d_string.empty())
+ d_string.append(1, ' ');
+
+ d_string.append(SvcParam::keyToString(param.getKey()));
+ if (param.getKey() != SvcParam::no_default_alpn) {
+ d_string.append(1, '=');
+ }
+
+ switch (param.getKey())
+ {
+ case SvcParam::no_default_alpn:
+ break;
+ case SvcParam::ipv4hint: /* fall-through */
+ case SvcParam::ipv6hint:
+ // TODO use xfrCA and put commas in between?
+ d_string.append(ComboAddress::caContainerToString(param.getIPHints(), false));
+ break;
+ case SvcParam::alpn:
+ // This is safe, as this value needs no quotes
+ d_string.append(boost::join(param.getALPN(), ","));
+ break;
+ case SvcParam::mandatory:
+ {
+ bool doComma = false;
+ for (auto const &k: param.getMandatory()) {
+ if (doComma)
+ d_string.append(1, ',');
+ d_string.append(SvcParam::keyToString(k));
+ doComma = true;
+ }
+ break;
+ }
+ case SvcParam::port: {
+ auto str = d_string;
+ d_string.clear();
+ xfr16BitInt(param.getPort());
+ d_string = str + d_string;
+ break;
+ }
+ case SvcParam::echconfig: {
+ auto str = d_string;
+ d_string.clear();
+ xfrBlobNoSpaces(param.getEchConfig());
+ d_string = str + '"' + d_string + '"';
+ break;
+ }
+ default:
+ d_string.append(param.getValue());
+ break;
+ }
+ }
+}
+
void RecordTextWriter::xfrText(const string& val, bool multi, bool lenField)
{
if(!d_string.empty())
#include "namespaces.hh"
#include "dnsname.hh"
#include "iputils.hh"
+#include "svc-records.hh"
class RecordTextException : public runtime_error
{
void xfrBlobNoSpaces(string& val, int len=-1);
void xfrBlob(string& val, int len=-1);
+ void xfrSvcParamKeyVals(set<SvcParam>& val);
+
const string getRemaining() const {
return d_string.substr(d_pos);
}
void xfrBlobNoSpaces(const string& val, int len=-1);
void xfrBlob(const string& val, int len=-1);
void xfrHexBlob(const string& val, bool keepReading=false);
+ void xfrSvcParamKeyVals(const set<SvcParam>& val);
bool eof() { return true; };
const string getRemaining() const {
sortlist.cc sortlist.hh \
sstuff.hh \
stable-bloom.hh \
+ svc-records.cc svc-records.hh \
syncres.cc syncres.hh \
threadname.hh threadname.cc \
tsigverifier.cc tsigverifier.hh \
sholder.hh \
sstuff.hh \
stable-bloom.hh \
+ svc-records.cc svc-records.hh \
syncres.cc syncres.hh \
test-arguments_cc.cc \
test-base32_cc.cc \
--- /dev/null
+../svc-records.cc
\ No newline at end of file
--- /dev/null
+../svc-records.hh
\ No newline at end of file
d_echconfig = value;
return;
}
- d_value = value;
+ d_value = std::move(value);
}
-SvcParam::SvcParam(const SvcParamKey &key, const std::set<std::string> &value) {
+SvcParam::SvcParam(const SvcParamKey &key, const std::vector<std::string> & value) {
d_key = key;
- if (d_key != SvcParamKey::alpn && d_key != SvcParamKey::mandatory) {
+ if (d_key != SvcParamKey::alpn) {
throw std::invalid_argument("can not create SvcParam for " + keyToString(key) + " with a string-set value");
}
if (d_key == SvcParamKey::alpn) {
- d_alpn = value;
+ d_alpn = std::move(value);
+ }
+}
+
+SvcParam::SvcParam(const SvcParamKey &key, const std::set<std::string> &value) {
+ d_key = key;
+ if (d_key != SvcParamKey::mandatory) {
+ throw std::invalid_argument("can not create SvcParam for " + keyToString(key) + " with a string-set value");
}
if (d_key == SvcParamKey::mandatory) {
- // TODO validate entries
- d_mandatory = value;
+ for (auto const &v: value) {
+ d_mandatory.insert(keyFromString(std::move(v)));
+ }
}
}
-SvcParam::SvcParam(const SvcParamKey &key, const std::set<ComboAddress> &value) {
+SvcParam::SvcParam(const SvcParamKey &key, const std::set<SvcParam::SvcParamKey> &value) {
+ d_key = key;
+ if (d_key != SvcParamKey::mandatory) {
+ throw std::invalid_argument("can not create SvcParam for " + keyToString(key) + " with a string-set value");
+ }
+ d_mandatory = std::move(value);
+}
+
+SvcParam::SvcParam(const SvcParamKey &key, const std::vector<ComboAddress> &value) {
d_key = key;
if (d_key != SvcParamKey::ipv6hint && d_key != SvcParamKey::ipv4hint) {
throw std::invalid_argument("can not create SvcParam for " + keyToString(key) + " with an IP address value");
throw std::invalid_argument("non-IPv4 address ('" + addr.toString() + "') passed for " + keyToString(key));
}
}
- d_ipHints = value;
+ d_ipHints = std::move(value);
}
SvcParam::SvcParam(const SvcParamKey &key, const uint16_t value) {
d_port = value;
}
-std::set<ComboAddress> SvcParam::getIPHints() const {
+//! This ensures an std::set<SvcParam> will be sorted by key (section 2.2 mandates this for wire format)
+bool SvcParam::operator<(const SvcParam& other) const {
+ return this->d_key < other.getKey();
+}
+
+std::vector<ComboAddress> SvcParam::getIPHints() const {
if (d_key != SvcParamKey::ipv6hint && d_key != SvcParamKey::ipv4hint) {
throw std::invalid_argument("getIPHints called for non-IP address key '" + keyToString(d_key) + "'");
}
return d_port;
}
-std::set<std::string> SvcParam::getALPN() const {
+std::vector<std::string> SvcParam::getALPN() const {
if (d_key != SvcParam::alpn) {
throw std::invalid_argument("getALPN called for non-alpn key '" + keyToString(d_key) + "'");
}
return d_alpn;
}
-std::set<std::string> SvcParam::getMandatory() const {
+std::set<SvcParam::SvcParamKey> SvcParam::getMandatory() const {
if (d_key != SvcParam::mandatory) {
throw std::invalid_argument("getMandatory called for non-mandatory key '" + keyToString(d_key) + "'");
}
//! To create a "generic" SvcParam (for keyNNNNN and echconfig)
SvcParam(const SvcParamKey &key, const std::string &value);
- //! To create a multi-value SvcParam (like alpn and mandatory)
+ //! To create a multi-value SvcParam (like mandatory)
SvcParam(const SvcParamKey &key, const std::set<std::string> &value);
+ //! To create a multi-value SvcParam (like alpn)
+ SvcParam(const SvcParamKey &key, const std::vector<std::string> &value);
+
+ //! To create a multi-value SvcParam with key values (like mandatory)
+ SvcParam(const SvcParamKey &key, const std::set<SvcParamKey> &value);
+
//! To create and ipv{4,6}hists SvcParam
- SvcParam(const SvcParamKey &key, const std::set<ComboAddress> &value);
+ SvcParam(const SvcParamKey &key, const std::vector<ComboAddress> &value);
//! To create a port SvcParam
SvcParam(const SvcParamKey &key, const uint16_t value);
//! Returns the string value of the SvcParamKey
static std::string keyToString(const SvcParamKey &k);
- bool operator< (const SvcParam &other) const {
- return this->d_key < other.d_key;
- };
+ bool operator< (const SvcParam &other) const;
SvcParamKey getKey() const {
return d_key;
}
uint16_t getPort() const;
- std::set<ComboAddress> getIPHints() const;
- std::set<std::string> getALPN() const;
- std::set<std::string> getMandatory() const;
+ std::vector<ComboAddress> getIPHints() const;
+ std::vector<std::string> getALPN() const;
+ std::set<SvcParamKey> getMandatory() const;
std::string getEchConfig() const;
std::string getValue() const;
SvcParamKey d_key;
std::string d_value; // For keyNNNNN vals
- std::set<std::string> d_alpn; // For ALPN
- std::set<std::string> d_mandatory; // For mandatory
- std::set<ComboAddress> d_ipHints; // For ipv{6,4}hints
+ std::vector<std::string> d_alpn; // For ALPN
+ std::set<SvcParamKey> d_mandatory; // For mandatory
+ std::vector<ComboAddress> d_ipHints; // For ipv{6,4}hints
std::string d_echconfig; // For echconfig
uint16_t d_port; // For port
(CASE_S(QType::OPENPGPKEY, "mQINBFUIXh0BEADNPlL6NpWEaR2KJx6p19scIVpsBIo7UqzCIzeFbRJaGDhn/HlQgcwAalcVNmWUX0ZQsrdn9CEfLWuFu9ON2o1TslYiwn+oSAlH2raFm2eyJTp/iM7IUUCte5jmf3d+L9rjVI7JjmMnbVo6SVY2KDDD72dULcg7IqYcCAN4CT+tPZP5y4cYf+DxRlpxhxvqqiGyAi6lAcJ24/8fJ4hsG0lS1vU12LWeWTHa5aRMM+x9kmv3GYdXG+FxFqZw52kZEnAscpC2ymbX+1YFCr8sjGYGde/D+5cLvuu4PGNZ4fkSeS+0yXve/s6u1mX6RkkF6SOGWuJfBJOGdWzYwber9kqgqpHTjpr8HOybzVroBijtTlB/tommIUd4BTk9Jv4fv2gA4UkC13UM9KBF1NnzUnKC+Js49O3mj0HZDoCrkWMnZyDsEmhMyQPU6YRFHWmB6OTKeD/Znk+b1uz+HIBgrbNuiG/A0c00Vnj7lR4p94oOuypI00XusLsJwPsjI4EgFGKdoRtM0spJhi+3gf88Vq0NENBaFVHLBGWVFaVrffurGcDZYUAdnvm8jSPCgBPfFxpZutexNkLjyaaXjDtga5/n5gSd/3RpWCvp9u3W5jcTNDZF4TORnOXUWHcot/+XmyH8/+cn8ydt0prOLGQ+FtdI+AWyMCXHen6aaZ1jeSLZqwARAQABtFpwZG5zIHJlZ3Jlc3Npb24gdGVzdGluZyBrZXkgKG9ubHkgZm9yIHRlc3RpbmcgdGhlIG9wZW5wZ3BrZXkgcnIpIDxyZWdyZXNzaW9uQHBvd2VyZG5zLm9yZz6JAjcEEwEIACEFAlUIXh0CGwMFCwkIBwIGFQgJCgsCBBYCAwECHgECF4AACgkQPr/KqoyK2Z7A6Q//YOBu8nwt+fguSo/vyCln0PqnTiBm4RvE2gPDUnsKuoXoP5F56XHBXKl9kEgmycht/nc7c7NRHzUhacM2RQau6CgNZE8KLaqDTKlEuc/ANtrnGGYG8gMId4TlzU5taLEA8yrHIHnwnMuDDpx1a0ETkbYCrj7CynqdhXCABqFjgRL7Qb37UnLPE7YdFt7fRGwZVLnb3GVZLKHurZ0TANvLdRVDST3f0lCcYMppPbHAvi2MIU71FPGkms++tj4gTltq0VRvrMNm1e5v4+hHZ++QN4sm4+DJGlo7l850gnMXc7c7GkRGtg8gV0h5k5jX5icdgxyvENTuBQ+QprkYTRh9uYzpoTQ+NYRZlgaJxxaDIv1K/kb3oPtnAEKJBC02IZbB0EiS3R5pxYXhUNoWV7ez2A4hX1L+tfvlgCAbbQ/cBLvqXgpgsf9x4ygSi52vQBy3twZyrtLsogxacxADfPcyleHtju/+lSku+Z6+W6OojA0kY2HlaMyQATJLIXd+6NE/tYy70RsU9Oq0OyVTjxh21SPLsExeSwSfciVSLn7IuKGIOV82MEHFhpo1Uhv+G52J8T1fI730sS4Tl5DekLaCz1pg/FmI/EQeAsYqm98uDAaFQcs6gDse8VYGmp2XYsoCW72as8ElKmMIbQ/xD7qxDORLmjCtVoyKH19+s6Pp61a5Ag0EVQheHQEQAMN6pcLJUhw9bfO5kqhLv4prt0AqVBUok6U8tIaEc9vDaasBcFHXgPsoOG97DXB6BdvsHuK/5uMVH5PNe58MLp08iCoIt0C0CbN3+D9Qbeg37AyKyFanB/CXq1tPKVCJc6BMNkO/BswnUsTTmlcd4GovpaJUOOZzblGUQBbhzRohhmOGfdsScGeeYME/yNFqzt1ZArV4va1hOLOUpNFv9TOy0ZVi/yDi+sYA9fCSZU9alWI/cbBct5I+3bh1l26umlZsYQm8uqnSgiQWpRm6UJO6xQbmUN9GzCYyKCmpzZRduqqjjtiF10W1yzioTfTtq2cvU6PdINYY8w2UuOjRd9gChtvGuduOIwqlRTYSaXX1dDoFe1vWqZzRm+pIDumO9eX5jMmzFXLDG2pD2l97zoSjVFf/pYoBasgX43e3V/aEk9PUgXbYFm2QxFMcIYSO9GEDMoE+QxoMXf1UjLxMCK5gD5iHL3Ff2zyXLzlTZE+fHPMLcAkzcp2u6pJ9xpAGekqqeqnISXZ2o8yXsqv8NVvl1zaSiSqU+kak9mIg/2+WC9W1qO2PeSLW2tiis980QnmyDOBg2oL01ITh/u+GTodEGwfRYJoNAJgUjcUMpWl0LuoG8lG6wukhA4QYFWpf2QPVgTR63VbpFgwCnUcSEPqHB0BRCsDHsd0k+/YSuPolABEBAAGJAh8EGAEIAAkFAlUIXh0CGwwACgkQPr/KqoyK2Z6zPA/+PkJTzP8kQw4GW0x2ZxXfOmkRVYpSEoHehf6y9YFN00+T8pb71RGItvuX5v6oPKPClOnIVg2WVHOq6Q3HsXEzl7oIbOtPE98WXHiVXud/djc54uHz9WjSPfy/idP7SMslo29BHR/K9nQkiGtayD57wdxgbLXObE3fA0gl4AsWl1EZzNcWVL4SIrvnBGpYIUGBcsTIiP3p09bu4Qf6HjJRXZlBuizigIgeO39l/G6tb6GA1cnbq4y6aCtQeXHLrnvak1jRqznlJWUqS1mQgOPF1MuOduHAvQbfMBQXAEfgOTzuH9PuKoGm7MePwTrU5GsOpNgS4LbvIRODJxYD+vIwA5BniijgfN9aj9KQVMURrd4Np7i0EVmj8P9FtNgYsEaDt7laGpNB9+9Y9heb6kNEulF7KI7y8CKikgvFGHHCyX2BCCbQBqi6wbEGq16qkTJmesYu9ig4v4xD/Q/cLJFziJLjEcWsL7hq7q2o6e7NL6hf5aTH0/bdeMXMqRzDCAFQ5Z+x0QUCgVonxzj+CuTD/LeOs/QHu/9emvm9EOMYY/X9vidLf58PT/AMqMiYbNWty6qY6k2LMw74Yd4+hO+Tjrk8MrqbCUs9h6ih9IOCo68JTWQQbgWSk2TAyd3U4OqTyBnHWr0HhHDRTOxyDbZUtXbk/r4Q4gTcAt+qjpswPyk=", "\x99\x02\x0d\x04\x55\x08\x5e\x1d\x01\x10\x00\xcd\x3e\x52\xfa\x36\x95\x84\x69\x1d\x8a\x27\x1e\xa9\xd7\xdb\x1c\x21\x5a\x6c\x04\x8a\x3b\x52\xac\xc2\x23\x37\x85\x6d\x12\x5a\x18\x38\x67\xfc\x79\x50\x81\xcc\x00\x6a\x57\x15\x36\x65\x94\x5f\x46\x50\xb2\xb7\x67\xf4\x21\x1f\x2d\x6b\x85\xbb\xd3\x8d\xda\x8d\x53\xb2\x56\x22\xc2\x7f\xa8\x48\x09\x47\xda\xb6\x85\x9b\x67\xb2\x25\x3a\x7f\x88\xce\xc8\x51\x40\xad\x7b\x98\xe6\x7f\x77\x7e\x2f\xda\xe3\x54\x8e\xc9\x8e\x63\x27\x6d\x5a\x3a\x49\x56\x36\x28\x30\xc3\xef\x67\x54\x2d\xc8\x3b\x22\xa6\x1c\x08\x03\x78\x09\x3f\xad\x3d\x93\xf9\xcb\x87\x18\x7f\xe0\xf1\x46\x5a\x71\x87\x1b\xea\xaa\x21\xb2\x02\x2e\xa5\x01\xc2\x76\xe3\xff\x1f\x27\x88\x6c\x1b\x49\x52\xd6\xf5\x35\xd8\xb5\x9e\x59\x31\xda\xe5\xa4\x4c\x33\xec\x7d\x92\x6b\xf7\x19\x87\x57\x1b\xe1\x71\x16\xa6\x70\xe7\x69\x19\x12\x70\x2c\x72\x90\xb6\xca\x66\xd7\xfb\x56\x05\x0a\xbf\x2c\x8c\x66\x06\x75\xef\xc3\xfb\x97\x0b\xbe\xeb\xb8\x3c\x63\x59\xe1\xf9\x12\x79\x2f\xb4\xc9\x7b\xde\xfe\xce\xae\xd6\x65\xfa\x46\x49\x05\xe9\x23\x86\x5a\xe2\x5f\x04\x93\x86\x75\x6c\xd8\xc1\xb7\xab\xf6\x4a\xa0\xaa\x91\xd3\x8e\x9a\xfc\x1c\xec\x9b\xcd\x5a\xe8\x06\x28\xed\x4e\x50\x7f\xb6\x89\xa6\x21\x47\x78\x05\x39\x3d\x26\xfe\x1f\xbf\x68\x00\xe1\x49\x02\xd7\x75\x0c\xf4\xa0\x45\xd4\xd9\xf3\x52\x72\x82\xf8\x9b\x38\xf4\xed\xe6\x8f\x41\xd9\x0e\x80\xab\x91\x63\x27\x67\x20\xec\x12\x68\x4c\xc9\x03\xd4\xe9\x84\x45\x1d\x69\x81\xe8\xe4\xca\x78\x3f\xd9\x9e\x4f\x9b\xd6\xec\xfe\x1c\x80\x60\xad\xb3\x6e\x88\x6f\xc0\xd1\xcd\x34\x56\x78\xfb\x95\x1e\x29\xf7\x8a\x0e\xbb\x2a\x48\xd3\x45\xee\xb0\xbb\x09\xc0\xfb\x23\x23\x81\x20\x14\x62\x9d\xa1\x1b\x4c\xd2\xca\x49\x86\x2f\xb7\x81\xff\x3c\x56\xad\x0d\x10\xd0\x5a\x15\x51\xcb\x04\x65\x95\x15\xa5\x6b\x7d\xfb\xab\x19\xc0\xd9\x61\x40\x1d\x9e\xf9\xbc\x8d\x23\xc2\x80\x13\xdf\x17\x1a\x59\xba\xd7\xb1\x36\x42\xe3\xc9\xa6\x97\x8c\x3b\x60\x6b\x9f\xe7\xe6\x04\x9d\xff\x74\x69\x58\x2b\xe9\xf6\xed\xd6\xe6\x37\x13\x34\x36\x45\xe1\x33\x91\x9c\xe5\xd4\x58\x77\x28\xb7\xff\x97\x9b\x21\xfc\xff\xe7\x27\xf3\x27\x6d\xd2\x9a\xce\x2c\x64\x3e\x16\xd7\x48\xf8\x05\xb2\x30\x25\xc7\x7a\x7e\x9a\x69\x9d\x63\x79\x22\xd9\xab\x00\x11\x01\x00\x01\xb4\x5a\x70\x64\x6e\x73\x20\x72\x65\x67\x72\x65\x73\x73\x69\x6f\x6e\x20\x74\x65\x73\x74\x69\x6e\x67\x20\x6b\x65\x79\x20\x28\x6f\x6e\x6c\x79\x20\x66\x6f\x72\x20\x74\x65\x73\x74\x69\x6e\x67\x20\x74\x68\x65\x20\x6f\x70\x65\x6e\x70\x67\x70\x6b\x65\x79\x20\x72\x72\x29\x20\x3c\x72\x65\x67\x72\x65\x73\x73\x69\x6f\x6e\x40\x70\x6f\x77\x65\x72\x64\x6e\x73\x2e\x6f\x72\x67\x3e\x89\x02\x37\x04\x13\x01\x08\x00\x21\x05\x02\x55\x08\x5e\x1d\x02\x1b\x03\x05\x0b\x09\x08\x07\x02\x06\x15\x08\x09\x0a\x0b\x02\x04\x16\x02\x03\x01\x02\x1e\x01\x02\x17\x80\x00\x0a\x09\x10\x3e\xbf\xca\xaa\x8c\x8a\xd9\x9e\xc0\xe9\x0f\xff\x60\xe0\x6e\xf2\x7c\x2d\xf9\xf8\x2e\x4a\x8f\xef\xc8\x29\x67\xd0\xfa\xa7\x4e\x20\x66\xe1\x1b\xc4\xda\x03\xc3\x52\x7b\x0a\xba\x85\xe8\x3f\x91\x79\xe9\x71\xc1\x5c\xa9\x7d\x90\x48\x26\xc9\xc8\x6d\xfe\x77\x3b\x73\xb3\x51\x1f\x35\x21\x69\xc3\x36\x45\x06\xae\xe8\x28\x0d\x64\x4f\x0a\x2d\xaa\x83\x4c\xa9\x44\xb9\xcf\xc0\x36\xda\xe7\x18\x66\x06\xf2\x03\x08\x77\x84\xe5\xcd\x4e\x6d\x68\xb1\x00\xf3\x2a\xc7\x20\x79\xf0\x9c\xcb\x83\x0e\x9c\x75\x6b\x41\x13\x91\xb6\x02\xae\x3e\xc2\xca\x7a\x9d\x85\x70\x80\x06\xa1\x63\x81\x12\xfb\x41\xbd\xfb\x52\x72\xcf\x13\xb6\x1d\x16\xde\xdf\x44\x6c\x19\x54\xb9\xdb\xdc\x65\x59\x2c\xa1\xee\xad\x9d\x13\x00\xdb\xcb\x75\x15\x43\x49\x3d\xdf\xd2\x50\x9c\x60\xca\x69\x3d\xb1\xc0\xbe\x2d\x8c\x21\x4e\xf5\x14\xf1\xa4\x9a\xcf\xbe\xb6\x3e\x20\x4e\x5b\x6a\xd1\x54\x6f\xac\xc3\x66\xd5\xee\x6f\xe3\xe8\x47\x67\xef\x90\x37\x8b\x26\xe3\xe0\xc9\x1a\x5a\x3b\x97\xce\x74\x82\x73\x17\x73\xb7\x3b\x1a\x44\x46\xb6\x0f\x20\x57\x48\x79\x93\x98\xd7\xe6\x27\x1d\x83\x1c\xaf\x10\xd4\xee\x05\x0f\x90\xa6\xb9\x18\x4d\x18\x7d\xb9\x8c\xe9\xa1\x34\x3e\x35\x84\x59\x96\x06\x89\xc7\x16\x83\x22\xfd\x4a\xfe\x46\xf7\xa0\xfb\x67\x00\x42\x89\x04\x2d\x36\x21\x96\xc1\xd0\x48\x92\xdd\x1e\x69\xc5\x85\xe1\x50\xda\x16\x57\xb7\xb3\xd8\x0e\x21\x5f\x52\xfe\xb5\xfb\xe5\x80\x20\x1b\x6d\x0f\xdc\x04\xbb\xea\x5e\x0a\x60\xb1\xff\x71\xe3\x28\x12\x8b\x9d\xaf\x40\x1c\xb7\xb7\x06\x72\xae\xd2\xec\xa2\x0c\x5a\x73\x10\x03\x7c\xf7\x32\x95\xe1\xed\x8e\xef\xfe\x95\x29\x2e\xf9\x9e\xbe\x5b\xa3\xa8\x8c\x0d\x24\x63\x61\xe5\x68\xcc\x90\x01\x32\x4b\x21\x77\x7e\xe8\xd1\x3f\xb5\x8c\xbb\xd1\x1b\x14\xf4\xea\xb4\x3b\x25\x53\x8f\x18\x76\xd5\x23\xcb\xb0\x4c\x5e\x4b\x04\x9f\x72\x25\x52\x2e\x7e\xc8\xb8\xa1\x88\x39\x5f\x36\x30\x41\xc5\x86\x9a\x35\x52\x1b\xfe\x1b\x9d\x89\xf1\x3d\x5f\x23\xbd\xf4\xb1\x2e\x13\x97\x90\xde\x90\xb6\x82\xcf\x5a\x60\xfc\x59\x88\xfc\x44\x1e\x02\xc6\x2a\x9b\xdf\x2e\x0c\x06\x85\x41\xcb\x3a\x80\x3b\x1e\xf1\x56\x06\x9a\x9d\x97\x62\xca\x02\x5b\xbd\x9a\xb3\xc1\x25\x2a\x63\x08\x6d\x0f\xf1\x0f\xba\xb1\x0c\xe4\x4b\x9a\x30\xad\x56\x8c\x8a\x1f\x5f\x7e\xb3\xa3\xe9\xeb\x56\xb9\x02\x0d\x04\x55\x08\x5e\x1d\x01\x10\x00\xc3\x7a\xa5\xc2\xc9\x52\x1c\x3d\x6d\xf3\xb9\x92\xa8\x4b\xbf\x8a\x6b\xb7\x40\x2a\x54\x15\x28\x93\xa5\x3c\xb4\x86\x84\x73\xdb\xc3\x69\xab\x01\x70\x51\xd7\x80\xfb\x28\x38\x6f\x7b\x0d\x70\x7a\x05\xdb\xec\x1e\xe2\xbf\xe6\xe3\x15\x1f\x93\xcd\x7b\x9f\x0c\x2e\x9d\x3c\x88\x2a\x08\xb7\x40\xb4\x09\xb3\x77\xf8\x3f\x50\x6d\xe8\x37\xec\x0c\x8a\xc8\x56\xa7\x07\xf0\x97\xab\x5b\x4f\x29\x50\x89\x73\xa0\x4c\x36\x43\xbf\x06\xcc\x27\x52\xc4\xd3\x9a\x57\x1d\xe0\x6a\x2f\xa5\xa2\x54\x38\xe6\x73\x6e\x51\x94\x40\x16\xe1\xcd\x1a\x21\x86\x63\x86\x7d\xdb\x12\x70\x67\x9e\x60\xc1\x3f\xc8\xd1\x6a\xce\xdd\x59\x02\xb5\x78\xbd\xad\x61\x38\xb3\x94\xa4\xd1\x6f\xf5\x33\xb2\xd1\x95\x62\xff\x20\xe2\xfa\xc6\x00\xf5\xf0\x92\x65\x4f\x5a\x95\x62\x3f\x71\xb0\x5c\xb7\x92\x3e\xdd\xb8\x75\x97\x6e\xae\x9a\x56\x6c\x61\x09\xbc\xba\xa9\xd2\x82\x24\x16\xa5\x19\xba\x50\x93\xba\xc5\x06\xe6\x50\xdf\x46\xcc\x26\x32\x28\x29\xa9\xcd\x94\x5d\xba\xaa\xa3\x8e\xd8\x85\xd7\x45\xb5\xcb\x38\xa8\x4d\xf4\xed\xab\x67\x2f\x53\xa3\xdd\x20\xd6\x18\xf3\x0d\x94\xb8\xe8\xd1\x77\xd8\x02\x86\xdb\xc6\xb9\xdb\x8e\x23\x0a\xa5\x45\x36\x12\x69\x75\xf5\x74\x3a\x05\x7b\x5b\xd6\xa9\x9c\xd1\x9b\xea\x48\x0e\xe9\x8e\xf5\xe5\xf9\x8c\xc9\xb3\x15\x72\xc3\x1b\x6a\x43\xda\x5f\x7b\xce\x84\xa3\x54\x57\xff\xa5\x8a\x01\x6a\xc8\x17\xe3\x77\xb7\x57\xf6\x84\x93\xd3\xd4\x81\x76\xd8\x16\x6d\x90\xc4\x53\x1c\x21\x84\x8e\xf4\x61\x03\x32\x81\x3e\x43\x1a\x0c\x5d\xfd\x54\x8c\xbc\x4c\x08\xae\x60\x0f\x98\x87\x2f\x71\x5f\xdb\x3c\x97\x2f\x39\x53\x64\x4f\x9f\x1c\xf3\x0b\x70\x09\x33\x72\x9d\xae\xea\x92\x7d\xc6\x90\x06\x7a\x4a\xaa\x7a\xa9\xc8\x49\x76\x76\xa3\xcc\x97\xb2\xab\xfc\x35\x5b\xe5\xd7\x36\x92\x89\x2a\x94\xfa\x46\xa4\xf6\x62\x20\xff\x6f\x96\x0b\xd5\xb5\xa8\xed\x8f\x79\x22\xd6\xda\xd8\xa2\xb3\xdf\x34\x42\x79\xb2\x0c\xe0\x60\xda\x82\xf4\xd4\x84\xe1\xfe\xef\x86\x4e\x87\x44\x1b\x07\xd1\x60\x9a\x0d\x00\x98\x14\x8d\xc5\x0c\xa5\x69\x74\x2e\xea\x06\xf2\x51\xba\xc2\xe9\x21\x03\x84\x18\x15\x6a\x5f\xd9\x03\xd5\x81\x34\x7a\xdd\x56\xe9\x16\x0c\x02\x9d\x47\x12\x10\xfa\x87\x07\x40\x51\x0a\xc0\xc7\xb1\xdd\x24\xfb\xf6\x12\xb8\xfa\x25\x00\x11\x01\x00\x01\x89\x02\x1f\x04\x18\x01\x08\x00\x09\x05\x02\x55\x08\x5e\x1d\x02\x1b\x0c\x00\x0a\x09\x10\x3e\xbf\xca\xaa\x8c\x8a\xd9\x9e\xb3\x3c\x0f\xfe\x3e\x42\x53\xcc\xff\x24\x43\x0e\x06\x5b\x4c\x76\x67\x15\xdf\x3a\x69\x11\x55\x8a\x52\x12\x81\xde\x85\xfe\xb2\xf5\x81\x4d\xd3\x4f\x93\xf2\x96\xfb\xd5\x11\x88\xb6\xfb\x97\xe6\xfe\xa8\x3c\xa3\xc2\x94\xe9\xc8\x56\x0d\x96\x54\x73\xaa\xe9\x0d\xc7\xb1\x71\x33\x97\xba\x08\x6c\xeb\x4f\x13\xdf\x16\x5c\x78\x95\x5e\xe7\x7f\x76\x37\x39\xe2\xe1\xf3\xf5\x68\xd2\x3d\xfc\xbf\x89\xd3\xfb\x48\xcb\x25\xa3\x6f\x41\x1d\x1f\xca\xf6\x74\x24\x88\x6b\x5a\xc8\x3e\x7b\xc1\xdc\x60\x6c\xb5\xce\x6c\x4d\xdf\x03\x48\x25\xe0\x0b\x16\x97\x51\x19\xcc\xd7\x16\x54\xbe\x12\x22\xbb\xe7\x04\x6a\x58\x21\x41\x81\x72\xc4\xc8\x88\xfd\xe9\xd3\xd6\xee\xe1\x07\xfa\x1e\x32\x51\x5d\x99\x41\xba\x2c\xe2\x80\x88\x1e\x3b\x7f\x65\xfc\x6e\xad\x6f\xa1\x80\xd5\xc9\xdb\xab\x8c\xba\x68\x2b\x50\x79\x71\xcb\xae\x7b\xda\x93\x58\xd1\xab\x39\xe5\x25\x65\x2a\x4b\x59\x90\x80\xe3\xc5\xd4\xcb\x8e\x76\xe1\xc0\xbd\x06\xdf\x30\x14\x17\x00\x47\xe0\x39\x3c\xee\x1f\xd3\xee\x2a\x81\xa6\xec\xc7\x8f\xc1\x3a\xd4\xe4\x6b\x0e\xa4\xd8\x12\xe0\xb6\xef\x21\x13\x83\x27\x16\x03\xfa\xf2\x30\x03\x90\x67\x8a\x28\xe0\x7c\xdf\x5a\x8f\xd2\x90\x54\xc5\x11\xad\xde\x0d\xa7\xb8\xb4\x11\x59\xa3\xf0\xff\x45\xb4\xd8\x18\xb0\x46\x83\xb7\xb9\x5a\x1a\x93\x41\xf7\xef\x58\xf6\x17\x9b\xea\x43\x44\xba\x51\x7b\x28\x8e\xf2\xf0\x22\xa2\x92\x0b\xc5\x18\x71\xc2\xc9\x7d\x81\x08\x26\xd0\x06\xa8\xba\xc1\xb1\x06\xab\x5e\xaa\x91\x32\x66\x7a\xc6\x2e\xf6\x28\x38\xbf\x8c\x43\xfd\x0f\xdc\x2c\x91\x73\x88\x92\xe3\x11\xc5\xac\x2f\xb8\x6a\xee\xad\xa8\xe9\xee\xcd\x2f\xa8\x5f\xe5\xa4\xc7\xd3\xf6\xdd\x78\xc5\xcc\xa9\x1c\xc3\x08\x01\x50\xe5\x9f\xb1\xd1\x05\x02\x81\x5a\x27\xc7\x38\xfe\x0a\xe4\xc3\xfc\xb7\x8e\xb3\xf4\x07\xbb\xff\x5e\x9a\xf9\xbd\x10\xe3\x18\x63\xf5\xfd\xbe\x27\x4b\x7f\x9f\x0f\x4f\xf0\x0c\xa8\xc8\x98\x6c\xd5\xad\xcb\xaa\x98\xea\x4d\x8b\x33\x0e\xf8\x61\xde\x3e\x84\xef\x93\x8e\xb9\x3c\x32\xba\x9b\x09\x4b\x3d\x87\xa8\xa1\xf4\x83\x82\xa3\xaf\x09\x4d\x64\x10\x6e\x05\x92\x93\x64\xc0\xc9\xdd\xd4\xe0\xea\x93\xc8\x19\xc7\x5a\xbd\x07\x84\x70\xd1\x4c\xec\x72\x0d\xb6\x54\xb5\x76\xe4\xfe\xbe\x10\xe2\x04\xdc\x02\xdf\xaa\x8e\x9b\x30\x3f\x29"))
+ // Alias mode
+ (CASE_S(QType::SVCB, "0 foo.powerdns.org.", "\0\0\3foo\x08powerdns\x03org\x00"))
+ (CASE_L(QType::SVCB, "0 foo.powerdns.org", "0 foo.powerdns.org.", "\0\0\3foo\x08powerdns\x03org\x00"))
+
+ // Service mode
+ (CASE_S(QType::SVCB, "1 .", "\x00\x01\x00"))
+ (CASE_S(QType::SVCB, "1 foo.powerdns.org. mandatory=alpn", "\0\x01\3foo\x08powerdns\x03org\x00\x00\x00\x00\x02\x00\x01"))
+ (CASE_S(QType::SVCB, "1 foo.powerdns.org. no-default-alpn", "\0\x01\3foo\x08powerdns\x03org\x00\x00\x02\x00\x00"))
+ (CASE_S(QType::SVCB, "1 foo.powerdns.org. alpn=h3,h2", "\0\x01\3foo\x08powerdns\x03org\x00\x00\x01\x00\x06\x02h3\x02h2"))
+ (CASE_S(QType::SVCB, "1 foo.powerdns.org. port=53", "\0\x01\3foo\x08powerdns\x03org\x00\x00\x03\x00\x02\x00\x35"))
+ (CASE_S(QType::SVCB, "1 foo.powerdns.org. ipv4hint=192.0.2.53,192.0.2.2", "\0\x01\3foo\x08powerdns\x03org\x00\x00\x04\x00\x08\xc0\x00\x02\x35\xc0\x00\x02\x02"))
+ (CASE_S(QType::SVCB, "1 foo.powerdns.org. echconfig=\"aGVsbG8=\"", "\0\x01\3foo\x08powerdns\x03org\x00\x00\x05\x00\x05hello"))
+ (CASE_L(QType::SVCB, "1 foo.powerdns.org. echconfig=aGVsbG8=", "1 foo.powerdns.org. echconfig=\"aGVsbG8=\"", "\0\x01\3foo\x08powerdns\x03org\x00\x00\x05\x00\x05hello"))
+ (CASE_S(QType::SVCB, "1 foo.powerdns.org. ipv6hint=2001:db8::1,2001:db8::53:1", "\0\x01\3foo\x08powerdns\x03org\x00\x00\x06\x00\x20\x20\x01\x0d\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x20\x01\x0d\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x53\x00\x01"))
+
+ (CASE_S(QType::SVCB, "16 foo.powerdns.org. mandatory=alpn alpn=h2,h3 ipv4hint=192.0.2.1", "\0\x10\3foo\x08powerdns\x03org\x00\x00\x00\x00\x02\x00\x01\x00\x01\x00\x06\x02h2\x02h3\x00\x04\x00\x04\xc0\x00\x02\x01"))
+ (CASE_L(QType::SVCB, "16 foo.powerdns.org. alpn=h2,h3 mandatory=alpn ipv4hint=192.0.2.1", "16 foo.powerdns.org. mandatory=alpn alpn=h2,h3 ipv4hint=192.0.2.1", "\0\x10\3foo\x08powerdns\x03org\x00\x00\x00\x00\x02\x00\x01\x00\x01\x00\x06\x02h2\x02h3\x00\x04\x00\x04\xc0\x00\x02\x01"))
+
(CASE_S(QType::SPF, "\"v=spf1 a:mail.rec.test ~all\"", "\x1bv=spf1 a:mail.rec.test ~all"))
(CASE_S(QType::EUI48, "00-11-22-33-44-55", "\x00\x11\x22\x33\x44\x55"))
(CASE_S(QType::EUI64, "00-11-22-33-44-55-66-77", "\x00\x11\x22\x33\x44\x55\x66\x77"))
BOOST_CHECK_NO_THROW(MOADNSParser mdp(false, spacket));
}
+BOOST_AUTO_TEST_CASE(test_xfrSvcParamKeyVals_mandatory) {
+ DNSName name("powerdns.com.");
+ vector<uint8_t> packet;
+ DNSPacketWriter pwR(packet, name, QType::SVCB, QClass::IN, 0);
+ pwR.getHeader()->qr = 1;
+
+ set<string> keys({"alpn", "ipv6hint"});
+ set<SvcParam> params({SvcParam(SvcParam::mandatory, keys)});
+
+ pwR.startRecord(name, QType::SVCB);
+ pwR.commit();
+ auto start = pwR.getContent().size();
+
+ pwR.xfrSvcParamKeyVals(params);
+ pwR.commit();
+ auto cit = pwR.getContent().begin();
+ for (size_t i = 0; i<start; i++)
+ cit++;
+
+ vector<uint8_t> c(cit, pwR.getContent().end());
+ BOOST_CHECK(c == vector<uint8_t>({0,0,0,4,0,1,0,6}));
+}
+
+BOOST_AUTO_TEST_CASE(test_xfrSvcParamKeyVals_alpn) {
+ DNSName name("powerdns.com.");
+ vector<uint8_t> packet;
+ DNSPacketWriter pwR(packet, name, QType::SVCB, QClass::IN, 0);
+ pwR.getHeader()->qr = 1;
+
+ vector<string> alpns({"h2", "h2c", "h3"});
+ set<SvcParam> params({SvcParam(SvcParam::alpn, alpns)});
+
+ pwR.startRecord(name, QType::SVCB);
+ pwR.commit();
+ auto start = pwR.getContent().size();
+
+ pwR.xfrSvcParamKeyVals(params);
+ pwR.commit();
+ auto cit = pwR.getContent().begin();
+ for (size_t i = 0; i<start; i++)
+ cit++;
+
+ vector<uint8_t> c(cit, pwR.getContent().end());
+ BOOST_CHECK(c == vector<uint8_t>({
+ 0,1,0,10,
+ 2,'h','2',
+ 3,'h','2','c',
+ 2,'h','3'}));
+}
+
+BOOST_AUTO_TEST_CASE(test_xfrSvcParamKeyVals_no_default_alpn) {
+ DNSName name("powerdns.com.");
+ vector<uint8_t> packet;
+ DNSPacketWriter pwR(packet, name, QType::SVCB, QClass::IN, 0);
+ pwR.getHeader()->qr = 1;
+
+ set<SvcParam> params({SvcParam(SvcParam::no_default_alpn)});
+
+ pwR.startRecord(name, QType::SVCB);
+ pwR.commit();
+ auto start = pwR.getContent().size();
+
+ pwR.xfrSvcParamKeyVals(params);
+ pwR.commit();
+ auto cit = pwR.getContent().begin();
+ for (size_t i = 0; i<start; i++)
+ cit++;
+
+ vector<uint8_t> c(cit, pwR.getContent().end());
+ BOOST_CHECK(c == vector<uint8_t>({0,2,0,0}));
+}
+
+BOOST_AUTO_TEST_CASE(test_xfrSvcParamKeyVals_port) {
+ DNSName name("powerdns.com.");
+ vector<uint8_t> packet;
+ DNSPacketWriter pwR(packet, name, QType::SVCB, QClass::IN, 0);
+ pwR.getHeader()->qr = 1;
+
+ set<SvcParam> params({SvcParam(SvcParam::port, 53)});
+
+ pwR.startRecord(name, QType::SVCB);
+ pwR.commit();
+ auto start = pwR.getContent().size();
+
+ pwR.xfrSvcParamKeyVals(params);
+ pwR.commit();
+ auto cit = pwR.getContent().begin();
+ for (size_t i = 0; i<start; i++)
+ cit++;
+
+ vector<uint8_t> c(cit, pwR.getContent().end());
+ BOOST_CHECK(c == vector<uint8_t>({0,3,0,2,0,53}));
+}
+
+BOOST_AUTO_TEST_CASE(test_xfrSvcParamKeyVals_ipv4hint) {
+ DNSName name("powerdns.com.");
+ vector<uint8_t> packet;
+ DNSPacketWriter pwR(packet, name, QType::SVCB, QClass::IN, 0);
+ pwR.getHeader()->qr = 1;
+
+ vector<ComboAddress> addrs({ComboAddress("192.0.2.1"), ComboAddress("192.0.2.2")});
+ set<SvcParam> params({SvcParam(SvcParam::ipv4hint, addrs)});
+
+ pwR.startRecord(name, QType::SVCB);
+ pwR.commit();
+ auto start = pwR.getContent().size();
+
+ pwR.xfrSvcParamKeyVals(params);
+ pwR.commit();
+ auto cit = pwR.getContent().begin();
+ for (size_t i = 0; i<start; i++)
+ cit++;
+
+ vector<uint8_t> c(cit, pwR.getContent().end());
+ BOOST_CHECK(c == vector<uint8_t>({0,4,0,8,192,0,2,1,192,0,2,2}));
+}
+
+BOOST_AUTO_TEST_CASE(test_xfrSvcParamKeyVals_echconfig) {
+ DNSName name("powerdns.com.");
+ vector<uint8_t> packet;
+ DNSPacketWriter pwR(packet, name, QType::SVCB, QClass::IN, 0);
+ pwR.getHeader()->qr = 1;
+
+ set<SvcParam> params({SvcParam(SvcParam::echconfig, "a very bogus echconfig value")});
+
+ pwR.startRecord(name, QType::SVCB);
+ pwR.commit();
+ auto start = pwR.getContent().size();
+
+ pwR.xfrSvcParamKeyVals(params);
+ pwR.commit();
+ auto cit = pwR.getContent().begin();
+ for (size_t i = 0; i<start; i++)
+ cit++;
+
+ vector<uint8_t> c(cit, pwR.getContent().end());
+ BOOST_CHECK(c == vector<uint8_t>({0,5,0,28,
+ 'a',' ','v','e','r','y',' ','b','o','g','u','s',' ',
+ 'e','c','h','c','o','n','f','i','g',' ','v','a','l','u','e'
+ }));
+}
+
+BOOST_AUTO_TEST_CASE(test_xfrSvcParamKeyVals_ipv6hint) {
+ DNSName name("powerdns.com.");
+ vector<uint8_t> packet;
+ DNSPacketWriter pwR(packet, name, QType::SVCB, QClass::IN, 0);
+ pwR.getHeader()->qr = 1;
+
+ vector<ComboAddress> addrs({ComboAddress("2001:db8::1"), ComboAddress("2001:db8::2")});
+ set<SvcParam> params({SvcParam(SvcParam::ipv6hint, addrs)});
+
+ pwR.startRecord(name, QType::SVCB);
+ pwR.commit();
+ auto start = pwR.getContent().size();
+
+ pwR.xfrSvcParamKeyVals(params);
+ pwR.commit();
+ auto cit = pwR.getContent().begin();
+ for (size_t i = 0; i<start; i++)
+ cit++;
+
+ vector<uint8_t> c(cit, pwR.getContent().end());
+ BOOST_CHECK(c == vector<uint8_t>({0,6,0,32,
+ 32,1,13,184,0,0,0,0,0,0,0,0,0,0,0,1,
+ 32,1,13,184,0,0,0,0,0,0,0,0,0,0,0,2}));
+}
+
+BOOST_AUTO_TEST_CASE(test_xfrSvcParamKeyVals_generic) {
+ DNSName name("powerdns.com.");
+ vector<uint8_t> packet;
+ DNSPacketWriter pwR(packet, name, QType::SVCB, QClass::IN, 0);
+ pwR.getHeader()->qr = 1;
+
+ set<SvcParam> params({SvcParam(SvcParam::keyFromString("key666"), "mycoolvalue")});
+
+ pwR.startRecord(name, QType::SVCB);
+ pwR.commit();
+ auto start = pwR.getContent().size();
+
+ pwR.xfrSvcParamKeyVals(params);
+ pwR.commit();
+ auto cit = pwR.getContent().begin();
+ for (size_t i = 0; i<start; i++)
+ cit++;
+
+ vector<uint8_t> c(cit, pwR.getContent().end());
+ BOOST_CHECK(c == vector<uint8_t>({2,154,0,11,
+ 'm','y','c','o','o','l','v','a','l','u','e'
+ }));
+}
+
+BOOST_AUTO_TEST_CASE(test_xfrSvcParamKeyVals_multiple) {
+ DNSName name("powerdns.com.");
+ vector<uint8_t> packet;
+ DNSPacketWriter pwR(packet, name, QType::SVCB, QClass::IN, 0);
+ pwR.getHeader()->qr = 1;
+
+ vector<ComboAddress> addrs({ComboAddress("2001:db8::1"), ComboAddress("2001:db8::2")});
+ vector<string> alpns({"h2", "h2c", "h3"});
+ set<SvcParam> params({SvcParam(SvcParam::alpn, alpns), SvcParam(SvcParam::ipv6hint, addrs), SvcParam(SvcParam::port, 53)});
+
+ pwR.startRecord(name, QType::SVCB);
+ pwR.commit();
+ auto start = pwR.getContent().size();
+
+ pwR.xfrSvcParamKeyVals(params);
+ pwR.commit();
+ auto cit = pwR.getContent().begin();
+ for (size_t i = 0; i<start; i++)
+ cit++;
+
+ vector<uint8_t> c(cit, pwR.getContent().end());
+ BOOST_CHECK(c == vector<uint8_t>({
+ 0,1,0,10,2,'h','2',3,'h','2','c',2,'h','3', // alpn
+ 0,3,0,2,0,53, // port
+ 0,6,0,32, // ipv6
+ 32,1,13,184,0,0,0,0,0,0,0,0,0,0,0,1,
+ 32,1,13,184,0,0,0,0,0,0,0,0,0,0,0,2}));
+}
+
BOOST_AUTO_TEST_SUITE_END()
}
-BOOST_AUTO_TEST_SUITE_END()
+BOOST_AUTO_TEST_CASE(test_xfrSvcParamKeyVals_alpn) {
+ string source("alpn=h2");
+ RecordTextReader rtr(source);
+ set<SvcParam> v;
+ rtr.xfrSvcParamKeyVals(v);
+ BOOST_CHECK_EQUAL(v.size(), 1);
+ auto alpn = v.begin()->getALPN();
+ BOOST_CHECK_EQUAL(alpn.size(), 1);
+ auto val = alpn.begin();
+ BOOST_CHECK_EQUAL(*val, "h2");
+ // Check the writer
+ string target;
+ RecordTextWriter rtw(target);
+ rtw.xfrSvcParamKeyVals(v);
+ BOOST_CHECK_EQUAL(target, source);
+
+ v.clear();
+ source = "alpn=h2,h3";
+ RecordTextReader rtr2(source);
+ rtr2.xfrSvcParamKeyVals(v);
+ BOOST_CHECK_EQUAL(v.size(), 1);
+ alpn = v.begin()->getALPN();
+ BOOST_CHECK_EQUAL(alpn.size(), 2);
+ val = alpn.begin();
+ BOOST_CHECK_EQUAL(*val, "h2");
+ val++;
+ BOOST_CHECK_EQUAL(*val, "h3");
+
+ // Check the writer
+ target.clear();
+ RecordTextWriter rtw2(target);
+ rtw2.xfrSvcParamKeyVals(v);
+ BOOST_CHECK_EQUAL(target, source);
+}
+
+BOOST_AUTO_TEST_CASE(test_xfrSvcParamKeyVals_mandatory) {
+ string source("mandatory=alpn");
+ RecordTextReader rtr(source);
+ set<SvcParam> v;
+ rtr.xfrSvcParamKeyVals(v);
+ BOOST_CHECK_EQUAL(v.size(), 1);
+ auto m = v.begin()->getMandatory();
+ BOOST_CHECK_EQUAL(m.size(), 1);
+ auto val = m.begin();
+ BOOST_CHECK(*val == SvcParam::alpn);
+
+ // Check the writer
+ string target;
+ RecordTextWriter rtw(target);
+ rtw.xfrSvcParamKeyVals(v);
+ BOOST_CHECK_EQUAL(target, source);
+
+ v.clear();
+ source = "mandatory=alpn,ipv4hint";
+ RecordTextReader rtr2("mandatory=alpn,ipv4hint");
+ rtr2.xfrSvcParamKeyVals(v);
+ BOOST_CHECK_EQUAL(v.size(), 1);
+ m = v.begin()->getMandatory();
+ BOOST_CHECK_EQUAL(m.size(), 2);
+ val = m.begin();
+ BOOST_CHECK(*val == SvcParam::alpn);
+ val++;
+ BOOST_CHECK(*val == SvcParam::ipv4hint);
+
+ // Check the writer
+ target.clear();
+ RecordTextWriter rtw2(target);
+ rtw2.xfrSvcParamKeyVals(v);
+ BOOST_CHECK_EQUAL(target, source);
+}
+
+BOOST_AUTO_TEST_CASE(test_xfrSvcParamKeyVals_no_default_alpn) {
+ string source("no-default-alpn");
+ RecordTextReader rtr(source);
+ set<SvcParam> v;
+ rtr.xfrSvcParamKeyVals(v);
+ BOOST_CHECK_EQUAL(v.size(), 1);
+ auto k = v.begin()->getKey();
+ BOOST_CHECK(k == SvcParam::no_default_alpn);
+
+ // Check the writer
+ string target;
+ RecordTextWriter rtw(target);
+ rtw.xfrSvcParamKeyVals(v);
+ BOOST_CHECK_EQUAL(target, source);
+
+ RecordTextReader rtr2("no-default-alpn=");
+ v.clear();
+ BOOST_CHECK_THROW(rtr2.xfrSvcParamKeyVals(v), RecordTextException);
+}
+
+BOOST_AUTO_TEST_CASE(test_xfrSvcParamKeyVals_ipv4hint) {
+ string source("ipv4hint=192.0.2.1");
+ RecordTextReader rtr(source);
+ set<SvcParam> v;
+ rtr.xfrSvcParamKeyVals(v);
+ BOOST_CHECK_EQUAL(v.size(), 1);
+ auto k = v.begin()->getKey();
+ BOOST_CHECK(k == SvcParam::ipv4hint);
+ auto val = v.begin()->getIPHints();
+ BOOST_CHECK_EQUAL(val.size(), 1);
+ BOOST_CHECK_EQUAL(val.begin()->toString(), "192.0.2.1");
+
+ // Check the writer
+ string target;
+ RecordTextWriter rtw(target);
+ rtw.xfrSvcParamKeyVals(v);
+ BOOST_CHECK_EQUAL(target, source);
+
+ v.clear();
+ source = "ipv4hint=192.0.2.1,192.0.2.2,192.0.2.3";
+ RecordTextReader rtr2(source);
+ rtr2.xfrSvcParamKeyVals(v);
+ BOOST_CHECK_EQUAL(v.size(), 1);
+ k = v.begin()->getKey();
+ BOOST_CHECK(k == SvcParam::ipv4hint);
+
+ val = v.begin()->getIPHints();
+ BOOST_CHECK_EQUAL(val.size(), 3);
+ auto valit = val.begin();
+ BOOST_CHECK_EQUAL(valit->toString(), "192.0.2.1");
+ valit++;
+ BOOST_CHECK_EQUAL(valit->toString(), "192.0.2.2");
+ valit++;
+ BOOST_CHECK_EQUAL(valit->toString(), "192.0.2.3");
+
+ // Check the writer
+ target.clear();
+ RecordTextWriter rtw2(target);
+ rtw2.xfrSvcParamKeyVals(v);
+ BOOST_CHECK_EQUAL(target, source);
+
+ v.clear();
+ RecordTextReader rtr3("ipv4hint=2001:db8::1");
+ BOOST_CHECK_THROW(rtr3.xfrSvcParamKeyVals(v), RecordTextException);
+
+ v.clear();
+ RecordTextReader rtr4("ipv4hint=192.0.2.1,2001:db8::1");
+ BOOST_CHECK_THROW(rtr4.xfrSvcParamKeyVals(v), RecordTextException);
+}
+
+BOOST_AUTO_TEST_CASE(test_xfrSvcParamKeyVals_ipv6hint) {
+ string source("ipv6hint=2001:db8::1");
+ RecordTextReader rtr(source);
+ set<SvcParam> v;
+ rtr.xfrSvcParamKeyVals(v);
+ BOOST_CHECK_EQUAL(v.size(), 1);
+ auto k = v.begin()->getKey();
+ BOOST_CHECK(k == SvcParam::ipv6hint);
+ auto val = v.begin()->getIPHints();
+ BOOST_CHECK_EQUAL(val.size(), 1);
+ BOOST_CHECK_EQUAL(val.begin()->toString(), "2001:db8::1");
+
+ // Check the writer
+ string target;
+ RecordTextWriter rtw(target);
+ rtw.xfrSvcParamKeyVals(v);
+ BOOST_CHECK_EQUAL(target, source);
+
+ v.clear();
+ source = "ipv6hint=2001:db8::1,2001:db8::2,2001:db8::3";
+ RecordTextReader rtr2(source);
+ rtr2.xfrSvcParamKeyVals(v);
+ BOOST_CHECK_EQUAL(v.size(), 1);
+ k = v.begin()->getKey();
+ BOOST_CHECK(k == SvcParam::ipv6hint);
+
+ val = v.begin()->getIPHints();
+ BOOST_CHECK_EQUAL(val.size(), 3);
+ auto valit = val.begin();
+ BOOST_CHECK_EQUAL(valit->toString(), "2001:db8::1");
+ valit++;
+ BOOST_CHECK_EQUAL(valit->toString(), "2001:db8::2");
+ valit++;
+ BOOST_CHECK_EQUAL(valit->toString(), "2001:db8::3");
+
+ // Check the writer
+ target.clear();
+ RecordTextWriter rtw2(target);
+ rtw2.xfrSvcParamKeyVals(v);
+ BOOST_CHECK_EQUAL(target, source);
+
+ v.clear();
+ RecordTextReader rtr3("ipv6hint=192.0.2.1");
+ BOOST_CHECK_THROW(rtr3.xfrSvcParamKeyVals(v), RecordTextException);
+
+ v.clear();
+ RecordTextReader rtr4("ipv6hint=192.0.2.1,2001:db8::1");
+ BOOST_CHECK_THROW(rtr4.xfrSvcParamKeyVals(v), RecordTextException);
+}
+
+BOOST_AUTO_TEST_CASE(test_xfrSvcParamKeyVals_port) {
+ string source("port=53");
+ RecordTextReader rtr(source);
+ set<SvcParam> v;
+ rtr.xfrSvcParamKeyVals(v);
+ BOOST_CHECK_EQUAL(v.size(), 1);
+ auto k = v.begin()->getKey();
+ BOOST_CHECK(k == SvcParam::port);
+ auto val = v.begin()->getPort();
+ BOOST_CHECK_EQUAL(val, 53);
+
+ // Check the writer
+ string target;
+ RecordTextWriter rtw(target);
+ rtw.xfrSvcParamKeyVals(v);
+ BOOST_CHECK_EQUAL(target, source);
+
+ v.clear();
+ RecordTextReader rtr2("port=100000");
+ BOOST_CHECK_THROW(rtr2.xfrSvcParamKeyVals(v), RecordTextException);
+
+ v.clear();
+ RecordTextReader rtr3("port=foo");
+ BOOST_CHECK_THROW(rtr3.xfrSvcParamKeyVals(v), RecordTextException);
+
+ v.clear();
+ RecordTextReader rtr4("port=");
+ BOOST_CHECK_THROW(rtr4.xfrSvcParamKeyVals(v), RecordTextException);
+
+ v.clear();
+ RecordTextReader rtr5("port");
+ BOOST_CHECK_THROW(rtr5.xfrSvcParamKeyVals(v), RecordTextException);
+}
+
+BOOST_AUTO_TEST_CASE(test_xfrSvcParamKeyVals_generic) {
+ string source("key666=foobar");
+ RecordTextReader rtr(source);
+ set<SvcParam> v;
+ rtr.xfrSvcParamKeyVals(v);
+ BOOST_CHECK_EQUAL(v.size(), 1);
+ auto k = v.begin()->getKey();
+ BOOST_CHECK(k == 666);
+ auto val = v.begin()->getValue();
+ BOOST_CHECK_EQUAL(val, "foobar");
+
+ // Check the writer
+ string target;
+ RecordTextWriter rtw(target);
+ rtw.xfrSvcParamKeyVals(v);
+ BOOST_CHECK_EQUAL(target, source);
+
+ v.clear();
+ RecordTextReader rtr2("key666=");
+ BOOST_CHECK_THROW(rtr2.xfrSvcParamKeyVals(v), RecordTextException);
+
+ v.clear();
+ RecordTextReader rtr3("key666");
+ BOOST_CHECK_THROW(rtr3.xfrSvcParamKeyVals(v), RecordTextException);
+
+ v.clear();
+ source = "key666=\"blablabla\"";
+ RecordTextReader rtr4(source);
+ rtr4.xfrSvcParamKeyVals(v);
+ BOOST_CHECK_EQUAL(v.size(), 1);
+ k = v.begin()->getKey();
+ BOOST_CHECK(k == SvcParam::keyFromString("key666"));
+ val = v.begin()->getValue();
+ BOOST_CHECK_EQUAL(val, "\"blablabla\"");
+
+ // Check the writer
+ target.clear();
+ RecordTextWriter rtw2(target);
+ rtw2.xfrSvcParamKeyVals(v);
+ BOOST_CHECK_EQUAL(target, source);
+}
+
+BOOST_AUTO_TEST_CASE(test_xfrSvcParamKeyVals_multiple) {
+ RecordTextReader rtr("key666=foobar echconfig=\"dG90YWxseSBib2d1cyBlY2hjb25maWcgdmFsdWU=\" ipv6hint=2001:db8::1 alpn=h2,h3 mandatory=alpn ipv4hint=192.0.2.1,192.0.2.2"); // out of order, resulting set should be in-order
+ set<SvcParam> v;
+ rtr.xfrSvcParamKeyVals(v);
+ BOOST_CHECK_EQUAL(v.size(), 6);
+ auto vit = v.begin();
+
+ // Check ordering
+ for (size_t i = 0; i < v.size(); i++) {
+ if (i == 0) {
+ BOOST_CHECK(vit->getKey() == SvcParam::mandatory);
+ }
+ if (i == 1) {
+ BOOST_CHECK(vit->getKey() == SvcParam::alpn);
+ }
+ if (i == 2) {
+ BOOST_CHECK(vit->getKey() == SvcParam::ipv4hint);
+ }
+ if (i == 3) {
+ BOOST_CHECK(vit->getKey() == SvcParam::echconfig);
+ }
+ if (i == 4) {
+ BOOST_CHECK(vit->getKey() == SvcParam::ipv6hint);
+ }
+ if (i == 5) {
+ BOOST_CHECK(vit->getKey() == SvcParam::keyFromString("key666"));
+ }
+ vit++;
+ }
+
+ // Check the writer
+ string target;
+ RecordTextWriter rtw(target);
+ rtw.xfrSvcParamKeyVals(v);
+ BOOST_CHECK_EQUAL(target, "mandatory=alpn alpn=h2,h3 ipv4hint=192.0.2.1,192.0.2.2 echconfig=\"dG90YWxseSBib2d1cyBlY2hjb25maWcgdmFsdWU=\" ipv6hint=2001:db8::1 key666=foobar");
+}
+
+BOOST_AUTO_TEST_CASE(test_xfrSvcParamKeyVals_echconfig) {
+ string source("echconfig=\"dG90YWxseSBib2d1cyBlY2hjb25maWcgdmFsdWU=\"");
+ RecordTextReader rtr(source);
+ set<SvcParam> v;
+ rtr.xfrSvcParamKeyVals(v);
+ BOOST_CHECK_EQUAL(v.size(), 1);
+ auto k = v.begin()->getKey();
+ BOOST_CHECK(k == SvcParam::echconfig);
+ auto val = v.begin()->getEchConfig();
+ BOOST_CHECK_EQUAL(val, "totally bogus echconfig value"); // decoded!
+
+ // Check the writer
+ string target;
+ RecordTextWriter rtw(target);
+ rtw.xfrSvcParamKeyVals(v);
+ BOOST_CHECK_EQUAL(source, target);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
\ No newline at end of file
SvcParam::SvcParamKey k;
k = SvcParam::keyFromString("mandatory");
- BOOST_CHECK_EQUAL(k, 0);
- BOOST_CHECK_EQUAL(k, SvcParam::mandatory);
+ BOOST_CHECK(k == 0);
+ BOOST_CHECK(k == SvcParam::mandatory);
k = SvcParam::keyFromString("alpn");
- BOOST_CHECK_EQUAL(k, 1);
- BOOST_CHECK_EQUAL(k, SvcParam::alpn);
+ BOOST_CHECK(k == 1);
+ BOOST_CHECK(k == SvcParam::alpn);
k = SvcParam::keyFromString("no-default-alpn");
- BOOST_CHECK_EQUAL(k, 2);
- BOOST_CHECK_EQUAL(k, SvcParam::no_default_alpn);
+ BOOST_CHECK(k == 2);
+ BOOST_CHECK(k == SvcParam::no_default_alpn);
k = SvcParam::keyFromString("port");
- BOOST_CHECK_EQUAL(k, 3);
- BOOST_CHECK_EQUAL(k, SvcParam::port);
+ BOOST_CHECK(k == 3);
+ BOOST_CHECK(k == SvcParam::port);
k = SvcParam::keyFromString("ipv4hint");
- BOOST_CHECK_EQUAL(k, 4);
- BOOST_CHECK_EQUAL(k, SvcParam::ipv4hint);
+ BOOST_CHECK(k == 4);
+ BOOST_CHECK(k == SvcParam::ipv4hint);
k = SvcParam::keyFromString("echconfig");
- BOOST_CHECK_EQUAL(k, 5);
- BOOST_CHECK_EQUAL(k, SvcParam::echconfig);
+ BOOST_CHECK(k == 5);
+ BOOST_CHECK(k == SvcParam::echconfig);
k = SvcParam::keyFromString("ipv6hint");
- BOOST_CHECK_EQUAL(k, 6);
- BOOST_CHECK_EQUAL(k, SvcParam::ipv6hint);
+ BOOST_CHECK(k == 6);
+ BOOST_CHECK(k == SvcParam::ipv6hint);
k = SvcParam::keyFromString("key0");
- BOOST_CHECK_EQUAL(k, 0);
- BOOST_CHECK_EQUAL(k, SvcParam::mandatory);
+ BOOST_CHECK(k == 0);
+ BOOST_CHECK(k == SvcParam::mandatory);
k = SvcParam::keyFromString("key666");
- BOOST_CHECK_EQUAL(k, 666);
+ BOOST_CHECK(k == 666);
BOOST_CHECK_THROW(SvcParam::keyFromString("MANDATORY"), std::invalid_argument);
}
}
BOOST_AUTO_TEST_CASE(test_SvcParam_ctor_no_value) {
- BOOST_CHECK_NO_THROW(SvcParam(SvcParam::no_default_alpn));
- BOOST_CHECK_THROW(SvcParam(SvcParam::alpn), std::invalid_argument);
+ BOOST_CHECK_NO_THROW(SvcParam(SvcParam::keyFromString("no-default-alpn")));
+ BOOST_CHECK_THROW(SvcParam(SvcParam::keyFromString("alpn")), std::invalid_argument);
BOOST_CHECK_THROW(SvcParam(SvcParam::keyFromString("key666")), std::invalid_argument);
}
BOOST_AUTO_TEST_CASE(test_SvcParam_ctor_set_string_value) {
set<string> val({"foo", "bar", "baz"});
+ BOOST_CHECK_THROW(SvcParam(SvcParam::alpn, val), std::invalid_argument);
BOOST_CHECK_THROW(SvcParam(SvcParam::no_default_alpn, val), std::invalid_argument);
BOOST_CHECK_THROW(SvcParam(SvcParam::port, val), std::invalid_argument);
BOOST_CHECK_THROW(SvcParam(SvcParam::ipv4hint, val), std::invalid_argument);
BOOST_CHECK_THROW(SvcParam(SvcParam::echconfig, val), std::invalid_argument);
BOOST_CHECK_THROW(SvcParam(SvcParam::ipv6hint, val), std::invalid_argument);
+ set<string> mandatoryVal = {"alpn", "key666"};
+ set<SvcParam::SvcParamKey> mandatoryExpected = {SvcParam::alpn, (SvcParam::SvcParamKey)666};
SvcParam param;
- BOOST_CHECK_NO_THROW(param = SvcParam(SvcParam::keyFromString("mandatory"), val)); // TODO this will fail once we start checking the contents
+ BOOST_CHECK_NO_THROW(param = SvcParam(SvcParam::keyFromString("mandatory"), mandatoryVal));
auto retval = param.getMandatory();
- BOOST_CHECK_EQUAL_COLLECTIONS(retval.begin(), retval.end(), val.begin(), val.end());
+ BOOST_CHECK(retval == mandatoryExpected);
BOOST_CHECK_THROW(param.getALPN(), std::invalid_argument);
BOOST_CHECK_THROW(param.getEchConfig(), std::invalid_argument);
BOOST_CHECK_THROW(param.getIPHints(), std::invalid_argument);
BOOST_CHECK_THROW(param.getPort(), std::invalid_argument);
BOOST_CHECK_THROW(param.getValue(), std::invalid_argument);
+}
- retval.clear();
+BOOST_AUTO_TEST_CASE(test_SvcParam_ctor_vector_string_value) {
+ auto val = vector<string>({"h3, h2"});
+
+ BOOST_CHECK_THROW(SvcParam(SvcParam::mandatory, val), std::invalid_argument);
+ BOOST_CHECK_THROW(SvcParam(SvcParam::no_default_alpn, val), std::invalid_argument);
+ BOOST_CHECK_THROW(SvcParam(SvcParam::port, val), std::invalid_argument);
+ BOOST_CHECK_THROW(SvcParam(SvcParam::ipv4hint, val), std::invalid_argument);
+ BOOST_CHECK_THROW(SvcParam(SvcParam::echconfig, val), std::invalid_argument);
+ BOOST_CHECK_THROW(SvcParam(SvcParam::ipv6hint, val), std::invalid_argument);
+
+ SvcParam param;
BOOST_CHECK_NO_THROW(param = SvcParam(SvcParam::keyFromString("alpn"), val));
- retval = param.getALPN();
- BOOST_CHECK_EQUAL_COLLECTIONS(retval.begin(), retval.end(), val.begin(), val.end());
+ auto alpns = param.getALPN();
+
+ BOOST_CHECK_EQUAL_COLLECTIONS(alpns.begin(), alpns.end(), val.begin(), val.end());
BOOST_CHECK_THROW(param.getMandatory(), std::invalid_argument);
BOOST_CHECK_THROW(param.getEchConfig(), std::invalid_argument);
BOOST_CHECK_THROW(param.getIPHints(), std::invalid_argument);
ComboAddress ca3("2001:db8::1");
ComboAddress ca4("2001:db8::2");
- set<ComboAddress> mixedVal({ca1, ca3});
- set<ComboAddress> v4Val({ca1, ca2});
- set<ComboAddress> v6Val({ca3, ca4});
+ vector<ComboAddress> mixedVal({ca1, ca3});
+ vector<ComboAddress> v4Val({ca1, ca2});
+ vector<ComboAddress> v6Val({ca3, ca4});
BOOST_CHECK_THROW(SvcParam(SvcParam::mandatory, v4Val), std::invalid_argument);
BOOST_CHECK_THROW(SvcParam(SvcParam::alpn, v4Val), std::invalid_argument);
BOOST_CHECK_THROW(param.getValue(), std::invalid_argument);
}
-BOOST_AUTO_TEST_SUITE_END()
\ No newline at end of file
+BOOST_AUTO_TEST_SUITE_END()