Fix bugs in discarding stun address
If mdns obfuscation is enabled, the stun address "MUST NOT be
considered redundant" when it is equal to local socket address.
Reference:
https://datatracker.ietf.org/doc/html/draft-ietf-mmusic-mdns-ice-candidates-03#section-3.1.2.2
This fixes
Bug: webrtc:13426
Change-Id: I28e981fd1b8818f6f8294bc3fedf23b8d9146819
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/285421
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Commit-Queue: Harald Alvestrand <hta@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#38774}
diff --git a/AUTHORS b/AUTHORS
index ad0220d..bd7ab24 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -68,6 +68,7 @@
Keiichi Enomoto <enm10k@gmail.com>
Kiran Thind <kiran.thind@gmail.com>
Korniltsev Anatoly <korniltsev.anatoly@gmail.com>
+Kyutae Lee <gorisanson@gmail.com>
Lennart Grahl <lennart.grahl@gmail.com>
Luke Weber <luke.weber@gmail.com>
Maksim Khobat <maksimkhobat@gmail.com>
diff --git a/p2p/base/stun_port.cc b/p2p/base/stun_port.cc
index 5d57d1a..fdb7edc 100644
--- a/p2p/base/stun_port.cc
+++ b/p2p/base/stun_port.cc
@@ -550,11 +550,12 @@
}
bind_request_succeeded_servers_.insert(stun_server_addr);
// If socket is shared and `stun_reflected_addr` is equal to local socket
- // address, or if the same address has been added by another STUN server,
- // then discarding the stun address.
+ // address and mDNS obfuscation is not enabled, or if the same address has
+ // been added by another STUN server, then discarding the stun address.
// For STUN, related address is the local socket address.
- if ((!SharedSocket() || stun_reflected_addr != socket_->GetLocalAddress()) &&
- !HasCandidateWithAddress(stun_reflected_addr)) {
+ if ((!SharedSocket() || stun_reflected_addr != socket_->GetLocalAddress() ||
+ Network()->GetMdnsResponder() != nullptr) &&
+ !HasStunCandidateWithAddress(stun_reflected_addr)) {
rtc::SocketAddress related_address = socket_->GetLocalAddress();
// If we can't stamp the related address correctly, empty it to avoid leak.
if (!MaybeSetDefaultLocalAddress(&related_address)) {
@@ -637,11 +638,12 @@
stats_.stun_binding_requests_sent++;
}
-bool UDPPort::HasCandidateWithAddress(const rtc::SocketAddress& addr) const {
+bool UDPPort::HasStunCandidateWithAddress(
+ const rtc::SocketAddress& addr) const {
const std::vector<Candidate>& existing_candidates = Candidates();
std::vector<Candidate>::const_iterator it = existing_candidates.begin();
for (; it != existing_candidates.end(); ++it) {
- if (it->address() == addr)
+ if (it->type() == STUN_PORT_TYPE && it->address() == addr)
return true;
}
return false;
diff --git a/p2p/base/stun_port.h b/p2p/base/stun_port.h
index 06b5e1a..1397007 100644
--- a/p2p/base/stun_port.h
+++ b/p2p/base/stun_port.h
@@ -234,7 +234,7 @@
// changed to SignalPortReady.
void MaybeSetPortCompleteOrError();
- bool HasCandidateWithAddress(const rtc::SocketAddress& addr) const;
+ bool HasStunCandidateWithAddress(const rtc::SocketAddress& addr) const;
// If this is a low-cost network, it will keep on sending STUN binding
// requests indefinitely to keep the NAT binding alive. Otherwise, stop
diff --git a/p2p/base/stun_port_unittest.cc b/p2p/base/stun_port_unittest.cc
index 003a58a..59841ad 100644
--- a/p2p/base/stun_port_unittest.cc
+++ b/p2p/base/stun_port_unittest.cc
@@ -89,6 +89,29 @@
DnsResolverExpectations expectations_;
};
+class FakeMdnsResponder : public webrtc::MdnsResponderInterface {
+ public:
+ void CreateNameForAddress(const rtc::IPAddress& addr,
+ NameCreatedCallback callback) override {
+ callback(addr, std::string("unittest-mdns-host-name.local"));
+ }
+
+ void RemoveNameForAddress(const rtc::IPAddress& addr,
+ NameRemovedCallback callback) override {}
+};
+
+class FakeMdnsResponderProvider : public rtc::MdnsResponderProvider {
+ public:
+ FakeMdnsResponderProvider() : mdns_responder_(new FakeMdnsResponder()) {}
+
+ webrtc::MdnsResponderInterface* GetMdnsResponder() const override {
+ return mdns_responder_.get();
+ }
+
+ private:
+ std::unique_ptr<webrtc::MdnsResponderInterface> mdns_responder_;
+};
+
// Base class for tests connecting a StunPort to a fake STUN server
// (cricket::StunServer).
class StunPortTestBase : public ::testing::Test, public sigslot::has_slots<> {
@@ -105,6 +128,7 @@
socket_factory_(ss_.get()),
stun_server_1_(cricket::TestStunServer::Create(ss_.get(), kStunAddr1)),
stun_server_2_(cricket::TestStunServer::Create(ss_.get(), kStunAddr2)),
+ mdns_responder_provider_(new FakeMdnsResponderProvider()),
done_(false),
error_(false),
stun_keepalive_delay_(1),
@@ -200,6 +224,10 @@
/* packet_time_us */ -1);
}
+ void EnableMdnsObfuscation() {
+ network_.set_mdns_responder_provider(mdns_responder_provider_.get());
+ }
+
protected:
static void SetUpTestSuite() {
// Ensure the RNG is inited.
@@ -237,6 +265,7 @@
std::unique_ptr<cricket::TestStunServer> stun_server_1_;
std::unique_ptr<cricket::TestStunServer> stun_server_2_;
std::unique_ptr<rtc::AsyncPacketSocket> socket_;
+ std::unique_ptr<rtc::MdnsResponderProvider> mdns_responder_provider_;
bool done_;
bool error_;
int stun_keepalive_delay_;
@@ -386,6 +415,41 @@
// No crash is success.
}
+// Test that a stun candidate (srflx candidate) is discarded whose address is
+// equal to that of a local candidate if mDNS obfuscation is not enabled.
+TEST_F(StunPortTest, TestStunCandidateDiscardedWithMdnsObfuscationNotEnabled) {
+ CreateSharedUdpPort(kStunAddr1, nullptr);
+ PrepareAddress();
+ EXPECT_TRUE_SIMULATED_WAIT(done(), kTimeoutMs, fake_clock);
+ ASSERT_EQ(1U, port()->Candidates().size());
+ EXPECT_TRUE(kLocalAddr.EqualIPs(port()->Candidates()[0].address()));
+ EXPECT_EQ(port()->Candidates()[0].type(), cricket::LOCAL_PORT_TYPE);
+}
+
+// Test that a stun candidate (srflx candidate) is generated whose address is
+// equal to that of a local candidate if mDNS obfuscation is enabled.
+TEST_F(StunPortTest, TestStunCandidateGeneratedWithMdnsObfuscationEnabled) {
+ EnableMdnsObfuscation();
+ CreateSharedUdpPort(kStunAddr1, nullptr);
+ PrepareAddress();
+ EXPECT_TRUE_SIMULATED_WAIT(done(), kTimeoutMs, fake_clock);
+ ASSERT_EQ(2U, port()->Candidates().size());
+
+ // The addresses of the candidates are both equal to kLocalAddr.
+ EXPECT_TRUE(kLocalAddr.EqualIPs(port()->Candidates()[0].address()));
+ EXPECT_TRUE(kLocalAddr.EqualIPs(port()->Candidates()[1].address()));
+
+ // One of the generated candidates is a local candidate and the other is a
+ // stun candidate.
+ EXPECT_NE(port()->Candidates()[0].type(), port()->Candidates()[1].type());
+ if (port()->Candidates()[0].type() == cricket::LOCAL_PORT_TYPE) {
+ EXPECT_EQ(port()->Candidates()[1].type(), cricket::STUN_PORT_TYPE);
+ } else {
+ EXPECT_EQ(port()->Candidates()[0].type(), cricket::STUN_PORT_TYPE);
+ EXPECT_EQ(port()->Candidates()[1].type(), cricket::LOCAL_PORT_TYPE);
+ }
+}
+
// Test that the same address is added only once if two STUN servers are in
// use.
TEST_F(StunPortTest, TestNoDuplicatedAddressWithTwoStunServers) {