Commit c2213d5d authored by Qingsi Wang's avatar Qingsi Wang Committed by Commit Bot

Add the mDNS responder service.

WebRTC will improve its IP handling with mDNS and replace private IP
addresses with mDNS hostnames when signaling ICE host candidates to the
application. See the Internet Draft (draft-mdns-ice-candidates-02) for
the detailed approach.

This CL defines a Mojo interface of mDNS responder and implements it as
a service that will be consumed by WebRTC.

Bug: 878465
Cq-Include-Trybots: luci.chromium.try:linux_mojo
Change-Id: I4b644286467622b3dfdb728a9d5f3a4bde9fc1ec
Reviewed-on: https://chromium-review.googlesource.com/c/1182875Reviewed-by: default avatarChris Palmer <palmer@chromium.org>
Reviewed-by: default avatarEric Orth <ericorth@chromium.org>
Reviewed-by: default avatarMatt Menke <mmenke@chromium.org>
Reviewed-by: default avatarAvi Drissman <avi@chromium.org>
Commit-Queue: Qingsi Wang <qingsi@google.com>
Cr-Commit-Position: refs/heads/master@{#604803}
parent 884edb78
......@@ -4006,17 +4006,6 @@ jumbo_split_static_library("browser") {
]
}
if (enable_mdns) {
sources += [
"local_discovery/service_discovery_client_impl.cc",
"local_discovery/service_discovery_client_impl.h",
"local_discovery/service_discovery_client_mdns.cc",
"local_discovery/service_discovery_client_mdns.h",
"printing/cloud_print/privet_traffic_detector.cc",
"printing/cloud_print/privet_traffic_detector.h",
]
}
if (enable_message_center) {
sources += [
"notifications/notification_platform_bridge_message_center.cc",
......@@ -4348,6 +4337,17 @@ jumbo_split_static_library("browser") {
"printing/cloud_print/privet_url_loader.cc",
"printing/cloud_print/privet_url_loader.h",
]
if (enable_mdns) {
sources += [
"local_discovery/service_discovery_client_impl.cc",
"local_discovery/service_discovery_client_impl.h",
"local_discovery/service_discovery_client_mdns.cc",
"local_discovery/service_discovery_client_mdns.h",
"printing/cloud_print/privet_traffic_detector.cc",
"printing/cloud_print/privet_traffic_detector.h",
]
}
}
if (enable_session_service) {
......@@ -5339,7 +5339,7 @@ static_library("test_support") {
deps += [ "//media/cdm:cdm_paths" ]
}
if (enable_mdns) {
if (enable_service_discovery) {
sources += [
"local_discovery/test_service_discovery_client.cc",
"local_discovery/test_service_discovery_client.h",
......
......@@ -43,7 +43,7 @@ declare_args() {
enable_one_click_signin =
is_win || is_mac || (is_linux && !is_chromeos && !is_chromecast)
enable_service_discovery = enable_mdns || is_mac
enable_service_discovery = (enable_mdns && !is_android && !is_ios) || is_mac
# Enables use of the session service, which is enabled by default.
# Android stores them separately on the Java side.
......
......@@ -2107,7 +2107,7 @@ test("browser_tests") {
]
}
}
if (enable_mdns) {
if (enable_service_discovery && !is_mac) {
sources += [
"../browser/ui/webui/local_discovery/local_discovery_ui_browsertest.cc",
]
......@@ -3875,14 +3875,6 @@ test("unit_tests") {
deps += [ "//chrome/browser/ui/libgtkui" ]
}
if (enable_mdns) {
sources += [
"../browser/local_discovery/local_domain_resolver_unittest.cc",
"../browser/local_discovery/service_discovery_client_unittest.cc",
"../browser/printing/cloud_print/privet_device_lister_unittest.cc",
"../browser/printing/cloud_print/privet_local_printer_lister_unittest.cc",
]
}
if (enable_service_discovery) {
sources += [
"../browser/devtools/device/cast_device_provider_unittest.cc",
......@@ -3894,6 +3886,15 @@ test("unit_tests") {
"../browser/printing/cloud_print/privet_notifications_unittest.cc",
"../browser/printing/cloud_print/privet_url_loader_unittest.cc",
]
if (!is_mac) {
sources += [
"../browser/local_discovery/local_domain_resolver_unittest.cc",
"../browser/local_discovery/service_discovery_client_unittest.cc",
"../browser/printing/cloud_print/privet_device_lister_unittest.cc",
"../browser/printing/cloud_print/privet_local_printer_lister_unittest.cc",
]
}
}
if (safe_browsing_mode > 0) {
......
......@@ -2228,6 +2228,13 @@ void RenderProcessHostImpl::RegisterMojoInterfaces() {
base::BindRepeating(&P2PSocketDispatcherHost::BindRequest,
base::Unretained(p2p_socket_dispatcher_host_.get())));
#if BUILDFLAG(ENABLE_MDNS)
AddUIThreadInterface(
registry.get(),
base::BindRepeating(&RenderProcessHostImpl::CreateMdnsResponder,
base::Unretained(this)));
#endif // BUILDFLAG(ENABLE_MDNS)
AddUIThreadInterface(registry.get(), base::Bind(&FieldTrialRecorder::Create));
associated_interfaces_ =
......@@ -4557,6 +4564,14 @@ void RenderProcessHostImpl::CreateMediaStreamTrackMetricsHost(
media_stream_track_metrics_host_->BindRequest(std::move(request));
}
#if BUILDFLAG(ENABLE_MDNS)
void RenderProcessHostImpl::CreateMdnsResponder(
network::mojom::MdnsResponderRequest request) {
GetStoragePartition()->GetNetworkContext()->CreateMdnsResponder(
std::move(request));
}
#endif // BUILDFLAG(ENABLE_MDNS)
void RenderProcessHostImpl::OnRegisterAecDumpConsumer(int id) {
base::PostTaskWithTraits(
FROM_HERE, {BrowserThread::UI},
......
......@@ -51,6 +51,7 @@
#include "mojo/public/cpp/bindings/associated_binding_set.h"
#include "mojo/public/cpp/bindings/interface_ptr.h"
#include "mojo/public/cpp/system/invitation.h"
#include "services/network/public/mojom/mdns_responder.mojom.h"
#include "services/network/public/mojom/url_loader_factory.mojom.h"
#include "services/service_manager/public/cpp/binder_registry.h"
#include "services/service_manager/public/mojom/service.mojom.h"
......@@ -599,6 +600,10 @@ class CONTENT_EXPORT RenderProcessHostImpl
void CreateMediaStreamTrackMetricsHost(
mojom::MediaStreamTrackMetricsHostRequest request);
#if BUILDFLAG(ENABLE_MDNS)
void CreateMdnsResponder(network::mojom::MdnsResponderRequest request);
#endif // BUILDFLAG(ENABLE_MDNS)
void OnRegisterAecDumpConsumer(int id);
void OnUnregisterAecDumpConsumer(int id);
void RegisterAecDumpConsumerOnUIThread(int id);
......
......@@ -76,6 +76,7 @@
"memory_coordinator.mojom.MemoryCoordinatorHandle",
"metrics.mojom.SingleSampleMetricsProvider",
"network.mojom.P2PSocketManager",
"network.mojom.MdnsResponder",
"network.mojom.URLLoaderFactory",
"resource_coordinator.mojom.ProcessCoordinationUnit",
"viz.mojom.CompositingModeReporter",
......
......@@ -322,6 +322,7 @@ source_set("mdns_client") {
"//chrome/browser/chromeos",
"//chrome/tools/service_discovery_sniffer",
"//net/*",
"//services/network/*",
]
public = []
......
......@@ -126,6 +126,7 @@ static const uint16_t kTypeAAAA = 28;
static const uint16_t kTypeSRV = 33;
static const uint16_t kTypeOPT = 41;
static const uint16_t kTypeNSEC = 47;
static const uint16_t kTypeANY = 255;
// DNS reply codes (RCODEs).
//
......
......@@ -6,6 +6,7 @@
#include <limits>
#include <numeric>
#include <utility>
#include <vector>
#include "base/big_endian.h"
......@@ -38,13 +39,81 @@ const size_t kResourceRecordSizeInBytesWithoutNameAndRData = 10;
DnsResourceRecord::DnsResourceRecord() = default;
DnsResourceRecord::DnsResourceRecord(const DnsResourceRecord& other) = default;
DnsResourceRecord::DnsResourceRecord(const DnsResourceRecord& other)
: name(other.name),
type(other.type),
klass(other.klass),
ttl(other.ttl),
owned_rdata(other.owned_rdata) {
if (!owned_rdata.empty())
rdata = owned_rdata;
else
rdata = other.rdata;
}
DnsResourceRecord::DnsResourceRecord(DnsResourceRecord&& other)
: name(std::move(other.name)),
type(other.type),
klass(other.klass),
ttl(other.ttl),
owned_rdata(std::move(other.owned_rdata)) {
if (!owned_rdata.empty())
rdata = owned_rdata;
else
rdata = other.rdata;
}
DnsResourceRecord::~DnsResourceRecord() = default;
DnsRecordParser::DnsRecordParser() : packet_(NULL), length_(0), cur_(0) {
DnsResourceRecord& DnsResourceRecord::operator=(
const DnsResourceRecord& other) {
name = other.name;
type = other.type;
klass = other.klass;
ttl = other.ttl;
owned_rdata = other.owned_rdata;
if (!owned_rdata.empty())
rdata = owned_rdata;
else
rdata = other.rdata;
return *this;
}
DnsResourceRecord& DnsResourceRecord::operator=(DnsResourceRecord&& other) {
name = std::move(other.name);
type = other.type;
klass = other.klass;
ttl = other.ttl;
owned_rdata = std::move(other.owned_rdata);
if (!owned_rdata.empty())
rdata = owned_rdata;
else
rdata = other.rdata;
return *this;
}
void DnsResourceRecord::SetOwnedRdata(std::string value) {
owned_rdata = std::move(value);
rdata = owned_rdata;
}
size_t DnsResourceRecord::CalculateRecordSize() const {
bool has_final_dot = name.back() == '.';
// Depending on if |name| in the dotted format has the final dot for the root
// domain or not, the corresponding wire data in the DNS domain name format is
// 1 byte (with dot) or 2 bytes larger in size. See RFC 1035, Section 3.1 and
// DNSDomainFromDot.
return name.size() + (has_final_dot ? 1 : 2) +
kResourceRecordSizeInBytesWithoutNameAndRData +
(owned_rdata.empty() ? rdata.size() : owned_rdata.size());
}
DnsRecordParser::DnsRecordParser() : packet_(nullptr), length_(0), cur_(0) {}
DnsRecordParser::DnsRecordParser(const void* packet,
size_t length,
size_t offset)
......@@ -148,7 +217,7 @@ bool DnsRecordParser::ReadRecord(DnsResourceRecord* out) {
}
bool DnsRecordParser::SkipQuestion() {
size_t consumed = ReadName(cur_, NULL);
size_t consumed = ReadName(cur_, nullptr);
if (!consumed)
return false;
......@@ -178,9 +247,9 @@ DnsResponse::DnsResponse(
header.qdcount = 1;
}
header.flags |= dns_protocol::kFlagResponse;
if (is_authoritative) {
if (is_authoritative)
header.flags |= dns_protocol::kFlagAA;
}
header.ancount = answers.size();
header.arcount = additional_records.size();
......@@ -189,18 +258,11 @@ DnsResponse::DnsResponse(
? sizeof(header) + query.value().question_size()
: sizeof(header);
// Add the size of all answers and additional records.
auto do_accumulation = [](size_t cur_size, const DnsResourceRecord& answer) {
bool has_final_dot = answer.name.back() == '.';
// Depending on if answer.name in the dotted format has the final dot
// for the root domain or not, the corresponding DNS domain name format
// to be written to rdata is 1 byte (with dot) or 2 bytes larger in
// size. See RFC 1035, Section 3.1 and DNSDomainFromDot.
return cur_size + answer.name.size() + (has_final_dot ? 1 : 2) +
kResourceRecordSizeInBytesWithoutNameAndRData + answer.rdata.size();
auto do_accumulation = [](size_t cur_size, const DnsResourceRecord& record) {
return cur_size + record.CalculateRecordSize();
};
response_size = std::accumulate(answers.begin(), answers.end(), response_size,
do_accumulation);
response_size =
std::accumulate(additional_records.begin(), additional_records.end(),
response_size, do_accumulation);
......@@ -232,11 +294,10 @@ DnsResponse::DnsResponse(
// Ensure we don't have any remaining uninitialized bytes in the buffer.
DCHECK(!writer.remaining());
memset(writer.ptr(), 0, writer.remaining());
if (has_query) {
if (has_query)
InitParse(io_buffer_size_, query.value());
} else {
else
InitParseWithoutQuery(io_buffer_size_);
}
}
DnsResponse::DnsResponse()
......@@ -462,7 +523,13 @@ bool DnsResponse::WriteQuestion(base::BigEndianWriter* writer,
bool DnsResponse::WriteRecord(base::BigEndianWriter* writer,
const DnsResourceRecord& record) {
if (!RecordRdata::HasValidSize(record.rdata, record.type)) {
if (record.rdata.data() != record.owned_rdata.data() ||
record.rdata.size() != record.owned_rdata.size()) {
VLOG(1) << "record.rdata should point to record.owned_rdata.";
return false;
}
if (!RecordRdata::HasValidSize(record.owned_rdata, record.type)) {
VLOG(1) << "Invalid RDATA size for a record.";
return false;
}
......@@ -474,8 +541,10 @@ bool DnsResponse::WriteRecord(base::BigEndianWriter* writer,
return writer->WriteBytes(domain_name.data(), domain_name.size()) &&
writer->WriteU16(record.type) && writer->WriteU16(record.klass) &&
writer->WriteU32(record.ttl) &&
writer->WriteU16(record.rdata.size()) &&
writer->WriteBytes(record.rdata.data(), record.rdata.size());
writer->WriteU16(record.owned_rdata.size()) &&
// Use the owned RDATA in the record to construct the response.
writer->WriteBytes(record.owned_rdata.data(),
record.owned_rdata.size());
}
bool DnsResponse::WriteAnswer(base::BigEndianWriter* writer,
......
......@@ -36,13 +36,31 @@ struct Header;
struct NET_EXPORT_PRIVATE DnsResourceRecord {
DnsResourceRecord();
explicit DnsResourceRecord(const DnsResourceRecord& other);
DnsResourceRecord(DnsResourceRecord&& other);
~DnsResourceRecord();
DnsResourceRecord& operator=(const DnsResourceRecord& other);
DnsResourceRecord& operator=(DnsResourceRecord&& other);
// A helper to set |owned_rdata| that also sets |rdata| to point to it.
// See the definition of |owned_rdata| below.
void SetOwnedRdata(std::string value);
// NAME (variable length) + TYPE (2 bytes) + CLASS (2 bytes) + TTL (4 bytes) +
// RDLENGTH (2 bytes) + RDATA (variable length)
//
// Uses |owned_rdata| for RDATA if non-empty.
size_t CalculateRecordSize() const;
std::string name; // in dotted form
uint16_t type = 0;
uint16_t klass = 0;
uint32_t ttl = 0;
base::StringPiece rdata; // points to the original response buffer
// Points to the original response buffer or otherwise to |owned_rdata|.
base::StringPiece rdata;
// Used to construct a DnsResponse from data. This field is empty if |rdata|
// points to the response buffer.
std::string owned_rdata;
};
// Iterator to walk over resource records of the DNS response packet.
......
......@@ -670,7 +670,7 @@ TEST(DnsResponseWriteTest, SingleARecordAnswer) {
answer.type = dns_protocol::kTypeA;
answer.klass = dns_protocol::kClassIN;
answer.ttl = 120; // 120 seconds.
answer.rdata = base::StringPiece("\xc0\xa8\x00\x01", 4);
answer.SetOwnedRdata(std::string("\xc0\xa8\x00\x01", 4));
std::vector<DnsResourceRecord> answers(1, answer);
DnsResponse response(0x1234 /* response_id */, true /* is_authoritative*/,
answers, {} /* additional records */, base::nullopt);
......@@ -704,7 +704,7 @@ TEST(DnsResponseWriteTest, SingleARecordAnswerWithFinalDotInName) {
answer.type = dns_protocol::kTypeA;
answer.klass = dns_protocol::kClassIN;
answer.ttl = 120; // 120 seconds.
answer.rdata = base::StringPiece("\xc0\xa8\x00\x01", 4);
answer.SetOwnedRdata(std::string("\xc0\xa8\x00\x01", 4));
std::vector<DnsResourceRecord> answers(1, answer);
DnsResponse response(0x1234 /* response_id */, true /* is_authoritative*/,
answers, {} /* additional records */, base::nullopt);
......@@ -750,7 +750,7 @@ TEST(DnsResponseWriteTest, SingleARecordAnswerWithQuestion) {
answer.type = dns_protocol::kTypeA;
answer.klass = dns_protocol::kClassIN;
answer.ttl = 120; // 120 seconds.
answer.rdata = base::StringPiece("\xc0\xa8\x00\x01", 4);
answer.SetOwnedRdata(std::string("\xc0\xa8\x00\x01", 4));
std::vector<DnsResourceRecord> answers(1, answer);
DnsResponse response(0x1234 /* id */, true /* is_authoritative*/, answers,
{} /* additional records */, query);
......@@ -813,7 +813,7 @@ TEST(DnsResponseWriteTest,
answer.type = dns_protocol::kTypeA;
answer.klass = dns_protocol::kClassIN;
answer.ttl = 120; // 120 seconds.
answer.rdata = base::StringPiece("\xc0\xa8\x00\x01", 4);
answer.SetOwnedRdata(std::string("\xc0\xa8\x00\x01", 4));
std::vector<DnsResourceRecord> answers(1, answer);
DnsResponse response(0x1234 /* id */, true /* is_authoritative*/, answers,
{} /* additional records */, query);
......@@ -848,8 +848,8 @@ TEST(DnsResponseWriteTest, SingleQuadARecordAnswer) {
answer.type = dns_protocol::kTypeAAAA;
answer.klass = dns_protocol::kClassIN;
answer.ttl = 120; // 120 seconds.
answer.rdata = base::StringPiece(
"\xfd\x12\x34\x56\x78\x9a\x00\x01\x00\x00\x00\x00\x00\x00\x00\x01", 16);
answer.SetOwnedRdata(std::string(
"\xfd\x12\x34\x56\x78\x9a\x00\x01\x00\x00\x00\x00\x00\x00\x00\x01", 16));
std::vector<DnsResourceRecord> answers(1, answer);
DnsResponse response(0x1234 /* id */, true /* is_authoritative*/, answers,
{} /* additional records */, base::nullopt);
......@@ -904,7 +904,7 @@ TEST(DnsResponseWriteTest,
answer.type = dns_protocol::kTypeA;
answer.klass = dns_protocol::kClassIN;
answer.ttl = 120; // 120 seconds.
answer.rdata = base::StringPiece("\xc0\xa8\x00\x01", 4);
answer.SetOwnedRdata(std::string("\xc0\xa8\x00\x01", 4));
std::vector<DnsResourceRecord> answers(1, answer);
net::DnsResourceRecord additional_record;
additional_record.name = dotted_name;
......@@ -912,7 +912,7 @@ TEST(DnsResponseWriteTest,
additional_record.klass = dns_protocol::kClassIN;
additional_record.ttl = 120; // 120 seconds.
// Bitmap for "www.example.com" with type A set.
additional_record.rdata = base::StringPiece("\xc0\x0c\x00\x01\x40", 5);
additional_record.SetOwnedRdata(std::string("\xc0\x0c\x00\x01\x40", 5));
std::vector<DnsResourceRecord> additional_records(1, additional_record);
DnsResponse response(0x1234 /* id */, true /* is_authoritative*/, answers,
additional_records, query);
......@@ -954,14 +954,14 @@ TEST(DnsResponseWriteTest, TwoAnswersWithAAndQuadARecords) {
answer1.type = dns_protocol::kTypeA;
answer1.klass = dns_protocol::kClassIN;
answer1.ttl = 120; // 120 seconds.
answer1.rdata = base::StringPiece("\xc0\xa8\x00\x01", 4);
answer1.SetOwnedRdata(std::string("\xc0\xa8\x00\x01", 4));
net::DnsResourceRecord answer2;
answer2.name = "example.org";
answer2.type = dns_protocol::kTypeAAAA;
answer2.klass = dns_protocol::kClassIN;
answer2.ttl = 60;
answer2.rdata = base::StringPiece(
"\xfd\x12\x34\x56\x78\x9a\x00\x01\x00\x00\x00\x00\x00\x00\x00\x01", 16);
answer2.SetOwnedRdata(std::string(
"\xfd\x12\x34\x56\x78\x9a\x00\x01\x00\x00\x00\x00\x00\x00\x00\x01", 16));
std::vector<DnsResourceRecord> answers(2);
answers[0] = answer1;
answers[1] = answer2;
......@@ -982,14 +982,14 @@ TEST(DnsResponseWriteTest, WrittenResponseCanBeParsed) {
answer.type = dns_protocol::kTypeA;
answer.klass = dns_protocol::kClassIN;
answer.ttl = 120; // 120 seconds.
answer.rdata = base::StringPiece("\xc0\xa8\x00\x01", 4);
answer.SetOwnedRdata(std::string("\xc0\xa8\x00\x01", 4));
std::vector<DnsResourceRecord> answers(1, answer);
net::DnsResourceRecord additional_record;
additional_record.name = dotted_name;
additional_record.type = dns_protocol::kTypeNSEC;
additional_record.klass = dns_protocol::kClassIN;
additional_record.ttl = 120; // 120 seconds.
additional_record.rdata = base::StringPiece("\xc0\x0c\x00\x01\x04", 5);
additional_record.SetOwnedRdata(std::string("\xc0\x0c\x00\x01\x04", 5));
std::vector<DnsResourceRecord> additional_records(1, additional_record);
DnsResponse response(0x1234 /* response_id */, true /* is_authoritative*/,
answers, additional_records, base::nullopt);
......@@ -1005,14 +1005,14 @@ TEST(DnsResponseWriteTest, WrittenResponseCanBeParsed) {
EXPECT_EQ(answer.type, parsed_record.type);
EXPECT_EQ(answer.klass, parsed_record.klass);
EXPECT_EQ(answer.ttl, parsed_record.ttl);
EXPECT_EQ(answer.rdata, parsed_record.rdata);
EXPECT_EQ(answer.owned_rdata, parsed_record.rdata);
// Additional NSEC record.
EXPECT_TRUE(parser.ReadRecord(&parsed_record));
EXPECT_EQ(additional_record.name, parsed_record.name);
EXPECT_EQ(additional_record.type, parsed_record.type);
EXPECT_EQ(additional_record.klass, parsed_record.klass);
EXPECT_EQ(additional_record.ttl, parsed_record.ttl);
EXPECT_EQ(additional_record.rdata, parsed_record.rdata);
EXPECT_EQ(additional_record.owned_rdata, parsed_record.rdata);
}
} // namespace
......
......@@ -12,6 +12,7 @@
#include <unordered_map>
#include <vector>
#include "base/big_endian.h"
#include "base/metrics/field_trial.h"
#include "base/metrics/histogram_macros.h"
#include "base/strings/string_number_conversions.h"
......@@ -31,6 +32,10 @@ namespace {
// by that number of octets.
const int kMaxLabelLength = 63;
// RFC 1035, section 4.1.4: the first two bits of a 16-bit name pointer are
// ones.
const uint16_t kFlagNamePointer = 0xc000;
} // namespace
#if defined(OS_POSIX)
......@@ -240,4 +245,12 @@ AddressListDeltaType FindAddressListDeltaType(const AddressList& a,
return DELTA_DISJOINT;
}
std::string CreateNamePointer(uint16_t offset) {
DCHECK_LE(offset, 0x3fff);
offset |= kFlagNamePointer;
char buf[2];
base::WriteBigEndian(buf, offset);
return std::string(buf, sizeof(buf));
}
} // namespace net
......@@ -21,8 +21,8 @@ class AddressList;
//
// dotted: a string in dotted form: "www.google.com"
// out: a result in DNS form: "\x03www\x06google\x03com\x00"
NET_EXPORT_PRIVATE bool DNSDomainFromDot(const base::StringPiece& dotted,
std::string* out);
NET_EXPORT bool DNSDomainFromDot(const base::StringPiece& dotted,
std::string* out);
// Checks that a hostname is valid. Simple wrapper around DNSDomainFromDot.
NET_EXPORT_PRIVATE bool IsValidDNSDomain(const base::StringPiece& dotted);
......@@ -44,8 +44,7 @@ NET_EXPORT_PRIVATE bool IsValidHostLabelCharacter(char c, bool is_first_char);
// DNSDomainToString converts a domain in DNS format to a dotted string.
// Excludes the dot at the end.
NET_EXPORT_PRIVATE std::string DNSDomainToString(
const base::StringPiece& domain);
NET_EXPORT std::string DNSDomainToString(const base::StringPiece& domain);
// Return the expanded template when no variables have corresponding values.
NET_EXPORT_PRIVATE std::string GetURLFromTemplateWithoutParameters(
......@@ -86,6 +85,13 @@ NET_EXPORT
AddressListDeltaType FindAddressListDeltaType(const AddressList& a,
const AddressList& b);
// Creates a 2-byte string that represents the name pointer defined in Section
// 4.1.1 of RFC 1035 for the given offset. The first two bits in the first byte
// of the name pointer are ones, and the rest 14 bits are given to |offset|,
// which specifies an offset from the start of the message for the pointed name.
// Note that |offset| must be less than 2^14 - 1 by definition.
NET_EXPORT std::string CreateNamePointer(uint16_t offset);
} // namespace net
#endif // NET_DNS_DNS_UTIL_H_
......@@ -26,7 +26,7 @@ class DnsRecordParser;
// Parsed represenation of the extra data in a record. Does not include standard
// DNS record data such as TTL, Name, Type and Class.
class NET_EXPORT_PRIVATE RecordRdata {
class NET_EXPORT RecordRdata {
public:
virtual ~RecordRdata() {}
......@@ -79,7 +79,7 @@ class NET_EXPORT_PRIVATE SrvRecordRdata : public RecordRdata {
// A Record format (http://www.ietf.org/rfc/rfc1035.txt):
// 4 bytes for IP address.
class NET_EXPORT_PRIVATE ARecordRdata : public RecordRdata {
class NET_EXPORT ARecordRdata : public RecordRdata {
public:
static const uint16_t kType = dns_protocol::kTypeA;
......@@ -101,7 +101,7 @@ class NET_EXPORT_PRIVATE ARecordRdata : public RecordRdata {
// AAAA Record format (http://www.ietf.org/rfc/rfc1035.txt):
// 16 bytes for IP address.
class NET_EXPORT_PRIVATE AAAARecordRdata : public RecordRdata {
class NET_EXPORT AAAARecordRdata : public RecordRdata {
public:
static const uint16_t kType = dns_protocol::kTypeAAAA;
......
......@@ -27,7 +27,7 @@ declare_args() {
disable_brotli_filter = false
# Multicast DNS.
enable_mdns = is_win || is_linux || is_fuchsia
enable_mdns = is_win || is_linux || is_fuchsia || is_mac || is_ios
# Reporting not used on iOS.
enable_reporting = !is_ios
......
......@@ -4,6 +4,7 @@
import("//build/config/jumbo.gni")
import("//mojo/public/tools/bindings/mojom.gni")
import("//net/features.gni")
import("//services/catalog/public/tools/catalog.gni")
import("//services/network/public/cpp/features.gni")
import("//services/service_manager/public/cpp/service.gni")
......@@ -158,6 +159,13 @@ jumbo_component("network_service") {
"url_request_context_owner.h",
]
if (enable_mdns) {
sources += [
"mdns_responder.cc",
"mdns_responder.h",
]
}
if (!is_ios) {
sources += [
"websocket.cc",
......@@ -301,6 +309,10 @@ source_set("tests") {
"url_loader_unittest.cc",
]
if (enable_mdns) {
sources += [ "mdns_responder_unittest.cc" ]
}
if (!is_ios) {
sources += [
"proxy_resolver_factory_mojo_unittest.cc",
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -118,6 +118,10 @@
#include "net/url_request/http_user_agent_settings.h"
#endif // BUILDFLAG(ENABLE_REPORTING)
#if BUILDFLAG(ENABLE_MDNS)
#include "services/network/mdns_responder.h"
#endif // BUILDFLAG(ENABLE_MDNS)
#if defined(USE_NSS_CERTS)
#include "net/cert_net/nss_ocsp.h"
#endif // defined(USE_NSS_CERTS)
......@@ -1458,6 +1462,18 @@ void NetworkContext::CreateP2PSocketManager(
socket_managers_[socket_manager.get()] = std::move(socket_manager);
}
void NetworkContext::CreateMdnsResponder(
mojom::MdnsResponderRequest responder_request) {
#if BUILDFLAG(ENABLE_MDNS)
if (!mdns_responder_manager_)
mdns_responder_manager_ = std::make_unique<MdnsResponderManager>();
mdns_responder_manager_->CreateMdnsResponder(std::move(responder_request));
#else
NOTREACHED();
#endif // BUILDFLAG(ENABLE_MDNS)
}
void NetworkContext::ResetURLLoaderFactories() {
for (const auto& factory : url_loader_factories_)
factory->ClearBindings();
......
......@@ -69,6 +69,7 @@ class ExpectCTReporter;
class HostResolver;
class NetworkService;
class NetworkServiceProxyDelegate;
class MdnsResponderManager;
class P2PSocketManager;
class ProxyLookupRequest;
class ResourceScheduler;
......@@ -300,6 +301,9 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) NetworkContext
mojom::P2PTrustedSocketManagerClientPtr client,
mojom::P2PTrustedSocketManagerRequest trusted_socket_manager,
mojom::P2PSocketManagerRequest socket_manager_request) override;
void CreateMdnsResponder(
mojom::MdnsResponderRequest responder_request) override;
void ResetURLLoaderFactories() override;
void QueueReport(const std::string& type,
const std::string& group,
......@@ -431,6 +435,10 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) NetworkContext
base::flat_map<P2PSocketManager*, std::unique_ptr<P2PSocketManager>>
socket_managers_;
#if BUILDFLAG(ENABLE_MDNS)
std::unique_ptr<MdnsResponderManager> mdns_responder_manager_;
#endif // BUILDFLAG(ENABLE_MDNS)
mojo::StrongBindingSet<mojom::NetLogExporter> net_log_exporter_bindings_;
mojo::StrongBindingSet<mojom::RestrictedCookieManager>
......
......@@ -82,6 +82,7 @@ mojom("mojom") {
"fetch_api.mojom",
"host_resolver.mojom",
"http_request_headers.mojom",
"mdns_responder.mojom",
"net_log.mojom",
"network_change_manager.mojom",
"network_context.mojom",
......
// Copyright 2018 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.
module network.mojom;
import "net/interfaces/ip_address.mojom";
// An mDNS responder is created for each Mojo binding and it manages the
// name-address maps created through the interface. The name-address maps are
// isolated among different responders, so that the creation and the removal
// of a name for an address is specific to the given responder. When the Mojo
// pipe is closed, all name-address maps created through the interface are
// removed by the responder and the responder is destroyed afterwards. For a
// given responder, all created names are reference counted, and each
// CreateNameForAddress call and RemoveNameForAddress call respectively
// increases and decreases the reference count for existing names.
//
// This interface is intended to be safe to use from renderer processes.
interface MdnsResponder {
// Creates and returns a new name for the address if there is no name mapped
// to it by this responder, and initializes the reference count of this name
// to one. Otherwise the existing name mapped to the given address is returned
// and its reference count is incremented by one. Since the name-address maps
// are specific to the given responder, there could be separated names for the
// same address. After a new name is mapped to an address, an mDNS response to
// announce the ownership of this name is scheduled to send to the mDNS
// multicast group over all interfaces, with a TTL for the name set to 120
// seconds (see RFC 6762, Section 10). Returns true in
// |announcement_scheduled| if the schedule is done on all interfaces after
// rate limiting, and false otherwise. The responder will also start to
// respond to queries for the created name until its reference count is
// decremented to zero.
CreateNameForAddress(net.interfaces.IPAddress address)
=> (string name, bool announcement_scheduled);
// Decrements the reference count of the mapped name of the given address, if
// there is a map created previously via CreateNameForAddress; removes the
// association between the address and its mapped name and returns true in
// |removed| if the decremented reference count reaches zero. Otherwise no
// operation is done and false is returned in |removed|. If the association
// between the address and its mapped name is removed, an mDNS response to
// renounce the ownership of this name is scheduled to send to the mDNS
// multicast group over all interfaces, by setting a zero TTL. Returns true in
// |goodbye_scheduled| if the schedule is done on all interfaces after rate
// limiting, and false otherwise. The responder will also stop responding to
// queries for the removed name. Note that this does not impact separated
// names mapped to the same address by other responders.
RemoveNameForAddress(net.interfaces.IPAddress address)
=> (bool removed, bool goodbye_scheduled);
};
......@@ -14,6 +14,7 @@ import "services/network/public/mojom/cookie_manager.mojom";
import "services/network/public/mojom/cors_origin_pattern.mojom";
import "services/network/public/mojom/host_resolver.mojom";
import "services/network/public/mojom/http_request_headers.mojom";
import "services/network/public/mojom/mdns_responder.mojom";
import "services/network/public/mojom/mutable_network_traffic_annotation_tag.mojom";
import "services/network/public/mojom/net_log.mojom";
import "services/network/public/mojom/network_param.mojom";
......@@ -651,6 +652,9 @@ interface NetworkContext {
P2PTrustedSocketManager& trusted_socket_manager,
P2PSocketManager& socket_manager);
// Creates an MdnsResponder instance.
CreateMdnsResponder(MdnsResponder& responder_request);
// Destroys all URLLoaderFactory bindings, which should then be regenerated.
// This should be called if there is a change to the proxies which should be
// used on URLLoaders.
......
......@@ -180,6 +180,9 @@ class TestNetworkContext : public mojom::NetworkContext {
mojom::P2PTrustedSocketManagerClientPtr client,
mojom::P2PTrustedSocketManagerRequest trusted_socket_manager,
mojom::P2PSocketManagerRequest socket_manager_request) override {}
void CreateMdnsResponder(
mojom::MdnsResponderRequest responder_request) override {}
void ResetURLLoaderFactories() override {}
void ForceReloadProxyConfig(
ForceReloadProxyConfigCallback callback) override {}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment