Extending UsagePattern and private IP addresses.

Adding additional usage bits to the UsagePattern to:
- Track whether a mDNS candidate was collected
- Track whether a mDNS candidate was received from the remote peer
- Track whether a private IP address was received from the remote peer

The definition of a private IP address is extended to include 100.64/10 addresses.


Bug: None
Change-Id: I77182685120413d5c13c5f67e480d33fdcaefc6a
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/134000
Commit-Queue: Jeroen de Borst <jeroendb@webrtc.org>
Reviewed-by: Justin Uberti <juberti@google.com>
Reviewed-by: Steve Anton <steveanton@webrtc.org>
Reviewed-by: Qingsi Wang <qingsi@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#27747}
diff --git a/pc/peer_connection.cc b/pc/peer_connection.cc
index 1b011a3..f7cfc9a 100644
--- a/pc/peer_connection.cc
+++ b/pc/peer_connection.cc
@@ -76,9 +76,9 @@
 using cricket::TransportInfo;
 
 using cricket::LOCAL_PORT_TYPE;
-using cricket::STUN_PORT_TYPE;
-using cricket::RELAY_PORT_TYPE;
 using cricket::PRFLX_PORT_TYPE;
+using cricket::RELAY_PORT_TYPE;
+using cricket::STUN_PORT_TYPE;
 
 namespace webrtc {
 
@@ -3584,6 +3584,12 @@
     bool result = UseCandidate(ice_candidate);
     if (result) {
       NoteUsageEvent(UsageEvent::REMOTE_CANDIDATE_ADDED);
+      if (ice_candidate->candidate().address().IsUnresolvedIP()) {
+        NoteUsageEvent(UsageEvent::REMOTE_MDNS_CANDIDATE_ADDED);
+      }
+      if (ice_candidate->candidate().address().IsPrivateIP()) {
+        NoteUsageEvent(UsageEvent::REMOTE_PRIVATE_CANDIDATE_ADDED);
+      }
       NoteAddIceCandidateResult(kAddIceCandidateSuccess);
     } else {
       NoteAddIceCandidateResult(kAddIceCandidateFailNotUsable);
@@ -4154,6 +4160,10 @@
       candidate->candidate().address().IsPrivateIP()) {
     NoteUsageEvent(UsageEvent::PRIVATE_CANDIDATE_COLLECTED);
   }
+  if (candidate->candidate().type() == LOCAL_PORT_TYPE &&
+      candidate->candidate().address().IsUnresolvedIP()) {
+    NoteUsageEvent(UsageEvent::MDNS_CANDIDATE_COLLECTED);
+  }
   Observer()->OnIceCandidate(candidate.get());
 }
 
diff --git a/pc/peer_connection.h b/pc/peer_connection.h
index c21261c..39cb867 100644
--- a/pc/peer_connection.h
+++ b/pc/peer_connection.h
@@ -73,7 +73,10 @@
     ICE_STATE_CONNECTED = 0x200,
     CLOSE_CALLED = 0x400,
     PRIVATE_CANDIDATE_COLLECTED = 0x800,
