Commit 58c1542a authored by David Schinazi's avatar David Schinazi Committed by Commit Bot

Remove QUIC connection migration over IPv4-mapped IPv6 addresses

This feature never worked as advertised. IPv4-mapped
addresses are a host-only concept. They never appear
on the wire. For example, if I open a TCP socket to
IPv6 address ::ffff:1.2.3.4 and port 443, my device
will send out an IPv4 packet with destination
address 1.2.3.4. It will not send an IPv6 packet.
IPv4-mapped IPv6 addresses exist to allow
applications to only use IPv6 but still work on
IPv4 networks. More details here:
https://tools.ietf.org/html/rfc4038#section-4.2

R=zhongyi@chromium.org

Change-Id: I4e9f349c1753aaab19dbaf040fa5d40a6a1740d6
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2204826
Commit-Queue: David Schinazi <dschinazi@chromium.org>
Reviewed-by: default avatarZhongyi Shi <zhongyi@chromium.org>
Auto-Submit: David Schinazi <dschinazi@chromium.org>
Cr-Commit-Position: refs/heads/master@{#770778}
parent 6d7df0f9
...@@ -1537,29 +1537,19 @@ void QuicChromiumClientSession::OnConfigNegotiated() { ...@@ -1537,29 +1537,19 @@ void QuicChromiumClientSession::OnConfigNegotiated() {
IPEndPoint old_address; IPEndPoint old_address;
GetDefaultSocket()->GetPeerAddress(&old_address); GetDefaultSocket()->GetPeerAddress(&old_address);
// Migrate only if address families match, or if new address family is v6, // Migrate only if address families match.
// since a v4 address should be reachable over a v6 network (using a
// v4-mapped v6 address).
IPEndPoint new_address; IPEndPoint new_address;
if (old_address.GetFamily() == ADDRESS_FAMILY_IPV6) { if (old_address.GetFamily() == ADDRESS_FAMILY_IPV6) {
if (config()->HasReceivedIPv6AlternateServerAddress()) { if (!config()->HasReceivedIPv6AlternateServerAddress()) {
return;
}
new_address = new_address =
ToIPEndPoint(config()->ReceivedIPv6AlternateServerAddress()); ToIPEndPoint(config()->ReceivedIPv6AlternateServerAddress());
} else {
new_address =
ToIPEndPoint(config()->ReceivedIPv4AlternateServerAddress());
// Use a v4-mapped v6 address.
new_address =
IPEndPoint(ConvertIPv4ToIPv4MappedIPv6(new_address.address()),
new_address.port());
}
} else if (old_address.GetFamily() == ADDRESS_FAMILY_IPV4) { } else if (old_address.GetFamily() == ADDRESS_FAMILY_IPV4) {
if (config()->HasReceivedIPv4AlternateServerAddress()) { if (!config()->HasReceivedIPv4AlternateServerAddress()) {
new_address =
ToIPEndPoint(config()->ReceivedIPv4AlternateServerAddress());
} else {
return; return;
} }
new_address = ToIPEndPoint(config()->ReceivedIPv4AlternateServerAddress());
} }
DCHECK_EQ(new_address.GetFamily(), old_address.GetFamily()); DCHECK_EQ(new_address.GetFamily(), old_address.GetFamily());
......
...@@ -10189,7 +10189,10 @@ TEST_P(QuicStreamFactoryTest, ServerMigrationIPv6ToIPv6) { ...@@ -10189,7 +10189,10 @@ TEST_P(QuicStreamFactoryTest, ServerMigrationIPv6ToIPv6) {
VerifyServerMigration(config, alt_address); VerifyServerMigration(config, alt_address);
} }
TEST_P(QuicStreamFactoryTest, ServerMigrationIPv6ToIPv4) { TEST_P(QuicStreamFactoryTest, ServerMigrationIPv6ToIPv4Fails) {
quic_params_->allow_server_migration = true;
Initialize();
// Add a resolver rule to make initial connection to an IPv6 address. // Add a resolver rule to make initial connection to an IPv6 address.
host_resolver_->rules()->AddIPLiteralRule(host_port_pair_.host(), host_resolver_->rules()->AddIPLiteralRule(host_port_pair_.host(),
"fe80::aebc:32ff:febb:1e33", ""); "fe80::aebc:32ff:febb:1e33", "");
...@@ -10197,9 +10200,75 @@ TEST_P(QuicStreamFactoryTest, ServerMigrationIPv6ToIPv4) { ...@@ -10197,9 +10200,75 @@ TEST_P(QuicStreamFactoryTest, ServerMigrationIPv6ToIPv4) {
IPEndPoint alt_address = IPEndPoint(IPAddress(1, 2, 3, 4), 123); IPEndPoint alt_address = IPEndPoint(IPAddress(1, 2, 3, 4), 123);
quic::QuicConfig config; quic::QuicConfig config;
config.SetIPv4AlternateServerAddressToSend(ToQuicSocketAddress(alt_address)); config.SetIPv4AlternateServerAddressToSend(ToQuicSocketAddress(alt_address));
IPEndPoint expected_address(
ConvertIPv4ToIPv4MappedIPv6(alt_address.address()), alt_address.port()); ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
VerifyServerMigration(config, expected_address); crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
crypto_client_stream_factory_.SetConfig(config);
// Set up only socket data provider.
MockQuicData socket_data1(version_);
socket_data1.AddRead(SYNCHRONOUS, ERR_IO_PENDING);
int packet_num = 1;
if (VersionUsesHttp3(version_.transport_version)) {
socket_data1.AddWrite(SYNCHRONOUS,
ConstructInitialSettingsPacket(packet_num++));
socket_data1.AddWrite(
SYNCHRONOUS, client_maker_.MakeDataPacket(
packet_num++, GetQpackDecoderStreamId(), true, false,
StreamCancellationQpackDecoderInstruction(0)));
}
socket_data1.AddWrite(
SYNCHRONOUS,
client_maker_.MakeRstPacket(packet_num++, true,
GetNthClientInitiatedBidirectionalStreamId(0),
quic::QUIC_STREAM_CANCELLED));
socket_data1.AddSocketDataToFactory(socket_factory_.get());
// Create request and QuicHttpStream.
QuicStreamRequest request(factory_.get());
EXPECT_EQ(
ERR_IO_PENDING,
request.Request(
host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY,
SocketTag(), NetworkIsolationKey(), false /* disable_secure_dns */,
/*cert_verify_flags=*/0, url_, net_log_, &net_error_details_,
failed_on_default_network_callback_, callback_.callback()));
EXPECT_EQ(OK, callback_.WaitForResult());
std::unique_ptr<HttpStream> stream = CreateStream(&request);
EXPECT_TRUE(stream.get());
// Cause QUIC stream to be created.
HttpRequestInfo request_info;
request_info.method = "GET";
request_info.url = GURL("https://www.example.org/");
request_info.traffic_annotation =
MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
EXPECT_EQ(OK, stream->InitializeStream(&request_info, true, DEFAULT_PRIORITY,
net_log_, CompletionOnceCallback()));
// Ensure that session is alive and active.
QuicChromiumClientSession* session = GetActiveSession(host_port_pair_);
EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
EXPECT_TRUE(HasActiveSession(host_port_pair_));
IPEndPoint actual_address;
session->GetDefaultSocket()->GetPeerAddress(&actual_address);
// No migration should have happened.
IPEndPoint expected_address =
IPEndPoint(IPAddress(0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0xae, 0xbc, 0x32, 0xff,
0xfe, 0xbb, 0x1e, 0x33),
kDefaultServerPort);
EXPECT_EQ(actual_address, expected_address);
DVLOG(1) << "Socket connected to: " << actual_address.address().ToString()
<< " " << actual_address.port();
DVLOG(1) << "Expected address: " << expected_address.address().ToString()
<< " " << expected_address.port();
stream.reset();
EXPECT_TRUE(socket_data1.AllReadDataConsumed());
EXPECT_TRUE(socket_data1.AllWriteDataConsumed());
} }
TEST_P(QuicStreamFactoryTest, ServerMigrationIPv4ToIPv6Fails) { TEST_P(QuicStreamFactoryTest, ServerMigrationIPv4ToIPv6Fails) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment