diff --git a/CMakeLists.txt b/CMakeLists.txt index 778d741..01d85cf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,7 +10,6 @@ set(ENABLE_ASAN OFF) set(ENABLE_UBSAN OFF) set(BUILD_DEMO OFF) set(BUILD_HTTP OFF) -set(BUILD_LOGLIB ON) set(BUILD_LOGREADER OFF) set(BUILD_TESTING OFF) @@ -23,13 +22,12 @@ endif() if(${CMAKE_BUILD_TYPE} STREQUAL "Debug") list(APPEND PICOQUIC_ADDITIONAL_C_FLAGS -Og) list(APPEND PICOQUIC_ADDITIONAL_CXX_FLAGS -Og) + list(APPEND PICOQUIC_COMPILE_DEFINITIONS BUILD_LOGLIB) + set(BUILD_LOGLIB ON) else() list(APPEND PICOQUIC_ADDITIONAL_C_FLAGS -O3) list(APPEND PICOQUIC_ADDITIONAL_CXX_FLAGS -O3) -endif() - -if(BUILD_LOGLIB) - list(APPEND PICOQUIC_COMPILE_DEFINITIONS BUILD_LOGLIB) + set(BUILD_LOGLIB OFF) endif() if(POLICY CMP0048) diff --git a/extern/picoquic b/extern/picoquic index 7ac027d..afb1a46 160000 --- a/extern/picoquic +++ b/extern/picoquic @@ -1 +1 @@ -Subproject commit 7ac027d6e16ef344a19f8e32d49c93a6caef15da +Subproject commit afb1a46057b1e506d48d8126b4f958fbc1e9d869 diff --git a/include/slipstream_dns_request_buffer.h b/include/slipstream_dns_request_buffer.h index e92dcd2..5c9f5a0 100644 --- a/include/slipstream_dns_request_buffer.h +++ b/include/slipstream_dns_request_buffer.h @@ -2,21 +2,24 @@ #define SLIPSTREAM_DNS_REQUEST_BUFFER #include - +#include #include "SPCDNS/src/dns.h" -#define GLOBAL_BUFFER_SIZE 4096 +#define GLOBAL_BUFFER_SIZE 32 typedef struct st_slipstream_cnxid_dns_request_buffer_t slipstream_cnxid_dns_request_buffer_t; typedef struct st_element_t { dns_decoded_t dns_decoded[DNS_DECODEBUF_4K]; struct sockaddr_storage peer_addr; + struct sockaddr_storage local_addr; struct st_element_t* buffer_prev; struct st_element_t* buffer_next; struct st_element_t* cnxid_buffer_prev; struct st_element_t* cnxid_buffer_next; slipstream_cnxid_dns_request_buffer_t* cnxid_buffer; + uint64_t created_time; + int query_id; } slot_t; typedef struct st_slipstream_cnxid_dns_request_buffer_t { @@ -25,11 +28,13 @@ typedef struct st_slipstream_cnxid_dns_request_buffer_t { } slipstream_cnxid_dns_request_buffer_t; typedef struct { - slot_t elements[GLOBAL_BUFFER_SIZE]; + slot_t slots[GLOBAL_BUFFER_SIZE]; slot_t* head; slot_t* tail; slot_t* free; picohash_table* cnxid_to_cnxid_buffer; + slipstream_cnxid_dns_request_buffer_t** cnxid_buffers; + size_t cnxid_buffers_len; } slipstream_dns_request_buffer_t; typedef struct st_cnxid_to_cnxid_buffer_t { @@ -43,6 +48,8 @@ void slipstream_dns_request_buffer_init(slipstream_dns_request_buffer_t* buffer) slipstream_cnxid_dns_request_buffer_t* slipstream_dns_request_buffer_get_cnxid_buffer( slipstream_dns_request_buffer_t* buffer, picoquic_connection_id_t* initial_cnxid, bool create); +void slipstream_dns_request_buffer_free_slot(slipstream_dns_request_buffer_t* buffer, slot_t* slot); + slot_t* slipstream_dns_request_buffer_get_write_slot(slipstream_dns_request_buffer_t* buffer); void slipstream_dns_request_buffer_commit_slot_to_cnxid_buffer(slipstream_dns_request_buffer_t* buffer, diff --git a/src/slipstream_client.c b/src/slipstream_client.c index 7a14d19..340e872 100644 --- a/src/slipstream_client.c +++ b/src/slipstream_client.c @@ -47,7 +47,7 @@ ssize_t client_encode_segment(picoquic_quic_t* quic, dns_packet_t* packet, size_ edns.opt.type = RR_OPT; edns.opt.class = CLASS_UNKNOWN; edns.opt.ttl = 0; - edns.opt.udp_payload = 4096; + edns.opt.udp_payload = 1232; dns_query_t query = {0}; query.id = rand() % UINT16_MAX; @@ -62,14 +62,14 @@ ssize_t client_encode_segment(picoquic_quic_t* quic, dns_packet_t* packet, size_ const dns_rcode_t rc = dns_encode(packet, packet_len, &query); if (rc != RCODE_OKAY) { - fprintf(stderr, "dns_encode() = (%d) %s\n", rc, dns_rcode_text(rc)); + DBG_PRINTF( "dns_encode() = (%d) %s\n", rc, dns_rcode_text(rc)); return -1; } return 0; } -ssize_t client_encode(picoquic_quic_t* quic, picoquic_cnx_t* cnx, unsigned char** dest_buf, const unsigned char* src_buf, size_t src_buf_len, size_t* segment_len, struct sockaddr_storage* peer_addr) { +ssize_t client_encode(picoquic_quic_t* quic, picoquic_cnx_t* cnx, picoquic_socket_ctx_t* s_ctx, size_t s_ctx_len, unsigned char** dest_buf, const unsigned char* src_buf, size_t src_buf_len, size_t* segment_len, struct sockaddr_storage* peer_addr, struct sockaddr_storage* local_addr) { // optimize path for single segment if (src_buf_len <= *segment_len) { size_t packet_len = MAX_DNS_QUERY_SIZE; @@ -124,34 +124,34 @@ ssize_t client_decode(picoquic_quic_t* quic, picoquic_socket_ctx_t* s_ctx, size_ *dest_buf = NULL; size_t bufsize = DNS_DECODEBUF_4K * sizeof(dns_decoded_t); - dns_decoded_t decoded[DNS_DECODEBUF_4K]; + dns_decoded_t decoded[DNS_DECODEBUF_4K] = {0}; const dns_rcode_t rc = dns_decode(decoded, &bufsize, (const dns_packet_t*) src_buf, src_buf_len); if (rc != RCODE_OKAY) { - fprintf(stderr, "dns_decode() = (%d) %s\n", rc, dns_rcode_text(rc)); + DBG_PRINTF("dns_decode() = (%d) %s", rc, dns_rcode_text(rc)); return -1; } const dns_query_t *query = (dns_query_t *)decoded; if (query->query == 1) { - fprintf(stderr, "dns record is not a response\n"); - return -1; + DBG_PRINTF("[%d] dns record is not a response", query->id, NULL); + return 0; } if (query->rcode != RCODE_OKAY) { - fprintf(stderr, "dns record rcode not okay: %d\n", query->rcode); - return -1; + DBG_PRINTF("[%d] dns record rcode not okay: %d", query->id, query->rcode); + return 0; } if (query->ancount != 1) { - fprintf(stderr, "dns record should contain exactly one answer\n"); - return -1; + DBG_PRINTF("[%d] dns record should contain exactly one answer", query->id); + return 0; } dns_txt_t *answer_txt = (dns_txt_t*) &query->answers[0]; if (answer_txt->type != RR_TXT) { - fprintf(stderr, "answer type is not TXT\n"); - return -1; + DBG_PRINTF("[%d] answer type is not TXT", query->id, NULL); + return 0; } *dest_buf = malloc(answer_txt->len); @@ -164,13 +164,13 @@ ssize_t client_decode(picoquic_quic_t* quic, picoquic_socket_ctx_t* s_ctx, size_ int ret = slipstream_packet_parse(*dest_buf, answer_txt->len, PICOQUIC_SHORT_HEADER_CONNECTION_ID_SIZE, &incoming_src_connection_id, &incoming_dest_connection_id, &is_poll_packet); if (ret != 0 || is_poll_packet) { - fprintf(stderr, "error parsing slipstream packet: %d\n", ret); + DBG_PRINTF("[%d] error parsing slipstream packet: %d", query->id, ret); return answer_txt->len; } const SOCKET_TYPE send_socket = picoquic_socket_get_send_socket(s_ctx, s_ctx_len, peer_addr, local_addr); if (send_socket == INVALID_SOCKET) { - fprintf(stderr, "no valid socket found for poll packet\n"); + DBG_PRINTF("[%d] no valid socket found for poll packet", query->id); return answer_txt->len; } @@ -188,15 +188,15 @@ ssize_t client_decode(picoquic_quic_t* quic, picoquic_socket_ctx_t* s_ctx, size_ size_t poll_packet_len; ret = slipstream_packet_create_poll(&poll_packet_buf, &poll_packet_len, outgoing_dest_connection_id); if (ret < 0) { - fprintf(stderr, "error creating poll packet\n"); + DBG_PRINTF("error creating poll packet", NULL); return answer_txt->len; } unsigned char* encoded; - ssize_t encoded_len = client_encode(quic, cnx, &encoded, poll_packet_buf, poll_packet_len, &poll_packet_len, - peer_addr); + ssize_t encoded_len = client_encode(quic, cnx, s_ctx, s_ctx_len, &encoded, poll_packet_buf, poll_packet_len, + &poll_packet_len, peer_addr, local_addr); if (encoded_len <= 0) { - fprintf(stderr, "error encoding poll packet\n"); + DBG_PRINTF("error encoding poll packet", NULL); free(poll_packet_buf); return answer_txt->len; } @@ -206,7 +206,7 @@ ssize_t client_decode(picoquic_quic_t* quic, picoquic_socket_ctx_t* s_ctx, size_ (struct sockaddr*)peer_addr, (struct sockaddr*)local_addr, 0, (const char*)encoded, encoded_len, 0, &sock_err); if (ret < 0) { - fprintf(stderr, "Error sending poll packet, ret=%d, sock_err=%d %s\n", ret, sock_err, strerror(sock_err)); + DBG_PRINTF("Error sending poll packet, ret=%d, sock_err=%d %s", ret, sock_err, strerror(sock_err)); free(poll_packet_buf); free(encoded); return answer_txt->len; @@ -577,6 +577,14 @@ int slipstream_client_callback(picoquic_cnx_t* cnx, 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(); + // convert server address to string + char host[NI_MAXHOST]; + socklen_t addrlen = sizeof(*server_address); + ret = getnameinfo(server_address, addrlen, host, sizeof(host), NULL, 0, NI_NUMERICHOST | NI_NUMERICSERV); + if (ret == 0) { + printf("Probing path: %s", host); + } + ret = picoquic_probe_new_path(cnx, server_address, NULL, current_time); if (ret != 0) { fprintf(stderr, "Could not create probe new path\n"); @@ -630,6 +638,9 @@ static int slipstream_connect(struct sockaddr_storage* server_address, return -1; } + // 400ms + picoquic_enable_keep_alive(*cnx, 400000); + /* Document connection in client's context */ client_ctx->cnx = *cnx; /* Set the client callback context */ @@ -704,6 +715,7 @@ int picoquic_slipstream_client(int listen_port, char const* resolver_addresses_f debug_printf_push_stream(stderr); #endif picoquic_set_key_log_file_from_env(quic); + // TODO: idle timeout? /* Read the server address list from the file */ client_ctx->server_addresses = read_resolver_addresses(resolver_addresses_filename, &client_ctx->server_address_count); diff --git a/src/slipstream_dns_request_buffer.c b/src/slipstream_dns_request_buffer.c index 5854533..54eee16 100644 --- a/src/slipstream_dns_request_buffer.c +++ b/src/slipstream_dns_request_buffer.c @@ -28,7 +28,7 @@ void slipstream_dns_request_buffer_init(slipstream_dns_request_buffer_t* buffer) buffer->tail = NULL; for (int i = 0; i < GLOBAL_BUFFER_SIZE; i++) { - slot_t* element = &buffer->elements[i]; + slot_t* element = &buffer->slots[i]; element->buffer_next = buffer->free; element->buffer_prev = NULL; buffer->free = element; @@ -70,31 +70,42 @@ slipstream_cnxid_dns_request_buffer_t* slipstream_dns_request_buffer_get_cnxid_b fprintf(stderr, "error adding a cnx buffer for a new cnx id\n"); return NULL; } + + buffer->cnxid_buffers_len++; + slipstream_cnxid_dns_request_buffer_t** cnxid_buffers = realloc(buffer->cnxid_buffers, + buffer->cnxid_buffers_len * sizeof(slipstream_cnxid_dns_request_buffer_t*)); + if (cnxid_buffers == NULL) { + return NULL; + } + buffer->cnxid_buffers = cnxid_buffers; + buffer->cnxid_buffers[buffer->cnxid_buffers_len - 1] = new_key->cnxid_buffer; + return new_key->cnxid_buffer; } -void slipstream_cnxid_dns_request_buffer_free_slot(slipstream_cnxid_dns_request_buffer_t* cnxid_buffer, slot_t* slot) { - if (slot->cnxid_buffer_prev != NULL) { - slot->cnxid_buffer_prev->cnxid_buffer_next = slot->cnxid_buffer_next; - } - - if (slot->cnxid_buffer_next != NULL) { - slot->cnxid_buffer_next->cnxid_buffer_prev = slot->cnxid_buffer_prev; - } - - if (cnxid_buffer->head == slot) { - cnxid_buffer->head = slot->cnxid_buffer_next; - } - - if (cnxid_buffer->tail == slot) { - cnxid_buffer->tail = slot->cnxid_buffer_prev; - } - - slot->cnxid_buffer = NULL; -} - void slipstream_dns_request_buffer_free_slot(slipstream_dns_request_buffer_t* buffer, slot_t* slot) { + slipstream_cnxid_dns_request_buffer_t* cnxid_buffer = slot->cnxid_buffer; + if (cnxid_buffer != NULL) { + if (slot->cnxid_buffer_prev != NULL) { + slot->cnxid_buffer_prev->cnxid_buffer_next = slot->cnxid_buffer_next; + } + + if (slot->cnxid_buffer_next != NULL) { + slot->cnxid_buffer_next->cnxid_buffer_prev = slot->cnxid_buffer_prev; + } + + if (cnxid_buffer->head == slot) { + cnxid_buffer->head = slot->cnxid_buffer_next; + } + + if (cnxid_buffer->tail == slot) { + cnxid_buffer->tail = slot->cnxid_buffer_prev; + } + + slot->cnxid_buffer = NULL; + } + if (slot->buffer_prev != NULL) { slot->buffer_prev->buffer_next = slot->buffer_next; } @@ -116,14 +127,12 @@ void slipstream_dns_request_buffer_free_slot(slipstream_dns_request_buffer_t* bu } slot->buffer_next = buffer->free; buffer->free = slot; + slot->query_id = 0; } slot_t* slipstream_dns_request_buffer_get_write_slot(slipstream_dns_request_buffer_t* buffer) { if (!buffer->free) { - slot_t* tail = buffer->tail; - assert(tail != NULL); - slipstream_cnxid_dns_request_buffer_free_slot(tail->cnxid_buffer, tail); - slipstream_dns_request_buffer_free_slot(buffer, tail); + return NULL; } // Get the first free element @@ -167,16 +176,13 @@ void slipstream_dns_request_buffer_commit_slot_to_cnxid_buffer(slipstream_dns_re } slot_t* slipstream_dns_request_buffer_get_read_slot(slipstream_dns_request_buffer_t* buffer, - slipstream_cnxid_dns_request_buffer_t* cnxid_buffer) { + slipstream_cnxid_dns_request_buffer_t* cnxid_buffer) { // Get the last element from the cnxid buffer slot_t* slot = cnxid_buffer->tail; if (!slot) { return NULL; } - slipstream_cnxid_dns_request_buffer_free_slot(slot->cnxid_buffer, slot); - slipstream_dns_request_buffer_free_slot(buffer, slot); - return slot; } diff --git a/src/slipstream_server.c b/src/slipstream_server.c index 8b39953..44c9f81 100644 --- a/src/slipstream_server.c +++ b/src/slipstream_server.c @@ -6,7 +6,6 @@ #ifdef BUILD_LOGLIB #include #endif -#include #include #include #include @@ -30,7 +29,53 @@ size_t server_domain_name_len = 0; slipstream_dns_request_buffer_t slipstream_server_dns_request_buffer; -ssize_t server_encode(picoquic_quic_t* quic, picoquic_cnx_t* cnx, unsigned char** dest_buf, const unsigned char* src_buf, size_t src_buf_len, size_t* segment_size, struct sockaddr_storage *peer_addr) { +ssize_t respond_and_free_slot(slot_t* slot, const picoquic_socket_ctx_t* s_ctx, const size_t s_ctx_len, dns_rcode_t rcode) { + const dns_query_t *query = (dns_query_t *) slot->dns_decoded; + + dns_query_t response = {0}; + response.id = query->id; + response.query = false; + response.opcode = query->opcode; + response.aa = true; + response.rd = query->rd; + response.cd = query->cd; + response.rcode = rcode; + response.qdcount = query->qdcount; + response.questions = query->questions; + + dns_packet_t packet[DNS_BUFFER_UDP_MAX]; + size_t packet_len = MAX_UDP_PACKET_SIZE; + dns_rcode_t rc = dns_encode(packet, &packet_len, &response); + // slot not used anymore, free it + slipstream_dns_request_buffer_free_slot(&slipstream_server_dns_request_buffer, slot); + if (rc != RCODE_OKAY) { + DBG_PRINTF("dns_encode() = (%d) %s", rc, dns_rcode_text(rc)); + return -1; + } + + const struct sockaddr_storage *peer_addr = &slot->peer_addr; + const struct sockaddr_storage *local_addr = &slot->local_addr; + const SOCKET_TYPE send_socket = picoquic_socket_get_send_socket(s_ctx, s_ctx_len, peer_addr, local_addr); + if (send_socket == INVALID_SOCKET) { + DBG_PRINTF("no valid socket found for poll packet", NULL); + return -1; + } + + int sock_err = 0; + int ret = picoquic_sendmsg(send_socket, + (struct sockaddr*)peer_addr, (struct sockaddr*)local_addr, 0, + (const char*)packet, packet_len, 0, &sock_err); + if (ret < 0) { + DBG_PRINTF("Error sending poll packet, ret=%d, sock_err=%d %s", ret, sock_err, strerror(sock_err)); + return -1; + } + + return 0; +} + +ssize_t server_encode(picoquic_quic_t* quic, picoquic_cnx_t* cnx, picoquic_socket_ctx_t* s_ctx, size_t s_ctx_len, + unsigned char** dest_buf, const unsigned char* src_buf, size_t src_buf_len, size_t* segment_size, + struct sockaddr_storage* peer_addr, struct sockaddr_storage* local_addr) { // we don't support segmentation in the server assert(segment_size == NULL || *segment_size == 0 || *segment_size == src_buf_len); @@ -39,22 +84,16 @@ ssize_t server_encode(picoquic_quic_t* quic, picoquic_cnx_t* cnx, unsigned char* slipstream_cnxid_dns_request_buffer_t* cnxid_buffer = slipstream_dns_request_buffer_get_cnxid_buffer( &slipstream_server_dns_request_buffer, &initial_cnxid, false); if (cnxid_buffer == NULL) { - fprintf(stderr, "error getting cnxid buffer\n"); + DBG_PRINTF("error getting cnxid buffer", NULL); return -1; } slot_t *slot = slipstream_dns_request_buffer_get_read_slot(&slipstream_server_dns_request_buffer, cnxid_buffer); if (slot == NULL) { - fprintf(stderr, "no available DNS request to respond to\n"); + DBG_PRINTF("no available DNS request to respond to", NULL); return -1; } dns_query_t *query = (dns_query_t *) slot->dns_decoded; - - if (query->questions == NULL) { - fprintf(stderr, "no questions in DNS request\n"); - return -1; - } - const dns_question_t *question = &query->questions[0]; // assuming server_decode ensures there is exactly one question dns_txt_t answer_txt; answer_txt.name = question->name; @@ -69,13 +108,15 @@ ssize_t server_encode(picoquic_quic_t* quic, picoquic_cnx_t* cnx, unsigned char* edns.opt.type = RR_OPT; edns.opt.class = CLASS_UNKNOWN; edns.opt.ttl = 0; - edns.opt.udp_payload = 4096; + edns.opt.udp_payload = 1232; dns_query_t response = {0}; response.id = query->id; response.query = false; response.opcode = OP_QUERY; - response.rd = true; + response.aa = true; + response.rd = query->rd; + response.cd = query->cd; response.rcode = RCODE_OKAY; response.qdcount = 1; response.questions = query->questions; @@ -87,9 +128,10 @@ ssize_t server_encode(picoquic_quic_t* quic, picoquic_cnx_t* cnx, unsigned char* dns_packet_t* packet = malloc(MAX_UDP_PACKET_SIZE); size_t packet_len = MAX_UDP_PACKET_SIZE; dns_rcode_t rc = dns_encode(packet, &packet_len, &response); + slipstream_dns_request_buffer_free_slot(&slipstream_server_dns_request_buffer, slot); if (rc != RCODE_OKAY) { free(packet); - fprintf(stderr, "dns_encode() = (%d) %s\n", rc, dns_rcode_text(rc)); + DBG_PRINTF("dns_encode() = (%d) %s", rc, dns_rcode_text(rc)); return EXIT_FAILURE; } *dest_buf = (unsigned char*)packet; @@ -102,46 +144,60 @@ ssize_t server_encode(picoquic_quic_t* quic, picoquic_cnx_t* cnx, unsigned char* ssize_t server_decode(picoquic_quic_t* quic, picoquic_socket_ctx_t* s_ctx, size_t s_ctx_len, unsigned char** dest_buf, const unsigned char* src_buf, size_t src_buf_len, struct sockaddr_storage *peer_addr, struct sockaddr_storage *local_addr) { *dest_buf = NULL; - slot_t* slot = slipstream_dns_request_buffer_get_write_slot(&slipstream_server_dns_request_buffer); + slot_t* slot; + if (!slipstream_server_dns_request_buffer.free) { + slot = slipstream_server_dns_request_buffer.tail; + assert(slot != NULL); + assert(slot->cnxid_buffer != NULL); + respond_and_free_slot(slot, s_ctx, s_ctx_len, RCODE_NAME_ERROR); + } + + slot = slipstream_dns_request_buffer_get_write_slot(&slipstream_server_dns_request_buffer); if (slot == NULL) { - fprintf(stderr, "error getting write slot\n"); + DBG_PRINTF("error getting write slot", NULL); sockaddr_dummy(peer_addr); return -1; } + slot->created_time = picoquic_current_time(); // DNS packets arrive from random source ports, so: // * save the original address in the dns query slot // * set the source address to a dummy address (to prevent QUIC from using it) memcpy(&slot->peer_addr, peer_addr, sizeof(struct sockaddr_storage)); sockaddr_dummy(peer_addr); + // Save local address for right response local addr + memcpy(&slot->local_addr, local_addr, sizeof(struct sockaddr_storage)); size_t packet_len = DNS_DECODEBUF_4K * sizeof(dns_decoded_t); dns_decoded_t* packet = slot->dns_decoded; const dns_rcode_t rc = dns_decode(packet, &packet_len, (const dns_packet_t*) src_buf, src_buf_len); if (rc != RCODE_OKAY) { - fprintf(stderr, "dns_decode() = (%d) %s\n", rc, dns_rcode_text(rc)); - return -1; + DBG_PRINTF("dns_decode() = (%d) %s", rc, dns_rcode_text(rc)); + return respond_and_free_slot(slot, s_ctx, s_ctx_len, RCODE_SERVER_FAILURE); } const dns_query_t *query = (dns_query_t*) packet; - if (!query->query) { - fprintf(stderr, "dns record is not a query\n"); - return -1; + DBG_PRINTF("dns record is not a query", NULL); + return respond_and_free_slot(slot, s_ctx, s_ctx_len, RCODE_REFUSED); } if (query->qdcount != 1) { - fprintf(stderr, "dns record should contain exactly one query\n"); - return -1; + DBG_PRINTF("dns record should contain exactly one query", NULL); + return respond_and_free_slot(slot, s_ctx, s_ctx_len, RCODE_REFUSED); } const dns_question_t *question = &query->questions[0]; if (question->type != RR_TXT) { - fprintf(stderr, "query type is not TXT\n"); - return -1; + DBG_PRINTF("query type is not TXT", NULL); + return respond_and_free_slot(slot, s_ctx, s_ctx_len, RCODE_REFUSED); } - const size_t data_len = strlen(question->name) - server_domain_name_len - 1 - 1; + const ssize_t data_len = strlen(question->name) - server_domain_name_len - 1 - 1; + if (data_len <= 0) { + DBG_PRINTF("subdomain is empty", NULL); + return respond_and_free_slot(slot, s_ctx, s_ctx_len, RCODE_REFUSED); + } // copy the subdomain from name to a new buffer char data_buf[data_len]; @@ -153,8 +209,8 @@ ssize_t server_decode(picoquic_quic_t* quic, picoquic_socket_ctx_t* s_ctx, size_ const size_t decoded_len = b32_decode(decoded_buf, data_buf, encoded_len, false); if (decoded_len == (size_t) -1) { free(decoded_buf); - fprintf(stderr, "error decoding base32: %lu\n", decoded_len); - return -1; + DBG_PRINTF("error decoding base32: %lu", decoded_len); + return respond_and_free_slot(slot, s_ctx, s_ctx_len, RCODE_SERVER_FAILURE); } picoquic_connection_id_t incoming_src_connection_id = {0}; @@ -165,8 +221,8 @@ ssize_t server_decode(picoquic_quic_t* quic, picoquic_socket_ctx_t* s_ctx, size_ &incoming_src_connection_id, &incoming_dest_connection_id, &is_poll_packet); if (ret != 0) { free(decoded_buf); - fprintf(stderr, "error parsing slipstream packet: %d\n", ret); - return -1; + DBG_PRINTF("error parsing slipstream packet: %d", ret); + return respond_and_free_slot(slot, s_ctx, s_ctx_len, RCODE_SERVER_FAILURE); } picoquic_cnx_t *cnx = picoquic_cnx_by_id_(quic, incoming_dest_connection_id); @@ -181,10 +237,11 @@ ssize_t server_decode(picoquic_quic_t* quic, picoquic_socket_ctx_t* s_ctx, size_ &slipstream_server_dns_request_buffer, &initial_cnxid, true); if (cnxid_buffer == NULL) { free(decoded_buf); - fprintf(stderr, "error getting or creating cnxid buffer\n"); - return -1; + DBG_PRINTF("error getting or creating cnxid buffer", NULL); + return respond_and_free_slot(slot, s_ctx, s_ctx_len, RCODE_SERVER_FAILURE); } + slot->query_id = query->id; slipstream_dns_request_buffer_commit_slot_to_cnxid_buffer(&slipstream_server_dns_request_buffer, cnxid_buffer, slot); if (is_poll_packet) { @@ -295,6 +352,28 @@ int slipstream_server_sockloop_callback(picoquic_quic_t* quic, picoquic_packet_l slipstream_server_ctx_t* server_ctx = callback_ctx; switch (cb_mode) { + case picoquic_packet_loop_after_select: + const picoquic_socket_ctxs_t* s_ctxs = (picoquic_socket_ctxs_t*)callback_arg; + + uint64_t current_time = picoquic_current_time(); + for (int i = 0; i < slipstream_server_dns_request_buffer.cnxid_buffers_len; ++i) { + const slipstream_cnxid_dns_request_buffer_t* cnxid_buffer = slipstream_server_dns_request_buffer.cnxid_buffers[i]; + assert(cnxid_buffer != NULL); + slot_t* slot = cnxid_buffer->tail; + while (slot != NULL) { + const uint64_t age = current_time - slot->created_time; + if (age < 10000) { + DBG_PRINTF("[%d][age:%d] found young slot", slot->query_id, age); + break; + } + + // attempt to reply before resolver retries + DBG_PRINTF("[%d][age:%d] freeing old slot", slot->query_id, age); + respond_and_free_slot(slot, s_ctxs->s_ctx, s_ctxs->len, RCODE_NAME_ERROR); + slot = slot->cnxid_buffer_prev; + } + } + break; case picoquic_packet_loop_wake_up: if (callback_ctx == NULL) { return 0; diff --git a/unbound.conf b/unbound.conf new file mode 100755 index 0000000..4db3733 --- /dev/null +++ b/unbound.conf @@ -0,0 +1,22 @@ +server: + interface: 0.0.0.0 + access-control: 0.0.0.0/0 allow + do-not-query-localhost: no + verbosity: 1 + do-tcp: no + log-queries: yes + log-replies: yes + +remote-control: + control-enable: yes + control-interface: 0.0.0.0 + control-port: 8953 + control-use-cert: no + +stub-zone: + name: "test.com" + stub-addr: 127.0.0.3@8853 + +forward-zone: + name: "." + forward-addr: 10.64.0.1