-    MAX_VALUE = 0x1000,
+    REMOTE_PRIVATE_CANDIDATE_ADDED = 0x1000,
+    MDNS_CANDIDATE_COLLECTED = 0x2000,
+    REMOTE_MDNS_CANDIDATE_ADDED = 0x4000,
+    MAX_VALUE = 0x8000,
   };
 
   explicit PeerConnection(PeerConnectionFactory* factory,
diff --git a/pc/peer_connection_histogram_unittest.cc b/pc/peer_connection_histogram_unittest.cc
index 78b41d5..97555a9 100644
--- a/pc/peer_connection_histogram_unittest.cc
+++ b/pc/peer_connection_histogram_unittest.cc
@@ -23,6 +23,7 @@
 #include "api/rtc_error.h"
 #include "api/scoped_refptr.h"
 #include "media/base/fake_media_engine.h"
+#include "p2p/base/mock_async_resolver.h"
 #include "p2p/base/port_allocator.h"
 #include "p2p/client/basic_port_allocator.h"
 #include "pc/peer_connection.h"
@@ -30,6 +31,7 @@
 #include "pc/peer_connection_wrapper.h"
 #include "pc/sdp_utils.h"
 #include "pc/test/mock_peer_connection_observers.h"
+#include "rtc_base/arraysize.h"
 #include "rtc_base/checks.h"
 #include "rtc_base/fake_network.h"
 #include "rtc_base/gunit.h"
@@ -39,17 +41,19 @@
 #include "rtc_base/thread.h"
 #include "rtc_base/virtual_socket_server.h"
 #include "system_wrappers/include/metrics.h"
-#include "test/gtest.h"
+#include "test/gmock.h"
 
 namespace webrtc {
 
 using RTCConfiguration = PeerConnectionInterface::RTCConfiguration;
 using RTCOfferAnswerOptions = PeerConnectionInterface::RTCOfferAnswerOptions;
+using ::testing::NiceMock;
 using ::testing::Values;
 
 static const char kUsagePatternMetric[] = "WebRTC.PeerConnection.UsagePattern";
 static constexpr int kDefaultTimeout = 10000;
-static const rtc::SocketAddress kDefaultLocalAddress("1.1.1.1", 0);
+static const rtc::SocketAddress kLocalAddrs[2] = {
+    rtc::SocketAddress("1.1.1.1", 0), rtc::SocketAddress("2.2.2.2", 0)};
 static const rtc::SocketAddress kPrivateLocalAddress("10.1.1.1", 0);
 
 int MakeUsageFingerprint(std::set<PeerConnection::UsageEvent> events) {
@@ -234,6 +238,27 @@
         config, PeerConnectionFactoryInterface::Options(), nullptr, false);
   }
 
+  WrapperPtr CreatePeerConnectionWithMdns(const RTCConfiguration& config) {
+    auto resolver_factory =
+        absl::make_unique<NiceMock<webrtc::MockAsyncResolverFactory>>();
+
+    webrtc::PeerConnectionDependencies deps(nullptr /* observer_in */);
+
+    auto fake_network = NewFakeNetwork();
+    fake_network->CreateMdnsResponder(rtc::Thread::Current());
+    fake_network->AddInterface(NextLocalAddress());
+
+    std::unique_ptr<cricket::BasicPortAllocator> port_allocator(
+        new cricket::BasicPortAllocator(fake_network));
+
+    deps.async_resolver_factory = std::move(resolver_factory);
+    deps.allocator = std::move(port_allocator);
+
+    return CreatePeerConnection(config,
+                                PeerConnectionFactoryInterface::Options(),
+                                std::move(deps), false);
+  }
+
   WrapperPtr CreatePeerConnectionWithImmediateReport() {
     return CreatePeerConnection(RTCConfiguration(),
                                 PeerConnectionFactoryInterface::Options(),
@@ -241,11 +266,13 @@
   }
 
   WrapperPtr CreatePeerConnectionWithPrivateLocalAddresses() {
-    fake_network_manager_.reset(new rtc::FakeNetworkManager());
-    fake_network_manager_->AddInterface(kDefaultLocalAddress);
-    fake_network_manager_->AddInterface(kPrivateLocalAddress);
-    std::unique_ptr<cricket::BasicPortAllocator> port_allocator(
-        new cricket::BasicPortAllocator(fake_network_manager_.get()));
+    auto* fake_network = NewFakeNetwork();
+    fake_network->AddInterface(NextLocalAddress());
+    fake_network->AddInterface(kPrivateLocalAddress);
+
+    auto port_allocator =
+        absl::make_unique<cricket::BasicPortAllocator>(fake_network);
+
     return CreatePeerConnection(RTCConfiguration(),
                                 PeerConnectionFactoryInterface::Options(),
                                 std::move(port_allocator), false);
@@ -256,6 +283,18 @@
       const PeerConnectionFactoryInterface::Options factory_options,
       std::unique_ptr<cricket::PortAllocator> allocator,
       bool immediate_report) {
+    PeerConnectionDependencies deps(nullptr);
+    deps.allocator = std::move(allocator);
+
+    return CreatePeerConnection(config, factory_options, std::move(deps),
+                                immediate_report);
+  }
+
+  WrapperPtr CreatePeerConnection(
+      const RTCConfiguration& config,
+      const PeerConnectionFactoryInterface::Options factory_options,
+      PeerConnectionDependencies deps,
+      bool immediate_report) {
     rtc::scoped_refptr<PeerConnectionFactoryForUsageHistogramTest> pc_factory(
         new PeerConnectionFactoryForUsageHistogramTest());
     pc_factory->SetOptions(factory_options);
@@ -263,9 +302,20 @@
     if (immediate_report) {
       pc_factory->ReturnHistogramVeryQuickly();
     }
+
+    // If no allocator is provided, one will be created using a network manager
+    // that uses the host network. This doesn't work on all trybots.
+    if (!deps.allocator) {
+      auto fake_network = NewFakeNetwork();
+      fake_network->AddInterface(NextLocalAddress());
+      deps.allocator =
+          absl::make_unique<cricket::BasicPortAllocator>(fake_network);
+    }
+
     auto observer = absl::make_unique<ObserverForUsageHistogramTest>();
-    auto pc = pc_factory->CreatePeerConnection(config, std::move(allocator),
-                                               nullptr, observer.get());
+    deps.observer = observer.get();
+
+    auto pc = pc_factory->CreatePeerConnection(config, std::move(deps));
     if (!pc) {
       return nullptr;
     }
@@ -284,7 +334,23 @@
     return webrtc::metrics::MinSample(kUsagePatternMetric);
   }
 
-  std::unique_ptr<rtc::FakeNetworkManager> fake_network_manager_;
+  // The PeerConnection's port allocator is tied to the PeerConnection's
+  // lifetime and expects the underlying NetworkManager to outlive it.  That
+  // prevents us from having the PeerConnectionWrapper own the fake network.
+  // Therefore, the test fixture will own all the fake networks even though
+  // tests should access the fake network through the PeerConnectionWrapper.
+  rtc::FakeNetworkManager* NewFakeNetwork() {
+    fake_networks_.emplace_back(absl::make_unique<rtc::FakeNetworkManager>());
+    return fake_networks_.back().get();
+  }
+
+  rtc::SocketAddress NextLocalAddress() {
+    RTC_DCHECK(next_local_address_ < (int)arraysize(kLocalAddrs));
+    return kLocalAddrs[next_local_address_++];
+  }
+
+  std::vector<std::unique_ptr<rtc::FakeNetworkManager>> fake_networks_;
+  int next_local_address_ = 0;
   std::unique_ptr<rtc::VirtualSocketServer> vss_;
   rtc::AutoSocketServerThread main_;
 };
@@ -343,12 +409,7 @@
   auto callee = CreatePeerConnection(config);
   caller->AddAudioTrack("audio");
   caller->AddVideoTrack("video");
-  // Under some bot configurations, this will fail - presumably bots where
-  // no working non-host addresses exist.
-  if (!caller->ConnectTo(callee.get())) {
-    return;
-  }
-  // If we manage to connect, we should get this precise fingerprint.
+  ASSERT_TRUE(caller->ConnectTo(callee.get()));
   caller->pc()->Close();
   callee->pc()->Close();
   int expected_fingerprint = MakeUsageFingerprint(
@@ -365,6 +426,91 @@
       2, webrtc::metrics::NumEvents(kUsagePatternMetric, expected_fingerprint));
 }
 
+// Test getting the usage fingerprint when there are no host candidates.
+TEST_F(PeerConnectionUsageHistogramTest, FingerprintWithMdnsCaller) {
+  RTCConfiguration config;
+
+  // Enable hostname candidates with mDNS names.
+  auto caller = CreatePeerConnectionWithMdns(config);
+  auto callee = CreatePeerConnection(config);
+
+  caller->AddAudioTrack("audio");
+  caller->AddVideoTrack("video");
+  ASSERT_TRUE(caller->ConnectTo(callee.get()));
+  caller->pc()->Close();
+  callee->pc()->Close();
+
+  int expected_fingerprint_caller = MakeUsageFingerprint(
+      {PeerConnection::UsageEvent::AUDIO_ADDED,
+       PeerConnection::UsageEvent::VIDEO_ADDED,
+       PeerConnection::UsageEvent::SET_LOCAL_DESCRIPTION_CALLED,
+       PeerConnection::UsageEvent::SET_REMOTE_DESCRIPTION_CALLED,
+       PeerConnection::UsageEvent::CANDIDATE_COLLECTED,
+       PeerConnection::UsageEvent::MDNS_CANDIDATE_COLLECTED,
+       PeerConnection::UsageEvent::REMOTE_CANDIDATE_ADDED,
+       PeerConnection::UsageEvent::ICE_STATE_CONNECTED,
+       PeerConnection::UsageEvent::CLOSE_CALLED});
+
+  int expected_fingerprint_callee = MakeUsageFingerprint(
+      {PeerConnection::UsageEvent::AUDIO_ADDED,
+       PeerConnection::UsageEvent::VIDEO_ADDED,
+       PeerConnection::UsageEvent::SET_LOCAL_DESCRIPTION_CALLED,
+       PeerConnection::UsageEvent::SET_REMOTE_DESCRIPTION_CALLED,
+       PeerConnection::UsageEvent::CANDIDATE_COLLECTED,
+       PeerConnection::UsageEvent::REMOTE_CANDIDATE_ADDED,
+       PeerConnection::UsageEvent::REMOTE_MDNS_CANDIDATE_ADDED,
+       PeerConnection::UsageEvent::ICE_STATE_CONNECTED,
+       PeerConnection::UsageEvent::CLOSE_CALLED});
+
+  EXPECT_EQ(2, webrtc::metrics::NumSamples(kUsagePatternMetric));
+  EXPECT_EQ(1, webrtc::metrics::NumEvents(kUsagePatternMetric,
+                                          expected_fingerprint_caller));
+  EXPECT_EQ(1, webrtc::metrics::NumEvents(kUsagePatternMetric,
+                                          expected_fingerprint_callee));
+}
+
+TEST_F(PeerConnectionUsageHistogramTest, FingerprintWithMdnsCallee) {
+  RTCConfiguration config;
+
+  // Enable hostname candidates with mDNS names.
+  auto caller = CreatePeerConnection(config);
+  auto callee = CreatePeerConnectionWithMdns(config);
+
+  caller->AddAudioTrack("audio");
+  caller->AddVideoTrack("video");
+  ASSERT_TRUE(caller->ConnectTo(callee.get()));
+  caller->pc()->Close();
+  callee->pc()->Close();
+
+  int expected_fingerprint_caller = MakeUsageFingerprint(
+      {PeerConnection::UsageEvent::AUDIO_ADDED,
+       PeerConnection::UsageEvent::VIDEO_ADDED,
+       PeerConnection::UsageEvent::SET_LOCAL_DESCRIPTION_CALLED,
+       PeerConnection::UsageEvent::SET_REMOTE_DESCRIPTION_CALLED,
+       PeerConnection::UsageEvent::CANDIDATE_COLLECTED,
+       PeerConnection::UsageEvent::REMOTE_CANDIDATE_ADDED,
+       PeerConnection::UsageEvent::REMOTE_MDNS_CANDIDATE_ADDED,
+       PeerConnection::UsageEvent::ICE_STATE_CONNECTED,
+       PeerConnection::UsageEvent::CLOSE_CALLED});
+
+  int expected_fingerprint_callee = MakeUsageFingerprint(
+      {PeerConnection::UsageEvent::AUDIO_ADDED,
+       PeerConnection::UsageEvent::VIDEO_ADDED,
+       PeerConnection::UsageEvent::SET_LOCAL_DESCRIPTION_CALLED,
+       PeerConnection::UsageEvent::SET_REMOTE_DESCRIPTION_CALLED,
+       PeerConnection::UsageEvent::CANDIDATE_COLLECTED,
+       PeerConnection::UsageEvent::MDNS_CANDIDATE_COLLECTED,
+       PeerConnection::UsageEvent::REMOTE_CANDIDATE_ADDED,
+       PeerConnection::UsageEvent::ICE_STATE_CONNECTED,
+       PeerConnection::UsageEvent::CLOSE_CALLED});
+
+  EXPECT_EQ(2, webrtc::metrics::NumSamples(kUsagePatternMetric));
+  EXPECT_EQ(1, webrtc::metrics::NumEvents(kUsagePatternMetric,
+                                          expected_fingerprint_caller));
+  EXPECT_EQ(1, webrtc::metrics::NumEvents(kUsagePatternMetric,
+                                          expected_fingerprint_callee));
+}
+
 #ifdef HAVE_SCTP
 TEST_F(PeerConnectionUsageHistogramTest, FingerprintDataOnly) {
   auto caller = CreatePeerConnection();
@@ -441,20 +587,74 @@
       1, webrtc::metrics::NumEvents(kUsagePatternMetric, expected_fingerprint));
 }
 
