DNSoverQUIC (#871)

* - dnsoverquic, configure --with-libngtcp2 option.

* - dnsoverquic, create comm_point for doq and receive cmsg local address.

* - dnsoverquic, less obtrusive debug.

* - dnsoverquic, log and fix local port number. Neater subroutines and ifdefs.

* - dnsoverquic, add testcode/doqclient.

* - dnsoverquic, review fixes on doqclient.

* - dnsoverquic, fix unit test testbound link.

* - dnsoverquic, parse query in doqclient.

* - dnsoverquic, link with libngtcp2_crypto_openssl and code for doqclient.

* - dnsoverquic, random routine for doqclient and fix ngaddr allocation, and
  check ub_initstate return.

* - dnsoverquic, fix doqclient free of allocated ngaddr addresses.

* - dnsoverquic, enable debug output with -v for doqclient.

* - dnsoverquic, create and set TLS object and TLS context in doqclient.

* - dnsoverquic, work on quic tls context in doqclient.

* - dnsoverquic, set default dnsoverquic port to the standardized 853 port.

* - dnsoverquic, remove debug comment.

* - dnsoverquic, dns-over-quic quic-port: 853 config option.

* - dnsoverquic, log type of interface created at start of unbound.

* - dnsoverquic, log type of no tls https as https when interface is created.

* - dnsoverquic, setup client quic tls methods.

* - dnsoverquic, event work in doqclient.

* - dnsoverquic, explain in documentation that QUIC uses UDP.

* - dnsoverquic, make doqclient exit.

* - dnsoverquic, doqclient cleanup run routine.

* - dnsoverquic, doqclient code nicer.

* - dnsoverquic, doqclient read and timer.

* - dnsoverquic, doqclient write work.

* - dnsoverquic, review fixes.

* - dnsoverquic, detect openssl quic support at configure time.

* - dnsoverquic, do not allow QUIC on port 53 to stop confusion of DoQ and DNS.

* - dnsoverquic, in doqclient, when idle close is returned, drop the connection
  without calling ngtcp2_conn_write_connection_close.

* - dnsoverquic, in doqclient, log callbacks.

* - dnsoverquic, in doqclient add extend_max_local_streams_bidi callback.

* - dnsoverquic, in doqclient add client query lists.

* - dnsoverquic, in doqclient, code cleaner, log text nicer.

* - dnsoverquic, in doqclient, work on write_streams.

* - dnsoverquic, in doqclient, use signed int for stream_id, work on the
  ngtcp2_recv_stream_data callback.

* - dnsoverquic, in doqclient, print result and fixes for recv data.

* - dnsoverquic, in doqclient, add the event callbacks to fptr wlist.

* - dnsoverquic, in doqclient, when already expired, use zero timeout timer.

* - dnsoverquic, in doqclient, ignore unused return codes from
  ngtcp2_conn_writev_stream.

* - dnsoverquic, add doqclient event functions to the unbound-dnstap-socket
  test tool for linking.

* - dnsoverquic, in doqclient, fix multiple operands for the commandline.
  neater dns message output.

* - dnsoverquic, in doqclient, store packet when write blocks and try later.

* - dnsoverquic, in doqclient, limit number of packets and number of bytes sent.

* - dnsoverquic, in doqclient, better size estimate for outgoing packet.

* - dnsoverquic, in doqclient, fix that already written next packet is not
  counted for data length to send.

* - dnsoverquic, in doqclient, early data transmission and session resumption.

* - dnsoverquic, send version negotiation packet.

* - dnsoverquic, send retry and accept the connection.

* - dnsoverquic, storage structures.

* - dnsoverquic, doq connection setup.

* - dnsoverquic, neater code layout for new conn. Fix verbosity of log print.

* - dnsoverquic, doq conn callback functions.

* - dnsoverquic, doq_fill_rand routine in header file.

* - dnsoverquic, keep track of connection ids.

* - dnsoverquic, get_new_connection_id callback.

* - dnsoverquic, create doq_conid tree.

* - dnsoverquic, settings for server connection.

* - dnsoverquic, tls context.

* - dnsoverquic, sendmsg error handling.

* - dnsoverquic, neat code.

* - dnsoverquic, track doq connection last error.

* - dnsoverquic, neater packet address parameters.

* - dnsoverquic, fix uninitialized bytes in msg control in doq sendmsg, and
  fix tree cleanup of conid tree.

* - dnsoverquic, better usage text for doqclient.

* - dnsoverquic, neat code.

* - dnsoverquic, connection receive packet handling.

* - dnsoverquic, debug output.

* - dnsoverquic, debug switched meaning of scid and dcid gives
  ERR_TRANSPORT_PARAM.

* - dnsoverquic, remove debug output.

* - dnsoverquic, connection delete routine and error from connection read in
  more detail with less clutter.

* - dnsoverquic, write to stream, and receive stream data, log packet.

* - dnsoverquic, alpn set up.

* - dnsoverquic, connection close.

* - dnsoverquic, doq_table and locks.

* - dnsoverquic, fix tests.

* - dnsoverquic, better locking.

* - dnsoverquic, doq_stream.

* - dnsoverquic, remove compile warning.

* - dnsoverquic, doq_stream receive data.

* - dnsoverquic, fixes for locks and keep length bytes allocated.

* - dnsoverquic, lock connection on initial insertion.

* - dnsoverquic, reply information, and reply buffer.

* - dnsoverquic, reply info from cache, local-zone and recursion lookups.

* - dnsoverquic, spelling in comment about buffer storage.

* - dnsoverquic, stream write list and doqclient fixes to exit and printout.

* - dnsoverquic, doqclient -q option for short printout.

* - dnsoverquic, unit test with local data reply.

* - dnsoverquic, write connection and write event is set.

* - dnsoverquic, neater logging for write event connection stream writes.

* - dnsoverquic, log remote connection when the streams are written for it.

* - dnsoverquic, better threaded use, threads can write to doq connections at
  the same time.

* - dnsoverquic, unit test for the calculation of connection size with a query.

* - dnsoverquic, use less memory per connection.

* - dnsoverquic, remove unit test output.

* - dnsoverquic, add MSG_DONTWAIT so that there is no mistakenly blocking
  socket operations.

* - dnsoverquic, doqclient logs address on connection failures.

* - dnsoverquic, compat code for clock get time routine.

* - dnsoverquic, use skip_test for doq unit test.

* - dnsoverquic, fixes for proxyprotocol, use remote_addr and set proxyprotocol
  disabled on the doq connection.

* - dnsoverquic, doqclient sets log identity to its name, instead of "unbound".

* - dnsoverquic, handle blocked udp packet writes.

* - dnsoverquic, fix function documentation for verbose_print_addr from
  services/listen_dnsport.c.

* - dnsoverquic, fix doq_conn lock protection. The checklock allows to set
  the output file name, and doqclient uses that. Print place of lock_protect.

* - dnsoverquic, neater buffer clear when write of blocked packet fails, make
  sure that memory area does not overlap for blocked packet addresses when
  write of blocked packet fails, and size blocked packet buffer to the pkt buf.

* - dnsoverquic, move lock check after the test to test script in doq test.

* - dnsoverquic, the doq test uses valgrind when enabled.

* - dnsoverquic, git ignore the doqclient test.

* - dnsoverquic, limit the buffer for packets to max packet size with some more.

* - dnsoverquic, spelling fix.

* - dnsoverquic, timer work, structure and adds and deletes.

* - dnsoverquic, timer_tree uses table.lock.

* - dnsoverquic, fix timer tree remove and spelling in header file comment.

* - dnsoverquic, fix testbound for timer compare function linkage.

* - dnsoverquic, timer set add debug output.

* - dnsoverquic, doq_conn_check_timer function.

* - dnsoverquic, doq_done_setup_timer_and_write function.

* - dnsoverquic, fix that doq conn is not deleted whilst editing write and timer.

* - dnsoverquic, Fix #861 make ERROR netevent.h:1073:32: error: field 'blocked_pkt_pi' has incomplete type

* - dnsoverquic, timer element has timeout setup when socket callback complete.

* - dnsoverquic, fix unit test compile.

* - dnsoverquic, timer callback routine, handle timeout and close and delete the
  connection if necessary.

* - dnsoverquic, timer pickup stops at current time.

* - dnsoverquic, timer comparable with the event base time.

* - dnsoverquic, erase marked time when timer disabled.

* - dnsoverquic, fix timer to set correctly and lock popped write connection
  early, before it is modified.

* - dnsoverquic, fix to unlock connection lock when it is unlinked and deleted.

* - dnsoverquic, fix to unlock connection lock when it is deleted because it is
  a duplicate connection.

* - dnsoverquic, fix that doq timer is not disabled when not set.

* - dnsoverquic, quic-size: 8m maximum number of bytes for QUIC buffers.

* - dnsoverquic, flex and bison.

* - dnsoverquic, quic-size turn away new connections when full.

* - dnsoverquic, doqclient outputs stream reset information.

* - dnsoverquic, detect stream close and reset.

* - dnsoverquic, free stream buffers when data is acked and stream is closed.

* - dnsoverquic, delete stream when closed. Unlink it. Allow stream_id 4 as first.

* - dnsoverquic, stats output for mem.quic and num.query.quic.

* - dnsoverquic, review fix.

* - dnsoverquic, fix when compiled without ngtcp2.

* - dnsoverquic, fix to detect ngtcp2_crypto_quictls for openssl crypto, after
  change in libngtcp2.

* - dnsoverquic, fix for newer ngtcp2 versions. detect ngtcp2_ccerr_default,
  ngtcp2/ngtcp2_crypto_quictls.h, struct ngtcp2_pkt_hd.tokenlen,
  struct ngtcp2_settings.tokenlen and struct ngtcp2_version_cid.

* - dnsoverquic, fix for newer ngtcp2 version, detect number of arguments for
  ngtcp2_conn_shutdown_stream.

* - dnsoverquic, fix for newer ngtcp2.

* - dnsoverquic, use the functions from util/timeval_func.h.

* - dnsoverquic, fix in doqclient only write transport parameters once.

* - dnsoverquic, debug log output removed.

* - dnsoverquic, fix in doqclient to work with renamed NGTCP2_CC_ALGO_BBR_V2
  from ngtcp2.

* - dnsoverquic, fix to check in doq_server_socket_create that tls-service-key
  and tls-service-pem have a value.

* - dnsoverquic, fix to error when doq_server_socket_create fails.

* - dnsoverquic, improve linebreaks in configparser additions.

* - dnsoverquic, fix port from interface pickup after main branch change.

* Fix getting user data from SSL, fix calloc warning.

* Fix fwrite return value check in doqclient

* - timeval_substruct from timeval_func.h
- lock_protect also for HAVE_NGTCP2_CCERR_DEFAULT
- fix doq logging for inet_ntop failures

* - memset for consistency
- no value returned from msghdr_get_ecn when S_SPLINT_S is defined

* - dnsoverquic, rerun autoconf.

---------

Co-authored-by: Yorgos Thessalonikefs <yorgos@nlnetlabs.nl>
This commit is contained in:
Wouter Wijngaards 2024-10-09 10:32:03 +02:00 committed by GitHub
parent dcf7afd722
commit 3d89c26d32
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
44 changed files with 8769 additions and 49 deletions

1
.gitignore vendored
View file

@ -36,6 +36,7 @@
/asynclook
/delayer
/dohclient
/doqclient
/lock-verify
/memstats
/perf

View file

@ -179,11 +179,11 @@ testcode/unitlruhash.c testcode/unitmain.c testcode/unitmsgparse.c \
testcode/unitneg.c testcode/unitregional.c testcode/unitslabhash.c \
testcode/unitverify.c testcode/readhex.c testcode/testpkts.c testcode/unitldns.c \
testcode/unitecs.c testcode/unitauth.c testcode/unitzonemd.c \
testcode/unittcpreuse.c
testcode/unittcpreuse.c testcode/unitdoq.c
UNITTEST_OBJ=unitanchor.lo unitdname.lo unitlruhash.lo unitmain.lo \
unitmsgparse.lo unitneg.lo unitregional.lo unitslabhash.lo unitverify.lo \
readhex.lo testpkts.lo unitldns.lo unitecs.lo unitauth.lo unitzonemd.lo \
unittcpreuse.lo
unittcpreuse.lo unitdoq.lo
UNITTEST_OBJ_LINK=$(UNITTEST_OBJ) worker_cb.lo $(COMMON_OBJ) $(SLDNS_OBJ) \
$(COMPAT_OBJ)
DAEMON_SRC=daemon/acl_list.c daemon/cachedump.c daemon/daemon.c \
@ -242,6 +242,10 @@ DOHCLIENT_SRC=testcode/dohclient.c
DOHCLIENT_OBJ=dohclient.lo
DOHCLIENT_OBJ_LINK=$(DOHCLIENT_OBJ) worker_cb.lo $(COMMON_OBJ) $(COMPAT_OBJ) \
$(SLDNS_OBJ)
DOQCLIENT_SRC=testcode/doqclient.c
DOQCLIENT_OBJ=doqclient.lo
DOQCLIENT_OBJ_LINK=$(DOQCLIENT_OBJ) $(COMMON_OBJ) $(COMPAT_OBJ) \
$(SLDNS_OBJ)
PERF_SRC=testcode/perf.c
PERF_OBJ=perf.lo
PERF_OBJ_LINK=$(PERF_OBJ) worker_cb.lo $(COMMON_OBJ) $(COMPAT_OBJ) $(SLDNS_OBJ)
@ -288,7 +292,7 @@ ALL_SRC=$(COMMON_SRC) $(UNITTEST_SRC) $(DAEMON_SRC) \
$(CONTROL_SRC) $(UBANCHOR_SRC) $(PETAL_SRC) $(DNSTAP_SOCKET_SRC)\
$(PYTHONMOD_SRC) $(PYUNBOUND_SRC) $(WIN_DAEMON_THE_SRC) \
$(SVCINST_SRC) $(SVCUNINST_SRC) $(ANCHORUPD_SRC) $(SLDNS_SRC) \
$(DOHCLIENT_SRC) $(READZONE_SRC)
$(DOHCLIENT_SRC) $(DOQCLIENT_SRC) $(READZONE_SRC)
ALL_OBJ=$(COMMON_OBJ) $(UNITTEST_OBJ) $(DAEMON_OBJ) \
$(TESTBOUND_OBJ) $(LOCKVERIFY_OBJ) $(PKTVIEW_OBJ) \
@ -297,7 +301,7 @@ ALL_OBJ=$(COMMON_OBJ) $(UNITTEST_OBJ) $(DAEMON_OBJ) \
$(CONTROL_OBJ) $(UBANCHOR_OBJ) $(PETAL_OBJ) $(DNSTAP_SOCKET_OBJ)\
$(COMPAT_OBJ) $(PYUNBOUND_OBJ) \
$(SVCINST_OBJ) $(SVCUNINST_OBJ) $(ANCHORUPD_OBJ) $(SLDNS_OBJ) \
$(DOHCLIENT_OBJ) $(READZONE_OBJ)
$(DOHCLIENT_OBJ) $(DOQCLIENT_OBJ) $(READZONE_OBJ)
COMPILE=$(LIBTOOL) --tag=CC --mode=compile $(CC) $(CPPFLAGS) $(CFLAGS) @PTHREAD_CFLAGS_ONLY@
LINK=$(LIBTOOL) --tag=CC --mode=link $(CC) $(staticexe) $(RUNTIME_PATH) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS)
@ -334,7 +338,7 @@ rsrc_unbound_checkconf.o: $(srcdir)/winrc/rsrc_unbound_checkconf.rc config.h
TEST_BIN=asynclook$(EXEEXT) delayer$(EXEEXT) \
lock-verify$(EXEEXT) memstats$(EXEEXT) perf$(EXEEXT) \
petal$(EXEEXT) pktview$(EXEEXT) streamtcp$(EXEEXT) \
$(DNSTAP_SOCKET_TESTBIN) dohclient$(EXEEXT) \
$(DNSTAP_SOCKET_TESTBIN) dohclient$(EXEEXT) doqclient$(EXEEXT) \
testbound$(EXEEXT) unittest$(EXEEXT) readzone$(EXEEXT)
tests: all $(TEST_BIN)
@ -416,6 +420,9 @@ streamtcp$(EXEEXT): $(STREAMTCP_OBJ_LINK)
dohclient$(EXEEXT): $(DOHCLIENT_OBJ_LINK)
$(LINK) -o $@ $(DOHCLIENT_OBJ_LINK) $(SSLLIB) $(LIBS)
doqclient$(EXEEXT): $(DOQCLIENT_OBJ_LINK)
$(LINK) -o $@ $(DOQCLIENT_OBJ_LINK) $(SSLLIB) $(LIBS)
perf$(EXEEXT): $(PERF_OBJ_LINK)
$(LINK) -o $@ $(PERF_OBJ_LINK) $(SSLLIB) $(LIBS)
@ -703,6 +710,8 @@ depend:
# build rules
ipset.lo ipset.o: $(srcdir)/ipset/ipset.c
doqclient.lo doqclient.o: $(srcdir)/testcode/doqclient.c
unitdoq.lo unitdoq.o: $(srcdir)/testcode/unitdoq.c
# Dependencies
dns.lo dns.o: $(srcdir)/services/cache/dns.c config.h $(srcdir)/iterator/iter_delegpt.h $(srcdir)/util/log.h \

View file

@ -129,6 +129,14 @@
and to 0 if you don't. */
#undef HAVE_DECL_NGHTTP2_SESSION_SERVER_NEW
/* Define to 1 if you have the declaration of `ngtcp2_conn_server_new', and to
0 if you don't. */
#undef HAVE_DECL_NGTCP2_CONN_SERVER_NEW
/* Define to 1 if you have the declaration of `ngtcp2_crypto_encrypt_cb', and
to 0 if you don't. */
#undef HAVE_DECL_NGTCP2_CRYPTO_ENCRYPT_CB
/* Define to 1 if you have the declaration of `NID_ED25519', and to 0 if you
don't. */
#undef HAVE_DECL_NID_ED25519
@ -421,6 +429,65 @@
/* Define to 1 if you have the <nghttp2/nghttp2.h> header file. */
#undef HAVE_NGHTTP2_NGHTTP2_H
/* Define this to use ngtcp2. */
#undef HAVE_NGTCP2
/* 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 <ngtcp2/ngtcp2_crypto_openssl.h> header file.
*/
#undef HAVE_NGTCP2_NGTCP2_CRYPTO_OPENSSL_H
/* Define to 1 if you have the <ngtcp2/ngtcp2_crypto_quictls.h> header file.
*/
#undef HAVE_NGTCP2_NGTCP2_CRYPTO_QUICTLS_H
/* Define to 1 if you have the <ngtcp2/ngtcp2.h> header file. */
#undef HAVE_NGTCP2_NGTCP2_H
/* Use libnss for crypto */
#undef HAVE_NSS
@ -587,6 +654,9 @@
/* Define to 1 if you have the `SSL_get1_peer_certificate' function. */
#undef HAVE_SSL_GET1_PEER_CERTIFICATE
/* Define to 1 if you have the `SSL_is_quic' function. */
#undef HAVE_SSL_IS_QUIC
/* Define to 1 if you have the `SSL_set1_host' function. */
#undef HAVE_SSL_SET1_HOST
@ -629,6 +699,23 @@
/* Define to 1 if `ipi_spec_dst' is a member of `struct in_pktinfo'. */
#undef HAVE_STRUCT_IN_PKTINFO_IPI_SPEC_DST
/* 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
/* Define to 1 if `sun_len' is a member of `struct sockaddr_un'. */
#undef HAVE_STRUCT_SOCKADDR_UN_SUN_LEN
@ -1521,6 +1608,8 @@ char *unbound_stat_strdup_log(const char *s, const char* file, int line,
#define UNBOUND_DNS_OVER_TLS_PORT 853
/** default port for DNS over HTTPS traffic. */
#define UNBOUND_DNS_OVER_HTTPS_PORT 443
/** default port for DNS over QUIC traffic. */
#define UNBOUND_DNS_OVER_QUIC_PORT 853
/** default port for unbound control traffic, registered port with IANA,
ub-dns-control 8953/tcp unbound dns nameserver control */
#define UNBOUND_CONTROL_PORT 8953

351
configure vendored
View file

@ -921,6 +921,7 @@ with_libevent
with_libexpat
with_libhiredis
with_libnghttp2
with_libngtcp2
enable_static_exe
enable_fully_static
enable_lock_checks
@ -1709,6 +1710,7 @@ Optional Packages:
--with-libexpat=path specify explicit path for libexpat.
--with-libhiredis=path specify explicit path for libhiredis.
--with-libnghttp2=path specify explicit path for libnghttp2.
--with-libngtcp2=path specify explicit path for libngtcp2, for QUIC.
--with-dnstap-socket-path=pathname
set default dnstap socket path
--with-protobuf-c=path Path where protobuf-c is installed, for dnstap
@ -22205,6 +22207,353 @@ printf "%s\n" "#define HAVE_DECL_NGHTTP2_SESSION_SERVER_NEW $ac_have_decl" >>con
fi
# ngtcp2
# Check whether --with-libngtcp2 was given.
if test ${with_libngtcp2+y}
then :
withval=$with_libngtcp2;
else $as_nop
withval="no"
fi
found_libngtcp2="no"
if test x_$withval = x_yes -o x_$withval != x_no; then
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for libngtcp2" >&5
printf %s "checking for libngtcp2... " >&6; }
if test x_$withval = x_ -o x_$withval = x_yes; then
withval="/usr/local /opt/local /usr/lib /usr/pkg /usr/sfw /usr"
fi
for dir in $withval ; do
if test -f "$dir/include/ngtcp2/ngtcp2.h"; then
found_libngtcp2="yes"
if test "$dir" != "/usr"; then
CPPFLAGS="$CPPFLAGS -I$dir/include"
LDFLAGS="$LDFLAGS -L$dir/lib"
fi
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: found in $dir" >&5
printf "%s\n" "found in $dir" >&6; }
printf "%s\n" "#define HAVE_NGTCP2 1" >>confdefs.h
LIBS="$LIBS -lngtcp2"
break;
fi
done
if test x_$found_libngtcp2 != x_yes; then
as_fn_error $? "Could not find libngtcp2, ngtcp2.h" "$LINENO" 5
fi
ac_fn_c_check_header_compile "$LINENO" "ngtcp2/ngtcp2.h" "ac_cv_header_ngtcp2_ngtcp2_h" "$ac_includes_default
"
if test "x$ac_cv_header_ngtcp2_ngtcp2_h" = xyes
then :
printf "%s\n" "#define HAVE_NGTCP2_NGTCP2_H 1" >>confdefs.h
fi
ac_fn_c_check_header_compile "$LINENO" "ngtcp2/ngtcp2_crypto_openssl.h" "ac_cv_header_ngtcp2_ngtcp2_crypto_openssl_h" "$ac_includes_default
"
if test "x$ac_cv_header_ngtcp2_ngtcp2_crypto_openssl_h" = xyes
then :
printf "%s\n" "#define HAVE_NGTCP2_NGTCP2_CRYPTO_OPENSSL_H 1" >>confdefs.h
fi
ac_fn_c_check_header_compile "$LINENO" "ngtcp2/ngtcp2_crypto_quictls.h" "ac_cv_header_ngtcp2_ngtcp2_crypto_quictls_h" "$ac_includes_default
"
if test "x$ac_cv_header_ngtcp2_ngtcp2_crypto_quictls_h" = xyes
then :
printf "%s\n" "#define HAVE_NGTCP2_NGTCP2_CRYPTO_QUICTLS_H 1" >>confdefs.h
fi
ac_fn_check_decl "$LINENO" "ngtcp2_conn_server_new" "ac_cv_have_decl_ngtcp2_conn_server_new" "$ac_includes_default
#include <ngtcp2/ngtcp2.h>
" "$ac_c_undeclared_builtin_options" "CFLAGS"
if test "x$ac_cv_have_decl_ngtcp2_conn_server_new" = xyes
then :
ac_have_decl=1
else $as_nop
ac_have_decl=0
fi
printf "%s\n" "#define HAVE_DECL_NGTCP2_CONN_SERVER_NEW $ac_have_decl" >>confdefs.h
ac_fn_check_decl "$LINENO" "ngtcp2_crypto_encrypt_cb" "ac_cv_have_decl_ngtcp2_crypto_encrypt_cb" "$ac_includes_default
#include <ngtcp2/ngtcp2_crypto.h>
" "$ac_c_undeclared_builtin_options" "CFLAGS"
if test "x$ac_cv_have_decl_ngtcp2_crypto_encrypt_cb" = xyes
then :
ac_have_decl=1
else $as_nop
ac_have_decl=0
fi
printf "%s\n" "#define HAVE_DECL_NGTCP2_CRYPTO_ENCRYPT_CB $ac_have_decl" >>confdefs.h
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ngtcp2_crypto_encrypt_cb in -lngtcp2_crypto_openssl" >&5
printf %s "checking for ngtcp2_crypto_encrypt_cb in -lngtcp2_crypto_openssl... " >&6; }
if test ${ac_cv_lib_ngtcp2_crypto_openssl_ngtcp2_crypto_encrypt_cb+y}
then :
printf %s "(cached) " >&6
else $as_nop
ac_check_lib_save_LIBS=$LIBS
LIBS="-lngtcp2_crypto_openssl $LIBS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
/* Override any GCC internal prototype to avoid an error.
Use char because int might match the return type of a GCC
builtin and then its argument prototype would still apply. */
char ngtcp2_crypto_encrypt_cb ();
int
main (void)
{
return ngtcp2_crypto_encrypt_cb ();
;
return 0;
}
_ACEOF
if ac_fn_c_try_link "$LINENO"
then :
ac_cv_lib_ngtcp2_crypto_openssl_ngtcp2_crypto_encrypt_cb=yes
else $as_nop
ac_cv_lib_ngtcp2_crypto_openssl_ngtcp2_crypto_encrypt_cb=no
fi
rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
LIBS=$ac_check_lib_save_LIBS
fi
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ngtcp2_crypto_openssl_ngtcp2_crypto_encrypt_cb" >&5
printf "%s\n" "$ac_cv_lib_ngtcp2_crypto_openssl_ngtcp2_crypto_encrypt_cb" >&6; }
if test "x$ac_cv_lib_ngtcp2_crypto_openssl_ngtcp2_crypto_encrypt_cb" = xyes
then :
LIBS="$LIBS -lngtcp2_crypto_openssl"
fi
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ngtcp2_crypto_encrypt_cb in -lngtcp2_crypto_quictls" >&5
printf %s "checking for ngtcp2_crypto_encrypt_cb in -lngtcp2_crypto_quictls... " >&6; }
if test ${ac_cv_lib_ngtcp2_crypto_quictls_ngtcp2_crypto_encrypt_cb+y}
then :
printf %s "(cached) " >&6
else $as_nop
ac_check_lib_save_LIBS=$LIBS
LIBS="-lngtcp2_crypto_quictls $LIBS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
/* Override any GCC internal prototype to avoid an error.
Use char because int might match the return type of a GCC
builtin and then its argument prototype would still apply. */
char ngtcp2_crypto_encrypt_cb ();
int
main (void)
{
return ngtcp2_crypto_encrypt_cb ();
;
return 0;
}
_ACEOF
if ac_fn_c_try_link "$LINENO"
then :
ac_cv_lib_ngtcp2_crypto_quictls_ngtcp2_crypto_encrypt_cb=yes
else $as_nop
ac_cv_lib_ngtcp2_crypto_quictls_ngtcp2_crypto_encrypt_cb=no
fi
rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
LIBS=$ac_check_lib_save_LIBS
fi
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ngtcp2_crypto_quictls_ngtcp2_crypto_encrypt_cb" >&5
printf "%s\n" "$ac_cv_lib_ngtcp2_crypto_quictls_ngtcp2_crypto_encrypt_cb" >&6; }
if test "x$ac_cv_lib_ngtcp2_crypto_quictls_ngtcp2_crypto_encrypt_cb" = xyes
then :
LIBS="$LIBS -lngtcp2_crypto_quictls"
fi
ac_fn_c_check_func "$LINENO" "ngtcp2_crypto_encrypt_cb" "ac_cv_func_ngtcp2_crypto_encrypt_cb"
if test "x$ac_cv_func_ngtcp2_crypto_encrypt_cb" = xyes
then :
printf "%s\n" "#define HAVE_NGTCP2_CRYPTO_ENCRYPT_CB 1" >>confdefs.h
fi
ac_fn_c_check_func "$LINENO" "ngtcp2_ccerr_default" "ac_cv_func_ngtcp2_ccerr_default"
if test "x$ac_cv_func_ngtcp2_ccerr_default" = xyes
then :
printf "%s\n" "#define HAVE_NGTCP2_CCERR_DEFAULT 1" >>confdefs.h
fi
ac_fn_c_check_func "$LINENO" "ngtcp2_conn_in_closing_period" "ac_cv_func_ngtcp2_conn_in_closing_period"
if test "x$ac_cv_func_ngtcp2_conn_in_closing_period" = xyes
then :
printf "%s\n" "#define HAVE_NGTCP2_CONN_IN_CLOSING_PERIOD 1" >>confdefs.h
fi
ac_fn_c_check_func "$LINENO" "ngtcp2_conn_in_draining_period" "ac_cv_func_ngtcp2_conn_in_draining_period"
if test "x$ac_cv_func_ngtcp2_conn_in_draining_period" = xyes
then :
printf "%s\n" "#define HAVE_NGTCP2_CONN_IN_DRAINING_PERIOD 1" >>confdefs.h
fi
ac_fn_c_check_func "$LINENO" "ngtcp2_conn_get_max_local_streams_uni" "ac_cv_func_ngtcp2_conn_get_max_local_streams_uni"
if test "x$ac_cv_func_ngtcp2_conn_get_max_local_streams_uni" = xyes
then :
printf "%s\n" "#define HAVE_NGTCP2_CONN_GET_MAX_LOCAL_STREAMS_UNI 1" >>confdefs.h
fi
ac_fn_c_check_func "$LINENO" "ngtcp2_crypto_quictls_from_ossl_encryption_level" "ac_cv_func_ngtcp2_crypto_quictls_from_ossl_encryption_level"
if test "x$ac_cv_func_ngtcp2_crypto_quictls_from_ossl_encryption_level" = xyes
then :
printf "%s\n" "#define HAVE_NGTCP2_CRYPTO_QUICTLS_FROM_OSSL_ENCRYPTION_LEVEL 1" >>confdefs.h
fi
ac_fn_c_check_func "$LINENO" "ngtcp2_crypto_quictls_configure_server_context" "ac_cv_func_ngtcp2_crypto_quictls_configure_server_context"
if test "x$ac_cv_func_ngtcp2_crypto_quictls_configure_server_context" = xyes
then :
printf "%s\n" "#define HAVE_NGTCP2_CRYPTO_QUICTLS_CONFIGURE_SERVER_CONTEXT 1" >>confdefs.h
fi
ac_fn_c_check_func "$LINENO" "ngtcp2_crypto_quictls_configure_client_context" "ac_cv_func_ngtcp2_crypto_quictls_configure_client_context"
if test "x$ac_cv_func_ngtcp2_crypto_quictls_configure_client_context" = xyes
then :
printf "%s\n" "#define HAVE_NGTCP2_CRYPTO_QUICTLS_CONFIGURE_CLIENT_CONTEXT 1" >>confdefs.h
fi
ac_fn_c_check_func "$LINENO" "ngtcp2_conn_get_num_scid" "ac_cv_func_ngtcp2_conn_get_num_scid"
if test "x$ac_cv_func_ngtcp2_conn_get_num_scid" = xyes
then :
printf "%s\n" "#define HAVE_NGTCP2_CONN_GET_NUM_SCID 1" >>confdefs.h
fi
ac_fn_c_check_func "$LINENO" "ngtcp2_conn_tls_early_data_rejected" "ac_cv_func_ngtcp2_conn_tls_early_data_rejected"
if test "x$ac_cv_func_ngtcp2_conn_tls_early_data_rejected" = xyes
then :
printf "%s\n" "#define HAVE_NGTCP2_CONN_TLS_EARLY_DATA_REJECTED 1" >>confdefs.h
fi
ac_fn_c_check_func "$LINENO" "ngtcp2_conn_encode_0rtt_transport_params" "ac_cv_func_ngtcp2_conn_encode_0rtt_transport_params"
if test "x$ac_cv_func_ngtcp2_conn_encode_0rtt_transport_params" = xyes
then :
printf "%s\n" "#define HAVE_NGTCP2_CONN_ENCODE_0RTT_TRANSPORT_PARAMS 1" >>confdefs.h
fi
for ac_func in SSL_is_quic
do :
ac_fn_c_check_func "$LINENO" "SSL_is_quic" "ac_cv_func_SSL_is_quic"
if test "x$ac_cv_func_SSL_is_quic" = xyes
then :
printf "%s\n" "#define HAVE_SSL_IS_QUIC 1" >>confdefs.h
else $as_nop
as_fn_error $? "No QUIC support detected in OpenSSL. Need OpenSSL version with QUIC support to enable DNS over QUIC with libngtcp2." "$LINENO" 5
fi
done
ac_fn_c_check_type "$LINENO" "struct ngtcp2_version_cid" "ac_cv_type_struct_ngtcp2_version_cid" "$ac_includes_default
#include <ngtcp2/ngtcp2.h>
"
if test "x$ac_cv_type_struct_ngtcp2_version_cid" = xyes
then :
printf "%s\n" "#define HAVE_STRUCT_NGTCP2_VERSION_CID 1" >>confdefs.h
fi
ac_fn_c_check_type "$LINENO" "ngtcp2_encryption_level" "ac_cv_type_ngtcp2_encryption_level" "$ac_includes_default
#include <ngtcp2/ngtcp2.h>
"
if test "x$ac_cv_type_ngtcp2_encryption_level" = xyes
then :
printf "%s\n" "#define HAVE_NGTCP2_ENCRYPTION_LEVEL 1" >>confdefs.h
fi
ac_fn_c_check_member "$LINENO" "struct ngtcp2_pkt_hd" "tokenlen" "ac_cv_member_struct_ngtcp2_pkt_hd_tokenlen" "$ac_includes_default
#include <ngtcp2/ngtcp2.h>
"
if test "x$ac_cv_member_struct_ngtcp2_pkt_hd_tokenlen" = xyes
then :
printf "%s\n" "#define HAVE_STRUCT_NGTCP2_PKT_HD_TOKENLEN 1" >>confdefs.h
fi
ac_fn_c_check_member "$LINENO" "struct ngtcp2_settings" "tokenlen" "ac_cv_member_struct_ngtcp2_settings_tokenlen" "$ac_includes_default
#include <ngtcp2/ngtcp2.h>
"
if test "x$ac_cv_member_struct_ngtcp2_settings_tokenlen" = xyes
then :
printf "%s\n" "#define HAVE_STRUCT_NGTCP2_SETTINGS_TOKENLEN 1" >>confdefs.h
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 <ngtcp2/ngtcp2.h>
"
if test "x$ac_cv_member_struct_ngtcp2_settings_max_tx_udp_payload_size" = xyes
then :
printf "%s\n" "#define HAVE_STRUCT_NGTCP2_SETTINGS_MAX_TX_UDP_PAYLOAD_SIZE 1" >>confdefs.h
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 <ngtcp2/ngtcp2.h>
"
if test "x$ac_cv_member_struct_ngtcp2_transport_params_original_dcid_present" = xyes
then :
printf "%s\n" "#define HAVE_STRUCT_NGTCP2_TRANSPORT_PARAMS_ORIGINAL_DCID_PRESENT 1" >>confdefs.h
fi
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether ngtcp2_conn_shutdown_stream has 4 arguments" >&5
printf %s "checking whether ngtcp2_conn_shutdown_stream has 4 arguments... " >&6; }
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
$ac_includes_default
#include <ngtcp2/ngtcp2.h>
int
main (void)
{
(void)ngtcp2_conn_shutdown_stream(NULL, 0, 0, 0);
;
return 0;
}
_ACEOF
if ac_fn_c_try_compile "$LINENO"
then :
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
printf "%s\n" "yes" >&6; }
printf "%s\n" "#define HAVE_NGTCP2_CONN_SHUTDOWN_STREAM4 1" >>confdefs.h
else $as_nop
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
printf "%s\n" "no" >&6; }
fi
rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
# set static linking for uninstalled libraries if requested
staticexe=""
@ -23788,10 +24137,12 @@ if test x_$enable_lock_checks = x_yes; then
UBSYMS="-export-symbols clubsyms.def"
cp ${srcdir}/libunbound/ubsyms.def clubsyms.def
echo lock_protect >> clubsyms.def
echo lock_protect_place >> clubsyms.def
echo lock_unprotect >> clubsyms.def
echo lock_get_mem >> clubsyms.def
echo checklock_start >> clubsyms.def
echo checklock_stop >> clubsyms.def
echo checklock_set_output_name >> clubsyms.def
echo checklock_lock >> clubsyms.def
echo checklock_unlock >> clubsyms.def
echo checklock_init >> clubsyms.def

View file

@ -1579,6 +1579,64 @@ if test x_$withval = x_yes -o x_$withval != x_no; then
])
fi
# ngtcp2
AC_ARG_WITH(libngtcp2, AS_HELP_STRING([--with-libngtcp2=path],[specify explicit path for libngtcp2, for QUIC.]),
[ ],[ withval="no" ])
found_libngtcp2="no"
if test x_$withval = x_yes -o x_$withval != x_no; then
AC_MSG_CHECKING(for libngtcp2)
if test x_$withval = x_ -o x_$withval = x_yes; then
withval="/usr/local /opt/local /usr/lib /usr/pkg /usr/sfw /usr"
fi
for dir in $withval ; do
if test -f "$dir/include/ngtcp2/ngtcp2.h"; then
found_libngtcp2="yes"
dnl assume /usr is in default path.
if test "$dir" != "/usr"; then
CPPFLAGS="$CPPFLAGS -I$dir/include"
LDFLAGS="$LDFLAGS -L$dir/lib"
fi
AC_MSG_RESULT(found in $dir)
AC_DEFINE([HAVE_NGTCP2], [1], [Define this to use ngtcp2.])
LIBS="$LIBS -lngtcp2"
break;
fi
done
if test x_$found_libngtcp2 != x_yes; then
AC_MSG_ERROR([Could not find libngtcp2, ngtcp2.h])
fi
AC_CHECK_HEADERS([ngtcp2/ngtcp2.h ngtcp2/ngtcp2_crypto_openssl.h ngtcp2/ngtcp2_crypto_quictls.h],,, [AC_INCLUDES_DEFAULT])
AC_CHECK_DECLS([ngtcp2_conn_server_new], [], [], [AC_INCLUDES_DEFAULT
#include <ngtcp2/ngtcp2.h>
])
AC_CHECK_DECLS([ngtcp2_crypto_encrypt_cb], [], [], [AC_INCLUDES_DEFAULT
#include <ngtcp2/ngtcp2_crypto.h>
])
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 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, ngtcp2_encryption_level],,,[AC_INCLUDES_DEFAULT
#include <ngtcp2/ngtcp2.h>
])
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 <ngtcp2/ngtcp2.h>
])
AC_MSG_CHECKING([whether ngtcp2_conn_shutdown_stream has 4 arguments])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([AC_INCLUDES_DEFAULT
#include <ngtcp2/ngtcp2.h>
],[
(void)ngtcp2_conn_shutdown_stream(NULL, 0, 0, 0);
])],[
AC_MSG_RESULT(yes)
AC_DEFINE(HAVE_NGTCP2_CONN_SHUTDOWN_STREAM4, 1, [Define if ngtcp2_conn_shutdown_stream has 4 arguments.])
],[
AC_MSG_RESULT(no)
])
fi
# set static linking for uninstalled libraries if requested
AC_SUBST(staticexe)
staticexe=""
@ -1894,10 +1952,12 @@ if test x_$enable_lock_checks = x_yes; then
UBSYMS="-export-symbols clubsyms.def"
cp ${srcdir}/libunbound/ubsyms.def clubsyms.def
echo lock_protect >> clubsyms.def
echo lock_protect_place >> clubsyms.def
echo lock_unprotect >> clubsyms.def
echo lock_get_mem >> clubsyms.def
echo checklock_start >> clubsyms.def
echo checklock_stop >> clubsyms.def
echo checklock_set_output_name >> clubsyms.def
echo checklock_lock >> clubsyms.def
echo checklock_unlock >> clubsyms.def
echo checklock_init >> clubsyms.def
@ -2356,6 +2416,8 @@ char *unbound_stat_strdup_log(const char *s, const char* file, int line,
#define UNBOUND_DNS_OVER_TLS_PORT 853
/** default port for DNS over HTTPS traffic. */
#define UNBOUND_DNS_OVER_HTTPS_PORT 443
/** default port for DNS over QUIC traffic. */
#define UNBOUND_DNS_OVER_QUIC_PORT 853
/** default port for unbound control traffic, registered port with IANA,
ub-dns-control 8953/tcp unbound dns nameserver control */
#define UNBOUND_CONTROL_PORT 8953

View file

@ -558,6 +558,12 @@ daemon_create_workers(struct daemon* daemon)
numport = daemon_get_shufport(daemon, shufport);
verbose(VERB_ALGO, "total of %d outgoing ports available", numport);
#ifdef HAVE_NGTCP2
daemon->doq_table = doq_table_create(daemon->cfg, daemon->rand);
if(!daemon->doq_table)
fatal_exit("could not create doq_table: out of memory");
#endif
daemon->num = (daemon->cfg->num_threads?daemon->cfg->num_threads:1);
if(daemon->reuseport && (int)daemon->num < (int)daemon->num_ports) {
log_warn("cannot reduce num-threads to %d because so-reuseport "
@ -906,6 +912,10 @@ daemon_cleanup(struct daemon* daemon)
#ifdef USE_DNSCRYPT
dnsc_delete(daemon->dnscenv);
daemon->dnscenv = NULL;
#endif
#ifdef HAVE_NGTCP2
doq_table_delete(daemon->doq_table);
daemon->doq_table = NULL;
#endif
daemon->cfg = NULL;
}

View file

@ -58,6 +58,7 @@ struct ub_randstate;
struct daemon_remote;
struct respip_set;
struct shm_main_info;
struct doq_table;
struct cookie_secrets;
#include "dnstap/dnstap_config.h"
@ -147,6 +148,8 @@ struct daemon {
/** the dnscrypt environment */
struct dnsc_env* dnscenv;
#endif
/** the doq connection table */
struct doq_table* doq_table;
/** reuse existing cache on reload if other conditions allow it. */
int reuse_cache;
/** the EDNS cookie secrets from the cookie-secret-file */

View file

@ -302,7 +302,7 @@ add_open(const char* ip, int nr, struct listen_port** list, int noproto_is_err,
/* open fd */
fd = create_tcp_accept_sock(res, 1, &noproto, 0,
cfg->ip_transparent, 0, 0, cfg->ip_freebind,
cfg->use_systemd, cfg->ip_dscp);
cfg->use_systemd, cfg->ip_dscp, "unbound-control");
freeaddrinfo(res);
}
@ -866,6 +866,10 @@ print_mem(RES* ssl, struct worker* worker, struct daemon* daemon,
if(!print_longnum(ssl, "mem.http.response_buffer"SQ,
(size_t)s->svr.mem_http2_response_buffer))
return 0;
#ifdef HAVE_NGTCP2
if(!print_longnum(ssl, "mem.quic"SQ, (size_t)s->svr.mem_quic))
return 0;
#endif /* HAVE_NGTCP2 */
return 1;
}
@ -996,6 +1000,10 @@ print_ext(RES* ssl, struct ub_stats_info* s, int inhibit_zero)
(unsigned long)s->svr.qipv6)) return 0;
if(!ssl_printf(ssl, "num.query.https"SQ"%lu\n",
(unsigned long)s->svr.qhttps)) return 0;
#ifdef HAVE_NGTCP2
if(!ssl_printf(ssl, "num.query.quic"SQ"%lu\n",
(unsigned long)s->svr.qquic)) return 0;
#endif /* HAVE_NGTCP2 */
/* flags */
if(!ssl_printf(ssl, "num.query.flags.QR"SQ"%lu\n",
(unsigned long)s->svr.qbit_QR)) return 0;

View file

@ -346,6 +346,12 @@ server_stats_compile(struct worker* worker, struct ub_stats_info* s, int reset)
(long long)http2_get_query_buffer_size();
s->svr.mem_http2_response_buffer =
(long long)http2_get_response_buffer_size();
#ifdef HAVE_NGTCP2
s->svr.mem_quic = (long long)doq_table_quic_size_get(
worker->daemon->doq_table);
#else
s->svr.mem_quic = 0;
#endif /* HAVE_NGTCP2 */
/* Set neg cache usage numbers */
set_neg_cache_stats(worker, &s->svr, reset);
@ -474,6 +480,7 @@ void server_stats_add(struct ub_stats_info* total, struct ub_stats_info* a)
total->svr.qtls += a->svr.qtls;
total->svr.qtls_resume += a->svr.qtls_resume;
total->svr.qhttps += a->svr.qhttps;
total->svr.qquic += a->svr.qquic;
total->svr.qipv6 += a->svr.qipv6;
total->svr.qbit_QR += a->svr.qbit_QR;
total->svr.qbit_AA += a->svr.qbit_AA;
@ -533,6 +540,7 @@ void server_stats_insquery(struct ub_server_stats* stats, struct comm_point* c,
else stats->qclass_big++;
stats->qopcode[ LDNS_OPCODE_WIRE(sldns_buffer_begin(c->buffer)) ]++;
if(c->type != comm_udp) {
if(c->type != comm_doq)
stats->qtcp++;
if(c->ssl != NULL) {
stats->qtls++;
@ -542,6 +550,10 @@ void server_stats_insquery(struct ub_server_stats* stats, struct comm_point* c,
#endif
if(c->type == comm_http)
stats->qhttps++;
#ifdef HAVE_NGTCP2
else if(c->type == comm_doq)
stats->qquic++;
#endif
}
}
if(repinfo && addr_is_ip6(&repinfo->remote_addr, repinfo->remote_addrlen))

View file

@ -2174,7 +2174,9 @@ worker_init(struct worker* worker, struct config_file *cfg,
cfg->harden_large_queries, cfg->http_max_streams,
cfg->http_endpoint, cfg->http_notls_downstream,
worker->daemon->tcl, worker->daemon->listen_sslctx,
dtenv, worker_handle_request, worker);
dtenv, worker->daemon->doq_table, worker->env.rnd,
cfg->ssl_service_key, cfg->ssl_service_pem, cfg,
worker_handle_request, worker);
if(!worker->front) {
log_err("could not create listening sockets");
worker_delete(worker);
@ -2508,3 +2510,19 @@ void dtio_mainfdcallback(int ATTR_UNUSED(fd), short ATTR_UNUSED(ev),
log_assert(0);
}
#endif
#ifdef HAVE_NGTCP2
void doq_client_event_cb(int ATTR_UNUSED(fd), short ATTR_UNUSED(ev),
void* ATTR_UNUSED(arg))
{
log_assert(0);
}
#endif
#ifdef HAVE_NGTCP2
void doq_client_timer_cb(int ATTR_UNUSED(fd), short ATTR_UNUSED(ev),
void* ATTR_UNUSED(arg))
{
log_assert(0);
}
#endif

View file

@ -1785,3 +1785,19 @@ void remote_get_opt_ssl(char* ATTR_UNUSED(str), void* ATTR_UNUSED(arg))
{
log_assert(0);
}
#ifdef HAVE_NGTCP2
void doq_client_event_cb(int ATTR_UNUSED(fd), short ATTR_UNUSED(ev),
void* ATTR_UNUSED(arg))
{
log_assert(0);
}
#endif
#ifdef HAVE_NGTCP2
void doq_client_timer_cb(int ATTR_UNUSED(fd), short ATTR_UNUSED(ev),
void* ATTR_UNUSED(arg))
{
log_assert(0);
}
#endif

View file

@ -920,6 +920,7 @@ server:
# tls-service-pem: "path/to/publiccertfile.pem"
# tls-port: 853
# https-port: 443
# quic-port: 853
# cipher setting for TLSv1.2
# tls-ciphers: "DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256"
@ -984,6 +985,9 @@ server:
# Disable TLS for DNS-over-HTTP downstream service.
# http-notls-downstream: no
# Maximum number of bytes used for QUIC buffers.
# quic-size: 8m
# The interfaces that use these listed port numbers will support and
# expect PROXYv2. For UDP and TCP/TLS interfaces.
# proxy-protocol-port: portno for each of the port numbers.

View file

@ -606,6 +606,10 @@ queries waiting for request stream completion.
Memory in bytes used by the HTTP/2 response buffers. Containing DNS responses
waiting to be written back to the clients.
.TP
.I mem.quic
Memory in bytes used by QUIC. Containing connection information, stream
information, queries read and responses written back to the clients.
.TP
.I histogram.<sec>.<usec>.to.<sec>.<usec>
Shows a histogram, summed over all threads. Every element counts the
recursive queries whose reply time fit between the lower and upper bound.
@ -654,6 +658,10 @@ Number of queries that were made using HTTPS towards the Unbound server.
These are also counted in num.query.tcp and num.query.tls, because HTTPS
uses TLS and TCP.
.TP
.I num.query.quic
Number of queries that were made using QUIC towards the Unbound server.
These are also counted in num.query.tls, because TLS is used for these queries.
.TP
.I num.query.ipv6
Number of queries that were made using IPv6 towards the Unbound server.
.TP

View file

@ -719,6 +719,18 @@ PROXYv2 is supported for UDP and TCP/TLS listening interfaces.
There is no support for PROXYv2 on a DoH or DNSCrypt listening interface.
Can list multiple, each on a new statement.
.TP
.B quic\-port: \fI<number>
The port number on which to provide DNS-over-QUIC service, default 853, only
interfaces configured with that port number as @number get the QUIC service.
The interface uses QUIC for the UDP traffic on that port number.
.TP
.B quic\-size: \fI<size in bytes>
Maximum number of bytes for all QUIC buffers and data combined. Default is 8
megabytes. A plain number is in bytes, append 'k', 'm' or 'g' for kilobytes,
megabytes or gigabytes (1024*1024 bytes in a megabyte). New connections receive
connection refused when the limit is exceeded. New streams are reset when the
limit is exceeded.
.TP
.B use\-systemd: \fI<yes or no>
Enable or disable systemd socket activation.
Default is no.

View file

@ -1058,3 +1058,19 @@ void dtio_mainfdcallback(int ATTR_UNUSED(fd), short ATTR_UNUSED(ev),
log_assert(0);
}
#endif
#ifdef HAVE_NGTCP2
void doq_client_event_cb(int ATTR_UNUSED(fd), short ATTR_UNUSED(ev),
void* ATTR_UNUSED(arg))
{
log_assert(0);
}
#endif
#ifdef HAVE_NGTCP2
void doq_client_timer_cb(int ATTR_UNUSED(fd), short ATTR_UNUSED(ev),
void* ATTR_UNUSED(arg))
{
log_assert(0);
}
#endif

View file

@ -845,6 +845,10 @@ struct ub_server_stats {
long long qtls_resume;
/** RPZ action stats */
long long rpz_action[UB_STATS_RPZ_ACTION_NUM];
/** number of bytes in QUIC buffers */
long long mem_quic;
/** number of queries over (DNS over) QUIC */
long long qquic;
};
/**

File diff suppressed because it is too large Load diff

View file

@ -43,10 +43,16 @@
#define LISTEN_DNSPORT_H
#include "util/netevent.h"
#include "util/rbtree.h"
#include "util/locks.h"
#include "daemon/acl_list.h"
#ifdef HAVE_NGHTTP2_NGHTTP2_H
#include <nghttp2/nghttp2.h>
#endif
#ifdef HAVE_NGTCP2
#include <ngtcp2/ngtcp2.h>
#include <ngtcp2/ngtcp2_crypto.h>
#endif
struct listen_list;
struct config_file;
struct addrinfo;
@ -100,7 +106,9 @@ enum listen_type {
/** udp ipv6 (v4mapped) for use with ancillary data + dnscrypt*/
listen_type_udpancil_dnscrypt,
/** HTTP(2) over TLS over TCP */
listen_type_http
listen_type_http,
/** DNS over QUIC */
listen_type_doq
};
/*
@ -188,6 +196,11 @@ int resolve_interface_names(char** ifs, int num_ifs,
* @param tcp_conn_limit: TCP connection limit info.
* @param sslctx: nonNULL if ssl context.
* @param dtenv: nonNULL if dnstap enabled.
* @param doq_table: the doq connection table, with shared information.
* @param rnd: random state.
* @param ssl_service_key: the SSL service key file.
* @param ssl_service_pem: the SSL service pem file.
* @param cfg: config file struct.
* @param cb: callback function when a request arrives. It is passed
* the packet and user argument. Return true to send a reply.
* @param cb_arg: user data argument for callback function.
@ -198,8 +211,10 @@ listen_create(struct comm_base* base, struct listen_port* ports,
size_t bufsize, int tcp_accept_count, int tcp_idle_timeout,
int harden_large_queries, uint32_t http_max_streams,
char* http_endpoint, int http_notls, struct tcl_list* tcp_conn_limit,
void* sslctx, struct dt_env* dtenv, comm_point_callback_type* cb,
void *cb_arg);
void* sslctx, struct dt_env* dtenv, struct doq_table* doq_table,
struct ub_randstate* rnd, const char* ssl_service_key,
const char* ssl_service_pem, struct config_file* cfg,
comm_point_callback_type* cb, void *cb_arg);
/**
* delete the listening structure
@ -278,11 +293,12 @@ int create_udp_sock(int family, int socktype, struct sockaddr* addr,
* @param freebind: set IP_FREEBIND socket option.
* @param use_systemd: if true, fetch sockets from systemd.
* @param dscp: DSCP to use.
* @param additional: additional log information for the socket type.
* @return: the socket. -1 on error.
*/
int create_tcp_accept_sock(struct addrinfo *addr, int v6only, int* noproto,
int* reuseport, int transparent, int mss, int nodelay, int freebind,
int use_systemd, int dscp);
int use_systemd, int dscp, const char* additional);
/**
* Create and bind local listening socket
@ -452,6 +468,377 @@ int http2_submit_dns_response(struct http2_session* h2_session);
int http2_submit_dns_response(void* v);
#endif /* HAVE_NGHTTP2 */
#ifdef HAVE_NGTCP2
struct doq_conid;
struct doq_server_socket;
/**
* DoQ shared connection table. This is the connections for the host.
* And some config parameter values for connections. The host has to
* respond on that ip,port for those connections, so they are shared
* between threads.
*/
struct doq_table {
/** the lock on the tree and config elements. insert and deletion,
* also lookup in the tree needs to hold the lock. */
lock_rw_type lock;
/** rbtree of doq_conn, the connections to different destination
* addresses, and can be found by dcid. */
struct rbtree_type* conn_tree;
/** lock for the conid tree, needed for the conid tree and also
* the conid elements */
lock_rw_type conid_lock;
/** rbtree of doq_conid, connections can be found by their
* connection ids. Lookup by connection id, finds doq_conn. */
struct rbtree_type* conid_tree;
/** the server scid length */
int sv_scidlen;
/** the static secret for the server */
uint8_t* static_secret;
/** length of the static secret */
size_t static_secret_len;
/** the idle timeout in nanoseconds */
uint64_t idle_timeout;
/** the list of write interested connections, hold the doq_table.lock
* to change them */
struct doq_conn* write_list_first, *write_list_last;
/** rbtree of doq_timer. */
struct rbtree_type* timer_tree;
/** lock on the current_size counter. */
lock_basic_type size_lock;
/** current use, in bytes, of QUIC buffers.
* The doq_conn ngtcp2_conn structure, SSL structure and conid structs
* are not counted. */
size_t current_size;
};
/** create doq table */
struct doq_table* doq_table_create(struct config_file* cfg,
struct ub_randstate* rnd);
/** delete doq table */
void doq_table_delete(struct doq_table* table);
/**
* Timer information for doq timer.
*/
struct doq_timer {
/** The rbnode in the tree sorted by timeout value. Key this struct. */
struct rbnode_type node;
/** The timeout value. Absolute time value. */
struct timeval time;
/** If the timer is in the time tree, with the node. */
int timer_in_tree;
/** If there are more timers with the exact same timeout value,
* they form a set of timers. The rbnode timer has a link to the list
* with the other timers in the set. The rbnode timer is not a
* member of the list with the other timers. The other timers are not
* linked into the tree. */
struct doq_timer* setlist_first, *setlist_last;
/** If the timer is on the setlist. */
int timer_in_list;
/** If in the setlist, the next and prev element. */
struct doq_timer* setlist_next, *setlist_prev;
/** The connection that is timeouted. */
struct doq_conn* conn;
/** The worker that is waiting for the timeout event.
* Set for the rbnode tree linked element. If a worker is waiting
* for the event. If NULL, no worker is waiting for this timeout. */
struct doq_server_socket* worker_doq_socket;
};
/**
* Key information that makes a doq_conn node in the tree lookup.
*/
struct doq_conn_key {
/** the remote endpoint and local endpoint and ifindex */
struct doq_pkt_addr paddr;
/** the doq connection dcid */
uint8_t* dcid;
/** length of dcid */
size_t dcidlen;
};
/**
* DoQ connection, for DNS over QUIC. One connection to a remote endpoint
* with a number of streams in it. Every stream is like a tcp stream with
* a uint16_t length, query read, and a uint16_t length and answer written.
*/
struct doq_conn {
/** rbtree node, key is addresses and dcid */
struct rbnode_type node;
/** lock on the connection */
lock_basic_type lock;
/** the key information, with dcid and address endpoint */
struct doq_conn_key key;
/** the doq server socket for inside callbacks */
struct doq_server_socket* doq_socket;
/** the doq table this connection is part of */
struct doq_table* table;
/** if the connection is about to be deleted. */
uint8_t is_deleted;
/** the version, the client chosen version of QUIC */
uint32_t version;
/** the ngtcp2 connection, a server connection */
struct ngtcp2_conn* conn;
/** the connection ids that are associated with this doq_conn.
* There can be a number, that can change. They are linked here,
* so that upon removal, the list of actually associated conid
* elements can be removed as well. */
struct doq_conid* conid_list;
/** the ngtcp2 last error for the connection */
#ifdef HAVE_NGTCP2_CCERR_DEFAULT
struct ngtcp2_ccerr ccerr;
#else
struct ngtcp2_connection_close_error last_error;
#endif
/** the recent tls alert error code */
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. */
size_t close_pkt_len;
/** closure ecn */
uint32_t close_ecn;
/** the streams for this connection, of type doq_stream */
struct rbtree_type stream_tree;
/** the streams that want write, they have something to write.
* The list is ordered, the last have to wait for the first to
* get their data written. */
struct doq_stream* stream_write_first, *stream_write_last;
/** the conn has write interest if true, no write interest if false. */
uint8_t write_interest;
/** if the conn is on the connection write list */
uint8_t on_write_list;
/** the connection write list prev and next, if on the write list */
struct doq_conn* write_prev, *write_next;
/** The timer for the connection. If unused, it is not in the tree
* and not in the list. It is alloced here, so that it is prealloced.
* It has to be set after every read and write on the connection, so
* this improves performance, but also the allocation does not fail. */
struct doq_timer timer;
};
/**
* Connection ID and the doq_conn that is that connection. A connection
* has an original dcid, and then more connection ids associated.
*/
struct doq_conid {
/** rbtree node, key is the connection id. */
struct rbnode_type node;
/** the next and prev in the list of conids for the doq_conn */
struct doq_conid* next, *prev;
/** key to the doq_conn that is the connection */
struct doq_conn_key key;
/** the connection id, byte string */
uint8_t* cid;
/** the length of cid */
size_t cidlen;
};
/**
* DoQ stream, for DNS over QUIC.
*/
struct doq_stream {
/** the rbtree node for the stream, key is the stream_id */
rbnode_type node;
/** the stream id */
int64_t stream_id;
/** if the stream is closed */
uint8_t is_closed;
/** if the query is complete */
uint8_t is_query_complete;
/** the number of bytes read on the stream, up to querylen+2. */
size_t nread;
/** the length of the input query bytes */
size_t inlen;
/** the input bytes */
uint8_t* in;
/** does the stream have an answer to send */
uint8_t is_answer_available;
/** the answer bytes sent, up to outlen+2. */
size_t nwrite;
/** the length of the output answer bytes */
size_t outlen;
/** the output length in network wireformat */
uint16_t outlen_wire;
/** the output packet bytes */
uint8_t* out;
/** if the stream is on the write list */
uint8_t on_write_list;
/** the prev and next on the write list, if on the list */
struct doq_stream* write_prev, *write_next;
};
/** doq application error code that is sent when a stream is closed */
#define DOQ_APP_ERROR_CODE 1
/**
* Create the doq connection.
* @param c: the comm point for the listening doq socket.
* @param paddr: with remote and local address and ifindex for the
* connection destination. This is where packets are sent.
* @param dcid: the dcid, Destination Connection ID.
* @param dcidlen: length of dcid.
* @param version: client chosen version.
* @return new doq connection or NULL on allocation failure.
*/
struct doq_conn* doq_conn_create(struct comm_point* c,
struct doq_pkt_addr* paddr, const uint8_t* dcid, size_t dcidlen,
uint32_t version);
/**
* Delete the doq connection structure.
* @param conn: to delete.
* @param table: with memory size.
*/
void doq_conn_delete(struct doq_conn* conn, struct doq_table* table);
/** compare function of doq_conn */
int doq_conn_cmp(const void* key1, const void* key2);
/** compare function of doq_conid */
int doq_conid_cmp(const void* key1, const void* key2);
/** compare function of doq_timer */
int doq_timer_cmp(const void* key1, const void* key2);
/** compare function of doq_stream */
int doq_stream_cmp(const void* key1, const void* key2);
/** setup the doq_socket server tls context */
int doq_socket_setup_ctx(struct doq_server_socket* doq_socket);
/** setup the doq connection callbacks, and settings. */
int doq_conn_setup(struct doq_conn* conn, uint8_t* scid, size_t scidlen,
uint8_t* ocid, size_t ocidlen, const uint8_t* token, size_t tokenlen);
/** fill a buffer with random data */
void doq_fill_rand(struct ub_randstate* rnd, uint8_t* buf, size_t len);
/** delete a doq_conid */
void doq_conid_delete(struct doq_conid* conid);
/** add a connection id to the doq_conn.
* caller must hold doq_table.conid_lock. */
int doq_conn_associate_conid(struct doq_conn* conn, uint8_t* data,
size_t datalen);
/** remove a connection id from the doq_conn.
* caller must hold doq_table.conid_lock. */
void doq_conn_dissociate_conid(struct doq_conn* conn, const uint8_t* data,
size_t datalen);
/** initial setup to link current connection ids to the doq_conn */
int doq_conn_setup_conids(struct doq_conn* conn);
/** remove the connection ids from the doq_conn.
* caller must hold doq_table.conid_lock. */
void doq_conn_clear_conids(struct doq_conn* conn);
/** find a conid in the doq_conn connection.
* caller must hold table.conid_lock. */
struct doq_conid* doq_conid_find(struct doq_table* doq_table,
const uint8_t* data, size_t datalen);
/** receive a packet for a connection */
int doq_conn_recv(struct comm_point* c, struct doq_pkt_addr* paddr,
struct doq_conn* conn, struct ngtcp2_pkt_info* pi, int* err_retry,
int* err_drop);
/** send packets for a connection */
int doq_conn_write_streams(struct comm_point* c, struct doq_conn* conn,
int* err_drop);
/** send the close packet for the connection, perhaps again. */
int doq_conn_send_close(struct comm_point* c, struct doq_conn* conn);
/** delete doq stream */
void doq_stream_delete(struct doq_stream* stream);
/** doq read a connection key from repinfo. It is not malloced, but points
* into the repinfo for the dcid. */
void doq_conn_key_from_repinfo(struct doq_conn_key* key,
struct comm_reply* repinfo);
/** doq find a stream in the connection */
struct doq_stream* doq_stream_find(struct doq_conn* conn, int64_t stream_id);
/** doq shutdown the stream. */
int doq_stream_close(struct doq_conn* conn, struct doq_stream* stream,
int send_shutdown);
/** send reply for a connection */
int doq_stream_send_reply(struct doq_conn* conn, struct doq_stream* stream,
struct sldns_buffer* buf);
/** the connection has write interest, wants to write packets */
void doq_conn_write_enable(struct doq_conn* conn);
/** the connection has no write interest, does not want to write packets */
void doq_conn_write_disable(struct doq_conn* conn);
/** set the connection on or off the write list, depending on write interest */
void doq_conn_set_write_list(struct doq_table* table, struct doq_conn* conn);
/** doq remove the connection from the write list */
void doq_conn_write_list_remove(struct doq_table* table,
struct doq_conn* conn);
/** doq get the first conn from the write list, if any, popped from list.
* Locks the conn that is returned. */
struct doq_conn* doq_table_pop_first(struct doq_table* table);
/**
* doq check if the timer for the conn needs to be changed.
* @param conn: connection, caller must hold lock on it.
* @param tv: time value, absolute time, returned.
* @return true if timer needs to be set to tv, false if no change is needed
* to the timer. The timer is already set to the right time in that case.
*/
int doq_conn_check_timer(struct doq_conn* conn, struct timeval* tv);
/** doq remove timer from tree */
void doq_timer_tree_remove(struct doq_table* table, struct doq_timer* timer);
/** doq remove timer from list */
void doq_timer_list_remove(struct doq_table* table, struct doq_timer* timer);
/** doq unset the timer if it was set. */
void doq_timer_unset(struct doq_table* table, struct doq_timer* timer);
/** doq set the timer and add it. */
void doq_timer_set(struct doq_table* table, struct doq_timer* timer,
struct doq_server_socket* worker_doq_socket, struct timeval* tv);
/** doq find a timeout in the timer tree */
struct doq_timer* doq_timer_find_time(struct doq_table* table,
struct timeval* tv);
/** doq handle timeout for a connection. Pass conn locked. Returns false for
* deletion. */
int doq_conn_handle_timeout(struct doq_conn* conn);
/** doq add size to the current quic buffer counter */
void doq_table_quic_size_add(struct doq_table* table, size_t add);
/** doq subtract size from the current quic buffer counter */
void doq_table_quic_size_subtract(struct doq_table* table, size_t subtract);
/** doq check if mem is available for quic. */
int doq_table_quic_size_available(struct doq_table* table,
struct config_file* cfg, size_t mem);
/** doq get the quic size value */
size_t doq_table_quic_size_get(struct doq_table* table);
#endif /* HAVE_NGTCP2 */
char* set_ip_dscp(int socket, int addrfamily, int ds);
/** for debug and profiling purposes only
@ -459,4 +846,14 @@ char* set_ip_dscp(int socket, int addrfamily, int ds);
*/
void verbose_print_unbound_socket(struct unbound_socket* ub_sock);
/** event callback for testcode/doqclient */
void doq_client_event_cb(int fd, short event, void* arg);
/** timer event callback for testcode/doqclient */
void doq_client_timer_cb(int fd, short event, void* arg);
#ifdef HAVE_NGTCP2
/** get a timestamp in nanoseconds */
ngtcp2_tstamp doq_get_timestamp_nanosec(void);
#endif
#endif /* LISTEN_DNSPORT_H */

