Skip to content

Commit

Permalink
tests: update func alpn and interop tests for path migration
Browse files Browse the repository at this point in the history
Improve alpn_test to support the path migration IPv4 -> IPv6,
IPv6 -> IPv4, IPv4->IPv4 and IPv6 -> IPv6 tests.

Add IOP_CONNECTIONMIGRATION testcase for interop tests.

Path migration doesn't affect the source active connection ID,
so fix the check in func_test accordingly.

Signed-off-by: Xin Long <lucien.xin@gmail.com>
  • Loading branch information
lxin committed Jan 28, 2025
1 parent f968619 commit 03b61ff
Show file tree
Hide file tree
Showing 5 changed files with 143 additions and 54 deletions.
78 changes: 57 additions & 21 deletions tests/alpn_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,27 @@ static void set_port(struct sockaddr_storage *sas, unsigned short port)
((struct sockaddr_in6 *)sas)->sin6_port = htons(port);
}

static int do_client_alpn(char *ip, int port, char *alpn, int preferred_port)
static void print_address(char *info, struct sockaddr_storage *sas)
{
struct sockaddr_storage sa = {};
struct sockaddr_in6 *sain6 = (struct sockaddr_in6 *)sas;
struct sockaddr_in *sain = (struct sockaddr_in *)sas;
char ip_str[INET6_ADDRSTRLEN];
int port;

if (sas->ss_family == AF_INET) {
inet_ntop(AF_INET, &(sain->sin_addr), ip_str, INET_ADDRSTRLEN);
port = ntohs(sain->sin_port);
printf("%s: %s:%d\n", info, ip_str, port);
return;
}
inet_ntop(AF_INET6, &(sain6->sin6_addr), ip_str, INET6_ADDRSTRLEN);
port = ntohs(sain6->sin6_port);
printf("%s: %s:%d\n", info, ip_str, port);
}

static int do_client_alpn(char *ip, int port, char *alpn, char *preferred_addr, int preferred_port)
{
struct sockaddr_storage sa = {}, pa = {};
char port_string[16];
unsigned int len;
int ret, sockfd;
Expand All @@ -58,7 +76,14 @@ static int do_client_alpn(char *ip, int port, char *alpn, int preferred_port)
return -1;
}

sockfd = socket(sa.ss_family, SOCK_DGRAM, IPPROTO_QUIC);
sprintf(port_string, "%d", preferred_port);
rc = parse_address(preferred_addr, port_string, &pa);
if (rc != NULL) {
printf("parse address failed: %s\n", rc);
return -1;
}

