Creating Subclasses of Opt to hold different Opt records.
Currently, the Opt class holds an Opt record without a dedicated
subclass. This CL involves creating a subclass of Opt for each specific
Opt record, along with an UnknownOpt subclass to contain Opt records
without a specific subclass, as well as making Opt an abstract class.
Bug: 1347517
Change-Id: Iccdbac2fdc1b3c54e2f6ade2c6e4a6217722c3bd
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3821163
Commit-Queue: Sukrit Ganesh <sukritganesh@google.com>
Reviewed-by: Dan McArdle <dmcardle@chromium.org>
Reviewed-by: Eric Orth <ericorth@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1035523}
diff --git a/net/dns/dns_query.cc b/net/dns/dns_query.cc
index d1aab2b..01d7bab 100644
--- a/net/dns/dns_query.cc
+++ b/net/dns/dns_query.cc
@@ -87,11 +87,8 @@
// OPT header is the minimum amount of padding.
DCHECK(padding_size >= OptRecordRdata::Opt::kHeaderSize);
- std::unique_ptr<OptRecordRdata::Opt> opt =
- std::make_unique<OptRecordRdata::Opt>(
- dns_protocol::kEdnsPadding,
- std::string(padding_size - OptRecordRdata::Opt::kHeaderSize, 0));
- merged_opt_rdata->AddOpt(std::move(opt));
+ merged_opt_rdata->AddOpt(std::make_unique<OptRecordRdata::PaddingOpt>(
+ padding_size - OptRecordRdata::Opt::kHeaderSize));
}
return merged_opt_rdata;
diff --git a/net/dns/dns_query_unittest.cc b/net/dns/dns_query_unittest.cc
index 010140f7..b09d6c8 100644
--- a/net/dns/dns_query_unittest.cc
+++ b/net/dns/dns_query_unittest.cc
@@ -124,7 +124,7 @@
base::StringPiece qname(kQNameData, sizeof(kQNameData));
OptRecordRdata opt_rdata;
opt_rdata.AddOpt(
- std::make_unique<OptRecordRdata::Opt>(255, "\xde\xad\xbe\xef"));
+ OptRecordRdata::UnknownOpt::CreateForTesting(255, "\xde\xad\xbe\xef"));
DnsQuery q1(0xbeef, qname, dns_protocol::kTypeA, &opt_rdata);
EXPECT_EQ(dns_protocol::kTypeA, q1.qtype());
diff --git a/net/dns/dns_response_unittest.cc b/net/dns/dns_response_unittest.cc
index e68a204..6908103b 100644
--- a/net/dns/dns_response_unittest.cc
+++ b/net/dns/dns_response_unittest.cc
@@ -1322,7 +1322,7 @@
OptRecordRdata opt_rdata;
opt_rdata.AddOpt(
- std::make_unique<OptRecordRdata::Opt>(255, "\xde\xad\xbe\xef"));
+ OptRecordRdata::UnknownOpt::CreateForTesting(255, "\xde\xad\xbe\xef"));
absl::optional<DnsQuery> query;
query.emplace(0x1234 /* id */, dns_name, dns_protocol::kTypeA, &opt_rdata);
diff --git a/net/dns/dns_transaction_unittest.cc b/net/dns/dns_transaction_unittest.cc
index a4f9d37..db7bfd9 100644
--- a/net/dns/dns_transaction_unittest.cc
+++ b/net/dns/dns_transaction_unittest.cc
@@ -983,9 +983,9 @@
OptRecordRdata expected_opt_rdata;
transaction_factory_->AddEDNSOption(
- std::make_unique<OptRecordRdata::Opt>(123, "\xbe\xef"));
+ OptRecordRdata::UnknownOpt::CreateForTesting(123, "\xbe\xef"));
expected_opt_rdata.AddOpt(
- std::make_unique<OptRecordRdata::Opt>(123, "\xbe\xef"));
+ OptRecordRdata::UnknownOpt::CreateForTesting(123, "\xbe\xef"));
AddAsyncQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype,
kT0ResponseDatagram, std::size(kT0ResponseDatagram),
@@ -1009,9 +1009,10 @@
for (auto& param : params) {
transaction_factory_->AddEDNSOption(
- std::make_unique<OptRecordRdata::Opt>(param.first, param.second));
- expected_opt_rdata.AddOpt(
- std::make_unique<OptRecordRdata::Opt>(param.first, param.second));
+ OptRecordRdata::UnknownOpt::CreateForTesting(param.first,
+ param.second));
+ expected_opt_rdata.AddOpt(OptRecordRdata::UnknownOpt::CreateForTesting(
+ param.first, param.second));
}
AddAsyncQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype,
diff --git a/net/dns/opt_record_rdata.cc b/net/dns/opt_record_rdata.cc
index 6cca6f1..cb4fe256 100644
--- a/net/dns/opt_record_rdata.cc
+++ b/net/dns/opt_record_rdata.cc
@@ -5,17 +5,18 @@
#include "net/dns/opt_record_rdata.h"
#include <algorithm>
+#include <memory>
#include <numeric>
#include <utility>
#include "base/big_endian.h"
-#include "base/check_op.h"
+#include "base/check_is_test.h"
+#include "base/containers/contains.h"
#include "base/memory/ptr_util.h"
+#include "base/numerics/safe_conversions.h"
#include "base/strings/string_piece.h"
#include "base/strings/string_util.h"
-#include "net/base/io_buffer.h"
-#include "net/dns/dns_response.h"
-#include "third_party/abseil-cpp/absl/types/optional.h"
+#include "net/dns/public/dns_protocol.h"
namespace net {
@@ -30,8 +31,7 @@
}
} // namespace
-OptRecordRdata::Opt::Opt(uint16_t code, std::string data)
- : code_(code), data_(std::move(data)) {}
+OptRecordRdata::Opt::Opt(std::string data) : data_(std::move(data)) {}
bool OptRecordRdata::Opt::operator==(const OptRecordRdata::Opt& other) const {
return IsEqual(other);
@@ -42,11 +42,11 @@
}
bool OptRecordRdata::Opt::IsEqual(const OptRecordRdata::Opt& other) const {
- return code_ == other.code_ && data() == other.data();
+ return GetCode() == other.GetCode() && data() == other.data();
}
OptRecordRdata::EdeOpt::EdeOpt(uint16_t info_code, std::string extra_text)
- : Opt(EdeOpt::kOptCode, SerializeEdeOpt(info_code, extra_text)),
+ : Opt(SerializeEdeOpt(info_code, extra_text)),
info_code_(info_code),
extra_text_(std::move(extra_text)) {
CHECK(base::IsStringUTF8(extra_text_));
@@ -74,6 +74,10 @@
return std::make_unique<EdeOpt>(info_code, std::move(extra_text_str));
}
+uint16_t OptRecordRdata::EdeOpt::GetCode() const {
+ return EdeOpt::kOptCode;
+}
+
OptRecordRdata::EdeOpt::EdeInfoCode
OptRecordRdata::EdeOpt::GetEnumFromInfoCode() const {
return GetEnumFromInfoCode(info_code_);
@@ -143,7 +147,35 @@
}
}
-OptRecordRdata::EdeOpt::EdeOpt() = default;
+OptRecordRdata::PaddingOpt::PaddingOpt(std::string padding)
+ : Opt(std::move(padding)) {}
+
+OptRecordRdata::PaddingOpt::PaddingOpt(uint16_t padding_len)
+ : Opt(std::string(base::checked_cast<size_t>(padding_len), '\0')) {}
+
+OptRecordRdata::PaddingOpt::~PaddingOpt() = default;
+
+uint16_t OptRecordRdata::PaddingOpt::GetCode() const {
+ return PaddingOpt::kOptCode;
+}
+
+OptRecordRdata::UnknownOpt::~UnknownOpt() = default;
+
+std::unique_ptr<OptRecordRdata::UnknownOpt>
+OptRecordRdata::UnknownOpt::CreateForTesting(uint16_t code, std::string data) {
+ CHECK_IS_TEST();
+ return base::WrapUnique(
+ new OptRecordRdata::UnknownOpt(code, std::move(data)));
+}
+
+OptRecordRdata::UnknownOpt::UnknownOpt(uint16_t code, std::string data)
+ : Opt(std::move(data)), code_(code) {
+ CHECK(!base::Contains(kOptsWithDedicatedClasses, code));
+}
+
+uint16_t OptRecordRdata::UnknownOpt::GetCode() const {
+ return code_;
+}
OptRecordRdata::OptRecordRdata() = default;
@@ -181,11 +213,17 @@
std::unique_ptr<Opt> opt;
- if (opt_code == dns_protocol::kEdnsExtendedDnsError) {
- opt = OptRecordRdata::EdeOpt::Create(std::move(opt_data));
- } else {
- opt =
- std::make_unique<OptRecordRdata::Opt>(opt_code, std::move(opt_data));
+ switch (opt_code) {
+ case dns_protocol::kEdnsPadding:
+ opt = std::make_unique<OptRecordRdata::PaddingOpt>(std::move(opt_data));
+ break;
+ case dns_protocol::kEdnsExtendedDnsError:
+ opt = OptRecordRdata::EdeOpt::Create(std::move(opt_data));
+ break;
+ default:
+ opt = base::WrapUnique(
+ new OptRecordRdata::UnknownOpt(opt_code, std::move(opt_data)));
+ break;
}
// Confirm that opt is not null, which would be the result of a failed
@@ -205,8 +243,9 @@
}
bool OptRecordRdata::IsEqual(const RecordRdata* other) const {
- if (other->Type() != Type())
+ if (other->Type() != Type()) {
return false;
+ }
const OptRecordRdata* opt_other = static_cast<const OptRecordRdata*>(other);
return opt_other->buf_ == buf_;
}
@@ -221,12 +260,12 @@
// Start writing from the end of the existing rdata.
base::BigEndianWriter writer(buf_.data(), buf_.size());
CHECK(writer.Skip(orig_rdata_size));
- bool success = writer.WriteU16(opt->code()) &&
+ bool success = writer.WriteU16(opt->GetCode()) &&
writer.WriteU16(opt_data.size()) &&
writer.WriteBytes(opt_data.data(), opt_data.size());
DCHECK(success);
- opts_.emplace(opt->code(), std::move(opt));
+ opts_.emplace(opt->GetCode(), std::move(opt));
}
bool OptRecordRdata::ContainsOptCode(uint16_t opt_code) const {
@@ -242,6 +281,16 @@
return opts;
}
+std::vector<const OptRecordRdata::PaddingOpt*> OptRecordRdata::GetPaddingOpts()
+ const {
+ std::vector<const OptRecordRdata::PaddingOpt*> opts;
+ auto range = opts_.equal_range(dns_protocol::kEdnsPadding);
+ for (auto it = range.first; it != range.second; ++it) {
+ opts.push_back(static_cast<const PaddingOpt*>(it->second.get()));
+ }
+ return opts;
+}
+
std::vector<const OptRecordRdata::EdeOpt*> OptRecordRdata::GetEdeOpts() const {
std::vector<const OptRecordRdata::EdeOpt*> opts;
auto range = opts_.equal_range(dns_protocol::kEdnsExtendedDnsError);
diff --git a/net/dns/opt_record_rdata.h b/net/dns/opt_record_rdata.h
index 14de53a..9c7c4bfb3 100644
--- a/net/dns/opt_record_rdata.h
+++ b/net/dns/opt_record_rdata.h
@@ -12,8 +12,6 @@
#include <string>
#include <vector>
-#include "base/compiler_specific.h"
-#include "base/logging.h"
#include "base/strings/string_piece.h"
#include "net/base/net_export.h"
#include "net/dns/public/dns_protocol.h"
@@ -24,12 +22,14 @@
// OPT record format (https://tools.ietf.org/html/rfc6891):
class NET_EXPORT_PRIVATE OptRecordRdata : public RecordRdata {
public:
+ static std::unique_ptr<OptRecordRdata> Create(base::StringPiece data);
+
class NET_EXPORT_PRIVATE Opt {
public:
static constexpr size_t kHeaderSize = 4; // sizeof(code) + sizeof(size)
- Opt() = default;
- Opt(uint16_t code, std::string data);
+ Opt() = delete;
+ explicit Opt(std::string data);
Opt(const Opt& other) = delete;
Opt& operator=(const Opt& other) = delete;
@@ -40,12 +40,11 @@
bool operator==(const Opt& other) const;
bool operator!=(const Opt& other) const;
- uint16_t code() const { return code_; }
+ virtual uint16_t GetCode() const = 0;
base::StringPiece data() const { return data_; }
private:
bool IsEqual(const Opt& other) const;
- uint16_t code_;
std::string data_;
};
@@ -100,6 +99,7 @@
// Attempts to parse an EDE option from `data`. Returns nullptr on failure.
static std::unique_ptr<EdeOpt> Create(std::string data);
+ uint16_t GetCode() const override;
uint16_t info_code() const { return info_code_; }
base::StringPiece extra_text() const { return extra_text_; }
@@ -115,6 +115,60 @@
std::string extra_text_;
};
+ class NET_EXPORT_PRIVATE PaddingOpt : public Opt {
+ public:
+ static const uint16_t kOptCode = dns_protocol::kEdnsPadding;
+
+ PaddingOpt() = delete;
+ // Construct a PaddingOpt with the specified padding string.
+ explicit PaddingOpt(std::string padding);
+ // Constructs PaddingOpt with '\0' character padding of specified length.
+ // Note: This padding_len only specifies the length of the data section.
+ // Users must take into account the header length `Opt::kHeaderSize`
+ explicit PaddingOpt(uint16_t padding_len);
+
+ PaddingOpt(const PaddingOpt& other) = delete;
+ PaddingOpt& operator=(const PaddingOpt& other) = delete;
+ PaddingOpt(PaddingOpt&& other) = delete;
+ PaddingOpt& operator=(PaddingOpt&& other) = delete;
+ ~PaddingOpt() override;
+
+ uint16_t GetCode() const override;
+ };
+
+ class NET_EXPORT_PRIVATE UnknownOpt : public Opt {
+ public:
+ UnknownOpt() = delete;
+ UnknownOpt(const UnknownOpt& other) = delete;
+ UnknownOpt& operator=(const UnknownOpt& other) = delete;
+ UnknownOpt(UnknownOpt&& other) = delete;
+ UnknownOpt& operator=(UnknownOpt&& other) = delete;
+ ~UnknownOpt() override;
+
+ // Create UnknownOpt with option code and data.
+ // Cannot instantiate UnknownOpt directly in order to prevent Opt with
+ // dedicated class class (ex. EdeOpt) from being stored in UnknownOpt.
+ // object.
+ // This method must purely be used for testing.
+ // Only the parser can instantiate an UnknownOpt object (via friend
+ // classes).
+ static std::unique_ptr<UnknownOpt> CreateForTesting(uint16_t code,
+ std::string data);
+
+ uint16_t GetCode() const override;
+
+ private:
+ UnknownOpt(uint16_t code, std::string data);
+
+ uint16_t code_;
+
+ friend std::unique_ptr<OptRecordRdata> OptRecordRdata::Create(
+ base::StringPiece data);
+ };
+
+ static constexpr uint16_t kOptsWithDedicatedClasses[] = {
+ dns_protocol::kEdnsPadding, dns_protocol::kEdnsExtendedDnsError};
+
static const uint16_t kType = dns_protocol::kTypeOPT;
OptRecordRdata();
@@ -130,8 +184,6 @@
bool operator==(const RecordRdata& other) const;
bool operator!=(const RecordRdata& other) const;
- static std::unique_ptr<OptRecordRdata> Create(base::StringPiece data);
-
// Checks whether two OptRecordRdata objects are equal. This comparison takes
// into account the order of insertion. Two OptRecordRdata objects with
// identical Opt records inserted in a different order will not be equal.
@@ -159,6 +211,9 @@
// Returns all EDE options in insertion order.
std::vector<const EdeOpt*> GetEdeOpts() const;
+ // Returns all Padding options in insertion order.
+ std::vector<const PaddingOpt*> GetPaddingOpts() const;
+
private:
// Opt objects are stored in a multimap; key is the opt code.
std::multimap<uint16_t, const std::unique_ptr<const Opt>> opts_;
diff --git a/net/dns/opt_record_rdata_unittest.cc b/net/dns/opt_record_rdata_unittest.cc
index 426560b8..7745bbcb 100644
--- a/net/dns/opt_record_rdata_unittest.cc
+++ b/net/dns/opt_record_rdata_unittest.cc
@@ -61,10 +61,15 @@
// character will be truncated.
// https://crbug.com/1348679
- ASSERT_EQ(*(rdata_obj->GetOpts()[0]),
- OptRecordRdata::Opt(1, std::string("\xde\xad", 2)));
- ASSERT_EQ(*(rdata_obj->GetOpts()[1]),
- OptRecordRdata::Opt(255, std::string("\xde\xad\xbe\xef", 4)));
+ std::unique_ptr<OptRecordRdata::UnknownOpt> opt0 =
+ OptRecordRdata::UnknownOpt::CreateForTesting(1,
+ std::string("\xde\xad", 2));
+ std::unique_ptr<OptRecordRdata::UnknownOpt> opt1 =
+ OptRecordRdata::UnknownOpt::CreateForTesting(
+ 255, std::string("\xde\xad\xbe\xef", 4));
+
+ ASSERT_EQ(*(rdata_obj->GetOpts()[0]), *(opt0.get()));
+ ASSERT_EQ(*(rdata_obj->GetOpts()[1]), *(opt1.get()));
}
TEST(OptRecordRdataTest, ParseOptRecordWithShorterSizeThanData) {
@@ -101,19 +106,25 @@
ASSERT_THAT(rdata_obj, IsNull());
}
-TEST(OptRecordRdataTest, AddOptToOptRecord) {
- // This is just the rdata portion of an OPT record, rather than a complete
- // record.
- const uint8_t expected_rdata[] = {
- 0x00, 0xFF, // OPT code
- 0x00, 0x04, // OPT data size
- 0xDE, 0xAD, 0xBE, 0xEF // OPT data
- };
+TEST(OptRecordRdataTest, CreateEdeOpt) {
+ OptRecordRdata::EdeOpt opt0(22, std::string("Don Quixote"));
- OptRecordRdata rdata;
- rdata.AddOpt(std::make_unique<OptRecordRdata::Opt>(
- 255, std::string("\xde\xad\xbe\xef", 4)));
- EXPECT_THAT(rdata.buf(), ElementsAreArray(expected_rdata));
+ ASSERT_EQ(opt0.data(), std::string("\x00\x16"
+ "Don Quixote",
+ 13));
+ ASSERT_EQ(opt0.info_code(), 22u);
+ ASSERT_EQ(opt0.extra_text(), std::string("Don Quixote"));
+
+ std::unique_ptr<OptRecordRdata::EdeOpt> opt1 =
+ OptRecordRdata::EdeOpt::Create(std::string("\x00\x08"
+ "Manhattan",
+ 11));
+
+ ASSERT_EQ(opt1->data(), std::string("\x00\x08"
+ "Manhattan",
+ 11));
+ ASSERT_EQ(opt1->info_code(), 8u);
+ ASSERT_EQ(opt1->extra_text(), std::string("Manhattan"));
}
TEST(OptRecordRdataTest, TestEdeInfoCode) {
@@ -146,13 +157,13 @@
0x00, 0x0F, // OPT code (15 for EDE)
0x00, 0x05, // OPT data size (info code + extra text)
0x00, 0x0D, // EDE info code (13 for Cached Error)
- 'U', 'S', 'A', // UTF-8 EDE extra text ("USA")
+ 'M', 'T', 'A', // UTF-8 EDE extra text ("MTA")
// Third OPT (EDE record)
0x00, 0x0F, // OPT code (15 for EDE)
0x00, 0x06, // OPT data size (info code + extra text)
0x00, 0x10, // EDE info code (16 for Censored)
- 'B', 'I', 'O', 'S' // UTF-8 EDE extra text ("BIOS")
+ 'M', 'B', 'T', 'A' // UTF-8 EDE extra text ("MBTA")
};
base::StringPiece rdata_strpiece = MakeStringPiece(rdata, sizeof(rdata));
@@ -163,23 +174,17 @@
ASSERT_THAT(rdata_obj, NotNull());
ASSERT_EQ(rdata_obj->OptCount(), 3u);
- // Test Non EDE (all opts in OPT format)
- OptRecordRdata::Opt opt0(6, std::string("\xb0\xba\xfe\x77", 4));
- OptRecordRdata::Opt opt1(15, std::string("\x00\x0d"
- "USA",
- 5));
- OptRecordRdata::Opt opt2(15, std::string("\x00\x10"
- "BIOS",
- 6));
+ // Test Unknown Opt
+ std::unique_ptr<OptRecordRdata::UnknownOpt> opt0 =
+ OptRecordRdata::UnknownOpt::CreateForTesting(
+ 6, std::string("\xb0\xba\xfe\x77", 4));
ASSERT_THAT(rdata_obj->GetOpts(), SizeIs(3));
- ASSERT_EQ(*rdata_obj->GetOpts()[0], opt0);
- ASSERT_EQ(*rdata_obj->GetOpts()[1], opt1);
- ASSERT_EQ(*rdata_obj->GetOpts()[2], opt2);
+ ASSERT_EQ(*rdata_obj->GetOpts()[0], *opt0.get());
// Test EDE
- OptRecordRdata::EdeOpt edeOpt0(13, std::string("USA", 3));
- OptRecordRdata::EdeOpt edeOpt1(16, std::string("BIOS", 4));
+ OptRecordRdata::EdeOpt edeOpt0(13, std::string("MTA", 3));
+ OptRecordRdata::EdeOpt edeOpt1(16, std::string("MBTA", 4));
ASSERT_THAT(rdata_obj->GetEdeOpts(), SizeIs(2));
ASSERT_EQ(*rdata_obj->GetEdeOpts()[0], edeOpt0);
@@ -189,8 +194,8 @@
ASSERT_EQ(rdata_obj->GetEdeOpts()[0]->data(), edeOpt0.data());
ASSERT_EQ(rdata_obj->GetEdeOpts()[1]->data(), edeOpt1.data());
- ASSERT_EQ(rdata_obj->GetEdeOpts()[0]->extra_text(), std::string("USA", 3));
- ASSERT_EQ(rdata_obj->GetEdeOpts()[1]->extra_text(), std::string("BIOS", 4));
+ ASSERT_EQ(rdata_obj->GetEdeOpts()[0]->extra_text(), std::string("MTA", 3));
+ ASSERT_EQ(rdata_obj->GetEdeOpts()[1]->extra_text(), std::string("MBTA", 4));
ASSERT_EQ(rdata_obj->GetEdeOpts()[0]->info_code(), edeOpt0.info_code());
ASSERT_EQ(rdata_obj->GetEdeOpts()[1]->info_code(), edeOpt1.info_code());
@@ -202,7 +207,7 @@
// `rdata_obj1` second opt has extra text "BIOO"
// Note: rdata_obj0 and rdata_obj1 have 2 common Opts and 1 different one.
OptRecordRdata rdata_obj0;
- rdata_obj0.AddOpt(std::make_unique<OptRecordRdata::Opt>(
+ rdata_obj0.AddOpt(OptRecordRdata::UnknownOpt::CreateForTesting(
6, std::string("\xb0\xba\xfe\x77", 4)));
rdata_obj0.AddOpt(
std::make_unique<OptRecordRdata::EdeOpt>(13, std::string("USA", 3)));
@@ -211,7 +216,7 @@
ASSERT_EQ(rdata_obj0.OptCount(), 3u);
OptRecordRdata rdata_obj1;
- rdata_obj1.AddOpt(std::make_unique<OptRecordRdata::Opt>(
+ rdata_obj1.AddOpt(OptRecordRdata::UnknownOpt::CreateForTesting(
6, std::string("\xb0\xba\xfe\x77", 4)));
rdata_obj1.AddOpt(
std::make_unique<OptRecordRdata::EdeOpt>(13, std::string("USA", 3)));
@@ -300,10 +305,10 @@
// Check that an EDE record with an unknown info code is parsed correctly.
TEST(OptRecordRdataTest, EdeRecordUnknownInfoCode) {
const uint8_t rdata[] = {
- 0x00, 0x0F, // OPT code (15 for EDE)
- 0x00, 0x06, // OPT data size (info code + extra text)
- 0x00, 0x44, // Info Code (68 doesn't exist)
- 'R', '2', 'D', '2' // Extra Text ("R2D2")
+ 0x00, 0x0F, // OPT code (15 for EDE)
+ 0x00, 0x08, // OPT data size (info code + extra text)
+ 0x00, 0x44, // Info Code (68 doesn't exist)
+ 'B', 'O', 'S', 'T', 'O', 'N' // Extra Text ("BOSTON")
};
base::StringPiece rdata_strpiece = MakeStringPiece(rdata, sizeof(rdata));
@@ -313,28 +318,87 @@
ASSERT_THAT(rdata_obj->GetEdeOpts(), SizeIs(1));
auto* opt = rdata_obj->GetEdeOpts()[0];
ASSERT_EQ(opt->data(), std::string("\x00\x44"
- "R2D2",
- 6));
+ "BOSTON",
+ 8));
ASSERT_EQ(opt->info_code(), 68u);
- ASSERT_EQ(opt->extra_text(), std::string("R2D2", 4));
+ ASSERT_EQ(opt->extra_text(), std::string("BOSTON", 6));
ASSERT_EQ(opt->GetEnumFromInfoCode(),
OptRecordRdata::EdeOpt::EdeInfoCode::kUnrecognizedErrorCode);
}
-TEST(OptRecordRdataTest, EqualityIsOptOrderInsensitive) {
+TEST(OptRecordRdataTest, CreatePaddingOpt) {
+ std::unique_ptr<OptRecordRdata::PaddingOpt> opt0 =
+ std::make_unique<OptRecordRdata::PaddingOpt>(12);
+
+ ASSERT_EQ(opt0->data(), std::string(12, '\0'));
+ ASSERT_THAT(opt0->data(), SizeIs(12u));
+
+ std::unique_ptr<OptRecordRdata::PaddingOpt> opt1 =
+ std::make_unique<OptRecordRdata::PaddingOpt>("MASSACHUSETTS");
+
+ ASSERT_EQ(opt1->data(), std::string("MASSACHUSETTS"));
+ ASSERT_THAT(opt1->data(), SizeIs(13u));
+}
+
+TEST(OptRecordRdataTest, ParsePaddingOpt) {
+ const uint8_t rdata[] = {
+ // First OPT
+ 0x00, 0x0C, // OPT code
+ 0x00, 0x07, // OPT data size
+ 0xB0, 0x03, // OPT data padding (Book of Boba Fett)
+ 0x0F, 0xB0, 0xBA, 0xFE, 0x77,
+ };
+
+ base::StringPiece rdata_strpiece = MakeStringPiece(rdata, sizeof(rdata));
+ std::unique_ptr<OptRecordRdata> rdata_obj =
+ OptRecordRdata::Create(rdata_strpiece);
+
+ ASSERT_THAT(rdata_obj, NotNull());
+ ASSERT_EQ(rdata_obj->OptCount(), 1u);
+ ASSERT_THAT(rdata_obj->GetOpts(), SizeIs(1));
+ ASSERT_THAT(rdata_obj->GetPaddingOpts(), SizeIs(1));
+
+ // Check elements
+ OptRecordRdata::PaddingOpt opt0(
+ std::string("\xb0\x03\x0f\xb0\xba\xfe\x77", 7));
+
+ ASSERT_EQ(*(rdata_obj->GetOpts()[0]), opt0);
+ ASSERT_EQ(*(rdata_obj->GetPaddingOpts()[0]), opt0);
+ ASSERT_THAT(opt0.data(), SizeIs(7u));
+}
+
+TEST(OptRecordRdataTest, AddOptToOptRecord) {
+ // This is just the rdata portion of an OPT record, rather than a complete
+ // record.
+ const uint8_t expected_rdata[] = {
+ 0x00, 0xFF, // OPT code
+ 0x00, 0x04, // OPT data size
+ 0xDE, 0xAD, 0xBE, 0xEF // OPT data
+ };
+
+ OptRecordRdata rdata;
+ rdata.AddOpt(OptRecordRdata::UnknownOpt::CreateForTesting(
+ 255, std::string("\xde\xad\xbe\xef", 4)));
+ EXPECT_THAT(rdata.buf(), ElementsAreArray(expected_rdata));
+}
+
+// Test the OptRecordRdata equality operator.
+// Equality must be order sensitive. If Opts are same but inserted in different
+// order, test will fail epically.
+TEST(OptRecordRdataTest, EqualityIsOptOrderSensitive) {
// Control rdata
OptRecordRdata rdata_obj0;
- rdata_obj0.AddOpt(std::make_unique<OptRecordRdata::Opt>(
+ rdata_obj0.AddOpt(OptRecordRdata::UnknownOpt::CreateForTesting(
1, std::string("\xb0\xba\xfe\x77", 4)));
- rdata_obj0.AddOpt(std::make_unique<OptRecordRdata::Opt>(
+ rdata_obj0.AddOpt(OptRecordRdata::UnknownOpt::CreateForTesting(
2, std::string("\xb1\x05\xf0\x0d", 4)));
ASSERT_EQ(rdata_obj0.OptCount(), 2u);
// Same as `rdata_obj0`
OptRecordRdata rdata_obj1;
- rdata_obj1.AddOpt(std::make_unique<OptRecordRdata::Opt>(
+ rdata_obj1.AddOpt(OptRecordRdata::UnknownOpt::CreateForTesting(
1, std::string("\xb0\xba\xfe\x77", 4)));
- rdata_obj1.AddOpt(std::make_unique<OptRecordRdata::Opt>(
+ rdata_obj1.AddOpt(OptRecordRdata::UnknownOpt::CreateForTesting(
2, std::string("\xb1\x05\xf0\x0d", 4)));
ASSERT_EQ(rdata_obj1.OptCount(), 2u);
@@ -342,9 +406,9 @@
// Same contents as `rdata_obj0` & `rdata_obj1`, but different order
OptRecordRdata rdata_obj2;
- rdata_obj2.AddOpt(std::make_unique<OptRecordRdata::Opt>(
+ rdata_obj2.AddOpt(OptRecordRdata::UnknownOpt::CreateForTesting(
2, std::string("\xb1\x05\xf0\x0d", 4)));
- rdata_obj2.AddOpt(std::make_unique<OptRecordRdata::Opt>(
+ rdata_obj2.AddOpt(OptRecordRdata::UnknownOpt::CreateForTesting(
1, std::string("\xb0\xba\xfe\x77", 4)));
ASSERT_EQ(rdata_obj2.OptCount(), 2u);
@@ -354,13 +418,13 @@
// Contains only `rdata_obj0` first opt
// 2nd opt is added later
OptRecordRdata rdata_obj3;
- rdata_obj3.AddOpt(std::make_unique<OptRecordRdata::Opt>(
+ rdata_obj3.AddOpt(OptRecordRdata::UnknownOpt::CreateForTesting(
1, std::string("\xb0\xba\xfe\x77", 4)));
ASSERT_EQ(rdata_obj3.OptCount(), 1u);
ASSERT_FALSE(rdata_obj0.IsEqual(&rdata_obj3));
- rdata_obj3.AddOpt(std::make_unique<OptRecordRdata::Opt>(
+ rdata_obj3.AddOpt(OptRecordRdata::UnknownOpt::CreateForTesting(
2, std::string("\xb1\x05\xf0\x0d", 4)));
ASSERT_TRUE(rdata_obj0.IsEqual(&rdata_obj3));
@@ -375,12 +439,12 @@
// Sort by key, then by insertion order.
TEST(OptRecordRdataTest, TestGetOptsOrder) {
OptRecordRdata rdata_obj0;
- rdata_obj0.AddOpt(
- std::make_unique<OptRecordRdata::Opt>(10, std::string("\x33\x33", 2)));
- rdata_obj0.AddOpt(
- std::make_unique<OptRecordRdata::Opt>(5, std::string("\x11\x11", 2)));
- rdata_obj0.AddOpt(
- std::make_unique<OptRecordRdata::Opt>(5, std::string("\x22\x22", 2)));
+ rdata_obj0.AddOpt(OptRecordRdata::UnknownOpt::CreateForTesting(
+ 10, std::string("\x33\x33", 2)));
+ rdata_obj0.AddOpt(OptRecordRdata::UnknownOpt::CreateForTesting(
+ 5, std::string("\x11\x11", 2)));
+ rdata_obj0.AddOpt(OptRecordRdata::UnknownOpt::CreateForTesting(
+ 5, std::string("\x22\x22", 2)));
ASSERT_EQ(rdata_obj0.OptCount(), 3u);
auto opts = rdata_obj0.GetOpts();
diff --git a/net/dns/public/dns_protocol.h b/net/dns/public/dns_protocol.h
index 7b9a972..f3d28de 100644
--- a/net/dns/public/dns_protocol.h
+++ b/net/dns/public/dns_protocol.h
@@ -190,7 +190,7 @@
// DNS EDNS(0) option codes (OPT)
//
// https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml#dns-parameters-11
-static const uint16_t kEdnsPadding = 12;
+static constexpr uint16_t kEdnsPadding = 12;
static constexpr uint16_t kEdnsExtendedDnsError = 15;
// DNS header flags.