blob: 5694500219d44fec49b5d707b7838a757284755b [file] [log] [blame]
// Copyright (c) 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "net/dns/record_parsed.h"
#include <memory>
#include "base/time/time.h"
#include "net/dns/dns_response.h"
#include "net/dns/dns_test_util.h"
#include "net/dns/public/dns_protocol.h"
#include "net/dns/record_rdata.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace net {
static const uint8_t kT1ResponseWithCacheFlushBit[] = {
0x0a, 'c', 'o', 'd', 'e', 'r', 'e', 'v', 'i', 'e', 'w', 0x08, 'c', 'h', 'r',
'o', 'm', 'i', 'u', 'm', 0x03, 'o', 'r', 'g', 0x00, 0x00,
0x05, // TYPE is CNAME.
0x80, 0x01, // CLASS is IN with cache flush bit set.
0x00, 0x01, // TTL (4 bytes) is 20 hours, 47 minutes, 48 seconds.
0x24, 0x74, 0x00, 0x12, // RDLENGTH is 18 bytes.
// ghs.l.google.com in DNS format.
0x03, 'g', 'h', 's', 0x01, 'l', 0x06, 'g', 'o', 'o', 'g', 'l', 'e', 0x03,
'c', 'o', 'm', 0x00};
TEST(RecordParsedTest, ParseSingleRecord) {
DnsRecordParser parser(kT1ResponseDatagram, sizeof(kT1ResponseDatagram),
sizeof(dns_protocol::Header));
std::unique_ptr<const RecordParsed> record;
const CnameRecordRdata* rdata;
parser.SkipQuestion();
record = RecordParsed::CreateFrom(&parser, base::Time());
EXPECT_TRUE(record != nullptr);
ASSERT_EQ("codereview.chromium.org", record->name());
ASSERT_EQ(dns_protocol::kTypeCNAME, record->type());
ASSERT_EQ(dns_protocol::kClassIN, record->klass());
rdata = record->rdata<CnameRecordRdata>();
ASSERT_TRUE(rdata != nullptr);
ASSERT_EQ(kT1CanonName, rdata->cname());
ASSERT_FALSE(record->rdata<SrvRecordRdata>());
ASSERT_TRUE(record->IsEqual(record.get(), true));
}
TEST(RecordParsedTest, CacheFlushBitCompare) {
DnsRecordParser parser1(kT1ResponseDatagram, sizeof(kT1ResponseDatagram),
sizeof(dns_protocol::Header));
parser1.SkipQuestion();
std::unique_ptr<const RecordParsed> record1 =
RecordParsed::CreateFrom(&parser1, base::Time());
DnsRecordParser parser2(kT1ResponseWithCacheFlushBit,
sizeof(kT1ResponseWithCacheFlushBit),
0);
std::unique_ptr<const RecordParsed> record2 =
RecordParsed::CreateFrom(&parser2, base::Time());
EXPECT_FALSE(record1->IsEqual(record2.get(), false));
EXPECT_TRUE(record1->IsEqual(record2.get(), true));
EXPECT_FALSE(record2->IsEqual(record1.get(), false));
EXPECT_TRUE(record2->IsEqual(record1.get(), true));
}
TEST(RecordParsedTest, ParseUnknownRdata) {
static const char kRecordData[] =
// NAME="foo.test"
"\003foo\004test\000"
// TYPE=MD (an obsolete type that will likely never be recognized by
// Chrome)
"\000\003"
// CLASS=IN
"\000\001"
// TTL=30 seconds
"\000\000\000\036"
// RDLENGTH=12 bytes
"\000\014"
// RDATA="garbage data"
"garbage data";
DnsRecordParser parser(kRecordData, sizeof(kRecordData) - 1, 0 /* offset */);
std::unique_ptr<const RecordParsed> record =
RecordParsed::CreateFrom(&parser, base::Time());
ASSERT_TRUE(record);
EXPECT_EQ(record->name(), "foo.test");
EXPECT_EQ(record->type(), 3u);
EXPECT_EQ(record->klass(), dns_protocol::kClassIN);
EXPECT_EQ(record->ttl(), 30u);
EXPECT_FALSE(record->rdata<ARecordRdata>());
EXPECT_FALSE(record->rdata_for_testing());
}
TEST(RecordParsedTest, EqualityHandlesUnknownRdata) {
static constexpr char kData[] =
// NAME="foo.test"
"\003foo\004test\000"
// TYPE=MD (an obsolete type that will likely never be recognized by
// Chrome)
"\000\003"
// CLASS=IN
"\000\001"
// TTL=30 seconds
"\000\000\000\036"
// RDLENGTH=12 bytes
"\000\014"
// RDATA="garbage data"
"garbage data"
// NAME="foo.test"
"\003foo\004test\000"
// TYPE=A
"\000\001"
// CLASS=IN
"\000\001"
// TTL=30 seconds
"\000\000\000\036"
// RDLENGTH=4 bytes
"\000\004"
// RDATA=8.8.8.8
"\010\010\010\010";
DnsRecordParser parser(kData, sizeof(kData) - 1, 0 /* offset */);
std::unique_ptr<const RecordParsed> unknown_record =
RecordParsed::CreateFrom(&parser, base::Time());
ASSERT_TRUE(unknown_record);
ASSERT_FALSE(unknown_record->rdata_for_testing());
std::unique_ptr<const RecordParsed> known_record =
RecordParsed::CreateFrom(&parser, base::Time());
ASSERT_TRUE(known_record);
ASSERT_TRUE(known_record->rdata_for_testing());
EXPECT_TRUE(
unknown_record->IsEqual(unknown_record.get(), false /* is_mdns */));
EXPECT_TRUE(
unknown_record->IsEqual(unknown_record.get(), true /* is_mdns */));
EXPECT_TRUE(known_record->IsEqual(known_record.get(), false /* is_mdns */));
EXPECT_TRUE(known_record->IsEqual(known_record.get(), true /* is_mdns */));
EXPECT_FALSE(
unknown_record->IsEqual(known_record.get(), false /* is_mdns */));
EXPECT_FALSE(unknown_record->IsEqual(known_record.get(), true /* is_mdns */));
EXPECT_FALSE(
known_record->IsEqual(unknown_record.get(), false /* is_mdns */));
EXPECT_FALSE(known_record->IsEqual(unknown_record.get(), true /* is_mdns */));
}
TEST(RecordParsedTest, RejectMalformedRdata) {
static const char kRecordData[] =
// NAME="foo.test"
"\003foo\004test\000"
// TYPE=PTR
"\000\014"
// CLASS=IN
"\000\001"
// TTL=31 seconds
"\000\000\000\037"
// RDLENGTH=1 byte
"\000\001"
// RDATA=truncated name
"\001";
DnsRecordParser parser(kRecordData, sizeof(kRecordData) - 1, 0 /* offset */);
std::unique_ptr<const RecordParsed> record =
RecordParsed::CreateFrom(&parser, base::Time());
EXPECT_FALSE(record);
}
} // namespace net