From: Frantisek Tobias Date: Mon, 26 May 2025 10:39:26 +0000 (+0200) Subject: daemon/quic: enable QUIC protolayer X-Git-Tag: v6.2.0~2^2~65 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=8a28e004d58ea6ff1414fd6fb386ed9abe7d8891;p=thirdparty%2Fknot-resolver.git daemon/quic: enable QUIC protolayer --- diff --git a/daemon/bindings/net.c b/daemon/bindings/net.c index d9e8f1658..be6c7b7d8 100644 --- a/daemon/bindings/net.c +++ b/daemon/bindings/net.c @@ -142,13 +142,20 @@ static bool net_listen_addrs(lua_State *L, int port, endpoint_flags_t flags, int flags.sock_type = SOCK_DGRAM; ret = network_listen(str, port, nic_queue, flags); } + if (!flags.kind && flags.doq && ret == 0) { + flags.sock_type = SOCK_DGRAM; + ret = network_listen(str, port, nic_queue, flags); + } if (!flags.kind && !flags.xdp && ret == 0) { /* common for TCP, DoT and DoH (v2) */ flags.sock_type = SOCK_STREAM; ret = network_listen(str, port, nic_queue, flags); } if (flags.kind) { flags.kind = strdup(flags.kind); - flags.sock_type = SOCK_STREAM; /* TODO: allow to override this? */ + if (flags.doq) + flags.sock_type = SOCK_DGRAM; + else + flags.sock_type = SOCK_STREAM; /* TODO: allow to override this? */ ret = network_listen(str, (is_unix ? 0 : port), nic_queue, flags); } if (ret == 0) return true; /* success */ diff --git a/daemon/lua/postconfig.lua b/daemon/lua/postconfig.lua index ac71660ee..21e3efebb 100644 --- a/daemon/lua/postconfig.lua +++ b/daemon/lua/postconfig.lua @@ -13,7 +13,8 @@ local function count_sockets() socket.kind == 'xdp' or socket.kind == 'tls' or socket.kind == 'doh_legacy' or - socket.kind == 'doh2') then + socket.kind == 'doh2' or + socket.kind == 'doq') then dns_socks = dns_socks + 1 end end diff --git a/daemon/network.c b/daemon/network.c index a32861cb8..5e491ba6d 100644 --- a/daemon/network.c +++ b/daemon/network.c @@ -439,12 +439,12 @@ static int open_endpoint(const char *addr_str, } /* else */ if (ep->flags.sock_type == SOCK_DGRAM) { - if (kr_fails_assert(!ep->flags.tls)) + if (kr_fails_assert(!ep->flags.tls || ep->flags.doq)) return kr_error(EINVAL); uv_udp_t *ep_handle = malloc(sizeof(uv_udp_t)); ep->handle = (uv_handle_t *)ep_handle; ret = !ep->handle ? ENOMEM - : io_listen_udp(the_network->loop, ep_handle, ep->fd); + : io_listen_udp(the_network->loop, ep_handle, ep->fd, ep->flags.doq); goto finish_ret; } /* else */ diff --git a/daemon/quic.c b/daemon/quic.c index 7b3bdc2c9..334368c5c 100644 --- a/daemon/quic.c +++ b/daemon/quic.c @@ -27,206 +27,6 @@ #include -#define SERVER_DEFAULT_SCIDLEN 18 - -#define ENABLE_QUIC - - -// Macros from knot quic impl -#define SERVER_DEFAULT_SCIDLEN 18 -#define QUIC_REGULAR_TOKEN_TIMEOUT (24 * 3600 * 1000000000LLU) -#define QUIC_SEND_VERSION_NEGOTIATION NGTCP2_ERR_VERSION_NEGOTIATION -#define QUIC_SEND_RETRY NGTCP2_ERR_RETRY -#define QUIC_SEND_STATELESS_RESET (-NGTCP2_STATELESS_RESET_TOKENLEN) -#define QUIC_SEND_CONN_CLOSE (-KNOT_QUIC_HANDLE_RET_CLOSE) -#define QUIC_SEND_EXCESSIVE_LOAD (-KNOT_QUIC_ERR_EXCESSIVE_LOAD) -#define MAX_STREAMS_PER_CONN 10 // this limits the number of un-finished streams per conn (i.e. if response has been recvd with FIN, it doesn't count) - -typedef enum { - KR_QUIC_SEND_IGNORE_LASTBYTE = (1 << 0), - KR_QUIC_SEND_IGNORE_BLOCKED = (1 << 1), -} kr_quic_send_flag_t; - -struct quic_ctx; -// TODO maybe rename to something more in line with iter_data -struct pl_quic_state { - struct protolayer_data h; - struct quic_ctx *quic_ctx; - /* struct ortt_ NOTE: Or some other data */ ; -}; - -struct kr_quic_conn; -typedef struct kr_quic_cid { - uint8_t cid_placeholder[32]; - struct kr_quic_conn *conn; - struct kr_quic_cid *next; -} kr_quic_cid_t; - -typedef enum { - KNOT_QUIC_TABLE_CLIENT_ONLY = (1 << 0), -} kr_quic_table_flag_t; - -typedef struct { - void *get_conn; - void *user_data; -} nc_conn_ref_placeholder_t; - -typedef struct kr_quic_table { - kr_quic_table_flag_t flags; - size_t size; - size_t usage; - size_t pointers; - size_t max_conns; - size_t ibufs_max; - size_t obufs_max; - size_t ibufs_size; - size_t obufs_size; - size_t udp_payload_limit; - void (*log_cb)(const char *); - const char *qlog_dir; - uint64_t hash_secret[4]; - struct tls_credentials *creds; - struct gnutls_priority_st *priority; - struct heap *expiry_heap; - kr_quic_cid_t *conns[]; -} kr_quic_table_t; - -typedef struct kr_quic_obuf { - /*ucw_*/node_t node; - size_t len; - // struct wire_buf buf;? - char buf[]; -} kr_quic_obuf_t; - -typedef enum { - KR_QUIC_CONN_HANDSHAKE_DONE = (1 << 0), - KR_QUIC_CONN_SESSION_TAKEN = (1 << 1), - KR_QUIC_CONN_BLOCKED = (1 << 2), - KR_QUIC_CONN_AUTHORIZED = (1 << 3), -} kr_quic_conn_flag_t; - -typedef struct kr_tcp_inbufs_upd_res { - size_t n_inbufs; - struct kr_tcp_inbufs_upd_res *next; - struct iovec inbufs[]; -} kr_tcp_inbufs_udp_res_t; - -typedef struct kr_quic_stream { - /** the inbuf for small, singlepacket messages - * while the latter is for larger comunications, but still... */ - struct iovec inbuf; - struct kr_tcp_inbufs_upd_res *inbufs; - - size_t firstib_consumed; - /*ucw_*/list_t outbufs; - size_t obufs_size; - - kr_quic_obuf_t *unsent_obuf; - size_t first_offset; - size_t unsent_offset; -} kr_quic_stream_t; - -typedef struct quic_ctx { - ngtcp2_crypto_conn_ref conn_ref; - - // // Parameters - // quic_params_t params; - // - // // Context - // ngtcp2_settings settings; - // struct { - // int64_t id; - // uint64_t out_ack; - // struct iovec in_buffer; - // struct knot_tcp_inbufs_upd_res *in_parsed; - // size_t in_parsed_it; - // size_t in_parsed_total; - // } stream; - // ngtcp2_ccerr last_err; - // uint8_t secret[32]; - - // tls_ctx_t *tls; - - // convenient struct to store Connection ID, its associated path, and stateless reset token. - ngtcp2_cid_token dcid_token; - ngtcp2_cid_token scid_token; - // ngtcp2_cid_token odcid_token; // maybe? - ngtcp2_conn *conn; - ngtcp2_pkt_info pi; - ngtcp2_path path; - quic_state_t state; -} quic_ctx_t; - -typedef struct kr_quic_conn { - int heap_node_placeholder; // MUST be first field of the struct - uint64_t next_expiry; - - // placeholder for internal struct ngtcp2_crypto_conn_ref - nc_conn_ref_placeholder_t conn_ref; - - // conn_table next conn link - struct ngtcp2_conn *conn; - struct kr_quic_conn *next; - - gnutls_session_t tls_session; - - // crypto callbacks - ngtcp2_crypto_conn_ref crypto_ref; - - // QUIC stream abstraction - kr_quic_stream_t *streams; - // number of allocated streams structures - int16_t streams_count; - // index of first stream that has complete incomming data to be processed (aka inbuf_fin) - int16_t stream_inprocess; - // stream_id/4 of first allocated stream - int64_t first_stream_id; - - ngtcp2_ccerr last_error; - kr_quic_conn_flag_t flags; - int qlog_fd; - - // TODO: consider removing - size_t ibufs_size; - size_t obufs_size; - - // TODO: Definitelly move - ngtcp2_pkt_info pi; - - // back-pointer - struct kr_quic_table *quic_table; -} kr_quic_conn_t; - -typedef struct pl_quic_sess_data { - struct protolayer_data h; - // ngtcp2_conn *conns; This one might be wrong - // ngtcp2_crypto_conn_ref conn_ref; - // Parameters - quic_params_t params; - ngtcp2_settings settings; - - // Context - // struct { - // int64_t id; - // uint64_t out_ack; - // struct iovec in_buffer; - // struct knot_tcp_inbufs_upd_res *in_parsed; - // size_t in_parsed_it; - // size_t in_parsed_total; - // } stream; - // ngtcp2_ccerr last_err; - // uint8_t secret[32]; - - uint32_t conn_count; - protolayer_iter_ctx_queue_t unwrap_queue; - protolayer_iter_ctx_queue_t wrap_queue; - - kr_quic_table_t *conn_table; - - struct kr_request *req; - quic_state_t state; - struct wire_buf wire_buf; -} pl_quic_sess_data_t; static uint64_t cid2hash(const ngtcp2_cid *cid, kr_quic_table_t *table); kr_quic_conn_t *kr_quic_table_lookup(const ngtcp2_cid *cid, kr_quic_table_t *table); diff --git a/daemon/quic.h b/daemon/quic.h index 9edfbc0cc..1713ef085 100644 --- a/daemon/quic.h +++ b/daemon/quic.h @@ -10,6 +10,28 @@ #include // #include "daemon/tls.h" +#include +#include +#include +#include "lib/log.h" +#include "session2.h" +#include "network.h" +#include "lib/resolve.h" +// #include "libknot/quic/quic.h" +#include "libdnssec/random.h" +#include +#include +#include +#include "contrib/openbsd/siphash.h" +#include "lib/utils.h" +#include "libdnssec/error.h" + +#include +#include + +#include + + #define MAX_QUIC_FRAME_SIZE 65536 typedef enum { @@ -222,5 +244,5 @@ typedef struct pl_quic_sess_data { struct kr_request *req; quic_state_t state; - struct wire_buf wire_buf; + // struct wire_buf wire_buf; } pl_quic_sess_data_t; diff --git a/daemon/session2.c b/daemon/session2.c index 1712037c7..0c729476a 100644 --- a/daemon/session2.c +++ b/daemon/session2.c @@ -67,11 +67,12 @@ static const enum protolayer_type protolayer_grp_doh[] = { }; static const enum protolayer_type protolayer_grp_doq[] = { - // PROTOLAYER_TYPE_UDP, + PROTOLAYER_TYPE_UDP, // PROTOLAYER_TYPE_PROXYV2_DGRAM, // PROTOLAYER_TYPE_DEFER, PROTOLAYER_TYPE_QUIC, // PROTOLAYER_TYPE_DNS_DGRAM, + // PROTOLAYER_TYPE_NULL, }; struct protolayer_grp { @@ -1525,7 +1526,10 @@ static int session2_transport_pushv(struct session2 *s, return kr_ok(); } else { int ret = uv_udp_try_send((uv_udp_t*)handle, (uv_buf_t *)iov, iovcnt, - the_network->enable_connect_udp ? NULL : comm->comm_addr); + the_network->enable_connect_udp + && s->proto != KR_PROTO_DOQ + ? NULL : comm->comm_addr); + if (ret > 0) // equals buffer size, only confuses us ret = 0; if (ret == UV_EAGAIN) { diff --git a/daemon/tls.h b/daemon/tls.h index b24b61658..63eaa0534 100644 --- a/daemon/tls.h +++ b/daemon/tls.h @@ -15,6 +15,7 @@ #define MAX_TLS_PADDING KR_EDNS_PAYLOAD #define TLS_MAX_UNCORK_RETRIES 100 +#define ENABLE_QUIC /* rfc 5476, 7.3 - handshake Protocol overview * https://tools.ietf.org/html/rfc5246#page-33 @@ -44,6 +45,10 @@ struct tls_credentials { gnutls_certificate_credentials_t credentials; time_t valid_until; char *ephemeral_servicename; +#ifdef ENABLE_QUIC + gnutls_anti_replay_t tls_anti_replay; + // gnutls_datum_t tls_ticket_key; +#endif /* ENABLE_QUIC */ }; diff --git a/lib/defines.h b/lib/defines.h index 1ee0ac4e0..e8daf884d 100644 --- a/lib/defines.h +++ b/lib/defines.h @@ -81,6 +81,7 @@ const char * kr_strerror(int e) #define KR_DNS_PORT 53 #define KR_DNS_DOH_PORT 443 #define KR_DNS_TLS_PORT 853 +#define KR_DNS_DOQ_PORT 853 #define KR_EDNS_VERSION 0 #define KR_EDNS_PAYLOAD 1232 /* Default UDP payload; see https://www.dnsflagday.net/2020/ */ #define KR_CACHE_DEFAULT_TTL_MIN (5) /* avoid bursts of queries */ diff --git a/lib/proto.h b/lib/proto.h index 875fe8e30..d91c09e43 100644 --- a/lib/proto.h +++ b/lib/proto.h @@ -26,8 +26,7 @@ XX(TCP53, tcp53, "DNS TCP") \ XX(DOT, dot, "DNS-over-TLS") \ XX(DOH, doh, "DNS-over-HTTPS") \ - XX(DOQ, doq, "DNS-over-QUIC") /* unused for now */ \ - // + XX(DOQ, doq, "DNS-over-QUIC") \ /** DNS protocol set - mutually exclusive options, contrary to * kr_request_qsource_flags diff --git a/python/knot_resolver/datamodel/network_schema.py b/python/knot_resolver/datamodel/network_schema.py index 3d1451697..662cd9d28 100644 --- a/python/knot_resolver/datamodel/network_schema.py +++ b/python/knot_resolver/datamodel/network_schema.py @@ -139,7 +139,7 @@ class ListenSchema(ConfigSchema): return origin.port # default port number based on kind if origin.interface: - if origin.kind == "dot": + if origin.kind == "dot" or origin.kind == "doq": return PortNumber(853) if origin.kind in ["doh-legacy", "doh2"]: return PortNumber(443)