View file

@ -293,6 +293,9 @@ static void print_mem(struct ub_shm_stat_info* shm_stat,
PR_LL("mem.streamwait", s->svr.mem_stream_wait);
PR_LL("mem.http.query_buffer", s->svr.mem_http2_query_buffer);
PR_LL("mem.http.response_buffer", s->svr.mem_http2_response_buffer);
#ifdef HAVE_NGTCP2
PR_LL("mem.quic", s->svr.mem_quic);
#endif
}
/** print histogram */
@ -359,6 +362,9 @@ static void print_extended(struct ub_stats_info* s, int inhibit_zero)
PR_UL("num.query.tls_resume", s->svr.qtls_resume);
PR_UL("num.query.ipv6", s->svr.qipv6);
PR_UL("num.query.https", s->svr.qhttps);
#ifdef HAVE_NGTCP2
PR_UL("num.query.quic", s->svr.qquic);
#endif
/* flags */
PR_UL("num.query.flags.QR", s->svr.qbit_QR);

View file

@ -255,3 +255,19 @@ void dtio_mainfdcallback(int ATTR_UNUSED(fd), short ATTR_UNUSED(ev),
log_assert(0);
}
#endif
#ifdef HAVE_NGTCP2
void doq_client_event_cb(int ATTR_UNUSED(fd), short ATTR_UNUSED(ev),
void* ATTR_UNUSED(arg))
{
log_assert(0);
}
#endif
#ifdef HAVE_NGTCP2
void doq_client_timer_cb(int ATTR_UNUSED(fd), short ATTR_UNUSED(ev),
void* ATTR_UNUSED(arg))
{
log_assert(0);
}
#endif

