Add the multicast DNS message format.
This CL adds the utilities to generate and parse mDNS messages (RFC 1035 and RFC 6762). TBR=phoglund@webrtc.org Bug: webrtc:9605 Change-Id: Id6121c17926887cd3a41a2dfc829462fd15f3a4c Reviewed-on: https://webrtc-review.googlesource.com/93241 Commit-Queue: Qingsi Wang <qingsi@google.com> Reviewed-by: Mirko Bonadei <mbonadei@webrtc.org> Reviewed-by: Qingsi Wang <qingsi@webrtc.org> Reviewed-by: Steve Anton <steveanton@webrtc.org> Reviewed-by: Alex Loiko <aleloi@webrtc.org> Cr-Commit-Position: refs/heads/master@{#24505}
This commit is contained in:
@ -31,6 +31,8 @@ rtc_static_library("rtc_p2p") {
|
|||||||
"base/dtlstransportinternal.h",
|
"base/dtlstransportinternal.h",
|
||||||
"base/icetransportinternal.cc",
|
"base/icetransportinternal.cc",
|
||||||
"base/icetransportinternal.h",
|
"base/icetransportinternal.h",
|
||||||
|
"base/mdns_message.cc",
|
||||||
|
"base/mdns_message.h",
|
||||||
"base/p2pconstants.cc",
|
"base/p2pconstants.cc",
|
||||||
"base/p2pconstants.h",
|
"base/p2pconstants.h",
|
||||||
"base/p2ptransportchannel.cc",
|
"base/p2ptransportchannel.cc",
|
||||||
@ -150,6 +152,7 @@ if (rtc_include_tests) {
|
|||||||
"base/asyncstuntcpsocket_unittest.cc",
|
"base/asyncstuntcpsocket_unittest.cc",
|
||||||
"base/basicasyncresolverfactory_unittest.cc",
|
"base/basicasyncresolverfactory_unittest.cc",
|
||||||
"base/dtlstransport_unittest.cc",
|
"base/dtlstransport_unittest.cc",
|
||||||
|
"base/mdns_message_unittest.cc",
|
||||||
"base/p2ptransportchannel_unittest.cc",
|
"base/p2ptransportchannel_unittest.cc",
|
||||||
"base/packetlossestimator_unittest.cc",
|
"base/packetlossestimator_unittest.cc",
|
||||||
"base/port_unittest.cc",
|
"base/port_unittest.cc",
|
||||||
|
395
p2p/base/mdns_message.cc
Normal file
395
p2p/base/mdns_message.cc
Normal file
@ -0,0 +1,395 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2018 The WebRTC Project Authors. All rights reserved.
|
||||||
|
*
|
||||||
|
* Use of this source code is governed by a BSD-style license
|
||||||
|
* that can be found in the LICENSE file in the root of the source
|
||||||
|
* tree. An additional intellectual property rights grant can be found
|
||||||
|
* in the file PATENTS. All contributing project authors may
|
||||||
|
* be found in the AUTHORS file in the root of the source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "p2p/base/mdns_message.h"
|
||||||
|
#include "rtc_base/logging.h"
|
||||||
|
#include "rtc_base/nethelpers.h"
|
||||||
|
#include "rtc_base/stringencode.h"
|
||||||
|
|
||||||
|
namespace webrtc {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
// RFC 1035, Section 4.1.1.
|
||||||
|
//
|
||||||
|
// QR bit.
|
||||||
|
constexpr uint16_t kMDnsFlagMaskQueryOrResponse = 0x8000;
|
||||||
|
// AA bit.
|
||||||
|
constexpr uint16_t kMDnsFlagMaskAuthoritative = 0x0400;
|
||||||
|
// RFC 1035, Section 4.1.2, QCLASS and RFC 6762, Section 18.12, repurposing of
|
||||||
|
// top bit of QCLASS as the unicast response bit.
|
||||||
|
constexpr uint16_t kMDnsQClassMaskUnicastResponse = 0x8000;
|
||||||
|
constexpr size_t kMDnsHeaderSizeBytes = 12;
|
||||||
|
|
||||||
|
bool ReadDomainName(MessageBufferReader* buf, std::string* name) {
|
||||||
|
size_t name_start_pos = buf->CurrentOffset();
|
||||||
|
uint8_t label_length;
|
||||||
|
if (!buf->ReadUInt8(&label_length)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// RFC 1035, Section 4.1.4.
|
||||||
|
//
|
||||||
|
// If the first two bits of the length octet are ones, the name is compressed
|
||||||
|
// and the rest six bits with the next octet denotes its position in the
|
||||||
|
// message by the offset from the start of the message.
|
||||||
|
auto is_pointer = [](uint8_t octet) {
|
||||||
|
return (octet & 0x80) && (octet & 0x40);
|
||||||
|
};
|
||||||
|
while (label_length && !is_pointer(label_length)) {
|
||||||
|
// RFC 1035, Section 2.3.1, labels are restricted to 63 octets or less.
|
||||||
|
if (label_length > 63) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
std::string label;
|
||||||
|
if (!buf->ReadString(&label, label_length)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
(*name) += label + ".";
|
||||||
|
if (!buf->ReadUInt8(&label_length)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (is_pointer(label_length)) {
|
||||||
|
uint8_t next_octet;
|
||||||
|
if (!buf->ReadUInt8(&next_octet)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
size_t pos_jump_to = ((label_length & 0x3f) << 8) | next_octet;
|
||||||
|
// A legitimate pointer only refers to a prior occurrence of the same name,
|
||||||
|
// and we should only move strictly backward to a prior name field after the
|
||||||
|
// header.
|
||||||
|
if (pos_jump_to >= name_start_pos || pos_jump_to < kMDnsHeaderSizeBytes) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
MessageBufferReader new_buf(buf->MessageData(), buf->MessageLength());
|
||||||
|
if (!new_buf.Consume(pos_jump_to)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return ReadDomainName(&new_buf, name);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WriteDomainName(rtc::ByteBufferWriter* buf, const std::string& name) {
|
||||||
|
std::vector<std::string> labels;
|
||||||
|
rtc::tokenize(name, '.', &labels);
|
||||||
|
for (const auto& label : labels) {
|
||||||
|
buf->WriteUInt8(label.length());
|
||||||
|
buf->WriteString(label);
|
||||||
|
}
|
||||||
|
buf->WriteUInt8(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
void MDnsHeader::SetQueryOrResponse(bool is_query) {
|
||||||
|
if (is_query) {
|
||||||
|
flags &= ~kMDnsFlagMaskQueryOrResponse;
|
||||||
|
} else {
|
||||||
|
flags |= kMDnsFlagMaskQueryOrResponse;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MDnsHeader::SetAuthoritative(bool is_authoritative) {
|
||||||
|
if (is_authoritative) {
|
||||||
|
flags |= kMDnsFlagMaskAuthoritative;
|
||||||
|
} else {
|
||||||
|
flags &= ~kMDnsFlagMaskAuthoritative;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MDnsHeader::IsAuthoritative() const {
|
||||||
|
return flags & kMDnsFlagMaskAuthoritative;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MDnsHeader::Read(MessageBufferReader* buf) {
|
||||||
|
if (!buf->ReadUInt16(&id) || !buf->ReadUInt16(&flags) ||
|
||||||
|
!buf->ReadUInt16(&qdcount) || !buf->ReadUInt16(&ancount) ||
|
||||||
|
!buf->ReadUInt16(&nscount) || !buf->ReadUInt16(&arcount)) {
|
||||||
|
RTC_LOG(LS_ERROR) << "Invalid mDNS header.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MDnsHeader::Write(rtc::ByteBufferWriter* buf) const {
|
||||||
|
buf->WriteUInt16(id);
|
||||||
|
buf->WriteUInt16(flags);
|
||||||
|
buf->WriteUInt16(qdcount);
|
||||||
|
buf->WriteUInt16(ancount);
|
||||||
|
buf->WriteUInt16(nscount);
|
||||||
|
buf->WriteUInt16(arcount);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MDnsHeader::IsQuery() const {
|
||||||
|
return !(flags & kMDnsFlagMaskQueryOrResponse);
|
||||||
|
}
|
||||||
|
|
||||||
|
MDnsSectionEntry::MDnsSectionEntry() = default;
|
||||||
|
MDnsSectionEntry::~MDnsSectionEntry() = default;
|
||||||
|
MDnsSectionEntry::MDnsSectionEntry(const MDnsSectionEntry& other) = default;
|
||||||
|
|
||||||
|
void MDnsSectionEntry::SetType(SectionEntryType type) {
|
||||||
|
switch (type) {
|
||||||
|
case SectionEntryType::kA:
|
||||||
|
type_ = 1;
|
||||||
|
return;
|
||||||
|
case SectionEntryType::kAAAA:
|
||||||
|
type_ = 28;
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
RTC_NOTREACHED();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SectionEntryType MDnsSectionEntry::GetType() const {
|
||||||
|
switch (type_) {
|
||||||
|
case 1:
|
||||||
|
return SectionEntryType::kA;
|
||||||
|
case 28:
|
||||||
|
return SectionEntryType::kAAAA;
|
||||||
|
default:
|
||||||
|
return SectionEntryType::kUnsupported;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MDnsSectionEntry::SetClass(SectionEntryClass cls) {
|
||||||
|
switch (cls) {
|
||||||
|
case SectionEntryClass::kIN:
|
||||||
|
class_ = 1;
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
RTC_NOTREACHED();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SectionEntryClass MDnsSectionEntry::GetClass() const {
|
||||||
|
switch (class_) {
|
||||||
|
case 1:
|
||||||
|
return SectionEntryClass::kIN;
|
||||||
|
default:
|
||||||
|
return SectionEntryClass::kUnsupported;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MDnsQuestion::MDnsQuestion() = default;
|
||||||
|
MDnsQuestion::MDnsQuestion(const MDnsQuestion& other) = default;
|
||||||
|
MDnsQuestion::~MDnsQuestion() = default;
|
||||||
|
|
||||||
|
bool MDnsQuestion::Read(MessageBufferReader* buf) {
|
||||||
|
if (!ReadDomainName(buf, &name_)) {
|
||||||
|
RTC_LOG(LS_ERROR) << "Invalid name.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!buf->ReadUInt16(&type_) || !buf->ReadUInt16(&class_)) {
|
||||||
|
RTC_LOG(LS_ERROR) << "Invalid type and class.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MDnsQuestion::Write(rtc::ByteBufferWriter* buf) const {
|
||||||
|
WriteDomainName(buf, name_);
|
||||||
|
buf->WriteUInt16(type_);
|
||||||
|
buf->WriteUInt16(class_);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MDnsQuestion::SetUnicastResponse(bool should_unicast) {
|
||||||
|
if (should_unicast) {
|
||||||
|
class_ |= kMDnsQClassMaskUnicastResponse;
|
||||||
|
} else {
|
||||||
|
class_ &= ~kMDnsQClassMaskUnicastResponse;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MDnsQuestion::ShouldUnicastResponse() const {
|
||||||
|
return class_ & kMDnsQClassMaskUnicastResponse;
|
||||||
|
}
|
||||||
|
|
||||||
|
MDnsResourceRecord::MDnsResourceRecord() = default;
|
||||||
|
MDnsResourceRecord::MDnsResourceRecord(const MDnsResourceRecord& other) =
|
||||||
|
default;
|
||||||
|
MDnsResourceRecord::~MDnsResourceRecord() = default;
|
||||||
|
|
||||||
|
bool MDnsResourceRecord::Read(MessageBufferReader* buf) {
|
||||||
|
if (!ReadDomainName(buf, &name_)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!buf->ReadUInt16(&type_) || !buf->ReadUInt16(&class_) ||
|
||||||
|
!buf->ReadUInt32(&ttl_seconds_) || !buf->ReadUInt16(&rdlength_)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (GetType()) {
|
||||||
|
case SectionEntryType::kA:
|
||||||
|
return ReadARData(buf);
|
||||||
|
case SectionEntryType::kAAAA:
|
||||||
|
return ReadQuadARData(buf);
|
||||||
|
case SectionEntryType::kUnsupported:
|
||||||
|
return false;
|
||||||
|
default:
|
||||||
|
RTC_NOTREACHED();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
bool MDnsResourceRecord::ReadARData(MessageBufferReader* buf) {
|
||||||
|
// A RDATA contains a 32-bit IPv4 address.
|
||||||
|
return buf->ReadString(&rdata_, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MDnsResourceRecord::ReadQuadARData(MessageBufferReader* buf) {
|
||||||
|
// AAAA RDATA contains a 128-bit IPv6 address.
|
||||||
|
return buf->ReadString(&rdata_, 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MDnsResourceRecord::Write(rtc::ByteBufferWriter* buf) const {
|
||||||
|
WriteDomainName(buf, name_);
|
||||||
|
buf->WriteUInt16(type_);
|
||||||
|
buf->WriteUInt16(class_);
|
||||||
|
buf->WriteUInt32(ttl_seconds_);
|
||||||
|
buf->WriteUInt16(rdlength_);
|
||||||
|
switch (GetType()) {
|
||||||
|
case SectionEntryType::kA:
|
||||||
|
WriteARData(buf);
|
||||||
|
return true;
|
||||||
|
case SectionEntryType::kAAAA:
|
||||||
|
WriteQuadARData(buf);
|
||||||
|
return true;
|
||||||
|
case SectionEntryType::kUnsupported:
|
||||||
|
return false;
|
||||||
|
default:
|
||||||
|
RTC_NOTREACHED();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MDnsResourceRecord::WriteARData(rtc::ByteBufferWriter* buf) const {
|
||||||
|
buf->WriteString(rdata_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MDnsResourceRecord::WriteQuadARData(rtc::ByteBufferWriter* buf) const {
|
||||||
|
buf->WriteString(rdata_);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MDnsResourceRecord::SetIPAddressInRecordData(
|
||||||
|
const rtc::IPAddress& address) {
|
||||||
|
int af = address.family();
|
||||||
|
if (af != AF_INET && af != AF_INET6) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
char out[16] = {0};
|
||||||
|
if (!rtc::inet_pton(af, address.ToString().c_str(), out)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
rdlength_ = (af == AF_INET) ? 4 : 16;
|
||||||
|
rdata_ = std::string(out, rdlength_);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MDnsResourceRecord::GetIPAddressFromRecordData(
|
||||||
|
rtc::IPAddress* address) const {
|
||||||
|
if (GetType() != SectionEntryType::kA &&
|
||||||
|
GetType() != SectionEntryType::kAAAA) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (rdata_.size() != 4 && rdata_.size() != 16) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
char out[INET6_ADDRSTRLEN] = {0};
|
||||||
|
int af = (GetType() == SectionEntryType::kA) ? AF_INET : AF_INET6;
|
||||||
|
if (!rtc::inet_ntop(af, rdata_.data(), out, sizeof(out))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return rtc::IPFromString(std::string(out), address);
|
||||||
|
}
|
||||||
|
|
||||||
|
MDnsMessage::MDnsMessage() = default;
|
||||||
|
MDnsMessage::~MDnsMessage() = default;
|
||||||
|
|
||||||
|
bool MDnsMessage::Read(MessageBufferReader* buf) {
|
||||||
|
RTC_DCHECK_EQ(0u, buf->CurrentOffset());
|
||||||
|
if (!header_.Read(buf)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto read_question = [&buf](std::vector<MDnsQuestion>* section,
|
||||||
|
uint16_t count) {
|
||||||
|
section->resize(count);
|
||||||
|
for (auto& question : (*section)) {
|
||||||
|
if (!question.Read(buf)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
auto read_rr = [&buf](std::vector<MDnsResourceRecord>* section,
|
||||||
|
uint16_t count) {
|
||||||
|
section->resize(count);
|
||||||
|
for (auto& rr : (*section)) {
|
||||||
|
if (!rr.Read(buf)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!read_question(&question_section_, header_.qdcount) ||
|
||||||
|
!read_rr(&answer_section_, header_.ancount) ||
|
||||||
|
!read_rr(&authority_section_, header_.nscount) ||
|
||||||
|
!read_rr(&additional_section_, header_.arcount)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MDnsMessage::Write(rtc::ByteBufferWriter* buf) const {
|
||||||
|
header_.Write(buf);
|
||||||
|
|
||||||
|
auto write_rr = [&buf](const std::vector<MDnsResourceRecord>& section) {
|
||||||
|
for (auto rr : section) {
|
||||||
|
if (!rr.Write(buf)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
for (auto question : question_section_) {
|
||||||
|
if (!question.Write(buf)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!write_rr(answer_section_) || !write_rr(authority_section_) ||
|
||||||
|
!write_rr(additional_section_)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MDnsMessage::ShouldUnicastResponse() const {
|
||||||
|
bool should_unicast = false;
|
||||||
|
for (const auto& question : question_section_) {
|
||||||
|
should_unicast |= question.ShouldUnicastResponse();
|
||||||
|
}
|
||||||
|
return should_unicast;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MDnsMessage::AddQuestion(const MDnsQuestion& question) {
|
||||||
|
question_section_.push_back(question);
|
||||||
|
header_.qdcount = question_section_.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MDnsMessage::AddAnswerRecord(const MDnsResourceRecord& answer) {
|
||||||
|
answer_section_.push_back(answer);
|
||||||
|
header_.ancount = answer_section_.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace webrtc
|
207
p2p/base/mdns_message.h
Normal file
207
p2p/base/mdns_message.h
Normal file
@ -0,0 +1,207 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2018 The WebRTC Project Authors. All rights reserved.
|
||||||
|
*
|
||||||
|
* Use of this source code is governed by a BSD-style license
|
||||||
|
* that can be found in the LICENSE file in the root of the source
|
||||||
|
* tree. An additional intellectual property rights grant can be found
|
||||||
|
* in the file PATENTS. All contributing project authors may
|
||||||
|
* be found in the AUTHORS file in the root of the source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef P2P_BASE_MDNS_MESSAGE_H_
|
||||||
|
#define P2P_BASE_MDNS_MESSAGE_H_
|
||||||
|
|
||||||
|
// This file contains classes to read and write mDNSs message defined in RFC
|
||||||
|
// 6762 and RFC 1025 (DNS messages). Note that it is recommended by RFC 6762 to
|
||||||
|
// use the name compression scheme defined in RFC 1035 whenever possible. We
|
||||||
|
// currently only implement the capability of reading compressed names in mDNS
|
||||||
|
// messages in MDnsMessage::Read(); however, the MDnsMessage::Write() does not
|
||||||
|
// support name compression yet.
|
||||||
|
//
|
||||||
|
// Fuzzer tests (test/fuzzers/mdns_parser_fuzzer.cc) MUST always be performed
|
||||||
|
// after changes made to this file.
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <memory>
|
||||||
|
#include <set>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "rtc_base/bytebuffer.h"
|
||||||
|
#include "rtc_base/ipaddress.h"
|
||||||
|
#include "rtc_base/message_buffer_reader.h"
|
||||||
|
|
||||||
|
namespace webrtc {
|
||||||
|
|
||||||
|
// We use "section entry" to denote either a question or a resource record.
|
||||||
|
//
|
||||||
|
// RFC 1035 Section 3.2.2.
|
||||||
|
enum class SectionEntryType {
|
||||||
|
kA,
|
||||||
|
kAAAA,
|
||||||
|
// Only the above types are processed in the current implementation.
|
||||||
|
kUnsupported,
|
||||||
|
};
|
||||||
|
|
||||||
|
// RFC 1035 Section 3.2.4.
|
||||||
|
enum class SectionEntryClass {
|
||||||
|
kIN,
|
||||||
|
kUnsupported,
|
||||||
|
};
|
||||||
|
|
||||||
|
// RFC 1035, Section 4.1.1.
|
||||||
|
class MDnsHeader final {
|
||||||
|
public:
|
||||||
|
bool Read(MessageBufferReader* buf);
|
||||||
|
void Write(rtc::ByteBufferWriter* buf) const;
|
||||||
|
|
||||||
|
void SetQueryOrResponse(bool is_query);
|
||||||
|
bool IsQuery() const;
|
||||||
|
void SetAuthoritative(bool is_authoritative);
|
||||||
|
bool IsAuthoritative() const;
|
||||||
|
|
||||||
|
uint16_t id = 0;
|
||||||
|
uint16_t flags = 0;
|
||||||
|
// Number of entries in the question section.
|
||||||
|
uint16_t qdcount = 0;
|
||||||
|
// Number of resource records in the answer section.
|
||||||
|
uint16_t ancount = 0;
|
||||||
|
// Number of name server resource records in the authority records section.
|
||||||
|
uint16_t nscount = 0;
|
||||||
|
// Number of resource records in the additional records section.
|
||||||
|
uint16_t arcount = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Entries in each section after the header share a common structure. Note that
|
||||||
|
// this is not a concept defined in RFC 1035.
|
||||||
|
class MDnsSectionEntry {
|
||||||
|
public:
|
||||||
|
MDnsSectionEntry();
|
||||||
|
MDnsSectionEntry(const MDnsSectionEntry& other);
|
||||||
|
virtual ~MDnsSectionEntry();
|
||||||
|
virtual bool Read(MessageBufferReader* buf) = 0;
|
||||||
|
virtual bool Write(rtc::ByteBufferWriter* buf) const = 0;
|
||||||
|
|
||||||
|
void SetName(const std::string& name) { name_ = name; }
|
||||||
|
// Returns the fully qualified domain name in the section entry, i.e., QNAME
|
||||||
|
// in a question or NAME in a resource record.
|
||||||
|
std::string GetName() const { return name_; }
|
||||||
|
|
||||||
|
void SetType(SectionEntryType type);
|
||||||
|
SectionEntryType GetType() const;
|
||||||
|
void SetClass(SectionEntryClass cls);
|
||||||
|
SectionEntryClass GetClass() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::string name_; // Fully qualified domain name.
|
||||||
|
uint16_t type_ = 0;
|
||||||
|
uint16_t class_ = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
// RFC 1035, Section 4.1.2.
|
||||||
|
class MDnsQuestion final : public MDnsSectionEntry {
|
||||||
|
public:
|
||||||
|
MDnsQuestion();
|
||||||
|
MDnsQuestion(const MDnsQuestion& other);
|
||||||
|
~MDnsQuestion() override;
|
||||||
|
|
||||||
|
bool Read(MessageBufferReader* buf) override;
|
||||||
|
bool Write(rtc::ByteBufferWriter* buf) const override;
|
||||||
|
|
||||||
|
void SetUnicastResponse(bool should_unicast);
|
||||||
|
bool ShouldUnicastResponse() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
// RFC 1035, Section 4.1.3.
|
||||||
|
class MDnsResourceRecord final : public MDnsSectionEntry {
|
||||||
|
public:
|
||||||
|
MDnsResourceRecord();
|
||||||
|
MDnsResourceRecord(const MDnsResourceRecord& other);
|
||||||
|
~MDnsResourceRecord() override;
|
||||||
|
|
||||||
|
bool Read(MessageBufferReader* buf) override;
|
||||||
|
bool Write(rtc::ByteBufferWriter* buf) const override;
|
||||||
|
|
||||||
|
void SetTtlSeconds(uint32_t ttl_seconds) { ttl_seconds_ = ttl_seconds; }
|
||||||
|
uint32_t GetTtlSeconds() const { return ttl_seconds_; }
|
||||||
|
// Returns true if |address| is in the address family AF_INET or AF_INET6 and
|
||||||
|
// |address| has a valid IPv4 or IPv6 address; false otherwise.
|
||||||
|
bool SetIPAddressInRecordData(const rtc::IPAddress& address);
|
||||||
|
// Returns true if the record is of type A or AAAA and the record has a valid
|
||||||
|
// IPv4 or IPv6 address; false otherwise. Stores the valid IP in |address|.
|
||||||
|
bool GetIPAddressFromRecordData(rtc::IPAddress* address) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
// The list of methods reading and writing rdata can grow as we support more
|
||||||
|
// types of rdata.
|
||||||
|
bool ReadARData(MessageBufferReader* buf);
|
||||||
|
void WriteARData(rtc::ByteBufferWriter* buf) const;
|
||||||
|
|
||||||
|
bool ReadQuadARData(MessageBufferReader* buf);
|
||||||
|
void WriteQuadARData(rtc::ByteBufferWriter* buf) const;
|
||||||
|
|
||||||
|
uint32_t ttl_seconds_ = 0;
|
||||||
|
uint16_t rdlength_ = 0;
|
||||||
|
std::string rdata_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class MDnsMessage final {
|
||||||
|
public:
|
||||||
|
// RFC 1035, Section 4.1.
|
||||||
|
enum class Section { kQuestion, kAnswer, kAuthority, kAdditional };
|
||||||
|
|
||||||
|
MDnsMessage();
|
||||||
|
~MDnsMessage();
|
||||||
|
// Reads the mDNS message in |buf| and populates the corresponding fields in
|
||||||
|
// MDnsMessage.
|
||||||
|
bool Read(MessageBufferReader* buf);
|
||||||
|
// Write an mDNS message to |buf| based on the fields in MDnsMessage.
|
||||||
|
//
|
||||||
|
// TODO(qingsi): Implement name compression when writing mDNS messages.
|
||||||
|
bool Write(rtc::ByteBufferWriter* buf) const;
|
||||||
|
|
||||||
|
void SetId(uint16_t id) { header_.id = id; }
|
||||||
|
uint16_t GetId() const { return header_.id; }
|
||||||
|
|
||||||
|
void SetQueryOrResponse(bool is_query) {
|
||||||
|
header_.SetQueryOrResponse(is_query);
|
||||||
|
}
|
||||||
|
bool IsQuery() const { return header_.IsQuery(); }
|
||||||
|
|
||||||
|
void SetAuthoritative(bool is_authoritative) {
|
||||||
|
header_.SetAuthoritative(is_authoritative);
|
||||||
|
}
|
||||||
|
bool IsAuthoritative() const { return header_.IsAuthoritative(); }
|
||||||
|
|
||||||
|
// Returns true if the message is a query and the unicast response is
|
||||||
|
// preferred. False otherwise.
|
||||||
|
bool ShouldUnicastResponse() const;
|
||||||
|
|
||||||
|
void AddQuestion(const MDnsQuestion& question);
|
||||||
|
// TODO(qingsi): Implement AddXRecord for name server and additional records.
|
||||||
|
void AddAnswerRecord(const MDnsResourceRecord& answer);
|
||||||
|
|
||||||
|
const std::vector<MDnsQuestion>& question_section() const {
|
||||||
|
return question_section_;
|
||||||
|
}
|
||||||
|
const std::vector<MDnsResourceRecord>& answer_section() const {
|
||||||
|
return answer_section_;
|
||||||
|
}
|
||||||
|
const std::vector<MDnsResourceRecord>& authority_section() const {
|
||||||
|
return authority_section_;
|
||||||
|
}
|
||||||
|
const std::vector<MDnsResourceRecord>& additional_section() const {
|
||||||
|
return additional_section_;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
MDnsHeader header_;
|
||||||
|
std::vector<MDnsQuestion> question_section_;
|
||||||
|
std::vector<MDnsResourceRecord> answer_section_;
|
||||||
|
std::vector<MDnsResourceRecord> authority_section_;
|
||||||
|
std::vector<MDnsResourceRecord> additional_section_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace webrtc
|
||||||
|
|
||||||
|
#endif // P2P_BASE_MDNS_MESSAGE_H_
|
570
p2p/base/mdns_message_unittest.cc
Normal file
570
p2p/base/mdns_message_unittest.cc
Normal file
@ -0,0 +1,570 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2018 The WebRTC Project Authors. All rights reserved.
|
||||||
|
*
|
||||||
|
* Use of this source code is governed by a BSD-style license
|
||||||
|
* that can be found in the LICENSE file in the root of the source
|
||||||
|
* tree. An additional intellectual property rights grant can be found
|
||||||
|
* in the file PATENTS. All contributing project authors may
|
||||||
|
* be found in the AUTHORS file in the root of the source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <set>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "p2p/base/mdns_message.h"
|
||||||
|
#include "rtc_base/bytebuffer.h"
|
||||||
|
#include "rtc_base/gunit.h"
|
||||||
|
#include "rtc_base/ipaddress.h"
|
||||||
|
#include "rtc_base/socketaddress.h"
|
||||||
|
#include "test/gmock.h"
|
||||||
|
|
||||||
|
#define ReadMDnsMessage(X, Y) ReadMDnsMessageTestCase(X, Y, sizeof(Y))
|
||||||
|
#define WriteMDnsMessageAndCompare(X, Y) \
|
||||||
|
WriteMDnsMessageAndCompareWithTestCast(X, Y, sizeof(Y))
|
||||||
|
|
||||||
|
using ::testing::ElementsAre;
|
||||||
|
using ::testing::Pair;
|
||||||
|
using ::testing::UnorderedElementsAre;
|
||||||
|
|
||||||
|
namespace webrtc {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
const uint8_t kSingleQuestionForIPv4AddrWithUnicastResponse[] = {
|
||||||
|
0x12, 0x34, // ID
|
||||||
|
0x00, 0x00, // flags
|
||||||
|
0x00, 0x01, // number of questions
|
||||||
|
0x00, 0x00, // number of answer rr
|
||||||
|
0x00, 0x00, // number of name server rr
|
||||||
|
0x00, 0x00, // number of additional rr
|
||||||
|
0x06, 0x77, 0x65, 0x62, 0x72, 0x74, 0x63, // webrtc
|
||||||
|
0x03, 0x6f, 0x72, 0x67, // org
|
||||||
|
0x00, // null label
|
||||||
|
0x00, 0x01, // type A Record
|
||||||
|
0x80, 0x01, // class IN, unicast response
|
||||||
|
};
|
||||||
|
|
||||||
|
const uint8_t kTwoQuestionsForIPv4AndIPv6AddrWithMulticastResponse[] = {
|
||||||
|
0x12, 0x34, // ID
|
||||||
|
0x00, 0x00, // flags
|
||||||
|
0x00, 0x02, // number of questions
|
||||||
|
0x00, 0x00, // number of answer rr
|
||||||
|
0x00, 0x00, // number of name server rr
|
||||||
|
0x00, 0x00, // number of additional rr
|
||||||
|
0x07, 0x77, 0x65, 0x62, 0x72, 0x74, 0x63, 0x34, // webrtc4
|
||||||
|
0x03, 0x6f, 0x72, 0x67, // org
|
||||||
|
0x00, // null label
|
||||||
|
0x00, 0x01, // type A Record
|
||||||
|
0x00, 0x01, // class IN, multicast response
|
||||||
|
0x07, 0x77, 0x65, 0x62, 0x72, 0x74, 0x63, 0x36, // webrtc6
|
||||||
|
0x03, 0x6f, 0x72, 0x67, // org
|
||||||
|
0x00, // null label
|
||||||
|
0x00, 0x1C, // type AAAA Record
|
||||||
|
0x00, 0x01, // class IN, multicast response
|
||||||
|
};
|
||||||
|
|
||||||
|
const uint8_t
|
||||||
|
kTwoQuestionsForIPv4AndIPv6AddrWithMulticastResponseAndNameCompression[] = {
|
||||||
|
0x12, 0x34, // ID
|
||||||
|
0x00, 0x00, // flags
|
||||||
|
0x00, 0x02, // number of questions
|
||||||
|
0x00, 0x00, // number of answer rr
|
||||||
|
0x00, 0x00, // number of name server rr
|
||||||
|
0x00, 0x00, // number of additional rr
|
||||||
|
0x03, 0x77, 0x77, 0x77, // www
|
||||||
|
0x06, 0x77, 0x65, 0x62, 0x72, 0x74, 0x63, // webrtc
|
||||||
|
0x03, 0x6f, 0x72, 0x67, // org
|
||||||
|
0x00, // null label
|
||||||
|
0x00, 0x01, // type A Record
|
||||||
|
0x00, 0x01, // class IN, multicast response
|
||||||
|
0x04, 0x6d, 0x64, 0x6e, 0x73, // mdns
|
||||||
|
0xc0, 0x10, // offset 16, webrtc.org.
|
||||||
|
0x00, 0x1C, // type AAAA Record
|
||||||
|
0x00, 0x01, // class IN, multicast response
|
||||||
|
};
|
||||||
|
|
||||||
|
const uint8_t kThreeQuestionsWithTwoPointersToTheSameNameSuffix[] = {
|
||||||
|
0x12, 0x34, // ID
|
||||||
|
0x00, 0x00, // flags
|
||||||
|
0x00, 0x03, // number of questions
|
||||||
|
0x00, 0x00, // number of answer rr
|
||||||
|
0x00, 0x00, // number of name server rr
|
||||||
|
0x00, 0x00, // number of additional rr
|
||||||
|
0x03, 0x77, 0x77, 0x77, // www
|
||||||
|
0x06, 0x77, 0x65, 0x62, 0x72, 0x74, 0x63, // webrtc
|
||||||
|
0x03, 0x6f, 0x72, 0x67, // org
|
||||||
|
0x00, // null label
|
||||||
|
0x00, 0x01, // type A Record
|
||||||
|
0x00, 0x01, // class IN, multicast response
|
||||||
|
0x04, 0x6d, 0x64, 0x6e, 0x73, // mdns
|
||||||
|
0xc0, 0x10, // offset 16, webrtc.org.
|
||||||
|
0x00, 0x1C, // type AAAA Record
|
||||||
|
0x00, 0x01, // class IN, multicast response
|
||||||
|
0xc0, 0x10, // offset 16, webrtc.org.
|
||||||
|
0x00, 0x01, // type A Record
|
||||||
|
0x00, 0x01, // class IN, multicast response
|
||||||
|
};
|
||||||
|
|
||||||
|
const uint8_t kThreeQuestionsWithPointerToNameSuffixContainingAnotherPointer[] =
|
||||||
|
{
|
||||||
|
0x12, 0x34, // ID
|
||||||
|
0x00, 0x00, // flags
|
||||||
|
0x00, 0x03, // number of questions
|
||||||
|
0x00, 0x00, // number of answer rr
|
||||||
|
0x00, 0x00, // number of name server rr
|
||||||
|
0x00, 0x00, // number of additional rr
|
||||||
|
0x03, 0x77, 0x77, 0x77, // www
|
||||||
|
0x06, 0x77, 0x65, 0x62, 0x72, 0x74, 0x63, // webrtc
|
||||||
|
0x03, 0x6f, 0x72, 0x67, // org
|
||||||
|
0x00, // null label
|
||||||
|
0x00, 0x01, // type A Record
|
||||||
|
0x00, 0x01, // class IN, multicast response
|
||||||
|
0x04, 0x6d, 0x64, 0x6e, 0x73, // mdns
|
||||||
|
0xc0, 0x10, // offset 16, webrtc.org.
|
||||||
|
0x00, 0x1C, // type AAAA Record
|
||||||
|
0x00, 0x01, // class IN, multicast response
|
||||||
|
0x03, 0x77, 0x77, 0x77, // www
|
||||||
|
0xc0, 0x20, // offset 32, mdns.webrtc.org.
|
||||||
|
0x00, 0x01, // type A Record
|
||||||
|
0x00, 0x01, // class IN, multicast response
|
||||||
|
};
|
||||||
|
|
||||||
|
const uint8_t kCorruptedQuestionWithNameCompression1[] = {
|
||||||
|
0x12, 0x34, // ID
|
||||||
|
0x84, 0x00, // flags
|
||||||
|
0x00, 0x01, // number of questions
|
||||||
|
0x00, 0x00, // number of answer rr
|
||||||
|
0x00, 0x00, // number of name server rr
|
||||||
|
0x00, 0x00, // number of additional rr
|
||||||
|
0xc0, 0x0c, // offset 12,
|
||||||
|
0x00, 0x01, // type A Record
|
||||||
|
0x00, 0x01, // class IN
|
||||||
|
};
|
||||||
|
|
||||||
|
const uint8_t kCorruptedQuestionWithNameCompression2[] = {
|
||||||
|
0x12, 0x34, // ID
|
||||||
|
0x84, 0x00, // flags
|
||||||
|
0x00, 0x01, // number of questions
|
||||||
|
0x00, 0x00, // number of answer rr
|
||||||
|
0x00, 0x00, // number of name server rr
|
||||||
|
0x00, 0x00, // number of additional rr
|
||||||
|
0x01, 0x77, // w
|
||||||
|
0xc0, 0x0c, // offset 12,
|
||||||
|
0x00, 0x01, // type A Record
|
||||||
|
0x00, 0x01, // class IN
|
||||||
|
};
|
||||||
|
|
||||||
|
const uint8_t kSingleAuthoritativeAnswerWithIPv4Addr[] = {
|
||||||
|
0x12, 0x34, // ID
|
||||||
|
0x84, 0x00, // flags
|
||||||
|
0x00, 0x00, // number of questions
|
||||||
|
0x00, 0x01, // number of answer rr
|
||||||
|
0x00, 0x00, // number of name server rr
|
||||||
|
0x00, 0x00, // number of additional rr
|
||||||
|
0x06, 0x77, 0x65, 0x62, 0x72, 0x74, 0x63, // webrtc
|
||||||
|
0x03, 0x6f, 0x72, 0x67, // org
|
||||||
|
0x00, // null label
|
||||||
|
0x00, 0x01, // type A Record
|
||||||
|
0x00, 0x01, // class IN
|
||||||
|
0x00, 0x00, 0x00, 0x78, // TTL, 120 seconds
|
||||||
|
0x00, 0x04, // rdlength, 32 bits
|
||||||
|
0xC0, 0xA8, 0x00, 0x01, // 192.168.0.1
|
||||||
|
};
|
||||||
|
|
||||||
|
const uint8_t kTwoAuthoritativeAnswersWithIPv4AndIPv6Addr[] = {
|
||||||
|
0x12, 0x34, // ID
|
||||||
|
0x84, 0x00, // flags
|
||||||
|
0x00, 0x00, // number of questions
|
||||||
|
0x00, 0x02, // number of answer rr
|
||||||
|
0x00, 0x00, // number of name server rr
|
||||||
|
0x00, 0x00, // number of additional rr
|
||||||
|
0x07, 0x77, 0x65, 0x62, 0x72, 0x74, 0x63, 0x34, // webrtc4
|
||||||
|
0x03, 0x6f, 0x72, 0x67, // org
|
||||||
|
0x00, // null label
|
||||||
|
0x00, 0x01, // type A Record
|
||||||
|
0x00, 0x01, // class IN
|
||||||
|
0x00, 0x00, 0x00, 0x3c, // TTL, 60 seconds
|
||||||
|
0x00, 0x04, // rdlength, 32 bits
|
||||||
|
0xC0, 0xA8, 0x00, 0x01, // 192.168.0.1
|
||||||
|
0x07, 0x77, 0x65, 0x62, 0x72, 0x74, 0x63, 0x36, // webrtc6
|
||||||
|
0x03, 0x6f, 0x72, 0x67, // org
|
||||||
|
0x00, // null label
|
||||||
|
0x00, 0x1C, // type AAAA Record
|
||||||
|
0x00, 0x01, // class IN
|
||||||
|
0x00, 0x00, 0x00, 0x78, // TTL, 120 seconds
|
||||||
|
0x00, 0x10, // rdlength, 128 bits
|
||||||
|
0xfd, 0x12, 0x34, 0x56, 0x78, 0x9a, 0x00, 0x01, // fd12:3456:789a:1::1
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
|
||||||
|
};
|
||||||
|
|
||||||
|
const uint8_t kTwoAuthoritativeAnswersWithIPv4AndIPv6AddrWithNameCompression[] =
|
||||||
|
{
|
||||||
|
0x12, 0x34, // ID
|
||||||
|
0x84, 0x00, // flags
|
||||||
|
0x00, 0x00, // number of questions
|
||||||
|
0x00, 0x02, // number of answer rr
|
||||||
|
0x00, 0x00, // number of name server rr
|
||||||
|
0x00, 0x00, // number of additional rr
|
||||||
|
0x03, 0x77, 0x77, 0x77, // www
|
||||||
|
0x06, 0x77, 0x65, 0x62, 0x72, 0x74, 0x63, // webrtc
|
||||||
|
0x03, 0x6f, 0x72, 0x67, // org
|
||||||
|
0x00, // null label
|
||||||
|
0x00, 0x01, // type A Record
|
||||||
|
0x00, 0x01, // class IN
|
||||||
|
0x00, 0x00, 0x00, 0x3c, // TTL, 60 seconds
|
||||||
|
0x00, 0x04, // rdlength, 32 bits
|
||||||
|
0xc0, 0xA8, 0x00, 0x01, // 192.168.0.1
|
||||||
|
0xc0, 0x10, // offset 16, webrtc.org.
|
||||||
|
0x00, 0x1C, // type AAAA Record
|
||||||
|
0x00, 0x01, // class IN
|
||||||
|
0x00, 0x00, 0x00, 0x78, // TTL, 120 seconds
|
||||||
|
0x00, 0x10, // rdlength, 128 bits
|
||||||
|
0xfd, 0x12, 0x34, 0x56, 0x78, 0x9a, 0x00, 0x01, // fd12:3456:789a:1::1
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
|
||||||
|
};
|
||||||
|
|
||||||
|
const uint8_t kCorruptedAnswerWithNameCompression1[] = {
|
||||||
|
0x12, 0x34, // ID
|
||||||
|
0x84, 0x00, // flags
|
||||||
|
0x00, 0x00, // number of questions
|
||||||
|
0x00, 0x01, // number of answer rr
|
||||||
|
0x00, 0x00, // number of name server rr
|
||||||
|
0x00, 0x00, // number of additional rr
|
||||||
|
0xc0, 0x0c, // offset 12,
|
||||||
|
0x00, 0x01, // type A Record
|
||||||
|
0x00, 0x01, // class IN
|
||||||
|
0x00, 0x00, 0x00, 0x3c, // TTL, 60 seconds
|
||||||
|
0x00, 0x04, // rdlength, 32 bits
|
||||||
|
0xc0, 0xA8, 0x00, 0x01, // 192.168.0.1
|
||||||
|
};
|
||||||
|
|
||||||
|
const uint8_t kCorruptedAnswerWithNameCompression2[] = {
|
||||||
|
0x12, 0x34, // ID
|
||||||
|
0x84, 0x00, // flags
|
||||||
|
0x00, 0x00, // number of questions
|
||||||
|
0x00, 0x01, // number of answer rr
|
||||||
|
0x00, 0x00, // number of name server rr
|
||||||
|
0x00, 0x00, // number of additional rr
|
||||||
|
0x01, 0x77, // w
|
||||||
|
0xc0, 0x0c, // offset 12,
|
||||||
|
0x00, 0x01, // type A Record
|
||||||
|
0x00, 0x01, // class IN
|
||||||
|
0x00, 0x00, 0x00, 0x3c, // TTL, 60 seconds
|
||||||
|
0x00, 0x04, // rdlength, 32 bits
|
||||||
|
0xc0, 0xA8, 0x00, 0x01, // 192.168.0.1
|
||||||
|
};
|
||||||
|
|
||||||
|
bool ReadMDnsMessageTestCase(MDnsMessage* msg,
|
||||||
|
const uint8_t* testcase,
|
||||||
|
size_t size) {
|
||||||
|
MessageBufferReader buf(reinterpret_cast<const char*>(testcase), size);
|
||||||
|
return msg->Read(&buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WriteMDnsMessageAndCompareWithTestCast(MDnsMessage* msg,
|
||||||
|
const uint8_t* testcase,
|
||||||
|
size_t size) {
|
||||||
|
rtc::ByteBufferWriter out;
|
||||||
|
EXPECT_TRUE(msg->Write(&out));
|
||||||
|
EXPECT_EQ(size, out.Length());
|
||||||
|
int len = static_cast<int>(out.Length());
|
||||||
|
rtc::ByteBufferReader read_buf(out);
|
||||||
|
std::string bytes;
|
||||||
|
read_buf.ReadString(&bytes, len);
|
||||||
|
std::string testcase_bytes(reinterpret_cast<const char*>(testcase), size);
|
||||||
|
EXPECT_EQ(testcase_bytes, bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GetQueriedNames(MDnsMessage* msg, std::set<std::string>* names) {
|
||||||
|
if (!msg->IsQuery() || msg->question_section().empty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (const auto& question : msg->question_section()) {
|
||||||
|
names->insert(question.GetName());
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GetResolution(MDnsMessage* msg,
|
||||||
|
std::map<std::string, rtc::IPAddress>* names) {
|
||||||
|
if (msg->IsQuery() || msg->answer_section().empty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (const auto& answer : msg->answer_section()) {
|
||||||
|
rtc::IPAddress resolved_addr;
|
||||||
|
if (!answer.GetIPAddressFromRecordData(&resolved_addr)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
(*names)[answer.GetName()] = resolved_addr;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
TEST(MDnsMessageTest, ReadSingleQuestionForIPv4Address) {
|
||||||
|
MDnsMessage msg;
|
||||||
|
ASSERT_TRUE(
|
||||||
|
ReadMDnsMessage(&msg, kSingleQuestionForIPv4AddrWithUnicastResponse));
|
||||||
|
EXPECT_TRUE(msg.IsQuery());
|
||||||
|
EXPECT_EQ(0x1234, msg.GetId());
|
||||||
|
ASSERT_EQ(1u, msg.question_section().size());
|
||||||
|
EXPECT_EQ(0u, msg.answer_section().size());
|
||||||
|
EXPECT_EQ(0u, msg.authority_section().size());
|
||||||
|
EXPECT_EQ(0u, msg.additional_section().size());
|
||||||
|
EXPECT_TRUE(msg.ShouldUnicastResponse());
|
||||||
|
|
||||||
|
const auto& question = msg.question_section()[0];
|
||||||
|
EXPECT_EQ(SectionEntryType::kA, question.GetType());
|
||||||
|
|
||||||
|
std::set<std::string> queried_names;
|
||||||
|
EXPECT_TRUE(GetQueriedNames(&msg, &queried_names));
|
||||||
|
EXPECT_THAT(queried_names, ElementsAre("webrtc.org."));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(MDnsMessageTest, ReadTwoQuestionsForIPv4AndIPv6Addr) {
|
||||||
|
MDnsMessage msg;
|
||||||
|
ASSERT_TRUE(ReadMDnsMessage(
|
||||||
|
&msg, kTwoQuestionsForIPv4AndIPv6AddrWithMulticastResponse));
|
||||||
|
EXPECT_TRUE(msg.IsQuery());
|
||||||
|
EXPECT_EQ(0x1234, msg.GetId());
|
||||||
|
ASSERT_EQ(2u, msg.question_section().size());
|
||||||
|
EXPECT_EQ(0u, msg.answer_section().size());
|
||||||
|
EXPECT_EQ(0u, msg.authority_section().size());
|
||||||
|
EXPECT_EQ(0u, msg.additional_section().size());
|
||||||
|
|
||||||
|
const auto& question1 = msg.question_section()[0];
|
||||||
|
const auto& question2 = msg.question_section()[1];
|
||||||
|
EXPECT_EQ(SectionEntryType::kA, question1.GetType());
|
||||||
|
EXPECT_EQ(SectionEntryType::kAAAA, question2.GetType());
|
||||||
|
|
||||||
|
std::set<std::string> queried_names;
|
||||||
|
EXPECT_TRUE(GetQueriedNames(&msg, &queried_names));
|
||||||
|
EXPECT_THAT(queried_names,
|
||||||
|
UnorderedElementsAre("webrtc4.org.", "webrtc6.org."));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(MDnsMessageTest, ReadTwoQuestionsForIPv4AndIPv6AddrWithNameCompression) {
|
||||||
|
MDnsMessage msg;
|
||||||
|
ASSERT_TRUE(ReadMDnsMessage(
|
||||||
|
&msg,
|
||||||
|
kTwoQuestionsForIPv4AndIPv6AddrWithMulticastResponseAndNameCompression));
|
||||||
|
|
||||||
|
ASSERT_EQ(2u, msg.question_section().size());
|
||||||
|
const auto& question1 = msg.question_section()[0];
|
||||||
|
const auto& question2 = msg.question_section()[1];
|
||||||
|
EXPECT_EQ(SectionEntryType::kA, question1.GetType());
|
||||||
|
EXPECT_EQ(SectionEntryType::kAAAA, question2.GetType());
|
||||||
|
|
||||||
|
std::set<std::string> queried_names;
|
||||||
|
EXPECT_TRUE(GetQueriedNames(&msg, &queried_names));
|
||||||
|
EXPECT_THAT(queried_names,
|
||||||
|
UnorderedElementsAre("www.webrtc.org.", "mdns.webrtc.org."));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(MDnsMessageTest, ReadThreeQuestionsWithTwoPointersToTheSameNameSuffix) {
|
||||||
|
MDnsMessage msg;
|
||||||
|
ASSERT_TRUE(
|
||||||
|
ReadMDnsMessage(&msg, kThreeQuestionsWithTwoPointersToTheSameNameSuffix));
|
||||||
|
|
||||||
|
ASSERT_EQ(3u, msg.question_section().size());
|
||||||
|
const auto& question1 = msg.question_section()[0];
|
||||||
|
const auto& question2 = msg.question_section()[1];
|
||||||
|
const auto& question3 = msg.question_section()[2];
|
||||||
|
EXPECT_EQ(SectionEntryType::kA, question1.GetType());
|
||||||
|
EXPECT_EQ(SectionEntryType::kAAAA, question2.GetType());
|
||||||
|
EXPECT_EQ(SectionEntryType::kA, question3.GetType());
|
||||||
|
|
||||||
|
std::set<std::string> queried_names;
|
||||||
|
EXPECT_TRUE(GetQueriedNames(&msg, &queried_names));
|
||||||
|
EXPECT_THAT(queried_names,
|
||||||
|
UnorderedElementsAre("www.webrtc.org.", "mdns.webrtc.org.",
|
||||||
|
"webrtc.org."));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(MDnsMessageTest,
|
||||||
|
ReadThreeQuestionsWithPointerToNameSuffixContainingAnotherPointer) {
|
||||||
|
MDnsMessage msg;
|
||||||
|
ASSERT_TRUE(ReadMDnsMessage(
|
||||||
|
&msg, kThreeQuestionsWithPointerToNameSuffixContainingAnotherPointer));
|
||||||
|
|
||||||
|
ASSERT_EQ(3u, msg.question_section().size());
|
||||||
|
const auto& question1 = msg.question_section()[0];
|
||||||
|
const auto& question2 = msg.question_section()[1];
|
||||||
|
const auto& question3 = msg.question_section()[2];
|
||||||
|
EXPECT_EQ(SectionEntryType::kA, question1.GetType());
|
||||||
|
EXPECT_EQ(SectionEntryType::kAAAA, question2.GetType());
|
||||||
|
EXPECT_EQ(SectionEntryType::kA, question3.GetType());
|
||||||
|
|
||||||
|
std::set<std::string> queried_names;
|
||||||
|
EXPECT_TRUE(GetQueriedNames(&msg, &queried_names));
|
||||||
|
EXPECT_THAT(queried_names,
|
||||||
|
UnorderedElementsAre("www.webrtc.org.", "mdns.webrtc.org.",
|
||||||
|
"www.mdns.webrtc.org."));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(MDnsMessageTest,
|
||||||
|
ReadQuestionWithCorruptedPointerInNameCompressionShouldFail) {
|
||||||
|
MDnsMessage msg;
|
||||||
|
EXPECT_FALSE(ReadMDnsMessage(&msg, kCorruptedQuestionWithNameCompression1));
|
||||||
|
EXPECT_FALSE(ReadMDnsMessage(&msg, kCorruptedQuestionWithNameCompression2));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(MDnsMessageTest, ReadSingleAnswerForIPv4Addr) {
|
||||||
|
MDnsMessage msg;
|
||||||
|
ASSERT_TRUE(ReadMDnsMessage(&msg, kSingleAuthoritativeAnswerWithIPv4Addr));
|
||||||
|
EXPECT_FALSE(msg.IsQuery());
|
||||||
|
EXPECT_TRUE(msg.IsAuthoritative());
|
||||||
|
EXPECT_EQ(0x1234, msg.GetId());
|
||||||
|
EXPECT_EQ(0u, msg.question_section().size());
|
||||||
|
ASSERT_EQ(1u, msg.answer_section().size());
|
||||||
|
EXPECT_EQ(0u, msg.authority_section().size());
|
||||||
|
EXPECT_EQ(0u, msg.additional_section().size());
|
||||||
|
|
||||||
|
const auto& answer = msg.answer_section()[0];
|
||||||
|
EXPECT_EQ(SectionEntryType::kA, answer.GetType());
|
||||||
|
EXPECT_EQ(120u, answer.GetTtlSeconds());
|
||||||
|
|
||||||
|
std::map<std::string, rtc::IPAddress> resolution;
|
||||||
|
EXPECT_TRUE(GetResolution(&msg, &resolution));
|
||||||
|
rtc::IPAddress expected_addr(rtc::SocketAddress("192.168.0.1", 0).ipaddr());
|
||||||
|
EXPECT_THAT(resolution, ElementsAre(Pair("webrtc.org.", expected_addr)));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(MDnsMessageTest, ReadTwoAnswersForIPv4AndIPv6Addr) {
|
||||||
|
MDnsMessage msg;
|
||||||
|
ASSERT_TRUE(
|
||||||
|
ReadMDnsMessage(&msg, kTwoAuthoritativeAnswersWithIPv4AndIPv6Addr));
|
||||||
|
EXPECT_FALSE(msg.IsQuery());
|
||||||
|
EXPECT_TRUE(msg.IsAuthoritative());
|
||||||
|
EXPECT_EQ(0x1234, msg.GetId());
|
||||||
|
EXPECT_EQ(0u, msg.question_section().size());
|
||||||
|
ASSERT_EQ(2u, msg.answer_section().size());
|
||||||
|
EXPECT_EQ(0u, msg.authority_section().size());
|
||||||
|
EXPECT_EQ(0u, msg.additional_section().size());
|
||||||
|
|
||||||
|
const auto& answer1 = msg.answer_section()[0];
|
||||||
|
const auto& answer2 = msg.answer_section()[1];
|
||||||
|
EXPECT_EQ(SectionEntryType::kA, answer1.GetType());
|
||||||
|
EXPECT_EQ(SectionEntryType::kAAAA, answer2.GetType());
|
||||||
|
EXPECT_EQ(60u, answer1.GetTtlSeconds());
|
||||||
|
EXPECT_EQ(120u, answer2.GetTtlSeconds());
|
||||||
|
|
||||||
|
std::map<std::string, rtc::IPAddress> resolution;
|
||||||
|
EXPECT_TRUE(GetResolution(&msg, &resolution));
|
||||||
|
rtc::IPAddress expected_addr_ipv4(
|
||||||
|
rtc::SocketAddress("192.168.0.1", 0).ipaddr());
|
||||||
|
rtc::IPAddress expected_addr_ipv6(
|
||||||
|
rtc::SocketAddress("fd12:3456:789a:1::1", 0).ipaddr());
|
||||||
|
EXPECT_THAT(resolution,
|
||||||
|
UnorderedElementsAre(Pair("webrtc4.org.", expected_addr_ipv4),
|
||||||
|
Pair("webrtc6.org.", expected_addr_ipv6)));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(MDnsMessageTest, ReadTwoAnswersForIPv4AndIPv6AddrWithNameCompression) {
|
||||||
|
MDnsMessage msg;
|
||||||
|
ASSERT_TRUE(ReadMDnsMessage(
|
||||||
|
&msg, kTwoAuthoritativeAnswersWithIPv4AndIPv6AddrWithNameCompression));
|
||||||
|
|
||||||
|
std::map<std::string, rtc::IPAddress> resolution;
|
||||||
|
EXPECT_TRUE(GetResolution(&msg, &resolution));
|
||||||
|
rtc::IPAddress expected_addr_ipv4(
|
||||||
|
rtc::SocketAddress("192.168.0.1", 0).ipaddr());
|
||||||
|
rtc::IPAddress expected_addr_ipv6(
|
||||||
|
rtc::SocketAddress("fd12:3456:789a:1::1", 0).ipaddr());
|
||||||
|
EXPECT_THAT(resolution,
|
||||||
|
UnorderedElementsAre(Pair("www.webrtc.org.", expected_addr_ipv4),
|
||||||
|
Pair("webrtc.org.", expected_addr_ipv6)));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(MDnsMessageTest,
|
||||||
|
ReadAnswerWithCorruptedPointerInNameCompressionShouldFail) {
|
||||||
|
MDnsMessage msg;
|
||||||
|
EXPECT_FALSE(ReadMDnsMessage(&msg, kCorruptedAnswerWithNameCompression1));
|
||||||
|
EXPECT_FALSE(ReadMDnsMessage(&msg, kCorruptedAnswerWithNameCompression2));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(MDnsMessageTest, WriteSingleQuestionForIPv4Addr) {
|
||||||
|
MDnsMessage msg;
|
||||||
|
msg.SetId(0x1234);
|
||||||
|
msg.SetQueryOrResponse(true);
|
||||||
|
|
||||||
|
MDnsQuestion question;
|
||||||
|
question.SetName("webrtc.org.");
|
||||||
|
question.SetType(SectionEntryType::kA);
|
||||||
|
question.SetClass(SectionEntryClass::kIN);
|
||||||
|
question.SetUnicastResponse(true);
|
||||||
|
msg.AddQuestion(question);
|
||||||
|
|
||||||
|
WriteMDnsMessageAndCompare(&msg,
|
||||||
|
kSingleQuestionForIPv4AddrWithUnicastResponse);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(MDnsMessageTest, WriteTwoQuestionsForIPv4AndIPv6Addr) {
|
||||||
|
MDnsMessage msg;
|
||||||
|
msg.SetId(0x1234);
|
||||||
|
msg.SetQueryOrResponse(true);
|
||||||
|
|
||||||
|
MDnsQuestion question1;
|
||||||
|
question1.SetName("webrtc4.org.");
|
||||||
|
question1.SetType(SectionEntryType::kA);
|
||||||
|
question1.SetClass(SectionEntryClass::kIN);
|
||||||
|
msg.AddQuestion(question1);
|
||||||
|
|
||||||
|
MDnsQuestion question2;
|
||||||
|
question2.SetName("webrtc6.org.");
|
||||||
|
question2.SetType(SectionEntryType::kAAAA);
|
||||||
|
question2.SetClass(SectionEntryClass::kIN);
|
||||||
|
msg.AddQuestion(question2);
|
||||||
|
|
||||||
|
WriteMDnsMessageAndCompare(
|
||||||
|
&msg, kTwoQuestionsForIPv4AndIPv6AddrWithMulticastResponse);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(MDnsMessageTest, WriteSingleAnswerToIPv4Addr) {
|
||||||
|
MDnsMessage msg;
|
||||||
|
msg.SetId(0x1234);
|
||||||
|
msg.SetQueryOrResponse(false);
|
||||||
|
msg.SetAuthoritative(true);
|
||||||
|
|
||||||
|
MDnsResourceRecord answer;
|
||||||
|
answer.SetName("webrtc.org.");
|
||||||
|
answer.SetType(SectionEntryType::kA);
|
||||||
|
answer.SetClass(SectionEntryClass::kIN);
|
||||||
|
EXPECT_TRUE(answer.SetIPAddressInRecordData(
|
||||||
|
rtc::SocketAddress("192.168.0.1", 0).ipaddr()));
|
||||||
|
answer.SetTtlSeconds(120);
|
||||||
|
msg.AddAnswerRecord(answer);
|
||||||
|
|
||||||
|
WriteMDnsMessageAndCompare(&msg, kSingleAuthoritativeAnswerWithIPv4Addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(MDnsMessageTest, WriteTwoAnswersToIPv4AndIPv6Addr) {
|
||||||
|
MDnsMessage msg;
|
||||||
|
msg.SetId(0x1234);
|
||||||
|
msg.SetQueryOrResponse(false);
|
||||||
|
msg.SetAuthoritative(true);
|
||||||
|
|
||||||
|
MDnsResourceRecord answer1;
|
||||||
|
answer1.SetName("webrtc4.org.");
|
||||||
|
answer1.SetType(SectionEntryType::kA);
|
||||||
|
answer1.SetClass(SectionEntryClass::kIN);
|
||||||
|
answer1.SetIPAddressInRecordData(
|
||||||
|
rtc::SocketAddress("192.168.0.1", 0).ipaddr());
|
||||||
|
answer1.SetTtlSeconds(60);
|
||||||
|
msg.AddAnswerRecord(answer1);
|
||||||
|
|
||||||
|
MDnsResourceRecord answer2;
|
||||||
|
answer2.SetName("webrtc6.org.");
|
||||||
|
answer2.SetType(SectionEntryType::kAAAA);
|
||||||
|
answer2.SetClass(SectionEntryClass::kIN);
|
||||||
|
answer2.SetIPAddressInRecordData(
|
||||||
|
rtc::SocketAddress("fd12:3456:789a:1::1", 0).ipaddr());
|
||||||
|
answer2.SetTtlSeconds(120);
|
||||||
|
msg.AddAnswerRecord(answer2);
|
||||||
|
|
||||||
|
WriteMDnsMessageAndCompare(&msg, kTwoAuthoritativeAnswersWithIPv4AndIPv6Addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace webrtc
|
@ -413,6 +413,7 @@ rtc_source_set("rtc_base_approved_generic") {
|
|||||||
"ignore_wundef.h",
|
"ignore_wundef.h",
|
||||||
"location.cc",
|
"location.cc",
|
||||||
"location.h",
|
"location.h",
|
||||||
|
"message_buffer_reader.h",
|
||||||
"numerics/histogram_percentile_counter.cc",
|
"numerics/histogram_percentile_counter.cc",
|
||||||
"numerics/histogram_percentile_counter.h",
|
"numerics/histogram_percentile_counter.h",
|
||||||
"numerics/mod_ops.h",
|
"numerics/mod_ops.h",
|
||||||
|
@ -185,7 +185,7 @@ class ByteBufferReader : public ByteBuffer {
|
|||||||
// after this call.
|
// after this call.
|
||||||
bool Consume(size_t size);
|
bool Consume(size_t size);
|
||||||
|
|
||||||
private:
|
protected:
|
||||||
void Construct(const char* bytes, size_t size);
|
void Construct(const char* bytes, size_t size);
|
||||||
|
|
||||||
const char* bytes_;
|
const char* bytes_;
|
||||||
@ -193,6 +193,7 @@ class ByteBufferReader : public ByteBuffer {
|
|||||||
size_t start_;
|
size_t start_;
|
||||||
size_t end_;
|
size_t end_;
|
||||||
|
|
||||||
|
private:
|
||||||
RTC_DISALLOW_COPY_AND_ASSIGN(ByteBufferReader);
|
RTC_DISALLOW_COPY_AND_ASSIGN(ByteBufferReader);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
37
rtc_base/message_buffer_reader.h
Normal file
37
rtc_base/message_buffer_reader.h
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2018 The WebRTC Project Authors. All rights reserved.
|
||||||
|
*
|
||||||
|
* Use of this source code is governed by a BSD-style license
|
||||||
|
* that can be found in the LICENSE file in the root of the source
|
||||||
|
* tree. An additional intellectual property rights grant can be found
|
||||||
|
* in the file PATENTS. All contributing project authors may
|
||||||
|
* be found in the AUTHORS file in the root of the source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef RTC_BASE_MESSAGE_BUFFER_READER_H_
|
||||||
|
#define RTC_BASE_MESSAGE_BUFFER_READER_H_
|
||||||
|
|
||||||
|
#include "rtc_base/bytebuffer.h"
|
||||||
|
|
||||||
|
namespace webrtc {
|
||||||
|
|
||||||
|
// A simple subclass of the ByteBufferReader that exposes the starting address
|
||||||
|
// of the message and its length, so that we can recall previously parsed data.
|
||||||
|
class MessageBufferReader : public rtc::ByteBufferReader {
|
||||||
|
public:
|
||||||
|
MessageBufferReader(const char* bytes, size_t len)
|
||||||
|
: rtc::ByteBufferReader(bytes, len) {}
|
||||||
|
~MessageBufferReader() = default;
|
||||||
|
|
||||||
|
// Starting address of the message.
|
||||||
|
const char* MessageData() const { return bytes_; }
|
||||||
|
// Total length of the message. Note that this is different from Length(),
|
||||||
|
// which is the length of the remaining message from the current offset.
|
||||||
|
size_t MessageLength() const { return size_; }
|
||||||
|
// Current offset in the message.
|
||||||
|
size_t CurrentOffset() const { return start_; }
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace webrtc
|
||||||
|
|
||||||
|
#endif // RTC_BASE_MESSAGE_BUFFER_READER_H_
|
@ -32,6 +32,9 @@ specific_include_rules = {
|
|||||||
"+modules/pacing/packet_router.h",
|
"+modules/pacing/packet_router.h",
|
||||||
"+modules/remote_bitrate_estimator/include/remote_bitrate_estimator.h",
|
"+modules/remote_bitrate_estimator/include/remote_bitrate_estimator.h",
|
||||||
],
|
],
|
||||||
|
".*mdns_parser_fuzzer\.cc": [
|
||||||
|
"+p2p/base/mdns_message.h",
|
||||||
|
],
|
||||||
".*pseudotcp_parser_fuzzer\.cc": [
|
".*pseudotcp_parser_fuzzer\.cc": [
|
||||||
"+p2p/base/pseudotcp.h",
|
"+p2p/base/pseudotcp.h",
|
||||||
],
|
],
|
||||||
|
@ -438,6 +438,18 @@ webrtc_fuzzer_test("stun_validator_fuzzer") {
|
|||||||
dict = "corpora/stun.tokens"
|
dict = "corpora/stun.tokens"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
webrtc_fuzzer_test("mdns_parser_fuzzer") {
|
||||||
|
sources = [
|
||||||
|
"mdns_parser_fuzzer.cc",
|
||||||
|
]
|
||||||
|
deps = [
|
||||||
|
"../../p2p:rtc_p2p",
|
||||||
|
"../../rtc_base:rtc_base_approved",
|
||||||
|
"//third_party/abseil-cpp/absl/memory",
|
||||||
|
]
|
||||||
|
seed_corpus = "corpora/mdns-corpus"
|
||||||
|
}
|
||||||
|
|
||||||
webrtc_fuzzer_test("pseudotcp_parser_fuzzer") {
|
webrtc_fuzzer_test("pseudotcp_parser_fuzzer") {
|
||||||
sources = [
|
sources = [
|
||||||
"pseudotcp_parser_fuzzer.cc",
|
"pseudotcp_parser_fuzzer.cc",
|
||||||
|
BIN
test/fuzzers/corpora/mdns-corpus/1.mdns
Normal file
BIN
test/fuzzers/corpora/mdns-corpus/1.mdns
Normal file
Binary file not shown.
BIN
test/fuzzers/corpora/mdns-corpus/10.mdns
Normal file
BIN
test/fuzzers/corpora/mdns-corpus/10.mdns
Normal file
Binary file not shown.
BIN
test/fuzzers/corpora/mdns-corpus/11.mdns
Normal file
BIN
test/fuzzers/corpora/mdns-corpus/11.mdns
Normal file
Binary file not shown.
BIN
test/fuzzers/corpora/mdns-corpus/12.mdns
Normal file
BIN
test/fuzzers/corpora/mdns-corpus/12.mdns
Normal file
Binary file not shown.
BIN
test/fuzzers/corpora/mdns-corpus/13.mdns
Normal file
BIN
test/fuzzers/corpora/mdns-corpus/13.mdns
Normal file
Binary file not shown.
BIN
test/fuzzers/corpora/mdns-corpus/14.mdns
Normal file
BIN
test/fuzzers/corpora/mdns-corpus/14.mdns
Normal file
Binary file not shown.
BIN
test/fuzzers/corpora/mdns-corpus/15.mdns
Normal file
BIN
test/fuzzers/corpora/mdns-corpus/15.mdns
Normal file
Binary file not shown.
BIN
test/fuzzers/corpora/mdns-corpus/16.mdns
Normal file
BIN
test/fuzzers/corpora/mdns-corpus/16.mdns
Normal file
Binary file not shown.
BIN
test/fuzzers/corpora/mdns-corpus/17.mdns
Normal file
BIN
test/fuzzers/corpora/mdns-corpus/17.mdns
Normal file
Binary file not shown.
BIN
test/fuzzers/corpora/mdns-corpus/18.mdns
Normal file
BIN
test/fuzzers/corpora/mdns-corpus/18.mdns
Normal file
Binary file not shown.
BIN
test/fuzzers/corpora/mdns-corpus/19.mdns
Normal file
BIN
test/fuzzers/corpora/mdns-corpus/19.mdns
Normal file
Binary file not shown.
BIN
test/fuzzers/corpora/mdns-corpus/2.mdns
Normal file
BIN
test/fuzzers/corpora/mdns-corpus/2.mdns
Normal file
Binary file not shown.
BIN
test/fuzzers/corpora/mdns-corpus/20.mdns
Normal file
BIN
test/fuzzers/corpora/mdns-corpus/20.mdns
Normal file
Binary file not shown.
BIN
test/fuzzers/corpora/mdns-corpus/3.mdns
Normal file
BIN
test/fuzzers/corpora/mdns-corpus/3.mdns
Normal file
Binary file not shown.
BIN
test/fuzzers/corpora/mdns-corpus/4.mdns
Normal file
BIN
test/fuzzers/corpora/mdns-corpus/4.mdns
Normal file
Binary file not shown.
BIN
test/fuzzers/corpora/mdns-corpus/5.mdns
Normal file
BIN
test/fuzzers/corpora/mdns-corpus/5.mdns
Normal file
Binary file not shown.
BIN
test/fuzzers/corpora/mdns-corpus/6.mdns
Normal file
BIN
test/fuzzers/corpora/mdns-corpus/6.mdns
Normal file
Binary file not shown.
BIN
test/fuzzers/corpora/mdns-corpus/7.mdns
Normal file
BIN
test/fuzzers/corpora/mdns-corpus/7.mdns
Normal file
Binary file not shown.
BIN
test/fuzzers/corpora/mdns-corpus/8.mdns
Normal file
BIN
test/fuzzers/corpora/mdns-corpus/8.mdns
Normal file
Binary file not shown.
BIN
test/fuzzers/corpora/mdns-corpus/9.mdns
Normal file
BIN
test/fuzzers/corpora/mdns-corpus/9.mdns
Normal file
Binary file not shown.
26
test/fuzzers/mdns_parser_fuzzer.cc
Normal file
26
test/fuzzers/mdns_parser_fuzzer.cc
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2018 The WebRTC Project Authors. All rights reserved.
|
||||||
|
*
|
||||||
|
* Use of this source code is governed by a BSD-style license
|
||||||
|
* that can be found in the LICENSE file in the root of the source
|
||||||
|
* tree. An additional intellectual property rights grant can be found
|
||||||
|
* in the file PATENTS. All contributing project authors may
|
||||||
|
* be found in the AUTHORS file in the root of the source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "absl/memory/memory.h"
|
||||||
|
#include "p2p/base/mdns_message.h"
|
||||||
|
#include "rtc_base/message_buffer_reader.h"
|
||||||
|
|
||||||
|
namespace webrtc {
|
||||||
|
|
||||||
|
void FuzzOneInput(const uint8_t* data, size_t size) {
|
||||||
|
MessageBufferReader buf(reinterpret_cast<const char*>(data), size);
|
||||||
|
auto mdns_msg = absl::make_unique<MDnsMessage>();
|
||||||
|
mdns_msg->Read(&buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace webrtc
|
Reference in New Issue
Block a user