diff --git a/tests/alpn_test.c b/tests/alpn_test.c index 40d4686..d36eb0d 100644 --- a/tests/alpn_test.c +++ b/tests/alpn_test.c @@ -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; @@ -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; @@ -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; } @@ -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 \n", argv[0]); + printf("%s client [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; @@ -180,9 +207,9 @@ 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] = {}; @@ -190,7 +217,7 @@ static int do_server(int argc, char *argv[]) if (argc < 5) { printf("%s server " - "\n", argv[0]); + " [PREF ADDR]\n", argv[0]); return 0; } @@ -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; @@ -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; @@ -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); diff --git a/tests/func_test.c b/tests/func_test.c index b47ea5b..cf09973 100644 --- a/tests/func_test.c +++ b/tests/func_test.c @@ -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; } @@ -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; } diff --git a/tests/interop/Dockerfile b/tests/interop/Dockerfile index c2f8289..09ccf50 100644 --- a/tests/interop/Dockerfile +++ b/tests/interop/Dockerfile @@ -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 . diff --git a/tests/interop/interop_test.c b/tests/interop/interop_test.c index b72d80e..ea7dc25 100644 --- a/tests/interop/interop_test.c +++ b/tests/interop/interop_test.c @@ -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]; @@ -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; @@ -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; @@ -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); @@ -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); @@ -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) { @@ -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; } diff --git a/tests/runtest.sh b/tests/runtest.sh index 9867c71..be4f912 100755 --- a/tests/runtest.sh +++ b/tests/runtest.sh @@ -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 @@ -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