blob: 351922211d326b4b696118070325edf245a6035b [file] [log] [blame]
// Copyright 2020 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 <map>
#include <vector>
#include "base/optional.h"
#include "base/run_loop.h"
#include "base/strings/strcat.h"
#include "base/strings/stringprintf.h"
#include "base/test/bind.h"
#include "base/test/scoped_feature_list.h"
#include "content/browser/direct_sockets/direct_sockets_service_impl.h"
#include "content/browser/renderer_host/frame_tree_node.h"
#include "content/browser/renderer_host/render_frame_host_impl.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/content_features.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/content_browser_test.h"
#include "content/public/test/content_browser_test_utils.h"
#include "content/shell/browser/shell.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "mojo/public/cpp/system/data_pipe.h"
#include "net/base/ip_address.h"
#include "net/base/ip_endpoint.h"
#include "net/base/net_errors.h"
#include "net/net_buildflags.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
#include "net/traffic_annotation/network_traffic_annotation.h"
#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
#include "services/network/public/mojom/host_resolver.mojom.h"
#include "services/network/public/mojom/network_context.mojom.h"
#include "services/network/public/mojom/tcp_socket.mojom.h"
#include "services/network/test/test_network_context.h"
#include "testing/gmock/include/gmock/gmock-matchers.h"
#include "url/gurl.h"
// The tests in this file use a mock implementation of NetworkContext, to test
// DNS resolving, and the opening of TCP and UDP sockets.
using testing::StartsWith;
namespace content {
namespace {
struct RecordedCall {
DirectSocketsServiceImpl::ProtocolType protocol_type;
std::string remote_address;
uint16_t remote_port;
int32_t send_buffer_size = 0;
int32_t receive_buffer_size = 0;
bool no_delay = false;
};
constexpr char kPermissionDeniedHistogramName[] =
"DirectSockets.PermissionDeniedFailures";
const std::string kIPv4_tests[] = {
// 0.0.0.0/8
"0.0.0.0", "0.255.255.255",
// 10.0.0.0/8
"10.0.0.0", "10.255.255.255",
// 100.64.0.0/10
"100.64.0.0", "100.127.255.255",
// 127.0.0.0/8
"127.0.0.0", "127.255.255.255",
// 169.254.0.0/16
"169.254.0.0", "169.254.255.255",
// 172.16.0.0/12
"172.16.0.0", "172.31.255.255",
// 192.0.2.0/24
"192.0.2.0", "192.0.2.255",
// 192.88.99.0/24
"192.88.99.0", "192.88.99.255",
// 192.168.0.0/16
"192.168.0.0", "192.168.255.255",
// 198.18.0.0/15
"198.18.0.0", "198.19.255.255",
// 198.51.100.0/24
"198.51.100.0", "198.51.100.255",
// 203.0.113.0/24
"203.0.113.0", "203.0.113.255",
// 224.0.0.0/8 - 255.0.0.0/8
"224.0.0.0", "255.255.255.255"};
const std::string kIPv6_tests[] = {
// 0000::/8.
// Skip testing ::ffff:/96 explicitly since it will be tested through
// mapping Ipv4 Addresses.
"0:0:0:0:0:0:0:0", "ff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
// 0100::/8
"100:0:0:0:0:0:0:0", "1ff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
// 0200::/7
"200:0:0:0:0:0:0:0", "3ff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
// 0400::/6
"400:0:0:0:0:0:0:0", "7ff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
// 0800::/5
"800:0:0:0:0:0:0:0", "fff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
// 1000::/4
"1000:0:0:0:0:0:0:0", "1fff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
// 4000::/3
"4000:0:0:0:0:0:0:0", "5fff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
// 6000::/3
"6000:0:0:0:0:0:0:0", "7fff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
// 8000::/3
"8000:0:0:0:0:0:0:0", "9fff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
// c000::/3
"c000:0:0:0:0:0:0:0", "dfff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
// e000::/4
"e000:0:0:0:0:0:0:0", "efff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
// f000::/5
"f000:0:0:0:0:0:0:0", "f7ff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
// f800::/6
"f800:0:0:0:0:0:0:0", "fbff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
// fc00::/7
"fc00:0:0:0:0:0:0:0", "fdff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
// fe00::/9
"fe00:0:0:0:0:0:0:0", "fe7f:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
// fe80::/10
"fe80:0:0:0:0:0:0:0", "febf:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
// fec0::/10
"fec0:0:0:0:0:0:0:0", "feff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"};
class MockHostResolver : public network::mojom::HostResolver {
public:
explicit MockHostResolver(
mojo::PendingReceiver<network::mojom::HostResolver> resolver_receiver,
net::HostResolver* internal_resolver)
: receiver_(this), internal_resolver_(internal_resolver) {
receiver_.Bind(std::move(resolver_receiver));
}
MockHostResolver(const MockHostResolver&) = delete;
MockHostResolver& operator=(const MockHostResolver&) = delete;
void ResolveHost(const ::net::HostPortPair& host,
const ::net::NetworkIsolationKey& network_isolation_key,
network::mojom::ResolveHostParametersPtr optional_parameters,
::mojo::PendingRemote<network::mojom::ResolveHostClient>
pending_response_client) override {
DCHECK(!internal_request_);
DCHECK(!response_client_.is_bound());
internal_request_ = internal_resolver_->CreateRequest(
host, network_isolation_key,
net::NetLogWithSource::Make(net::NetLog::Get(),
net::NetLogSourceType::NONE),
base::nullopt);
mojo::Remote<network::mojom::ResolveHostClient> response_client(
std::move(pending_response_client));
int rv = internal_request_->Start(
base::BindOnce(&MockHostResolver::OnComplete, base::Unretained(this)));
if (rv != net::ERR_IO_PENDING) {
response_client->OnComplete(rv, internal_request_->GetResolveErrorInfo(),
internal_request_->GetAddressResults());
return;
}
response_client_ = std::move(response_client);
}
void MdnsListen(
const ::net::HostPortPair& host,
::net::DnsQueryType query_type,
::mojo::PendingRemote<network::mojom::MdnsListenClient> response_client,
MdnsListenCallback callback) override {
NOTIMPLEMENTED();
}
private:
void OnComplete(int error) {
DCHECK(response_client_.is_bound());
DCHECK(internal_request_);
response_client_->OnComplete(error,
internal_request_->GetResolveErrorInfo(),
internal_request_->GetAddressResults());
response_client_.reset();
}
std::unique_ptr<net::HostResolver::ResolveHostRequest> internal_request_;
mojo::Remote<network::mojom::ResolveHostClient> response_client_;
mojo::Receiver<network::mojom::HostResolver> receiver_;
net::HostResolver* const internal_resolver_;
};
class MockNetworkContext : public network::TestNetworkContext {
public:
explicit MockNetworkContext(net::Error result) : result_(result) {}
MockNetworkContext(const MockNetworkContext&) = delete;
MockNetworkContext& operator=(const MockNetworkContext&) = delete;
const std::vector<RecordedCall>& history() const { return history_; }
// network::TestNetworkContext:
void CreateTCPConnectedSocket(
const base::Optional<net::IPEndPoint>& local_addr,
const net::AddressList& remote_addr_list,
network::mojom::TCPConnectedSocketOptionsPtr tcp_connected_socket_options,
const net::MutableNetworkTrafficAnnotationTag& traffic_annotation,
mojo::PendingReceiver<network::mojom::TCPConnectedSocket> socket,
mojo::PendingRemote<network::mojom::SocketObserver> observer,
CreateTCPConnectedSocketCallback callback) override {
const net::IPEndPoint& peer_addr = remote_addr_list.front();
history_.push_back(
RecordedCall{DirectSocketsServiceImpl::ProtocolType::kTcp,
peer_addr.address().ToString(), peer_addr.port(),
tcp_connected_socket_options->send_buffer_size,
tcp_connected_socket_options->receive_buffer_size,
tcp_connected_socket_options->no_delay});
mojo::ScopedDataPipeProducerHandle producer;
mojo::ScopedDataPipeConsumerHandle consumer;
DCHECK_EQ(MOJO_RESULT_OK,
mojo::CreateDataPipe(nullptr, producer, consumer));
std::move(callback).Run(result_, local_addr, peer_addr, std::move(consumer),
std::move(producer));
}
void CreateHostResolver(
const base::Optional<net::DnsConfigOverrides>& config_overrides,
mojo::PendingReceiver<network::mojom::HostResolver> receiver) override {
DCHECK(!config_overrides.has_value());
DCHECK(!internal_resolver_);
DCHECK(!host_resolver_);
internal_resolver_ = net::HostResolver::CreateStandaloneResolver(
net::NetLog::Get(), /*options=*/base::nullopt, host_mapping_rules_,
/*enable_caching=*/false);
host_resolver_ = std::make_unique<MockHostResolver>(
std::move(receiver), internal_resolver_.get());
}
// If set to non-empty, the mapping rules will be applied to requests to the
// created internal host resolver. See MappedHostResolver for details. Should
// be called before CreateHostResolver().
void set_host_mapping_rules(std::string host_mapping_rules) {
DCHECK(!internal_resolver_);
host_mapping_rules_ = std::move(host_mapping_rules);
}
private:
const net::Error result_;
std::vector<RecordedCall> history_;
std::string host_mapping_rules_;
std::unique_ptr<net::HostResolver> internal_resolver_;
std::unique_ptr<network::mojom::HostResolver> host_resolver_;
};
net::Error UnconditionallyPermitConnection(
const blink::mojom::DirectSocketOptions& options) {
DCHECK(options.remote_hostname.has_value());
return net::OK;
}
} // anonymous namespace
class DirectSocketsOpenBrowserTest : public ContentBrowserTest {
public:
DirectSocketsOpenBrowserTest() {
feature_list_.InitAndEnableFeature(features::kDirectSockets);
}
~DirectSocketsOpenBrowserTest() override = default;
GURL GetTestOpenPageURL() {
return embedded_test_server()->GetURL("/direct_sockets/open.html");
}
void IPRoutableTest(const std::string& address,
const DirectSocketsServiceImpl::ProtocolType protocol) {
EXPECT_TRUE(NavigateToURL(shell(), GetTestOpenPageURL()));
const char kExampleHostname[] = "mail.example.com";
const std::string mapping_rules =
base::StringPrintf("MAP %s %s", kExampleHostname, address.c_str());
MockNetworkContext mock_network_context(net::OK);
mock_network_context.set_host_mapping_rules(mapping_rules);
DirectSocketsServiceImpl::SetNetworkContextForTesting(
&mock_network_context);
const std::string type =
protocol == DirectSocketsServiceImpl::ProtocolType::kTcp ? "Tcp"
: "Udp";
const std::string expected_result = base::StringPrintf(
"open%s failed: NotAllowedError: Permission denied", type.c_str());
base::HistogramTester histogram_tester;
histogram_tester.ExpectBucketCount(
kPermissionDeniedHistogramName,
DirectSocketsServiceImpl::FailureType::kResolvingToNonPublic, 0);
const std::string script =
base::StringPrintf("open%s({remoteAddress: '%s', remotePort: 993})",
type.c_str(), kExampleHostname);
EXPECT_EQ(expected_result, EvalJs(shell(), script));
histogram_tester.ExpectBucketCount(
kPermissionDeniedHistogramName,
DirectSocketsServiceImpl::FailureType::kResolvingToNonPublic, 1);
}
protected:
void SetUp() override {
DirectSocketsServiceImpl::SetEnterpriseManagedForTesting(false);
embedded_test_server()->AddDefaultHandlers(GetTestDataFilePath());
ASSERT_TRUE(embedded_test_server()->Start());
ContentBrowserTest::SetUp();
}
private:
base::test::ScopedFeatureList feature_list_;
};
IN_PROC_BROWSER_TEST_F(DirectSocketsOpenBrowserTest, OpenTcp_Success_Hostname) {
EXPECT_TRUE(NavigateToURL(shell(), GetTestOpenPageURL()));
const char kExampleHostname[] = "mail.example.com";
const char kExampleAddress[] = "98.76.54.32";
const std::string mapping_rules =
base::StringPrintf("MAP %s %s", kExampleHostname, kExampleAddress);
MockNetworkContext mock_network_context(net::OK);
mock_network_context.set_host_mapping_rules(mapping_rules);
DirectSocketsServiceImpl::SetNetworkContextForTesting(&mock_network_context);
const std::string expected_result = base::StringPrintf(
"openTcp succeeded: {remoteAddress: \"%s\", remotePort: 993}",
kExampleAddress);
const std::string script = base::StringPrintf(
"openTcp({remoteAddress: '%s', remotePort: 993})", kExampleHostname);
EXPECT_EQ(expected_result, EvalJs(shell(), script));
}
// TODO(crbug.com/1196515): Fix this flaky test.
IN_PROC_BROWSER_TEST_F(DirectSocketsOpenBrowserTest,
DISABLED_OpenTcp_TransientActivation) {
EXPECT_TRUE(NavigateToURL(shell(), GetTestOpenPageURL()));
base::HistogramTester histogram_tester;
histogram_tester.ExpectBucketCount(
kPermissionDeniedHistogramName,
DirectSocketsServiceImpl::FailureType::kTransientActivation, 0);
MockNetworkContext mock_network_context(net::OK);
DirectSocketsServiceImpl::SetNetworkContextForTesting(&mock_network_context);
const std::string script =
"openTcp({remoteAddress: '::1', remotePort: 993});\
openTcp({remoteAddress: '::1', remotePort: 993})";
EXPECT_EQ("openTcp failed: NotAllowedError: Permission denied",
EvalJs(shell(), script));
histogram_tester.ExpectBucketCount(
kPermissionDeniedHistogramName,
DirectSocketsServiceImpl::FailureType::kTransientActivation, 1);
}
IN_PROC_BROWSER_TEST_F(DirectSocketsOpenBrowserTest, OpenTcp_CannotEvadeCors) {
EXPECT_TRUE(NavigateToURL(shell(), GetTestOpenPageURL()));
base::HistogramTester histogram_tester;
histogram_tester.ExpectBucketCount(
kPermissionDeniedHistogramName,
DirectSocketsServiceImpl::FailureType::kCORS, 0);
// HTTPS uses port 443.
const std::string script =
"openTcp({remoteAddress: '127.0.0.1', remotePort: 443})";
EXPECT_EQ("openTcp failed: NotAllowedError: Permission denied",
EvalJs(shell(), script));
histogram_tester.ExpectBucketCount(
kPermissionDeniedHistogramName,
DirectSocketsServiceImpl::FailureType::kCORS, 1);
}
IN_PROC_BROWSER_TEST_F(DirectSocketsOpenBrowserTest,
OpenTcp_RestrictedByEnterprisePolicies) {
EXPECT_TRUE(NavigateToURL(shell(), GetTestOpenPageURL()));
base::HistogramTester histogram_tester;
histogram_tester.ExpectBucketCount(
kPermissionDeniedHistogramName,
DirectSocketsServiceImpl::FailureType::kEnterprisePolicy, 0);
DirectSocketsServiceImpl::SetEnterpriseManagedForTesting(true);
const std::string script =
"openTcp({remoteAddress: '127.0.0.1', remotePort: 993})";
EXPECT_EQ("openTcp failed: NotAllowedError: Permission denied",
EvalJs(shell(), script));
histogram_tester.ExpectBucketCount(
kPermissionDeniedHistogramName,
DirectSocketsServiceImpl::FailureType::kEnterprisePolicy, 1);
}
IN_PROC_BROWSER_TEST_F(DirectSocketsOpenBrowserTest,
OpenTcp_CannotConnectNonPublic) {
const auto protocol = DirectSocketsServiceImpl::ProtocolType::kTcp;
// Tests for the reserved IPv4 ranges. The reserved ranges are tested by
// checking the first and last address of each range. These tests cover the
// entire IPv4 address range, as well as this range mapped to IPv6.
for (const auto& test : kIPv4_tests) {
IPRoutableTest(test, protocol);
// Check these IPv4 addresses when mapped to IPv6.
net::IPAddress address;
EXPECT_TRUE(address.AssignFromIPLiteral(test));
net::IPAddress mapped_address = net::ConvertIPv4ToIPv4MappedIPv6(address);
IPRoutableTest(base::StrCat({"[", mapped_address.ToString(), "]"}),
protocol);
}
// Tests for the reserved IPv6 ranges. The reserved ranges are tested by
// checking the first and last address of each range. These tests cover the
// entire IPv6 address range.
for (const auto& test : kIPv6_tests)
IPRoutableTest(base::StrCat({"[", test, "]"}), protocol);
}
IN_PROC_BROWSER_TEST_F(DirectSocketsOpenBrowserTest, OpenTcp_OptionsOne) {
EXPECT_TRUE(NavigateToURL(shell(), GetTestOpenPageURL()));
DirectSocketsServiceImpl::SetPermissionCallbackForTesting(
base::BindRepeating(&UnconditionallyPermitConnection));
MockNetworkContext mock_network_context(net::ERR_PROXY_CONNECTION_FAILED);
DirectSocketsServiceImpl::SetNetworkContextForTesting(&mock_network_context);
const std::string expected_result =
"openTcp failed: NotAllowedError: Permission denied";
const std::string script =
R"(
openTcp({
remoteAddress: '12.34.56.78',
remotePort: 9012,
sendBufferSize: 3456,
receiveBufferSize: 7890,
noDelay: false
})
)";
EXPECT_EQ(expected_result, EvalJs(shell(), script));
DCHECK_EQ(1U, mock_network_context.history().size());
const RecordedCall& call = mock_network_context.history()[0];
EXPECT_EQ(DirectSocketsServiceImpl::ProtocolType::kTcp, call.protocol_type);
EXPECT_EQ("12.34.56.78", call.remote_address);
EXPECT_EQ(9012, call.remote_port);
EXPECT_EQ(3456, call.send_buffer_size);
EXPECT_EQ(7890, call.receive_buffer_size);
EXPECT_EQ(false, call.no_delay);
}
IN_PROC_BROWSER_TEST_F(DirectSocketsOpenBrowserTest, OpenTcp_OptionsTwo) {
EXPECT_TRUE(NavigateToURL(shell(), GetTestOpenPageURL()));
DirectSocketsServiceImpl::SetPermissionCallbackForTesting(
base::BindRepeating(&UnconditionallyPermitConnection));
MockNetworkContext mock_network_context(net::OK);
DirectSocketsServiceImpl::SetNetworkContextForTesting(&mock_network_context);
const std::string script =
R"(
openTcp({
remoteAddress: 'fedc:ba98:7654:3210:fedc:ba98:7654:3210',
remotePort: 789,
sendBufferSize: 0,
receiveBufferSize: 1234,
noDelay: true
})
)";
EXPECT_THAT(EvalJs(shell(), script).ExtractString(),
StartsWith("openTcp succeeded"));
DCHECK_EQ(1U, mock_network_context.history().size());
const RecordedCall& call = mock_network_context.history()[0];
EXPECT_EQ(DirectSocketsServiceImpl::ProtocolType::kTcp, call.protocol_type);
EXPECT_EQ("fedc:ba98:7654:3210:fedc:ba98:7654:3210", call.remote_address);
EXPECT_EQ(789, call.remote_port);
EXPECT_EQ(0, call.send_buffer_size);
EXPECT_EQ(1234, call.receive_buffer_size);
EXPECT_EQ(true, call.no_delay);
}
// TODO(crbug.com/1141241): Resolve failures on linux-bfcache-rel bots.
IN_PROC_BROWSER_TEST_F(DirectSocketsOpenBrowserTest, DISABLED_OpenUdp_Success) {
EXPECT_TRUE(NavigateToURL(shell(), GetTestOpenPageURL()));
DirectSocketsServiceImpl::SetPermissionCallbackForTesting(
base::BindRepeating(&UnconditionallyPermitConnection));
// TODO(crbug.com/1119620): Use port from a listening net::UDPServerSocket.
const std::string script = base::StringPrintf(
"openUdp({remoteAddress: '127.0.0.1', remotePort: %d})", 0);
EXPECT_EQ("openUdp succeeded", EvalJs(shell(), script));
}
IN_PROC_BROWSER_TEST_F(DirectSocketsOpenBrowserTest,
OpenUdp_TransientActivation) {
EXPECT_TRUE(NavigateToURL(shell(), GetTestOpenPageURL()));
base::HistogramTester histogram_tester;
histogram_tester.ExpectBucketCount(
kPermissionDeniedHistogramName,
DirectSocketsServiceImpl::FailureType::kTransientActivation, 0);
const std::string script = base::StringPrintf(
"openUdp({remoteAddress: '127.0.0.1', remotePort: %d});\
openUdp({remoteAddress: '127.0.0.1', remotePort: %d})",
0, 0);
EXPECT_EQ("openUdp failed: NotAllowedError: Permission denied",
EvalJs(shell(), script));
histogram_tester.ExpectBucketCount(
kPermissionDeniedHistogramName,
DirectSocketsServiceImpl::FailureType::kTransientActivation, 1);
}
IN_PROC_BROWSER_TEST_F(DirectSocketsOpenBrowserTest, OpenUdp_NotAllowedError) {
EXPECT_TRUE(NavigateToURL(shell(), GetTestOpenPageURL()));
// TODO(crbug.com/1119620): Use port from a listening net::UDPServerSocket.
const std::string script = base::StringPrintf(
"openUdp({remoteAddress: '127.0.0.1', remotePort: %d})", 0);
EXPECT_EQ("openUdp failed: NotAllowedError: Permission denied",
EvalJs(shell(), script));
}
IN_PROC_BROWSER_TEST_F(DirectSocketsOpenBrowserTest, OpenUdp_CannotEvadeCors) {
EXPECT_TRUE(NavigateToURL(shell(), GetTestOpenPageURL()));
base::HistogramTester histogram_tester;
histogram_tester.ExpectBucketCount(
kPermissionDeniedHistogramName,
DirectSocketsServiceImpl::FailureType::kCORS, 0);
// QUIC uses port 443.
const std::string script =
"openUdp({remoteAddress: '127.0.0.1', remotePort: 443})";
EXPECT_EQ("openUdp failed: NotAllowedError: Permission denied",
EvalJs(shell(), script));
histogram_tester.ExpectBucketCount(
kPermissionDeniedHistogramName,
DirectSocketsServiceImpl::FailureType::kCORS, 1);
}
IN_PROC_BROWSER_TEST_F(DirectSocketsOpenBrowserTest,
OpenUdp_RestrictedByEnterprisePolicies) {
EXPECT_TRUE(NavigateToURL(shell(), GetTestOpenPageURL()));
base::HistogramTester histogram_tester;
histogram_tester.ExpectBucketCount(
kPermissionDeniedHistogramName,
DirectSocketsServiceImpl::FailureType::kEnterprisePolicy, 0);
DirectSocketsServiceImpl::SetEnterpriseManagedForTesting(true);
const std::string script =
"openUdp({remoteAddress: '127.0.0.1', remotePort: 993})";
EXPECT_EQ("openUdp failed: NotAllowedError: Permission denied",
EvalJs(shell(), script));
histogram_tester.ExpectBucketCount(
kPermissionDeniedHistogramName,
DirectSocketsServiceImpl::FailureType::kEnterprisePolicy, 1);
}
IN_PROC_BROWSER_TEST_F(DirectSocketsOpenBrowserTest,
OpenUdp_CannotConnectNonPublic) {
const auto protocol = DirectSocketsServiceImpl::ProtocolType::kUdp;
// Tests for the reserved IPv4 ranges. The reserved ranges are tested by
// checking the first and last address of each range. These tests cover the
// entire IPv4 address range, as well as this range mapped to IPv6.
for (const auto& test : kIPv4_tests) {
IPRoutableTest(test, protocol);
// Check these IPv4 addresses when mapped to IPv6.
net::IPAddress address;
EXPECT_TRUE(address.AssignFromIPLiteral(test));
net::IPAddress mapped_address = net::ConvertIPv4ToIPv4MappedIPv6(address);
IPRoutableTest(base::StrCat({"[", mapped_address.ToString(), "]"}),
protocol);
}
// Tests for the reserved IPv6 ranges. The reserved ranges are tested by
// checking the first and last address of each range. These tests cover the
// entire IPv6 address range.
for (const auto& test : kIPv6_tests)
IPRoutableTest(base::StrCat({"[", test, "]"}), protocol);
}
} // namespace content