View file

@ -68,6 +68,8 @@ static struct thr_check* thread_infos[THRDEBUG_MAX_THREADS];
int check_locking_order = 1;
/** the pid of this runset, reasonably unique. */
static pid_t check_lock_pid;
/** the name of the output file */
static const char* output_name = "ublocktrace";
/**
* Should checklocks print a trace of the lock and unlock calls.
* It uses fprintf for that because the log function uses a lock and that
@ -142,7 +144,8 @@ acquire_locklock(struct checked_lock* lock,
/** add protected region */
void
lock_protect(void *p, void* area, size_t size)
lock_protect_place(void* p, void* area, size_t size, const char* def_func,
const char* def_file, int def_line, const char* def_area)
{
struct checked_lock* lock = *(struct checked_lock**)p;
struct protected_area* e = (struct protected_area*)malloc(
@ -151,6 +154,10 @@ lock_protect(void *p, void* area, size_t size)
fatal_exit("lock_protect: out of memory");
e->region = area;
e->size = size;
e->def_func = def_func;
e->def_file = def_file;
e->def_line = def_line;
e->def_area = def_area;
e->hold = malloc(size);
if(!e->hold)
fatal_exit("lock_protect: out of memory");
@ -203,6 +210,9 @@ prot_check(struct checked_lock* lock,
if(memcmp(p->hold, p->region, p->size) != 0) {
log_hex("memory prev", p->hold, p->size);
log_hex("memory here", p->region, p->size);
log_err("lock_protect on %s %s:%d %s failed",
p->def_func, p->def_file, p->def_line,
p->def_area);
lock_error(lock, func, file, line,
"protected area modified");
}
@ -675,13 +685,19 @@ checklock_unlock(enum check_lock_type type, struct checked_lock* lock,
}
}
void
checklock_set_output_name(const char* name)
{
output_name = name;
}
/** open order info debug file, thr->num must be valid */
static void
open_lockorder(struct thr_check* thr)
{
char buf[24];
time_t t;
snprintf(buf, sizeof(buf), "ublocktrace.%d", thr->num);
snprintf(buf, sizeof(buf), "%s.%d", output_name, thr->num);
thr->order_info = fopen(buf, "w");
if(!thr->order_info)
fatal_exit("could not open %s: %s", buf, strerror(errno));

View file

@ -90,6 +90,14 @@ struct protected_area {
void* hold;
/** next protected area in list */
struct protected_area* next;
/** the place where the lock_protect is made, at init. */
const char* def_func;
/** the file where the lock_protect is made */
const char* def_file;
/** the line number where the lock_protect is made */
int def_line;
/** the text string for the area that is protected, at init call. */
const char* def_area;
};
/**
@ -181,12 +189,19 @@ struct checked_lock {
* It demangles the lock itself (struct checked_lock**).
* @param area: ptr to mem.
* @param size: length of area.
* @param def_func: function where the lock_protect() line is.
* @param def_file: file where the lock_protect() line is.
* @param def_line: line where the lock_protect() line is.
* @param def_area: area string
* You can call it multiple times with the same lock to give several areas.
* Call it when you are done initializing the area, since it will be copied
* at this time and protected right away against unauthorised changes until
* the next lock() call is done.
*/
void lock_protect(void* lock, void* area, size_t size);
void lock_protect_place(void* lock, void* area, size_t size,
const char* def_func, const char* def_file, int def_line,
const char* def_area);
#define lock_protect(lock, area, size) lock_protect_place(lock, area, size, __func__, __FILE__, __LINE__, #area)
/**
* Remove protected area from lock.
@ -203,6 +218,13 @@ void lock_unprotect(void* lock, void* area);
*/
size_t lock_get_mem(void* lock);
/**
* Set the output name, prefix, of the lock check output file(s).
* Call it before the checklock_start or thread creation. Pass a fixed string.
* @param name: string to use for output data file names.
*/
void checklock_set_output_name(const char* name);
/**
* Initialise checklock. Sets up internal debug structures.
*/

2685
testcode/doqclient.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -939,6 +939,11 @@ listen_create(struct comm_base* base, struct listen_port* ATTR_UNUSED(ports),
int ATTR_UNUSED(http_notls),
struct tcl_list* ATTR_UNUSED(tcp_conn_limit),
void* ATTR_UNUSED(sslctx), struct dt_env* ATTR_UNUSED(dtenv),
struct doq_table* ATTR_UNUSED(table),
struct ub_randstate* ATTR_UNUSED(rnd),
const char* ATTR_UNUSED(ssl_service_key),
const char* ATTR_UNUSED(ssl_service_pem),
struct config_file* ATTR_UNUSED(cfg),
comm_point_callback_type* cb, void *cb_arg)
{
struct replay_runtime* runtime = (struct replay_runtime*)base;

View file

@ -600,3 +600,52 @@ void listen_desetup_locks(void)
{
/* nothing */
}
#ifdef HAVE_NGTCP2
void comm_point_doq_callback(int ATTR_UNUSED(fd), short ATTR_UNUSED(event),
void* ATTR_UNUSED(arg))
{
/* nothing */
}
int doq_conn_cmp(const void* ATTR_UNUSED(key1), const void* ATTR_UNUSED(key2))
{
return 0;
}
int doq_conid_cmp(const void* ATTR_UNUSED(key1), const void* ATTR_UNUSED(key2))
{
return 0;
}
int doq_timer_cmp(const void* ATTR_UNUSED(key1), const void* ATTR_UNUSED(key2))
{
return 0;
}
int doq_stream_cmp(const void* ATTR_UNUSED(key1), const void* ATTR_UNUSED(key2))
{
return 0;
}
struct doq_table* doq_table_create(struct config_file* ATTR_UNUSED(cfg),
struct ub_randstate* ATTR_UNUSED(rnd))
{
return calloc(1, sizeof(struct doq_table));
}
void doq_table_delete(struct doq_table* table)
{
free(table);
}
void doq_timer_cb(void* ATTR_UNUSED(arg))
{
/* nothing */
}
size_t doq_table_quic_size_get(struct doq_table* ATTR_UNUSED(table))
{
return 0;
}
#endif

84
testcode/unitdoq.c Normal file
View file

@ -0,0 +1,84 @@
/*
* testcode/unitdoq.c - unit test for doq routines.
*
* Copyright (c) 2022, NLnet Labs. All rights reserved.
*
* This software is open source.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of the NLNET LABS nor the names of its contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
/**
* \file
* Calls doq related unit tests. Exits with code 1 on a failure.
*/
#include "config.h"
#ifdef HAVE_NGTCP2
#include "util/netevent.h"
#include "services/listen_dnsport.h"
#include "testcode/unitmain.h"
/** check the size of a connection for doq */
static void
doq_size_conn_check()
{
/* Printout the size of one doq connection, in memory usage.
* A connection with a couple cids, of type doq_conid, and
* it has one stream, and that has a query and an answer. */
size_t answer_size = 233; /* size of www.nlnetlabs.nl minimal answer
with dnssec and one A record. The unsigned answer is 176 with
additional data, 61 bytes minimal response one A record. */
size_t query_size = 45; /* size of query for www.nlnetlabs.nl, with
an EDNS record with DO flag. */
size_t conn_size = sizeof(struct doq_conn);
size_t conid_size = sizeof(struct doq_conid);
size_t stream_size = sizeof(struct doq_stream);
conn_size += 16; /* DCID len in the conn key */
conn_size += 0; /* the size of the ngtcp2_conn */
conn_size += 0; /* the size of the SSL record */
conn_size += 0; /* size of the close pkt,
but we do not count it here. Only if the conn gets closed. */
conid_size += 16; /* the dcid of the conn key */
conid_size += 16; /* the cid */
stream_size += query_size; /* size of in buffer */
stream_size += answer_size; /* size of out buffer */
printf("doq connection size %u bytes\n", (unsigned)(conn_size +
conid_size*3 + stream_size));
}
void doq_test(void)
{
unit_show_feature("doq");
doq_size_conn_check();
}
#endif /* HAVE_NGTCP2 */

View file

@ -1432,6 +1432,9 @@ main(int argc, char* argv[])
#ifdef CLIENT_SUBNET
ecs_test();
#endif /* CLIENT_SUBNET */
#ifdef HAVE_NGTCP2
doq_test();
#endif /* HAVE_NGTCP2 */
if(log_get_lock()) {
lock_basic_destroy((lock_basic_type*)log_get_lock());
}

View file

@ -84,5 +84,7 @@ void authzone_test(void);
void zonemd_test(void);
/** unit test for tcp_reuse functions */
void tcpreuse_test(void);
/** unit test for doq functions */
void doq_test(void);
#endif /* TESTCODE_UNITMAIN_H */

View file

@ -0,0 +1,21 @@
server:
verbosity: 2
# num-threads: 1
interface: 127.0.0.1@@PORT@
quic-port: @PORT@
tls-service-key: "unbound_server.key"
tls-service-pem: "unbound_server.pem"
use-syslog: no
directory: .
pidfile: "unbound.pid"
chroot: ""
username: ""
do-not-query-localhost: no
local-zone: "example.net" static
local-data: "www.example.net. IN A 1.2.3.4"
local-zone: "drop.net" deny
forward-zone:
name: "."
forward-addr: "127.0.0.1@@TOPORT@"

View file

@ -0,0 +1,16 @@
BaseName: doq_downstream
Version: 1.0
Description: Test DNS-over-QUIC query processing
CreationDate: Mon Aug 01 16:00:00 CEST 2022
Maintainer:
Category:
Component:
CmdDepends:
Depends:
Help:
Pre: doq_downstream.pre
Post: doq_downstream.post
Test: doq_downstream.test
AuxFiles:
Passed:
Failure:

View file

@ -0,0 +1,13 @@
# #-- doq_downstream.post --#
# source the master var file when it's there
[ -f ../.tpkg.var.master ] && source ../.tpkg.var.master
# source the test var file when it's there
[ -f .tpkg.var.test ] && source .tpkg.var.test
#
# do your teardown here
PRE="../.."
. ../common.sh
kill_pid $FWD_PID
if test -f unbound.pid; then
kill_pid $UNBOUND_PID
fi

View file

@ -0,0 +1,44 @@
# #-- doq_downstream.pre--#
# source the master var file when it's there
[ -f ../.tpkg.var.master ] && source ../.tpkg.var.master
# use .tpkg.var.test for in test variable passing
[ -f .tpkg.var.test ] && source .tpkg.var.test
PRE="../.."
. ../common.sh
if grep "define HAVE_NGTCP2 1" $PRE/config.h; then echo test enabled; else skip_test "test skipped"; fi
if test -f $PRE/unbound_do_valgrind_in_test; then
do_valgrind=yes
else
do_valgrind=no
fi
VALGRIND_FLAGS="--leak-check=full --show-leak-kinds=all"
get_random_port 2
UNBOUND_PORT=$RND_PORT
FWD_PORT=$(($RND_PORT + 1))
echo "UNBOUND_PORT=$UNBOUND_PORT" >> .tpkg.var.test
echo "FWD_PORT=$FWD_PORT" >> .tpkg.var.test
# start forwarder
get_ldns_testns
$LDNS_TESTNS -p $FWD_PORT doq_downstream.testns >fwd.log 2>&1 &
FWD_PID=$!
echo "FWD_PID=$FWD_PID" >> .tpkg.var.test
# make config file
sed -e 's/@PORT\@/'$UNBOUND_PORT'/' -e 's/@TOPORT\@/'$FWD_PORT'/' < doq_downstream.conf > ub.conf
# start unbound in the background
if test $do_valgrind = "yes"; then
valgrind $VALGRIND_FLAGS $PRE/unbound -vvvv -d -c ub.conf >unbound.log 2>&1 &
else
$PRE/unbound -vvvv -d -c ub.conf >unbound.log 2>&1 &
fi
UNBOUND_PID=$!
echo "UNBOUND_PID=$UNBOUND_PID" >> .tpkg.var.test
cat .tpkg.var.test
wait_ldns_testns_up fwd.log
wait_unbound_up unbound.log

View file

@ -0,0 +1,109 @@
# #-- doq_downstream.test --#
# source the master var file when it's there
[ -f ../.tpkg.var.master ] && source ../.tpkg.var.master
# use .tpkg.var.test for in test variable passing
[ -f .tpkg.var.test ] && source .tpkg.var.test
PRE="../.."
. ../common.sh
get_make
(cd $PRE; $MAKE doqclient)
# test query from local-data, immediate like from cache
echo "> query www.example.net."
$PRE/doqclient -s 127.0.0.1 -p $UNBOUND_PORT www.example.net. A IN >outfile 2>&1
cat outfile
if test "$?" -ne 0; then
echo "exit status not OK"
echo "> cat logfiles"
cat outfile
cat fwd.log
cat unbound.log
echo "Not OK"
exit 1
fi
if grep "www.example.net" outfile | grep "1.2.3.4"; then
echo "content OK"
else
echo "result contents not OK"
echo "> cat logfiles"
cat outfile
cat fwd.log
cat unbound.log
echo "result contents not OK"
exit 1
fi
echo "OK"
# test query that is resolved
echo "> query www.example.com."
$PRE/doqclient -s 127.0.0.1 -p $UNBOUND_PORT www.example.com. A IN >outfile 2>&1
cat outfile
if test "$?" -ne 0; then
echo "exit status not OK"
echo "> cat logfiles"
cat outfile
cat fwd.log
cat unbound.log
echo "Not OK"
exit 1
fi
if grep "www.example.com" outfile | grep "10.20.30.40"; then
echo "content OK"
else
echo "result contents not OK"
echo "> cat logfiles"
cat outfile
cat fwd.log
cat unbound.log
echo "result contents not OK"
exit 1
fi
echo "OK"
# Perform the lock verify tests, stop the server first.
kill_pid $UNBOUND_PID
cat unbound.log
# Remove pidfile so that the post script does not try to stop the server,
# it is already stopped.
rm -f unbound.pid
if test -f ublocktrace-doqclient.0; then
if $PRE/lock-verify ublocktrace-doqclient.* 2>&1; then
echo "lock-verify test ublocktrace-doqclient worked."
else
echo "lock-verify test ublocktrace-doqclient failed."
exit 1
fi
fi
if test -f ublocktrace.0; then
if $PRE/lock-verify ublocktrace.* 2>&1; then
echo "lock-verify test ublocktrace worked."
else
echo "lock-verify test ublocktrace failed."
exit 1
fi
if grep "lock error" unbound.log >/dev/null; then
echo "lock error"
exit 1
fi
fi
# check valgrind output
if test -f $PRE/unbound_do_valgrind_in_test; then
if grep "All heap blocks were freed -- no leaks are possible" unbound.log; then
: # clean
else
grep "^==" unbound.log
echo "Memory leaked"
grep "in use at exit" unbound.log
exit 1
fi
if grep "ERROR SUMMARY: 0 errors from 0 contexts" unbound.log; then
: # clean
else
grep "^==" unbound.log
echo "Errors"
grep "ERROR SUMMARY" unbound.log
exit 1
fi
fi
exit 0

View file

@ -0,0 +1,13 @@
; nameserver test file
$ORIGIN example.com.
$TTL 3600
ENTRY_BEGIN
MATCH opcode qtype qname
REPLY QR AA NOERROR
ADJUST copy_id
SECTION QUESTION
www IN A
SECTION ANSWER
www IN A 10.20.30.40
ENTRY_END

View file

@ -0,0 +1,15 @@
-----BEGIN RSA PRIVATE KEY-----
MIICWwIBAAKBgQC3F7Jsv2u01pLL9rFnjsMU/IaCFUIz/624DcaE84Z4gjMl5kWA
3axQcqul1wlwSrbKwrony+d9hH/+MX0tZwvl8w3OmhmOAiaQ+SHCsIuOjVwQjX0s
RLB61Pz5+PAiVvnPa9JIYB5QrK6DVEsxIHj8MOc5JKORrnESsFDh6yeMeQIDAQAB
AoGAAuWoGBprTOA8UGfl5LqYkaNxSWumsYXxLMFjC8WCsjN1NbtQDDr1uAwodSZS
6ujzvX+ZTHnofs7y64XC8k34HTOCD2zlW7kijWbT8YjRYFU6o9F5zUGD9RCan0ds
sVscT2psLSzfdsmFAcbmnGdxYkXk2PC1FHtaqExxehralGUCQQDcqrg9uQKXlhQi
XAaPr8SiWvtRm2a9IMMZkRfUWZclPHq6fCWNuUaCD+cTat4wAuqeknAz33VEosw3
fXGsok//AkEA1GjIHXrOcSlpfVJb6NeOBugjRtZ7ZDT5gbtnMS9ob0qntKV6saaL
CNmJwuD9Q3XkU5j1+uHvYGP2NzcJd2CjhwJACV0hNlVMe9w9fHvFN4Gw6WbM9ViP
0oS6YrJafYNTu5vGZXVxLoNnL4u3NYa6aPUmuZXjNwBLfJ8f5VboZPf6RwJAINd2
oYA8bSi/A755MX4qmozH74r4Fx1Nuq5UHTm8RwDe/0Javx8F/j9MWpJY9lZDEF3l
In5OebPa/NyInSmW/wJAZuP9aRn0nDBkHYri++1A7NykMiJ/nH0mDECbnk+wxx0S
LwqIetBhxb8eQwMg45+iAH7CHAMQ8BQuF/nFE6eotg==
-----END RSA PRIVATE KEY-----

View file

@ -0,0 +1,11 @@
-----BEGIN CERTIFICATE-----
MIIBmzCCAQQCCQDsNJ1UmphEFzANBgkqhkiG9w0BAQUFADASMRAwDgYDVQQDEwd1
bmJvdW5kMB4XDTA4MDkxMTA5MDk0MFoXDTI4MDUyOTA5MDk0MFowEjEQMA4GA1UE
AxMHdW5ib3VuZDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAtxeybL9rtNaS
y/axZ47DFPyGghVCM/+tuA3GhPOGeIIzJeZFgN2sUHKrpdcJcEq2ysK6J8vnfYR/
/jF9LWcL5fMNzpoZjgImkPkhwrCLjo1cEI19LESwetT8+fjwIlb5z2vSSGAeUKyu
g1RLMSB4/DDnOSSjka5xErBQ4esnjHkCAwEAATANBgkqhkiG9w0BAQUFAAOBgQAZ
9N0lnLENs4JMvPS+mn8C5m9bkkFITd32IiLjf0zgYpIUbFXH6XaEr9GNZBUG8feG
l/6WRXnbnVSblI5odQ4XxGZ9inYY6qtW30uv76HvoKp+QZ1c3460ddR8NauhcCHH
Z7S+QbLXi+r2JAhpPozZCjBHlRD0ixzA1mKQTJhJZg==
-----END CERTIFICATE-----

View file

@ -135,6 +135,8 @@ config_create(void)
cfg->http_query_buffer_size = 4*1024*1024;
cfg->http_response_buffer_size = 4*1024*1024;
cfg->http_nodelay = 1;
cfg->quic_port = UNBOUND_DNS_OVER_QUIC_PORT;
cfg->quic_size = 8*1024*1024;
cfg->use_syslog = 1;
cfg->log_identity = NULL; /* changed later with argv[0] */
cfg->log_time_ascii = 0;
@ -604,6 +606,8 @@ int config_set_option(struct config_file* cfg, const char* opt,
else S_MEMSIZE("http-response-buffer-size:", http_response_buffer_size)
else S_YNO("http-nodelay:", http_nodelay)
else S_YNO("http-notls-downstream:", http_notls_downstream)
else S_NUMBER_NONZERO("quic-port:", quic_port)
else S_MEMSIZE("quic-size:", quic_size)
else S_YNO("interface-automatic:", if_automatic)
else S_STR("interface-automatic-ports:", if_automatic_ports)
else S_YNO("use-systemd:", use_systemd)
@ -1154,6 +1158,8 @@ config_get_option(struct config_file* cfg, const char* opt,
else O_MEM(opt, "http-response-buffer-size", http_response_buffer_size)
else O_YNO(opt, "http-nodelay", http_nodelay)
else O_YNO(opt, "http-notls-downstream", http_notls_downstream)
else O_DEC(opt, "quic-port", quic_port)
else O_MEM(opt, "quic-size", quic_size)
else O_YNO(opt, "use-systemd", use_systemd)
else O_YNO(opt, "do-daemonize", do_daemonize)
else O_STR(opt, "chroot", chrootdir)
@ -2821,3 +2827,15 @@ if_is_dnscrypt(const char* ifname, const char* port, int dnscrypt_port)
return 0;
#endif
}
/** see if interface is quic, its port number == the quic port number */
int
if_is_quic(const char* ifname, const char* port, int quic_port)
{
char* p = strchr(ifname, '@');
if(!p && atoi(port) == quic_port)
return 1;
if(p && atoi(p+1) == quic_port)
return 1;
return 0;
}

View file

@ -161,6 +161,11 @@ struct config_file {
/** Disable TLS for http sockets downstream */
int http_notls_downstream;
/** port on which to provide DNS over QUIC service */
int quic_port;
/** size of the quic data, max bytes */
size_t quic_size;
/** outgoing port range number of ports (per thread) */
int outgoing_num_ports;
/** number of outgoing tcp buffers per (per thread) */
@ -1406,6 +1411,10 @@ int if_is_pp2(const char* ifname, const char* port,
/** see if interface is DNSCRYPT, its port number == the dnscrypt port number */
int if_is_dnscrypt(const char* ifname, const char* port, int dnscrypt_port);
/** see if interface is quic, its port number == the quic port number */
int if_is_quic(const char* ifname, const char* port, int quic_port);
#ifdef USE_LINUX_IP_LOCAL_PORT_RANGE
#define LINUX_IP_LOCAL_PORT_RANGE_PATH "/proc/sys/net/ipv4/ip_local_port_range"
#endif

View file

@ -269,6 +269,8 @@ http-query-buffer-size{COLON} { YDVAR(1, VAR_HTTP_QUERY_BUFFER_SIZE) }
http-response-buffer-size{COLON} { YDVAR(1, VAR_HTTP_RESPONSE_BUFFER_SIZE) }
http-nodelay{COLON} { YDVAR(1, VAR_HTTP_NODELAY) }
http-notls-downstream{COLON} { YDVAR(1, VAR_HTTP_NOTLS_DOWNSTREAM) }
quic-port{COLON} { YDVAR(1, VAR_QUIC_PORT) }
quic-size{COLON} { YDVAR(1, VAR_QUIC_SIZE) }
use-systemd{COLON} { YDVAR(1, VAR_USE_SYSTEMD) }
do-daemonize{COLON} { YDVAR(1, VAR_DO_DAEMONIZE) }
interface{COLON} { YDVAR(1, VAR_INTERFACE) }

View file

@ -203,6 +203,7 @@ extern struct config_parser_state* cfg_parser;
%token VAR_RPZ_SIGNAL_NXDOMAIN_RA VAR_INTERFACE_AUTOMATIC_PORTS VAR_EDE
%token VAR_INTERFACE_ACTION VAR_INTERFACE_VIEW VAR_INTERFACE_TAG
%token VAR_INTERFACE_TAG_ACTION VAR_INTERFACE_TAG_DATA
%token VAR_QUIC_PORT VAR_QUIC_SIZE
%token VAR_PROXY_PROTOCOL_PORT VAR_STATISTICS_INHIBIT_ZERO
%token VAR_HARDEN_UNKNOWN_ADDITIONAL VAR_DISABLE_EDNS_DO VAR_CACHEDB_NO_STORE
%token VAR_LOG_DESTADDR VAR_CACHEDB_CHECK_WHEN_SERVE_EXPIRED
@ -342,6 +343,7 @@ content_server: server_num_threads | server_verbosity | server_port |
server_edns_client_string_opcode | server_nsid |
server_zonemd_permissive_mode | server_max_reuse_tcp_queries |
server_tcp_reuse_timeout | server_tcp_auth_query_timeout |
server_quic_port | server_quic_size |
server_interface_automatic_ports | server_ede |
server_proxy_protocol_port | server_statistics_inhibit_zero |
server_harden_unknown_additional | server_disable_edns_do |
@ -1209,6 +1211,21 @@ server_http_notls_downstream: VAR_HTTP_NOTLS_DOWNSTREAM STRING_ARG
else cfg_parser->cfg->http_notls_downstream = (strcmp($2, "yes")==0);
free($2);
};
server_quic_port: VAR_QUIC_PORT STRING_ARG
{
OUTYY(("P(server_quic_port:%s)\n", $2));
if(atoi($2) == 0)
yyerror("port number expected");
else cfg_parser->cfg->quic_port = atoi($2);
free($2);
};
server_quic_size: VAR_QUIC_SIZE STRING_ARG
{
OUTYY(("P(server_quic_size:%s)\n", $2));
if(!cfg_parse_memsize($2, &cfg_parser->cfg->quic_size))
yyerror("memory size expected");
free($2);
};
server_use_systemd: VAR_USE_SYSTEMD STRING_ARG
{
OUTYY(("P(server_use_systemd:%s)\n", $2));

View file

@ -47,6 +47,7 @@
#include "util/fptr_wlist.h"
#include "util/mini_event.h"
#include "services/outside_network.h"
#include "services/listen_dnsport.h"
#include "services/mesh.h"
#include "services/localzone.h"
#include "services/authzone.h"
@ -132,6 +133,9 @@ fptr_whitelist_comm_timer(void (*fptr)(void*))
else if(fptr == &worker_stat_timer_cb) return 1;
else if(fptr == &worker_probe_timer_cb) return 1;
else if(fptr == &validate_suspend_timer_cb) return 1;
#ifdef HAVE_NGTCP2
else if(fptr == &doq_timer_cb) return 1;
#endif
#ifdef UB_ON_WINDOWS
else if(fptr == &wsvc_cron_cb) return 1;
#endif
@ -181,6 +185,9 @@ fptr_whitelist_event(void (*fptr)(int, short, void *))
else if(fptr == &tube_handle_signal) return 1;
else if(fptr == &comm_base_handle_slow_accept) return 1;
else if(fptr == &comm_point_http_handle_callback) return 1;
#ifdef HAVE_NGTCP2
else if(fptr == &comm_point_doq_callback) return 1;
#endif
#ifdef USE_DNSTAP
else if(fptr == &dtio_output_cb) return 1;
else if(fptr == &dtio_cmd_cb) return 1;
@ -190,6 +197,10 @@ fptr_whitelist_event(void (*fptr)(int, short, void *))
else if(fptr == &dtio_tap_callback) return 1;
else if(fptr == &dtio_mainfdcallback) return 1;
#endif
#ifdef HAVE_NGTCP2
else if(fptr == &doq_client_event_cb) return 1;
else if(fptr == &doq_client_timer_cb) return 1;
#endif
#ifdef UB_ON_WINDOWS
else if(fptr == &worker_win_stop_cb) return 1;
#endif
@ -248,6 +259,12 @@ fptr_whitelist_rbtree_cmp(int (*fptr) (const void *, const void *))
else if(fptr == &auth_zone_cmp) return 1;
else if(fptr == &auth_data_cmp) return 1;
else if(fptr == &auth_xfer_cmp) return 1;
#ifdef HAVE_NGTCP2
else if(fptr == &doq_conn_cmp) return 1;
else if(fptr == &doq_conid_cmp) return 1;
else if(fptr == &doq_timer_cmp) return 1;
else if(fptr == &doq_stream_cmp) return 1;
#endif
return 0;
}

View file

@ -88,6 +88,7 @@
#define lock_get_mem(lock) (0) /* nothing */
#define checklock_start() /* nop */
#define checklock_stop() /* nop */
#define checklock_set_output_name(name) /* nop */
#ifdef HAVE_PTHREAD
#include <pthread.h>

File diff suppressed because it is too large Load diff

View file

@ -65,6 +65,9 @@
#ifdef HAVE_NGHTTP2_NGHTTP2_H
#include <nghttp2/nghttp2.h>
#endif
#ifdef HAVE_NGTCP2
#include <ngtcp2/ngtcp2.h>
#endif
struct sldns_buffer;
struct comm_point;
@ -72,6 +75,11 @@ struct comm_reply;
struct tcl_list;
struct ub_event_base;
struct unbound_socket;
struct doq_server_socket;
struct doq_table;
struct doq_conn;
struct config_file;
struct ub_randstate;
struct mesh_state;
struct mesh_area;
@ -105,6 +113,8 @@ typedef int comm_point_callback_type(struct comm_point*, void*, int,
#define NETEVENT_SLOW_ACCEPT_TIME 2000
/** timeout to slow down log print, so it does not spam the logs, in sec */
#define SLOW_LOG_TIME 10
/** for doq, the maximum dcid length, in ngtcp2 it is 20. */
#define DOQ_MAX_CIDLEN 24
/**
* A communication point dispatcher. Thread specific.
@ -164,6 +174,19 @@ struct comm_reply {
struct sockaddr_storage client_addr;
/** the original address length */
socklen_t client_addrlen;
#ifdef HAVE_NGTCP2
/** the doq ifindex, together with addr and localaddr in pktinfo,
* and dcid makes the doq_conn_key to find the connection */
int doq_ifindex;
/** the doq dcid, the connection id used to find the connection */
uint8_t doq_dcid[DOQ_MAX_CIDLEN];
/** the length of the doq dcid */
size_t doq_dcidlen;
/** the doq stream id where the query came in on */
int64_t doq_streamid;
/** port number for doq */
int doq_srcport;
#endif /* HAVE_NGTCP2 */
};
/**
@ -266,6 +289,11 @@ struct comm_point {
/** maximum number of HTTP/2 streams per connection. Send in HTTP/2
* SETTINGS frame. */
uint32_t http2_max_streams;
/* -------- DoQ ------- */
#ifdef HAVE_NGTCP2
/** the doq server socket, with list of doq connections */
struct doq_server_socket* doq_socket;
#endif
/* -------- dnstap ------- */
/** the dnstap environment */
@ -281,6 +309,8 @@ struct comm_point {
comm_tcp,
/** HTTP handler socket */
comm_http,
/** DOQ handler socket */
comm_doq,
/** AF_UNIX socket - for internal commands. */
comm_local,
/** raw - not DNS format - for pipe readers and writers */
@ -552,6 +582,30 @@ struct comm_point* comm_point_create_udp_ancil(struct comm_base* base,
int fd, struct sldns_buffer* buffer, int pp2_enabled,
comm_point_callback_type* callback, void* callback_arg, struct unbound_socket* socket);
/**
* Create an UDP comm point for DoQ. Calls malloc.
* setups the structure with the parameters you provide.
* @param base: in which base to alloc the commpoint.
* @param fd : file descriptor of open UDP socket.
* @param buffer: shared buffer by UDP sockets from this thread.
* @param callback: callback function pointer.
* @param callback_arg: will be passed to your callback function.
* @param socket: and opened socket properties will be passed to your callback function.
* @param table: the doq connection table for the host.
* @param rnd: random generator to use.
* @param ssl_service_key: the ssl service key file.
* @param ssl_service_pem: the ssl service pem file.
* @param cfg: config file struct.
* @return: returns the allocated communication point. NULL on error.
* Sets timeout to NULL. Turns off TCP options.
*/
struct comm_point* comm_point_create_doq(struct comm_base* base,
int fd, struct sldns_buffer* buffer,
comm_point_callback_type* callback, void* callback_arg,
struct unbound_socket* socket, struct doq_table* table,
struct ub_randstate* rnd, const char* ssl_service_key,
const char* ssl_service_pem, struct config_file* cfg);
/**
* Create a TCP listener comm point. Calls malloc.
* Setups the structure with the parameters you provide.
@ -821,6 +875,16 @@ void comm_point_udp_callback(int fd, short event, void* arg);
*/
void comm_point_udp_ancil_callback(int fd, short event, void* arg);
/**
* This routine is published for checks and tests, and is only used internally.
* handle libevent callback for doq comm point.
* @param fd: file descriptor.
* @param event: event bits from libevent:
* EV_READ, EV_WRITE, EV_SIGNAL, EV_TIMEOUT.
* @param arg: the comm_point structure.
*/
void comm_point_doq_callback(int fd, short event, void* arg);
/**
* This routine is published for checks and tests, and is only used internally.
* handle libevent callback for tcp accept comm point
@ -958,6 +1022,106 @@ void http2_stream_add_meshstate(struct http2_stream* h2_stream,
/** Remove mesh state from stream. When the mesh state has been removed. */
void http2_stream_remove_mesh_state(struct http2_stream* h2_stream);
/**
* DoQ socket address storage for IP4 or IP6 address. Smaller than
* the sockaddr_storage because not with af_unix pathnames.
*/
struct doq_addr_storage {
union {
struct sockaddr_in in;
#ifdef AF_INET6
struct sockaddr_in6 in6;
#endif
} sockaddr;
};
/**
* The DoQ server socket information, for DNS over QUIC.
*/
struct doq_server_socket {
/** the doq connection table */
struct doq_table* table;
/** random generator */
struct ub_randstate* rnd;
/** if address validation is enabled */
uint8_t validate_addr;
/** the ssl service key file */
char* ssl_service_key;
/** the ssl service pem file */
char* ssl_service_pem;
/** the ssl verify pem file */
char* ssl_verify_pem;
/** the server scid length */
int sv_scidlen;
/** the idle timeout in nanoseconds */
uint64_t idle_timeout;
/** the static secret for the server */
uint8_t* static_secret;
/** length of the static secret */
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 */
struct sldns_buffer* pkt_buf;
/** the current doq connection when we are in callbacks to worker,
* so that we have the already locked structure at our disposal. */
struct doq_conn* current_conn;
/** if the callback event on the fd has write flags */
uint8_t event_has_write;
/** if there is a blocked packet in the blocked_pkt buffer */
int have_blocked_pkt;
/** store blocked packet, a packet that could not be send on the
* nonblocking socket. It has to be sent later, when the write on
* the udp socket unblocks. */
struct sldns_buffer* blocked_pkt;
#ifdef HAVE_NGTCP2
/** the ecn info for the blocked packet, congestion information. */
struct ngtcp2_pkt_info blocked_pkt_pi;
#endif
/** the packet destination for the blocked packet. */
struct doq_pkt_addr* blocked_paddr;
/** timer for this worker on this comm_point to wait on. */
struct comm_timer* timer;
/** the timer that is marked by the doq_socket as waited on. */
struct timeval marked_time;
/** the current time for use by time functions, time_t. */
time_t* now_tt;
/** the current time for use by time functions, timeval. */
struct timeval* now_tv;
/** config file for the worker. */
struct config_file* cfg;
};
/**
* DoQ packet address information. From pktinfo, stores local and remote
* address and ifindex, so the packet can be sent there.
*/
struct doq_pkt_addr {
/** the remote addr, and local addr */
struct doq_addr_storage addr, localaddr;
/** length of addr and length of localaddr */
socklen_t addrlen, localaddrlen;
/** interface index from pktinfo ancillary information */
int ifindex;
};
/** Initialize the pkt addr with lengths set to sizeof. That is ready for
* a call to recv. */
void doq_pkt_addr_init(struct doq_pkt_addr* paddr);
/** send doq packet over UDP. */
void doq_send_pkt(struct comm_point* c, struct doq_pkt_addr* paddr,
uint32_t ecn);
/** doq timer callback function. */
void doq_timer_cb(void* arg);
/**
* This routine is published for checks and tests, and is only used internally.
* handle libevent callback for timer comm.