Implement the WebRTC MdnsResponderInterface in Chromium.

MdnsResponderInterface is introduced in WebRTC to handle the hostname
generation and resolution of ICE host candidates when concealing their
local IP addresses. For WebRTC in Chromium, we implement it as a client
of the service provided by network::mojom::MdnsResponder.

Bug: 878465
Change-Id: Id7b79694deba0ef308e51f83d6134062ddcb3985
Reviewed-on: https://chromium-review.googlesource.com/c/1206002
Commit-Queue: Qingsi Wang <[email protected]>
Reviewed-by: Sergey Ulanov <[email protected]>
Reviewed-by: Avi Drissman <[email protected]>
Reviewed-by: Jesse Doherty <[email protected]>
Cr-Commit-Position: refs/heads/master@{#605153}
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 0f97c13..5082a05 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -1412,6 +1412,10 @@
      flag_descriptions::kWebrtcNewEncodeCpuLoadEstimatorName,
      flag_descriptions::kWebrtcNewEncodeCpuLoadEstimatorDescription, kOsAll,
      FEATURE_VALUE_TYPE(media::kNewEncodeCpuLoadEstimator)},
+    {"enable-webrtc-hide-local-ips-with-mdns",
+     flag_descriptions::kWebrtcHideLocalIpsWithMdnsName,
+     flag_descriptions::kWebrtcHideLocalIpsWithMdnsDecription, kOsDesktop,
+     FEATURE_VALUE_TYPE(features::kWebRtcHideLocalIpsWithMdns)},
     {"webrtc-unified-plan-by-default",
      flag_descriptions::kWebrtcUnifiedPlanByDefaultName,
      flag_descriptions::kWebrtcUnifiedPlanByDefaultDescription, kOsAll,
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index c7e7686..992b02e 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -2075,6 +2075,11 @@
 const char kWebrtcEchoCanceller3Description[] =
     "Experimental WebRTC echo canceller (AEC3).";
 
+const char kWebrtcHideLocalIpsWithMdnsName[] =
+    "Anonymize local IPs exposed by WebRTC.";
+const char kWebrtcHideLocalIpsWithMdnsDecription[] =
+    "Conceal local IP addresses with mDNS hostnames.";
+
 const char kWebrtcHybridAgcName[] = "WebRTC hybrid Agc2/Agc1.";
 const char kWebrtcHybridAgcDescription[] =
     "WebRTC Agc2 digital adaptation with Agc1 analog adaptation.";
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index 1f27c64..ff171832 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -1248,6 +1248,9 @@
 extern const char kWebrtcEchoCanceller3Name[];
 extern const char kWebrtcEchoCanceller3Description[];
 
+extern const char kWebrtcHideLocalIpsWithMdnsName[];
+extern const char kWebrtcHideLocalIpsWithMdnsDecription[];
+
 extern const char kWebrtcHybridAgcName[];
 extern const char kWebrtcHybridAgcDescription[];
 
diff --git a/content/renderer/BUILD.gn b/content/renderer/BUILD.gn
index 005311f..fdb2672 100644
--- a/content/renderer/BUILD.gn
+++ b/content/renderer/BUILD.gn
@@ -485,6 +485,8 @@
     "p2p/ipc_network_manager.h",
     "p2p/ipc_socket_factory.cc",
     "p2p/ipc_socket_factory.h",
+    "p2p/mdns_responder_adapter.cc",
+    "p2p/mdns_responder_adapter.h",
     "p2p/network_list_manager.h",
     "p2p/network_list_observer.h",
     "p2p/network_manager_uma.cc",
diff --git a/content/renderer/media/webrtc/peer_connection_dependency_factory.cc b/content/renderer/media/webrtc/peer_connection_dependency_factory.cc
index 87c3c87..0c67b3d 100644
--- a/content/renderer/media/webrtc/peer_connection_dependency_factory.cc
+++ b/content/renderer/media/webrtc/peer_connection_dependency_factory.cc
@@ -45,6 +45,7 @@
 #include "content/renderer/p2p/filtering_network_manager.h"
 #include "content/renderer/p2p/ipc_network_manager.h"
 #include "content/renderer/p2p/ipc_socket_factory.h"
+#include "content/renderer/p2p/mdns_responder_adapter.h"
 #include "content/renderer/p2p/port_allocator.h"
 #include "content/renderer/render_frame_impl.h"
 #include "content/renderer/render_thread_impl.h"
@@ -207,11 +208,18 @@
   base::WaitableEvent create_network_manager_event(
       base::WaitableEvent::ResetPolicy::MANUAL,
       base::WaitableEvent::InitialState::NOT_SIGNALED);
+  std::unique_ptr<MdnsResponderAdapter> mdns_responder;
+#if BUILDFLAG(ENABLE_MDNS)
+  if (base::FeatureList::IsEnabled(features::kWebRtcHideLocalIpsWithMdns)) {
+    mdns_responder = std::make_unique<MdnsResponderAdapter>();
+  }
+#endif  // BUILDFLAG(ENABLE_MDNS)
   chrome_worker_thread_.task_runner()->PostTask(
       FROM_HERE,
       base::BindOnce(&PeerConnectionDependencyFactory::
                          CreateIpcNetworkManagerOnWorkerThread,
-                     base::Unretained(this), &create_network_manager_event));
+                     base::Unretained(this), &create_network_manager_event,
+                     std::move(mdns_responder)));
 
   start_worker_event.Wait();
   create_network_manager_event.Wait();
@@ -471,11 +479,11 @@
   std::unique_ptr<rtc::NetworkManager> network_manager;
   if (port_config.enable_multiple_routes) {
     FilteringNetworkManager* filtering_network_manager =
-        new FilteringNetworkManager(network_manager_, requesting_origin,
+        new FilteringNetworkManager(network_manager_.get(), requesting_origin,
                                     media_permission);
     network_manager.reset(filtering_network_manager);
   } else {
-    network_manager.reset(new EmptyNetworkManager(network_manager_));
+    network_manager.reset(new EmptyNetworkManager(network_manager_.get()));
   }
   auto port_allocator = std::make_unique<P2PPortAllocator>(
       p2p_socket_dispatcher_, std::move(network_manager), socket_factory_.get(),
@@ -567,21 +575,22 @@
     const std::string& params) {
   DCHECK(network_manager_);
   DCHECK(chrome_worker_thread_.task_runner()->BelongsToCurrentThread());
-  stun_trial_.reset(
-      new StunProberTrial(network_manager_, params, socket_factory_.get()));
+  stun_trial_.reset(new StunProberTrial(network_manager_.get(), params,
+                                        socket_factory_.get()));
 }
 
 void PeerConnectionDependencyFactory::CreateIpcNetworkManagerOnWorkerThread(
-    base::WaitableEvent* event) {
+    base::WaitableEvent* event,
+    std::unique_ptr<MdnsResponderAdapter> mdns_responder) {
   DCHECK(chrome_worker_thread_.task_runner()->BelongsToCurrentThread());
-  network_manager_ = new IpcNetworkManager(p2p_socket_dispatcher_.get());
+  network_manager_ = std::make_unique<IpcNetworkManager>(
+      p2p_socket_dispatcher_.get(), std::move(mdns_responder));
   event->Signal();
 }
 
 void PeerConnectionDependencyFactory::DeleteIpcNetworkManager() {
   DCHECK(chrome_worker_thread_.task_runner()->BelongsToCurrentThread());
-  delete network_manager_;
-  network_manager_ = nullptr;
+  network_manager_.reset();
 }
 
 void PeerConnectionDependencyFactory::CleanupPeerConnectionFactory() {
diff --git a/content/renderer/media/webrtc/peer_connection_dependency_factory.h b/content/renderer/media/webrtc/peer_connection_dependency_factory.h
index 39f6f9ed..720c39087 100644
--- a/content/renderer/media/webrtc/peer_connection_dependency_factory.h
+++ b/content/renderer/media/webrtc/peer_connection_dependency_factory.h
@@ -42,6 +42,7 @@
 
 class IpcNetworkManager;
 class IpcPacketSocketFactory;
+class MdnsResponderAdapter;
 class P2PPortAllocator;
 class WebRtcAudioDeviceImpl;
 
@@ -49,8 +50,7 @@
 class CONTENT_EXPORT PeerConnectionDependencyFactory
     : base::MessageLoopCurrent::DestructionObserver {
  public:
-  PeerConnectionDependencyFactory(
-      P2PSocketDispatcher* p2p_socket_dispatcher);
+  PeerConnectionDependencyFactory(P2PSocketDispatcher* p2p_socket_dispatcher);
   ~PeerConnectionDependencyFactory() override;
 
   // Create a RTCPeerConnectionHandler object that implements the
@@ -146,13 +146,15 @@
   void InitializeWorkerThread(rtc::Thread** thread,
                               base::WaitableEvent* event);
 
-  void CreateIpcNetworkManagerOnWorkerThread(base::WaitableEvent* event);
+  void CreateIpcNetworkManagerOnWorkerThread(
+      base::WaitableEvent* event,
+      std::unique_ptr<MdnsResponderAdapter> mdns_responder);
   void DeleteIpcNetworkManager();
   void CleanupPeerConnectionFactory();
 
-  // We own network_manager_, must be deleted on the worker thread.
-  // The network manager uses |p2p_socket_dispatcher_|.
-  IpcNetworkManager* network_manager_;
+  // network_manager_ must be deleted on the worker thread. The network manager
+  // uses |p2p_socket_dispatcher_|.
+  std::unique_ptr<IpcNetworkManager> network_manager_;
   std::unique_ptr<IpcPacketSocketFactory> socket_factory_;
 
   scoped_refptr<webrtc::PeerConnectionFactoryInterface> pc_factory_;
diff --git a/content/renderer/p2p/filtering_network_manager.cc b/content/renderer/p2p/filtering_network_manager.cc
index f8b2ec4..66fb08a 100644
--- a/content/renderer/p2p/filtering_network_manager.cc
+++ b/content/renderer/p2p/filtering_network_manager.cc
@@ -91,6 +91,11 @@
   return network_manager_->GetDefaultLocalAddress(family, ipaddress);
 }
 
+webrtc::MdnsResponderInterface* FilteringNetworkManager::GetMdnsResponder()
+    const {
+  return network_manager_->GetMdnsResponder();
+}
+
 void FilteringNetworkManager::CheckPermission() {
   DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!started_permission_check_);
diff --git a/content/renderer/p2p/filtering_network_manager.h b/content/renderer/p2p/filtering_network_manager.h
index 16ef60d..7d3b292c 100644
--- a/content/renderer/p2p/filtering_network_manager.h
+++ b/content/renderer/p2p/filtering_network_manager.h
@@ -54,6 +54,8 @@
   bool GetDefaultLocalAddress(int family,
                               rtc::IPAddress* ipaddress) const override;
 
+  webrtc::MdnsResponderInterface* GetMdnsResponder() const override;
+
  private:
   // Check mic/camera permission.
   void CheckPermission();
diff --git a/content/renderer/p2p/ipc_network_manager.cc b/content/renderer/p2p/ipc_network_manager.cc
index 169c27a0..2f64d9a 100644
--- a/content/renderer/p2p/ipc_network_manager.cc
+++ b/content/renderer/p2p/ipc_network_manager.cc
@@ -43,10 +43,11 @@
 
 }  // namespace
 
-IpcNetworkManager::IpcNetworkManager(NetworkListManager* network_list_manager)
+IpcNetworkManager::IpcNetworkManager(
+    NetworkListManager* network_list_manager,
+    std::unique_ptr<MdnsResponderAdapter> mdns_responder)
     : network_list_manager_(network_list_manager),
-      start_count_(0),
-      network_list_received_(false),
+      mdns_responder_(std::move(mdns_responder)),
       weak_factory_(this) {
   network_list_manager_->AddNetworkListObserver(this);
 }
@@ -184,6 +185,10 @@
                            stats.ipv6_network_count);
 }
 
+webrtc::MdnsResponderInterface* IpcNetworkManager::GetMdnsResponder() const {
+  return mdns_responder_.get();
+}
+
 void IpcNetworkManager::SendNetworksChangedSignal() {
   SignalNetworksChanged();
 }
diff --git a/content/renderer/p2p/ipc_network_manager.h b/content/renderer/p2p/ipc_network_manager.h
index 1d511ff0..c0395753 100644
--- a/content/renderer/p2p/ipc_network_manager.h
+++ b/content/renderer/p2p/ipc_network_manager.h
@@ -5,18 +5,21 @@
 #ifndef CONTENT_RENDERER_P2P_IPC_NETWORK_MANAGER_H_
 #define CONTENT_RENDERER_P2P_IPC_NETWORK_MANAGER_H_
 
+#include <memory>
 #include <vector>
 
 #include "base/compiler_specific.h"
 #include "base/memory/weak_ptr.h"
 #include "content/common/content_export.h"
+#include "content/renderer/p2p/mdns_responder_adapter.h"
 #include "content/renderer/p2p/network_list_manager.h"
 #include "content/renderer/p2p/network_list_observer.h"
+#include "third_party/webrtc/rtc_base/mdns_responder_interface.h"
 #include "third_party/webrtc/rtc_base/network.h"
 
 namespace net {
 class IPAddress;
-}
+}  // namespace net
 
 namespace content {
 
@@ -26,12 +29,15 @@
                           public NetworkListObserver {
  public:
   // Constructor doesn't take ownership of the |network_list_manager|.
-  CONTENT_EXPORT IpcNetworkManager(NetworkListManager* network_list_manager);
+  CONTENT_EXPORT IpcNetworkManager(
+      NetworkListManager* network_list_manager,
+      std::unique_ptr<MdnsResponderAdapter> mdns_responder);
   ~IpcNetworkManager() override;
 
   // rtc:::NetworkManager:
   void StartUpdating() override;
   void StopUpdating() override;
+  webrtc::MdnsResponderInterface* GetMdnsResponder() const override;
 
   // P2PSocketDispatcher::NetworkListObserver interface.
   void OnNetworkListChanged(
@@ -43,8 +49,9 @@
   void SendNetworksChangedSignal();
 
   NetworkListManager* network_list_manager_;
-  int start_count_;
-  bool network_list_received_;
+  std::unique_ptr<MdnsResponderAdapter> mdns_responder_;
+  int start_count_ = 0;
+  bool network_list_received_ = false;
 
   base::WeakPtrFactory<IpcNetworkManager> weak_factory_;
 };
diff --git a/content/renderer/p2p/ipc_network_manager_unittest.cc b/content/renderer/p2p/ipc_network_manager_unittest.cc
index 06bb29c..26b96cf 100644
--- a/content/renderer/p2p/ipc_network_manager_unittest.cc
+++ b/content/renderer/p2p/ipc_network_manager_unittest.cc
@@ -41,7 +41,8 @@
  public:
   IpcNetworkManagerTest()
       : network_list_manager_(new MockP2PSocketDispatcher()),
-        network_manager_(new IpcNetworkManager(network_list_manager_.get())) {}
+        network_manager_(
+            new IpcNetworkManager(network_list_manager_.get(), nullptr)) {}
 
  protected:
   std::unique_ptr<MockP2PSocketDispatcher> network_list_manager_;
diff --git a/content/renderer/p2p/mdns_responder_adapter.cc b/content/renderer/p2p/mdns_responder_adapter.cc
new file mode 100644
index 0000000..849a946
--- /dev/null
+++ b/content/renderer/p2p/mdns_responder_adapter.cc
@@ -0,0 +1,62 @@
+// 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.
+
+#include "content/renderer/p2p/mdns_responder_adapter.h"
+
+#include <string>
+
+#include "base/bind.h"
+#include "content/child/child_thread_impl.h"
+#include "content/public/common/service_names.mojom.h"
+#include "jingle/glue/utils.h"
+#include "net/base/ip_address.h"
+#include "net/base/ip_endpoint.h"
+#include "services/service_manager/public/cpp/connector.h"
+#include "third_party/webrtc/rtc_base/ipaddress.h"
+
+namespace content {
+
+namespace {
+
+void OnNameCreatedForAddress(
+    webrtc::MdnsResponderInterface::NameCreatedCallback callback,
+    const rtc::IPAddress& addr,
+    const std::string& name,
+    bool announcement_scheduled) {
+  // We currently ignore whether there is an announcement sent for the name.
+  callback(addr, name);
+}
+
+void OnNameRemovedForAddress(
+    webrtc::MdnsResponderInterface::NameRemovedCallback callback,
+    bool removed,
+    bool goodbye_scheduled) {
+  // We currently ignore whether there is a goodbye sent for the name.
+  callback(removed);
+}
+
+}  // namespace
+
+MdnsResponderAdapter::MdnsResponderAdapter() {
+  ChildThreadImpl::current()->GetConnector()->BindInterface(
+      mojom::kBrowserServiceName, mojo::MakeRequest(&client_));
+}
+
+MdnsResponderAdapter::~MdnsResponderAdapter() = default;
+
+void MdnsResponderAdapter::CreateNameForAddress(const rtc::IPAddress& addr,
+                                                NameCreatedCallback callback) {
+  client_->CreateNameForAddress(
+      jingle_glue::RtcIPAddressToNetIPAddress(addr),
+      base::BindOnce(&OnNameCreatedForAddress, callback, addr));
+}
+
+void MdnsResponderAdapter::RemoveNameForAddress(const rtc::IPAddress& addr,
+                                                NameRemovedCallback callback) {
+  client_->RemoveNameForAddress(
+      jingle_glue::RtcIPAddressToNetIPAddress(addr),
+      base::BindOnce(&OnNameRemovedForAddress, callback));
+}
+
+}  // namespace content
diff --git a/content/renderer/p2p/mdns_responder_adapter.h b/content/renderer/p2p/mdns_responder_adapter.h
new file mode 100644
index 0000000..dfada7f
--- /dev/null
+++ b/content/renderer/p2p/mdns_responder_adapter.h
@@ -0,0 +1,42 @@
+// 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.
+
+#ifndef CONTENT_RENDERER_P2P_MDNS_RESPONDER_ADAPTER_H_
+#define CONTENT_RENDERER_P2P_MDNS_RESPONDER_ADAPTER_H_
+
+#include "services/network/public/mojom/mdns_responder.mojom.h"
+#include "third_party/webrtc/rtc_base/mdns_responder_interface.h"
+
+namespace rtc {
+class IPAddress;
+}  // namespace rtc
+
+namespace content {
+
+// This class is created on the main thread but is used only on the WebRTC
+// worker threads. The MdnsResponderAdapter implements the WebRTC mDNS responder
+// interface via the MdnsResponder service in Chromium, and is used to register
+// and resolve mDNS hostnames to conceal local IP addresses.
+class MdnsResponderAdapter : public webrtc::MdnsResponderInterface {
+ public:
+  // The adapter should be created on the main thread to have access to the
+  // connector to the service manager.
+  MdnsResponderAdapter();
+  ~MdnsResponderAdapter() override;
+
+  // webrtc::MdnsResponderInterface implementation.
+  void CreateNameForAddress(const rtc::IPAddress& addr,
+                            NameCreatedCallback callback) override;
+  void RemoveNameForAddress(const rtc::IPAddress& addr,
+                            NameRemovedCallback callback) override;
+
+ private:
+  network::mojom::MdnsResponderPtr client_;
+
+  DISALLOW_COPY_AND_ASSIGN(MdnsResponderAdapter);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_RENDERER_P2P_MDNS_RESPONDER_ADAPTER_H_
diff --git a/jingle/glue/utils.cc b/jingle/glue/utils.cc
index 816bf724..9fba7b6 100644
--- a/jingle/glue/utils.cc
+++ b/jingle/glue/utils.cc
@@ -51,6 +51,13 @@
   return rtc::IPAddress();
 }
 
+net::IPAddress RtcIPAddressToNetIPAddress(const rtc::IPAddress& ip_address) {
+  rtc::SocketAddress socket_address(ip_address, 0);
+  net::IPEndPoint ip_endpoint;
+  jingle_glue::SocketAddressToIPEndPoint(socket_address, &ip_endpoint);
+  return ip_endpoint.address();
+}
+
 std::string SerializeP2PCandidate(const cricket::Candidate& candidate) {
   // TODO(sergeyu): Use SDP to format candidates?
   base::DictionaryValue value;
diff --git a/jingle/glue/utils.h b/jingle/glue/utils.h
index 53272f9..8a5dfc77 100644
--- a/jingle/glue/utils.h
+++ b/jingle/glue/utils.h
@@ -34,6 +34,8 @@
 
 rtc::IPAddress NetIPAddressToRtcIPAddress(const net::IPAddress& ip_address);
 
+net::IPAddress RtcIPAddressToNetIPAddress(const rtc::IPAddress& ip_address);
+
 // Helper functions to serialize and deserialize P2P candidates.
 std::string SerializeP2PCandidate(const cricket::Candidate& candidate);
 bool DeserializeP2PCandidate(const std::string& address,
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index ebf9865..4c1be06d 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -30020,6 +30020,7 @@
   <int value="-59401847" label="ContentSuggestionsLargeThumbnail:disabled"/>
   <int value="-58242474" label="ash-disable-swipe-to-close-in-overview-mode"/>
   <int value="-57986995" label="DisablePostScriptPrinting:enabled"/>
+  <int value="-56235502" label="WebRtcHideLocalIpsWithMdns:enabled"/>
   <int value="-55944747" label="disable-child-account-detection"/>
   <int value="-52483823" label="disable-new-video-renderer"/>
   <int value="-52241456" label="enable-single-click-autofill"/>
@@ -30310,6 +30311,7 @@
   <int value="513356954" label="InstantTethering:disabled"/>
   <int value="513372959" label="ViewsProfileChooser:enabled"/>
   <int value="517568645" label="AnimatedAppMenuIcon:disabled"/>
+  <int value="533064367" label="WebRtcHideLocalIpsWithMdns:disabled"/>
   <int value="535131384" label="OmniboxTailSuggestions:enabled"/>
   <int value="535976218" label="enable-plugin-power-saver"/>
   <int value="538468149" label="OfflinePagesCT:enabled"/>