-TEST_F(PeerConnectionUsageHistogramTest, FingerprintWithPrivateIP) {
+TEST_F(PeerConnectionUsageHistogramTest, FingerprintWithPrivateIPCaller) {
   auto caller = CreatePeerConnectionWithPrivateLocalAddresses();
+  auto callee = CreatePeerConnection();
   caller->AddAudioTrack("audio");
-  ASSERT_TRUE(caller->GenerateOfferAndCollectCandidates());
+  ASSERT_TRUE(caller->ConnectTo(callee.get()));
   caller->pc()->Close();
-  int expected_fingerprint = MakeUsageFingerprint(
+  callee->pc()->Close();
+
+  int expected_fingerprint_caller = MakeUsageFingerprint(
       {PeerConnection::UsageEvent::AUDIO_ADDED,
        PeerConnection::UsageEvent::SET_LOCAL_DESCRIPTION_CALLED,
+       PeerConnection::UsageEvent::SET_REMOTE_DESCRIPTION_CALLED,
        PeerConnection::UsageEvent::CANDIDATE_COLLECTED,
-       PeerConnection::UsageEvent::CLOSE_CALLED,
-       PeerConnection::UsageEvent::PRIVATE_CANDIDATE_COLLECTED});
-  EXPECT_EQ(1, webrtc::metrics::NumSamples(kUsagePatternMetric));
-  EXPECT_EQ(
-      1, webrtc::metrics::NumEvents(kUsagePatternMetric, expected_fingerprint));
+       PeerConnection::UsageEvent::PRIVATE_CANDIDATE_COLLECTED,
+       PeerConnection::UsageEvent::REMOTE_CANDIDATE_ADDED,
+       PeerConnection::UsageEvent::ICE_STATE_CONNECTED,
+       PeerConnection::UsageEvent::CLOSE_CALLED});
+
+  int expected_fingerprint_callee = MakeUsageFingerprint(
+      {PeerConnection::UsageEvent::AUDIO_ADDED,
+       PeerConnection::UsageEvent::SET_LOCAL_DESCRIPTION_CALLED,
+       PeerConnection::UsageEvent::SET_REMOTE_DESCRIPTION_CALLED,
+       PeerConnection::UsageEvent::CANDIDATE_COLLECTED,
+       PeerConnection::UsageEvent::REMOTE_CANDIDATE_ADDED,
+       PeerConnection::UsageEvent::REMOTE_PRIVATE_CANDIDATE_ADDED,
+       PeerConnection::UsageEvent::ICE_STATE_CONNECTED,
+       PeerConnection::UsageEvent::CLOSE_CALLED});
+
+  EXPECT_EQ(2, webrtc::metrics::NumSamples(kUsagePatternMetric));
+  EXPECT_EQ(1, webrtc::metrics::NumEvents(kUsagePatternMetric,
+                                          expected_fingerprint_caller));
+  EXPECT_EQ(1, webrtc::metrics::NumEvents(kUsagePatternMetric,
+                                          expected_fingerprint_callee));
+}
+
+TEST_F(PeerConnectionUsageHistogramTest, FingerprintWithPrivateIPCallee) {
+  auto caller = CreatePeerConnection();
+  auto callee = CreatePeerConnectionWithPrivateLocalAddresses();
+  caller->AddAudioTrack("audio");
+  ASSERT_TRUE(caller->ConnectTo(callee.get()));
+  caller->pc()->Close();
+  callee->pc()->Close();
+
+  int expected_fingerprint_caller = MakeUsageFingerprint(
+      {PeerConnection::UsageEvent::AUDIO_ADDED,
+       PeerConnection::UsageEvent::SET_LOCAL_DESCRIPTION_CALLED,
+       PeerConnection::UsageEvent::SET_REMOTE_DESCRIPTION_CALLED,
+       PeerConnection::UsageEvent::CANDIDATE_COLLECTED,
+       PeerConnection::UsageEvent::REMOTE_CANDIDATE_ADDED,
+       PeerConnection::UsageEvent::REMOTE_PRIVATE_CANDIDATE_ADDED,
+       PeerConnection::UsageEvent::ICE_STATE_CONNECTED,
+       PeerConnection::UsageEvent::CLOSE_CALLED});
+
+  int expected_fingerprint_callee = MakeUsageFingerprint(
+      {PeerConnection::UsageEvent::AUDIO_ADDED,
+       PeerConnection::UsageEvent::SET_LOCAL_DESCRIPTION_CALLED,
+       PeerConnection::UsageEvent::SET_REMOTE_DESCRIPTION_CALLED,
+       PeerConnection::UsageEvent::CANDIDATE_COLLECTED,
+       PeerConnection::UsageEvent::PRIVATE_CANDIDATE_COLLECTED,
+       PeerConnection::UsageEvent::REMOTE_CANDIDATE_ADDED,
+       PeerConnection::UsageEvent::ICE_STATE_CONNECTED,
+       PeerConnection::UsageEvent::CLOSE_CALLED});
+
+  EXPECT_EQ(2, webrtc::metrics::NumSamples(kUsagePatternMetric));
+  EXPECT_EQ(1, webrtc::metrics::NumEvents(kUsagePatternMetric,
+                                          expected_fingerprint_caller));
+  EXPECT_EQ(1, webrtc::metrics::NumEvents(kUsagePatternMetric,
+                                          expected_fingerprint_callee));
 }
 
 #ifndef WEBRTC_ANDROID
