record_rdata_unittest.cc 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382
  1. // Copyright (c) 2013 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "net/dns/record_rdata.h"
  5. #include <algorithm>
  6. #include <memory>
  7. #include <utility>
  8. #include "base/big_endian.h"
  9. #include "net/dns/dns_response.h"
  10. #include "net/dns/dns_test_util.h"
  11. #include "net/test/gtest_util.h"
  12. #include "testing/gmock/include/gmock/gmock.h"
  13. #include "testing/gtest/include/gtest/gtest.h"
  14. #include "third_party/abseil-cpp/absl/types/optional.h"
  15. namespace net {
  16. namespace {
  17. using ::testing::ElementsAreArray;
  18. using ::testing::IsNull;
  19. using ::testing::NotNull;
  20. using ::testing::SizeIs;
  21. base::StringPiece MakeStringPiece(const uint8_t* data, unsigned size) {
  22. const char* data_cc = reinterpret_cast<const char*>(data);
  23. return base::StringPiece(data_cc, size);
  24. }
  25. base::StringPiece MakeStringPiece(const std::vector<uint8_t>& vec) {
  26. return MakeStringPiece(vec.data(), vec.size());
  27. }
  28. TEST(RecordRdataTest, ParseSrvRecord) {
  29. // These are just the rdata portions of the DNS records, rather than complete
  30. // records, but it works well enough for this test.
  31. const uint8_t
  32. record[] =
  33. {
  34. 0x00, 0x01, 0x00, 0x02, 0x00, 0x50, 0x03, 'w', 'w',
  35. 'w', 0x06, 'g', 'o', 'o', 'g', 'l', 'e', 0x03,
  36. 'c', 'o', 'm', 0x00, 0x01, 0x01, 0x01, 0x02, 0x01,
  37. 0x03, 0x04, 'w', 'w', 'w', '2', 0xc0, 0x0a, // Pointer to
  38. // "google.com"
  39. };
  40. DnsRecordParser parser(record, sizeof(record), 0, /*num_records=*/0);
  41. const unsigned first_record_len = 22;
  42. base::StringPiece record1_strpiece = MakeStringPiece(
  43. record, first_record_len);
  44. base::StringPiece record2_strpiece = MakeStringPiece(
  45. record + first_record_len, sizeof(record) - first_record_len);
  46. std::unique_ptr<SrvRecordRdata> record1_obj =
  47. SrvRecordRdata::Create(record1_strpiece, parser);
  48. ASSERT_TRUE(record1_obj != nullptr);
  49. ASSERT_EQ(1, record1_obj->priority());
  50. ASSERT_EQ(2, record1_obj->weight());
  51. ASSERT_EQ(80, record1_obj->port());
  52. ASSERT_EQ("www.google.com", record1_obj->target());
  53. std::unique_ptr<SrvRecordRdata> record2_obj =
  54. SrvRecordRdata::Create(record2_strpiece, parser);
  55. ASSERT_TRUE(record2_obj != nullptr);
  56. ASSERT_EQ(257, record2_obj->priority());
  57. ASSERT_EQ(258, record2_obj->weight());
  58. ASSERT_EQ(259, record2_obj->port());
  59. ASSERT_EQ("www2.google.com", record2_obj->target());
  60. ASSERT_TRUE(record1_obj->IsEqual(record1_obj.get()));
  61. ASSERT_FALSE(record1_obj->IsEqual(record2_obj.get()));
  62. }
  63. TEST(RecordRdataTest, ParseARecord) {
  64. // These are just the rdata portions of the DNS records, rather than complete
  65. // records, but it works well enough for this test.
  66. const uint8_t record[] = {
  67. 0x7F, 0x00, 0x00, 0x01 // 127.0.0.1
  68. };
  69. DnsRecordParser parser(record, sizeof(record), 0, /*num_records=*/0);
  70. base::StringPiece record_strpiece = MakeStringPiece(record, sizeof(record));
  71. std::unique_ptr<ARecordRdata> record_obj =
  72. ARecordRdata::Create(record_strpiece, parser);
  73. ASSERT_TRUE(record_obj != nullptr);
  74. ASSERT_EQ("127.0.0.1", record_obj->address().ToString());
  75. ASSERT_TRUE(record_obj->IsEqual(record_obj.get()));
  76. }
  77. TEST(RecordRdataTest, ParseAAAARecord) {
  78. // These are just the rdata portions of the DNS records, rather than complete
  79. // records, but it works well enough for this test.
  80. const uint8_t record[] = {
  81. 0x12, 0x34, 0x56, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00,
  82. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09 // 1234:5678::9A
  83. };
  84. DnsRecordParser parser(record, sizeof(record), 0, /*num_records=*/0);
  85. base::StringPiece record_strpiece = MakeStringPiece(record, sizeof(record));
  86. std::unique_ptr<AAAARecordRdata> record_obj =
  87. AAAARecordRdata::Create(record_strpiece, parser);
  88. ASSERT_TRUE(record_obj != nullptr);
  89. ASSERT_EQ("1234:5678::9", record_obj->address().ToString());
  90. ASSERT_TRUE(record_obj->IsEqual(record_obj.get()));
  91. }
  92. TEST(RecordRdataTest, ParseCnameRecord) {
  93. // These are just the rdata portions of the DNS records, rather than complete
  94. // records, but it works well enough for this test.
  95. const uint8_t record[] = {0x03, 'w', 'w', 'w', 0x06, 'g', 'o', 'o',
  96. 'g', 'l', 'e', 0x03, 'c', 'o', 'm', 0x00};
  97. DnsRecordParser parser(record, sizeof(record), 0, /*num_records=*/0);
  98. base::StringPiece record_strpiece = MakeStringPiece(record, sizeof(record));
  99. std::unique_ptr<CnameRecordRdata> record_obj =
  100. CnameRecordRdata::Create(record_strpiece, parser);
  101. ASSERT_TRUE(record_obj != nullptr);
  102. ASSERT_EQ("www.google.com", record_obj->cname());
  103. ASSERT_TRUE(record_obj->IsEqual(record_obj.get()));
  104. }
  105. TEST(RecordRdataTest, ParsePtrRecord) {
  106. // These are just the rdata portions of the DNS records, rather than complete
  107. // records, but it works well enough for this test.
  108. const uint8_t record[] = {0x03, 'w', 'w', 'w', 0x06, 'g', 'o', 'o',
  109. 'g', 'l', 'e', 0x03, 'c', 'o', 'm', 0x00};
  110. DnsRecordParser parser(record, sizeof(record), 0, /*num_records=*/0);
  111. base::StringPiece record_strpiece = MakeStringPiece(record, sizeof(record));
  112. std::unique_ptr<PtrRecordRdata> record_obj =
  113. PtrRecordRdata::Create(record_strpiece, parser);
  114. ASSERT_TRUE(record_obj != nullptr);
  115. ASSERT_EQ("www.google.com", record_obj->ptrdomain());
  116. ASSERT_TRUE(record_obj->IsEqual(record_obj.get()));
  117. }
  118. TEST(RecordRdataTest, ParseTxtRecord) {
  119. // These are just the rdata portions of the DNS records, rather than complete
  120. // records, but it works well enough for this test.
  121. const uint8_t record[] = {0x03, 'w', 'w', 'w', 0x06, 'g', 'o', 'o',
  122. 'g', 'l', 'e', 0x03, 'c', 'o', 'm'};
  123. DnsRecordParser parser(record, sizeof(record), 0, /*num_records=*/0);
  124. base::StringPiece record_strpiece = MakeStringPiece(record, sizeof(record));
  125. std::unique_ptr<TxtRecordRdata> record_obj =
  126. TxtRecordRdata::Create(record_strpiece, parser);
  127. ASSERT_TRUE(record_obj != nullptr);
  128. std::vector<std::string> expected;
  129. expected.push_back("www");
  130. expected.push_back("google");
  131. expected.push_back("com");
  132. ASSERT_EQ(expected, record_obj->texts());
  133. ASSERT_TRUE(record_obj->IsEqual(record_obj.get()));
  134. }
  135. TEST(RecordRdataTest, ParseNsecRecord) {
  136. // These are just the rdata portions of the DNS records, rather than complete
  137. // records, but it works well enough for this test.
  138. const uint8_t record[] = {0x03, 'w', 'w', 'w', 0x06, 'g', 'o',
  139. 'o', 'g', 'l', 'e', 0x03, 'c', 'o',
  140. 'm', 0x00, 0x00, 0x02, 0x40, 0x01};
  141. DnsRecordParser parser(record, sizeof(record), 0, /*num_records=*/0);
  142. base::StringPiece record_strpiece = MakeStringPiece(record, sizeof(record));
  143. std::unique_ptr<NsecRecordRdata> record_obj =
  144. NsecRecordRdata::Create(record_strpiece, parser);
  145. ASSERT_TRUE(record_obj != nullptr);
  146. ASSERT_EQ(16u, record_obj->bitmap_length());
  147. EXPECT_FALSE(record_obj->GetBit(0));
  148. EXPECT_TRUE(record_obj->GetBit(1));
  149. for (int i = 2; i < 15; i++) {
  150. EXPECT_FALSE(record_obj->GetBit(i));
  151. }
  152. EXPECT_TRUE(record_obj->GetBit(15));
  153. ASSERT_TRUE(record_obj->IsEqual(record_obj.get()));
  154. }
  155. TEST(RecordRdataTest, CreateNsecRecordWithEmptyBitmapReturnsNull) {
  156. // These are just the rdata portions of the DNS records, rather than complete
  157. // records, but it works well enough for this test.
  158. // This record has a bitmap that is 0 bytes long.
  159. const uint8_t record[] = {0x03, 'w', 'w', 'w', 0x06, 'g', 'o', 'o', 'g',
  160. 'l', 'e', 0x03, 'c', 'o', 'm', 0x00, 0x00, 0x00};
  161. DnsRecordParser parser(record, sizeof(record), 0, /*num_records=*/0);
  162. base::StringPiece record_strpiece = MakeStringPiece(record, sizeof(record));
  163. std::unique_ptr<NsecRecordRdata> record_obj =
  164. NsecRecordRdata::Create(record_strpiece, parser);
  165. ASSERT_FALSE(record_obj);
  166. }
  167. TEST(RecordRdataTest, CreateNsecRecordWithOversizedBitmapReturnsNull) {
  168. // These are just the rdata portions of the DNS records, rather than complete
  169. // records, but it works well enough for this test.
  170. // This record has a bitmap that is 33 bytes long. The maximum size allowed by
  171. // RFC 3845, Section 2.1.2, is 32 bytes.
  172. const uint8_t record[] = {
  173. 0x03, 'w', 'w', 'w', 0x06, 'g', 'o', 'o', 'g', 'l', 'e',
  174. 0x03, 'c', 'o', 'm', 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00,
  175. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  176. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  177. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
  178. DnsRecordParser parser(record, sizeof(record), 0, /*num_records=*/0);
  179. base::StringPiece record_strpiece = MakeStringPiece(record, sizeof(record));
  180. std::unique_ptr<NsecRecordRdata> record_obj =
  181. NsecRecordRdata::Create(record_strpiece, parser);
  182. ASSERT_FALSE(record_obj);
  183. }
  184. // Test that for arbitrary IntegrityRecordRdata r, Parse(Serialize(r)) == r.
  185. TEST(RecordRdataTest, IntegrityParseSerializeInverseProperty) {
  186. IntegrityRecordRdata record(IntegrityRecordRdata::Random());
  187. EXPECT_TRUE(record.IsIntact());
  188. absl::optional<std::vector<uint8_t>> serialized = record.Serialize();
  189. EXPECT_TRUE(serialized);
  190. std::unique_ptr<IntegrityRecordRdata> reparsed =
  191. IntegrityRecordRdata::Create(MakeStringPiece(*serialized));
  192. EXPECT_TRUE(reparsed);
  193. EXPECT_TRUE(reparsed->IsEqual(&record));
  194. }
  195. TEST(RecordRdataTest, IntegrityEmptyNonceCornerCase) {
  196. const IntegrityRecordRdata::Nonce empty_nonce;
  197. IntegrityRecordRdata record(empty_nonce);
  198. EXPECT_TRUE(record.IsIntact());
  199. absl::optional<std::vector<uint8_t>> serialized = record.Serialize();
  200. EXPECT_TRUE(serialized);
  201. std::unique_ptr<IntegrityRecordRdata> reparsed =
  202. IntegrityRecordRdata::Create(MakeStringPiece(*serialized));
  203. EXPECT_TRUE(reparsed);
  204. EXPECT_TRUE(reparsed->IsIntact());
  205. EXPECT_TRUE(reparsed->IsEqual(&record));
  206. EXPECT_EQ(reparsed->nonce().size(), 0u);
  207. }
  208. TEST(RecordRdataTest, IntegrityMoveConstructor) {
  209. IntegrityRecordRdata record_a(IntegrityRecordRdata::Random());
  210. EXPECT_TRUE(record_a.IsIntact());
  211. absl::optional<std::vector<uint8_t>> serialized_a = record_a.Serialize();
  212. EXPECT_TRUE(serialized_a);
  213. IntegrityRecordRdata record_b = std::move(record_a);
  214. EXPECT_TRUE(record_b.IsIntact());
  215. absl::optional<std::vector<uint8_t>> serialized_b = record_b.Serialize();
  216. EXPECT_TRUE(serialized_b);
  217. EXPECT_EQ(serialized_a, serialized_b);
  218. }
  219. TEST(RecordRdataTest, IntegrityRandomRecordsDiffer) {
  220. IntegrityRecordRdata record_a(IntegrityRecordRdata::Random());
  221. IntegrityRecordRdata record_b(IntegrityRecordRdata::Random());
  222. EXPECT_TRUE(!record_a.IsEqual(&record_b));
  223. }
  224. TEST(RecordRdataTest, IntegritySerialize) {
  225. IntegrityRecordRdata record({'A'});
  226. EXPECT_TRUE(record.IsIntact());
  227. const absl::optional<std::vector<uint8_t>> serialized = record.Serialize();
  228. EXPECT_TRUE(serialized);
  229. // Expected payload contains the SHA256 hash of 'A'. For the lazy:
  230. // $ echo -n A | sha256sum | cut -f1 -d' ' | sed -e 's/\(..\)/0x\1, /g'
  231. const std::vector<uint8_t> expected = {
  232. 0, 1, 'A', // Length prefix and nonce
  233. // Begin digest
  234. 0x55, 0x9a, 0xea, 0xd0, 0x82, 0x64, 0xd5, 0x79, 0x5d, 0x39, 0x09, 0x71,
  235. 0x8c, 0xdd, 0x05, 0xab, 0xd4, 0x95, 0x72, 0xe8, 0x4f, 0xe5, 0x55, 0x90,
  236. 0xee, 0xf3, 0x1a, 0x88, 0xa0, 0x8f, 0xdf, 0xfd, // End digest
  237. };
  238. EXPECT_TRUE(*serialized == expected);
  239. }
  240. TEST(RecordRdataTest, IntegrityParse) {
  241. const std::vector<uint8_t> serialized = {
  242. 0, 6, 'f', 'o', 'o', 'b', 'a', 'r', // Length prefix and nonce
  243. 0xc3, 0xab, 0x8f, 0xf1, 0x37, 0x20, 0xe8, 0xad, 0x90, // Begin digest
  244. 0x47, 0xdd, 0x39, 0x46, 0x6b, 0x3c, 0x89, 0x74, 0xe5, 0x92, 0xc2,
  245. 0xfa, 0x38, 0x3d, 0x4a, 0x39, 0x60, 0x71, 0x4c, 0xae, 0xf0, 0xc4,
  246. 0xf2, // End digest
  247. };
  248. auto record = IntegrityRecordRdata::Create(MakeStringPiece(serialized));
  249. EXPECT_TRUE(record);
  250. EXPECT_TRUE(record->IsIntact());
  251. }
  252. TEST(RecordRdataTest, IntegrityBadParseEmptyRdata) {
  253. const std::vector<uint8_t> serialized = {};
  254. auto record = IntegrityRecordRdata::Create(MakeStringPiece(serialized));
  255. EXPECT_TRUE(record);
  256. EXPECT_FALSE(record->IsIntact());
  257. }
  258. TEST(RecordRdataTest, IntegrityBadParseTruncatedNonce) {
  259. const std::vector<uint8_t> serialized = {
  260. 0, 6, 'f', 'o', 'o' // Length prefix and truncated nonce
  261. };
  262. auto record = IntegrityRecordRdata::Create(MakeStringPiece(serialized));
  263. EXPECT_TRUE(record);
  264. EXPECT_FALSE(record->IsIntact());
  265. }
  266. TEST(RecordRdataTest, IntegrityBadParseTruncatedDigest) {
  267. const std::vector<uint8_t> serialized = {
  268. 0, 6, 'f', 'o', 'o', 'b', 'a', 'r', // Length prefix and nonce
  269. // Begin Digest
  270. 0xc3, 0xab, 0x8f, 0xf1, 0x37, 0x20, 0xe8, 0xad, 0x90, 0x47, 0xdd, 0x39,
  271. 0x46, 0x6b, 0x3c, 0x89, 0x74, 0xe5, 0x92, 0xc2, 0xfa, 0x38, 0x3d,
  272. 0x4a, // End digest
  273. };
  274. auto record = IntegrityRecordRdata::Create(MakeStringPiece(serialized));
  275. EXPECT_TRUE(record);
  276. EXPECT_FALSE(record->IsIntact());
  277. }
  278. TEST(RecordRdataTest, IntegrityBadParseExtraBytes) {
  279. const std::vector<uint8_t> serialized = {
  280. 0, 6, 'f', 'o', 'o', 'b', 'a', 'r', // Length prefix and nonce
  281. // Begin digest
  282. 0xc3, 0xab, 0x8f, 0xf1, 0x37, 0x20, 0xe8, 0xad, 0x90, 0x47, 0xdd, 0x39,
  283. 0x46, 0x6b, 0x3c, 0x89, 0x74, 0xe5, 0x92, 0xc2, 0xfa, 0x38, 0x3d, 0x4a,
  284. 0x39, 0x60, 0x71, 0x4c, 0xae, 0xf0, 0xc4, 0xf2, // End digest
  285. 'e', 'x', 't', 'r', 'a' // Trailing bytes
  286. };
  287. auto record = IntegrityRecordRdata::Create(MakeStringPiece(serialized));
  288. EXPECT_TRUE(record);
  289. EXPECT_FALSE(record->IsIntact());
  290. }
  291. TEST(RecordRdataTest, IntegrityCorruptedDigest) {
  292. const std::vector<uint8_t> serialized = {
  293. 0, 6, 'f', 'o', 'o', 'b', 'a', 'r', // Length prefix and nonce
  294. 0xde, 0xad, 0xbe, 0xef, 0x37, 0x20, 0xe8, 0xad, 0x90, // Begin digest
  295. 0x47, 0xdd, 0x39, 0x46, 0x6b, 0x3c, 0x89, 0x74, 0xe5, 0x92, 0xc2,
  296. 0xfa, 0x38, 0x3d, 0x4a, 0x39, 0x60, 0x71, 0x4c, 0xae, 0xf0, 0xc4,
  297. 0xf2, // End digest
  298. };
  299. auto record = IntegrityRecordRdata::Create(MakeStringPiece(serialized));
  300. EXPECT_TRUE(record);
  301. EXPECT_FALSE(record->IsIntact());
  302. }
  303. } // namespace
  304. } // namespace net