blob: 5fdf4d49d58673385261ae1d15e2d0350ca1b539 [file] [log] [blame]
// Copyright 2019 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 "cast/common/mdns/mdns_reader.h"
#include <memory>
#include "gmock/gmock.h"
#include "gtest/gtest.h"
namespace cast {
namespace mdns {
namespace {
template <class T>
void TestReadEntrySucceeds(const uint8_t* data,
size_t size,
const T& expected) {
MdnsReader reader(data, size);
T entry;
EXPECT_TRUE(reader.Read(&entry));
EXPECT_EQ(entry, expected);
EXPECT_EQ(reader.remaining(), UINT64_C(0));
}
template <class T>
void TestReadEntryFails(const uint8_t* data, size_t size) {
MdnsReader reader(data, size);
T entry;
EXPECT_FALSE(reader.Read(&entry));
// There should be no side effects for failing to read an entry. The
// underlying pointer should not have changed.
EXPECT_EQ(reader.offset(), UINT64_C(0));
}
} // namespace
TEST(MdnsReaderTest, ReadDomainName) {
constexpr uint8_t kMessage[] = {
// First name
0x07, 't', 'e', 's', 't', 'i', 'n', 'g', // Byte: 0
0x05, 'l', 'o', 'c', 'a', 'l', // Byte: 8
0x00, // Byte: 14
// Second name
0x07, 's', 'e', 'r', 'v', 'i', 'c', 'e', // Byte: 15
0xc0, 0x00, // Byte: 23
// Third name
0x06, 'd', 'e', 'v', 'i', 'c', 'e', // Byte: 25
0xc0, 0x0f, // Byte: 32
// Fourth name
0xc0, 0x20, // Byte: 34
};
MdnsReader reader(kMessage, sizeof(kMessage));
EXPECT_EQ(reader.begin(), kMessage);
EXPECT_EQ(reader.length(), sizeof(kMessage));
EXPECT_EQ(reader.offset(), 0u);
DomainName name;
EXPECT_TRUE(reader.Read(&name));
EXPECT_EQ(name.ToString(), "testing.local");
EXPECT_TRUE(reader.Read(&name));
EXPECT_EQ(name.ToString(), "service.testing.local");
EXPECT_TRUE(reader.Read(&name));
EXPECT_EQ(name.ToString(), "device.service.testing.local");
EXPECT_TRUE(reader.Read(&name));
EXPECT_EQ(name.ToString(), "service.testing.local");
EXPECT_EQ(reader.offset(), sizeof(kMessage));
EXPECT_EQ(0UL, reader.remaining());
EXPECT_FALSE(reader.Read(&name));
}
TEST(MdnsReaderTest, ReadDomainName_Empty) {
constexpr uint8_t kDomainName[] = {0x00};
TestReadEntrySucceeds(kDomainName, sizeof(kDomainName), DomainName());
}
TEST(MdnsReaderTest, ReadDomainName_TooShort) {
// Length 0x03 is longer than available data for the domain name
constexpr uint8_t kDomainName[] = {0x03, 'a', 'b'};
TestReadEntryFails<DomainName>(kDomainName, sizeof(kDomainName));
}
TEST(MdnsReaderTest, ReadDomainName_TooLong) {
std::vector<uint8_t> kDomainName;
for (uint8_t letter = 'a'; letter <= 'z'; ++letter) {
constexpr uint8_t repetitions = 10;
kDomainName.push_back(repetitions);
kDomainName.insert(kDomainName.end(), repetitions, letter);
}
kDomainName.push_back(0);
TestReadEntryFails<DomainName>(kDomainName.data(), kDomainName.size());
}
TEST(MdnsReaderTest, ReadDomainName_LabelPointerOutOfBounds) {
constexpr uint8_t kDomainName[] = {0xc0, 0x02};
TestReadEntryFails<DomainName>(kDomainName, sizeof(kDomainName));
}
TEST(MdnsReaderTest, ReadDomainName_InvalidLabel) {
constexpr uint8_t kDomainName[] = {0x80};
TestReadEntryFails<DomainName>(kDomainName, sizeof(kDomainName));
}
TEST(MdnsReaderTest, ReadDomainName_CircularCompression) {
// clang-format off
constexpr uint8_t kDomainName[] = {
// NOTE: Circular label pointer at end of name.
0x07, 't', 'e', 's', 't', 'i', 'n', 'g', // Byte: 0
0x05, 'l', 'o', 'c', 'a', 'l', // Byte: 8
0xc0, 0x00, // Byte: 14
};
// clang-format on
TestReadEntryFails<DomainName>(kDomainName, sizeof(kDomainName));
}
TEST(MdnsReaderTest, ReadRawRecordRdata) {
// clang-format off
constexpr uint8_t kRawRecordRdata[] = {
0x00, 0x08, // RDLENGTH = 8 bytes
0x05, 'c', 'n', 'a', 'm', 'e', 0xc0, 0x00,
};
// clang-format on
TestReadEntrySucceeds(
kRawRecordRdata, sizeof(kRawRecordRdata),
RawRecordRdata(kRawRecordRdata + 2, sizeof(kRawRecordRdata) - 2));
}
TEST(MdnsReaderTest, ReadRawRecord_Empty) {
// clang-format off
constexpr uint8_t kRawRecordRdata[] = {
0x00, 0x00, // RDLENGTH = 0 bytes
};
// clang-format on
TestReadEntrySucceeds(kRawRecordRdata, sizeof(kRawRecordRdata),
RawRecordRdata());
}
TEST(MdnsReaderTest, ReadRawRecordRdata_TooShort) {
// clang-format off
constexpr uint8_t kRawRecordRdata[] = {
0x00, 0x05, // RDLENGTH = 5 bytes is longer that available data
0x03, 'f', 'o', 'o'
};
// clang-format on
TestReadEntryFails<RawRecordRdata>(kRawRecordRdata, sizeof(kRawRecordRdata));
}
TEST(MdnsReaderTest, ReadSrvRecordRdata) {
// clang-format off
constexpr uint8_t kSrvRecordRdata[] = {
0x00, 0x15, // RDLENGTH = 21
0x00, 0x05, // PRIORITY = 5
0x00, 0x06, // WEIGHT = 6
0x1f, 0x49, // PORT = 8009
0x07, 't', 'e', 's', 't', 'i', 'n', 'g',
0x05, 'l', 'o', 'c', 'a', 'l', 0x00,
};
// clang-format on
TestReadEntrySucceeds(
kSrvRecordRdata, sizeof(kSrvRecordRdata),
SrvRecordRdata(5, 6, 8009, DomainName{"testing", "local"}));
}
TEST(MdnsReaderTest, ReadSrvRecordRdata_TooShort) {
// clang-format off
constexpr uint8_t kSrvRecordRdata[] = {
0x00, 0x14, // RDLENGTH = 21
0x00, 0x05, // PRIORITY = 5
0x00, 0x06, // WEIGHT = 6
// Missing bytes
};
// clang-format on
TestReadEntryFails<SrvRecordRdata>(kSrvRecordRdata, sizeof(kSrvRecordRdata));
}
TEST(MdnsReaderTest, ReadSrvRecordRdata_WrongLength) {
// clang-format off
constexpr uint8_t kSrvRecordRdata[] = {
0x00, 0x14, // RDLENGTH = 20
0x00, 0x05, // PRIORITY = 5
0x00, 0x06, // WEIGHT = 6
0x1f, 0x49, // PORT = 8009
0x07, 't', 'e', 's', 't', 'i', 'n', 'g',
0x05, 'l', 'o', 'c', 'a', 'l', 0x00,
};
// clang-format on
TestReadEntryFails<SrvRecordRdata>(kSrvRecordRdata, sizeof(kSrvRecordRdata));
}
TEST(MdnsReaderTest, ReadARecordRdata) {
constexpr uint8_t kARecordRdata[] = {
0x00, 0x4, // RDLENGTH = 4
0x08, 0x08, 0x08, 0x08, // ADDRESS = 8.8.8.8
};
TestReadEntrySucceeds(kARecordRdata, sizeof(kARecordRdata),
ARecordRdata(IPAddress{8, 8, 8, 8}));
}
TEST(MdnsReaderTest, ReadARecordRdata_TooShort) {
constexpr uint8_t kARecordRdata[] = {
0x00, 0x4, // RDLENGTH = 4
0x08, 0x08, // Address missing bytes
};
TestReadEntryFails<ARecordRdata>(kARecordRdata, sizeof(kARecordRdata));
}
TEST(MdnsReaderTest, ReadARecordRdata_WrongLength) {
constexpr uint8_t kARecordRdata[] = {
0x00, 0x5, // RDLENGTH = 5
0x08, 0x08, 0x08, 0x08, // ADDRESS = 8.8.8.8
};
TestReadEntryFails<ARecordRdata>(kARecordRdata, sizeof(kARecordRdata));
}
TEST(MdnsReaderTest, ReadAAAARecordRdata) {
// clang-format off
constexpr uint8_t kAAAARecordRdata[] = {
0x00, 0x10, // RDLENGTH = 16
// ADDRESS = FE80:0000:0000:0000:0202:B3FF:FE1E:8329
0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x02, 0x02, 0xb3, 0xff, 0xfe, 0x1e, 0x83, 0x29,
};
// clang-format on
TestReadEntrySucceeds(kAAAARecordRdata, sizeof(kAAAARecordRdata),
AAAARecordRdata(IPAddress(IPAddress::Version::kV6,
kAAAARecordRdata + 2)));
}
TEST(MdnsReaderTest, ReadAAAARecordRdata_TooShort) {
// clang-format off
constexpr uint8_t kAAAARecordRdata[] = {
0x00, 0x10, // RDLENGTH = 16
// ADDRESS missing bytes
0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
// clang-format on
TestReadEntryFails<AAAARecordRdata>(kAAAARecordRdata,
sizeof(kAAAARecordRdata));
}
TEST(MdnsReaderTest, ReadAAAARecordRdata_WrongLength) {
// clang-format off
constexpr uint8_t kAAAARecordRdata[] = {
0x00, 0x11, // RDLENGTH = 17
// ADDRESS = FE80:0000:0000:0000:0202:B3FF:FE1E:8329
0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x02, 0x02, 0xb3, 0xff, 0xfe, 0x1e, 0x83, 0x29,
};
// clang-format on
TestReadEntryFails<AAAARecordRdata>(kAAAARecordRdata,
sizeof(kAAAARecordRdata));
}
TEST(MdnsReaderTest, ReadPtrRecordRdata) {
// clang-format off
constexpr uint8_t kPtrRecordRdata[] = {
0x00, 0x18, // RDLENGTH = 24
0x08, 'm', 'y', 'd', 'e', 'v', 'i', 'c', 'e',
0x07, 't', 'e', 's', 't', 'i', 'n', 'g',
0x05, 'l', 'o', 'c', 'a', 'l',
0x00,
};
// clang-format on
TestReadEntrySucceeds(
kPtrRecordRdata, sizeof(kPtrRecordRdata),
PtrRecordRdata(DomainName{"mydevice", "testing", "local"}));
}
TEST(MdnsReaderTest, ReadPtrRecordRdata_TooShort) {
// clang-format off
constexpr uint8_t kPtrRecordRdata[] = {
0x00, 0x18, // RDLENGTH = 24
0x08, 'm', 'y', 'd', 'e', 'v', 'i', 'c', 'e',
0x07, 't', 'e', 's', 't', 'i', 'n', 'g',
0x05, 'l', 'o', 'c'
// Missing bytes
};
// clang-format on
TestReadEntryFails<PtrRecordRdata>(kPtrRecordRdata, sizeof(kPtrRecordRdata));
}
TEST(MdnsReaderTest, ReadPtrRecordRdata_WrongLength) {
// clang-format off
constexpr uint8_t kPtrRecordRdata[] = {
0x00, 0x18, // RDLENGTH = 24
0x07, 't', 'e', 's', 't', 'i', 'n', 'g',
0x05, 'l', 'o', 'c', 'a', 'l',
0x00,
};
// clang-format on
TestReadEntryFails<PtrRecordRdata>(kPtrRecordRdata, sizeof(kPtrRecordRdata));
}
TEST(MdnsReaderTest, ReadTxtRecordRdata) {
// clang-format off
constexpr uint8_t kTxtRecordRdata[] = {
0x00, 0x0C, // RDLENGTH = 12
0x05, 'f', 'o', 'o', '=', '1',
0x05, 'b', 'a', 'r', '=', '2',
};
// clang-format on
TestReadEntrySucceeds(kTxtRecordRdata, sizeof(kTxtRecordRdata),
TxtRecordRdata{"foo=1", "bar=2"});
}
TEST(MdnsReaderTest, ReadTxtRecordRdata_Empty) {
constexpr uint8_t kTxtRecordRdata[] = {
0x00, 0x01, // RDLENGTH = 1
0x00, // empty string
};
TestReadEntrySucceeds(kTxtRecordRdata, sizeof(kTxtRecordRdata),
TxtRecordRdata());
}
TEST(MdnsReaderTest, ReadTxtRecordRdata_WithNullInTheMiddle) {
// clang-format off
constexpr uint8_t kTxtRecordRdata[] = {
0x00, 0x10, // RDLENGTH = 16
0x09, 'w', 'i', 't', 'h', '\0', 'N', 'U', 'L', 'L',
0x05, 'o', 't', 'h', 'e', 'r',
};
// clang-format on
TestReadEntrySucceeds(
kTxtRecordRdata, sizeof(kTxtRecordRdata),
TxtRecordRdata{absl::string_view("with\0NULL", 9), "other"});
}
TEST(MdnsReaderTest, ReadTxtRecordRdata_EmptyEntries) {
// clang-format off
constexpr uint8_t kTxtRecordRdata[] = {
0x00, 0x0F, // RDLENGTH = 12
0x05, 'f', 'o', 'o', '=', '1',
0x00,
0x00,
0x05, 'b', 'a', 'r', '=', '2',
0x00,
};
// clang-format on
TestReadEntrySucceeds(kTxtRecordRdata, sizeof(kTxtRecordRdata),
TxtRecordRdata{"foo=1", "bar=2"});
}
TEST(MdnsReaderTest, ReadTxtRecordRdata_TooShort) {
// clang-format off
constexpr uint8_t kTxtRecordRdata[] = {
0x00, 0x0C, // RDLENGTH = 12
0x05, 'f', 'o', 'o', '=', '1',
};
// clang-format on
TestReadEntryFails<TxtRecordRdata>(kTxtRecordRdata, sizeof(kTxtRecordRdata));
}
TEST(MdnsReaderTest, ReadTxtRecordRdata_WrongLength) {
// clang-format off
constexpr uint8_t kTxtRecordRdata[] = {
0x00, 0x0F, // Wrong length specified
0x05, 'f', 'o', 'o', '=', '1',
0x05, 'b', 'a', 'r', '=', '2',
};
// clang-format on
TestReadEntryFails<TxtRecordRdata>(kTxtRecordRdata, sizeof(kTxtRecordRdata));
}
TEST(MdnsReaderTest, ReadMdnsRecord_ARecordRdata) {
// clang-format off
constexpr uint8_t kTestRecord[] = {
0x07, 't', 'e', 's', 't', 'i', 'n', 'g',
0x05, 'l', 'o', 'c', 'a', 'l',
0x00,
0x00, 0x01, // TYPE = A (1)
0x80, 0x01, // CLASS = IN (1) | CACHE_FLUSH_BIT
0x00, 0x00, 0x00, 0x78, // TTL = 120 seconds
0x00, 0x04, // RDLENGTH = 4 bytes
0x08, 0x08, 0x08, 0x08, // RDATA = 8.8.8.8
};
// clang-format on
TestReadEntrySucceeds(
kTestRecord, sizeof(kTestRecord),
MdnsRecord(DomainName{"testing", "local"}, DnsType::kA, DnsClass::kIN,
true, 120, ARecordRdata(IPAddress{8, 8, 8, 8})));
}
TEST(MdnsReaderTest, ReadMdnsRecord_UnknownRecordType) {
// clang-format off
constexpr uint8_t kTestRecord[] = {
0x07, 't', 'e', 's', 't', 'i', 'n', 'g',
0x05, 'l', 'o', 'c', 'a', 'l',
0x00,
0x00, 0x05, // TYPE = CNAME (5)
0x80, 0x01, // CLASS = IN (1) | CACHE_FLUSH_BIT
0x00, 0x00, 0x00, 0x78, // TTL = 120 seconds
0x00, 0x08, // RDLENGTH = 8 bytes
0x05, 'c', 'n', 'a', 'm', 'e', 0xc0, 0x00,
};
constexpr uint8_t kCnameRdata[] = {
0x05, 'c', 'n', 'a', 'm', 'e', 0xc0, 0x00,
};
// clang-format on
TestReadEntrySucceeds(
kTestRecord, sizeof(kTestRecord),
MdnsRecord(DomainName{"testing", "local"},
static_cast<DnsType>(5) /*CNAME class*/, DnsClass::kIN, true,
120, RawRecordRdata(kCnameRdata, sizeof(kCnameRdata))));
}
TEST(MdnsReaderTest, ReadMdnsRecord_CompressedNames) {
// clang-format off
constexpr uint8_t kTestRecord[] = {
// First message
0x07, 't', 'e', 's', 't', 'i', 'n', 'g',
0x05, 'l', 'o', 'c', 'a', 'l',
0x00,
0x00, 0x0c, // TYPE = PTR (12)
0x00, 0x01, // CLASS = IN (1)
0x00, 0x00, 0x00, 0x78, // TTL = 120 seconds
0x00, 0x06, // RDLENGTH = 6 bytes
0x03, 'p', 't', 'r',
0xc0, 0x00, // Domain name label pointer to byte 0
// Second message
0x03, 'o', 'n', 'e',
0x03, 't', 'w', 'o',
0xc0, 0x00, // Domain name label pointer to byte 0
0x00, 0x01, // TYPE = A (1)
0x80, 0x01, // CLASS = IN (1) | CACHE_FLUSH_BIT
0x00, 0x00, 0x00, 0x78, // TTL = 120 seconds
0x00, 0x04, // RDLENGTH = 4 bytes
0x08, 0x08, 0x08, 0x08, // RDATA = 8.8.8.8
};
// clang-format on
MdnsReader reader(kTestRecord, sizeof(kTestRecord));
MdnsRecord record;
EXPECT_TRUE(reader.Read(&record));
EXPECT_EQ(record,
MdnsRecord(DomainName{"testing", "local"}, DnsType::kPTR,
DnsClass::kIN, false, 120,
PtrRecordRdata(DomainName{"ptr", "testing", "local"})));
EXPECT_TRUE(reader.Read(&record));
EXPECT_EQ(record, MdnsRecord(DomainName{"one", "two", "testing", "local"},
DnsType::kA, DnsClass::kIN, true, 120,
ARecordRdata(IPAddress{8, 8, 8, 8})));
}
TEST(MdnsReaderTest, ReadMdnsRecord_MissingRdata) {
// clang-format off
constexpr uint8_t kTestRecord[] = {
0x05, 'l', 'o', 'c', 'a', 'l',
0x00,
0x00, 0x01, // TYPE = A (1)
0x00, 0x01, // CLASS = IN (1)
0x00, 0x00, 0x00, 0x78, // TTL = 120 seconds
0x00, 0x04, // RDLENGTH = 4 bytes
// Missing RDATA
};
// clang-format on
TestReadEntryFails<MdnsRecord>(kTestRecord, sizeof(kTestRecord));
}
TEST(MdnsReaderTest, ReadMdnsRecord_InvalidHostName) {
// clang-format off
constexpr uint8_t kTestRecord[] = {
// Invalid NAME: length byte too short
0x03, 'i', 'n', 'v', 'a', 'l', 'i', 'd',
0x00,
0x00, 0x01, // TYPE = A (1)
0x00, 0x01, // CLASS = IN (1)
0x00, 0x00, 0x00, 0x78, // TTL = 120 seconds
0x00, 0x04, // RDLENGTH = 4 bytes
0x08, 0x08, 0x08, 0x08, // RDATA = 8.8.8.8
};
// clang-format on
TestReadEntryFails<MdnsRecord>(kTestRecord, sizeof(kTestRecord));
}
TEST(MdnsReaderTest, ReadMdnsQuestion) {
// clang-format off
constexpr uint8_t kTestQuestion[] = {
0x07, 't', 'e', 's', 't', 'i', 'n', 'g',
0x05, 'l', 'o', 'c', 'a', 'l',
0x00,
0x00, 0x01, // TYPE = A (1)
0x80, 0x01, // CLASS = IN (1) | UNICAST_BIT
};
// clang-format on
TestReadEntrySucceeds(kTestQuestion, sizeof(kTestQuestion),
MdnsQuestion(DomainName{"testing", "local"},
DnsType::kA, DnsClass::kIN, true));
}
TEST(MdnsReaderTest, ReadMdnsQuestion_CompressedNames) {
// clang-format off
constexpr uint8_t kTestQuestions[] = {
// First Question
0x05, 'f', 'i', 'r', 's', 't',
0x05, 'l', 'o', 'c', 'a', 'l',
0x00,
0x00, 0x01, // TYPE = A (1)
0x80, 0x01, // CLASS = IN (1) | UNICAST_BIT
// Second Question
0x06, 's', 'e', 'c', 'o', 'n', 'd',
0xc0, 0x06, // Domain name label pointer
0x00, 0x0c, // TYPE = PTR (12)
0x00, 0x01, // CLASS = IN (1)
};
// clang-format on
MdnsReader reader(kTestQuestions, sizeof(kTestQuestions));
MdnsQuestion question;
EXPECT_TRUE(reader.Read(&question));
EXPECT_EQ(question, MdnsQuestion(DomainName{"first", "local"}, DnsType::kA,
DnsClass::kIN, true));
EXPECT_TRUE(reader.Read(&question));
EXPECT_EQ(question, MdnsQuestion(DomainName{"second", "local"}, DnsType::kPTR,
DnsClass::kIN, false));
EXPECT_EQ(reader.remaining(), UINT64_C(0));
}
TEST(MdnsReaderTest, ReadMdnsQuestion_InvalidHostName) {
// clang-format off
constexpr uint8_t kTestQuestion[] = {
// Invalid NAME: length byte too short
0x03, 'i', 'n', 'v', 'a', 'l', 'i', 'd',
0x00,
0x00, 0x01, // TYPE = A (1)
0x00, 0x01, // CLASS = IN (1)
};
// clang-format on
TestReadEntryFails<MdnsQuestion>(kTestQuestion, sizeof(kTestQuestion));
}
TEST(MdnsReaderTest, ReadMdnsMessage) {
// clang-format off
constexpr uint8_t kTestMessage[] = {
// Header
0x00, 0x01, // ID = 1
0x84, 0x00, // FLAGS = AA | RESPONSE
0x00, 0x00, // Questions = 0
0x00, 0x01, // Answers = 1
0x00, 0x00, // Authority = 0
0x00, 0x01, // Additional = 1
// Record 1
0x07, 'r', 'e', 'c', 'o', 'r', 'd', '1',
0x00,
0x00, 0x0c, // TYPE = PTR (12)
0x00, 0x01, // CLASS = IN (1)
0x00, 0x00, 0x00, 0x78, // TTL = 120 seconds
0x00, 0x0f, // RDLENGTH = 15 bytes
0x07, 't', 'e', 's', 't', 'i', 'n', 'g',
0x05, 'l', 'o', 'c', 'a', 'l',
0x00,
// Record 2
0x07, 'r', 'e', 'c', 'o', 'r', 'd', '2',
0x00,
0x00, 0x01, // TYPE = A (1)
0x00, 0x01, // CLASS = IN (1)
0x00, 0x00, 0x00, 0x78, // TTL = 120 seconds
0x00, 0x04, // RDLENGTH = 4 bytes
0xac, 0x00, 0x00, 0x01, // 172.0.0.1
};
// clang-format on
MdnsRecord record1(DomainName{"record1"}, DnsType::kPTR, DnsClass::kIN, false,
120, PtrRecordRdata(DomainName{"testing", "local"}));
MdnsRecord record2(DomainName{"record2"}, DnsType::kA, DnsClass::kIN, false,
120, ARecordRdata(IPAddress{172, 0, 0, 1}));
MdnsMessage message(1, MessageType::Response, std::vector<MdnsQuestion>{},
std::vector<MdnsRecord>{record1},
std::vector<MdnsRecord>{},
std::vector<MdnsRecord>{record2});
TestReadEntrySucceeds(kTestMessage, sizeof(kTestMessage), message);
}
TEST(MdnsReaderTest, ReadMdnsMessage_MissingAnswerRecord) {
// clang-format off
constexpr uint8_t kInvalidMessage[] = {
0x00, 0x00, // ID = 0
0x00, 0x00, // FLAGS = 0
0x00, 0x01, // Questions = 1
0x00, 0x01, // Answers = 1
0x00, 0x00, // Authority = 0
0x00, 0x00, // Additional = 0
0x07, 't', 'e', 's', 't', 'i', 'n', 'g',
0x05, 'l', 'o', 'c', 'a', 'l',
0x00,
0x00, 0x0c, // TYPE = PTR (12)
0x00, 0x01, // CLASS = IN (1)
// NOTE: Missing answer record
};
// clang-format on
TestReadEntryFails<MdnsMessage>(kInvalidMessage, sizeof(kInvalidMessage));
}
TEST(MdnsReaderTest, ReadMdnsMessage_MissingAdditionalRecord) {
// clang-format off
constexpr uint8_t kInvalidMessage[] = {
0x00, 0x00, // ID = 0
0x00, 0x00, // FLAGS = 0
0x00, 0x00, // Questions = 0
0x00, 0x00, // Answers = 0
0x00, 0x00, // Authority = 0
0x00, 0x02, // Additional = 2
0x07, 't', 'e', 's', 't', 'i', 'n', 'g',
0x05, 'l', 'o', 'c', 'a', 'l',
0x00,
0x00, 0x0c, // TYPE = PTR (12)
0x00, 0x01, // CLASS = IN (1)
0x00, 0x00, 0x00, 0x78, // TTL = 120 seconds
0x00, 0x00, // RDLENGTH = 0
// NOTE: Only 1 answer record is given.
};
// clang-format on
TestReadEntryFails<MdnsMessage>(kInvalidMessage, sizeof(kInvalidMessage));
}
} // namespace mdns
} // namespace cast