sockfd = socket(AF_INET6, SOCK_DGRAM, IPPROTO_QUIC);
if (sockfd < 0) {
printf("socket create failed\n");
return -1;
Expand Down Expand Up @@ -89,15 +114,16 @@ static int do_client_alpn(char *ip, int port, char *alpn, int preferred_port)
printf("recv: \"%s\", len: %d\n", msg, ret);

sleep(1);
memset(&sa, 0, sizeof(sa));
len = sizeof(sa);
ret = getpeername(sockfd, (struct sockaddr *)&sa, &len);
if (ret == -1) {
printf("socket getpeername error %d\n", errno);
return -1;
}
printf("PEER PORT: %d\n", get_port(&sa));
if (get_port(&sa) != preferred_port) {
printf("preferred port: %d\n", preferred_port);
print_address("PEER IP:PORT", &sa);
if (memcmp(&sa, &pa, sizeof(sa))) {
print_address("EXPECTED IP:PORT", &pa);
return -1;
}

Expand All @@ -108,21 +134,22 @@ static int do_client_alpn(char *ip, int port, char *alpn, int preferred_port)

static int do_client(int argc, char *argv[])
{
char *ip;
char *ip, *pref;
int port;

if (argc < 3) {
printf("%s client <PEER ADDR> <PEER PORT>\n", argv[0]);
printf("%s client <PEER ADDR> <PEER PORT> [PREF ADDR]\n", argv[0]);
return 0;
}

port = atoi(argv[3]);
ip = argv[2];
if (do_client_alpn(ip, port, "smbd", port + 1))
pref = argv[4];
port = atoi(argv[3]);
if (do_client_alpn(ip, port, "smbd", pref, port + 1))
return -1;
if (do_client_alpn(ip, port, "h3", port + 2))
if (do_client_alpn(ip, port, "h3", pref, port + 2))
return -1;
if (do_client_alpn(ip, port, "ksmbd", port + 3))
if (do_client_alpn(ip, port, "ksmbd", pref, port + 3))
return -1;

return 0;
Expand Down Expand Up @@ -180,17 +207,17 @@ static int server_handshake(int sockfd, const char *pkey, const char *cert,

static int do_server(int argc, char *argv[])
{
struct sockaddr_storage sa = {}, pa = {};
char alpns[20] = "smbd, h3, ksmbd";
int listenfd, sockfd, ret, i = 0;
struct sockaddr_storage sa = {};
unsigned int addrlen, len;
int preferred_port;
char msg[50] = {};
char const *rc;

if (argc < 5) {
printf("%s server <LOCAL ADDR> <LOCAL PORT> <PRIVATE_KEY_FILE> "
"<CERTIFICATE_FILE>\n", argv[0]);
"<CERTIFICATE_FILE> [PREF ADDR]\n", argv[0]);
return 0;
}

Expand All @@ -200,7 +227,7 @@ static int do_server(int argc, char *argv[])
return -1;
}

listenfd = socket(sa.ss_family, SOCK_DGRAM, IPPROTO_QUIC);
listenfd = socket(AF_INET6, SOCK_DGRAM, IPPROTO_QUIC);
if (listenfd < 0) {
printf("socket create failed\n");
return -1;
Expand Down Expand Up @@ -239,8 +266,16 @@ static int do_server(int argc, char *argv[])
return -1;
}
preferred_port = get_port(&sa) + i;
set_port(&sa, preferred_port); /* you can also change addr */
ret = setsockopt(sockfd, SOL_QUIC, QUIC_SOCKOPT_CONNECTION_MIGRATION, &sa, addrlen);
if (argv[6]) {
rc = parse_address(argv[6], "0", &pa);
if (rc != NULL) {
printf("parse address failed: %s\n", rc);
return -1;
}
addrlen = sizeof(pa);
}
set_port(&pa, preferred_port); /* you can also change addr */
ret = setsockopt(sockfd, SOL_QUIC, QUIC_SOCKOPT_CONNECTION_MIGRATION, &pa, addrlen);
if (ret == -1) {
printf("socket setsockopt migration error %d\n", errno);
return -1;
Expand Down Expand Up @@ -269,15 +304,16 @@ static int do_server(int argc, char *argv[])
printf("send %d\n", ret);

sleep(1);
memset(&sa, 0, sizeof(sa));
ret = getsockname(sockfd, (struct sockaddr *)&sa, &addrlen);
if (ret == -1) {
printf("socket getsockname error %d\n", errno);
return -1;
}
printf("LOCAL PORT %d\n", get_port(&sa));
if (preferred_port != get_port(&sa)) {
printf("preferred port: %d\n", preferred_port);
//return -1;
print_address("LOCAL IP:PORT: ", &sa);
if (memcmp(&sa, &pa, sizeof(sa))) {
print_address("EXPECTED IP:PORT: ", &pa);
return -1;
}

recv(sockfd, msg, sizeof(msg), 0);
Expand Down
11 changes: 2 additions & 9 deletions tests/func_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -1076,16 +1076,9 @@ static int do_client_connection_test(int sockfd)
}
printf("test15: PASS (connection migration is done)\n");

optlen = sizeof(info);
info.dest = 0;
ret = getsockopt(sockfd, SOL_QUIC, QUIC_SOCKOPT_CONNECTION_ID, &info, &optlen);
if (ret == -1 || info.active != 12) {
printf("teset16: FAIL ret %d, source %u\n", ret, info.active);
return -1;
}
info.dest = 1;
ret = getsockopt(sockfd, SOL_QUIC, QUIC_SOCKOPT_CONNECTION_ID, &info, &optlen);
if (ret == -1 || info.active != 11) {
if (ret == -1 || info.active != 12) {
printf("teset16: FAIL ret %d, dest %u\n", ret, info.active);
return -1;
}
Expand Down Expand Up @@ -1128,7 +1121,7 @@ static int do_client_connection_test(int sockfd)
optlen = sizeof(info);
info.dest = 1;
ret = getsockopt(sockfd, SOL_QUIC, QUIC_SOCKOPT_CONNECTION_ID, &info, &optlen);
if (ret == -1 || info.active != 12) {
if (ret == -1 || info.active != 13) {
printf("teset20: FAIL ret %d, dest %u, source %u\n", ret, info.dest, info.prior_to);
return -1;
}
Expand Down
4 changes: 2 additions & 2 deletions tests/interop/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ RUN cd quic && ./autogen.sh && \
install -m 644 modules/include/uapi/linux/quic.h /usr/include/linux && \
./configure --prefix=/usr && make -j$(nproc) && make install && cd ..

RUN cp quic/tests/interop/interop_test.c . && \
gcc interop_test.c -o interop_test -lnghttp3 -lquic -lgnutls && \
COPY interop_test.c interop_test.c
RUN gcc interop_test.c -o interop_test -lnghttp3 -lquic -lgnutls && \
rm -rf quic interop_test.c

COPY run_endpoint.sh .
Expand Down
63 changes: 47 additions & 16 deletions tests/interop/interop_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ static int http_log_level = LOG_INFO;
#define IOP_ZERORTT 10
#define IOP_V2 11
#define IOP_ECN 12
#define IOP_CONNECTIONMIGRATION 13

struct http_req {
char user_agent[32];
Expand Down Expand Up @@ -366,7 +367,7 @@ static int http_client_setup_socket(char *host, char *port, int testcase)
goto err_free;
}

sockfd = socket(rp->ai_family, SOCK_DGRAM, IPPROTO_QUIC);
sockfd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_QUIC);
if (sockfd < 0) {
http_log_error("socket create failed\n");
goto err_free;
Expand Down Expand Up @@ -430,7 +431,7 @@ static int http_server_setup_socket(char *host, char *port, char *alpn, int test
goto err_free;
}

listenfd = socket(rp->ai_family, SOCK_DGRAM, IPPROTO_QUIC);
listenfd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_QUIC);
if (listenfd < 0) {
http_log_error("socket create failed\n");
goto err_free;
Expand Down Expand Up @@ -548,10 +549,40 @@ static int http_server_handshake(int sockfd, const char *pkey, const char *cert,
static int http_server_accept_socket(int sockfd, const char *pkey_file, const char *cert_file,
char *alpn, int testcase)
{
struct sockaddr_storage sa = {};
char host[16], port[16];
struct addrinfo *res;
unsigned int addrlen;
unsigned int keylen;
uint8_t key[64];
int ret;

if (testcase == IOP_ZERORTT)
usleep(500000);

if (testcase == IOP_CONNECTIONMIGRATION) {
addrlen = sizeof(sa);
if (getsockname(sockfd, (struct sockaddr *)&sa, &addrlen)) {
http_log_error("socket getsockname error %d\n", errno);
return -1;
}

strcpy(host, "server4");
if (sa.ss_family == AF_INET)
strcpy(host, "server6");
sprintf(port, "%d", ntohs(((struct sockaddr_in *)&sa)->sin_port));
if (getaddrinfo(host, port, NULL, &res)) {
http_log_error("getaddrinfo error\n");
return -1;
}

if (setsockopt(sockfd, SOL_QUIC, QUIC_SOCKOPT_CONNECTION_MIGRATION,
res->ai_addr, res->ai_addrlen)) {
http_log_error("socket setsockopt migration error %d\n", errno);
return -1;
}
}

keylen = sizeof(key);
if (getsockopt(sockfd, SOL_QUIC, QUIC_SOCKOPT_SESSION_TICKET, key, &keylen)) {
http_log_error("socket getsockopt session ticket error %d", errno);
Expand Down Expand Up @@ -1604,6 +1635,7 @@ static int http09_client(char *urls, const char *sess_file, const char *tp_file,
if (http09_run_loop(ctx))
ret = -errno;
free:
sleep(1);
close(sockfd);
out:
free(ctx);
Expand All @@ -1615,9 +1647,6 @@ static void *http09_process(void *arg)
struct http_ctx *ctx = arg;
long ret;

if (ctx->testcase == IOP_ZERORTT)
usleep(500000);

ret = http_server_accept_socket(ctx->sockfd, ctx->pkey_file, ctx->cert_file,
"hq-interop", ctx->testcase);
if (ret < 0) {
Expand Down Expand Up @@ -1701,30 +1730,32 @@ static int iop_get_testcase(char *testcase)
{
if (!testcase)
return 0;
if(!strcmp(testcase, "chacha20"))
if (!strcmp(testcase, "chacha20"))
return IOP_CHACHA20;
if(!strcmp(testcase, "handshake"))
if (!strcmp(testcase, "handshake"))
return IOP_HANDSHAKE;
if(!strcmp(testcase, "http3"))
if (!strcmp(testcase, "http3"))
return IOP_HTTP3;
if(!strcmp(testcase, "keyupdate"))
if (!strcmp(testcase, "keyupdate"))
return IOP_KEYUPDATE;
if(!strcmp(testcase, "multiconnect"))
if (!strcmp(testcase, "multiconnect"))
return IOP_MULTICONNECT;
if(!strcmp(testcase, "resumption"))
if (!strcmp(testcase, "resumption"))
return IOP_RESUMPTION;
if(!strcmp(testcase, "retry"))
if (!strcmp(testcase, "retry"))
return IOP_RETRY;
if(!strcmp(testcase, "transfer"))
if (!strcmp(testcase, "transfer"))
return IOP_TRANSFER;
if (!strcmp(testcase, "versionnegotiation"))
return IOP_VERSIONNEGOTIATION;
if(!strcmp(testcase, "zerortt"))
if (!strcmp(testcase, "zerortt"))
return IOP_ZERORTT;
if(!strcmp(testcase, "v2"))
if (!strcmp(testcase, "v2"))
return IOP_V2;
if(!strcmp(testcase, "ecn"))
if (!strcmp(testcase, "ecn"))
return IOP_ECN;
if (!strcmp(testcase, "connectionmigration"))
return IOP_CONNECTIONMIGRATION;
return 0;
}

Expand Down
41 changes: 35 additions & 6 deletions tests/runtest.sh
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ daemon_run()
cleanup()
{
exit_code=$?
ip -6 addr del ::2/128 dev lo > /dev/null 2>&1
ip addr del 127.0.0.2/8 dev lo > /dev/null 2>&1
tc qdisc del dev lo root netem loss 30% > /dev/null 2>&1
pkill func_test > /dev/null 2>&1
pkill perf_test > /dev/null 2>&1
Expand Down Expand Up @@ -235,25 +237,52 @@ tlshd_tests()
daemon_stop "ticket_test"
}

sample_tests()
alpn_tests()
{
print_start "ALPN and Preferred Address Tests (IPv4 -> IPv6)"
daemon_run ./alpn_test server 0.0.0.0 1234 ./keys/server-key.pem ./keys/server-cert.pem ::1
./alpn_test client 127.0.0.1 1234 ::1 || return 1
daemon_stop "alpn_test"

print_start "ALPN and Preferred Address Tests (IPv6 -> IPv4)"
daemon_run ./alpn_test server :: 1234 ./keys/server-key.pem ./keys/server-cert.pem 127.0.0.1
./alpn_test client ::1 1234 127.0.0.1 || return 1
daemon_stop "alpn_test"

print_start "ALPN and Preferred Address Tests (IPv4 -> IPv4)"
ip addr add 127.0.0.2/8 dev lo
daemon_run ./alpn_test server 0.0.0.0 1234 ./keys/server-key.pem ./keys/server-cert.pem \
127.0.0.2
./alpn_test client 127.0.0.1 1234 127.0.0.2 || return 1
ip addr del 127.0.0.2/8 dev lo
daemon_stop "alpn_test"

print_start "ALPN and Preferred Address Tests (IPv6 -> IPv6)"
ip -6 addr add ::2/128 dev lo
daemon_run ./alpn_test server :: 1234 ./keys/server-key.pem ./keys/server-cert.pem ::2
./alpn_test client ::1 1234 ::2 || return 1
ip -6 addr del ::2/128 dev lo
daemon_stop "alpn_test"
}

ticket_tests()
{
print_start "Session Resumption Tests"
daemon_run ./ticket_test server 0.0.0.0 1234 ./keys/server-key.pem ./keys/server-cert.pem
./ticket_test client 127.0.0.1 1234 || return 1
daemon_stop "ticket_test"
}

sample_tests()
{
print_start "Sample Tests"
daemon_run ./sample_test server 0.0.0.0 1234 ./keys/server-key.pem ./keys/server-cert.pem
./sample_test client 127.0.0.1 1234 none none || return 1
daemon_stop "sample_test"

print_start "ALPN and Preferred Address Tests"
daemon_run ./alpn_test server 0.0.0.0 1234 ./keys/server-key.pem ./keys/server-cert.pem
./alpn_test client 127.0.0.1 1234 || return 1
daemon_stop "alpn_test"
}

TESTS="func perf netem http3 tlshd sample"
TESTS="func perf netem http3 tlshd alpn ticket sample"
trap cleanup EXIT

[ "$1" = "" ] || TESTS=$1
Expand Down

0 comments on commit 03b61ff

Please sign in to comment.