diff --git a/rtc_base/ip_address.cc b/rtc_base/ip_address.cc
index ff0be13..96d1001 100644
--- a/rtc_base/ip_address.cc
+++ b/rtc_base/ip_address.cc
@@ -235,6 +235,18 @@
   return false;
 }
 
+static bool IPIsSharedNetworkV4(const IPAddress& ip) {
+  uint32_t ip_in_host_order = ip.v4AddressAsHostOrderInteger();
+  return (ip_in_host_order >> 22) == ((100 << 2) | 1);
+}
+
+bool IPIsSharedNetwork(const IPAddress& ip) {
+  if (ip.family() == AF_INET) {
+    return IPIsSharedNetworkV4(ip);
+  }
+  return false;
+}
+
 in_addr ExtractMappedAddress(const in6_addr& in6) {
   in_addr ipv4;
   ::memcpy(&ipv4.s_addr, &in6.s6_addr[12], sizeof(ipv4.s_addr));
@@ -319,7 +331,8 @@
 }
 
 bool IPIsPrivate(const IPAddress& ip) {
-  return IPIsLinkLocal(ip) || IPIsLoopback(ip) || IPIsPrivateNetwork(ip);
+  return IPIsLinkLocal(ip) || IPIsLoopback(ip) || IPIsPrivateNetwork(ip) ||
+         IPIsSharedNetwork(ip);
 }
 
 bool IPIsUnspec(const IPAddress& ip) {
@@ -407,7 +420,9 @@
       bits = (i * 32);
       break;
     }
