LNA: Introduce LnaPermissionInterface::ShouldRequestPermission()
Before this CL there was only one method RequestPermission which
performed some synchronous checks e.g. if the address space was less
public, and if necessary asynchronously requested the LNA permission.
This CL introduces ShouldRequestPermission that only performs the
synchronous part of the check. This allows us to centralize the logic
for permission checking into the embedder and more importantly, allows
us to avoid having to post a task for cases where it's not necessary to
request a permission.
Blink change: https://crrev.com/c/6794524
Bug: chromium:421223919
Change-Id: I8edb06f7b604eaae76e5230d404dd19c02d0e24b
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/402460
Commit-Queue: Giovanni Ortuno Urquidi <ortuno@chromium.org>
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Reviewed-by: Tomas Gunnarsson <tommi@webrtc.org>
Reviewed-by: Jonas Oreland <jonaso@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#45335}
diff --git a/api/local_network_access_permission.h b/api/local_network_access_permission.h
index 0dad57f..7fc923b 100644
--- a/api/local_network_access_permission.h
+++ b/api/local_network_access_permission.h
@@ -62,6 +62,15 @@
public:
virtual ~LocalNetworkAccessPermissionInterface() = default;
+ // Returns whether or not the caller should request permission. Depending
+ // on the originator's address space, sometimes it's not necessary to request
+ // permission.
+ // TODO(crbug.com/421223919): Make this method pure virtual once all
+ // implementations implement it.
+ virtual bool ShouldRequestPermission(const SocketAddress& addr) {
+ return addr.IsPrivateIP() || addr.IsLoopbackIP();
+ }
+
// The callback will be called when the permission is granted or denied. The
// callback will be called on the sequence that the caller runs on.
virtual void RequestPermission(
diff --git a/api/test/mock_local_network_access_permission.cc b/api/test/mock_local_network_access_permission.cc
index 523a7a9..ad07ed0 100644
--- a/api/test/mock_local_network_access_permission.cc
+++ b/api/test/mock_local_network_access_permission.cc
@@ -25,24 +25,28 @@
namespace webrtc {
FakeLocalNetworkAccessPermissionFactory::
- FakeLocalNetworkAccessPermissionFactory(
- LocalNetworkAccessPermissionStatus status) {
- EXPECT_CALL(*this, Create()).WillRepeatedly([status]() {
+ FakeLocalNetworkAccessPermissionFactory(Result result) {
+ EXPECT_CALL(*this, Create()).WillRepeatedly([result]() {
auto mock_lna_permission =
std::make_unique<MockLocalNetworkAccessPermission>();
-
- EXPECT_CALL(*mock_lna_permission, RequestPermission(_, _))
+ EXPECT_CALL(*mock_lna_permission, ShouldRequestPermission(_))
.WillRepeatedly(
- [status](
- const SocketAddress& /* addr */,
- absl::AnyInvocable<void(
- webrtc::LocalNetworkAccessPermissionStatus)> callback) {
- Thread::Current()->PostTask(
- [callback = std::move(callback), status]() mutable {
- callback(status);
- });
- });
-
+ ::testing::Return(result != Result::kPermissionNotNeeded));
+ if (result != Result::kPermissionNotNeeded) {
+ EXPECT_CALL(*mock_lna_permission, RequestPermission(_, _))
+ .WillRepeatedly(
+ [result](
+ const SocketAddress& /* addr */,
+ absl::AnyInvocable<void(
+ webrtc::LocalNetworkAccessPermissionStatus)> callback) {
+ Thread::Current()->PostTask([callback = std::move(callback),
+ result]() mutable {
+ callback(result == Result::kPermissionGranted
+ ? LocalNetworkAccessPermissionStatus::kGranted
+ : LocalNetworkAccessPermissionStatus::kDenied);
+ });
+ });
+ }
return mock_lna_permission;
});
}
diff --git a/api/test/mock_local_network_access_permission.h b/api/test/mock_local_network_access_permission.h
index 66c1422..3f18e87 100644
--- a/api/test/mock_local_network_access_permission.h
+++ b/api/test/mock_local_network_access_permission.h
@@ -23,6 +23,11 @@
class MockLocalNetworkAccessPermission
: public LocalNetworkAccessPermissionInterface {
public:
+ MOCK_METHOD(bool,
+ ShouldRequestPermission,
+ (const SocketAddress& addr),
+ (override));
+
MOCK_METHOD(
void,
RequestPermission,
@@ -45,8 +50,18 @@
class FakeLocalNetworkAccessPermissionFactory
: public MockLocalNetworkAccessPermissionFactory {
public:
- explicit FakeLocalNetworkAccessPermissionFactory(
- LocalNetworkAccessPermissionStatus status);
+ enum class Result {
+ // Use when the permission is not needed i.e. ShouldRequestPermission will
+ // return false.
+ kPermissionNotNeeded,
+ // Use when the permission is needed i.e. ShouldRequestPermission will
+ // return true, and RequestPermission will return kGranted/kDenied
+ // respectively.
+ kPermissionGranted,
+ kPermissionDenied,
+ };
+
+ explicit FakeLocalNetworkAccessPermissionFactory(Result result);
~FakeLocalNetworkAccessPermissionFactory() override;
};
diff --git a/p2p/BUILD.gn b/p2p/BUILD.gn
index ef49a91..147c21b 100644
--- a/p2p/BUILD.gn
+++ b/p2p/BUILD.gn
@@ -1148,6 +1148,7 @@
sources = [
"base/async_stun_tcp_socket_unittest.cc",
"base/ice_credentials_iterator_unittest.cc",
+ "base/local_network_access_port_unittest.cc",
"base/p2p_transport_channel_unittest.cc",
"base/packet_transport_internal_unittest.cc",
"base/port_allocator_unittest.cc",
@@ -1281,6 +1282,7 @@
"//third_party/abseil-cpp/absl/functional:any_invocable",
"//third_party/abseil-cpp/absl/memory",
"//third_party/abseil-cpp/absl/strings",
+ "//third_party/abseil-cpp/absl/strings:str_format",
"//third_party/abseil-cpp/absl/strings:string_view",
]
}
diff --git a/p2p/DEPS b/p2p/DEPS
index 291d059..bcf268b 100644
--- a/p2p/DEPS
+++ b/p2p/DEPS
@@ -3,4 +3,5 @@
"+net",
"+system_wrappers",
"+absl/functional/any_invocable.h",
+ "+absl/strings",
]
diff --git a/p2p/base/local_network_access_port_unittest.cc b/p2p/base/local_network_access_port_unittest.cc
new file mode 100644
index 0000000..b9dc7e6
--- /dev/null
+++ b/p2p/base/local_network_access_port_unittest.cc
@@ -0,0 +1,304 @@
+/*
+ * Copyright 2025 The WebRTC Project Authors. All rights reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include <memory>
+#include <optional>
+#include <string>
+#include <tuple>
+#include <utility>
+
+#include "absl/functional/any_invocable.h"
+#include "absl/strings/str_format.h"
+#include "absl/strings/str_replace.h"
+#include "absl/strings/string_view.h"
+#include "api/environment/environment.h"
+#include "api/environment/environment_factory.h"
+#include "api/local_network_access_permission.h"
+#include "api/test/mock_async_dns_resolver.h"
+#include "api/test/mock_local_network_access_permission.h"
+#include "api/test/rtc_error_matchers.h"
+#include "p2p/base/port.h"
+#include "p2p/base/port_allocator.h"
+#include "p2p/base/port_interface.h"
+#include "p2p/base/stun_port.h"
+#include "p2p/base/turn_port.h"
+#include "p2p/client/relay_port_factory_interface.h"
+#include "p2p/test/mock_dns_resolving_packet_socket_factory.h"
+#include "p2p/test/test_stun_server.h"
+#include "p2p/test/test_turn_server.h"
+#include "p2p/test/turn_server.h"
+#include "rtc_base/fake_clock.h"
+#include "rtc_base/net_helpers.h"
+#include "rtc_base/network.h"
+#include "rtc_base/socket.h"
+#include "rtc_base/socket_address.h"
+#include "rtc_base/third_party/sigslot/sigslot.h"
+#include "rtc_base/thread.h"
+#include "rtc_base/virtual_socket_server.h"
+#include "test/gmock.h"
+#include "test/gtest.h"
+#include "test/wait_until.h"
+
+namespace webrtc {
+namespace {
+
+using LnaFakeResult = FakeLocalNetworkAccessPermissionFactory::Result;
+using ::testing::_;
+using ::testing::DoAll;
+using ::testing::IsTrue;
+using ::testing::Return;
+using ::testing::ReturnPointee;
+using ::testing::SetArgPointee;
+
+const SocketAddress kTurnUdpIntAddr("99.99.99.3", webrtc::TURN_SERVER_PORT);
+const SocketAddress kTurnUdpExtAddr("99.99.99.5", 0);
+const SocketAddress kLocalAddr("11.11.11.11", 0);
+const SocketAddress kLocalIPv6Addr("2401:fa00:4:1000:be30:5bff:fee5:c3", 0);
+
+constexpr char kIceUfrag[] = "TESTICEUFRAG0001";
+constexpr char kIcePwd[] = "TESTICEPWD00000000000001";
+constexpr char kTurnUsername[] = "test";
+constexpr char kTurnPassword[] = "test";
+
+enum ServerType { kStun, kTurn };
+
+// Class to test LocalNetworkAccess integration with STUN and TURN ports.
+class LocalNetworkAccessPortTest
+ : public ::testing::Test,
+ public sigslot::has_slots<>,
+ public ::testing::WithParamInterface<
+ std::tuple<ServerType, absl::string_view, LnaFakeResult>> {
+ public:
+ LocalNetworkAccessPortTest() {
+ network_.AddIP(local_address_.ipaddr());
+
+ switch (server_type()) {
+ case kStun:
+ stun_server_ =
+ TestStunServer::Create(&ss_, {server_address(), 5000}, thread_);
+ break;
+ case kTurn:
+ turn_server_.AddInternalSocket({server_address(), 5000}, PROTO_UDP);
+ break;
+ }
+ }
+
+ ~LocalNetworkAccessPortTest() override = default;
+
+ void OnPortComplete(Port* port) { port_ready_ = true; }
+ void OnPortError(Port* port) { port_error_ = true; }
+
+ protected:
+ static ServerType server_type() { return std::get<0>(GetParam()); }
+ static absl::string_view server_address() { return std::get<1>(GetParam()); }
+ static LnaFakeResult lna_fake_result() { return std::get<2>(GetParam()); }
+
+ // Creates STUN or TURN port depending on the type of port we are testing.
+ std::unique_ptr<Port> CreatePort(
+ absl::string_view server_address,
+ LocalNetworkAccessPermissionFactoryInterface& lna_permission_factory) {
+ switch (server_type()) {
+ case kStun:
+ return CreateStunPort(server_address, lna_permission_factory);
+ case kTurn:
+ return CreateTurnPort(server_address, lna_permission_factory);
+ }
+ }
+
+ std::unique_ptr<TurnPort> CreateTurnPort(
+ absl::string_view server_address,
+ LocalNetworkAccessPermissionFactoryInterface& lna_permission_factory) {
+ RelayServerConfig config;
+ config.credentials = RelayCredentials(kTurnUsername, kTurnPassword);
+
+ ProtocolAddress proto_server_address({server_address, 5000}, PROTO_UDP);
+ CreateRelayPortArgs args = {
+ .env = env_,
+ .network_thread = &thread_,
+ .socket_factory = &socket_factory_,
+ .network = &network_,
+ .server_address = &proto_server_address,
+ .config = &config,
+ .username = kIceUfrag,
+ .password = kIcePwd,
+ .lna_permission_factory = &lna_permission_factory,
+ };
+
+ auto turn_port = TurnPort::Create(args, /*min_port=*/0, /*max_port=*/0);
+ turn_port->SignalPortComplete.connect(
+ this, &LocalNetworkAccessPortTest::OnPortComplete);
+ turn_port->SignalPortError.connect(
+ this, &LocalNetworkAccessPortTest::OnPortError);
+
+ return turn_port;
+ }
+
+ std::unique_ptr<StunPort> CreateStunPort(
+ absl::string_view server_address,
+ LocalNetworkAccessPermissionFactoryInterface& lna_permission_factory) {
+ Port::PortParametersRef params = {
+ .env = env_,
+ .network_thread = &thread_,
+ .socket_factory = &socket_factory_,
+ .network = &network_,
+ .ice_username_fragment = kIceUfrag,
+ .ice_password = kIcePwd,
+ .lna_permission_factory = &lna_permission_factory,
+ };
+
+ auto stun_port = StunPort::Create(
+ params, 0, 0, {SocketAddress(server_address, 5000)}, std::nullopt);
+ stun_port->SignalPortComplete.connect(
+ this, &LocalNetworkAccessPortTest::OnPortComplete);
+ stun_port->SignalPortError.connect(
+ this, &LocalNetworkAccessPortTest::OnPortError);
+
+ return stun_port;
+ }
+
+ void setup_dns_resolver_mock() {
+ auto expectations =
+ [&](webrtc::MockAsyncDnsResolver* resolver,
+ webrtc::MockAsyncDnsResolverResult* resolver_result) {
+ EXPECT_CALL(*resolver, Start(_, _, _))
+ .WillOnce(
+ [](const webrtc::SocketAddress& /* addr */, int /* family */,
+ absl::AnyInvocable<void()> callback) { callback(); });
+
+ EXPECT_CALL(*resolver, result)
+ .WillRepeatedly(ReturnPointee(resolver_result));
+ EXPECT_CALL(*resolver_result, GetError).WillRepeatedly(Return(0));
+ EXPECT_CALL(*resolver_result, GetResolvedAddress(_, _))
+ .WillOnce(
+ DoAll(SetArgPointee<1>(SocketAddress(server_address(), 5000)),
+ Return(true)));
+ };
+
+ socket_factory_.SetExpectations(std::move(expectations));
+ }
+
+ bool port_ready_ = false;
+ bool port_error_ = false;
+
+ ScopedFakeClock fake_clock_;
+ const Environment env_ = CreateEnvironment();
+ VirtualSocketServer ss_;
+ AutoSocketServerThread thread_{&ss_};
+ MockDnsResolvingPacketSocketFactory socket_factory_{&ss_};
+
+ const bool is_using_ipv6_{SocketAddress(server_address(), 5000).family() ==
+ AF_INET6};
+ const SocketAddress local_address_{is_using_ipv6_ ? kLocalIPv6Addr
+ : kLocalAddr};
+ Network network_{"unittest", "unittest", local_address_.ipaddr(), 32};
+
+ TestTurnServer turn_server_{&thread_, &ss_, kTurnUdpIntAddr, kTurnUdpExtAddr};
+ TestStunServer::StunServerPtr stun_server_;
+};
+
+std::string GetTestName(
+ const testing::TestParamInfo<LocalNetworkAccessPortTest::ParamType>& info) {
+ std::string protocol_str;
+ switch (std::get<0>(info.param)) {
+ case kStun:
+ protocol_str = "Stun";
+ break;
+ case kTurn:
+ protocol_str = "Turn";
+ break;
+ }
+
+ // Remove ":"
+ std::string sanitized_address = absl::StrReplaceAll(
+ std::get<1>(info.param), {{"::", "_"}, {":", "_"}, {".", "_"}});
+
+ std::string result_str;
+ switch (std::get<2>(info.param)) {
+ case LnaFakeResult::kPermissionNotNeeded:
+ result_str = "PermissionNotNeeded";
+ break;
+ case LnaFakeResult::kPermissionGranted:
+ result_str = "PermissionGranted";
+ break;
+ case LnaFakeResult::kPermissionDenied:
+ result_str = "PermissionDenied";
+ break;
+ }
+
+ return absl::StrFormat("%s_%s_%s", protocol_str, sanitized_address,
+ result_str);
+}
+
+constexpr absl::string_view kTestAddresses[] = {
+ "127.0.0.1",
+ "10.0.0.3",
+ "1.1.1.1",
+ "::1",
+ "fd00:4860:4860::8844",
+ "2001:4860:4860::8888",
+};
+
+INSTANTIATE_TEST_SUITE_P(
+ All,
+ LocalNetworkAccessPortTest,
+ ::testing::Combine(::testing::Values(kStun, kTurn),
+ ::testing::ValuesIn(kTestAddresses),
+ ::testing::Values(LnaFakeResult::kPermissionNotNeeded,
+ LnaFakeResult::kPermissionGranted,
+ LnaFakeResult::kPermissionDenied)),
+ &GetTestName);
+
+TEST_P(LocalNetworkAccessPortTest, ResolvedAddress) {
+ FakeLocalNetworkAccessPermissionFactory factory(lna_fake_result());
+
+ auto port = CreatePort(server_address(), factory);
+ port->PrepareAddress();
+
+ if (lna_fake_result() == LnaFakeResult::kPermissionNotNeeded ||
+ lna_fake_result() == LnaFakeResult::kPermissionGranted) {
+ EXPECT_THAT(WaitUntil([&] { return port_ready_; }, IsTrue(),
+ {.clock = &fake_clock_}),
+ IsRtcOk());
+ EXPECT_EQ(1u, port->Candidates().size());
+ EXPECT_NE(SOCKET_ERROR, port->GetError());
+ } else {
+ EXPECT_THAT(WaitUntil([&] { return port_error_; }, IsTrue(),
+ {.clock = &fake_clock_}),
+ IsRtcOk());
+ EXPECT_EQ(0u, port->Candidates().size());
+ EXPECT_NE(SOCKET_ERROR, port->GetError());
+ }
+}
+
+TEST_P(LocalNetworkAccessPortTest, UnresolvedAddress) {
+ setup_dns_resolver_mock();
+ FakeLocalNetworkAccessPermissionFactory factory(lna_fake_result());
+
+ auto port = CreatePort("fakehost.test", factory);
+ port->PrepareAddress();
+
+ if (lna_fake_result() == LnaFakeResult::kPermissionNotNeeded ||
+ lna_fake_result() == LnaFakeResult::kPermissionGranted) {
+ EXPECT_THAT(WaitUntil([&] { return port_ready_; }, IsTrue(),
+ {.clock = &fake_clock_}),
+ IsRtcOk());
+ EXPECT_EQ(1u, port->Candidates().size());
+ EXPECT_NE(SOCKET_ERROR, port->GetError());
+ } else {
+ EXPECT_THAT(WaitUntil([&] { return port_error_; }, IsTrue(),
+ {.clock = &fake_clock_}),
+ IsRtcOk());
+ EXPECT_EQ(0u, port->Candidates().size());
+ EXPECT_NE(SOCKET_ERROR, port->GetError());
+ }
+}
+
+} // namespace
+} // namespace webrtc
diff --git a/p2p/base/p2p_transport_channel.cc b/p2p/base/p2p_transport_channel.cc
index c2afc27..7a693f1 100644
--- a/p2p/base/p2p_transport_channel.cc
+++ b/p2p/base/p2p_transport_channel.cc
@@ -1315,17 +1315,16 @@
return;
}
- if (!candidate.address().IsPrivateIP() &&
- !candidate.address().IsLoopbackIP()) {
- RTC_LOG(LS_VERBOSE) << "Skipping LNA permission check for public IP "
+ std::unique_ptr<LocalNetworkAccessPermissionInterface> permission_query =
+ lna_permission_factory_->Create();
+ if (!permission_query->ShouldRequestPermission(candidate.address())) {
+ RTC_LOG(LS_VERBOSE) << "No need to request permission for candidate: "
<< candidate.address().ipaddr().ToSensitiveString()
<< ".";
FinishAddingRemoteCandidate(candidate);
return;
}
- std::unique_ptr<LocalNetworkAccessPermissionInterface> permission_query =
- lna_permission_factory_->Create();
auto permission_query_ptr = permission_query.get();
permission_queries_.emplace_back(candidate, std::move(permission_query));
diff --git a/p2p/base/p2p_transport_channel_unittest.cc b/p2p/base/p2p_transport_channel_unittest.cc
index 83d2d1c..3a70363 100644
--- a/p2p/base/p2p_transport_channel_unittest.cc
+++ b/p2p/base/p2p_transport_channel_unittest.cc
@@ -18,6 +18,7 @@
#include <memory>
#include <optional>
#include <string>
+#include <tuple>
#include <utility>
#include <vector>
@@ -30,7 +31,6 @@
#include "api/environment/environment.h"
#include "api/environment/environment_factory.h"
#include "api/ice_transport_interface.h"
-#include "api/local_network_access_permission.h"
#include "api/packet_socket_factory.h"
#include "api/scoped_refptr.h"
#include "api/task_queue/pending_task_safety_flag.h"
@@ -119,6 +119,7 @@
using ::testing::SizeIs;
using ::testing::Values;
using ::testing::WithParamInterface;
+using LnaFakeResult = FakeLocalNetworkAccessPermissionFactory::Result;
// Default timeout for tests in this file.
// Should be large enough for slow buildbots to run the tests reliably.
@@ -6798,63 +6799,27 @@
DestroyChannels();
}
-struct LocalAreaNetworkPermissionTestConfig {
- template <typename Sink>
- friend void AbslStringify(
- Sink& sink,
- const LocalAreaNetworkPermissionTestConfig& config) {
- sink.Append(config.address);
- sink.Append("_");
- switch (config.lna_permission_status) {
- case LocalNetworkAccessPermissionStatus::kDenied:
- sink.Append("Denied");
- break;
- case LocalNetworkAccessPermissionStatus::kGranted:
- sink.Append("Granted");
- break;
- }
- }
-
- LocalNetworkAccessPermissionStatus lna_permission_status;
- absl::string_view address;
- bool candidate_added;
-} kAllLocalAreNetworkPermissionTestConfigs[] = {
- {LocalNetworkAccessPermissionStatus::kDenied, "127.0.0.1",
- /*candidate_added=*/false},
- {LocalNetworkAccessPermissionStatus::kDenied, "10.0.0.3",
- /*candidate_added=*/false},
- {LocalNetworkAccessPermissionStatus::kDenied, "1.1.1.1",
- /*candidate_added=*/true},
- {LocalNetworkAccessPermissionStatus::kDenied, "::1",
- /*candidate_added=*/false},
- {LocalNetworkAccessPermissionStatus::kDenied, "fd00:4860:4860::8844",
- /*candidate_added=*/false},
- {LocalNetworkAccessPermissionStatus::kDenied, "2001:4860:4860::8888",
- /*candidate_added=*/true},
- {LocalNetworkAccessPermissionStatus::kGranted, "127.0.0.1",
- /*candidate_added=*/true},
- {LocalNetworkAccessPermissionStatus::kGranted, "10.0.0.3",
- /*candidate_added=*/true},
- {LocalNetworkAccessPermissionStatus::kGranted, "1.1.1.1",
- /*candidate_added=*/true},
- {LocalNetworkAccessPermissionStatus::kGranted, "::1",
- /*candidate_added=*/true},
- {LocalNetworkAccessPermissionStatus::kGranted, "fd00:4860:4860::8844",
- /*candidate_added=*/true},
- {LocalNetworkAccessPermissionStatus::kGranted, "2001:4860:4860::8888",
- /*candidate_added=*/true},
+constexpr absl::string_view kTestAddresses[] = {
+ "127.0.0.1",
+ "10.0.0.3",
+ "1.1.1.1",
+ "::1",
+ "fd00:4860:4860::8844",
+ "2001:4860:4860::8888",
};
-class LocalAreaNetworkPermissionTest
+class LocalNetworkAccessPermissionTest
: public P2PTransportChannelPingTest,
public ::testing::WithParamInterface<
- LocalAreaNetworkPermissionTestConfig> {};
+ std::tuple<absl::string_view, LnaFakeResult>> {};
-TEST_P(LocalAreaNetworkPermissionTest, LiteralAddresses) {
+TEST_P(LocalNetworkAccessPermissionTest, LiteralAddresses) {
+ const auto [address, lna_fake_result] = GetParam();
+
const Environment env = CreateEnvironment();
FakePortAllocator pa(env, ss());
FakeLocalNetworkAccessPermissionFactory lna_permission_factory(
- GetParam().lna_permission_status);
+ lna_fake_result);
IceTransportInit init;
init.set_port_allocator(&pa);
@@ -6866,27 +6831,30 @@
ch->MaybeStartGathering();
ch->AddRemoteCandidate(
- CreateUdpCandidate(IceCandidateType::kHost, GetParam().address, 5000, 1));
+ CreateUdpCandidate(IceCandidateType::kHost, address, 5000, 1));
ASSERT_THAT(
WaitUntil([&] { return ch->PermissionQueriesOutstandingForTesting(); },
Eq(0)),
IsRtcOk());
- if (GetParam().candidate_added) {
+ if (lna_fake_result == LnaFakeResult::kPermissionNotNeeded ||
+ lna_fake_result == LnaFakeResult::kPermissionGranted) {
EXPECT_EQ(1u, ch->remote_candidates().size());
} else {
EXPECT_EQ(0u, ch->remote_candidates().size());
}
}
-TEST_P(LocalAreaNetworkPermissionTest, UnresolvedAddresses) {
+TEST_P(LocalNetworkAccessPermissionTest, UnresolvedAddresses) {
+ const auto [address, lna_fake_result] = GetParam();
+
const Environment env = CreateEnvironment();
FakePortAllocator pa(env, ss());
FakeLocalNetworkAccessPermissionFactory lna_permission_factory(
- GetParam().lna_permission_status);
+ lna_fake_result);
ResolverFactoryFixture resolver_fixture;
- resolver_fixture.SetAddressToReturn({GetParam().address, 5000});
+ resolver_fixture.SetAddressToReturn({address, 5000});
IceTransportInit init;
init.set_port_allocator(&pa);
@@ -6905,7 +6873,8 @@
WaitUntil([&] { return ch->PermissionQueriesOutstandingForTesting(); },
Eq(0)),
IsRtcOk());
- if (GetParam().candidate_added) {
+ if (lna_fake_result == LnaFakeResult::kPermissionNotNeeded ||
+ lna_fake_result == LnaFakeResult::kPermissionGranted) {
EXPECT_EQ(1u, ch->remote_candidates().size());
} else {
EXPECT_EQ(0u, ch->remote_candidates().size());
@@ -6914,8 +6883,11 @@
INSTANTIATE_TEST_SUITE_P(
All,
- LocalAreaNetworkPermissionTest,
- ::testing::ValuesIn(kAllLocalAreNetworkPermissionTestConfigs));
+ LocalNetworkAccessPermissionTest,
+ ::testing::Combine(::testing::ValuesIn(kTestAddresses),
+ ::testing::Values(LnaFakeResult::kPermissionNotNeeded,
+ LnaFakeResult::kPermissionGranted,
+ LnaFakeResult::kPermissionDenied)));
class GatherAfterConnectedTest : public P2PTransportChannelTest,
public WithParamInterface<bool> {};
diff --git a/p2p/base/port.cc b/p2p/base/port.cc
index cce7515..033e3f6 100644
--- a/p2p/base/port.cc
+++ b/p2p/base/port.cc
@@ -950,7 +950,9 @@
return;
}
- if (!address.IsPrivateIP() && !address.IsLoopbackIP()) {
+ std::unique_ptr<LocalNetworkAccessPermissionInterface> permission_query =
+ lna_permission_factory_->Create();
+ if (!permission_query->ShouldRequestPermission(address)) {
std::move(callback)(LocalNetworkAccessPermissionStatus::kGranted);
return;
}
@@ -958,8 +960,6 @@
RTC_LOG(LS_VERBOSE) << "Asynchronously requesting LNA permission."
<< address.HostAsSensitiveURIString();
- std::unique_ptr<LocalNetworkAccessPermissionInterface> permission_query =
- lna_permission_factory_->Create();
auto* permission_query_ptr = permission_query.get();
permission_queries_.push_back(std::move(permission_query));
diff --git a/p2p/base/stun_port_unittest.cc b/p2p/base/stun_port_unittest.cc
index ce28fdd..1fd40d4 100644
--- a/p2p/base/stun_port_unittest.cc
+++ b/p2p/base/stun_port_unittest.cc
@@ -16,7 +16,6 @@
#include <optional>
#include <set>
#include <string>
-#include <utility>
#include <vector>
#include "absl/functional/any_invocable.h"
@@ -25,10 +24,8 @@
#include "api/environment/environment_factory.h"
#include "api/field_trials.h"
#include "api/field_trials_view.h"
-#include "api/local_network_access_permission.h"
#include "api/packet_socket_factory.h"
#include "api/test/mock_async_dns_resolver.h"
-#include "api/test/mock_local_network_access_permission.h"
#include "api/test/rtc_error_matchers.h"
#include "api/transport/stun.h"
#include "api/units/time_delta.h"
@@ -195,26 +192,21 @@
}
void CreateStunPort(const webrtc::SocketAddress& server_addr,
- const webrtc::FieldTrialsView* field_trials = nullptr,
- webrtc::LocalNetworkAccessPermissionFactoryInterface*
- lna_permission_factory = nullptr) {
+ const webrtc::FieldTrialsView* field_trials = nullptr) {
ServerAddresses stun_servers;
stun_servers.insert(server_addr);
- CreateStunPort(stun_servers, field_trials, lna_permission_factory);
+ CreateStunPort(stun_servers, field_trials);
}
void CreateStunPort(const ServerAddresses& stun_servers,
- const webrtc::FieldTrialsView* field_trials = nullptr,
- webrtc::LocalNetworkAccessPermissionFactoryInterface*
- lna_permission_factory = nullptr) {
+ const webrtc::FieldTrialsView* field_trials = nullptr) {
stun_port_ = webrtc::StunPort::Create(
{.env = CreateEnvironment(field_trials),
.network_thread = &thread_,
.socket_factory = socket_factory(),
.network = network_,
.ice_username_fragment = webrtc::CreateRandomString(16),
- .ice_password = webrtc::CreateRandomString(22),
- .lna_permission_factory = lna_permission_factory},
+ .ice_password = webrtc::CreateRandomString(22)},
0, 0, stun_servers, std::nullopt);
stun_port_->SetIceTiebreaker(kTiebreakerDefault);
stun_port_->set_stun_keepalive_delay(stun_keepalive_delay_);
@@ -776,161 +768,6 @@
StunPortIPAddressTypeMetricsTest,
::testing::ValuesIn(kAllIPAddressTypeTestConfigs));
-struct LocalAreaNetworkPermissionTestConfig {
- template <typename Sink>
- friend void AbslStringify(
- Sink& sink,
- const LocalAreaNetworkPermissionTestConfig& config) {
- sink.Append(config.address);
- sink.Append("_");
- switch (config.lna_permission_status) {
- case webrtc::LocalNetworkAccessPermissionStatus::kDenied:
- sink.Append("Denied");
- break;
- case webrtc::LocalNetworkAccessPermissionStatus::kGranted:
- sink.Append("Granted");
- break;
- }
- }
-
- webrtc::LocalNetworkAccessPermissionStatus lna_permission_status;
- absl::string_view address;
- bool should_succeed;
-} kAllLocalAreNetworkPermissionTestConfigs[] = {
- {webrtc::LocalNetworkAccessPermissionStatus::kDenied, "127.0.0.1",
- /*should_succeed=*/false},
- {webrtc::LocalNetworkAccessPermissionStatus::kDenied, "10.0.0.3",
- /*should_succeed=*/false},
- {webrtc::LocalNetworkAccessPermissionStatus::kDenied, "1.1.1.1",
- /*should_succeed=*/true},
- {webrtc::LocalNetworkAccessPermissionStatus::kDenied, "::1",
- /*should_succeed=*/false},
- {webrtc::LocalNetworkAccessPermissionStatus::kDenied,
- "fd00:4860:4860::8844",
- /*should_succeed=*/false},
- {webrtc::LocalNetworkAccessPermissionStatus::kDenied,
- "2001:4860:4860::8888",
- /*should_succeed=*/true},
- {webrtc::LocalNetworkAccessPermissionStatus::kGranted, "127.0.0.1",
- /*should_succeed=*/true},
- {webrtc::LocalNetworkAccessPermissionStatus::kGranted, "10.0.0.3",
- /*should_succeed=*/true},
- {webrtc::LocalNetworkAccessPermissionStatus::kGranted, "1.1.1.1",
- /*should_succeed=*/true},
- {webrtc::LocalNetworkAccessPermissionStatus::kGranted, "::1",
- /*should_succeed=*/true},
- {webrtc::LocalNetworkAccessPermissionStatus::kGranted,
- "fd00:4860:4860::8844",
- /*should_succeed=*/true},
- {webrtc::LocalNetworkAccessPermissionStatus::kGranted,
- "2001:4860:4860::8888",
- /*should_succeed=*/true},
-};
-
-class StunPortLocalNetworkAccessPermissionTest
- : public FakeClockBase,
- public StunPortTestBase,
- public ::testing::WithParamInterface<
- LocalAreaNetworkPermissionTestConfig> {
- public:
- StunPortLocalNetworkAccessPermissionTest()
- : StunPortTestBase(
- /*address=*/using_ipv6_address() ? kPrivateIPv6.ipaddr()
- : kPrivateIP.ipaddr(),
- /*stun_server_addresses=*/{{GetParam().address, 5000}},
- /*nat_server_address=*/
- using_ipv6_address() ? kNatAddrIPv6 : kNatAddr),
- socket_factory_(ss()) {}
-
- protected:
- webrtc::PacketSocketFactory* socket_factory() override {
- return &socket_factory_;
- }
-
- void setup_dns_resolver_mock() {
- auto expectations =
- [](webrtc::MockAsyncDnsResolver* resolver,
- webrtc::MockAsyncDnsResolverResult* resolver_result) {
- EXPECT_CALL(*resolver, Start(_, _, _))
- .WillOnce(
- [](const webrtc::SocketAddress& /* addr */, int /* family */,
- absl::AnyInvocable<void()> callback) { callback(); });
-
- EXPECT_CALL(*resolver, result)
- .WillRepeatedly(ReturnPointee(resolver_result));
- EXPECT_CALL(*resolver_result, GetError).WillOnce(Return(0));
- EXPECT_CALL(*resolver_result, GetResolvedAddress(_, _))
- .WillOnce(DoAll(
- SetArgPointee<1>(SocketAddress(GetParam().address, 5000)),
- Return(true)));
- };
-
- socket_factory_.SetExpectations(std::move(expectations));
- }
-
- private:
- bool using_ipv6_address() {
- return SocketAddress(GetParam().address, 5000).family() == AF_INET6;
- }
-
- webrtc::MockDnsResolvingPacketSocketFactory socket_factory_;
-};
-
-TEST_P(StunPortLocalNetworkAccessPermissionTest, ResolvedAddresses) {
- webrtc::FakeLocalNetworkAccessPermissionFactory factory(
- GetParam().lna_permission_status);
-
- CreateStunPort({GetParam().address, 5000}, /*field_trials=*/nullptr,
- &factory);
-
- PrepareAddress();
- EXPECT_THAT(
- webrtc::WaitUntil([&] { return done(); }, IsTrue(),
- {.timeout = webrtc::TimeDelta::Millis(kTimeoutMs),
- .clock = &fake_clock}),
- webrtc::IsRtcOk());
-
- if (GetParam().should_succeed) {
- EXPECT_FALSE(error());
- EXPECT_EQ(1U, port()->Candidates().size());
- EXPECT_EQ(0, error_event_.error_code);
- } else {
- EXPECT_TRUE(error());
- EXPECT_EQ(0U, port()->Candidates().size());
- EXPECT_EQ(0, error_event_.error_code);
- }
-}
-
-TEST_P(StunPortLocalNetworkAccessPermissionTest, UnresolvedAddresses) {
- setup_dns_resolver_mock();
-
- webrtc::FakeLocalNetworkAccessPermissionFactory factory(
- GetParam().lna_permission_status);
- CreateStunPort({"fakehost.test", 5000}, /*field_trials=*/nullptr, &factory);
-
- PrepareAddress();
- EXPECT_THAT(
- webrtc::WaitUntil([&] { return done(); }, IsTrue(),
- {.timeout = webrtc::TimeDelta::Millis(kTimeoutMs),
- .clock = &fake_clock}),
- webrtc::IsRtcOk());
-
- if (GetParam().should_succeed) {
- EXPECT_FALSE(error());
- EXPECT_EQ(1U, port()->Candidates().size());
- EXPECT_EQ(0, error_event_.error_code);
- } else {
- EXPECT_TRUE(error());
- EXPECT_EQ(0U, port()->Candidates().size());
- EXPECT_EQ(0, error_event_.error_code);
- }
-}
-
-INSTANTIATE_TEST_SUITE_P(
- All,
- StunPortLocalNetworkAccessPermissionTest,
- ::testing::ValuesIn(kAllLocalAreNetworkPermissionTestConfigs));
-
class MockAsyncPacketSocket : public webrtc::AsyncPacketSocket {
public:
~MockAsyncPacketSocket() override = default;
diff --git a/p2p/base/turn_port_unittest.cc b/p2p/base/turn_port_unittest.cc
index d0c7124..c56c04b 100644
--- a/p2p/base/turn_port_unittest.cc
+++ b/p2p/base/turn_port_unittest.cc
@@ -24,10 +24,8 @@
#include "api/candidate.h"
#include "api/environment/environment.h"
#include "api/environment/environment_factory.h"
-#include "api/local_network_access_permission.h"
#include "api/packet_socket_factory.h"
#include "api/test/mock_async_dns_resolver.h"
-#include "api/test/mock_local_network_access_permission.h"
#include "api/test/rtc_error_matchers.h"
#include "api/transport/stun.h"
#include "api/units/time_delta.h"
@@ -281,12 +279,9 @@
bool CreateTurnPort(const SocketAddress& local_address,
absl::string_view username,
absl::string_view password,
- const ProtocolAddress& server_address,
- LocalNetworkAccessPermissionFactoryInterface*
- lna_permission_factory = nullptr) {
+ const ProtocolAddress& server_address) {
return CreateTurnPortWithAllParams(MakeNetwork(local_address), username,
- password, server_address,
- lna_permission_factory);
+ password, server_address);
}
bool CreateTurnPortWithNetwork(const Network* network,
@@ -303,9 +298,7 @@
bool CreateTurnPortWithAllParams(const Network* network,
absl::string_view username,
absl::string_view password,
- const ProtocolAddress& server_address,
- LocalNetworkAccessPermissionFactoryInterface*
- lna_permission_factory = nullptr) {
+ const ProtocolAddress& server_address) {
RelayServerConfig config;
config.credentials = RelayCredentials(username, password);
CreateRelayPortArgs args = {.env = env_};
@@ -317,7 +310,6 @@
args.server_address = &server_address;
args.config = &config;
args.turn_customizer = turn_customizer_.get();
- args.lna_permission_factory = lna_permission_factory;
turn_port_ = TurnPort::Create(args, 0, 0);
if (!turn_port_) {
@@ -2245,150 +2237,4 @@
TurnPortIPAddressTypeMetricsTest,
::testing::ValuesIn(kAllIPAddressTypeTestConfigs));
-struct LocalAreaNetworkPermissionTestConfig {
- template <typename Sink>
- friend void AbslStringify(
- Sink& sink,
- const LocalAreaNetworkPermissionTestConfig& config) {
- sink.Append(config.address);
- sink.Append("_");
- switch (config.lna_permission_status) {
- case webrtc::LocalNetworkAccessPermissionStatus::kDenied:
- sink.Append("Denied");
- break;
- case webrtc::LocalNetworkAccessPermissionStatus::kGranted:
- sink.Append("Granted");
- break;
- }
- }
-
- webrtc::LocalNetworkAccessPermissionStatus lna_permission_status;
- absl::string_view address;
- bool should_succeed;
-} kAllLocalAreNetworkPermissionTestConfigs[] = {
- {webrtc::LocalNetworkAccessPermissionStatus::kDenied, "127.0.0.1",
- /*should_succeed=*/false},
- {webrtc::LocalNetworkAccessPermissionStatus::kDenied, "10.0.0.3",
- /*should_succeed=*/false},
- {webrtc::LocalNetworkAccessPermissionStatus::kDenied, "1.1.1.1",
- /*should_succeed=*/true},
- {webrtc::LocalNetworkAccessPermissionStatus::kDenied, "::1",
- /*should_succeed=*/false},
- {webrtc::LocalNetworkAccessPermissionStatus::kDenied,
- "fd00:4860:4860::8844",
- /*should_succeed=*/false},
- {webrtc::LocalNetworkAccessPermissionStatus::kDenied,
- "2001:4860:4860::8888",
- /*should_succeed=*/true},
- {webrtc::LocalNetworkAccessPermissionStatus::kGranted, "127.0.0.1",
- /*should_succeed=*/true},
- {webrtc::LocalNetworkAccessPermissionStatus::kGranted, "10.0.0.3",
- /*should_succeed=*/true},
- {webrtc::LocalNetworkAccessPermissionStatus::kGranted, "1.1.1.1",
- /*should_succeed=*/true},
- {webrtc::LocalNetworkAccessPermissionStatus::kGranted, "::1",
- /*should_succeed=*/true},
- {webrtc::LocalNetworkAccessPermissionStatus::kGranted,
- "fd00:4860:4860::8844",
- /*should_succeed=*/true},
- {webrtc::LocalNetworkAccessPermissionStatus::kGranted,
- "2001:4860:4860::8888",
- /*should_succeed=*/true},
-};
-
-class TurnPortLocalNetworkAccessPermissionTest
- : public TurnPortWithMockDnsResolverTest,
- public ::testing::WithParamInterface<
- LocalAreaNetworkPermissionTestConfig> {
- protected:
- void CreateTurnPort(
- absl::string_view address,
- LocalNetworkAccessPermissionFactoryInterface* lna_permission_factory) {
- ProtocolAddress server_address({address, 5000}, PROTO_UDP);
-
- // Use the test's address instead of `server_address` because
- // `server_address` might not be a resolved address with an unknown family.
- SocketAddress local_address =
- SocketAddress(GetParam().address, 5000).family() == AF_INET6
- ? kLocalIPv6Addr
- : kLocalAddr1;
- TurnPortWithMockDnsResolverTest::CreateTurnPort(
- local_address, kTurnUsername, kTurnPassword, server_address,
- lna_permission_factory);
- }
-
- void setup_dns_resolver_mock() {
- auto expectations =
- [](webrtc::MockAsyncDnsResolver* resolver,
- webrtc::MockAsyncDnsResolverResult* resolver_result) {
- EXPECT_CALL(*resolver, Start(_, _, _))
- .WillOnce(
- [](const webrtc::SocketAddress& /* addr */, int /* family */,
- absl::AnyInvocable<void()> callback) { callback(); });
-
- EXPECT_CALL(*resolver, result)
- .WillRepeatedly(ReturnPointee(resolver_result));
- EXPECT_CALL(*resolver_result, GetError).WillRepeatedly(Return(0));
- EXPECT_CALL(*resolver_result, GetResolvedAddress(_, _))
- .WillOnce(DoAll(
- SetArgPointee<1>(SocketAddress(GetParam().address, 5000)),
- Return(true)));
- };
-
- SetDnsResolverExpectations(std::move(expectations));
- }
-};
-
-TEST_P(TurnPortLocalNetworkAccessPermissionTest, ResolvedAddresses) {
- turn_server_.AddInternalSocket({GetParam().address, 5000}, PROTO_UDP);
-
- FakeLocalNetworkAccessPermissionFactory factory(
- GetParam().lna_permission_status);
- CreateTurnPort(GetParam().address, &factory);
- turn_port_->PrepareAddress();
-
- if (GetParam().should_succeed) {
- EXPECT_THAT(WaitUntil([&] { return turn_ready_; }, IsTrue(),
- {.clock = &fake_clock_}),
- IsRtcOk());
- EXPECT_EQ(1u, turn_port_->Candidates().size());
- EXPECT_NE(SOCKET_ERROR, turn_port_->error());
- } else {
- EXPECT_THAT(WaitUntil([&] { return turn_error_; }, IsTrue(),
- {.clock = &fake_clock_}),
- IsRtcOk());
- EXPECT_EQ(0u, turn_port_->Candidates().size());
- EXPECT_NE(SOCKET_ERROR, turn_port_->error());
- }
-}
-
-TEST_P(TurnPortLocalNetworkAccessPermissionTest, UnresolvedAddresses) {
- turn_server_.AddInternalSocket({GetParam().address, 5000}, PROTO_UDP);
- setup_dns_resolver_mock();
-
- FakeLocalNetworkAccessPermissionFactory factory(
- GetParam().lna_permission_status);
- CreateTurnPort("fakehost.test", &factory);
- turn_port_->PrepareAddress();
-
- if (GetParam().should_succeed) {
- EXPECT_THAT(WaitUntil([&] { return turn_ready_; }, IsTrue(),
- {.clock = &fake_clock_}),
- IsRtcOk());
- EXPECT_EQ(1u, turn_port_->Candidates().size());
- EXPECT_NE(SOCKET_ERROR, turn_port_->error());
- } else {
- EXPECT_THAT(WaitUntil([&] { return turn_error_; }, IsTrue(),
- {.clock = &fake_clock_}),
- IsRtcOk());
- EXPECT_EQ(0u, turn_port_->Candidates().size());
- EXPECT_NE(SOCKET_ERROR, turn_port_->error());
- }
-}
-
-INSTANTIATE_TEST_SUITE_P(
- All,
- TurnPortLocalNetworkAccessPermissionTest,
- ::testing::ValuesIn(kAllLocalAreNetworkPermissionTestConfigs));
-
} // namespace webrtc