From 8feb8a7b99e4d48355cbfc0defede5171f83bdda Mon Sep 17 00:00:00 2001 From: "W.C.A. Wijngaards" Date: Thu, 24 Aug 2023 18:08:16 +0200 Subject: [PATCH] - dnsoverquic, fix for newer ngtcp2. --- config.h.in | 44 ++++++++++ configure | 38 ++++++++- configure.ac | 6 +- services/listen_dnsport.c | 92 +++++++++++++++++++-- services/listen_dnsport.h | 5 ++ testcode/doqclient.c | 166 ++++++++++++++++++++++++++++++++++++-- util/netevent.c | 40 ++++++++- util/netevent.h | 2 + 8 files changed, 371 insertions(+), 22 deletions(-) diff --git a/config.h.in b/config.h.in index 97887a2fa..5f6ef2867 100644 --- a/config.h.in +++ b/config.h.in @@ -423,12 +423,48 @@ /* Define to 1 if you have the `ngtcp2_ccerr_default' function. */ #undef HAVE_NGTCP2_CCERR_DEFAULT +/* Define to 1 if you have the `ngtcp2_conn_encode_0rtt_transport_params' + function. */ +#undef HAVE_NGTCP2_CONN_ENCODE_0RTT_TRANSPORT_PARAMS + +/* Define to 1 if you have the `ngtcp2_conn_get_max_local_streams_uni' + function. */ +#undef HAVE_NGTCP2_CONN_GET_MAX_LOCAL_STREAMS_UNI + +/* Define to 1 if you have the `ngtcp2_conn_get_num_scid' function. */ +#undef HAVE_NGTCP2_CONN_GET_NUM_SCID + +/* Define to 1 if you have the `ngtcp2_conn_in_closing_period' function. */ +#undef HAVE_NGTCP2_CONN_IN_CLOSING_PERIOD + +/* Define to 1 if you have the `ngtcp2_conn_in_draining_period' function. */ +#undef HAVE_NGTCP2_CONN_IN_DRAINING_PERIOD + /* Define if ngtcp2_conn_shutdown_stream has 4 arguments. */ #undef HAVE_NGTCP2_CONN_SHUTDOWN_STREAM4 +/* Define to 1 if you have the `ngtcp2_conn_tls_early_data_rejected' function. + */ +#undef HAVE_NGTCP2_CONN_TLS_EARLY_DATA_REJECTED + /* Define to 1 if you have the `ngtcp2_crypto_encrypt_cb' function. */ #undef HAVE_NGTCP2_CRYPTO_ENCRYPT_CB +/* Define to 1 if you have the + `ngtcp2_crypto_quictls_configure_client_context' function. */ +#undef HAVE_NGTCP2_CRYPTO_QUICTLS_CONFIGURE_CLIENT_CONTEXT + +/* Define to 1 if you have the + `ngtcp2_crypto_quictls_configure_server_context' function. */ +#undef HAVE_NGTCP2_CRYPTO_QUICTLS_CONFIGURE_SERVER_CONTEXT + +/* Define to 1 if you have the + `ngtcp2_crypto_quictls_from_ossl_encryption_level' function. */ +#undef HAVE_NGTCP2_CRYPTO_QUICTLS_FROM_OSSL_ENCRYPTION_LEVEL + +/* Define to 1 if the system has the type `ngtcp2_encryption_level'. */ +#undef HAVE_NGTCP2_ENCRYPTION_LEVEL + /* Define to 1 if you have the header file. */ #undef HAVE_NGTCP2_NGTCP2_CRYPTO_OPENSSL_H @@ -648,9 +684,17 @@ /* Define to 1 if `tokenlen' is a member of `struct ngtcp2_pkt_hd'. */ #undef HAVE_STRUCT_NGTCP2_PKT_HD_TOKENLEN +/* Define to 1 if `max_tx_udp_payload_size' is a member of `struct + ngtcp2_settings'. */ +#undef HAVE_STRUCT_NGTCP2_SETTINGS_MAX_TX_UDP_PAYLOAD_SIZE + /* Define to 1 if `tokenlen' is a member of `struct ngtcp2_settings'. */ #undef HAVE_STRUCT_NGTCP2_SETTINGS_TOKENLEN +/* Define to 1 if `original_dcid_present' is a member of `struct + ngtcp2_transport_params'. */ +#undef HAVE_STRUCT_NGTCP2_TRANSPORT_PARAMS_ORIGINAL_DCID_PRESENT + /* Define to 1 if the system has the type `struct ngtcp2_version_cid'. */ #undef HAVE_STRUCT_NGTCP2_VERSION_CID diff --git a/configure b/configure index dcc533371..77a3a8123 100755 --- a/configure +++ b/configure @@ -20219,7 +20219,7 @@ if test "x$ac_cv_lib_ngtcp2_crypto_quictls_ngtcp2_crypto_encrypt_cb" = xyes; the LIBS="$LIBS -lngtcp2_crypto_quictls" fi - for ac_func in ngtcp2_crypto_encrypt_cb ngtcp2_ccerr_default + for ac_func in ngtcp2_crypto_encrypt_cb ngtcp2_ccerr_default ngtcp2_conn_in_closing_period ngtcp2_conn_in_draining_period ngtcp2_conn_get_max_local_streams_uni ngtcp2_crypto_quictls_from_ossl_encryption_level ngtcp2_crypto_quictls_configure_server_context ngtcp2_crypto_quictls_configure_client_context ngtcp2_conn_get_num_scid ngtcp2_conn_tls_early_data_rejected ngtcp2_conn_encode_0rtt_transport_params do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" @@ -20255,6 +20255,18 @@ cat >>confdefs.h <<_ACEOF _ACEOF +fi +ac_fn_c_check_type "$LINENO" "ngtcp2_encryption_level" "ac_cv_type_ngtcp2_encryption_level" "$ac_includes_default + #include + +" +if test "x$ac_cv_type_ngtcp2_encryption_level" = xyes; then : + +cat >>confdefs.h <<_ACEOF +#define HAVE_NGTCP2_ENCRYPTION_LEVEL 1 +_ACEOF + + fi ac_fn_c_check_member "$LINENO" "struct ngtcp2_pkt_hd" "tokenlen" "ac_cv_member_struct_ngtcp2_pkt_hd_tokenlen" "$ac_includes_default @@ -20280,6 +20292,30 @@ cat >>confdefs.h <<_ACEOF _ACEOF +fi +ac_fn_c_check_member "$LINENO" "struct ngtcp2_settings" "max_tx_udp_payload_size" "ac_cv_member_struct_ngtcp2_settings_max_tx_udp_payload_size" "$ac_includes_default + #include + +" +if test "x$ac_cv_member_struct_ngtcp2_settings_max_tx_udp_payload_size" = xyes; then : + +cat >>confdefs.h <<_ACEOF +#define HAVE_STRUCT_NGTCP2_SETTINGS_MAX_TX_UDP_PAYLOAD_SIZE 1 +_ACEOF + + +fi +ac_fn_c_check_member "$LINENO" "struct ngtcp2_transport_params" "original_dcid_present" "ac_cv_member_struct_ngtcp2_transport_params_original_dcid_present" "$ac_includes_default + #include + +" +if test "x$ac_cv_member_struct_ngtcp2_transport_params_original_dcid_present" = xyes; then : + +cat >>confdefs.h <<_ACEOF +#define HAVE_STRUCT_NGTCP2_TRANSPORT_PARAMS_ORIGINAL_DCID_PRESENT 1 +_ACEOF + + fi diff --git a/configure.ac b/configure.ac index 96f979a3c..6f7f3e2c4 100644 --- a/configure.ac +++ b/configure.ac @@ -1534,12 +1534,12 @@ if test x_$withval = x_yes -o x_$withval != x_no; then ]) AC_CHECK_LIB([ngtcp2_crypto_openssl], [ngtcp2_crypto_encrypt_cb], [ LIBS="$LIBS -lngtcp2_crypto_openssl" ]) AC_CHECK_LIB([ngtcp2_crypto_quictls], [ngtcp2_crypto_encrypt_cb], [ LIBS="$LIBS -lngtcp2_crypto_quictls" ]) - AC_CHECK_FUNCS([ngtcp2_crypto_encrypt_cb ngtcp2_ccerr_default]) + AC_CHECK_FUNCS([ngtcp2_crypto_encrypt_cb ngtcp2_ccerr_default ngtcp2_conn_in_closing_period ngtcp2_conn_in_draining_period ngtcp2_conn_get_max_local_streams_uni ngtcp2_crypto_quictls_from_ossl_encryption_level ngtcp2_crypto_quictls_configure_server_context ngtcp2_crypto_quictls_configure_client_context ngtcp2_conn_get_num_scid ngtcp2_conn_tls_early_data_rejected ngtcp2_conn_encode_0rtt_transport_params]) AC_CHECK_FUNCS([SSL_is_quic], [], [AC_MSG_ERROR([No QUIC support detected in OpenSSL. Need OpenSSL version with QUIC support to enable DNS over QUIC with libngtcp2.])]) - AC_CHECK_TYPES([struct ngtcp2_version_cid],,,[AC_INCLUDES_DEFAULT + AC_CHECK_TYPES([struct ngtcp2_version_cid, ngtcp2_encryption_level],,,[AC_INCLUDES_DEFAULT #include ]) - AC_CHECK_MEMBERS([struct ngtcp2_pkt_hd.tokenlen, struct ngtcp2_settings.tokenlen],,,[AC_INCLUDES_DEFAULT + AC_CHECK_MEMBERS([struct ngtcp2_pkt_hd.tokenlen, struct ngtcp2_settings.tokenlen, struct ngtcp2_settings.max_tx_udp_payload_size, struct ngtcp2_transport_params.original_dcid_present],,,[AC_INCLUDES_DEFAULT #include ]) diff --git a/services/listen_dnsport.c b/services/listen_dnsport.c index 956f740e8..5c37a12f1 100644 --- a/services/listen_dnsport.c +++ b/services/listen_dnsport.c @@ -4196,8 +4196,10 @@ doq_handshake_completed_cb(ngtcp2_conn* ATTR_UNUSED(conn), void* user_data) verbose(VERB_ALGO, "doq handshake_completed callback"); verbose(VERB_ALGO, "ngtcp2_conn_get_max_data_left is %d", (int)ngtcp2_conn_get_max_data_left(doq_conn->conn)); +#ifdef HAVE_NGTCP2_CONN_GET_MAX_LOCAL_STREAMS_UNI verbose(VERB_ALGO, "ngtcp2_conn_get_max_local_streams_uni is %d", (int)ngtcp2_conn_get_max_local_streams_uni(doq_conn->conn)); +#endif verbose(VERB_ALGO, "ngtcp2_conn_get_streams_uni_left is %d", (int)ngtcp2_conn_get_streams_uni_left(doq_conn->conn)); verbose(VERB_ALGO, "ngtcp2_conn_get_streams_bidi_left is %d", @@ -4275,7 +4277,12 @@ doq_recv_stream_data_cb(ngtcp2_conn* ATTR_UNUSED(conn), uint32_t flags, verbose(VERB_ALGO, "doq recv stream data stream id %d offset %d " "datalen %d%s%s", (int)stream_id, (int)offset, (int)datalen, ((flags&NGTCP2_STREAM_DATA_FLAG_FIN)!=0?" FIN":""), - ((flags&NGTCP2_STREAM_DATA_FLAG_EARLY)!=0?" EARLY":"")); +#ifdef NGTCP2_STREAM_DATA_FLAG_0RTT + ((flags&NGTCP2_STREAM_DATA_FLAG_0RTT)!=0?" 0RTT":"") +#else + ((flags&NGTCP2_STREAM_DATA_FLAG_EARLY)!=0?" EARLY":"") +#endif + ); stream = doq_stream_find(doq_conn, stream_id); if(!stream) { verbose(VERB_ALGO, "doq: received stream data for " @@ -4398,6 +4405,7 @@ doq_log_printf_cb(void* ATTR_UNUSED(user_data), const char* fmt, ...) va_end(ap); } +#ifndef HAVE_NGTCP2_CRYPTO_QUICTLS_CONFIGURE_SERVER_CONTEXT /** the doq application tx key callback, false on failure */ static int doq_application_tx_key_cb(struct doq_conn* conn) @@ -4407,8 +4415,10 @@ doq_application_tx_key_cb(struct doq_conn* conn) * the client instead initiates by opening bidi streams. */ verbose(VERB_ALGO, "doq ngtcp2_conn_get_max_data_left is %d", (int)ngtcp2_conn_get_max_data_left(conn->conn)); +#ifdef HAVE_NGTCP2_CONN_GET_MAX_LOCAL_STREAMS_UNI verbose(VERB_ALGO, "doq ngtcp2_conn_get_max_local_streams_uni is %d", (int)ngtcp2_conn_get_max_local_streams_uni(conn->conn)); +#endif verbose(VERB_ALGO, "doq ngtcp2_conn_get_streams_uni_left is %d", (int)ngtcp2_conn_get_streams_uni_left(conn->conn)); verbose(VERB_ALGO, "doq ngtcp2_conn_get_streams_bidi_left is %d", @@ -4423,8 +4433,17 @@ doq_set_encryption_secrets(SSL *ssl, OSSL_ENCRYPTION_LEVEL ossl_level, size_t secret_len) { struct doq_conn* doq_conn = (struct doq_conn*)SSL_get_app_data(ssl); - ngtcp2_crypto_level level = +#ifdef HAVE_NGTCP2_ENCRYPTION_LEVEL + ngtcp2_encryption_level +#else + ngtcp2_crypto_level +#endif + level = +#ifdef HAVE_NGTCP2_CRYPTO_QUICTLS_FROM_OSSL_ENCRYPTION_LEVEL + ngtcp2_crypto_quictls_from_ossl_encryption_level(ossl_level); +#else ngtcp2_crypto_openssl_from_ossl_encryption_level(ossl_level); +#endif if(read_secret) { verbose(VERB_ALGO, "doq: ngtcp2_crypto_derive_and_install_rx_key for level %d ossl %d", (int)level, (int)ossl_level); @@ -4460,8 +4479,17 @@ doq_add_handshake_data(SSL *ssl, OSSL_ENCRYPTION_LEVEL ossl_level, const uint8_t *data, size_t len) { struct doq_conn* doq_conn = (struct doq_conn*)SSL_get_app_data(ssl); - ngtcp2_crypto_level level = +#ifdef HAVE_NGTCP2_ENCRYPTION_LEVEL + ngtcp2_encryption_level +#else + ngtcp2_crypto_level +#endif + level = +#ifdef HAVE_NGTCP2_CRYPTO_QUICTLS_FROM_OSSL_ENCRYPTION_LEVEL + ngtcp2_crypto_quictls_from_ossl_encryption_level(ossl_level); +#else ngtcp2_crypto_openssl_from_ossl_encryption_level(ossl_level); +#endif int rv; verbose(VERB_ALGO, "doq_add_handshake_data: " @@ -4492,6 +4520,7 @@ doq_send_alert(SSL *ssl, enum ssl_encryption_level_t ATTR_UNUSED(level), doq_conn->tls_alert = alert; return 1; } +#endif /* HAVE_NGTCP2_CRYPTO_QUICTLS_CONFIGURE_SERVER_CONTEXT */ /** ALPN select callback for the doq SSL context */ static int @@ -4514,7 +4543,9 @@ static SSL_CTX* doq_ctx_server_setup(struct doq_server_socket* doq_socket) { char* sid_ctx = "unbound server"; +#ifndef HAVE_NGTCP2_CRYPTO_QUICTLS_CONFIGURE_SERVER_CONTEXT SSL_QUIC_METHOD* quic_method; +#endif SSL_CTX* ctx = SSL_CTX_new(TLS_server_method()); if(!ctx) { log_crypto_err("Could not SSL_CTX_new"); @@ -4575,6 +4606,13 @@ doq_ctx_server_setup(struct doq_server_socket* doq_socket) } SSL_CTX_set_max_early_data(ctx, 0xffffffff); +#ifdef HAVE_NGTCP2_CRYPTO_QUICTLS_CONFIGURE_SERVER_CONTEXT + if(ngtcp2_crypto_quictls_configure_server_context(ctx) != 0) { + log_err("ngtcp2_crypto_quictls_configure_server_context failed"); + SSL_CTX_free(ctx); + return NULL; + } +#else /* The quic_method needs to remain valid during the SSL_CTX * lifetime, so we allocate it. It is freed with the * doq_server_socket. */ @@ -4590,9 +4628,17 @@ doq_ctx_server_setup(struct doq_server_socket* doq_socket) quic_method->flush_flight = doq_flush_flight; quic_method->send_alert = doq_send_alert; SSL_CTX_set_quic_method(ctx, doq_socket->quic_method); +#endif return ctx; } +/** Get the ngtcp2_conn from ssl userdata of type ngtcp2_conn_ref */ +static ngtcp2_conn* doq_conn_ref_get_conn(ngtcp2_crypto_conn_ref* conn_ref) +{ + struct doq_conn* conn = (struct doq_conn*)conn_ref->user_data; + return conn->conn; +} + /** create new SSL session for server connection */ static SSL* doq_ssl_server_setup(SSL_CTX* ctx, struct doq_conn* conn) @@ -4602,7 +4648,13 @@ doq_ssl_server_setup(SSL_CTX* ctx, struct doq_conn* conn) log_crypto_err("doq: SSL_new failed"); return NULL; } +#ifdef HAVE_NGTCP2_CRYPTO_QUICTLS_CONFIGURE_SERVER_CONTEXT + conn->conn_ref.get_conn = &doq_conn_ref_get_conn; + conn->conn_ref.user_data = conn; + SSL_set_app_data(ssl, &conn->conn_ref); +#else SSL_set_app_data(ssl, conn); +#endif SSL_set_accept_state(ssl); SSL_set_quic_early_data_enabled(ssl, 1); return ssl; @@ -4702,6 +4754,9 @@ doq_conn_setup(struct doq_conn* conn, uint8_t* scid, size_t scidlen, ngtcp2_cid_init(¶ms.original_dcid, conn->key.dcid, conn->key.dcidlen); } +#ifdef HAVE_STRUCT_NGTCP2_TRANSPORT_PARAMS_ORIGINAL_DCID_PRESENT + params.original_dcid_present = 1; +#endif doq_fill_rand(conn->doq_socket->rnd, params.stateless_reset_token, sizeof(params.stateless_reset_token)); sv_scid.datalen = conn->doq_socket->sv_scidlen; @@ -4886,7 +4941,12 @@ doq_conn_setup_id_array_and_dcid(struct doq_conn* conn, int doq_conn_setup_conids(struct doq_conn* conn) { - size_t num_scid = ngtcp2_conn_get_num_scid(conn->conn); + size_t num_scid = +#ifndef HAVE_NGTCP2_CONN_GET_NUM_SCID + ngtcp2_conn_get_scid(conn->conn, NULL); +#else + ngtcp2_conn_get_num_scid(conn->conn); +#endif if(num_scid <= 4) { struct ngtcp2_cid ids[4]; /* Usually there are not that many scids when just accepted, @@ -4954,9 +5014,21 @@ doq_conn_start_closing_period(struct comm_point* c, struct doq_conn* conn) ngtcp2_ssize ret; if(!conn) return 1; - if(ngtcp2_conn_is_in_closing_period(conn->conn)) + if( +#ifdef HAVE_NGTCP2_CONN_IN_CLOSING_PERIOD + ngtcp2_conn_in_closing_period(conn->conn) +#else + ngtcp2_conn_is_in_closing_period(conn->conn) +#endif + ) return 1; - if(ngtcp2_conn_is_in_draining_period(conn->conn)) { + if( +#ifdef HAVE_NGTCP2_CONN_IN_DRAINING_PERIOD + ngtcp2_conn_in_draining_period(conn->conn) +#else + ngtcp2_conn_is_in_draining_period(conn->conn) +#endif + ) { doq_conn_write_disable(conn); return 1; } @@ -5031,7 +5103,13 @@ doq_conn_close_error(struct comm_point* c, struct doq_conn* conn) #endif if(!doq_conn_start_closing_period(c, conn)) return 0; - if(ngtcp2_conn_is_in_draining_period(conn->conn)) { + if( +#ifdef HAVE_NGTCP2_CONN_IN_DRAINING_PERIOD + ngtcp2_conn_in_draining_period(conn->conn) +#else + ngtcp2_conn_is_in_draining_period(conn->conn) +#endif + ) { doq_conn_write_disable(conn); return 1; } diff --git a/services/listen_dnsport.h b/services/listen_dnsport.h index 6f607c6ad..984dcc027 100644 --- a/services/listen_dnsport.h +++ b/services/listen_dnsport.h @@ -51,6 +51,7 @@ #endif #ifdef HAVE_NGTCP2 #include +#include #endif struct listen_list; struct config_file; @@ -593,6 +594,10 @@ struct doq_conn { uint8_t tls_alert; /** the ssl context, SSL* */ void* ssl; +#ifdef HAVE_NGTCP2_CRYPTO_QUICTLS_CONFIGURE_SERVER_CONTEXT + /** the connection reference for ngtcp2_conn and userdata in ssl */ + struct ngtcp2_crypto_conn_ref conn_ref; +#endif /** closure packet, if any */ uint8_t* close_pkt; /** length of closure packet. */ diff --git a/testcode/doqclient.c b/testcode/doqclient.c index a9a1c8a1f..f058ccb32 100644 --- a/testcode/doqclient.c +++ b/testcode/doqclient.c @@ -107,6 +107,10 @@ struct doq_client_data { SSL_CTX* ctx; /** SSL object */ SSL* ssl; +#ifdef HAVE_NGTCP2_CRYPTO_QUICTLS_CONFIGURE_CLIENT_CONTEXT + /** the connection reference for ngtcp2_conn and userdata in ssl */ + struct ngtcp2_crypto_conn_ref conn_ref; +#endif /** the quic version to use */ uint32_t quic_version; /** the last error */ @@ -193,8 +197,10 @@ struct doq_client_stream { int query_is_done; }; +#ifndef HAVE_NGTCP2_CRYPTO_QUICTLS_CONFIGURE_CLIENT_CONTEXT /** the quic method struct, must remain valid during the QUIC connection. */ static SSL_QUIC_METHOD quic_method; +#endif /** write handle routine */ static void on_write(struct doq_client_data* data); @@ -202,6 +208,8 @@ static void on_write(struct doq_client_data* data); static void update_timer(struct doq_client_data* data); /** disconnect we are done */ static void disconnect(struct doq_client_data* data); +/** fetch and write the transport file */ +static void early_data_write_transport(struct doq_client_data* data); /** usage of doqclient */ static void usage(char* argv[]) @@ -776,7 +784,11 @@ early_data_is_rejected(struct doq_client_data* data) { int rv; verbose(1, "early data was rejected by the server"); +#ifdef HAVE_NGTCP2_CONN_TLS_EARLY_DATA_REJECTED + rv = ngtcp2_conn_tls_early_data_rejected(data->conn); +#else rv = ngtcp2_conn_early_data_rejected(data->conn); +#endif if(rv != 0) { log_err("ngtcp2_conn_early_data_rejected failed: %s", ngtcp2_strerror(rv)); @@ -814,8 +826,10 @@ handshake_completed(ngtcp2_conn* ATTR_UNUSED(conn), void* user_data) verbose(1, "handshake_completed callback"); verbose(1, "ngtcp2_conn_get_max_data_left is %d", (int)ngtcp2_conn_get_max_data_left(data->conn)); +#ifdef HAVE_NGTCP2_CONN_GET_MAX_LOCAL_STREAMS_UNI verbose(1, "ngtcp2_conn_get_max_local_streams_uni is %d", (int)ngtcp2_conn_get_max_local_streams_uni(data->conn)); +#endif verbose(1, "ngtcp2_conn_get_streams_uni_left is %d", (int)ngtcp2_conn_get_streams_uni_left(data->conn)); verbose(1, "ngtcp2_conn_get_streams_bidi_left is %d", @@ -843,6 +857,9 @@ handshake_completed(ngtcp2_conn* ATTR_UNUSED(conn), void* user_data) verbose(1, "early data was accepted by the server"); } } + if(data->transport_file) { + early_data_write_transport(data); + } return 0; } @@ -856,8 +873,10 @@ extend_max_local_streams_bidi(ngtcp2_conn* ATTR_UNUSED(conn), (int)max_streams); verbose(1, "ngtcp2_conn_get_max_data_left is %d", (int)ngtcp2_conn_get_max_data_left(data->conn)); +#ifdef HAVE_NGTCP2_CONN_GET_MAX_LOCAL_STREAMS_UNI verbose(1, "ngtcp2_conn_get_max_local_streams_uni is %d", (int)ngtcp2_conn_get_max_local_streams_uni(data->conn)); +#endif verbose(1, "ngtcp2_conn_get_streams_uni_left is %d", (int)ngtcp2_conn_get_streams_uni_left(data->conn)); verbose(1, "ngtcp2_conn_get_streams_bidi_left is %d", @@ -878,7 +897,12 @@ recv_stream_data(ngtcp2_conn* ATTR_UNUSED(conn), uint32_t flags, verbose(1, "recv_stream_data stream %d offset %d datalen %d%s%s", (int)stream_id, (int)offset, (int)datalen, ((flags&NGTCP2_STREAM_DATA_FLAG_FIN)!=0?" FIN":""), - ((flags&NGTCP2_STREAM_DATA_FLAG_EARLY)!=0?" EARLY":"")); +#ifdef NGTCP2_STREAM_DATA_FLAG_0RTT + ((flags&NGTCP2_STREAM_DATA_FLAG_0RTT)!=0?" 0RTT":"") +#else + ((flags&NGTCP2_STREAM_DATA_FLAG_EARLY)!=0?" EARLY":"") +#endif + ); if(verbosity > 0) log_hex("data", (void*)data, datalen); if(verbosity > 0) { @@ -1017,8 +1041,13 @@ static struct ngtcp2_conn* conn_client_setup(struct doq_client_data* data) data->quic_version = client_chosen_version; ngtcp2_settings_default(&settings); - if(str_is_ip6(data->svr)) + if(str_is_ip6(data->svr)) { +#ifdef HAVE_STRUCT_NGTCP2_SETTINGS_MAX_TX_UDP_PAYLOAD_SIZE + settings.max_tx_udp_payload_size = 1232; +#else settings.max_udp_payload_size = 1232; +#endif + } settings.rand_ctx.native_handle = data->rnd; if(verbosity > 0) { /* make debug logs */ @@ -1067,6 +1096,7 @@ static struct ngtcp2_conn* conn_client_setup(struct doq_client_data* data) return conn; } +#ifndef HAVE_NGTCP2_CONN_ENCODE_0RTT_TRANSPORT_PARAMS /** write the transport file */ static void transport_file_write(const char* file, struct ngtcp2_transport_params* params) @@ -1101,17 +1131,45 @@ transport_file_write(const char* file, struct ngtcp2_transport_params* params) } fclose(out); } +#endif /* HAVE_NGTCP2_CONN_ENCODE_0RTT_TRANSPORT_PARAMS */ /** fetch and write the transport file */ static void early_data_write_transport(struct doq_client_data* data) { +#ifdef HAVE_NGTCP2_CONN_ENCODE_0RTT_TRANSPORT_PARAMS + FILE* out; + uint8_t buf[1024]; + ngtcp2_ssize len = ngtcp2_conn_encode_0rtt_transport_params(data->conn, + buf, sizeof(buf)); + if(len < 0) { + log_err("ngtcp2_conn_encode_0rtt_transport_params failed: %s", + ngtcp2_strerror(len)); + return; + } + out = fopen(data->transport_file, "w"); + if(!out) { + perror(data->transport_file); + return; + } + if(fwrite(buf, 1, len, out) != 1) { + log_err("fwrite %s failed: %s", data->transport_file, + strerror(errno)); + } + if(ferror(out)) { + verbose(1, "There was an error writing %s: %s", + data->transport_file, strerror(errno)); + } + fclose(out); +#else struct ngtcp2_transport_params params; memset(¶ms, 0, sizeof(params)); ngtcp2_conn_get_remote_transport_params(data->conn, ¶ms); transport_file_write(data->transport_file, ¶ms); +#endif } +#ifndef HAVE_NGTCP2_CRYPTO_QUICTLS_CONFIGURE_CLIENT_CONTEXT /** applicatation rx key callback, this is where the rx key is set, * and streams can be opened, like http3 unidirectional streams, like * the http3 control and http3 qpack encode and decoder streams. */ @@ -1121,8 +1179,10 @@ application_rx_key_cb(struct doq_client_data* data) verbose(1, "application_rx_key_cb callback"); verbose(1, "ngtcp2_conn_get_max_data_left is %d", (int)ngtcp2_conn_get_max_data_left(data->conn)); +#ifdef HAVE_NGTCP2_CONN_GET_MAX_LOCAL_STREAMS_UNI verbose(1, "ngtcp2_conn_get_max_local_streams_uni is %d", (int)ngtcp2_conn_get_max_local_streams_uni(data->conn)); +#endif verbose(1, "ngtcp2_conn_get_streams_uni_left is %d", (int)ngtcp2_conn_get_streams_uni_left(data->conn)); verbose(1, "ngtcp2_conn_get_streams_bidi_left is %d", @@ -1141,8 +1201,17 @@ set_encryption_secrets(SSL *ssl, OSSL_ENCRYPTION_LEVEL ossl_level, { struct doq_client_data* data = (struct doq_client_data*) SSL_get_app_data(ssl); - ngtcp2_crypto_level level = +#ifdef HAVE_NGTCP2_ENCRYPTION_LEVEL + ngtcp2_encryption_level +#else + ngtcp2_crypto_level +#endif + level = +#ifdef HAVE_NGTCP2_CRYPTO_QUICTLS_FROM_OSSL_ENCRYPTION_LEVEL + ngtcp2_crypto_quictls_from_ossl_encryption_level(ossl_level); +#else ngtcp2_crypto_openssl_from_ossl_encryption_level(ossl_level); +#endif if(read_secret) { if(ngtcp2_crypto_derive_and_install_rx_key(data->conn, NULL, @@ -1173,8 +1242,17 @@ add_handshake_data(SSL *ssl, OSSL_ENCRYPTION_LEVEL ossl_level, { struct doq_client_data* doqdata = (struct doq_client_data*) SSL_get_app_data(ssl); - ngtcp2_crypto_level level = +#ifdef HAVE_NGTCP2_ENCRYPTION_LEVEL + ngtcp2_encryption_level +#else + ngtcp2_crypto_level +#endif + level = +#ifdef HAVE_NGTCP2_CRYPTO_QUICTLS_FROM_OSSL_ENCRYPTION_LEVEL + ngtcp2_crypto_quictls_from_ossl_encryption_level(ossl_level); +#else ngtcp2_crypto_openssl_from_ossl_encryption_level(ossl_level); +#endif int rv; rv = ngtcp2_conn_submit_crypto_data(doqdata->conn, level, data, len); @@ -1204,6 +1282,7 @@ send_alert(SSL *ssl, enum ssl_encryption_level_t ATTR_UNUSED(level), data->tls_alert = alert; return 1; } +#endif /* HAVE_NGTCP2_CRYPTO_QUICTLS_CONFIGURE_CLIENT_CONTEXT */ /** new session callback. We can write it to file for resumption later. */ static int @@ -1238,15 +1317,31 @@ ctx_client_setup(void) SSL_CTX_set_min_proto_version(ctx, TLS1_3_VERSION); SSL_CTX_set_max_proto_version(ctx, TLS1_3_VERSION); SSL_CTX_set_default_verify_paths(ctx); +#ifdef HAVE_NGTCP2_CRYPTO_QUICTLS_CONFIGURE_CLIENT_CONTEXT + if(ngtcp2_crypto_quictls_configure_client_context(ctx) != 0) { + log_err("ngtcp2_crypto_quictls_configure_client_context failed"); + exit(1); + } +#else memset(&quic_method, 0, sizeof(quic_method)); quic_method.set_encryption_secrets = &set_encryption_secrets; quic_method.add_handshake_data = &add_handshake_data; quic_method.flush_flight = &flush_flight; quic_method.send_alert = &send_alert; SSL_CTX_set_quic_method(ctx, &quic_method); +#endif return ctx; } +/** Get the connection ngtcp2_conn from the ssl app data + * ngtcp2_crypto_conn_ref */ +static ngtcp2_conn* conn_ref_get_conn(ngtcp2_crypto_conn_ref* conn_ref) +{ + struct doq_client_data* data = (struct doq_client_data*) + conn_ref->user_data; + return data->conn; +} + /* setup the TLS object */ static SSL* ssl_client_setup(struct doq_client_data* data) @@ -1256,7 +1351,13 @@ ssl_client_setup(struct doq_client_data* data) log_crypto_err("Could not SSL_new"); exit(1); } +#ifdef HAVE_NGTCP2_CRYPTO_QUICTLS_CONFIGURE_CLIENT_CONTEXT + data->conn_ref.get_conn = &conn_ref_get_conn; + data->conn_ref.user_data = data; + SSL_set_app_data(ssl, &data->conn_ref); +#else SSL_set_app_data(ssl, data); +#endif SSL_set_connect_state(ssl); if(!SSL_set_fd(ssl, data->fd)) { log_crypto_err("Could not SSL_set_fd"); @@ -1402,8 +1503,18 @@ write_conn_close(struct doq_client_data* data) struct ngtcp2_path_storage ps; struct ngtcp2_pkt_info pi; ngtcp2_ssize ret; - if(!data->conn || ngtcp2_conn_is_in_closing_period(data->conn) || - ngtcp2_conn_is_in_draining_period(data->conn)) + if(!data->conn || +#ifdef HAVE_NGTCP2_CONN_IN_CLOSING_PERIOD + ngtcp2_conn_in_closing_period(data->conn) || +#else + ngtcp2_conn_is_in_closing_period(data->conn) || +#endif +#ifdef HAVE_NGTCP2_CONN_IN_DRAINING_PERIOD + ngtcp2_conn_in_draining_period(data->conn) +#else + ngtcp2_conn_is_in_draining_period(data->conn) +#endif + ) return; /* Drop blocked packet if there is one, the connection is being * closed. And thus no further data traffic. */ @@ -1869,7 +1980,13 @@ on_write(struct doq_client_data* data) if(!send_blocked_pkt(data)) return; } - if(ngtcp2_conn_is_in_closing_period(data->conn)) + if( +#ifdef HAVE_NGTCP2_CONN_IN_CLOSING_PERIOD + ngtcp2_conn_in_closing_period(data->conn) +#else + ngtcp2_conn_is_in_closing_period(data->conn) +#endif + ) return; if(!write_streams(data)) return; @@ -1933,6 +2050,7 @@ early_data_setup_session(struct doq_client_data* data) return 1; } +#ifndef HAVE_NGTCP2_CONN_ENCODE_0RTT_TRANSPORT_PARAMS /** parse one line from the transport file */ static int transport_parse_line(struct ngtcp2_transport_params* params, char* line) @@ -1971,11 +2089,44 @@ transport_parse_line(struct ngtcp2_transport_params* params, char* line) } return 0; } +#endif /* HAVE_NGTCP2_CONN_ENCODE_0RTT_TRANSPORT_PARAMS */ /** setup the early data transport file and read it */ static int early_data_setup_transport(struct doq_client_data* data) { +#ifdef HAVE_NGTCP2_CONN_ENCODE_0RTT_TRANSPORT_PARAMS + FILE* in; + uint8_t buf[1024]; + size_t len; + int rv; + in = fopen(data->transport_file, "r"); + if(!in) { + if(errno == ENOENT) { + verbose(1, "transport file %s does not exist", + data->transport_file); + return 0; + } + perror(data->transport_file); + return 0; + } + len = fread(buf, 1, sizeof(buf), in); + if(ferror(in)) { + log_err("%s: read failed: %s", data->transport_file, + strerror(errno)); + fclose(in); + return 0; + } + fclose(in); + rv = ngtcp2_conn_decode_and_set_0rtt_transport_params(data->conn, + buf, len); + if(rv != 0) { + log_err("ngtcp2_conn_decode_and_set_0rtt_transport_params failed: %s", + ngtcp2_strerror(rv)); + return 0; + } + return 1; +#else FILE* in; char buf[1024]; struct ngtcp2_transport_params params; @@ -2006,6 +2157,7 @@ early_data_setup_transport(struct doq_client_data* data) } fclose(in); ngtcp2_conn_set_early_remote_transport_params(data->conn, ¶ms); +#endif return 1; } diff --git a/util/netevent.c b/util/netevent.c index e93fe0e78..e2284603f 100644 --- a/util/netevent.c +++ b/util/netevent.c @@ -2323,8 +2323,17 @@ doq_timer_cb(void* arg) while((conn = doq_timer_timeout_conn(doq_socket)) != NULL) { if(conn->is_deleted || +#ifdef HAVE_NGTCP2_CONN_IN_CLOSING_PERIOD + ngtcp2_conn_in_closing_period(conn->conn) || +#else ngtcp2_conn_is_in_closing_period(conn->conn) || - ngtcp2_conn_is_in_draining_period(conn->conn)) { +#endif +#ifdef HAVE_NGTCP2_CONN_IN_DRAINING_PERIOD + ngtcp2_conn_in_draining_period(conn->conn) +#else + ngtcp2_conn_is_in_draining_period(conn->conn) +#endif + ) { if(verbosity >= VERB_ALGO) { char remotestr[256]; addr_to_str((void*)&conn->key.paddr.addr, @@ -2385,8 +2394,17 @@ comm_point_doq_callback(int fd, short event, void* arg) num_len = doq_write_list_length(c); while((conn = doq_pop_write_conn(c)) != NULL) { if(conn->is_deleted || +#ifdef HAVE_NGTCP2_CONN_IN_CLOSING_PERIOD + ngtcp2_conn_in_closing_period(conn->conn) || +#else ngtcp2_conn_is_in_closing_period(conn->conn) || - ngtcp2_conn_is_in_draining_period(conn->conn)) { +#endif +#ifdef HAVE_NGTCP2_CONN_IN_DRAINING_PERIOD + ngtcp2_conn_in_draining_period(conn->conn) +#else + ngtcp2_conn_is_in_draining_period(conn->conn) +#endif + ) { conn->doq_socket = NULL; lock_basic_unlock(&conn->lock); if(c->doq_socket->have_blocked_pkt) { @@ -2483,7 +2501,13 @@ comm_point_doq_callback(int fd, short event, void* arg) doq_done_setup_timer_and_write(c, conn); continue; } - if(ngtcp2_conn_is_in_closing_period(conn->conn)) { + if( +#ifdef HAVE_NGTCP2_CONN_IN_CLOSING_PERIOD + ngtcp2_conn_in_closing_period(conn->conn) +#else + ngtcp2_conn_is_in_closing_period(conn->conn) +#endif + ) { if(!doq_conn_send_close(c, conn)) { doq_delete_connection(c, conn); } else { @@ -2491,7 +2515,13 @@ comm_point_doq_callback(int fd, short event, void* arg) } continue; } - if(ngtcp2_conn_is_in_draining_period(conn->conn)) { + if( +#ifdef HAVE_NGTCP2_CONN_IN_DRAINING_PERIOD + ngtcp2_conn_in_draining_period(conn->conn) +#else + ngtcp2_conn_is_in_draining_period(conn->conn) +#endif + ) { doq_done_setup_timer_and_write(c, conn); continue; } @@ -2637,7 +2667,9 @@ doq_server_socket_delete(struct doq_server_socket* doq_socket) return; free(doq_socket->static_secret); SSL_CTX_free(doq_socket->ctx); +#ifndef HAVE_NGTCP2_CRYPTO_QUICTLS_CONFIGURE_SERVER_CONTEXT free(doq_socket->quic_method); +#endif free(doq_socket->ssl_service_key); free(doq_socket->ssl_service_pem); free(doq_socket->ssl_verify_pem); diff --git a/util/netevent.h b/util/netevent.h index a698c9563..ac89add8d 100644 --- a/util/netevent.h +++ b/util/netevent.h @@ -1054,8 +1054,10 @@ struct doq_server_socket { size_t static_secret_len; /** ssl context, SSL_CTX* */ void* ctx; +#ifndef HAVE_NGTCP2_CRYPTO_QUICTLS_CONFIGURE_SERVER_CONTEXT /** quic method functions, SSL_QUIC_METHOD* */ void* quic_method; +#endif /** the comm point for this doq server socket */ struct comm_point* cp; /** the buffer for packets, doq in and out */ -- 2.47.2