Allow mixed QUIC/HTTPS proxy chains
The implementation of QUIC proxies allows mixed chains, as long as all of the SCHEME_QUIC servers come before all of the SCHEME_HTTPS servers. In practice, IP protection won't use such mixed chains, but to facilitate testing the new functionality this CL allows such chains to be constructed. Bug: 324462739 Change-Id: I506b4bd9cdc3d46aa1cf79286184fb1c7c611183 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5373589 Reviewed-by: mmenke <mmenke@chromium.org> Commit-Queue: Dustin Mitchell <djmitche@chromium.org> Cr-Commit-Position: refs/heads/main@{#1274919}
This commit is contained in:

committed by
Chromium LUCI CQ

parent
9885c50b61
commit
ca1a34d703
@@ -106,6 +106,9 @@ bool ProxyChain::IsValidInternal() const {
|
|||||||
if (!proxy_server_list_.has_value()) {
|
if (!proxy_server_list_.has_value()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (is_direct()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
if (is_single_proxy()) {
|
if (is_single_proxy()) {
|
||||||
bool is_valid = proxy_server_list_.value().at(0).is_valid();
|
bool is_valid = proxy_server_list_.value().at(0).is_valid();
|
||||||
if (proxy_server_list_.value().at(0).is_quic()) {
|
if (proxy_server_list_.value().at(0).is_quic()) {
|
||||||
@@ -113,15 +116,28 @@ bool ProxyChain::IsValidInternal() const {
|
|||||||
}
|
}
|
||||||
return is_valid;
|
return is_valid;
|
||||||
}
|
}
|
||||||
bool all_https = base::ranges::all_of(
|
DCHECK(is_multi_proxy());
|
||||||
proxy_server_list_.value(), [](const auto& proxy_server) {
|
|
||||||
return proxy_server.is_valid() && proxy_server.is_https();
|
// Verify that the chain is zero or more SCHEME_QUIC servers followed by zero
|
||||||
});
|
// or more SCHEME_HTTPS servers.
|
||||||
bool all_quic = base::ranges::all_of(
|
bool seen_quic = false;
|
||||||
proxy_server_list_.value(), [](const auto& proxy_server) {
|
bool seen_https = false;
|
||||||
return proxy_server.is_valid() && proxy_server.is_quic();
|
for (const auto& proxy_server : proxy_server_list_.value()) {
|
||||||
});
|
if (proxy_server.is_quic()) {
|
||||||
return all_https || (all_quic && is_for_ip_protection());
|
if (seen_https) {
|
||||||
|
// SCHEME_QUIC cannot follow SCHEME_HTTPS.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
seen_quic = true;
|
||||||
|
} else if (proxy_server.is_https()) {
|
||||||
|
seen_https = true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// QUIC is only allowed for IP protection.
|
||||||
|
return !seen_quic || is_for_ip_protection();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::ostream& operator<<(std::ostream& os, const ProxyChain& proxy_chain) {
|
std::ostream& operator<<(std::ostream& os, const ProxyChain& proxy_chain) {
|
||||||
|
@@ -67,7 +67,7 @@ class NET_EXPORT ProxyChain {
|
|||||||
static ProxyChain Direct() { return ProxyChain(std::vector<ProxyServer>()); }
|
static ProxyChain Direct() { return ProxyChain(std::vector<ProxyServer>()); }
|
||||||
|
|
||||||
// Creates a `ProxyChain` for use by the IP Protection feature. This is used
|
// Creates a `ProxyChain` for use by the IP Protection feature. This is used
|
||||||
// for metrics collection and for special handling. If not give, the
|
// for metrics collection and for special handling. If not given, the
|
||||||
// chain_id defaults to 0 which corresponds to an un-identified chain.
|
// chain_id defaults to 0 which corresponds to an un-identified chain.
|
||||||
static ProxyChain ForIpProtection(std::vector<ProxyServer> proxy_server_list,
|
static ProxyChain ForIpProtection(std::vector<ProxyServer> proxy_server_list,
|
||||||
int chain_id = 0) {
|
int chain_id = 0) {
|
||||||
@@ -179,11 +179,12 @@ class NET_EXPORT ProxyChain {
|
|||||||
// A negative value indicates this chain is not used for IP protection.
|
// A negative value indicates this chain is not used for IP protection.
|
||||||
int ip_protection_chain_id_ = kNotIpProtectionChainId;
|
int ip_protection_chain_id_ = kNotIpProtectionChainId;
|
||||||
|
|
||||||
// Returns true if this chain is valid. A chain is considered valid if (1) is
|
// Returns true if this chain is valid. A chain is considered valid if
|
||||||
// a single valid proxy server. If single QUIC proxy, it must
|
// (1) it is a single valid proxy server, or
|
||||||
// also be an IP protection proxy chain. (2) is multi-proxy and
|
// (2) it is a chain of servers, composed of zero or more SCHEME_QUIC servers
|
||||||
// all servers are either HTTPS or QUIC. If QUIC servers, it must also
|
// followed by zero or more SCHEME_HTTPS servers.
|
||||||
// be an IP protection proxy chain.
|
// If any SCHEME_QUIC servers are included, then the chain must be for IP
|
||||||
|
// protection.
|
||||||
bool IsValidInternal() const;
|
bool IsValidInternal() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -8,6 +8,7 @@
|
|||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
#include "base/strings/string_number_conversions.h"
|
#include "base/strings/string_number_conversions.h"
|
||||||
|
#include "base/test/gtest_util.h"
|
||||||
#include "net/base/proxy_server.h"
|
#include "net/base/proxy_server.h"
|
||||||
#include "net/base/proxy_string_util.h"
|
#include "net/base/proxy_string_util.h"
|
||||||
#include "testing/gtest/include/gtest/gtest.h"
|
#include "testing/gtest/include/gtest/gtest.h"
|
||||||
@@ -367,25 +368,43 @@ TEST(ProxyChainTest, IsGetToProxyAllowed) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST(ProxyChainTest, IsValid) {
|
TEST(ProxyChainTest, IsValid) {
|
||||||
auto direct_chain = ProxyChain::Direct();
|
|
||||||
|
|
||||||
// Single hop proxy of type Direct is valid.
|
// Single hop proxy of type Direct is valid.
|
||||||
EXPECT_TRUE(direct_chain.IsValid());
|
EXPECT_TRUE(ProxyChain::Direct().IsValid());
|
||||||
|
|
||||||
auto http_proxy1 =
|
auto https1 = ProxyUriToProxyServer("foo:444", ProxyServer::SCHEME_HTTPS);
|
||||||
ProxyUriToProxyServer("foo:444", ProxyServer::SCHEME_HTTPS);
|
auto https2 = ProxyUriToProxyServer("foo:555", ProxyServer::SCHEME_HTTPS);
|
||||||
auto http_proxy2 =
|
auto quic1 = ProxyUriToProxyServer("foo:666", ProxyServer::SCHEME_QUIC);
|
||||||
ProxyUriToProxyServer("foo:555", ProxyServer::SCHEME_HTTPS);
|
auto quic2 = ProxyUriToProxyServer("foo:777", ProxyServer::SCHEME_QUIC);
|
||||||
|
auto socks = ProxyUriToProxyServer("foo:777", ProxyServer::SCHEME_SOCKS5);
|
||||||
|
|
||||||
// Multi hop proxy with HTTPs type is valid.
|
EXPECT_TRUE(ProxyChain({https1}).IsValid());
|
||||||
EXPECT_TRUE(ProxyChain({http_proxy1, http_proxy2}).IsValid());
|
EXPECT_FALSE(ProxyChain({quic1}).IsValid());
|
||||||
|
EXPECT_TRUE(ProxyChain({https1, https2}).IsValid());
|
||||||
|
EXPECT_FALSE(ProxyChain({quic1, https1}).IsValid());
|
||||||
|
EXPECT_FALSE(ProxyChain({quic1, quic2, https1, https2}).IsValid());
|
||||||
|
EXPECT_FALSE(ProxyChain({https1, quic2}).IsValid());
|
||||||
|
EXPECT_FALSE(ProxyChain({https1, https2, quic1, quic2}).IsValid());
|
||||||
|
EXPECT_FALSE(ProxyChain({socks, https1}).IsValid());
|
||||||
|
EXPECT_FALSE(ProxyChain({socks, https1, https2}).IsValid());
|
||||||
|
EXPECT_FALSE(ProxyChain({https1, socks}).IsValid());
|
||||||
|
EXPECT_FALSE(ProxyChain({https1, https2, socks}).IsValid());
|
||||||
|
|
||||||
auto quic_proxy1 = ProxyUriToProxyServer("foo:666", ProxyServer::SCHEME_QUIC);
|
// IP protection accepts chains with SCHEME_QUIC, but CHECKs on failure
|
||||||
auto quic_proxy2 = ProxyUriToProxyServer("foo:777", ProxyServer::SCHEME_QUIC);
|
// instead of just creating an invalid chain.
|
||||||
auto ip_protection_quic_proxy_chain =
|
auto IppChain = [](std::vector<ProxyServer> proxy_servers) {
|
||||||
ProxyChain::ForIpProtection({quic_proxy1, quic_proxy2});
|
return ProxyChain::ForIpProtection(std::move(proxy_servers));
|
||||||
// Multi hop proxy with QUIC and IP Protection is valid.
|
};
|
||||||
EXPECT_TRUE(ip_protection_quic_proxy_chain.IsValid());
|
EXPECT_TRUE(IppChain({https1}).IsValid());
|
||||||
|
EXPECT_TRUE(IppChain({quic1}).IsValid());
|
||||||
|
EXPECT_TRUE(IppChain({https1, https2}).IsValid());
|
||||||
|
EXPECT_TRUE(IppChain({quic1, https1}).IsValid());
|
||||||
|
EXPECT_TRUE(IppChain({quic1, quic2, https1, https2}).IsValid());
|
||||||
|
EXPECT_CHECK_DEATH(IppChain({https1, quic2}).IsValid());
|
||||||
|
EXPECT_CHECK_DEATH(IppChain({https1, https2, quic1, quic2}).IsValid());
|
||||||
|
EXPECT_CHECK_DEATH(IppChain({socks, https1}).IsValid());
|
||||||
|
EXPECT_CHECK_DEATH(IppChain({socks, https1, https2}).IsValid());
|
||||||
|
EXPECT_CHECK_DEATH(IppChain({https1, socks}).IsValid());
|
||||||
|
EXPECT_CHECK_DEATH(IppChain({https1, https2, socks}).IsValid());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(ProxyChainTest, Unequal) {
|
TEST(ProxyChainTest, Unequal) {
|
||||||
|
Reference in New Issue
Block a user