From 0d4fdbf15d8eec908b3e63b606f112b18a63015e Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Tue, 21 Jan 2025 11:42:20 +0100 Subject: [PATCH] asyn-thread: use c-ares to resolve HTTPS RR Allow building with c-ares and yet use threaded resolver for the main host A/AAAA resolving: `--with-ares` provides the c-ares install path and defaults to use c-ares for name resolving `--with-threaded-resolver` still uses c-ares in the build (for HTTPS) but uses the threaded resolver for "normal" resolves. It works similarly for cmake: ENABLE_ARES enables ares, and if ENABLE_THREADED_RESOLVER also is set, c-ares is used for HTTPS RR and the threaded resolver for "normal" resolves. HTTPSRR and c-ares-rr are new features return by curl_version_info() and thus shown by curl -V. The c-ares-rr feature bit is there to make it possible to distinguish between builds using c-ares for all name resolves and builds that use the threaded resolves for the regular name resolves and c-ares for HTTPSRR only. "c-ares-rr" means it does not use c-ares for "plain" name resolves. HTTPSRR support is EXPERIMENTAL only. Closes #16054 --- .github/scripts/spellcheck.words | 3 +- CMakeLists.txt | 19 ++- configure.ac | 116 ++++--------- docs/libcurl/curl_version_info.md | 75 ++++---- lib/asyn-ares.c | 274 ++++++++++++------------------ lib/asyn-thread.c | 96 ++++++----- lib/asyn.h | 64 +++++++ lib/curl_setup.h | 16 +- lib/hostip.h | 26 +-- lib/httpsrr.c | 79 +++++++++ lib/httpsrr.h | 35 ++++ lib/version.c | 10 ++ m4/curl-confopts.m4 | 65 ++----- tests/FILEFORMAT.md | 3 +- tests/data/test1014 | 2 +- tests/libtest/lib1565.c | 2 +- tests/runtests.pl | 3 +- tests/server/disabled.c | 3 - 18 files changed, 470 insertions(+), 421 deletions(-) diff --git a/.github/scripts/spellcheck.words b/.github/scripts/spellcheck.words index 85714c771d..1961715516 100644 --- a/.github/scripts/spellcheck.words +++ b/.github/scripts/spellcheck.words @@ -346,6 +346,7 @@ httpget HttpGet HTTPS https +HTTPSRR hyper's Högskolan IANA @@ -779,10 +780,10 @@ src SRP SRWLOCK SSL -SSLS ssl SSLeay SSLKEYLOGFILE +SSLS sslv SSLv SSLVERSION diff --git a/CMakeLists.txt b/CMakeLists.txt index f66b7e1fcb..1987cb1ac8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -243,9 +243,15 @@ elseif(DOS OR AMIGA) endif() option(CURL_LTO "Enable compiler Link Time Optimizations" OFF) -cmake_dependent_option(ENABLE_THREADED_RESOLVER "Enable threaded DNS lookup" - ON "NOT ENABLE_ARES;NOT DOS;NOT AMIGA" - OFF) +if(NOT DOS AND NOT AMIGA) + # if c-ares is used, default the threaded resolver to OFF + if(ENABLE_ARES) + set(_enable_threaded_resolver_default OFF) + else() + set(_enable_threaded_resolver_default ON) + endif() + option(ENABLE_THREADED_RESOLVER "Enable threaded DNS lookup" ${_enable_threaded_resolver_default}) +endif() include(PickyWarnings) @@ -1003,7 +1009,10 @@ if(USE_ECH) if(NOT HAVE_ECH) message(FATAL_ERROR "ECH support missing in OpenSSL/BoringSSL/AWS-LC/wolfSSL") else() - message(STATUS "ECH enabled.") + message(STATUS "ECH enabled") + # ECH wants HTTPSRR + set(USE_HTTPSRR ON) + message(STATUS "HTTPSRR enabled") endif() else() message(FATAL_ERROR "ECH requires ECH-enablded OpenSSL, BoringSSL, AWS-LC or wolfSSL") @@ -2098,6 +2107,7 @@ curl_add_if("brotli" HAVE_BROTLI) curl_add_if("gsasl" USE_GSASL) curl_add_if("zstd" HAVE_ZSTD) curl_add_if("AsynchDNS" USE_ARES OR USE_THREADS_POSIX OR USE_THREADS_WIN32) +curl_add_if("c-ares-rr" USE_ARES AND ENABLE_THREADED_RESOLVER) curl_add_if("IDN" (HAVE_LIBIDN2 AND HAVE_IDN2_H) OR USE_WIN32_IDN OR USE_APPLE_IDN) @@ -2128,6 +2138,7 @@ curl_add_if("threadsafe" HAVE_ATOMIC OR curl_add_if("Debug" ENABLE_DEBUG) curl_add_if("TrackMemory" ENABLE_CURLDEBUG) curl_add_if("ECH" _ssl_enabled AND HAVE_ECH) +curl_add_if("HTTPSRR" _ssl_enabled AND USE_HTTPSRR) curl_add_if("PSL" USE_LIBPSL) curl_add_if("CAcert" CURL_CA_EMBED_SET) curl_add_if("SSLS-EXPORT" _ssl_enabled AND USE_SSLS_EXPORT) diff --git a/configure.ac b/configure.ac index 3c1e64d534..a67dc76064 100644 --- a/configure.ac +++ b/configure.ac @@ -4134,74 +4134,26 @@ dnl set variable for use in automakefile(s) AM_CONDITIONAL(USE_MANUAL, test x"$USE_MANUAL" = x1) CURL_CHECK_LIB_ARES +CURL_CHECK_OPTION_THREADED_RESOLVER -if test "x$want_ares" != xyes; then - CURL_CHECK_OPTION_THREADED_RESOLVER - - if test "$ipv6" = yes; then - CURL_DARWIN_SYSTEMCONFIGURATION - fi +if test "$ipv6" = yes; then + CURL_DARWIN_SYSTEMCONFIGURATION fi -dnl ************************************************************ -dnl disable POSIX threads -dnl -AC_MSG_CHECKING([whether to use POSIX threads for threaded resolver]) -AC_ARG_ENABLE(pthreads, -AS_HELP_STRING([--enable-pthreads], - [Enable POSIX threads (default for threaded resolver)]) -AS_HELP_STRING([--disable-pthreads],[Disable POSIX threads]), -[ case "$enableval" in - no) - AC_MSG_RESULT(no) - want_pthreads=no - ;; - *) - AC_MSG_RESULT(yes) - want_pthreads=yes - ;; - esac ], [ - default_pthreads=1 - if test "$curl_cv_native_windows" = "yes"; then - default_pthreads=0 - else - case $host_os in - msdos*) - default_pthreads=0 - ;; - esac - fi - if test "$default_pthreads" = '0'; then - AC_MSG_RESULT(no) - want_pthreads=no - else - AC_MSG_RESULT(auto) - want_pthreads=auto - fi - ] -) - dnl turn off pthreads if rt is disabled -if test "$want_pthreads" != "no"; then - if test "$want_pthreads" = "yes" && test "$dontwant_rt" = "yes"; then - AC_MSG_ERROR([options --enable-pthreads and --disable-rt are mutually exclusive]) - fi - if test "$dontwant_rt" != "no"; then - dnl if --enable-pthreads was explicit then warn it's being ignored - if test "$want_pthreads" = "yes"; then - AC_MSG_WARN([--enable-pthreads Ignored since librt is disabled.]) - fi - want_pthreads=no - fi +if test "$want_threaded_resolver" = "yes" && test "$dontwant_rt" = "yes"; then + AC_MSG_ERROR([options --enable-pthreads and --disable-rt are mutually exclusive]) fi -dnl turn off pthreads if no threaded resolver -if test "$want_pthreads" != "no" && test "$want_thres" != "yes"; then - want_pthreads=no +dnl Windows threaded resolver check +if test "$want_threaded_resolver" = "yes" && test "$curl_cv_native_windows" = "yes"; then + USE_THREADS_WIN32=1 + AC_DEFINE(USE_THREADS_WIN32, 1, [if you want Win32 threaded DNS lookup]) + curl_res_msg="Win32 threaded" fi dnl detect pthreads -if test "$want_pthreads" != "no"; then +if test "$want_threaded_resolver" = "yes" && test "$USE_THREADS_WIN32" != "1"; then AC_CHECK_HEADER(pthread.h, [ AC_DEFINE(HAVE_PTHREAD_H, 1, [if you have ]) save_CFLAGS="$CFLAGS" @@ -4262,19 +4214,9 @@ if test "$want_pthreads" != "no"; then ]) fi -dnl threaded resolver check -if test "$want_thres" = "yes" && test "x$USE_THREADS_POSIX" != "x1"; then - if test "$want_pthreads" = "yes"; then - AC_MSG_ERROR([--enable-pthreads but pthreads was not found]) - fi - dnl If native Windows fallback on Win32 threads since no POSIX threads - if test "$curl_cv_native_windows" = "yes"; then - USE_THREADS_WIN32=1 - AC_DEFINE(USE_THREADS_WIN32, 1, [if you want Win32 threaded DNS lookup]) - curl_res_msg="Win32 threaded" - else - AC_MSG_ERROR([Threaded resolver enabled but no thread library found]) - fi +dnl Did we find a threading option? +if test "$want_threaded_resolver" != "no" -a "x$USE_THREADS_POSIX" != "x1" -a "x$USE_THREADS_WIN32" != "x1"; then + AC_MSG_ERROR([Threaded resolver enabled but no thread library found]) fi AC_CHECK_HEADER(dirent.h, @@ -4873,15 +4815,6 @@ if test "x$hsts" != "xyes"; then fi -dnl ************************************************************* -dnl check whether HTTPSRR support if desired -dnl -if test "x$want_httpsrr" != "xno"; then - AC_MSG_RESULT([HTTPSRR support is available]) - AC_DEFINE(USE_HTTPSRR, 1, [enable HTTPS RR support]) - experimental="$experimental HTTPSRR" -fi - dnl ************************************************************* dnl check whether ECH support, if desired, is actually available dnl @@ -4909,11 +4842,24 @@ if test "x$want_ech" != "xno"; then AC_DEFINE(USE_ECH, 1, [if ECH support is available]) AC_MSG_RESULT($ECH_SUPPORT) experimental="$experimental ECH" + dnl ECH wants HTTPSRR + want_httpsrr="yes" else AC_MSG_ERROR([--enable-ech ignored: No ECH support found]) fi fi +dnl ************************************************************* +dnl check whether HTTPSRR support if desired +dnl +if test "x$want_httpsrr" != "xno"; then + AC_MSG_RESULT([HTTPSRR support is enabled]) + AC_DEFINE(USE_HTTPSRR, 1, [enable HTTPS RR support]) + experimental="$experimental HTTPSRR" + curl_httpsrr_msg="enabled (--disable-httpsrr)" +fi + + dnl ************************************************************* dnl check whether OpenSSL (lookalikes) have SSL_set0_wbio dnl @@ -5071,6 +5017,9 @@ if test "x$USE_ARES" = "x1" -o "x$USE_THREADS_POSIX" = "x1" \ -o "x$USE_THREADS_WIN32" = "x1"; then SUPPORT_FEATURES="$SUPPORT_FEATURES AsynchDNS" fi +if test "x$USE_ARES" = "x1" -a "$want_threaded_resolver" = "yes"; then + SUPPORT_FEATURES="$SUPPORT_FEATURES c-ares-rr" +fi if test "x$IDN_ENABLED" = "x1"; then SUPPORT_FEATURES="$SUPPORT_FEATURES IDN" fi @@ -5177,6 +5126,10 @@ if test "x$OPENSSL_ENABLED" = "x1" -o -n "$SSL_ENABLED"; then fi fi +if test "x$want_httpsrr" != "xno"; then + SUPPORT_FEATURES="$SUPPORT_FEATURES HTTPSRR" +fi + if test "x$SSLS_EXPORT_ENABLED" = "x1"; then SUPPORT_FEATURES="$SUPPORT_FEATURES SSLS-EXPORT" fi @@ -5446,6 +5399,7 @@ AC_MSG_NOTICE([Configured to build curl/libcurl: HTTP2: ${curl_h2_msg} HTTP3: ${curl_h3_msg} ECH: ${curl_ech_msg} + HTTPS RR: ${curl_httpsrr_msg} SSLS-EXPORT: ${curl_ssls_export_msg} Protocols: ${SUPPORT_PROTOCOLS_LOWER} Features: ${SUPPORT_FEATURES} diff --git a/docs/libcurl/curl_version_info.md b/docs/libcurl/curl_version_info.md index a112058a6d..ed22a54df9 100644 --- a/docs/libcurl/curl_version_info.md +++ b/docs/libcurl/curl_version_info.md @@ -151,13 +151,13 @@ entry. # FEATURES -## alt-svc +## `alt-svc` *features* mask bit: CURL_VERSION_ALTSVC HTTP Alt-Svc parsing and the associated options (Added in 7.64.1) -## AsynchDNS +## `AsynchDNS` *features* mask bit: CURL_VERSION_ASYNCHDNS @@ -165,32 +165,40 @@ libcurl was built with support for asynchronous name lookups, which allows more exact timeouts (even on Windows) and less blocking when using the multi interface. (added in 7.10.7) -## brotli +## `brotli` *features* mask bit: CURL_VERSION_BROTLI supports HTTP Brotli content encoding using libbrotlidec (Added in 7.57.0) -## Debug +## `c-ares-rr` + +*features* mask bit: non-existent + +libcurl was built to use c-ares for EXPERIMENTAL HTTPS resource record +resolves, but uses the threaded resolver for "normal" resolves (Added in +8.12.0) + +## `Debug` *features* mask bit: CURL_VERSION_DEBUG libcurl was built with debug capabilities (added in 7.10.6) -## ECH +## `ECH` *features* mask bit: non-existent libcurl was built with ECH support (experimental, added in 8.8.0) -## gsasl +## `gsasl` *features* mask bit: CURL_VERSION_GSASL libcurl was built with libgsasl and thus with some extra SCRAM-SHA authentication methods. (added in 7.76.0) -## GSS-API +## `GSS-API` *features* mask bit: CURL_VERSION_GSSAPI @@ -199,66 +207,73 @@ functions for Kerberos and SPNEGO authentication. It also allows libcurl to use the current user credentials without the app having to pass them on. (Added in 7.38.0) -## HSTS +## `HSTS` *features* mask bit: CURL_VERSION_HSTS libcurl was built with support for HSTS (HTTP Strict Transport Security) (Added in 7.74.0) -## HTTP2 +## `HTTP2` *features* mask bit: CURL_VERSION_HTTP2 libcurl was built with support for HTTP2. (Added in 7.33.0) -## HTTP3 +## `HTTP3` *features* mask bit: CURL_VERSION_HTTP3 HTTP/3 and QUIC support are built-in (Added in 7.66.0) -## HTTPS-proxy +## `HTTPS-proxy` *features* mask bit: CURL_VERSION_HTTPS_PROXY libcurl was built with support for HTTPS-proxy. (Added in 7.52.0) -## IDN +## `HTTPSRR` + +*features* mask bit: non-existent + +libcurl was built with EXPERIMENTAL support for HTTPS resource records (Added +in 8.12.0) + +## `IDN` *features* mask bit: CURL_VERSION_IDN libcurl was built with support for IDNA, domain names with international letters. (Added in 7.12.0) -## IPv6 +## `IPv6` *features* mask bit: CURL_VERSION_IPV6 supports IPv6 -## Kerberos +## `Kerberos` *features* mask bit: CURL_VERSION_KERBEROS5 supports Kerberos V5 authentication for FTP, IMAP, LDAP, POP3, SMTP and SOCKSv5 proxy. (Added in 7.40.0) -## Largefile +## `Largefile` *features* mask bit: CURL_VERSION_LARGEFILE libcurl was built with support for large files. (Added in 7.11.1) -## libz +## `libz` *features* mask bit: CURL_VERSION_LIBZ supports HTTP deflate using libz (Added in 7.10) -## MultiSSL +## `MultiSSL` *features* mask bit: CURL_VERSION_MULTI_SSL @@ -266,20 +281,20 @@ libcurl was built with multiple SSL backends. For details, see curl_global_sslset(3). (Added in 7.56.0) -## NTLM +## `NTLM` *features* mask bit: CURL_VERSION_NTLM supports HTTP NTLM (added in 7.10.6) -## NTLM_WB +## `NTLM_WB` *features* mask bit: CURL_VERSION_NTLM_WB libcurl was built with support for NTLM delegation to a winbind helper. (Added in 7.22.0) This feature was removed from curl in 8.8.0. -## PSL +## `PSL` *features* mask bit: CURL_VERSION_PSL @@ -287,27 +302,27 @@ libcurl was built with support for Mozilla's Public Suffix List. This makes libcurl ignore cookies with a domain that is on the list. (Added in 7.47.0) -## SPNEGO +## `SPNEGO` *features* mask bit: CURL_VERSION_SPNEGO libcurl was built with support for SPNEGO authentication (Simple and Protected GSS-API Negotiation Mechanism, defined in RFC 2478.) (added in 7.10.8) -## SSL +## `SSL` *features* mask bit: CURL_VERSION_SSL supports SSL (HTTPS/FTPS) (Added in 7.10) -## SSLS-EXPORT +## `SSLS-EXPORT` *features* mask bit: non-existent libcurl was built with SSL session import/export support (experimental, added in 8.12.0) -## SSPI +## `SSPI` *features* mask bit: CURL_VERSION_SSPI @@ -316,42 +331,42 @@ makes libcurl use Windows-provided functions for Kerberos, NTLM, SPNEGO and Digest authentication. It also allows libcurl to use the current user credentials without the app having to pass them on. (Added in 7.13.2) -## threadsafe +## `threadsafe` *features* mask bit: CURL_VERSION_THREADSAFE libcurl was built with thread-safety support (Atomic or SRWLOCK) to protect curl initialization. (Added in 7.84.0) See libcurl-thread(3) -## TLS-SRP +## `TLS-SRP` *features* mask bit: CURL_VERSION_TLSAUTH_SRP libcurl was built with support for TLS-SRP (in one or more of the built-in TLS backends). (Added in 7.21.4) -## TrackMemory +## `TrackMemory` *features* mask bit: CURL_VERSION_CURLDEBUG libcurl was built with memory tracking debug capabilities. This is mainly of interest for libcurl hackers. (added in 7.19.6) -## Unicode +## `Unicode` *features* mask bit: CURL_VERSION_UNICODE libcurl was built with Unicode support on Windows. This makes non-ASCII characters work in filenames and options passed to libcurl. (Added in 7.72.0) -## UnixSockets +## `UnixSockets` *features* mask bit: CURL_VERSION_UNIX_SOCKETS libcurl was built with support for Unix domain sockets. (Added in 7.40.0) -## zstd +## `zstd` *features* mask bit: CURL_VERSION_ZSTD diff --git a/lib/asyn-ares.c b/lib/asyn-ares.c index 8123226b6e..fe2b800f25 100644 --- a/lib/asyn-ares.c +++ b/lib/asyn-ares.c @@ -24,14 +24,14 @@ #include "curl_setup.h" +#ifdef USE_ARES + /*********************************************************************** * Only for ares-enabled builds * And only for functions that fulfill the asynch resolver backend API * as defined in asyn.h, nothing else belongs in this file! **********************************************************************/ -#ifdef CURLRES_ARES - #include #ifdef HAVE_NETINET_IN_H #include @@ -70,6 +70,94 @@ #include /* really old c-ares did not include this by itself */ +/* + * Curl_ares_getsock() is called when the outside world (using + * curl_multi_fdset()) wants to get our fd_set setup and we are talking with + * ares. The caller must make sure that this function is only called when we + * have a working ares channel. + * + * Returns: sockets-in-use-bitmap + */ + +int Curl_ares_getsock(struct Curl_easy *data, + ares_channel channel, + curl_socket_t *socks) +{ + struct timeval maxtime = { CURL_TIMEOUT_RESOLVE, 0 }; + struct timeval timebuf; + int max = ares_getsock(channel, + (ares_socket_t *)socks, MAX_SOCKSPEREASYHANDLE); + struct timeval *timeout = ares_timeout(channel, &maxtime, &timebuf); + timediff_t milli = curlx_tvtoms(timeout); + Curl_expire(data, milli, EXPIRE_ASYNC_NAME); + return max; +} + +/* + * Curl_ares_perform() + * + * 1) Ask ares what sockets it currently plays with, then + * 2) wait for the timeout period to check for action on ares' sockets. + * 3) tell ares to act on all the sockets marked as "with action" + * + * return number of sockets it worked on, or -1 on error + */ + +int Curl_ares_perform(ares_channel channel, + timediff_t timeout_ms) +{ + int nfds; + int bitmask; + ares_socket_t socks[ARES_GETSOCK_MAXNUM]; + struct pollfd pfd[ARES_GETSOCK_MAXNUM]; + int i; + int num = 0; + + bitmask = ares_getsock(channel, socks, ARES_GETSOCK_MAXNUM); + + for(i = 0; i < ARES_GETSOCK_MAXNUM; i++) { + pfd[i].events = 0; + pfd[i].revents = 0; + if(ARES_GETSOCK_READABLE(bitmask, i)) { + pfd[i].fd = socks[i]; + pfd[i].events |= POLLRDNORM|POLLIN; + } + if(ARES_GETSOCK_WRITABLE(bitmask, i)) { + pfd[i].fd = socks[i]; + pfd[i].events |= POLLWRNORM|POLLOUT; + } + if(pfd[i].events) + num++; + else + break; + } + + if(num) { + nfds = Curl_poll(pfd, (unsigned int)num, timeout_ms); + if(nfds < 0) + return -1; + } + else + nfds = 0; + + if(!nfds) + /* Call ares_process() unconditionally here, even if we simply timed out + above, as otherwise the ares name resolve will not timeout! */ + ares_process_fd(channel, ARES_SOCKET_BAD, ARES_SOCKET_BAD); + else { + /* move through the descriptors and ask for processing on them */ + for(i = 0; i < num; i++) + ares_process_fd(channel, + (pfd[i].revents & (POLLRDNORM|POLLIN)) ? + pfd[i].fd : ARES_SOCKET_BAD, + (pfd[i].revents & (POLLWRNORM|POLLOUT)) ? + pfd[i].fd : ARES_SOCKET_BAD); + } + return nfds; +} + +#ifdef CURLRES_ARES + #if ARES_VERSION >= 0x010500 /* c-ares 1.5.0 or later, the callback proto is modified */ #define HAVE_CARES_CALLBACK_TIMEOUTS 1 @@ -98,8 +186,9 @@ #if ARES_VERSION >= 0x011c00 /* 1.28.0 and later have ares_query_dnsrec */ #define HAVE_ARES_QUERY_DNSREC 1 -#else -#undef USE_HTTPSRR +#ifdef USE_HTTPSRR +#define USE_HTTPSRR_ARES 1 +#endif #endif /* The last 3 #include files should be in this order */ @@ -107,20 +196,6 @@ #include "curl_memory.h" #include "memdebug.h" -struct thread_data { - int num_pending; /* number of outstanding c-ares requests */ - struct Curl_addrinfo *temp_ai; /* intermediary result while fetching c-ares - parts */ - int last_status; -#ifndef HAVE_CARES_GETADDRINFO - struct curltime happy_eyeballs_dns_time; /* when this timer started, or 0 */ -#endif -#ifdef USE_HTTPSRR - struct Curl_https_rrinfo hinfo; -#endif - char hostname[1]; -}; - /* How long we are willing to wait for additional parallel responses after obtaining a "definitive" one. For old c-ares without getaddrinfo. @@ -292,89 +367,13 @@ static void destroy_async_data(struct Curl_async *async) /* * Curl_resolver_getsock() is called when someone from the outside world - * (using curl_multi_fdset()) wants to get our fd_set setup and we are talking - * with ares. The caller must make sure that this function is only called when - * we have a working ares channel. - * - * Returns: sockets-in-use-bitmap - */ - -int Curl_resolver_getsock(struct Curl_easy *data, - curl_socket_t *socks) -{ - struct timeval maxtime = { CURL_TIMEOUT_RESOLVE, 0 }; - struct timeval timebuf; - int max = ares_getsock((ares_channel)data->state.async.resolver, - (ares_socket_t *)socks, MAX_SOCKSPEREASYHANDLE); - struct timeval *timeout = - ares_timeout((ares_channel)data->state.async.resolver, &maxtime, &timebuf); - timediff_t milli = curlx_tvtoms(timeout); - Curl_expire(data, milli, EXPIRE_ASYNC_NAME); - return max; -} - -/* - * waitperform() - * - * 1) Ask ares what sockets it currently plays with, then - * 2) wait for the timeout period to check for action on ares' sockets. - * 3) tell ares to act on all the sockets marked as "with action" - * - * return number of sockets it worked on, or -1 on error + * (using curl_multi_fdset()) wants to get our fd_set setup. */ -static int waitperform(struct Curl_easy *data, timediff_t timeout_ms) +int Curl_resolver_getsock(struct Curl_easy *data, curl_socket_t *socks) { - int nfds; - int bitmask; - ares_socket_t socks[ARES_GETSOCK_MAXNUM]; - struct pollfd pfd[ARES_GETSOCK_MAXNUM]; - int i; - int num = 0; - - bitmask = ares_getsock((ares_channel)data->state.async.resolver, socks, - ARES_GETSOCK_MAXNUM); - - for(i = 0; i < ARES_GETSOCK_MAXNUM; i++) { - pfd[i].events = 0; - pfd[i].revents = 0; - if(ARES_GETSOCK_READABLE(bitmask, i)) { - pfd[i].fd = socks[i]; - pfd[i].events |= POLLRDNORM|POLLIN; - } - if(ARES_GETSOCK_WRITABLE(bitmask, i)) { - pfd[i].fd = socks[i]; - pfd[i].events |= POLLWRNORM|POLLOUT; - } - if(pfd[i].events) - num++; - else - break; - } - - if(num) { - nfds = Curl_poll(pfd, (unsigned int)num, timeout_ms); - if(nfds < 0) - return -1; - } - else - nfds = 0; - - if(!nfds) - /* Call ares_process() unconditionally here, even if we simply timed out - above, as otherwise the ares name resolve will not timeout! */ - ares_process_fd((ares_channel)data->state.async.resolver, ARES_SOCKET_BAD, - ARES_SOCKET_BAD); - else { - /* move through the descriptors and ask for processing on them */ - for(i = 0; i < num; i++) - ares_process_fd((ares_channel)data->state.async.resolver, - (pfd[i].revents & (POLLRDNORM|POLLIN)) ? - pfd[i].fd : ARES_SOCKET_BAD, - (pfd[i].revents & (POLLWRNORM|POLLOUT)) ? - pfd[i].fd : ARES_SOCKET_BAD); - } - return nfds; + return Curl_ares_getsock(data, (ares_channel)data->state.async.resolver, + socks); } /* @@ -393,7 +392,7 @@ CURLcode Curl_resolver_is_resolved(struct Curl_easy *data, DEBUGASSERT(dns); *dns = NULL; - if(waitperform(data, 0) < 0) + if(Curl_ares_perform((ares_channel)data->state.async.resolver, 0) < 0) return CURLE_UNRECOVERABLE_POLL; #ifndef HAVE_CARES_GETADDRINFO @@ -431,7 +430,7 @@ CURLcode Curl_resolver_is_resolved(struct Curl_easy *data, result = Curl_resolver_error(data); else { *dns = data->state.async.dns; -#ifdef USE_HTTPSRR +#ifdef USE_HTTPSRR_ARES { struct Curl_https_rrinfo *lhrr = Curl_memdup(&res->hinfo, sizeof(struct Curl_https_rrinfo)); @@ -503,7 +502,8 @@ CURLcode Curl_resolver_wait_resolv(struct Curl_easy *data, else timeout_ms = 1000; - if(waitperform(data, timeout_ms) < 0) + if(Curl_ares_perform((ares_channel)data->state.async.resolver, + timeout_ms) < 0) return CURLE_UNRECOVERABLE_POLL; result = Curl_resolver_is_resolved(data, entry); @@ -768,72 +768,6 @@ static void addrinfo_cb(void *arg, int status, int timeouts, #endif -#ifdef USE_HTTPSRR -static void httpsrr_opt(struct Curl_easy *data, - const ares_dns_rr_t *rr, - ares_dns_rr_key_t key, size_t idx) -{ - size_t len = 0; - const unsigned char *val = NULL; - unsigned short code; - struct thread_data *res = data->state.async.tdata; - - code = ares_dns_rr_get_opt(rr, key, idx, &val, &len); - - switch(code) { - case HTTPS_RR_CODE_ALPN: /* str_list */ - Curl_httpsrr_decode_alpn(val, len, res->hinfo.alpns); - infof(data, "HTTPS RR ALPN: %u %u %u %u", - res->hinfo.alpns[0], res->hinfo.alpns[1], res->hinfo.alpns[2], - res->hinfo.alpns[3]); - break; - case HTTPS_RR_CODE_NO_DEF_ALPN: - infof(data, "HTTPS RR no-def-alpn"); - break; - case HTTPS_RR_CODE_IPV4: /* addr4 list */ - infof(data, "HTTPS RR IPv4"); - break; - case HTTPS_RR_CODE_ECH: - infof(data, "HTTPS RR ECH"); - break; - case HTTPS_RR_CODE_IPV6: /* addr6 list */ - infof(data, "HTTPS RR IPv6"); - break; - case HTTPS_RR_CODE_PORT: - infof(data, "HTTPS RR port"); - break; - default: - infof(data, "HTTPS RR unknown code"); - break; - } -} - -static void dnsrec_done_cb(void *arg, ares_status_t status, - size_t timeouts, - const ares_dns_record_t *dnsrec) -{ - struct Curl_easy *data = arg; - size_t i; - struct thread_data *res = data->state.async.tdata; - (void)timeouts; - - res->num_pending--; - if((ARES_SUCCESS != status) || !dnsrec) - return; - - for(i = 0; i < ares_dns_record_rr_cnt(dnsrec, ARES_SECTION_ANSWER); i++) { - size_t opt; - const ares_dns_rr_t *rr = - ares_dns_record_rr_get_const(dnsrec, ARES_SECTION_ANSWER, i); - if(ares_dns_rr_get_type(rr) != ARES_REC_TYPE_HTTPS) - continue; - for(opt = 0; opt < ares_dns_rr_get_opt_cnt(rr, ARES_RR_HTTPS_PARAMS); - opt++) - httpsrr_opt(data, rr, ARES_RR_HTTPS_PARAMS, opt); - } -} -#endif - /* * Curl_resolver_getaddrinfo() - when using ares * @@ -916,14 +850,14 @@ struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data, query_completed_cb, data); } #endif -#ifdef USE_HTTPSRR +#ifdef USE_HTTPSRR_ARES { res->num_pending++; /* one more */ memset(&res->hinfo, 0, sizeof(struct Curl_https_rrinfo)); ares_query_dnsrec((ares_channel)data->state.async.resolver, hostname, ARES_CLASS_IN, ARES_REC_TYPE_HTTPS, - dnsrec_done_cb, data, NULL); + Curl_dnsrec_done_cb, data, NULL); } #endif *waitp = 1; /* expect asynchronous response */ @@ -1058,3 +992,5 @@ CURLcode Curl_set_dns_local_ip6(struct Curl_easy *data, #endif } #endif /* CURLRES_ARES */ + +#endif /* USE_ARES */ diff --git a/lib/asyn-thread.c b/lib/asyn-thread.c index 32d496b107..c7e84353cb 100644 --- a/lib/asyn-thread.c +++ b/lib/asyn-thread.c @@ -64,6 +64,14 @@ #include "inet_ntop.h" #include "curl_threads.h" #include "connect.h" + +#ifdef USE_ARES +#include +#ifdef USE_HTTPSRR +#define USE_HTTPSRR_ARES 1 /* the combo */ +#endif +#endif + /* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" @@ -145,32 +153,6 @@ static bool init_resolve_thread(struct Curl_easy *data, const struct addrinfo *hints); -/* Data for synchronization between resolver thread and its parent */ -struct thread_sync_data { - curl_mutex_t *mtx; - int done; - int port; - char *hostname; /* hostname to resolve, Curl_async.hostname - duplicate */ -#ifndef CURL_DISABLE_SOCKETPAIR - struct Curl_easy *data; - curl_socket_t sock_pair[2]; /* eventfd/pipes/socket pair */ -#endif - int sock_error; - struct Curl_addrinfo *res; -#ifdef HAVE_GETADDRINFO - struct addrinfo hints; -#endif - struct thread_data *td; /* for thread-self cleanup */ -}; - -struct thread_data { - curl_thread_t thread_hnd; - unsigned int poll_interval; - timediff_t interval_end; - struct thread_sync_data tsd; -}; - static struct thread_sync_data *conn_thread_sync_data(struct Curl_easy *data) { return &(data->state.async.tdata->tsd); @@ -220,7 +202,7 @@ int init_thread_sync_data(struct thread_data *td, /* Treat the request as done until the thread actually starts so any early * cleanup gets done properly. */ - tsd->done = 1; + tsd->done = TRUE; #ifdef HAVE_GETADDRINFO DEBUGASSERT(hints); tsd->hints = *hints; @@ -343,7 +325,7 @@ CURL_STDCALL getaddrinfo_thread(void *arg) } } #endif - tsd->done = 1; + tsd->done = TRUE; Curl_mutex_release(tsd->mtx); } @@ -382,7 +364,7 @@ CURL_STDCALL gethostbyname_thread(void *arg) free(td); } else { - tsd->done = 1; + tsd->done = TRUE; Curl_mutex_release(tsd->mtx); } @@ -398,19 +380,22 @@ static void destroy_async_data(struct Curl_async *async) { if(async->tdata) { struct thread_data *td = async->tdata; - int done; + bool done; #ifndef CURL_DISABLE_SOCKETPAIR curl_socket_t sock_rd = td->tsd.sock_pair[0]; struct Curl_easy *data = td->tsd.data; #endif +#ifdef USE_HTTPSRR_ARES + ares_destroy(data->state.async.tdata->channel); +#endif /* * if the thread is still blocking in the resolve syscall, detach it and * let the thread do the cleanup... */ Curl_mutex_acquire(td->tsd.mtx); done = td->tsd.done; - td->tsd.done = 1; + td->tsd.done = TRUE; Curl_mutex_release(td->tsd.mtx); if(!done) { @@ -439,6 +424,24 @@ static void destroy_async_data(struct Curl_async *async) async->hostname = NULL; } +#ifdef USE_HTTPSRR_ARES +static CURLcode resolve_httpsrr(struct Curl_easy *data, + struct Curl_async *asp) +{ + int status = ares_init(&asp->tdata->channel); + if(status != ARES_SUCCESS) + return CURLE_FAILED_INIT; + + memset(&asp->tdata->hinfo, 0, sizeof(struct Curl_https_rrinfo)); + ares_query_dnsrec(asp->tdata->channel, + asp->hostname, ARES_CLASS_IN, + ARES_REC_TYPE_HTTPS, + Curl_dnsrec_done_cb, data, NULL); + + return CURLE_OK; +} +#endif + /* * init_resolve_thread() starts a new thread that performs the actual * resolve. This function returns before the resolve is done. @@ -474,8 +477,8 @@ static bool init_resolve_thread(struct Curl_easy *data, if(!asp->hostname) goto err_exit; - /* The thread will set this to 1 when complete. */ - td->tsd.done = 0; + /* The thread will set this TRUE when complete. */ + td->tsd.done = FALSE; #ifdef HAVE_GETADDRINFO td->thread_hnd = Curl_thread_create(getaddrinfo_thread, &td->tsd); @@ -485,11 +488,14 @@ static bool init_resolve_thread(struct Curl_easy *data, if(td->thread_hnd == curl_thread_t_null) { /* The thread never started, so mark it as done here for proper cleanup. */ - td->tsd.done = 1; + td->tsd.done = TRUE; err = errno; goto err_exit; } - +#ifdef USE_HTTPSRR_ARES + if(resolve_httpsrr(data, asp)) + goto err_exit; +#endif return TRUE; err_exit: @@ -587,7 +593,7 @@ CURLcode Curl_resolver_is_resolved(struct Curl_easy *data, struct Curl_dns_entry **entry) { struct thread_data *td = data->state.async.tdata; - int done = 0; + bool done = FALSE; DEBUGASSERT(entry); *entry = NULL; @@ -596,6 +602,10 @@ CURLcode Curl_resolver_is_resolved(struct Curl_easy *data, DEBUGASSERT(td); return CURLE_COULDNT_RESOLVE_HOST; } +#ifdef USE_HTTPSRR_ARES + if(Curl_ares_perform(data->state.async.tdata->channel, 0) < 0) + return CURLE_UNRECOVERABLE_POLL; +#endif Curl_mutex_acquire(td->tsd.mtx); done = td->tsd.done; @@ -643,18 +653,28 @@ int Curl_resolver_getsock(struct Curl_easy *data, curl_socket_t *socks) timediff_t milli; timediff_t ms; struct resdata *reslv = (struct resdata *)data->state.async.resolver; + int socketi = 0; #ifndef CURL_DISABLE_SOCKETPAIR struct thread_data *td = data->state.async.tdata; #else (void)socks; #endif +#ifdef USE_HTTPSRR_ARES + if(data->state.async.tdata) { + ret_val = Curl_ares_getsock(data, data->state.async.tdata->channel, socks); + for(socketi = 0; socketi < (MAX_SOCKSPEREASYHANDLE - 1); socketi++) + if(!ARES_GETSOCK_READABLE(ret_val, socketi) && + !ARES_GETSOCK_WRITABLE(ret_val, socketi)) + break; + } +#endif #ifndef CURL_DISABLE_SOCKETPAIR if(td) { /* return read fd to client for polling the DNS resolution status */ - socks[0] = td->tsd.sock_pair[0]; + socks[socketi] = td->tsd.sock_pair[0]; td->tsd.data = data; - ret_val = GETSOCK_READSOCK(0); + ret_val = GETSOCK_READSOCK(socketi); } else { #endif diff --git a/lib/asyn.h b/lib/asyn.h index 0ff2048845..c674541256 100644 --- a/lib/asyn.h +++ b/lib/asyn.h @@ -26,6 +26,7 @@ #include "curl_setup.h" #include "curl_addrinfo.h" +#include "httpsrr.h" struct addrinfo; struct hostent; @@ -33,6 +34,69 @@ struct Curl_easy; struct connectdata; struct Curl_dns_entry; +#ifdef CURLRES_THREADED +#include "curl_threads.h" + +/* Data for synchronization between resolver thread and its parent */ +struct thread_sync_data { + curl_mutex_t *mtx; + bool done; + int port; + char *hostname; /* hostname to resolve, Curl_async.hostname + duplicate */ +#ifndef CURL_DISABLE_SOCKETPAIR + struct Curl_easy *data; + curl_socket_t sock_pair[2]; /* eventfd/pipes/socket pair */ +#endif + int sock_error; + struct Curl_addrinfo *res; +#ifdef HAVE_GETADDRINFO + struct addrinfo hints; +#endif + struct thread_data *td; /* for thread-self cleanup */ +}; + +struct thread_data { + curl_thread_t thread_hnd; + unsigned int poll_interval; + timediff_t interval_end; + struct thread_sync_data tsd; +#if defined(USE_HTTPSRR) && defined(USE_ARES) + struct Curl_https_rrinfo hinfo; + ares_channel channel; +#endif +}; + +#elif defined(CURLRES_ARES) /* CURLRES_THREADED */ + +struct thread_data { + int num_pending; /* number of outstanding c-ares requests */ + struct Curl_addrinfo *temp_ai; /* intermediary result while fetching c-ares + parts */ + int last_status; +#ifndef HAVE_CARES_GETADDRINFO + struct curltime happy_eyeballs_dns_time; /* when this timer started, or 0 */ +#endif +#ifdef USE_HTTPSRR + struct Curl_https_rrinfo hinfo; +#endif + char hostname[1]; +}; + +#endif /* CURLRES_ARES */ + +#ifdef USE_ARES +#include + +/* for HTTPS RR purposes as well */ +int Curl_ares_getsock(struct Curl_easy *data, + ares_channel channel, + curl_socket_t *socks); +int Curl_ares_perform(ares_channel channel, + timediff_t timeout_ms); +#endif + + /* * This header defines all functions in the internal asynch resolver interface. * All asynch resolvers need to provide these functions. diff --git a/lib/curl_setup.h b/lib/curl_setup.h index c973794a6c..71326c35e6 100644 --- a/lib/curl_setup.h +++ b/lib/curl_setup.h @@ -282,14 +282,6 @@ # define CURL_DISABLE_HTTP_AUTH 1 #endif -/* - * ECH requires HTTPSRR. - */ - -#if defined(USE_ECH) && !defined(USE_HTTPSRR) -# define USE_HTTPSRR -#endif - /* ================================================================ */ /* No system header file shall be included in this file before this */ /* point. */ @@ -710,15 +702,15 @@ # define CURLRES_IPV4 #endif -#ifdef USE_ARES +#if defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32) +# define CURLRES_ASYNCH +# define CURLRES_THREADED +#elif defined(USE_ARES) # define CURLRES_ASYNCH # define CURLRES_ARES /* now undef the stock libc functions just to avoid them being used */ # undef HAVE_GETADDRINFO # undef HAVE_FREEADDRINFO -#elif defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32) -# define CURLRES_ASYNCH -# define CURLRES_THREADED #else # define CURLRES_SYNCH #endif diff --git a/lib/hostip.h b/lib/hostip.h index e5e0d32604..10f70b2ba8 100644 --- a/lib/hostip.h +++ b/lib/hostip.h @@ -29,6 +29,7 @@ #include "curl_addrinfo.h" #include "timeval.h" /* for timediff_t */ #include "asyn.h" +#include "httpsrr.h" #include @@ -69,31 +70,6 @@ enum alpnid { */ struct Curl_hash *Curl_global_host_cache_init(void); -#ifdef USE_HTTPSRR - -#define CURL_MAXLEN_host_name 253 -#define MAX_HTTPSRR_ALPNS 4 - -struct Curl_https_rrinfo { - /* - * Fields from HTTPS RR. The only mandatory fields are priority and target. - * See https://datatracker.ietf.org/doc/html/rfc9460#section-14.3.2 - */ - char *target; - unsigned char *ipv4hints; /* keytag = 4 */ - size_t ipv4hints_len; - unsigned char *echconfiglist; /* keytag = 5 */ - size_t echconfiglist_len; - unsigned char *ipv6hints; /* keytag = 6 */ - size_t ipv6hints_len; - unsigned char alpns[MAX_HTTPSRR_ALPNS]; /* keytag = 1 */ - /* store parsed alpnid entries in the array, end with ALPN_none */ - int port; /* -1 means not set */ - uint16_t priority; - bool no_def_alpn; /* keytag = 2 */ -}; -#endif - struct Curl_dns_entry { struct Curl_addrinfo *addr; #ifdef USE_HTTPSRR diff --git a/lib/httpsrr.c b/lib/httpsrr.c index 6e6b0a51c9..9884b92580 100644 --- a/lib/httpsrr.c +++ b/lib/httpsrr.c @@ -30,6 +30,12 @@ #include "curl_addrinfo.h" #include "httpsrr.h" #include "connect.h" +#include "sendf.h" + +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" +#include "curl_memory.h" +#include "memdebug.h" CURLcode Curl_httpsrr_decode_alpn(const unsigned char *cp, size_t len, unsigned char *alpns) @@ -85,4 +91,77 @@ err: return CURLE_BAD_CONTENT_ENCODING; } +#ifdef USE_ARES + +static void httpsrr_opt(struct Curl_easy *data, + const ares_dns_rr_t *rr, + ares_dns_rr_key_t key, size_t idx) +{ + size_t len = 0; + const unsigned char *val = NULL; + unsigned short code; + struct thread_data *res = data->state.async.tdata; + struct Curl_https_rrinfo *hi = &res->hinfo; + code = ares_dns_rr_get_opt(rr, key, idx, &val, &len); + + switch(code) { + case HTTPS_RR_CODE_ALPN: /* str_list */ + Curl_httpsrr_decode_alpn(val, len, hi->alpns); + infof(data, "HTTPS RR ALPN: %u %u %u %u", + hi->alpns[0], hi->alpns[1], hi->alpns[2], hi->alpns[3]); + break; + case HTTPS_RR_CODE_NO_DEF_ALPN: + infof(data, "HTTPS RR no-def-alpn"); + break; + case HTTPS_RR_CODE_IPV4: /* addr4 list */ + infof(data, "HTTPS RR IPv4"); + break; + case HTTPS_RR_CODE_ECH: + infof(data, "HTTPS RR ECH"); + break; + case HTTPS_RR_CODE_IPV6: /* addr6 list */ + infof(data, "HTTPS RR IPv6"); + break; + case HTTPS_RR_CODE_PORT: + infof(data, "HTTPS RR port"); + break; + default: + infof(data, "HTTPS RR unknown code"); + break; + } +} + +void Curl_dnsrec_done_cb(void *arg, ares_status_t status, + size_t timeouts, + const ares_dns_record_t *dnsrec) +{ + struct Curl_easy *data = arg; + size_t i; +#ifdef CURLRES_ARES + struct thread_data *res = data->state.async.tdata; + + res->num_pending--; #endif + (void)timeouts; + if((ARES_SUCCESS != status) || !dnsrec) + return; + + for(i = 0; i < ares_dns_record_rr_cnt(dnsrec, ARES_SECTION_ANSWER); i++) { + size_t opt; + const ares_dns_rr_t *rr = + ares_dns_record_rr_get_const(dnsrec, ARES_SECTION_ANSWER, i); + if(ares_dns_rr_get_type(rr) != ARES_REC_TYPE_HTTPS) + continue; + /* When SvcPriority is 0, the SVCB record is in AliasMode. Otherwise, it + is in ServiceMode */ + infof(data, "HTTPS RR priority: %u", + ares_dns_rr_get_u16(rr, ARES_RR_HTTPS_PRIORITY)); + for(opt = 0; opt < ares_dns_rr_get_opt_cnt(rr, ARES_RR_HTTPS_PARAMS); + opt++) + httpsrr_opt(data, rr, ARES_RR_HTTPS_PARAMS, opt); + } +} + +#endif /* USE_ARES */ + +#endif /* USE_HTTPSRR */ diff --git a/lib/httpsrr.h b/lib/httpsrr.h index 26f7a9826a..ade2126f0f 100644 --- a/lib/httpsrr.h +++ b/lib/httpsrr.h @@ -24,6 +24,36 @@ * ***************************************************************************/ +#include "curl_setup.h" + +#ifdef USE_ARES +#include +#endif + +#ifdef USE_HTTPSRR + +#define CURL_MAXLEN_host_name 253 +#define MAX_HTTPSRR_ALPNS 4 + +struct Curl_https_rrinfo { + /* + * Fields from HTTPS RR. The only mandatory fields are priority and target. + * See https://datatracker.ietf.org/doc/html/rfc9460#section-14.3.2 + */ + char *target; + unsigned char *ipv4hints; /* keytag = 4 */ + size_t ipv4hints_len; + unsigned char *echconfiglist; /* keytag = 5 */ + size_t echconfiglist_len; + unsigned char *ipv6hints; /* keytag = 6 */ + size_t ipv6hints_len; + unsigned char alpns[MAX_HTTPSRR_ALPNS]; /* keytag = 1 */ + /* store parsed alpnid entries in the array, end with ALPN_none */ + int port; /* -1 means not set */ + uint16_t priority; + bool no_def_alpn; /* keytag = 2 */ +}; +#endif /* * Code points for DNS wire format SvcParams as per RFC 9460 @@ -38,4 +68,9 @@ CURLcode Curl_httpsrr_decode_alpn(const unsigned char *cp, size_t len, unsigned char *alpns); +#if defined(USE_ARES) && defined(USE_HTTPSRR) +void Curl_dnsrec_done_cb(void *arg, ares_status_t status, + size_t timeouts, + const ares_dns_record_t *dnsrec); +#endif #endif /* HEADER_CURL_HTTPSRR_H */ diff --git a/lib/version.c b/lib/version.c index c5275495bc..0fcfed0379 100644 --- a/lib/version.c +++ b/lib/version.c @@ -467,11 +467,18 @@ static const struct feat features_table[] = { #ifdef HAVE_BROTLI FEATURE("brotli", NULL, CURL_VERSION_BROTLI), #endif +#if defined(CURLRES_ARES) && defined(CURLRES_THREADED) + FEATURE("c-ares-rr", NULL, 0), +#endif #ifdef DEBUGBUILD FEATURE("Debug", NULL, CURL_VERSION_DEBUG), #endif #if defined(USE_SSL) && defined(USE_ECH) FEATURE("ECH", ech_present, 0), + +#ifndef USE_HTTPSRR +#error "ECH enabled but not HTTPSRR, must be a config error" +#endif #endif #ifdef USE_GSASL FEATURE("gsasl", NULL, CURL_VERSION_GSASL), @@ -492,6 +499,9 @@ static const struct feat features_table[] = { !defined(CURL_DISABLE_HTTP) FEATURE("HTTPS-proxy", https_proxy_present, CURL_VERSION_HTTPS_PROXY), #endif +#if defined(USE_HTTPSRR) + FEATURE("HTTPSRR", NULL, 0), +#endif #if defined(USE_LIBIDN2) || defined(USE_WIN32_IDN) || defined(USE_APPLE_IDN) FEATURE("IDN", idn_present, CURL_VERSION_IDN), #endif diff --git a/m4/curl-confopts.m4 b/m4/curl-confopts.m4 index f7b99dffcc..7da8cb58be 100644 --- a/m4/curl-confopts.m4 +++ b/m4/curl-confopts.m4 @@ -29,7 +29,7 @@ dnl CURL_CHECK_OPTION_THREADED_RESOLVER dnl ------------------------------------------------- dnl Verify if configure has been invoked with option dnl --enable-threaded-resolver or --disable-threaded-resolver, and -dnl set shell variable want_thres as appropriate. +dnl set shell variable want_threaded_resolver as appropriate. AC_DEFUN([CURL_CHECK_OPTION_THREADED_RESOLVER], [ AC_MSG_CHECKING([whether to enable the threaded resolver]) @@ -41,25 +41,29 @@ AS_HELP_STRING([--disable-threaded-resolver],[Disable threaded resolver]), case "$OPT_THRES" in no) dnl --disable-threaded-resolver option used - want_thres="no" + want_threaded_resolver="no" ;; yes) dnl --enable-threaded-resolver option used - want_thres="yes" + want_threaded_resolver="yes" ;; *) dnl configure option not specified case $host_os in msdos* | amiga*) - want_thres="no" + want_threaded_resolver="no" ;; *) - want_thres="yes" + if test "$want_ares" = "yes"; then + want_threaded_resolver="no" + else + want_threaded_resolver="yes" + fi ;; esac ;; esac - AC_MSG_RESULT([$want_thres]) + AC_MSG_RESULT([$want_threaded_resolver]) ]) dnl CURL_CHECK_OPTION_ARES @@ -281,53 +285,6 @@ AS_HELP_STRING([--disable-symbol-hiding],[Disable hiding of library internal sym ]) -dnl CURL_CHECK_OPTION_THREADS -dnl ------------------------------------------------- -dnl Verify if configure has been invoked with option -dnl --enable-threads or --disable-threads, and -dnl set shell variable want_threads as appropriate. - -dnl AC_DEFUN([CURL_CHECK_OPTION_THREADS], [ -dnl AC_BEFORE([$0],[CURL_CHECK_LIB_THREADS])dnl -dnl AC_MSG_CHECKING([whether to enable threads for DNS lookups]) -dnl OPT_THREADS="default" -dnl AC_ARG_ENABLE(threads, -dnl AS_HELP_STRING([--enable-threads@<:@=PATH@:>@],[Enable threads for DNS lookups]) -dnl AS_HELP_STRING([--disable-threads],[Disable threads for DNS lookups]), -dnl OPT_THREADS=$enableval) -dnl case "$OPT_THREADS" in -dnl no) -dnl dnl --disable-threads option used -dnl want_threads="no" -dnl AC_MSG_RESULT([no]) -dnl ;; -dnl default) -dnl dnl configure option not specified -dnl want_threads="no" -dnl AC_MSG_RESULT([(assumed) no]) -dnl ;; -dnl *) -dnl dnl --enable-threads option used -dnl want_threads="yes" -dnl want_threads_path="$enableval" -dnl AC_MSG_RESULT([yes]) -dnl ;; -dnl esac -dnl # -dnl if test "$want_ares" = "assume_yes"; then -dnl if test "$want_threads" = "yes"; then -dnl AC_MSG_CHECKING([whether to ignore c-ares enabling assumed setting]) -dnl AC_MSG_RESULT([yes]) -dnl want_ares="no" -dnl else -dnl want_ares="yes" -dnl fi -dnl fi -dnl if test "$want_threads" = "yes" && test "$want_ares" = "yes"; then -dnl AC_MSG_ERROR([options --enable-ares and --enable-threads are mutually exclusive, at most one may be enabled.]) -dnl fi -dnl ]) - dnl CURL_CHECK_OPTION_RT dnl ------------------------------------------------- dnl Verify if configure has been invoked with option @@ -612,7 +569,7 @@ AS_HELP_STRING([--disable-httpsrr],[Disable HTTPSRR support]), *) dnl --enable-httpsrr option used want_httpsrr="yes" - curl_httpsrr_msg="enabled (--disable-httpsrr)" + curl_httpsrr_msg="enabled" AC_MSG_RESULT([yes]) ;; esac diff --git a/tests/FILEFORMAT.md b/tests/FILEFORMAT.md index a763f8711c..529bbc0196 100644 --- a/tests/FILEFORMAT.md +++ b/tests/FILEFORMAT.md @@ -434,7 +434,8 @@ Features testable here are: - `AppleIDN` - `bearssl` - `brotli` -- `c-ares` +- `c-ares` - c-ares is used for (all) name resolves +- `c-ares-rr` - c-ares is used for additional records only - `CharConv` - `codeset-utf8`. If the running codeset is UTF-8 capable. - `cookies` diff --git a/tests/data/test1014 b/tests/data/test1014 index a8f0a3b1d2..ce113a73b8 100644 --- a/tests/data/test1014 +++ b/tests/data/test1014 @@ -28,7 +28,7 @@ Compare curl --version with curl-config --features # Verify data after the test has been "shot" -%SRCDIR/libtest/test1013.pl ../curl-config %LOGDIR/stdout%TESTNUMBER features +%SRCDIR/libtest/test1013.pl ../curl-config %LOGDIR/stdout%TESTNUMBER features > %LOGDIR/result%TESTNUMBER 0 diff --git a/tests/libtest/lib1565.c b/tests/libtest/lib1565.c index b6b8ecf12d..3acbcb0338 100644 --- a/tests/libtest/lib1565.c +++ b/tests/libtest/lib1565.c @@ -205,6 +205,6 @@ test_cleanup: CURLcode test(char *URL) { (void)URL; - return 0; + return CURLE_OK; } #endif diff --git a/tests/runtests.pl b/tests/runtests.pl index 175a843eef..9ec2b8ca45 100755 --- a/tests/runtests.pl +++ b/tests/runtests.pl @@ -698,6 +698,8 @@ sub checksystemfeatures { $feature{"Unicode"} = $feat =~ /Unicode/i; # Thread-safe init $feature{"threadsafe"} = $feat =~ /threadsafe/i; + $feature{"HTTPSRR"} = $feat =~ /HTTPSRR/; + $feature{"c-ares-rr"} = $feat =~ /c-ares-rr/; } # # Test harness currently uses a non-stunnel server in order to @@ -822,7 +824,6 @@ sub checksystemfeatures { $feature{"large-time"} = 1; $feature{"large-size"} = 1; $feature{"sha512-256"} = 1; - $feature{"HTTPSRR"} = 1; $feature{"local-http"} = servers::localhttp(); $feature{"codeset-utf8"} = lc(langinfo(CODESET())) eq "utf-8"; diff --git a/tests/server/disabled.c b/tests/server/disabled.c index daf7b5d2a8..ef047c5485 100644 --- a/tests/server/disabled.c +++ b/tests/server/disabled.c @@ -115,9 +115,6 @@ static const char *disabled[]={ #ifndef CURL_CA_SEARCH_SAFE "win32-ca-search-safe", #endif -#endif -#ifndef USE_HTTPSRR - "HTTPSRR", #endif NULL }; -- 2.47.2