Skip to content

Commit

Permalink
Merge pull request #594 from h2o/kazuho/no-migration-during-handshake
Browse files Browse the repository at this point in the history
avoid entering hot loop when a packet is received from a different address during handshake
  • Loading branch information
kazuho authored Dec 20, 2024
2 parents be78a16 + a3cd527 commit 39b847b
Show file tree
Hide file tree
Showing 2 changed files with 91 additions and 0 deletions.
5 changes: 5 additions & 0 deletions lib/quicly.c
Original file line number Diff line number Diff line change
Expand Up @@ -7031,6 +7031,11 @@ int quicly_receive(quicly_conn_t *conn, struct sockaddr *dest_addr, struct socka
for (path_index = 0; path_index < PTLS_ELEMENTSOF(conn->paths); ++path_index)
if (conn->paths[path_index] != NULL && compare_socket_address(src_addr, &conn->paths[path_index]->address.remote.sa) == 0)
break;
if (path_index != 0 && !quicly_is_client(conn) &&
(QUICLY_PACKET_IS_LONG_HEADER(packet->octets.base[0]) || !conn->super.remote.address_validation.validated)) {
ret = QUICLY_ERROR_PACKET_IGNORED;
goto Exit;
}
if (path_index == PTLS_ELEMENTSOF(conn->paths) &&
conn->super.stats.num_paths.validation_failed >= conn->super.ctx->max_path_validation_failures) {
ret = QUICLY_ERROR_PACKET_IGNORED;
Expand Down
86 changes: 86 additions & 0 deletions t/test.c
Original file line number Diff line number Diff line change
Expand Up @@ -740,6 +740,90 @@ static void test_jumpstart_cwnd(void)
ok(derive_jumpstart_cwnd(&bounded_max, 250, 1000000, 250) == 80000);
}

static void do_test_migration_during_handshake(int second_flight_from_orig_address)
{
quicly_conn_t *client, *server;
const struct sockaddr_in serveraddr = {.sin_family = AF_INET, .sin_addr.s_addr = htonl(0x7f000001), .sin_port = htons(12345)},
clientaddr1 = {.sin_family = AF_INET, .sin_addr.s_addr = htonl(0x7f000002), .sin_port = htons(12345)},
clientaddr2 = {.sin_family = AF_INET, .sin_addr.s_addr = htonl(0x7f000003), .sin_port = htons(12345)};
quicly_address_t destaddr, srcaddr;
struct iovec datagrams[10];
uint8_t buf[quic_ctx.transport_params.max_udp_payload_size * 10];
quicly_decoded_packet_t packets[40];
size_t num_datagrams, num_packets;
int ret;

/* client send first flight */
ret = quicly_connect(&client, &quic_ctx, "example.com", (void *)&serveraddr, NULL, new_master_id(), ptls_iovec_init(NULL, 0),
NULL, NULL, NULL);
ok(ret == 0);
num_datagrams = 10;
ret = quicly_send(client, &destaddr, &srcaddr, datagrams, &num_datagrams, buf, sizeof(buf));
ok(ret == 0);
ok(num_datagrams > 0);

/* server accepts and responds, but the packets are dropped */
num_packets = decode_packets(packets, datagrams, num_datagrams);
ok(num_packets == 1);
ret = quicly_accept(&server, &quic_ctx, &destaddr.sa, (void *)&clientaddr1, packets, NULL, new_master_id(), NULL, NULL);
ok(ret == 0);
num_datagrams = 10;
ret = quicly_send(server, &destaddr, &srcaddr, datagrams, &num_datagrams, buf, sizeof(buf));
ok(ret == 0);
ok(num_datagrams > 0);

/* loop until timeout */
const struct sockaddr_in *clientaddr = second_flight_from_orig_address ? &clientaddr1 : &clientaddr2;
while (1) {
int64_t client_timeout = quicly_get_first_timeout(client), server_timeout = quicly_get_first_timeout(server),
smaller_timeout = client_timeout < server_timeout ? client_timeout : server_timeout;
if (quic_now < smaller_timeout)
quic_now = smaller_timeout;

/* when client times out, it resends Initials but from a different address and the server drops them */
if (quic_now >= client_timeout) {
num_datagrams = 10;
ret = quicly_send(client, &destaddr, &srcaddr, datagrams, &num_datagrams, buf, sizeof(buf));
if (ret == QUICLY_ERROR_FREE_CONNECTION)
break;
ok(ret == 0);
ok(num_datagrams > 0);
num_packets = decode_packets(packets, datagrams, num_datagrams);
ok(num_packets > 0);
for (size_t i = 0; i < num_packets; ++i) {
ret = quicly_receive(server, (void *)&serveraddr, (void *)clientaddr, &packets[i]);
if (clientaddr == &clientaddr1) {
ok(ret == 0);
} else {
ok(ret == QUICLY_ERROR_PACKET_IGNORED);
}
}
clientaddr = &clientaddr2;
}

/* when server times out it resends packets to the old client address */
if (quic_now >= server_timeout) {
num_datagrams = 10;
ret = quicly_send(server, &destaddr, &srcaddr, datagrams, &num_datagrams, buf, sizeof(buf));
if (ret == QUICLY_ERROR_FREE_CONNECTION)
break;
ok(ret == 0);
ok(num_datagrams > 0);
ok(destaddr.sin.sin_family == AF_INET);
ok(destaddr.sin.sin_addr.s_addr == clientaddr1.sin_addr.s_addr);
}
}

quicly_free(client);
quicly_free(server);
}

static void test_migration_during_handshake(void)
{
subtest("migrate-before-2nd", do_test_migration_during_handshake, 0);
subtest("migrate-before-3nd", do_test_migration_during_handshake, 1);
}

int main(int argc, char **argv)
{
static ptls_iovec_t cert;
Expand Down Expand Up @@ -812,5 +896,7 @@ int main(int argc, char **argv)
subtest("jumpstart-cwnd", test_jumpstart_cwnd);
subtest("jumpstart", test_jumpstart);

subtest("migration-during-handshake", test_migration_during_handshake);

return done_testing();
}

0 comments on commit 39b847b

Please sign in to comment.