From 0006c48e4bf9310d40f2b6d8d27504ac02965363 Mon Sep 17 00:00:00 2001 From: Jop Zitman Date: Mon, 16 Dec 2024 18:33:21 +0800 Subject: [PATCH] Add multipath support --- CMakeLists.txt | 2 + include/slipstream.h | 2 +- include/slipstream_resolver_addresses.h | 8 +++ resolvers-trusted.txt | 5 ++ src/slipstream.c | 9 ++- src/slipstream_client.c | 52 +++++++++++----- src/slipstream_resolver_addresses.c | 83 +++++++++++++++++++++++++ src/slipstream_server.c | 5 +- 8 files changed, 141 insertions(+), 25 deletions(-) create mode 100644 include/slipstream_resolver_addresses.h create mode 100644 resolvers-trusted.txt create mode 100644 src/slipstream_resolver_addresses.c diff --git a/CMakeLists.txt b/CMakeLists.txt index fdfe13d..f99cf9d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -43,9 +43,11 @@ add_executable(slipstream src/slipstream_server.c src/slipstream_server_circular_query_buffer.c src/slipstream_inline_dots.c + src/slipstream_resolver_addresses.c include/slipstream.h include/slipstream_server_circular_query_buffer.h include/slipstream_inline_dots.h + include/slipstream_resolver_addresses.h extern/lua-resty-base-encoding/b32_data.h extern/lua-resty-base-encoding/base32.c diff --git a/include/slipstream.h b/include/slipstream.h index 9a2d20e..24102a2 100644 --- a/include/slipstream.h +++ b/include/slipstream.h @@ -20,7 +20,7 @@ extern "C" { -int picoquic_slipstream_client(int listen_port, char const* server_name, int server_port, const char* domain_name); +int picoquic_slipstream_client(int listen_port, char const* resolver_addresses_filename, const char* domain_name); int picoquic_slipstream_server(int server_port, const char* pem_cert, const char* pem_key, char const* upstream_name, int upstream_port, const char* domain_name); diff --git a/include/slipstream_resolver_addresses.h b/include/slipstream_resolver_addresses.h new file mode 100644 index 0000000..55c16a2 --- /dev/null +++ b/include/slipstream_resolver_addresses.h @@ -0,0 +1,8 @@ +#ifndef SLIPSTREAM_RESOLVERS_H +#define SLIPSTREAM_RESOLVERS_H + +#include + +struct sockaddr_storage* read_resolver_addresses(const char *resolver_addresses_filename, size_t *count); + +#endif //SLIPSTREAM_RESOLVERS_H diff --git a/resolvers-trusted.txt b/resolvers-trusted.txt new file mode 100644 index 0000000..c54e1c7 --- /dev/null +++ b/resolvers-trusted.txt @@ -0,0 +1,5 @@ +127.0.0.1 8853 +127.0.0.2 8853 +127.0.0.3 8853 +127.0.0.4 8853 +172.17.0.1 8853 diff --git a/src/slipstream.c b/src/slipstream.c index f353d63..abb858f 100644 --- a/src/slipstream.c +++ b/src/slipstream.c @@ -34,15 +34,14 @@ int main(int argc, char** argv) usage(argv[0]); } else if (strcmp(argv[1], "client") == 0) { - if (argc != 6) { + if (argc != 5) { usage(argv[0]); } else { int local_port = atoi(argv[2]); - char const* remote_ip = argv[3]; - int remote_port = atoi(argv[4]); - const char* domain_name = argv[5]; - exit_code = picoquic_slipstream_client(local_port, remote_ip, remote_port, domain_name); + char const* resolver_addresses_filename = argv[3]; + const char* domain_name = argv[4]; + exit_code = picoquic_slipstream_client(local_port, resolver_addresses_filename, domain_name); } } else if (strcmp(argv[1], "server") == 0) { diff --git a/src/slipstream_client.c b/src/slipstream_client.c index bab1e58..2c4ce2c 100644 --- a/src/slipstream_client.c +++ b/src/slipstream_client.c @@ -19,6 +19,7 @@ #include "picoquic_config.h" #include "slipstream.h" #include "slipstream_inline_dots.h" +#include "slipstream_resolver_addresses.h" #include "SPCDNS/src/dns.h" #include "SPCDNS/src/mappings.h" @@ -163,6 +164,8 @@ typedef struct st_slipstream_client_ctx_t { picoquic_cnx_t* cnx; slipstream_client_stream_ctx_t* first_stream; picoquic_network_thread_ctx_t* thread_ctx; + struct sockaddr_storage* server_addresses; + size_t server_address_count; } slipstream_client_ctx_t; slipstream_client_stream_ctx_t* slipstream_client_create_stream_ctx(picoquic_cnx_t* cnx, @@ -501,6 +504,17 @@ int slipstream_client_callback(picoquic_cnx_t* cnx, break; case picoquic_callback_ready: fprintf(stdout, "Connection confirmed.\n"); + + // add rest of the resolvers + for (size_t i = 1; i < client_ctx->server_address_count; i++) { + struct sockaddr* server_address = (struct sockaddr*)&client_ctx->server_addresses[i]; + uint64_t current_time = picoquic_current_time(); + ret = picoquic_probe_new_path(cnx, server_address, NULL, current_time); + if (ret != 0) { + fprintf(stderr, "Could not create probe new path\n"); + return -1; + } + } break; default: /* unexpected -- just ignore. */ @@ -514,34 +528,35 @@ void client_sighandler(int signum) { printf("Signal %d received\n", signum); } -static int slipstream_connect(char const* server_name, int server_port, +static int slipstream_connect(struct sockaddr_storage* server_address, picoquic_quic_t* quic, picoquic_cnx_t** cnx, slipstream_client_ctx_t* client_ctx) { int ret = 0; char const* sni = SLIPSTREAM_SNI; uint64_t current_time = picoquic_current_time(); - struct sockaddr_storage server_address; *cnx = NULL; - /* Get the server's address */ - int is_name = 0; - ret = picoquic_get_server_address(server_name, server_port, &server_address, &is_name); + char host[NI_MAXHOST]; + socklen_t addrlen = sizeof(*server_address); + ret = getnameinfo((struct sockaddr*)server_address, addrlen, + host, sizeof(host), + NULL, 0, + NI_NUMERICHOST | NI_NUMERICSERV); if (ret != 0) { - fprintf(stderr, "Cannot get the IP address for <%s> port <%d>", server_name, server_port); + fprintf(stderr, "Could not get name info for server address\n"); return -1; } - sni = server_name; /* Initialize the callback context and create the connection context. * We use minimal options on the client side, keeping the transport * parameter values set by default for picoquic. This could be fixed later. */ - printf("Starting connection to %s, port %d\n", server_name, server_port); + printf("Starting connection to %s\n", host); /* Create a client connection */ *cnx = picoquic_create_cnx(quic, picoquic_null_connection_id, picoquic_null_connection_id, - (struct sockaddr*)&server_address, current_time, 0, sni, SLIPSTREAM_ALPN, 1); + (struct sockaddr*)server_address, current_time, 0, sni, SLIPSTREAM_ALPN, 1); if (*cnx == NULL) { fprintf(stderr, "Could not create connection context\n"); return -1; @@ -569,12 +584,10 @@ static int slipstream_connect(char const* server_name, int server_port, return ret; } -int picoquic_slipstream_client(int listen_port, char const* server_name, int server_port, const char* domain_name) { +int picoquic_slipstream_client(int listen_port, char const* resolver_addresses_filename, const char* domain_name) { /* Start: start the QUIC process */ int ret = 0; - picoquic_quic_t* quic = NULL; uint64_t current_time = 0; - picoquic_cnx_t* cnx = NULL; char const* ticket_store_filename = SLIPSTREAM_CLIENT_TICKET_STORE; char const* token_store_filename = SLIPSTREAM_CLIENT_TOKEN_STORE; @@ -593,12 +606,11 @@ int picoquic_slipstream_client(int listen_port, char const* server_name, int ser #ifdef BUILD_LOGLIB config.qlog_dir = SLIPSTREAM_QLOG_DIR; #endif - config.server_port = server_port; config.mtu_max = mtu; config.initial_send_mtu_ipv4 = mtu; config.initial_send_mtu_ipv6 = mtu; config.cc_algo_id = "cubic"; - config.multipath_option = 0; + config.multipath_option = 1; config.use_long_log = 1; config.do_preemptive_repeat = 1; config.disable_port_blocking = 1; @@ -612,7 +624,7 @@ int picoquic_slipstream_client(int listen_port, char const* server_name, int ser slipstream_client_ctx_t *client_ctx = malloc(sizeof(slipstream_client_ctx_t)); memset(client_ctx, 0, sizeof(slipstream_client_ctx_t)); /* Create QUIC context */ - quic = picoquic_create_and_configure(&config, slipstream_client_callback, client_ctx, current_time, NULL); + picoquic_quic_t* quic = picoquic_create_and_configure(&config, slipstream_client_callback, client_ctx, current_time, NULL); if (quic == NULL) { fprintf(stderr, "Could not create server context\n"); return -1; @@ -625,7 +637,15 @@ int picoquic_slipstream_client(int listen_port, char const* server_name, int ser #endif picoquic_set_key_log_file_from_env(quic); - ret = slipstream_connect(server_name, server_port, quic, &cnx, client_ctx); + /* Read the server address list from the file */ + client_ctx->server_addresses = read_resolver_addresses(resolver_addresses_filename, &client_ctx->server_address_count); + if (!client_ctx->server_addresses) { + printf("Failed to read IP addresses\n"); + return 1; + } + + picoquic_cnx_t* cnx = NULL; + ret = slipstream_connect(client_ctx->server_addresses, quic, &cnx, client_ctx); if (ret != 0) { fprintf(stderr, "Could not connect to server\n"); return -1; diff --git a/src/slipstream_resolver_addresses.c b/src/slipstream_resolver_addresses.c new file mode 100644 index 0000000..89cf78d --- /dev/null +++ b/src/slipstream_resolver_addresses.c @@ -0,0 +1,83 @@ +#include "slipstream_resolver_addresses.h" + +#include +#include + +#include + +#define MAX_IP_LENGTH 20 +#define INITIAL_CAPACITY 10 +#define MAX_LINE_LENGTH 50 +#define DEFAULT_PORT 53 + +struct sockaddr_storage* read_resolver_addresses(const char *resolver_addresses_filename, size_t *count) { + *count = 0; + + FILE *fp = fopen(resolver_addresses_filename, "r"); + if (!fp) { + return NULL; + } + + int capacity = INITIAL_CAPACITY; + struct sockaddr_storage* server_address = calloc(capacity, sizeof(struct sockaddr_storage)); + if (!server_address) { + fclose(fp); + return NULL; + } + + char line[MAX_LINE_LENGTH]; + int valid_addresses = 0; + + while (fgets(line, MAX_LINE_LENGTH, fp)) { + // Remove newline + line[strcspn(line, "\n")] = '\0'; + + // Skip empty or whitespace-only lines + if (strlen(line) == 0 || strspn(line, " \t") == strlen(line)) { + continue; + } + + // Resize array if needed + if (valid_addresses == capacity) { + capacity *= 2; + struct sockaddr_storage* temp = realloc(server_address, capacity * sizeof(struct sockaddr_storage)); + if (!temp) { + fprintf(stderr, "Memory allocation failed\n"); + free(server_address); + fclose(fp); + return NULL; + } + server_address = temp; + } + + char server_name[MAX_IP_LENGTH]; + int server_port = DEFAULT_PORT; + + // Parse line for IP and optional port + if (sscanf(line, "%s %d", server_name, &server_port) < 1) { + continue; // Invalid format + } + + printf("Adding %s:%d\n", server_name, server_port); + + int is_name = 0; + if (picoquic_get_server_address(server_name, server_port, &server_address[valid_addresses], &is_name) != 0) { + fprintf(stderr, "Cannot get the IP address for <%s> port <%d>\n", server_name, server_port); + continue; // Skip invalid addresses instead of failing + } + valid_addresses++; + } + + fclose(fp); + *count = valid_addresses; + + // Trim excess memory if needed + if (valid_addresses < capacity) { + struct sockaddr_storage* temp = realloc(server_address, valid_addresses * sizeof(struct sockaddr_storage)); + if (temp) { + server_address = temp; + } + } + + return server_address; +} diff --git a/src/slipstream_server.c b/src/slipstream_server.c index 044ae53..4d945e5 100644 --- a/src/slipstream_server.c +++ b/src/slipstream_server.c @@ -489,7 +489,6 @@ int picoquic_slipstream_server(int server_port, const char* server_cert, const c char const* upstream_name, int upstream_port, const char* domain_name) { /* Start: start the QUIC process with cert and key files */ int ret = 0; - picoquic_quic_t* quic = NULL; uint64_t current_time = 0; slipstream_server_ctx_t default_context = {0}; printf("Starting Picoquic Sample server on port %d\n", server_port); @@ -518,7 +517,7 @@ int picoquic_slipstream_server(int server_port, const char* server_cert, const c config.initial_send_mtu_ipv4 = mtu; config.initial_send_mtu_ipv6 = mtu; config.cc_algo_id = "cubic"; - config.multipath_option = 0; + config.multipath_option = 1; config.use_long_log = 1; config.do_preemptive_repeat = 1; config.disable_port_blocking = 1; @@ -529,7 +528,7 @@ int picoquic_slipstream_server(int server_port, const char* server_cert, const c /* Create the QUIC context for the server */ current_time = picoquic_current_time(); /* Create QUIC context */ - quic = picoquic_create_and_configure(&config, slipstream_server_callback, &default_context, current_time, NULL); + picoquic_quic_t* quic = picoquic_create_and_configure(&config, slipstream_server_callback, &default_context, current_time, NULL); if (quic == NULL) { fprintf(stderr, "Could not create server context\n"); return -1;