-    default: { return 0; }
+    default: {
+      return 0;
+    }
   }
   if (word_to_count == 0) {
     return bits;
diff --git a/rtc_base/ip_address.h b/rtc_base/ip_address.h
index 49dea68..2a52e1a 100644
--- a/rtc_base/ip_address.h
+++ b/rtc_base/ip_address.h
@@ -22,6 +22,7 @@
 #include <ws2tcpip.h>
 #endif
 #include <string.h>
+
 #include <string>
 
 #include "rtc_base/byte_order.h"
@@ -157,8 +158,12 @@
 // Identify a private network address like "192.168.111.222"
 // (see https://en.wikipedia.org/wiki/Private_network )
 bool IPIsPrivateNetwork(const IPAddress& ip);
+// Identify a shared network address like "100.72.16.122"
+// (see RFC6598)
+bool IPIsSharedNetwork(const IPAddress& ip);
 // Identify if an IP is "private", that is a loopback
-// or an address belonging to a link-local or a private network.
+// or an address belonging to a link-local, a private network or a shared
+// network.
 bool IPIsPrivate(const IPAddress& ip);
 bool IPIsUnspec(const IPAddress& ip);
 size_t HashIP(const IPAddress& ip);
diff --git a/rtc_base/ip_address_unittest.cc b/rtc_base/ip_address_unittest.cc
index c93244d..d79a7b4 100644
--- a/rtc_base/ip_address_unittest.cc
+++ b/rtc_base/ip_address_unittest.cc
@@ -18,6 +18,7 @@
 static const unsigned int kIPv6AddrSize = 16;
 static const unsigned int kIPv4RFC1918Addr = 0xC0A80701;
 static const unsigned int kIPv4PublicAddr = 0x01020304;
+static const unsigned int kIPv4RFC6598Addr = 0x64410801;
 static const unsigned int kIPv4LinkLocalAddr = 0xA9FE10C1;  // 169.254.16.193
 static const in6_addr kIPv6LinkLocalAddr = {
     {{0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0x30, 0x5b, 0xff,
@@ -41,6 +42,7 @@
 static const std::string kIPv4AnyAddrString = "0.0.0.0";
 static const std::string kIPv4LoopbackAddrString = "127.0.0.1";
 static const std::string kIPv4RFC1918AddrString = "192.168.7.1";
+static const std::string kIPv4RFC6598AddrString = "100.65.8.1";
 static const std::string kIPv4PublicAddrString = "1.2.3.4";
 static const std::string kIPv4PublicAddrAnonymizedString = "1.2.3.x";
 static const std::string kIPv6AnyAddrString = "::";
@@ -179,6 +181,7 @@
   addr = IPAddress(v4addr);
   EXPECT_FALSE(IPIsAny(addr));
   EXPECT_TRUE(IPIsLoopback(addr));
+  EXPECT_FALSE(IPIsSharedNetwork(addr));
   EXPECT_TRUE(IPIsPrivate(addr));
   EXPECT_EQ(kIPv4AddrSize, addr.Size());
   EXPECT_EQ(kIPv4LoopbackAddrString, addr.ToString());
@@ -188,10 +191,21 @@
   addr = IPAddress(v4addr);
   EXPECT_FALSE(IPIsAny(addr));
   EXPECT_FALSE(IPIsLoopback(addr));
+  EXPECT_FALSE(IPIsSharedNetwork(addr));
   EXPECT_TRUE(IPIsPrivate(addr));
   EXPECT_EQ(kIPv4AddrSize, addr.Size());
   EXPECT_EQ(kIPv4RFC1918AddrString, addr.ToString());
 
+  // Test an shared (RFC6598) address.
+  v4addr.s_addr = htonl(kIPv4RFC6598Addr);
+  addr = IPAddress(v4addr);
+  EXPECT_FALSE(IPIsAny(addr));
+  EXPECT_FALSE(IPIsLoopback(addr));
+  EXPECT_TRUE(IPIsPrivate(addr));
+  EXPECT_TRUE(IPIsSharedNetwork(addr));
+  EXPECT_EQ(kIPv4AddrSize, addr.Size());
+  EXPECT_EQ(kIPv4RFC6598AddrString, addr.ToString());
+
   // Test a 'normal' v4 address.
   v4addr.s_addr = htonl(kIPv4PublicAddr);
   addr = IPAddress(v4addr);
@@ -215,6 +229,7 @@
   addr = IPAddress(in6addr_loopback);
   EXPECT_FALSE(IPIsAny(addr));
   EXPECT_TRUE(IPIsLoopback(addr));
+  EXPECT_FALSE(IPIsSharedNetwork(addr));
   EXPECT_TRUE(IPIsPrivate(addr));
   EXPECT_EQ(kIPv6AddrSize, addr.Size());
   EXPECT_EQ(kIPv6LoopbackAddrString, addr.ToString());
@@ -223,6 +238,7 @@
   addr = IPAddress(kIPv6LinkLocalAddr);
   EXPECT_FALSE(IPIsAny(addr));
   EXPECT_FALSE(IPIsLoopback(addr));
+  EXPECT_FALSE(IPIsSharedNetwork(addr));
   EXPECT_TRUE(IPIsPrivate(addr));
   EXPECT_EQ(kIPv6AddrSize, addr.Size());
   EXPECT_EQ(kIPv6LinkLocalAddrString, addr.ToString());
@@ -249,6 +265,7 @@
   addr = IPAddress(INADDR_LOOPBACK);
   EXPECT_FALSE(IPIsAny(addr));
   EXPECT_TRUE(IPIsLoopback(addr));
+  EXPECT_FALSE(IPIsSharedNetwork(addr));
   EXPECT_TRUE(IPIsPrivate(addr));
   EXPECT_EQ(kIPv4AddrSize, addr.Size());
   EXPECT_EQ(kIPv4LoopbackAddrString, addr.ToString());
@@ -257,6 +274,7 @@
   addr = IPAddress(kIPv4RFC1918Addr);
   EXPECT_FALSE(IPIsAny(addr));
   EXPECT_FALSE(IPIsLoopback(addr));
+  EXPECT_FALSE(IPIsSharedNetwork(addr));
   EXPECT_TRUE(IPIsPrivate(addr));
   EXPECT_EQ(kIPv4AddrSize, addr.Size());
   EXPECT_EQ(kIPv4RFC1918AddrString, addr.ToString());
@@ -537,6 +555,7 @@
   EXPECT_FALSE(IPIsPrivate(IPAddress(kIPv4MappedPublicAddr)));
 
   EXPECT_TRUE(IPIsPrivate(IPAddress(kIPv4RFC1918Addr)));
+  EXPECT_TRUE(IPIsPrivate(IPAddress(kIPv4RFC6598Addr)));
   EXPECT_TRUE(IPIsPrivate(IPAddress(INADDR_LOOPBACK)));
   EXPECT_TRUE(IPIsPrivate(IPAddress(in6addr_loopback)));
   EXPECT_TRUE(IPIsPrivate(IPAddress(kIPv6LinkLocalAddr)));
@@ -559,6 +578,7 @@
   EXPECT_FALSE(IPIsLoopback(IPAddress(INADDR_ANY)));
   EXPECT_FALSE(IPIsLoopback(IPAddress(kIPv4PublicAddr)));
   EXPECT_FALSE(IPIsLoopback(IPAddress(in6addr_any)));
+  EXPECT_FALSE(IPIsLoopback(IPAddress(kIPv4RFC6598Addr)));
   EXPECT_FALSE(IPIsLoopback(IPAddress(kIPv6PublicAddr)));
   EXPECT_FALSE(IPIsLoopback(IPAddress(kIPv4MappedAnyAddr)));
   EXPECT_FALSE(IPIsLoopback(IPAddress(kIPv4MappedPublicAddr)));
@@ -577,6 +597,8 @@
   // loopback addresses
   EXPECT_FALSE(IPIsLinkLocal(IPAddress(INADDR_LOOPBACK)));
   EXPECT_FALSE(IPIsLinkLocal(IPAddress(in6addr_loopback)));
+  // shared addresses
+  EXPECT_FALSE(IPIsLinkLocal(IPAddress(kIPv4RFC6598Addr)));
   // public addresses
   EXPECT_FALSE(IPIsLinkLocal(IPAddress(kIPv4PublicAddr)));
   EXPECT_FALSE(IPIsLinkLocal(IPAddress(kIPv6PublicAddr)));