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:
parent
520e67dd39
commit
0d4fdbf15d
3
.github/scripts/spellcheck.words
vendored
3
.github/scripts/spellcheck.words
vendored
@ -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
|
||||
|
||||
@ -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)
|
||||
|
||||
106
configure.ac
106
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
|
||||
|
||||
if test "x$want_ares" != xyes; then
|
||||
CURL_CHECK_OPTION_THREADED_RESOLVER
|
||||
|
||||
if test "$ipv6" = yes; then
|
||||
CURL_DARWIN_SYSTEMCONFIGURATION
|
||||
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
|
||||
if test "$want_pthreads" != "no"; then
|
||||
if test "$want_pthreads" = "yes" && test "$dontwant_rt" = "yes"; then
|
||||
if test "$want_threaded_resolver" = "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
|
||||
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 <pthread.h>])
|
||||
save_CFLAGS="$CFLAGS"
|
||||
@ -4262,20 +4214,10 @@ 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
|
||||
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
|
||||
fi
|
||||
|
||||
AC_CHECK_HEADER(dirent.h,
|
||||
[ AC_DEFINE(HAVE_DIRENT_H, 1, [if you have <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}
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
274
lib/asyn-ares.c
274
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 <limits.h>
|
||||
#ifdef HAVE_NETINET_IN_H
|
||||
#include <netinet/in.h>
|
||||
@ -70,6 +70,94 @@
|
||||
#include <ares_version.h> /* 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
|
||||
* (using curl_multi_fdset()) wants to get our fd_set setup.
|
||||
*/
|
||||
|
||||
int Curl_resolver_getsock(struct Curl_easy *data,
|
||||
curl_socket_t *socks)
|
||||
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
|
||||
*/
|
||||
|
||||
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;
|
||||
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 */
|
||||
|
||||
@ -64,6 +64,14 @@
|
||||
#include "inet_ntop.h"
|
||||
#include "curl_threads.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 */
|
||||
#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
|
||||
|
||||
64
lib/asyn.h
64
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 <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.
|
||||
* All asynch resolvers need to provide these functions.
|
||||
|
||||
@ -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
|
||||
|
||||
26
lib/hostip.h
26
lib/hostip.h
@ -29,6 +29,7 @@
|
||||
#include "curl_addrinfo.h"
|
||||
#include "timeval.h" /* for timediff_t */
|
||||
#include "asyn.h"
|
||||
#include "httpsrr.h"
|
||||
|
||||
#include <setjmp.h>
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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 */
|
||||
|
||||
@ -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
|
||||
@ -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 */
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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`
|
||||
|
||||
@ -28,7 +28,7 @@ Compare curl --version with curl-config --features
|
||||
# Verify data after the test has been "shot"
|
||||
<verify>
|
||||
<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>
|
||||
<errorcode>
|
||||
0
|
||||
|
||||
@ -205,6 +205,6 @@ test_cleanup:
|
||||
CURLcode test(char *URL)
|
||||
{
|
||||
(void)URL;
|
||||
return 0;
|
||||
return CURLE_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -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";
|
||||
|
||||
|
||||
@ -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
|
||||
};
|
||||
|
||||
Loading…
Reference in New Issue
Block a user