Fix a bug that the local hostname candidate with a known address is
updated to prflx.

When the address of a local candidate is intentionally removed after
gathered, its would be incorrectly updated to prflx when receiving a
STUN message from a remote candidate after forming a candidate pair and
starting the connectivity check.

Bug: webrtc:9756, webrtc:9605
Change-Id: I6c699250565c1458e825eba742c2991a82229817
Reviewed-on: https://webrtc-review.googlesource.com/100624
Reviewed-by: Qingsi Wang <qingsi@webrtc.org>
Reviewed-by: Steve Anton <steveanton@webrtc.org>
Commit-Queue: Qingsi Wang <qingsi@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#24837}
diff --git a/p2p/base/p2ptransportchannel_unittest.cc b/p2p/base/p2ptransportchannel_unittest.cc
index fadcb0a..03a3103 100644
--- a/p2p/base/p2ptransportchannel_unittest.cc
+++ b/p2p/base/p2ptransportchannel_unittest.cc
@@ -4761,6 +4761,8 @@
   // with a peer reflexive candidate from ep2.
   ASSERT_TRUE_WAIT((ep1_ch1()->selected_connection()) != nullptr,
                    kMediumTimeout);
+  EXPECT_EQ(LOCAL_PORT_TYPE,
+            ep1_ch1()->selected_connection()->local_candidate().type());
   EXPECT_EQ(PRFLX_PORT_TYPE,
             ep1_ch1()->selected_connection()->remote_candidate().type());
 
diff --git a/p2p/base/port.cc b/p2p/base/port.cc
index 095b3a6..1fe7305 100644
--- a/p2p/base/port.cc
+++ b/p2p/base/port.cc
@@ -440,6 +440,11 @@
                                               const std::string& name) mutable {
         RTC_DCHECK(c.address().ipaddr() == addr);
         rtc::SocketAddress hostname_address(name, c.address().port());
+        // In Port and Connection, we need the IP address information to
+        // correctly handle the update of candidate type to prflx. The removal
+        // of IP address when signaling this candidate will take place in
+        // BasicPortAllocatorSession::OnCandidateReady, via SanitizeCandidate.
+        hostname_address.SetResolvedIP(addr);
         c.set_address(hostname_address);
         RTC_DCHECK(c.related_address() == rtc::SocketAddress());
         if (weak_ptr != nullptr) {
diff --git a/p2p/client/basicportallocator.cc b/p2p/client/basicportallocator.cc
index 5b48f5e..92c8338 100644
--- a/p2p/client/basicportallocator.cc
+++ b/p2p/client/basicportallocator.cc
@@ -496,13 +496,21 @@
     if (!CheckCandidateFilter(candidate)) {
       continue;
     }
-    candidates->push_back(SanitizeRelatedAddress(candidate));
+    auto sanitized_candidate = SanitizeCandidate(candidate);
+    candidates->push_back(sanitized_candidate);
   }
 }
 
-Candidate BasicPortAllocatorSession::SanitizeRelatedAddress(
+Candidate BasicPortAllocatorSession::SanitizeCandidate(
     const Candidate& c) const {
   Candidate copy = c;
+  // If the candidate has a generated hostname, we need to obfuscate its IP
+  // address when signaling this candidate.
+  if (!c.address().hostname().empty() && !c.address().IsUnresolvedIP()) {
+    rtc::SocketAddress hostname_only_addr(c.address().hostname(),
+                                          c.address().port());
+    copy.set_address(hostname_only_addr);
+  }
   // If adapter enumeration is disabled or host candidates are disabled,
   // clear the raddr of STUN candidates to avoid local address leakage.
   bool filter_stun_related_address =
@@ -916,7 +924,7 @@
 
   if (data->ready() && CheckCandidateFilter(c)) {
     std::vector<Candidate> candidates;
-    candidates.push_back(SanitizeRelatedAddress(c));
+    candidates.push_back(SanitizeCandidate(c));
     SignalCandidatesReady(this, candidates);
   } else {
     RTC_LOG(LS_INFO) << "Discarding candidate because it doesn't match filter.";
diff --git a/p2p/client/basicportallocator.h b/p2p/client/basicportallocator.h
index 07bf2f9..8b951ca 100644
--- a/p2p/client/basicportallocator.h
+++ b/p2p/client/basicportallocator.h
@@ -235,9 +235,10 @@
 
   bool CheckCandidateFilter(const Candidate& c) const;
   bool CandidatePairable(const Candidate& c, const Port* port) const;
-  // Clear the related address according to the flags and candidate filter
-  // in order to avoid leaking any information.
-  Candidate SanitizeRelatedAddress(const Candidate& c) const;
+  // Clears 1) the address if the candidate is supposedly a hostname candidate;
+  // 2) the related address according to the flags and candidate filter in order
+  // to avoid leaking any information.
+  Candidate SanitizeCandidate(const Candidate& c) const;
 
   std::vector<PortData*> GetUnprunedPorts(
       const std::vector<rtc::Network*>& networks);