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
This commit is contained in:
Daniel Stenberg 2025-01-21 11:42:20 +01:00
parent 520e67dd39
commit 0d4fdbf15d
No known key found for this signature in database
GPG Key ID: 5CC908FDB71E12C2
18 changed files with 470 additions and 421 deletions

View File

@ -346,6 +346,7 @@ httpget
HttpGet HttpGet
HTTPS HTTPS
https https
HTTPSRR
hyper's hyper's
Högskolan Högskolan
IANA IANA
@ -779,10 +780,10 @@ src
SRP SRP
SRWLOCK SRWLOCK
SSL SSL
SSLS
ssl ssl
SSLeay SSLeay
SSLKEYLOGFILE SSLKEYLOGFILE
SSLS
sslv sslv
SSLv SSLv
SSLVERSION SSLVERSION

View File

@ -243,9 +243,15 @@ elseif(DOS OR AMIGA)
endif() endif()
option(CURL_LTO "Enable compiler Link Time Optimizations" OFF) option(CURL_LTO "Enable compiler Link Time Optimizations" OFF)
cmake_dependent_option(ENABLE_THREADED_RESOLVER "Enable threaded DNS lookup" if(NOT DOS AND NOT AMIGA)
ON "NOT ENABLE_ARES;NOT DOS;NOT AMIGA" # if c-ares is used, default the threaded resolver to OFF
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) include(PickyWarnings)
@ -1003,7 +1009,10 @@ if(USE_ECH)
if(NOT HAVE_ECH) if(NOT HAVE_ECH)
message(FATAL_ERROR "ECH support missing in OpenSSL/BoringSSL/AWS-LC/wolfSSL") message(FATAL_ERROR "ECH support missing in OpenSSL/BoringSSL/AWS-LC/wolfSSL")
else() else()
message(STATUS "ECH enabled.") message(STATUS "ECH enabled")
# ECH wants HTTPSRR
set(USE_HTTPSRR ON)
message(STATUS "HTTPSRR enabled")
endif() endif()
else() else()
message(FATAL_ERROR "ECH requires ECH-enablded OpenSSL, BoringSSL, AWS-LC or wolfSSL") 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("gsasl" USE_GSASL)
curl_add_if("zstd" HAVE_ZSTD) curl_add_if("zstd" HAVE_ZSTD)
curl_add_if("AsynchDNS" USE_ARES OR USE_THREADS_POSIX OR USE_THREADS_WIN32) 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 curl_add_if("IDN" (HAVE_LIBIDN2 AND HAVE_IDN2_H) OR
USE_WIN32_IDN OR USE_WIN32_IDN OR
USE_APPLE_IDN) USE_APPLE_IDN)
@ -2128,6 +2138,7 @@ curl_add_if("threadsafe" HAVE_ATOMIC OR
curl_add_if("Debug" ENABLE_DEBUG) curl_add_if("Debug" ENABLE_DEBUG)
curl_add_if("TrackMemory" ENABLE_CURLDEBUG) curl_add_if("TrackMemory" ENABLE_CURLDEBUG)
curl_add_if("ECH" _ssl_enabled AND HAVE_ECH) 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("PSL" USE_LIBPSL)
curl_add_if("CAcert" CURL_CA_EMBED_SET) curl_add_if("CAcert" CURL_CA_EMBED_SET)
curl_add_if("SSLS-EXPORT" _ssl_enabled AND USE_SSLS_EXPORT) curl_add_if("SSLS-EXPORT" _ssl_enabled AND USE_SSLS_EXPORT)

View File

@ -4134,74 +4134,26 @@ dnl set variable for use in automakefile(s)
AM_CONDITIONAL(USE_MANUAL, test x"$USE_MANUAL" = x1) AM_CONDITIONAL(USE_MANUAL, test x"$USE_MANUAL" = x1)
CURL_CHECK_LIB_ARES CURL_CHECK_LIB_ARES
if test "x$want_ares" != xyes; then
CURL_CHECK_OPTION_THREADED_RESOLVER CURL_CHECK_OPTION_THREADED_RESOLVER
if test "$ipv6" = yes; then if test "$ipv6" = yes; then
CURL_DARWIN_SYSTEMCONFIGURATION CURL_DARWIN_SYSTEMCONFIGURATION
fi fi
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 dnl turn off pthreads if rt is disabled
if test "$want_pthreads" != "no"; then if test "$want_threaded_resolver" = "yes" && test "$dontwant_rt" = "yes"; then
if test "$want_pthreads" = "yes" && test "$dontwant_rt" = "yes"; then
AC_MSG_ERROR([options --enable-pthreads and --disable-rt are mutually exclusive]) AC_MSG_ERROR([options --enable-pthreads and --disable-rt are mutually exclusive])
fi 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
fi
dnl turn off pthreads if no threaded resolver dnl Windows threaded resolver check
if test "$want_pthreads" != "no" && test "$want_thres" != "yes"; then if test "$want_threaded_resolver" = "yes" && test "$curl_cv_native_windows" = "yes"; then
want_pthreads=no USE_THREADS_WIN32=1
AC_DEFINE(USE_THREADS_WIN32, 1, [if you want Win32 threaded DNS lookup])
curl_res_msg="Win32 threaded"
fi fi
dnl detect pthreads 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_CHECK_HEADER(pthread.h,
[ AC_DEFINE(HAVE_PTHREAD_H, 1, [if you have <pthread.h>]) [ AC_DEFINE(HAVE_PTHREAD_H, 1, [if you have <pthread.h>])
save_CFLAGS="$CFLAGS" save_CFLAGS="$CFLAGS"
@ -4262,20 +4214,10 @@ if test "$want_pthreads" != "no"; then
]) ])
fi fi
dnl threaded resolver check dnl Did we find a threading option?
if test "$want_thres" = "yes" && test "x$USE_THREADS_POSIX" != "x1"; then if test "$want_threaded_resolver" != "no" -a "x$USE_THREADS_POSIX" != "x1" -a "x$USE_THREADS_WIN32" != "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]) AC_MSG_ERROR([Threaded resolver enabled but no thread library found])
fi fi
fi
AC_CHECK_HEADER(dirent.h, AC_CHECK_HEADER(dirent.h,
[ AC_DEFINE(HAVE_DIRENT_H, 1, [if you have <dirent.h>]) [ AC_DEFINE(HAVE_DIRENT_H, 1, [if you have <dirent.h>])
@ -4873,15 +4815,6 @@ if test "x$hsts" != "xyes"; then
fi 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 *************************************************************
dnl check whether ECH support, if desired, is actually available dnl check whether ECH support, if desired, is actually available
dnl dnl
@ -4909,11 +4842,24 @@ if test "x$want_ech" != "xno"; then
AC_DEFINE(USE_ECH, 1, [if ECH support is available]) AC_DEFINE(USE_ECH, 1, [if ECH support is available])
AC_MSG_RESULT($ECH_SUPPORT) AC_MSG_RESULT($ECH_SUPPORT)
experimental="$experimental ECH" experimental="$experimental ECH"
dnl ECH wants HTTPSRR
want_httpsrr="yes"
else else
AC_MSG_ERROR([--enable-ech ignored: No ECH support found]) AC_MSG_ERROR([--enable-ech ignored: No ECH support found])
fi fi
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 *************************************************************
dnl check whether OpenSSL (lookalikes) have SSL_set0_wbio dnl check whether OpenSSL (lookalikes) have SSL_set0_wbio
dnl dnl
@ -5071,6 +5017,9 @@ if test "x$USE_ARES" = "x1" -o "x$USE_THREADS_POSIX" = "x1" \
-o "x$USE_THREADS_WIN32" = "x1"; then -o "x$USE_THREADS_WIN32" = "x1"; then
SUPPORT_FEATURES="$SUPPORT_FEATURES AsynchDNS" SUPPORT_FEATURES="$SUPPORT_FEATURES AsynchDNS"
fi 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 if test "x$IDN_ENABLED" = "x1"; then
SUPPORT_FEATURES="$SUPPORT_FEATURES IDN" SUPPORT_FEATURES="$SUPPORT_FEATURES IDN"
fi fi
@ -5177,6 +5126,10 @@ if test "x$OPENSSL_ENABLED" = "x1" -o -n "$SSL_ENABLED"; then
fi fi
fi fi
if test "x$want_httpsrr" != "xno"; then
SUPPORT_FEATURES="$SUPPORT_FEATURES HTTPSRR"
fi
if test "x$SSLS_EXPORT_ENABLED" = "x1"; then if test "x$SSLS_EXPORT_ENABLED" = "x1"; then
SUPPORT_FEATURES="$SUPPORT_FEATURES SSLS-EXPORT" SUPPORT_FEATURES="$SUPPORT_FEATURES SSLS-EXPORT"
fi fi
@ -5446,6 +5399,7 @@ AC_MSG_NOTICE([Configured to build curl/libcurl:
HTTP2: ${curl_h2_msg} HTTP2: ${curl_h2_msg}
HTTP3: ${curl_h3_msg} HTTP3: ${curl_h3_msg}
ECH: ${curl_ech_msg} ECH: ${curl_ech_msg}
HTTPS RR: ${curl_httpsrr_msg}
SSLS-EXPORT: ${curl_ssls_export_msg} SSLS-EXPORT: ${curl_ssls_export_msg}
Protocols: ${SUPPORT_PROTOCOLS_LOWER} Protocols: ${SUPPORT_PROTOCOLS_LOWER}
Features: ${SUPPORT_FEATURES} Features: ${SUPPORT_FEATURES}

View File

@ -151,13 +151,13 @@ entry.
# FEATURES # FEATURES
## alt-svc ## `alt-svc`
*features* mask bit: CURL_VERSION_ALTSVC *features* mask bit: CURL_VERSION_ALTSVC
HTTP Alt-Svc parsing and the associated options (Added in 7.64.1) HTTP Alt-Svc parsing and the associated options (Added in 7.64.1)
## AsynchDNS ## `AsynchDNS`
*features* mask bit: CURL_VERSION_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 more exact timeouts (even on Windows) and less blocking when using the multi
interface. (added in 7.10.7) interface. (added in 7.10.7)
## brotli ## `brotli`
*features* mask bit: CURL_VERSION_BROTLI *features* mask bit: CURL_VERSION_BROTLI
supports HTTP Brotli content encoding using libbrotlidec (Added in 7.57.0) 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 *features* mask bit: CURL_VERSION_DEBUG
libcurl was built with debug capabilities (added in 7.10.6) libcurl was built with debug capabilities (added in 7.10.6)
## ECH ## `ECH`
*features* mask bit: non-existent *features* mask bit: non-existent
libcurl was built with ECH support (experimental, added in 8.8.0) libcurl was built with ECH support (experimental, added in 8.8.0)
## gsasl ## `gsasl`
*features* mask bit: CURL_VERSION_GSASL *features* mask bit: CURL_VERSION_GSASL
libcurl was built with libgsasl and thus with some extra SCRAM-SHA libcurl was built with libgsasl and thus with some extra SCRAM-SHA
authentication methods. (added in 7.76.0) authentication methods. (added in 7.76.0)
## GSS-API ## `GSS-API`
*features* mask bit: CURL_VERSION_GSSAPI *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. to use the current user credentials without the app having to pass them on.
(Added in 7.38.0) (Added in 7.38.0)
## HSTS ## `HSTS`
*features* mask bit: CURL_VERSION_HSTS *features* mask bit: CURL_VERSION_HSTS
libcurl was built with support for HSTS (HTTP Strict Transport Security) libcurl was built with support for HSTS (HTTP Strict Transport Security)
(Added in 7.74.0) (Added in 7.74.0)
## HTTP2 ## `HTTP2`
*features* mask bit: CURL_VERSION_HTTP2 *features* mask bit: CURL_VERSION_HTTP2
libcurl was built with support for HTTP2. libcurl was built with support for HTTP2.
(Added in 7.33.0) (Added in 7.33.0)
## HTTP3 ## `HTTP3`
*features* mask bit: CURL_VERSION_HTTP3 *features* mask bit: CURL_VERSION_HTTP3
HTTP/3 and QUIC support are built-in (Added in 7.66.0) HTTP/3 and QUIC support are built-in (Added in 7.66.0)
## HTTPS-proxy ## `HTTPS-proxy`
*features* mask bit: CURL_VERSION_HTTPS_PROXY *features* mask bit: CURL_VERSION_HTTPS_PROXY
libcurl was built with support for HTTPS-proxy. libcurl was built with support for HTTPS-proxy.
(Added in 7.52.0) (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 *features* mask bit: CURL_VERSION_IDN
libcurl was built with support for IDNA, domain names with international libcurl was built with support for IDNA, domain names with international
letters. (Added in 7.12.0) letters. (Added in 7.12.0)
## IPv6 ## `IPv6`
*features* mask bit: CURL_VERSION_IPV6 *features* mask bit: CURL_VERSION_IPV6
supports IPv6 supports IPv6
## Kerberos ## `Kerberos`
*features* mask bit: CURL_VERSION_KERBEROS5 *features* mask bit: CURL_VERSION_KERBEROS5
supports Kerberos V5 authentication for FTP, IMAP, LDAP, POP3, SMTP and supports Kerberos V5 authentication for FTP, IMAP, LDAP, POP3, SMTP and
SOCKSv5 proxy. (Added in 7.40.0) SOCKSv5 proxy. (Added in 7.40.0)
## Largefile ## `Largefile`
*features* mask bit: CURL_VERSION_LARGEFILE *features* mask bit: CURL_VERSION_LARGEFILE
libcurl was built with support for large files. (Added in 7.11.1) libcurl was built with support for large files. (Added in 7.11.1)
## libz ## `libz`
*features* mask bit: CURL_VERSION_LIBZ *features* mask bit: CURL_VERSION_LIBZ
supports HTTP deflate using libz (Added in 7.10) supports HTTP deflate using libz (Added in 7.10)
## MultiSSL ## `MultiSSL`
*features* mask bit: CURL_VERSION_MULTI_SSL *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). curl_global_sslset(3).
(Added in 7.56.0) (Added in 7.56.0)
## NTLM ## `NTLM`
*features* mask bit: CURL_VERSION_NTLM *features* mask bit: CURL_VERSION_NTLM
supports HTTP NTLM (added in 7.10.6) supports HTTP NTLM (added in 7.10.6)
## NTLM_WB ## `NTLM_WB`
*features* mask bit: CURL_VERSION_NTLM_WB *features* mask bit: CURL_VERSION_NTLM_WB
libcurl was built with support for NTLM delegation to a winbind helper. 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. (Added in 7.22.0) This feature was removed from curl in 8.8.0.
## PSL ## `PSL`
*features* mask bit: CURL_VERSION_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. libcurl ignore cookies with a domain that is on the list.
(Added in 7.47.0) (Added in 7.47.0)
## SPNEGO ## `SPNEGO`
*features* mask bit: CURL_VERSION_SPNEGO *features* mask bit: CURL_VERSION_SPNEGO
libcurl was built with support for SPNEGO authentication (Simple and Protected libcurl was built with support for SPNEGO authentication (Simple and Protected
GSS-API Negotiation Mechanism, defined in RFC 2478.) (added in 7.10.8) GSS-API Negotiation Mechanism, defined in RFC 2478.) (added in 7.10.8)
## SSL ## `SSL`
*features* mask bit: CURL_VERSION_SSL *features* mask bit: CURL_VERSION_SSL
supports SSL (HTTPS/FTPS) (Added in 7.10) supports SSL (HTTPS/FTPS) (Added in 7.10)
## SSLS-EXPORT ## `SSLS-EXPORT`
*features* mask bit: non-existent *features* mask bit: non-existent
libcurl was built with SSL session import/export support libcurl was built with SSL session import/export support
(experimental, added in 8.12.0) (experimental, added in 8.12.0)
## SSPI ## `SSPI`
*features* mask bit: CURL_VERSION_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 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) credentials without the app having to pass them on. (Added in 7.13.2)
## threadsafe ## `threadsafe`
*features* mask bit: CURL_VERSION_THREADSAFE *features* mask bit: CURL_VERSION_THREADSAFE
libcurl was built with thread-safety support (Atomic or SRWLOCK) to protect libcurl was built with thread-safety support (Atomic or SRWLOCK) to protect
curl initialization. (Added in 7.84.0) See libcurl-thread(3) curl initialization. (Added in 7.84.0) See libcurl-thread(3)
## TLS-SRP ## `TLS-SRP`
*features* mask bit: CURL_VERSION_TLSAUTH_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 libcurl was built with support for TLS-SRP (in one or more of the built-in TLS
backends). (Added in 7.21.4) backends). (Added in 7.21.4)
## TrackMemory ## `TrackMemory`
*features* mask bit: CURL_VERSION_CURLDEBUG *features* mask bit: CURL_VERSION_CURLDEBUG
libcurl was built with memory tracking debug capabilities. This is mainly of libcurl was built with memory tracking debug capabilities. This is mainly of
interest for libcurl hackers. (added in 7.19.6) interest for libcurl hackers. (added in 7.19.6)
## Unicode ## `Unicode`
*features* mask bit: CURL_VERSION_UNICODE *features* mask bit: CURL_VERSION_UNICODE
libcurl was built with Unicode support on Windows. This makes non-ASCII 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) characters work in filenames and options passed to libcurl. (Added in 7.72.0)
## UnixSockets ## `UnixSockets`
*features* mask bit: CURL_VERSION_UNIX_SOCKETS *features* mask bit: CURL_VERSION_UNIX_SOCKETS
libcurl was built with support for Unix domain sockets. libcurl was built with support for Unix domain sockets.
(Added in 7.40.0) (Added in 7.40.0)
## zstd ## `zstd`
*features* mask bit: CURL_VERSION_ZSTD *features* mask bit: CURL_VERSION_ZSTD

View File

@ -24,14 +24,14 @@
#include "curl_setup.h" #include "curl_setup.h"
#ifdef USE_ARES
/*********************************************************************** /***********************************************************************
* Only for ares-enabled builds * Only for ares-enabled builds
* And only for functions that fulfill the asynch resolver backend API * And only for functions that fulfill the asynch resolver backend API
* as defined in asyn.h, nothing else belongs in this file! * as defined in asyn.h, nothing else belongs in this file!
**********************************************************************/ **********************************************************************/
#ifdef CURLRES_ARES
#include <limits.h> #include <limits.h>
#ifdef HAVE_NETINET_IN_H #ifdef HAVE_NETINET_IN_H
#include <netinet/in.h> #include <netinet/in.h>
@ -70,6 +70,94 @@
#include <ares_version.h> /* really old c-ares did not include this by #include <ares_version.h> /* really old c-ares did not include this by
itself */ 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 #if ARES_VERSION >= 0x010500
/* c-ares 1.5.0 or later, the callback proto is modified */ /* c-ares 1.5.0 or later, the callback proto is modified */
#define HAVE_CARES_CALLBACK_TIMEOUTS 1 #define HAVE_CARES_CALLBACK_TIMEOUTS 1
@ -98,8 +186,9 @@
#if ARES_VERSION >= 0x011c00 #if ARES_VERSION >= 0x011c00
/* 1.28.0 and later have ares_query_dnsrec */ /* 1.28.0 and later have ares_query_dnsrec */
#define HAVE_ARES_QUERY_DNSREC 1 #define HAVE_ARES_QUERY_DNSREC 1
#else #ifdef USE_HTTPSRR
#undef USE_HTTPSRR #define USE_HTTPSRR_ARES 1
#endif
#endif #endif
/* The last 3 #include files should be in this order */ /* The last 3 #include files should be in this order */
@ -107,20 +196,6 @@
#include "curl_memory.h" #include "curl_memory.h"
#include "memdebug.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 /* How long we are willing to wait for additional parallel responses after
obtaining a "definitive" one. For old c-ares without getaddrinfo. 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 * 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 * (using curl_multi_fdset()) wants to get our fd_set setup.
* 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, int Curl_resolver_getsock(struct Curl_easy *data, curl_socket_t *socks)
curl_socket_t *socks)
{ {
struct timeval maxtime = { CURL_TIMEOUT_RESOLVE, 0 }; return Curl_ares_getsock(data, (ares_channel)data->state.async.resolver,
struct timeval timebuf; socks);
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
*/
static int waitperform(struct Curl_easy *data, 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((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;
} }
/* /*
@ -393,7 +392,7 @@ CURLcode Curl_resolver_is_resolved(struct Curl_easy *data,
DEBUGASSERT(dns); DEBUGASSERT(dns);
*dns = NULL; *dns = NULL;
if(waitperform(data, 0) < 0) if(Curl_ares_perform((ares_channel)data->state.async.resolver, 0) < 0)
return CURLE_UNRECOVERABLE_POLL; return CURLE_UNRECOVERABLE_POLL;
#ifndef HAVE_CARES_GETADDRINFO #ifndef HAVE_CARES_GETADDRINFO
@ -431,7 +430,7 @@ CURLcode Curl_resolver_is_resolved(struct Curl_easy *data,
result = Curl_resolver_error(data); result = Curl_resolver_error(data);
else { else {
*dns = data->state.async.dns; *dns = data->state.async.dns;
#ifdef USE_HTTPSRR #ifdef USE_HTTPSRR_ARES
{ {
struct Curl_https_rrinfo *lhrr = struct Curl_https_rrinfo *lhrr =
Curl_memdup(&res->hinfo, sizeof(struct Curl_https_rrinfo)); Curl_memdup(&res->hinfo, sizeof(struct Curl_https_rrinfo));
@ -503,7 +502,8 @@ CURLcode Curl_resolver_wait_resolv(struct Curl_easy *data,
else else
timeout_ms = 1000; 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; return CURLE_UNRECOVERABLE_POLL;
result = Curl_resolver_is_resolved(data, entry); result = Curl_resolver_is_resolved(data, entry);
@ -768,72 +768,6 @@ static void addrinfo_cb(void *arg, int status, int timeouts,
#endif #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 * Curl_resolver_getaddrinfo() - when using ares
* *
@ -916,14 +850,14 @@ struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data,
query_completed_cb, data); query_completed_cb, data);
} }
#endif #endif
#ifdef USE_HTTPSRR #ifdef USE_HTTPSRR_ARES
{ {
res->num_pending++; /* one more */ res->num_pending++; /* one more */
memset(&res->hinfo, 0, sizeof(struct Curl_https_rrinfo)); memset(&res->hinfo, 0, sizeof(struct Curl_https_rrinfo));
ares_query_dnsrec((ares_channel)data->state.async.resolver, ares_query_dnsrec((ares_channel)data->state.async.resolver,
hostname, ARES_CLASS_IN, hostname, ARES_CLASS_IN,
ARES_REC_TYPE_HTTPS, ARES_REC_TYPE_HTTPS,
dnsrec_done_cb, data, NULL); Curl_dnsrec_done_cb, data, NULL);
} }
#endif #endif
*waitp = 1; /* expect asynchronous response */ *waitp = 1; /* expect asynchronous response */
@ -1058,3 +992,5 @@ CURLcode Curl_set_dns_local_ip6(struct Curl_easy *data,
#endif #endif
} }
#endif /* CURLRES_ARES */ #endif /* CURLRES_ARES */
#endif /* USE_ARES */

View File

@ -64,6 +64,14 @@
#include "inet_ntop.h" #include "inet_ntop.h"
#include "curl_threads.h" #include "curl_threads.h"
#include "connect.h" #include "connect.h"
#ifdef USE_ARES
#include <ares.h>
#ifdef USE_HTTPSRR
#define USE_HTTPSRR_ARES 1 /* the combo */
#endif
#endif
/* The last 3 #include files should be in this order */ /* The last 3 #include files should be in this order */
#include "curl_printf.h" #include "curl_printf.h"
#include "curl_memory.h" #include "curl_memory.h"
@ -145,32 +153,6 @@ static bool init_resolve_thread(struct Curl_easy *data,
const struct addrinfo *hints); 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) static struct thread_sync_data *conn_thread_sync_data(struct Curl_easy *data)
{ {
return &(data->state.async.tdata->tsd); 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 /* Treat the request as done until the thread actually starts so any early
* cleanup gets done properly. * cleanup gets done properly.
*/ */
tsd->done = 1; tsd->done = TRUE;
#ifdef HAVE_GETADDRINFO #ifdef HAVE_GETADDRINFO
DEBUGASSERT(hints); DEBUGASSERT(hints);
tsd->hints = *hints; tsd->hints = *hints;
@ -343,7 +325,7 @@ CURL_STDCALL getaddrinfo_thread(void *arg)
} }
} }
#endif #endif
tsd->done = 1; tsd->done = TRUE;
Curl_mutex_release(tsd->mtx); Curl_mutex_release(tsd->mtx);
} }
@ -382,7 +364,7 @@ CURL_STDCALL gethostbyname_thread(void *arg)
free(td); free(td);
} }
else { else {
tsd->done = 1; tsd->done = TRUE;
Curl_mutex_release(tsd->mtx); Curl_mutex_release(tsd->mtx);
} }
@ -398,19 +380,22 @@ static void destroy_async_data(struct Curl_async *async)
{ {
if(async->tdata) { if(async->tdata) {
struct thread_data *td = async->tdata; struct thread_data *td = async->tdata;
int done; bool done;
#ifndef CURL_DISABLE_SOCKETPAIR #ifndef CURL_DISABLE_SOCKETPAIR
curl_socket_t sock_rd = td->tsd.sock_pair[0]; curl_socket_t sock_rd = td->tsd.sock_pair[0];
struct Curl_easy *data = td->tsd.data; struct Curl_easy *data = td->tsd.data;
#endif #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 * if the thread is still blocking in the resolve syscall, detach it and
* let the thread do the cleanup... * let the thread do the cleanup...
*/ */
Curl_mutex_acquire(td->tsd.mtx); Curl_mutex_acquire(td->tsd.mtx);
done = td->tsd.done; done = td->tsd.done;
td->tsd.done = 1; td->tsd.done = TRUE;
Curl_mutex_release(td->tsd.mtx); Curl_mutex_release(td->tsd.mtx);
if(!done) { if(!done) {
@ -439,6 +424,24 @@ static void destroy_async_data(struct Curl_async *async)
async->hostname = NULL; 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 * init_resolve_thread() starts a new thread that performs the actual
* resolve. This function returns before the resolve is done. * 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) if(!asp->hostname)
goto err_exit; goto err_exit;
/* The thread will set this to 1 when complete. */ /* The thread will set this TRUE when complete. */
td->tsd.done = 0; td->tsd.done = FALSE;
#ifdef HAVE_GETADDRINFO #ifdef HAVE_GETADDRINFO
td->thread_hnd = Curl_thread_create(getaddrinfo_thread, &td->tsd); 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) { if(td->thread_hnd == curl_thread_t_null) {
/* The thread never started, so mark it as done here for proper cleanup. */ /* The thread never started, so mark it as done here for proper cleanup. */
td->tsd.done = 1; td->tsd.done = TRUE;
err = errno; err = errno;
goto err_exit; goto err_exit;
} }
#ifdef USE_HTTPSRR_ARES
if(resolve_httpsrr(data, asp))
goto err_exit;
#endif
return TRUE; return TRUE;
err_exit: err_exit:
@ -587,7 +593,7 @@ CURLcode Curl_resolver_is_resolved(struct Curl_easy *data,
struct Curl_dns_entry **entry) struct Curl_dns_entry **entry)
{ {
struct thread_data *td = data->state.async.tdata; struct thread_data *td = data->state.async.tdata;
int done = 0; bool done = FALSE;
DEBUGASSERT(entry); DEBUGASSERT(entry);
*entry = NULL; *entry = NULL;
@ -596,6 +602,10 @@ CURLcode Curl_resolver_is_resolved(struct Curl_easy *data,
DEBUGASSERT(td); DEBUGASSERT(td);
return CURLE_COULDNT_RESOLVE_HOST; 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); Curl_mutex_acquire(td->tsd.mtx);
done = td->tsd.done; 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 milli;
timediff_t ms; timediff_t ms;
struct resdata *reslv = (struct resdata *)data->state.async.resolver; struct resdata *reslv = (struct resdata *)data->state.async.resolver;
int socketi = 0;
#ifndef CURL_DISABLE_SOCKETPAIR #ifndef CURL_DISABLE_SOCKETPAIR
struct thread_data *td = data->state.async.tdata; struct thread_data *td = data->state.async.tdata;
#else #else
(void)socks; (void)socks;
#endif #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 #ifndef CURL_DISABLE_SOCKETPAIR
if(td) { if(td) {
/* return read fd to client for polling the DNS resolution status */ /* 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; td->tsd.data = data;
ret_val = GETSOCK_READSOCK(0); ret_val = GETSOCK_READSOCK(socketi);
} }
else { else {
#endif #endif

View File

@ -26,6 +26,7 @@
#include "curl_setup.h" #include "curl_setup.h"
#include "curl_addrinfo.h" #include "curl_addrinfo.h"
#include "httpsrr.h"
struct addrinfo; struct addrinfo;
struct hostent; struct hostent;
@ -33,6 +34,69 @@ struct Curl_easy;
struct connectdata; struct connectdata;
struct Curl_dns_entry; 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 <ares.h>
/* 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. * This header defines all functions in the internal asynch resolver interface.
* All asynch resolvers need to provide these functions. * All asynch resolvers need to provide these functions.

View File

@ -282,14 +282,6 @@
# define CURL_DISABLE_HTTP_AUTH 1 # define CURL_DISABLE_HTTP_AUTH 1
#endif #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 */ /* No system header file shall be included in this file before this */
/* point. */ /* point. */
@ -710,15 +702,15 @@
# define CURLRES_IPV4 # define CURLRES_IPV4
#endif #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_ASYNCH
# define CURLRES_ARES # define CURLRES_ARES
/* now undef the stock libc functions just to avoid them being used */ /* now undef the stock libc functions just to avoid them being used */
# undef HAVE_GETADDRINFO # undef HAVE_GETADDRINFO
# undef HAVE_FREEADDRINFO # undef HAVE_FREEADDRINFO
#elif defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32)
# define CURLRES_ASYNCH
# define CURLRES_THREADED
#else #else
# define CURLRES_SYNCH # define CURLRES_SYNCH
#endif #endif

View File

@ -29,6 +29,7 @@
#include "curl_addrinfo.h" #include "curl_addrinfo.h"
#include "timeval.h" /* for timediff_t */ #include "timeval.h" /* for timediff_t */
#include "asyn.h" #include "asyn.h"
#include "httpsrr.h"
#include <setjmp.h> #include <setjmp.h>
@ -69,31 +70,6 @@ enum alpnid {
*/ */
struct Curl_hash *Curl_global_host_cache_init(void); 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_dns_entry {
struct Curl_addrinfo *addr; struct Curl_addrinfo *addr;
#ifdef USE_HTTPSRR #ifdef USE_HTTPSRR

View File

@ -30,6 +30,12 @@
#include "curl_addrinfo.h" #include "curl_addrinfo.h"
#include "httpsrr.h" #include "httpsrr.h"
#include "connect.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, CURLcode Curl_httpsrr_decode_alpn(const unsigned char *cp, size_t len,
unsigned char *alpns) unsigned char *alpns)
@ -85,4 +91,77 @@ err:
return CURLE_BAD_CONTENT_ENCODING; 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 #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 */

View File

@ -24,6 +24,36 @@
* *
***************************************************************************/ ***************************************************************************/
#include "curl_setup.h"
#ifdef USE_ARES
#include <ares.h>
#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 * 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, CURLcode Curl_httpsrr_decode_alpn(const unsigned char *cp, size_t len,
unsigned char *alpns); 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 */ #endif /* HEADER_CURL_HTTPSRR_H */

View File

@ -467,11 +467,18 @@ static const struct feat features_table[] = {
#ifdef HAVE_BROTLI #ifdef HAVE_BROTLI
FEATURE("brotli", NULL, CURL_VERSION_BROTLI), FEATURE("brotli", NULL, CURL_VERSION_BROTLI),
#endif #endif
#if defined(CURLRES_ARES) && defined(CURLRES_THREADED)
FEATURE("c-ares-rr", NULL, 0),
#endif
#ifdef DEBUGBUILD #ifdef DEBUGBUILD
FEATURE("Debug", NULL, CURL_VERSION_DEBUG), FEATURE("Debug", NULL, CURL_VERSION_DEBUG),
#endif #endif
#if defined(USE_SSL) && defined(USE_ECH) #if defined(USE_SSL) && defined(USE_ECH)
FEATURE("ECH", ech_present, 0), FEATURE("ECH", ech_present, 0),
#ifndef USE_HTTPSRR
#error "ECH enabled but not HTTPSRR, must be a config error"
#endif
#endif #endif
#ifdef USE_GSASL #ifdef USE_GSASL
FEATURE("gsasl", NULL, CURL_VERSION_GSASL), FEATURE("gsasl", NULL, CURL_VERSION_GSASL),
@ -492,6 +499,9 @@ static const struct feat features_table[] = {
!defined(CURL_DISABLE_HTTP) !defined(CURL_DISABLE_HTTP)
FEATURE("HTTPS-proxy", https_proxy_present, CURL_VERSION_HTTPS_PROXY), FEATURE("HTTPS-proxy", https_proxy_present, CURL_VERSION_HTTPS_PROXY),
#endif #endif
#if defined(USE_HTTPSRR)
FEATURE("HTTPSRR", NULL, 0),
#endif
#if defined(USE_LIBIDN2) || defined(USE_WIN32_IDN) || defined(USE_APPLE_IDN) #if defined(USE_LIBIDN2) || defined(USE_WIN32_IDN) || defined(USE_APPLE_IDN)
FEATURE("IDN", idn_present, CURL_VERSION_IDN), FEATURE("IDN", idn_present, CURL_VERSION_IDN),
#endif #endif

View File

@ -29,7 +29,7 @@ dnl CURL_CHECK_OPTION_THREADED_RESOLVER
dnl ------------------------------------------------- dnl -------------------------------------------------
dnl Verify if configure has been invoked with option dnl Verify if configure has been invoked with option
dnl --enable-threaded-resolver or --disable-threaded-resolver, and 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_DEFUN([CURL_CHECK_OPTION_THREADED_RESOLVER], [
AC_MSG_CHECKING([whether to enable the 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 case "$OPT_THRES" in
no) no)
dnl --disable-threaded-resolver option used dnl --disable-threaded-resolver option used
want_thres="no" want_threaded_resolver="no"
;; ;;
yes) yes)
dnl --enable-threaded-resolver option used dnl --enable-threaded-resolver option used
want_thres="yes" want_threaded_resolver="yes"
;; ;;
*) *)
dnl configure option not specified dnl configure option not specified
case $host_os in case $host_os in
msdos* | amiga*) 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
;; ;;
esac esac
AC_MSG_RESULT([$want_thres]) AC_MSG_RESULT([$want_threaded_resolver])
]) ])
dnl CURL_CHECK_OPTION_ARES 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 CURL_CHECK_OPTION_RT
dnl ------------------------------------------------- dnl -------------------------------------------------
dnl Verify if configure has been invoked with option 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 dnl --enable-httpsrr option used
want_httpsrr="yes" want_httpsrr="yes"
curl_httpsrr_msg="enabled (--disable-httpsrr)" curl_httpsrr_msg="enabled"
AC_MSG_RESULT([yes]) AC_MSG_RESULT([yes])
;; ;;
esac esac

View File

@ -434,7 +434,8 @@ Features testable here are:
- `AppleIDN` - `AppleIDN`
- `bearssl` - `bearssl`
- `brotli` - `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` - `CharConv`
- `codeset-utf8`. If the running codeset is UTF-8 capable. - `codeset-utf8`. If the running codeset is UTF-8 capable.
- `cookies` - `cookies`

View File

@ -28,7 +28,7 @@ Compare curl --version with curl-config --features
# Verify data after the test has been "shot" # Verify data after the test has been "shot"
<verify> <verify>
<postcheck> <postcheck>
%SRCDIR/libtest/test1013.pl ../curl-config %LOGDIR/stdout%TESTNUMBER features %SRCDIR/libtest/test1013.pl ../curl-config %LOGDIR/stdout%TESTNUMBER features > %LOGDIR/result%TESTNUMBER
</postcheck> </postcheck>
<errorcode> <errorcode>
0 0

View File

@ -205,6 +205,6 @@ test_cleanup:
CURLcode test(char *URL) CURLcode test(char *URL)
{ {
(void)URL; (void)URL;
return 0; return CURLE_OK;
} }
#endif #endif

View File

@ -698,6 +698,8 @@ sub checksystemfeatures {
$feature{"Unicode"} = $feat =~ /Unicode/i; $feature{"Unicode"} = $feat =~ /Unicode/i;
# Thread-safe init # Thread-safe init
$feature{"threadsafe"} = $feat =~ /threadsafe/i; $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 # Test harness currently uses a non-stunnel server in order to
@ -822,7 +824,6 @@ sub checksystemfeatures {
$feature{"large-time"} = 1; $feature{"large-time"} = 1;
$feature{"large-size"} = 1; $feature{"large-size"} = 1;
$feature{"sha512-256"} = 1; $feature{"sha512-256"} = 1;
$feature{"HTTPSRR"} = 1;
$feature{"local-http"} = servers::localhttp(); $feature{"local-http"} = servers::localhttp();
$feature{"codeset-utf8"} = lc(langinfo(CODESET())) eq "utf-8"; $feature{"codeset-utf8"} = lc(langinfo(CODESET())) eq "utf-8";

View File

@ -115,9 +115,6 @@ static const char *disabled[]={
#ifndef CURL_CA_SEARCH_SAFE #ifndef CURL_CA_SEARCH_SAFE
"win32-ca-search-safe", "win32-ca-search-safe",
#endif #endif
#endif
#ifndef USE_HTTPSRR
"HTTPSRR",
#endif #endif
NULL NULL
}; };