Commit dd1a3ac9 authored by Eric Orth's avatar Eric Orth Committed by Commit Bot

Update HTTPS parsing to draft-ietf-dnsop-svcb-https-01

*Allow empty alias names (indicates that a service does not exist).
*Add the "mandatory" service param. Also added an IsCompatible() method
 to indicate if any listed keys are not handled by the parser. Normally
 I would consider that level of handling to be higher level than the
 wire-format stuff the parser should deal with, but the parser is the
 code that knows what params it can handle.
*Also added some extra IP hint validation in the fuzzer while I was
 poking at it for the other changes.

Bug: 1138620
Change-Id: I8172fb5cc9b6ba06d42e6f68c2d11517115f80e2
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2508429Reviewed-by: default avatarDan McArdle <dmcardle@chromium.org>
Commit-Queue: Eric Orth <ericorth@chromium.org>
Cr-Commit-Position: refs/heads/master@{#823281}
parent 2149b10a
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
"\x00\x19" "\x00\x19"
"\x00\x1B" "\x00\x1B"
"\x00\x1C" "\x00\x1C"
"\x00\x1D"
"\x00\x1F" "\x00\x1F"
"\x00\x20" "\x00\x20"
"\x00\x21" "\x00\x21"
...@@ -100,6 +101,7 @@ ...@@ -100,6 +101,7 @@
"\x00\x41\x00\x01\x00\x00\x14\x00\x00\x03\x00\x00\x00" "\x00\x41\x00\x01\x00\x00\x14\x00\x00\x03\x00\x00\x00"
# HTTPS service params # HTTPS service params
"\x00\x00\x00\x0C\x00\x01\x00\x02\x00\x03\x00\x04\x00\x05\x00\x06"
"\x00\x01\x00\x08\x03foo\x03bar" "\x00\x01\x00\x08\x03foo\x03bar"
"\x00\x02\x00\x00" "\x00\x02\x00\x00"
"\x00\x03\x00\x02\x14\xC3" "\x00\x03\x00\x02\x14\xC3"
......
...@@ -5,8 +5,11 @@ ...@@ -5,8 +5,11 @@
#include "net/dns/https_record_rdata.h" #include "net/dns/https_record_rdata.h"
#include <stdint.h> #include <stdint.h>
#include <algorithm>
#include <map> #include <map>
#include <memory> #include <memory>
#include <set>
#include <string> #include <string>
#include <utility> #include <utility>
#include <vector> #include <vector>
...@@ -14,6 +17,7 @@ ...@@ -14,6 +17,7 @@
#include "base/big_endian.h" #include "base/big_endian.h"
#include "base/check.h" #include "base/check.h"
#include "base/dcheck_is_on.h" #include "base/dcheck_is_on.h"
#include "base/immediate_crash.h"
#include "base/memory/ptr_util.h" #include "base/memory/ptr_util.h"
#include "base/optional.h" #include "base/optional.h"
#include "base/strings/string_piece.h" #include "base/strings/string_piece.h"
...@@ -47,6 +51,33 @@ bool ReadNextServiceParam(base::Optional<uint16_t> last_key, ...@@ -47,6 +51,33 @@ bool ReadNextServiceParam(base::Optional<uint16_t> last_key,
return true; return true;
} }
bool ParseMandatoryKeys(base::StringPiece param_value,
std::set<uint16_t>* out_parsed) {
DCHECK(out_parsed);
base::BigEndianReader reader(param_value.data(), param_value.size());
std::set<uint16_t> mandatory_keys;
// Do/while to require at least one key.
do {
uint16_t key;
if (!reader.ReadU16(&key))
return false;
// Mandatory key itself is disallowed from its list.
if (key == dns_protocol::kHttpsServiceParamKeyMandatory)
return false;
// Keys required to be listed in ascending order.
if (!mandatory_keys.empty() && key <= *mandatory_keys.rbegin())
return false;
CHECK(mandatory_keys.insert(key).second);
} while (reader.remaining() > 0);
*out_parsed = std::move(mandatory_keys);
return true;
}
bool ParseAlpnIds(base::StringPiece param_value, bool ParseAlpnIds(base::StringPiece param_value,
std::vector<std::string>* out_parsed) { std::vector<std::string>* out_parsed) {
DCHECK(out_parsed); DCHECK(out_parsed);
...@@ -161,7 +192,7 @@ std::unique_ptr<AliasFormHttpsRecordRdata> AliasFormHttpsRecordRdata::Parse( ...@@ -161,7 +192,7 @@ std::unique_ptr<AliasFormHttpsRecordRdata> AliasFormHttpsRecordRdata::Parse(
base::Optional<std::string> alias_name = base::Optional<std::string> alias_name =
DnsDomainToString(reader, true /* require_complete */); DnsDomainToString(reader, true /* require_complete */);
if (!alias_name.has_value() || alias_name.value().empty()) if (!alias_name.has_value())
return nullptr; return nullptr;
if (reader.remaining() != 0) if (reader.remaining() != 0)
...@@ -186,9 +217,13 @@ bool AliasFormHttpsRecordRdata::IsAlias() const { ...@@ -186,9 +217,13 @@ bool AliasFormHttpsRecordRdata::IsAlias() const {
return true; return true;
} }
// static
constexpr uint16_t ServiceFormHttpsRecordRdata::kSupportedKeys[];
ServiceFormHttpsRecordRdata::ServiceFormHttpsRecordRdata( ServiceFormHttpsRecordRdata::ServiceFormHttpsRecordRdata(
uint16_t priority, uint16_t priority,
std::string service_name, std::string service_name,
std::set<uint16_t> mandatory_keys,
std::vector<std::string> alpn_ids, std::vector<std::string> alpn_ids,
bool default_alpn, bool default_alpn,
base::Optional<uint16_t> port, base::Optional<uint16_t> port,
...@@ -198,6 +233,7 @@ ServiceFormHttpsRecordRdata::ServiceFormHttpsRecordRdata( ...@@ -198,6 +233,7 @@ ServiceFormHttpsRecordRdata::ServiceFormHttpsRecordRdata(
std::map<uint16_t, std::string> unparsed_params) std::map<uint16_t, std::string> unparsed_params)
: priority_(priority), : priority_(priority),
service_name_(std::move(service_name)), service_name_(std::move(service_name)),
mandatory_keys_(std::move(mandatory_keys)),
alpn_ids_(std::move(alpn_ids)), alpn_ids_(std::move(alpn_ids)),
default_alpn_(default_alpn), default_alpn_(default_alpn),
port_(port), port_(port),
...@@ -206,14 +242,19 @@ ServiceFormHttpsRecordRdata::ServiceFormHttpsRecordRdata( ...@@ -206,14 +242,19 @@ ServiceFormHttpsRecordRdata::ServiceFormHttpsRecordRdata(
ipv6_hint_(std::move(ipv6_hint)), ipv6_hint_(std::move(ipv6_hint)),
unparsed_params_(std::move(unparsed_params)) { unparsed_params_(std::move(unparsed_params)) {
DCHECK_NE(priority_, 0); DCHECK_NE(priority_, 0);
DCHECK(mandatory_keys_.find(dns_protocol::kHttpsServiceParamKeyMandatory) ==
mandatory_keys_.end());
#if DCHECK_IS_ON() #if DCHECK_IS_ON()
for (const IPAddress& address : ipv4_hint) { for (const IPAddress& address : ipv4_hint_) {
DCHECK(address.IsIPv4()); DCHECK(address.IsIPv4());
} }
for (const IPAddress& address : ipv6_hint) { for (const IPAddress& address : ipv6_hint_) {
DCHECK(address.IsIPv6()); DCHECK(address.IsIPv6());
} }
for (const auto& unparsed_param : unparsed_params_) {
DCHECK(!IsSupportedKey(unparsed_param.first));
}
#endif // DCHECK_IS_ON() #endif // DCHECK_IS_ON()
} }
...@@ -229,6 +270,7 @@ bool ServiceFormHttpsRecordRdata::IsEqual(const HttpsRecordRdata* other) const { ...@@ -229,6 +270,7 @@ bool ServiceFormHttpsRecordRdata::IsEqual(const HttpsRecordRdata* other) const {
static_cast<const ServiceFormHttpsRecordRdata*>(other); static_cast<const ServiceFormHttpsRecordRdata*>(other);
return priority_ == service->priority_ && return priority_ == service->priority_ &&
service_name_ == service->service_name_ && service_name_ == service->service_name_ &&
mandatory_keys_ == service->mandatory_keys_ &&
alpn_ids_ == service->alpn_ids_ && alpn_ids_ == service->alpn_ids_ &&
default_alpn_ == service->default_alpn_ && port_ == service->port_ && default_alpn_ == service->default_alpn_ && port_ == service->port_ &&
ipv4_hint_ == service->ipv4_hint_ && ipv4_hint_ == service->ipv4_hint_ &&
...@@ -259,6 +301,7 @@ std::unique_ptr<ServiceFormHttpsRecordRdata> ServiceFormHttpsRecordRdata::Parse( ...@@ -259,6 +301,7 @@ std::unique_ptr<ServiceFormHttpsRecordRdata> ServiceFormHttpsRecordRdata::Parse(
if (reader.remaining() == 0) { if (reader.remaining() == 0) {
return std::make_unique<ServiceFormHttpsRecordRdata>( return std::make_unique<ServiceFormHttpsRecordRdata>(
priority, std::move(service_name).value(), priority, std::move(service_name).value(),
std::set<uint16_t>() /* mandatory_keys */,
std::vector<std::string>() /* alpn_ids */, true /* default_alpn */, std::vector<std::string>() /* alpn_ids */, true /* default_alpn */,
base::nullopt /* port */, std::vector<IPAddress>() /* ipv4_hint */, base::nullopt /* port */, std::vector<IPAddress>() /* ipv4_hint */,
std::string() /* ech_config */, std::string() /* ech_config */,
...@@ -272,19 +315,23 @@ std::unique_ptr<ServiceFormHttpsRecordRdata> ServiceFormHttpsRecordRdata::Parse( ...@@ -272,19 +315,23 @@ std::unique_ptr<ServiceFormHttpsRecordRdata> ServiceFormHttpsRecordRdata::Parse(
&param_value)) &param_value))
return nullptr; return nullptr;
std::map<uint16_t, std::string> unparsed_params; // Assume keys less than Mandatory are not possible.
while (param_key < dns_protocol::kHttpsServiceParamKeyAlpn) { DCHECK_GE(param_key, dns_protocol::kHttpsServiceParamKeyMandatory);
CHECK(unparsed_params
.emplace(param_key, static_cast<std::string>(param_value)) std::set<uint16_t> mandatory_keys;
.second); if (param_key == dns_protocol::kHttpsServiceParamKeyMandatory) {
if (reader.remaining() == 0) DCHECK(IsSupportedKey(param_key));
break; if (!ParseMandatoryKeys(param_value, &mandatory_keys))
if (!ReadNextServiceParam(param_key, reader, &param_key, &param_value))
return nullptr; return nullptr;
if (reader.remaining() > 0 &&
!ReadNextServiceParam(param_key, reader, &param_key, &param_value)) {
return nullptr;
}
} }
std::vector<std::string> alpn_ids; std::vector<std::string> alpn_ids;
if (param_key == dns_protocol::kHttpsServiceParamKeyAlpn) { if (param_key == dns_protocol::kHttpsServiceParamKeyAlpn) {
DCHECK(IsSupportedKey(param_key));
if (!ParseAlpnIds(param_value, &alpn_ids)) if (!ParseAlpnIds(param_value, &alpn_ids))
return nullptr; return nullptr;
if (reader.remaining() > 0 && if (reader.remaining() > 0 &&
...@@ -295,6 +342,7 @@ std::unique_ptr<ServiceFormHttpsRecordRdata> ServiceFormHttpsRecordRdata::Parse( ...@@ -295,6 +342,7 @@ std::unique_ptr<ServiceFormHttpsRecordRdata> ServiceFormHttpsRecordRdata::Parse(
bool default_alpn = true; bool default_alpn = true;
if (param_key == dns_protocol::kHttpsServiceParamKeyNoDefaultAlpn) { if (param_key == dns_protocol::kHttpsServiceParamKeyNoDefaultAlpn) {
DCHECK(IsSupportedKey(param_key));
if (!param_value.empty()) if (!param_value.empty())
return nullptr; return nullptr;
default_alpn = false; default_alpn = false;
...@@ -306,6 +354,7 @@ std::unique_ptr<ServiceFormHttpsRecordRdata> ServiceFormHttpsRecordRdata::Parse( ...@@ -306,6 +354,7 @@ std::unique_ptr<ServiceFormHttpsRecordRdata> ServiceFormHttpsRecordRdata::Parse(
base::Optional<uint16_t> port; base::Optional<uint16_t> port;
if (param_key == dns_protocol::kHttpsServiceParamKeyPort) { if (param_key == dns_protocol::kHttpsServiceParamKeyPort) {
DCHECK(IsSupportedKey(param_key));
if (param_value.size() != 2) if (param_value.size() != 2)
return nullptr; return nullptr;
uint16_t port_val; uint16_t port_val;
...@@ -319,6 +368,7 @@ std::unique_ptr<ServiceFormHttpsRecordRdata> ServiceFormHttpsRecordRdata::Parse( ...@@ -319,6 +368,7 @@ std::unique_ptr<ServiceFormHttpsRecordRdata> ServiceFormHttpsRecordRdata::Parse(
std::vector<IPAddress> ipv4_hint; std::vector<IPAddress> ipv4_hint;
if (param_key == dns_protocol::kHttpsServiceParamKeyIpv4Hint) { if (param_key == dns_protocol::kHttpsServiceParamKeyIpv4Hint) {
DCHECK(IsSupportedKey(param_key));
if (!ParseIpAddresses<IPAddress::kIPv4AddressSize>(param_value, &ipv4_hint)) if (!ParseIpAddresses<IPAddress::kIPv4AddressSize>(param_value, &ipv4_hint))
return nullptr; return nullptr;
if (reader.remaining() > 0 && if (reader.remaining() > 0 &&
...@@ -329,6 +379,7 @@ std::unique_ptr<ServiceFormHttpsRecordRdata> ServiceFormHttpsRecordRdata::Parse( ...@@ -329,6 +379,7 @@ std::unique_ptr<ServiceFormHttpsRecordRdata> ServiceFormHttpsRecordRdata::Parse(
std::string ech_config; std::string ech_config;
if (param_key == dns_protocol::kHttpsServiceParamKeyEchConfig) { if (param_key == dns_protocol::kHttpsServiceParamKeyEchConfig) {
DCHECK(IsSupportedKey(param_key));
ech_config = std::string(param_value.data(), param_value.size()); ech_config = std::string(param_value.data(), param_value.size());
if (reader.remaining() > 0 && if (reader.remaining() > 0 &&
!ReadNextServiceParam(param_key, reader, &param_key, &param_value)) { !ReadNextServiceParam(param_key, reader, &param_key, &param_value)) {
...@@ -338,6 +389,7 @@ std::unique_ptr<ServiceFormHttpsRecordRdata> ServiceFormHttpsRecordRdata::Parse( ...@@ -338,6 +389,7 @@ std::unique_ptr<ServiceFormHttpsRecordRdata> ServiceFormHttpsRecordRdata::Parse(
std::vector<IPAddress> ipv6_hint; std::vector<IPAddress> ipv6_hint;
if (param_key == dns_protocol::kHttpsServiceParamKeyIpv6Hint) { if (param_key == dns_protocol::kHttpsServiceParamKeyIpv6Hint) {
DCHECK(IsSupportedKey(param_key));
if (!ParseIpAddresses<IPAddress::kIPv6AddressSize>(param_value, &ipv6_hint)) if (!ParseIpAddresses<IPAddress::kIPv6AddressSize>(param_value, &ipv6_hint))
return nullptr; return nullptr;
if (reader.remaining() > 0 && if (reader.remaining() > 0 &&
...@@ -348,8 +400,10 @@ std::unique_ptr<ServiceFormHttpsRecordRdata> ServiceFormHttpsRecordRdata::Parse( ...@@ -348,8 +400,10 @@ std::unique_ptr<ServiceFormHttpsRecordRdata> ServiceFormHttpsRecordRdata::Parse(
// Note that if parsing has already reached the end of the rdata, `param_key` // Note that if parsing has already reached the end of the rdata, `param_key`
// is still set for whatever param was read last. // is still set for whatever param was read last.
std::map<uint16_t, std::string> unparsed_params;
if (param_key > dns_protocol::kHttpsServiceParamKeyIpv6Hint) { if (param_key > dns_protocol::kHttpsServiceParamKeyIpv6Hint) {
for (;;) { for (;;) {
DCHECK(!IsSupportedKey(param_key));
CHECK(unparsed_params CHECK(unparsed_params
.emplace(param_key, static_cast<std::string>(param_value)) .emplace(param_key, static_cast<std::string>(param_value))
.second); .second);
...@@ -361,9 +415,40 @@ std::unique_ptr<ServiceFormHttpsRecordRdata> ServiceFormHttpsRecordRdata::Parse( ...@@ -361,9 +415,40 @@ std::unique_ptr<ServiceFormHttpsRecordRdata> ServiceFormHttpsRecordRdata::Parse(
} }
return std::make_unique<ServiceFormHttpsRecordRdata>( return std::make_unique<ServiceFormHttpsRecordRdata>(
priority, std::move(service_name).value(), std::move(alpn_ids), priority, std::move(service_name).value(), std::move(mandatory_keys),
default_alpn, port, std::move(ipv4_hint), std::move(ech_config), std::move(alpn_ids), default_alpn, port, std::move(ipv4_hint),
std::move(ipv6_hint), std::move(unparsed_params)); std::move(ech_config), std::move(ipv6_hint), std::move(unparsed_params));
}
bool ServiceFormHttpsRecordRdata::IsCompatible() const {
std::set<uint16_t> supported_keys(std::begin(kSupportedKeys),
std::end(kSupportedKeys));
for (uint16_t mandatory_key : mandatory_keys_) {
DCHECK_NE(mandatory_key, dns_protocol::kHttpsServiceParamKeyMandatory);
if (supported_keys.find(mandatory_key) == supported_keys.end())
return false;
}
#if DCHECK_IS_ON()
for (const auto& unparsed_param : unparsed_params_) {
DCHECK(mandatory_keys_.find(unparsed_param.first) == mandatory_keys_.end());
}
#endif // DCHECK_IS_ON()
return true;
}
// static
bool ServiceFormHttpsRecordRdata::IsSupportedKey(uint16_t key) {
#if DCHECK_IS_ON()
return std::find(std::begin(kSupportedKeys), std::end(kSupportedKeys), key) !=
std::end(kSupportedKeys);
#else
// Only intended for DCHECKs.
IMMEDIATE_CRASH();
#endif // DCHECK_IS_ON()
} }
} // namespace net } // namespace net
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include <stdint.h> #include <stdint.h>
#include <map> #include <map>
#include <memory> #include <memory>
#include <set>
#include <string> #include <string>
#include <vector> #include <vector>
...@@ -57,7 +58,7 @@ class NET_EXPORT_PRIVATE AliasFormHttpsRecordRdata : public HttpsRecordRdata { ...@@ -57,7 +58,7 @@ class NET_EXPORT_PRIVATE AliasFormHttpsRecordRdata : public HttpsRecordRdata {
bool IsEqual(const HttpsRecordRdata* other) const override; bool IsEqual(const HttpsRecordRdata* other) const override;
bool IsAlias() const override; bool IsAlias() const override;
base::StringPiece alias_name() { return alias_name_; } base::StringPiece alias_name() const { return alias_name_; }
private: private:
AliasFormHttpsRecordRdata() = default; AliasFormHttpsRecordRdata() = default;
...@@ -67,8 +68,18 @@ class NET_EXPORT_PRIVATE AliasFormHttpsRecordRdata : public HttpsRecordRdata { ...@@ -67,8 +68,18 @@ class NET_EXPORT_PRIVATE AliasFormHttpsRecordRdata : public HttpsRecordRdata {
class NET_EXPORT_PRIVATE ServiceFormHttpsRecordRdata : public HttpsRecordRdata { class NET_EXPORT_PRIVATE ServiceFormHttpsRecordRdata : public HttpsRecordRdata {
public: public:
static constexpr uint16_t kSupportedKeys[] = {
dns_protocol::kHttpsServiceParamKeyMandatory,
dns_protocol::kHttpsServiceParamKeyAlpn,
dns_protocol::kHttpsServiceParamKeyNoDefaultAlpn,
dns_protocol::kHttpsServiceParamKeyPort,
dns_protocol::kHttpsServiceParamKeyIpv4Hint,
dns_protocol::kHttpsServiceParamKeyEchConfig,
dns_protocol::kHttpsServiceParamKeyIpv6Hint};
ServiceFormHttpsRecordRdata(uint16_t priority, ServiceFormHttpsRecordRdata(uint16_t priority,
std::string service_name, std::string service_name,
std::set<uint16_t> mandatory_keys,
std::vector<std::string> alpn_ids, std::vector<std::string> alpn_ids,
bool default_alpn, bool default_alpn,
base::Optional<uint16_t> port, base::Optional<uint16_t> port,
...@@ -84,23 +95,33 @@ class NET_EXPORT_PRIVATE ServiceFormHttpsRecordRdata : public HttpsRecordRdata { ...@@ -84,23 +95,33 @@ class NET_EXPORT_PRIVATE ServiceFormHttpsRecordRdata : public HttpsRecordRdata {
bool IsEqual(const HttpsRecordRdata* other) const override; bool IsEqual(const HttpsRecordRdata* other) const override;
bool IsAlias() const override; bool IsAlias() const override;
uint16_t priority() { return priority_; } uint16_t priority() const { return priority_; }
base::StringPiece service_name() { return service_name_; } base::StringPiece service_name() const { return service_name_; }
const std::vector<std::string>& alpn_ids() { return alpn_ids_; } const std::set<uint16_t>& mandatory_keys() const { return mandatory_keys_; }
bool default_alpn() { return default_alpn_; } const std::vector<std::string>& alpn_ids() const { return alpn_ids_; }
base::Optional<uint16_t> port() { return port_; } bool default_alpn() const { return default_alpn_; }
const std::vector<IPAddress>& ipv4_hint() { return ipv4_hint_; } base::Optional<uint16_t> port() const { return port_; }
base::StringPiece ech_config() { return ech_config_; } const std::vector<IPAddress>& ipv4_hint() const { return ipv4_hint_; }
const std::vector<IPAddress>& ipv6_hint() { return ipv6_hint_; } base::StringPiece ech_config() const { return ech_config_; }
const std::map<uint16_t, std::string>& unparsed_params() { const std::vector<IPAddress>& ipv6_hint() const { return ipv6_hint_; }
const std::map<uint16_t, std::string>& unparsed_params() const {
return unparsed_params_; return unparsed_params_;
} }
// Returns whether or not this rdata parser is considered "compatible" with
// the parsed rdata. That is that all keys listed by mandatory_keys() (and all
// keys considered default mandatory for HTTPS records) are parsable by this
// parser.
bool IsCompatible() const;
private: private:
static bool IsSupportedKey(uint16_t key);
const uint16_t priority_; const uint16_t priority_;
const std::string service_name_; const std::string service_name_;
// Supported service parameters. // Supported service parameters.
const std::set<uint16_t> mandatory_keys_;
const std::vector<std::string> alpn_ids_; const std::vector<std::string> alpn_ids_;
const bool default_alpn_; const bool default_alpn_;
const base::Optional<uint16_t> port_; const base::Optional<uint16_t> port_;
......
...@@ -7,9 +7,12 @@ ...@@ -7,9 +7,12 @@
#include <stdint.h> #include <stdint.h>
#include <memory> #include <memory>
#include <set>
#include <vector>
#include "base/check.h" #include "base/check.h"
#include "base/strings/string_piece.h" #include "base/strings/string_piece.h"
#include "net/base/ip_address.h"
#include "net/dns/public/dns_protocol.h" #include "net/dns/public/dns_protocol.h"
namespace net { namespace net {
...@@ -30,7 +33,7 @@ void ParseAndExercise(base::StringPiece data) { ...@@ -30,7 +33,7 @@ void ParseAndExercise(base::StringPiece data) {
CHECK_EQ(parsed->Type(), dns_protocol::kTypeHttps); CHECK_EQ(parsed->Type(), dns_protocol::kTypeHttps);
if (parsed->IsAlias()) { if (parsed->IsAlias()) {
AliasFormHttpsRecordRdata* alias = parsed->AsAliasForm(); AliasFormHttpsRecordRdata* alias = parsed->AsAliasForm();
CHECK(!alias->alias_name().empty()); alias->alias_name();
} else { } else {
ServiceFormHttpsRecordRdata* service = parsed->AsServiceForm(); ServiceFormHttpsRecordRdata* service = parsed->AsServiceForm();
CHECK_GT(service->priority(), 0); CHECK_GT(service->priority(), 0);
...@@ -38,10 +41,23 @@ void ParseAndExercise(base::StringPiece data) { ...@@ -38,10 +41,23 @@ void ParseAndExercise(base::StringPiece data) {
service->alpn_ids(); service->alpn_ids();
service->default_alpn(); service->default_alpn();
service->port(); service->port();
service->ipv4_hint();
service->ech_config(); service->ech_config();
service->ipv6_hint();
service->unparsed_params(); service->unparsed_params();
service->IsCompatible();
std::set<uint16_t> mandatory_keys = service->mandatory_keys();
CHECK(mandatory_keys.find(dns_protocol::kHttpsServiceParamKeyMandatory) ==
mandatory_keys.end());
std::vector<IPAddress> ipv4_hint = service->ipv4_hint();
for (const IPAddress& address : ipv4_hint) {
CHECK(address.IsIPv4());
}
std::vector<IPAddress> ipv6_hint = service->ipv6_hint();
for (const IPAddress& address : ipv6_hint) {
CHECK(address.IsIPv6());
}
} }
} }
......
...@@ -43,6 +43,8 @@ TEST(HttpsRecordRdataTest, ParsesService) { ...@@ -43,6 +43,8 @@ TEST(HttpsRecordRdataTest, ParsesService) {
"\000\001" "\000\001"
// Service name: chromium.org // Service name: chromium.org
"\010chromium\003org\000" "\010chromium\003org\000"
// mandatory=alpn,no-default-alpn,port,ipv4hint,echconfig,ipv6hint
"\000\000\000\014\000\001\000\002\000\003\000\004\000\005\000\006"
// alpn=foo,bar // alpn=foo,bar
"\000\001\000\010\003foo\003bar" "\000\001\000\010\003foo\003bar"
// no-default-alpn // no-default-alpn
...@@ -66,7 +68,7 @@ TEST(HttpsRecordRdataTest, ParsesService) { ...@@ -66,7 +68,7 @@ TEST(HttpsRecordRdataTest, ParsesService) {
IPAddress expected_ipv6; IPAddress expected_ipv6;
ASSERT_TRUE(expected_ipv6.AssignFromIPLiteral("2001:4860:4860::8888")); ASSERT_TRUE(expected_ipv6.AssignFromIPLiteral("2001:4860:4860::8888"));
ServiceFormHttpsRecordRdata expected( ServiceFormHttpsRecordRdata expected(
1 /* priority */, "chromium.org", 1 /* priority */, "chromium.org", std::set<uint16_t>({1, 2, 3, 4, 5, 6}),
std::vector<std::string>({"foo", "bar"}) /* alpn_ids */, std::vector<std::string>({"foo", "bar"}) /* alpn_ids */,
false /* default_alpn */, base::Optional<uint16_t>(46) /* port */, false /* default_alpn */, base::Optional<uint16_t>(46) /* port */,
std::vector<IPAddress>({IPAddress(8, 8, 8, 8)}) /* ipv4_hint */, std::vector<IPAddress>({IPAddress(8, 8, 8, 8)}) /* ipv4_hint */,
...@@ -80,6 +82,8 @@ TEST(HttpsRecordRdataTest, ParsesService) { ...@@ -80,6 +82,8 @@ TEST(HttpsRecordRdataTest, ParsesService) {
ASSERT_TRUE(service_rdata); ASSERT_TRUE(service_rdata);
EXPECT_EQ(service_rdata->priority(), 1); EXPECT_EQ(service_rdata->priority(), 1);
EXPECT_EQ(service_rdata->service_name(), "chromium.org"); EXPECT_EQ(service_rdata->service_name(), "chromium.org");
EXPECT_THAT(service_rdata->mandatory_keys(),
testing::ElementsAre(1, 2, 3, 4, 5, 6));
EXPECT_THAT(service_rdata->alpn_ids(), testing::ElementsAre("foo", "bar")); EXPECT_THAT(service_rdata->alpn_ids(), testing::ElementsAre("foo", "bar"));
EXPECT_FALSE(service_rdata->default_alpn()); EXPECT_FALSE(service_rdata->default_alpn());
EXPECT_THAT(service_rdata->port(), testing::Optional(46)); EXPECT_THAT(service_rdata->port(), testing::Optional(46));
...@@ -89,6 +93,7 @@ TEST(HttpsRecordRdataTest, ParsesService) { ...@@ -89,6 +93,7 @@ TEST(HttpsRecordRdataTest, ParsesService) {
EXPECT_THAT(service_rdata->ipv6_hint(), testing::ElementsAre(expected_ipv6)); EXPECT_THAT(service_rdata->ipv6_hint(), testing::ElementsAre(expected_ipv6));
EXPECT_THAT(service_rdata->unparsed_params(), EXPECT_THAT(service_rdata->unparsed_params(),
testing::ElementsAre(testing::Pair(7, "foo"))); testing::ElementsAre(testing::Pair(7, "foo")));
EXPECT_TRUE(service_rdata->IsCompatible());
} }
TEST(HttpsRecordRdataTest, RejectCorruptRdata) { TEST(HttpsRecordRdataTest, RejectCorruptRdata) {
......
...@@ -189,7 +189,8 @@ static const uint16_t kFlagTC = 0x200; // Truncated - server flag. ...@@ -189,7 +189,8 @@ static const uint16_t kFlagTC = 0x200; // Truncated - server flag.
// SVCB/HTTPS ServiceParamKey // SVCB/HTTPS ServiceParamKey
// //
// IANA registration pending. Values from draft-ietf-dnsop-svcb-httpssvc-03. // IANA registration pending. Values from draft-ietf-dnsop-svcb-https-01.
static constexpr uint16_t kHttpsServiceParamKeyMandatory = 0;
static constexpr uint16_t kHttpsServiceParamKeyAlpn = 1; static constexpr uint16_t kHttpsServiceParamKeyAlpn = 1;
static constexpr uint16_t kHttpsServiceParamKeyNoDefaultAlpn = 2; static constexpr uint16_t kHttpsServiceParamKeyNoDefaultAlpn = 2;
static constexpr uint16_t kHttpsServiceParamKeyPort = 3; static constexpr uint16_t kHttpsServiceParamKeyPort = 3;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment