mirror of
https://github.com/EndPositive/slipstream.git
synced 2025-10-08 12:25:04 +00:00
Improve DNS handling for compatibility with actual resolvers
- included unbound config
This commit is contained in:
parent
eb6c7b538f
commit
16c45883b8
7 changed files with 213 additions and 89 deletions
|
|
@ -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)
|
||||
|
|
|
|||
2
extern/picoquic
vendored
2
extern/picoquic
vendored
|
|
@ -1 +1 @@
|
|||
Subproject commit 7ac027d6e16ef344a19f8e32d49c93a6caef15da
|
||||
Subproject commit afb1a46057b1e506d48d8126b4f958fbc1e9d869
|
||||
|
|
@ -2,21 +2,24 @@
|
|||
#define SLIPSTREAM_DNS_REQUEST_BUFFER
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <picohash.h>
|
||||
#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,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@
|
|||
#ifdef BUILD_LOGLIB
|
||||
#include <autoqlog.h>
|
||||
#endif
|
||||
#include <picohash.h>
|
||||
#include <pthread.h>
|
||||
#include <stdbool.h>
|
||||
#include <arpa/nameser.h>
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
22
unbound.conf
Executable file
22
unbound.conf
Executable file
|
|
@ -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
|
||||
Loading…
Add table
Add a link
Reference in a new issue