diff options
author | robot-contrib <robot-contrib@yandex-team.com> | 2024-08-07 11:23:56 +0300 |
---|---|---|
committer | robot-contrib <robot-contrib@yandex-team.com> | 2024-08-07 13:04:06 +0300 |
commit | 2137507f9ec8a5b7c48cc521943ffa038262a679 (patch) | |
tree | 1032db05350b9a3810833ce29ab3d238d34e256c | |
parent | a159873112d46d9c8a1822e0e61857bb939803c2 (diff) | |
download | ydb-2137507f9ec8a5b7c48cc521943ffa038262a679.tar.gz |
Update contrib/libs/c-ares to 1.33.0
023d295bf695dc8b9df70e1ee966dc423cdf62ca
131 files changed, 7468 insertions, 5984 deletions
diff --git a/contrib/libs/c-ares/CHANGES b/contrib/libs/c-ares/CHANGES deleted file mode 100644 index f1426fda79..0000000000 --- a/contrib/libs/c-ares/CHANGES +++ /dev/null @@ -1,7 +0,0 @@ -This file no longer holds the changelog. Now you can generate it yourself -like this: - - $ git log --pretty=fuller --no-color --date=short --decorate=full -1000 | - ./git2changes.pl - -The older, manually edited, changelog is found in git named CHANGES.0 diff --git a/contrib/libs/c-ares/CHANGES.0 b/contrib/libs/c-ares/CHANGES.0 deleted file mode 100644 index 0da401eabe..0000000000 --- a/contrib/libs/c-ares/CHANGES.0 +++ /dev/null @@ -1,1218 +0,0 @@ - Changelog for the c-ares project - -Version 1.7.5 (August 16, 2011) - -Fixed: - - o detection of semicolon comments in resolv.conf - o avoid using system's inet_net_pton affected by the WLB-2008080064 advisory - o replacement ares_inet_net_pton affected by the WLB-2008080064 advisory - o replacement ares_inet_ntop affected by potential out of bounds write - o added install target to Makefile.msvc - o only fall back to AF_INET searches when looking for AF_UNSPEC addresses - o fixed ares_parse_*_reply memory leaks - o Use correct sizeof in ares_getnameinfo() - o IPv6-on-windows: find DNS servers correctly - o man pages: docs for the c-ares utility programs - o getservbyport replacement for Win CE - o config_sortlist: (win32) missing else - o advance_tcp_send_queue: avoid NULL ptr dereference - o configure: fix a bashism - o ares_expand_name: Fix encoded length for indirect root - -Version 1.7.4 (December 9, 2010) - -Changed: - - o local-bind: Support binding to local interface/IPs, see - ares_set_local_ip4, ares_set_local_ip6, ares_set_local_dev - -Fixed: - - o memory leak in ares_getnameinfo - o add missing break that caused get_ares_servers to fail - o ares_parse_a_reply: fix CNAME response parsing - o init_by_options: don't copy an empty sortlist - o Replaced uint32_t with unsigned int to fix broken builds - on a couple of platforms - o Fix lookup with HOSTALIASES set - o adig: fix NAPTR parsing - o compiler warning cleanups - -Version 1.7.3 (June 11, 2010) - -Fixed: - - o builds on Android - o now includes all files necessary to build it (1.7.2 lacked a file) - -Version 1.7.2 (June 10, 2010) - -Changed: - - o Added ares_parse_mx_reply() - -Fixed: - - o ares_init: Last, not first instance of domain or search should win - o improve alternative definition of bool - o fix VS2010 compiler warnings - - -Version 1.7.1 (Mar 23, 2010) - -* May 31, 2010 (Jakub Hrozek) -- Use the last instance of domain/search, not the first one - -* March 23, 2010 (Daniel Stenberg) -- We switched from CVS to git. See http://github.com/bagder/c-ares - -* March 5, 2010 (Daniel Stenberg) -- Daniel Johnson provided fixes for building with the clang compiler. - -* March 5, 2010 (Yang Tse) -- Added IPv6 name servers support. Implementation has been based on code, - comments and feedback provided November and December of 2008 by Daniel - Stenberg, Gregor Jasny, Phil Blundell and myself, December 2009 by Cedric - Bail, and February 2010 by Jakub Hrozek on the c-ares mailing list. On - March I reviewed all that, selected the best of each, and adjusted or - extended parts of it to make the best fit. - - The external and visible result of all this is that two new functions are - added to the external API, ares_get_servers() and ares_set_servers(), which - becomes now the preferred way of getting and setting name servers for any - ares channel as these support both IPv4 and IPv6 name servers. - - In order to not break ABI compatibility, ares_init_options() with option - mask ARES_OPT_SERVERS and ares_save_options() may still be used in code - which is intended to run on IPv4-only stacks. But remember that these - functions do not support IPv6 name servers. This implies that if the user - is capable of defining or providing an IPv6 name server, and the app is - using ares_init_options() or ares_save_options() at some point to handle - the name servers, the app will likely lose IPv6 name servers. - -* January 28, 2010 (Daniel Stenberg) -- Tommie Gannert pointed out a silly bug in ares_process_fd() since it didn't - check for broken connections like ares_process() did. Based on that, I - merged the two functions into a single generic one with two front-ends. - -* December 29, 2009 (Yang Tse) -- Laszlo Tamas Szabo adjusted Makefile.msvc compiler options so that where - run-time error checks enabling compiler option /GZ was used it is replaced - with equivalent /RTCsu for Visual Studio 2003 and newer versions. Option - /GX is replaced with equivalent /EHsc for all versions. Also fixed socket - data type for internal configure_socket function. - -* December 21, 2009 (Yang Tse) -- Ingmar Runge noticed that Windows config-win32.h configuration file - did not include a definition for HAVE_CLOSESOCKET which resulted in - function close() being inappropriately used to close sockets. - -Version 1.7.0 (Nov 30, 2009) - -* November 26, 2009 (Yang Tse) -- Larry Lansing fixed ares_parse_srv_reply to properly parse replies - which might contain non-SRV answers, skipping over potential non-SRV - ones such as CNAMEs. - -* November 23, 2009 (Yang Tse) -- Changed naming convention for c-ares libraries built with MSVC, details - and build instructions provided in README.msvc file. - -* November 22, 2009 (Yang Tse) -- Jakub Hrozek fixed more function prototypes in man pages to sync them - with the ones declared in ares.h - -- Jakub Hrozek renamed addrttl and addr6ttl structs to ares_addrttl and - ares_addr6ttl in order to prevent name space pollution, along with - necessary changes to code base and man pages.This change does not break - ABI, there is no need to recompile existing applications. But existing - applications using these structs with the old name will need source code - adjustments when recompiled using c-ares 1.7.0. - -* November 21, 2009 (Yang Tse) -- Added manifest stuff to Makefile.msvc. - -* November 20, 2009 (Yang Tse) -- Fixed several function prototypes in man pages that were out of sync - with the ones declared in ares.h. Added ares_free_data() along with - man page. Updated ares_parse_srv_reply() and ares_parse_txt_reply() - with changes from Jakub Hrozek making these now return linked lists - instead of arrays, and merging the ares_free_data() adjustments. - -* November 10, 2009 (Yang Tse) -- Updated MSVC 6.0 project files to match settings from Makefile.msvc. - -* November 9, 2009 (Yang Tse) -- Makefile.msvc is now the reference method to build c-ares and sample - programs with any MSVC compiler or MS Visual Studio version. If no - option or target are specified it builds dynamic and static c-ares - libraries in debug and release flavours and also builds all sample - programs using each of the different c-ares libraries. - -* November 2, 2009 (Yang Tse) -- Renamed c-ares setup.h to ares_setup.h - -* October 31, 2009 (Yang Tse) -- Symbol hiding configure options are named now --enable-symbol-hiding - and --disable-symbol-hiding in an attempt to make them less ambiguous. - -* October 30, 2009 (Yang Tse) -- Many fixes for ares_parse_txt_reply() - -* October 29, 2009 (Daniel Stenberg) -- Jakub Hrozek added ares_parse_txt_reply() for TXT parsing - -* October 29, 2009 (Yang Tse) -- Updated MSVC 6.0 workspace and project files that allows building - dynamic and static c-ares libraries in debug and release flavours. - Additionally each of the three sample programs is built against - each of the four possible c-ares libraries, generating all this - a total number of 12 executables and 4 libraries. - -* October 28, 2009 (Yang Tse) -- Initial step towards the ability to reduce c-ares exported symbols - when built as a shared library based on the 'visibility' attribute - for GNUC and Intel compilers and based on __global for Sun compilers, - taking also in account __declspec function decoration for Win32 and - Symbian DLL's. - -* October 27, 2009 (Yang Tse) -- Fixed Pelles C Win32 target compilation issues. - -* October 23, 2009 (Yang Tse) -- John Engelhart noticed an unreleased problem relative to a duplicate - ARES_ECANCELLED error code value and missing error code description. - -* October 7, 2009 (Yang Tse) -- Overhauled ares__get_hostent() Fixing out of bounds memory overwrite - triggered with malformed /etc/hosts file. Improving parsing of /etc/hosts - file. Validating requested address family. Ensuring that failures always - return a NULL pointer. Adjusting header inclusions. - -* October 6, 2009 (Yang Tse) -- Fix ssize_t redefinition errors on WIN64 reported by Alexey Simak. - -* September 29, 2009 (Yang Tse) -- Make configure script also check if _REENTRANT definition is required to - make errno available as a preprocessor macro. - -* September 7, 2009 (Yang Tse) -- Add T_SRV portability check to ares_parse_srv_reply.c - -* 4 Sep 2009 (Daniel Stenberg) -- Jakub Hrozek added ares_parse_srv_reply() for SRV parsing - -* 3 Aug 2009 (Daniel Stenberg) -- Joshua Kwan fixed the init routine to fill in the defaults for stuff that - fails to get inited by other means. This fixes a case of when the c-ares - init fails when internet access is fone. - -- Timo Teras changed the reason code used in the resolve callback done when - ares_cancel() is used, to be ARES_ECANCELLED instead of ARES_ETIMEOUT to - better allow the callback to know what's happening. - -* 14 Jul 2009 (Guenter Knauf) -- renamed generated config.h to ares_config.h to avoid any future clashes - with config.h from other projects. - -* June 20 2009 (Yang Tse) -- Refactor how libraries are checked for connect() function in configure - script and check for connect() as it is done for other functions. - -* June 19 2009 (Yang Tse) -- Make sclose() function-like macro definition used to close a socket, - now solely based on HAVE_CLOSESOCKET and HAVE_CLOSESOCKET_CAMEL - config file preprocessor definitions - -* June 18 2009 (Yang Tse) -- Add CloseSocket camel case function check for configure script. - -* June 17 2009 (Yang Tse) -- Check for socket() and closesocket() as it is done for other functions - in configure script. - -* June 11 2009 (Yang Tse) -- Modified buildconf so that when automake runs it copies missing files - instead of symlinking them. - -* June 8 2009 (Yang Tse) -- Removed buildconf.bat from release and daily snapshot archives. This - file is only for CVS tree checkout builds. - -* May 26 2009 (Yang Tse) -- Added --enable-curldebug configure option to enable and disable building - with the low-level curl debug memory tracking 'feature' to allow decoupled - setting from --enable-debug, allowing again to build c-ares independently - out of the CVS tree. - - For the c-ares library option --enable-debug enables debug build features - which are _not_ related with memory tracking. For the c-ares library when - --enable-debug is given it does not enable the memory tracking feature. If - you wish to enable the curl debug memory tracking you must use configure - option --enable-curldebug explicitly to do so. - - Internally, definition of preprocessor symbol DEBUGBUILD restricts code - which is only compiled for debug enabled builds. And symbol CURLDEBUG is - used to differentiate code which is _only_ used for memory tracking. - - Make ares_init(), ares_dup() and ares_init_options() fail returning - ARES_ENOTINITIALIZED if library initialization has not been performed - calling ares_library_init(). - -* May 20 2009 (Yang Tse) -- Added ares_library_init() and ares_library_cleanup() man pages. - -* May 19 2009 (Yang Tse) -- Introduced ares_library_init() and ares_library_cleanup() functions. - - This is an API and ABI break for Win32/64 systems. Non-Win32/64 build targets - using c-ares 1.7.0 can still survive without calling these functions. Read all - the details on ares_library_init(3) and ares_library_cleanup(3) man pages that - are included. - - curl/libcurl 7.19.5 is fully compatible with c-ares 1.7.0 on all systems. - - In order to use c-ares 1.7.0 with curl/libcurl on Win32/64 systems it is - required that curl/libcurl is 7.19.5 or newer. In other words, it is not - possible on Win32/64 to use c-ares 1.7.0 with a curl/libcurl version less - than 7.19.5 - -* May 11 2009 (Daniel Stenberg) -- Gregor Jasny made c-ares link with libtool 's -export-symbols-regex option to - only expose functions starting with ares_. - -* May 7 2009 (Yang Tse) -- Fix an m4 overquoting triggering a spurious 'AS_TR_CPP' symbol definition - attempt in generated config.h - -* May 2 2009 (Yang Tse) -- Use a build-time configured ares_socklen_t data type instead of socklen_t. - -* April 21 2009 (Yang Tse) -- Moved potential inclusion of system's malloc.h and memory.h header files to - setup_once.h. Inclusion of each header file is based on the definition of - NEED_MALLOC_H and NEED_MEMORY_H respectively. - -* March 11 2009 (Yang Tse) -- Japheth Cleaver fixed acountry.c replacing u_long with unsigned long. - -* February 20 2009 (Yang Tse) -- Do not halt compilation when using VS2008 to build a Windows 2000 target. - -* February 3 2009 (Phil Blundell) -- If the server returns garbage or nothing at all in response to an AAAA query, - go on and ask for A records anyway. - -* January 31 2009 (Daniel Stenberg) -- ares_gethostbyname() now accepts 'AF_UNSPEC' as a family for resolving - either AF_INET6 or AF_INET. It works by accepting any of the looksups in the - hosts file, and it resolves the AAAA field with a fallback to A. - -* January 14 2009 (Daniel Stenberg) -- ares.h no longer uses the HAVE_STRUCT_IN6_ADDR define check, but instead it - now declares the private struct ares_in6_addr for all systems instead of - relying on one possibly not present in the system. - -* January 13 2009 (Phil Blundell) -- ares__send_query() now varies the retry timeout pseudo-randomly to avoid - packet storms when several queries were started at the same time. - -* January 11 2009 (Daniel Stenberg) -- Phil Blundell added the internal function ares__expand_name_for_response() - that is now used by the ares_parse_*_reply() functions instead of the - ares_expand_name() simply to easier return ARES_EBADRESP for the cases where - the name expansion fails as in responses that really isn't expected. - -Version 1.6.0 (Dec 9, 2008) - -* December 9 2008 (Gisle Vanem) - - Fixes for Win32 targets using the Watt-32 tcp/ip stack. - -* Dec 4 2008 (Daniel Stenberg) - - Gregor Jasny provided the patch that introduces ares_set_socket_callback(), - and I edited it to also get duped by ares_dup(). - -* Dec 3 2008 (Daniel Stenberg) - - API changes: - - I made sure the public ares_config struct looks like before and yet it - supports the ROTATE option thanks to c-ares now storing the "optmask" - internally. Thus we should be ABI compatible with the past release(s) - now. My efforts mentioned below should not break backwards ABI compliance. - - Here's how I suggest we proceed with the API: - - ares_init() will be primary "channel creator" function. - - ares_init_options() will continue to work exactly like now and before. For - starters, it will be the (only) way to set the existing options. - - ares_save_options() will continue to work like today, but will ONLY save - options that you can set today (including ARES_OPT_ROTATE actually) but new - options that we add may not be saved with this. - - Instead we introduce: - - ares_dup() that instead can make a new channel and clone the config used - from an existing channel. It will then clone all config options, including - future new things we add. - - ares_set_*() style functions that set (new) config options. As a start we - simply add these for new functionality, but over time we can also introduce - them for existing "struct ares_options" so that we can eventually deprecate - the two ares_*_options() functions. - - ares_get_*() style functions for extracting info from a channel handle that - should be used instead of ares_save_options(). - -* Nov 26 2008 (Yang Tse) -- Brad Spencer provided changes to allow buildconf to work on OS X. - -- Gerald Combs fixed a bug in ares_parse_ptr_reply() which would cause a - buffer to shrink instead of expand if a reply contained 8 or more records. - -* Nov 25 2008 (Yang Tse) -- In preparation for the upcoming IPv6 nameservers patch, the internal - ares_addr union is now changed into an internal struct which also holds - the address family. - -* Nov 19 2008 (Daniel Stenberg) -- Brad Spencer brought the new function ares_gethostbyname_file() which simply - resolves a host name from the given file, using the regular hosts syntax. - -* Nov 1 2008 (Daniel Stenberg) -- Carlo Contavalli added support for the glibc "rotate" option, as documented - in man resolv.conf: - - causes round robin selection of nameservers from among those listed. This - has the effect of spreading the query load among all listed servers, rather - than having all clients try the first listed server first every time. - - You can enable it with ARES_OPT_ROTATE - -* Oct 21 2008 (Yang Tse) - Charles Hardin added handling of EINPROGRESS for UDP connects. - -* Oct 18 2008 (Daniel Stenberg) - Charles Hardin made adig support a regular numerical dotted IP address for the - -s option as well. - -* Oct 7 2008 (Yang Tse) -- Added --enable-optimize configure option to enable and disable compiler - optimizations to allow decoupled setting from --enable-debug. - -* Oct 2 2008 (Yang Tse) -- Added --enable-warnings configure option to enable and disable strict - compiler warnings to allow decoupled setting from --enable-debug. - -* Sep 17 2008 (Yang Tse) -- Code reorganization to allow internal/private use of "nameser.h" to any - system that lacks arpa/nameser.h or arpa/nameser_compat.h header files. - -* Sep 16 2008 (Yang Tse) -- Code reorganization to allow internal/private use of ares_writev to any - system that lacks the writev function. - -* Sep 15 2008 (Yang Tse) -- Code reorganization to allow internal/private use of ares_strcasecmp to any - system that lacks the strcasecmp function. - -- Improve configure detection of some string functions. - -* Sep 11 2008 (Yang Tse) -- Code reorganization to allow internal/private use of ares_strdup to any - system that lacks the strdup function. - -Version 1.5.3 (Aug 29, 2008) - -* Aug 25 2008 (Yang Tse) -- Improvement by Brad House: - - This patch addresses an issue in which a response could be sent back to the - source port of a client from a different address than the request was made to. - This is one form of a DNS cache poisoning attack. - - The patch simply uses recvfrom() rather than recv() and validates that the - address returned from recvfrom() matches the address of the server we have - connected to. Only necessary on UDP sockets as they are connection-less, TCP - is unaffected. - -- Fix by George Neill: - Fixed compilation of acountry sample application failure on some systems. - -* Aug 4 2008 (Daniel Stenberg) -- Fix by Tofu Linden: - - The symptom: - * Users (usually, but not always) on 2-Wire routers and the Comcast service - and a wired connection to their router would find that the second and - subsequent DNS lookups from fresh processes using c-ares to resolve the same - address would cause the process to never see a reply (it keeps polling for - around 1m15s before giving up). - - The repro: - * On such a machine (and yeah, it took us a lot of QA to find the systems - that reproduce such a specific problem!), do 'ahost www.secondlife.com', - then do it again. The first process's lookup will work, subsequent lookups - will time-out and fail. - - The cause: - * init_id_key() was calling randomize_key() *before* it initialized - key->state, meaning that the randomness generated by randomize_key() is - immediately overwritten with deterministic values. (/dev/urandom was also - being read incorrectly in the c-ares version we were using, but this was - fixed in a later version.) - * This makes the stream of generated query-IDs from any new c-ares process - be an identical and predictable sequence of IDs. - * This makes the 2-Wire's default built-in DNS server detect these queries - as probable-duplicates and (erroneously) not respond at all. - - -* Aug 4 2008 (Yang Tse) -- Autoconf 2.62 has changed the behaviour of the AC_AIX macro which we use. - Prior versions of autoconf defined _ALL_SOURCE if _AIX was defined. 2.62 - version of AC_AIX defines _ALL_SOURCE and other four preprocessor symbols - no matter if the system is AIX or not. To keep the traditional behaviour, - and an uniform one across autoconf versions AC_AIX is replaced with our - own internal macro CARES_CHECK_AIX_ALL_SOURCE. - -* Aug 1 2008 (Yang Tse) -- Configure process now checks if the preprocessor _REENTRANT symbol is already - defined. If it isn't currently defined a set of checks are performed to test - if its definition is required to make visible to the compiler a set of *_r - functions. Finally, if _REENTRANT is already defined or needed it takes care - of making adjustments necessary to ensure that it is defined equally for the - configure process tests and generated config file. - -* Jul 20 2008 (Yang Tse) -- When recvfrom prototype uses a void pointer for arguments 2, 5 or 6 this will - now cause the definition, as appropriate, of RECVFROM_TYPE_ARG2_IS_VOID, - RECVFROM_TYPE_ARG5_IS_VOID or RECVFROM_TYPE_ARG6_IS_VOID. - -* Jul 17 2008 (Yang Tse) -- RECVFROM_TYPE_ARG2, RECVFROM_TYPE_ARG5 and RECVFROM_TYPE_ARG6 are now defined - to the data type pointed by its respective argument and not the pointer type. - -* Jul 16 2008 (Yang Tse) -- Improved configure detection of number of arguments for getservbyport_r. - Detection is now based on compilation checks instead of linker ones. - -- Configure process now checks availability of recvfrom() socket function and - finds out its return type and the types of its arguments. Added definitions - for non-configure systems config files, and introduced macro sreadfrom which - will be used on udp sockets as a recvfrom() wrapper in the future. - -* Jul 15 2008 (Yang Tse) -- Introduce definition of _REENTRANT symbol in setup.h to improve library - usability. Previously the configure process only used the AC_SYS_LARGEFILE - macro for debug builds, now it is also used for non-debug ones enabling the - use of configure options --enable-largefile and --disable-largefile which - might be needed for library compatibility. Remove checking the size of - curl_off_t, it is no longer needed. - -* Jul 3 2008 (Daniel Stenberg) -- Phil Blundell: If you ask ares_gethostbyname() to do an AF_INET6 lookup and - the target host has only A records, it automatically falls back to an - AF_INET lookup and gives you the A results. However, if the target host has - a CNAME record, this behaviour is defeated since the original query does - return some data even though ares_parse_aaa_reply() doesn't consider it - relevant. Here's a small patch to make it behave the same with and without - the CNAME. - -* Jul 2 2008 (Yang Tse) -- Fallback to gettimeofday when monotonic clock is unavailable at run-time. - -* Jun 30 2008 (Daniel Stenberg) - -- As was pointed out to me by Andreas Schuldei, the MAXHOSTNAMELEN define is - not posix or anything and thus c-ares failed to build on hurd (and possibly - elsewhere). The define was also somewhat artificially used in the windows - port. Now, I instead rewrote the use of gethostbyname to enlarge the host - name buffer in case of need and totally avoid the use of the MAXHOSTNAMELEN - define. I thus also removed the define from the namser.h file where it was - once added for the windows build. - - I also fixed init_by_defaults() function to not leak memory in case if - error. - -* Jun 9 2008 (Yang Tse) - -- Make libcares.pc generated file for pkg-config include information relative - to the libraries needed for the static linking of c-ares. - -* May 30 2008 (Yang Tse) - -- Brad House fixed a missing header file inclusion in adig sample program. - -Version 1.5.2 (May 29, 2008) - -* May 13 2008 (Daniel Stenberg) - -- Introducing millisecond resolution support for the timeout option. See - ares_init_options()'s ARES_OPT_TIMEOUTMS. - -* May 9 2008 (Yang Tse) - -- Use monotonic time source if available, for private function ares__tvnow() - -* May 7 2008 (Daniel Stenberg) - -- Sebastian made c-ares able to return all PTR-records when doing reverse - lookups. It is not common practice to have multiple PTR-Records for a single - IP, but its perfectly legal and some sites have those. - -- Doug Goldstein provided a configure patch: updates autoconf 2.13 usage to - autoconf 2.57 usage (which is the version you have specified as the minimum - version). It's a minor change but it does clean up some warnings with newer - autoconf (specifically 2.62). - -* May 5 2008 (Yang Tse) - -- Improved parsing of resolver configuration files. - -* April 4 2008 (Daniel Stenberg) - -- Eino Tuominen improved the code when a file is used to seed the randomizer. - -- Alexey Simak made adig support NAPTR records - -- Alexey Simak fixed the VC dsp file by adding the missing source file - ares_expand_string.c - -* December 11 2007 (Gisle Vanem) - -- Added another sample application; acountry.c which converts an - IPv4-address(es) and/or host-name(s) to country-name and country-code. - This uses the service of the DNSBL at countries.nerd.dk. - -* December 3 2007 (Daniel Stenberg) - -- Brad Spencer fixed the configure script to assume that there's no - /dev/urandom when built cross-compiled as then the script cannot check for - it. - -- Erik Kline cleaned up ares_gethostbyaddr.c:next_lookup() somewhat - -Version 1.5.1 (Nov 21, 2007) - -* November 21 2007 (Daniel Stenberg) - -- Robin Cornelius pointed out that ares_llist.h was missing in the release - archive for 1.5.0 - -Version 1.5.0 (Nov 21, 2007) - -* October 2 2007 (Daniel Stenberg) - -- ares_strerror() segfaulted if the input error number was out of the currently - supported range. - -- Yang Tse: Avoid a segfault when generating a DNS "Transaction ID" in - internal function init_id_key() under low memory conditions. - -* September 28 2007 (Daniel Stenberg) - -- Bumped version to 1.5.0 for next release and soname bumped to 2 due to ABI - and API changes in the progress callback (and possibly more coming up from - Steinar) - -* September 28 2007 (Steinar H. Gunderson) - -- Don't skip a server if it's the only one. (Bugfix from the Google tree.) - -- Made the query callbacks receive the number of timeouts that happened during - the execution of a query, and updated documentation accordingly. (Patch from - the Google tree.) - -- Support a few more socket options: ARES_OPT_SOCK_SNDBUF and - ARES_OPT_SOCK_RCVBUF - -- Always register for TCP events even if there are no outstanding queries, as - the other side could always close the connection, which is a valid event - which should be responded to. - -* September 22 2007 (Daniel Stenberg) - -- Steinar H. Gunderson fixed: Correctly clear sockets from the fd_set on in - several functions (write_tcp_data, read_tcp_data, read_udp_packets) so that - if it fails and the socket is closed the following code doesn't try to use - the file descriptor. - -- Steinar H. Gunderson modified c-ares to now also do to DNS retries even when - TCP is used since there are several edge cases where it still makes sense. - -- Brad House provided a fix for ares_save_options(): - - Apparently I overlooked something with the ares_save_options() where it - would try to do a malloc(0) when no options of that type needed to be saved. - On most platforms, this was fine because malloc(0) doesn't actually return - NULL, but on AIX it does, so ares_save_options would return ARES_ENOMEM. - -* July 14 2007 (Daniel Stenberg) - -- Vlad Dinulescu fixed two outstanding valgrind reports: - - 1. In ares_query.c , in find_query_by_id we compare q->qid (which is a short - int variable) with qid, which is declared as an int variable. Moreover, - DNS_HEADER_SET_QID is used to set the value of qid, but DNS_HEADER_SET_QID - sets only the first two bytes of qid. I think that qid should be declared as - "unsigned short" in this function. - - 2. The same problem occurs in ares_process.c, process_answer() . query->qid - (an unsigned short integer variable) is compared with id, which is an - integer variable. Moreover, id is initialized from DNS_HEADER_QID which sets - only the first two bytes of id. I think that the id variable should be - declared as "unsigned short" in this function. - - Even after declaring these variables as "unsigned short", the valgrind - errors are still there. Which brings us to the third problem. - - 3. The third problem is that Valgrind assumes that query->qid is not - initialised correctly. And it does that because query->qid is set from - DNS_HEADER_QID(qbuf); Valgrind says that qbuf has uninitialised bytes. And - qbuf has uninitialised bytes because of channel->next_id . And next_id is - set by ares_init.c:ares__generate_new_id() . I found that putting short r=0 - in this function (instead of short r) makes all Valgrind warnings go away. - I have studied ares__rc4() too, and this is the offending line: - - buffer_ptr[counter] ^= state[xorIndex]; (ares_query.c:62) - - This is what triggers Valgrind.. buffer_ptr is uninitialised in this function, - and by applying ^= on it, it remains uninitialised. - -Version 1.4.0 (June 8, 2007) - -* June 4 2007 (Daniel Stenberg) - -- James Bursa reported a major memory problem when resolving multi-IP names - and I found and fixed the problem. It was added by Ashish Sharma's patch - two days ago. - - When I then tried to verify multiple entries in /etc/hosts after my fix, I - got another segfault and decided this code was not ripe for inclusion and I - reverted the patch. - -* June 2 2007 - -- Brad Spencer found and fixed three flaws in the code, found with the new - gcc 4.2.0 warning: -Waddress - -- Brad House fixed VS2005 compiler warnings due to time_t being 64bit. - He also made recent Microsoft compilers use _strdup() instead of strdup(). - -- Brad House's man pages for ares_save_options() and ares_destroy_options() - were added. - -- Ashish Sharma provided a patch for supporting multiple entries in the - /etc/hosts file. Patch edited for coding style and functionality by me - (Daniel). - -* May 30 2007 - -- Shmulik Regev brought cryptographically secure transaction IDs: - - The c-ares library implementation uses a DNS "Transaction ID" field that is - seeded with a pseudo random number (based on gettimeofday) which is - incremented (++) between consecutive calls and is therefore rather - predictable. In general, predictability of DNS Transaction ID is a well - known security problem (e.g. - http://bak.spc.org/dms/archive/dns_id_attack.txt) and makes a c-ares based - implementation vulnerable to DNS poisoning. Credit goes to Amit Klein - (Trusteer) for identifying this problem. - - The patch I wrote changes the implementation to use a more secure way of - generating unique IDs. It starts by obtaining a key with reasonable entropy - which is used with an RC4 stream to generate the cryptographically secure - transaction IDs. - - Note that the key generation code (in ares_init:randomize_key) has two - versions, the Windows specific one uses a cryptographically safe function - provided (but undocumented :) by the operating system (described at - http://blogs.msdn.com/michael_howard/archive/2005/01/14/353379.aspx). The - default implementation is a bit naive and uses the standard 'rand' - function. Surely a better way to generate random keys exists for other - platforms. - - The patch can be tested by using the adig utility and using the '-s' option. - -- Brad House added ares_save_options() and ares_destroy_options() that can be - used to keep options for later re-usal when ares_init_options() is used. - - Problem: Calling ares_init() for each lookup can be unnecessarily resource - intensive. On windows, it must LoadLibrary() or search the registry - on each call to ares_init(). On unix, it must read and parse - multiple files to obtain the necessary configuration information. In - a single-threaded environment, it would make sense to only - ares_init() once, but in a heavily multi-threaded environment, it is - undesirable to ares_init() and ares_destroy() for each thread created - and track that. - - Solution: Create ares_save_options() and ares_destroy_options() functions to - retrieve and free options obtained from an initialized channel. The - options populated can be used to pass back into ares_init_options(), - it should populate all needed fields and not retrieve any information - from the system. Probably wise to destroy the cache every minute or - so to prevent the data from becoming stale. - -- Daniel S added ares_process_fd() to allow applications to ask for processing - on specific sockets and thus avoiding select() and associated - functions/macros. This function will be used by upcoming libcurl releases - for this very reason. It also made me export the ares_socket_t type in the - public ares.h header file, since ares_process_fd() uses that type for two of - the arguments. - -* May 25 2007 - -- Ravi Pratap fixed a flaw in the init_by_resolv_conf() function for windows - that could cause it to return a bad return code. - -* April 16 2007 - -- Yang Tse: Provide ares_getopt() command-line parser function as a source - code helper function, not belonging to the actual c-ares library. - -* February 19 2007 - -- Vlad Dinulescu added ares_parse_ns_reply(). - -* February 13 2007 - -- Yang Tse: Fix failure to get the search sequence of /etc/hosts and - DNS from /etc/nsswitch.conf, /etc/host.conf or /etc/svc.conf when - /etc/resolv.conf did not exist or was unable to read it. - -* November 22 2006 - -- Install ares_dns.h too - -- Michael Wallner fixed this problem: When I set domains in the options - struct, and there are domain/search entries in /etc/resolv.conf, the domains - of the options struct will be overridden. - -* November 6 2006 - -- Yang Tse removed a couple of potential zero size memory allocations. - -- Andreas Rieke fixed the line endings in the areslib.dsp file that I (Daniel) - broke in the 1.3.2 release. We should switch to a system where that file is - auto-generated. We could rip some code for that from curl... - -Version 1.3.2 (November 3, 2006) - -* October 12 2006 - -- Prevent ares_getsock() to overflow if more than 16 sockets are used. - -* September 11 2006 - -- Guilherme Balena Versiani: I noted a strange BUG in Win32 port - (ares_init.c/get_iphlpapi_dns_info() function): when I disable the network - by hand or disconnect the network cable in Windows 2000 or Windows XP, my - application gets 127.0.0.1 as the only name server. The problem comes from - 'GetNetworkParams' function, that returns the empty string "" as the only - name server in that case. Moreover, the Windows implementation of - inet_addr() returns INADDR_LOOPBACK instead of INADDR_NONE. - -* August 29 2006 - -- Brad Spencer did - - o made ares_version.h use extern "C" for c++ compilers - o fixed compiler warnings in ares_getnameinfo.c - o fixed a buffer position init for TCP reads - -* August 3 2006 - -- Ravi Pratap fixed ares_getsock() to actually return the proper bitmap and - not always zero! - -Version 1.3.1 (June 24, 2006) - -* July 23, 2006 - -- Gisle Vanem added getopt() to the ahost program. Currently accepts - only [-t {a|aaaa}] to specify address family in ares_gethostbyname(). - -* June 19, 2006 - -- (wahern) Removed "big endian" DNS section and RR data integer parser - macros from ares_dns.h, which break c-ares on my Sparc64. Bit-wise - operations in C operate on logical values. And in any event the octets are - already in big-endian (aka network) byte order so they're being reversed - (thus the source of the breakage). - -* June 18, 2006 - -- William Ahern handles EAGAIN/EWOULDBLOCK errors in most of the I/O calls - from area_process.c. - - TODO: Handle one last EAGAIN for a UDP socket send(2) in - ares__send_query(). - -* May 10, 2006 - -- Bram Matthys brought my attention to a libtool peculiarity where detecting - things such as C++ compiler actually is a bad thing and since we don't need - that detection I added a work-around, much inspired by a previous patch by - Paolo Bonzini. This also shortens the configure script quite a lot. - -* May 3, 2006 - -- Nick Mathewson added the ARES_OPT_SOCK_STATE_CB option that when set makes - c-ares call a callback on socket state changes. A better way than the - ares_getsock() to get full control over the socket state. - -* January 9, 2006 - -- Alexander Lazic improved the getservbyport_r() configure check. - -* January 6, 2006 - -- Alexander Lazic pointed out that the buildconf should use the ACLOCAL_FLAGS - variable for easier controlling what it does and how it runs. - -* January 5, 2006 - -- James Bursa fixed c-ares to find the hosts file on RISC OS, and made it - build with newer gcc versions that no longer defines "riscos". - -* December 22 - -- Daniel Stenberg added ares_getsock() that extracts the set of sockets to - wait for action on. Similar to ares_fds() but not restricted to using - select() for the waiting. - -* November 25 - -- Yang Tse fixed some send() / recv() compiler warnings - -* September 18 - -- Added constants that will be used by ares_getaddrinfo - -- Made ares_getnameinfo use the reentrant getservbyport (getservbyport_r) if it - is available to ensure it works properly in a threaded environment. - -* September 10 - -- configure fix for detecting a member in the sockaddr_in6 struct which failed - on ipv6-enabled HP-UX 11.00 - -Version 1.3.0 (August 29, 2005) - -* August 21 - -- Alfredo Tupone provided a fix for the Windows code in get_iphlpapi_dns_info() - when getting the DNS server etc. - -* June 19 - -- Added some checks for the addrinfo structure. - -* June 2 - -- William Ahern: - - Make UDP sockets non-blocking. I've confirmed that at least on Linux 2.4 a - read event can come back from poll() on a valid SOCK_DGRAM socket but - recv(2) will still block. This patch doesn't ignore EAGAIN in - read_udp_packets(), though maybe it should. (This patch was edited by Daniel - Stenberg and a new configure test was added (imported from curl's configure) - to properly detect what non-blocking socket approach to use.) - - I'm not quite sure how this was happening, but I've been seeing PTR queries - which seem to return empty responses. At least, they were empty when calling - ares_expand_name() on the record. Here's a patch which guarantees to - NUL-terminate the expanded name. The old behavior failed to NUL-terminate if - len was 0, and this was causing strlen() to run past the end of the buffer - after calling ares_expand_name() and getting ARES_SUCCESS as the return - value. If q is not greater than *s then it's equal and *s is always - allocated with at least one byte. - -* May 16 - -- Added ares_getnameinfo which mimics the getnameinfo API (another feature - that could use testing). - -* May 14 - -- Added an inet_ntop function from BIND for systems that do not have it. - -* April 9 - -- Made sortlist support IPv6 (this can probably use some testing). - -- Made sortlist support CIDR matching for IPv4. - -* April 8 - -- Added preliminary IPv6 support to ares_gethostbyname. Currently, sortlist - does not work with IPv6. Also provided an implementation of bitncmp from - BIND for systems that do not supply this function. This will be used to add - IPv6 support to sortlist. - -- Made ares_gethostbyaddr support IPv6 by specifying AF_INET6 as the family. - The function can lookup IPv6 addresses both from files (/etc/hosts) and - DNS lookups. - -* April 7 - -- Tupone Alfredo fixed includes of arpa/nameser_compat.h to build fine on Mac - OS X. - -* April 5 - -- Dominick Meglio: Provided implementations of inet_net_pton and inet_pton - from BIND for systems that do not include these functions. - -* March 11, 2005 - -- Dominick Meglio added ares_parse_aaaa_reply.c and did various - adjustments. The first little steps towards IPv6 support! - -* November 7 - -- Fixed the VC project and makefile to use ares_cancel and ares_version - -* October 24 - -- The released ares_version.h from 1.2.1 says 1.2.0 due to a maketgz flaw. - This is now fixed. - -Version 1.2.1 (October 20, 2004) - -* September 29 - -- Henrik Stoerner fix: got a report that Tru64 Unix (the unix from Digital - when they made Alpha's) uses /etc/svc.conf for the purpose fixed below for - other OSes. He made c-ares check for and understand it if present. - -- Now c-ares will use local host name lookup _before_ DNS resolving by default - if nothing else is told. - -* September 26 - -- Henrik Stoerner: found out that c-ares does not look at the /etc/host.conf - file to determine the sequence in which to search /etc/hosts and DNS. So on - systems where this order is defined by /etc/host.conf instead of a "lookup" - entry in /etc/resolv.conf, c-ares will always default to looking in DNS - first, and /etc/hosts second. - - c-ares now looks at - - 1) resolv.conf (for the "lookup" line); - 2) nsswitch.fon (for the "hosts:" line); - 3) host.conf (for the "order" line). - - First match wins. - -- Dominick Meglio patched: C-ares on Windows assumed that the HOSTS file is - located in a static location. It assumed - C:\Windows\System32\Drivers\Etc. This is a poor assumption to make. In fact, - the location of the HOSTS file can be changed via a registry setting. - - There is a key called DatabasePath which specifies the path to the HOSTS - file: - http://www.microsoft.com/technet/itsolutions/network/deploy/depovg/tcpip2k.mspx - - The patch will make c-ares correctly consult the registry for the location - of this file. - -* August 29 - -- Gisle Vanem fixed the MSVC build files. - -* August 20 - -- Gisle Vanem made c-ares build and work with his Watt-32 TCP/IP stack. - -* August 13 - -- Harshal Pradhan made a minor syntax change in ares_init.c to make it build - fine with MSVC 7.1 - -* July 24 - -- Made the lib get built static only if --enable-debug is used. - -- Gisle Vanem fixed: - - Basically in loops like handle_errors(), 'query->next' was assigned a local - variable and then query was referenced after the memory was freed by - next_server(). I've changed that so next_server() and end_query() returns - the next query. So callers should use this ret-value. - - The next problem was that 'server->tcp_buffer_pos' had a random value at - entry to 1st recv() (luckily causing Winsock to return ENOBUFS). - - I've also added a ares_writev() for Windows to streamline the code a bit - more. - -* July 20 -- Fixed a few variable return types for some system calls. Made configure - check for ssize_t to make it possible to use that when receiving the send() - error code. This is necessary to prevent compiler warnings on some systems. - -- Made configure create config.h, and all source files now include setup.h that - might include the proper config.h (or a handicrafted alternative). - -- Switched to 'ares_socket_t' type for sockets in ares, since Windows don't - use 'int' for that. - -- automake-ified and libool-ified c-ares. Now it builds libcares as a shared - lib on most platforms if wanted. (This bloated the size of the release - archive with another 200K!) - -- Makefile.am now uses Makefile.inc for the c sources, h headers and man - pages, to make it easier for other makefiles to use the exact same set of - files. - -- Adjusted 'maketgz' to use the new automake magic when building distribution - archives. - -- Anyone desires HTML and/or PDF versions of the man pages in the release - archives? - -* July 3 -- Günter Knauf made c-ares build and run on Novell Netware. - -* July 1 -- Gisle Vanem provided Makefile.dj to build with djgpp, added a few more djgpp - fixes and made ares not use 'errno' to provide further info on Windows. - -* June 30 -- Gisle Vanem made it build with djgpp and run fine with the Watt-32 stack. - -* June 10 -- Gisle Vanem's init patch for Windows: - - The init_by_resolv_conf() function fetches the DNS-server(s) - from a series of registry branches. - - This can be wrong in the case where DHCP has assigned nameservers, but the - user has overridden these servers with other preferred settings. Then it's - wrong to use the DHCPNAMESERVER setting in registry. - - In the case of no global DHCP-assigned or fixed servers, but DNS server(s) - per adapter, one has to query the adapter branches. But how can c-ares know - which adapter is valid for use? AFAICS it can't. There could be one adapter - that is down (e.g. a VPN adapter). - - So it's better to leave this to the IP Helper API (iphlapi) available in - Win-98/2000 and later. My patch falls-back to the old way if not available. - -* June 8 -- James Bursa fixed an init issue for RISC OS. - -* May 11 -- Nico Stappenbelt reported that when processing domain and search lines in - the resolv.conf file, the first entry encountered is processed and used as - the search list. According to the manual pages for both Linux, Solaris and - Tru64, the last entry of either a domain or a search field is used. - - This is now adjusted in the code - -Version 1.2.0 (April 13, 2004) - -* April 2, 2004 -- Updated various man pages to look nicer when converted to HTML on the web - site. - -* April 1, 2004 -- Dirk Manske provided a new function that is now named ares_cancel(). It is - used to cancel/cleanup a resolve/request made using ares functions on the - given ares channel. It does not destroy/kill the ares channel itself. - -- Dominick Meglio cleaned up the formatting in several man pages. - -* March 30, 2004 -- Dominick Meglio's new ares_expand_string. A helper function when decoding - incoming DNS packages. - -- Daniel Stenberg modified the Makefile.in to use a for loop for the man page - installation to improve overview and make it easier to add man pages. - -Version 1.1.0 (March 11, 2004) - -* March 9, 2004 -- Gisle Vanem improved build on Windows. - -* February 25, 2004 -- Dan Fandrich found a flaw in the Feb 22 fix. - -- Added better configure --enable-debug logic (taken from the curl configure - script). Added acinclude.m4 to the tarball. - -* February 23, 2004 -- Removed ares_free_errmem(), the function, the file and the man page. It was - not used and it did nothing. - -- Fixed a lot of code that wasn't "64bit clean" and thus caused a lot of - compiler warnings on picky compilers. - -* February 22, 2004 -- Dominick Meglio made ares init support multiple name servers in the - NameServer key on Windows. - -* February 16, 2004 -- Modified ares_private.h to include libcurl's memory debug header if - CURLDEBUG is set. This makes all the ares-functions supervised properly by - the curl test suite. This also forced me to add inclusion of the - ares_private.h header in a few more files that are using some kind of - memory-related resources. - -- Made the makefile only build ahost and adig if 'make demos' is used. - -* February 10, 2004 -- Dirk Manske made ares_version.h installed with 'make install' - -* February 4, 2004 -- ares_free_errmem() is subject for removal, it is simply present for future - purposes, and since we removed the extra parameter in strerror() it won't - be used by c-ares! -- configure --enable-debug now enables picky compiler options if gcc is used -- fixed several compiler warnings --enable-debug showed and Joerg Mueller-Tolk - reported - -Version 1.0.0 (February 3, 2004) - -* February 3, 2004 -- now we produce the libcares.a library instead of the previous libares.a - since we are no longer compatible - -* February 2, 2004 - -- ares_strerror() has one argument less. This is the first official - modification of the existing provided ares API. - -* January 29, 2004 - -- Dirk Manske fixed how the socket is set non-blocking. - -* January 4, 2004 - -- Dominick Meglio made the private gettimeofday() become ares_gettimeofday() - instead in order to not pollute the name space and risk colliding with - other libraries' versions of this function. - -* October 24, 2003. Daniel Stenberg - - Added ares_version(). - -Version 1.0-pre1 (8 October 2003) - -- James Bursa made it run on RISC OS - -- Dominick Meglio made it run fine on NT4 - -- Duncan Wilcox made it work fine on Mac OS X - -- Daniel Stenberg adjusted the windows port - -- liren at vivisimo.com made the initial windows port - -* Imported the sources from ares 1.1.1 diff --git a/contrib/libs/c-ares/INSTALL.md b/contrib/libs/c-ares/INSTALL.md index de766aad28..dc58ab8c04 100644 --- a/contrib/libs/c-ares/INSTALL.md +++ b/contrib/libs/c-ares/INSTALL.md @@ -1,5 +1,3 @@ -** This file is adapted from libcurl and not yet fully rewritten for c-ares! ** - ``` ___ __ _ _ __ ___ ___ / __| ___ / _` | '__/ _ \/ __| @@ -44,7 +42,7 @@ unpacked the source archive): You probably need to be root when doing the last command. If you have checked out the sources from the git repository, read the -[GIT-INFO](GIT_INFO) on how to proceed. +[GIT-INFO](GIT-INFO) on how to proceed. Get a full listing of all available configure options by invoking it like: @@ -309,6 +307,16 @@ first to rebuild every single library your app uses as well as your app using the debug multithreaded dynamic C runtime. +### MSYS + +Building is supported for native windows via both AutoTools and CMake. When +building with autotools, you can only build either a shared version or a static +version (use `--disable-shared` or `--disable-static`). CMake can build both +simultaneously. + +All of the MSYS environments are supported: `MINGW32`, `MINGW64`, `UCRT64`, +`CLANG32`, `CLANG64`, `CLANGARM64`. + ### MingW32 Make sure that MinGW32's bin dir is in the search path, for example: @@ -341,6 +349,26 @@ add `-DCARES_STATICLIB` to your `CFLAGS`. Otherwise the linker will look for dynamic import symbols. +DOS +--- + +c-ares supports building as a 32bit protected mode application via +[DJGPP](https://www.delorie.com/djgpp/). It is recommended to use a DJGPP +cross compiler from [Andrew Wu](https://github.com/andrewwutw/build-djgpp) +as building directly in a DOS environment can be difficult. + +It is required to also have [Watt-32](https://www.watt-32.net/) available +built using the same compiler. It is recommended to build the latest `master` +branch from [GitHub](https://github.com/sezero/watt32/tree/master). + +Finally, the `DJ_PREFIX` and `WATT_ROOT` environment variables must be set +appropriately before calling `make Makefile.dj` to build c-ares. + +Please refer to our CI +[GitHub Actions Workflow](https://github.com/c-ares/c-ares/blob/main/.github/workflows/djgpp.yml) +for a full build example, including building the latest Watt-32 release. + + IBM OS/2 -------- @@ -420,20 +448,25 @@ This is a probably incomplete list of known hardware and operating systems that c-ares has been compiled for. If you know a system c-ares compiles and runs on, that isn't listed, please let us know! - - Alpha Tru64 v5.0 5.1 - - ARM Android 1.5, 2.1, 2.3 - - MIPS IRIX 6.2, 6.5 - - Power AIX 3.2.5, 4.2, 4.3.1, 4.3.2, 5.1, 5.2 - - i386 Linux 1.3, 2.0, 2.2, 2.3, 2.4, 2.6 - - i386 Novell NetWare - - i386 Windows 95, 98, ME, NT, 2000, XP, 2003 - - x86_64 Linux + - Linux (i686, x86_64, AARCH64, and more) + - MacOS 10.4+ + - iOS + - Windows 8+ (i686, x86_64) + - Android (ARM, AARCH64, x86_64) + - FreeBSD + - NetBSD + - OpenBSD + - Solaris (SPARC, x86_64) + - AIX (POWER) + - Tru64 (Alpha) + - IRIX (MIPS) + - Novell NetWare (i386) Useful URLs =========== - c-ares: https://c-ares.org/ - - MingW: http://www.mingw.org/ - MinGW-w64: http://mingw-w64.sourceforge.net/ + - MSYS2: https://msys2.org - OpenWatcom: http://www.openwatcom.org/ diff --git a/contrib/libs/c-ares/LICENSE.md b/contrib/libs/c-ares/LICENSE.md index e27bae933f..910ddded5c 100644 --- a/contrib/libs/c-ares/LICENSE.md +++ b/contrib/libs/c-ares/LICENSE.md @@ -1,5 +1,3 @@ -# c-ares license - MIT License Copyright (c) 1998 Massachusetts Institute of Technology diff --git a/contrib/libs/c-ares/NEWS b/contrib/libs/c-ares/NEWS deleted file mode 100644 index 95a2eeea27..0000000000 --- a/contrib/libs/c-ares/NEWS +++ /dev/null @@ -1,21 +0,0 @@ -Major changes since: -* see the CHANGES file - -Major changes in release 1.1.1: -* ares should now compile as C++ code (no longer uses reserved word - "class"). -* Added SRV support to adig test program. -* Fixed a few error handling bugs in query processing. - -Major changes in release 1.1.0: -* Added ares_free_string() function so that memory can be freed in the - same layer as it is allocated, a desirable feature in some - environments. -* A few of the ares_dns.h macros are fixed to use the proper bitwise - operator. -* Fixed a couple of fenceposts fixed in ares_expand_name()'s - bounds-checking. -* In process_timeouts(), extract query->next before calling - next_server() and possibly freeing the query structure. -* Casted arguments to ctype macros casted to unsigned char, since not - all char values are valid inputs to those macros according to ANSI. diff --git a/contrib/libs/c-ares/README.cares b/contrib/libs/c-ares/README.cares deleted file mode 100644 index ec809ab948..0000000000 --- a/contrib/libs/c-ares/README.cares +++ /dev/null @@ -1,15 +0,0 @@ -c-ares -====== - -This package is based on ares 1.1.1 (written by Greg Hudson). Daniel Stenberg -decided to fork and release a separate project since the original ares author -didn't want the improvements that were vital for our use of it. - -This package is dubbed 'c-ares' since Daniel wanted this for use within the -curl project (hence the letter C) and it makes a nice pun. c-ares is not API -compatible with ares: a new name makes that more obvious to the public. - -The original libares was distributed at -ftp://athena-dist.mit.edu:pub/ATHENA/ares (which seems to not be alive -anymore). A local copy of the original ares package is kept here: -https://c-ares.org/download/ares-1.1.1.tar.gz diff --git a/contrib/libs/c-ares/README.md b/contrib/libs/c-ares/README.md index 5e022a85c1..c32d0677c8 100644 --- a/contrib/libs/c-ares/README.md +++ b/contrib/libs/c-ares/README.md @@ -2,12 +2,20 @@ [![Build Status](https://api.cirrus-ci.com/github/c-ares/c-ares.svg?branch=main)](https://cirrus-ci.com/github/c-ares/c-ares) [![Windows Build Status](https://ci.appveyor.com/api/projects/status/aevgc5914tm72pvs/branch/main?svg=true)](https://ci.appveyor.com/project/c-ares/c-ares/branch/main) -[![Coverage Status](https://coveralls.io/repos/github/c-ares/c-ares/badge.svg)](https://coveralls.io/github/c-ares/c-ares) +[![Coverage Status](https://coveralls.io/repos/github/c-ares/c-ares/badge.svg?branch=main)](https://coveralls.io/github/c-ares/c-ares?branch=main) [![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/291/badge)](https://bestpractices.coreinfrastructure.org/projects/291) [![Fuzzing Status](https://oss-fuzz-build-logs.storage.googleapis.com/badges/c-ares.svg)](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:c-ares) [![Bugs](https://sonarcloud.io/api/project_badges/measure?project=c-ares_c-ares&metric=bugs)](https://sonarcloud.io/summary/new_code?id=c-ares_c-ares) [![Coverity Scan Status](https://scan.coverity.com/projects/c-ares/badge.svg)](https://scan.coverity.com/projects/c-ares) +- [Overview](#overview) +- [Code](#code) +- [Communication](#communication) +- [Release Keys](#release-keys) + - [Verifying signatures](#verifying-signatures) +- [Features](#features) + - [RFCs and Proposals](#supported-rfcs-and-proposals) + ## Overview [c-ares](https://c-ares.org) is a modern DNS (stub) resolver library, written in C. It provides interfaces for asynchronous queries while trying to abstract the @@ -39,7 +47,7 @@ best practices in regards to C coding standards. The full source code and revision history is available in our [GitHub repository](https://github.com/c-ares/c-ares). Our signed releases -are available in the ['c-ares' release archives](https://c-ares.org/download/). +are available in the [release archives](https://c-ares.org/download/). See the [INSTALL.md](INSTALL.md) file for build information. @@ -99,3 +107,47 @@ gpg: There is no indication that the signature belongs to the owner. Primary key fingerprint: 27ED EAF2 2F3A BCEB 50DB 9A12 5CC9 08FD B71E 12C2 gpg: binary signature, digest algorithm SHA512, key algorithm rsa2048 ``` + +## Features +### Supported RFCs and Proposals +- [RFC1035](https://datatracker.ietf.org/doc/html/rfc7873). + Initial/Base DNS RFC +- [RFC2671](https://datatracker.ietf.org/doc/html/rfc2671), + [RFC6891](https://datatracker.ietf.org/doc/html/rfc6891). + EDNS0 option (meta-RR) +- [RFC3596](https://datatracker.ietf.org/doc/html/rfc3596). + IPv6 Address. `AAAA` Record. +- [RFC2782](https://datatracker.ietf.org/doc/html/rfc2782). + Server Selection. `SRV` Record. +- [RFC3403](https://datatracker.ietf.org/doc/html/rfc3403). + Naming Authority Pointer. `NAPTR` Record. +- [RFC6698](https://datatracker.ietf.org/doc/html/rfc6698). + DNS-Based Authentication of Named Entities (DANE) Transport Layer Security (TLS) Protocol. + `TLSA` Record. +- [RFC9460](https://datatracker.ietf.org/doc/html/rfc9460). + General Purpose Service Binding, Service Binding type for use with HTTPS. + `SVCB` and `HTTPS` Records. +- [RFC7553](https://datatracker.ietf.org/doc/html/rfc7553). + Uniform Resource Identifier. `URI` Record. +- [RFC6844](https://datatracker.ietf.org/doc/html/rfc6844). + Certification Authority Authorization. `CAA` Record. +- [RFC2535](https://datatracker.ietf.org/doc/html/rfc2535), + [RFC2931](https://datatracker.ietf.org/doc/html/rfc2931). + `SIG0` Record. Only basic parser, not full implementation. +- [RFC7873](https://datatracker.ietf.org/doc/html/rfc7873), + [RFC9018](https://datatracker.ietf.org/doc/html/rfc9018). + DNS Cookie off-path dns poisoning and amplification mitigation. +- [draft-vixie-dnsext-dns0x20-00](https://datatracker.ietf.org/doc/html/draft-vixie-dnsext-dns0x20-00). + DNS 0x20 query name case randomization to prevent cache poisioning attacks. +- [RFC7686](https://datatracker.ietf.org/doc/html/rfc7686). + Reject queries for `.onion` domain names with `NXDOMAIN`. +- [RFC2606](https://datatracker.ietf.org/doc/html/rfc2606), + [RFC6761](https://datatracker.ietf.org/doc/html/rfc6761). + Special case treatment for `localhost`/`.localhost`. +- [RFC2308](https://datatracker.ietf.org/doc/html/rfc2308), + [RFC9520](https://datatracker.ietf.org/doc/html/rfc9520). + Negative Caching of DNS Resolution Failures. +- [RFC6724](https://datatracker.ietf.org/doc/html/rfc6724). + IPv6 address sorting as used by `ares_getaddrinfo()`. +- [RFC7413](https://datatracker.ietf.org/doc/html/rfc7413). + TCP FastOpen (TFO) for 0-RTT TCP Connection Resumption. diff --git a/contrib/libs/c-ares/RELEASE-NOTES.md b/contrib/libs/c-ares/RELEASE-NOTES.md index 7d30a3d4e7..b072feb29f 100644 --- a/contrib/libs/c-ares/RELEASE-NOTES.md +++ b/contrib/libs/c-ares/RELEASE-NOTES.md @@ -1,33 +1,33 @@ -## c-ares version 1.30.0 - June 7 2024 +## c-ares version 1.33.0 - August 2 2024 -This is a maintenance and bugfix release. +This is a feature and bugfix release. Features: - -* Basic support for SIG RR record (RFC 2931 / RFC 2535) [PR #773](https://github.com/c-ares/c-ares/pull/773) +* Add DNS cookie support (RFC7873 + RFC9018) to help prevent off-path cache + poisoning attacks. [PR #833](https://github.com/c-ares/c-ares/pull/833) +* Implement TCP FastOpen (TFO) RFC7413, which will make TCP reconnects 0-RTT + on supported systems. [PR #840](https://github.com/c-ares/c-ares/pull/840) Changes: - -* Validation that DNS strings can only consist of printable ascii characters - otherwise will trigger a parse failure. - [75de16c](https://github.com/c-ares/c-ares/commit/75de16c) and - [40fb125](https://github.com/c-ares/c-ares/commit/40fb125) -* Windows: use `GetTickCount64()` for a monotonic timer that does not wrap. [1dff8f6](https://github.com/c-ares/c-ares/commit/1dff8f6) +* Reorganize source tree. [PR #822](https://github.com/c-ares/c-ares/pull/822) +* Refactoring of connection handling to prevent code duplication. + [PR #839](https://github.com/c-ares/c-ares/pull/839) +* New dynamic array data structure to prevent simple logic flaws in array + handling in various code paths. + [PR #841](https://github.com/c-ares/c-ares/pull/841) Bugfixes: +* `ares_destroy()` race condition during shutdown due to missing lock. + [PR #831](https://github.com/c-ares/c-ares/pull/831) +* Android: Preserve thread name after attaching it to JVM. + [PR #838](https://github.com/c-ares/c-ares/pull/838) +* Windows UWP (Store) support fix. + [PR #845](https://github.com/c-ares/c-ares/pull/845) -* QueryCache: Fix issue where purging on server changes wasn't working. [a6c8fe6](https://github.com/c-ares/c-ares/commit/a6c8fe6) -* Windows: Fix Y2K38 issue by creating our own `ares_timeval_t` datatype. [PR #772](https://github.com/c-ares/c-ares/pull/772) -* Fix packaging issue affecting MacOS due to a missing header. [55afad6](https://github.com/c-ares/c-ares/commit/55afad6) -* MacOS: Fix UBSAN warnings that are likely meaningless due to alignment issues - in new MacOS config reader. -* Android: arm 32bit build failure due to missing symbol. [d1722e6](https://github.com/c-ares/c-ares/commit/d1722e6) Thanks go to these friendly people for their efforts and contributions for this release: * Brad House (@bradh352) -* Daniel Stenberg (@bagder) - - +* Yauheni Khnykin (@Hsilgos) diff --git a/contrib/libs/c-ares/RELEASE-PROCEDURE.md b/contrib/libs/c-ares/RELEASE-PROCEDURE.md index 1abc9a3822..c686a9f97b 100644 --- a/contrib/libs/c-ares/RELEASE-PROCEDURE.md +++ b/contrib/libs/c-ares/RELEASE-PROCEDURE.md @@ -4,49 +4,74 @@ c-ares release procedure - how to do a release in the source code repo ----------------------- -- edit `RELEASE-NOTES` to be accurate - +- edit `RELEASE-NOTES.md` to be accurate - edit `configure.ac`'s `CARES_VERSION_INFO`, and `CMakeLists.txt`'s `CARES_LIB_VERSIONINFO` set to the same value to denote the current shared object versioning. - - edit `include/ares_version.h` and set `ARES_VERSION_*` definitions to reflect the current version. - -- make sure all relevant changes are committed on the master branch - -- tag the git repo in this style: `git tag -a cares-1_14_0` -a annotates the - tag and we use underscores instead of dots in the version number. - -- run "./maketgz 1.14.0" to build the release tarball. It is important that - you run this on a machine with the correct set of autotools etc installed - as this is what then will be shipped and used by most users on *nix like - systems. - -- push the git commits and the new tag - -- gpg sign the tarball - -- upload the resulting files to https://c-ares.org/download/ +- All release tags need to be made off a release branch named `vX.Y`, where `X` + is the Major version number, and `Y` is the minor version number. We also + want to create an empty commit in the branch with a message, this ensures + when we tag a release from the branch, it gets tied to the branch itself and + not a commit which may be shared across this branch and `main`. Create the + branch like: +``` +BRANCH=1.32 +git pull && \ +git checkout main && \ +git checkout -b v${BRANCH} main && \ +git commit --allow-empty -m "Created release branch v${BRANCH}" && \ +git push -u origin v${BRANCH} +``` +- make sure all relevant changes are committed on the release branch +- Create a signed tag for the release using a name of `vX.Y.Z` where `X` is the + Major version number, `Y` is the minor version number, and `Z` is the release. + This tag needs to be created from the release branch, for example: +``` +BRANCH=1.32 +RELEASE=1.32.0 +git checkout v${BRANCH} && \ +git pull && \ +git tag -s v${RELEASE} -m 'c-ares release v${RELEASE}' v${BRANCH} && \ +git push origin --tags +``` +- Create the release tarball using `make dist`, it is best to check out the + specific tag fresh and build from that: +``` +RELEASE=1.32.0 +git clone --depth 1 --branch v${RELEASE} https://github.com/c-ares/c-ares c-ares-${RELEASE} && \ +cd c-ares-${RELEASE} && \ +autoreconf -fi && \ +./configure && \ +make && \ +make dist VERSION=${RELEASE} +``` +- GPG sign the release with a detached signature. Valid signing keys are currently: + - Daniel Stenberg <daniel@haxx.se> - 27EDEAF22F3ABCEB50DB9A125CC908FDB71E12C2 + - Brad House <brad@brad-house.com> - DA7D64E4C82C6294CB73A20E22E3D13B5411B7CA +``` +gpg -ab c-ares-${RELEASE}.tar.gz +``` +- Create a new release on GitHub using the `RELEASE-NOTES.md` as the body. + Upload the generated tarball and signature as an artifact. in the c-ares-www repo ---------------------- -- edit `index.t` (version number and date), - -- edit `changelog.t` (add the new release in there) - +- edit `index.md`, change version and date in frontmatter +- edit `changelog.md`, copy `RELEASE-NOTES.md` content +- edit `download.md`, add new version and date in frontmatter - commit all local changes - -- tag the repo with the same tag as used for the source repo - -- push the git commits and the new tag +- push the git commits inform ------ -- send an email to the c-ares mailing list. Insert the RELEASE-NOTES into the +- send an email to the c-ares mailing list. Insert the RELEASE-NOTES.md into the mail. +- Create an announcement in the GitHub Discussions Announcements section: + https://github.com/c-ares/c-ares/discussions/categories/announcements celebrate --------- diff --git a/contrib/libs/c-ares/include/ares.h b/contrib/libs/c-ares/include/ares.h index 46cdf9fa8e..adb2fe8419 100644 --- a/contrib/libs/c-ares/include/ares.h +++ b/contrib/libs/c-ares/include/ares.h @@ -30,18 +30,43 @@ #include "ares_version.h" /* c-ares version defines */ #include "ares_build.h" /* c-ares build definitions */ -#include "ares_rules.h" /* c-ares rules enforcement */ -/* - * Define WIN32 when build target is Win32 API - */ +#if defined(_WIN32) +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# endif +#endif + +#ifdef CARES_HAVE_SYS_TYPES_H +# include <sys/types.h> +#endif + +#ifdef CARES_HAVE_SYS_SOCKET_H +# include <sys/socket.h> +#endif + +#ifdef CARES_HAVE_SYS_SELECT_H +# include <sys/select.h> +#endif -#if (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32) && \ - !defined(__SYMBIAN32__) -# define WIN32 +#ifdef CARES_HAVE_WINSOCK2_H +# include <winsock2.h> +/* To aid with linking against a static c-ares build, lets tell the microsoft + * compiler to pull in needed dependencies */ +# ifdef _MSC_VER +# pragma comment(lib, "ws2_32") +# pragma comment(lib, "advapi32") +# pragma comment(lib, "iphlpapi") +# endif +#endif + +#ifdef CARES_HAVE_WS2TCPIP_H +# include <ws2tcpip.h> #endif -#include <sys/types.h> +#ifdef CARES_HAVE_WINDOWS_H +# include <windows.h> +#endif /* HP-UX systems version 9, 10 and 11 lack sys/select.h and so does oldish libc5-based Linux systems. Only include it on system that are known to @@ -52,43 +77,26 @@ defined(__QNXNTO__) || defined(__MVS__) || defined(__HAIKU__) # include <sys/select.h> #endif + #if (defined(NETWARE) && !defined(__NOVELL_LIBC__)) # include <sys/bsdskt.h> #endif -#if defined(WATT32) +#if !defined(_WIN32) # include <netinet/in.h> -# include <sys/socket.h> +#endif + +#ifdef WATT32 # include <tcp.h> -#elif defined(_WIN32_WCE) -# ifndef WIN32_LEAN_AND_MEAN -# define WIN32_LEAN_AND_MEAN -# endif -# include <windows.h> -# include <winsock.h> -#elif defined(WIN32) -# ifndef WIN32_LEAN_AND_MEAN -# define WIN32_LEAN_AND_MEAN -# endif -# include <windows.h> -# include <winsock2.h> -# include <ws2tcpip.h> -/* To aid with linking against a static c-ares build, lets tell the microsoft - * compiler to pull in needed dependencies */ -# ifdef _MSC_VER -# pragma comment(lib, "ws2_32") -# pragma comment(lib, "advapi32") -# pragma comment(lib, "iphlpapi") -# endif -#else -# include <sys/socket.h> -# include <netinet/in.h> #endif #if defined(ANDROID) || defined(__ANDROID__) # include <jni.h> #endif +typedef CARES_TYPEOF_ARES_SOCKLEN_T ares_socklen_t; +typedef CARES_TYPEOF_ARES_SSIZE_T ares_ssize_t; + #ifdef __cplusplus extern "C" { #endif @@ -230,6 +238,7 @@ typedef enum { #define ARES_FLAG_NOCHECKRESP (1 << 7) #define ARES_FLAG_EDNS (1 << 8) #define ARES_FLAG_NO_DFLT_SVR (1 << 9) +#define ARES_FLAG_DNS0x20 (1 << 10) /* Option mask values */ #define ARES_OPT_FLAGS (1 << 0) @@ -315,7 +324,7 @@ typedef enum { */ #ifndef ares_socket_typedef -# ifdef WIN32 +# if defined(_WIN32) && !defined(WATT32) typedef SOCKET ares_socket_t; # define ARES_SOCKET_BAD INVALID_SOCKET # else diff --git a/contrib/libs/c-ares/include/ares_build-linux.h b/contrib/libs/c-ares/include/ares_build-linux.h index bf3692fbbe..25bf2193b8 100644 --- a/contrib/libs/c-ares/include/ares_build-linux.h +++ b/contrib/libs/c-ares/include/ares_build-linux.h @@ -13,10 +13,10 @@ * for C-Ares */ #define CARES_HAVE_SYS_TYPES_H #define CARES_HAVE_SYS_SOCKET_H +#define CARES_HAVE_SYS_SELECT_H /* #undef CARES_HAVE_WINDOWS_H */ /* #undef CARES_HAVE_WS2TCPIP_H */ /* #undef CARES_HAVE_WINSOCK2_H */ -/* #undef CARES_HAVE_WINDOWS_H */ #define CARES_HAVE_ARPA_NAMESER_H #define CARES_HAVE_ARPA_NAMESER_COMPAT_H @@ -28,6 +28,10 @@ # include <sys/socket.h> #endif +#ifdef CARES_HAVE_SYS_SELECT_H +# include <sys/select.h> +#endif + #ifdef CARES_HAVE_WINSOCK2_H # include <winsock2.h> #endif @@ -40,8 +44,4 @@ # include <windows.h> #endif - -typedef CARES_TYPEOF_ARES_SOCKLEN_T ares_socklen_t; -typedef CARES_TYPEOF_ARES_SSIZE_T ares_ssize_t; - #endif /* __CARES_BUILD_H */ diff --git a/contrib/libs/c-ares/include/ares_dns_record.h b/contrib/libs/c-ares/include/ares_dns_record.h index 5533929f65..2896eab24b 100644 --- a/contrib/libs/c-ares/include/ares_dns_record.h +++ b/contrib/libs/c-ares/include/ares_dns_record.h @@ -94,7 +94,7 @@ typedef enum { ARES_OPCODE_IQUERY = 1, /*!< Inverse query. Obsolete. */ ARES_OPCODE_STATUS = 2, /*!< Name server status query */ ARES_OPCODE_NOTIFY = 4, /*!< Zone change notification (RFC 1996) */ - ARES_OPCODE_UPDATE = 5, /*!< Zone update message (RFC2136) */ + ARES_OPCODE_UPDATE = 5 /*!< Zone update message (RFC2136) */ } ares_dns_opcode_t; /*! DNS Header flags */ @@ -108,7 +108,7 @@ typedef enum { ARES_FLAG_AD = 1 << 5, /*!< RFC 2065. Authentic Data bit indicates in a * response that the data included has been verified by * the server providing it */ - ARES_FLAG_CD = 1 << 6, /*!< RFC 2065. Checking Disabled bit indicates in a + ARES_FLAG_CD = 1 << 6 /*!< RFC 2065. Checking Disabled bit indicates in a * query that non-verified data is acceptable to the * resolver sending the query. */ } ares_dns_flags_t; @@ -152,7 +152,7 @@ typedef enum { ARES_RCODE_BADNAME = 20, /*!< RFC 2930. Duplicate Key Name */ ARES_RCODE_BADALG = 21, /*!< RFC 2930. Algorithm not supported */ ARES_RCODE_BADTRUNC = 22, /*!< RFC 8945. Bad Truncation */ - ARES_RCODE_BADCOOKIE = 23, /*!< RVC 7973. Bad/missing Server Cookie */ + ARES_RCODE_BADCOOKIE = 23 /*!< RFC 7873. Bad/missing Server Cookie */ } ares_dns_rcode_t; /*! Data types used */ @@ -171,6 +171,9 @@ typedef enum { * length) */ ARES_DATATYPE_OPT = 10, /*!< Array of options. 16bit identifier, BIN * data. */ + ARES_DATATYPE_ABINP = 11 /*!< Array of binary data, likely printable. + * Guaranteed to have a NULL terminator for + * convenience (not included in length) */ } ares_dns_datatype_t; /*! Keys used for all RR Types. We take the record type and multiply by 100 @@ -207,7 +210,7 @@ typedef enum { ARES_RR_MX_PREFERENCE = (ARES_REC_TYPE_MX * 100) + 1, /*! MX Record. Exchange, domain. Datatype: NAME */ ARES_RR_MX_EXCHANGE = (ARES_REC_TYPE_MX * 100) + 2, - /*! TXT Record. Data. Datatype: BINP */ + /*! TXT Record. Data. Datatype: ABINP */ ARES_RR_TXT_DATA = (ARES_REC_TYPE_TXT * 100) + 1, /*! SIG Record. Type Covered. Datatype: U16 */ ARES_RR_SIG_TYPE_COVERED = (ARES_REC_TYPE_SIG * 100) + 1, @@ -292,7 +295,7 @@ typedef enum { /*! RAW Record. RR Type. Datatype: U16 */ ARES_RR_RAW_RR_TYPE = (ARES_REC_TYPE_RAW_RR * 100) + 1, /*! RAW Record. RR Data. Datatype: BIN */ - ARES_RR_RAW_RR_DATA = (ARES_REC_TYPE_RAW_RR * 100) + 2, + ARES_RR_RAW_RR_DATA = (ARES_REC_TYPE_RAW_RR * 100) + 2 } ares_dns_rr_key_t; /*! TLSA Record ARES_RR_TLSA_CERT_USAGE known values */ @@ -372,7 +375,7 @@ typedef enum { /*! RFC 8145. Signaling Trust Anchor Knowledge in DNSSEC */ ARES_OPT_PARAM_EDNS_KEY_TAG = 14, /*! RFC 8914. Extended ERROR code and message */ - ARES_OPT_PARAM_EXTENDED_DNS_ERROR = 15, + ARES_OPT_PARAM_EXTENDED_DNS_ERROR = 15 } ares_opt_param_t; /*! Data type for option records for keys like ARES_RR_OPT_OPTIONS and @@ -600,6 +603,15 @@ CARES_EXTERN void ares_dns_record_destroy(ares_dns_record_t *dnsrec); CARES_EXTERN unsigned short ares_dns_record_get_id(const ares_dns_record_t *dnsrec); +/*! Overwrite the DNS query id + * + * \param[in] dnsrec Initialized record object + * \param[in] id DNS query id + * \return ARES_TRUE on success, ARES_FALSE on usage error + */ +CARES_EXTERN ares_bool_t ares_dns_record_set_id(ares_dns_record_t *dnsrec, + unsigned short id); + /*! Get the DNS Record Flags * * \param[in] dnsrec Initialized record object @@ -863,6 +875,34 @@ CARES_EXTERN ares_status_t ares_dns_rr_set_bin(ares_dns_rr_t *dns_rr, const unsigned char *val, size_t len); +/*! Add binary array value (ABINP) data for specified resource record and key. + * Can only be used on keys with datatype ARES_DATATYPE_ABINP. The value will + * Be added as the last element in the array. + * + * \param[in] dns_rr Pointer to resource record + * \param[in] key DNS Resource Record Key + * \param[in] val Pointer to binary data. + * \param[in] len Length of binary data + * \return ARES_SUCCESS on success + */ +CARES_EXTERN ares_status_t ares_dns_rr_add_abin(ares_dns_rr_t *dns_rr, + ares_dns_rr_key_t key, + const unsigned char *val, + size_t len); + +/*! Delete binary array value (ABINP) data for specified resource record and + * key by specified index. Can only be used on keys with datatype + * ARES_DATATYPE_ABINP. The value at the index will be deleted. + * + * \param[in] dns_rr Pointer to resource record + * \param[in] key DNS Resource Record Key + * \param[in] idx Index to delete + * \return ARES_SUCCESS on success + */ +CARES_EXTERN ares_status_t ares_dns_rr_del_abin(ares_dns_rr_t *dns_rr, + ares_dns_rr_key_t key, + size_t idx); + /*! Set the option for the RR * * \param[in] dns_rr Pointer to resource record @@ -878,6 +918,17 @@ CARES_EXTERN ares_status_t ares_dns_rr_set_opt(ares_dns_rr_t *dns_rr, const unsigned char *val, size_t val_len); +/*! Delete the option for the RR by id + * + * \param[in] dns_rr Pointer to resource record + * \param[in] key DNS Resource Record Key + * \param[in] opt Option record key id. + * \return ARES_SUCCESS if removed, ARES_ENOTFOUND if not found + */ +CARES_EXTERN ares_status_t ares_dns_rr_del_opt_byid(ares_dns_rr_t *dns_rr, + ares_dns_rr_key_t key, + unsigned short opt); + /*! Retrieve a pointer to the ipv4 address. Can only be used on keys with * datatype ARES_DATATYPE_INADDR. * @@ -939,8 +990,9 @@ CARES_EXTERN unsigned int ares_dns_rr_get_u32(const ares_dns_rr_t *dns_rr, ares_dns_rr_key_t key); /*! Retrieve a pointer to the binary data. Can only be used on keys with - * datatype ARES_DATATYPE_BIN or ARES_DATATYPE_BINP. If BINP, the data is - * guaranteed to have a NULL terminator which is NOT included in the length. + * datatype ARES_DATATYPE_BIN, ARES_DATATYPE_BINP, or ARES_DATATYPE_ABINP. + * If BINP or ABINP, the data is guaranteed to have a NULL terminator which + * is NOT included in the length. * * \param[in] dns_rr Pointer to resource record * \param[in] key DNS Resource Record Key @@ -951,6 +1003,33 @@ CARES_EXTERN const unsigned char * ares_dns_rr_get_bin(const ares_dns_rr_t *dns_rr, ares_dns_rr_key_t key, size_t *len); +/*! Retrieve the count of the array of stored binary values. Can only be used on + * keys with datatype ARES_DATATYPE_ABINP. + * + * \param[in] dns_rr Pointer to resource record + * \param[in] key DNS Resource Record Key + * \return count of values + */ +CARES_EXTERN size_t ares_dns_rr_get_abin_cnt(const ares_dns_rr_t *dns_rr, + ares_dns_rr_key_t key); + +/*! Retrieve a pointer to the binary array data from the specified index. Can + * only be used on keys with datatype ARES_DATATYPE_ABINP. If ABINP, the data + * is guaranteed to have a NULL terminator which is NOT included in the length. + * If want all array membersconcatenated, may use ares_dns_rr_get_bin() + * instead. + * + * \param[in] dns_rr Pointer to resource record + * \param[in] key DNS Resource Record Key + * \param[in] idx Index of value to retrieve + * \param[out] len Length of binary data returned + * \return pointer binary data or NULL on error + */ +CARES_EXTERN const unsigned char * + ares_dns_rr_get_abin(const ares_dns_rr_t *dns_rr, ares_dns_rr_key_t key, + size_t idx, size_t *len); + + /*! Retrieve the number of options stored for the RR. * * \param[in] dns_rr Pointer to resource record diff --git a/contrib/libs/c-ares/include/ares_rules.h b/contrib/libs/c-ares/include/ares_rules.h deleted file mode 100644 index 450dc8ab2d..0000000000 --- a/contrib/libs/c-ares/include/ares_rules.h +++ /dev/null @@ -1,133 +0,0 @@ -/* MIT License - * - * Copyright (c) 2009 Daniel Stenberg - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * SPDX-License-Identifier: MIT - */ -#ifndef __CARES_RULES_H -#define __CARES_RULES_H - -/* ================================================================ */ -/* COMPILE TIME SANITY CHECKS */ -/* ================================================================ */ - -/* - * NOTE 1: - * ------- - * - * All checks done in this file are intentionally placed in a public - * header file which is pulled by ares.h when an application is - * being built using an already built c-ares library. Additionally - * this file is also included and used when building the library. - * - * If compilation fails on this file it is certainly sure that the - * problem is elsewhere. It could be a problem in the ares_build.h - * header file, or simply that you are using different compilation - * settings than those used to build the library. - * - * Nothing in this file is intended to be modified or adjusted by the - * c-ares library user nor by the c-ares library builder. - * - * Do not deactivate any check, these are done to make sure that the - * library is properly built and used. - * - * You can find further help on the c-ares development mailing list: - * http://lists.haxx.se/listinfo/c-ares/ - * - * NOTE 2 - * ------ - * - * Some of the following compile time checks are based on the fact - * that the dimension of a constant array can not be a negative one. - * In this way if the compile time verification fails, the compilation - * will fail issuing an error. The error description wording is compiler - * dependent but it will be quite similar to one of the following: - * - * "negative subscript or subscript is too large" - * "array must have at least one element" - * "-1 is an illegal array size" - * "size of array is negative" - * - * If you are building an application which tries to use an already - * built c-ares library and you are getting this kind of errors on - * this file, it is a clear indication that there is a mismatch between - * how the library was built and how you are trying to use it for your - * application. Your already compiled or binary library provider is the - * only one who can give you the details you need to properly use it. - */ - -/* - * Verify that some macros are actually defined. - */ - -#ifndef CARES_TYPEOF_ARES_SOCKLEN_T -# error "CARES_TYPEOF_ARES_SOCKLEN_T definition is missing!" -Error Compilation_aborted_CARES_TYPEOF_ARES_SOCKLEN_T_is_missing -#endif - -/* - * Macros private to this header file. - */ - -#define CareschkszEQ(t, s) sizeof(t) == s ? 1 : -1 - -#define CareschkszGE(t1, t2) sizeof(t1) >= sizeof(t2) ? 1 : -1 - - /* - * Verify that the size previously defined and expected for - * ares_socklen_t is actually the same as the one reported - * by sizeof() at compile time. - */ - - typedef char __cares_rule_02__[CareschkszEQ( - ares_socklen_t, sizeof(CARES_TYPEOF_ARES_SOCKLEN_T))]; - -/* - * Verify at compile time that the size of ares_socklen_t as reported - * by sizeof() is greater or equal than the one reported for int for - * the current compilation. - */ - -typedef char __cares_rule_03__[CareschkszGE(ares_socklen_t, int)]; - -/* ================================================================ */ -/* EXTERNALLY AND INTERNALLY VISIBLE DEFINITIONS */ -/* ================================================================ */ - -/* - * Get rid of macros private to this header file. - */ - -#undef CareschkszEQ -#undef CareschkszGE - -/* - * Get rid of macros not intended to exist beyond this point. - */ - -#undef CARES_PULL_WS2TCPIP_H -#undef CARES_PULL_SYS_TYPES_H -#undef CARES_PULL_SYS_SOCKET_H - -#undef CARES_TYPEOF_ARES_SOCKLEN_T - -#endif /* __CARES_RULES_H */ diff --git a/contrib/libs/c-ares/include/ares_version.h b/contrib/libs/c-ares/include/ares_version.h index e791568e6b..fef66b7397 100644 --- a/contrib/libs/c-ares/include/ares_version.h +++ b/contrib/libs/c-ares/include/ares_version.h @@ -31,19 +31,14 @@ #define ARES_COPYRIGHT "2004 - 2024 Daniel Stenberg, <daniel@haxx.se>." #define ARES_VERSION_MAJOR 1 -#define ARES_VERSION_MINOR 30 +#define ARES_VERSION_MINOR 33 #define ARES_VERSION_PATCH 0 #define ARES_VERSION \ ((ARES_VERSION_MAJOR << 16) | (ARES_VERSION_MINOR << 8) | \ (ARES_VERSION_PATCH)) -#define ARES_VERSION_STR "1.30.0" +#define ARES_VERSION_STR "1.33.0" -#if (ARES_VERSION >= 0x010700) -# define CARES_HAVE_ARES_LIBRARY_INIT 1 -# define CARES_HAVE_ARES_LIBRARY_CLEANUP 1 -#else -# undef CARES_HAVE_ARES_LIBRARY_INIT -# undef CARES_HAVE_ARES_LIBRARY_CLEANUP -#endif +#define CARES_HAVE_ARES_LIBRARY_INIT 1 +#define CARES_HAVE_ARES_LIBRARY_CLEANUP 1 #endif diff --git a/contrib/libs/c-ares/src/lib/ares__addrinfo2hostent.c b/contrib/libs/c-ares/src/lib/ares__addrinfo2hostent.c index 95717890c2..f7b6d1edd2 100644 --- a/contrib/libs/c-ares/src/lib/ares__addrinfo2hostent.c +++ b/contrib/libs/c-ares/src/lib/ares__addrinfo2hostent.c @@ -27,7 +27,7 @@ * SPDX-License-Identifier: MIT */ -#include "ares_setup.h" +#include "ares_private.h" #ifdef HAVE_NETINET_IN_H # include <netinet/in.h> @@ -39,8 +39,6 @@ # include <arpa/inet.h> #endif -#include "ares_nameser.h" - #ifdef HAVE_STRINGS_H # include <strings.h> #endif @@ -49,10 +47,6 @@ # include <limits.h> #endif -#include "ares.h" -#include "ares_dns.h" -#include "ares_inet_net_pton.h" -#include "ares_private.h" ares_status_t ares__addrinfo2hostent(const struct ares_addrinfo *ai, int family, struct hostent **host) @@ -67,7 +61,7 @@ ares_status_t ares__addrinfo2hostent(const struct ares_addrinfo *ai, int family, size_t i; if (ai == NULL || host == NULL) { - return ARES_EBADQUERY; + return ARES_EBADQUERY; /* LCOV_EXCL_LINE: DefensiveCoding */ } /* Use the first node of the response as the family, since hostent can only @@ -78,12 +72,12 @@ ares_status_t ares__addrinfo2hostent(const struct ares_addrinfo *ai, int family, } if (family != AF_INET && family != AF_INET6) { - return ARES_EBADQUERY; + return ARES_EBADQUERY; /* LCOV_EXCL_LINE: DefensiveCoding */ } *host = ares_malloc(sizeof(**host)); if (!(*host)) { - goto enomem; + goto enomem; /* LCOV_EXCL_LINE: OutOfMemory */ } memset(*host, 0, sizeof(**host)); @@ -105,7 +99,7 @@ ares_status_t ares__addrinfo2hostent(const struct ares_addrinfo *ai, int family, aliases = ares_malloc((naliases + 1) * sizeof(char *)); if (!aliases) { - goto enomem; + goto enomem; /* LCOV_EXCL_LINE: OutOfMemory */ } (*host)->h_aliases = aliases; memset(aliases, 0, (naliases + 1) * sizeof(char *)); @@ -118,7 +112,7 @@ ares_status_t ares__addrinfo2hostent(const struct ares_addrinfo *ai, int family, } aliases[alias] = ares_strdup(next_cname->alias); if (!aliases[alias]) { - goto enomem; + goto enomem; /* LCOV_EXCL_LINE: OutOfMemory */ } alias++; } @@ -127,7 +121,7 @@ ares_status_t ares__addrinfo2hostent(const struct ares_addrinfo *ai, int family, (*host)->h_addr_list = ares_malloc((naddrs + 1) * sizeof(char *)); if (!(*host)->h_addr_list) { - goto enomem; + goto enomem; /* LCOV_EXCL_LINE: OutOfMemory */ } memset((*host)->h_addr_list, 0, (naddrs + 1) * sizeof(char *)); @@ -135,12 +129,12 @@ ares_status_t ares__addrinfo2hostent(const struct ares_addrinfo *ai, int family, if (ai->cnames) { (*host)->h_name = ares_strdup(ai->cnames->name); if ((*host)->h_name == NULL && ai->cnames->name) { - goto enomem; + goto enomem; /* LCOV_EXCL_LINE: OutOfMemory */ } } else { (*host)->h_name = ares_strdup(ai->name); if ((*host)->h_name == NULL && ai->name) { - goto enomem; + goto enomem; /* LCOV_EXCL_LINE: OutOfMemory */ } } @@ -157,7 +151,7 @@ ares_status_t ares__addrinfo2hostent(const struct ares_addrinfo *ai, int family, if (naddrs) { addrs = ares_malloc(naddrs * (size_t)(*host)->h_length); if (!addrs) { - goto enomem; + goto enomem; /* LCOV_EXCL_LINE: OutOfMemory */ } i = 0; @@ -167,16 +161,16 @@ ares_status_t ares__addrinfo2hostent(const struct ares_addrinfo *ai, int family, } (*host)->h_addr_list[i] = addrs + (i * (size_t)(*host)->h_length); if (family == AF_INET6) { - memcpy( - (*host)->h_addr_list[i], - &(CARES_INADDR_CAST(struct sockaddr_in6 *, next->ai_addr)->sin6_addr), - (size_t)(*host)->h_length); + memcpy((*host)->h_addr_list[i], + &(CARES_INADDR_CAST(const struct sockaddr_in6 *, next->ai_addr) + ->sin6_addr), + (size_t)(*host)->h_length); } if (family == AF_INET) { - memcpy( - (*host)->h_addr_list[i], - &(CARES_INADDR_CAST(struct sockaddr_in *, next->ai_addr)->sin_addr), - (size_t)(*host)->h_length); + memcpy((*host)->h_addr_list[i], + &(CARES_INADDR_CAST(const struct sockaddr_in *, next->ai_addr) + ->sin_addr), + (size_t)(*host)->h_length); } ++i; } @@ -194,10 +188,12 @@ ares_status_t ares__addrinfo2hostent(const struct ares_addrinfo *ai, int family, return ARES_SUCCESS; +/* LCOV_EXCL_START: OutOfMemory */ enomem: ares_free_hostent(*host); *host = NULL; return ARES_ENOMEM; + /* LCOV_EXCL_STOP */ } ares_status_t ares__addrinfo2addrttl(const struct ares_addrinfo *ai, int family, @@ -211,23 +207,23 @@ ares_status_t ares__addrinfo2addrttl(const struct ares_addrinfo *ai, int family, int cname_ttl = INT_MAX; if (family != AF_INET && family != AF_INET6) { - return ARES_EBADQUERY; + return ARES_EBADQUERY; /* LCOV_EXCL_LINE: DefensiveCoding */ } if (ai == NULL || naddrttls == NULL) { - return ARES_EBADQUERY; + return ARES_EBADQUERY; /* LCOV_EXCL_LINE: DefensiveCoding */ } if (family == AF_INET && addrttls == NULL) { - return ARES_EBADQUERY; + return ARES_EBADQUERY; /* LCOV_EXCL_LINE: DefensiveCoding */ } if (family == AF_INET6 && addr6ttls == NULL) { - return ARES_EBADQUERY; + return ARES_EBADQUERY; /* LCOV_EXCL_LINE: DefensiveCoding */ } if (req_naddrttls == 0) { - return ARES_EBADQUERY; + return ARES_EBADQUERY; /* LCOV_EXCL_LINE: DefensiveCoding */ } *naddrttls = 0; @@ -256,20 +252,20 @@ ares_status_t ares__addrinfo2addrttl(const struct ares_addrinfo *ai, int family, addr6ttls[*naddrttls].ttl = next->ai_ttl; } - memcpy( - &addr6ttls[*naddrttls].ip6addr, - &(CARES_INADDR_CAST(struct sockaddr_in6 *, next->ai_addr)->sin6_addr), - sizeof(struct ares_in6_addr)); + memcpy(&addr6ttls[*naddrttls].ip6addr, + &(CARES_INADDR_CAST(const struct sockaddr_in6 *, next->ai_addr) + ->sin6_addr), + sizeof(struct ares_in6_addr)); } else { if (next->ai_ttl > cname_ttl) { addrttls[*naddrttls].ttl = cname_ttl; } else { addrttls[*naddrttls].ttl = next->ai_ttl; } - memcpy( - &addrttls[*naddrttls].ipaddr, - &(CARES_INADDR_CAST(struct sockaddr_in *, next->ai_addr)->sin_addr), - sizeof(struct in_addr)); + memcpy(&addrttls[*naddrttls].ipaddr, + &(CARES_INADDR_CAST(const struct sockaddr_in *, next->ai_addr) + ->sin_addr), + sizeof(struct in_addr)); } (*naddrttls)++; } diff --git a/contrib/libs/c-ares/src/lib/ares__addrinfo_localhost.c b/contrib/libs/c-ares/src/lib/ares__addrinfo_localhost.c index baa9b37212..e98dd4e277 100644 --- a/contrib/libs/c-ares/src/lib/ares__addrinfo_localhost.c +++ b/contrib/libs/c-ares/src/lib/ares__addrinfo_localhost.c @@ -25,7 +25,7 @@ * SPDX-License-Identifier: MIT */ -#include "ares_setup.h" +#include "ares_private.h" #ifdef HAVE_NETINET_IN_H # include <netinet/in.h> @@ -37,11 +37,10 @@ # include <arpa/inet.h> #endif -#if defined(_WIN32) && defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0600 -# include <ws2ipdef.h> -#endif - #if defined(USE_WINSOCK) +# if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0600 +# include <ws2ipdef.h> +# endif # if defined(HAVE_IPHLPAPI_H) # include <iphlpapi.h> # endif @@ -50,10 +49,6 @@ # endif #endif -#include "ares.h" -#include "ares_inet_net_pton.h" -#include "ares_private.h" - ares_status_t ares_append_ai_node(int aftype, unsigned short port, unsigned int ttl, const void *adata, struct ares_addrinfo_node **nodes) @@ -62,7 +57,7 @@ ares_status_t ares_append_ai_node(int aftype, unsigned short port, node = ares__append_addrinfo_node(nodes); if (!node) { - return ARES_ENOMEM; + return ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ } memset(node, 0, sizeof(*node)); @@ -70,7 +65,7 @@ ares_status_t ares_append_ai_node(int aftype, unsigned short port, if (aftype == AF_INET) { struct sockaddr_in *sin = ares_malloc(sizeof(*sin)); if (!sin) { - return ARES_ENOMEM; + return ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ } memset(sin, 0, sizeof(*sin)); @@ -88,7 +83,7 @@ ares_status_t ares_append_ai_node(int aftype, unsigned short port, if (aftype == AF_INET6) { struct sockaddr_in6 *sin6 = ares_malloc(sizeof(*sin6)); if (!sin6) { - return ARES_ENOMEM; + return ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ } memset(sin6, 0, sizeof(*sin6)); @@ -117,7 +112,7 @@ static ares_status_t ares_inet_pton(AF_INET6, "::1", &addr6); status = ares_append_ai_node(AF_INET6, port, 0, &addr6, nodes); if (status != ARES_SUCCESS) { - return status; + return status; /* LCOV_EXCL_LINE: OutOfMemory */ } } @@ -126,7 +121,7 @@ static ares_status_t ares_inet_pton(AF_INET, "127.0.0.1", &addr4); status = ares_append_ai_node(AF_INET, port, 0, &addr4, nodes); if (status != ARES_SUCCESS) { - return status; + return status; /* LCOV_EXCL_LINE: OutOfMemory */ } } @@ -137,11 +132,11 @@ static ares_status_t ares__system_loopback_addrs(int aftype, unsigned short port, struct ares_addrinfo_node **nodes) { -#if defined(_WIN32) && defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0600 && \ +#if defined(USE_WINSOCK) && defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0600 && \ !defined(__WATCOMC__) PMIB_UNICASTIPADDRESS_TABLE table; unsigned int i; - ares_status_t status; + ares_status_t status = ARES_ENOTFOUND; *nodes = NULL; @@ -209,13 +204,13 @@ ares_status_t ares__addrinfo_localhost(const char *name, unsigned short port, case AF_INET6: case AF_UNSPEC: break; - default: - return ARES_EBADFAMILY; + default: /* LCOV_EXCL_LINE: DefensiveCoding */ + return ARES_EBADFAMILY; /* LCOV_EXCL_LINE: DefensiveCoding */ } ai->name = ares_strdup(name); if (!ai->name) { - goto enomem; + goto enomem; /* LCOV_EXCL_LINE: OutOfMemory */ } status = ares__system_loopback_addrs(hints->ai_family, port, &nodes); @@ -228,9 +223,11 @@ ares_status_t ares__addrinfo_localhost(const char *name, unsigned short port, return status; +/* LCOV_EXCL_START: OutOfMemory */ enomem: ares__freeaddrinfo_nodes(nodes); ares_free(ai->name); ai->name = NULL; return ARES_ENOMEM; + /* LCOV_EXCL_STOP */ } diff --git a/contrib/libs/c-ares/src/lib/ares__close_sockets.c b/contrib/libs/c-ares/src/lib/ares__close_sockets.c index 03ba4abf89..27bbaacf0e 100644 --- a/contrib/libs/c-ares/src/lib/ares__close_sockets.c +++ b/contrib/libs/c-ares/src/lib/ares__close_sockets.c @@ -25,33 +25,33 @@ * SPDX-License-Identifier: MIT */ -#include "ares_setup.h" - -#include "ares.h" #include "ares_private.h" #include <assert.h> -static void ares__requeue_queries(struct server_connection *conn) +static void ares__requeue_queries(ares_conn_t *conn, + ares_status_t requeue_status) { - struct query *query; - ares_timeval_t now = ares__tvnow(); + ares_query_t *query; + ares_timeval_t now; + + ares__tvnow(&now); while ((query = ares__llist_first_val(conn->queries_to_conn)) != NULL) { - ares__requeue_query(query, &now); + ares__requeue_query(query, &now, requeue_status, ARES_TRUE); } } -void ares__close_connection(struct server_connection *conn) +void ares__close_connection(ares_conn_t *conn, ares_status_t requeue_status) { - struct server_state *server = conn->server; - ares_channel_t *channel = server->channel; + ares_server_t *server = conn->server; + ares_channel_t *channel = server->channel; /* Unlink */ ares__llist_node_claim( ares__htable_asvp_get_direct(channel->connnode_by_socket, conn->fd)); ares__htable_asvp_remove(channel->connnode_by_socket, conn->fd); - if (conn->is_tcp) { + if (conn->flags & ARES_CONN_FLAG_TCP) { /* Reset any existing input and output buffer. */ ares__buf_consume(server->tcp_parser, ares__buf_len(server->tcp_parser)); ares__buf_consume(server->tcp_send, ares__buf_len(server->tcp_send)); @@ -59,7 +59,7 @@ void ares__close_connection(struct server_connection *conn) } /* Requeue queries to other connections */ - ares__requeue_queries(conn); + ares__requeue_queries(conn, requeue_status); ares__llist_destroy(conn->queries_to_conn); @@ -69,51 +69,68 @@ void ares__close_connection(struct server_connection *conn) ares_free(conn); } -void ares__close_sockets(struct server_state *server) +void ares__close_sockets(ares_server_t *server) { ares__llist_node_t *node; while ((node = ares__llist_node_first(server->connections)) != NULL) { - struct server_connection *conn = ares__llist_node_val(node); - ares__close_connection(conn); + ares_conn_t *conn = ares__llist_node_val(node); + ares__close_connection(conn, ARES_SUCCESS); } } -void ares__check_cleanup_conn(const ares_channel_t *channel, - struct server_connection *conn) +void ares__check_cleanup_conns(const ares_channel_t *channel) { - ares_bool_t do_cleanup = ARES_FALSE; - - if (channel == NULL || conn == NULL) { - return; - } - - if (ares__llist_len(conn->queries_to_conn)) { - return; - } + ares__slist_node_t *snode; - /* If we are configured not to stay open, close it out */ - if (!(channel->flags & ARES_FLAG_STAYOPEN)) { - do_cleanup = ARES_TRUE; + if (channel == NULL) { + return; /* LCOV_EXCL_LINE: DefensiveCoding */ } - /* If the associated server has failures, close it out. Resetting the - * connection (and specifically the source port number) can help resolve - * situations where packets are being dropped. - */ - if (conn->server->consec_failures > 0) { - do_cleanup = ARES_TRUE; + /* Iterate across each server */ + for (snode = ares__slist_node_first(channel->servers); snode != NULL; + snode = ares__slist_node_next(snode)) { + ares_server_t *server = ares__slist_node_val(snode); + ares__llist_node_t *cnode; + + /* Iterate across each connection */ + cnode = ares__llist_node_first(server->connections); + while (cnode != NULL) { + ares__llist_node_t *next = ares__llist_node_next(cnode); + ares_conn_t *conn = ares__llist_node_val(cnode); + ares_bool_t do_cleanup = ARES_FALSE; + cnode = next; + + /* Has connections, not eligible */ + if (ares__llist_len(conn->queries_to_conn)) { + continue; + } + + /* If we are configured not to stay open, close it out */ + if (!(channel->flags & ARES_FLAG_STAYOPEN)) { + do_cleanup = ARES_TRUE; + } + + /* If the associated server has failures, close it out. Resetting the + * connection (and specifically the source port number) can help resolve + * situations where packets are being dropped. + */ + if (conn->server->consec_failures > 0) { + do_cleanup = ARES_TRUE; + } + + /* If the udp connection hit its max queries, always close it */ + if (!(conn->flags & ARES_CONN_FLAG_TCP) && channel->udp_max_queries > 0 && + conn->total_queries >= channel->udp_max_queries) { + do_cleanup = ARES_TRUE; + } + + if (!do_cleanup) { + continue; + } + + /* Clean it up */ + ares__close_connection(conn, ARES_SUCCESS); + } } - - /* If the udp connection hit its max queries, always close it */ - if (!conn->is_tcp && channel->udp_max_queries > 0 && - conn->total_queries >= channel->udp_max_queries) { - do_cleanup = ARES_TRUE; - } - - if (!do_cleanup) { - return; - } - - ares__close_connection(conn); } diff --git a/contrib/libs/c-ares/src/lib/ares__hosts_file.c b/contrib/libs/c-ares/src/lib/ares__hosts_file.c index e279623de3..ae9c071d7a 100644 --- a/contrib/libs/c-ares/src/lib/ares__hosts_file.c +++ b/contrib/libs/c-ares/src/lib/ares__hosts_file.c @@ -23,8 +23,6 @@ * * SPDX-License-Identifier: MIT */ -#include "ares_setup.h" -#include "ares.h" #include "ares_private.h" #ifdef HAVE_SYS_TYPES_H # include <sys/types.h> @@ -105,7 +103,7 @@ const void *ares_dns_pton(const char *ipaddr, struct ares_addr *addr, size_t ptr_len = 0; if (ipaddr == NULL || addr == NULL || out_len == NULL) { - return NULL; + return NULL; /* LCOV_EXCL_LINE: DefensiveCoding */ } *out_len = 0; @@ -150,7 +148,7 @@ static ares_bool_t ares__normalize_ipaddr(const char *ipaddr, char *out, } if (!ares_inet_ntop(data.family, addr, out, (ares_socklen_t)out_len)) { - return ARES_FALSE; + return ARES_FALSE; /* LCOV_EXCL_LINE: DefensiveCoding */ } return ARES_TRUE; @@ -315,8 +313,8 @@ static ares_status_t ares__hosts_file_add(ares_hosts_file_t *hosts, if (matchtype != ARES_MATCH_NONE) { status = ares__hosts_file_merge_entry(hosts, match, entry, matchtype); if (status != ARES_SUCCESS) { - ares__hosts_entry_destroy(entry); - return status; + ares__hosts_entry_destroy(entry); /* LCOV_EXCL_LINE: DefensiveCoding */ + return status; /* LCOV_EXCL_LINE: DefensiveCoding */ } /* entry was invalidated above by merging */ entry = match; @@ -617,7 +615,8 @@ static ares_bool_t ares__hosts_expired(const char *filename, /* Expire every 60s if we can't get a time */ if (mod_ts == 0) { - mod_ts = time(NULL) - 60; + mod_ts = + time(NULL) - 60; /* LCOV_EXCL_LINE: only on systems without stat() */ } /* If filenames are different, its expired */ @@ -642,7 +641,7 @@ static ares_status_t ares__hosts_path(const ares_channel_t *channel, if (channel->hosts_path) { path_hosts = ares_strdup(channel->hosts_path); if (!path_hosts) { - return ARES_ENOMEM; + return ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ } } @@ -653,12 +652,12 @@ static ares_status_t ares__hosts_path(const ares_channel_t *channel, path_hosts = ares_strdup(getenv("CARES_HOSTS")); if (!path_hosts) { - return ARES_ENOMEM; + return ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ } } if (!path_hosts) { -#ifdef WIN32 +#if defined(USE_WINSOCK) char PATH_HOSTS[MAX_PATH] = ""; char tmp[MAX_PATH]; HKEY hkeyHosts; @@ -728,7 +727,7 @@ ares_status_t ares__hosts_search_ipaddr(ares_channel_t *channel, } if (channel->hf == NULL) { - return ARES_ENOTFOUND; + return ARES_ENOTFOUND; /* LCOV_EXCL_LINE: DefensiveCoding */ } if (!ares__normalize_ipaddr(ipaddr, addr, sizeof(addr))) { @@ -757,7 +756,7 @@ ares_status_t ares__hosts_search_host(ares_channel_t *channel, } if (channel->hf == NULL) { - return ARES_ENOTFOUND; + return ARES_ENOTFOUND; /* LCOV_EXCL_LINE: DefensiveCoding */ } *entry = ares__htable_strvp_get_direct(channel->hf->hosthash, host); @@ -768,124 +767,6 @@ ares_status_t ares__hosts_search_host(ares_channel_t *channel, return ARES_SUCCESS; } -ares_status_t ares__hosts_entry_to_hostent(const ares_hosts_entry_t *entry, - int family, struct hostent **hostent) -{ - ares_status_t status; - size_t naliases; - ares__llist_node_t *node; - size_t idx; - - *hostent = ares_malloc_zero(sizeof(**hostent)); - if (*hostent == NULL) { - status = ARES_ENOMEM; - goto fail; - } - - (*hostent)->h_addrtype = (HOSTENT_ADDRTYPE_TYPE)family; - - /* Copy IP addresses that match the address family */ - idx = 0; - for (node = ares__llist_node_first(entry->ips); node != NULL; - node = ares__llist_node_next(node)) { - struct ares_addr addr; - const void *ptr = NULL; - size_t ptr_len = 0; - const char *ipaddr = ares__llist_node_val(node); - char **temp = NULL; - - memset(&addr, 0, sizeof(addr)); - - addr.family = family; - ptr = ares_dns_pton(ipaddr, &addr, &ptr_len); - if (ptr == NULL) { - continue; - } - - /* If family == AF_UNSPEC, then we want to inherit this for future - * conversions as we can only support a single address class */ - if (family == AF_UNSPEC) { - family = addr.family; - (*hostent)->h_addrtype = (HOSTENT_ADDRTYPE_TYPE)addr.family; - } - - temp = ares_realloc_zero((*hostent)->h_addr_list, - (idx + 1) * sizeof(*(*hostent)->h_addr_list), - (idx + 2) * sizeof(*(*hostent)->h_addr_list)); - if (temp == NULL) { - status = ARES_ENOMEM; - goto fail; - } - - (*hostent)->h_addr_list = temp; - - (*hostent)->h_addr_list[idx] = ares_malloc(ptr_len); - if ((*hostent)->h_addr_list[idx] == NULL) { - status = ARES_ENOMEM; - goto fail; - } - - memcpy((*hostent)->h_addr_list[idx], ptr, ptr_len); - idx++; - (*hostent)->h_length = (HOSTENT_LENGTH_TYPE)ptr_len; - } - - /* entry didn't match address class */ - if (idx == 0) { - status = ARES_ENOTFOUND; - goto fail; - } - - /* Copy main hostname */ - (*hostent)->h_name = ares_strdup(ares__llist_first_val(entry->hosts)); - if ((*hostent)->h_name == NULL) { - status = ARES_ENOMEM; - goto fail; - } - - /* Copy aliases */ - naliases = ares__llist_len(entry->hosts) - 1; - - /* Cap at 100, some people use https://github.com/StevenBlack/hosts and we - * don't need 200k+ aliases */ - if (naliases > 100) { - naliases = 100; - } - - (*hostent)->h_aliases = - ares_malloc_zero((naliases + 1) * sizeof(*(*hostent)->h_aliases)); - if ((*hostent)->h_aliases == NULL) { - status = ARES_ENOMEM; - goto fail; - } - - /* Copy all entries to the alias except the first */ - idx = 0; - node = ares__llist_node_first(entry->hosts); - node = ares__llist_node_next(node); - while (node != NULL) { - (*hostent)->h_aliases[idx] = ares_strdup(ares__llist_node_val(node)); - if ((*hostent)->h_aliases[idx] == NULL) { - status = ARES_ENOMEM; - goto fail; - } - idx++; - - /* Break out if artificially capped */ - if (idx == naliases) { - break; - } - node = ares__llist_node_next(node); - } - - return ARES_SUCCESS; - -fail: - ares_free_hostent(*hostent); - *hostent = NULL; - return status; -} - static ares_status_t ares__hosts_ai_append_cnames(const ares_hosts_entry_t *entry, struct ares_addrinfo_cname **cnames_out) @@ -909,25 +790,25 @@ static ares_status_t * https://github.com/StevenBlack/hosts and we don't need 200k+ aliases */ cnt++; if (cnt > 100) { - break; + break; /* LCOV_EXCL_LINE: DefensiveCoding */ } cname = ares__append_addrinfo_cname(&cnames); if (cname == NULL) { - status = ARES_ENOMEM; - goto done; + status = ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ + goto done; /* LCOV_EXCL_LINE: OutOfMemory */ } cname->alias = ares_strdup(host); if (cname->alias == NULL) { - status = ARES_ENOMEM; - goto done; + status = ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ + goto done; /* LCOV_EXCL_LINE: OutOfMemory */ } cname->name = ares_strdup(primaryhost); if (cname->name == NULL) { - status = ARES_ENOMEM; - goto done; + status = ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ + goto done; /* LCOV_EXCL_LINE: OutOfMemory */ } node = ares__llist_node_next(node); @@ -937,22 +818,22 @@ static ares_status_t if (cnames == NULL) { cname = ares__append_addrinfo_cname(&cnames); if (cname == NULL) { - status = ARES_ENOMEM; - goto done; + status = ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ + goto done; /* LCOV_EXCL_LINE: OutOfMemory */ } cname->name = ares_strdup(primaryhost); if (cname->name == NULL) { - status = ARES_ENOMEM; - goto done; + status = ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ + goto done; /* LCOV_EXCL_LINE: OutOfMemory */ } } status = ARES_SUCCESS; done: if (status != ARES_SUCCESS) { - ares__freeaddrinfo_cnames(cnames); - return status; + ares__freeaddrinfo_cnames(cnames); /* LCOV_EXCL_LINE: DefensiveCoding */ + return status; /* LCOV_EXCL_LINE: DefensiveCoding */ } *cnames_out = cnames; @@ -975,14 +856,16 @@ ares_status_t ares__hosts_entry_to_addrinfo(const ares_hosts_entry_t *entry, case AF_INET6: case AF_UNSPEC: break; - default: - return ARES_EBADFAMILY; + default: /* LCOV_EXCL_LINE: DefensiveCoding */ + return ARES_EBADFAMILY; /* LCOV_EXCL_LINE: DefensiveCoding */ } - ai->name = ares_strdup(name); - if (ai->name == NULL) { - status = ARES_ENOMEM; - goto done; + if (name != NULL) { + ai->name = ares_strdup(name); + if (ai->name == NULL) { + status = ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ + goto done; /* LCOV_EXCL_LINE: OutOfMemory */ + } } for (node = ares__llist_node_first(entry->ips); node != NULL; @@ -1002,14 +885,14 @@ ares_status_t ares__hosts_entry_to_addrinfo(const ares_hosts_entry_t *entry, status = ares_append_ai_node(addr.family, port, 0, ptr, &ainodes); if (status != ARES_SUCCESS) { - goto done; + goto done; /* LCOV_EXCL_LINE: DefensiveCoding */ } } if (want_cnames) { status = ares__hosts_ai_append_cnames(entry, &cnames); if (status != ARES_SUCCESS) { - goto done; + goto done; /* LCOV_EXCL_LINE: DefensiveCoding */ } } @@ -1017,14 +900,48 @@ ares_status_t ares__hosts_entry_to_addrinfo(const ares_hosts_entry_t *entry, done: if (status != ARES_SUCCESS) { + /* LCOV_EXCL_START: defensive coding */ ares__freeaddrinfo_cnames(cnames); ares__freeaddrinfo_nodes(ainodes); ares_free(ai->name); ai->name = NULL; return status; + /* LCOV_EXCL_STOP */ } ares__addrinfo_cat_cnames(&ai->cnames, cnames); ares__addrinfo_cat_nodes(&ai->nodes, ainodes); return status; } + +ares_status_t ares__hosts_entry_to_hostent(const ares_hosts_entry_t *entry, + int family, struct hostent **hostent) +{ + ares_status_t status; + struct ares_addrinfo *ai = ares_malloc_zero(sizeof(*ai)); + + *hostent = NULL; + + if (ai == NULL) { + return ARES_ENOMEM; + } + + status = ares__hosts_entry_to_addrinfo(entry, NULL, family, 0, ARES_TRUE, ai); + if (status != ARES_SUCCESS) { + goto done; + } + + status = ares__addrinfo2hostent(ai, family, hostent); + if (status != ARES_SUCCESS) { + goto done; + } + +done: + ares_freeaddrinfo(ai); + if (status != ARES_SUCCESS) { + ares_free_hostent(*hostent); + *hostent = NULL; + } + + return status; +} diff --git a/contrib/libs/c-ares/src/lib/ares__parse_into_addrinfo.c b/contrib/libs/c-ares/src/lib/ares__parse_into_addrinfo.c index 90e951c02f..65c94c0401 100644 --- a/contrib/libs/c-ares/src/lib/ares__parse_into_addrinfo.c +++ b/contrib/libs/c-ares/src/lib/ares__parse_into_addrinfo.c @@ -24,7 +24,7 @@ * * SPDX-License-Identifier: MIT */ -#include "ares_setup.h" +#include "ares_private.h" #ifdef HAVE_NETINET_IN_H # include <netinet/in.h> @@ -44,8 +44,6 @@ # include <limits.h> #endif -#include "ares.h" -#include "ares_private.h" ares_status_t ares__parse_into_addrinfo(const ares_dns_record_t *dnsrec, ares_bool_t cname_only_is_enodata, @@ -65,7 +63,7 @@ ares_status_t ares__parse_into_addrinfo(const ares_dns_record_t *dnsrec, /* Save question hostname */ status = ares_dns_record_query_get(dnsrec, 0, &hostname, NULL, NULL); if (status != ARES_SUCCESS) { - goto done; + goto done; /* LCOV_EXCL_LINE: DefensiveCoding */ } ancount = ares_dns_record_rr_cnt(dnsrec, ARES_SECTION_ANSWER); @@ -107,19 +105,19 @@ ares_status_t ares__parse_into_addrinfo(const ares_dns_record_t *dnsrec, cname = ares__append_addrinfo_cname(&cnames); if (cname == NULL) { - status = ARES_ENOMEM; - goto done; + status = ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ + goto done; /* LCOV_EXCL_LINE: OutOfMemory */ } cname->ttl = (int)ares_dns_rr_get_ttl(rr); cname->alias = ares_strdup(ares_dns_rr_get_name(rr)); if (cname->alias == NULL) { - status = ARES_ENOMEM; - goto done; + status = ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ + goto done; /* LCOV_EXCL_LINE: OutOfMemory */ } cname->name = ares_strdup(hostname); if (cname->name == NULL) { - status = ARES_ENOMEM; - goto done; + status = ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ + goto done; /* LCOV_EXCL_LINE: OutOfMemory */ } } else if (rtype == ARES_REC_TYPE_A) { got_a = ARES_TRUE; @@ -127,7 +125,7 @@ ares_status_t ares__parse_into_addrinfo(const ares_dns_record_t *dnsrec, ares_append_ai_node(AF_INET, port, ares_dns_rr_get_ttl(rr), ares_dns_rr_get_addr(rr, ARES_RR_A_ADDR), &nodes); if (status != ARES_SUCCESS) { - goto done; + goto done; /* LCOV_EXCL_LINE: OutOfMemory */ } } else if (rtype == ARES_REC_TYPE_AAAA) { got_aaaa = ARES_TRUE; @@ -135,7 +133,7 @@ ares_status_t ares__parse_into_addrinfo(const ares_dns_record_t *dnsrec, ares_dns_rr_get_addr6(rr, ARES_RR_AAAA_ADDR), &nodes); if (status != ARES_SUCCESS) { - goto done; + goto done; /* LCOV_EXCL_LINE: OutOfMemory */ } } else { continue; @@ -153,8 +151,8 @@ ares_status_t ares__parse_into_addrinfo(const ares_dns_record_t *dnsrec, ares_free(ai->name); ai->name = ares_strdup(hostname); if (ai->name == NULL) { - status = ARES_ENOMEM; - goto done; + status = ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ + goto done; /* LCOV_EXCL_LINE: OutOfMemory */ } } diff --git a/contrib/libs/c-ares/src/lib/ares__socket.c b/contrib/libs/c-ares/src/lib/ares__socket.c index d3990e7660..345ab95ba1 100644 --- a/contrib/libs/c-ares/src/lib/ares__socket.c +++ b/contrib/libs/c-ares/src/lib/ares__socket.c @@ -24,7 +24,7 @@ * * SPDX-License-Identifier: MIT */ -#include "ares_setup.h" +#include "ares_private.h" #ifdef HAVE_SYS_UIO_H # include <sys/uio.h> @@ -56,8 +56,77 @@ #include <fcntl.h> #include <limits.h> -#include "ares.h" -#include "ares_private.h" +#if defined(__linux__) && defined(MSG_FASTOPEN) +# define TFO_SUPPORTED 1 +# define TFO_SKIP_CONNECT 0 +# define TFO_USE_SENDTO 0 +# define TFO_USE_CONNECTX 0 +# define TFO_CLIENT_SOCKOPT 0 +#elif defined(__FreeBSD__) && defined(TCP_FASTOPEN) +# define TFO_SUPPORTED 1 +# define TFO_SKIP_CONNECT 1 +# define TFO_USE_SENDTO 1 +# define TFO_USE_CONNECTX 0 +# define TFO_CLIENT_SOCKOPT TCP_FASTOPEN +#elif defined(__APPLE__) && defined(HAVE_CONNECTX) +# define TFO_SUPPORTED 1 +# define TFO_SKIP_CONNECT 0 +# define TFO_USE_SENDTO 0 +# define TFO_USE_CONNECTX 1 +# undef TFO_CLIENT_SOCKOPT +#else +# define TFO_SUPPORTED 0 +#endif + + +#ifndef HAVE_WRITEV +/* Structure for scatter/gather I/O. */ +struct iovec { + void *iov_base; /* Pointer to data. */ + size_t iov_len; /* Length of data. */ +}; +#endif + + +/* Return 1 if the specified error number describes a readiness error, or 0 + * otherwise. This is mostly for HP-UX, which could return EAGAIN or + * EWOULDBLOCK. See this man page + * + * http://devrsrc1.external.hp.com/STKS/cgi-bin/man2html? + * manpage=/usr/share/man/man2.Z/send.2 + */ +ares_bool_t ares__socket_try_again(int errnum) +{ +#if !defined EWOULDBLOCK && !defined EAGAIN +# error "Neither EWOULDBLOCK nor EAGAIN defined" +#endif + +#ifdef EWOULDBLOCK + if (errnum == EWOULDBLOCK) { + return ARES_TRUE; + } +#endif + +#if defined EAGAIN && EAGAIN != EWOULDBLOCK + if (errnum == EAGAIN) { + return ARES_TRUE; + } +#endif + + return ARES_FALSE; +} + +ares_ssize_t ares__socket_recv(ares_channel_t *channel, ares_socket_t s, + void *data, size_t data_len) +{ + if (channel->sock_funcs && channel->sock_funcs->arecvfrom) { + return channel->sock_funcs->arecvfrom(s, data, data_len, 0, 0, 0, + channel->sock_func_cb_data); + } + + return (ares_ssize_t)recv((RECV_TYPE_ARG1)s, (RECV_TYPE_ARG2)data, + (RECV_TYPE_ARG3)data_len, (RECV_TYPE_ARG4)(0)); +} ares_ssize_t ares__socket_recvfrom(ares_channel_t *channel, ares_socket_t s, void *data, size_t data_len, int flags, @@ -73,20 +142,142 @@ ares_ssize_t ares__socket_recvfrom(ares_channel_t *channel, ares_socket_t s, return (ares_ssize_t)recvfrom(s, data, (RECVFROM_TYPE_ARG3)data_len, flags, from, from_len); #else - return sread(s, data, data_len); + return ares__socket_recv(channel, s, data, data_len); #endif } -ares_ssize_t ares__socket_recv(ares_channel_t *channel, ares_socket_t s, - void *data, size_t data_len) +/* Use like: + * struct sockaddr_storage sa_storage; + * ares_socklen_t salen = sizeof(sa_storage); + * struct sockaddr *sa = (struct sockaddr *)&sa_storage; + * ares__conn_set_sockaddr(conn, sa, &salen); + */ +static ares_status_t ares__conn_set_sockaddr(const ares_conn_t *conn, + struct sockaddr *sa, + ares_socklen_t *salen) { - if (channel->sock_funcs && channel->sock_funcs->arecvfrom) { - return channel->sock_funcs->arecvfrom(s, data, data_len, 0, 0, 0, - channel->sock_func_cb_data); + const ares_server_t *server = conn->server; + unsigned short port = + conn->flags & ARES_CONN_FLAG_TCP ? server->tcp_port : server->udp_port; + struct sockaddr_in *sin; + struct sockaddr_in6 *sin6; + + switch (server->addr.family) { + case AF_INET: + sin = (struct sockaddr_in *)(void *)sa; + if (*salen < (ares_socklen_t)sizeof(*sin)) { + return ARES_EFORMERR; + } + *salen = sizeof(*sin); + memset(sin, 0, sizeof(*sin)); + sin->sin_family = AF_INET; + sin->sin_port = htons(port); + memcpy(&sin->sin_addr, &server->addr.addr.addr4, sizeof(sin->sin_addr)); + return ARES_SUCCESS; + case AF_INET6: + sin6 = (struct sockaddr_in6 *)(void *)sa; + if (*salen < (ares_socklen_t)sizeof(*sin6)) { + return ARES_EFORMERR; + } + *salen = sizeof(*sin6); + memset(sin6, 0, sizeof(*sin6)); + sin6->sin6_family = AF_INET6; + sin6->sin6_port = htons(port); + memcpy(&sin6->sin6_addr, &server->addr.addr.addr6, + sizeof(sin6->sin6_addr)); +#ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID + sin6->sin6_scope_id = server->ll_scope; +#endif + return ARES_SUCCESS; + default: + break; } - /* sread() is a wrapper for read() or recv() depending on the system */ - return sread(s, data, data_len); + return ARES_EBADFAMILY; +} + +static ares_status_t ares_conn_set_self_ip(ares_conn_t *conn, ares_bool_t early) +{ + struct sockaddr_storage sa_storage; + int rv; + ares_socklen_t len = sizeof(sa_storage); + + /* We call this twice on TFO, if we already have the IP we can go ahead and + * skip processing */ + if (!early && conn->self_ip.family != AF_UNSPEC) { + return ARES_SUCCESS; + } + + memset(&sa_storage, 0, sizeof(sa_storage)); + + rv = getsockname(conn->fd, (struct sockaddr *)(void *)&sa_storage, &len); + if (rv != 0) { + /* During TCP FastOpen, we can't get the IP this early since connect() + * may not be called. That's ok, we'll try again later */ + if (early && conn->flags & ARES_CONN_FLAG_TCP && + conn->flags & ARES_CONN_FLAG_TFO) { + memset(&conn->self_ip, 0, sizeof(conn->self_ip)); + return ARES_SUCCESS; + } + return ARES_ECONNREFUSED; + } + + if (!ares_sockaddr_to_ares_addr(&conn->self_ip, NULL, + (struct sockaddr *)(void *)&sa_storage)) { + return ARES_ECONNREFUSED; + } + + return ARES_SUCCESS; +} + +ares_ssize_t ares__conn_write(ares_conn_t *conn, const void *data, size_t len) +{ + ares_channel_t *channel = conn->server->channel; + int flags = 0; + +#ifdef HAVE_MSG_NOSIGNAL + flags |= MSG_NOSIGNAL; +#endif + + if (channel->sock_funcs && channel->sock_funcs->asendv) { + struct iovec vec; + vec.iov_base = (void *)((size_t)data); /* Cast off const */ + vec.iov_len = len; + return channel->sock_funcs->asendv(conn->fd, &vec, 1, + channel->sock_func_cb_data); + } + + if (conn->flags & ARES_CONN_FLAG_TFO_INITIAL) { + conn->flags &= ~((unsigned int)ARES_CONN_FLAG_TFO_INITIAL); + +#if defined(TFO_USE_SENDTO) && TFO_USE_SENDTO + { + struct sockaddr_storage sa_storage; + ares_socklen_t salen = sizeof(sa_storage); + struct sockaddr *sa = (struct sockaddr *)&sa_storage; + ares_status_t status; + ares_ssize_t rv; + + status = ares__conn_set_sockaddr(conn, sa, &salen); + if (status != ARES_SUCCESS) { + return status; + } + + rv = (ares_ssize_t)sendto((SEND_TYPE_ARG1)conn->fd, (SEND_TYPE_ARG2)data, + (SEND_TYPE_ARG3)len, (SEND_TYPE_ARG4)flags, sa, + salen); + + /* If using TFO, we might not have been able to get an IP earlier, since + * we hadn't informed the OS of the destination. When using sendto() + * now we have so we should be able to fetch it */ + ares_conn_set_self_ip(conn, ARES_TRUE); + return rv; + } +#endif + } + + return (ares_ssize_t)send((SEND_TYPE_ARG1)conn->fd, (SEND_TYPE_ARG2)data, + (SEND_TYPE_ARG3)len, (SEND_TYPE_ARG4)flags); } /* @@ -145,7 +336,7 @@ static int setsocknonblock(ares_socket_t sockfd, /* operate on this */ #endif } -#if defined(IPV6_V6ONLY) && defined(WIN32) +#if defined(IPV6_V6ONLY) && defined(USE_WINSOCK) /* It makes support for IPv4-mapped IPv6 addresses. * Linux kernel, NetBSD, FreeBSD and Darwin: default is off; * Windows Vista and later: default is on; @@ -161,7 +352,7 @@ static void set_ipv6_v6only(ares_socket_t sockfd, int on) # define set_ipv6_v6only(s, v) #endif -static int configure_socket(ares_socket_t s, struct server_state *server) +static ares_status_t configure_socket(ares_conn_t *conn) { union { struct sockaddr sa; @@ -170,43 +361,53 @@ static int configure_socket(ares_socket_t s, struct server_state *server) } local; ares_socklen_t bindlen = 0; + ares_server_t *server = conn->server; ares_channel_t *channel = server->channel; /* do not set options for user-managed sockets */ if (channel->sock_funcs && channel->sock_funcs->asocket) { - return 0; + return ARES_SUCCESS; } - (void)setsocknonblock(s, 1); + (void)setsocknonblock(conn->fd, 1); #if defined(FD_CLOEXEC) && !defined(MSDOS) /* Configure the socket fd as close-on-exec. */ - if (fcntl(s, F_SETFD, FD_CLOEXEC) == -1) { - return -1; /* LCOV_EXCL_LINE */ + if (fcntl(conn->fd, F_SETFD, FD_CLOEXEC) != 0) { + return ARES_ECONNREFUSED; /* LCOV_EXCL_LINE */ + } +#endif + + /* No need to emit SIGPIPE on socket errors */ +#if defined(SO_NOSIGPIPE) + { + int opt = 1; + (void)setsockopt(conn->fd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&opt, + sizeof(opt)); } #endif /* Set the socket's send and receive buffer sizes. */ - if ((channel->socket_send_buffer_size > 0) && - setsockopt(s, SOL_SOCKET, SO_SNDBUF, + if (channel->socket_send_buffer_size > 0 && + setsockopt(conn->fd, SOL_SOCKET, SO_SNDBUF, (void *)&channel->socket_send_buffer_size, - sizeof(channel->socket_send_buffer_size)) == -1) { - return -1; + sizeof(channel->socket_send_buffer_size)) != 0) { + return ARES_ECONNREFUSED; /* LCOV_EXCL_LINE: UntestablePath */ } - if ((channel->socket_receive_buffer_size > 0) && - setsockopt(s, SOL_SOCKET, SO_RCVBUF, + if (channel->socket_receive_buffer_size > 0 && + setsockopt(conn->fd, SOL_SOCKET, SO_RCVBUF, (void *)&channel->socket_receive_buffer_size, - sizeof(channel->socket_receive_buffer_size)) == -1) { - return -1; + sizeof(channel->socket_receive_buffer_size)) != 0) { + return ARES_ECONNREFUSED; /* LCOV_EXCL_LINE: UntestablePath */ } #ifdef SO_BINDTODEVICE - if (channel->local_dev_name[0] && - setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE, channel->local_dev_name, - sizeof(channel->local_dev_name))) { - /* Only root can do this, and usually not fatal if it doesn't work, so */ - /* just continue on. */ + if (ares_strlen(channel->local_dev_name)) { + /* Only root can do this, and usually not fatal if it doesn't work, so + * just continue on. */ + (void)setsockopt(conn->fd, SOL_SOCKET, SO_BINDTODEVICE, + channel->local_dev_name, sizeof(channel->local_dev_name)); } #endif @@ -226,130 +427,215 @@ static int configure_socket(ares_socket_t s, struct server_state *server) bindlen = sizeof(local.sa6); } - if (bindlen && bind(s, &local.sa, bindlen) < 0) { - return -1; + if (bindlen && bind(conn->fd, &local.sa, bindlen) < 0) { + return ARES_ECONNREFUSED; } if (server->addr.family == AF_INET6) { - set_ipv6_v6only(s, 0); - } - - return 0; -} - -ares_status_t ares__open_connection(ares_channel_t *channel, - struct server_state *server, - ares_bool_t is_tcp) -{ - ares_socket_t s; - int opt; - ares_socklen_t salen; - - union { - struct sockaddr_in sa4; - struct sockaddr_in6 sa6; - } saddr; - struct sockaddr *sa; - struct server_connection *conn; - ares__llist_node_t *node; - int type = is_tcp ? SOCK_STREAM : SOCK_DGRAM; - - switch (server->addr.family) { - case AF_INET: - sa = (void *)&saddr.sa4; - salen = sizeof(saddr.sa4); - memset(sa, 0, (size_t)salen); - saddr.sa4.sin_family = AF_INET; - saddr.sa4.sin_port = htons(is_tcp ? server->tcp_port : server->udp_port); - memcpy(&saddr.sa4.sin_addr, &server->addr.addr.addr4, - sizeof(saddr.sa4.sin_addr)); - break; - case AF_INET6: - sa = (void *)&saddr.sa6; - salen = sizeof(saddr.sa6); - memset(sa, 0, (size_t)salen); - saddr.sa6.sin6_family = AF_INET6; - saddr.sa6.sin6_port = htons(is_tcp ? server->tcp_port : server->udp_port); - memcpy(&saddr.sa6.sin6_addr, &server->addr.addr.addr6, - sizeof(saddr.sa6.sin6_addr)); -#ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID - saddr.sa6.sin6_scope_id = server->ll_scope; -#endif - break; - default: - return ARES_EBADFAMILY; /* LCOV_EXCL_LINE */ - } - - /* Acquire a socket. */ - s = ares__open_socket(channel, server->addr.family, type, 0); - if (s == ARES_SOCKET_BAD) { - return ARES_ECONNREFUSED; + set_ipv6_v6only(conn->fd, 0); } - /* Configure it. */ - if (configure_socket(s, server) < 0) { - ares__close_socket(channel, s); - return ARES_ECONNREFUSED; - } + if (conn->flags & ARES_CONN_FLAG_TCP) { + int opt = 1; #ifdef TCP_NODELAY - if (is_tcp) { /* * Disable the Nagle algorithm (only relevant for TCP sockets, and thus not * in configure_socket). In general, in DNS lookups we're pretty much * interested in firing off a single request and then waiting for a reply, * so batching isn't very interesting. */ - opt = 1; - if ((!channel->sock_funcs || !channel->sock_funcs->asocket) && - setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (void *)&opt, sizeof(opt)) == - -1) { - ares__close_socket(channel, s); + if (setsockopt(conn->fd, IPPROTO_TCP, TCP_NODELAY, (void *)&opt, + sizeof(opt)) != 0) { return ARES_ECONNREFUSED; } - } #endif - if (channel->sock_config_cb) { - int err = channel->sock_config_cb(s, type, channel->sock_config_cb_data); - if (err < 0) { - ares__close_socket(channel, s); - return ARES_ECONNREFUSED; +#if defined(TFO_CLIENT_SOCKOPT) + if (conn->flags & ARES_CONN_FLAG_TFO && + setsockopt(conn->fd, IPPROTO_TCP, TFO_CLIENT_SOCKOPT, (void *)&opt, + sizeof(opt)) != 0) { + /* Disable TFO if flag can't be set. */ + conn->flags &= ~((unsigned int)ARES_CONN_FLAG_TFO); } +#endif } - /* Connect to the server. */ - if (ares__connect_socket(channel, s, sa, salen) == -1) { - int err = SOCKERRNO; + return ARES_SUCCESS; +} - if (err != EINPROGRESS && err != EWOULDBLOCK) { - ares__close_socket(channel, s); - return ARES_ECONNREFUSED; +ares_bool_t ares_sockaddr_to_ares_addr(struct ares_addr *ares_addr, + unsigned short *port, + const struct sockaddr *sockaddr) +{ + if (sockaddr->sa_family == AF_INET) { + /* NOTE: memcpy sockaddr_in due to alignment issues found by UBSAN due to + * dnsinfo packing on MacOS */ + struct sockaddr_in sockaddr_in; + memcpy(&sockaddr_in, sockaddr, sizeof(sockaddr_in)); + + ares_addr->family = AF_INET; + memcpy(&ares_addr->addr.addr4, &(sockaddr_in.sin_addr), + sizeof(ares_addr->addr.addr4)); + + if (port) { + *port = ntohs(sockaddr_in.sin_port); } + return ARES_TRUE; } - if (channel->sock_create_cb) { - int err = channel->sock_create_cb(s, type, channel->sock_create_cb_data); - if (err < 0) { - ares__close_socket(channel, s); - return ARES_ECONNREFUSED; + if (sockaddr->sa_family == AF_INET6) { + /* NOTE: memcpy sockaddr_in6 due to alignment issues found by UBSAN due to + * dnsinfo packing on MacOS */ + struct sockaddr_in6 sockaddr_in6; + memcpy(&sockaddr_in6, sockaddr, sizeof(sockaddr_in6)); + + ares_addr->family = AF_INET6; + memcpy(&ares_addr->addr.addr6, &(sockaddr_in6.sin6_addr), + sizeof(ares_addr->addr.addr6)); + if (port) { + *port = ntohs(sockaddr_in6.sin6_port); } + return ARES_TRUE; } + return ARES_FALSE; +} + +static ares_status_t ares__conn_connect(ares_conn_t *conn, struct sockaddr *sa, + ares_socklen_t salen) +{ + /* Normal non TCPFastOpen style connect */ + if (!(conn->flags & ARES_CONN_FLAG_TFO)) { + return ares__connect_socket(conn->server->channel, conn->fd, sa, salen); + } + + /* FreeBSD don't want any sort of connect() so skip */ +#if defined(TFO_SKIP_CONNECT) && TFO_SKIP_CONNECT + return ARES_SUCCESS; +#elif defined(TFO_USE_CONNECTX) && TFO_USE_CONNECTX + { + int rv; + int err; + + do { + sa_endpoints_t endpoints; + memset(&endpoints, 0, sizeof(endpoints)); + endpoints.sae_dstaddr = sa; + endpoints.sae_dstaddrlen = salen; + + rv = connectx(conn->fd, &endpoints, SAE_ASSOCID_ANY, + CONNECT_DATA_IDEMPOTENT | CONNECT_RESUME_ON_READ_WRITE, + NULL, 0, NULL, NULL); + + err = SOCKERRNO; + if (rv == -1 && err != EINPROGRESS && err != EWOULDBLOCK) { + return ARES_ECONNREFUSED; + } + + } while (rv == -1 && err == EINTR); + } + return ARES_SUCCESS; +#elif defined(TFO_SUPPORTED) && TFO_SUPPORTED + return ares__connect_socket(conn->server->channel, conn->fd, sa, salen); +#else + /* Shouldn't be possible */ + return ARES_ECONNREFUSED; +#endif +} + +ares_status_t ares__open_connection(ares_conn_t **conn_out, + ares_channel_t *channel, + ares_server_t *server, ares_bool_t is_tcp) +{ + ares_status_t status; + struct sockaddr_storage sa_storage; + ares_socklen_t salen = sizeof(sa_storage); + struct sockaddr *sa = (struct sockaddr *)&sa_storage; + ares_conn_t *conn; + ares__llist_node_t *node = NULL; + int stype = is_tcp ? SOCK_STREAM : SOCK_DGRAM; + + *conn_out = NULL; + conn = ares_malloc(sizeof(*conn)); if (conn == NULL) { - ares__close_socket(channel, s); - return ARES_ENOMEM; + return ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ } + memset(conn, 0, sizeof(*conn)); - conn->fd = s; + conn->fd = ARES_SOCKET_BAD; conn->server = server; conn->queries_to_conn = ares__llist_create(NULL); - conn->is_tcp = is_tcp; + conn->flags = is_tcp ? ARES_CONN_FLAG_TCP : ARES_CONN_FLAG_NONE; + + /* Enable TFO if the OS supports it and we were passed in data to send during + * the connect. It might be disabled later if an error is encountered. Make + * sure a user isn't overriding anything. */ + if (conn->flags & ARES_CONN_FLAG_TCP && channel->sock_funcs == NULL && + TFO_SUPPORTED) { + conn->flags |= ARES_CONN_FLAG_TFO; + } + if (conn->queries_to_conn == NULL) { - ares__close_socket(channel, s); - ares_free(conn); - return ARES_ENOMEM; + /* LCOV_EXCL_START: OutOfMemory */ + status = ARES_ENOMEM; + goto done; + /* LCOV_EXCL_STOP */ + } + + /* Convert into the struct sockaddr structure needed by the OS */ + status = ares__conn_set_sockaddr(conn, sa, &salen); + if (status != ARES_SUCCESS) { + goto done; + } + + /* Acquire a socket. */ + conn->fd = ares__open_socket(channel, server->addr.family, stype, 0); + if (conn->fd == ARES_SOCKET_BAD) { + status = ARES_ECONNREFUSED; + goto done; + } + + /* Configure it. */ + status = configure_socket(conn); + if (status != ARES_SUCCESS) { + goto done; + } + + if (channel->sock_config_cb) { + int err = + channel->sock_config_cb(conn->fd, stype, channel->sock_config_cb_data); + if (err < 0) { + status = ARES_ECONNREFUSED; + goto done; + } + } + + /* Connect */ + status = ares__conn_connect(conn, sa, salen); + if (status != ARES_SUCCESS) { + goto done; + } + + if (channel->sock_create_cb) { + int err = + channel->sock_create_cb(conn->fd, stype, channel->sock_create_cb_data); + if (err < 0) { + status = ARES_ECONNREFUSED; + goto done; + } + } + + /* Let the connection know we haven't written our first packet yet for TFO */ + if (conn->flags & ARES_CONN_FLAG_TFO) { + conn->flags |= ARES_CONN_FLAG_TFO_INITIAL; + } + + /* Need to store our own ip for DNS cookie support */ + status = ares_conn_set_self_ip(conn, ARES_FALSE); + if (status != ARES_SUCCESS) { + goto done; /* LCOV_EXCL_LINE: UntestablePath */ } /* TCP connections are thrown to the end as we don't spawn multiple TCP @@ -361,29 +647,37 @@ ares_status_t ares__open_connection(ares_channel_t *channel, node = ares__llist_insert_first(server->connections, conn); } if (node == NULL) { - ares__close_socket(channel, s); - ares__llist_destroy(conn->queries_to_conn); - ares_free(conn); - return ARES_ENOMEM; + /* LCOV_EXCL_START: OutOfMemory */ + status = ARES_ENOMEM; + goto done; + /* LCOV_EXCL_STOP */ } /* Register globally to quickly map event on file descriptor to connection * node object */ - if (!ares__htable_asvp_insert(channel->connnode_by_socket, s, node)) { - ares__close_socket(channel, s); - ares__llist_destroy(conn->queries_to_conn); - ares__llist_node_claim(node); - ares_free(conn); - return ARES_ENOMEM; + if (!ares__htable_asvp_insert(channel->connnode_by_socket, conn->fd, node)) { + /* LCOV_EXCL_START: OutOfMemory */ + status = ARES_ENOMEM; + goto done; + /* LCOV_EXCL_STOP */ } - SOCK_STATE_CALLBACK(channel, s, 1, 0); + SOCK_STATE_CALLBACK(channel, conn->fd, 1, is_tcp ? 1 : 0); if (is_tcp) { server->tcp_conn = conn; } - return ARES_SUCCESS; +done: + if (status != ARES_SUCCESS) { + ares__llist_node_claim(node); + ares__llist_destroy(conn->queries_to_conn); + ares__close_socket(channel, conn->fd); + ares_free(conn); + } else { + *conn_out = conn; + } + return status; } ares_socket_t ares__open_socket(ares_channel_t *channel, int af, int type, @@ -397,15 +691,31 @@ ares_socket_t ares__open_socket(ares_channel_t *channel, int af, int type, return socket(af, type, protocol); } -int ares__connect_socket(ares_channel_t *channel, ares_socket_t sockfd, - const struct sockaddr *addr, ares_socklen_t addrlen) +ares_status_t ares__connect_socket(ares_channel_t *channel, + ares_socket_t sockfd, + const struct sockaddr *addr, + ares_socklen_t addrlen) { - if (channel->sock_funcs && channel->sock_funcs->aconnect) { - return channel->sock_funcs->aconnect(sockfd, addr, addrlen, + int rv; + int err; + + do { + if (channel->sock_funcs && channel->sock_funcs->aconnect) { + rv = channel->sock_funcs->aconnect(sockfd, addr, addrlen, channel->sock_func_cb_data); - } + } else { + rv = connect(sockfd, addr, addrlen); + } + + err = SOCKERRNO; + + if (rv == -1 && err != EINPROGRESS && err != EWOULDBLOCK) { + return ARES_ECONNREFUSED; + } - return connect(sockfd, addr, addrlen); + } while (rv == -1 && err == EINTR); + + return ARES_SUCCESS; } void ares__close_socket(ares_channel_t *channel, ares_socket_t s) @@ -421,26 +731,6 @@ void ares__close_socket(ares_channel_t *channel, ares_socket_t s) } } -#ifndef HAVE_WRITEV -/* Structure for scatter/gather I/O. */ -struct iovec { - void *iov_base; /* Pointer to data. */ - size_t iov_len; /* Length of data. */ -}; -#endif - -ares_ssize_t ares__socket_write(ares_channel_t *channel, ares_socket_t s, - const void *data, size_t len) -{ - if (channel->sock_funcs && channel->sock_funcs->asendv) { - struct iovec vec; - vec.iov_base = (void *)((size_t)data); /* Cast off const */ - vec.iov_len = len; - return channel->sock_funcs->asendv(s, &vec, 1, channel->sock_func_cb_data); - } - return swrite(s, data, len); -} - void ares_set_socket_callback(ares_channel_t *channel, ares_sock_create_callback cb, void *data) { diff --git a/contrib/libs/c-ares/src/lib/ares__sortaddrinfo.c b/contrib/libs/c-ares/src/lib/ares__sortaddrinfo.c index 155cc8caf4..1aab81ecf8 100644 --- a/contrib/libs/c-ares/src/lib/ares__sortaddrinfo.c +++ b/contrib/libs/c-ares/src/lib/ares__sortaddrinfo.c @@ -36,7 +36,7 @@ * SPDX-License-Identifier: BSD-3-Clause */ -#include "ares_setup.h" +#include "ares_private.h" #ifdef HAVE_NETINET_IN_H # include <netinet/in.h> @@ -51,9 +51,6 @@ #include <assert.h> #include <limits.h> -#include "ares.h" -#include "ares_private.h" - struct addrinfo_sort_elem { struct ares_addrinfo_node *ai; ares_bool_t has_src_addr; @@ -349,7 +346,6 @@ static int find_src_addr(ares_channel_t *channel, const struct sockaddr *addr, struct sockaddr *src_addr) { ares_socket_t sock; - int ret; ares_socklen_t len; switch (addr->sa_family) { @@ -366,18 +362,14 @@ static int find_src_addr(ares_channel_t *channel, const struct sockaddr *addr, sock = ares__open_socket(channel, addr->sa_family, SOCK_DGRAM, IPPROTO_UDP); if (sock == ARES_SOCKET_BAD) { - if (errno == EAFNOSUPPORT) { + if (SOCKERRNO == EAFNOSUPPORT) { return 0; } else { return -1; } } - do { - ret = ares__connect_socket(channel, sock, addr, len); - } while (ret == -1 && errno == EINTR); - - if (ret == -1) { + if (ares__connect_socket(channel, sock, addr, len) != ARES_SUCCESS) { ares__close_socket(channel, sock); return 0; } diff --git a/contrib/libs/c-ares/src/lib/ares_android.c b/contrib/libs/c-ares/src/lib/ares_android.c index 778d4d1060..4c0ffa04f7 100644 --- a/contrib/libs/c-ares/src/lib/ares_android.c +++ b/contrib/libs/c-ares/src/lib/ares_android.c @@ -24,13 +24,9 @@ * SPDX-License-Identifier: MIT */ #if defined(ANDROID) || defined(__ANDROID__) - -# include <jni.h> - -# include "ares_setup.h" -# include "ares.h" -# include "ares_android.h" # include "ares_private.h" +# include <jni.h> +# include <sys/prctl.h> static JavaVM *android_jvm = NULL; static jobject android_connectivity_manager = NULL; @@ -85,6 +81,23 @@ static jmethodID jni_get_method_id(JNIEnv *env, jclass cls, return mid; } +static int jvm_attach(JNIEnv **env) +{ + char name[17] = {0}; + + JavaVMAttachArgs args; + + args.version = JNI_VERSION_1_6; + if (prctl(PR_GET_NAME, name) == 0) { + args.name = name; + } else { + args.name = NULL; + } + args.group = NULL; + + return (*android_jvm)->AttachCurrentThread(android_jvm, env, &args); +} + void ares_library_init_jvm(JavaVM *jvm) { android_jvm = jvm; @@ -105,7 +118,7 @@ int ares_library_init_android(jobject connectivity_manager) res = (*android_jvm)->GetEnv(android_jvm, (void **)&env, JNI_VERSION_1_6); if (res == JNI_EDETACHED) { env = NULL; - res = (*android_jvm)->AttachCurrentThread(android_jvm, &env, NULL); + res = jvm_attach(&env); need_detatch = 1; } if (res != JNI_OK || env == NULL) { @@ -238,7 +251,7 @@ void ares_library_cleanup_android(void) res = (*android_jvm)->GetEnv(android_jvm, (void **)&env, JNI_VERSION_1_6); if (res == JNI_EDETACHED) { env = NULL; - res = (*android_jvm)->AttachCurrentThread(android_jvm, &env, NULL); + res = jvm_attach(&env); need_detatch = 1; } if (res != JNI_OK || env == NULL) { @@ -290,7 +303,7 @@ char **ares_get_android_server_list(size_t max_servers, size_t *num_servers) res = (*android_jvm)->GetEnv(android_jvm, (void **)&env, JNI_VERSION_1_6); if (res == JNI_EDETACHED) { env = NULL; - res = (*android_jvm)->AttachCurrentThread(android_jvm, &env, NULL); + res = jvm_attach(&env); need_detatch = 1; } if (res != JNI_OK || env == NULL) { @@ -408,7 +421,7 @@ char *ares_get_android_search_domains_list(void) res = (*android_jvm)->GetEnv(android_jvm, (void **)&env, JNI_VERSION_1_6); if (res == JNI_EDETACHED) { env = NULL; - res = (*android_jvm)->AttachCurrentThread(android_jvm, &env, NULL); + res = jvm_attach(&env); need_detatch = 1; } if (res != JNI_OK || env == NULL) { diff --git a/contrib/libs/c-ares/src/lib/ares_cancel.c b/contrib/libs/c-ares/src/lib/ares_cancel.c index 5a9fb722cb..c29d8ef82f 100644 --- a/contrib/libs/c-ares/src/lib/ares_cancel.c +++ b/contrib/libs/c-ares/src/lib/ares_cancel.c @@ -24,10 +24,6 @@ * SPDX-License-Identifier: MIT */ -#include "ares_setup.h" -#include <assert.h> - -#include "ares.h" #include "ares_private.h" /* @@ -57,35 +53,33 @@ void ares_cancel(ares_channel_t *channel) /* Out of memory, this function doesn't return a result code though so we * can't report to caller */ if (channel->all_queries == NULL) { - channel->all_queries = list_copy; - goto done; + channel->all_queries = list_copy; /* LCOV_EXCL_LINE: OutOfMemory */ + goto done; /* LCOV_EXCL_LINE: OutOfMemory */ } node = ares__llist_node_first(list_copy); while (node != NULL) { - struct query *query; - struct server_connection *conn; + ares_query_t *query; /* Cache next since this node is being deleted */ next = ares__llist_node_next(node); query = ares__llist_node_claim(node); - conn = query->conn; query->node_all_queries = NULL; /* NOTE: its possible this may enqueue new queries */ query->callback(query->arg, ARES_ECANCELLED, 0, NULL); ares__free_query(query); - /* See if the connection should be cleaned up */ - ares__check_cleanup_conn(channel, conn); - node = next; } ares__llist_destroy(list_copy); } + /* See if the connections should be cleaned up */ + ares__check_cleanup_conns(channel); + ares_queue_notify_empty(channel); done: diff --git a/contrib/libs/c-ares/src/lib/ares_config-linux.h b/contrib/libs/c-ares/src/lib/ares_config-linux.h index ff485b0d38..d18434ea63 100644 --- a/contrib/libs/c-ares/src/lib/ares_config-linux.h +++ b/contrib/libs/c-ares/src/lib/ares_config-linux.h @@ -41,22 +41,22 @@ #define GETSERVBYNAME_R_ARGS 6 /* Define to 1 if you have AF_INET6. */ -#define HAVE_AF_INET6 +#define HAVE_AF_INET6 1 /* Define to 1 if you have the <arpa/inet.h> header file. */ -#define HAVE_ARPA_INET_H +#define HAVE_ARPA_INET_H 1 /* Define to 1 if you have the <arpa/nameser_compat.h> header file. */ -#define HAVE_ARPA_NAMESER_COMPAT_H +#define HAVE_ARPA_NAMESER_COMPAT_H 1 /* Define to 1 if you have the <arpa/nameser.h> header file. */ -#define HAVE_ARPA_NAMESER_H +#define HAVE_ARPA_NAMESER_H 1 /* Define to 1 if you have the <assert.h> header file. */ -#define HAVE_ASSERT_H +#define HAVE_ASSERT_H 1 /* Define to 1 if you have the clock_gettime function and monotonic timer. */ -#define HAVE_CLOCK_GETTIME_MONOTONIC +#define HAVE_CLOCK_GETTIME_MONOTONIC 1 /* Define to 1 if you have the closesocket function. */ /* #undef HAVE_CLOSESOCKET */ @@ -65,79 +65,82 @@ /* #undef HAVE_CLOSESOCKET_CAMEL */ /* Define to 1 if you have the connect function. */ -#define HAVE_CONNECT +#define HAVE_CONNECT 1 + +/* Define to 1 if you have the connectx function. */ +/* #undef HAVE_CONNECTX */ /* define if the compiler supports basic C++11 syntax */ /* #undef HAVE_CXX11 */ /* Define to 1 if you have the <dlfcn.h> header file. */ -#define HAVE_DLFCN_H +#define HAVE_DLFCN_H 1 /* Define to 1 if you have the <errno.h> header file. */ -#define HAVE_ERRNO_H +#define HAVE_ERRNO_H 1 /* Define to 1 if you have the <poll.h> header file. */ -#define HAVE_POLL_H +#define HAVE_POLL_H 1 /* Define to 1 if you have the poll function. */ -#define HAVE_POLL +#define HAVE_POLL 1 /* Define to 1 if you have the pipe function. */ -#define HAVE_PIPE +#define HAVE_PIPE 1 /* Define to 1 if you have the pipe2 function. */ -#define HAVE_PIPE2 +#define HAVE_PIPE2 1 /* Define to 1 if you have the kqueue function. */ /* #undef HAVE_KQUEUE */ /* Define to 1 if you have the epoll{_create,ctl,wait} functions. */ -#define HAVE_EPOLL +#define HAVE_EPOLL 1 /* Define to 1 if you have the fcntl function. */ -#define HAVE_FCNTL +#define HAVE_FCNTL 1 /* Define to 1 if you have the <fcntl.h> header file. */ -#define HAVE_FCNTL_H +#define HAVE_FCNTL_H 1 /* Define to 1 if you have a working fcntl O_NONBLOCK function. */ -#define HAVE_FCNTL_O_NONBLOCK +#define HAVE_FCNTL_O_NONBLOCK 1 /* Define to 1 if you have the freeaddrinfo function. */ -#define HAVE_FREEADDRINFO +#define HAVE_FREEADDRINFO 1 /* Define to 1 if you have a working getaddrinfo function. */ -#define HAVE_GETADDRINFO +#define HAVE_GETADDRINFO 1 /* Define to 1 if the getaddrinfo function is threadsafe. */ /* #undef HAVE_GETADDRINFO_THREADSAFE */ /* Define to 1 if you have the getenv function. */ -#define HAVE_GETENV +#define HAVE_GETENV 1 /* Define to 1 if you have the gethostname function. */ -#define HAVE_GETHOSTNAME +#define HAVE_GETHOSTNAME 1 /* Define to 1 if you have the getnameinfo function. */ -#define HAVE_GETNAMEINFO +#define HAVE_GETNAMEINFO 1 /* Define to 1 if you have the getrandom function. */ -#define HAVE_GETRANDOM +#define HAVE_GETRANDOM 1 /* Define to 1 if you have the getservbyport_r function. */ -#define HAVE_GETSERVBYPORT_R +#define HAVE_GETSERVBYPORT_R 1 /* Define to 1 if you have the getservbyname_r function. */ -#define HAVE_GETSERVBYNAME_R +#define HAVE_GETSERVBYNAME_R 1 /* Define to 1 if you have the `gettimeofday' function. */ -#define HAVE_GETTIMEOFDAY +#define HAVE_GETTIMEOFDAY 1 /* Define to 1 if you have the `if_indextoname' function. */ -#define HAVE_IF_INDEXTONAME +#define HAVE_IF_INDEXTONAME 1 /* Define to 1 if you have the `if_nametoindex' function. */ -#define HAVE_IF_NAMETOINDEX +#define HAVE_IF_NAMETOINDEX 1 /* Define to 1 if you have the `ConvertInterfaceIndexToLuid' function. */ /* #undef HAVE_CONVERTINTERFACEINDEXTOLUID */ @@ -145,20 +148,26 @@ /* Define to 1 if you have the `ConvertInterfaceLuidToNameA' function. */ /* #undef HAVE_CONVERTINTERFACELUIDTONAMEA */ +/* Define to 1 if you have the `NotifyIpInterfaceChange' function. */ +/* #undef HAVE_NOTIFYIPINTERFACECHANGE */ + +/* Define to 1 if you have the `RegisterWaitForSingleObject' function. */ +/* #undef HAVE_REGISTERWAITFORSINGLEOBJECT */ + /* Define to 1 if you have a IPv6 capable working inet_net_pton function. */ /* #undef HAVE_INET_NET_PTON */ /* Define to 1 if you have a IPv6 capable working inet_ntop function. */ -#define HAVE_INET_NTOP +#define HAVE_INET_NTOP 1 /* Define to 1 if you have a IPv6 capable working inet_pton function. */ -#define HAVE_INET_PTON +#define HAVE_INET_PTON 1 /* Define to 1 if you have the <inttypes.h> header file. */ -#define HAVE_INTTYPES_H +#define HAVE_INTTYPES_H 1 /* Define to 1 if you have the ioctl function. */ -#define HAVE_IOCTL +#define HAVE_IOCTL 1 /* Define to 1 if you have the ioctlsocket function. */ /* #undef HAVE_IOCTLSOCKET */ @@ -174,10 +183,10 @@ /* #undef HAVE_IOCTLSOCKET_FIONBIO */ /* Define to 1 if you have a working ioctl FIONBIO function. */ -#define HAVE_IOCTL_FIONBIO +#define HAVE_IOCTL_FIONBIO 1 /* Define to 1 if you have a working ioctl SIOCGIFADDR function. */ -#define HAVE_IOCTL_SIOCGIFADDR +#define HAVE_IOCTL_SIOCGIFADDR 1 /* Define to 1 if you have the `resolve' library (-lresolve). */ /* #undef HAVE_LIBRESOLV */ @@ -189,97 +198,97 @@ /* #undef HAVE_NETIOAPI_H */ /* Define to 1 if you have the <limits.h> header file. */ -#define HAVE_LIMITS_H +#define HAVE_LIMITS_H 1 /* Define to 1 if the compiler supports the 'long long' data type. */ -#define HAVE_LONGLONG +#define HAVE_LONGLONG 1 /* Define to 1 if you have the malloc.h header file. */ -#define HAVE_MALLOC_H +#define HAVE_MALLOC_H 1 /* Define to 1 if you have the memory.h header file. */ -#define HAVE_MEMORY_H +#define HAVE_MEMORY_H 1 /* Define to 1 if you have the AvailabilityMacros.h header file. */ /* #undef HAVE_AVAILABILITYMACROS_H */ /* Define to 1 if you have the MSG_NOSIGNAL flag. */ -#define HAVE_MSG_NOSIGNAL +#define HAVE_MSG_NOSIGNAL 1 /* Define to 1 if you have the <netdb.h> header file. */ -#define HAVE_NETDB_H +#define HAVE_NETDB_H 1 /* Define to 1 if you have the <netinet/in.h> header file. */ -#define HAVE_NETINET_IN_H +#define HAVE_NETINET_IN_H 1 /* Define to 1 if you have the <netinet6/in6.h> header file. */ /* #undef HAVE_NETINET6_IN6_H */ /* Define to 1 if you have the <netinet/tcp.h> header file. */ -#define HAVE_NETINET_TCP_H +#define HAVE_NETINET_TCP_H 1 /* Define to 1 if you have the <net/if.h> header file. */ -#define HAVE_NET_IF_H +#define HAVE_NET_IF_H 1 /* Define to 1 if you have PF_INET6. */ -#define HAVE_PF_INET6 +#define HAVE_PF_INET6 1 /* Define to 1 if you have the recv function. */ -#define HAVE_RECV +#define HAVE_RECV 1 /* Define to 1 if you have the recvfrom function. */ -#define HAVE_RECVFROM +#define HAVE_RECVFROM 1 /* Define to 1 if you have the send function. */ -#define HAVE_SEND +#define HAVE_SEND 1 /* Define to 1 if you have the setsockopt function. */ -#define HAVE_SETSOCKOPT +#define HAVE_SETSOCKOPT 1 /* Define to 1 if you have a working setsockopt SO_NONBLOCK function. */ /* #undef HAVE_SETSOCKOPT_SO_NONBLOCK */ /* Define to 1 if you have the <signal.h> header file. */ -#define HAVE_SIGNAL_H +#define HAVE_SIGNAL_H 1 /* Define to 1 if your struct sockaddr_in6 has sin6_scope_id. */ -#define HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID +#define HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID 1 /* Define to 1 if you have the socket function. */ -#define HAVE_SOCKET +#define HAVE_SOCKET 1 /* Define to 1 if you have the <socket.h> header file. */ /* #undef HAVE_SOCKET_H */ /* Define to 1 if you have the <stdbool.h> header file. */ -#define HAVE_STDBOOL_H +#define HAVE_STDBOOL_H 1 /* Define to 1 if you have the <stdint.h> header file. */ -#define HAVE_STDINT_H +#define HAVE_STDINT_H 1 /* Define to 1 if you have the <stdlib.h> header file. */ -#define HAVE_STDLIB_H +#define HAVE_STDLIB_H 1 /* Define to 1 if you have the strcasecmp function. */ -#define HAVE_STRCASECMP +#define HAVE_STRCASECMP 1 /* Define to 1 if you have the strcmpi function. */ /* #undef HAVE_STRCMPI */ /* Define to 1 if you have the strdup function. */ -#define HAVE_STRDUP +#define HAVE_STRDUP 1 /* Define to 1 if you have the stricmp function. */ /* #undef HAVE_STRICMP */ /* Define to 1 if you have the <strings.h> header file. */ -#define HAVE_STRINGS_H +#define HAVE_STRINGS_H 1 /* Define to 1 if you have the <string.h> header file. */ -#define HAVE_STRING_H +#define HAVE_STRING_H 1 /* Define to 1 if you have the strncasecmp function. */ -#define HAVE_STRNCASECMP +#define HAVE_STRNCASECMP 1 /* Define to 1 if you have the strncmpi function. */ /* #undef HAVE_STRNCMPI */ @@ -291,61 +300,61 @@ /* #undef HAVE_STROPTS_H */ /* Define to 1 if you have struct addrinfo. */ -#define HAVE_STRUCT_ADDRINFO +#define HAVE_STRUCT_ADDRINFO 1 /* Define to 1 if you have struct in6_addr. */ -#define HAVE_STRUCT_IN6_ADDR +#define HAVE_STRUCT_IN6_ADDR 1 /* Define to 1 if you have struct sockaddr_in6. */ -#define HAVE_STRUCT_SOCKADDR_IN6 +#define HAVE_STRUCT_SOCKADDR_IN6 1 /* if struct sockaddr_storage is defined */ -#define HAVE_STRUCT_SOCKADDR_STORAGE +#define HAVE_STRUCT_SOCKADDR_STORAGE 1 /* Define to 1 if you have the timeval struct. */ -#define HAVE_STRUCT_TIMEVAL +#define HAVE_STRUCT_TIMEVAL 1 /* Define to 1 if you have the <sys/ioctl.h> header file. */ -#define HAVE_SYS_IOCTL_H +#define HAVE_SYS_IOCTL_H 1 /* Define to 1 if you have the <sys/param.h> header file. */ -#define HAVE_SYS_PARAM_H +#define HAVE_SYS_PARAM_H 1 /* Define to 1 if you have the <sys/random.h> header file. */ -#define HAVE_SYS_RANDOM_H +#define HAVE_SYS_RANDOM_H 1 /* Define to 1 if you have the <sys/event.h> header file. */ /* #undef HAVE_SYS_EVENT_H */ /* Define to 1 if you have the <sys/epoll.h> header file. */ -#define HAVE_SYS_EPOLL_H +#define HAVE_SYS_EPOLL_H 1 /* Define to 1 if you have the <sys/select.h> header file. */ -#define HAVE_SYS_SELECT_H +#define HAVE_SYS_SELECT_H 1 /* Define to 1 if you have the <sys/socket.h> header file. */ -#define HAVE_SYS_SOCKET_H +#define HAVE_SYS_SOCKET_H 1 /* Define to 1 if you have the <sys/stat.h> header file. */ -#define HAVE_SYS_STAT_H +#define HAVE_SYS_STAT_H 1 /* Define to 1 if you have the <sys/time.h> header file. */ -#define HAVE_SYS_TIME_H +#define HAVE_SYS_TIME_H 1 /* Define to 1 if you have the <sys/types.h> header file. */ -#define HAVE_SYS_TYPES_H +#define HAVE_SYS_TYPES_H 1 /* Define to 1 if you have the <sys/uio.h> header file. */ -#define HAVE_SYS_UIO_H +#define HAVE_SYS_UIO_H 1 /* Define to 1 if you have the <time.h> header file. */ -#define HAVE_TIME_H +#define HAVE_TIME_H 1 /* Define to 1 if you have the <ifaddrs.h> header file. */ -#define HAVE_IFADDRS_H +#define HAVE_IFADDRS_H 1 /* Define to 1 if you have the <unistd.h> header file. */ -#define HAVE_UNISTD_H +#define HAVE_UNISTD_H 1 /* Define to 1 if you have the windows.h header file. */ /* #undef HAVE_WINDOWS_H */ @@ -369,7 +378,7 @@ /* #undef HAVE_NTDEF_H */ /* Define to 1 if you have the writev function. */ -#define HAVE_WRITEV +#define HAVE_WRITEV 1 /* Define to 1 if you have the ws2tcpip.h header file. */ /* #undef HAVE_WS2TCPIP_H */ @@ -377,20 +386,14 @@ /* Define to 1 if you have the __system_property_get function */ /* #undef HAVE___SYSTEM_PROPERTY_GET */ -/* Define to 1 if you need the malloc.h header file even with stdlib.h */ -/* #undef NEED_MALLOC_H */ - -/* Define to 1 if you need the memory.h header file even with stdlib.h */ -/* #undef NEED_MEMORY_H */ - /* Define if have arc4random_buf() */ /* #undef HAVE_ARC4RANDOM_BUF */ /* Define if have getifaddrs() */ -#define HAVE_GETIFADDRS +#define HAVE_GETIFADDRS 1 /* Define if have stat() */ -#define HAVE_STAT +#define HAVE_STAT 1 /* a suitable file/device to read random data from */ #define CARES_RANDOM_FILE "/dev/urandom" @@ -443,14 +446,11 @@ /* Define to the function return type for recv. */ #define RECV_TYPE_RETV ssize_t -/* Define to the type qualifier of arg 2 for send. */ -#define SEND_QUAL_ARG2 - /* Define to the type of arg 1 for send. */ #define SEND_TYPE_ARG1 int /* Define to the type of arg 2 for send. */ -#define SEND_TYPE_ARG2 void * +#define SEND_TYPE_ARG2 const void * /* Define to the type of arg 3 for send. */ #define SEND_TYPE_ARG3 size_t @@ -468,13 +468,13 @@ #undef WIN32_LEAN_AND_MEAN /* Define to 1 if you have the pthread.h header file. */ -#define HAVE_PTHREAD_H +#define HAVE_PTHREAD_H 1 /* Define to 1 if you have the pthread_np.h header file. */ /* #undef HAVE_PTHREAD_NP_H */ /* Define to 1 if threads are enabled */ -#define CARES_THREADS +#define CARES_THREADS 1 /* Define to 1 if pthread_init() exists */ /* #undef HAVE_PTHREAD_INIT */ diff --git a/contrib/libs/c-ares/src/lib/ares_cookie.c b/contrib/libs/c-ares/src/lib/ares_cookie.c new file mode 100644 index 0000000000..0680fe9ec7 --- /dev/null +++ b/contrib/libs/c-ares/src/lib/ares_cookie.c @@ -0,0 +1,459 @@ +/* MIT License + * + * Copyright (c) 2024 Brad House + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * SPDX-License-Identifier: MIT + */ + +/* DNS cookies are a simple form of learned mutual authentication supported by + * most DNS server implementations these days and can help prevent DNS Cache + * Poisoning attacks for clients and DNS amplification attacks for servers. + * + * A good overview is here: + * https://www.dotmagazine.online/issues/digital-responsibility-and-sustainability/dns-cookies-transaction-mechanism + * + * RFCs used for implementation are + * [RFC7873](https://datatracker.ietf.org/doc/html/rfc7873) which is extended by + * [RFC9018](https://datatracker.ietf.org/doc/html/rfc9018). + * + * Though this could be used on TCP, the likelihood of it being useful is small + * and could cause some issues. TCP is better used as a fallback in case there + * are issues with DNS Cookie support in the upstream servers (e.g. AnyCast + * cluster issues). + * + * While most recursive DNS servers support DNS Cookies, public DNS servers like + * Google (8.8.8.8, 8.8.4.4) and CloudFlare (1.1.1.1, 1.0.0.1) don't seem to + * have this enabled yet for unknown reasons. + * + * The risk to having DNS Cookie support always enabled is nearly zero as there + * is built-in detection support and it will simply bypass using cookies if the + * remote server doesn't support it. The problem arises if a remote server + * supports DNS cookies, then stops supporting them (such as if an administrator + * reconfigured the server, or maybe there are different servers in a cluster + * with different configurations). We need to detect this behavior by tracking + * how much time has gone by since we received our last valid cookie reply, and + * if we exceed the threshold, reset all cookie parameters like we haven't + * attempted a request yet. + * + * ## Implementation Plan + * + * ### Constants: + * - `COOKIE_CLIENT_TIMEOUT`: 86400s (1 day) + * - How often to regenerate the per-server client cookie, even if our + * source ip address hasn't changed. + * - `COOKIE_UNSUPPORTED_TIMEOUT`: 300s (5 minutes) + * - If a server responds without a cookie in the reply, this is how long to + * wait before attempting to send a client cookie again. + * - `COOKIE_REGRESSION_TIMEOUT`: 120s (2 minutes) + * - If a server was once known to return cookies, and all of a sudden stops + * returning cookies (but the reply is otherwise valid), this is how long + * to continue to attempt to use cookies before giving up and resetting. + * Such an event would cause an outage for this duration, but since a + * cache poisoning attack should be dropping invalid replies we should be + * able to still get the valid reply and not assume it is a server + * regression just because we received replies without cookies. + * - `COOKIE_RESEND_MAX`: 3 + * - Maximum times to resend a query to a server due to the server responding + * with `BAD_COOKIE`, after this, we switch to TCP. + * + * ### Per-server variables: + * - `cookie.state`: Known state of cookie support, enumeration. + * - `INITIAL` (0): Initial state, not yet determined. Used during startup. + * - `GENERATED` (1): Cookie has been generated and sent to a server, but no + * validated response yet. + * - `SUPPORTED` (2): Server has been determined to properly support cookies + * - `UNSUPPORTED` (3): Server has been determined to not support cookies + * - `cookie.client` : 8 byte randomly generated client cookie + * - `cookie.client_ts`: Timestamp client cookie was generated + * - `cookie.client_ip`: IP address client used to connect to server + * - `cookie.server`: 8 to 32 byte server cookie + * - `cookie.server_len`: length of server cookie + * - `cookie.unsupported_ts`: Timestamp of last attempt to use a cookies, but + * it was determined that the server didn't support them. + * + * ### Per-query variables: + * - `query.client_cookie`: Duplicate of `cookie.client` at the point in time + * the query is put on the wire. This should be available in the + * `ares_dns_record_t` for the request for verification purposes so we don't + * actually need to duplicate this, just naming it here for the ease of + * documentation below. + * - `query.cookie_try_count`: Number of tries to send a cookie but receive + * `BAD_COOKIE` responses. Used to know when we need to switch to TCP. + * + * ### Procedure: + * **NOTE**: These steps will all be done after obtaining a connection handle as + * some of these steps depend on determining the source ip address for the + * connection. + * + * 1. If the query is not using EDNS, then **skip any remaining processing**. + * 2. If using TCP, ensure there is no EDNS cookie opt (10) set (there may have + * been if this is a resend after upgrade to TCP), then **skip any remaining + * processing**. + * 3. If `cookie.state == SUPPORTED`, `cookie.unsupported_ts` is non-zero, and + * evaluates greater than `COOKIE_REGRESSION_TIMEOUT`, then clear all cookie + * settings, set `cookie.state = INITIAL`. Continue to next step (4) + * 4. If `cookie.state == UNSUPPORTED` + * - If `cookie.unsupported_ts` evaluates less than + * `COOKIE_UNSUPPORTED_TIMEOUT` + * - Ensure there is no EDNS cookie opt (10) set (shouldn't be unless + * requestor had put this themselves), then **skip any remaining + * processing** as we don't want to try to send cookies. + * - Otherwise: + * - clear all cookie settings, set `cookie.state = INITIAL`. + * - Continue to next step (5) which will send a new cookie. + * 5. If `cookie.state == INITIAL`: + * - randomly generate new `cookie.client` + * - set `cookie.client_ts` to the current timestamp. + * - set `cookie.state = GENERATED`. + * - set `cookie.client_ip` to the current source ip address. + * 6. If `cookie.state == GENERATED || cookie.state == SUPPORTED` and + * `cookie.client_ip` does not match the current source ip address: + * - clear `cookie.server` + * - randomly generate new `cookie.client` + * - set `cookie.client_ts` to the current timestamp. + * - set `cookie.client_ip` to the current source ip address. + * - do not change the `cookie.state` + * 7. If `cookie.state == SUPPORTED` and `cookie.client_ts` evaluation exceeds + * `COOKIE_CLIENT_TIMEOUT`: + * - clear `cookie.server` + * - randomly generate new `cookie.client` + * - set `cookie.client_ts` to the current timestamp. + * - set `cookie.client_ip` to the current source ip address. + * - do not change the `cookie.state` + * 8. Generate EDNS OPT record (10) for client cookie. The option value will be + * the `cookie.client` concatenated with the `cookie.server`. If there is no + * known server cookie, it will not be appended. Copy `cookie.client` to + * `query.client_cookie` to handle possible client cookie changes by other + * queries before a reply is received (technically this is in the cached + * `ares_dns_record_t` so no need to manually do this). Send request to + * server. + * 9. Evaluate response: + * 1. If invalid EDNS OPT cookie (10) length sent back in response (valid + * length is 16-40), or bad client cookie value (validate first 8 bytes + * against `query.client_cookie` not `cookie.client`), **drop response** + * as if it hadn't been received. This is likely a spoofing attack. + * Wait for valid response up to normal response timeout. + * 2. If a EDNS OPT cookie (10) server cookie is returned: + * - set `cookie.unsupported_ts` to zero and `cookie.state = SUPPORTED`. + * We can confirm this server supports cookies based on the existence + * of this record. + * - If a new EDNS OPT cookie (10) server cookie is in the response, and + * the `client.cookie` matches the `query.client_cookie` still (hasn't + * been rotated by some other parallel query), save it as + * `cookie.server`. + * 3. If dns response `rcode` is `BAD_COOKIE`: + * - Ensure a EDNS OPT cookie (10) is returned, otherwise **drop + * response**, this is completely invalid and likely an spoof of some + * sort. + * - Otherwise + * - Increment `query.cookie_try_count` + * - If `query.cookie_try_count >= COOKIE_RESEND_MAX`, set + * `query.using_tcp` to force the next attempt to use TCP. + * - **Requeue the query**, but do not increment the normal + * `try_count` as a `BAD_COOKIE` reply isn't a normal try failure. + * This should end up going all the way back to step 1 on the next + * attempt. + * 4. If EDNS OPT cookie (10) is **NOT** returned in the response: + * - If `cookie.state == SUPPORTED` + * - if `cookie.unsupported_ts` is zero, set to the current timestamp. + * - Drop the response, wait for a valid response to be returned + * - if `cookie.state == GENERATED` + * - clear all cookie settings + * - set `cookie.state = UNSUPPORTED` + * - set `cookie.unsupported_ts` to the current time + * - Accept response (state should be `UNSUPPORTED` if we're here) + */ + +#include "ares_private.h" + +/* 1 day */ +#define COOKIE_CLIENT_TIMEOUT_MS (86400 * 1000) + +/* 5 minutes */ +#define COOKIE_UNSUPPORTED_TIMEOUT_MS (300 * 1000) + +/* 2 minutes */ +#define COOKIE_REGRESSION_TIMEOUT_MS (120 * 1000) + +#define COOKIE_RESEND_MAX 3 + +static const unsigned char * + ares_dns_cookie_fetch(const ares_dns_record_t *dnsrec, size_t *len) +{ + const ares_dns_rr_t *rr = ares_dns_get_opt_rr_const(dnsrec); + const unsigned char *val = NULL; + *len = 0; + + if (rr == NULL) { + return NULL; + } + + if (!ares_dns_rr_get_opt_byid(rr, ARES_RR_OPT_OPTIONS, ARES_OPT_PARAM_COOKIE, + &val, len)) { + return NULL; + } + + return val; +} + +static ares_bool_t timeval_is_set(const ares_timeval_t *tv) +{ + if (tv->sec != 0 && tv->usec != 0) { + return ARES_TRUE; + } + return ARES_FALSE; +} + +static ares_bool_t timeval_expired(const ares_timeval_t *tv, + const ares_timeval_t *now, + unsigned long millsecs) +{ + ares_int64_t tvdiff_ms; + ares_timeval_t tvdiff; + ares__timeval_diff(&tvdiff, tv, now); + + tvdiff_ms = tvdiff.sec * 1000 + tvdiff.usec / 1000; + if (tvdiff_ms >= (ares_int64_t)millsecs) { + return ARES_TRUE; + } + return ARES_FALSE; +} + +static void ares_cookie_clear(ares_cookie_t *cookie) +{ + memset(cookie, 0, sizeof(*cookie)); + cookie->state = ARES_COOKIE_INITIAL; +} + +static void ares_cookie_generate(ares_cookie_t *cookie, ares_conn_t *conn, + const ares_timeval_t *now) +{ + ares_channel_t *channel = conn->server->channel; + + ares__rand_bytes(channel->rand_state, cookie->client, sizeof(cookie->client)); + memcpy(&cookie->client_ts, now, sizeof(cookie->client_ts)); + memcpy(&cookie->client_ip, &conn->self_ip, sizeof(cookie->client_ip)); +} + +static void ares_cookie_clear_server(ares_cookie_t *cookie) +{ + memset(cookie->server, 0, sizeof(cookie->server)); + cookie->server_len = 0; +} + +static ares_bool_t ares_addr_equal(const struct ares_addr *addr1, + const struct ares_addr *addr2) +{ + if (addr1->family != addr2->family) { + return ARES_FALSE; + } + + switch (addr1->family) { + case AF_INET: + if (memcmp(&addr1->addr.addr4, &addr2->addr.addr4, + sizeof(addr1->addr.addr4)) == 0) { + return ARES_TRUE; + } + break; + case AF_INET6: + /* This structure is weird, and due to padding SonarCloud complains if + * you don't punch all the way down. At some point we should rework + * this structure */ + if (memcmp(&addr1->addr.addr6._S6_un._S6_u8, + &addr2->addr.addr6._S6_un._S6_u8, + sizeof(addr1->addr.addr6._S6_un._S6_u8)) == 0) { + return ARES_TRUE; + } + break; + default: + break; /* LCOV_EXCL_LINE */ + } + + return ARES_FALSE; +} + +ares_status_t ares_cookie_apply(ares_dns_record_t *dnsrec, ares_conn_t *conn, + const ares_timeval_t *now) +{ + ares_server_t *server = conn->server; + ares_cookie_t *cookie = &server->cookie; + ares_dns_rr_t *rr = ares_dns_get_opt_rr(dnsrec); + unsigned char c[40]; + size_t c_len; + + /* If there is no OPT record, then EDNS isn't supported, and therefore + * cookies can't be supported */ + if (rr == NULL) { + return ARES_SUCCESS; + } + + /* No cookies on TCP, make sure we remove one if one is present */ + if (conn->flags & ARES_CONN_FLAG_TCP) { + ares_dns_rr_del_opt_byid(rr, ARES_RR_OPT_OPTIONS, ARES_OPT_PARAM_COOKIE); + return ARES_SUCCESS; + } + + /* Look for regression */ + if (cookie->state == ARES_COOKIE_SUPPORTED && + timeval_is_set(&cookie->unsupported_ts) && + timeval_expired(&cookie->unsupported_ts, now, + COOKIE_REGRESSION_TIMEOUT_MS)) { + ares_cookie_clear(cookie); + } + + /* Handle unsupported state */ + if (cookie->state == ARES_COOKIE_UNSUPPORTED) { + /* If timer hasn't expired, just delete any possible cookie and return */ + if (!timeval_expired(&cookie->unsupported_ts, now, + COOKIE_REGRESSION_TIMEOUT_MS)) { + ares_dns_rr_del_opt_byid(rr, ARES_RR_OPT_OPTIONS, ARES_OPT_PARAM_COOKIE); + return ARES_SUCCESS; + } + + /* We want to try to "learn" again */ + ares_cookie_clear(cookie); + } + + /* Generate a new cookie */ + if (cookie->state == ARES_COOKIE_INITIAL) { + ares_cookie_generate(cookie, conn, now); + cookie->state = ARES_COOKIE_GENERATED; + } + + /* Regenerate the cookie and clear the server cookie if the client ip has + * changed */ + if ((cookie->state == ARES_COOKIE_GENERATED || + cookie->state == ARES_COOKIE_SUPPORTED) && + !ares_addr_equal(&conn->self_ip, &cookie->client_ip)) { + ares_cookie_clear_server(cookie); + ares_cookie_generate(cookie, conn, now); + } + + /* If the client cookie has reached its maximum time, refresh it */ + if (cookie->state == ARES_COOKIE_SUPPORTED && + timeval_expired(&cookie->client_ts, now, COOKIE_CLIENT_TIMEOUT_MS)) { + ares_cookie_clear_server(cookie); + ares_cookie_generate(cookie, conn, now); + } + + /* Generate the full cookie which is the client cookie concatenated with the + * server cookie (if there is one) and apply it. */ + memcpy(c, cookie->client, sizeof(cookie->client)); + if (cookie->server_len) { + memcpy(c + sizeof(cookie->client), cookie->server, cookie->server_len); + } + c_len = sizeof(cookie->client) + cookie->server_len; + + return ares_dns_rr_set_opt(rr, ARES_RR_OPT_OPTIONS, ARES_OPT_PARAM_COOKIE, c, + c_len); +} + +ares_status_t ares_cookie_validate(ares_query_t *query, + const ares_dns_record_t *dnsresp, + ares_conn_t *conn, const ares_timeval_t *now) +{ + ares_server_t *server = conn->server; + ares_cookie_t *cookie = &server->cookie; + const ares_dns_record_t *dnsreq = query->query; + const unsigned char *resp_cookie; + size_t resp_cookie_len; + const unsigned char *req_cookie; + size_t req_cookie_len; + + resp_cookie = ares_dns_cookie_fetch(dnsresp, &resp_cookie_len); + + /* Invalid cookie length, drop */ + if (resp_cookie && (resp_cookie_len < 8 || resp_cookie_len > 40)) { + return ARES_EBADRESP; + } + + req_cookie = ares_dns_cookie_fetch(dnsreq, &req_cookie_len); + + /* Didn't request cookies, so we can stop evaluating */ + if (req_cookie == NULL) { + return ARES_SUCCESS; + } + + /* If 8-byte prefix for returned cookie doesn't match the requested cookie, + * drop for spoofing */ + if (resp_cookie && memcmp(req_cookie, resp_cookie, 8) != 0) { + return ARES_EBADRESP; + } + + if (resp_cookie && resp_cookie_len > 8) { + /* Make sure we record that we successfully received a cookie response */ + cookie->state = ARES_COOKIE_SUPPORTED; + memset(&cookie->unsupported_ts, 0, sizeof(cookie->unsupported_ts)); + + /* If client cookie hasn't been rotated, save the returned server cookie */ + if (memcmp(cookie->client, req_cookie, sizeof(cookie->client)) == 0) { + cookie->server_len = resp_cookie_len - 8; + memcpy(cookie->server, resp_cookie + 8, cookie->server_len); + } + } + + if (ares_dns_record_get_rcode(dnsresp) == ARES_RCODE_BADCOOKIE) { + /* Illegal to return BADCOOKIE but no cookie, drop */ + if (resp_cookie == NULL) { + return ARES_EBADRESP; + } + + /* If we have too many attempts to send a cookie, we need to requeue as + * tcp */ + query->cookie_try_count++; + if (query->cookie_try_count >= COOKIE_RESEND_MAX) { + query->using_tcp = ARES_TRUE; + } + + /* Resend the request, hopefully it will work the next time as we should + * have recorded a server cookie */ + ares__requeue_query(query, now, ARES_SUCCESS, + ARES_FALSE /* Don't increment try count */); + + /* Parent needs to drop this response */ + return ARES_EBADRESP; + } + + /* We've got a response with a server cookie, and we've done all the + * evaluation we can, return success */ + if (resp_cookie_len > 8) { + return ARES_SUCCESS; + } + + if (cookie->state == ARES_COOKIE_SUPPORTED) { + /* If we're not currently tracking an error time yet, start */ + if (!timeval_is_set(&cookie->unsupported_ts)) { + memcpy(&cookie->unsupported_ts, now, sizeof(cookie->unsupported_ts)); + } + /* Drop it since we expected a cookie */ + return ARES_EBADRESP; + } + + if (cookie->state == ARES_COOKIE_GENERATED) { + ares_cookie_clear(cookie); + cookie->state = ARES_COOKIE_UNSUPPORTED; + memcpy(&cookie->unsupported_ts, now, sizeof(cookie->unsupported_ts)); + } + + /* Cookie state should be UNSUPPORTED if we're here */ + return ARES_SUCCESS; +} diff --git a/contrib/libs/c-ares/src/lib/ares_data.c b/contrib/libs/c-ares/src/lib/ares_data.c index e37088283b..d25c3fafff 100644 --- a/contrib/libs/c-ares/src/lib/ares_data.c +++ b/contrib/libs/c-ares/src/lib/ares_data.c @@ -24,14 +24,10 @@ * SPDX-License-Identifier: MIT */ - -#include "ares_setup.h" - +#include "ares_private.h" #include <stddef.h> - -#include "ares.h" +#include <assert.h> #include "ares_data.h" -#include "ares_private.h" /* ** ares_free_data() - c-ares external API function. diff --git a/contrib/libs/c-ares/src/lib/ares_destroy.c b/contrib/libs/c-ares/src/lib/ares_destroy.c index 672f8b0618..d75b5e227c 100644 --- a/contrib/libs/c-ares/src/lib/ares_destroy.c +++ b/contrib/libs/c-ares/src/lib/ares_destroy.c @@ -25,13 +25,9 @@ * SPDX-License-Identifier: MIT */ -#include "ares_setup.h" - -#include <assert.h> - -#include "ares.h" #include "ares_private.h" -#include "ares_event.h" +#include "event/ares_event.h" +#include <assert.h> void ares_destroy(ares_channel_t *channel) { @@ -42,7 +38,17 @@ void ares_destroy(ares_channel_t *channel) return; } - /* Disable configuration change monitoring */ + /* Mark as being shutdown */ + ares__channel_lock(channel); + channel->sys_up = ARES_FALSE; + ares__channel_unlock(channel); + + /* Disable configuration change monitoring. We can't hold a lock because + * some cleanup routines, such as on Windows, are synchronous operations. + * What we've observed is a system config change event was triggered right + * at shutdown time and it tries to take the channel lock and the destruction + * waits for that event to complete before it continues so we get a channel + * lock deadlock at shutdown if we hold a lock during this process. */ if (channel->optmask & ARES_OPT_EVENT_THREAD) { ares_event_thread_t *e = channel->sock_state_cb_data; if (e && e->configchg) { @@ -51,21 +57,23 @@ void ares_destroy(ares_channel_t *channel) } } - /* Wait for reinit thread to exit if there was one pending */ + /* Wait for reinit thread to exit if there was one pending, can't be + * holding a lock as the thread may take locks. */ if (channel->reinit_thread != NULL) { void *rv; ares__thread_join(channel->reinit_thread, &rv); channel->reinit_thread = NULL; } - /* Lock because callbacks will be triggered */ + /* Lock because callbacks will be triggered, and any system-generated + * callbacks need to hold a channel lock. */ ares__channel_lock(channel); /* Destroy all queries */ node = ares__llist_node_first(channel->all_queries); while (node != NULL) { ares__llist_node_t *next = ares__llist_node_next(node); - struct query *query = ares__llist_node_claim(node); + ares_query_t *query = ares__llist_node_claim(node); query->node_all_queries = NULL; query->callback(query->arg, ARES_EDESTRUCTION, 0, NULL); @@ -126,10 +134,10 @@ void ares_destroy(ares_channel_t *channel) ares_free(channel); } -void ares__destroy_server(struct server_state *server) +void ares__destroy_server(ares_server_t *server) { if (server == NULL) { - return; + return; /* LCOV_EXCL_LINE: DefensiveCoding */ } ares__close_sockets(server); @@ -144,7 +152,7 @@ void ares__destroy_servers_state(ares_channel_t *channel) ares__slist_node_t *node; while ((node = ares__slist_node_first(channel->servers)) != NULL) { - struct server_state *server = ares__slist_node_claim(node); + ares_server_t *server = ares__slist_node_claim(node); ares__destroy_server(server); } diff --git a/contrib/libs/c-ares/src/lib/ares_event_win32.c b/contrib/libs/c-ares/src/lib/ares_event_win32.c deleted file mode 100644 index 718e865085..0000000000 --- a/contrib/libs/c-ares/src/lib/ares_event_win32.c +++ /dev/null @@ -1,601 +0,0 @@ -/* MIT License - * - * Copyright (c) 2024 Brad House - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * SPDX-License-Identifier: MIT - */ - -#include "ares_setup.h" -#include "ares.h" -#include "ares_private.h" -#include "ares_event.h" -#include "ares_event_win32.h" -#ifdef HAVE_LIMITS_H -# include <limits.h> -#endif - -#ifdef _WIN32 - -/* IMPLEMENTATION NOTES - * ==================== - * - * This implementation uses some undocumented functionality within Windows for - * monitoring sockets. The Ancillary Function Driver (AFD) is the low level - * implementation that Winsock2 sits on top of. Winsock2 unfortunately does - * not expose the equivalent of epoll() or kqueue(), but it is possible to - * access AFD directly and use along with IOCP to simulate the functionality. - * We want to use IOCP if possible as it gives us the ability to monitor more - * than just sockets (WSAPoll is not an option), and perform arbitrary callbacks - * which means we can hook in non-socket related events. - * - * The information for this implementation was gathered from "wepoll" and - * "libuv" which both use slight variants on this, but this implementation - * doesn't directly follow either methodology. - * - * Initialization: - * 1. Dynamically load the NtDeviceIoControlFile and NtCancelIoFileEx internal - * symbols from ntdll.dll. These functions are used to submit the AFD POLL - * request and to cancel a prior request, respectively. - * 2. Create an IO Completion Port base handle via CreateIoCompletionPort() - * that all socket events will be delivered through. - * 3. Create a callback to be used to be able to interrupt waiting for IOCP - * events, this may be called for allowing enqueuing of additional socket - * events or removing socket events. PostQueuedCompletionStatus() is the - * obvious choice. Use the same container structure as used with a Socket - * but tagged indicating it is not as the CompletionKey (important!). - * - * Socket Add: - * 1. Create/Allocate a container for holding metadata about a socket: - * - SOCKET base_socket; - * - SOCKET peer_socket; - * - OVERLAPPED overlapped; -- Used by AFD POLL - * - AFD_POLL_INFO afd_poll_info; -- Used by AFD POLL - * 2. Call WSAIoctl(..., SIO_BASE_HANDLE, ...) to unwrap the SOCKET and get - * the "base socket" we can use for polling. It appears this may fail so - * we should call WSAIoctl(..., SIO_BSP_HANDLE_POLL, ...) as a fallback. - * 3. The SOCKET handle we have is most likely not capable of supporting - * OVERLAPPED, and we need to have a way to unbind a socket from IOCP - * (which is done via a simple closesocket()) so we need to duplicate the - * "base socket" using WSADuplicateSocketW() followed by - * WSASocketW(..., WSA_FLAG_OVERLAPPED) to create this "peer socket" for - * submitting AFD POLL requests. - * 4. Bind to IOCP using CreateIoCompletionPort() referencing the "peer - * socket" and the base IOCP handle from "Initialization". Use the - * pointer to the socket container as the "CompletionKey" which will be - * returned when an event occurs. - * 5. Submit AFD POLL request (see "AFD POLL Request" section) - * - * Socket Delete: - * 1. Call "AFD Poll Cancel" (see Section of same name) - * 2. If a cancel was requested (not bypassed due to no events, etc), tag the - * "container" for the socket as pending delete, and when the next IOCP - * event for the socket is dequeued, cleanup. - * 3. Otherwise, call closesocket(peer_socket) then free() the container - * which will officially delete it. - * NOTE: Deferring delete may be completely unnecessary. In theory closing - * the peer_socket() should guarantee no additional events will be - * delivered. But maybe if there's a pending event that hasn't been - * read yet but already trigggered it would be an issue, so this is - * "safer" unless we can prove its not necessary. - * - * Socket Modify: - * 1. Call "AFD Poll Cancel" (see Section of same name) - * 2. If a cancel was not enqueued because there is no pending request, - * submit AFD POLL request (see "AFD POLL Request" section), otherwise - * defer until next socket event. - * - * Event Wait: - * 1. Call GetQueuedCompletionStatusEx() with the base IOCP handle, a - * stack allocated array of OVERLAPPED_ENTRY's, and an appropriate - * timeout. - * 2. Iterate across returned events, the CompletionKey is a pointer to the - * container registered with CreateIoCompletionPort() or - * PostQueuedCompletionStatus() - * 3. If object indicates it is pending delete, go ahead and - * closesocket(peer_socket) and free() the container. Go to the next event. - * 4. Submit AFD POLL Request (see "AFD POLL Request"). We must re-enable - * the request each time we receive a response, it is not persistent. - * 5. Notify of any events received as indicated in the AFD_POLL_INFO - * Handles[0].Events (NOTE: check NumberOfHandles first, make sure it is - * > 0, otherwise we might not have events such as if our last request - * was cancelled). - * - * AFD Poll Request: - * 1. Initialize the AFD_POLL_INFO structure: - * Exclusive = TRUE; // Auto cancel duplicates for same socket - * NumberOfHandles = 1; - * Timeout.QuadPart = LLONG_MAX; - * Handles[0].Handle = (HANDLE)base_socket; - * Handles[0].Status = 0; - * Handles[0].Events = ... set as appropriate AFD_POLL_RECEIVE, etc; - * 2. Zero out the OVERLAPPED structure - * 3. Create an IO_STATUS_BLOCK pointer (iosb) and set it to the address of - * the OVERLAPPED "Internal" member. - * 4. Set the "Status" member of IO_STATUS_BLOCK to STATUS_PENDING - * 5. Call - * NtDeviceIoControlFile((HANDLE)peer_socket, NULL, NULL, &overlapped, - * iosb, IOCTL_AFD_POLL - * &afd_poll_info, sizeof(afd_poll_info), - * &afd_poll_info, sizeof(afd_poll_info)); - * NOTE: Its not clear to me if the IO_STATUS_BLOCK pointing to OVERLAPPED - * is for efficiency or if its a requirement for AFD. This is what - * libuv does, so I'm doing it here too. - * - * AFD Poll Cancel: - * 1. Check to see if the IO_STATUS_BLOCK "Status" member for the socket - * is still STATUS_PENDING, if not, no cancel request is necessary. - * 2. Call - * NtCancelIoFileEx((HANDLE)peer_socket, iosb, &temp_iosb); - * - * - * References: - * - https://github.com/piscisaureus/wepoll/ - * - https://github.com/libuv/libuv/ - */ - -typedef struct { - /* Dynamically loaded symbols */ - NtDeviceIoControlFile_t NtDeviceIoControlFile; - NtCancelIoFileEx_t NtCancelIoFileEx; - - /* Implementation details */ - HANDLE iocp_handle; -} ares_evsys_win32_t; - -typedef struct { - /*! Pointer to parent event container */ - ares_event_t *event; - /*! Socket passed in to monitor */ - SOCKET socket; - /*! Base socket derived from provided socket */ - SOCKET base_socket; - /*! New socket (duplicate base_socket handle) supporting OVERLAPPED operation - */ - SOCKET peer_socket; - /*! Structure for submitting AFD POLL requests (Internals!) */ - AFD_POLL_INFO afd_poll_info; - /*! Overlapped structure submitted with AFD POLL requests and returned with - * IOCP results */ - OVERLAPPED overlapped; -} ares_evsys_win32_eventdata_t; - -static void ares_iocpevent_signal(const ares_event_t *event) -{ - ares_event_thread_t *e = event->e; - ares_evsys_win32_t *ew = e->ev_sys_data; - - if (e == NULL) { - return; - } - - PostQueuedCompletionStatus(ew->iocp_handle, 0, (ULONG_PTR)event->data, NULL); -} - -static void ares_iocpevent_cb(ares_event_thread_t *e, ares_socket_t fd, - void *data, ares_event_flags_t flags) -{ - (void)e; - (void)data; - (void)fd; - (void)flags; -} - -static ares_event_t *ares_iocpevent_create(ares_event_thread_t *e) -{ - ares_event_t *event = NULL; - ares_status_t status; - - status = - ares_event_update(&event, e, ARES_EVENT_FLAG_OTHER, ares_iocpevent_cb, - ARES_SOCKET_BAD, NULL, NULL, ares_iocpevent_signal); - if (status != ARES_SUCCESS) { - return NULL; - } - - return event; -} - -static void ares_evsys_win32_destroy(ares_event_thread_t *e) -{ - ares_evsys_win32_t *ew = NULL; - - if (e == NULL) { - return; - } - - ew = e->ev_sys_data; - if (ew == NULL) { - return; - } - - if (ew->iocp_handle != NULL) { - CloseHandle(ew->iocp_handle); - } - - ares_free(ew); - e->ev_sys_data = NULL; -} - -static ares_bool_t ares_evsys_win32_init(ares_event_thread_t *e) -{ - ares_evsys_win32_t *ew = NULL; - HMODULE ntdll; - - ew = ares_malloc_zero(sizeof(*ew)); - if (ew == NULL) { - return ARES_FALSE; - } - - e->ev_sys_data = ew; - - /* All apps should have ntdll.dll already loaded, so just get a handle to - * this */ - ntdll = GetModuleHandleA("ntdll.dll"); - if (ntdll == NULL) { - goto fail; - } - - /* Load Internal symbols not typically accessible */ - ew->NtDeviceIoControlFile = (NtDeviceIoControlFile_t)(void *)GetProcAddress( - ntdll, "NtDeviceIoControlFile"); - ew->NtCancelIoFileEx = - (NtCancelIoFileEx_t)(void *)GetProcAddress(ntdll, "NtCancelIoFileEx"); - - if (ew->NtCancelIoFileEx == NULL || ew->NtDeviceIoControlFile == NULL) { - goto fail; - } - - ew->iocp_handle = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0); - if (ew->iocp_handle == NULL) { - goto fail; - } - - e->ev_signal = ares_iocpevent_create(e); - if (e->ev_signal == NULL) { - goto fail; - } - - return ARES_TRUE; - -fail: - ares_evsys_win32_destroy(e); - return ARES_FALSE; -} - -static ares_socket_t ares_evsys_win32_basesocket(ares_socket_t socket) -{ - while (1) { - DWORD bytes; /* Not used */ - ares_socket_t base_socket = ARES_SOCKET_BAD; - int rv; - - rv = WSAIoctl(socket, SIO_BASE_HANDLE, NULL, 0, &base_socket, - sizeof(base_socket), &bytes, NULL, NULL); - if (rv != SOCKET_ERROR && base_socket != ARES_SOCKET_BAD) { - socket = base_socket; - break; - } - - /* If we're here, an error occurred */ - if (GetLastError() == WSAENOTSOCK) { - /* This is critical, exit */ - return ARES_SOCKET_BAD; - } - - /* Work around known bug in Komodia based LSPs, use ARES_BSP_HANDLE_POLL - * to retrieve the underlying socket to then loop and get the base socket: - * https://docs.microsoft.com/en-us/windows/win32/winsock/winsock-ioctls - * https://www.komodia.com/newwiki/index.php?title=Komodia%27s_Redirector_bug_fixes#Version_2.2.2.6 - */ - base_socket = ARES_SOCKET_BAD; - rv = WSAIoctl(socket, SIO_BSP_HANDLE_POLL, NULL, 0, &base_socket, - sizeof(base_socket), &bytes, NULL, NULL); - - if (rv != SOCKET_ERROR && base_socket != ARES_SOCKET_BAD && - base_socket != socket) { - socket = base_socket; - continue; /* loop! */ - } - - return ARES_SOCKET_BAD; - } - - return socket; -} - -static ares_bool_t ares_evsys_win32_afd_enqueue(ares_event_t *event, - ares_event_flags_t flags) -{ - ares_event_thread_t *e = event->e; - ares_evsys_win32_t *ew = e->ev_sys_data; - ares_evsys_win32_eventdata_t *ed = event->data; - NTSTATUS status; - IO_STATUS_BLOCK *iosb_ptr; - - if (e == NULL || ed == NULL || ew == NULL) { - return ARES_FALSE; - } - - /* Enqueue AFD Poll */ - ed->afd_poll_info.Exclusive = TRUE; - ed->afd_poll_info.NumberOfHandles = 1; - ed->afd_poll_info.Timeout.QuadPart = LLONG_MAX; - ed->afd_poll_info.Handles[0].Handle = (HANDLE)ed->base_socket; - ed->afd_poll_info.Handles[0].Status = 0; - ed->afd_poll_info.Handles[0].Events = 0; - - if (flags & ARES_EVENT_FLAG_READ) { - ed->afd_poll_info.Handles[0].Events |= - (AFD_POLL_RECEIVE | AFD_POLL_DISCONNECT | AFD_POLL_ACCEPT | - AFD_POLL_ABORT); - } - if (flags & ARES_EVENT_FLAG_WRITE) { - ed->afd_poll_info.Handles[0].Events |= - (AFD_POLL_SEND | AFD_POLL_CONNECT_FAIL); - } - if (flags == 0) { - ed->afd_poll_info.Handles[0].Events |= AFD_POLL_DISCONNECT; - } - - memset(&ed->overlapped, 0, sizeof(ed->overlapped)); - iosb_ptr = (IO_STATUS_BLOCK *)&ed->overlapped.Internal; - iosb_ptr->Status = STATUS_PENDING; - - status = ew->NtDeviceIoControlFile( - (HANDLE)ed->peer_socket, NULL, NULL, &ed->overlapped, iosb_ptr, - IOCTL_AFD_POLL, &ed->afd_poll_info, sizeof(ed->afd_poll_info), - &ed->afd_poll_info, sizeof(ed->afd_poll_info)); - if (status != STATUS_SUCCESS && status != STATUS_PENDING) { - printf("%s(): failed to perform IOCTL_AFD_POLL operation\n", __FUNCTION__); - fflush(stdout); - return ARES_FALSE; - } - - return ARES_TRUE; -} - -static ares_bool_t ares_evsys_win32_afd_cancel(ares_evsys_win32_eventdata_t *ed) -{ - IO_STATUS_BLOCK *iosb_ptr; - IO_STATUS_BLOCK cancel_iosb; - ares_evsys_win32_t *ew; - NTSTATUS status; - - /* Detached due to destroy */ - if (ed->event == NULL) { - return ARES_FALSE; - } - - iosb_ptr = (IO_STATUS_BLOCK *)&ed->overlapped.Internal; - /* Not pending, nothing to do */ - if (iosb_ptr->Status != STATUS_PENDING) { - return ARES_FALSE; - } - - ew = ed->event->e->ev_sys_data; - status = - ew->NtCancelIoFileEx((HANDLE)ed->peer_socket, iosb_ptr, &cancel_iosb); - - /* NtCancelIoFileEx() may return STATUS_NOT_FOUND if the operation completed - * just before calling NtCancelIoFileEx(), but we have not yet received the - * notifiction (but it should be queued for the next IOCP event). */ - if (status == STATUS_SUCCESS || status == STATUS_NOT_FOUND) { - return ARES_TRUE; - } - - return ARES_FALSE; -} - -static void ares_evsys_win32_eventdata_destroy(ares_evsys_win32_eventdata_t *ed) -{ - if (ed == NULL) { - return; - } - - if (ed->peer_socket != ARES_SOCKET_BAD) { - closesocket(ed->peer_socket); - } - - ares_free(ed); -} - -static ares_bool_t ares_evsys_win32_event_add(ares_event_t *event) -{ - ares_event_thread_t *e = event->e; - ares_evsys_win32_t *ew = e->ev_sys_data; - ares_evsys_win32_eventdata_t *ed; - WSAPROTOCOL_INFOW protocol_info; - - ed = ares_malloc_zero(sizeof(*ed)); - ed->event = event; - ed->socket = event->fd; - ed->base_socket = ARES_SOCKET_BAD; - ed->peer_socket = ARES_SOCKET_BAD; - - /* Likely a signal event, not something we will directly handle. We create - * the ares_evsys_win32_eventdata_t as the placeholder to use as the - * IOCP Completion Key */ - if (ed->socket == ARES_SOCKET_BAD) { - event->data = ed; - return ARES_TRUE; - } - - ed->base_socket = ares_evsys_win32_basesocket(ed->socket); - if (ed->base_socket == ARES_SOCKET_BAD) { - fprintf(stderr, "%s(): could not determine base socket for fd %d\n", - __FUNCTION__, (int)event->fd); - ares_evsys_win32_eventdata_destroy(ed); - return ARES_FALSE; - } - - /* Create a peer socket that supports OVERLAPPED so we can use IOCP on the - * socket handle */ - if (WSADuplicateSocketW(ed->base_socket, GetCurrentProcessId(), - &protocol_info) != 0) { - fprintf(stderr, - "%s(): could not retrieve protocol info for creating peer socket\n", - __FUNCTION__); - ares_evsys_win32_eventdata_destroy(ed); - return ARES_FALSE; - } - - ed->peer_socket = - WSASocketW(protocol_info.iAddressFamily, protocol_info.iSocketType, - protocol_info.iProtocol, &protocol_info, 0, WSA_FLAG_OVERLAPPED); - if (ed->peer_socket == ARES_SOCKET_BAD) { - fprintf(stderr, "%s(): could not create peer socket\n", __FUNCTION__); - ares_evsys_win32_eventdata_destroy(ed); - return ARES_FALSE; - } - - SetHandleInformation((HANDLE)ed->peer_socket, HANDLE_FLAG_INHERIT, 0); - - if (CreateIoCompletionPort((HANDLE)ed->peer_socket, ew->iocp_handle, - (ULONG_PTR)ed, 0) == NULL) { - fprintf(stderr, "%s(): failed to bind peer socket to IOCP\n", __FUNCTION__); - ares_evsys_win32_eventdata_destroy(ed); - return ARES_FALSE; - } - - event->data = ed; - - if (!ares_evsys_win32_afd_enqueue(event, event->flags)) { - event->data = NULL; - ares_evsys_win32_eventdata_destroy(ed); - return ARES_FALSE; - } - - return ARES_TRUE; -} - -static void ares_evsys_win32_event_del(ares_event_t *event) -{ - ares_evsys_win32_eventdata_t *ed = event->data; - ares_event_thread_t *e = event->e; - - if (event->fd == ARES_SOCKET_BAD || !e->isup || ed == NULL || - !ares_evsys_win32_afd_cancel(ed)) { - /* Didn't need to enqueue a cancellation, for one of these reasons: - * - Not an IOCP socket - * - This is during shutdown of the event thread, no more signals can be - * delivered. - * - It has been determined there is no AFD POLL queued currently for the - * socket. - */ - ares_evsys_win32_eventdata_destroy(ed); - event->data = NULL; - } else { - /* Detach from event, so when the cancel event comes through, - * it will clean up */ - ed->event = NULL; - event->data = NULL; - } -} - -static void ares_evsys_win32_event_mod(ares_event_t *event, - ares_event_flags_t new_flags) -{ - ares_evsys_win32_eventdata_t *ed = event->data; - - /* Not for us */ - if (event->fd == ARES_SOCKET_BAD || ed == NULL) { - return; - } - - /* Try to cancel any current outstanding poll, if one is not running, - * go ahead and queue it up */ - if (!ares_evsys_win32_afd_cancel(ed)) { - ares_evsys_win32_afd_enqueue(event, new_flags); - } -} - -static size_t ares_evsys_win32_wait(ares_event_thread_t *e, - unsigned long timeout_ms) -{ - ares_evsys_win32_t *ew = e->ev_sys_data; - OVERLAPPED_ENTRY entries[16]; - ULONG nentries = sizeof(entries) / sizeof(*entries); - BOOL status; - size_t i; - size_t cnt = 0; - - status = GetQueuedCompletionStatusEx( - ew->iocp_handle, entries, nentries, &nentries, - (timeout_ms == 0) ? INFINITE : (DWORD)timeout_ms, FALSE); - - if (!status) { - return 0; - } - - for (i = 0; i < (size_t)nentries; i++) { - ares_event_flags_t flags = 0; - ares_evsys_win32_eventdata_t *ed = - (ares_evsys_win32_eventdata_t *)entries[i].lpCompletionKey; - ares_event_t *event = ed->event; - - if (ed->socket == ARES_SOCKET_BAD) { - /* Some sort of signal event */ - flags = ARES_EVENT_FLAG_OTHER; - } else { - /* Process events */ - if (ed->afd_poll_info.NumberOfHandles > 0) { - if (ed->afd_poll_info.Handles[0].Events & - (AFD_POLL_RECEIVE | AFD_POLL_DISCONNECT | AFD_POLL_ACCEPT | - AFD_POLL_ABORT)) { - flags |= ARES_EVENT_FLAG_READ; - } - if (ed->afd_poll_info.Handles[0].Events & - (AFD_POLL_SEND | AFD_POLL_CONNECT_FAIL)) { - flags |= ARES_EVENT_FLAG_WRITE; - } - - /* XXX: Handle ed->afd_poll_info.Handles[0].Events & - * AFD_POLL_LOCAL_CLOSE */ - } - - if (event == NULL) { - /* This means we need to cleanup the private event data as we've been - * detached */ - ares_evsys_win32_eventdata_destroy(ed); - } else { - /* Re-enqueue so we can get more events on the socket */ - ares_evsys_win32_afd_enqueue(event, event->flags); - } - } - - if (event != NULL && flags != 0) { - cnt++; - event->cb(e, event->fd, event->data, flags); - } - } - - return cnt; -} - -const ares_event_sys_t ares_evsys_win32 = { "win32", - ares_evsys_win32_init, - ares_evsys_win32_destroy, - ares_evsys_win32_event_add, - ares_evsys_win32_event_del, - ares_evsys_win32_event_mod, - ares_evsys_win32_wait }; -#endif diff --git a/contrib/libs/c-ares/src/lib/ares_free_hostent.c b/contrib/libs/c-ares/src/lib/ares_free_hostent.c index a088c1b15c..bf2037238b 100644 --- a/contrib/libs/c-ares/src/lib/ares_free_hostent.c +++ b/contrib/libs/c-ares/src/lib/ares_free_hostent.c @@ -24,16 +24,12 @@ * * SPDX-License-Identifier: MIT */ - -#include "ares_setup.h" +#include "ares_private.h" #ifdef HAVE_NETDB_H # include <netdb.h> #endif -#include "ares.h" -#include "ares_private.h" /* for memdebug */ - void ares_free_hostent(struct hostent *host) { char **p; diff --git a/contrib/libs/c-ares/src/lib/ares_free_string.c b/contrib/libs/c-ares/src/lib/ares_free_string.c index 39773067bd..048ad5d2ae 100644 --- a/contrib/libs/c-ares/src/lib/ares_free_string.c +++ b/contrib/libs/c-ares/src/lib/ares_free_string.c @@ -25,9 +25,6 @@ * SPDX-License-Identifier: MIT */ -#include "ares_setup.h" - -#include "ares.h" #include "ares_private.h" void ares_free_string(void *str) diff --git a/contrib/libs/c-ares/src/lib/ares_freeaddrinfo.c b/contrib/libs/c-ares/src/lib/ares_freeaddrinfo.c index 45d931a3f8..2a49f57531 100644 --- a/contrib/libs/c-ares/src/lib/ares_freeaddrinfo.c +++ b/contrib/libs/c-ares/src/lib/ares_freeaddrinfo.c @@ -25,15 +25,12 @@ * SPDX-License-Identifier: MIT */ -#include "ares_setup.h" +#include "ares_private.h" #ifdef HAVE_NETDB_H # include <netdb.h> #endif -#include "ares.h" -#include "ares_private.h" - void ares__freeaddrinfo_cnames(struct ares_addrinfo_cname *head) { struct ares_addrinfo_cname *current; diff --git a/contrib/libs/c-ares/src/lib/ares_getaddrinfo.c b/contrib/libs/c-ares/src/lib/ares_getaddrinfo.c index cfc889c70a..f67acdec2f 100644 --- a/contrib/libs/c-ares/src/lib/ares_getaddrinfo.c +++ b/contrib/libs/c-ares/src/lib/ares_getaddrinfo.c @@ -26,7 +26,7 @@ * SPDX-License-Identifier: MIT */ -#include "ares_setup.h" +#include "ares_private.h" #ifdef HAVE_GETSERVBYNAME_R # if !defined(GETSERVBYNAME_R_ARGS) || (GETSERVBYNAME_R_ARGS < 4) || \ @@ -56,14 +56,9 @@ # include <limits.h> #endif -#include "ares.h" -#include "ares_private.h" #include "ares_dns.h" -#ifdef WATT32 -# undef WIN32 -#endif -#ifdef WIN32 +#ifdef _WIN32 # include "ares_platform.h" #endif @@ -112,7 +107,7 @@ struct ares_addrinfo_cname * struct ares_addrinfo_cname *last = *head; if (tail == NULL) { - return NULL; + return NULL; /* LCOV_EXCL_LINE: OutOfMemory */ } if (!last) { @@ -152,7 +147,7 @@ struct ares_addrinfo_node * struct ares_addrinfo_node *last = *head; if (tail == NULL) { - return NULL; + return NULL; /* LCOV_EXCL_LINE: OutOfMemory */ } if (!last) { @@ -257,7 +252,7 @@ static ares_bool_t fake_addrinfo(const char *name, unsigned short port, ares_bool_t valid = ARES_TRUE; const char *p; for (p = name; *p; p++) { - if (!ISDIGIT(*p) && *p != '.') { + if (!ares__isdigit(*p) && *p != '.') { valid = ARES_FALSE; break; } else if (*p == '.') { @@ -277,8 +272,8 @@ static ares_bool_t fake_addrinfo(const char *name, unsigned short port, if (result) { status = ares_append_ai_node(AF_INET, port, 0, &addr4, &ai->nodes); if (status != ARES_SUCCESS) { - callback(arg, (int)status, 0, NULL); - return ARES_TRUE; + callback(arg, (int)status, 0, NULL); /* LCOV_EXCL_LINE: OutOfMemory */ + return ARES_TRUE; /* LCOV_EXCL_LINE: OutOfMemory */ } } } @@ -291,8 +286,8 @@ static ares_bool_t fake_addrinfo(const char *name, unsigned short port, if (result) { status = ares_append_ai_node(AF_INET6, port, 0, &addr6, &ai->nodes); if (status != ARES_SUCCESS) { - callback(arg, (int)status, 0, NULL); - return ARES_TRUE; + callback(arg, (int)status, 0, NULL); /* LCOV_EXCL_LINE: OutOfMemory */ + return ARES_TRUE; /* LCOV_EXCL_LINE: OutOfMemory */ } } } @@ -304,9 +299,11 @@ static ares_bool_t fake_addrinfo(const char *name, unsigned short port, if (hints->ai_flags & ARES_AI_CANONNAME) { cname = ares__append_addrinfo_cname(&ai->cnames); if (!cname) { + /* LCOV_EXCL_START: OutOfMemory */ ares_freeaddrinfo(ai); callback(arg, ARES_ENOMEM, 0, NULL); return ARES_TRUE; + /* LCOV_EXCL_STOP */ } /* Duplicate the name, to avoid a constness violation. */ @@ -371,7 +368,7 @@ ares_bool_t ares__is_localhost(const char *name) size_t len; if (name == NULL) { - return ARES_FALSE; + return ARES_FALSE; /* LCOV_EXCL_LINE: DefensiveCoding */ } if (strcmp(name, "localhost") == 0) { @@ -415,7 +412,7 @@ static ares_status_t file_lookup(struct host_query *hquery) hquery->ai); if (status != ARES_SUCCESS) { - goto done; + goto done; /* LCOV_EXCL_LINE: OutOfMemory */ } @@ -472,7 +469,7 @@ static void terminate_retries(const struct host_query *hquery, unsigned short term_qid = (qid == hquery->qid_a) ? hquery->qid_aaaa : hquery->qid_a; const ares_channel_t *channel = hquery->channel; - struct query *query = NULL; + ares_query_t *query = NULL; /* No other outstanding queries, nothing to do */ if (!hquery->remaining) { @@ -497,7 +494,7 @@ static void host_callback(void *arg, ares_status_t status, size_t timeouts, if (status == ARES_SUCCESS) { if (dnsrec == NULL) { - addinfostatus = ARES_EBADRESP; + addinfostatus = ARES_EBADRESP; /* LCOV_EXCL_LINE: DefensiveCoding */ } else { addinfostatus = ares__parse_into_addrinfo(dnsrec, ARES_TRUE, hquery->port, hquery->ai); @@ -675,20 +672,20 @@ static ares_bool_t next_dns_lookup(struct host_query *hquery) switch (hquery->hints.ai_family) { case AF_INET: hquery->remaining += 1; - ares_query_dnsrec(hquery->channel, name, ARES_CLASS_IN, ARES_REC_TYPE_A, + ares_query_nolock(hquery->channel, name, ARES_CLASS_IN, ARES_REC_TYPE_A, host_callback, hquery, &hquery->qid_a); break; case AF_INET6: hquery->remaining += 1; - ares_query_dnsrec(hquery->channel, name, ARES_CLASS_IN, + ares_query_nolock(hquery->channel, name, ARES_CLASS_IN, ARES_REC_TYPE_AAAA, host_callback, hquery, &hquery->qid_aaaa); break; case AF_UNSPEC: hquery->remaining += 2; - ares_query_dnsrec(hquery->channel, name, ARES_CLASS_IN, ARES_REC_TYPE_A, + ares_query_nolock(hquery->channel, name, ARES_CLASS_IN, ARES_REC_TYPE_A, host_callback, hquery, &hquery->qid_a); - ares_query_dnsrec(hquery->channel, name, ARES_CLASS_IN, + ares_query_nolock(hquery->channel, name, ARES_CLASS_IN, ARES_REC_TYPE_AAAA, host_callback, hquery, &hquery->qid_aaaa); break; diff --git a/contrib/libs/c-ares/src/lib/ares_getenv.c b/contrib/libs/c-ares/src/lib/ares_getenv.c index 08601a61e5..4f471673b9 100644 --- a/contrib/libs/c-ares/src/lib/ares_getenv.c +++ b/contrib/libs/c-ares/src/lib/ares_getenv.c @@ -25,7 +25,7 @@ * SPDX-License-Identifier: MIT */ -#include "ares_setup.h" +#include "ares_private.h" #include "ares_getenv.h" #ifndef HAVE_GETENV diff --git a/contrib/libs/c-ares/src/lib/ares_getenv.h b/contrib/libs/c-ares/src/lib/ares_getenv.h index d8bd3a2195..490097fc8d 100644 --- a/contrib/libs/c-ares/src/lib/ares_getenv.h +++ b/contrib/libs/c-ares/src/lib/ares_getenv.h @@ -27,8 +27,6 @@ #ifndef HEADER_CARES_GETENV_H #define HEADER_CARES_GETENV_H -#include "ares_setup.h" - #ifndef HAVE_GETENV extern char *ares_getenv(const char *name); #endif diff --git a/contrib/libs/c-ares/src/lib/ares_gethostbyaddr.c b/contrib/libs/c-ares/src/lib/ares_gethostbyaddr.c index 453673260d..1db81ec2b4 100644 --- a/contrib/libs/c-ares/src/lib/ares_gethostbyaddr.c +++ b/contrib/libs/c-ares/src/lib/ares_gethostbyaddr.c @@ -25,7 +25,7 @@ * SPDX-License-Identifier: MIT */ -#include "ares_setup.h" +#include "ares_private.h" #ifdef HAVE_NETINET_IN_H # include <netinet/in.h> @@ -38,15 +38,8 @@ #endif #include "ares_nameser.h" - -#include "ares.h" #include "ares_inet_net_pton.h" #include "ares_platform.h" -#include "ares_private.h" - -#ifdef WATT32 -# undef WIN32 -#endif struct addr_query { /* Arguments passed to ares_gethostbyaddr() */ @@ -68,9 +61,9 @@ static ares_status_t file_lookup(ares_channel_t *channel, const struct ares_addr *addr, struct hostent **host); -static void ares_gethostbyaddr_int(ares_channel_t *channel, const void *addr, - int addrlen, int family, - ares_host_callback callback, void *arg) +void ares_gethostbyaddr_nolock(ares_channel_t *channel, const void *addr, + int addrlen, int family, + ares_host_callback callback, void *arg) { struct addr_query *aquery; @@ -92,9 +85,11 @@ static void ares_gethostbyaddr_int(ares_channel_t *channel, const void *addr, } aquery->lookups = ares_strdup(channel->lookups); if (aquery->lookups == NULL) { + /* LCOV_EXCL_START: OutOfMemory */ ares_free(aquery); callback(arg, ARES_ENOMEM, 0, NULL); return; + /* LCOV_EXCL_STOP */ } aquery->channel = channel; if (family == AF_INET) { @@ -118,7 +113,7 @@ void ares_gethostbyaddr(ares_channel_t *channel, const void *addr, int addrlen, return; } ares__channel_lock(channel); - ares_gethostbyaddr_int(channel, addr, addrlen, family, callback, arg); + ares_gethostbyaddr_nolock(channel, addr, addrlen, family, callback, arg); ares__channel_unlock(channel); } @@ -134,11 +129,12 @@ static void next_lookup(struct addr_query *aquery) case 'b': name = ares_dns_addr_to_ptr(&aquery->addr); if (name == NULL) { - end_aquery(aquery, ARES_ENOMEM, NULL); - return; + end_aquery(aquery, ARES_ENOMEM, + NULL); /* LCOV_EXCL_LINE: OutOfMemory */ + return; /* LCOV_EXCL_LINE: OutOfMemory */ } aquery->remaining_lookups = p + 1; - ares_query_dnsrec(aquery->channel, name, ARES_CLASS_IN, + ares_query_nolock(aquery->channel, name, ARES_CLASS_IN, ARES_REC_TYPE_PTR, addr_callback, aquery, NULL); ares_free(name); return; @@ -227,7 +223,7 @@ static ares_status_t file_lookup(ares_channel_t *channel, status = ares__hosts_entry_to_hostent(entry, addr->family, host); if (status != ARES_SUCCESS) { - return status; + return status; /* LCOV_EXCL_LINE: OutOfMemory */ } return ARES_SUCCESS; diff --git a/contrib/libs/c-ares/src/lib/ares_gethostbyname.c b/contrib/libs/c-ares/src/lib/ares_gethostbyname.c index 299c35b416..6db86e0eed 100644 --- a/contrib/libs/c-ares/src/lib/ares_gethostbyname.c +++ b/contrib/libs/c-ares/src/lib/ares_gethostbyname.c @@ -25,7 +25,7 @@ * SPDX-License-Identifier: MIT */ -#include "ares_setup.h" +#include "ares_private.h" #ifdef HAVE_NETINET_IN_H # include <netinet/in.h> @@ -43,10 +43,8 @@ # include <strings.h> #endif -#include "ares.h" #include "ares_inet_net_pton.h" #include "ares_platform.h" -#include "ares_private.h" static void sort_addresses(const struct hostent *host, const struct apattern *sortlist, size_t nsort); @@ -102,13 +100,17 @@ static void ares_gethostbyname_callback(void *arg, int status, int timeouts, void ares_gethostbyname(ares_channel_t *channel, const char *name, int family, ares_host_callback callback, void *arg) { - const struct ares_addrinfo_hints hints = { ARES_AI_CANONNAME, family, 0, 0 }; - struct host_query *ghbn_arg; + struct ares_addrinfo_hints hints; + struct host_query *ghbn_arg; if (!callback) { return; } + memset(&hints, 0, sizeof(hints)); + hints.ai_flags = ARES_AI_CANONNAME; + hints.ai_family = family; + ghbn_arg = ares_malloc(sizeof(*ghbn_arg)); if (!ghbn_arg) { callback(arg, ARES_ENOMEM, 0, NULL); @@ -248,18 +250,18 @@ static ares_status_t ares__hostent_localhost(const char *name, int family, ai = ares_malloc_zero(sizeof(*ai)); if (ai == NULL) { - status = ARES_ENOMEM; - goto done; + status = ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ + goto done; /* LCOV_EXCL_LINE: OutOfMemory */ } status = ares__addrinfo_localhost(name, 0, &hints, ai); if (status != ARES_SUCCESS) { - goto done; + goto done; /* LCOV_EXCL_LINE: OutOfMemory */ } status = ares__addrinfo2hostent(ai, family, host_out); if (status != ARES_SUCCESS) { - goto done; + goto done; /* LCOV_EXCL_LINE: OutOfMemory */ } done: @@ -298,7 +300,7 @@ static ares_status_t ares_gethostbyname_file_int(ares_channel_t *channel, status = ares__hosts_entry_to_hostent(entry, family, host); if (status != ARES_SUCCESS) { - goto done; + goto done; /* LCOV_EXCL_LINE: OutOfMemory */ } done: diff --git a/contrib/libs/c-ares/src/lib/ares_getnameinfo.c b/contrib/libs/c-ares/src/lib/ares_getnameinfo.c index d4cf58ea51..622c1adb1c 100644 --- a/contrib/libs/c-ares/src/lib/ares_getnameinfo.c +++ b/contrib/libs/c-ares/src/lib/ares_getnameinfo.c @@ -23,7 +23,7 @@ * * SPDX-License-Identifier: MIT */ -#include "ares_setup.h" +#include "ares_private.h" #ifdef HAVE_GETSERVBYPORT_R # if !defined(GETSERVBYPORT_R_ARGS) || (GETSERVBYPORT_R_ARGS < 4) || \ @@ -51,9 +51,7 @@ # include <iphlpapi.h> #endif -#include "ares.h" #include "ares_ipv6.h" -#include "ares_private.h" struct nameinfo_query { ares_nameinfo_callback callback; @@ -81,8 +79,8 @@ static void nameinfo_callback(void *arg, int status, int timeouts, static char *lookup_service(unsigned short port, unsigned int flags, char *buf, size_t buflen); #ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID -static void append_scopeid(const struct sockaddr_in6 *addr6, - unsigned int scopeid, char *buf, size_t buflen); +static void append_scopeid(const struct sockaddr_in6 *addr6, unsigned int flags, + char *buf, size_t buflen); #endif static char *ares_striendstr(const char *s1, const char *s2); @@ -100,11 +98,11 @@ static void ares_getnameinfo_int(ares_channel_t *channel, /* Validate socket address family and length */ if (sa && sa->sa_family == AF_INET && salen >= (ares_socklen_t)sizeof(struct sockaddr_in)) { - addr = CARES_INADDR_CAST(struct sockaddr_in *, sa); + addr = CARES_INADDR_CAST(const struct sockaddr_in *, sa); port = addr->sin_port; } else if (sa && sa->sa_family == AF_INET6 && salen >= (ares_socklen_t)sizeof(struct sockaddr_in6)) { - addr6 = CARES_INADDR_CAST(struct sockaddr_in6 *, sa); + addr6 = CARES_INADDR_CAST(const struct sockaddr_in6 *, sa); port = addr6->sin6_port; } else { callback(arg, ARES_ENOTIMP, 0, NULL, NULL); @@ -173,14 +171,15 @@ static void ares_getnameinfo_int(ares_channel_t *channel, if (sa->sa_family == AF_INET) { niquery->family = AF_INET; memcpy(&niquery->addr.addr4, addr, sizeof(niquery->addr.addr4)); - ares_gethostbyaddr(channel, &addr->sin_addr, sizeof(struct in_addr), - AF_INET, nameinfo_callback, niquery); + ares_gethostbyaddr_nolock(channel, &addr->sin_addr, + sizeof(struct in_addr), AF_INET, + nameinfo_callback, niquery); } else { niquery->family = AF_INET6; memcpy(&niquery->addr.addr6, addr6, sizeof(niquery->addr.addr6)); - ares_gethostbyaddr(channel, &addr6->sin6_addr, - sizeof(struct ares_in6_addr), AF_INET6, - nameinfo_callback, niquery); + ares_gethostbyaddr_nolock(channel, &addr6->sin6_addr, + sizeof(struct ares_in6_addr), AF_INET6, + nameinfo_callback, niquery); } } } @@ -411,8 +410,8 @@ static char *ares_striendstr(const char *s1, const char *s2) c1 = c1_begin; c2 = s2; while (c2 < s2 + s2_len) { - lo1 = TOLOWER(*c1); - lo2 = TOLOWER(*c2); + lo1 = ares__tolower((unsigned char)*c1); + lo2 = ares__tolower((unsigned char)*c2); if (lo1 != lo2) { return NULL; } else { diff --git a/contrib/libs/c-ares/src/lib/ares_init.c b/contrib/libs/c-ares/src/lib/ares_init.c index c8b4c34564..6dc5f4f935 100644 --- a/contrib/libs/c-ares/src/lib/ares_init.c +++ b/contrib/libs/c-ares/src/lib/ares_init.c @@ -25,7 +25,7 @@ * SPDX-License-Identifier: MIT */ -#include "ares_setup.h" +#include "ares_private.h" #ifdef HAVE_SYS_PARAM_H # include <sys/param.h> @@ -61,16 +61,9 @@ # include <iphlpapi.h> #endif -#include "ares.h" #include "ares_inet_net_pton.h" #include "ares_platform.h" -#include "ares_private.h" -#include "ares_event.h" - -#ifdef WATT32 -# undef WIN32 /* Redefined in MingW/MSVC headers */ -#endif - +#include "event/ares_event.h" int ares_init(ares_channel_t **channelptr) { @@ -79,8 +72,8 @@ int ares_init(ares_channel_t **channelptr) static int ares_query_timeout_cmp_cb(const void *arg1, const void *arg2) { - const struct query *q1 = arg1; - const struct query *q2 = arg2; + const ares_query_t *q1 = arg1; + const ares_query_t *q2 = arg2; if (q1->timeout.sec > q2->timeout.sec) { return 1; @@ -101,8 +94,8 @@ static int ares_query_timeout_cmp_cb(const void *arg1, const void *arg2) static int server_sort_cb(const void *data1, const void *data2) { - const struct server_state *s1 = data1; - const struct server_state *s2 = data2; + const ares_server_t *s1 = data1; + const ares_server_t *s2 = data2; if (s1->consec_failures < s2->consec_failures) { return -1; @@ -122,7 +115,7 @@ static int server_sort_cb(const void *data1, const void *data2) static void server_destroy_cb(void *data) { if (data == NULL) { - return; + return; /* LCOV_EXCL_LINE: DefensiveCoding */ } ares__destroy_server(data); } @@ -167,7 +160,7 @@ static ares_status_t init_by_defaults(ares_channel_t *channel) rc = ares__sconfig_append(&sconfig, &addr, 0, 0, NULL); if (rc != ARES_SUCCESS) { - goto error; + goto error; /* LCOV_EXCL_LINE: OutOfMemory */ } rc = ares__servers_update(channel, sconfig, ARES_FALSE); @@ -201,8 +194,8 @@ static ares_status_t init_by_defaults(ares_channel_t *channel) hostname = ares_malloc(len); if (!hostname) { - rc = ARES_ENOMEM; - goto error; + rc = ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ + goto error; /* LCOV_EXCL_LINE: OutOfMemory */ } do { @@ -214,8 +207,8 @@ static ares_status_t init_by_defaults(ares_channel_t *channel) lenv *= 2; p = ares_realloc(hostname, len); if (!p) { - rc = ARES_ENOMEM; - goto error; + rc = ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ + goto error; /* LCOV_EXCL_LINE: OutOfMemory */ } hostname = p; continue; @@ -233,13 +226,13 @@ static ares_status_t init_by_defaults(ares_channel_t *channel) /* a dot was found */ channel->domains = ares_malloc(sizeof(char *)); if (!channel->domains) { - rc = ARES_ENOMEM; - goto error; + rc = ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ + goto error; /* LCOV_EXCL_LINE: OutOfMemory */ } channel->domains[0] = ares_strdup(dot + 1); if (!channel->domains[0]) { - rc = ARES_ENOMEM; - goto error; + rc = ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ + goto error; /* LCOV_EXCL_LINE: OutOfMemory */ } channel->ndomains = 1; } @@ -253,7 +246,7 @@ static ares_status_t init_by_defaults(ares_channel_t *channel) if (!channel->lookups) { channel->lookups = ares_strdup("fb"); if (!channel->lookups) { - rc = ARES_ENOMEM; + rc = ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ } } @@ -287,6 +280,9 @@ int ares_init_options(ares_channel_t **channelptr, return ARES_ENOMEM; } + /* We are in a good state */ + channel->sys_up = ARES_TRUE; + /* One option where zero is valid, so set default value here */ channel->ndots = 1; @@ -351,12 +347,13 @@ int ares_init_options(ares_channel_t **channelptr, goto done; } - if (channel->qcache_max_ttl > 0) { - status = ares__qcache_create(channel->rand_state, channel->qcache_max_ttl, - &channel->qcache); - if (status != ARES_SUCCESS) { - goto done; - } + /* Go ahead and let it initialize the query cache even if the ttl is 0 and + * completely unused. This reduces the number of different code paths that + * might be followed even if there is a minor performance hit. */ + status = ares__qcache_create(channel->rand_state, channel->qcache_max_ttl, + &channel->qcache); + if (status != ARES_SUCCESS) { + goto done; /* LCOV_EXCL_LINE: OutOfMemory */ } if (status == ARES_SUCCESS) { @@ -384,7 +381,7 @@ int ares_init_options(ares_channel_t **channelptr, status = ares_event_thread_init(channel); if (status != ARES_SUCCESS) { - goto done; + goto done; /* LCOV_EXCL_LINE: UntestablePath */ } /* Initialize monitor for configuration changes. In some rare cases, @@ -392,7 +389,7 @@ int ares_init_options(ares_channel_t **channelptr, e = channel->sock_state_cb_data; status = ares_event_configchg_init(&e->configchg, e); if (status != ARES_SUCCESS && status != ARES_ENOTIMP) { - goto done; + goto done; /* LCOV_EXCL_LINE: UntestablePath */ } status = ARES_SUCCESS; } @@ -443,8 +440,9 @@ ares_status_t ares_reinit(ares_channel_t *channel) ares__channel_lock(channel); - /* If a reinit is already in process, lets not do it again */ - if (channel->reinit_pending) { + /* If a reinit is already in process, lets not do it again. Or if we are + * shutting down, skip. */ + if (!channel->sys_up || channel->reinit_pending) { ares__channel_unlock(channel); return ARES_SUCCESS; } @@ -464,9 +462,11 @@ ares_status_t ares_reinit(ares_channel_t *channel) status = ares__thread_create(&channel->reinit_thread, ares_reinit_thread, channel); if (status != ARES_SUCCESS) { + /* LCOV_EXCL_START: UntestablePath */ ares__channel_lock(channel); channel->reinit_pending = ARES_FALSE; ares__channel_unlock(channel); + /* LCOV_EXCL_STOP */ } } else { /* Threading support not available, call directly */ @@ -490,7 +490,6 @@ int ares_dup(ares_channel_t **dest, const ares_channel_t *src) *dest = NULL; /* in case of failure return NULL explicitly */ - ares__channel_lock(src); /* First get the options supported by the old ares_save_options() function, which is most of them */ rc = (ares_status_t)ares_save_options(src, &opts, &optmask); @@ -509,6 +508,7 @@ int ares_dup(ares_channel_t **dest, const ares_channel_t *src) goto done; } + ares__channel_lock(src); /* Now clone the options that ares_save_options() doesn't support, but are * user-provided */ (*dest)->sock_create_cb = src->sock_create_cb; @@ -524,7 +524,7 @@ int ares_dup(ares_channel_t **dest, const ares_channel_t *src) sizeof((*dest)->local_dev_name)); (*dest)->local_ip4 = src->local_ip4; memcpy((*dest)->local_ip6, src->local_ip6, sizeof(src->local_ip6)); - + ares__channel_unlock(src); /* Servers are a bit unique as ares_init_options() only allows ipv4 servers * and not a port per server, but there are other user specified ways, that @@ -539,24 +539,27 @@ int ares_dup(ares_channel_t **dest, const ares_channel_t *src) if (optmask & ARES_OPT_SERVERS) { char *csv = ares_get_servers_csv(src); if (csv == NULL) { + /* LCOV_EXCL_START: OutOfMemory */ ares_destroy(*dest); *dest = NULL; rc = ARES_ENOMEM; goto done; + /* LCOV_EXCL_STOP */ } rc = (ares_status_t)ares_set_servers_ports_csv(*dest, csv); ares_free_string(csv); if (rc != ARES_SUCCESS) { + /* LCOV_EXCL_START: OutOfMemory */ ares_destroy(*dest); *dest = NULL; goto done; + /* LCOV_EXCL_STOP */ } } rc = ARES_SUCCESS; done: - ares__channel_unlock(src); return (int)rc; /* everything went fine */ } diff --git a/contrib/libs/c-ares/src/lib/ares_library_init.c b/contrib/libs/c-ares/src/lib/ares_library_init.c index 5d8abf10a0..01d8ff1a44 100644 --- a/contrib/libs/c-ares/src/lib/ares_library_init.c +++ b/contrib/libs/c-ares/src/lib/ares_library_init.c @@ -25,9 +25,6 @@ * SPDX-License-Identifier: MIT */ -#include "ares_setup.h" - -#include "ares.h" #include "ares_private.h" /* library-private global and unique instance vars */ @@ -55,7 +52,7 @@ static void *default_malloc(size_t size) return malloc(size); } -#if defined(WIN32) +#if defined(_WIN32) /* We need indirections to handle Windows DLL rules. */ static void *default_realloc(void *p, size_t size) { diff --git a/contrib/libs/c-ares/src/lib/ares_metrics.c b/contrib/libs/c-ares/src/lib/ares_metrics.c new file mode 100644 index 0000000000..aa0ea8c017 --- /dev/null +++ b/contrib/libs/c-ares/src/lib/ares_metrics.c @@ -0,0 +1,261 @@ +/* MIT License + * + * Copyright (c) 2024 Brad House + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * SPDX-License-Identifier: MIT + */ + + +/* IMPLEMENTATION NOTES + * ==================== + * + * With very little effort we should be able to determine fairly proper timeouts + * we can use based on prior query history. We track in order to be able to + * auto-scale when network conditions change (e.g. maybe there is a provider + * failover and timings change due to that). Apple appears to do this within + * their system resolver in MacOS. Obviously we should have a minimum, maximum, + * and initial value to make sure the algorithm doesn't somehow go off the + * rails. + * + * Values: + * - Minimum Timeout: 250ms (approximate RTT half-way around the globe) + * - Maximum Timeout: 5000ms (Recommended timeout in RFC 1123), can be reduced + * by ARES_OPT_MAXTIMEOUTMS, but otherwise the bound specified by the option + * caps the retry timeout. + * - Initial Timeout: User-specified via configuration or ARES_OPT_TIMEOUTMS + * - Average latency multiplier: 5x (a local DNS server returning a cached value + * will be quicker than if it needs to recurse so we need to account for this) + * - Minimum Count for Average: 3. This is the minimum number of queries we + * need to form an average for the bucket. + * + * Per-server buckets for tracking latency over time (these are ephemeral + * meaning they don't persist once a channel is destroyed). We record both the + * current timespan for the bucket and the immediate preceding timespan in case + * of roll-overs we can still maintain recent metrics for calculations: + * - 1 minute + * - 15 minutes + * - 1 hr + * - 1 day + * - since inception + * + * Each bucket would contain: + * - timestamp (divided by interval) + * - minimum latency + * - maximum latency + * - total time + * - count + * NOTE: average latency is (total time / count), we will calculate this + * dynamically when needed + * + * Basic algorithm for calculating timeout to use would be: + * - Scan from most recent bucket to least recent + * - Check timestamp of bucket, if doesn't match current time, continue to next + * bucket + * - Check count of bucket, if its not at least the "Minimum Count for Average", + * check the previous bucket, otherwise continue to next bucket + * - If we reached the end with no bucket match, use "Initial Timeout" + * - If bucket is selected, take ("total time" / count) as Average latency, + * multiply by "Average Latency Multiplier", bound by "Minimum Timeout" and + * "Maximum Timeout" + * NOTE: The timeout calculated may not be the timeout used. If we are retrying + * the query on the same server another time, then it will use a larger value + * + * On each query reply where the response is legitimate (proper response or + * NXDOMAIN) and not something like a server error: + * - Cycle through each bucket in order + * - Check timestamp of bucket against current timestamp, if out of date + * overwrite previous entry with values, clear current values + * - Compare current minimum and maximum recorded latency against query time and + * adjust if necessary + * - Increment "count" by 1 and "total time" by the query time + * + * Other Notes: + * - This is always-on, the only user-configurable value is the initial + * timeout which will simply re-uses the current option. + * - Minimum and Maximum latencies for a bucket are currently unused but are + * there in case we find a need for them in the future. + */ + +#include "ares_private.h" + +/*! Minimum timeout value. Chosen due to it being approximately RTT half-way + * around the world */ +#define MIN_TIMEOUT_MS 250 + +/*! Multiplier to apply to average latency to come up with an initial timeout */ +#define AVG_TIMEOUT_MULTIPLIER 5 + +/*! Upper timeout bounds, only used if channel->maxtimeout not set */ +#define MAX_TIMEOUT_MS 5000 + +/*! Minimum queries required to form an average */ +#define MIN_COUNT_FOR_AVERAGE 3 + +static time_t ares_metric_timestamp(ares_server_bucket_t bucket, + const ares_timeval_t *now, + ares_bool_t is_previous) +{ + time_t divisor = 1; /* Silence bogus MSVC warning by setting default value */ + + switch (bucket) { + case ARES_METRIC_1MINUTE: + divisor = 60; + break; + case ARES_METRIC_15MINUTES: + divisor = 15 * 60; + break; + case ARES_METRIC_1HOUR: + divisor = 60 * 60; + break; + case ARES_METRIC_1DAY: + divisor = 24 * 60 * 60; + break; + case ARES_METRIC_INCEPTION: + return is_previous ? 0 : 1; + case ARES_METRIC_COUNT: + return 0; /* Invalid! */ + } + + if (is_previous) { + if (divisor >= now->sec) { + return 0; + } + return (time_t)((now->sec - divisor) / divisor); + } + + return (time_t)(now->sec / divisor); +} + +void ares_metrics_record(const ares_query_t *query, ares_server_t *server, + ares_status_t status, const ares_dns_record_t *dnsrec) +{ + ares_timeval_t now; + ares_timeval_t tvdiff; + unsigned int query_ms; + ares_dns_rcode_t rcode; + ares_server_bucket_t i; + + if (status != ARES_SUCCESS) { + return; + } + + if (server == NULL) { + return; + } + + ares__tvnow(&now); + + rcode = ares_dns_record_get_rcode(dnsrec); + if (rcode != ARES_RCODE_NOERROR && rcode != ARES_RCODE_NXDOMAIN) { + return; + } + + ares__timeval_diff(&tvdiff, &query->ts, &now); + query_ms = (unsigned int)(tvdiff.sec + (tvdiff.usec / 1000)); + if (query_ms == 0) { + query_ms = 1; + } + + /* Place in each bucket */ + for (i = 0; i < ARES_METRIC_COUNT; i++) { + time_t ts = ares_metric_timestamp(i, &now, ARES_FALSE); + + /* Copy metrics to prev and clear */ + if (ts != server->metrics[i].ts) { + server->metrics[i].prev_ts = server->metrics[i].ts; + server->metrics[i].prev_total_ms = server->metrics[i].total_ms; + server->metrics[i].prev_total_count = server->metrics[i].total_count; + server->metrics[i].ts = ts; + server->metrics[i].latency_min_ms = 0; + server->metrics[i].latency_max_ms = 0; + server->metrics[i].total_ms = 0; + server->metrics[i].total_count = 0; + } + + if (server->metrics[i].latency_min_ms == 0 || + server->metrics[i].latency_min_ms > query_ms) { + server->metrics[i].latency_min_ms = query_ms; + } + + if (query_ms > server->metrics[i].latency_max_ms) { + server->metrics[i].latency_min_ms = query_ms; + } + + server->metrics[i].total_count++; + server->metrics[i].total_ms += (ares_uint64_t)query_ms; + } +} + +size_t ares_metrics_server_timeout(const ares_server_t *server, + const ares_timeval_t *now) +{ + const ares_channel_t *channel = server->channel; + ares_server_bucket_t i; + size_t timeout_ms = 0; + size_t max_timeout_ms; + + for (i = 0; i < ARES_METRIC_COUNT; i++) { + time_t ts = ares_metric_timestamp(i, now, ARES_FALSE); + + /* This ts has been invalidated, see if we should use the previous + * time period */ + if (ts != server->metrics[i].ts || + server->metrics[i].total_count < MIN_COUNT_FOR_AVERAGE) { + time_t prev_ts = ares_metric_timestamp(i, now, ARES_TRUE); + if (prev_ts != server->metrics[i].prev_ts || + server->metrics[i].prev_total_count < MIN_COUNT_FOR_AVERAGE) { + /* Move onto next bucket */ + continue; + } + /* Calculate average time for previous bucket */ + timeout_ms = (size_t)(server->metrics[i].prev_total_ms / + server->metrics[i].prev_total_count); + } else { + /* Calculate average time for current bucket*/ + timeout_ms = + (size_t)(server->metrics[i].total_ms / server->metrics[i].total_count); + } + + /* Multiply average by constant to get timeout value */ + timeout_ms *= AVG_TIMEOUT_MULTIPLIER; + break; + } + + /* If we're here, that means its the first query for the server, so we just + * use the initial default timeout */ + if (timeout_ms == 0) { + timeout_ms = channel->timeout; + } + + /* don't go below lower bounds */ + if (timeout_ms < MIN_TIMEOUT_MS) { + timeout_ms = MIN_TIMEOUT_MS; + } + + /* don't go above upper bounds */ + max_timeout_ms = channel->maxtimeout ? channel->maxtimeout : MAX_TIMEOUT_MS; + if (timeout_ms > max_timeout_ms) { + timeout_ms = max_timeout_ms; + } + + return timeout_ms; +} diff --git a/contrib/libs/c-ares/src/lib/ares_options.c b/contrib/libs/c-ares/src/lib/ares_options.c index 6f50f2e498..9aeb4bad3d 100644 --- a/contrib/libs/c-ares/src/lib/ares_options.c +++ b/contrib/libs/c-ares/src/lib/ares_options.c @@ -25,16 +25,14 @@ * SPDX-License-Identifier: MIT */ -#include "ares_setup.h" +#include "ares_private.h" #ifdef HAVE_ARPA_INET_H # include <arpa/inet.h> #endif -#include "ares.h" #include "ares_data.h" #include "ares_inet_net_pton.h" -#include "ares_private.h" void ares_destroy_options(struct ares_options *options) { @@ -68,7 +66,7 @@ static struct in_addr *ares_save_opt_servers(const ares_channel_t *channel, for (snode = ares__slist_node_first(channel->servers); snode != NULL; snode = ares__slist_node_next(snode)) { - const struct server_state *server = ares__slist_node_val(snode); + const ares_server_t *server = ares__slist_node_val(snode); if (server->addr.family != AF_INET) { continue; @@ -249,7 +247,7 @@ static ares_status_t ares__init_options_servers(ares_channel_t *channel, status = ares_in_addr_to_server_config_llist(servers, nservers, &slist); if (status != ARES_SUCCESS) { - return status; + return status; /* LCOV_EXCL_LINE: OutOfMemory */ } status = ares__servers_update(channel, slist, ARES_TRUE); @@ -266,12 +264,12 @@ ares_status_t ares__init_by_options(ares_channel_t *channel, size_t i; if (channel == NULL) { - return ARES_ENODATA; + return ARES_ENODATA; /* LCOV_EXCL_LINE: DefensiveCoding */ } if (options == NULL) { if (optmask != 0) { - return ARES_ENODATA; + return ARES_ENODATA; /* LCOV_EXCL_LINE: DefensiveCoding */ } return ARES_SUCCESS; } @@ -389,13 +387,13 @@ ares_status_t ares__init_by_options(ares_channel_t *channel, channel->domains = ares_malloc_zero((size_t)options->ndomains * sizeof(char *)); if (!channel->domains) { - return ARES_ENOMEM; + return ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ } channel->ndomains = (size_t)options->ndomains; for (i = 0; i < (size_t)options->ndomains; i++) { channel->domains[i] = ares_strdup(options->domains[i]); if (!channel->domains[i]) { - return ARES_ENOMEM; + return ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ } } } @@ -407,7 +405,7 @@ ares_status_t ares__init_by_options(ares_channel_t *channel, } else { channel->lookups = ares_strdup(options->lookups); if (!channel->lookups) { - return ARES_ENOMEM; + return ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ } } } @@ -418,7 +416,7 @@ ares_status_t ares__init_by_options(ares_channel_t *channel, channel->sortlist = ares_malloc((size_t)options->nsort * sizeof(struct apattern)); if (!channel->sortlist) { - return ARES_ENOMEM; + return ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ } for (i = 0; i < (size_t)options->nsort; i++) { channel->sortlist[i] = options->sortlist[i]; @@ -432,7 +430,7 @@ ares_status_t ares__init_by_options(ares_channel_t *channel, } else { channel->resolvconf_path = ares_strdup(options->resolvconf_path); if (channel->resolvconf_path == NULL) { - return ARES_ENOMEM; + return ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ } } } @@ -444,7 +442,7 @@ ares_status_t ares__init_by_options(ares_channel_t *channel, } else { channel->hosts_path = ares_strdup(options->hosts_path); if (channel->hosts_path == NULL) { - return ARES_ENOMEM; + return ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ } } } @@ -457,13 +455,15 @@ ares_status_t ares__init_by_options(ares_channel_t *channel, } } + /* As of c-ares 1.31.0, the Query Cache is on by default. The only way to + * disable it is to set options->qcache_max_ttl = 0 while specifying the + * ARES_OPT_QUERY_CACHE which will actually disable it completely. */ if (optmask & ARES_OPT_QUERY_CACHE) { /* qcache_max_ttl is unsigned unlike the others */ - if (options->qcache_max_ttl == 0) { - optmask &= ~(ARES_OPT_QUERY_CACHE); - } else { - channel->qcache_max_ttl = options->qcache_max_ttl; - } + channel->qcache_max_ttl = options->qcache_max_ttl; + } else { + optmask |= ARES_OPT_QUERY_CACHE; + channel->qcache_max_ttl = 3600; } /* Initialize the ipv4 servers if provided */ @@ -475,7 +475,7 @@ ares_status_t ares__init_by_options(ares_channel_t *channel, status = ares__init_options_servers(channel, options->servers, (size_t)options->nservers); if (status != ARES_SUCCESS) { - return status; + return status; /* LCOV_EXCL_LINE: OutOfMemory */ } } } diff --git a/contrib/libs/c-ares/src/lib/ares_platform.c b/contrib/libs/c-ares/src/lib/ares_platform.c index 58a5019871..8f0a1dbffb 100644 --- a/contrib/libs/c-ares/src/lib/ares_platform.c +++ b/contrib/libs/c-ares/src/lib/ares_platform.c @@ -25,13 +25,10 @@ * SPDX-License-Identifier: MIT */ -#include "ares_setup.h" - -#include "ares.h" -#include "ares_platform.h" #include "ares_private.h" +#include "ares_platform.h" -#if defined(WIN32) && !defined(MSDOS) +#if defined(_WIN32) && !defined(MSDOS) # define V_PLATFORM_WIN32s 0 # define V_PLATFORM_WIN32_WINDOWS 1 @@ -78,7 +75,7 @@ win_platform ares__getplatform(void) } } -#endif /* WIN32 && ! MSDOS */ +#endif /* _WIN32 && ! MSDOS */ #if defined(_WIN32_WCE) diff --git a/contrib/libs/c-ares/src/lib/ares_platform.h b/contrib/libs/c-ares/src/lib/ares_platform.h index 44b2c03644..768eaddddd 100644 --- a/contrib/libs/c-ares/src/lib/ares_platform.h +++ b/contrib/libs/c-ares/src/lib/ares_platform.h @@ -27,9 +27,7 @@ #ifndef HEADER_CARES_PLATFORM_H #define HEADER_CARES_PLATFORM_H -#include "ares_setup.h" - -#if defined(WIN32) && !defined(MSDOS) +#if defined(_WIN32) && !defined(MSDOS) typedef enum { WIN_UNKNOWN, diff --git a/contrib/libs/c-ares/src/lib/ares_private.h b/contrib/libs/c-ares/src/lib/ares_private.h index 6d9fc11771..b85ecb5e14 100644 --- a/contrib/libs/c-ares/src/lib/ares_private.h +++ b/contrib/libs/c-ares/src/lib/ares_private.h @@ -27,23 +27,19 @@ #ifndef __ARES_PRIVATE_H #define __ARES_PRIVATE_H -/* - * Define WIN32 when build target is Win32 API +/* ============================================================================ + * NOTE: All c-ares source files should include ares_private.h as the first + * header. + * ============================================================================ */ -#if (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32) -# define WIN32 -#endif +#include "ares_setup.h" +#include "ares.h" #ifdef HAVE_NETINET_IN_H # include <netinet/in.h> #endif -#ifdef WATT32 -# include <tcp.h> -# include <sys/ioctl.h> -#endif - #define DEFAULT_TIMEOUT 2000 /* milliseconds */ #define DEFAULT_TRIES 3 #ifndef INADDR_NONE @@ -54,9 +50,9 @@ * warning: cast from 'const struct sockaddr *' to 'const struct sockaddr_in6 *' * increases required alignment from 1 to 4 [-Wcast-align] */ -#define CARES_INADDR_CAST(type, var) ((type)((void *)var)) +#define CARES_INADDR_CAST(type, var) ((type)((const void *)var)) -#if defined(WIN32) && !defined(WATT32) +#if defined(USE_WINSOCK) # define WIN_NS_9X "System\\CurrentControlSet\\Services\\VxD\\MSTCP" # define WIN_NS_NT_KEY "System\\CurrentControlSet\\Services\\Tcpip\\Parameters" @@ -109,32 +105,34 @@ W32_FUNC const char *_w32_GetHostsFile(void); struct ares_rand_state; typedef struct ares_rand_state ares_rand_state; -#include "ares__llist.h" -#include "ares__slist.h" -#include "ares__htable_strvp.h" -#include "ares__htable_szvp.h" -#include "ares__htable_asvp.h" -#include "ares__htable_vpvp.h" -#include "ares__buf.h" -#include "ares_dns_private.h" -#include "ares__iface_ips.h" -#include "ares__threads.h" +#include "dsa/ares__array.h" +#include "dsa/ares__llist.h" +#include "dsa/ares__slist.h" +#include "dsa/ares__htable_strvp.h" +#include "dsa/ares__htable_szvp.h" +#include "dsa/ares__htable_asvp.h" +#include "dsa/ares__htable_vpvp.h" +#include "record/ares_dns_multistring.h" +#include "str/ares__buf.h" +#include "record/ares_dns_private.h" +#include "util/ares__iface_ips.h" +#include "util/ares__threads.h" #ifndef HAVE_GETENV # include "ares_getenv.h" # define getenv(ptr) ares_getenv(ptr) #endif -#include "ares_str.h" -#include "ares_strsplit.h" +#include "str/ares_str.h" +#include "str/ares_strsplit.h" #ifndef HAVE_STRCASECMP -# include "ares_strcasecmp.h" +# include "str/ares_strcasecmp.h" # define strcasecmp(p1, p2) ares_strcasecmp(p1, p2) #endif #ifndef HAVE_STRNCASECMP -# include "ares_strcasecmp.h" +# include "str/ares_strcasecmp.h" # define strncasecmp(p1, p2, n) ares_strncasecmp(p1, p2, n) #endif @@ -153,18 +151,36 @@ typedef struct ares_rand_state ares_rand_state; #define DEFAULT_SERVER_RETRY_CHANCE 10 #define DEFAULT_SERVER_RETRY_DELAY 5000 -struct query; - -struct server_state; - -struct server_connection { - struct server_state *server; - ares_socket_t fd; - ares_bool_t is_tcp; +struct ares_query; +typedef struct ares_query ares_query_t; + +struct ares_server; +typedef struct ares_server ares_server_t; + +struct ares_conn; +typedef struct ares_conn ares_conn_t; + +typedef enum { + /*! No flags */ + ARES_CONN_FLAG_NONE = 0, + /*! TCP connection, not UDP */ + ARES_CONN_FLAG_TCP = 1 << 0, + /*! TCP Fast Open is enabled and being used if supported by the OS */ + ARES_CONN_FLAG_TFO = 1 << 1, + /*! TCP Fast Open has not yet sent its first packet. Gets unset on first + * write to a connection */ + ARES_CONN_FLAG_TFO_INITIAL = 1 << 2 +} ares_conn_flags_t; + +struct ares_conn { + ares_server_t *server; + ares_socket_t fd; + struct ares_addr self_ip; + ares_conn_flags_t flags; /* total number of queries run on this connection since it was established */ - size_t total_queries; + size_t total_queries; /* list of outstanding queries to this connection */ - ares__llist_t *queries_to_conn; + ares__llist_t *queries_to_conn; }; #ifdef _MSC_VER @@ -183,67 +199,128 @@ typedef struct { unsigned int usec; /*!< Microseconds. Can't be negative. */ } ares_timeval_t; -struct server_state { +/*! Various buckets for grouping history */ +typedef enum { + ARES_METRIC_1MINUTE = 0, /*!< Bucket for tracking over the last minute */ + ARES_METRIC_15MINUTES, /*!< Bucket for tracking over the last 15 minutes */ + ARES_METRIC_1HOUR, /*!< Bucket for tracking over the last hour */ + ARES_METRIC_1DAY, /*!< Bucket for tracking over the last day */ + ARES_METRIC_INCEPTION, /*!< Bucket for tracking since inception */ + ARES_METRIC_COUNT /*!< Count of buckets, not a real bucket */ +} ares_server_bucket_t; + +/*! Data metrics collected for each bucket */ +typedef struct { + time_t ts; /*!< Timestamp divided by bucket divisor */ + unsigned int latency_min_ms; /*!< Minimum latency for queries */ + unsigned int latency_max_ms; /*!< Maximum latency for queries */ + ares_uint64_t total_ms; /*!< Cumulative query time for bucket */ + ares_uint64_t total_count; /*!< Number of queries for bucket */ + + time_t prev_ts; /*!< Previous period bucket timestamp */ + ares_uint64_t + prev_total_ms; /*!< Previous period bucket cumulative query time */ + ares_uint64_t prev_total_count; /*!< Previous period bucket query count */ +} ares_server_metrics_t; + +typedef enum { + ARES_COOKIE_INITIAL = 0, + ARES_COOKIE_GENERATED = 1, + ARES_COOKIE_SUPPORTED = 2, + ARES_COOKIE_UNSUPPORTED = 3 +} ares_cookie_state_t; + +/*! Structure holding tracking data for RFC 7873/9018 DNS cookies. + * Implementation plan for this feature is here: + * https://github.com/c-ares/c-ares/issues/620 + */ +typedef struct { + /*! starts at INITIAL, transitions as needed. */ + ares_cookie_state_t state; + /*! randomly-generate client cookie */ + unsigned char client[8]; + /*! timestamp client cookie was generated, used for rotation purposes */ + ares_timeval_t client_ts; + /*! IP address last used for client to connect to server. If this changes + * The client cookie gets invalidated */ + struct ares_addr client_ip; + /*! Server Cookie last received, 8-32 bytes in length */ + unsigned char server[32]; + /*! Length of server cookie on file. */ + size_t server_len; + /*! Timestamp of last attempt to use cookies, but it was determined that the + * server didn't support them */ + ares_timeval_t unsupported_ts; +} ares_cookie_t; + +struct ares_server { /* Configuration */ - size_t idx; /* index for server in system configuration */ - struct ares_addr addr; - unsigned short udp_port; /* host byte order */ - unsigned short tcp_port; /* host byte order */ - char ll_iface[64]; /* IPv6 Link Local Interface */ - unsigned int ll_scope; /* IPv6 Link Local Scope */ - - size_t consec_failures; /* Consecutive query failure count - * can be hard errors or timeouts - */ - ares__llist_t *connections; - struct server_connection *tcp_conn; + size_t idx; /* index for server in system configuration */ + struct ares_addr addr; + unsigned short udp_port; /* host byte order */ + unsigned short tcp_port; /* host byte order */ + char ll_iface[64]; /* IPv6 Link Local Interface */ + unsigned int ll_scope; /* IPv6 Link Local Scope */ + + size_t consec_failures; /* Consecutive query failure count + * can be hard errors or timeouts + */ + ares__llist_t *connections; + ares_conn_t *tcp_conn; /* The next time when we will retry this server if it has hit failures */ - ares_timeval_t next_retry_time; + ares_timeval_t next_retry_time; /* TCP buffer since multiple responses can come back in one read, or partial * in a read */ - ares__buf_t *tcp_parser; + ares__buf_t *tcp_parser; /* TCP output queue */ - ares__buf_t *tcp_send; + ares__buf_t *tcp_send; + + /*! Buckets for collecting metrics about the server */ + ares_server_metrics_t metrics[ARES_METRIC_COUNT]; + + /*! RFC 7873/9018 DNS Cookies */ + ares_cookie_t cookie; /* Link back to owning channel */ - ares_channel_t *channel; + ares_channel_t *channel; }; /* State to represent a DNS query */ -struct query { +struct ares_query { /* Query ID from qbuf, for faster lookup, and current timeout */ - unsigned short qid; /* host byte order */ - ares_timeval_t timeout; - ares_channel_t *channel; + unsigned short qid; /* host byte order */ + ares_timeval_t ts; /*!< Timestamp query was sent */ + ares_timeval_t timeout; + ares_channel_t *channel; /* * Node object for each list entry the query belongs to in order to * make removal operations O(1). */ - ares__slist_node_t *node_queries_by_timeout; - ares__llist_node_t *node_queries_to_conn; - ares__llist_node_t *node_all_queries; + ares__slist_node_t *node_queries_by_timeout; + ares__llist_node_t *node_queries_to_conn; + ares__llist_node_t *node_all_queries; /* connection handle query is associated with */ - struct server_connection *conn; + ares_conn_t *conn; - /* Arguments passed to ares_send() */ - unsigned char *qbuf; - size_t qlen; + /* Query */ + ares_dns_record_t *query; - ares_callback_dnsrec callback; - void *arg; + ares_callback_dnsrec callback; + void *arg; /* Query status */ size_t try_count; /* Number of times we tried this query already. */ + size_t cookie_try_count; /* Attempt count for cookie resends */ ares_bool_t using_tcp; ares_status_t error_status; - size_t timeouts; /* number of timeouts we saw for this request */ - ares_bool_t no_retries; /* do not perform any additional retries, this is set - * when a query is to be canceled */ + size_t timeouts; /* number of timeouts we saw for this request */ + ares_bool_t no_retries; /* do not perform any additional retries, this is + * set when a query is to be canceled */ }; struct apattern { @@ -361,6 +438,12 @@ struct ares_channeldata { * exit. */ ares_bool_t reinit_pending; ares__thread_t *reinit_thread; + + /* Whether the system is up or not. This is mainly to prevent deadlocks + * and access violations during the cleanup process. Some things like + * system config changes might get triggered and we need a flag to make + * sure we don't take action. */ + ares_bool_t sys_up; }; /* Does the domain end in ".onion" or ".onion."? Case-insensitive. */ @@ -378,9 +461,11 @@ ares_bool_t ares__timedout(const ares_timeval_t *now, const ares_timeval_t *check); /* Returns one of the normal ares status codes like ARES_SUCCESS */ -ares_status_t ares__send_query(struct query *query, const ares_timeval_t *now); -ares_status_t ares__requeue_query(struct query *query, - const ares_timeval_t *now); +ares_status_t ares__send_query(ares_query_t *query, const ares_timeval_t *now); +ares_status_t ares__requeue_query(ares_query_t *query, + const ares_timeval_t *now, + ares_status_t status, + ares_bool_t inc_try_count); /*! Retrieve a list of names to use for searching. The first successful * query in the list wins. This function also uses the HOSTSALIASES file @@ -408,38 +493,34 @@ void *ares__dnsrec_convert_arg(ares_callback callback, void *arg); void ares__dnsrec_convert_cb(void *arg, ares_status_t status, size_t timeouts, const ares_dns_record_t *dnsrec); -void ares__close_connection(struct server_connection *conn); -void ares__close_sockets(struct server_state *server); -void ares__check_cleanup_conn(const ares_channel_t *channel, - struct server_connection *conn); -void ares__free_query(struct query *query); +void ares__close_connection(ares_conn_t *conn, ares_status_t requeue_status); +void ares__close_sockets(ares_server_t *server); +void ares__check_cleanup_conns(const ares_channel_t *channel); +void ares__free_query(ares_query_t *query); ares_rand_state *ares__init_rand_state(void); void ares__destroy_rand_state(ares_rand_state *state); void ares__rand_bytes(ares_rand_state *state, unsigned char *buf, size_t len); unsigned short ares__generate_new_id(ares_rand_state *state); -ares_timeval_t ares__tvnow(void); +void ares__tvnow(ares_timeval_t *now); void ares__timeval_remaining(ares_timeval_t *remaining, const ares_timeval_t *now, const ares_timeval_t *tout); -ares_status_t ares__expand_name_validated(const unsigned char *encoded, - const unsigned char *abuf, - size_t alen, char **s, size_t *enclen, - ares_bool_t is_hostname); -ares_status_t ares__expand_name_for_response(const unsigned char *encoded, - const unsigned char *abuf, - size_t alen, char **s, - size_t *enclen, - ares_bool_t is_hostname); -ares_status_t ares_expand_string_ex(const unsigned char *encoded, - const unsigned char *abuf, size_t alen, - unsigned char **s, size_t *enclen); -ares_status_t ares__init_servers_state(ares_channel_t *channel); -ares_status_t ares__init_by_options(ares_channel_t *channel, - const struct ares_options *options, - int optmask); -ares_status_t ares__init_by_sysconfig(ares_channel_t *channel); +void ares__timeval_diff(ares_timeval_t *tvdiff, const ares_timeval_t *tvstart, + const ares_timeval_t *tvstop); +ares_status_t ares__expand_name_validated(const unsigned char *encoded, + const unsigned char *abuf, + size_t alen, char **s, size_t *enclen, + ares_bool_t is_hostname); +ares_status_t ares_expand_string_ex(const unsigned char *encoded, + const unsigned char *abuf, size_t alen, + unsigned char **s, size_t *enclen); +ares_status_t ares__init_servers_state(ares_channel_t *channel); +ares_status_t ares__init_by_options(ares_channel_t *channel, + const struct ares_options *options, + int optmask); +ares_status_t ares__init_by_sysconfig(ares_channel_t *channel); typedef struct { ares__llist_t *sconfig; @@ -465,6 +546,9 @@ ares_status_t ares__init_sysconfig_files(const ares_channel_t *channel, #ifdef __APPLE__ ares_status_t ares__init_sysconfig_macos(ares_sysconfig_t *sysconfig); #endif +#ifdef USE_WINSOCK +ares_status_t ares__init_sysconfig_windows(ares_sysconfig_t *sysconfig); +#endif ares_status_t ares__parse_sortlist(struct apattern **sortlist, size_t *nsort, const char *str); @@ -519,23 +603,28 @@ ares_status_t ares__addrinfo2addrttl(const struct ares_addrinfo *ai, int family, ares_status_t ares__addrinfo_localhost(const char *name, unsigned short port, const struct ares_addrinfo_hints *hints, struct ares_addrinfo *ai); -ares_status_t ares__open_connection(ares_channel_t *channel, - struct server_state *server, - ares_bool_t is_tcp); +ares_status_t ares__open_connection(ares_conn_t **conn_out, + ares_channel_t *channel, + ares_server_t *server, ares_bool_t is_tcp); +ares_bool_t ares_sockaddr_to_ares_addr(struct ares_addr *ares_addr, + unsigned short *port, + const struct sockaddr *sockaddr); ares_socket_t ares__open_socket(ares_channel_t *channel, int af, int type, int protocol); -ares_ssize_t ares__socket_write(ares_channel_t *channel, ares_socket_t s, - const void *data, size_t len); +ares_bool_t ares__socket_try_again(int errnum); +ares_ssize_t ares__conn_write(ares_conn_t *conn, const void *data, size_t len); ares_ssize_t ares__socket_recvfrom(ares_channel_t *channel, ares_socket_t s, void *data, size_t data_len, int flags, struct sockaddr *from, ares_socklen_t *from_len); ares_ssize_t ares__socket_recv(ares_channel_t *channel, ares_socket_t s, void *data, size_t data_len); -void ares__close_socket(ares_channel, ares_socket_t); -int ares__connect_socket(ares_channel_t *channel, ares_socket_t sockfd, - const struct sockaddr *addr, ares_socklen_t addrlen); -void ares__destroy_server(struct server_state *server); +void ares__close_socket(ares_channel_t *channel, ares_socket_t s); +ares_status_t ares__connect_socket(ares_channel_t *channel, + ares_socket_t sockfd, + const struct sockaddr *addr, + ares_socklen_t addrlen); +void ares__destroy_server(ares_server_t *server); ares_status_t ares__servers_update(ares_channel_t *channel, ares__llist_t *server_list, @@ -551,8 +640,8 @@ ares_status_t ares__sconfig_append_fromstr(ares__llist_t **sconfig, ares_status_t ares_in_addr_to_server_config_llist(const struct in_addr *servers, size_t nservers, ares__llist_t **llist); -ares_status_t ares_get_server_addr(const struct server_state *server, - ares__buf_t *buf); +ares_status_t ares_get_server_addr(const ares_server_t *server, + ares__buf_t *buf); struct ares_hosts_entry; typedef struct ares_hosts_entry ares_hosts_entry_t; @@ -573,6 +662,26 @@ ares_status_t ares__hosts_entry_to_addrinfo(const ares_hosts_entry_t *entry, ares_bool_t want_cnames, struct ares_addrinfo *ai); +/* Same as ares_query_dnsrec() except does not take a channel lock. Use this + * if a channel lock is already held */ +ares_status_t ares_query_nolock(ares_channel_t *channel, const char *name, + ares_dns_class_t dnsclass, + ares_dns_rec_type_t type, + ares_callback_dnsrec callback, void *arg, + unsigned short *qid); + +/* Same as ares_send_dnsrec() except does not take a channel lock. Use this + * if a channel lock is already held */ +ares_status_t ares_send_nolock(ares_channel_t *channel, + const ares_dns_record_t *dnsrec, + ares_callback_dnsrec callback, void *arg, + unsigned short *qid); + +/* Same as ares_gethostbyaddr() except does not take a channel lock. Use this + * if a channel lock is already held */ +void ares_gethostbyaddr_nolock(ares_channel_t *channel, const void *addr, + int addrlen, int family, + ares_host_callback callback, void *arg); /*! Parse a compressed DNS name as defined in RFC1035 starting at the current * offset within the buffer. @@ -622,13 +731,6 @@ ares_status_t ares__dns_name_write(ares__buf_t *buf, ares__llist_t **list, void ares_queue_notify_empty(ares_channel_t *channel); -#define ARES_SWAP_BYTE(a, b) \ - do { \ - unsigned char swapByte = *(a); \ - *(a) = *(b); \ - *(b) = swapByte; \ - } while (0) - #define SOCK_STATE_CALLBACK(c, s, r, w) \ do { \ if ((c)->sock_state_cb) { \ @@ -645,6 +747,7 @@ ares_bool_t ares__subnet_match(const struct ares_addr *addr, unsigned char netmask); ares_bool_t ares__addr_is_linklocal(const struct ares_addr *addr); +ares_bool_t ares__is_64bit(void); size_t ares__round_up_pow2(size_t n); size_t ares__log2(size_t n); size_t ares__pow(size_t x, size_t y); @@ -658,13 +761,25 @@ ares_status_t ares__qcache_create(ares_rand_state *rand_state, void ares__qcache_flush(ares__qcache_t *cache); ares_status_t ares_qcache_insert(ares_channel_t *channel, const ares_timeval_t *now, - const struct query *query, + const ares_query_t *query, ares_dns_record_t *dnsrec); ares_status_t ares_qcache_fetch(ares_channel_t *channel, const ares_timeval_t *now, const ares_dns_record_t *dnsrec, const ares_dns_record_t **dnsrec_resp); +void ares_metrics_record(const ares_query_t *query, ares_server_t *server, + ares_status_t status, const ares_dns_record_t *dnsrec); +size_t ares_metrics_server_timeout(const ares_server_t *server, + const ares_timeval_t *now); + +ares_status_t ares_cookie_apply(ares_dns_record_t *dnsrec, ares_conn_t *conn, + const ares_timeval_t *now); +ares_status_t ares_cookie_validate(ares_query_t *query, + const ares_dns_record_t *dnsresp, + ares_conn_t *conn, + const ares_timeval_t *now); + ares_status_t ares__channel_threading_init(ares_channel_t *channel); void ares__channel_threading_destroy(ares_channel_t *channel); void ares__channel_lock(const ares_channel_t *channel); diff --git a/contrib/libs/c-ares/src/lib/ares_process.c b/contrib/libs/c-ares/src/lib/ares_process.c index 0d8f3ca9ed..65ee673f6e 100644 --- a/contrib/libs/c-ares/src/lib/ares_process.c +++ b/contrib/libs/c-ares/src/lib/ares_process.c @@ -25,8 +25,7 @@ * SPDX-License-Identifier: MIT */ -#include "ares_setup.h" - +#include "ares_private.h" #ifdef HAVE_STRINGS_H # include <strings.h> @@ -45,13 +44,8 @@ #include <fcntl.h> #include <limits.h> -#include "ares.h" -#include "ares_private.h" -#include "ares_nameser.h" -#include "ares_dns.h" static void timeadd(ares_timeval_t *now, size_t millisecs); -static ares_bool_t try_again(int errnum); static void write_tcp_data(ares_channel_t *channel, fd_set *write_fds, ares_socket_t write_fd); static void read_packets(ares_channel_t *channel, fd_set *read_fds, @@ -60,21 +54,32 @@ static void process_timeouts(ares_channel_t *channel, const ares_timeval_t *now); static ares_status_t process_answer(ares_channel_t *channel, const unsigned char *abuf, size_t alen, - struct server_connection *conn, - ares_bool_t tcp, const ares_timeval_t *now); -static void handle_conn_error(struct server_connection *conn, - ares_bool_t critical_failure); - -static ares_bool_t same_questions(const ares_dns_record_t *qrec, - const ares_dns_record_t *arec); -static ares_bool_t same_address(const struct sockaddr *sa, - const struct ares_addr *aa); -static void end_query(ares_channel_t *channel, struct query *query, - ares_status_t status, const ares_dns_record_t *dnsrec); + ares_conn_t *conn, ares_bool_t tcp, + const ares_timeval_t *now); +static void handle_conn_error(ares_conn_t *conn, ares_bool_t critical_failure, + ares_status_t failure_status); + +static ares_bool_t same_questions(const ares_query_t *query, + const ares_dns_record_t *arec); +static ares_bool_t same_address(const struct sockaddr *sa, + const struct ares_addr *aa); +static void end_query(ares_channel_t *channel, ares_server_t *server, + ares_query_t *query, ares_status_t status, + const ares_dns_record_t *dnsrec); + +static void ares__query_disassociate_from_conn(ares_query_t *query) +{ + /* If its not part of a connection, it can't be tracked for timeouts either */ + ares__slist_node_destroy(query->node_queries_by_timeout); + ares__llist_node_destroy(query->node_queries_to_conn); + query->node_queries_by_timeout = NULL; + query->node_queries_to_conn = NULL; + query->conn = NULL; +} /* Invoke the server state callback after a success or failure */ -static void invoke_server_state_cb(const struct server_state *server, - ares_bool_t success, int flags) +static void invoke_server_state_cb(const ares_server_t *server, + ares_bool_t success, int flags) { const ares_channel_t *channel = server->channel; ares__buf_t *buf; @@ -87,19 +92,19 @@ static void invoke_server_state_cb(const struct server_state *server, buf = ares__buf_create(); if (buf == NULL) { - return; + return; /* LCOV_EXCL_LINE: OutOfMemory */ } status = ares_get_server_addr(server, buf); if (status != ARES_SUCCESS) { - ares__buf_destroy(buf); - return; + ares__buf_destroy(buf); /* LCOV_EXCL_LINE: OutOfMemory */ + return; /* LCOV_EXCL_LINE: OutOfMemory */ } server_string = ares__buf_finish_str(buf, NULL); buf = NULL; if (server_string == NULL) { - return; + return; /* LCOV_EXCL_LINE: OutOfMemory */ } channel->server_state_cb(server_string, success, flags, @@ -107,8 +112,8 @@ static void invoke_server_state_cb(const struct server_state *server, ares_free(server_string); } -static void server_increment_failures(struct server_state *server, - ares_bool_t used_tcp) +static void server_increment_failures(ares_server_t *server, + ares_bool_t used_tcp) { ares__slist_node_t *node; const ares_channel_t *channel = server->channel; @@ -116,13 +121,13 @@ static void server_increment_failures(struct server_state *server, node = ares__slist_node_find(channel->servers, server); if (node == NULL) { - return; + return; /* LCOV_EXCL_LINE: DefensiveCoding */ } server->consec_failures++; ares__slist_node_reinsert(node); - next_retry_time = ares__tvnow(); + ares__tvnow(&next_retry_time); timeadd(&next_retry_time, channel->server_retry_delay); server->next_retry_time = next_retry_time; @@ -131,14 +136,14 @@ static void server_increment_failures(struct server_state *server, : ARES_SERV_STATE_UDP); } -static void server_set_good(struct server_state *server, ares_bool_t used_tcp) +static void server_set_good(ares_server_t *server, ares_bool_t used_tcp) { ares__slist_node_t *node; const ares_channel_t *channel = server->channel; node = ares__slist_node_find(channel->servers, server); if (node == NULL) { - return; + return; /* LCOV_EXCL_LINE: DefensiveCoding */ } if (server->consec_failures > 0) { @@ -195,17 +200,19 @@ static void processfds(ares_channel_t *channel, fd_set *read_fds, ares_timeval_t now; if (channel == NULL) { - return; + return; /* LCOV_EXCL_LINE: DefensiveCoding */ } ares__channel_lock(channel); - now = ares__tvnow(); + ares__tvnow(&now); read_packets(channel, read_fds, read_fd, &now); process_timeouts(channel, &now); /* Write last as the other 2 operations might have triggered writes */ write_tcp_data(channel, write_fds, write_fd); + /* See if any connections should be cleaned up */ + ares__check_cleanup_conns(channel); ares__channel_unlock(channel); } @@ -228,34 +235,6 @@ void ares_process_fd(ares_channel_t *channel, processfds(channel, NULL, read_fd, NULL, write_fd); } -/* Return 1 if the specified error number describes a readiness error, or 0 - * otherwise. This is mostly for HP-UX, which could return EAGAIN or - * EWOULDBLOCK. See this man page - * - * http://devrsrc1.external.hp.com/STKS/cgi-bin/man2html? - * manpage=/usr/share/man/man2.Z/send.2 - */ -static ares_bool_t try_again(int errnum) -{ -#if !defined EWOULDBLOCK && !defined EAGAIN -# error "Neither EWOULDBLOCK nor EAGAIN defined" -#endif - -#ifdef EWOULDBLOCK - if (errnum == EWOULDBLOCK) { - return ARES_TRUE; - } -#endif - -#if defined EAGAIN && EAGAIN != EWOULDBLOCK - if (errnum == EAGAIN) { - return ARES_TRUE; - } -#endif - - return ARES_FALSE; -} - /* If any TCP sockets select true for writing, write out queued data * we have for them. */ @@ -271,7 +250,7 @@ static void write_tcp_data(ares_channel_t *channel, fd_set *write_fds, for (node = ares__slist_node_first(channel->servers); node != NULL; node = ares__slist_node_next(node)) { - struct server_state *server = ares__slist_node_val(node); + ares_server_t *server = ares__slist_node_val(node); const unsigned char *data; size_t data_len; ares_ssize_t count; @@ -302,10 +281,10 @@ static void write_tcp_data(ares_channel_t *channel, fd_set *write_fds, } data = ares__buf_peek(server->tcp_send, &data_len); - count = ares__socket_write(channel, server->tcp_conn->fd, data, data_len); + count = ares__conn_write(server->tcp_conn, data, data_len); if (count <= 0) { - if (!try_again(SOCKERRNO)) { - handle_conn_error(server->tcp_conn, ARES_TRUE); + if (!ares__socket_try_again(SOCKERRNO)) { + handle_conn_error(server->tcp_conn, ARES_TRUE, ARES_ECONNREFUSED); } continue; } @@ -324,21 +303,21 @@ static void write_tcp_data(ares_channel_t *channel, fd_set *write_fds, * allocate a buffer if we finish reading the length word, and process * a packet if we finish reading one. */ -static void read_tcp_data(ares_channel_t *channel, - struct server_connection *conn, - const ares_timeval_t *now) +static void read_tcp_data(ares_channel_t *channel, ares_conn_t *conn, + const ares_timeval_t *now) { - ares_ssize_t count; - struct server_state *server = conn->server; + ares_ssize_t count; + ares_server_t *server = conn->server; /* Fetch buffer to store data we are reading */ - size_t ptr_len = 65535; - unsigned char *ptr; + size_t ptr_len = 65535; + unsigned char *ptr; ptr = ares__buf_append_start(server->tcp_parser, &ptr_len); if (ptr == NULL) { - handle_conn_error(conn, ARES_FALSE /* not critical to connection */); + handle_conn_error(conn, ARES_FALSE /* not critical to connection */, + ARES_SUCCESS); return; /* bail out on malloc failure. TODO: make this function return error codes */ } @@ -347,8 +326,8 @@ static void read_tcp_data(ares_channel_t *channel, count = ares__socket_recv(channel, conn->fd, ptr, ptr_len); if (count <= 0) { ares__buf_append_finish(server->tcp_parser, 0); - if (!(count == -1 && try_again(SOCKERRNO))) { - handle_conn_error(conn, ARES_TRUE); + if (!(count == -1 && ares__socket_try_again(SOCKERRNO))) { + handle_conn_error(conn, ARES_TRUE, ARES_ECONNREFUSED); } return; } @@ -380,7 +359,7 @@ static void read_tcp_data(ares_channel_t *channel, /* Can't fail except for misuse */ data = ares__buf_tag_fetch(server->tcp_parser, &data_len); - if (data == NULL) { + if (data == NULL || data_len < 2) { ares__buf_tag_clear(server->tcp_parser); break; } @@ -392,80 +371,57 @@ static void read_tcp_data(ares_channel_t *channel, /* We finished reading this answer; process it */ status = process_answer(channel, data, data_len, conn, ARES_TRUE, now); if (status != ARES_SUCCESS) { - handle_conn_error(conn, ARES_TRUE); + handle_conn_error(conn, ARES_TRUE, status); return; } /* Since we processed the answer, clear the tag so space can be reclaimed */ ares__buf_tag_clear(server->tcp_parser); } - - ares__check_cleanup_conn(channel, conn); -} - -static int socket_list_append(ares_socket_t **socketlist, ares_socket_t fd, - size_t *alloc_cnt, size_t *num) -{ - if (*num >= *alloc_cnt) { - /* Grow by powers of 2 */ - size_t new_alloc = (*alloc_cnt) << 1; - ares_socket_t *new_list = - ares_realloc(socketlist, new_alloc * sizeof(*new_list)); - if (new_list == NULL) { - return 0; - } - *alloc_cnt = new_alloc; - *socketlist = new_list; - } - - (*socketlist)[(*num)++] = fd; - return 1; } static ares_socket_t *channel_socket_list(const ares_channel_t *channel, size_t *num) { - size_t alloc_cnt = 1 << 4; - ares_socket_t *out = ares_malloc(alloc_cnt * sizeof(*out)); ares__slist_node_t *snode; + ares__array_t *arr = ares__array_create(sizeof(ares_socket_t), NULL); *num = 0; - if (out == NULL) { - return NULL; + if (arr == NULL) { + return NULL; /* LCOV_EXCL_LINE: OutOfMemory */ } for (snode = ares__slist_node_first(channel->servers); snode != NULL; snode = ares__slist_node_next(snode)) { - struct server_state *server = ares__slist_node_val(snode); - ares__llist_node_t *node; + ares_server_t *server = ares__slist_node_val(snode); + ares__llist_node_t *node; for (node = ares__llist_node_first(server->connections); node != NULL; node = ares__llist_node_next(node)) { - const struct server_connection *conn = ares__llist_node_val(node); + const ares_conn_t *conn = ares__llist_node_val(node); + ares_socket_t *sptr; + ares_status_t status; if (conn->fd == ARES_SOCKET_BAD) { continue; } - if (!socket_list_append(&out, conn->fd, &alloc_cnt, num)) { - goto fail; + status = ares__array_insert_last((void **)&sptr, arr); + if (status != ARES_SUCCESS) { + ares__array_destroy(arr); /* LCOV_EXCL_LINE: OutOfMemory */ + return NULL; /* LCOV_EXCL_LINE: OutOfMemory */ } + *sptr = conn->fd; } } - return out; - -fail: - ares_free(out); - *num = 0; - return NULL; + return ares__array_finish(arr, num); } /* If any UDP sockets select true for reading, process them. */ -static void read_udp_packets_fd(ares_channel_t *channel, - struct server_connection *conn, - const ares_timeval_t *now) +static void read_udp_packets_fd(ares_channel_t *channel, ares_conn_t *conn, + const ares_timeval_t *now) { ares_ssize_t read_len; unsigned char buf[MAXENDSSZ + 1]; @@ -503,11 +459,11 @@ static void read_udp_packets_fd(ares_channel_t *channel, * tcp */ continue; } else if (read_len < 0) { - if (try_again(SOCKERRNO)) { + if (ares__socket_try_again(SOCKERRNO)) { break; } - handle_conn_error(conn, ARES_TRUE); + handle_conn_error(conn, ARES_TRUE, ARES_ECONNREFUSED); return; #ifdef HAVE_RECVFROM } else if (!same_address(&from.sa, &conn->server->addr)) { @@ -524,18 +480,16 @@ static void read_udp_packets_fd(ares_channel_t *channel, /* Try to read again only if *we* set up the socket, otherwise it may be * a blocking socket and would cause recvfrom to hang. */ } while (read_len >= 0 && channel->sock_funcs == NULL); - - ares__check_cleanup_conn(channel, conn); } static void read_packets(ares_channel_t *channel, fd_set *read_fds, ares_socket_t read_fd, const ares_timeval_t *now) { - size_t i; - ares_socket_t *socketlist = NULL; - size_t num_sockets = 0; - struct server_connection *conn = NULL; - ares__llist_node_t *node = NULL; + size_t i; + ares_socket_t *socketlist = NULL; + size_t num_sockets = 0; + ares_conn_t *conn = NULL; + ares__llist_node_t *node = NULL; if (!read_fds && (read_fd == ARES_SOCKET_BAD)) { /* no possible action */ @@ -551,7 +505,7 @@ static void read_packets(ares_channel_t *channel, fd_set *read_fds, conn = ares__llist_node_val(node); - if (conn->is_tcp) { + if (conn->flags & ARES_CONN_FLAG_TCP) { read_tcp_data(channel, conn, now); } else { read_udp_packets_fd(channel, conn, now); @@ -585,7 +539,7 @@ static void read_packets(ares_channel_t *channel, fd_set *read_fds, conn = ares__llist_node_val(node); - if (conn->is_tcp) { + if (conn->flags & ARES_CONN_FLAG_TCP) { read_tcp_data(channel, conn, now); } else { read_udp_packets_fd(channel, conn, now); @@ -598,47 +552,42 @@ static void read_packets(ares_channel_t *channel, fd_set *read_fds, /* If any queries have timed out, note the timeout and move them on. */ static void process_timeouts(ares_channel_t *channel, const ares_timeval_t *now) { - ares__slist_node_t *node = - ares__slist_node_first(channel->queries_by_timeout); - while (node != NULL) { - struct query *query = ares__slist_node_val(node); - /* Node might be removed, cache next */ - ares__slist_node_t *next = ares__slist_node_next(node); - struct server_connection *conn; + ares__slist_node_t *node; + + /* Just keep popping off the first as this list will re-sort as things come + * and go. We don't want to try to rely on 'next' as some operation might + * cause a cleanup of that pointer and would become invalid */ + while ((node = ares__slist_node_first(channel->queries_by_timeout)) != NULL) { + ares_query_t *query = ares__slist_node_val(node); + ares_conn_t *conn; + /* Since this is sorted, as soon as we hit a query that isn't timed out, * break */ if (!ares__timedout(now, &query->timeout)) { break; } - query->error_status = ARES_ETIMEOUT; query->timeouts++; conn = query->conn; server_increment_failures(conn->server, query->using_tcp); - ares__requeue_query(query, now); - ares__check_cleanup_conn(channel, conn); - - node = next; + ares__requeue_query(query, now, ARES_ETIMEOUT, ARES_TRUE); } } -static ares_status_t rewrite_without_edns(ares_dns_record_t *qdnsrec, - struct query *query) +static ares_status_t rewrite_without_edns(ares_query_t *query) { - ares_status_t status; - size_t i; - ares_bool_t found_opt_rr = ARES_FALSE; - unsigned char *msg = NULL; - size_t msglen = 0; + ares_status_t status = ARES_SUCCESS; + size_t i; + ares_bool_t found_opt_rr = ARES_FALSE; /* Find and remove the OPT RR record */ - for (i = 0; i < ares_dns_record_rr_cnt(qdnsrec, ARES_SECTION_ADDITIONAL); + for (i = 0; i < ares_dns_record_rr_cnt(query->query, ARES_SECTION_ADDITIONAL); i++) { const ares_dns_rr_t *rr; - rr = ares_dns_record_rr_get(qdnsrec, ARES_SECTION_ADDITIONAL, i); + rr = ares_dns_record_rr_get(query->query, ARES_SECTION_ADDITIONAL, i); if (ares_dns_rr_get_type(rr) == ARES_REC_TYPE_OPT) { - ares_dns_record_rr_del(qdnsrec, ARES_SECTION_ADDITIONAL, i); + ares_dns_record_rr_del(query->query, ARES_SECTION_ADDITIONAL, i); found_opt_rr = ARES_TRUE; break; } @@ -649,16 +598,6 @@ static ares_status_t rewrite_without_edns(ares_dns_record_t *qdnsrec, goto done; } - /* Rewrite the DNS message */ - status = ares_dns_write(qdnsrec, &msg, &msglen); - if (status != ARES_SUCCESS) { - goto done; - } - - ares_free(query->qbuf); - query->qbuf = msg; - query->qlen = msglen; - done: return status; } @@ -668,17 +607,16 @@ done: * the connection to be terminated after this call. */ static ares_status_t process_answer(ares_channel_t *channel, const unsigned char *abuf, size_t alen, - struct server_connection *conn, - ares_bool_t tcp, const ares_timeval_t *now) + ares_conn_t *conn, ares_bool_t tcp, + const ares_timeval_t *now) { - struct query *query; + ares_query_t *query; /* Cache these as once ares__send_query() gets called, it may end up * invalidating the connection all-together */ - struct server_state *server = conn->server; - ares_dns_record_t *rdnsrec = NULL; - ares_dns_record_t *qdnsrec = NULL; - ares_status_t status; - ares_bool_t is_cached = ARES_FALSE; + ares_server_t *server = conn->server; + ares_dns_record_t *rdnsrec = NULL; + ares_status_t status; + ares_bool_t is_cached = ARES_FALSE; /* Parse the response */ status = ares_dns_parse(abuf, alen, 0, &rdnsrec); @@ -699,21 +637,22 @@ static ares_status_t process_answer(ares_channel_t *channel, goto cleanup; } - /* Parse the question we sent as we use it to compare */ - status = ares_dns_parse(query->qbuf, query->qlen, 0, &qdnsrec); - if (status != ARES_SUCCESS) { - end_query(channel, query, status, NULL); - goto cleanup; - } - /* Both the query id and the questions must be the same. We will drop any * replies that aren't for the same query as this is considered invalid. */ - if (!same_questions(qdnsrec, rdnsrec)) { + if (!same_questions(query, rdnsrec)) { /* Possible qid conflict due to delayed response, that's ok */ status = ARES_SUCCESS; goto cleanup; } + /* Validate DNS cookie in response. This function may need to requeue the + * query. */ + if (ares_cookie_validate(query, rdnsrec, conn, now) != ARES_SUCCESS) { + /* Drop response and return */ + status = ARES_SUCCESS; + goto cleanup; + } + /* At this point we know we've received an answer for this query, so we should * remove it from the connection's queue so we can possibly invalidate the * connection. Delay cleaning up the connection though as we may enqueue @@ -725,10 +664,11 @@ static ares_status_t process_answer(ares_channel_t *channel, * protocol extension is not understood by the responder. We must retry the * query without EDNS enabled. */ if (ares_dns_record_get_rcode(rdnsrec) == ARES_RCODE_FORMERR && - ares_dns_has_opt_rr(qdnsrec) && !ares_dns_has_opt_rr(rdnsrec)) { - status = rewrite_without_edns(qdnsrec, query); + ares_dns_get_opt_rr_const(query->query) != NULL && + ares_dns_get_opt_rr_const(rdnsrec) == NULL) { + status = rewrite_without_edns(query); if (status != ARES_SUCCESS) { - end_query(channel, query, status, NULL); + end_query(channel, server, query, status, NULL); goto cleanup; } @@ -758,20 +698,20 @@ static ares_status_t process_answer(ares_channel_t *channel, rcode == ARES_RCODE_REFUSED) { switch (rcode) { case ARES_RCODE_SERVFAIL: - query->error_status = ARES_ESERVFAIL; + status = ARES_ESERVFAIL; break; case ARES_RCODE_NOTIMP: - query->error_status = ARES_ENOTIMP; + status = ARES_ENOTIMP; break; case ARES_RCODE_REFUSED: - query->error_status = ARES_EREFUSED; + status = ARES_EREFUSED; break; default: break; } server_increment_failures(server, query->using_tcp); - ares__requeue_query(query, now); + ares__requeue_query(query, now, status, ARES_TRUE); /* Should any of these cause a connection termination? * Maybe SERVER_FAILURE? */ @@ -787,7 +727,7 @@ static ares_status_t process_answer(ares_channel_t *channel, } server_set_good(server, query->using_tcp); - end_query(channel, query, ARES_SUCCESS, rdnsrec); + end_query(channel, server, query, ARES_SUCCESS, rdnsrec); status = ARES_SUCCESS; @@ -797,32 +737,42 @@ cleanup: ares_dns_record_destroy(rdnsrec); } - ares_dns_record_destroy(qdnsrec); return status; } -static void handle_conn_error(struct server_connection *conn, - ares_bool_t critical_failure) +static void handle_conn_error(ares_conn_t *conn, ares_bool_t critical_failure, + ares_status_t failure_status) { - struct server_state *server = conn->server; + ares_server_t *server = conn->server; /* Increment failures first before requeue so it is unlikely to requeue * to the same server */ if (critical_failure) { - server_increment_failures(server, conn->is_tcp); + server_increment_failures( + server, (conn->flags & ARES_CONN_FLAG_TCP) ? ARES_TRUE : ARES_FALSE); } /* This will requeue any connections automatically */ - ares__close_connection(conn); + ares__close_connection(conn, failure_status); } -ares_status_t ares__requeue_query(struct query *query, - const ares_timeval_t *now) +ares_status_t ares__requeue_query(ares_query_t *query, + const ares_timeval_t *now, + ares_status_t status, + ares_bool_t inc_try_count) { ares_channel_t *channel = query->channel; size_t max_tries = ares__slist_len(channel->servers) * channel->tries; - query->try_count++; + ares__query_disassociate_from_conn(query); + + if (status != ARES_SUCCESS) { + query->error_status = status; + } + + if (inc_try_count) { + query->try_count++; + } if (query->try_count < max_tries && !query->no_retries) { return ares__send_query(query, now); @@ -833,14 +783,14 @@ ares_status_t ares__requeue_query(struct query *query, query->error_status = ARES_ETIMEOUT; } - end_query(channel, query, query->error_status, NULL); + end_query(channel, NULL, query, query->error_status, NULL); return ARES_ETIMEOUT; } /* Pick a random server from the list, we first get a random number in the * range of the number of servers, then scan until we find that server in * the list */ -static struct server_state *ares__random_server(ares_channel_t *channel) +static ares_server_t *ares__random_server(ares_channel_t *channel) { unsigned char c; size_t cnt; @@ -884,16 +834,15 @@ static struct server_state *ares__random_server(ares_channel_t *channel) * To resolve this, with some probability we select a failed server to retry * instead. */ -static struct server_state *ares__failover_server(ares_channel_t *channel) +static ares_server_t *ares__failover_server(ares_channel_t *channel) { - struct server_state *first_server = ares__slist_first_val(channel->servers); - const struct server_state *last_server = - ares__slist_last_val(channel->servers); - unsigned short r; + ares_server_t *first_server = ares__slist_first_val(channel->servers); + const ares_server_t *last_server = ares__slist_last_val(channel->servers); + unsigned short r; /* Defensive code against no servers being available on the channel. */ if (first_server == NULL) { - return NULL; + return NULL; /* LCOV_EXCL_LINE: DefensiveCoding */ } /* If no servers have failures, then prefer the first server in the list. */ @@ -916,11 +865,13 @@ static struct server_state *ares__failover_server(ares_channel_t *channel) ares__rand_bytes(channel->rand_state, (unsigned char *)&r, sizeof(r)); if (r % channel->server_retry_chance == 0) { /* Select a suitable failed server to retry. */ - ares_timeval_t now = ares__tvnow(); + ares_timeval_t now; ares__slist_node_t *node; + + ares__tvnow(&now); for (node = ares__slist_node_first(channel->servers); node != NULL; node = ares__slist_node_next(node)) { - struct server_state *node_val = ares__slist_node_val(node); + ares_server_t *node_val = ares__slist_node_val(node); if (node_val != NULL && node_val->consec_failures > 0 && ares__timedout(&now, &node_val->next_retry_time)) { return node_val; @@ -932,27 +883,18 @@ static struct server_state *ares__failover_server(ares_channel_t *channel) return first_server; } -static ares_status_t ares__append_tcpbuf(struct server_state *server, - const struct query *query) -{ - ares_status_t status; - - status = ares__buf_append_be16(server->tcp_send, (unsigned short)query->qlen); - if (status != ARES_SUCCESS) { - return status; - } - return ares__buf_append(server->tcp_send, query->qbuf, query->qlen); -} - -static size_t ares__calc_query_timeout(const struct query *query) +static size_t ares__calc_query_timeout(const ares_query_t *query, + const ares_server_t *server, + const ares_timeval_t *now) { const ares_channel_t *channel = query->channel; - size_t timeplus = channel->timeout; + size_t timeout = ares_metrics_server_timeout(server, now); + size_t timeplus = timeout; size_t rounds; size_t num_servers = ares__slist_len(channel->servers); if (num_servers == 0) { - return 0; + return 0; /* LCOV_EXCL_LINE: DefensiveCoding */ } /* For each trip through the entire server list, we want to double the @@ -986,159 +928,211 @@ static size_t ares__calc_query_timeout(const struct query *query) /* We want explicitly guarantee that timeplus is greater or equal to timeout * specified in channel options. */ - if (timeplus < channel->timeout) { - timeplus = channel->timeout; + if (timeplus < timeout) { + timeplus = timeout; } return timeplus; } -ares_status_t ares__send_query(struct query *query, const ares_timeval_t *now) +static ares_conn_t *ares__fetch_connection(const ares_channel_t *channel, + ares_server_t *server, + const ares_query_t *query) { - ares_channel_t *channel = query->channel; - struct server_state *server; - struct server_connection *conn; - size_t timeplus; - ares_status_t status; - ares_bool_t new_connection = ARES_FALSE; - - query->conn = NULL; + ares__llist_node_t *node; + ares_conn_t *conn; - /* Choose the server to send the query to */ - if (channel->rotate) { - /* Pull random server */ - server = ares__random_server(channel); - } else { - /* Pull server with failover behavior */ - server = ares__failover_server(channel); + if (query->using_tcp) { + return server->tcp_conn; } - if (server == NULL) { - end_query(channel, query, ARES_ENOSERVER /* ? */, NULL); - return ARES_ENOSERVER; + /* Fetch existing UDP connection */ + node = ares__llist_node_first(server->connections); + if (node == NULL) { + return NULL; } - if (query->using_tcp) { - size_t prior_len = 0; - /* Make sure the TCP socket for this server is set up and queue - * a send request. - */ - if (server->tcp_conn == NULL) { - new_connection = ARES_TRUE; - status = ares__open_connection(channel, server, ARES_TRUE); - switch (status) { - /* Good result, continue on */ - case ARES_SUCCESS: - break; + conn = ares__llist_node_val(node); + /* Not UDP, skip */ + if (conn->flags & ARES_CONN_FLAG_TCP) { + return NULL; + } - /* These conditions are retryable as they are server-specific - * error codes */ - case ARES_ECONNREFUSED: - case ARES_EBADFAMILY: - server_increment_failures(server, query->using_tcp); - query->error_status = status; - return ares__requeue_query(query, now); + /* Used too many times */ + if (channel->udp_max_queries > 0 && + conn->total_queries >= channel->udp_max_queries) { + return NULL; + } - /* Anything else is not retryable, likely ENOMEM */ - default: - end_query(channel, query, status, NULL); - return status; - } - } + return conn; +} - conn = server->tcp_conn; +static ares_status_t ares__conn_query_write(ares_conn_t *conn, + ares_query_t *query, + const ares_timeval_t *now) +{ + unsigned char *qbuf = NULL; + size_t qbuf_len = 0; + ares_ssize_t len; + ares_server_t *server = conn->server; + ares_channel_t *channel = server->channel; + ares_status_t status; + + status = ares_cookie_apply(query->query, conn, now); + if (status != ARES_SUCCESS) { + return status; + } - prior_len = ares__buf_len(server->tcp_send); + if (conn->flags & ARES_CONN_FLAG_TCP) { + size_t prior_len = ares__buf_len(server->tcp_send); - status = ares__append_tcpbuf(server, query); + status = ares_dns_write_buf_tcp(query->query, server->tcp_send); if (status != ARES_SUCCESS) { - end_query(channel, query, status, NULL); + return status; + } - /* Only safe to kill connection if it was new, otherwise it should be - * cleaned up by another process later */ - if (new_connection) { - ares__close_connection(conn); + if (conn->flags & ARES_CONN_FLAG_TFO_INITIAL) { + /* When using TFO, we need to put it on the wire immediately. */ + size_t data_len; + const unsigned char *data = NULL; + + data = ares__buf_peek(server->tcp_send, &data_len); + len = ares__conn_write(conn, data, data_len); + if (len <= 0) { + if (ares__socket_try_again(SOCKERRNO)) { + /* This means we must not have qualified for TFO, keep the data + * buffered, wait on write signal. */ + return ARES_SUCCESS; + } + + /* TCP TFO might delay failure. Reflect that here */ + return ARES_ECONNREFUSED; } - return status; + + /* Consume what was written */ + ares__buf_consume(server->tcp_send, (size_t)len); + return ARES_SUCCESS; } if (prior_len == 0) { SOCK_STATE_CALLBACK(channel, conn->fd, 1, 1); } - } else { - ares__llist_node_t *node = ares__llist_node_first(server->connections); - - /* Don't use the found connection if we've gone over the maximum number - * of queries. Also, skip over the TCP connection if it is the first in - * the list */ - if (node != NULL) { - conn = ares__llist_node_val(node); - if (conn->is_tcp) { - node = NULL; - } else if (channel->udp_max_queries > 0 && - conn->total_queries >= channel->udp_max_queries) { - node = NULL; - } + return ARES_SUCCESS; + } + + /* UDP Here */ + status = ares_dns_write(query->query, &qbuf, &qbuf_len); + if (status != ARES_SUCCESS) { + return status; + } + + len = ares__conn_write(conn, qbuf, qbuf_len); + ares_free(qbuf); + + if (len == -1) { + if (ares__socket_try_again(SOCKERRNO)) { + return ARES_ESERVFAIL; } + /* UDP is connection-less, but we might receive an ICMP unreachable which + * means we can't talk to the remote host at all and that will be + * reflected here */ + return ARES_ECONNREFUSED; + } - if (node == NULL) { - new_connection = ARES_TRUE; - status = ares__open_connection(channel, server, ARES_FALSE); - switch (status) { - /* Good result, continue on */ - case ARES_SUCCESS: - break; + return ARES_SUCCESS; +} + +ares_status_t ares__send_query(ares_query_t *query, const ares_timeval_t *now) +{ + ares_channel_t *channel = query->channel; + ares_server_t *server; + ares_conn_t *conn; + size_t timeplus; + ares_status_t status; - /* These conditions are retryable as they are server-specific - * error codes */ - case ARES_ECONNREFUSED: - case ARES_EBADFAMILY: - server_increment_failures(server, query->using_tcp); - query->error_status = status; - return ares__requeue_query(query, now); + /* Choose the server to send the query to */ + if (channel->rotate) { + /* Pull random server */ + server = ares__random_server(channel); + } else { + /* Pull server with failover behavior */ + server = ares__failover_server(channel); + } - /* Anything else is not retryable, likely ENOMEM */ - default: - end_query(channel, query, status, NULL); - return status; - } - node = ares__llist_node_first(server->connections); + if (server == NULL) { + end_query(channel, server, query, ARES_ENOSERVER /* ? */, NULL); + return ARES_ENOSERVER; + } + + conn = ares__fetch_connection(channel, server, query); + if (conn == NULL) { + status = ares__open_connection(&conn, channel, server, query->using_tcp); + switch (status) { + /* Good result, continue on */ + case ARES_SUCCESS: + break; + + /* These conditions are retryable as they are server-specific + * error codes */ + case ARES_ECONNREFUSED: + case ARES_EBADFAMILY: + server_increment_failures(server, query->using_tcp); + return ares__requeue_query(query, now, status, ARES_TRUE); + + /* Anything else is not retryable, likely ENOMEM */ + default: + end_query(channel, server, query, status, NULL); + return status; } + } - conn = ares__llist_node_val(node); - if (ares__socket_write(channel, conn->fd, query->qbuf, query->qlen) == -1) { - /* FIXME: Handle EAGAIN here since it likely can happen. */ - server_increment_failures(server, query->using_tcp); - status = ares__requeue_query(query, now); + /* Write the query */ + status = ares__conn_query_write(conn, query, now); + switch (status) { + /* Good result, continue on */ + case ARES_SUCCESS: + break; - /* Only safe to kill connection if it was new, otherwise it should be - * cleaned up by another process later */ - if (new_connection) { - ares__close_connection(conn); + case ARES_ENOMEM: + /* Not retryable */ + end_query(channel, server, query, status, NULL); + return status; + + /* These conditions are retryable as they are server-specific + * error codes */ + case ARES_ECONNREFUSED: + case ARES_EBADFAMILY: + handle_conn_error(conn, ARES_TRUE, status); + status = ares__requeue_query(query, now, status, ARES_TRUE); + if (status == ARES_ETIMEOUT) { + status = ARES_ECONNREFUSED; } + return status; + /* FIXME: Handle EAGAIN here since it likely can happen. Right now we + * just requeue to a different server/connection. */ + default: + server_increment_failures(server, query->using_tcp); + status = ares__requeue_query(query, now, status, ARES_TRUE); return status; - } } - timeplus = ares__calc_query_timeout(query); + timeplus = ares__calc_query_timeout(query, server, now); /* Keep track of queries bucketed by timeout, so we can process * timeout events quickly. */ ares__slist_node_destroy(query->node_queries_by_timeout); + query->ts = *now; query->timeout = *now; timeadd(&query->timeout, timeplus); query->node_queries_by_timeout = ares__slist_insert(channel->queries_by_timeout, query); if (!query->node_queries_by_timeout) { - end_query(channel, query, ARES_ENOMEM, NULL); - /* Only safe to kill connection if it was new, otherwise it should be - * cleaned up by another process later */ - if (new_connection) { - ares__close_connection(conn); - } + /* LCOV_EXCL_START: OutOfMemory */ + end_query(channel, server, query, ARES_ENOMEM, NULL); return ARES_ENOMEM; + /* LCOV_EXCL_STOP */ } /* Keep track of queries bucketed by connection, so we can process errors @@ -1148,13 +1142,10 @@ ares_status_t ares__send_query(struct query *query, const ares_timeval_t *now) ares__llist_insert_last(conn->queries_to_conn, query); if (query->node_queries_to_conn == NULL) { - end_query(channel, query, ARES_ENOMEM, NULL); - /* Only safe to kill connection if it was new, otherwise it should be - * cleaned up by another process later */ - if (new_connection) { - ares__close_connection(conn); - } + /* LCOV_EXCL_START: OutOfMemory */ + end_query(channel, server, query, ARES_ENOMEM, NULL); return ARES_ENOMEM; + /* LCOV_EXCL_STOP */ } query->conn = conn; @@ -1162,11 +1153,13 @@ ares_status_t ares__send_query(struct query *query, const ares_timeval_t *now) return ARES_SUCCESS; } -static ares_bool_t same_questions(const ares_dns_record_t *qrec, +static ares_bool_t same_questions(const ares_query_t *query, const ares_dns_record_t *arec) { - size_t i; - ares_bool_t rv = ARES_FALSE; + size_t i; + ares_bool_t rv = ARES_FALSE; + const ares_dns_record_t *qrec = query->query; + const ares_channel_t *channel = query->channel; if (ares_dns_record_query_cnt(qrec) != ares_dns_record_query_cnt(arec)) { @@ -1192,9 +1185,26 @@ static ares_bool_t same_questions(const ares_dns_record_t *qrec, aname == NULL) { goto done; } - if (strcasecmp(qname, aname) != 0 || qtype != atype || qclass != aclass) { + + if (qtype != atype || qclass != aclass) { goto done; } + + if (channel->flags & ARES_FLAG_DNS0x20 && !query->using_tcp) { + /* NOTE: for DNS 0x20, part of the protection is to use a case-sensitive + * comparison of the DNS query name. This expects the upstream DNS + * server to preserve the case of the name in the response packet. + * https://datatracker.ietf.org/doc/html/draft-vixie-dnsext-dns0x20-00 + */ + if (strcmp(qname, aname) != 0) { + goto done; + } + } else { + /* without DNS0x20 use case-insensitive matching */ + if (strcasecmp(qname, aname) != 0) { + goto done; + } + } } rv = ARES_TRUE; @@ -1213,14 +1223,15 @@ static ares_bool_t same_address(const struct sockaddr *sa, switch (aa->family) { case AF_INET: addr1 = &aa->addr.addr4; - addr2 = &(CARES_INADDR_CAST(struct sockaddr_in *, sa))->sin_addr; + addr2 = &(CARES_INADDR_CAST(const struct sockaddr_in *, sa))->sin_addr; if (memcmp(addr1, addr2, sizeof(aa->addr.addr4)) == 0) { return ARES_TRUE; /* match */ } break; case AF_INET6: addr1 = &aa->addr.addr6; - addr2 = &(CARES_INADDR_CAST(struct sockaddr_in6 *, sa))->sin6_addr; + addr2 = + &(CARES_INADDR_CAST(const struct sockaddr_in6 *, sa))->sin6_addr; if (memcmp(addr1, addr2, sizeof(aa->addr.addr6)) == 0) { return ARES_TRUE; /* match */ } @@ -1232,21 +1243,21 @@ static ares_bool_t same_address(const struct sockaddr *sa, return ARES_FALSE; /* different */ } -static void ares_detach_query(struct query *query) +static void ares_detach_query(ares_query_t *query) { /* Remove the query from all the lists in which it is linked */ + ares__query_disassociate_from_conn(query); ares__htable_szvp_remove(query->channel->queries_by_qid, query->qid); - ares__slist_node_destroy(query->node_queries_by_timeout); - ares__llist_node_destroy(query->node_queries_to_conn); ares__llist_node_destroy(query->node_all_queries); - query->node_queries_by_timeout = NULL; - query->node_queries_to_conn = NULL; - query->node_all_queries = NULL; + query->node_all_queries = NULL; } -static void end_query(ares_channel_t *channel, struct query *query, - ares_status_t status, const ares_dns_record_t *dnsrec) +static void end_query(ares_channel_t *channel, ares_server_t *server, + ares_query_t *query, ares_status_t status, + const ares_dns_record_t *dnsrec) { + ares_metrics_record(query, server, status, dnsrec); + /* Invoke the callback. */ query->callback(query->arg, status, query->timeouts, dnsrec); ares__free_query(query); @@ -1259,14 +1270,14 @@ static void end_query(ares_channel_t *channel, struct query *query, ares_queue_notify_empty(channel); } -void ares__free_query(struct query *query) +void ares__free_query(ares_query_t *query) { ares_detach_query(query); /* Zero out some important stuff, to help catch bugs */ query->callback = NULL; query->arg = NULL; /* Deallocate the memory associated with the query */ - ares_free(query->qbuf); + ares_dns_record_destroy(query->query); ares_free(query); } diff --git a/contrib/libs/c-ares/src/lib/ares_qcache.c b/contrib/libs/c-ares/src/lib/ares_qcache.c index 087518d7b8..aee1328b51 100644 --- a/contrib/libs/c-ares/src/lib/ares_qcache.c +++ b/contrib/libs/c-ares/src/lib/ares_qcache.c @@ -23,8 +23,6 @@ * * SPDX-License-Identifier: MIT */ -#include "ares_setup.h" -#include "ares.h" #include "ares_private.h" struct ares__qcache { @@ -48,7 +46,7 @@ static char *ares__qcache_calc_key(const ares_dns_record_t *dnsrec) ares_dns_flags_t flags; if (dnsrec == NULL || buf == NULL) { - return NULL; + return NULL; /* LCOV_EXCL_LINE: DefensiveCoding */ } /* Format is OPCODE|FLAGS[|QTYPE1|QCLASS1|QNAME1]... */ @@ -56,12 +54,12 @@ static char *ares__qcache_calc_key(const ares_dns_record_t *dnsrec) status = ares__buf_append_str( buf, ares_dns_opcode_tostr(ares_dns_record_get_opcode(dnsrec))); if (status != ARES_SUCCESS) { - goto fail; + goto fail; /* LCOV_EXCL_LINE: OutOfMemory */ } status = ares__buf_append_byte(buf, '|'); if (status != ARES_SUCCESS) { - goto fail; + goto fail; /* LCOV_EXCL_LINE: OutOfMemory */ } flags = ares_dns_record_get_flags(dnsrec); @@ -69,13 +67,13 @@ static char *ares__qcache_calc_key(const ares_dns_record_t *dnsrec) if (flags & ARES_FLAG_RD) { status = ares__buf_append_str(buf, "rd"); if (status != ARES_SUCCESS) { - goto fail; + goto fail; /* LCOV_EXCL_LINE: OutOfMemory */ } } if (flags & ARES_FLAG_CD) { status = ares__buf_append_str(buf, "cd"); if (status != ARES_SUCCESS) { - goto fail; + goto fail; /* LCOV_EXCL_LINE: OutOfMemory */ } } @@ -87,32 +85,32 @@ static char *ares__qcache_calc_key(const ares_dns_record_t *dnsrec) status = ares_dns_record_query_get(dnsrec, i, &name, &qtype, &qclass); if (status != ARES_SUCCESS) { - goto fail; + goto fail; /* LCOV_EXCL_LINE: DefensiveCoding */ } status = ares__buf_append_byte(buf, '|'); if (status != ARES_SUCCESS) { - goto fail; + goto fail; /* LCOV_EXCL_LINE: OutOfMemory */ } status = ares__buf_append_str(buf, ares_dns_rec_type_tostr(qtype)); if (status != ARES_SUCCESS) { - goto fail; + goto fail; /* LCOV_EXCL_LINE: OutOfMemory */ } status = ares__buf_append_byte(buf, '|'); if (status != ARES_SUCCESS) { - goto fail; + goto fail; /* LCOV_EXCL_LINE: OutOfMemory */ } status = ares__buf_append_str(buf, ares_dns_class_tostr(qclass)); if (status != ARES_SUCCESS) { - goto fail; + goto fail; /* LCOV_EXCL_LINE: OutOfMemory */ } status = ares__buf_append_byte(buf, '|'); if (status != ARES_SUCCESS) { - goto fail; + goto fail; /* LCOV_EXCL_LINE: OutOfMemory */ } /* On queries, a '.' may be appended to the name to indicate an explicit @@ -125,15 +123,17 @@ static char *ares__qcache_calc_key(const ares_dns_record_t *dnsrec) status = ares__buf_append(buf, (const unsigned char *)name, name_len); if (status != ARES_SUCCESS) { - goto fail; + goto fail; /* LCOV_EXCL_LINE: OutOfMemory */ } } return ares__buf_finish_str(buf, NULL); +/* LCOV_EXCL_START: OutOfMemory */ fail: ares__buf_destroy(buf); return NULL; + /* LCOV_EXCL_STOP */ } static void ares__qcache_expire(ares__qcache_t *cache, @@ -194,7 +194,7 @@ static void ares__qcache_entry_destroy_cb(void *arg) { ares__qcache_entry_t *entry = arg; if (entry == NULL) { - return; + return; /* LCOV_EXCL_LINE: DefensiveCoding */ } ares_free(entry->key); @@ -211,21 +211,21 @@ ares_status_t ares__qcache_create(ares_rand_state *rand_state, cache = ares_malloc_zero(sizeof(*cache)); if (cache == NULL) { - status = ARES_ENOMEM; - goto done; + status = ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ + goto done; /* LCOV_EXCL_LINE: OutOfMemory */ } cache->cache = ares__htable_strvp_create(NULL); if (cache->cache == NULL) { - status = ARES_ENOMEM; - goto done; + status = ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ + goto done; /* LCOV_EXCL_LINE: OutOfMemory */ } cache->expire = ares__slist_create(rand_state, ares__qcache_entry_sort_cb, ares__qcache_entry_destroy_cb); if (cache->expire == NULL) { - status = ARES_ENOMEM; - goto done; + status = ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ + goto done; /* LCOV_EXCL_LINE: OutOfMemory */ } cache->max_ttl = max_ttl; @@ -299,37 +299,18 @@ static unsigned int ares__qcache_soa_minimum(ares_dns_record_t *dnsrec) return 0; } -static char *ares__qcache_calc_key_frombuf(const unsigned char *qbuf, - size_t qlen) -{ - ares_status_t status; - ares_dns_record_t *dnsrec = NULL; - char *key = NULL; - - status = ares_dns_parse(qbuf, qlen, 0, &dnsrec); - if (status != ARES_SUCCESS) { - goto done; - } - - key = ares__qcache_calc_key(dnsrec); - -done: - ares_dns_record_destroy(dnsrec); - return key; -} - /* On success, takes ownership of dnsrec */ -static ares_status_t ares__qcache_insert(ares__qcache_t *qcache, - ares_dns_record_t *dnsrec, - const unsigned char *qbuf, size_t qlen, - const ares_timeval_t *now) +static ares_status_t ares__qcache_insert(ares__qcache_t *qcache, + ares_dns_record_t *qresp, + const ares_dns_record_t *qreq, + const ares_timeval_t *now) { ares__qcache_entry_t *entry; unsigned int ttl; - ares_dns_rcode_t rcode = ares_dns_record_get_rcode(dnsrec); - ares_dns_flags_t flags = ares_dns_record_get_flags(dnsrec); + ares_dns_rcode_t rcode = ares_dns_record_get_rcode(qresp); + ares_dns_flags_t flags = ares_dns_record_get_flags(qresp); - if (qcache == NULL || dnsrec == NULL) { + if (qcache == NULL || qresp == NULL) { return ARES_EFORMERR; } @@ -345,9 +326,13 @@ static ares_status_t ares__qcache_insert(ares__qcache_t *qcache, /* Look at SOA for NXDOMAIN for minimum */ if (rcode == ARES_RCODE_NXDOMAIN) { - ttl = ares__qcache_soa_minimum(dnsrec); + ttl = ares__qcache_soa_minimum(qresp); } else { - ttl = ares__qcache_calc_minttl(dnsrec); + ttl = ares__qcache_calc_minttl(qresp); + } + + if (ttl > qcache->max_ttl) { + ttl = qcache->max_ttl; } /* Don't cache something that is already expired */ @@ -355,16 +340,12 @@ static ares_status_t ares__qcache_insert(ares__qcache_t *qcache, return ARES_EREFUSED; } - if (ttl > qcache->max_ttl) { - ttl = qcache->max_ttl; - } - entry = ares_malloc_zero(sizeof(*entry)); if (entry == NULL) { - goto fail; + goto fail; /* LCOV_EXCL_LINE: OutOfMemory */ } - entry->dnsrec = dnsrec; + entry->dnsrec = qresp; entry->expire_ts = now->sec + (time_t)ttl; entry->insert_ts = now->sec; @@ -372,21 +353,22 @@ static ares_status_t ares__qcache_insert(ares__qcache_t *qcache, * request had, so we have to re-parse the request in order to generate the * key for caching, but we'll only do this once we know for sure we really * want to cache it */ - entry->key = ares__qcache_calc_key_frombuf(qbuf, qlen); + entry->key = ares__qcache_calc_key(qreq); if (entry->key == NULL) { - goto fail; + goto fail; /* LCOV_EXCL_LINE: OutOfMemory */ } if (!ares__htable_strvp_insert(qcache->cache, entry->key, entry)) { - goto fail; + goto fail; /* LCOV_EXCL_LINE: OutOfMemory */ } if (ares__slist_insert(qcache->expire, entry) == NULL) { - goto fail; + goto fail; /* LCOV_EXCL_LINE: OutOfMemory */ } return ARES_SUCCESS; +/* LCOV_EXCL_START: OutOfMemory */ fail: if (entry != NULL && entry->key != NULL) { ares__htable_strvp_remove(qcache->cache, entry->key); @@ -394,6 +376,7 @@ fail: ares_free(entry); } return ARES_ENOMEM; + /* LCOV_EXCL_STOP */ } ares_status_t ares_qcache_fetch(ares_channel_t *channel, @@ -417,8 +400,8 @@ ares_status_t ares_qcache_fetch(ares_channel_t *channel, key = ares__qcache_calc_key(dnsrec); if (key == NULL) { - status = ARES_ENOMEM; - goto done; + status = ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ + goto done; /* LCOV_EXCL_LINE: OutOfMemory */ } entry = ares__htable_strvp_get_direct(channel->qcache->cache, key); @@ -439,9 +422,8 @@ done: ares_status_t ares_qcache_insert(ares_channel_t *channel, const ares_timeval_t *now, - const struct query *query, + const ares_query_t *query, ares_dns_record_t *dnsrec) { - return ares__qcache_insert(channel->qcache, dnsrec, query->qbuf, query->qlen, - now); + return ares__qcache_insert(channel->qcache, dnsrec, query->query, now); } diff --git a/contrib/libs/c-ares/src/lib/ares_query.c b/contrib/libs/c-ares/src/lib/ares_query.c index 0eea80e7fc..4d0861a5f5 100644 --- a/contrib/libs/c-ares/src/lib/ares_query.c +++ b/contrib/libs/c-ares/src/lib/ares_query.c @@ -25,18 +25,12 @@ * SPDX-License-Identifier: MIT */ -#include "ares_setup.h" +#include "ares_private.h" #ifdef HAVE_NETINET_IN_H # include <netinet/in.h> #endif -#include "ares_nameser.h" - -#include "ares.h" -#include "ares_dns.h" -#include "ares_private.h" - typedef struct { ares_callback_dnsrec callback; void *arg; @@ -64,11 +58,11 @@ static void ares_query_dnsrec_cb(void *arg, ares_status_t status, ares_free(qquery); } -static ares_status_t ares_query_int(ares_channel_t *channel, const char *name, - ares_dns_class_t dnsclass, - ares_dns_rec_type_t type, - ares_callback_dnsrec callback, void *arg, - unsigned short *qid) +ares_status_t ares_query_nolock(ares_channel_t *channel, const char *name, + ares_dns_class_t dnsclass, + ares_dns_rec_type_t type, + ares_callback_dnsrec callback, void *arg, + unsigned short *qid) { ares_status_t status; ares_dns_record_t *dnsrec = NULL; @@ -76,11 +70,13 @@ static ares_status_t ares_query_int(ares_channel_t *channel, const char *name, ares_query_dnsrec_arg_t *qquery = NULL; if (channel == NULL || name == NULL || callback == NULL) { + /* LCOV_EXCL_START: DefensiveCoding */ status = ARES_EFORMERR; if (callback != NULL) { callback(arg, status, 0, NULL); } return status; + /* LCOV_EXCL_STOP */ } if (!(channel->flags & ARES_FLAG_NORECURSE)) { @@ -91,23 +87,25 @@ static ares_status_t ares_query_int(ares_channel_t *channel, const char *name, &dnsrec, name, dnsclass, type, 0, flags, (size_t)(channel->flags & ARES_FLAG_EDNS) ? channel->ednspsz : 0); if (status != ARES_SUCCESS) { - callback(arg, status, 0, NULL); - return status; + callback(arg, status, 0, NULL); /* LCOV_EXCL_LINE: OutOfMemory */ + return status; /* LCOV_EXCL_LINE: OutOfMemory */ } qquery = ares_malloc(sizeof(*qquery)); if (qquery == NULL) { + /* LCOV_EXCL_START: OutOfMemory */ status = ARES_ENOMEM; callback(arg, status, 0, NULL); ares_dns_record_destroy(dnsrec); return status; + /* LCOV_EXCL_STOP */ } qquery->callback = callback; qquery->arg = arg; /* Send it off. qcallback will be called when we get an answer. */ - status = ares_send_dnsrec(channel, dnsrec, ares_query_dnsrec_cb, qquery, qid); + status = ares_send_nolock(channel, dnsrec, ares_query_dnsrec_cb, qquery, qid); ares_dns_record_destroy(dnsrec); return status; @@ -126,7 +124,7 @@ ares_status_t ares_query_dnsrec(ares_channel_t *channel, const char *name, } ares__channel_lock(channel); - status = ares_query_int(channel, name, dnsclass, type, callback, arg, qid); + status = ares_query_nolock(channel, name, dnsclass, type, callback, arg, qid); ares__channel_unlock(channel); return status; } @@ -142,8 +140,8 @@ void ares_query(ares_channel_t *channel, const char *name, int dnsclass, carg = ares__dnsrec_convert_arg(callback, arg); if (carg == NULL) { - callback(arg, ARES_ENOMEM, 0, NULL, 0); - return; + callback(arg, ARES_ENOMEM, 0, NULL, 0); /* LCOV_EXCL_LINE: OutOfMemory */ + return; /* LCOV_EXCL_LINE: OutOfMemory */ } ares_query_dnsrec(channel, name, (ares_dns_class_t)dnsclass, diff --git a/contrib/libs/c-ares/src/lib/ares_search.c b/contrib/libs/c-ares/src/lib/ares_search.c index 4fd909cd4f..ae98df39a8 100644 --- a/contrib/libs/c-ares/src/lib/ares_search.c +++ b/contrib/libs/c-ares/src/lib/ares_search.c @@ -25,16 +25,12 @@ * SPDX-License-Identifier: MIT */ -#include "ares_setup.h" +#include "ares_private.h" #ifdef HAVE_STRINGS_H # include <strings.h> #endif -#include "ares.h" -#include "ares_private.h" -#include "ares_dns.h" - struct search_query { /* Arguments passed to ares_search_dnsrec() */ ares_channel_t *channel; @@ -57,7 +53,7 @@ struct search_query { static void squery_free(struct search_query *squery) { if (squery == NULL) { - return; + return; /* LCOV_EXCL_LINE: DefensiveCoding */ } ares__strsplit_free(squery->names, squery->names_cnt); ares_dns_record_destroy(squery->dnsrec); @@ -87,7 +83,7 @@ static ares_status_t ares_search_next(ares_channel_t *channel, /* Misuse check */ if (squery->next_name_idx >= squery->names_cnt) { - return ARES_EFORMERR; + return ARES_EFORMERR; /* LCOV_EXCL_LINE: DefensiveCoding */ } status = ares_dns_record_query_set_name( @@ -97,7 +93,7 @@ static ares_status_t ares_search_next(ares_channel_t *channel, } status = - ares_send_dnsrec(channel, squery->dnsrec, search_callback, squery, NULL); + ares_send_nolock(channel, squery->dnsrec, search_callback, squery, NULL); if (status != ARES_EFORMERR) { *skip_cleanup = ARES_TRUE; @@ -200,8 +196,8 @@ ares_status_t ares__search_name_list(const ares_channel_t *channel, list_len = 1; list = ares_malloc_zero(sizeof(*list) * list_len); if (list == NULL) { - status = ARES_ENOMEM; - goto done; + status = ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ + goto done; /* LCOV_EXCL_LINE: OutOfMemory */ } list[0] = alias; alias = NULL; @@ -215,12 +211,12 @@ ares_status_t ares__search_name_list(const ares_channel_t *channel, list_len = 1; list = ares_malloc_zero(sizeof(*list) * list_len); if (list == NULL) { - status = ARES_ENOMEM; - goto done; + status = ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ + goto done; /* LCOV_EXCL_LINE: OutOfMemory */ } list[0] = ares_strdup(name); if (list[0] == NULL) { - status = ARES_ENOMEM; + status = ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ } else { status = ARES_SUCCESS; } @@ -322,8 +318,8 @@ static ares_status_t ares_search_int(ares_channel_t *channel, */ squery = ares_malloc_zero(sizeof(*squery)); if (squery == NULL) { - status = ARES_ENOMEM; - goto fail; + status = ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ + goto fail; /* LCOV_EXCL_LINE: OutOfMemory */ } squery->channel = channel; @@ -331,8 +327,8 @@ static ares_status_t ares_search_int(ares_channel_t *channel, /* Duplicate DNS record since, name will need to be rewritten */ squery->dnsrec = ares_dns_record_duplicate(dnsrec); if (squery->dnsrec == NULL) { - status = ARES_ENOMEM; - goto fail; + status = ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ + goto fail; /* LCOV_EXCL_LINE: OutOfMemory */ } squery->callback = callback; @@ -456,7 +452,7 @@ ares_status_t ares_search_dnsrec(ares_channel_t *channel, ares_status_t status; if (channel == NULL || dnsrec == NULL || callback == NULL) { - return ARES_EFORMERR; + return ARES_EFORMERR; /* LCOV_EXCL_LINE: DefensiveCoding */ } ares__channel_lock(channel); @@ -498,7 +494,7 @@ ares_status_t ares__lookup_hostaliases(const ares_channel_t *channel, ares__llist_node_t *node; if (channel == NULL || name == NULL || alias == NULL) { - return ARES_EFORMERR; + return ARES_EFORMERR; /* LCOV_EXCL_LINE: DefensiveCoding */ } *alias = NULL; @@ -521,8 +517,8 @@ ares_status_t ares__lookup_hostaliases(const ares_channel_t *channel, buf = ares__buf_create(); if (buf == NULL) { - status = ARES_ENOMEM; - goto done; + status = ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ + goto done; /* LCOV_EXCL_LINE: OutOfMemory */ } status = ares__buf_load_file(hostaliases, buf); @@ -581,8 +577,8 @@ ares_status_t ares__lookup_hostaliases(const ares_channel_t *channel, *alias = ares_strdup(fqdn); if (*alias == NULL) { - status = ARES_ENOMEM; - goto done; + status = ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ + goto done; /* LCOV_EXCL_LINE: OutOfMemory */ } /* Good! */ diff --git a/contrib/libs/c-ares/src/lib/ares_send.c b/contrib/libs/c-ares/src/lib/ares_send.c index 8bbc6e758b..9441534404 100644 --- a/contrib/libs/c-ares/src/lib/ares_send.c +++ b/contrib/libs/c-ares/src/lib/ares_send.c @@ -25,18 +25,13 @@ * SPDX-License-Identifier: MIT */ -#include "ares_setup.h" +#include "ares_private.h" #ifdef HAVE_NETINET_IN_H # include <netinet/in.h> #endif - #include "ares_nameser.h" -#include "ares.h" -#include "ares_dns.h" -#include "ares_private.h" - static unsigned short generate_unique_qid(ares_channel_t *channel) { unsigned short id; @@ -48,18 +43,77 @@ static unsigned short generate_unique_qid(ares_channel_t *channel) return id; } -static ares_status_t ares_send_dnsrec_int(ares_channel_t *channel, - const ares_dns_record_t *dnsrec, - ares_callback_dnsrec callback, - void *arg, unsigned short *qid) +/* https://datatracker.ietf.org/doc/html/draft-vixie-dnsext-dns0x20-00 */ +static ares_status_t ares_apply_dns0x20(ares_channel_t *channel, + ares_dns_record_t *dnsrec) +{ + ares_status_t status = ARES_SUCCESS; + const char *name = NULL; + char dns0x20name[256]; + unsigned char randdata[256 / 8]; + size_t len; + size_t remaining_bits; + size_t total_bits; + size_t i; + + status = ares_dns_record_query_get(dnsrec, 0, &name, NULL, NULL); + if (status != ARES_SUCCESS) { + goto done; + } + + len = ares_strlen(name); + if (len == 0 || len >= sizeof(dns0x20name)) { + status = ARES_EBADNAME; + goto done; + } + + memset(dns0x20name, 0, sizeof(dns0x20name)); + + /* Fetch the minimum amount of random data we'd need for the string, which + * is 1 bit per byte */ + total_bits = ((len + 7) / 8) * 8; + remaining_bits = total_bits; + ares__rand_bytes(channel->rand_state, randdata, total_bits / 8); + + /* Randomly apply 0x20 to name */ + for (i = 0; i < len; i++) { + size_t bit; + + /* Only apply 0x20 to alpha characters */ + if (!ares__isalpha(name[i])) { + dns0x20name[i] = name[i]; + continue; + } + + /* coin flip */ + bit = total_bits - remaining_bits; + if (randdata[bit / 8] & (1 << (bit % 8))) { + dns0x20name[i] = name[i] | 0x20; /* Set 0x20 */ + } else { + dns0x20name[i] = (char)(((unsigned char)name[i]) & 0xDF); /* Unset 0x20 */ + } + remaining_bits--; + } + + status = ares_dns_record_query_set_name(dnsrec, 0, dns0x20name); + +done: + return status; +} + +ares_status_t ares_send_nolock(ares_channel_t *channel, + const ares_dns_record_t *dnsrec, + ares_callback_dnsrec callback, void *arg, + unsigned short *qid) { - struct query *query; - size_t packetsz; - ares_timeval_t now = ares__tvnow(); + ares_query_t *query; + ares_timeval_t now; ares_status_t status; unsigned short id = generate_unique_qid(channel); const ares_dns_record_t *dnsrec_resp = NULL; + ares__tvnow(&now); + if (ares__slist_len(channel->servers) == 0) { callback(arg, ARES_ENOSERVER, 0, NULL); return ARES_ENOSERVER; @@ -75,29 +129,40 @@ static ares_status_t ares_send_dnsrec_int(ares_channel_t *channel, } /* Allocate space for query and allocated fields. */ - query = ares_malloc(sizeof(struct query)); + query = ares_malloc(sizeof(ares_query_t)); if (!query) { - callback(arg, ARES_ENOMEM, 0, NULL); - return ARES_ENOMEM; + callback(arg, ARES_ENOMEM, 0, NULL); /* LCOV_EXCL_LINE: OutOfMemory */ + return ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ } memset(query, 0, sizeof(*query)); - query->channel = channel; + query->channel = channel; + query->qid = id; + query->timeout.sec = 0; + query->timeout.usec = 0; + query->using_tcp = + (channel->flags & ARES_FLAG_USEVC) ? ARES_TRUE : ARES_FALSE; - status = ares_dns_write(dnsrec, &query->qbuf, &query->qlen); + /* Duplicate Query */ + status = ares_dns_record_duplicate_ex(&query->query, dnsrec); if (status != ARES_SUCCESS) { ares_free(query); callback(arg, status, 0, NULL); return status; } - query->qid = id; - query->timeout.sec = 0; - query->timeout.usec = 0; - - /* Ignore first 2 bytes, assign our own query id */ - query->qbuf[0] = (unsigned char)((id >> 8) & 0xFF); - query->qbuf[1] = (unsigned char)(id & 0xFF); + ares_dns_record_set_id(query->query, id); + + if (channel->flags & ARES_FLAG_DNS0x20 && !query->using_tcp) { + status = ares_apply_dns0x20(channel, query->query); + if (status != ARES_SUCCESS) { + /* LCOV_EXCL_START: OutOfMemory */ + callback(arg, status, 0, NULL); + ares__free_query(query); + return status; + /* LCOV_EXCL_STOP */ + } + } /* Fill in query arguments. */ query->callback = callback; @@ -106,9 +171,6 @@ static ares_status_t ares_send_dnsrec_int(ares_channel_t *channel, /* Initialize query status. */ query->try_count = 0; - packetsz = (channel->flags & ARES_FLAG_EDNS) ? channel->ednspsz : PACKETSZ; - query->using_tcp = - (channel->flags & ARES_FLAG_USEVC) || query->qlen > packetsz; query->error_status = ARES_SUCCESS; query->timeouts = 0; @@ -121,18 +183,22 @@ static ares_status_t ares_send_dnsrec_int(ares_channel_t *channel, query->node_all_queries = ares__llist_insert_last(channel->all_queries, query); if (query->node_all_queries == NULL) { + /* LCOV_EXCL_START: OutOfMemory */ callback(arg, ARES_ENOMEM, 0, NULL); ares__free_query(query); return ARES_ENOMEM; + /* LCOV_EXCL_STOP */ } /* Keep track of queries bucketed by qid, so we can process DNS * responses quickly. */ if (!ares__htable_szvp_insert(channel->queries_by_qid, query->qid, query)) { + /* LCOV_EXCL_START: OutOfMemory */ callback(arg, ARES_ENOMEM, 0, NULL); ares__free_query(query); return ARES_ENOMEM; + /* LCOV_EXCL_STOP */ } /* Perform the first query action. */ @@ -152,12 +218,12 @@ ares_status_t ares_send_dnsrec(ares_channel_t *channel, ares_status_t status; if (channel == NULL) { - return ARES_EFORMERR; + return ARES_EFORMERR; /* LCOV_EXCL_LINE: DefensiveCoding */ } ares__channel_lock(channel); - status = ares_send_dnsrec_int(channel, dnsrec, callback, arg, qid); + status = ares_send_nolock(channel, dnsrec, callback, arg, qid); ares__channel_unlock(channel); @@ -189,10 +255,12 @@ void ares_send(ares_channel_t *channel, const unsigned char *qbuf, int qlen, carg = ares__dnsrec_convert_arg(callback, arg); if (carg == NULL) { + /* LCOV_EXCL_START: OutOfMemory */ status = ARES_ENOMEM; ares_dns_record_destroy(dnsrec); callback(arg, (int)status, 0, NULL, 0); return; + /* LCOV_EXCL_STOP */ } ares_send_dnsrec(channel, dnsrec, ares__dnsrec_convert_cb, carg, NULL); diff --git a/contrib/libs/c-ares/src/lib/ares_setup.h b/contrib/libs/c-ares/src/lib/ares_setup.h index c506449dbd..d771e4e141 100644 --- a/contrib/libs/c-ares/src/lib/ares_setup.h +++ b/contrib/libs/c-ares/src/lib/ares_setup.h @@ -23,17 +23,17 @@ * * SPDX-License-Identifier: MIT */ -#ifndef HEADER_CARES_SETUP_H -#define HEADER_CARES_SETUP_H - -/* - * Define WIN32 when build target is Win32 API +#ifndef __ARES_SETUP_H +#define __ARES_SETUP_H + +/* ============================================================================ + * NOTE: This file is automatically included by ares_private.h and should not + * typically be included directly. + * All c-ares source files should include ares_private.h as the + * first header. + * ============================================================================ */ -#if (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32) -# define WIN32 -#endif - /* * Include configuration script results or hand-crafted * configuration file for platforms which lack config tool. @@ -42,62 +42,17 @@ #if defined(HAVE_CONFIG_H) && !defined(_MSC_VER) # include "ares_config.h" #else - -# ifdef WIN32 +# ifdef _WIN32 # include "config-win32.h" # endif - #endif /* HAVE_CONFIG_H */ -/* ================================================================ */ -/* Definition of preprocessor macros/symbols which modify compiler */ -/* behaviour or generated code characteristics must be done here, */ -/* as appropriate, before any system header file is included. It is */ -/* also possible to have them defined in the config file included */ -/* before this point. As a result of all this we frown inclusion of */ -/* system header files in our config files, avoid this at any cost. */ -/* ================================================================ */ - -/* - * AIX 4.3 and newer needs _THREAD_SAFE defined to build - * proper reentrant code. Others may also need it. - */ - -#ifdef NEED_THREAD_SAFE -# ifndef _THREAD_SAFE -# define _THREAD_SAFE -# endif -#endif - -/* - * Tru64 needs _REENTRANT set for a few function prototypes and - * things to appear in the system header files. Unixware needs it - * to build proper reentrant code. Others may also need it. - */ - -#ifdef NEED_REENTRANT -# ifndef _REENTRANT -# define _REENTRANT -# endif -#endif - -/* ================================================================ */ -/* If you need to include a system header file for your platform, */ -/* please, do it beyond the point further indicated in this file. */ -/* ================================================================ */ - /* * c-ares external interface definitions are also used internally, * and might also include required system header files to define them. */ -#include <ares_build.h> - -/* - * Compile time sanity checks must also be done when building the library. - */ - -#include <ares_rules.h> +#include "ares_build.h" /* ================================================================= */ /* No system header file shall be included in this file before this */ @@ -115,6 +70,10 @@ * neither HAVE_WS2TCPIP_H when __CYGWIN__ is defined. */ +#ifdef USE_WINSOCK +# undef USE_WINSOCK +#endif + #ifdef HAVE_WINDOWS_H # ifndef WIN32_LEAN_AND_MEAN # define WIN32_LEAN_AND_MEAN @@ -122,52 +81,56 @@ # include <windows.h> # ifdef HAVE_WINSOCK2_H # include <winsock2.h> +# define USE_WINSOCK 2 # ifdef HAVE_WS2TCPIP_H # include <ws2tcpip.h> # endif # else # ifdef HAVE_WINSOCK_H # include <winsock.h> +# define USE_WINSOCK 1 # endif # endif #endif -/* - * Define USE_WINSOCK to 2 if we have and use WINSOCK2 API, else - * define USE_WINSOCK to 1 if we have and use WINSOCK API, else - * undefine USE_WINSOCK. - */ -#ifdef USE_WINSOCK -# undef USE_WINSOCK +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> +#include <ctype.h> + +#ifdef HAVE_ERRNO_H +# include <errno.h> #endif -#ifdef HAVE_WINSOCK2_H -# define USE_WINSOCK 2 -#else -# ifdef HAVE_WINSOCK_H -# define USE_WINSOCK 1 -# endif + +#ifdef HAVE_SYS_TYPES_H +# include <sys/types.h> #endif -/* - * Work-arounds for systems without configure support - */ +#ifdef HAVE_MALLOC_H +# include <malloc.h> +#endif -#ifndef HAVE_CONFIG_H +#ifdef HAVE_SYS_STAT_H +# include <sys/stat.h> +#endif -# if !defined(HAVE_SYS_TIME_H) && !defined(_MSC_VER) && !defined(__WATCOMC__) -# define HAVE_SYS_TIME_H -# endif +#ifdef HAVE_SYS_TIME_H +# include <sys/time.h> +#endif -# if !defined(HAVE_UNISTD_H) && !defined(_MSC_VER) -# define HAVE_UNISTD_H 1 -# endif +#ifdef HAVE_TIME_H +# include <time.h> +#endif -# if !defined(HAVE_SYS_UIO_H) && !defined(WIN32) && !defined(MSDOS) -# define HAVE_SYS_UIO_H -# endif +#ifdef HAVE_UNISTD_H +# include <unistd.h> +#endif -#endif /* HAVE_CONFIG_H */ +#ifdef HAVE_SYS_SOCKET_H +# include <sys/socket.h> +#endif /* * Arg 2 type for gethostname in case it hasn't been defined in config file. @@ -235,12 +198,170 @@ # endif #endif + +#ifdef __hpux +# if !defined(_XOPEN_SOURCE_EXTENDED) || defined(_KERNEL) +# ifdef _APP32_64BIT_OFF_T +# define OLD_APP32_64BIT_OFF_T _APP32_64BIT_OFF_T +# undef _APP32_64BIT_OFF_T +# else +# undef OLD_APP32_64BIT_OFF_T +# endif +# endif +#endif + +#ifdef __hpux +# if !defined(_XOPEN_SOURCE_EXTENDED) || defined(_KERNEL) +# ifdef OLD_APP32_64BIT_OFF_T +# define _APP32_64BIT_OFF_T OLD_APP32_64BIT_OFF_T +# undef OLD_APP32_64BIT_OFF_T +# endif +# endif +#endif + + +/* + * Definition of timeval struct for platforms that don't have it. + */ + +#ifndef HAVE_STRUCT_TIMEVAL +struct timeval { + long tv_sec; + long tv_usec; +}; +#endif + +/* + * Function-like macro definition used to close a socket. + */ + +#if defined(HAVE_CLOSESOCKET) +# define sclose(x) closesocket((x)) +#elif defined(HAVE_CLOSESOCKET_CAMEL) +# define sclose(x) CloseSocket((x)) +#elif defined(HAVE_CLOSE_S) +# define sclose(x) close_s((x)) +#else +# define sclose(x) close((x)) +#endif + /* - * Include macros and defines that should only be processed once. + * Macro used to include code only in debug builds. */ -#ifndef __SETUP_ONCE_H -# include "setup_once.h" +#ifdef DEBUGBUILD +# define DEBUGF(x) x +#else +# define DEBUGF(x) \ + do { \ + } while (0) +#endif + +/* + * Macro SOCKERRNO / SET_SOCKERRNO() returns / sets the *socket-related* errno + * (or equivalent) on this platform to hide platform details to code using it. + */ + +#ifdef USE_WINSOCK +# define SOCKERRNO ((int)WSAGetLastError()) +# define SET_SOCKERRNO(x) (WSASetLastError((int)(x))) +#else +# define SOCKERRNO (errno) +# define SET_SOCKERRNO(x) (errno = (x)) +#endif + + +/* + * Macro ERRNO / SET_ERRNO() returns / sets the NOT *socket-related* errno + * (or equivalent) on this platform to hide platform details to code using it. + */ + +#if defined(WIN32) && !defined(WATT32) +# define ERRNO ((int)GetLastError()) +# define SET_ERRNO(x) (SetLastError((DWORD)(x))) +#else +# define ERRNO (errno) +# define SET_ERRNO(x) (errno = (x)) +#endif + + +/* + * Portable error number symbolic names defined to Winsock error codes. + */ + +#ifdef USE_WINSOCK +# undef EBADF /* override definition in errno.h */ +# define EBADF WSAEBADF +# undef EINTR /* override definition in errno.h */ +# define EINTR WSAEINTR +# undef EINVAL /* override definition in errno.h */ +# define EINVAL WSAEINVAL +# undef EWOULDBLOCK /* override definition in errno.h */ +# define EWOULDBLOCK WSAEWOULDBLOCK +# undef EINPROGRESS /* override definition in errno.h */ +# define EINPROGRESS WSAEINPROGRESS +# undef EALREADY /* override definition in errno.h */ +# define EALREADY WSAEALREADY +# undef ENOTSOCK /* override definition in errno.h */ +# define ENOTSOCK WSAENOTSOCK +# undef EDESTADDRREQ /* override definition in errno.h */ +# define EDESTADDRREQ WSAEDESTADDRREQ +# undef EMSGSIZE /* override definition in errno.h */ +# define EMSGSIZE WSAEMSGSIZE +# undef EPROTOTYPE /* override definition in errno.h */ +# define EPROTOTYPE WSAEPROTOTYPE +# undef ENOPROTOOPT /* override definition in errno.h */ +# define ENOPROTOOPT WSAENOPROTOOPT +# undef EPROTONOSUPPORT /* override definition in errno.h */ +# define EPROTONOSUPPORT WSAEPROTONOSUPPORT +# define ESOCKTNOSUPPORT WSAESOCKTNOSUPPORT +# undef EOPNOTSUPP /* override definition in errno.h */ +# define EOPNOTSUPP WSAEOPNOTSUPP +# define EPFNOSUPPORT WSAEPFNOSUPPORT +# undef EAFNOSUPPORT /* override definition in errno.h */ +# define EAFNOSUPPORT WSAEAFNOSUPPORT +# undef EADDRINUSE /* override definition in errno.h */ +# define EADDRINUSE WSAEADDRINUSE +# undef EADDRNOTAVAIL /* override definition in errno.h */ +# define EADDRNOTAVAIL WSAEADDRNOTAVAIL +# undef ENETDOWN /* override definition in errno.h */ +# define ENETDOWN WSAENETDOWN +# undef ENETUNREACH /* override definition in errno.h */ +# define ENETUNREACH WSAENETUNREACH +# undef ENETRESET /* override definition in errno.h */ +# define ENETRESET WSAENETRESET +# undef ECONNABORTED /* override definition in errno.h */ +# define ECONNABORTED WSAECONNABORTED +# undef ECONNRESET /* override definition in errno.h */ +# define ECONNRESET WSAECONNRESET +# undef ENOBUFS /* override definition in errno.h */ +# define ENOBUFS WSAENOBUFS +# undef EISCONN /* override definition in errno.h */ +# define EISCONN WSAEISCONN +# undef ENOTCONN /* override definition in errno.h */ +# define ENOTCONN WSAENOTCONN +# define ESHUTDOWN WSAESHUTDOWN +# define ETOOMANYREFS WSAETOOMANYREFS +# undef ETIMEDOUT /* override definition in errno.h */ +# define ETIMEDOUT WSAETIMEDOUT +# undef ECONNREFUSED /* override definition in errno.h */ +# define ECONNREFUSED WSAECONNREFUSED +# undef ELOOP /* override definition in errno.h */ +# define ELOOP WSAELOOP +# ifndef ENAMETOOLONG /* possible previous definition in errno.h */ +# define ENAMETOOLONG WSAENAMETOOLONG +# endif +# define EHOSTDOWN WSAEHOSTDOWN +# undef EHOSTUNREACH /* override definition in errno.h */ +# define EHOSTUNREACH WSAEHOSTUNREACH +# ifndef ENOTEMPTY /* possible previous definition in errno.h */ +# define ENOTEMPTY WSAENOTEMPTY +# endif +# define EPROCLIM WSAEPROCLIM +# define EUSERS WSAEUSERS +# define EDQUOT WSAEDQUOT +# define ESTALE WSAESTALE +# define EREMOTE WSAEREMOTE #endif -#endif /* HEADER_CARES_SETUP_H */ +#endif /* __ARES_SETUP_H */ diff --git a/contrib/libs/c-ares/src/lib/ares_strerror.c b/contrib/libs/c-ares/src/lib/ares_strerror.c index ae94f9619e..d9f6411620 100644 --- a/contrib/libs/c-ares/src/lib/ares_strerror.c +++ b/contrib/libs/c-ares/src/lib/ares_strerror.c @@ -25,9 +25,7 @@ * SPDX-License-Identifier: MIT */ -#include "ares_setup.h" -#include <assert.h> -#include "ares.h" +#include "ares_private.h" const char *ares_strerror(int code) { diff --git a/contrib/libs/c-ares/src/lib/ares_sysconfig.c b/contrib/libs/c-ares/src/lib/ares_sysconfig.c index d56ee22e08..2cd3df2823 100644 --- a/contrib/libs/c-ares/src/lib/ares_sysconfig.c +++ b/contrib/libs/c-ares/src/lib/ares_sysconfig.c @@ -25,7 +25,7 @@ * SPDX-License-Identifier: MIT */ -#include "ares_setup.h" +#include "ares_private.h" #ifdef HAVE_SYS_PARAM_H # include <sys/param.h> @@ -43,8 +43,6 @@ # include <arpa/inet.h> #endif -#include "ares_nameser.h" - #if defined(ANDROID) || defined(__ANDROID__) # include <sys/system_properties.h> # include "ares_android.h" @@ -57,586 +55,9 @@ # include <resolv.h> #endif -#if defined(USE_WINSOCK) -# if defined(HAVE_IPHLPAPI_H) -# include <iphlpapi.h> -# endif -# if defined(HAVE_NETIOAPI_H) -# include <netioapi.h> -# endif -#endif - -#include "ares.h" #include "ares_inet_net_pton.h" #include "ares_platform.h" -#include "ares_private.h" - -#ifdef WATT32 -# undef WIN32 /* Redefined in MingW/MSVC headers */ -#endif - - -#ifdef WIN32 -/* - * get_REG_SZ() - * - * Given a 'hKey' handle to an open registry key and a 'leafKeyName' pointer - * to the name of the registry leaf key to be queried, fetch it's string - * value and return a pointer in *outptr to a newly allocated memory area - * holding it as a null-terminated string. - * - * Returns 0 and nullifies *outptr upon inability to return a string value. - * - * Returns 1 and sets *outptr when returning a dynamically allocated string. - * - * Supported on Windows NT 3.5 and newer. - */ -static ares_bool_t get_REG_SZ(HKEY hKey, const char *leafKeyName, char **outptr) -{ - DWORD size = 0; - int res; - - *outptr = NULL; - - /* Find out size of string stored in registry */ - res = RegQueryValueExA(hKey, leafKeyName, 0, NULL, NULL, &size); - if ((res != ERROR_SUCCESS && res != ERROR_MORE_DATA) || !size) { - return ARES_FALSE; - } - - /* Allocate buffer of indicated size plus one given that string - might have been stored without null termination */ - *outptr = ares_malloc(size + 1); - if (!*outptr) { - return ARES_FALSE; - } - - /* Get the value for real */ - res = RegQueryValueExA(hKey, leafKeyName, 0, NULL, (unsigned char *)*outptr, - &size); - if ((res != ERROR_SUCCESS) || (size == 1)) { - ares_free(*outptr); - *outptr = NULL; - return ARES_FALSE; - } - - /* Null terminate buffer always */ - *(*outptr + size) = '\0'; - - return ARES_TRUE; -} - -static void commanjoin(char **dst, const char * const src, const size_t len) -{ - char *newbuf; - size_t newsize; - - /* 1 for terminating 0 and 2 for , and terminating 0 */ - newsize = len + (*dst ? (ares_strlen(*dst) + 2) : 1); - newbuf = ares_realloc(*dst, newsize); - if (!newbuf) { - return; - } - if (*dst == NULL) { - *newbuf = '\0'; - } - *dst = newbuf; - if (ares_strlen(*dst) != 0) { - strcat(*dst, ","); - } - strncat(*dst, src, len); -} - -/* - * commajoin() - * - * RTF code. - */ -static void commajoin(char **dst, const char *src) -{ - commanjoin(dst, src, ares_strlen(src)); -} -/* A structure to hold the string form of IPv4 and IPv6 addresses so we can - * sort them by a metric. - */ -typedef struct { - /* The metric we sort them by. */ - ULONG metric; - - /* Original index of the item, used as a secondary sort parameter to make - * qsort() stable if the metrics are equal */ - size_t orig_idx; - - /* Room enough for the string form of any IPv4 or IPv6 address that - * ares_inet_ntop() will create. Based on the existing c-ares practice. - */ - char text[INET6_ADDRSTRLEN + 8 + 64]; /* [%s]:NNNNN%iface */ -} Address; - -/* Sort Address values \a left and \a right by metric, returning the usual - * indicators for qsort(). - */ -static int compareAddresses(const void *arg1, const void *arg2) -{ - const Address * const left = arg1; - const Address * const right = arg2; - /* Lower metric the more preferred */ - if (left->metric < right->metric) { - return -1; - } - if (left->metric > right->metric) { - return 1; - } - /* If metrics are equal, lower original index more preferred */ - if (left->orig_idx < right->orig_idx) { - return -1; - } - if (left->orig_idx > right->orig_idx) { - return 1; - } - return 0; -} - -/* There can be multiple routes to "the Internet". And there can be different - * DNS servers associated with each of the interfaces that offer those routes. - * We have to assume that any DNS server can serve any request. But, some DNS - * servers may only respond if requested over their associated interface. But - * we also want to use "the preferred route to the Internet" whenever possible - * (and not use DNS servers on a non-preferred route even by forcing request - * to go out on the associated non-preferred interface). i.e. We want to use - * the DNS servers associated with the same interface that we would use to - * make a general request to anything else. - * - * But, Windows won't sort the DNS servers by the metrics associated with the - * routes and interfaces _even_ though it obviously sends IP packets based on - * those same routes and metrics. So, we must do it ourselves. - * - * So, we sort the DNS servers by the same metric values used to determine how - * an outgoing IP packet will go, thus effectively using the DNS servers - * associated with the interface that the DNS requests themselves will - * travel. This gives us optimal routing and avoids issues where DNS servers - * won't respond to requests that don't arrive via some specific subnetwork - * (and thus some specific interface). - * - * This function computes the metric we use to sort. On the interface - * identified by \a luid, it determines the best route to \a dest and combines - * that route's metric with \a interfaceMetric to compute a metric for the - * destination address on that interface. This metric can be used as a weight - * to sort the DNS server addresses associated with each interface (lower is - * better). - * - * Note that by restricting the route search to the specific interface with - * which the DNS servers are associated, this function asks the question "What - * is the metric for sending IP packets to this DNS server?" which allows us - * to sort the DNS servers correctly. - */ -static ULONG getBestRouteMetric(IF_LUID * const luid, /* Can't be const :( */ - const SOCKADDR_INET * const dest, - const ULONG interfaceMetric) -{ - /* On this interface, get the best route to that destination. */ -# if defined(__WATCOMC__) - /* OpenWatcom's builtin Windows SDK does not have a definition for - * MIB_IPFORWARD_ROW2, and also does not allow the usage of SOCKADDR_INET - * as a variable. Let's work around this by returning the worst possible - * metric, but only when using the OpenWatcom compiler. - * It may be worth investigating using a different version of the Windows - * SDK with OpenWatcom in the future, though this may be fixed in OpenWatcom - * 2.0. - */ - return (ULONG)-1; -# else - MIB_IPFORWARD_ROW2 row; - SOCKADDR_INET ignored; - if (GetBestRoute2(/* The interface to use. The index is ignored since we are - * passing a LUID. - */ - luid, 0, - /* No specific source address. */ - NULL, - /* Our destination address. */ - dest, - /* No options. */ - 0, - /* The route row. */ - &row, - /* The best source address, which we don't need. */ - &ignored) != NO_ERROR - /* If the metric is "unused" (-1) or too large for us to add the two - * metrics, use the worst possible, thus sorting this last. - */ - || row.Metric == (ULONG)-1 || - row.Metric > ((ULONG)-1) - interfaceMetric) { - /* Return the worst possible metric. */ - return (ULONG)-1; - } - - /* Return the metric value from that row, plus the interface metric. - * - * See - * http://msdn.microsoft.com/en-us/library/windows/desktop/aa814494(v=vs.85).aspx - * which describes the combination as a "sum". - */ - return row.Metric + interfaceMetric; -# endif /* __WATCOMC__ */ -} - -/* - * get_DNS_Windows() - * - * Locates DNS info using GetAdaptersAddresses() function from the Internet - * Protocol Helper (IP Helper) API. When located, this returns a pointer - * in *outptr to a newly allocated memory area holding a null-terminated - * string with a space or comma separated list of DNS IP addresses. - * - * Returns 0 and nullifies *outptr upon inability to return DNSes string. - * - * Returns 1 and sets *outptr when returning a dynamically allocated string. - * - * Implementation supports Windows XP and newer. - */ -# define IPAA_INITIAL_BUF_SZ 15 * 1024 -# define IPAA_MAX_TRIES 3 - -static ares_bool_t get_DNS_Windows(char **outptr) -{ - IP_ADAPTER_DNS_SERVER_ADDRESS *ipaDNSAddr; - IP_ADAPTER_ADDRESSES *ipaa; - IP_ADAPTER_ADDRESSES *newipaa; - IP_ADAPTER_ADDRESSES *ipaaEntry; - ULONG ReqBufsz = IPAA_INITIAL_BUF_SZ; - ULONG Bufsz = IPAA_INITIAL_BUF_SZ; - ULONG AddrFlags = 0; - int trying = IPAA_MAX_TRIES; - ULONG res; - - /* The capacity of addresses, in elements. */ - size_t addressesSize; - /* The number of elements in addresses. */ - size_t addressesIndex = 0; - /* The addresses we will sort. */ - Address *addresses; - - union { - struct sockaddr *sa; - struct sockaddr_in *sa4; - struct sockaddr_in6 *sa6; - } namesrvr; - - *outptr = NULL; - - ipaa = ares_malloc(Bufsz); - if (!ipaa) { - return ARES_FALSE; - } - - /* Start with enough room for a few DNS server addresses and we'll grow it - * as we encounter more. - */ - addressesSize = 4; - addresses = (Address *)ares_malloc(sizeof(Address) * addressesSize); - if (addresses == NULL) { - /* We need room for at least some addresses to function. */ - ares_free(ipaa); - return ARES_FALSE; - } - - /* Usually this call succeeds with initial buffer size */ - res = GetAdaptersAddresses(AF_UNSPEC, AddrFlags, NULL, ipaa, &ReqBufsz); - if ((res != ERROR_BUFFER_OVERFLOW) && (res != ERROR_SUCCESS)) { - goto done; - } - - while ((res == ERROR_BUFFER_OVERFLOW) && (--trying)) { - if (Bufsz < ReqBufsz) { - newipaa = ares_realloc(ipaa, ReqBufsz); - if (!newipaa) { - goto done; - } - Bufsz = ReqBufsz; - ipaa = newipaa; - } - res = GetAdaptersAddresses(AF_UNSPEC, AddrFlags, NULL, ipaa, &ReqBufsz); - if (res == ERROR_SUCCESS) { - break; - } - } - if (res != ERROR_SUCCESS) { - goto done; - } - - for (ipaaEntry = ipaa; ipaaEntry; ipaaEntry = ipaaEntry->Next) { - if (ipaaEntry->OperStatus != IfOperStatusUp) { - continue; - } - - /* For each interface, find any associated DNS servers as IPv4 or IPv6 - * addresses. For each found address, find the best route to that DNS - * server address _on_ _that_ _interface_ (at this moment in time) and - * compute the resulting total metric, just as Windows routing will do. - * Then, sort all the addresses found by the metric. - */ - for (ipaDNSAddr = ipaaEntry->FirstDnsServerAddress; ipaDNSAddr; - ipaDNSAddr = ipaDNSAddr->Next) { - char ipaddr[INET6_ADDRSTRLEN] = ""; - namesrvr.sa = ipaDNSAddr->Address.lpSockaddr; - - if (namesrvr.sa->sa_family == AF_INET) { - if ((namesrvr.sa4->sin_addr.S_un.S_addr == INADDR_ANY) || - (namesrvr.sa4->sin_addr.S_un.S_addr == INADDR_NONE)) { - continue; - } - - /* Allocate room for another address, if necessary, else skip. */ - if (addressesIndex == addressesSize) { - const size_t newSize = addressesSize + 4; - Address * const newMem = - (Address *)ares_realloc(addresses, sizeof(Address) * newSize); - if (newMem == NULL) { - continue; - } - addresses = newMem; - addressesSize = newSize; - } - - addresses[addressesIndex].metric = getBestRouteMetric( - &ipaaEntry->Luid, (SOCKADDR_INET *)((void *)(namesrvr.sa)), - ipaaEntry->Ipv4Metric); - - /* Record insertion index to make qsort stable */ - addresses[addressesIndex].orig_idx = addressesIndex; - - if (!ares_inet_ntop(AF_INET, &namesrvr.sa4->sin_addr, ipaddr, - sizeof(ipaddr))) { - continue; - } - snprintf(addresses[addressesIndex].text, - sizeof(addresses[addressesIndex].text), "[%s]:%u", ipaddr, - ntohs(namesrvr.sa4->sin_port)); - ++addressesIndex; - } else if (namesrvr.sa->sa_family == AF_INET6) { - unsigned int ll_scope = 0; - struct ares_addr addr; - - if (memcmp(&namesrvr.sa6->sin6_addr, &ares_in6addr_any, - sizeof(namesrvr.sa6->sin6_addr)) == 0) { - continue; - } - - /* Allocate room for another address, if necessary, else skip. */ - if (addressesIndex == addressesSize) { - const size_t newSize = addressesSize + 4; - Address * const newMem = - (Address *)ares_realloc(addresses, sizeof(Address) * newSize); - if (newMem == NULL) { - continue; - } - addresses = newMem; - addressesSize = newSize; - } - - /* See if its link-local */ - memset(&addr, 0, sizeof(addr)); - addr.family = AF_INET6; - memcpy(&addr.addr.addr6, &namesrvr.sa6->sin6_addr, 16); - if (ares__addr_is_linklocal(&addr)) { - ll_scope = ipaaEntry->Ipv6IfIndex; - } - - addresses[addressesIndex].metric = getBestRouteMetric( - &ipaaEntry->Luid, (SOCKADDR_INET *)((void *)(namesrvr.sa)), - ipaaEntry->Ipv6Metric); - - /* Record insertion index to make qsort stable */ - addresses[addressesIndex].orig_idx = addressesIndex; - - if (!ares_inet_ntop(AF_INET6, &namesrvr.sa6->sin6_addr, ipaddr, - sizeof(ipaddr))) { - continue; - } - - if (ll_scope) { - snprintf(addresses[addressesIndex].text, - sizeof(addresses[addressesIndex].text), "[%s]:%u%%%u", - ipaddr, ntohs(namesrvr.sa6->sin6_port), ll_scope); - } else { - snprintf(addresses[addressesIndex].text, - sizeof(addresses[addressesIndex].text), "[%s]:%u", ipaddr, - ntohs(namesrvr.sa6->sin6_port)); - } - ++addressesIndex; - } else { - /* Skip non-IPv4/IPv6 addresses completely. */ - continue; - } - } - } - - /* Sort all of the textual addresses by their metric (and original index if - * metrics are equal). */ - qsort(addresses, addressesIndex, sizeof(*addresses), compareAddresses); - - /* Join them all into a single string, removing duplicates. */ - { - size_t i; - for (i = 0; i < addressesIndex; ++i) { - size_t j; - /* Look for this address text appearing previously in the results. */ - for (j = 0; j < i; ++j) { - if (strcmp(addresses[j].text, addresses[i].text) == 0) { - break; - } - } - /* Iff we didn't emit this address already, emit it now. */ - if (j == i) { - /* Add that to outptr (if we can). */ - commajoin(outptr, addresses[i].text); - } - } - } - -done: - ares_free(addresses); - - if (ipaa) { - ares_free(ipaa); - } - - if (!*outptr) { - return ARES_FALSE; - } - - return ARES_TRUE; -} - -/* - * get_SuffixList_Windows() - * - * Reads the "DNS Suffix Search List" from registry and writes the list items - * whitespace separated to outptr. If the Search List is empty, the - * "Primary Dns Suffix" is written to outptr. - * - * Returns 0 and nullifies *outptr upon inability to return the suffix list. - * - * Returns 1 and sets *outptr when returning a dynamically allocated string. - * - * Implementation supports Windows Server 2003 and newer - */ -static ares_bool_t get_SuffixList_Windows(char **outptr) -{ - HKEY hKey; - HKEY hKeyEnum; - char keyName[256]; - DWORD keyNameBuffSize; - DWORD keyIdx = 0; - char *p = NULL; - - *outptr = NULL; - - if (ares__getplatform() != WIN_NT) { - return ARES_FALSE; - } - - /* 1. Global DNS Suffix Search List */ - if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, WIN_NS_NT_KEY, 0, KEY_READ, &hKey) == - ERROR_SUCCESS) { - get_REG_SZ(hKey, SEARCHLIST_KEY, outptr); - if (get_REG_SZ(hKey, DOMAIN_KEY, &p)) { - commajoin(outptr, p); - ares_free(p); - p = NULL; - } - RegCloseKey(hKey); - } - - if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, WIN_NT_DNSCLIENT, 0, KEY_READ, &hKey) == - ERROR_SUCCESS) { - if (get_REG_SZ(hKey, SEARCHLIST_KEY, &p)) { - commajoin(outptr, p); - ares_free(p); - p = NULL; - } - RegCloseKey(hKey); - } - - /* 2. Connection Specific Search List composed of: - * a. Primary DNS Suffix */ - if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, WIN_DNSCLIENT, 0, KEY_READ, &hKey) == - ERROR_SUCCESS) { - if (get_REG_SZ(hKey, PRIMARYDNSSUFFIX_KEY, &p)) { - commajoin(outptr, p); - ares_free(p); - p = NULL; - } - RegCloseKey(hKey); - } - - /* b. Interface SearchList, Domain, DhcpDomain */ - if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, WIN_NS_NT_KEY "\\" INTERFACES_KEY, 0, - KEY_READ, &hKey) == ERROR_SUCCESS) { - for (;;) { - keyNameBuffSize = sizeof(keyName); - if (RegEnumKeyExA(hKey, keyIdx++, keyName, &keyNameBuffSize, 0, NULL, - NULL, NULL) != ERROR_SUCCESS) { - break; - } - if (RegOpenKeyExA(hKey, keyName, 0, KEY_QUERY_VALUE, &hKeyEnum) != - ERROR_SUCCESS) { - continue; - } - /* p can be comma separated (SearchList) */ - if (get_REG_SZ(hKeyEnum, SEARCHLIST_KEY, &p)) { - commajoin(outptr, p); - ares_free(p); - p = NULL; - } - if (get_REG_SZ(hKeyEnum, DOMAIN_KEY, &p)) { - commajoin(outptr, p); - ares_free(p); - p = NULL; - } - if (get_REG_SZ(hKeyEnum, DHCPDOMAIN_KEY, &p)) { - commajoin(outptr, p); - ares_free(p); - p = NULL; - } - RegCloseKey(hKeyEnum); - } - RegCloseKey(hKey); - } - - return *outptr != NULL ? ARES_TRUE : ARES_FALSE; -} - -static ares_status_t ares__init_sysconfig_windows(ares_sysconfig_t *sysconfig) -{ - char *line = NULL; - ares_status_t status = ARES_SUCCESS; - - if (get_DNS_Windows(&line)) { - status = ares__sconfig_append_fromstr(&sysconfig->sconfig, line, ARES_TRUE); - ares_free(line); - if (status != ARES_SUCCESS) { - goto done; - } - } - - if (get_SuffixList_Windows(&line)) { - sysconfig->domains = ares__strsplit(line, ", ", &sysconfig->ndomains); - ares_free(line); - if (sysconfig->domains == NULL) { - status = ARES_EFILE; - } - if (status != ARES_SUCCESS) { - goto done; - } - } - -done: - return status; -} -#endif #if defined(__MVS__) static ares_status_t ares__init_sysconfig_mvs(ares_sysconfig_t *sysconfig) @@ -1012,7 +433,7 @@ static ares_status_t ares_sysconfig_apply(ares_channel_t *channel, char **temp = ares__strsplit_duplicate(sysconfig->domains, sysconfig->ndomains); if (temp == NULL) { - return ARES_ENOMEM; + return ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ } ares__strsplit_free(channel->domains, channel->ndomains); @@ -1023,7 +444,7 @@ static ares_status_t ares_sysconfig_apply(ares_channel_t *channel, if (sysconfig->lookups && !(channel->optmask & ARES_OPT_LOOKUPS)) { char *temp = ares_strdup(sysconfig->lookups); if (temp == NULL) { - return ARES_ENOMEM; + return ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ } ares_free(channel->lookups); @@ -1034,7 +455,7 @@ static ares_status_t ares_sysconfig_apply(ares_channel_t *channel, struct apattern *temp = ares_malloc(sizeof(*channel->sortlist) * sysconfig->nsortlist); if (temp == NULL) { - return ARES_ENOMEM; + return ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ } memcpy(temp, sysconfig->sortlist, sizeof(*channel->sortlist) * sysconfig->nsortlist); @@ -1044,7 +465,7 @@ static ares_status_t ares_sysconfig_apply(ares_channel_t *channel, channel->nsort = sysconfig->nsortlist; } - if (sysconfig->ndots && !(channel->optmask & ARES_OPT_NDOTS)) { + if (!(channel->optmask & ARES_OPT_NDOTS)) { channel->ndots = sysconfig->ndots; } @@ -1074,7 +495,7 @@ ares_status_t ares__init_by_sysconfig(ares_channel_t *channel) memset(&sysconfig, 0, sizeof(sysconfig)); -#ifdef _WIN32 +#if defined(USE_WINSOCK) status = ares__init_sysconfig_windows(&sysconfig); #elif defined(__MVS__) status = ares__init_sysconfig_mvs(&sysconfig); diff --git a/contrib/libs/c-ares/src/lib/ares_sysconfig_files.c b/contrib/libs/c-ares/src/lib/ares_sysconfig_files.c index 5771a581db..7b8bdbe418 100644 --- a/contrib/libs/c-ares/src/lib/ares_sysconfig_files.c +++ b/contrib/libs/c-ares/src/lib/ares_sysconfig_files.c @@ -25,7 +25,7 @@ * SPDX-License-Identifier: MIT */ -#include "ares_setup.h" +#include "ares_private.h" #ifdef HAVE_SYS_PARAM_H # include <sys/param.h> @@ -43,8 +43,6 @@ # include <arpa/inet.h> #endif -#include "ares_nameser.h" - #if defined(ANDROID) || defined(__ANDROID__) # include <sys/system_properties.h> # include "ares_android.h" @@ -61,10 +59,8 @@ # include <iphlpapi.h> #endif -#include "ares.h" #include "ares_inet_net_pton.h" #include "ares_platform.h" -#include "ares_private.h" static unsigned char ip_natural_mask(const struct ares_addr *addr) { @@ -103,7 +99,7 @@ static ares_bool_t sortlist_append(struct apattern **sortlist, size_t *nsort, newsort = ares_realloc(*sortlist, (*nsort + 1) * sizeof(*newsort)); if (newsort == NULL) { - return ARES_FALSE; + return ARES_FALSE; /* LCOV_EXCL_LINE: OutOfMemory */ } *sortlist = newsort; @@ -223,7 +219,7 @@ ares_status_t ares__parse_sortlist(struct apattern **sortlist, size_t *nsort, ares__llist_node_t *node = NULL; if (sortlist == NULL || nsort == NULL || str == NULL) { - return ARES_EFORMERR; + return ARES_EFORMERR; /* LCOV_EXCL_LINE: DefensiveCoding */ } if (*sortlist != NULL) { @@ -262,8 +258,8 @@ ares_status_t ares__parse_sortlist(struct apattern **sortlist, size_t *nsort, } if (!sortlist_append(sortlist, nsort, &pat)) { - status = ARES_ENOMEM; - goto done; + status = ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ + goto done; /* LCOV_EXCL_LINE: OutOfMemory */ } } @@ -371,7 +367,7 @@ static ares_status_t config_lookup(ares_sysconfig_t *sysconfig, ares_free(sysconfig->lookups); sysconfig->lookups = ares_strdup(lookupstr); if (sysconfig->lookups == NULL) { - return ARES_ENOMEM; + return ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ } } @@ -462,7 +458,7 @@ ares_status_t ares__sysconfig_set_options(ares_sysconfig_t *sysconfig, status = process_option(sysconfig, valbuf); /* Out of memory is the only fatal condition */ if (status == ARES_ENOMEM) { - goto done; + goto done; /* LCOV_EXCL_LINE: OutOfMemory */ } } @@ -484,7 +480,7 @@ ares_status_t ares__init_by_environment(ares_sysconfig_t *sysconfig) if (localdomain) { char *temp = ares_strdup(localdomain); if (temp == NULL) { - return ARES_ENOMEM; + return ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ } status = config_search(sysconfig, temp, 1); ares_free(temp); diff --git a/contrib/libs/c-ares/src/lib/ares_sysconfig_mac.c b/contrib/libs/c-ares/src/lib/ares_sysconfig_mac.c index 302bd0d344..38ac451ca5 100644 --- a/contrib/libs/c-ares/src/lib/ares_sysconfig_mac.c +++ b/contrib/libs/c-ares/src/lib/ares_sysconfig_mac.c @@ -45,16 +45,24 @@ * private header extracted from: * https://opensource.apple.com/source/configd/configd-1109.140.1/dnsinfo/dnsinfo.h */ -# include "ares_setup.h" + +/* The apple header uses anonymous unions which came with C11 */ +# if defined(__clang__) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wc11-extensions" +# endif + +# include "ares_private.h" # include <stdio.h> # include <stdlib.h> # include <string.h> # include <dlfcn.h> # include <arpa/inet.h> # include "thirdparty/apple/dnsinfo.h" -# include <SystemConfiguration/SCNetworkConfiguration.h> -# include "ares.h" -# include "ares_private.h" +# include <AvailabilityMacros.h> +# if MAC_OS_X_VERSION_MIN_REQUIRED >= 1080 /* MacOS 10.8 */ +# include <SystemConfiguration/SCNetworkConfiguration.h> +# endif typedef struct { void *handle; @@ -79,6 +87,13 @@ static ares_status_t dnsinfo_init(dnsinfo_t **dnsinfo_out) { dnsinfo_t *dnsinfo = NULL; ares_status_t status = ARES_SUCCESS; + size_t i; + const char *searchlibs[] = { + "/usr/lib/libSystem.dylib", + "/System/Library/Frameworks/SystemConfiguration.framework/" + "SystemConfiguration", + NULL + }; if (dnsinfo_out == NULL) { status = ARES_EFORMERR; @@ -88,22 +103,34 @@ static ares_status_t dnsinfo_init(dnsinfo_t **dnsinfo_out) *dnsinfo_out = NULL; dnsinfo = ares_malloc_zero(sizeof(*dnsinfo)); - if (dnsinfo == NULL) { status = ARES_ENOMEM; goto done; } - dnsinfo->handle = dlopen("/usr/lib/libSystem.dylib", RTLD_LAZY | RTLD_NOLOAD); - if (dnsinfo->handle == NULL) { - status = ARES_ESERVFAIL; - goto done; + for (i = 0; searchlibs[i] != NULL; i++) { + dnsinfo->handle = dlopen(searchlibs[i], RTLD_LAZY /* | RTLD_NOLOAD */); + if (dnsinfo->handle == NULL) { + /* Fail, loop */ + continue; + } + + dnsinfo->dns_configuration_copy = (dns_config_t * (*)(void)) + dlsym(dnsinfo->handle, "dns_configuration_copy"); + + dnsinfo->dns_configuration_free = (void (*)(dns_config_t *))dlsym( + dnsinfo->handle, "dns_configuration_free"); + + if (dnsinfo->dns_configuration_copy != NULL && + dnsinfo->dns_configuration_free != NULL) { + break; + } + + /* Fail, loop */ + dlclose(dnsinfo->handle); + dnsinfo->handle = NULL; } - dnsinfo->dns_configuration_copy = - dlsym(dnsinfo->handle, "dns_configuration_copy"); - dnsinfo->dns_configuration_free = - dlsym(dnsinfo->handle, "dns_configuration_free"); if (dnsinfo->dns_configuration_copy == NULL || dnsinfo->dns_configuration_free == NULL) { @@ -141,13 +168,19 @@ static ares_status_t read_resolver(const dns_resolver_t *resolver, unsigned short port = 0; ares_status_t status = ARES_SUCCESS; +# if MAC_OS_X_VERSION_MIN_REQUIRED >= 1080 /* MacOS 10.8 */ /* XXX: resolver->domain is for domain-specific servers. When we implement * this support, we'll want to use this. But for now, we're going to - * skip any servers which set this since we can't properly route. */ + * skip any servers which set this since we can't properly route. + * MacOS used to use this setting for a different purpose in the + * past however, so on versions of MacOS < 10.8 just ignore this + * completely. */ if (resolver->domain != NULL) { return ARES_SUCCESS; } +# endif +# if MAC_OS_X_VERSION_MIN_REQUIRED >= 1080 /* MacOS 10.8 */ /* Check to see if DNS server should be used, base this on if the server is * reachable or can be reachable automatically if we send traffic that * direction. */ @@ -156,6 +189,7 @@ static ares_status_t read_resolver(const dns_resolver_t *resolver, kSCNetworkReachabilityFlagsConnectionOnTraffic))) { return ARES_SUCCESS; } +# endif /* NOTE: it doesn't look like resolver->flags is relevant */ @@ -219,7 +253,8 @@ static ares_status_t read_resolver(const dns_resolver_t *resolver, * - resolver->timeout appears unused, always 0, so we ignore this * - resolver->service_identifier doesn't appear relevant to us * - resolver->cid also isn't relevant - * - resolver->if_index we don't need, if_name is used instead. + * - resolver->if_name we won't use since it isn't available in MacOS 10.8 + * or earlier, use resolver->if_index instead to then lookup the name. */ /* XXX: resolver->search_order appears like it might be relevant, we might @@ -233,37 +268,24 @@ static ares_status_t read_resolver(const dns_resolver_t *resolver, struct ares_addr addr; unsigned short addrport; const struct sockaddr *sockaddr; + char if_name_str[256] = ""; + const char *if_name; /* UBSAN alignment workaround to fetch memory address */ memcpy(&sockaddr, resolver->nameserver + i, sizeof(sockaddr)); - if (sockaddr->sa_family == AF_INET) { - /* NOTE: memcpy sockaddr_in due to alignment issues found by UBSAN due to - * dnsinfo packing */ - struct sockaddr_in addr_in; - memcpy(&addr_in, sockaddr, sizeof(addr_in)); - - addr.family = AF_INET; - memcpy(&addr.addr.addr4, &(addr_in.sin_addr), sizeof(addr.addr.addr4)); - addrport = ntohs(addr_in.sin_port); - } else if (sockaddr->sa_family == AF_INET6) { - /* NOTE: memcpy sockaddr_in6 due to alignment issues found by UBSAN due to - * dnsinfo packing */ - struct sockaddr_in6 addr_in6; - memcpy(&addr_in6, sockaddr, sizeof(addr_in6)); - - addr.family = AF_INET6; - memcpy(&addr.addr.addr6, &(addr_in6.sin6_addr), sizeof(addr.addr.addr6)); - addrport = ntohs(addr_in6.sin6_port); - } else { + if (!ares_sockaddr_to_ares_addr(&addr, &addrport, sockaddr)) { continue; } if (addrport == 0) { addrport = port; } - status = ares__sconfig_append(&sysconfig->sconfig, &addr, addrport, - addrport, resolver->if_name); + + if_name = ares__if_indextoname(resolver->if_index, if_name_str, + sizeof(if_name_str)); + status = ares__sconfig_append(&sysconfig->sconfig, &addr, addrport, + addrport, if_name); if (status != ARES_SUCCESS) { return status; } @@ -280,7 +302,6 @@ static ares_status_t read_resolvers(dns_resolver_t **resolvers, int nresolvers, for (i = 0; status == ARES_SUCCESS && i < nresolvers; i++) { const dns_resolver_t *resolver_ptr; - dns_resolver_t resolver; /* UBSAN doesn't like that this is unaligned, lets use memcpy to get the * address. Equivalent to: @@ -288,10 +309,7 @@ static ares_status_t read_resolvers(dns_resolver_t **resolvers, int nresolvers, */ memcpy(&resolver_ptr, resolvers + i, sizeof(resolver_ptr)); - /* UBSAN. If the pointer is misaligned, try to use memcpy to get the data - * into a new structure that is hopefully aligned properly */ - memcpy(&resolver, resolver_ptr, sizeof(resolver)); - status = read_resolver(&resolver, sysconfig); + status = read_resolver(resolver_ptr, sysconfig); } return status; @@ -335,5 +353,13 @@ done: return status; } +# if defined(__clang__) +# pragma GCC diagnostic pop +# endif + +#else + +/* Prevent compiler warnings due to empty translation unit */ +typedef int make_iso_compilers_happy; #endif diff --git a/contrib/libs/c-ares/src/lib/ares_sysconfig_win.c b/contrib/libs/c-ares/src/lib/ares_sysconfig_win.c new file mode 100644 index 0000000000..ce2a261cec --- /dev/null +++ b/contrib/libs/c-ares/src/lib/ares_sysconfig_win.c @@ -0,0 +1,619 @@ +/* MIT License + * + * Copyright (c) 1998 Massachusetts Institute of Technology + * Copyright (c) 2007 Daniel Stenberg + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * SPDX-License-Identifier: MIT + */ + +#include "ares_private.h" + +#ifdef HAVE_SYS_PARAM_H +# include <sys/param.h> +#endif + +#ifdef HAVE_NETINET_IN_H +# include <netinet/in.h> +#endif + +#ifdef HAVE_NETDB_H +# include <netdb.h> +#endif + +#ifdef HAVE_ARPA_INET_H +# include <arpa/inet.h> +#endif + +#if defined(USE_WINSOCK) +# if defined(HAVE_IPHLPAPI_H) +# include <iphlpapi.h> +# endif +# if defined(HAVE_NETIOAPI_H) +# include <netioapi.h> +# endif +#endif + +#include "ares_inet_net_pton.h" +#include "ares_platform.h" + +#if defined(USE_WINSOCK) +/* + * get_REG_SZ() + * + * Given a 'hKey' handle to an open registry key and a 'leafKeyName' pointer + * to the name of the registry leaf key to be queried, fetch it's string + * value and return a pointer in *outptr to a newly allocated memory area + * holding it as a null-terminated string. + * + * Returns 0 and nullifies *outptr upon inability to return a string value. + * + * Returns 1 and sets *outptr when returning a dynamically allocated string. + * + * Supported on Windows NT 3.5 and newer. + */ +static ares_bool_t get_REG_SZ(HKEY hKey, const char *leafKeyName, char **outptr) +{ + DWORD size = 0; + int res; + + *outptr = NULL; + + /* Find out size of string stored in registry */ + res = RegQueryValueExA(hKey, leafKeyName, 0, NULL, NULL, &size); + if ((res != ERROR_SUCCESS && res != ERROR_MORE_DATA) || !size) { + return ARES_FALSE; + } + + /* Allocate buffer of indicated size plus one given that string + might have been stored without null termination */ + *outptr = ares_malloc(size + 1); + if (!*outptr) { + return ARES_FALSE; + } + + /* Get the value for real */ + res = RegQueryValueExA(hKey, leafKeyName, 0, NULL, (unsigned char *)*outptr, + &size); + if ((res != ERROR_SUCCESS) || (size == 1)) { + ares_free(*outptr); + *outptr = NULL; + return ARES_FALSE; + } + + /* Null terminate buffer always */ + *(*outptr + size) = '\0'; + + return ARES_TRUE; +} + +static void commanjoin(char **dst, const char * const src, const size_t len) +{ + char *newbuf; + size_t newsize; + + /* 1 for terminating 0 and 2 for , and terminating 0 */ + newsize = len + (*dst ? (ares_strlen(*dst) + 2) : 1); + newbuf = ares_realloc(*dst, newsize); + if (!newbuf) { + return; + } + if (*dst == NULL) { + *newbuf = '\0'; + } + *dst = newbuf; + if (ares_strlen(*dst) != 0) { + strcat(*dst, ","); + } + strncat(*dst, src, len); +} + +/* + * commajoin() + * + * RTF code. + */ +static void commajoin(char **dst, const char *src) +{ + commanjoin(dst, src, ares_strlen(src)); +} + +/* A structure to hold the string form of IPv4 and IPv6 addresses so we can + * sort them by a metric. + */ +typedef struct { + /* The metric we sort them by. */ + ULONG metric; + + /* Original index of the item, used as a secondary sort parameter to make + * qsort() stable if the metrics are equal */ + size_t orig_idx; + + /* Room enough for the string form of any IPv4 or IPv6 address that + * ares_inet_ntop() will create. Based on the existing c-ares practice. + */ + char text[INET6_ADDRSTRLEN + 8 + 64]; /* [%s]:NNNNN%iface */ +} Address; + +/* Sort Address values \a left and \a right by metric, returning the usual + * indicators for qsort(). + */ +static int compareAddresses(const void *arg1, const void *arg2) +{ + const Address * const left = arg1; + const Address * const right = arg2; + /* Lower metric the more preferred */ + if (left->metric < right->metric) { + return -1; + } + if (left->metric > right->metric) { + return 1; + } + /* If metrics are equal, lower original index more preferred */ + if (left->orig_idx < right->orig_idx) { + return -1; + } + if (left->orig_idx > right->orig_idx) { + return 1; + } + return 0; +} + +/* There can be multiple routes to "the Internet". And there can be different + * DNS servers associated with each of the interfaces that offer those routes. + * We have to assume that any DNS server can serve any request. But, some DNS + * servers may only respond if requested over their associated interface. But + * we also want to use "the preferred route to the Internet" whenever possible + * (and not use DNS servers on a non-preferred route even by forcing request + * to go out on the associated non-preferred interface). i.e. We want to use + * the DNS servers associated with the same interface that we would use to + * make a general request to anything else. + * + * But, Windows won't sort the DNS servers by the metrics associated with the + * routes and interfaces _even_ though it obviously sends IP packets based on + * those same routes and metrics. So, we must do it ourselves. + * + * So, we sort the DNS servers by the same metric values used to determine how + * an outgoing IP packet will go, thus effectively using the DNS servers + * associated with the interface that the DNS requests themselves will + * travel. This gives us optimal routing and avoids issues where DNS servers + * won't respond to requests that don't arrive via some specific subnetwork + * (and thus some specific interface). + * + * This function computes the metric we use to sort. On the interface + * identified by \a luid, it determines the best route to \a dest and combines + * that route's metric with \a interfaceMetric to compute a metric for the + * destination address on that interface. This metric can be used as a weight + * to sort the DNS server addresses associated with each interface (lower is + * better). + * + * Note that by restricting the route search to the specific interface with + * which the DNS servers are associated, this function asks the question "What + * is the metric for sending IP packets to this DNS server?" which allows us + * to sort the DNS servers correctly. + */ +static ULONG getBestRouteMetric(IF_LUID * const luid, /* Can't be const :( */ + const SOCKADDR_INET * const dest, + const ULONG interfaceMetric) +{ + /* On this interface, get the best route to that destination. */ +# if defined(__WATCOMC__) + /* OpenWatcom's builtin Windows SDK does not have a definition for + * MIB_IPFORWARD_ROW2, and also does not allow the usage of SOCKADDR_INET + * as a variable. Let's work around this by returning the worst possible + * metric, but only when using the OpenWatcom compiler. + * It may be worth investigating using a different version of the Windows + * SDK with OpenWatcom in the future, though this may be fixed in OpenWatcom + * 2.0. + */ + return (ULONG)-1; +# else + MIB_IPFORWARD_ROW2 row; + SOCKADDR_INET ignored; + if (GetBestRoute2(/* The interface to use. The index is ignored since we are + * passing a LUID. + */ + luid, 0, + /* No specific source address. */ + NULL, + /* Our destination address. */ + dest, + /* No options. */ + 0, + /* The route row. */ + &row, + /* The best source address, which we don't need. */ + &ignored) != NO_ERROR + /* If the metric is "unused" (-1) or too large for us to add the two + * metrics, use the worst possible, thus sorting this last. + */ + || row.Metric == (ULONG)-1 || + row.Metric > ((ULONG)-1) - interfaceMetric) { + /* Return the worst possible metric. */ + return (ULONG)-1; + } + + /* Return the metric value from that row, plus the interface metric. + * + * See + * http://msdn.microsoft.com/en-us/library/windows/desktop/aa814494(v=vs.85).aspx + * which describes the combination as a "sum". + */ + return row.Metric + interfaceMetric; +# endif /* __WATCOMC__ */ +} + +/* + * get_DNS_Windows() + * + * Locates DNS info using GetAdaptersAddresses() function from the Internet + * Protocol Helper (IP Helper) API. When located, this returns a pointer + * in *outptr to a newly allocated memory area holding a null-terminated + * string with a space or comma separated list of DNS IP addresses. + * + * Returns 0 and nullifies *outptr upon inability to return DNSes string. + * + * Returns 1 and sets *outptr when returning a dynamically allocated string. + * + * Implementation supports Windows XP and newer. + */ +# define IPAA_INITIAL_BUF_SZ 15 * 1024 +# define IPAA_MAX_TRIES 3 + +static ares_bool_t get_DNS_Windows(char **outptr) +{ + IP_ADAPTER_DNS_SERVER_ADDRESS *ipaDNSAddr; + IP_ADAPTER_ADDRESSES *ipaa; + IP_ADAPTER_ADDRESSES *newipaa; + IP_ADAPTER_ADDRESSES *ipaaEntry; + ULONG ReqBufsz = IPAA_INITIAL_BUF_SZ; + ULONG Bufsz = IPAA_INITIAL_BUF_SZ; + ULONG AddrFlags = 0; + int trying = IPAA_MAX_TRIES; + ULONG res; + + /* The capacity of addresses, in elements. */ + size_t addressesSize; + /* The number of elements in addresses. */ + size_t addressesIndex = 0; + /* The addresses we will sort. */ + Address *addresses; + + union { + struct sockaddr *sa; + struct sockaddr_in *sa4; + struct sockaddr_in6 *sa6; + } namesrvr; + + *outptr = NULL; + + ipaa = ares_malloc(Bufsz); + if (!ipaa) { + return ARES_FALSE; + } + + /* Start with enough room for a few DNS server addresses and we'll grow it + * as we encounter more. + */ + addressesSize = 4; + addresses = (Address *)ares_malloc(sizeof(Address) * addressesSize); + if (addresses == NULL) { + /* We need room for at least some addresses to function. */ + ares_free(ipaa); + return ARES_FALSE; + } + + /* Usually this call succeeds with initial buffer size */ + res = GetAdaptersAddresses(AF_UNSPEC, AddrFlags, NULL, ipaa, &ReqBufsz); + if ((res != ERROR_BUFFER_OVERFLOW) && (res != ERROR_SUCCESS)) { + goto done; + } + + while ((res == ERROR_BUFFER_OVERFLOW) && (--trying)) { + if (Bufsz < ReqBufsz) { + newipaa = ares_realloc(ipaa, ReqBufsz); + if (!newipaa) { + goto done; + } + Bufsz = ReqBufsz; + ipaa = newipaa; + } + res = GetAdaptersAddresses(AF_UNSPEC, AddrFlags, NULL, ipaa, &ReqBufsz); + if (res == ERROR_SUCCESS) { + break; + } + } + if (res != ERROR_SUCCESS) { + goto done; + } + + for (ipaaEntry = ipaa; ipaaEntry; ipaaEntry = ipaaEntry->Next) { + if (ipaaEntry->OperStatus != IfOperStatusUp) { + continue; + } + + /* For each interface, find any associated DNS servers as IPv4 or IPv6 + * addresses. For each found address, find the best route to that DNS + * server address _on_ _that_ _interface_ (at this moment in time) and + * compute the resulting total metric, just as Windows routing will do. + * Then, sort all the addresses found by the metric. + */ + for (ipaDNSAddr = ipaaEntry->FirstDnsServerAddress; ipaDNSAddr != NULL; + ipaDNSAddr = ipaDNSAddr->Next) { + char ipaddr[INET6_ADDRSTRLEN] = ""; + + namesrvr.sa = ipaDNSAddr->Address.lpSockaddr; + + if (namesrvr.sa->sa_family == AF_INET) { + if ((namesrvr.sa4->sin_addr.S_un.S_addr == INADDR_ANY) || + (namesrvr.sa4->sin_addr.S_un.S_addr == INADDR_NONE)) { + continue; + } + + /* Allocate room for another address, if necessary, else skip. */ + if (addressesIndex == addressesSize) { + const size_t newSize = addressesSize + 4; + Address * const newMem = + (Address *)ares_realloc(addresses, sizeof(Address) * newSize); + if (newMem == NULL) { + continue; + } + addresses = newMem; + addressesSize = newSize; + } + + addresses[addressesIndex].metric = getBestRouteMetric( + &ipaaEntry->Luid, (SOCKADDR_INET *)((void *)(namesrvr.sa)), + ipaaEntry->Ipv4Metric); + + /* Record insertion index to make qsort stable */ + addresses[addressesIndex].orig_idx = addressesIndex; + + if (!ares_inet_ntop(AF_INET, &namesrvr.sa4->sin_addr, ipaddr, + sizeof(ipaddr))) { + continue; + } + snprintf(addresses[addressesIndex].text, + sizeof(addresses[addressesIndex].text), "[%s]:%u", ipaddr, + ntohs(namesrvr.sa4->sin_port)); + ++addressesIndex; + } else if (namesrvr.sa->sa_family == AF_INET6) { + unsigned int ll_scope = 0; + struct ares_addr addr; + + if (memcmp(&namesrvr.sa6->sin6_addr, &ares_in6addr_any, + sizeof(namesrvr.sa6->sin6_addr)) == 0) { + continue; + } + + /* Allocate room for another address, if necessary, else skip. */ + if (addressesIndex == addressesSize) { + const size_t newSize = addressesSize + 4; + Address * const newMem = + (Address *)ares_realloc(addresses, sizeof(Address) * newSize); + if (newMem == NULL) { + continue; + } + addresses = newMem; + addressesSize = newSize; + } + + /* See if its link-local */ + memset(&addr, 0, sizeof(addr)); + addr.family = AF_INET6; + memcpy(&addr.addr.addr6, &namesrvr.sa6->sin6_addr, 16); + if (ares__addr_is_linklocal(&addr)) { + ll_scope = ipaaEntry->Ipv6IfIndex; + } + + addresses[addressesIndex].metric = getBestRouteMetric( + &ipaaEntry->Luid, (SOCKADDR_INET *)((void *)(namesrvr.sa)), + ipaaEntry->Ipv6Metric); + + /* Record insertion index to make qsort stable */ + addresses[addressesIndex].orig_idx = addressesIndex; + + if (!ares_inet_ntop(AF_INET6, &namesrvr.sa6->sin6_addr, ipaddr, + sizeof(ipaddr))) { + continue; + } + + if (ll_scope) { + snprintf(addresses[addressesIndex].text, + sizeof(addresses[addressesIndex].text), "[%s]:%u%%%u", + ipaddr, ntohs(namesrvr.sa6->sin6_port), ll_scope); + } else { + snprintf(addresses[addressesIndex].text, + sizeof(addresses[addressesIndex].text), "[%s]:%u", ipaddr, + ntohs(namesrvr.sa6->sin6_port)); + } + ++addressesIndex; + } else { + /* Skip non-IPv4/IPv6 addresses completely. */ + continue; + } + } + } + + /* Sort all of the textual addresses by their metric (and original index if + * metrics are equal). */ + qsort(addresses, addressesIndex, sizeof(*addresses), compareAddresses); + + /* Join them all into a single string, removing duplicates. */ + { + size_t i; + for (i = 0; i < addressesIndex; ++i) { + size_t j; + /* Look for this address text appearing previously in the results. */ + for (j = 0; j < i; ++j) { + if (strcmp(addresses[j].text, addresses[i].text) == 0) { + break; + } + } + /* Iff we didn't emit this address already, emit it now. */ + if (j == i) { + /* Add that to outptr (if we can). */ + commajoin(outptr, addresses[i].text); + } + } + } + +done: + ares_free(addresses); + + if (ipaa) { + ares_free(ipaa); + } + + if (!*outptr) { + return ARES_FALSE; + } + + return ARES_TRUE; +} + +/* + * get_SuffixList_Windows() + * + * Reads the "DNS Suffix Search List" from registry and writes the list items + * whitespace separated to outptr. If the Search List is empty, the + * "Primary Dns Suffix" is written to outptr. + * + * Returns 0 and nullifies *outptr upon inability to return the suffix list. + * + * Returns 1 and sets *outptr when returning a dynamically allocated string. + * + * Implementation supports Windows Server 2003 and newer + */ +static ares_bool_t get_SuffixList_Windows(char **outptr) +{ + HKEY hKey; + HKEY hKeyEnum; + char keyName[256]; + DWORD keyNameBuffSize; + DWORD keyIdx = 0; + char *p = NULL; + + *outptr = NULL; + + if (ares__getplatform() != WIN_NT) { + return ARES_FALSE; + } + + /* 1. Global DNS Suffix Search List */ + if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, WIN_NS_NT_KEY, 0, KEY_READ, &hKey) == + ERROR_SUCCESS) { + get_REG_SZ(hKey, SEARCHLIST_KEY, outptr); + if (get_REG_SZ(hKey, DOMAIN_KEY, &p)) { + commajoin(outptr, p); + ares_free(p); + p = NULL; + } + RegCloseKey(hKey); + } + + if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, WIN_NT_DNSCLIENT, 0, KEY_READ, &hKey) == + ERROR_SUCCESS) { + if (get_REG_SZ(hKey, SEARCHLIST_KEY, &p)) { + commajoin(outptr, p); + ares_free(p); + p = NULL; + } + RegCloseKey(hKey); + } + + /* 2. Connection Specific Search List composed of: + * a. Primary DNS Suffix */ + if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, WIN_DNSCLIENT, 0, KEY_READ, &hKey) == + ERROR_SUCCESS) { + if (get_REG_SZ(hKey, PRIMARYDNSSUFFIX_KEY, &p)) { + commajoin(outptr, p); + ares_free(p); + p = NULL; + } + RegCloseKey(hKey); + } + + /* b. Interface SearchList, Domain, DhcpDomain */ + if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, WIN_NS_NT_KEY "\\" INTERFACES_KEY, 0, + KEY_READ, &hKey) == ERROR_SUCCESS) { + for (;;) { + keyNameBuffSize = sizeof(keyName); + if (RegEnumKeyExA(hKey, keyIdx++, keyName, &keyNameBuffSize, 0, NULL, + NULL, NULL) != ERROR_SUCCESS) { + break; + } + if (RegOpenKeyExA(hKey, keyName, 0, KEY_QUERY_VALUE, &hKeyEnum) != + ERROR_SUCCESS) { + continue; + } + /* p can be comma separated (SearchList) */ + if (get_REG_SZ(hKeyEnum, SEARCHLIST_KEY, &p)) { + commajoin(outptr, p); + ares_free(p); + p = NULL; + } + if (get_REG_SZ(hKeyEnum, DOMAIN_KEY, &p)) { + commajoin(outptr, p); + ares_free(p); + p = NULL; + } + if (get_REG_SZ(hKeyEnum, DHCPDOMAIN_KEY, &p)) { + commajoin(outptr, p); + ares_free(p); + p = NULL; + } + RegCloseKey(hKeyEnum); + } + RegCloseKey(hKey); + } + + return *outptr != NULL ? ARES_TRUE : ARES_FALSE; +} + +ares_status_t ares__init_sysconfig_windows(ares_sysconfig_t *sysconfig) +{ + char *line = NULL; + ares_status_t status = ARES_SUCCESS; + + if (get_DNS_Windows(&line)) { + status = ares__sconfig_append_fromstr(&sysconfig->sconfig, line, ARES_TRUE); + ares_free(line); + if (status != ARES_SUCCESS) { + goto done; + } + } + + if (get_SuffixList_Windows(&line)) { + sysconfig->domains = ares__strsplit(line, ", ", &sysconfig->ndomains); + ares_free(line); + if (sysconfig->domains == NULL) { + status = ARES_EFILE; + } + if (status != ARES_SUCCESS) { + goto done; + } + } + +done: + return status; +} +#endif diff --git a/contrib/libs/c-ares/src/lib/ares_timeout.c b/contrib/libs/c-ares/src/lib/ares_timeout.c index 3acc66a87f..5ed8b553a3 100644 --- a/contrib/libs/c-ares/src/lib/ares_timeout.c +++ b/contrib/libs/c-ares/src/lib/ares_timeout.c @@ -25,14 +25,12 @@ * SPDX-License-Identifier: MIT */ -#include "ares_setup.h" +#include "ares_private.h" #ifdef HAVE_LIMITS_H # include <limits.h> #endif -#include "ares.h" -#include "ares_private.h" void ares__timeval_remaining(ares_timeval_t *remaining, const ares_timeval_t *now, @@ -55,30 +53,42 @@ void ares__timeval_remaining(ares_timeval_t *remaining, } } -static struct timeval ares_timeval_to_struct_timeval(const ares_timeval_t *atv) +void ares__timeval_diff(ares_timeval_t *tvdiff, const ares_timeval_t *tvstart, + const ares_timeval_t *tvstop) { - struct timeval tv; - - tv.tv_sec = (time_t)atv->sec; - tv.tv_usec = (int)atv->usec; - - return tv; + tvdiff->sec = tvstop->sec - tvstart->sec; + if (tvstop->usec > tvstart->usec) { + tvdiff->usec = tvstop->usec - tvstart->usec; + } else { + tvdiff->sec -= 1; + tvdiff->usec = tvstop->usec + 1000000 - tvstart->usec; + } } -static ares_timeval_t struct_timeval_to_ares_timeval(const struct timeval *tv) +static void ares_timeval_to_struct_timeval(struct timeval *tv, + const ares_timeval_t *atv) { - ares_timeval_t atv; +#ifdef USE_WINSOCK + tv->tv_sec = (long)atv->sec; +#else + tv->tv_sec = (time_t)atv->sec; +#endif - atv.sec = (ares_int64_t)tv->tv_sec; - atv.usec = (unsigned int)tv->tv_usec; + tv->tv_usec = (int)atv->usec; +} - return atv; +static void struct_timeval_to_ares_timeval(ares_timeval_t *atv, + const struct timeval *tv) +{ + atv->sec = (ares_int64_t)tv->tv_sec; + atv->usec = (unsigned int)tv->tv_usec; } -struct timeval *ares_timeout(const ares_channel_t *channel, - struct timeval *maxtv, struct timeval *tvbuf) +static struct timeval *ares_timeout_int(const ares_channel_t *channel, + struct timeval *maxtv, + struct timeval *tvbuf) { - const struct query *query; + const ares_query_t *query; ares__slist_node_t *node; ares_timeval_t now; ares_timeval_t atvbuf; @@ -94,18 +104,18 @@ struct timeval *ares_timeout(const ares_channel_t *channel, query = ares__slist_node_val(node); - now = ares__tvnow(); + ares__tvnow(&now); ares__timeval_remaining(&atvbuf, &now, &query->timeout); - *tvbuf = ares_timeval_to_struct_timeval(&atvbuf); + ares_timeval_to_struct_timeval(tvbuf, &atvbuf); if (maxtv == NULL) { return tvbuf; } /* Return the minimum time between maxtv and tvbuf */ - amaxtv = struct_timeval_to_ares_timeval(maxtv); + struct_timeval_to_ares_timeval(&amaxtv, maxtv); if (atvbuf.sec > amaxtv.sec) { return maxtv; @@ -121,3 +131,21 @@ struct timeval *ares_timeout(const ares_channel_t *channel, return tvbuf; } + +struct timeval *ares_timeout(const ares_channel_t *channel, + struct timeval *maxtv, struct timeval *tvbuf) +{ + struct timeval *rv; + + if (channel == NULL || tvbuf == NULL) { + return NULL; + } + + ares__channel_lock(channel); + + rv = ares_timeout_int(channel, maxtv, tvbuf); + + ares__channel_unlock(channel); + + return rv; +} diff --git a/contrib/libs/c-ares/src/lib/ares_update_servers.c b/contrib/libs/c-ares/src/lib/ares_update_servers.c index 8075b1d1c0..639f79d815 100644 --- a/contrib/libs/c-ares/src/lib/ares_update_servers.c +++ b/contrib/libs/c-ares/src/lib/ares_update_servers.c @@ -25,7 +25,7 @@ * * SPDX-License-Identifier: MIT */ -#include "ares_setup.h" +#include "ares_private.h" #ifdef HAVE_ARPA_INET_H # include <arpa/inet.h> @@ -49,10 +49,8 @@ # endif #endif -#include "ares.h" #include "ares_data.h" #include "ares_inet_net_pton.h" -#include "ares_private.h" typedef struct { struct ares_addr addr; @@ -67,11 +65,11 @@ static ares_bool_t ares__addr_match(const struct ares_addr *addr1, const struct ares_addr *addr2) { if (addr1 == NULL && addr2 == NULL) { - return ARES_TRUE; + return ARES_TRUE; /* LCOV_EXCL_LINE: DefensiveCoding */ } if (addr1 == NULL || addr2 == NULL) { - return ARES_FALSE; + return ARES_FALSE; /* LCOV_EXCL_LINE: DefensiveCoding */ } if (addr1->family != addr2->family) { @@ -102,7 +100,7 @@ ares_bool_t ares__subnet_match(const struct ares_addr *addr, size_t i; if (addr == NULL || subnet == NULL) { - return ARES_FALSE; + return ARES_FALSE; /* LCOV_EXCL_LINE: DefensiveCoding */ } if (addr->family != subnet->family) { @@ -115,7 +113,7 @@ ares_bool_t ares__subnet_match(const struct ares_addr *addr, len = 4; if (netmask > 32) { - return ARES_FALSE; + return ARES_FALSE; /* LCOV_EXCL_LINE: DefensiveCoding */ } } else if (addr->family == AF_INET6) { addr_ptr = (const unsigned char *)&addr->addr.addr6; @@ -123,10 +121,10 @@ ares_bool_t ares__subnet_match(const struct ares_addr *addr, len = 16; if (netmask > 128) { - return ARES_FALSE; + return ARES_FALSE; /* LCOV_EXCL_LINE: DefensiveCoding */ } } else { - return ARES_FALSE; + return ARES_FALSE; /* LCOV_EXCL_LINE: DefensiveCoding */ } for (i = 0; i < len && netmask > 0; i++) { @@ -380,7 +378,7 @@ ares_status_t ares__sconfig_append(ares__llist_t **sconfig, ares_status_t status; if (sconfig == NULL || addr == NULL) { - return ARES_EFORMERR; + return ARES_EFORMERR; /* LCOV_EXCL_LINE: DefensiveCoding */ } /* Silently skip blacklisted IPv6 servers. */ @@ -390,14 +388,14 @@ ares_status_t ares__sconfig_append(ares__llist_t **sconfig, s = ares_malloc_zero(sizeof(*s)); if (s == NULL) { - return ARES_ENOMEM; + return ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ } if (*sconfig == NULL) { *sconfig = ares__llist_create(ares_free); if (*sconfig == NULL) { - status = ARES_ENOMEM; - goto fail; + status = ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ + goto fail; /* LCOV_EXCL_LINE: OutOfMemory */ } } @@ -422,8 +420,8 @@ ares_status_t ares__sconfig_append(ares__llist_t **sconfig, } if (ares__llist_insert_last(*sconfig, s) == NULL) { - status = ARES_ENOMEM; - goto fail; + status = ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ + goto fail; /* LCOV_EXCL_LINE: OutOfMemory */ } return ARES_SUCCESS; @@ -491,7 +489,7 @@ ares_status_t ares__sconfig_append_fromstr(ares__llist_t **sconfig, status = ares__sconfig_append(sconfig, &s.addr, s.udp_port, s.tcp_port, s.ll_iface); if (status != ARES_SUCCESS) { - goto done; + goto done; /* LCOV_EXCL_LINE: OutOfMemory */ } } @@ -527,7 +525,7 @@ static ares__slist_node_t *ares__server_find(ares_channel_t *channel, for (node = ares__slist_node_first(channel->servers); node != NULL; node = ares__slist_node_next(node)) { - const struct server_state *server = ares__slist_node_val(node); + const ares_server_t *server = ares__slist_node_val(node); if (!ares__addr_match(&server->addr, &s->addr)) { continue; @@ -581,11 +579,11 @@ static ares_status_t ares__server_create(ares_channel_t *channel, const ares_sconfig_t *sconfig, size_t idx) { - ares_status_t status; - struct server_state *server = ares_malloc_zero(sizeof(*server)); + ares_status_t status; + ares_server_t *server = ares_malloc_zero(sizeof(*server)); if (server == NULL) { - return ARES_ENOMEM; + return ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ } server->idx = idx; @@ -612,39 +610,39 @@ static ares_status_t ares__server_create(ares_channel_t *channel, server->tcp_parser = ares__buf_create(); if (server->tcp_parser == NULL) { - status = ARES_ENOMEM; - goto done; + status = ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ + goto done; /* LCOV_EXCL_LINE: OutOfMemory */ } server->tcp_send = ares__buf_create(); if (server->tcp_send == NULL) { - status = ARES_ENOMEM; - goto done; + status = ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ + goto done; /* LCOV_EXCL_LINE: OutOfMemory */ } server->connections = ares__llist_create(NULL); if (server->connections == NULL) { - status = ARES_ENOMEM; - goto done; + status = ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ + goto done; /* LCOV_EXCL_LINE: OutOfMemory */ } if (ares__slist_insert(channel->servers, server) == NULL) { - status = ARES_ENOMEM; - goto done; + status = ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ + goto done; /* LCOV_EXCL_LINE: OutOfMemory */ } status = ARES_SUCCESS; done: if (status != ARES_SUCCESS) { - ares__destroy_server(server); + ares__destroy_server(server); /* LCOV_EXCL_LINE: OutOfMemory */ } return status; } -static ares_bool_t ares__server_in_newconfig(const struct server_state *server, - ares__llist_t *srvlist) +static ares_bool_t ares__server_in_newconfig(const ares_server_t *server, + ares__llist_t *srvlist) { ares__llist_node_t *node; const ares_channel_t *channel = server->channel; @@ -678,8 +676,8 @@ static ares_bool_t ares__servers_remove_stale(ares_channel_t *channel, ares__slist_node_t *snode = ares__slist_node_first(channel->servers); while (snode != NULL) { - ares__slist_node_t *snext = ares__slist_node_next(snode); - const struct server_state *server = ares__slist_node_val(snode); + ares__slist_node_t *snext = ares__slist_node_next(snode); + const ares_server_t *server = ares__slist_node_val(snode); if (!ares__server_in_newconfig(server, srvlist)) { /* This will clean up all server state via the destruction callback and * move any queries to new servers */ @@ -708,11 +706,9 @@ ares_status_t ares__servers_update(ares_channel_t *channel, ares_bool_t list_changed = ARES_FALSE; if (channel == NULL) { - return ARES_EFORMERR; + return ARES_EFORMERR; /* LCOV_EXCL_LINE: DefensiveCoding */ } - ares__channel_lock(channel); - /* NOTE: a NULL or zero entry server list is considered valid due to * real-world people needing support for this for their test harnesses */ @@ -730,7 +726,7 @@ ares_status_t ares__servers_update(ares_channel_t *channel, snode = ares__server_find(channel, sconfig); if (snode != NULL) { - struct server_state *server = ares__slist_node_val(snode); + ares_server_t *server = ares__slist_node_val(snode); /* Copy over link-local settings. Its possible some of this data has * changed, maybe ... */ @@ -781,7 +777,6 @@ ares_status_t ares__servers_update(ares_channel_t *channel, status = ARES_SUCCESS; done: - ares__channel_unlock(channel); return status; } @@ -796,7 +791,7 @@ static ares_status_t s = ares__llist_create(ares_free); if (s == NULL) { - goto fail; + goto fail; /* LCOV_EXCL_LINE: OutOfMemory */ } for (node = servers; node != NULL; node = node->next) { @@ -809,7 +804,7 @@ static ares_status_t sconfig = ares_malloc_zero(sizeof(*sconfig)); if (sconfig == NULL) { - goto fail; + goto fail; /* LCOV_EXCL_LINE: OutOfMemory */ } sconfig->addr.family = node->family; @@ -822,17 +817,19 @@ static ares_status_t } if (ares__llist_insert_last(s, sconfig) == NULL) { - ares_free(sconfig); - goto fail; + ares_free(sconfig); /* LCOV_EXCL_LINE: OutOfMemory */ + goto fail; /* LCOV_EXCL_LINE: OutOfMemory */ } } *llist = s; return ARES_SUCCESS; +/* LCOV_EXCL_START: OutOfMemory */ fail: ares__llist_destroy(s); return ARES_ENOMEM; + /* LCOV_EXCL_STOP */ } static ares_status_t ares_addr_port_node_to_server_config_llist( @@ -845,7 +842,7 @@ static ares_status_t ares_addr_port_node_to_server_config_llist( s = ares__llist_create(ares_free); if (s == NULL) { - goto fail; + goto fail; /* LCOV_EXCL_LINE: OutOfMemory */ } for (node = servers; node != NULL; node = node->next) { @@ -858,7 +855,7 @@ static ares_status_t ares_addr_port_node_to_server_config_llist( sconfig = ares_malloc_zero(sizeof(*sconfig)); if (sconfig == NULL) { - goto fail; + goto fail; /* LCOV_EXCL_LINE: OutOfMemory */ } sconfig->addr.family = node->family; @@ -874,17 +871,19 @@ static ares_status_t ares_addr_port_node_to_server_config_llist( sconfig->udp_port = (unsigned short)node->udp_port; if (ares__llist_insert_last(s, sconfig) == NULL) { - ares_free(sconfig); - goto fail; + ares_free(sconfig); /* LCOV_EXCL_LINE: OutOfMemory */ + goto fail; /* LCOV_EXCL_LINE: OutOfMemory */ } } *llist = s; return ARES_SUCCESS; +/* LCOV_EXCL_START: OutOfMemory */ fail: ares__llist_destroy(s); return ARES_ENOMEM; + /* LCOV_EXCL_STOP */ } ares_status_t ares_in_addr_to_server_config_llist(const struct in_addr *servers, @@ -898,7 +897,7 @@ ares_status_t ares_in_addr_to_server_config_llist(const struct in_addr *servers, s = ares__llist_create(ares_free); if (s == NULL) { - goto fail; + goto fail; /* LCOV_EXCL_LINE: OutOfMemory */ } for (i = 0; servers != NULL && i < nservers; i++) { @@ -906,7 +905,7 @@ ares_status_t ares_in_addr_to_server_config_llist(const struct in_addr *servers, sconfig = ares_malloc_zero(sizeof(*sconfig)); if (sconfig == NULL) { - goto fail; + goto fail; /* LCOV_EXCL_LINE: OutOfMemory */ } sconfig->addr.family = AF_INET; @@ -914,21 +913,23 @@ ares_status_t ares_in_addr_to_server_config_llist(const struct in_addr *servers, sizeof(sconfig->addr.addr.addr4)); if (ares__llist_insert_last(s, sconfig) == NULL) { - goto fail; + goto fail; /* LCOV_EXCL_LINE: OutOfMemory */ } } *llist = s; return ARES_SUCCESS; +/* LCOV_EXCL_START: OutOfMemory */ fail: ares__llist_destroy(s); return ARES_ENOMEM; + /* LCOV_EXCL_STOP */ } /* Write out the details of a server to a buffer */ -ares_status_t ares_get_server_addr(const struct server_state *server, - ares__buf_t *buf) +ares_status_t ares_get_server_addr(const ares_server_t *server, + ares__buf_t *buf) { ares_status_t status; char addr[INET6_ADDRSTRLEN]; @@ -937,7 +938,7 @@ ares_status_t ares_get_server_addr(const struct server_state *server, if (server->addr.family == AF_INET6) { status = ares__buf_append_byte(buf, '['); if (status != ARES_SUCCESS) { - return status; + return status; /* LCOV_EXCL_LINE: OutOfMemory */ } } @@ -945,37 +946,37 @@ ares_status_t ares_get_server_addr(const struct server_state *server, status = ares__buf_append_str(buf, addr); if (status != ARES_SUCCESS) { - return status; + return status; /* LCOV_EXCL_LINE: OutOfMemory */ } if (server->addr.family == AF_INET6) { status = ares__buf_append_byte(buf, ']'); if (status != ARES_SUCCESS) { - return status; + return status; /* LCOV_EXCL_LINE: OutOfMemory */ } } /* :port */ status = ares__buf_append_byte(buf, ':'); if (status != ARES_SUCCESS) { - return status; + return status; /* LCOV_EXCL_LINE: OutOfMemory */ } status = ares__buf_append_num_dec(buf, server->udp_port, 0); if (status != ARES_SUCCESS) { - return status; + return status; /* LCOV_EXCL_LINE: OutOfMemory */ } /* %iface */ if (ares_strlen(server->ll_iface)) { status = ares__buf_append_byte(buf, '%'); if (status != ARES_SUCCESS) { - return status; + return status; /* LCOV_EXCL_LINE: OutOfMemory */ } status = ares__buf_append_str(buf, server->ll_iface); if (status != ARES_SUCCESS) { - return status; + return status; /* LCOV_EXCL_LINE: OutOfMemory */ } } @@ -999,7 +1000,7 @@ int ares_get_servers(const ares_channel_t *channel, for (node = ares__slist_node_first(channel->servers); node != NULL; node = ares__slist_node_next(node)) { - const struct server_state *server = ares__slist_node_val(node); + const ares_server_t *server = ares__slist_node_val(node); /* Allocate storage for this server node appending it to the list */ srvr_curr = ares_malloc_data(ARES_DATATYPE_ADDR_NODE); @@ -1054,7 +1055,7 @@ int ares_get_servers_ports(const ares_channel_t *channel, for (node = ares__slist_node_first(channel->servers); node != NULL; node = ares__slist_node_next(node)) { - const struct server_state *server = ares__slist_node_val(node); + const ares_server_t *server = ares__slist_node_val(node); /* Allocate storage for this server node appending it to the list */ srvr_curr = ares_malloc_data(ARES_DATATYPE_ADDR_PORT_NODE); @@ -1109,8 +1110,9 @@ int ares_set_servers(ares_channel_t *channel, return (int)status; } - /* NOTE: lock is in ares__servers_update() */ + ares__channel_lock(channel); status = ares__servers_update(channel, slist, ARES_TRUE); + ares__channel_unlock(channel); ares__llist_destroy(slist); @@ -1132,8 +1134,9 @@ int ares_set_servers_ports(ares_channel_t *channel, return (int)status; } - /* NOTE: lock is in ares__servers_update() */ + ares__channel_lock(channel); status = ares__servers_update(channel, slist, ARES_TRUE); + ares__channel_unlock(channel); ares__llist_destroy(slist); @@ -1151,11 +1154,12 @@ static ares_status_t set_servers_csv(ares_channel_t *channel, const char *_csv) return ARES_ENODATA; } - /* NOTE: lock is in ares__servers_update() */ - if (ares_strlen(_csv) == 0) { /* blank all servers */ - return ares__servers_update(channel, NULL, ARES_TRUE); + ares__channel_lock(channel); + status = ares__servers_update(channel, NULL, ARES_TRUE); + ares__channel_unlock(channel); + return status; } status = ares__sconfig_append_fromstr(&slist, _csv, ARES_FALSE); @@ -1164,8 +1168,9 @@ static ares_status_t set_servers_csv(ares_channel_t *channel, const char *_csv) return status; } - /* NOTE: lock is in ares__servers_update() */ + ares__channel_lock(channel); status = ares__servers_update(channel, slist, ARES_TRUE); + ares__channel_unlock(channel); ares__llist_destroy(slist); @@ -1175,13 +1180,11 @@ static ares_status_t set_servers_csv(ares_channel_t *channel, const char *_csv) /* We'll go ahead and honor ports anyhow */ int ares_set_servers_csv(ares_channel_t *channel, const char *_csv) { - /* NOTE: lock is in ares__servers_update() */ return (int)set_servers_csv(channel, _csv); } int ares_set_servers_ports_csv(ares_channel_t *channel, const char *_csv) { - /* NOTE: lock is in ares__servers_update() */ return (int)set_servers_csv(channel, _csv); } @@ -1195,24 +1198,24 @@ char *ares_get_servers_csv(const ares_channel_t *channel) buf = ares__buf_create(); if (buf == NULL) { - goto done; + goto done; /* LCOV_EXCL_LINE: OutOfMemory */ } for (node = ares__slist_node_first(channel->servers); node != NULL; node = ares__slist_node_next(node)) { - ares_status_t status; - const struct server_state *server = ares__slist_node_val(node); + ares_status_t status; + const ares_server_t *server = ares__slist_node_val(node); if (ares__buf_len(buf)) { status = ares__buf_append_byte(buf, ','); if (status != ARES_SUCCESS) { - goto done; + goto done; /* LCOV_EXCL_LINE: OutOfMemory */ } } status = ares_get_server_addr(server, buf); if (status != ARES_SUCCESS) { - goto done; + goto done; /* LCOV_EXCL_LINE: OutOfMemory */ } } @@ -1229,7 +1232,7 @@ void ares_set_server_state_callback(ares_channel_t *channel, ares_server_state_callback cb, void *data) { if (channel == NULL) { - return; + return; /* LCOV_EXCL_LINE: DefensiveCoding */ } channel->server_state_cb = cb; channel->server_state_cb_data = data; diff --git a/contrib/libs/c-ares/src/lib/ares_version.c b/contrib/libs/c-ares/src/lib/ares_version.c index ca15fa77dc..f50f65b0d6 100644 --- a/contrib/libs/c-ares/src/lib/ares_version.c +++ b/contrib/libs/c-ares/src/lib/ares_version.c @@ -24,8 +24,7 @@ * * SPDX-License-Identifier: MIT */ -#include "ares_setup.h" -#include "ares.h" +#include "ares_private.h" const char *ares_version(int *version) { diff --git a/contrib/libs/c-ares/src/lib/config-win32.h b/contrib/libs/c-ares/src/lib/config-win32.h index 752e17afe6..003f3937e5 100644 --- a/contrib/libs/c-ares/src/lib/config-win32.h +++ b/contrib/libs/c-ares/src/lib/config-win32.h @@ -88,7 +88,7 @@ #define HAVE_IPHLPAPI_H 1 /* Define if you have <netioapi.h> header file */ -#ifndef __WATCOMC__ +#if !defined(__WATCOMC__) && !defined(WATT32) # define HAVE_NETIOAPI_H 1 #endif @@ -196,11 +196,8 @@ /* Define to the type of arg 1 for send. */ #define SEND_TYPE_ARG1 SOCKET -/* Define to the type qualifier of arg 2 for send. */ -#define SEND_QUAL_ARG2 const - /* Define to the type of arg 2 for send. */ -#define SEND_TYPE_ARG2 char * +#define SEND_TYPE_ARG2 const char * /* Define to the type of arg 3 for send. */ #define SEND_TYPE_ARG3 int @@ -213,21 +210,34 @@ /* Specifics for the Watt-32 tcp/ip stack. */ #ifdef WATT32 -# define SOCKET int +# undef RECV_TYPE_ARG1 +# define RECV_TYPE_ARG1 int +# undef SEND_TYPE_ARG1 +# define SEND_TYPE_ARG1 int +# undef RECVFROM_TYPE_ARG1 +# define RECVFROM_TYPE_ARG1 int # define NS_INADDRSZ 4 # define HAVE_ARPA_NAMESER_H 1 # define HAVE_ARPA_INET_H 1 # define HAVE_NETDB_H 1 # define HAVE_NETINET_IN_H 1 # define HAVE_SYS_SOCKET_H 1 +# define HAVE_SYS_IOCTL_H 1 # define HAVE_NETINET_TCP_H 1 # define HAVE_AF_INET6 1 # define HAVE_PF_INET6 1 # define HAVE_STRUCT_IN6_ADDR 1 # define HAVE_STRUCT_SOCKADDR_IN6 1 +# define HAVE_WRITEV 1 +# define HAVE_IF_NAMETOINDEX 1 +# define HAVE_IF_INDEXTONAME 1 +# define HAVE_GETSERVBYPORT_R 1 +# define GETSERVBYPORT_R_ARGS 6 # undef HAVE_WINSOCK_H # undef HAVE_WINSOCK2_H # undef HAVE_WS2TCPIP_H +# undef HAVE_IPHLPAPI_H +# undef HAVE_NETIOAPI_H #endif /* Threading support enabled */ @@ -348,7 +358,11 @@ # define HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID 1 #endif -#if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0600) && !defined(__WATCOMC__) +/* Define to 1 if you have the `RegisterWaitForSingleObject' function. */ +#define HAVE_REGISTERWAITFORSINGLEOBJECT 1 + +#if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0600) && \ + !defined(__WATCOMC__) && !defined(WATT32) /* Define if you have if_nametoindex() */ # define HAVE_IF_NAMETOINDEX 1 /* Define if you have if_indextoname() */ @@ -357,6 +371,8 @@ # define HAVE_CONVERTINTERFACEINDEXTOLUID 1 /* Define to 1 if you have the `ConvertInterfaceLuidToNameA' function. */ # define HAVE_CONVERTINTERFACELUIDTONAMEA 1 +/* Define to 1 if you have the `NotifyIpInterfaceChange' function. */ +# define HAVE_NOTIFYIPINTERFACECHANGE 1 #endif /* ---------------------------------------------------------------- */ diff --git a/contrib/libs/c-ares/src/lib/dsa/ares__array.c b/contrib/libs/c-ares/src/lib/dsa/ares__array.c new file mode 100644 index 0000000000..0c724248bf --- /dev/null +++ b/contrib/libs/c-ares/src/lib/dsa/ares__array.c @@ -0,0 +1,356 @@ +/* MIT License + * + * Copyright (c) 2024 Brad House + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * SPDX-License-Identifier: MIT + */ +#include "ares_private.h" +#include "ares__array.h" + +#define ARES__ARRAY_MIN 4 + +struct ares__array { + ares__array_destructor_t destruct; + void *arr; + size_t member_size; + size_t cnt; + size_t offset; + size_t alloc_cnt; +}; + +ares__array_t *ares__array_create(size_t member_size, + ares__array_destructor_t destruct) +{ + ares__array_t *arr; + + if (member_size == 0) { + return NULL; + } + + arr = ares_malloc_zero(sizeof(*arr)); + if (arr == NULL) { + return NULL; + } + + arr->member_size = member_size; + arr->destruct = destruct; + return arr; +} + +size_t ares__array_len(const ares__array_t *arr) +{ + if (arr == NULL) { + return 0; + } + return arr->cnt; +} + +void *ares__array_at(ares__array_t *arr, size_t idx) +{ + if (arr == NULL || idx >= arr->cnt) { + return NULL; + } + return (unsigned char *)arr->arr + ((idx + arr->offset) * arr->member_size); +} + +const void *ares__array_at_const(const ares__array_t *arr, size_t idx) +{ + if (arr == NULL || idx >= arr->cnt) { + return NULL; + } + return (unsigned char *)arr->arr + ((idx + arr->offset) * arr->member_size); +} + +ares_status_t ares__array_sort(ares__array_t *arr, ares__array_cmp_t cmp) +{ + if (arr == NULL || cmp == NULL) { + return ARES_EFORMERR; + } + + /* Nothing to sort */ + if (arr->cnt < 2) { + return ARES_SUCCESS; + } + + qsort((unsigned char *)arr->arr + (arr->offset * arr->member_size), arr->cnt, + arr->member_size, cmp); + return ARES_SUCCESS; +} + +void ares__array_destroy(ares__array_t *arr) +{ + size_t i; + + if (arr == NULL) { + return; + } + + if (arr->destruct != NULL) { + for (i = 0; i < arr->cnt; i++) { + arr->destruct(ares__array_at(arr, i)); + } + } + + ares_free(arr->arr); + ares_free(arr); +} + +/* NOTE: this function operates on actual indexes, NOT indexes using the + * arr->offset */ +static ares_status_t ares__array_move(ares__array_t *arr, size_t dest_idx, + size_t src_idx) +{ + void *dest_ptr; + const void *src_ptr; + size_t nmembers; + + if (arr == NULL || dest_idx >= arr->alloc_cnt || src_idx >= arr->alloc_cnt) { + return ARES_EFORMERR; + } + + /* Nothing to do */ + if (dest_idx == src_idx) { + return ARES_SUCCESS; + } + + dest_ptr = (unsigned char *)arr->arr + (dest_idx * arr->member_size); + src_ptr = (unsigned char *)arr->arr + (src_idx * arr->member_size); + + /* Check to make sure shifting to the right won't overflow our allocation + * boundary */ + if (dest_idx > src_idx && arr->cnt + (dest_idx - src_idx) > arr->alloc_cnt) { + return ARES_EFORMERR; + } + if (dest_idx < src_idx) { + nmembers = arr->cnt - dest_idx; + } else { + nmembers = arr->cnt - src_idx; + } + + memmove(dest_ptr, src_ptr, nmembers * arr->member_size); + + return ARES_SUCCESS; +} + +void *ares__array_finish(ares__array_t *arr, size_t *num_members) +{ + void *ptr; + + if (arr == NULL || num_members == NULL) { + return NULL; + } + + /* Make sure we move data to beginning of allocation */ + if (arr->offset != 0) { + if (ares__array_move(arr, 0, arr->offset) != ARES_SUCCESS) { + return NULL; + } + arr->offset = 0; + } + + ptr = arr->arr; + *num_members = arr->cnt; + ares_free(arr); + return ptr; +} + +ares_status_t ares__array_set_size(ares__array_t *arr, size_t size) +{ + void *temp; + + if (arr == NULL || size == 0 || size < arr->cnt) { + return ARES_EFORMERR; + } + + /* Always operate on powers of 2 */ + size = ares__round_up_pow2(size); + + if (size < ARES__ARRAY_MIN) { + size = ARES__ARRAY_MIN; + } + + /* If our allocation size is already large enough, skip */ + if (size <= arr->alloc_cnt) { + return ARES_SUCCESS; + } + + temp = ares_realloc_zero(arr->arr, arr->alloc_cnt * arr->member_size, + size * arr->member_size); + if (temp == NULL) { + return ARES_ENOMEM; + } + arr->alloc_cnt = size; + arr->arr = temp; + return ARES_SUCCESS; +} + +ares_status_t ares__array_insert_at(void **elem_ptr, ares__array_t *arr, + size_t idx) +{ + void *ptr; + ares_status_t status; + + if (arr == NULL) { + return ARES_EFORMERR; + } + + /* Not >= since we are allowed to append to the end */ + if (idx > arr->cnt) { + return ARES_EFORMERR; + } + + /* Allocate more if needed */ + status = ares__array_set_size(arr, arr->cnt + 1); + if (status != ARES_SUCCESS) { + return status; + } + + /* Shift if we have memory but not enough room at the end */ + if (arr->cnt + 1 + arr->offset > arr->alloc_cnt) { + status = ares__array_move(arr, 0, arr->offset); + if (status != ARES_SUCCESS) { + return status; + } + arr->offset = 0; + } + + /* If we're inserting anywhere other than the end, we need to move some + * elements out of the way */ + if (idx != arr->cnt) { + status = ares__array_move(arr, idx + arr->offset + 1, idx + arr->offset); + if (status != ARES_SUCCESS) { + return status; + } + } + + /* Ok, we're guaranteed to have a gap where we need it, lets zero it out, + * and return it */ + ptr = (unsigned char *)arr->arr + ((idx + arr->offset) * arr->member_size); + memset(ptr, 0, arr->member_size); + arr->cnt++; + + if (elem_ptr) { + *elem_ptr = ptr; + } + + return ARES_SUCCESS; +} + +ares_status_t ares__array_insert_last(void **elem_ptr, ares__array_t *arr) +{ + return ares__array_insert_at(elem_ptr, arr, ares__array_len(arr)); +} + +ares_status_t ares__array_insert_first(void **elem_ptr, ares__array_t *arr) +{ + return ares__array_insert_at(elem_ptr, arr, 0); +} + +void *ares__array_first(ares__array_t *arr) +{ + return ares__array_at(arr, 0); +} + +void *ares__array_last(ares__array_t *arr) +{ + size_t cnt = ares__array_len(arr); + if (cnt == 0) { + return NULL; + } + return ares__array_at(arr, cnt - 1); +} + +const void *ares__array_first_const(const ares__array_t *arr) +{ + return ares__array_at_const(arr, 0); +} + +const void *ares__array_last_const(const ares__array_t *arr) +{ + size_t cnt = ares__array_len(arr); + if (cnt == 0) { + return NULL; + } + return ares__array_at_const(arr, cnt - 1); +} + +ares_status_t ares__array_claim_at(void *dest, size_t dest_size, + ares__array_t *arr, size_t idx) +{ + ares_status_t status; + + if (arr == NULL || idx >= arr->cnt) { + return ARES_EFORMERR; + } + + if (dest != NULL && dest_size < arr->member_size) { + return ARES_EFORMERR; + } + + if (dest) { + memcpy(dest, ares__array_at(arr, idx), arr->member_size); + } + + if (idx == 0) { + /* Optimization, if first element, just increment offset, makes removing a + * lot from the start quick */ + arr->offset++; + } else if (idx != arr->cnt - 1) { + /* Must shift entire array if removing an element from the middle. Does + * nothing if removing last element other than decrement count. */ + status = ares__array_move(arr, idx + arr->offset, idx + arr->offset + 1); + if (status != ARES_SUCCESS) { + return status; + } + } + + arr->cnt--; + return ARES_SUCCESS; +} + +ares_status_t ares__array_remove_at(ares__array_t *arr, size_t idx) +{ + void *ptr = ares__array_at(arr, idx); + if (arr == NULL || ptr == NULL) { + return ARES_EFORMERR; + } + + if (arr->destruct != NULL) { + arr->destruct(ptr); + } + + return ares__array_claim_at(NULL, 0, arr, idx); +} + +ares_status_t ares__array_remove_first(ares__array_t *arr) +{ + return ares__array_remove_at(arr, 0); +} + +ares_status_t ares__array_remove_last(ares__array_t *arr) +{ + size_t cnt = ares__array_len(arr); + if (cnt == 0) { + return ARES_EFORMERR; + } + return ares__array_remove_at(arr, cnt - 1); +} diff --git a/contrib/libs/c-ares/src/lib/dsa/ares__array.h b/contrib/libs/c-ares/src/lib/dsa/ares__array.h new file mode 100644 index 0000000000..6fa1c0e15e --- /dev/null +++ b/contrib/libs/c-ares/src/lib/dsa/ares__array.h @@ -0,0 +1,223 @@ +/* MIT License + * + * Copyright (c) 2024 Brad House + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * SPDX-License-Identifier: MIT + */ +#ifndef __ARES__ARRAY_H +#define __ARES__ARRAY_H + +/*! \addtogroup ares__array Array Data Structure + * + * This is an array with helpers. It is meant to have as little overhead + * as possible over direct array management by applications but to provide + * safety and some optimization features. It can also return the array in + * native form once all manipulation has been performed. + * + * @{ + */ + +struct ares__array; + +/*! Opaque data structure for array */ +typedef struct ares__array ares__array_t; + +/*! Callback to free user-defined member data + * + * \param[in] data pointer to member of array to be destroyed. The pointer + * itself must not be destroyed, just the data it contains. + */ +typedef void (*ares__array_destructor_t)(void *data); + +/*! Callback to compare two array elements used for sorting + * + * \param[in] data1 array member 1 + * \param[in] data2 array member 2 + * \return < 0 if data1 < data2, > 0 if data1 > data2, 0 if data1 == data2 + */ +typedef int (*ares__array_cmp_t)(const void *data1, const void *data2); + +/*! Create an array object + * + * NOTE: members of the array are typically going to be an going to be a + * struct with compiler/ABI specific padding to ensure proper alignment. + * Care needs to be taken if using primitive types, especially floating + * point numbers which size may not indicate the required alignment. + * For example, a double may be 80 bits (10 bytes), but required + * alignment of 16 bytes. In such a case, a member_size of 16 would be + * required to be used. + * + * \param[in] destruct Optional. Destructor to call on a removed member + * \param[in] member_size Size of array member, usually determined using + * sizeof() for the member such as a struct. + * + * \return array object or NULL on out of memory + */ +ares__array_t *ares__array_create(size_t member_size, + ares__array_destructor_t destruct); + + +/*! Request the array be at least the requested size. Useful if the desired + * array size is known prior to populating the array to prevent reallocations. + * + * \param[in] arr Initialized array object. + * \param[in] size Minimum number of members + * \return ARES_SUCCESS on success, ARES_EFORMERR on misuse, + * ARES_ENOMEM on out of memory */ +ares_status_t ares__array_set_size(ares__array_t *arr, size_t size); + +/*! Sort the array using the given comparison function. This is not + * persistent, any future elements inserted will not maintain this sort. + * + * \param[in] arr Initialized array object. + * \param[in] cb Sort callback + * \return ARES_SUCCESS on success + */ +ares_status_t ares__array_sort(ares__array_t *arr, ares__array_cmp_t cmp); + +/*! Destroy an array object. If a destructor is set, will be called on each + * member of the array. + * + * \param[in] arr Initialized array object. + */ +void ares__array_destroy(ares__array_t *arr); + +/*! Retrieve the array in the native format. This will also destroy the + * container. It is the responsibility of the caller to free the returned + * pointer and also any data within each array element. + * + * \param[in] arr Initialized array object + * \param[out] num_members the number of members in the returned array + * \return pointer to native array on success, NULL on failure. + */ +void *ares__array_finish(ares__array_t *arr, size_t *num_members); + +/*! Retrieve the number of members in the array + * + * \param[in] arr Initialized array object. + * \return numbrer of members + */ +size_t ares__array_len(const ares__array_t *arr); + +/*! Insert a new array member at the given index + * + * \param[out] elem_ptr Optional. Pointer to the returned array element. + * \param[in] arr Initialized array object. + * \param[in] idx Index in array to place new element, will shift any + * elements down that exist after this point. + * \return ARES_SUCCESS on success, ARES_EFORMERR on bad index, + * ARES_ENOMEM on out of memory. + */ +ares_status_t ares__array_insert_at(void **elem_ptr, ares__array_t *arr, + size_t idx); + +/*! Insert a new array member at the end of the array + * + * \param[out] elem_ptr Optional. Pointer to the returned array element. + * \param[in] arr Initialized array object. + * \return ARES_SUCCESS on success, ARES_ENOMEM on out of memory. + */ +ares_status_t ares__array_insert_last(void **elem_ptr, ares__array_t *arr); + +/*! Insert a new array member at the beginning of the array + * + * \param[out] elem_ptr Optional. Pointer to the returned array element. + * \param[in] arr Initialized array object. + * \return ARES_SUCCESS on success, ARES_ENOMEM on out of memory. + */ +ares_status_t ares__array_insert_first(void **elem_ptr, ares__array_t *arr); + +/*! Fetch a pointer to the given element in the array + * \param[in] array Initialized array object + * \param[in] idx Index to fetch + * \return pointer on success, NULL on failure */ +void *ares__array_at(ares__array_t *arr, size_t idx); + +/*! Fetch a pointer to the first element in the array + * \param[in] array Initialized array object + * \return pointer on success, NULL on failure */ +void *ares__array_first(ares__array_t *arr); + +/*! Fetch a pointer to the last element in the array + * \param[in] array Initialized array object + * \return pointer on success, NULL on failure */ +void *ares__array_last(ares__array_t *arr); + +/*! Fetch a constant pointer to the given element in the array + * \param[in] array Initialized array object + * \param[in] idx Index to fetch + * \return pointer on success, NULL on failure */ +const void *ares__array_at_const(const ares__array_t *arr, size_t idx); + +/*! Fetch a constant pointer to the first element in the array + * \param[in] array Initialized array object + * \return pointer on success, NULL on failure */ +const void *ares__array_first_const(const ares__array_t *arr); + +/*! Fetch a constant pointer to the last element in the array + * \param[in] array Initialized array object + * \return pointer on success, NULL on failure */ +const void *ares__array_last_const(const ares__array_t *arr); + +/*! Claim the data from the specified array index, copying it to the buffer + * provided by the caller. The index specified in the array will then be + * removed (without calling any possible destructor) + * + * \param[in,out] dest Optional. Buffer to hold array member. Pass NULL + * if not needed. This could leak memory if array + * member needs destructor if not provided. + * \param[in] dest_size Size of buffer provided, used as a sanity check. + * Must match member_size provided to + * ares__array_create() if dest_size specified. + * \param[in] arr Initialized array object + * \param[in] idx Index to claim + * \return ARES_SUCCESS on success, ARES_EFORMERR on usage failure. + */ +ares_status_t ares__array_claim_at(void *dest, size_t dest_size, + ares__array_t *arr, size_t idx); + +/*! Remove the member at the specified array index. The destructor will be + * called. + * + * \param[in] arr Initialized array object + * \param[in] idx Index to remove + * \return ARES_SUCCESS if removed, ARES_EFORMERR on invalid use + */ +ares_status_t ares__array_remove_at(ares__array_t *arr, size_t idx); + +/*! Remove the first member of the array. + * + * \param[in] arr Initialized array object + * \return ARES_SUCCESS if removed, ARES_EFORMERR on invalid use + */ +ares_status_t ares__array_remove_first(ares__array_t *arr); + +/*! Remove the last member of the array. + * + * \param[in] arr Initialized array object + * \return ARES_SUCCESS if removed, ARES_EFORMERR on invalid use + */ +ares_status_t ares__array_remove_last(ares__array_t *arr); + +/*! @} */ + +#endif /* __ARES__ARRAY_H */ diff --git a/contrib/libs/c-ares/src/lib/ares__htable.c b/contrib/libs/c-ares/src/lib/dsa/ares__htable.c index f09c9ea295..d608d60ce3 100644 --- a/contrib/libs/c-ares/src/lib/ares__htable.c +++ b/contrib/libs/c-ares/src/lib/dsa/ares__htable.c @@ -23,8 +23,6 @@ * * SPDX-License-Identifier: MIT */ -#include "ares_setup.h" -#include "ares.h" #include "ares_private.h" #include "ares__llist.h" #include "ares__htable.h" @@ -207,7 +205,7 @@ static ares_bool_t ares__htable_expand(ares__htable_t *htable) * middle, we wouldn't be able to recover. */ buckets = ares_malloc_zero(sizeof(*buckets) * htable->size); if (buckets == NULL) { - goto done; /* LCOV_EXCL_LINE */ + goto done; /* LCOV_EXCL_LINE */ } /* The maximum number of new llists we'll need is the number of collisions @@ -270,7 +268,7 @@ static ares_bool_t ares__htable_expand(ares__htable_t *htable) if (buckets[idx] == NULL) { /* Silence static analysis, this isn't possible but it doesn't know */ if (prealloc_llist == NULL || prealloc_llist_len == 0) { - goto done; /* LCOV_EXCL_LINE */ + goto done; /* LCOV_EXCL_LINE */ } buckets[idx] = prealloc_llist[prealloc_llist_len - 1]; prealloc_llist_len--; @@ -304,7 +302,7 @@ done: /* On failure, we need to restore the htable size */ if (rv != ARES_TRUE) { - htable->size = old_size; /* LCOV_EXCL_LINE */ + htable->size = old_size; /* LCOV_EXCL_LINE */ } return rv; @@ -336,7 +334,7 @@ ares_bool_t ares__htable_insert(ares__htable_t *htable, void *bucket) if (htable->num_keys + 1 > (htable->size * ARES__HTABLE_EXPAND_PERCENT) / 100) { if (!ares__htable_expand(htable)) { - return ARES_FALSE; /* LCOV_EXCL_LINE */ + return ARES_FALSE; /* LCOV_EXCL_LINE */ } /* If we expanded, need to calculate a new index */ idx = HASH_IDX(htable, key); diff --git a/contrib/libs/c-ares/src/lib/ares__htable.h b/contrib/libs/c-ares/src/lib/dsa/ares__htable.h index d09c865977..d09c865977 100644 --- a/contrib/libs/c-ares/src/lib/ares__htable.h +++ b/contrib/libs/c-ares/src/lib/dsa/ares__htable.h diff --git a/contrib/libs/c-ares/src/lib/ares__htable_asvp.c b/contrib/libs/c-ares/src/lib/dsa/ares__htable_asvp.c index 3c1d2a336f..4b9267ff6c 100644 --- a/contrib/libs/c-ares/src/lib/ares__htable_asvp.c +++ b/contrib/libs/c-ares/src/lib/dsa/ares__htable_asvp.c @@ -23,8 +23,6 @@ * * SPDX-License-Identifier: MIT */ -#include "ares_setup.h" -#include "ares.h" #include "ares_private.h" #include "ares__htable.h" #include "ares__htable_asvp.h" @@ -121,7 +119,7 @@ ares_socket_t *ares__htable_asvp_keys(const ares__htable_asvp_t *htable, size_t i; if (htable == NULL || num == NULL) { - return NULL; + return NULL; /* LCOV_EXCL_LINE: DefensiveCoding */ } *num = 0; @@ -133,8 +131,8 @@ ares_socket_t *ares__htable_asvp_keys(const ares__htable_asvp_t *htable, out = ares_malloc_zero(sizeof(*out) * cnt); if (out == NULL) { - ares_free(buckets); - return NULL; + ares_free(buckets); /* LCOV_EXCL_LINE: OutOfMemory */ + return NULL; /* LCOV_EXCL_LINE: OutOfMemory */ } for (i = 0; i < cnt; i++) { @@ -157,7 +155,7 @@ ares_bool_t ares__htable_asvp_insert(ares__htable_asvp_t *htable, bucket = ares_malloc(sizeof(*bucket)); if (bucket == NULL) { - goto fail; + goto fail; /* LCOV_EXCL_LINE: OutOfMemory */ } bucket->parent = htable; @@ -165,14 +163,14 @@ ares_bool_t ares__htable_asvp_insert(ares__htable_asvp_t *htable, bucket->val = val; if (!ares__htable_insert(htable->hash, bucket)) { - goto fail; + goto fail; /* LCOV_EXCL_LINE: OutOfMemory */ } return ARES_TRUE; fail: if (bucket) { - ares_free(bucket); + ares_free(bucket); /* LCOV_EXCL_LINE: OutOfMemory */ } return ARES_FALSE; } diff --git a/contrib/libs/c-ares/src/lib/ares__htable_asvp.h b/contrib/libs/c-ares/src/lib/dsa/ares__htable_asvp.h index 49a766d023..49a766d023 100644 --- a/contrib/libs/c-ares/src/lib/ares__htable_asvp.h +++ b/contrib/libs/c-ares/src/lib/dsa/ares__htable_asvp.h diff --git a/contrib/libs/c-ares/src/lib/ares__htable_strvp.c b/contrib/libs/c-ares/src/lib/dsa/ares__htable_strvp.c index bfae4c3622..d73a1928a7 100644 --- a/contrib/libs/c-ares/src/lib/ares__htable_strvp.c +++ b/contrib/libs/c-ares/src/lib/dsa/ares__htable_strvp.c @@ -23,8 +23,6 @@ * * SPDX-License-Identifier: MIT */ -#include "ares_setup.h" -#include "ares.h" #include "ares_private.h" #include "ares__htable.h" #include "ares__htable_strvp.h" diff --git a/contrib/libs/c-ares/src/lib/ares__htable_strvp.h b/contrib/libs/c-ares/src/lib/dsa/ares__htable_strvp.h index 25dd2b9077..878c71869a 100644 --- a/contrib/libs/c-ares/src/lib/ares__htable_strvp.h +++ b/contrib/libs/c-ares/src/lib/dsa/ares__htable_strvp.h @@ -115,4 +115,4 @@ size_t ares__htable_strvp_num_keys(const ares__htable_strvp_t *htable); /*! @} */ -#endif /* __ARES__HTABLE_STVP_H */ +#endif /* __ARES__HTABLE_STRVP_H */ diff --git a/contrib/libs/c-ares/src/lib/ares__htable_szvp.c b/contrib/libs/c-ares/src/lib/dsa/ares__htable_szvp.c index 2ff64784bc..b3e88d8b9a 100644 --- a/contrib/libs/c-ares/src/lib/ares__htable_szvp.c +++ b/contrib/libs/c-ares/src/lib/dsa/ares__htable_szvp.c @@ -23,8 +23,6 @@ * * SPDX-License-Identifier: MIT */ -#include "ares_setup.h" -#include "ares.h" #include "ares_private.h" #include "ares__htable.h" #include "ares__htable_szvp.h" @@ -123,7 +121,7 @@ ares_bool_t ares__htable_szvp_insert(ares__htable_szvp_t *htable, size_t key, bucket = ares_malloc(sizeof(*bucket)); if (bucket == NULL) { - goto fail; + goto fail; /* LCOV_EXCL_LINE: OutOfMemory */ } bucket->parent = htable; @@ -131,14 +129,14 @@ ares_bool_t ares__htable_szvp_insert(ares__htable_szvp_t *htable, size_t key, bucket->val = val; if (!ares__htable_insert(htable->hash, bucket)) { - goto fail; + goto fail; /* LCOV_EXCL_LINE: OutOfMemory */ } return ARES_TRUE; fail: if (bucket) { - ares_free(bucket); + ares_free(bucket); /* LCOV_EXCL_LINE: OutOfMemory */ } return ARES_FALSE; } diff --git a/contrib/libs/c-ares/src/lib/ares__htable_szvp.h b/contrib/libs/c-ares/src/lib/dsa/ares__htable_szvp.h index 62b1776be9..62b1776be9 100644 --- a/contrib/libs/c-ares/src/lib/ares__htable_szvp.h +++ b/contrib/libs/c-ares/src/lib/dsa/ares__htable_szvp.h diff --git a/contrib/libs/c-ares/src/lib/ares__htable_vpvp.c b/contrib/libs/c-ares/src/lib/dsa/ares__htable_vpvp.c index 3558fa5a9b..9042c48dd7 100644 --- a/contrib/libs/c-ares/src/lib/ares__htable_vpvp.c +++ b/contrib/libs/c-ares/src/lib/dsa/ares__htable_vpvp.c @@ -23,8 +23,6 @@ * * SPDX-License-Identifier: MIT */ -#include "ares_setup.h" -#include "ares.h" #include "ares_private.h" #include "ares__htable.h" #include "ares__htable_vpvp.h" @@ -44,7 +42,7 @@ typedef struct { void ares__htable_vpvp_destroy(ares__htable_vpvp_t *htable) { if (htable == NULL) { - return; + return; /* LCOV_EXCL_LINE: DefensiveCoding */ } ares__htable_destroy(htable->hash); @@ -93,13 +91,13 @@ ares__htable_vpvp_t * { ares__htable_vpvp_t *htable = ares_malloc(sizeof(*htable)); if (htable == NULL) { - goto fail; + goto fail; /* LCOV_EXCL_LINE: OutOfMemory */ } htable->hash = ares__htable_create(hash_func, bucket_key, bucket_free, key_eq); if (htable->hash == NULL) { - goto fail; + goto fail; /* LCOV_EXCL_LINE: OutOfMemory */ } htable->free_key = key_free; @@ -107,12 +105,14 @@ ares__htable_vpvp_t * return htable; +/* LCOV_EXCL_START: OutOfMemory */ fail: if (htable) { ares__htable_destroy(htable->hash); ares_free(htable); } return NULL; + /* LCOV_EXCL_STOP */ } ares_bool_t ares__htable_vpvp_insert(ares__htable_vpvp_t *htable, void *key, diff --git a/contrib/libs/c-ares/src/lib/ares__htable_vpvp.h b/contrib/libs/c-ares/src/lib/dsa/ares__htable_vpvp.h index 1e0c750d86..1e0c750d86 100644 --- a/contrib/libs/c-ares/src/lib/ares__htable_vpvp.h +++ b/contrib/libs/c-ares/src/lib/dsa/ares__htable_vpvp.h diff --git a/contrib/libs/c-ares/src/lib/ares__llist.c b/contrib/libs/c-ares/src/lib/dsa/ares__llist.c index d175da2bd3..96936c1abe 100644 --- a/contrib/libs/c-ares/src/lib/ares__llist.c +++ b/contrib/libs/c-ares/src/lib/dsa/ares__llist.c @@ -23,8 +23,6 @@ * * SPDX-License-Identifier: MIT */ -#include "ares_setup.h" -#include "ares.h" #include "ares_private.h" #include "ares__llist.h" @@ -77,7 +75,7 @@ static void ares__llist_attach_at(ares__llist_t *list, ares__llist_node_t *node) { if (list == NULL || node == NULL) { - return; + return; /* LCOV_EXCL_LINE: DefensiveCoding */ } node->parent = list; @@ -127,7 +125,7 @@ static ares__llist_node_t *ares__llist_insert_at(ares__llist_t *list, ares__llist_node_t *node = NULL; if (list == NULL || val == NULL) { - return NULL; + return NULL; /* LCOV_EXCL_LINE: DefensiveCoding */ } node = ares_malloc_zero(sizeof(*node)); @@ -186,6 +184,26 @@ ares__llist_node_t *ares__llist_node_first(ares__llist_t *list) return list->head; } +ares__llist_node_t *ares__llist_node_idx(ares__llist_t *list, size_t idx) +{ + ares__llist_node_t *node; + size_t cnt; + + if (list == NULL) { + return NULL; + } + if (idx >= list->cnt) { + return NULL; + } + + node = list->head; + for (cnt = 0; node != NULL && cnt < idx; cnt++) { + node = node->next; + } + + return node; +} + ares__llist_node_t *ares__llist_node_last(ares__llist_t *list) { if (list == NULL) { @@ -250,7 +268,7 @@ static void ares__llist_node_detach(ares__llist_node_t *node) ares__llist_t *list; if (node == NULL) { - return; + return; /* LCOV_EXCL_LINE: DefensiveCoding */ } list = node->parent; @@ -323,7 +341,7 @@ void ares__llist_node_replace(ares__llist_node_t *node, void *val) node->data = val; } -void ares__llist_destroy(ares__llist_t *list) +void ares__llist_clear(ares__llist_t *list) { ares__llist_node_t *node; @@ -334,6 +352,14 @@ void ares__llist_destroy(ares__llist_t *list) while ((node = ares__llist_node_first(list)) != NULL) { ares__llist_node_destroy(node); } +} + +void ares__llist_destroy(ares__llist_t *list) +{ + if (list == NULL) { + return; + } + ares__llist_clear(list); ares_free(list); } @@ -341,7 +367,7 @@ void ares__llist_node_move_parent_last(ares__llist_node_t *node, ares__llist_t *new_parent) { if (node == NULL || new_parent == NULL) { - return; + return; /* LCOV_EXCL_LINE: DefensiveCoding */ } ares__llist_node_detach(node); @@ -352,7 +378,7 @@ void ares__llist_node_move_parent_first(ares__llist_node_t *node, ares__llist_t *new_parent) { if (node == NULL || new_parent == NULL) { - return; + return; /* LCOV_EXCL_LINE: DefensiveCoding */ } ares__llist_node_detach(node); diff --git a/contrib/libs/c-ares/src/lib/ares__llist.h b/contrib/libs/c-ares/src/lib/dsa/ares__llist.h index 7d57bdab3b..213f54134b 100644 --- a/contrib/libs/c-ares/src/lib/ares__llist.h +++ b/contrib/libs/c-ares/src/lib/dsa/ares__llist.h @@ -122,6 +122,14 @@ ares__llist_node_t *ares__llist_node_first(ares__llist_t *list); */ ares__llist_node_t *ares__llist_node_last(ares__llist_t *list); +/*! Obtain a node based on its index. This is an O(n) operation. + * + * \param[in] list Initialized list object + * \param[in] idx Index of node to retrieve + * \return node at index or NULL if invalid index + */ +ares__llist_node_t *ares__llist_node_idx(ares__llist_t *list, size_t idx); + /*! Obtain next node in respect to specified node * * \param[in] node Node referenced @@ -136,6 +144,7 @@ ares__llist_node_t *ares__llist_node_next(ares__llist_node_t *node); */ ares__llist_node_t *ares__llist_node_prev(ares__llist_node_t *node); + /*! Obtain value from node * * \param[in] node Node referenced @@ -150,6 +159,12 @@ void *ares__llist_node_val(ares__llist_node_t *node); */ size_t ares__llist_len(const ares__llist_t *list); +/*! Clear all entries in the list, but don't destroy the list object. + * + * \param[in] list Initialized list object + */ +void ares__llist_clear(ares__llist_t *list); + /*! Obtain list object from referenced node * * \param[in] node Node referenced diff --git a/contrib/libs/c-ares/src/lib/ares__slist.c b/contrib/libs/c-ares/src/lib/dsa/ares__slist.c index 5b80984355..f0e3f8b14a 100644 --- a/contrib/libs/c-ares/src/lib/ares__slist.c +++ b/contrib/libs/c-ares/src/lib/dsa/ares__slist.c @@ -23,8 +23,6 @@ * * SPDX-License-Identifier: MIT */ -#include "ares_setup.h" -#include "ares.h" #include "ares_private.h" #include "ares__slist.h" @@ -206,7 +204,7 @@ ares__slist_node_t *ares__slist_insert(ares__slist_t *list, void *val) node = ares_malloc_zero(sizeof(*node)); if (node == NULL) { - goto fail; + goto fail; /* LCOV_EXCL_LINE: OutOfMemory */ } node->data = val; @@ -218,12 +216,12 @@ ares__slist_node_t *ares__slist_insert(ares__slist_t *list, void *val) /* Allocate array of next and prev nodes for linking each level */ node->next = ares_malloc_zero(sizeof(*node->next) * node->levels); if (node->next == NULL) { - goto fail; + goto fail; /* LCOV_EXCL_LINE: OutOfMemory */ } node->prev = ares_malloc_zero(sizeof(*node->prev) * node->levels); if (node->prev == NULL) { - goto fail; + goto fail; /* LCOV_EXCL_LINE: OutOfMemory */ } /* If the number of levels is greater than we currently support in the slist, @@ -233,7 +231,7 @@ ares__slist_node_t *ares__slist_insert(ares__slist_t *list, void *val) ares_realloc_zero(list->head, sizeof(*list->head) * list->levels, sizeof(*list->head) * node->levels); if (ptr == NULL) { - goto fail; + goto fail; /* LCOV_EXCL_LINE: OutOfMemory */ } list->head = ptr; @@ -246,6 +244,7 @@ ares__slist_node_t *ares__slist_insert(ares__slist_t *list, void *val) return node; +/* LCOV_EXCL_START: OutOfMemory */ fail: if (node) { ares_free(node->prev); @@ -253,6 +252,7 @@ fail: ares_free(node); } return NULL; + /* LCOV_EXCL_STOP */ } static void ares__slist_node_pop(ares__slist_node_t *node) diff --git a/contrib/libs/c-ares/src/lib/ares__slist.h b/contrib/libs/c-ares/src/lib/dsa/ares__slist.h index 26af88fa78..26af88fa78 100644 --- a/contrib/libs/c-ares/src/lib/ares__slist.h +++ b/contrib/libs/c-ares/src/lib/dsa/ares__slist.h diff --git a/contrib/libs/c-ares/src/lib/ares_event.h b/contrib/libs/c-ares/src/lib/event/ares_event.h index f5d044d2a6..317731fc42 100644 --- a/contrib/libs/c-ares/src/lib/ares_event.h +++ b/contrib/libs/c-ares/src/lib/event/ares_event.h @@ -26,8 +26,6 @@ #ifndef __ARES__EVENT_H #define __ARES__EVENT_H -#include "ares_setup.h" - struct ares_event; typedef struct ares_event ares_event_t; diff --git a/contrib/libs/c-ares/src/lib/ares_event_configchg.c b/contrib/libs/c-ares/src/lib/event/ares_event_configchg.c index c7bc9ffd58..030c76c69c 100644 --- a/contrib/libs/c-ares/src/lib/ares_event_configchg.c +++ b/contrib/libs/c-ares/src/lib/event/ares_event_configchg.c @@ -23,8 +23,6 @@ * * SPDX-License-Identifier: MIT */ -#include "ares_setup.h" -#include "ares.h" #include "ares_private.h" #include "ares_event.h" @@ -54,7 +52,7 @@ struct ares_event_configchg { void ares_event_configchg_destroy(ares_event_configchg_t *configchg) { if (configchg == NULL) { - return; + return; /* LCOV_EXCL_LINE: DefensiveCoding */ } /* Tell event system to stop monitoring for changes. This will cause the @@ -67,7 +65,7 @@ static void ares_event_configchg_free(void *data) { ares_event_configchg_t *configchg = data; if (configchg == NULL) { - return; + return; /* LCOV_EXCL_LINE: DefensiveCoding */ } if (configchg->inotify_fd >= 0) { @@ -142,22 +140,22 @@ ares_status_t ares_event_configchg_init(ares_event_configchg_t **configchg, c = ares_malloc_zero(sizeof(*c)); if (c == NULL) { - return ARES_ENOMEM; + return ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ } c->e = e; c->inotify_fd = inotify_init1(IN_NONBLOCK | IN_CLOEXEC); if (c->inotify_fd == -1) { - status = ARES_ESERVFAIL; - goto done; + status = ARES_ESERVFAIL; /* LCOV_EXCL_LINE: UntestablePath */ + goto done; /* LCOV_EXCL_LINE: UntestablePath */ } /* We need to monitor /etc/resolv.conf, /etc/nsswitch.conf */ if (inotify_add_watch(c->inotify_fd, "/etc", IN_CREATE | IN_MODIFY | IN_MOVED_TO | IN_ONLYDIR) == -1) { - status = ARES_ESERVFAIL; - goto done; + status = ARES_ESERVFAIL; /* LCOV_EXCL_LINE: UntestablePath */ + goto done; /* LCOV_EXCL_LINE: UntestablePath */ } status = @@ -173,7 +171,7 @@ done: return status; } -#elif defined(_WIN32) +#elif defined(USE_WINSOCK) # include <winsock2.h> # include <iphlpapi.h> @@ -182,31 +180,68 @@ done: struct ares_event_configchg { HANDLE ifchg_hnd; + HKEY regip4; + HANDLE regip4_event; + HANDLE regip4_wait; + HKEY regip6; + HANDLE regip6_event; + HANDLE regip6_wait; ares_event_thread_t *e; }; void ares_event_configchg_destroy(ares_event_configchg_t *configchg) { -# ifdef __WATCOMC__ - /* Not supported */ -# else if (configchg == NULL) { return; } +# ifdef HAVE_NOTIFYIPINTERFACECHANGE if (configchg->ifchg_hnd != NULL) { CancelMibChangeNotify2(configchg->ifchg_hnd); configchg->ifchg_hnd = NULL; } +# endif + +# ifdef HAVE_REGISTERWAITFORSINGLEOBJECT + if (configchg->regip4_wait != NULL) { + UnregisterWait(configchg->regip4_wait); + configchg->regip4_wait = NULL; + } - ares_free(configchg); + if (configchg->regip6_wait != NULL) { + UnregisterWait(configchg->regip6_wait); + configchg->regip6_wait = NULL; + } + + if (configchg->regip4 != NULL) { + RegCloseKey(configchg->regip4); + configchg->regip4 = NULL; + } + + if (configchg->regip6 != NULL) { + RegCloseKey(configchg->regip6); + configchg->regip6 = NULL; + } + + if (configchg->regip4_event != NULL) { + CloseHandle(configchg->regip4_event); + configchg->regip4_event = NULL; + } + + if (configchg->regip6_event != NULL) { + CloseHandle(configchg->regip6_event); + configchg->regip6_event = NULL; + } # endif + + ares_free(configchg); } -# ifndef __WATCOMC__ -static void ares_event_configchg_cb(PVOID CallerContext, - PMIB_IPINTERFACE_ROW Row, - MIB_NOTIFICATION_TYPE NotificationType) + +# ifdef HAVE_NOTIFYIPINTERFACECHANGE +static void NETIOAPI_API_ + ares_event_configchg_ip_cb(PVOID CallerContext, PMIB_IPINTERFACE_ROW Row, + MIB_NOTIFICATION_TYPE NotificationType) { ares_event_configchg_t *configchg = CallerContext; (void)Row; @@ -215,43 +250,130 @@ static void ares_event_configchg_cb(PVOID CallerContext, } # endif +static ares_bool_t + ares_event_configchg_regnotify(ares_event_configchg_t *configchg) +{ +# ifdef HAVE_REGISTERWAITFORSINGLEOBJECT +# if defined(__WATCOMC__) && !defined(REG_NOTIFY_THREAD_AGNOSTIC) +# define REG_NOTIFY_THREAD_AGNOSTIC 0x10000000L +# endif + DWORD flags = REG_NOTIFY_CHANGE_NAME | REG_NOTIFY_CHANGE_LAST_SET | + REG_NOTIFY_THREAD_AGNOSTIC; + + if (RegNotifyChangeKeyValue(configchg->regip4, TRUE, flags, + configchg->regip4_event, TRUE) != ERROR_SUCCESS) { + return ARES_FALSE; + } + + if (RegNotifyChangeKeyValue(configchg->regip6, TRUE, flags, + configchg->regip6_event, TRUE) != ERROR_SUCCESS) { + return ARES_FALSE; + } +# else + (void)configchg; +# endif + return ARES_TRUE; +} + +static VOID CALLBACK ares_event_configchg_reg_cb(PVOID lpParameter, + BOOLEAN TimerOrWaitFired) +{ + ares_event_configchg_t *configchg = lpParameter; + (void)TimerOrWaitFired; + + ares_reinit(configchg->e->channel); + + /* Re-arm, as its single-shot. However, we don't know which one needs to + * be re-armed, so we just do both */ + ares_event_configchg_regnotify(configchg); +} ares_status_t ares_event_configchg_init(ares_event_configchg_t **configchg, ares_event_thread_t *e) { -# ifdef __WATCOMC__ - return ARES_ENOTIMP; -# else - ares_status_t status = ARES_SUCCESS; + ares_status_t status = ARES_SUCCESS; + ares_event_configchg_t *c = NULL; - *configchg = ares_malloc_zero(sizeof(**configchg)); - if (*configchg == NULL) { + c = ares_malloc_zero(sizeof(**configchg)); + if (c == NULL) { return ARES_ENOMEM; } - (*configchg)->e = e; + c->e = e; +# ifdef HAVE_NOTIFYIPINTERFACECHANGE /* NOTE: If a user goes into the control panel and changes the network * adapter DNS addresses manually, this will NOT trigger a notification. * We've also tried listening on NotifyUnicastIpAddressChange(), but * that didn't get triggered either. */ + if (NotifyIpInterfaceChange(AF_UNSPEC, ares_event_configchg_ip_cb, c, FALSE, + &c->ifchg_hnd) != NO_ERROR) { + status = ARES_ESERVFAIL; + goto done; + } +# endif + +# ifdef HAVE_REGISTERWAITFORSINGLEOBJECT + /* Monitor HKLM\SYSTEM\CurrentControlSet\Services\Tcpip6\Parameters\Interfaces + * and HKLM\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\Interfaces + * for changes via RegNotifyChangeKeyValue() */ + if (RegOpenKeyExW( + HKEY_LOCAL_MACHINE, + L"SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces", + 0, KEY_NOTIFY, &c->regip4) != ERROR_SUCCESS) { + status = ARES_ESERVFAIL; + goto done; + } + + if (RegOpenKeyExW( + HKEY_LOCAL_MACHINE, + L"SYSTEM\\CurrentControlSet\\Services\\Tcpip6\\Parameters\\Interfaces", + 0, KEY_NOTIFY, &c->regip6) != ERROR_SUCCESS) { + status = ARES_ESERVFAIL; + goto done; + } + + c->regip4_event = CreateEvent(NULL, TRUE, FALSE, NULL); + if (c->regip4_event == NULL) { + status = ARES_ESERVFAIL; + goto done; + } + + c->regip6_event = CreateEvent(NULL, TRUE, FALSE, NULL); + if (c->regip6_event == NULL) { + status = ARES_ESERVFAIL; + goto done; + } + + if (!RegisterWaitForSingleObject(&c->regip4_wait, c->regip4_event, + ares_event_configchg_reg_cb, c, INFINITE, + WT_EXECUTEDEFAULT)) { + status = ARES_ESERVFAIL; + goto done; + } + + if (!RegisterWaitForSingleObject(&c->regip6_wait, c->regip6_event, + ares_event_configchg_reg_cb, c, INFINITE, + WT_EXECUTEDEFAULT)) { + status = ARES_ESERVFAIL; + goto done; + } +# endif - if (NotifyIpInterfaceChange( - AF_UNSPEC, (PIPINTERFACE_CHANGE_CALLBACK)ares_event_configchg_cb, - *configchg, FALSE, &(*configchg)->ifchg_hnd) != NO_ERROR) { + if (!ares_event_configchg_regnotify(c)) { status = ARES_ESERVFAIL; goto done; } done: if (status != ARES_SUCCESS) { - ares_event_configchg_destroy(*configchg); - *configchg = NULL; + ares_event_configchg_destroy(c); + } else { + *configchg = c; } return status; -# endif } #elif defined(__APPLE__) @@ -260,6 +382,7 @@ done: # include <unistd.h> # include <notify.h> # include <dlfcn.h> +# include <fcntl.h> struct ares_event_configchg { int fd; @@ -333,6 +456,13 @@ ares_status_t ares_event_configchg_init(ares_event_configchg_t **configchg, const char *(*pdns_configuration_notify_key)(void) = NULL; const char *notify_key = NULL; int flags; + size_t i; + const char *searchlibs[] = { + "/usr/lib/libSystem.dylib", + "/System/Library/Frameworks/SystemConfiguration.framework/" + "SystemConfiguration", + NULL + }; *configchg = ares_malloc_zero(sizeof(**configchg)); if (*configchg == NULL) { @@ -340,13 +470,23 @@ ares_status_t ares_event_configchg_init(ares_event_configchg_t **configchg, } /* Load symbol as it isn't normally public */ - handle = dlopen("/usr/lib/libSystem.dylib", RTLD_LAZY | RTLD_NOLOAD); - if (handle == NULL) { - status = ARES_ESERVFAIL; - goto done; - } + for (i = 0; searchlibs[i] != NULL; i++) { + handle = dlopen(searchlibs[i], RTLD_LAZY); + if (handle == NULL) { + /* Fail, loop! */ + continue; + } - pdns_configuration_notify_key = dlsym(handle, "dns_configuration_notify_key"); + pdns_configuration_notify_key = + (const char *(*)(void))dlsym(handle, "dns_configuration_notify_key"); + if (pdns_configuration_notify_key != NULL) { + break; + } + + /* Fail, loop! */ + dlclose(handle); + handle = NULL; + } if (pdns_configuration_notify_key == NULL) { status = ARES_ESERVFAIL; @@ -388,7 +528,7 @@ done: return status; } -#elif defined(HAVE_STAT) +#elif defined(HAVE_STAT) && !defined(_WIN32) # ifdef HAVE_SYS_TYPES_H # include <sys/types.h> # endif @@ -415,9 +555,14 @@ static ares_status_t config_change_check(ares__htable_strvp_t *filestat, const char *resolvconf_path) { size_t i; - const char *configfiles[] = { resolvconf_path, "/etc/nsswitch.conf", - "/etc/netsvc.conf", "/etc/svc.conf", NULL }; - ares_bool_t changed = ARES_FALSE; + const char *configfiles[5]; + ares_bool_t changed = ARES_FALSE; + + configfiles[0] = resolvconf_path; + configfiles[1] = "/etc/nsswitch.conf"; + configfiles[2] = "/etc/netsvc.conf"; + configfiles[3] = "/etc/svc.conf"; + configfiles[4] = NULL; for (i = 0; configfiles[i] != NULL; i++) { fileinfo_t *fi = ares__htable_strvp_get_direct(filestat, configfiles[i]); diff --git a/contrib/libs/c-ares/src/lib/ares_event_epoll.c b/contrib/libs/c-ares/src/lib/event/ares_event_epoll.c index 78cbbc368c..5eb25cccc9 100644 --- a/contrib/libs/c-ares/src/lib/ares_event_epoll.c +++ b/contrib/libs/c-ares/src/lib/event/ares_event_epoll.c @@ -23,8 +23,6 @@ * * SPDX-License-Identifier: MIT */ -#include "ares_setup.h" -#include "ares.h" #include "ares_private.h" #include "ares_event.h" @@ -46,12 +44,12 @@ static void ares_evsys_epoll_destroy(ares_event_thread_t *e) ares_evsys_epoll_t *ep = NULL; if (e == NULL) { - return; + return; /* LCOV_EXCL_LINE: DefensiveCoding */ } ep = e->ev_sys_data; if (ep == NULL) { - return; + return; /* LCOV_EXCL_LINE: DefensiveCoding */ } if (ep->epoll_fd != -1) { @@ -68,25 +66,21 @@ static ares_bool_t ares_evsys_epoll_init(ares_event_thread_t *e) ep = ares_malloc_zero(sizeof(*ep)); if (ep == NULL) { - return ARES_FALSE; + return ARES_FALSE; /* LCOV_EXCL_LINE: OutOfMemory */ } e->ev_sys_data = ep; - ep->epoll_fd = epoll_create1(0); + ep->epoll_fd = epoll_create1(EPOLL_CLOEXEC); if (ep->epoll_fd == -1) { - ares_evsys_epoll_destroy(e); - return ARES_FALSE; + ares_evsys_epoll_destroy(e); /* LCOV_EXCL_LINE: UntestablePath */ + return ARES_FALSE; /* LCOV_EXCL_LINE: UntestablePath */ } -# ifdef FD_CLOEXEC - fcntl(ep->epoll_fd, F_SETFD, FD_CLOEXEC); -# endif - e->ev_signal = ares_pipeevent_create(e); if (e->ev_signal == NULL) { - ares_evsys_epoll_destroy(e); - return ARES_FALSE; + ares_evsys_epoll_destroy(e); /* LCOV_EXCL_LINE: UntestablePath */ + return ARES_FALSE; /* LCOV_EXCL_LINE: UntestablePath */ } return ARES_TRUE; @@ -108,7 +102,7 @@ static ares_bool_t ares_evsys_epoll_event_add(ares_event_t *event) epev.events |= EPOLLOUT; } if (epoll_ctl(ep->epoll_fd, EPOLL_CTL_ADD, event->fd, &epev) != 0) { - return ARES_FALSE; + return ARES_FALSE; /* LCOV_EXCL_LINE: UntestablePath */ } return ARES_TRUE; } @@ -158,7 +152,7 @@ static size_t ares_evsys_epoll_wait(ares_event_thread_t *e, rv = epoll_wait(ep->epoll_fd, events, (int)nevents, (timeout_ms == 0) ? -1 : (int)timeout_ms); if (rv < 0) { - return 0; + return 0; /* LCOV_EXCL_LINE: UntestablePath */ } nevents = (size_t)rv; @@ -170,7 +164,7 @@ static size_t ares_evsys_epoll_wait(ares_event_thread_t *e, ev = ares__htable_asvp_get_direct(e->ev_sock_handles, (ares_socket_t)events[i].data.fd); if (ev == NULL || ev->cb == NULL) { - continue; + continue; /* LCOV_EXCL_LINE: DefensiveCoding */ } cnt++; diff --git a/contrib/libs/c-ares/src/lib/ares_event_kqueue.c b/contrib/libs/c-ares/src/lib/event/ares_event_kqueue.c index 7e2c60abf5..1c35c14f16 100644 --- a/contrib/libs/c-ares/src/lib/ares_event_kqueue.c +++ b/contrib/libs/c-ares/src/lib/event/ares_event_kqueue.c @@ -23,8 +23,6 @@ * * SPDX-License-Identifier: MIT */ -#include "ares_setup.h" -#include "ares.h" #include "ares_private.h" #include "ares_event.h" @@ -95,7 +93,7 @@ static ares_bool_t ares_evsys_kqueue_init(ares_event_thread_t *e) kq->nchanges_alloc = 8; kq->changelist = - ares_malloc_zero(sizeof(*kq->changelist) * kq->nchanges_alloc); + ares_malloc_zero(kq->nchanges_alloc * sizeof(*kq->changelist)); if (kq->changelist == NULL) { ares_evsys_kqueue_destroy(e); return ARES_FALSE; @@ -125,8 +123,9 @@ static void ares_evsys_kqueue_enqueue(ares_evsys_kqueue_t *kq, int fd, if (kq->nchanges > kq->nchanges_alloc) { kq->nchanges_alloc <<= 1; - kq->changelist = ares_realloc_zero(kq->changelist, kq->nchanges_alloc >> 1, - kq->nchanges_alloc); + kq->changelist = ares_realloc_zero( + kq->changelist, (kq->nchanges_alloc >> 1) * sizeof(*kq->changelist), + kq->nchanges_alloc * sizeof(*kq->changelist)); } EV_SET(&kq->changelist[idx], fd, filter, flags, 0, 0, 0); @@ -197,7 +196,7 @@ static size_t ares_evsys_kqueue_wait(ares_event_thread_t *e, size_t cnt = 0; if (timeout_ms != 0) { - ts.tv_sec = timeout_ms / 1000; + ts.tv_sec = (time_t)timeout_ms / 1000; ts.tv_nsec = (timeout_ms % 1000) * 1000 * 1000; timeout = &ts; } diff --git a/contrib/libs/c-ares/src/lib/ares_event_poll.c b/contrib/libs/c-ares/src/lib/event/ares_event_poll.c index a06c6e3fc4..42ffd912e9 100644 --- a/contrib/libs/c-ares/src/lib/ares_event_poll.c +++ b/contrib/libs/c-ares/src/lib/event/ares_event_poll.c @@ -23,8 +23,6 @@ * * SPDX-License-Identifier: MIT */ -#include "ares_setup.h" -#include "ares.h" #include "ares_private.h" #include "ares_event.h" #ifdef HAVE_POLL_H @@ -37,7 +35,7 @@ static ares_bool_t ares_evsys_poll_init(ares_event_thread_t *e) { e->ev_signal = ares_pipeevent_create(e); if (e->ev_signal == NULL) { - return ARES_FALSE; + return ARES_FALSE; /* LCOV_EXCL_LINE: UntestablePath */ } return ARES_TRUE; } @@ -78,7 +76,7 @@ static size_t ares_evsys_poll_wait(ares_event_thread_t *e, if (fdlist != NULL && num_fds) { pollfd = ares_malloc_zero(sizeof(*pollfd) * num_fds); if (pollfd == NULL) { - goto done; + goto done; /* LCOV_EXCL_LINE: OutOfMemory */ } for (i = 0; i < num_fds; i++) { const ares_event_t *ev = @@ -111,7 +109,7 @@ static size_t ares_evsys_poll_wait(ares_event_thread_t *e, ev = ares__htable_asvp_get_direct(e->ev_sock_handles, pollfd[i].fd); if (ev == NULL || ev->cb == NULL) { - continue; + continue; /* LCOV_EXCL_LINE: DefensiveCoding */ } if (pollfd[i].revents & (POLLERR | POLLHUP | POLLIN)) { diff --git a/contrib/libs/c-ares/src/lib/ares_event_select.c b/contrib/libs/c-ares/src/lib/event/ares_event_select.c index 57a4271ea7..e1266ea990 100644 --- a/contrib/libs/c-ares/src/lib/ares_event_select.c +++ b/contrib/libs/c-ares/src/lib/event/ares_event_select.c @@ -29,8 +29,6 @@ * anyhow */ #define FD_SETSIZE 4096 -#include "ares_setup.h" -#include "ares.h" #include "ares_private.h" #include "ares_event.h" #ifdef HAVE_SYS_SELECT_H @@ -45,7 +43,7 @@ static ares_bool_t ares_evsys_select_init(ares_event_thread_t *e) { e->ev_signal = ares_pipeevent_create(e); if (e->ev_signal == NULL) { - return ARES_FALSE; + return ARES_FALSE; /* LCOV_EXCL_LINE: UntestablePath */ } return ARES_TRUE; } @@ -83,12 +81,14 @@ static size_t ares_evsys_select_wait(ares_event_thread_t *e, size_t i; fd_set read_fds; fd_set write_fds; + fd_set except_fds; int nfds = 0; struct timeval tv; struct timeval *tout = NULL; FD_ZERO(&read_fds); FD_ZERO(&write_fds); + FD_ZERO(&except_fds); for (i = 0; i < num_fds; i++) { const ares_event_t *ev = @@ -99,6 +99,7 @@ static size_t ares_evsys_select_wait(ares_event_thread_t *e, if (ev->flags & ARES_EVENT_FLAG_WRITE) { FD_SET(ev->fd, &write_fds); } + FD_SET(ev->fd, &except_fds); if (ev->fd + 1 > nfds) { nfds = ev->fd + 1; } @@ -110,7 +111,7 @@ static size_t ares_evsys_select_wait(ares_event_thread_t *e, tout = &tv; } - rv = select(nfds, &read_fds, &write_fds, NULL, tout); + rv = select(nfds, &read_fds, &write_fds, &except_fds, tout); if (rv > 0) { for (i = 0; i < num_fds; i++) { ares_event_t *ev; @@ -118,10 +119,10 @@ static size_t ares_evsys_select_wait(ares_event_thread_t *e, ev = ares__htable_asvp_get_direct(e->ev_sock_handles, fdlist[i]); if (ev == NULL || ev->cb == NULL) { - continue; + continue; /* LCOV_EXCL_LINE: DefensiveCoding */ } - if (FD_ISSET(fdlist[i], &read_fds)) { + if (FD_ISSET(fdlist[i], &read_fds) || FD_ISSET(fdlist[i], &except_fds)) { flags |= ARES_EVENT_FLAG_READ; } diff --git a/contrib/libs/c-ares/src/lib/ares_event_thread.c b/contrib/libs/c-ares/src/lib/event/ares_event_thread.c index d9d904f29b..8b332e9b01 100644 --- a/contrib/libs/c-ares/src/lib/ares_event_thread.c +++ b/contrib/libs/c-ares/src/lib/event/ares_event_thread.c @@ -23,8 +23,6 @@ * * SPDX-License-Identifier: MIT */ -#include "ares_setup.h" -#include "ares.h" #include "ares_private.h" #include "ares_event.h" @@ -32,7 +30,7 @@ static void ares_event_destroy_cb(void *arg) { ares_event_t *event = arg; if (event == NULL) { - return; + return; /* LCOV_EXCL_LINE: DefensiveCoding */ } /* Unregister from the event thread if it was registered with one */ @@ -49,6 +47,23 @@ static void ares_event_destroy_cb(void *arg) ares_free(event); } +static void ares_event_signal(const ares_event_t *event) +{ + if (event == NULL || event->signal_cb == NULL) { + return; /* LCOV_EXCL_LINE: DefensiveCoding */ + } + event->signal_cb(event); +} + +static void ares_event_thread_wake(const ares_event_thread_t *e) +{ + if (e == NULL) { + return; /* LCOV_EXCL_LINE: DefensiveCoding */ + } + + ares_event_signal(e->ev_signal); +} + /* See if a pending update already exists. We don't want to enqueue multiple * updates for the same event handle. Right now this is O(n) based on number * of updates already enqueued. In the future, it might make sense to make @@ -88,9 +103,10 @@ ares_status_t ares_event_update(ares_event_t **event, ares_event_thread_t *e, ares_event_signal_cb_t signal_cb) { ares_event_t *ev = NULL; + ares_status_t status; if (e == NULL) { - return ARES_EFORMERR; + return ARES_EFORMERR; /* LCOV_EXCL_LINE: DefensiveCoding */ } /* Callback must be specified if not a removal event. */ @@ -118,18 +134,22 @@ ares_status_t ares_event_update(ares_event_t **event, ares_event_thread_t *e, /* That's all the validation we can really do */ + ares__thread_mutex_lock(e->mutex); + /* See if we have a queued update already */ ev = ares_event_update_find(e, fd, data); if (ev == NULL) { /* Allocate a new one */ ev = ares_malloc_zero(sizeof(*ev)); if (ev == NULL) { - return ARES_ENOMEM; + status = ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ + goto done; /* LCOV_EXCL_LINE: OutOfMemory */ } if (ares__llist_insert_last(e->ev_updates, ev) == NULL) { - ares_free(ev); - return ARES_ENOMEM; + ares_free(ev); /* LCOV_EXCL_LINE: OutOfMemory */ + status = ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ + goto done; /* LCOV_EXCL_LINE: OutOfMemory */ } } @@ -152,24 +172,17 @@ ares_status_t ares_event_update(ares_event_t **event, ares_event_thread_t *e, *event = ev; } - return ARES_SUCCESS; -} + status = ARES_SUCCESS; -static void ares_event_signal(const ares_event_t *event) -{ - if (event == NULL || event->signal_cb == NULL) { - return; +done: + if (status == ARES_SUCCESS) { + /* Wake event thread if successful so it can pull the updates */ + ares_event_thread_wake(e); } - event->signal_cb(event); -} -static void ares_event_thread_wake(const ares_event_thread_t *e) -{ - if (e == NULL) { - return; - } + ares__thread_mutex_unlock(e->mutex); - ares_event_signal(e->ev_signal); + return status; } static void ares_event_thread_process_fd(ares_event_thread_t *e, @@ -197,15 +210,10 @@ static void ares_event_thread_sockstate_cb(void *data, ares_socket_t socket_fd, flags |= ARES_EVENT_FLAG_WRITE; } - /* Update channel fd */ - ares__thread_mutex_lock(e->mutex); + /* Update channel fd. This function will lock e->mutex and also wake the + * event thread to process the update */ ares_event_update(NULL, e, flags, ares_event_thread_process_fd, socket_fd, NULL, NULL, NULL); - - /* Wake the event thread so it properly enqueues any updates */ - ares_event_thread_wake(e); - - ares__thread_mutex_unlock(e->mutex); } static void ares_event_process_updates(ares_event_thread_t *e) @@ -264,6 +272,35 @@ static void ares_event_process_updates(ares_event_thread_t *e) } } +static void ares_event_thread_cleanup(ares_event_thread_t *e) +{ + /* Manually free any updates that weren't processed */ + if (e->ev_updates != NULL) { + ares__llist_node_t *node; + + while ((node = ares__llist_node_first(e->ev_updates)) != NULL) { + ares_event_destroy_cb(ares__llist_node_claim(node)); + } + ares__llist_destroy(e->ev_updates); + e->ev_updates = NULL; + } + + if (e->ev_sock_handles != NULL) { + ares__htable_asvp_destroy(e->ev_sock_handles); + e->ev_sock_handles = NULL; + } + + if (e->ev_cust_handles != NULL) { + ares__htable_vpvp_destroy(e->ev_cust_handles); + e->ev_cust_handles = NULL; + } + + if (e->ev_sys != NULL && e->ev_sys->destroy != NULL) { + e->ev_sys->destroy(e); + e->ev_sys = NULL; + } +} + static void *ares_event_thread(void *arg) { ares_event_thread_t *e = arg; @@ -274,16 +311,19 @@ static void *ares_event_thread(void *arg) const struct timeval *tvout; unsigned long timeout_ms = 0; /* 0 = unlimited */ + ares_event_process_updates(e); + + /* Don't hold a mutex while waiting on events or calling into anything + * that might require a c-ares channel lock since a callback could be + * triggered cross-thread */ + ares__thread_mutex_unlock(e->mutex); + tvout = ares_timeout(e->channel, NULL, &tv); if (tvout != NULL) { timeout_ms = (unsigned long)((tvout->tv_sec * 1000) + (tvout->tv_usec / 1000) + 1); } - ares_event_process_updates(e); - - /* Don't hold a mutex while waiting on events */ - ares__thread_mutex_unlock(e->mutex); e->ev_sys->wait(e, timeout_ms); /* Each iteration should do timeout processing */ @@ -295,14 +335,16 @@ static void *ares_event_thread(void *arg) ares__thread_mutex_lock(e->mutex); } + /* Lets cleanup while we're in the thread itself */ + ares_event_thread_cleanup(e); + ares__thread_mutex_unlock(e->mutex); + return NULL; } static void ares_event_thread_destroy_int(ares_event_thread_t *e) { - ares__llist_node_t *node; - /* Wake thread and tell it to shutdown if it exists */ ares__thread_mutex_lock(e->mutex); if (e->isup) { @@ -313,26 +355,14 @@ static void ares_event_thread_destroy_int(ares_event_thread_t *e) /* Wait for thread to shutdown */ if (e->thread) { - ares__thread_join(e->thread, NULL); + void *rv = NULL; + ares__thread_join(e->thread, &rv); e->thread = NULL; } - /* Manually free any updates that weren't processed */ - while ((node = ares__llist_node_first(e->ev_updates)) != NULL) { - ares_event_destroy_cb(ares__llist_node_claim(node)); - } - ares__llist_destroy(e->ev_updates); - e->ev_updates = NULL; - - ares__htable_asvp_destroy(e->ev_sock_handles); - e->ev_sock_handles = NULL; - - ares__htable_vpvp_destroy(e->ev_cust_handles); - e->ev_cust_handles = NULL; - - if (e->ev_sys && e->ev_sys->destroy) { - e->ev_sys->destroy(e); - } + /* If the event thread ever got to the point of starting, this is a no-op + * as it runs this same cleanup when it shuts down */ + ares_event_thread_cleanup(e); ares__thread_mutex_destroy(e->mutex); e->mutex = NULL; @@ -345,17 +375,19 @@ void ares_event_thread_destroy(ares_channel_t *channel) ares_event_thread_t *e = channel->sock_state_cb_data; if (e == NULL) { - return; + return; /* LCOV_EXCL_LINE: DefensiveCoding */ } ares_event_thread_destroy_int(e); + channel->sock_state_cb_data = NULL; + channel->sock_state_cb = NULL; } static const ares_event_sys_t *ares_event_fetch_sys(ares_evsys_t evsys) { switch (evsys) { case ARES_EVSYS_WIN32: -#if defined(_WIN32) +#if defined(USE_WINSOCK) return &ares_evsys_win32; #else return NULL; @@ -391,22 +423,23 @@ static const ares_event_sys_t *ares_event_fetch_sys(ares_evsys_t evsys) /* case ARES_EVSYS_DEFAULT: */ default: -#if defined(_WIN32) - return &ares_evsys_win32; + break; + } + + /* default */ +#if defined(USE_WINSOCK) + return &ares_evsys_win32; #elif defined(HAVE_KQUEUE) - return &ares_evsys_kqueue; + return &ares_evsys_kqueue; #elif defined(HAVE_EPOLL) - return &ares_evsys_epoll; + return &ares_evsys_epoll; #elif defined(HAVE_POLL) - return &ares_evsys_poll; + return &ares_evsys_poll; #elif defined(HAVE_PIPE) - return &ares_evsys_select; + return &ares_evsys_select; #else - break; -#endif - } - return NULL; +#endif } ares_status_t ares_event_thread_init(ares_channel_t *channel) @@ -415,49 +448,51 @@ ares_status_t ares_event_thread_init(ares_channel_t *channel) e = ares_malloc_zero(sizeof(*e)); if (e == NULL) { - return ARES_ENOMEM; + return ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ } e->mutex = ares__thread_mutex_create(); if (e->mutex == NULL) { - ares_event_thread_destroy_int(e); - return ARES_ENOMEM; + ares_event_thread_destroy_int(e); /* LCOV_EXCL_LINE: OutOfMemory */ + return ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ } e->ev_updates = ares__llist_create(NULL); if (e->ev_updates == NULL) { - ares_event_thread_destroy_int(e); - return ARES_ENOMEM; + ares_event_thread_destroy_int(e); /* LCOV_EXCL_LINE: OutOfMemory */ + return ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ } e->ev_sock_handles = ares__htable_asvp_create(ares_event_destroy_cb); if (e->ev_sock_handles == NULL) { - ares_event_thread_destroy_int(e); - return ARES_ENOMEM; + ares_event_thread_destroy_int(e); /* LCOV_EXCL_LINE: OutOfMemory */ + return ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ } e->ev_cust_handles = ares__htable_vpvp_create(NULL, ares_event_destroy_cb); if (e->ev_cust_handles == NULL) { - ares_event_thread_destroy_int(e); - return ARES_ENOMEM; + ares_event_thread_destroy_int(e); /* LCOV_EXCL_LINE: OutOfMemory */ + return ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ } e->channel = channel; e->isup = ARES_TRUE; e->ev_sys = ares_event_fetch_sys(channel->evsys); if (e->ev_sys == NULL) { - ares_event_thread_destroy_int(e); - return ARES_ENOTIMP; + ares_event_thread_destroy_int(e); /* LCOV_EXCL_LINE: UntestablePath */ + return ARES_ENOTIMP; /* LCOV_EXCL_LINE: UntestablePath */ } channel->sock_state_cb = ares_event_thread_sockstate_cb; channel->sock_state_cb_data = e; if (!e->ev_sys->init(e)) { + /* LCOV_EXCL_START: UntestablePath */ ares_event_thread_destroy_int(e); channel->sock_state_cb = NULL; channel->sock_state_cb_data = NULL; return ARES_ESERVFAIL; + /* LCOV_EXCL_STOP */ } /* Before starting the thread, process any possible events the initialization @@ -469,10 +504,12 @@ ares_status_t ares_event_thread_init(ares_channel_t *channel) /* Start thread */ if (ares__thread_create(&e->thread, ares_event_thread, e) != ARES_SUCCESS) { + /* LCOV_EXCL_START: UntestablePath */ ares_event_thread_destroy_int(e); channel->sock_state_cb = NULL; channel->sock_state_cb_data = NULL; return ARES_ESERVFAIL; + /* LCOV_EXCL_STOP */ } return ARES_SUCCESS; diff --git a/contrib/libs/c-ares/src/lib/ares_event_wake_pipe.c b/contrib/libs/c-ares/src/lib/event/ares_event_wake_pipe.c index a2cd6f609a..282d013dc6 100644 --- a/contrib/libs/c-ares/src/lib/ares_event_wake_pipe.c +++ b/contrib/libs/c-ares/src/lib/event/ares_event_wake_pipe.c @@ -23,8 +23,6 @@ * * SPDX-License-Identifier: MIT */ -#include "ares_setup.h" -#include "ares.h" #include "ares_private.h" #include "ares_event.h" #ifdef HAVE_UNISTD_H @@ -60,7 +58,7 @@ static ares_pipeevent_t *ares_pipeevent_init(void) { ares_pipeevent_t *p = ares_malloc_zero(sizeof(*p)); if (p == NULL) { - return NULL; + return NULL; /* LCOV_EXCL_LINE: OutOfMemory */ } p->filedes[0] = -1; @@ -68,8 +66,8 @@ static ares_pipeevent_t *ares_pipeevent_init(void) # ifdef HAVE_PIPE2 if (pipe2(p->filedes, O_NONBLOCK | O_CLOEXEC) != 0) { - ares_pipeevent_destroy(p); - return NULL; + ares_pipeevent_destroy(p); /* LCOV_EXCL_LINE: UntestablePath */ + return NULL; /* LCOV_EXCL_LINE: UntestablePath */ } # else if (pipe(p->filedes) != 0) { @@ -113,7 +111,7 @@ static void ares_pipeevent_signal(const ares_event_t *e) const ares_pipeevent_t *p; if (e == NULL || e->data == NULL) { - return; + return; /* LCOV_EXCL_LINE: DefensiveCoding */ } p = e->data; @@ -131,7 +129,7 @@ static void ares_pipeevent_cb(ares_event_thread_t *e, ares_socket_t fd, (void)flags; if (data == NULL) { - return; + return; /* LCOV_EXCL_LINE: DefensiveCoding */ } p = data; @@ -156,8 +154,8 @@ ares_event_t *ares_pipeevent_create(ares_event_thread_t *e) p->filedes[0], p, ares_pipeevent_destroy_cb, ares_pipeevent_signal); if (status != ARES_SUCCESS) { - ares_pipeevent_destroy(p); - return NULL; + ares_pipeevent_destroy(p); /* LCOV_EXCL_LINE: DefensiveCoding */ + return NULL; /* LCOV_EXCL_LINE: DefensiveCoding */ } return event; diff --git a/contrib/libs/c-ares/src/lib/event/ares_event_win32.c b/contrib/libs/c-ares/src/lib/event/ares_event_win32.c new file mode 100644 index 0000000000..0b7e535bbb --- /dev/null +++ b/contrib/libs/c-ares/src/lib/event/ares_event_win32.c @@ -0,0 +1,976 @@ +/* MIT License + * + * Copyright (c) 2024 Brad House + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * SPDX-License-Identifier: MIT + */ + +/* Uses an anonymous union */ +#if defined(__clang__) || defined(__GNUC__) +# pragma GCC diagnostic push +# if defined(__clang__) +# pragma GCC diagnostic ignored "-Wc11-extensions" +# else +# pragma GCC diagnostic ignored "-Wpedantic" +# endif +#endif + +#include "ares_private.h" +#include "ares_event.h" +#include "ares_event_win32.h" +#ifdef HAVE_LIMITS_H +# include <limits.h> +#endif + +#if defined(USE_WINSOCK) + +/* IMPLEMENTATION NOTES + * ==================== + * + * This implementation uses some undocumented functionality within Windows for + * monitoring sockets. The Ancillary Function Driver (AFD) is the low level + * implementation that Winsock2 sits on top of. Winsock2 unfortunately does + * not expose the equivalent of epoll() or kqueue(), but it is possible to + * access AFD directly and use along with IOCP to simulate the functionality. + * We want to use IOCP if possible as it gives us the ability to monitor more + * than just sockets (WSAPoll is not an option), and perform arbitrary callbacks + * which means we can hook in non-socket related events. + * + * The information for this implementation was gathered from "wepoll" and + * "libuv" which both use slight variants on this. We originally went with + * an implementation methodology more similar to "libuv", but we had a few + * user reports of crashes during shutdown and memory leaks due to some + * events not being delivered for cleanup of closed sockets. + * + * Initialization: + * 1. Dynamically load the NtDeviceIoControlFile, NtCreateFile, and + * NtCancelIoFileEx internal symbols from ntdll.dll. (Don't believe + * Microsoft's documentation for NtCancelIoFileEx as it documents an + * invalid prototype). These functions are to open a reference to the + * Ancillary Function Driver (AFD), and to submit and cancel POLL + * requests. + * 2. Create an IO Completion Port base handle via CreateIoCompletionPort() + * that all socket events will be delivered through. + * 3. Create a list of AFD Handles and track the number of poll requests + * per AFD handle. When we exceed a pre-determined limit of poll requests + * for a handle (128), we will automatically create a new handle. The + * reason behind this is NtCancelIoFileEx uses a horrible algorithm for + * issuing cancellations. See: + * https://github.com/python-trio/trio/issues/52#issuecomment-548215128 + * 4. Create a callback to be used to be able to interrupt waiting for IOCP + * events, this may be called for allowing enqueuing of additional socket + * events or removing socket events. PostQueuedCompletionStatus() is the + * obvious choice. We can use the same container format, the event + * delivered won't have an OVERLAPPED pointer so we can differentiate from + * socket events. Use the container as the completion key. + * + * Socket Add: + * 1. Create/Allocate a container for holding metadata about a socket + * including: + * - SOCKET base_socket; + * - IO_STATUS_BLOCK iosb; -- Used by AFD POLL, returned as OVERLAPPED + * - AFD_POLL_INFO afd_poll_info; -- Used by AFD POLL + * - afd list node -- for tracking which AFD handle a POLL request was + * submitted to. + * 2. Call WSAIoctl(..., SIO_BASE_HANDLE, ...) to unwrap the SOCKET and get + * the "base socket" we can use for polling. It appears this may fail so + * we should call WSAIoctl(..., SIO_BSP_HANDLE_POLL, ...) as a fallback. + * 3. Submit AFD POLL request (see "AFD POLL Request" section) + * 4. Record a mapping between the "IO Status Block" and the socket container + * so when events are delivered we can dereference. + * + * Socket Delete: + * 1. Call + * NtCancelIoFileEx(afd, iosb, &temp_iosb); + * to cancel any pending operations. + * 2. Tag the socket container as being queued for deletion + * 3. Wait for an event to be delivered for the socket (cancel isn't + * immediate, it delivers an event to know its complete). Delete only once + * that event has been delivered. If we don't do this we could try to + * access free()'d memory at a later point. + * + * Socket Modify: + * 1. Call + * NtCancelIoFileEx(afd, iosb, &temp_iosb) + * to cancel any pending operation. + * 2. When the event comes through that the cancel is complete, enqueue + * another "AFD Poll Request" for the desired events. + * + * Event Wait: + * 1. Call GetQueuedCompletionStatusEx() with the base IOCP handle, a + * stack allocated array of OVERLAPPED_ENTRY's, and an appropriate + * timeout. + * 2. Iterate across returned events, if the lpOverlapped is NULL, then the + * the CompletionKey is a pointer to the container registered via + * PostQueuedCompletionStatus(), otherwise it is the "IO Status Block" + * registered with the "AFD Poll Request" which needs to be dereferenced + * to the "socket container". + * 3. If it is a "socket container", disassociate it from the afd list node + * it was previously submitted to. + * 4. If it is a "socket container" check to see if we are cleaning up, if so, + * clean it up. + * 5. If it is a "socket container" that is still valid, Submit an + * AFD POLL Request (see "AFD POLL Request"). We must re-enable the request + * each time we receive a response, it is not persistent. + * 6. Notify of any events received as indicated in the AFD_POLL_INFO + * Handles[0].Events (NOTE: check NumberOfHandles > 0, and the status in + * the IO_STATUS_BLOCK. If we received an AFD_POLL_LOCAL_CLOSE, clean up + * the connection like the integrator requested it to be cleaned up. + * + * AFD Poll Request: + * 1. Find an afd poll handle in the list that has fewer pending requests than + * the limit. + * 2. If an afd poll handle was not associated (e.g. due to all being over + * limit), create a new afd poll handle by calling NtCreateFile() + * with path \Device\Afd , then add the AFD handle to the IO Completion + * Port. We can leave the completion key as blank since events for + * multiple sockets will be delivered through this and we need to + * differentiate via the OVERLAPPED member returned. Add the new AFD + * handle to the list of handles. + * 3. Initialize the AFD_POLL_INFO structure: + * Exclusive = FALSE; // allow multiple requests + * NumberOfHandles = 1; + * Timeout.QuadPart = LLONG_MAX; + * Handles[0].Handle = (HANDLE)base_socket; + * Handles[0].Status = 0; + * Handles[0].Events = AFD_POLL_LOCAL_CLOSE + additional events to wait for + * such as AFD_POLL_RECEIVE, etc; + * 4. Zero out the IO_STATUS_BLOCK structures + * 5. Set the "Status" member of IO_STATUS_BLOCK to STATUS_PENDING + * 6. Call + * NtDeviceIoControlFile(afd, NULL, NULL, &iosb, + * &iosb, IOCTL_AFD_POLL + * &afd_poll_info, sizeof(afd_poll_info), + * &afd_poll_info, sizeof(afd_poll_info)); + * + * + * References: + * - https://github.com/piscisaureus/wepoll/ + * - https://github.com/libuv/libuv/ + */ + +/* Cap the number of outstanding AFD poll requests per AFD handle due to known + * slowdowns with large lists and NtCancelIoFileEx() */ +# define AFD_POLL_PER_HANDLE 128 + +# include <stdarg.h> + +/* # define CARES_DEBUG 1 */ + +# ifdef __GNUC__ +# define CARES_PRINTF_LIKE(fmt, args) \ + __attribute__((format(printf, fmt, args))) +# else +# define CARES_PRINTF_LIKE(fmt, args) +# endif + +static void CARES_DEBUG_LOG(const char *fmt, ...) CARES_PRINTF_LIKE(1, 2); + +static void CARES_DEBUG_LOG(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); +# ifdef CARES_DEBUG + vfprintf(stderr, fmt, ap); + fflush(stderr); +# endif + va_end(ap); +} + +typedef struct { + /* Dynamically loaded symbols */ + NtCreateFile_t NtCreateFile; + NtDeviceIoControlFile_t NtDeviceIoControlFile; + NtCancelIoFileEx_t NtCancelIoFileEx; + + /* Implementation details */ + ares__slist_t *afd_handles; + HANDLE iocp_handle; + + /* IO_STATUS_BLOCK * -> ares_evsys_win32_eventdata_t * mapping. There is + * no completion key passed to IOCP with this method so we have to look + * up based on the lpOverlapped returned (which is mapped to IO_STATUS_BLOCK) + */ + ares__htable_vpvp_t *sockets; + + /* Flag about whether or not we are shutting down */ + ares_bool_t is_shutdown; +} ares_evsys_win32_t; + +typedef enum { + POLL_STATUS_NONE = 0, + POLL_STATUS_PENDING = 1, + POLL_STATUS_CANCEL = 2, + POLL_STATUS_DESTROY = 3 +} poll_status_t; + +typedef struct { + /*! Pointer to parent event container */ + ares_event_t *event; + /*! Socket passed in to monitor */ + SOCKET socket; + /*! Base socket derived from provided socket */ + SOCKET base_socket; + /*! Structure for submitting AFD POLL requests (Internals!) */ + AFD_POLL_INFO afd_poll_info; + /*! Status of current polling operation */ + poll_status_t poll_status; + /*! IO Status Block structure submitted with AFD POLL requests and returned + * with IOCP results as lpOverlapped (even though its a different structure) + */ + IO_STATUS_BLOCK iosb; + /*! AFD handle node an outstanding poll request is associated with */ + ares__slist_node_t *afd_handle_node; + /* Lock is only for PostQueuedCompletionStatus() to prevent multiple + * signals. Tracking via POLL_STATUS_PENDING/POLL_STATUS_NONE */ + ares__thread_mutex_t *lock; +} ares_evsys_win32_eventdata_t; + +static size_t ares_evsys_win32_wait(ares_event_thread_t *e, + unsigned long timeout_ms); + +static void ares_iocpevent_signal(const ares_event_t *event) +{ + ares_event_thread_t *e = event->e; + ares_evsys_win32_t *ew = e->ev_sys_data; + ares_evsys_win32_eventdata_t *ed = event->data; + ares_bool_t queue_event = ARES_FALSE; + + ares__thread_mutex_lock(ed->lock); + if (ed->poll_status != POLL_STATUS_PENDING) { + ed->poll_status = POLL_STATUS_PENDING; + queue_event = ARES_TRUE; + } + ares__thread_mutex_unlock(ed->lock); + + if (!queue_event) { + return; + } + + PostQueuedCompletionStatus(ew->iocp_handle, 0, (ULONG_PTR)event->data, NULL); +} + +static void ares_iocpevent_cb(ares_event_thread_t *e, ares_socket_t fd, + void *data, ares_event_flags_t flags) +{ + ares_evsys_win32_eventdata_t *ed = data; + (void)e; + (void)fd; + (void)flags; + ares__thread_mutex_lock(ed->lock); + ed->poll_status = POLL_STATUS_NONE; + ares__thread_mutex_unlock(ed->lock); +} + +static ares_event_t *ares_iocpevent_create(ares_event_thread_t *e) +{ + ares_event_t *event = NULL; + ares_status_t status; + + status = + ares_event_update(&event, e, ARES_EVENT_FLAG_OTHER, ares_iocpevent_cb, + ARES_SOCKET_BAD, NULL, NULL, ares_iocpevent_signal); + if (status != ARES_SUCCESS) { + return NULL; + } + + return event; +} + +static void ares_evsys_win32_destroy(ares_event_thread_t *e) +{ + ares_evsys_win32_t *ew = NULL; + + if (e == NULL) { + return; + } + + CARES_DEBUG_LOG("** Win32 Event Destroy\n"); + + ew = e->ev_sys_data; + if (ew == NULL) { + return; + } + + ew->is_shutdown = ARES_TRUE; + CARES_DEBUG_LOG(" ** waiting on %lu remaining sockets to be destroyed\n", + (unsigned long)ares__htable_vpvp_num_keys(ew->sockets)); + while (ares__htable_vpvp_num_keys(ew->sockets)) { + ares_evsys_win32_wait(e, 0); + } + CARES_DEBUG_LOG(" ** all sockets cleaned up\n"); + + + if (ew->iocp_handle != NULL) { + CloseHandle(ew->iocp_handle); + } + + ares__slist_destroy(ew->afd_handles); + + ares__htable_vpvp_destroy(ew->sockets); + + ares_free(ew); + e->ev_sys_data = NULL; +} + +typedef struct { + size_t poll_cnt; + HANDLE afd_handle; +} ares_afd_handle_t; + +static void ares_afd_handle_destroy(void *arg) +{ + ares_afd_handle_t *hnd = arg; + if (hnd != NULL && hnd->afd_handle != NULL) { + CloseHandle(hnd->afd_handle); + } + ares_free(hnd); +} + +static int ares_afd_handle_cmp(const void *data1, const void *data2) +{ + const ares_afd_handle_t *hnd1 = data1; + const ares_afd_handle_t *hnd2 = data2; + + if (hnd1->poll_cnt > hnd2->poll_cnt) { + return 1; + } + if (hnd1->poll_cnt < hnd2->poll_cnt) { + return -1; + } + return 0; +} + +static void fill_object_attributes(OBJECT_ATTRIBUTES *attr, + UNICODE_STRING *name, ULONG attributes) +{ + memset(attr, 0, sizeof(*attr)); + attr->Length = sizeof(*attr); + attr->ObjectName = name; + attr->Attributes = attributes; +} + +# define UNICODE_STRING_CONSTANT(s) \ + { (sizeof(s) - 1) * sizeof(wchar_t), sizeof(s) * sizeof(wchar_t), L##s } + +static ares__slist_node_t *ares_afd_handle_create(ares_evsys_win32_t *ew) +{ + UNICODE_STRING afd_device_name = UNICODE_STRING_CONSTANT("\\Device\\Afd"); + OBJECT_ATTRIBUTES afd_attributes; + NTSTATUS status; + IO_STATUS_BLOCK iosb; + ares_afd_handle_t *afd = ares_malloc_zero(sizeof(*afd)); + ares__slist_node_t *node = NULL; + if (afd == NULL) { + goto fail; + } + + /* Open a handle to the AFD subsystem */ + fill_object_attributes(&afd_attributes, &afd_device_name, 0); + memset(&iosb, 0, sizeof(iosb)); + iosb.Status = STATUS_PENDING; + status = ew->NtCreateFile(&afd->afd_handle, SYNCHRONIZE, &afd_attributes, + &iosb, NULL, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, + FILE_OPEN, 0, NULL, 0); + if (status != STATUS_SUCCESS) { + CARES_DEBUG_LOG("** Failed to create AFD endpoint\n"); + goto fail; + } + + if (CreateIoCompletionPort(afd->afd_handle, ew->iocp_handle, + 0 /* CompletionKey */, 0) == NULL) { + goto fail; + } + + if (!SetFileCompletionNotificationModes(afd->afd_handle, + FILE_SKIP_SET_EVENT_ON_HANDLE)) { + goto fail; + } + + node = ares__slist_insert(ew->afd_handles, afd); + if (node == NULL) { + goto fail; + } + + return node; + +fail: + + ares_afd_handle_destroy(afd); + return NULL; +} + +/* Fetch the lowest poll count entry, but if it exceeds the limit, create a + * new one and return that */ +static ares__slist_node_t *ares_afd_handle_fetch(ares_evsys_win32_t *ew) +{ + ares__slist_node_t *node = ares__slist_node_first(ew->afd_handles); + ares_afd_handle_t *afd = ares__slist_node_val(node); + + if (afd != NULL && afd->poll_cnt < AFD_POLL_PER_HANDLE) { + return node; + } + + return ares_afd_handle_create(ew); +} + +static ares_bool_t ares_evsys_win32_init(ares_event_thread_t *e) +{ + ares_evsys_win32_t *ew = NULL; + HMODULE ntdll; + + CARES_DEBUG_LOG("** Win32 Event Init\n"); + + ew = ares_malloc_zero(sizeof(*ew)); + if (ew == NULL) { + return ARES_FALSE; + } + + e->ev_sys_data = ew; + + /* All apps should have ntdll.dll already loaded, so just get a handle to + * this */ + ntdll = GetModuleHandleA("ntdll.dll"); + if (ntdll == NULL) { + goto fail; + } + +# ifdef __GNUC__ +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wpedantic" +/* Without the (void *) cast we get: + * warning: cast between incompatible function types from 'FARPROC' {aka 'long + * long int (*)()'} to 'NTSTATUS (*)(...)'} [-Wcast-function-type] but with it + * we get: warning: ISO C forbids conversion of function pointer to object + * pointer type [-Wpedantic] look unsolvable short of killing the warning. + */ +# endif + + /* Load Internal symbols not typically accessible */ + ew->NtCreateFile = + (NtCreateFile_t)(void *)GetProcAddress(ntdll, "NtCreateFile"); + ew->NtDeviceIoControlFile = (NtDeviceIoControlFile_t)(void *)GetProcAddress( + ntdll, "NtDeviceIoControlFile"); + ew->NtCancelIoFileEx = + (NtCancelIoFileEx_t)(void *)GetProcAddress(ntdll, "NtCancelIoFileEx"); + +# ifdef __GNUC__ +# pragma GCC diagnostic pop +# endif + + if (ew->NtCreateFile == NULL || ew->NtCancelIoFileEx == NULL || + ew->NtDeviceIoControlFile == NULL) { + goto fail; + } + + ew->iocp_handle = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0); + if (ew->iocp_handle == NULL) { + goto fail; + } + + ew->afd_handles = ares__slist_create( + e->channel->rand_state, ares_afd_handle_cmp, ares_afd_handle_destroy); + if (ew->afd_handles == NULL) { + goto fail; + } + + /* Create at least the first afd handle, so we know of any critical system + * issues during startup */ + if (ares_afd_handle_create(ew) == NULL) { + goto fail; + } + + e->ev_signal = ares_iocpevent_create(e); + if (e->ev_signal == NULL) { + goto fail; + } + + ew->sockets = ares__htable_vpvp_create(NULL, NULL); + if (ew->sockets == NULL) { + goto fail; + } + + return ARES_TRUE; + +fail: + ares_evsys_win32_destroy(e); + return ARES_FALSE; +} + +static ares_socket_t ares_evsys_win32_basesocket(ares_socket_t socket) +{ + while (1) { + DWORD bytes; /* Not used */ + ares_socket_t base_socket = ARES_SOCKET_BAD; + int rv; + + rv = WSAIoctl(socket, SIO_BASE_HANDLE, NULL, 0, &base_socket, + sizeof(base_socket), &bytes, NULL, NULL); + if (rv != SOCKET_ERROR && base_socket != ARES_SOCKET_BAD) { + socket = base_socket; + break; + } + + /* If we're here, an error occurred */ + if (GetLastError() == WSAENOTSOCK) { + /* This is critical, exit */ + return ARES_SOCKET_BAD; + } + + /* Work around known bug in Komodia based LSPs, use ARES_BSP_HANDLE_POLL + * to retrieve the underlying socket to then loop and get the base socket: + * https://docs.microsoft.com/en-us/windows/win32/winsock/winsock-ioctls + * https://www.komodia.com/newwiki/index.php?title=Komodia%27s_Redirector_bug_fixes#Version_2.2.2.6 + */ + base_socket = ARES_SOCKET_BAD; + rv = WSAIoctl(socket, SIO_BSP_HANDLE_POLL, NULL, 0, &base_socket, + sizeof(base_socket), &bytes, NULL, NULL); + + if (rv != SOCKET_ERROR && base_socket != ARES_SOCKET_BAD && + base_socket != socket) { + socket = base_socket; + continue; /* loop! */ + } + + return ARES_SOCKET_BAD; + } + + return socket; +} + +static ares_bool_t ares_evsys_win32_afd_enqueue(ares_event_t *event, + ares_event_flags_t flags) +{ + ares_event_thread_t *e = event->e; + ares_evsys_win32_t *ew = e->ev_sys_data; + ares_evsys_win32_eventdata_t *ed = event->data; + ares_afd_handle_t *afd; + NTSTATUS status; + + if (e == NULL || ed == NULL || ew == NULL) { + return ARES_FALSE; + } + + /* Misuse */ + if (ed->poll_status != POLL_STATUS_NONE) { + return ARES_FALSE; + } + + ed->afd_handle_node = ares_afd_handle_fetch(ew); + /* System resource issue? */ + if (ed->afd_handle_node == NULL) { + return ARES_FALSE; + } + + afd = ares__slist_node_val(ed->afd_handle_node); + + /* Enqueue AFD Poll */ + ed->afd_poll_info.Exclusive = FALSE; + ed->afd_poll_info.NumberOfHandles = 1; + ed->afd_poll_info.Timeout.QuadPart = LLONG_MAX; + ed->afd_poll_info.Handles[0].Handle = (HANDLE)ed->base_socket; + ed->afd_poll_info.Handles[0].Status = 0; + ed->afd_poll_info.Handles[0].Events = AFD_POLL_LOCAL_CLOSE; + + if (flags & ARES_EVENT_FLAG_READ) { + ed->afd_poll_info.Handles[0].Events |= + (AFD_POLL_RECEIVE | AFD_POLL_DISCONNECT | AFD_POLL_ACCEPT | + AFD_POLL_ABORT); + } + if (flags & ARES_EVENT_FLAG_WRITE) { + ed->afd_poll_info.Handles[0].Events |= + (AFD_POLL_SEND | AFD_POLL_CONNECT_FAIL); + } + if (flags == 0) { + ed->afd_poll_info.Handles[0].Events |= AFD_POLL_DISCONNECT; + } + + memset(&ed->iosb, 0, sizeof(ed->iosb)); + ed->iosb.Status = STATUS_PENDING; + + status = ew->NtDeviceIoControlFile( + afd->afd_handle, NULL, NULL, &ed->iosb, &ed->iosb, IOCTL_AFD_POLL, + &ed->afd_poll_info, sizeof(ed->afd_poll_info), &ed->afd_poll_info, + sizeof(ed->afd_poll_info)); + if (status != STATUS_SUCCESS && status != STATUS_PENDING) { + CARES_DEBUG_LOG("** afd_enqueue ed=%p FAILED\n", (void *)ed); + ed->afd_handle_node = NULL; + return ARES_FALSE; + } + + /* Record that we submitted a poll request to this handle and tell it to + * re-sort the node since we changed its sort value */ + afd->poll_cnt++; + ares__slist_node_reinsert(ed->afd_handle_node); + + ed->poll_status = POLL_STATUS_PENDING; + CARES_DEBUG_LOG("++ afd_enqueue ed=%p flags=%X\n", (void *)ed, + (unsigned int)flags); + return ARES_TRUE; +} + +static ares_bool_t ares_evsys_win32_afd_cancel(ares_evsys_win32_eventdata_t *ed) +{ + IO_STATUS_BLOCK cancel_iosb; + ares_evsys_win32_t *ew; + NTSTATUS status; + ares_afd_handle_t *afd; + + ew = ed->event->e->ev_sys_data; + + /* Misuse */ + if (ed->poll_status != POLL_STATUS_PENDING) { + return ARES_FALSE; + } + + afd = ares__slist_node_val(ed->afd_handle_node); + + /* Misuse */ + if (afd == NULL) { + return ARES_FALSE; + } + + ed->poll_status = POLL_STATUS_CANCEL; + + /* Not pending, nothing to do. Most likely that means there is a pending + * event that hasn't yet been delivered otherwise it would be re-armed + * already */ + if (ed->iosb.Status != STATUS_PENDING) { + CARES_DEBUG_LOG("** cancel not needed for ed=%p\n", (void *)ed); + return ARES_FALSE; + } + + status = ew->NtCancelIoFileEx(afd->afd_handle, &ed->iosb, &cancel_iosb); + + CARES_DEBUG_LOG("** Enqueued cancel for ed=%p, status = %lX\n", (void *)ed, + status); + + /* NtCancelIoFileEx() may return STATUS_NOT_FOUND if the operation completed + * just before calling NtCancelIoFileEx(), but we have not yet received the + * notifiction (but it should be queued for the next IOCP event). */ + if (status == STATUS_SUCCESS || status == STATUS_NOT_FOUND) { + return ARES_TRUE; + } + + return ARES_FALSE; +} + +static void ares_evsys_win32_eventdata_destroy(ares_evsys_win32_t *ew, + ares_evsys_win32_eventdata_t *ed) +{ + if (ew == NULL || ed == NULL) { + return; + } + CARES_DEBUG_LOG("-- deleting ed=%p (%s)\n", (void *)ed, + (ed->socket == ARES_SOCKET_BAD) ? "data" : "socket"); + /* These type of handles are deferred destroy. Update tracking. */ + if (ed->socket != ARES_SOCKET_BAD) { + ares__htable_vpvp_remove(ew->sockets, &ed->iosb); + } + + ares__thread_mutex_destroy(ed->lock); + + if (ed->event != NULL) { + ed->event->data = NULL; + } + + ares_free(ed); +} + +static ares_bool_t ares_evsys_win32_event_add(ares_event_t *event) +{ + ares_event_thread_t *e = event->e; + ares_evsys_win32_t *ew = e->ev_sys_data; + ares_evsys_win32_eventdata_t *ed; + ares_bool_t rc = ARES_FALSE; + + ed = ares_malloc_zero(sizeof(*ed)); + ed->event = event; + ed->socket = event->fd; + ed->base_socket = ARES_SOCKET_BAD; + event->data = ed; + + CARES_DEBUG_LOG("++ add ed=%p (%s) flags=%X\n", (void *)ed, + (ed->socket == ARES_SOCKET_BAD) ? "data" : "socket", + (unsigned int)event->flags); + + /* Likely a signal event, not something we will directly handle. We create + * the ares_evsys_win32_eventdata_t as the placeholder to use as the + * IOCP Completion Key */ + if (ed->socket == ARES_SOCKET_BAD) { + ed->lock = ares__thread_mutex_create(); + if (ed->lock == NULL) { + goto done; + } + rc = ARES_TRUE; + goto done; + } + + ed->base_socket = ares_evsys_win32_basesocket(ed->socket); + if (ed->base_socket == ARES_SOCKET_BAD) { + goto done; + } + + if (!ares__htable_vpvp_insert(ew->sockets, &ed->iosb, ed)) { + goto done; + } + + if (!ares_evsys_win32_afd_enqueue(event, event->flags)) { + goto done; + } + + rc = ARES_TRUE; + +done: + if (!rc) { + ares_evsys_win32_eventdata_destroy(ew, ed); + event->data = NULL; + } + return rc; +} + +static void ares_evsys_win32_event_del(ares_event_t *event) +{ + ares_evsys_win32_eventdata_t *ed = event->data; + + /* Already cleaned up, likely a LOCAL_CLOSE */ + if (ed == NULL) { + return; + } + + CARES_DEBUG_LOG("-- DELETE requested for ed=%p (%s)\n", (void *)ed, + (ed->socket != ARES_SOCKET_BAD) ? "socket" : "data"); + + /* + * Cancel pending AFD Poll operation. + */ + if (ed->socket != ARES_SOCKET_BAD) { + ares_evsys_win32_afd_cancel(ed); + ed->poll_status = POLL_STATUS_DESTROY; + ed->event = NULL; + } else { + ares_evsys_win32_eventdata_destroy(event->e->ev_sys_data, ed); + } + + event->data = NULL; +} + +static void ares_evsys_win32_event_mod(ares_event_t *event, + ares_event_flags_t new_flags) +{ + ares_evsys_win32_eventdata_t *ed = event->data; + + /* Not for us */ + if (event->fd == ARES_SOCKET_BAD || ed == NULL) { + return; + } + + CARES_DEBUG_LOG("** mod ed=%p new_flags=%X\n", (void *)ed, + (unsigned int)new_flags); + + /* All we need to do is cancel the pending operation. When the event gets + * delivered for the cancellation, it will automatically re-enqueue a new + * event */ + ares_evsys_win32_afd_cancel(ed); +} + +static ares_bool_t ares_evsys_win32_process_other_event( + ares_evsys_win32_t *ew, ares_evsys_win32_eventdata_t *ed, size_t i) +{ + ares_event_t *event; + + /* NOTE: do NOT dereference 'ed' if during shutdown as this could be an + * invalid pointer if the signal handle was cleaned up, but there was still a + * pending event! */ + + if (ew->is_shutdown) { + CARES_DEBUG_LOG("\t\t** i=%lu, skip non-socket handle during shutdown\n", + (unsigned long)i); + return ARES_FALSE; + } + + event = ed->event; + CARES_DEBUG_LOG("\t\t** i=%lu, ed=%p (data)\n", (unsigned long)i, (void *)ed); + + event->cb(event->e, event->fd, event->data, ARES_EVENT_FLAG_OTHER); + return ARES_TRUE; +} + +static ares_bool_t ares_evsys_win32_process_socket_event( + ares_evsys_win32_t *ew, ares_evsys_win32_eventdata_t *ed, size_t i) +{ + ares_event_flags_t flags = 0; + ares_event_t *event = NULL; + ares_afd_handle_t *afd = NULL; + + /* Shouldn't be possible */ + if (ed == NULL) { + CARES_DEBUG_LOG("\t\t** i=%lu, Invalid handle.\n", (unsigned long)i); + return ARES_FALSE; + } + + event = ed->event; + + CARES_DEBUG_LOG("\t\t** i=%lu, ed=%p (socket)\n", (unsigned long)i, + (void *)ed); + + /* Process events */ + if (ed->poll_status == POLL_STATUS_PENDING && + ed->iosb.Status == STATUS_SUCCESS && + ed->afd_poll_info.NumberOfHandles > 0) { + if (ed->afd_poll_info.Handles[0].Events & + (AFD_POLL_RECEIVE | AFD_POLL_DISCONNECT | AFD_POLL_ACCEPT | + AFD_POLL_ABORT)) { + flags |= ARES_EVENT_FLAG_READ; + } + if (ed->afd_poll_info.Handles[0].Events & + (AFD_POLL_SEND | AFD_POLL_CONNECT_FAIL)) { + flags |= ARES_EVENT_FLAG_WRITE; + } + if (ed->afd_poll_info.Handles[0].Events & AFD_POLL_LOCAL_CLOSE) { + CARES_DEBUG_LOG("\t\t** ed=%p LOCAL CLOSE\n", (void *)ed); + ed->poll_status = POLL_STATUS_DESTROY; + } + } + + CARES_DEBUG_LOG("\t\t** ed=%p, iosb status=%lX, poll_status=%d, flags=%X\n", + (void *)ed, (unsigned long)ed->iosb.Status, + (int)ed->poll_status, (unsigned int)flags); + + /* Decrement poll count for AFD handle then resort, also disassociate + * with socket */ + afd = ares__slist_node_val(ed->afd_handle_node); + afd->poll_cnt--; + ares__slist_node_reinsert(ed->afd_handle_node); + ed->afd_handle_node = NULL; + + /* Pending destroy, go ahead and kill it */ + if (ed->poll_status == POLL_STATUS_DESTROY) { + ares_evsys_win32_eventdata_destroy(ew, ed); + return ARES_FALSE; + } + + ed->poll_status = POLL_STATUS_NONE; + + /* Mask flags against current desired flags. We could have an event + * queued that is outdated. */ + flags &= event->flags; + + /* Don't actually do anything with the event that was delivered as we are + * in a shutdown/cleanup process. Mostly just handling the delayed + * destruction of sockets */ + if (ew->is_shutdown) { + return ARES_FALSE; + } + + /* Re-enqueue so we can get more events on the socket, we either + * received a real event, or a cancellation notice. Both cases we + * re-queue using the current configured event flags. + * + * If we can't re-enqueue, that likely means the socket has been + * closed, so we want to kill our reference to it + */ + if (!ares_evsys_win32_afd_enqueue(event, event->flags)) { + ares_evsys_win32_eventdata_destroy(ew, ed); + return ARES_FALSE; + } + + /* No events we recognize to deliver */ + if (flags == 0) { + return ARES_FALSE; + } + + event->cb(event->e, event->fd, event->data, flags); + return ARES_TRUE; +} + +static size_t ares_evsys_win32_wait(ares_event_thread_t *e, + unsigned long timeout_ms) +{ + ares_evsys_win32_t *ew = e->ev_sys_data; + OVERLAPPED_ENTRY entries[16]; + ULONG maxentries = sizeof(entries) / sizeof(*entries); + ULONG nentries; + BOOL status; + size_t i; + size_t cnt = 0; + DWORD tout = (timeout_ms == 0) ? INFINITE : (DWORD)timeout_ms; + + CARES_DEBUG_LOG("** Wait Enter\n"); + /* Process in a loop for as long as it fills the entire entries buffer, and + * on subsequent attempts, ensure the timeout is 0 */ + do { + nentries = maxentries; + status = GetQueuedCompletionStatusEx(ew->iocp_handle, entries, nentries, + &nentries, tout, FALSE); + + /* Next loop around, we want to return instantly if there are no events to + * be processed */ + tout = 0; + + if (!status) { + break; + } + + CARES_DEBUG_LOG("\t** GetQueuedCompletionStatusEx returned %lu entries\n", + (unsigned long)nentries); + for (i = 0; i < (size_t)nentries; i++) { + ares_evsys_win32_eventdata_t *ed = NULL; + ares_bool_t rc; + + /* For things triggered via PostQueuedCompletionStatus() we have an + * lpCompletionKey we can just use. Otherwise we need to dereference the + * pointer returned in lpOverlapped to determine the referenced + * socket */ + if (entries[i].lpCompletionKey) { + ed = (ares_evsys_win32_eventdata_t *)entries[i].lpCompletionKey; + rc = ares_evsys_win32_process_other_event(ew, ed, i); + } else { + ed = ares__htable_vpvp_get_direct(ew->sockets, entries[i].lpOverlapped); + rc = ares_evsys_win32_process_socket_event(ew, ed, i); + } + + /* We processed actual events */ + if (rc) { + cnt++; + } + } + } while (nentries == maxentries); + + CARES_DEBUG_LOG("** Wait Exit\n"); + + return cnt; +} + +const ares_event_sys_t ares_evsys_win32 = { "win32", + ares_evsys_win32_init, + ares_evsys_win32_destroy, + ares_evsys_win32_event_add, + ares_evsys_win32_event_del, + ares_evsys_win32_event_mod, + ares_evsys_win32_wait }; +#endif + +#if defined(__clang__) || defined(__GNUC__) +# pragma GCC diagnostic pop +#endif diff --git a/contrib/libs/c-ares/src/lib/ares_event_win32.h b/contrib/libs/c-ares/src/lib/event/ares_event_win32.h index 99cd5c90f3..5d0274cd85 100644 --- a/contrib/libs/c-ares/src/lib/ares_event_win32.h +++ b/contrib/libs/c-ares/src/lib/event/ares_event_win32.h @@ -67,17 +67,53 @@ typedef VOID(NTAPI *PIO_APC_ROUTINE)(PVOID ApcContext, # define STATUS_CANCELLED ((NTSTATUS)0xC0000120L) # define STATUS_NOT_FOUND ((NTSTATUS)0xC0000225L) +typedef struct _UNICODE_STRING { + USHORT Length; + USHORT MaximumLength; + LPCWSTR Buffer; +} UNICODE_STRING, *PUNICODE_STRING; + +typedef struct _OBJECT_ATTRIBUTES { + ULONG Length; + HANDLE RootDirectory; + PUNICODE_STRING ObjectName; + ULONG Attributes; + PVOID SecurityDescriptor; + PVOID SecurityQualityOfService; +} OBJECT_ATTRIBUTES, *POBJECT_ATTRIBUTES; + +# ifndef FILE_OPEN +# define FILE_OPEN 0x00000001UL +# endif + /* Not sure what headers might have these */ # define IOCTL_AFD_POLL 0x00012024 -# define AFD_POLL_RECEIVE 0x0001 -# define AFD_POLL_RECEIVE_EXPEDITED 0x0002 -# define AFD_POLL_SEND 0x0004 -# define AFD_POLL_DISCONNECT 0x0008 -# define AFD_POLL_ABORT 0x0010 -# define AFD_POLL_LOCAL_CLOSE 0x0020 -# define AFD_POLL_ACCEPT 0x0080 -# define AFD_POLL_CONNECT_FAIL 0x0100 +# define AFD_POLL_RECEIVE_BIT 0 +# define AFD_POLL_RECEIVE (1 << AFD_POLL_RECEIVE_BIT) +# define AFD_POLL_RECEIVE_EXPEDITED_BIT 1 +# define AFD_POLL_RECEIVE_EXPEDITED (1 << AFD_POLL_RECEIVE_EXPEDITED_BIT) +# define AFD_POLL_SEND_BIT 2 +# define AFD_POLL_SEND (1 << AFD_POLL_SEND_BIT) +# define AFD_POLL_DISCONNECT_BIT 3 +# define AFD_POLL_DISCONNECT (1 << AFD_POLL_DISCONNECT_BIT) +# define AFD_POLL_ABORT_BIT 4 +# define AFD_POLL_ABORT (1 << AFD_POLL_ABORT_BIT) +# define AFD_POLL_LOCAL_CLOSE_BIT 5 +# define AFD_POLL_LOCAL_CLOSE (1 << AFD_POLL_LOCAL_CLOSE_BIT) +# define AFD_POLL_CONNECT_BIT 6 +# define AFD_POLL_CONNECT (1 << AFD_POLL_CONNECT_BIT) +# define AFD_POLL_ACCEPT_BIT 7 +# define AFD_POLL_ACCEPT (1 << AFD_POLL_ACCEPT_BIT) +# define AFD_POLL_CONNECT_FAIL_BIT 8 +# define AFD_POLL_CONNECT_FAIL (1 << AFD_POLL_CONNECT_FAIL_BIT) +# define AFD_POLL_QOS_BIT 9 +# define AFD_POLL_QOS (1 << AFD_POLL_QOS_BIT) +# define AFD_POLL_GROUP_QOS_BIT 10 +# define AFD_POLL_GROUP_QOS (1 << AFD_POLL_GROUP_QOS_BIT) + +# define AFD_NUM_POLL_EVENTS 11 +# define AFD_POLL_ALL ((1 << AFD_NUM_POLL_EVENTS) - 1) typedef struct _AFD_POLL_HANDLE_INFO { HANDLE Handle; @@ -101,6 +137,12 @@ typedef NTSTATUS(NTAPI *NtDeviceIoControlFile_t)( PIO_STATUS_BLOCK IoStatusBlock, ULONG IoControlCode, PVOID InputBuffer, ULONG InputBufferLength, PVOID OutputBuffer, ULONG OutputBufferLength); +typedef NTSTATUS(NTAPI *NtCreateFile_t)( + PHANDLE FileHandle, ACCESS_MASK DesiredAccess, + POBJECT_ATTRIBUTES ObjectAttributes, PIO_STATUS_BLOCK IoStatusBlock, + PLARGE_INTEGER AllocationSize, ULONG FileAttributes, ULONG ShareAccess, + ULONG CreateDisposition, ULONG CreateOptions, PVOID EaBuffer, ULONG EaLength); + /* On UWP/Windows Store, these definitions aren't there for some reason */ # ifndef SIO_BSP_HANDLE_POLL # define SIO_BSP_HANDLE_POLL 0x4800001D diff --git a/contrib/libs/c-ares/src/lib/inet_net_pton.c b/contrib/libs/c-ares/src/lib/inet_net_pton.c index 19429f205d..5356778c47 100644 --- a/contrib/libs/c-ares/src/lib/inet_net_pton.c +++ b/contrib/libs/c-ares/src/lib/inet_net_pton.c @@ -18,7 +18,7 @@ * SPDX-License-Identifier: MIT */ -#include "ares_setup.h" +#include "ares_private.h" #ifdef HAVE_NETINET_IN_H # include <netinet/in.h> @@ -29,11 +29,8 @@ #include "ares_nameser.h" -#include "ares.h" #include "ares_ipv6.h" #include "ares_inet_net_pton.h" -#include "ares_private.h" - const struct ares_in6_addr ares_in6addr_any = { { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } }; @@ -72,17 +69,17 @@ static int ares_inet_net_pton_ipv4(const char *src, unsigned char *dst, const unsigned char *odst = dst; ch = *src++; - if (ch == '0' && (src[0] == 'x' || src[0] == 'X') && ISASCII(src[1]) && - ISXDIGIT(src[1])) { + if (ch == '0' && (src[0] == 'x' || src[0] == 'X') && ares__isascii(src[1]) && + ares__isxdigit(src[1])) { /* Hexadecimal: Eat nybble string. */ if (!size) { goto emsgsize; } dirty = 0; src++; /* skip x or X. */ - while ((ch = *src++) != '\0' && ISASCII(ch) && ISXDIGIT(ch)) { - if (ISUPPER(ch)) { - ch = tolower(ch); + while ((ch = *src++) != '\0' && ares__isascii(ch) && ares__isxdigit(ch)) { + if (ares__isupper(ch)) { + ch = ares__tolower((unsigned char)ch); } n = (int)(strchr(xdigits, ch) - xdigits); if (dirty == 0) { @@ -104,7 +101,7 @@ static int ares_inet_net_pton_ipv4(const char *src, unsigned char *dst, } *dst++ = (unsigned char)(tmp << 4); } - } else if (ISASCII(ch) && ISDIGIT(ch)) { + } else if (ares__isascii(ch) && ares__isdigit(ch)) { /* Decimal: eat dotted digit string. */ for (;;) { tmp = 0; @@ -115,7 +112,7 @@ static int ares_inet_net_pton_ipv4(const char *src, unsigned char *dst, if (tmp > 255) { goto enoent; } - } while ((ch = *src++) != '\0' && ISASCII(ch) && ISDIGIT(ch)); + } while ((ch = *src++) != '\0' && ares__isascii(ch) && ares__isdigit(ch)); if (!size--) { goto emsgsize; } @@ -127,7 +124,7 @@ static int ares_inet_net_pton_ipv4(const char *src, unsigned char *dst, goto enoent; } ch = *src++; - if (!ISASCII(ch) || !ISDIGIT(ch)) { + if (!ares__isascii(ch) || !ares__isdigit(ch)) { goto enoent; } } @@ -136,7 +133,8 @@ static int ares_inet_net_pton_ipv4(const char *src, unsigned char *dst, } bits = -1; - if (ch == '/' && ISASCII(src[0]) && ISDIGIT(src[0]) && dst > odst) { + if (ch == '/' && ares__isascii(src[0]) && ares__isdigit(src[0]) && + dst > odst) { /* CIDR width specifier. Nothing can follow it. */ ch = *src++; /* Skip over the /. */ bits = 0; @@ -147,7 +145,7 @@ static int ares_inet_net_pton_ipv4(const char *src, unsigned char *dst, if (bits > 32) { goto enoent; } - } while ((ch = *src++) != '\0' && ISASCII(ch) && ISDIGIT(ch)); + } while ((ch = *src++) != '\0' && ares__isascii(ch) && ares__isdigit(ch)); if (ch != '\0') { goto enoent; } diff --git a/contrib/libs/c-ares/src/lib/inet_ntop.c b/contrib/libs/c-ares/src/lib/inet_ntop.c index 622befa995..6f96b92ccc 100644 --- a/contrib/libs/c-ares/src/lib/inet_ntop.c +++ b/contrib/libs/c-ares/src/lib/inet_ntop.c @@ -17,7 +17,7 @@ * SPDX-License-Identifier: MIT */ -#include "ares_setup.h" +#include "ares_private.h" #ifdef HAVE_NETINET_IN_H # include <netinet/in.h> @@ -27,12 +27,7 @@ #endif #include "ares_nameser.h" - -#include "ares.h" #include "ares_ipv6.h" -#include "ares_private.h" - -#ifndef HAVE_INET_NTOP /* * WARNING: Don't even consider trying to compile this on a system where @@ -60,14 +55,14 @@ const char *ares_inet_ntop(int af, const void *src, char *dst, { switch (af) { case AF_INET: - return (inet_ntop4(src, dst, (size_t)size)); + return inet_ntop4(src, dst, (size_t)size); case AF_INET6: - return (inet_ntop6(src, dst, (size_t)size)); + return inet_ntop6(src, dst, (size_t)size); default: - SET_ERRNO(EAFNOSUPPORT); - return (NULL); + break; } - /* NOTREACHED */ + SET_ERRNO(EAFNOSUPPORT); + return NULL; } /* const char * @@ -86,13 +81,18 @@ static const char *inet_ntop4(const unsigned char *src, char *dst, size_t size) static const char fmt[] = "%u.%u.%u.%u"; char tmp[sizeof("255.255.255.255")]; + if (size < sizeof(tmp)) { + SET_ERRNO(ENOSPC); + return NULL; + } + if ((size_t)snprintf(tmp, sizeof(tmp), fmt, src[0], src[1], src[2], src[3]) >= size) { SET_ERRNO(ENOSPC); - return (NULL); + return NULL; } ares_strcpy(dst, tmp, size); - return (dst); + return dst; } /* const char * @@ -114,11 +114,12 @@ static const char *inet_ntop6(const unsigned char *src, char *dst, size_t size) char *tp; struct { - int base, len; + ares_ssize_t base; + size_t len; } best, cur; unsigned int words[NS_IN6ADDRSZ / NS_INT16SZ]; - int i; + size_t i; /* * Preprocess: @@ -136,7 +137,8 @@ static const char *inet_ntop6(const unsigned char *src, char *dst, size_t size) for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) { if (words[i] == 0) { if (cur.base == -1) { - cur.base = i, cur.len = 1; + cur.base = (ares_ssize_t)i; + cur.len = 1; } else { cur.len++; } @@ -164,8 +166,9 @@ static const char *inet_ntop6(const unsigned char *src, char *dst, size_t size) tp = tmp; for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) { /* Are we inside the best run of 0x00's? */ - if (best.base != -1 && i >= best.base && i < (best.base + best.len)) { - if (i == best.base) { + if (best.base != -1 && i >= (size_t)best.base && + i < ((size_t)best.base + best.len)) { + if (i == (size_t)best.base) { *tp++ = ':'; } continue; @@ -188,7 +191,7 @@ static const char *inet_ntop6(const unsigned char *src, char *dst, size_t size) } /* Was it a trailing run of 0x00's? */ if (best.base != -1 && - (best.base + best.len) == (NS_IN6ADDRSZ / NS_INT16SZ)) { + ((size_t)best.base + best.len) == (NS_IN6ADDRSZ / NS_INT16SZ)) { *tp++ = ':'; } *tp++ = '\0'; @@ -198,19 +201,8 @@ static const char *inet_ntop6(const unsigned char *src, char *dst, size_t size) */ if ((size_t)(tp - tmp) > size) { SET_ERRNO(ENOSPC); - return (NULL); + return NULL; } ares_strcpy(dst, tmp, size); - return (dst); -} - -#else /* HAVE_INET_NTOP */ - -const char *ares_inet_ntop(int af, const void *src, char *dst, - ares_socklen_t size) -{ - /* just relay this to the underlying function */ - return inet_ntop(af, src, dst, size); + return dst; } - -#endif /* HAVE_INET_NTOP */ diff --git a/contrib/libs/c-ares/src/lib/ares_create_query.c b/contrib/libs/c-ares/src/lib/legacy/ares_create_query.c index a2f2caac6e..f71a71c951 100644 --- a/contrib/libs/c-ares/src/lib/ares_create_query.c +++ b/contrib/libs/c-ares/src/lib/legacy/ares_create_query.c @@ -24,8 +24,6 @@ * SPDX-License-Identifier: MIT */ -#include "ares_setup.h" -#include "ares.h" #include "ares_private.h" static int ares_create_query_int(const char *name, int dnsclass, int type, diff --git a/contrib/libs/c-ares/src/lib/ares_expand_name.c b/contrib/libs/c-ares/src/lib/legacy/ares_expand_name.c index 280490b86a..63bd645166 100644 --- a/contrib/libs/c-ares/src/lib/ares_expand_name.c +++ b/contrib/libs/c-ares/src/lib/legacy/ares_expand_name.c @@ -25,7 +25,7 @@ * SPDX-License-Identifier: MIT */ -#include "ares_setup.h" +#include "ares_private.h" #ifdef HAVE_NETINET_IN_H # include <netinet/in.h> @@ -33,9 +33,6 @@ #include "ares_nameser.h" -#include "ares.h" -#include "ares_private.h" /* for the memdebug */ - ares_status_t ares__expand_name_validated(const unsigned char *encoded, const unsigned char *abuf, size_t alen, char **s, size_t *enclen, @@ -91,8 +88,8 @@ int ares_expand_name(const unsigned char *encoded, const unsigned char *abuf, size_t enclen_temp = 0; ares_status_t status; - if (alen < 0) { - return ARES_EBADRESP; + if (encoded == NULL || abuf == NULL || alen <= 0 || enclen == NULL) { + return ARES_EBADNAME; } status = ares__expand_name_validated(encoded, abuf, (size_t)alen, s, @@ -100,19 +97,3 @@ int ares_expand_name(const unsigned char *encoded, const unsigned char *abuf, *enclen = (long)enclen_temp; return (int)status; } - -/* Like ares_expand_name_validated but returns EBADRESP in case of invalid - * input. */ -ares_status_t ares__expand_name_for_response(const unsigned char *encoded, - const unsigned char *abuf, - size_t alen, char **s, - size_t *enclen, - ares_bool_t is_hostname) -{ - ares_status_t status = - ares__expand_name_validated(encoded, abuf, alen, s, enclen, is_hostname); - if (status == ARES_EBADNAME) { - status = ARES_EBADRESP; - } - return status; -} diff --git a/contrib/libs/c-ares/src/lib/ares_expand_string.c b/contrib/libs/c-ares/src/lib/legacy/ares_expand_string.c index be7034e271..b3e99daa54 100644 --- a/contrib/libs/c-ares/src/lib/ares_expand_string.c +++ b/contrib/libs/c-ares/src/lib/legacy/ares_expand_string.c @@ -25,7 +25,7 @@ * SPDX-License-Identifier: MIT */ -#include "ares_setup.h" +#include "ares_private.h" #ifdef HAVE_NETINET_IN_H # include <netinet/in.h> @@ -33,9 +33,6 @@ #include "ares_nameser.h" -#include "ares.h" -#include "ares_private.h" /* for the memdebug */ - /* Simply decodes a length-encoded character string. The first byte of the * input is the length of the string to be returned and the bytes thereafter * are the characters of the string. The returned result will be NULL @@ -77,8 +74,7 @@ ares_status_t ares_expand_string_ex(const unsigned char *encoded, } start_len = ares__buf_len(buf); - status = - ares__buf_parse_dns_binstr(buf, ares__buf_len(buf), s, &len, ARES_FALSE); + status = ares__buf_parse_dns_binstr(buf, ares__buf_len(buf), s, &len); /* hrm, no way to pass back 'len' with the prototype */ if (status != ARES_SUCCESS) { goto done; @@ -100,7 +96,7 @@ int ares_expand_string(const unsigned char *encoded, const unsigned char *abuf, ares_status_t status; size_t temp_enclen = 0; - if (alen < 0) { + if (encoded == NULL || abuf == NULL || alen <= 0 || enclen == NULL) { return ARES_EBADRESP; } diff --git a/contrib/libs/c-ares/src/lib/ares_fds.c b/contrib/libs/c-ares/src/lib/legacy/ares_fds.c index e39823304a..3aedd2c90e 100644 --- a/contrib/libs/c-ares/src/lib/ares_fds.c +++ b/contrib/libs/c-ares/src/lib/legacy/ares_fds.c @@ -25,9 +25,6 @@ * SPDX-License-Identifier: MIT */ -#include "ares_setup.h" - -#include "ares.h" #include "ares_private.h" int ares_fds(const ares_channel_t *channel, fd_set *read_fds, fd_set *write_fds) @@ -48,14 +45,14 @@ int ares_fds(const ares_channel_t *channel, fd_set *read_fds, fd_set *write_fds) nfds = 0; for (snode = ares__slist_node_first(channel->servers); snode != NULL; snode = ares__slist_node_next(snode)) { - struct server_state *server = ares__slist_node_val(snode); - ares__llist_node_t *node; + ares_server_t *server = ares__slist_node_val(snode); + ares__llist_node_t *node; for (node = ares__llist_node_first(server->connections); node != NULL; node = ares__llist_node_next(node)) { - const struct server_connection *conn = ares__llist_node_val(node); + const ares_conn_t *conn = ares__llist_node_val(node); - if (!active_queries && !conn->is_tcp) { + if (!active_queries && !(conn->flags & ARES_CONN_FLAG_TCP)) { continue; } @@ -72,7 +69,7 @@ int ares_fds(const ares_channel_t *channel, fd_set *read_fds, fd_set *write_fds) } /* TCP only wait on write if we have buffered data */ - if (conn->is_tcp && ares__buf_len(server->tcp_send)) { + if (conn->flags & ARES_CONN_FLAG_TCP && ares__buf_len(server->tcp_send)) { FD_SET(conn->fd, write_fds); } } diff --git a/contrib/libs/c-ares/src/lib/ares_getsock.c b/contrib/libs/c-ares/src/lib/legacy/ares_getsock.c index b64c075572..8c8476fa95 100644 --- a/contrib/libs/c-ares/src/lib/ares_getsock.c +++ b/contrib/libs/c-ares/src/lib/legacy/ares_getsock.c @@ -24,9 +24,6 @@ * SPDX-License-Identifier: MIT */ -#include "ares_setup.h" - -#include "ares.h" #include "ares_private.h" int ares_getsock(const ares_channel_t *channel, ares_socket_t *socks, @@ -50,12 +47,12 @@ int ares_getsock(const ares_channel_t *channel, ares_socket_t *socks, for (snode = ares__slist_node_first(channel->servers); snode != NULL; snode = ares__slist_node_next(snode)) { - struct server_state *server = ares__slist_node_val(snode); - ares__llist_node_t *node; + ares_server_t *server = ares__slist_node_val(snode); + ares__llist_node_t *node; for (node = ares__llist_node_first(server->connections); node != NULL; node = ares__llist_node_next(node)) { - const struct server_connection *conn = ares__llist_node_val(node); + const ares_conn_t *conn = ares__llist_node_val(node); if (sockindex >= (size_t)numsocks || sockindex >= ARES_GETSOCK_MAXNUM) { break; @@ -64,17 +61,17 @@ int ares_getsock(const ares_channel_t *channel, ares_socket_t *socks, /* We only need to register interest in UDP sockets if we have * outstanding queries. */ - if (!active_queries && !conn->is_tcp) { + if (!active_queries && !(conn->flags & ARES_CONN_FLAG_TCP)) { continue; } socks[sockindex] = conn->fd; - if (active_queries || conn->is_tcp) { + if (active_queries || conn->flags & ARES_CONN_FLAG_TCP) { bitmap |= ARES_GETSOCK_READABLE(setbits, sockindex); } - if (conn->is_tcp && ares__buf_len(server->tcp_send)) { + if (conn->flags & ARES_CONN_FLAG_TCP && ares__buf_len(server->tcp_send)) { /* then the tcp socket is also writable! */ bitmap |= ARES_GETSOCK_WRITABLE(setbits, sockindex); } diff --git a/contrib/libs/c-ares/src/lib/ares_parse_a_reply.c b/contrib/libs/c-ares/src/lib/legacy/ares_parse_a_reply.c index da841f0da9..0981b90eea 100644 --- a/contrib/libs/c-ares/src/lib/ares_parse_a_reply.c +++ b/contrib/libs/c-ares/src/lib/legacy/ares_parse_a_reply.c @@ -25,7 +25,7 @@ * SPDX-License-Identifier: MIT */ -#include "ares_setup.h" +#include "ares_private.h" #ifdef HAVE_NETINET_IN_H # include <netinet/in.h> @@ -37,8 +37,6 @@ # include <arpa/inet.h> #endif -#include "ares_nameser.h" - #ifdef HAVE_STRINGS_H # include <strings.h> #endif @@ -47,10 +45,6 @@ # include <limits.h> #endif -#include "ares.h" -#include "ares_dns.h" -#include "ares_private.h" - int ares_parse_a_reply(const unsigned char *abuf, int alen, struct hostent **host, struct ares_addrttl *addrttls, int *naddrttls) @@ -85,7 +79,7 @@ int ares_parse_a_reply(const unsigned char *abuf, int alen, if (host != NULL) { status = ares__addrinfo2hostent(&ai, AF_INET, host); if (status != ARES_SUCCESS && status != ARES_ENODATA) { - goto fail; + goto fail; /* LCOV_EXCL_LINE: DefensiveCoding */ } } diff --git a/contrib/libs/c-ares/src/lib/ares_parse_aaaa_reply.c b/contrib/libs/c-ares/src/lib/legacy/ares_parse_aaaa_reply.c index b3eba166be..3f6932643b 100644 --- a/contrib/libs/c-ares/src/lib/ares_parse_aaaa_reply.c +++ b/contrib/libs/c-ares/src/lib/legacy/ares_parse_aaaa_reply.c @@ -26,7 +26,7 @@ * SPDX-License-Identifier: MIT */ -#include "ares_setup.h" +#include "ares_private.h" #ifdef HAVE_NETINET_IN_H # include <netinet/in.h> @@ -38,8 +38,6 @@ # include <arpa/inet.h> #endif -#include "ares_nameser.h" - #ifdef HAVE_STRINGS_H # include <strings.h> #endif @@ -48,10 +46,7 @@ # include <limits.h> #endif -#include "ares.h" -#include "ares_dns.h" #include "ares_inet_net_pton.h" -#include "ares_private.h" int ares_parse_aaaa_reply(const unsigned char *abuf, int alen, struct hostent **host, struct ares_addr6ttl *addrttls, @@ -87,7 +82,7 @@ int ares_parse_aaaa_reply(const unsigned char *abuf, int alen, if (host != NULL) { status = ares__addrinfo2hostent(&ai, AF_INET6, host); if (status != ARES_SUCCESS && status != ARES_ENODATA) { - goto fail; + goto fail; /* LCOV_EXCL_LINE: DefensiveCoding */ } } diff --git a/contrib/libs/c-ares/src/lib/ares_parse_caa_reply.c b/contrib/libs/c-ares/src/lib/legacy/ares_parse_caa_reply.c index 6c30305ee1..f74358f456 100644 --- a/contrib/libs/c-ares/src/lib/ares_parse_caa_reply.c +++ b/contrib/libs/c-ares/src/lib/legacy/ares_parse_caa_reply.c @@ -24,10 +24,8 @@ * SPDX-License-Identifier: MIT */ -#include "ares_setup.h" -#include "ares.h" -#include "ares_data.h" #include "ares_private.h" +#include "ares_data.h" int ares_parse_caa_reply(const unsigned char *abuf, int alen_int, struct ares_caa_reply **caa_out) @@ -66,8 +64,8 @@ int ares_parse_caa_reply(const unsigned char *abuf, int alen_int, if (rr == NULL) { /* Shouldn't be possible */ - status = ARES_EBADRESP; - goto done; + status = ARES_EBADRESP; /* LCOV_EXCL_LINE: DefensiveCoding */ + goto done; /* LCOV_EXCL_LINE: DefensiveCoding */ } /* XXX: Why do we allow Chaos class? */ @@ -84,8 +82,8 @@ int ares_parse_caa_reply(const unsigned char *abuf, int alen_int, /* Allocate storage for this CAA answer appending it to the list */ caa_curr = ares_malloc_data(ARES_DATATYPE_CAA_REPLY); if (caa_curr == NULL) { - status = ARES_ENOMEM; - goto done; + status = ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ + goto done; /* LCOV_EXCL_LINE: OutOfMemory */ } /* Link in the record */ @@ -100,8 +98,8 @@ int ares_parse_caa_reply(const unsigned char *abuf, int alen_int, caa_curr->property = (unsigned char *)ares_strdup(ares_dns_rr_get_str(rr, ARES_RR_CAA_TAG)); if (caa_curr->property == NULL) { - status = ARES_ENOMEM; - break; + status = ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ + break; /* LCOV_EXCL_LINE: OutOfMemory */ } /* RFC6844 says this can only be ascii, so not sure why we're recording a * length */ @@ -109,15 +107,15 @@ int ares_parse_caa_reply(const unsigned char *abuf, int alen_int, ptr = ares_dns_rr_get_bin(rr, ARES_RR_CAA_VALUE, &ptr_len); if (ptr == NULL) { - status = ARES_EBADRESP; - goto done; + status = ARES_EBADRESP; /* LCOV_EXCL_LINE: DefensiveCoding */ + goto done; /* LCOV_EXCL_LINE: DefensiveCoding */ } /* Wants NULL termination for some reason */ caa_curr->value = ares_malloc(ptr_len + 1); if (caa_curr->value == NULL) { - status = ARES_ENOMEM; - goto done; + status = ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ + goto done; /* LCOV_EXCL_LINE: OutOfMemory */ } memcpy(caa_curr->value, ptr, ptr_len); caa_curr->value[ptr_len] = 0; diff --git a/contrib/libs/c-ares/src/lib/ares_parse_mx_reply.c b/contrib/libs/c-ares/src/lib/legacy/ares_parse_mx_reply.c index db7155d2e8..480074f670 100644 --- a/contrib/libs/c-ares/src/lib/ares_parse_mx_reply.c +++ b/contrib/libs/c-ares/src/lib/legacy/ares_parse_mx_reply.c @@ -24,10 +24,8 @@ * SPDX-License-Identifier: MIT */ -#include "ares_setup.h" -#include "ares.h" -#include "ares_data.h" #include "ares_private.h" +#include "ares_data.h" int ares_parse_mx_reply(const unsigned char *abuf, int alen_int, struct ares_mx_reply **mx_out) @@ -64,8 +62,8 @@ int ares_parse_mx_reply(const unsigned char *abuf, int alen_int, if (rr == NULL) { /* Shouldn't be possible */ - status = ARES_EBADRESP; - goto done; + status = ARES_EBADRESP; /* LCOV_EXCL_LINE: DefensiveCoding */ + goto done; /* LCOV_EXCL_LINE: DefensiveCoding */ } if (ares_dns_rr_get_class(rr) != ARES_CLASS_IN || @@ -76,8 +74,8 @@ int ares_parse_mx_reply(const unsigned char *abuf, int alen_int, /* Allocate storage for this MX answer appending it to the list */ mx_curr = ares_malloc_data(ARES_DATATYPE_MX_REPLY); if (mx_curr == NULL) { - status = ARES_ENOMEM; - goto done; + status = ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ + goto done; /* LCOV_EXCL_LINE: OutOfMemory */ } /* Link in the record */ @@ -92,8 +90,8 @@ int ares_parse_mx_reply(const unsigned char *abuf, int alen_int, mx_curr->host = ares_strdup(ares_dns_rr_get_str(rr, ARES_RR_MX_EXCHANGE)); if (mx_curr->host == NULL) { - status = ARES_ENOMEM; - goto done; + status = ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ + goto done; /* LCOV_EXCL_LINE: OutOfMemory */ } } diff --git a/contrib/libs/c-ares/src/lib/ares_parse_naptr_reply.c b/contrib/libs/c-ares/src/lib/legacy/ares_parse_naptr_reply.c index 1a304ccdd3..c00ce71066 100644 --- a/contrib/libs/c-ares/src/lib/ares_parse_naptr_reply.c +++ b/contrib/libs/c-ares/src/lib/legacy/ares_parse_naptr_reply.c @@ -23,10 +23,8 @@ * * SPDX-License-Identifier: MIT */ -#include "ares_setup.h" -#include "ares.h" -#include "ares_data.h" #include "ares_private.h" +#include "ares_data.h" int ares_parse_naptr_reply(const unsigned char *abuf, int alen_int, struct ares_naptr_reply **naptr_out) @@ -63,8 +61,8 @@ int ares_parse_naptr_reply(const unsigned char *abuf, int alen_int, if (rr == NULL) { /* Shouldn't be possible */ - status = ARES_EBADRESP; - goto done; + status = ARES_EBADRESP; /* LCOV_EXCL_LINE: DefensiveCoding */ + goto done; /* LCOV_EXCL_LINE: DefensiveCoding */ } if (ares_dns_rr_get_class(rr) != ARES_CLASS_IN || @@ -75,8 +73,8 @@ int ares_parse_naptr_reply(const unsigned char *abuf, int alen_int, /* Allocate storage for this NAPTR answer appending it to the list */ naptr_curr = ares_malloc_data(ARES_DATATYPE_NAPTR_REPLY); if (naptr_curr == NULL) { - status = ARES_ENOMEM; - goto done; + status = ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ + goto done; /* LCOV_EXCL_LINE: OutOfMemory */ } /* Link in the record */ @@ -94,28 +92,28 @@ int ares_parse_naptr_reply(const unsigned char *abuf, int alen_int, naptr_curr->flags = (unsigned char *)ares_strdup( ares_dns_rr_get_str(rr, ARES_RR_NAPTR_FLAGS)); if (naptr_curr->flags == NULL) { - status = ARES_ENOMEM; - goto done; + status = ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ + goto done; /* LCOV_EXCL_LINE: OutOfMemory */ } /* XXX: Why is this unsigned char * ? */ naptr_curr->service = (unsigned char *)ares_strdup( ares_dns_rr_get_str(rr, ARES_RR_NAPTR_SERVICES)); if (naptr_curr->service == NULL) { - status = ARES_ENOMEM; - goto done; + status = ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ + goto done; /* LCOV_EXCL_LINE: OutOfMemory */ } /* XXX: Why is this unsigned char * ? */ naptr_curr->regexp = (unsigned char *)ares_strdup( ares_dns_rr_get_str(rr, ARES_RR_NAPTR_REGEXP)); if (naptr_curr->regexp == NULL) { - status = ARES_ENOMEM; - goto done; + status = ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ + goto done; /* LCOV_EXCL_LINE: OutOfMemory */ } naptr_curr->replacement = ares_strdup(ares_dns_rr_get_str(rr, ARES_RR_NAPTR_REPLACEMENT)); if (naptr_curr->replacement == NULL) { - status = ARES_ENOMEM; - goto done; + status = ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ + goto done; /* LCOV_EXCL_LINE: OutOfMemory */ } } diff --git a/contrib/libs/c-ares/src/lib/ares_parse_ns_reply.c b/contrib/libs/c-ares/src/lib/legacy/ares_parse_ns_reply.c index 18fda82f41..fc9ab9219d 100644 --- a/contrib/libs/c-ares/src/lib/ares_parse_ns_reply.c +++ b/contrib/libs/c-ares/src/lib/legacy/ares_parse_ns_reply.c @@ -24,7 +24,7 @@ * SPDX-License-Identifier: MIT */ -#include "ares_setup.h" +#include "ares_private.h" #ifdef HAVE_NETINET_IN_H # include <netinet/in.h> @@ -36,9 +36,6 @@ # include <arpa/inet.h> #endif -#include "ares.h" -#include "ares_private.h" - int ares_parse_ns_reply(const unsigned char *abuf, int alen_int, struct hostent **host) { @@ -73,16 +70,16 @@ int ares_parse_ns_reply(const unsigned char *abuf, int alen_int, /* Response structure */ hostent = ares_malloc(sizeof(*hostent)); if (hostent == NULL) { - status = ARES_ENOMEM; - goto done; + status = ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ + goto done; /* LCOV_EXCL_LINE: OutOfMemory */ } memset(hostent, 0, sizeof(*hostent)); hostent->h_addr_list = ares_malloc(sizeof(*hostent->h_addr_list)); if (hostent->h_addr_list == NULL) { - status = ARES_ENOMEM; - goto done; + status = ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ + goto done; /* LCOV_EXCL_LINE: OutOfMemory */ } hostent->h_addr_list[0] = NULL; hostent->h_addrtype = AF_INET; @@ -91,19 +88,19 @@ int ares_parse_ns_reply(const unsigned char *abuf, int alen_int, /* Fill in hostname */ status = ares_dns_record_query_get(dnsrec, 0, &hostname, NULL, NULL); if (status != ARES_SUCCESS) { - goto done; + goto done; /* LCOV_EXCL_LINE: DefensiveCoding */ } hostent->h_name = ares_strdup(hostname); if (hostent->h_name == NULL) { - status = ARES_ENOMEM; - goto done; + status = ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ + goto done; /* LCOV_EXCL_LINE: OutOfMemory */ } /* Preallocate the maximum number + 1 */ hostent->h_aliases = ares_malloc((ancount + 1) * sizeof(*hostent->h_aliases)); if (hostent->h_aliases == NULL) { - status = ARES_ENOMEM; - goto done; + status = ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ + goto done; /* LCOV_EXCL_LINE: OutOfMemory */ } memset(hostent->h_aliases, 0, (ancount + 1) * sizeof(*hostent->h_aliases)); @@ -113,8 +110,8 @@ int ares_parse_ns_reply(const unsigned char *abuf, int alen_int, if (rr == NULL) { /* Shouldn't be possible */ - status = ARES_EBADRESP; - goto done; + status = ARES_EBADRESP; /* LCOV_EXCL_LINE: DefensiveCoding */ + goto done; /* LCOV_EXCL_LINE: DefensiveCoding */ } if (ares_dns_rr_get_class(rr) != ARES_CLASS_IN || @@ -124,8 +121,8 @@ int ares_parse_ns_reply(const unsigned char *abuf, int alen_int, hostname = ares_dns_rr_get_str(rr, ARES_RR_NS_NSDNAME); if (hostname == NULL) { - status = ARES_EBADRESP; - goto done; + status = ARES_EBADRESP; /* LCOV_EXCL_LINE: DefensiveCoding */ + goto done; /* LCOV_EXCL_LINE: DefensiveCoding */ } hostent->h_aliases[nscount] = ares_strdup(hostname); diff --git a/contrib/libs/c-ares/src/lib/ares_parse_ptr_reply.c b/contrib/libs/c-ares/src/lib/legacy/ares_parse_ptr_reply.c index 6ee20f722e..56a7b5f94e 100644 --- a/contrib/libs/c-ares/src/lib/ares_parse_ptr_reply.c +++ b/contrib/libs/c-ares/src/lib/legacy/ares_parse_ptr_reply.c @@ -24,7 +24,7 @@ * SPDX-License-Identifier: MIT */ -#include "ares_setup.h" +#include "ares_private.h" #ifdef HAVE_NETINET_IN_H # include <netinet/in.h> @@ -33,8 +33,6 @@ # include <netdb.h> #endif -#include "ares.h" -#include "ares_private.h" ares_status_t ares_parse_ptr_reply_dnsrec(const ares_dns_record_t *dnsrec, const void *addr, int addrlen, @@ -105,8 +103,8 @@ ares_status_t ares_parse_ptr_reply_dnsrec(const ares_dns_record_t *dnsrec, if (rr == NULL) { /* Shouldn't be possible */ - status = ARES_EBADRESP; - goto done; + status = ARES_EBADRESP; /* LCOV_EXCL_LINE: DefensiveCoding */ + goto done; /* LCOV_EXCL_LINE: DefensiveCoding */ } if (ares_dns_rr_get_class(rr) != ARES_CLASS_IN) { @@ -117,8 +115,8 @@ ares_status_t ares_parse_ptr_reply_dnsrec(const ares_dns_record_t *dnsrec, if (ares_dns_rr_get_type(rr) == ARES_REC_TYPE_CNAME) { ptrname = ares_dns_rr_get_str(rr, ARES_RR_CNAME_CNAME); if (ptrname == NULL) { - status = ARES_EBADRESP; - goto done; + status = ARES_EBADRESP; /* LCOV_EXCL_LINE: DefensiveCoding */ + goto done; /* LCOV_EXCL_LINE: DefensiveCoding */ } } @@ -145,8 +143,8 @@ ares_status_t ares_parse_ptr_reply_dnsrec(const ares_dns_record_t *dnsrec, /* Save most recent PTR record as the hostname */ hostname = ares_dns_rr_get_str(rr, ARES_RR_PTR_DNAME); if (hostname == NULL) { - status = ARES_EBADRESP; - goto done; + status = ARES_EBADRESP; /* LCOV_EXCL_LINE: DefensiveCoding */ + goto done; /* LCOV_EXCL_LINE: DefensiveCoding */ } /* Append as an alias */ @@ -168,8 +166,8 @@ ares_status_t ares_parse_ptr_reply_dnsrec(const ares_dns_record_t *dnsrec, /* Fill in hostname */ hostent->h_name = ares_strdup(hostname); if (hostent->h_name == NULL) { - status = ARES_ENOMEM; - goto done; + status = ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ + goto done; /* LCOV_EXCL_LINE: OutOfMemory */ } done: diff --git a/contrib/libs/c-ares/src/lib/ares_parse_soa_reply.c b/contrib/libs/c-ares/src/lib/legacy/ares_parse_soa_reply.c index 2777dbcb0b..46b40dedc4 100644 --- a/contrib/libs/c-ares/src/lib/ares_parse_soa_reply.c +++ b/contrib/libs/c-ares/src/lib/legacy/ares_parse_soa_reply.c @@ -24,10 +24,8 @@ * SPDX-License-Identifier: MIT */ -#include "ares_setup.h" -#include "ares.h" -#include "ares_data.h" #include "ares_private.h" +#include "ares_data.h" int ares_parse_soa_reply(const unsigned char *abuf, int alen_int, struct ares_soa_reply **soa_out) @@ -62,8 +60,8 @@ int ares_parse_soa_reply(const unsigned char *abuf, int alen_int, if (rr == NULL) { /* Shouldn't be possible */ - status = ARES_EBADRESP; - goto done; + status = ARES_EBADRESP; /* LCOV_EXCL_LINE: DefensiveCoding */ + goto done; /* LCOV_EXCL_LINE: DefensiveCoding */ } if (ares_dns_rr_get_class(rr) != ARES_CLASS_IN || @@ -74,8 +72,8 @@ int ares_parse_soa_reply(const unsigned char *abuf, int alen_int, /* allocate result struct */ soa = ares_malloc_data(ARES_DATATYPE_SOA_REPLY); if (soa == NULL) { - status = ARES_ENOMEM; - goto done; + status = ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ + goto done; /* LCOV_EXCL_LINE: OutOfMemory */ } soa->serial = ares_dns_rr_get_u32(rr, ARES_RR_SOA_SERIAL); @@ -85,13 +83,13 @@ int ares_parse_soa_reply(const unsigned char *abuf, int alen_int, soa->minttl = ares_dns_rr_get_u32(rr, ARES_RR_SOA_MINIMUM); soa->nsname = ares_strdup(ares_dns_rr_get_str(rr, ARES_RR_SOA_MNAME)); if (soa->nsname == NULL) { - status = ARES_ENOMEM; - goto done; + status = ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ + goto done; /* LCOV_EXCL_LINE: OutOfMemory */ } soa->hostmaster = ares_strdup(ares_dns_rr_get_str(rr, ARES_RR_SOA_RNAME)); if (soa->hostmaster == NULL) { - status = ARES_ENOMEM; - goto done; + status = ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ + goto done; /* LCOV_EXCL_LINE: OutOfMemory */ } break; } diff --git a/contrib/libs/c-ares/src/lib/ares_parse_srv_reply.c b/contrib/libs/c-ares/src/lib/legacy/ares_parse_srv_reply.c index f27bcce733..3f9fd95ebf 100644 --- a/contrib/libs/c-ares/src/lib/ares_parse_srv_reply.c +++ b/contrib/libs/c-ares/src/lib/legacy/ares_parse_srv_reply.c @@ -24,10 +24,8 @@ * SPDX-License-Identifier: MIT */ -#include "ares_setup.h" -#include "ares.h" -#include "ares_data.h" #include "ares_private.h" +#include "ares_data.h" int ares_parse_srv_reply(const unsigned char *abuf, int alen_int, struct ares_srv_reply **srv_out) @@ -64,8 +62,8 @@ int ares_parse_srv_reply(const unsigned char *abuf, int alen_int, if (rr == NULL) { /* Shouldn't be possible */ - status = ARES_EBADRESP; - goto done; + status = ARES_EBADRESP; /* LCOV_EXCL_LINE: DefensiveCoding */ + goto done; /* LCOV_EXCL_LINE: DefensiveCoding */ } if (ares_dns_rr_get_class(rr) != ARES_CLASS_IN || @@ -76,8 +74,8 @@ int ares_parse_srv_reply(const unsigned char *abuf, int alen_int, /* Allocate storage for this SRV answer appending it to the list */ srv_curr = ares_malloc_data(ARES_DATATYPE_SRV_REPLY); if (srv_curr == NULL) { - status = ARES_ENOMEM; - goto done; + status = ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ + goto done; /* LCOV_EXCL_LINE: OutOfMemory */ } /* Link in the record */ @@ -96,8 +94,8 @@ int ares_parse_srv_reply(const unsigned char *abuf, int alen_int, srv_curr->host = ares_strdup(ares_dns_rr_get_str(rr, ARES_RR_SRV_TARGET)); if (srv_curr->host == NULL) { - status = ARES_ENOMEM; - goto done; + status = ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ + goto done; /* LCOV_EXCL_LINE: OutOfMemory */ } } diff --git a/contrib/libs/c-ares/src/lib/ares_parse_txt_reply.c b/contrib/libs/c-ares/src/lib/legacy/ares_parse_txt_reply.c index 85c3644b8c..71ee084111 100644 --- a/contrib/libs/c-ares/src/lib/ares_parse_txt_reply.c +++ b/contrib/libs/c-ares/src/lib/legacy/ares_parse_txt_reply.c @@ -24,10 +24,8 @@ * SPDX-License-Identifier: MIT */ -#include "ares_setup.h" -#include "ares.h" -#include "ares_data.h" #include "ares_private.h" +#include "ares_data.h" static int ares__parse_txt_reply(const unsigned char *abuf, size_t alen, ares_bool_t ex, void **txt_out) @@ -54,13 +52,14 @@ static int ares__parse_txt_reply(const unsigned char *abuf, size_t alen, for (i = 0; i < ares_dns_record_rr_cnt(dnsrec, ARES_SECTION_ANSWER); i++) { const ares_dns_rr_t *rr = ares_dns_record_rr_get(dnsrec, ARES_SECTION_ANSWER, i); - const unsigned char *ptr; - size_t ptr_len; + size_t j; + size_t cnt; + if (rr == NULL) { /* Shouldn't be possible */ - status = ARES_EBADRESP; - goto done; + status = ARES_EBADRESP; /* LCOV_EXCL_LINE: DefensiveCoding */ + goto done; /* LCOV_EXCL_LINE: DefensiveCoding */ } /* XXX: Why Chaos? */ @@ -70,37 +69,44 @@ static int ares__parse_txt_reply(const unsigned char *abuf, size_t alen, continue; } - /* Allocate storage for this TXT answer appending it to the list */ - txt_curr = - ares_malloc_data(ex ? ARES_DATATYPE_TXT_EXT : ARES_DATATYPE_TXT_REPLY); - if (txt_curr == NULL) { - status = ARES_ENOMEM; - goto done; - } - - /* Link in the record */ - if (txt_last) { - txt_last->next = txt_curr; - } else { - txt_head = txt_curr; - } - txt_last = txt_curr; - - /* These days, records are joined, always tag as start */ - if (ex) { - txt_curr->record_start = 1; - } - - ptr = ares_dns_rr_get_bin(rr, ARES_RR_TXT_DATA, &ptr_len); - - txt_curr->txt = ares_malloc(ptr_len + 1); - if (txt_curr->txt == NULL) { - status = ARES_ENOMEM; - goto done; + cnt = ares_dns_rr_get_abin_cnt(rr, ARES_RR_TXT_DATA); + + for (j = 0; j < cnt; j++) { + const unsigned char *ptr; + size_t ptr_len; + + /* Allocate storage for this TXT answer appending it to the list */ + txt_curr = + ares_malloc_data(ex ? ARES_DATATYPE_TXT_EXT : ARES_DATATYPE_TXT_REPLY); + if (txt_curr == NULL) { + status = ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ + goto done; /* LCOV_EXCL_LINE: OutOfMemory */ + } + + /* Link in the record */ + if (txt_last) { + txt_last->next = txt_curr; + } else { + txt_head = txt_curr; + } + txt_last = txt_curr; + + /* Tag start on first for each TXT record */ + if (ex && j == 0) { + txt_curr->record_start = 1; + } + + ptr = ares_dns_rr_get_abin(rr, ARES_RR_TXT_DATA, j, &ptr_len); + + txt_curr->txt = ares_malloc(ptr_len + 1); + if (txt_curr->txt == NULL) { + status = ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ + goto done; /* LCOV_EXCL_LINE: OutOfMemory */ + } + memcpy(txt_curr->txt, ptr, ptr_len); + txt_curr->txt[ptr_len] = 0; + txt_curr->length = ptr_len; } - memcpy(txt_curr->txt, ptr, ptr_len); - txt_curr->txt[ptr_len] = 0; - txt_curr->length = ptr_len; } done: diff --git a/contrib/libs/c-ares/src/lib/ares_parse_uri_reply.c b/contrib/libs/c-ares/src/lib/legacy/ares_parse_uri_reply.c index bff7023f78..317e204d5d 100644 --- a/contrib/libs/c-ares/src/lib/ares_parse_uri_reply.c +++ b/contrib/libs/c-ares/src/lib/legacy/ares_parse_uri_reply.c @@ -24,10 +24,8 @@ * SPDX-License-Identifier: MIT */ -#include "ares_setup.h" -#include "ares.h" -#include "ares_data.h" #include "ares_private.h" +#include "ares_data.h" int ares_parse_uri_reply(const unsigned char *abuf, int alen_int, struct ares_uri_reply **uri_out) @@ -64,8 +62,8 @@ int ares_parse_uri_reply(const unsigned char *abuf, int alen_int, if (rr == NULL) { /* Shouldn't be possible */ - status = ARES_EBADRESP; - goto done; + status = ARES_EBADRESP; /* LCOV_EXCL_LINE: DefensiveCoding */ + goto done; /* LCOV_EXCL_LINE: DefensiveCoding */ } if (ares_dns_rr_get_class(rr) != ARES_CLASS_IN || @@ -76,8 +74,8 @@ int ares_parse_uri_reply(const unsigned char *abuf, int alen_int, /* Allocate storage for this URI answer appending it to the list */ uri_curr = ares_malloc_data(ARES_DATATYPE_URI_REPLY); if (uri_curr == NULL) { - status = ARES_ENOMEM; - goto done; + status = ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ + goto done; /* LCOV_EXCL_LINE: OutOfMemory */ } /* Link in the record */ diff --git a/contrib/libs/c-ares/src/lib/ares_dns_mapping.c b/contrib/libs/c-ares/src/lib/record/ares_dns_mapping.c index 6c4362f000..738d2f3795 100644 --- a/contrib/libs/c-ares/src/lib/ares_dns_mapping.c +++ b/contrib/libs/c-ares/src/lib/record/ares_dns_mapping.c @@ -23,8 +23,6 @@ * * SPDX-License-Identifier: MIT */ -#include "ares_setup.h" -#include "ares.h" #include "ares_private.h" ares_bool_t ares_dns_opcode_isvalid(ares_dns_opcode_t opcode) @@ -518,9 +516,11 @@ ares_dns_datatype_t ares_dns_rr_key_datatype(ares_dns_rr_key_t key) return ARES_DATATYPE_U8; case ARES_RR_CAA_VALUE: - case ARES_RR_TXT_DATA: return ARES_DATATYPE_BINP; + case ARES_RR_TXT_DATA: + return ARES_DATATYPE_ABINP; + case ARES_RR_SIG_SIGNATURE: case ARES_RR_TLSA_DATA: case ARES_RR_RAW_RR_DATA: @@ -548,18 +548,14 @@ static const ares_dns_rr_key_t rr_hinfo_keys[] = { ARES_RR_HINFO_CPU, ARES_RR_HINFO_OS }; static const ares_dns_rr_key_t rr_mx_keys[] = { ARES_RR_MX_PREFERENCE, ARES_RR_MX_EXCHANGE }; -static const ares_dns_rr_key_t rr_sig_keys[] = { ARES_RR_SIG_TYPE_COVERED, - ARES_RR_SIG_ALGORITHM, - ARES_RR_SIG_LABELS, - ARES_RR_SIG_ORIGINAL_TTL, - ARES_RR_SIG_EXPIRATION, - ARES_RR_SIG_INCEPTION, - ARES_RR_SIG_KEY_TAG, - ARES_RR_SIG_SIGNERS_NAME, - ARES_RR_SIG_SIGNATURE }; -static const ares_dns_rr_key_t rr_txt_keys[] = { ARES_RR_TXT_DATA }; -static const ares_dns_rr_key_t rr_aaaa_keys[] = { ARES_RR_AAAA_ADDR }; -static const ares_dns_rr_key_t rr_srv_keys[] = { +static const ares_dns_rr_key_t rr_sig_keys[] = { + ARES_RR_SIG_TYPE_COVERED, ARES_RR_SIG_ALGORITHM, ARES_RR_SIG_LABELS, + ARES_RR_SIG_ORIGINAL_TTL, ARES_RR_SIG_EXPIRATION, ARES_RR_SIG_INCEPTION, + ARES_RR_SIG_KEY_TAG, ARES_RR_SIG_SIGNERS_NAME, ARES_RR_SIG_SIGNATURE +}; +static const ares_dns_rr_key_t rr_txt_keys[] = { ARES_RR_TXT_DATA }; +static const ares_dns_rr_key_t rr_aaaa_keys[] = { ARES_RR_AAAA_ADDR }; +static const ares_dns_rr_key_t rr_srv_keys[] = { ARES_RR_SRV_PRIORITY, ARES_RR_SRV_WEIGHT, ARES_RR_SRV_PORT, ARES_RR_SRV_TARGET }; static const ares_dns_rr_key_t rr_naptr_keys[] = { diff --git a/contrib/libs/c-ares/src/lib/record/ares_dns_multistring.c b/contrib/libs/c-ares/src/lib/record/ares_dns_multistring.c new file mode 100644 index 0000000000..bff5afb9f2 --- /dev/null +++ b/contrib/libs/c-ares/src/lib/record/ares_dns_multistring.c @@ -0,0 +1,224 @@ +/* MIT License + * + * Copyright (c) 2024 Brad House + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * SPDX-License-Identifier: MIT + */ +#include "ares_private.h" +#include "ares_dns_private.h" + +typedef struct { + unsigned char *data; + size_t len; +} multistring_data_t; + +struct ares__dns_multistring { + /*! whether or not cached concatenated string is valid */ + ares_bool_t cache_invalidated; + /*! combined/concatenated string cache */ + unsigned char *cache_str; + /*! length of combined/concatenated string */ + size_t cache_str_len; + /*! Data making up strings */ + ares__array_t *strs; /*!< multistring_data_t type */ +}; + +static void ares__dns_multistring_free_cb(void *arg) +{ + multistring_data_t *data = arg; + if (data == NULL) { + return; + } + ares_free(data->data); +} + +ares__dns_multistring_t *ares__dns_multistring_create(void) +{ + ares__dns_multistring_t *strs = ares_malloc_zero(sizeof(*strs)); + if (strs == NULL) { + return NULL; + } + + strs->strs = ares__array_create(sizeof(multistring_data_t), + ares__dns_multistring_free_cb); + if (strs->strs == NULL) { + ares_free(strs); + return NULL; + } + + return strs; +} + +void ares__dns_multistring_clear(ares__dns_multistring_t *strs) +{ + if (strs == NULL) { + return; + } + + while (ares__array_len(strs->strs)) { + ares__array_remove_last(strs->strs); + } +} + +void ares__dns_multistring_destroy(ares__dns_multistring_t *strs) +{ + if (strs == NULL) { + return; + } + ares__dns_multistring_clear(strs); + ares__array_destroy(strs->strs); + ares_free(strs->cache_str); + ares_free(strs); +} + +ares_status_t ares__dns_multistring_replace_own(ares__dns_multistring_t *strs, + size_t idx, unsigned char *str, + size_t len) +{ + multistring_data_t *data; + + if (strs == NULL || str == NULL || len == 0) { + return ARES_EFORMERR; + } + + strs->cache_invalidated = ARES_TRUE; + + data = ares__array_at(strs->strs, idx); + if (data == NULL) { + return ARES_EFORMERR; + } + + ares_free(data->data); + data->data = str; + data->len = len; + return ARES_SUCCESS; +} + +ares_status_t ares__dns_multistring_del(ares__dns_multistring_t *strs, + size_t idx) +{ + if (strs == NULL) { + return ARES_EFORMERR; + } + + strs->cache_invalidated = ARES_TRUE; + + return ares__array_remove_at(strs->strs, idx); +} + +ares_status_t ares__dns_multistring_add_own(ares__dns_multistring_t *strs, + unsigned char *str, size_t len) +{ + multistring_data_t *data; + ares_status_t status; + + if (strs == NULL) { + return ARES_EFORMERR; + } + + strs->cache_invalidated = ARES_TRUE; + + /* NOTE: its ok to have an empty string added */ + if (str == NULL && len != 0) { + return ARES_EFORMERR; + } + + status = ares__array_insert_last((void **)&data, strs->strs); + if (status != ARES_SUCCESS) { + return status; + } + + data->data = str; + data->len = len; + + return ARES_SUCCESS; +} + +size_t ares__dns_multistring_cnt(const ares__dns_multistring_t *strs) +{ + if (strs == NULL) { + return 0; + } + return ares__array_len(strs->strs); +} + +const unsigned char * + ares__dns_multistring_get(const ares__dns_multistring_t *strs, size_t idx, + size_t *len) +{ + const multistring_data_t *data; + + if (strs == NULL || len == NULL) { + return NULL; + } + + data = ares__array_at_const(strs->strs, idx); + if (data == NULL) { + return NULL; + } + + *len = data->len; + return data->data; +} + +const unsigned char * + ares__dns_multistring_get_combined(ares__dns_multistring_t *strs, size_t *len) +{ + ares__buf_t *buf = NULL; + size_t i; + + if (strs == NULL || len == NULL) { + return NULL; + } + + *len = 0; + + /* Return cache if possible */ + if (!strs->cache_invalidated) { + *len = strs->cache_str_len; + return strs->cache_str; + } + + /* Clear cache */ + ares_free(strs->cache_str); + strs->cache_str = NULL; + strs->cache_str_len = 0; + + buf = ares__buf_create(); + + for (i = 0; i < ares__array_len(strs->strs); i++) { + const multistring_data_t *data = ares__array_at_const(strs->strs, i); + if (data == NULL || + ares__buf_append(buf, data->data, data->len) != ARES_SUCCESS) { + ares__buf_destroy(buf); + return NULL; + } + } + + strs->cache_str = + (unsigned char *)ares__buf_finish_str(buf, &strs->cache_str_len); + if (strs->cache_str != NULL) { + strs->cache_invalidated = ARES_FALSE; + } + *len = strs->cache_str_len; + return strs->cache_str; +} diff --git a/contrib/libs/c-ares/src/lib/record/ares_dns_multistring.h b/contrib/libs/c-ares/src/lib/record/ares_dns_multistring.h new file mode 100644 index 0000000000..d9aa7ae378 --- /dev/null +++ b/contrib/libs/c-ares/src/lib/record/ares_dns_multistring.h @@ -0,0 +1,50 @@ +/* MIT License + * + * Copyright (c) 2024 Brad House + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * SPDX-License-Identifier: MIT + */ +#ifndef __ARES_DNS_MULTISTRING_H +#define __ARES_DNS_MULTISTRING_H + +struct ares__dns_multistring; +typedef struct ares__dns_multistring ares__dns_multistring_t; + +ares__dns_multistring_t *ares__dns_multistring_create(void); +void ares__dns_multistring_clear(ares__dns_multistring_t *strs); +void ares__dns_multistring_destroy(ares__dns_multistring_t *strs); +ares_status_t ares__dns_multistring_replace_own(ares__dns_multistring_t *strs, + size_t idx, unsigned char *str, + size_t len); +ares_status_t ares__dns_multistring_del(ares__dns_multistring_t *strs, + size_t idx); +ares_status_t ares__dns_multistring_add_own(ares__dns_multistring_t *strs, + unsigned char *str, size_t len); +size_t ares__dns_multistring_cnt(const ares__dns_multistring_t *strs); +const unsigned char * + ares__dns_multistring_get(const ares__dns_multistring_t *strs, size_t idx, + size_t *len); +const unsigned char * + ares__dns_multistring_get_combined(ares__dns_multistring_t *strs, + size_t *len); + +#endif diff --git a/contrib/libs/c-ares/src/lib/ares_dns_name.c b/contrib/libs/c-ares/src/lib/record/ares_dns_name.c index 85e26cd25b..a437553b0f 100644 --- a/contrib/libs/c-ares/src/lib/ares_dns_name.c +++ b/contrib/libs/c-ares/src/lib/record/ares_dns_name.c @@ -23,8 +23,6 @@ * * SPDX-License-Identifier: MIT */ -#include "ares_setup.h" -#include "ares.h" #include "ares_private.h" typedef struct { @@ -37,7 +35,7 @@ static void ares__nameoffset_free(void *arg) { ares_nameoffset_t *off = arg; if (off == NULL) { - return; + return; /* LCOV_EXCL_LINE: DefensiveCoding */ } ares_free(off->name); ares_free(off); @@ -51,20 +49,20 @@ static ares_status_t ares__nameoffset_create(ares__llist_t **list, if (list == NULL || name == NULL || ares_strlen(name) == 0 || ares_strlen(name) > 255) { - return ARES_EFORMERR; + return ARES_EFORMERR; /* LCOV_EXCL_LINE: DefensiveCoding */ } if (*list == NULL) { *list = ares__llist_create(ares__nameoffset_free); } if (*list == NULL) { - status = ARES_ENOMEM; - goto fail; + status = ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ + goto fail; /* LCOV_EXCL_LINE: OutOfMemory */ } off = ares_malloc_zero(sizeof(*off)); if (off == NULL) { - return ARES_ENOMEM; + return ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ } off->name = ares_strdup(name); @@ -72,15 +70,17 @@ static ares_status_t ares__nameoffset_create(ares__llist_t **list, off->idx = idx; if (ares__llist_insert_last(*list, off) == NULL) { - status = ARES_ENOMEM; - goto fail; + status = ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ + goto fail; /* LCOV_EXCL_LINE: OutOfMemory */ } return ARES_SUCCESS; +/* LCOV_EXCL_START: OutOfMemory */ fail: ares__nameoffset_free(off); return status; + /* LCOV_EXCL_STOP */ } static const ares_nameoffset_t *ares__nameoffset_find(ares__llist_t *list, @@ -111,7 +111,10 @@ static const ares_nameoffset_t *ares__nameoffset_find(ares__llist_t *list, prefix_len = name_len - val->name_len; - if (strcasecmp(val->name, name + prefix_len) != 0) { + /* Due to DNS 0x20, lets not inadvertently mangle things, use case-sensitive + * matching instead of case-insensitive. This may result in slightly + * larger DNS queries overall. */ + if (strcmp(val->name, name + prefix_len) != 0) { continue; } @@ -128,72 +131,62 @@ static const ares_nameoffset_t *ares__nameoffset_find(ares__llist_t *list, return longest_match; } -typedef struct { - ares__buf_t **label; - size_t num; -} ares_dns_labels_t; - -static void ares_dns_labels_free(ares_dns_labels_t *labels) +static void ares_dns_labels_free_cb(void *arg) { - size_t i; - - if (labels == NULL) { + ares__buf_t **buf = arg; + if (buf == NULL) { return; } - for (i = 0; i < labels->num; i++) { - ares__buf_destroy(labels->label[i]); - labels->label[i] = NULL; - } - ares_free(labels->label); - labels->label = NULL; - labels->num = 0; + ares__buf_destroy(*buf); } -static ares__buf_t *ares_dns_labels_add(ares_dns_labels_t *labels) +static ares__buf_t *ares_dns_labels_add(ares__array_t *labels) { - void *temp; + ares__buf_t **buf; if (labels == NULL) { - return NULL; + return NULL; /* LCOV_EXCL_LINE: DefensiveCoding */ } - temp = ares_realloc_zero(labels->label, sizeof(*labels->label) * labels->num, - sizeof(*labels->label) * (labels->num + 1)); - if (temp == NULL) { + if (ares__array_insert_last((void **)&buf, labels) != ARES_SUCCESS) { return NULL; } - labels->label = temp; - - labels->label[labels->num] = ares__buf_create(); - if (labels->label[labels->num] == NULL) { + *buf = ares__buf_create(); + if (*buf == NULL) { + ares__array_remove_last(labels); return NULL; } - labels->num++; - return labels->label[labels->num - 1]; + return *buf; } -static const ares__buf_t * - ares_dns_labels_get_last(const ares_dns_labels_t *labels) +static ares__buf_t *ares_dns_labels_get_last(ares__array_t *labels) { - if (labels == NULL || labels->num == 0) { + ares__buf_t **buf = ares__array_last(labels); + + if (buf == NULL) { return NULL; } - return labels->label[labels->num - 1]; + return *buf; } -static void ares_dns_name_labels_del_last(ares_dns_labels_t *labels) +static ares__buf_t *ares_dns_labels_get_at(ares__array_t *labels, size_t idx) { - if (labels == NULL || labels->num == 0) { - return; + ares__buf_t **buf = ares__array_at(labels, idx); + + if (buf == NULL) { + return NULL; } - ares__buf_destroy(labels->label[labels->num - 1]); - labels->label[labels->num - 1] = NULL; - labels->num--; + return *buf; +} + +static void ares_dns_name_labels_del_last(ares__array_t *labels) +{ + ares__array_remove_last(labels); } static ares_status_t ares_parse_dns_name_escape(ares__buf_t *namebuf, @@ -209,7 +202,7 @@ static ares_status_t ares_parse_dns_name_escape(ares__buf_t *namebuf, } /* If next character is a digit, read 2 more digits */ - if (isdigit(c)) { + if (ares__isdigit(c)) { size_t i; unsigned int val = 0; @@ -221,7 +214,7 @@ static ares_status_t ares_parse_dns_name_escape(ares__buf_t *namebuf, return ARES_EBADNAME; } - if (!isdigit(c)) { + if (!ares__isdigit(c)) { return ARES_EBADNAME; } val *= 10; @@ -248,9 +241,9 @@ static ares_status_t ares_parse_dns_name_escape(ares__buf_t *namebuf, return ares__buf_append_byte(label, c); } -static ares_status_t ares_split_dns_name(ares_dns_labels_t *labels, - ares_bool_t validate_hostname, - const char *name) +static ares_status_t ares_split_dns_name(ares__array_t *labels, + ares_bool_t validate_hostname, + const char *name) { ares_status_t status; ares__buf_t *label = NULL; @@ -260,29 +253,29 @@ static ares_status_t ares_split_dns_name(ares_dns_labels_t *labels, unsigned char c; if (name == NULL || labels == NULL) { - return ARES_EFORMERR; + return ARES_EFORMERR; /* LCOV_EXCL_LINE: DefensiveCoding */ } /* Put name into a buffer for parsing */ namebuf = ares__buf_create(); if (namebuf == NULL) { - status = ARES_ENOMEM; - goto done; + status = ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ + goto done; /* LCOV_EXCL_LINE: OutOfMemory */ } if (*name != '\0') { status = ares__buf_append(namebuf, (const unsigned char *)name, ares_strlen(name)); if (status != ARES_SUCCESS) { - goto done; + goto done; /* LCOV_EXCL_LINE: OutOfMemory */ } } /* Start with 1 label */ label = ares_dns_labels_add(labels); if (label == NULL) { - status = ARES_ENOMEM; - goto done; + status = ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ + goto done; /* LCOV_EXCL_LINE: OutOfMemory */ } while (ares__buf_fetch_bytes(namebuf, &c, 1) == ARES_SUCCESS) { @@ -290,8 +283,8 @@ static ares_status_t ares_split_dns_name(ares_dns_labels_t *labels, if (c == '.') { label = ares_dns_labels_add(labels); if (label == NULL) { - status = ARES_ENOMEM; - goto done; + status = ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ + goto done; /* LCOV_EXCL_LINE: OutOfMemory */ } continue; } @@ -313,7 +306,7 @@ static ares_status_t ares_split_dns_name(ares_dns_labels_t *labels, status = ares__buf_append_byte(label, c); if (status != ARES_SUCCESS) { - goto done; + goto done; /* LCOV_EXCL_LINE: OutOfMemory */ } } @@ -324,14 +317,15 @@ static ares_status_t ares_split_dns_name(ares_dns_labels_t *labels, /* If someone passed in "." there could have been 2 blank labels, check for * that */ - if (labels->num == 1 && + if (ares__array_len(labels) == 1 && ares__buf_len(ares_dns_labels_get_last(labels)) == 0) { ares_dns_name_labels_del_last(labels); } /* Scan to make sure label lengths are valid */ - for (i = 0; i < labels->num; i++) { - size_t len = ares__buf_len(labels->label[i]); + for (i = 0; i < ares__array_len(labels); i++) { + const ares__buf_t *buf = ares_dns_labels_get_at(labels, i); + size_t len = ares__buf_len(buf); /* No 0-length labels, and no labels over 63 bytes */ if (len == 0 || len > 63) { status = ARES_EBADNAME; @@ -341,7 +335,8 @@ static ares_status_t ares_split_dns_name(ares_dns_labels_t *labels, } /* Can't exceed maximum (unescaped) length */ - if (labels->num && total_len + labels->num - 1 > 255) { + if (ares__array_len(labels) && + total_len + ares__array_len(labels) - 1 > 255) { status = ARES_EBADNAME; goto done; } @@ -350,9 +345,6 @@ static ares_status_t ares_split_dns_name(ares_dns_labels_t *labels, done: ares__buf_destroy(namebuf); - if (status != ARES_SUCCESS) { - ares_dns_labels_free(labels); - } return status; } @@ -363,16 +355,19 @@ ares_status_t ares__dns_name_write(ares__buf_t *buf, ares__llist_t **list, const ares_nameoffset_t *off = NULL; size_t name_len; size_t orig_name_len; - size_t pos = ares__buf_len(buf); - ares_dns_labels_t labels; + size_t pos = ares__buf_len(buf); + ares__array_t *labels = NULL; char name_copy[512]; ares_status_t status; if (buf == NULL || name == NULL) { - return ARES_EFORMERR; + return ARES_EFORMERR; /* LCOV_EXCL_LINE: DefensiveCoding */ } - memset(&labels, 0, sizeof(labels)); + labels = ares__array_create(sizeof(ares__buf_t *), ares_dns_labels_free_cb); + if (labels == NULL) { + return ARES_ENOMEM; + } /* NOTE: due to possible escaping, name_copy buffer is > 256 to allow for * this */ @@ -393,23 +388,24 @@ ares_status_t ares__dns_name_write(ares__buf_t *buf, ares__llist_t **list, if (off == NULL || off->name_len != orig_name_len) { size_t i; - status = ares_split_dns_name(&labels, validate_hostname, name_copy); + status = ares_split_dns_name(labels, validate_hostname, name_copy); if (status != ARES_SUCCESS) { goto done; } - for (i = 0; i < labels.num; i++) { - size_t len = 0; - const unsigned char *ptr = ares__buf_peek(labels.label[i], &len); + for (i = 0; i < ares__array_len(labels); i++) { + size_t len = 0; + const ares__buf_t *lbuf = ares_dns_labels_get_at(labels, i); + const unsigned char *ptr = ares__buf_peek(lbuf, &len); status = ares__buf_append_byte(buf, (unsigned char)(len & 0xFF)); if (status != ARES_SUCCESS) { - goto done; + goto done; /* LCOV_EXCL_LINE: OutOfMemory */ } status = ares__buf_append(buf, ptr, len); if (status != ARES_SUCCESS) { - goto done; + goto done; /* LCOV_EXCL_LINE: OutOfMemory */ } } @@ -417,7 +413,7 @@ ares_status_t ares__dns_name_write(ares__buf_t *buf, ares__llist_t **list, if (off == NULL) { status = ares__buf_append_byte(buf, 0); if (status != ARES_SUCCESS) { - goto done; + goto done; /* LCOV_EXCL_LINE: OutOfMemory */ } } } @@ -428,7 +424,7 @@ ares_status_t ares__dns_name_write(ares__buf_t *buf, ares__llist_t **list, (unsigned short)0xC000 | (unsigned short)(off->idx & 0x3FFF); status = ares__buf_append_be16(buf, u16); if (status != ARES_SUCCESS) { - goto done; + goto done; /* LCOV_EXCL_LINE: OutOfMemory */ } } @@ -438,14 +434,14 @@ ares_status_t ares__dns_name_write(ares__buf_t *buf, ares__llist_t **list, name_len > 0) { status = ares__nameoffset_create(list, name /* not truncated copy! */, pos); if (status != ARES_SUCCESS) { - goto done; + goto done; /* LCOV_EXCL_LINE: OutOfMemory */ } } status = ARES_SUCCESS; done: - ares_dns_labels_free(&labels); + ares__array_destroy(labels); return status; } @@ -509,7 +505,7 @@ static ares_status_t ares__fetch_dnsname_into_buf(ares__buf_t *buf, status = ares__buf_append(dest, escape, sizeof(escape)); if (status != ARES_SUCCESS) { - goto fail; + goto fail; /* LCOV_EXCL_LINE: OutOfMemory */ } continue; @@ -519,13 +515,13 @@ static ares_status_t ares__fetch_dnsname_into_buf(ares__buf_t *buf, if (is_reservedch(c)) { status = ares__buf_append_byte(dest, '\\'); if (status != ARES_SUCCESS) { - goto fail; + goto fail; /* LCOV_EXCL_LINE: OutOfMemory */ } } status = ares__buf_append_byte(dest, c); if (status != ARES_SUCCESS) { - return status; + return status; /* LCOV_EXCL_LINE: OutOfMemory */ } } @@ -641,7 +637,7 @@ ares_status_t ares__dns_name_parse(ares__buf_t *buf, char **name, if (ares__buf_len(namebuf) != 0 && name != NULL) { status = ares__buf_append_byte(namebuf, '.'); if (status != ARES_SUCCESS) { - goto fail; + goto fail; /* LCOV_EXCL_LINE: OutOfMemory */ } } @@ -660,8 +656,8 @@ ares_status_t ares__dns_name_parse(ares__buf_t *buf, char **name, if (name != NULL) { *name = ares__buf_finish_str(namebuf, NULL); if (*name == NULL) { - status = ARES_ENOMEM; - goto fail; + status = ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ + goto fail; /* LCOV_EXCL_LINE: OutOfMemory */ } } diff --git a/contrib/libs/c-ares/src/lib/ares_dns_parse.c b/contrib/libs/c-ares/src/lib/record/ares_dns_parse.c index 8b771ee1fa..57cb0f714e 100644 --- a/contrib/libs/c-ares/src/lib/ares_dns_parse.c +++ b/contrib/libs/c-ares/src/lib/record/ares_dns_parse.c @@ -23,8 +23,6 @@ * * SPDX-License-Identifier: MIT */ -#include "ares_setup.h" -#include "ares.h" #include "ares_private.h" #include <limits.h> #ifdef HAVE_STDINT_H @@ -62,14 +60,16 @@ static ares_status_t ares_dns_parse_and_set_dns_name(ares__buf_t *buf, return ARES_SUCCESS; } -static ares_status_t ares_dns_parse_and_set_dns_str( - ares__buf_t *buf, size_t max_len, ares_bool_t allow_multiple, - ares_dns_rr_t *rr, ares_dns_rr_key_t key, ares_bool_t blank_allowed) +static ares_status_t ares_dns_parse_and_set_dns_str(ares__buf_t *buf, + size_t max_len, + ares_dns_rr_t *rr, + ares_dns_rr_key_t key, + ares_bool_t blank_allowed) { ares_status_t status; char *str = NULL; - status = ares__buf_parse_dns_str(buf, max_len, &str, allow_multiple); + status = ares__buf_parse_dns_str(buf, max_len, &str); if (status != ARES_SUCCESS) { return status; } @@ -88,23 +88,21 @@ static ares_status_t ares_dns_parse_and_set_dns_str( } static ares_status_t - ares_dns_parse_and_set_dns_binstr(ares__buf_t *buf, size_t max_len, - ares_bool_t allow_multiple, - ares_dns_rr_t *rr, ares_dns_rr_key_t key) + ares_dns_parse_and_set_dns_abin(ares__buf_t *buf, size_t max_len, + ares_dns_rr_t *rr, ares_dns_rr_key_t key, + ares_bool_t validate_printable) { - ares_status_t status; - unsigned char *bin = NULL; - size_t bin_len = 0; + ares_status_t status; + ares__dns_multistring_t *strs = NULL; - status = - ares__buf_parse_dns_binstr(buf, max_len, &bin, &bin_len, allow_multiple); + status = ares__buf_parse_dns_abinstr(buf, max_len, &strs, validate_printable); if (status != ARES_SUCCESS) { return status; } - status = ares_dns_rr_set_bin_own(rr, key, bin, bin_len); + status = ares_dns_rr_set_abin_own(rr, key, strs); if (status != ARES_SUCCESS) { - ares_free(bin); + ares__dns_multistring_destroy(strs); return status; } return ARES_SUCCESS; @@ -257,7 +255,7 @@ static ares_status_t ares_dns_parse_rr_hinfo(ares__buf_t *buf, /* CPU */ status = ares_dns_parse_and_set_dns_str( - buf, ares_dns_rr_remaining_len(buf, orig_len, rdlength), ARES_FALSE, rr, + buf, ares_dns_rr_remaining_len(buf, orig_len, rdlength), rr, ARES_RR_HINFO_CPU, ARES_TRUE); if (status != ARES_SUCCESS) { return status; @@ -265,7 +263,7 @@ static ares_status_t ares_dns_parse_rr_hinfo(ares__buf_t *buf, /* OS */ status = ares_dns_parse_and_set_dns_str( - buf, ares_dns_rr_remaining_len(buf, orig_len, rdlength), ARES_FALSE, rr, + buf, ares_dns_rr_remaining_len(buf, orig_len, rdlength), rr, ARES_RR_HINFO_OS, ARES_TRUE); return status; @@ -292,8 +290,8 @@ static ares_status_t ares_dns_parse_rr_mx(ares__buf_t *buf, ares_dns_rr_t *rr, static ares_status_t ares_dns_parse_rr_txt(ares__buf_t *buf, ares_dns_rr_t *rr, size_t rdlength) { - return ares_dns_parse_and_set_dns_binstr(buf, rdlength, ARES_TRUE, rr, - ARES_RR_TXT_DATA); + return ares_dns_parse_and_set_dns_abin(buf, rdlength, rr, ARES_RR_TXT_DATA, + ARES_FALSE); } static ares_status_t ares_dns_parse_rr_sig(ares__buf_t *buf, ares_dns_rr_t *rr, @@ -430,7 +428,7 @@ static ares_status_t ares_dns_parse_rr_naptr(ares__buf_t *buf, /* FLAGS */ status = ares_dns_parse_and_set_dns_str( - buf, ares_dns_rr_remaining_len(buf, orig_len, rdlength), ARES_FALSE, rr, + buf, ares_dns_rr_remaining_len(buf, orig_len, rdlength), rr, ARES_RR_NAPTR_FLAGS, ARES_TRUE); if (status != ARES_SUCCESS) { return status; @@ -438,7 +436,7 @@ static ares_status_t ares_dns_parse_rr_naptr(ares__buf_t *buf, /* SERVICES */ status = ares_dns_parse_and_set_dns_str( - buf, ares_dns_rr_remaining_len(buf, orig_len, rdlength), ARES_FALSE, rr, + buf, ares_dns_rr_remaining_len(buf, orig_len, rdlength), rr, ARES_RR_NAPTR_SERVICES, ARES_TRUE); if (status != ARES_SUCCESS) { return status; @@ -446,7 +444,7 @@ static ares_status_t ares_dns_parse_rr_naptr(ares__buf_t *buf, /* REGEXP */ status = ares_dns_parse_and_set_dns_str( - buf, ares_dns_rr_remaining_len(buf, orig_len, rdlength), ARES_FALSE, rr, + buf, ares_dns_rr_remaining_len(buf, orig_len, rdlength), rr, ARES_RR_NAPTR_REGEXP, ARES_TRUE); if (status != ARES_SUCCESS) { return status; @@ -731,7 +729,7 @@ static ares_status_t ares_dns_parse_rr_caa(ares__buf_t *buf, ares_dns_rr_t *rr, /* Tag */ status = ares_dns_parse_and_set_dns_str( - buf, ares_dns_rr_remaining_len(buf, orig_len, rdlength), ARES_FALSE, rr, + buf, ares_dns_rr_remaining_len(buf, orig_len, rdlength), rr, ARES_RR_CAA_TAG, ARES_FALSE); if (status != ARES_SUCCESS) { return status; @@ -925,7 +923,7 @@ static ares_status_t ares_dns_parse_header(ares__buf_t *buf, unsigned int flags, status = ares_dns_record_rr_prealloc(*dnsrec, ARES_SECTION_ANSWER, *ancount); if (status != ARES_SUCCESS) { - goto fail; + goto fail; /* LCOV_EXCL_LINE: OutOfMemory */ } } @@ -933,7 +931,7 @@ static ares_status_t ares_dns_parse_header(ares__buf_t *buf, unsigned int flags, status = ares_dns_record_rr_prealloc(*dnsrec, ARES_SECTION_AUTHORITY, *nscount); if (status != ARES_SUCCESS) { - goto fail; + goto fail; /* LCOV_EXCL_LINE: OutOfMemory */ } } @@ -941,7 +939,7 @@ static ares_status_t ares_dns_parse_header(ares__buf_t *buf, unsigned int flags, status = ares_dns_record_rr_prealloc(*dnsrec, ARES_SECTION_ADDITIONAL, *arcount); if (status != ARES_SUCCESS) { - goto fail; + goto fail; /* LCOV_EXCL_LINE: OutOfMemory */ } } @@ -1216,7 +1214,7 @@ static ares_status_t ares_dns_parse_buf(ares__buf_t *buf, unsigned int flags, unsigned short i; if (buf == NULL || dnsrec == NULL) { - return ARES_EFORMERR; + return ARES_EFORMERR; /* LCOV_EXCL_LINE: DefensiveCoding */ } /* Maximum DNS packet size is 64k, even over TCP */ diff --git a/contrib/libs/c-ares/src/lib/ares_dns_private.h b/contrib/libs/c-ares/src/lib/record/ares_dns_private.h index e8e783d559..5b86fed51f 100644 --- a/contrib/libs/c-ares/src/lib/ares_dns_private.h +++ b/contrib/libs/c-ares/src/lib/record/ares_dns_private.h @@ -26,6 +26,8 @@ #ifndef __ARES_DNS_PRIVATE_H #define __ARES_DNS_PRIVATE_H +ares_status_t ares_dns_record_duplicate_ex(ares_dns_record_t **dest, + const ares_dns_record_t *src); ares_bool_t ares_dns_rec_type_allow_name_compression(ares_dns_rec_type_t type); ares_bool_t ares_dns_opcode_isvalid(ares_dns_opcode_t opcode); ares_bool_t ares_dns_rcode_isvalid(ares_dns_rcode_t rcode); @@ -36,20 +38,32 @@ ares_bool_t ares_dns_class_isvalid(ares_dns_class_t qclass, ares_dns_rec_type_t type, ares_bool_t is_query); ares_bool_t ares_dns_section_isvalid(ares_dns_section_t sect); -ares_status_t ares_dns_rr_set_str_own(ares_dns_rr_t *dns_rr, - ares_dns_rr_key_t key, char *val); -ares_status_t ares_dns_rr_set_bin_own(ares_dns_rr_t *dns_rr, - ares_dns_rr_key_t key, unsigned char *val, - size_t len); -ares_status_t ares_dns_rr_set_opt_own(ares_dns_rr_t *dns_rr, - ares_dns_rr_key_t key, unsigned short opt, - unsigned char *val, size_t val_len); -ares_status_t ares_dns_record_rr_prealloc(ares_dns_record_t *dnsrec, - ares_dns_section_t sect, size_t cnt); -ares_bool_t ares_dns_has_opt_rr(const ares_dns_record_t *rec); +ares_status_t ares_dns_rr_set_str_own(ares_dns_rr_t *dns_rr, + ares_dns_rr_key_t key, char *val); +ares_status_t ares_dns_rr_set_bin_own(ares_dns_rr_t *dns_rr, + ares_dns_rr_key_t key, unsigned char *val, + size_t len); +ares_status_t ares_dns_rr_set_abin_own(ares_dns_rr_t *dns_rr, + ares_dns_rr_key_t key, + ares__dns_multistring_t *strs); +ares_status_t ares_dns_rr_set_opt_own(ares_dns_rr_t *dns_rr, + ares_dns_rr_key_t key, unsigned short opt, + unsigned char *val, size_t val_len); +ares_status_t ares_dns_record_rr_prealloc(ares_dns_record_t *dnsrec, + ares_dns_section_t sect, size_t cnt); +ares_dns_rr_t *ares_dns_get_opt_rr(ares_dns_record_t *rec); +const ares_dns_rr_t *ares_dns_get_opt_rr_const(const ares_dns_record_t *rec); void ares_dns_record_write_ttl_decrement(ares_dns_record_t *dnsrec, unsigned int ttl_decrement); +/* Same as ares_dns_write() but appends to an existing buffer object */ +ares_status_t ares_dns_write_buf(const ares_dns_record_t *dnsrec, + ares__buf_t *buf); + +/* Same as ares_dns_write_buf(), but prepends a 16bit length */ +ares_status_t ares_dns_write_buf_tcp(const ares_dns_record_t *dnsrec, + ares__buf_t *buf); + /*! Create a DNS record object for a query. The arguments are the same as * those for ares_create_query(). * @@ -120,8 +134,7 @@ typedef struct { } ares__dns_mx_t; typedef struct { - char *data; - size_t data_len; + ares__dns_multistring_t *strs; } ares__dns_txt_t; typedef struct { @@ -164,18 +177,11 @@ typedef struct { } ares__dns_optval_t; typedef struct { - ares__dns_optval_t *optval; /*!< Attribute/value pairs */ - size_t cnt; /*!< Count of Attribute/Value pairs */ - size_t alloc; /*!< Allocated count of attribute/value - * pairs */ -} ares__dns_options_t; - -typedef struct { - unsigned short udp_size; /*!< taken from class */ - unsigned char version; /*!< taken from bits 8-16 of ttl */ - unsigned short flags; /*!< Flags, remaining 16 bits, though only - * 1 currently defined */ - ares__dns_options_t *options; /*!< Attribute/Value pairs */ + unsigned short udp_size; /*!< taken from class */ + unsigned char version; /*!< taken from bits 8-16 of ttl */ + unsigned short flags; /*!< Flags, remaining 16 bits, though only + * 1 currently defined */ + ares__array_t *options; /*!< Type is ares__dns_optval_t */ } ares__dns_opt_t; typedef struct { @@ -187,9 +193,9 @@ typedef struct { } ares__dns_tlsa_t; typedef struct { - unsigned short priority; - char *target; - ares__dns_options_t *params; + unsigned short priority; + char *target; + ares__array_t *params; /*!< Type is ares__dns_optval_t */ } ares__dns_svcb_t; typedef struct { @@ -258,21 +264,10 @@ struct ares_dns_record { * the ttl of any resource records by * this amount. Used for cache */ - ares_dns_qd_t *qd; - size_t qdcount; - size_t qdalloc; - - ares_dns_rr_t *an; - size_t ancount; - size_t analloc; - - ares_dns_rr_t *ns; - size_t nscount; - size_t nsalloc; - - ares_dns_rr_t *ar; - size_t arcount; - size_t aralloc; + ares__array_t *qd; /*!< Type is ares_dns_qd_t */ + ares__array_t *an; /*!< Type is ares_dns_rr_t */ + ares__array_t *ns; /*!< Type is ares_dns_rr_t */ + ares__array_t *ar; /*!< Type is ares_dns_rr_t */ }; #endif diff --git a/contrib/libs/c-ares/src/lib/ares_dns_record.c b/contrib/libs/c-ares/src/lib/record/ares_dns_record.c index e6b7bf7fe1..1470494909 100644 --- a/contrib/libs/c-ares/src/lib/ares_dns_record.c +++ b/contrib/libs/c-ares/src/lib/record/ares_dns_record.c @@ -23,14 +23,31 @@ * * SPDX-License-Identifier: MIT */ -#include "ares_setup.h" -#include "ares.h" #include "ares_private.h" #include <limits.h> #ifdef HAVE_STDINT_H # include <stdint.h> #endif +static void ares__dns_rr_free(ares_dns_rr_t *rr); + +static void ares_dns_qd_free_cb(void *arg) +{ + ares_dns_qd_t *qd = arg; + if (qd == NULL) { + return; + } + ares_free(qd->name); +} + +static void ares_dns_rr_free_cb(void *arg) +{ + ares_dns_rr_t *rr = arg; + if (rr == NULL) { + return; + } + ares__dns_rr_free(rr); +} ares_status_t ares_dns_record_create(ares_dns_record_t **dnsrec, unsigned short id, unsigned short flags, @@ -57,6 +74,22 @@ ares_status_t ares_dns_record_create(ares_dns_record_t **dnsrec, (*dnsrec)->flags = flags; (*dnsrec)->opcode = opcode; (*dnsrec)->rcode = rcode; + (*dnsrec)->qd = + ares__array_create(sizeof(ares_dns_qd_t), ares_dns_qd_free_cb); + (*dnsrec)->an = + ares__array_create(sizeof(ares_dns_rr_t), ares_dns_rr_free_cb); + (*dnsrec)->ns = + ares__array_create(sizeof(ares_dns_rr_t), ares_dns_rr_free_cb); + (*dnsrec)->ar = + ares__array_create(sizeof(ares_dns_rr_t), ares_dns_rr_free_cb); + + if ((*dnsrec)->qd == NULL || (*dnsrec)->an == NULL || (*dnsrec)->ns == NULL || + (*dnsrec)->ar == NULL) { + ares_dns_record_destroy(*dnsrec); + *dnsrec = NULL; + return ARES_ENOMEM; + } + return ARES_SUCCESS; } @@ -68,6 +101,15 @@ unsigned short ares_dns_record_get_id(const ares_dns_record_t *dnsrec) return dnsrec->id; } +ares_bool_t ares_dns_record_set_id(ares_dns_record_t *dnsrec, unsigned short id) +{ + if (dnsrec == NULL) { + return ARES_FALSE; + } + dnsrec->id = id; + return ARES_TRUE; +} + unsigned short ares_dns_record_get_flags(const ares_dns_record_t *dnsrec) { if (dnsrec == NULL) { @@ -92,21 +134,6 @@ ares_dns_rcode_t ares_dns_record_get_rcode(const ares_dns_record_t *dnsrec) return dnsrec->rcode; } -static void ares__dns_options_free(ares__dns_options_t *options) -{ - size_t i; - - if (options == NULL) { - return; - } - - for (i = 0; i < options->cnt; i++) { - ares_free(options->optval[i].val); - } - ares_free(options->optval); - ares_free(options); -} - static void ares__dns_rr_free(ares_dns_rr_t *rr) { ares_free(rr->name); @@ -145,7 +172,7 @@ static void ares__dns_rr_free(ares_dns_rr_t *rr) break; case ARES_REC_TYPE_TXT: - ares_free(rr->r.txt.data); + ares__dns_multistring_destroy(rr->r.txt.strs); break; case ARES_REC_TYPE_SIG: @@ -165,7 +192,7 @@ static void ares__dns_rr_free(ares_dns_rr_t *rr) break; case ARES_REC_TYPE_OPT: - ares__dns_options_free(rr->r.opt.options); + ares__array_destroy(rr->r.opt.options); break; case ARES_REC_TYPE_TLSA: @@ -174,12 +201,12 @@ static void ares__dns_rr_free(ares_dns_rr_t *rr) case ARES_REC_TYPE_SVCB: ares_free(rr->r.svcb.target); - ares__dns_options_free(rr->r.svcb.params); + ares__array_destroy(rr->r.svcb.params); break; case ARES_REC_TYPE_HTTPS: ares_free(rr->r.https.target); - ares__dns_options_free(rr->r.https.params); + ares__array_destroy(rr->r.https.params); break; case ARES_REC_TYPE_URI: @@ -199,35 +226,21 @@ static void ares__dns_rr_free(ares_dns_rr_t *rr) void ares_dns_record_destroy(ares_dns_record_t *dnsrec) { - size_t i; - if (dnsrec == NULL) { return; } /* Free questions */ - for (i = 0; i < dnsrec->qdcount; i++) { - ares_free(dnsrec->qd[i].name); - } - ares_free(dnsrec->qd); + ares__array_destroy(dnsrec->qd); /* Free answers */ - for (i = 0; i < dnsrec->ancount; i++) { - ares__dns_rr_free(&dnsrec->an[i]); - } - ares_free(dnsrec->an); + ares__array_destroy(dnsrec->an); /* Free authority */ - for (i = 0; i < dnsrec->nscount; i++) { - ares__dns_rr_free(&dnsrec->ns[i]); - } - ares_free(dnsrec->ns); + ares__array_destroy(dnsrec->ns); /* Free additional */ - for (i = 0; i < dnsrec->arcount; i++) { - ares__dns_rr_free(&dnsrec->ar[i]); - } - ares_free(dnsrec->ar); + ares__array_destroy(dnsrec->ar); ares_free(dnsrec); } @@ -237,7 +250,7 @@ size_t ares_dns_record_query_cnt(const ares_dns_record_t *dnsrec) if (dnsrec == NULL) { return 0; } - return dnsrec->qdcount; + return ares__array_len(dnsrec->qd); } ares_status_t ares_dns_record_query_add(ares_dns_record_t *dnsrec, @@ -245,8 +258,9 @@ ares_status_t ares_dns_record_query_add(ares_dns_record_t *dnsrec, ares_dns_rec_type_t qtype, ares_dns_class_t qclass) { - ares_dns_qd_t *temp = NULL; size_t idx; + ares_dns_qd_t *qd; + ares_status_t status; if (dnsrec == NULL || name == NULL || !ares_dns_rec_type_isvalid(qtype, ARES_TRUE) || @@ -254,46 +268,39 @@ ares_status_t ares_dns_record_query_add(ares_dns_record_t *dnsrec, return ARES_EFORMERR; } - if (dnsrec->qdcount >= dnsrec->qdalloc) { - size_t alloc_cnt = ares__round_up_pow2(dnsrec->qdcount + 1); - - temp = ares_realloc_zero(dnsrec->qd, sizeof(*temp) * (dnsrec->qdalloc), - sizeof(*temp) * alloc_cnt); - if (temp == NULL) { - return ARES_ENOMEM; - } - - dnsrec->qdalloc = alloc_cnt; - dnsrec->qd = temp; + idx = ares__array_len(dnsrec->qd); + status = ares__array_insert_last((void **)&qd, dnsrec->qd); + if (status != ARES_SUCCESS) { + return status; } - idx = dnsrec->qdcount; - - dnsrec->qd[idx].name = ares_strdup(name); - if (dnsrec->qd[idx].name == NULL) { - /* No need to clean up anything */ + qd->name = ares_strdup(name); + if (qd->name == NULL) { + ares__array_remove_at(dnsrec->qd, idx); return ARES_ENOMEM; } - - dnsrec->qd[idx].qtype = qtype; - dnsrec->qd[idx].qclass = qclass; - dnsrec->qdcount++; + qd->qtype = qtype; + qd->qclass = qclass; return ARES_SUCCESS; } ares_status_t ares_dns_record_query_set_name(ares_dns_record_t *dnsrec, size_t idx, const char *name) { - char *orig_name = NULL; + char *orig_name = NULL; + ares_dns_qd_t *qd; - if (dnsrec == NULL || idx >= dnsrec->qdcount || name == NULL) { + if (dnsrec == NULL || idx >= ares__array_len(dnsrec->qd) || name == NULL) { return ARES_EFORMERR; } - orig_name = dnsrec->qd[idx].name; - dnsrec->qd[idx].name = ares_strdup(name); - if (dnsrec->qd[idx].name == NULL) { - dnsrec->qd[idx].name = orig_name; - return ARES_ENOMEM; + + qd = ares__array_at(dnsrec->qd, idx); + + orig_name = qd->name; + qd->name = ares_strdup(name); + if (qd->name == NULL) { + qd->name = orig_name; /* LCOV_EXCL_LINE: OutOfMemory */ + return ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ } ares_free(orig_name); @@ -304,12 +311,15 @@ ares_status_t ares_dns_record_query_set_type(ares_dns_record_t *dnsrec, size_t idx, ares_dns_rec_type_t qtype) { - if (dnsrec == NULL || idx >= dnsrec->qdcount || + ares_dns_qd_t *qd; + + if (dnsrec == NULL || idx >= ares__array_len(dnsrec->qd) || !ares_dns_rec_type_isvalid(qtype, ARES_TRUE)) { return ARES_EFORMERR; } - dnsrec->qd[idx].qtype = qtype; + qd = ares__array_at(dnsrec->qd, idx); + qd->qtype = qtype; return ARES_SUCCESS; } @@ -319,20 +329,22 @@ ares_status_t ares_dns_record_query_get(const ares_dns_record_t *dnsrec, ares_dns_rec_type_t *qtype, ares_dns_class_t *qclass) { - if (dnsrec == NULL || idx >= dnsrec->qdcount) { + const ares_dns_qd_t *qd; + if (dnsrec == NULL || idx >= ares__array_len(dnsrec->qd)) { return ARES_EFORMERR; } + qd = ares__array_at(dnsrec->qd, idx); if (name != NULL) { - *name = dnsrec->qd[idx].name; + *name = qd->name; } if (qtype != NULL) { - *qtype = dnsrec->qd[idx].qtype; + *qtype = qd->qtype; } if (qclass != NULL) { - *qclass = dnsrec->qd[idx].qclass; + *qclass = qd->qclass; } return ARES_SUCCESS; @@ -347,59 +359,42 @@ size_t ares_dns_record_rr_cnt(const ares_dns_record_t *dnsrec, switch (sect) { case ARES_SECTION_ANSWER: - return dnsrec->ancount; + return ares__array_len(dnsrec->an); case ARES_SECTION_AUTHORITY: - return dnsrec->nscount; + return ares__array_len(dnsrec->ns); case ARES_SECTION_ADDITIONAL: - return dnsrec->arcount; + return ares__array_len(dnsrec->ar); } - return 0; + return 0; /* LCOV_EXCL_LINE: DefensiveCoding */ } ares_status_t ares_dns_record_rr_prealloc(ares_dns_record_t *dnsrec, ares_dns_section_t sect, size_t cnt) { - ares_dns_rr_t **rr_ptr = NULL; - size_t *rr_alloc = NULL; - ares_dns_rr_t *temp = NULL; + ares__array_t *arr = NULL; - if (dnsrec == NULL || cnt == 0 || !ares_dns_section_isvalid(sect)) { + if (dnsrec == NULL || !ares_dns_section_isvalid(sect)) { return ARES_EFORMERR; } switch (sect) { case ARES_SECTION_ANSWER: - rr_ptr = &dnsrec->an; - rr_alloc = &dnsrec->analloc; + arr = dnsrec->an; break; case ARES_SECTION_AUTHORITY: - rr_ptr = &dnsrec->ns; - rr_alloc = &dnsrec->nsalloc; + arr = dnsrec->ns; break; case ARES_SECTION_ADDITIONAL: - rr_ptr = &dnsrec->ar; - rr_alloc = &dnsrec->aralloc; + arr = dnsrec->ar; break; } - /* Round up cnt to a power of 2 */ - cnt = ares__round_up_pow2(cnt); - - /* Already have that */ - if (cnt <= *rr_alloc) { - return ARES_SUCCESS; - } - - temp = ares_realloc_zero(*rr_ptr, sizeof(*temp) * (*rr_alloc), - sizeof(*temp) * cnt); - if (temp == NULL) { - return ARES_ENOMEM; + if (cnt < ares__array_len(arr)) { + return ARES_EFORMERR; } - *rr_alloc = cnt; - *rr_ptr = temp; - return ARES_SUCCESS; + return ares__array_set_size(arr, cnt); } ares_status_t ares_dns_record_rr_add(ares_dns_rr_t **rr_out, @@ -408,11 +403,10 @@ ares_status_t ares_dns_record_rr_add(ares_dns_rr_t **rr_out, ares_dns_rec_type_t type, ares_dns_class_t rclass, unsigned int ttl) { - ares_dns_rr_t **rr_ptr = NULL; - ares_dns_rr_t *rr = NULL; - size_t *rr_len = NULL; - ares_status_t status; - size_t idx; + ares_dns_rr_t *rr = NULL; + ares__array_t *arr = NULL; + ares_status_t status; + size_t idx; if (dnsrec == NULL || name == NULL || rr_out == NULL || !ares_dns_section_isvalid(sect) || @@ -425,30 +419,25 @@ ares_status_t ares_dns_record_rr_add(ares_dns_rr_t **rr_out, switch (sect) { case ARES_SECTION_ANSWER: - rr_ptr = &dnsrec->an; - rr_len = &dnsrec->ancount; + arr = dnsrec->an; break; case ARES_SECTION_AUTHORITY: - rr_ptr = &dnsrec->ns; - rr_len = &dnsrec->nscount; + arr = dnsrec->ns; break; case ARES_SECTION_ADDITIONAL: - rr_ptr = &dnsrec->ar; - rr_len = &dnsrec->arcount; + arr = dnsrec->ar; break; } - status = ares_dns_record_rr_prealloc(dnsrec, sect, *rr_len + 1); + idx = ares__array_len(arr); + status = ares__array_insert_last((void **)&rr, arr); if (status != ARES_SUCCESS) { - return status; + return status; /* LCOV_EXCL_LINE: OutOfMemory */ } - idx = *rr_len; - rr = &(*rr_ptr)[idx]; - rr->name = ares_strdup(name); if (rr->name == NULL) { - /* No need to clean up anything */ + ares__array_remove_at(arr, idx); return ARES_ENOMEM; } @@ -456,7 +445,6 @@ ares_status_t ares_dns_record_rr_add(ares_dns_rr_t **rr_out, rr->type = type; rr->rclass = rclass; rr->ttl = ttl; - (*rr_len)++; *rr_out = rr; @@ -466,9 +454,7 @@ ares_status_t ares_dns_record_rr_add(ares_dns_rr_t **rr_out, ares_status_t ares_dns_record_rr_del(ares_dns_record_t *dnsrec, ares_dns_section_t sect, size_t idx) { - ares_dns_rr_t *rr_ptr = NULL; - size_t *rr_len = NULL; - size_t cnt_after; + ares__array_t *arr = NULL; if (dnsrec == NULL || !ares_dns_section_isvalid(sect)) { return ARES_EFORMERR; @@ -476,40 +462,23 @@ ares_status_t ares_dns_record_rr_del(ares_dns_record_t *dnsrec, switch (sect) { case ARES_SECTION_ANSWER: - rr_ptr = dnsrec->an; - rr_len = &dnsrec->ancount; + arr = dnsrec->an; break; case ARES_SECTION_AUTHORITY: - rr_ptr = dnsrec->ns; - rr_len = &dnsrec->nscount; + arr = dnsrec->ns; break; case ARES_SECTION_ADDITIONAL: - rr_ptr = dnsrec->ar; - rr_len = &dnsrec->arcount; + arr = dnsrec->ar; break; } - if (idx >= *rr_len) { - return ARES_EFORMERR; - } - - ares__dns_rr_free(&rr_ptr[idx]); - - cnt_after = *rr_len - idx - 1; - - if (cnt_after) { - memmove(&rr_ptr[idx], &rr_ptr[idx + 1], sizeof(*rr_ptr) * cnt_after); - } - - (*rr_len)--; - return ARES_SUCCESS; + return ares__array_remove_at(arr, idx); } ares_dns_rr_t *ares_dns_record_rr_get(ares_dns_record_t *dnsrec, ares_dns_section_t sect, size_t idx) { - ares_dns_rr_t *rr_ptr = NULL; - size_t rr_len = 0; + ares__array_t *arr = NULL; if (dnsrec == NULL || !ares_dns_section_isvalid(sect)) { return NULL; @@ -517,24 +486,17 @@ ares_dns_rr_t *ares_dns_record_rr_get(ares_dns_record_t *dnsrec, switch (sect) { case ARES_SECTION_ANSWER: - rr_ptr = dnsrec->an; - rr_len = dnsrec->ancount; + arr = dnsrec->an; break; case ARES_SECTION_AUTHORITY: - rr_ptr = dnsrec->ns; - rr_len = dnsrec->nscount; + arr = dnsrec->ns; break; case ARES_SECTION_ADDITIONAL: - rr_ptr = dnsrec->ar; - rr_len = dnsrec->arcount; + arr = dnsrec->ar; break; } - if (idx >= rr_len) { - return NULL; - } - - return &rr_ptr[idx]; + return ares__array_at(arr, idx); } const ares_dns_rr_t * @@ -580,7 +542,7 @@ static void *ares_dns_rr_data_ptr(ares_dns_rr_t *dns_rr, ares_dns_rr_key_t key, size_t **lenptr) { if (dns_rr == NULL || dns_rr->type != ares_dns_rr_key_to_rec_type(key)) { - return NULL; + return NULL; /* LCOV_EXCL_LINE: DefensiveCoding */ } switch (key) { @@ -664,11 +626,7 @@ static void *ares_dns_rr_data_ptr(ares_dns_rr_t *dns_rr, ares_dns_rr_key_t key, return &dns_rr->r.sig.signature; case ARES_RR_TXT_DATA: - if (lenptr == NULL) { - return NULL; - } - *lenptr = &dns_rr->r.txt.data_len; - return &dns_rr->r.txt.data; + return &dns_rr->r.txt.strs; case ARES_RR_SRV_PRIORITY: return &dns_rr->r.srv.priority; @@ -883,26 +841,138 @@ const unsigned char *ares_dns_rr_get_bin(const ares_dns_rr_t *dns_rr, size_t const *bin_len = NULL; if ((ares_dns_rr_key_datatype(key) != ARES_DATATYPE_BIN && - ares_dns_rr_key_datatype(key) != ARES_DATATYPE_BINP) || + ares_dns_rr_key_datatype(key) != ARES_DATATYPE_BINP && + ares_dns_rr_key_datatype(key) != ARES_DATATYPE_ABINP) || len == NULL) { return NULL; } + /* Array of strings, return concatenated version */ + if (ares_dns_rr_key_datatype(key) == ARES_DATATYPE_ABINP) { + ares__dns_multistring_t * const *strs = + ares_dns_rr_data_ptr_const(dns_rr, key, NULL); + + if (strs == NULL) { + return NULL; + } + + return ares__dns_multistring_get_combined(*strs, len); + } + + /* Not a multi-string, just straight binary data */ bin = ares_dns_rr_data_ptr_const(dns_rr, key, &bin_len); if (bin == NULL) { - return 0; + return NULL; } /* Shouldn't be possible */ if (bin_len == NULL) { return NULL; } - *len = *bin_len; return *bin; } +size_t ares_dns_rr_get_abin_cnt(const ares_dns_rr_t *dns_rr, + ares_dns_rr_key_t key) +{ + ares__dns_multistring_t * const *strs; + + if (ares_dns_rr_key_datatype(key) != ARES_DATATYPE_ABINP) { + return 0; + } + + strs = ares_dns_rr_data_ptr_const(dns_rr, key, NULL); + if (strs == NULL) { + return 0; + } + + return ares__dns_multistring_cnt(*strs); +} + +const unsigned char *ares_dns_rr_get_abin(const ares_dns_rr_t *dns_rr, + ares_dns_rr_key_t key, size_t idx, + size_t *len) +{ + ares__dns_multistring_t * const *strs; + + if (ares_dns_rr_key_datatype(key) != ARES_DATATYPE_ABINP) { + return NULL; + } + + strs = ares_dns_rr_data_ptr_const(dns_rr, key, NULL); + if (strs == NULL) { + return NULL; + } + + return ares__dns_multistring_get(*strs, idx, len); +} + +ares_status_t ares_dns_rr_del_abin(ares_dns_rr_t *dns_rr, ares_dns_rr_key_t key, + size_t idx) +{ + ares__dns_multistring_t **strs; + + if (ares_dns_rr_key_datatype(key) != ARES_DATATYPE_ABINP) { + return ARES_EFORMERR; + } + + strs = ares_dns_rr_data_ptr(dns_rr, key, NULL); + if (strs == NULL) { + return ARES_EFORMERR; + } + + return ares__dns_multistring_del(*strs, idx); +} + +ares_status_t ares_dns_rr_add_abin(ares_dns_rr_t *dns_rr, ares_dns_rr_key_t key, + const unsigned char *val, size_t len) +{ + ares_status_t status; + ares_dns_datatype_t datatype = ares_dns_rr_key_datatype(key); + ares_bool_t is_nullterm = + (datatype == ARES_DATATYPE_ABINP) ? ARES_TRUE : ARES_FALSE; + size_t alloclen = is_nullterm ? len + 1 : len; + unsigned char *temp; + ares__dns_multistring_t **strs; + + if (ares_dns_rr_key_datatype(key) != ARES_DATATYPE_ABINP) { + return ARES_EFORMERR; + } + + strs = ares_dns_rr_data_ptr(dns_rr, key, NULL); + if (strs == NULL) { + return ARES_EFORMERR; + } + + if (*strs == NULL) { + *strs = ares__dns_multistring_create(); + if (*strs == NULL) { + return ARES_ENOMEM; + } + } + + temp = ares_malloc(alloclen); + if (temp == NULL) { + return ARES_ENOMEM; + } + + memcpy(temp, val, len); + + /* NULL-term ABINP */ + if (is_nullterm) { + temp[len] = 0; + } + + status = ares__dns_multistring_add_own(*strs, temp, len); + if (status != ARES_SUCCESS) { + ares_free(temp); + } + + return status; +} + const char *ares_dns_rr_get_str(const ares_dns_rr_t *dns_rr, ares_dns_rr_key_t key) { @@ -924,7 +994,7 @@ const char *ares_dns_rr_get_str(const ares_dns_rr_t *dns_rr, size_t ares_dns_rr_get_opt_cnt(const ares_dns_rr_t *dns_rr, ares_dns_rr_key_t key) { - ares__dns_options_t * const *opts; + ares__array_t * const *opts; if (ares_dns_rr_key_datatype(key) != ARES_DATATYPE_OPT) { return 0; @@ -935,14 +1005,15 @@ size_t ares_dns_rr_get_opt_cnt(const ares_dns_rr_t *dns_rr, return 0; } - return (*opts)->cnt; + return ares__array_len(*opts); } unsigned short ares_dns_rr_get_opt(const ares_dns_rr_t *dns_rr, ares_dns_rr_key_t key, size_t idx, const unsigned char **val, size_t *val_len) { - ares__dns_options_t * const *opts; + ares__array_t * const *opts; + const ares__dns_optval_t *opt; if (val) { *val = NULL; @@ -960,26 +1031,29 @@ unsigned short ares_dns_rr_get_opt(const ares_dns_rr_t *dns_rr, return 65535; } - if (idx >= (*opts)->cnt) { + opt = ares__array_at(*opts, idx); + if (opt == NULL) { return 65535; } if (val) { - *val = (*opts)->optval[idx].val; + *val = opt->val; } if (val_len) { - *val_len = (*opts)->optval[idx].val_len; + *val_len = opt->val_len; } - return (*opts)->optval[idx].opt; + return opt->opt; } ares_bool_t ares_dns_rr_get_opt_byid(const ares_dns_rr_t *dns_rr, ares_dns_rr_key_t key, unsigned short opt, const unsigned char **val, size_t *val_len) { - ares__dns_options_t * const *opts; - size_t i; + ares__array_t * const *opts; + size_t i; + size_t cnt; + const ares__dns_optval_t *optptr = NULL; if (val) { *val = NULL; @@ -997,21 +1071,26 @@ ares_bool_t ares_dns_rr_get_opt_byid(const ares_dns_rr_t *dns_rr, return ARES_FALSE; } - for (i = 0; i < (*opts)->cnt; i++) { - if ((*opts)->optval[i].opt == opt) { + cnt = ares__array_len(*opts); + for (i = 0; i < cnt; i++) { + optptr = ares__array_at(*opts, i); + if (optptr == NULL) { + return ARES_FALSE; + } + if (optptr->opt == opt) { break; } } - if (i >= (*opts)->cnt) { + if (i >= cnt || optptr == NULL) { return ARES_FALSE; } if (val) { - *val = (*opts)->optval[i].val; + *val = optptr->val; } if (val_len) { - *val_len = (*opts)->optval[i].val_len; + *val_len = optptr->val_len; } return ARES_TRUE; } @@ -1115,10 +1194,30 @@ ares_status_t ares_dns_rr_set_bin_own(ares_dns_rr_t *dns_rr, size_t *bin_len = NULL; if (ares_dns_rr_key_datatype(key) != ARES_DATATYPE_BIN && - ares_dns_rr_key_datatype(key) != ARES_DATATYPE_BINP) { + ares_dns_rr_key_datatype(key) != ARES_DATATYPE_BINP && + ares_dns_rr_key_datatype(key) != ARES_DATATYPE_ABINP) { return ARES_EFORMERR; } + if (ares_dns_rr_key_datatype(key) == ARES_DATATYPE_ABINP) { + ares__dns_multistring_t **strs = ares_dns_rr_data_ptr(dns_rr, key, NULL); + if (strs == NULL) { + return ARES_EFORMERR; + } + + if (*strs == NULL) { + *strs = ares__dns_multistring_create(); + if (*strs == NULL) { + return ARES_ENOMEM; + } + } + + /* Clear all existing entries as this is an override */ + ares__dns_multistring_clear(*strs); + + return ares__dns_multistring_add_own(*strs, val, len); + } + bin = ares_dns_rr_data_ptr(dns_rr, key, &bin_len); if (bin == NULL || bin_len == NULL) { return ARES_EFORMERR; @@ -1138,7 +1237,11 @@ ares_status_t ares_dns_rr_set_bin(ares_dns_rr_t *dns_rr, ares_dns_rr_key_t key, { ares_status_t status; ares_dns_datatype_t datatype = ares_dns_rr_key_datatype(key); - size_t alloclen = (datatype == ARES_DATATYPE_BINP) ? len + 1 : len; + ares_bool_t is_nullterm = + (datatype == ARES_DATATYPE_BINP || datatype == ARES_DATATYPE_ABINP) + ? ARES_TRUE + : ARES_FALSE; + size_t alloclen = is_nullterm ? len + 1 : len; unsigned char *temp = ares_malloc(alloclen); if (temp == NULL) { @@ -1148,7 +1251,7 @@ ares_status_t ares_dns_rr_set_bin(ares_dns_rr_t *dns_rr, ares_dns_rr_key_t key, memcpy(temp, val, len); /* NULL-term BINP */ - if (datatype == ARES_DATATYPE_BINP) { + if (is_nullterm) { temp[len] = 0; } @@ -1204,12 +1307,47 @@ ares_status_t ares_dns_rr_set_str(ares_dns_rr_t *dns_rr, ares_dns_rr_key_t key, return status; } +ares_status_t ares_dns_rr_set_abin_own(ares_dns_rr_t *dns_rr, + ares_dns_rr_key_t key, + ares__dns_multistring_t *strs) +{ + ares__dns_multistring_t **strs_ptr; + + if (ares_dns_rr_key_datatype(key) != ARES_DATATYPE_ABINP) { + return ARES_EFORMERR; + } + + strs_ptr = ares_dns_rr_data_ptr(dns_rr, key, NULL); + if (strs_ptr == NULL) { + return ARES_EFORMERR; + } + + if (*strs_ptr != NULL) { + ares__dns_multistring_destroy(*strs_ptr); + } + *strs_ptr = strs; + + return ARES_SUCCESS; +} + +static void ares__dns_opt_free_cb(void *arg) +{ + ares__dns_optval_t *opt = arg; + if (opt == NULL) { + return; + } + ares_free(opt->val); +} + ares_status_t ares_dns_rr_set_opt_own(ares_dns_rr_t *dns_rr, ares_dns_rr_key_t key, unsigned short opt, unsigned char *val, size_t val_len) { - ares__dns_options_t **options; - size_t idx; + ares__array_t **options; + ares__dns_optval_t *optptr = NULL; + size_t idx; + size_t cnt; + ares_status_t status; if (ares_dns_rr_key_datatype(key) != ARES_DATATYPE_OPT) { return ARES_EFORMERR; @@ -1221,54 +1359,39 @@ ares_status_t ares_dns_rr_set_opt_own(ares_dns_rr_t *dns_rr, } if (*options == NULL) { - *options = ares_malloc_zero(sizeof(**options)); + *options = + ares__array_create(sizeof(ares__dns_optval_t), ares__dns_opt_free_cb); } if (*options == NULL) { return ARES_ENOMEM; } - for (idx = 0; idx < (*options)->cnt; idx++) { - if ((*options)->optval[idx].opt == opt) { + cnt = ares__array_len(*options); + for (idx = 0; idx < cnt; idx++) { + optptr = ares__array_at(*options, idx); + if (optptr == NULL) { + return ARES_EFORMERR; + } + if (optptr->opt == opt) { break; } } /* Duplicate entry, replace */ - if (idx != (*options)->cnt) { + if (idx != cnt && optptr != NULL) { goto done; } - idx = (*options)->cnt; - - /* Expand by powers of 2 */ - if (idx >= (*options)->alloc) { - size_t alloc_size = (*options)->alloc; - void *temp; - - if (alloc_size == 0) { - alloc_size = 1; - } else { - alloc_size <<= 1; - } - - temp = ares_realloc_zero((*options)->optval, - (*options)->alloc * sizeof(*(*options)->optval), - alloc_size * sizeof(*(*options)->optval)); - if (temp == NULL) { - return ARES_ENOMEM; - } - - (*options)->optval = temp; - (*options)->alloc = alloc_size; + status = ares__array_insert_last((void **)&optptr, *options); + if (status != ARES_SUCCESS) { + return status; } - (*options)->cnt++; - done: - ares_free((*options)->optval[idx].val); - (*options)->optval[idx].opt = opt; - (*options)->optval[idx].val = val; - (*options)->optval[idx].val_len = val_len; + ares_free(optptr->val); + optptr->opt = opt; + optptr->val = val; + optptr->val_len = val_len; return ARES_SUCCESS; } @@ -1297,6 +1420,43 @@ ares_status_t ares_dns_rr_set_opt(ares_dns_rr_t *dns_rr, ares_dns_rr_key_t key, return status; } +ares_status_t ares_dns_rr_del_opt_byid(ares_dns_rr_t *dns_rr, + ares_dns_rr_key_t key, + unsigned short opt) +{ + ares__array_t **options; + const ares__dns_optval_t *optptr; + size_t idx; + size_t cnt; + + if (ares_dns_rr_key_datatype(key) != ARES_DATATYPE_OPT) { + return ARES_EFORMERR; + } + + options = ares_dns_rr_data_ptr(dns_rr, key, NULL); + if (options == NULL) { + return ARES_EFORMERR; + } + + /* No options */ + if (*options == NULL) { + return ARES_SUCCESS; + } + + cnt = ares__array_len(*options); + for (idx = 0; idx < cnt; idx++) { + optptr = ares__array_at_const(*options, idx); + if (optptr == NULL) { + return ARES_ENOTFOUND; + } + if (optptr->opt == opt) { + return ares__array_remove_at(*options, idx); + } + } + + return ARES_ENOTFOUND; +} + char *ares_dns_addr_to_ptr(const struct ares_addr *addr) { ares__buf_t *buf = NULL; @@ -1369,8 +1529,20 @@ fail: return NULL; } -/* search for an OPT RR in the response */ -ares_bool_t ares_dns_has_opt_rr(const ares_dns_record_t *rec) +ares_dns_rr_t *ares_dns_get_opt_rr(ares_dns_record_t *rec) +{ + size_t i; + for (i = 0; i < ares_dns_record_rr_cnt(rec, ARES_SECTION_ADDITIONAL); i++) { + ares_dns_rr_t *rr = ares_dns_record_rr_get(rec, ARES_SECTION_ADDITIONAL, i); + + if (ares_dns_rr_get_type(rr) == ARES_REC_TYPE_OPT) { + return rr; + } + } + return NULL; +} + +const ares_dns_rr_t *ares_dns_get_opt_rr_const(const ares_dns_record_t *rec) { size_t i; for (i = 0; i < ares_dns_record_rr_cnt(rec, ARES_SECTION_ADDITIONAL); i++) { @@ -1378,10 +1550,10 @@ ares_bool_t ares_dns_has_opt_rr(const ares_dns_record_t *rec) ares_dns_record_rr_get_const(rec, ARES_SECTION_ADDITIONAL, i); if (ares_dns_rr_get_type(rr) == ARES_REC_TYPE_OPT) { - return ARES_TRUE; + return rr; } } - return ARES_FALSE; + return NULL; } /* Construct a DNS record for a name with given class and type. Used internally @@ -1460,26 +1632,34 @@ done: return status; } -ares_dns_record_t *ares_dns_record_duplicate(const ares_dns_record_t *dnsrec) +ares_status_t ares_dns_record_duplicate_ex(ares_dns_record_t **dest, + const ares_dns_record_t *src) { - unsigned char *data = NULL; - size_t data_len = 0; - ares_dns_record_t *out = NULL; - ares_status_t status; + unsigned char *data = NULL; + size_t data_len = 0; + ares_status_t status; - if (dnsrec == NULL) { - return NULL; + if (dest == NULL || src == NULL) { + return ARES_EFORMERR; } - status = ares_dns_write(dnsrec, &data, &data_len); + *dest = NULL; + + status = ares_dns_write(src, &data, &data_len); if (status != ARES_SUCCESS) { - return NULL; + return status; } - status = ares_dns_parse(data, data_len, 0, &out); + status = ares_dns_parse(data, data_len, 0, dest); ares_free(data); - if (status != ARES_SUCCESS) { - return NULL; - } - return out; + + return status; +} + +ares_dns_record_t *ares_dns_record_duplicate(const ares_dns_record_t *dnsrec) +{ + ares_dns_record_t *dest = NULL; + + ares_dns_record_duplicate_ex(&dest, dnsrec); + return dest; } diff --git a/contrib/libs/c-ares/src/lib/ares_dns_write.c b/contrib/libs/c-ares/src/lib/record/ares_dns_write.c index 1643f08103..8a3addd9f0 100644 --- a/contrib/libs/c-ares/src/lib/ares_dns_write.c +++ b/contrib/libs/c-ares/src/lib/record/ares_dns_write.c @@ -23,8 +23,6 @@ * * SPDX-License-Identifier: MIT */ -#include "ares_setup.h" -#include "ares.h" #include "ares_private.h" #include <limits.h> #ifdef HAVE_STDINT_H @@ -44,7 +42,7 @@ static ares_status_t ares_dns_write_header(const ares_dns_record_t *dnsrec, /* ID */ status = ares__buf_append_be16(buf, dnsrec->id); if (status != ARES_SUCCESS) { - return status; + return status; /* LCOV_EXCL_LINE: OutOfMemory */ } /* Flags */ @@ -93,7 +91,7 @@ static ares_status_t ares_dns_write_header(const ares_dns_record_t *dnsrec, } /* RCODE */ - if (dnsrec->rcode > 15 && !ares_dns_has_opt_rr(dnsrec)) { + if (dnsrec->rcode > 15 && ares_dns_get_opt_rr_const(dnsrec) == NULL) { /* Must have OPT RR in order to write extended error codes */ rcode = ARES_RCODE_SERVFAIL; } else { @@ -103,31 +101,35 @@ static ares_status_t ares_dns_write_header(const ares_dns_record_t *dnsrec, status = ares__buf_append_be16(buf, u16); if (status != ARES_SUCCESS) { - return status; + return status; /* LCOV_EXCL_LINE: OutOfMemory */ } /* QDCOUNT */ - status = ares__buf_append_be16(buf, (unsigned short)dnsrec->qdcount); + status = ares__buf_append_be16( + buf, (unsigned short)ares_dns_record_query_cnt(dnsrec)); if (status != ARES_SUCCESS) { - return status; + return status; /* LCOV_EXCL_LINE: OutOfMemory */ } /* ANCOUNT */ - status = ares__buf_append_be16(buf, (unsigned short)dnsrec->ancount); + status = ares__buf_append_be16( + buf, (unsigned short)ares_dns_record_rr_cnt(dnsrec, ARES_SECTION_ANSWER)); if (status != ARES_SUCCESS) { - return status; + return status; /* LCOV_EXCL_LINE: OutOfMemory */ } /* NSCOUNT */ - status = ares__buf_append_be16(buf, (unsigned short)dnsrec->nscount); + status = ares__buf_append_be16(buf, (unsigned short)ares_dns_record_rr_cnt( + dnsrec, ARES_SECTION_AUTHORITY)); if (status != ARES_SUCCESS) { - return status; + return status; /* LCOV_EXCL_LINE: OutOfMemory */ } /* ARCOUNT */ - status = ares__buf_append_be16(buf, (unsigned short)dnsrec->arcount); + status = ares__buf_append_be16(buf, (unsigned short)ares_dns_record_rr_cnt( + dnsrec, ARES_SECTION_ADDITIONAL)); if (status != ARES_SUCCESS) { - return status; + return status; /* LCOV_EXCL_LINE: OutOfMemory */ } return ARES_SUCCESS; @@ -159,13 +161,13 @@ static ares_status_t ares_dns_write_questions(const ares_dns_record_t *dnsrec, /* Type */ status = ares__buf_append_be16(buf, (unsigned short)qtype); if (status != ARES_SUCCESS) { - return status; + return status; /* LCOV_EXCL_LINE: OutOfMemory */ } /* Class */ status = ares__buf_append_be16(buf, (unsigned short)qclass); if (status != ARES_SUCCESS) { - return status; + return status; /* LCOV_EXCL_LINE: OutOfMemory */ } } @@ -182,7 +184,7 @@ static ares_status_t ares_dns_write_rr_name(ares__buf_t *buf, name = ares_dns_rr_get_str(rr, key); if (name == NULL) { - return ARES_EFORMERR; + return ARES_EFORMERR; /* LCOV_EXCL_LINE: DefensiveCoding */ } return ares__dns_name_write(buf, namelist, validate_hostname, name); @@ -198,7 +200,7 @@ static ares_status_t ares_dns_write_rr_str(ares__buf_t *buf, str = ares_dns_rr_get_str(rr, key); if (str == NULL) { - return ARES_EFORMERR; + return ARES_EFORMERR; /* LCOV_EXCL_LINE: DefensiveCoding */ } len = ares_strlen(str); @@ -209,7 +211,7 @@ static ares_status_t ares_dns_write_rr_str(ares__buf_t *buf, /* Write 1 byte length */ status = ares__buf_append_byte(buf, (unsigned char)(len & 0xFF)); if (status != ARES_SUCCESS) { - return status; + return status; /* LCOV_EXCL_LINE: OutOfMemory */ } if (len == 0) { @@ -220,20 +222,14 @@ static ares_status_t ares_dns_write_rr_str(ares__buf_t *buf, return ares__buf_append(buf, (const unsigned char *)str, len); } -static ares_status_t ares_dns_write_rr_binstrs(ares__buf_t *buf, - const ares_dns_rr_t *rr, - ares_dns_rr_key_t key) +static ares_status_t ares_dns_write_binstr(ares__buf_t *buf, + const unsigned char *bin, + size_t bin_len) { - const unsigned char *bin; const unsigned char *ptr; - size_t bin_len; size_t ptr_len; ares_status_t status; - bin = ares_dns_rr_get_bin(rr, key, &bin_len); - if (bin == NULL) { - return ARES_EFORMERR; - } /* split into possible multiple 255-byte or less length strings */ ptr = bin; ptr_len = bin_len; @@ -246,14 +242,14 @@ static ares_status_t ares_dns_write_rr_binstrs(ares__buf_t *buf, /* Length */ status = ares__buf_append_byte(buf, (unsigned char)(len & 0xFF)); if (status != ARES_SUCCESS) { - return status; + return status; /* LCOV_EXCL_LINE: OutOfMemory */ } /* String */ if (len) { status = ares__buf_append(buf, ptr, len); if (status != ARES_SUCCESS) { - return status; + return status; /* LCOV_EXCL_LINE: OutOfMemory */ } } @@ -264,12 +260,39 @@ static ares_status_t ares_dns_write_rr_binstrs(ares__buf_t *buf, return ARES_SUCCESS; } +static ares_status_t ares_dns_write_rr_abin(ares__buf_t *buf, + const ares_dns_rr_t *rr, + ares_dns_rr_key_t key) +{ + ares_status_t status = ARES_EFORMERR; + size_t i; + size_t cnt = ares_dns_rr_get_abin_cnt(rr, key); + + if (cnt == 0) { + return ARES_EFORMERR; + } + + for (i = 0; i < cnt; i++) { + const unsigned char *bin; + size_t bin_len; + + bin = ares_dns_rr_get_abin(rr, key, i, &bin_len); + + status = ares_dns_write_binstr(buf, bin, bin_len); + if (status != ARES_SUCCESS) { + break; + } + } + + return status; +} + static ares_status_t ares_dns_write_rr_be32(ares__buf_t *buf, const ares_dns_rr_t *rr, ares_dns_rr_key_t key) { if (ares_dns_rr_key_datatype(key) != ARES_DATATYPE_U32) { - return ARES_EFORMERR; + return ARES_EFORMERR; /* LCOV_EXCL_LINE: DefensiveCoding */ } return ares__buf_append_be32(buf, ares_dns_rr_get_u32(rr, key)); } @@ -279,7 +302,7 @@ static ares_status_t ares_dns_write_rr_be16(ares__buf_t *buf, ares_dns_rr_key_t key) { if (ares_dns_rr_key_datatype(key) != ARES_DATATYPE_U16) { - return ARES_EFORMERR; + return ARES_EFORMERR; /* LCOV_EXCL_LINE: DefensiveCoding */ } return ares__buf_append_be16(buf, ares_dns_rr_get_u16(rr, key)); } @@ -289,7 +312,7 @@ static ares_status_t ares_dns_write_rr_u8(ares__buf_t *buf, ares_dns_rr_key_t key) { if (ares_dns_rr_key_datatype(key) != ARES_DATATYPE_U8) { - return ARES_EFORMERR; + return ARES_EFORMERR; /* LCOV_EXCL_LINE: DefensiveCoding */ } return ares__buf_append_byte(buf, ares_dns_rr_get_u8(rr, key)); } @@ -303,7 +326,7 @@ static ares_status_t ares_dns_write_rr_a(ares__buf_t *buf, addr = ares_dns_rr_get_addr(rr, ARES_RR_A_ADDR); if (addr == NULL) { - return ARES_EFORMERR; + return ARES_EFORMERR; /* LCOV_EXCL_LINE: DefensiveCoding */ } return ares__buf_append(buf, (const unsigned char *)addr, sizeof(*addr)); @@ -348,25 +371,25 @@ static ares_status_t ares_dns_write_rr_soa(ares__buf_t *buf, /* SERIAL */ status = ares_dns_write_rr_be32(buf, rr, ARES_RR_SOA_SERIAL); if (status != ARES_SUCCESS) { - return status; + return status; /* LCOV_EXCL_LINE: OutOfMemory */ } /* REFRESH */ status = ares_dns_write_rr_be32(buf, rr, ARES_RR_SOA_REFRESH); if (status != ARES_SUCCESS) { - return status; + return status; /* LCOV_EXCL_LINE: OutOfMemory */ } /* RETRY */ status = ares_dns_write_rr_be32(buf, rr, ARES_RR_SOA_RETRY); if (status != ARES_SUCCESS) { - return status; + return status; /* LCOV_EXCL_LINE: OutOfMemory */ } /* EXPIRE */ status = ares_dns_write_rr_be32(buf, rr, ARES_RR_SOA_EXPIRE); if (status != ARES_SUCCESS) { - return status; + return status; /* LCOV_EXCL_LINE: OutOfMemory */ } /* MINIMUM */ @@ -408,7 +431,7 @@ static ares_status_t ares_dns_write_rr_mx(ares__buf_t *buf, /* PREFERENCE */ status = ares_dns_write_rr_be16(buf, rr, ARES_RR_MX_PREFERENCE); if (status != ARES_SUCCESS) { - return status; + return status; /* LCOV_EXCL_LINE: OutOfMemory */ } /* EXCHANGE */ @@ -421,7 +444,7 @@ static ares_status_t ares_dns_write_rr_txt(ares__buf_t *buf, ares__llist_t **namelist) { (void)namelist; - return ares_dns_write_rr_binstrs(buf, rr, ARES_RR_TXT_DATA); + return ares_dns_write_rr_abin(buf, rr, ARES_RR_TXT_DATA); } static ares_status_t ares_dns_write_rr_sig(ares__buf_t *buf, @@ -437,43 +460,43 @@ static ares_status_t ares_dns_write_rr_sig(ares__buf_t *buf, /* TYPE COVERED */ status = ares_dns_write_rr_be16(buf, rr, ARES_RR_SIG_TYPE_COVERED); if (status != ARES_SUCCESS) { - return status; + return status; /* LCOV_EXCL_LINE: OutOfMemory */ } /* ALGORITHM */ status = ares_dns_write_rr_u8(buf, rr, ARES_RR_SIG_ALGORITHM); if (status != ARES_SUCCESS) { - return status; + return status; /* LCOV_EXCL_LINE: OutOfMemory */ } /* LABELS */ status = ares_dns_write_rr_u8(buf, rr, ARES_RR_SIG_LABELS); if (status != ARES_SUCCESS) { - return status; + return status; /* LCOV_EXCL_LINE: OutOfMemory */ } /* ORIGINAL TTL */ status = ares_dns_write_rr_be32(buf, rr, ARES_RR_SIG_ORIGINAL_TTL); if (status != ARES_SUCCESS) { - return status; + return status; /* LCOV_EXCL_LINE: OutOfMemory */ } /* EXPIRATION */ status = ares_dns_write_rr_be32(buf, rr, ARES_RR_SIG_EXPIRATION); if (status != ARES_SUCCESS) { - return status; + return status; /* LCOV_EXCL_LINE: OutOfMemory */ } /* INCEPTION */ status = ares_dns_write_rr_be32(buf, rr, ARES_RR_SIG_INCEPTION); if (status != ARES_SUCCESS) { - return status; + return status; /* LCOV_EXCL_LINE: OutOfMemory */ } /* KEY TAG */ status = ares_dns_write_rr_be16(buf, rr, ARES_RR_SIG_KEY_TAG); if (status != ARES_SUCCESS) { - return status; + return status; /* LCOV_EXCL_LINE: OutOfMemory */ } /* SIGNERS NAME */ @@ -501,7 +524,7 @@ static ares_status_t ares_dns_write_rr_aaaa(ares__buf_t *buf, addr = ares_dns_rr_get_addr6(rr, ARES_RR_AAAA_ADDR); if (addr == NULL) { - return ARES_EFORMERR; + return ARES_EFORMERR; /* LCOV_EXCL_LINE: DefensiveCoding */ } return ares__buf_append(buf, (const unsigned char *)addr, sizeof(*addr)); @@ -516,19 +539,19 @@ static ares_status_t ares_dns_write_rr_srv(ares__buf_t *buf, /* PRIORITY */ status = ares_dns_write_rr_be16(buf, rr, ARES_RR_SRV_PRIORITY); if (status != ARES_SUCCESS) { - return status; + return status; /* LCOV_EXCL_LINE: OutOfMemory */ } /* WEIGHT */ status = ares_dns_write_rr_be16(buf, rr, ARES_RR_SRV_WEIGHT); if (status != ARES_SUCCESS) { - return status; + return status; /* LCOV_EXCL_LINE: OutOfMemory */ } /* PORT */ status = ares_dns_write_rr_be16(buf, rr, ARES_RR_SRV_PORT); if (status != ARES_SUCCESS) { - return status; + return status; /* LCOV_EXCL_LINE: OutOfMemory */ } /* TARGET */ @@ -545,31 +568,31 @@ static ares_status_t ares_dns_write_rr_naptr(ares__buf_t *buf, /* ORDER */ status = ares_dns_write_rr_be16(buf, rr, ARES_RR_NAPTR_ORDER); if (status != ARES_SUCCESS) { - return status; + return status; /* LCOV_EXCL_LINE: OutOfMemory */ } /* PREFERENCE */ status = ares_dns_write_rr_be16(buf, rr, ARES_RR_NAPTR_PREFERENCE); if (status != ARES_SUCCESS) { - return status; + return status; /* LCOV_EXCL_LINE: OutOfMemory */ } /* FLAGS */ status = ares_dns_write_rr_str(buf, rr, ARES_RR_NAPTR_FLAGS); if (status != ARES_SUCCESS) { - return status; + return status; /* LCOV_EXCL_LINE: OutOfMemory */ } /* SERVICES */ status = ares_dns_write_rr_str(buf, rr, ARES_RR_NAPTR_SERVICES); if (status != ARES_SUCCESS) { - return status; + return status; /* LCOV_EXCL_LINE: OutOfMemory */ } /* REGEXP */ status = ares_dns_write_rr_str(buf, rr, ARES_RR_NAPTR_REGEXP); if (status != ARES_SUCCESS) { - return status; + return status; /* LCOV_EXCL_LINE: OutOfMemory */ } /* REPLACEMENT */ @@ -589,6 +612,12 @@ static ares_status_t ares_dns_write_rr_opt(ares__buf_t *buf, (void)namelist; + /* Coverity reports on this even though its not possible when taken + * into context */ + if (len == 0) { + return ARES_EFORMERR; /* LCOV_EXCL_LINE: DefensiveCoding */ + } + /* We need to go back and overwrite the class and ttl that were emitted as * the OPT record overloads them for its own use (yes, very strange!) */ status = ares__buf_set_length(buf, len - 2 /* RDLENGTH */ @@ -601,7 +630,7 @@ static ares_status_t ares_dns_write_rr_opt(ares__buf_t *buf, /* Class -> UDP Size */ status = ares_dns_write_rr_be16(buf, rr, ARES_RR_OPT_UDP_SIZE); if (status != ARES_SUCCESS) { - return status; + return status; /* LCOV_EXCL_LINE: OutOfMemory */ } /* TTL -> rcode (u8) << 24 | version (u8) << 16 | flags (u16) */ @@ -611,7 +640,7 @@ static ares_status_t ares_dns_write_rr_opt(ares__buf_t *buf, status = ares__buf_append_be32(buf, ttl); if (status != ARES_SUCCESS) { - return status; + return status; /* LCOV_EXCL_LINE: OutOfMemory */ } /* Now go back to real end */ @@ -631,20 +660,20 @@ static ares_status_t ares_dns_write_rr_opt(ares__buf_t *buf, /* BE16 option */ status = ares__buf_append_be16(buf, opt); if (status != ARES_SUCCESS) { - return status; + return status; /* LCOV_EXCL_LINE: OutOfMemory */ } /* BE16 length */ status = ares__buf_append_be16(buf, (unsigned short)(val_len & 0xFFFF)); if (status != ARES_SUCCESS) { - return status; + return status; /* LCOV_EXCL_LINE: OutOfMemory */ } /* Value */ if (val && val_len) { status = ares__buf_append(buf, val, val_len); if (status != ARES_SUCCESS) { - return status; + return status; /* LCOV_EXCL_LINE: OutOfMemory */ } } } @@ -665,19 +694,19 @@ static ares_status_t ares_dns_write_rr_tlsa(ares__buf_t *buf, /* CERT_USAGE */ status = ares_dns_write_rr_u8(buf, rr, ARES_RR_TLSA_CERT_USAGE); if (status != ARES_SUCCESS) { - return status; + return status; /* LCOV_EXCL_LINE: OutOfMemory */ } /* SELECTOR */ status = ares_dns_write_rr_u8(buf, rr, ARES_RR_TLSA_SELECTOR); if (status != ARES_SUCCESS) { - return status; + return status; /* LCOV_EXCL_LINE: OutOfMemory */ } /* MATCH */ status = ares_dns_write_rr_u8(buf, rr, ARES_RR_TLSA_MATCH); if (status != ARES_SUCCESS) { - return status; + return status; /* LCOV_EXCL_LINE: OutOfMemory */ } /* DATA -- binary, rest of buffer, required to be non-zero length */ @@ -699,7 +728,7 @@ static ares_status_t ares_dns_write_rr_svcb(ares__buf_t *buf, /* PRIORITY */ status = ares_dns_write_rr_be16(buf, rr, ARES_RR_SVCB_PRIORITY); if (status != ARES_SUCCESS) { - return status; + return status; /* LCOV_EXCL_LINE: OutOfMemory */ } /* TARGET */ @@ -720,20 +749,20 @@ static ares_status_t ares_dns_write_rr_svcb(ares__buf_t *buf, /* BE16 option */ status = ares__buf_append_be16(buf, opt); if (status != ARES_SUCCESS) { - return status; + return status; /* LCOV_EXCL_LINE: OutOfMemory */ } /* BE16 length */ status = ares__buf_append_be16(buf, (unsigned short)(val_len & 0xFFFF)); if (status != ARES_SUCCESS) { - return status; + return status; /* LCOV_EXCL_LINE: OutOfMemory */ } /* Value */ if (val && val_len) { status = ares__buf_append(buf, val, val_len); if (status != ARES_SUCCESS) { - return status; + return status; /* LCOV_EXCL_LINE: OutOfMemory */ } } } @@ -750,7 +779,7 @@ static ares_status_t ares_dns_write_rr_https(ares__buf_t *buf, /* PRIORITY */ status = ares_dns_write_rr_be16(buf, rr, ARES_RR_HTTPS_PRIORITY); if (status != ARES_SUCCESS) { - return status; + return status; /* LCOV_EXCL_LINE: OutOfMemory */ } /* TARGET */ @@ -771,20 +800,20 @@ static ares_status_t ares_dns_write_rr_https(ares__buf_t *buf, /* BE16 option */ status = ares__buf_append_be16(buf, opt); if (status != ARES_SUCCESS) { - return status; + return status; /* LCOV_EXCL_LINE: OutOfMemory */ } /* BE16 length */ status = ares__buf_append_be16(buf, (unsigned short)(val_len & 0xFFFF)); if (status != ARES_SUCCESS) { - return status; + return status; /* LCOV_EXCL_LINE: OutOfMemory */ } /* Value */ if (val && val_len) { status = ares__buf_append(buf, val, val_len); if (status != ARES_SUCCESS) { - return status; + return status; /* LCOV_EXCL_LINE: OutOfMemory */ } } } @@ -803,13 +832,13 @@ static ares_status_t ares_dns_write_rr_uri(ares__buf_t *buf, /* PRIORITY */ status = ares_dns_write_rr_be16(buf, rr, ARES_RR_URI_PRIORITY); if (status != ARES_SUCCESS) { - return status; + return status; /* LCOV_EXCL_LINE: OutOfMemory */ } /* WEIGHT */ status = ares_dns_write_rr_be16(buf, rr, ARES_RR_URI_WEIGHT); if (status != ARES_SUCCESS) { - return status; + return status; /* LCOV_EXCL_LINE: OutOfMemory */ } /* TARGET -- not in DNS string format, rest of buffer, required to be @@ -836,13 +865,13 @@ static ares_status_t ares_dns_write_rr_caa(ares__buf_t *buf, /* CRITICAL */ status = ares_dns_write_rr_u8(buf, rr, ARES_RR_CAA_CRITICAL); if (status != ARES_SUCCESS) { - return status; + return status; /* LCOV_EXCL_LINE: OutOfMemory */ } /* Tag */ status = ares_dns_write_rr_str(buf, rr, ARES_RR_CAA_TAG); if (status != ARES_SUCCESS) { - return status; + return status; /* LCOV_EXCL_LINE: OutOfMemory */ } /* Value - binary! (remaining buffer */ @@ -865,6 +894,12 @@ static ares_status_t ares_dns_write_rr_raw_rr(ares__buf_t *buf, (void)namelist; + /* Coverity reports on this even though its not possible when taken + * into context */ + if (len == 0) { + return ARES_EFORMERR; /* LCOV_EXCL_LINE: DefensiveCoding */ + } + /* We need to go back and overwrite the type that was emitted by the parent * function */ status = ares__buf_set_length(buf, len - 2 /* RDLENGTH */ @@ -877,7 +912,7 @@ static ares_status_t ares_dns_write_rr_raw_rr(ares__buf_t *buf, status = ares_dns_write_rr_be16(buf, rr, ARES_RR_RAW_RR_TYPE); if (status != ARES_SUCCESS) { - return status; + return status; /* LCOV_EXCL_LINE: OutOfMemory */ } /* Now go back to real end */ @@ -919,7 +954,7 @@ static ares_status_t ares_dns_write_rr(const ares_dns_record_t *dnsrec, rr = ares_dns_record_rr_get_const(dnsrec, section, i); if (rr == NULL) { - return ARES_EFORMERR; + return ARES_EFORMERR; /* LCOV_EXCL_LINE: DefensiveCoding */ } type = ares_dns_rr_get_type(rr); @@ -938,14 +973,14 @@ static ares_status_t ares_dns_write_rr(const ares_dns_record_t *dnsrec, /* Type */ status = ares__buf_append_be16(buf, (unsigned short)type); if (status != ARES_SUCCESS) { - return status; + return status; /* LCOV_EXCL_LINE: OutOfMemory */ } /* Class */ status = ares__buf_append_be16(buf, (unsigned short)ares_dns_rr_get_class(rr)); if (status != ARES_SUCCESS) { - return status; + return status; /* LCOV_EXCL_LINE: OutOfMemory */ } /* TTL */ @@ -957,14 +992,14 @@ static ares_status_t ares_dns_write_rr(const ares_dns_record_t *dnsrec, } status = ares__buf_append_be32(buf, ttl); if (status != ARES_SUCCESS) { - return status; + return status; /* LCOV_EXCL_LINE: OutOfMemory */ } /* Length */ pos_len = ares__buf_len(buf); /* Save to write real length later */ status = ares__buf_append_be16(buf, 0); if (status != ARES_SUCCESS) { - return status; + return status; /* LCOV_EXCL_LINE: OutOfMemory */ } /* Data */ @@ -1047,7 +1082,7 @@ static ares_status_t ares_dns_write_rr(const ares_dns_record_t *dnsrec, status = ares__buf_append_be16(buf, (unsigned short)(rdlength & 0xFFFF)); if (status != ARES_SUCCESS) { - return status; + return status; /* LCOV_EXCL_LINE: OutOfMemory */ } status = ares__buf_set_length(buf, end_length); @@ -1059,52 +1094,121 @@ static ares_status_t ares_dns_write_rr(const ares_dns_record_t *dnsrec, return ARES_SUCCESS; } -ares_status_t ares_dns_write(const ares_dns_record_t *dnsrec, - unsigned char **buf, size_t *buf_len) +ares_status_t ares_dns_write_buf(const ares_dns_record_t *dnsrec, + ares__buf_t *buf) { - ares__buf_t *b = NULL; - ares_status_t status; ares__llist_t *namelist = NULL; + size_t orig_len; + ares_status_t status; - if (buf == NULL || buf_len == NULL || dnsrec == NULL) { + if (dnsrec == NULL || buf == NULL) { return ARES_EFORMERR; } - *buf = NULL; - *buf_len = 0; + orig_len = ares__buf_len(buf); - b = ares__buf_create(); - if (b == NULL) { - return ARES_ENOMEM; + status = ares_dns_write_header(dnsrec, buf); + if (status != ARES_SUCCESS) { + goto done; } - status = ares_dns_write_header(dnsrec, b); + status = ares_dns_write_questions(dnsrec, &namelist, buf); if (status != ARES_SUCCESS) { goto done; } - status = ares_dns_write_questions(dnsrec, &namelist, b); + status = ares_dns_write_rr(dnsrec, &namelist, ARES_SECTION_ANSWER, buf); if (status != ARES_SUCCESS) { goto done; } - status = ares_dns_write_rr(dnsrec, &namelist, ARES_SECTION_ANSWER, b); + status = ares_dns_write_rr(dnsrec, &namelist, ARES_SECTION_AUTHORITY, buf); if (status != ARES_SUCCESS) { goto done; } - status = ares_dns_write_rr(dnsrec, &namelist, ARES_SECTION_AUTHORITY, b); + status = ares_dns_write_rr(dnsrec, &namelist, ARES_SECTION_ADDITIONAL, buf); if (status != ARES_SUCCESS) { goto done; } - status = ares_dns_write_rr(dnsrec, &namelist, ARES_SECTION_ADDITIONAL, b); +done: + ares__llist_destroy(namelist); if (status != ARES_SUCCESS) { + ares__buf_set_length(buf, orig_len); + } + + return status; +} + +ares_status_t ares_dns_write_buf_tcp(const ares_dns_record_t *dnsrec, + ares__buf_t *buf) +{ + ares_status_t status; + size_t orig_len; + size_t msg_len; + size_t len; + + if (dnsrec == NULL || buf == NULL) { + return ARES_EFORMERR; + } + + orig_len = ares__buf_len(buf); + + /* Write placeholder for length */ + status = ares__buf_append_be16(buf, 0); + if (status != ARES_SUCCESS) { + goto done; /* LCOV_EXCL_LINE: OutOfMemory */ + } + + /* Write message */ + status = ares_dns_write_buf(dnsrec, buf); + if (status != ARES_SUCCESS) { + goto done; /* LCOV_EXCL_LINE: OutOfMemory */ + } + + len = ares__buf_len(buf); + msg_len = len - orig_len - 2; + if (msg_len > 65535) { + status = ARES_EBADQUERY; goto done; } + /* Now we need to overwrite the length, so we jump back to the original + * message length, overwrite the section and jump back */ + ares__buf_set_length(buf, orig_len); + status = ares__buf_append_be16(buf, (unsigned short)(msg_len & 0xFFFF)); + if (status != ARES_SUCCESS) { + goto done; /* LCOV_EXCL_LINE: UntestablePath */ + } + ares__buf_set_length(buf, len); + done: - ares__llist_destroy(namelist); + if (status != ARES_SUCCESS) { + ares__buf_set_length(buf, orig_len); + } + return status; +} + +ares_status_t ares_dns_write(const ares_dns_record_t *dnsrec, + unsigned char **buf, size_t *buf_len) +{ + ares__buf_t *b = NULL; + ares_status_t status; + + if (buf == NULL || buf_len == NULL || dnsrec == NULL) { + return ARES_EFORMERR; + } + + *buf = NULL; + *buf_len = 0; + + b = ares__buf_create(); + if (b == NULL) { + return ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ + } + + status = ares_dns_write_buf(dnsrec, b); if (status != ARES_SUCCESS) { ares__buf_destroy(b); diff --git a/contrib/libs/c-ares/src/lib/setup_once.h b/contrib/libs/c-ares/src/lib/setup_once.h deleted file mode 100644 index 38527ec442..0000000000 --- a/contrib/libs/c-ares/src/lib/setup_once.h +++ /dev/null @@ -1,469 +0,0 @@ -/* MIT License - * - * Copyright (c) 2004 Daniel Stenberg - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * SPDX-License-Identifier: MIT - */ -#ifndef __SETUP_ONCE_H -#define __SETUP_ONCE_H - - -/******************************************************************** - * NOTICE * - * ======== * - * * - * Content of header files lib/setup_once.h and ares/setup_once.h * - * must be kept in sync. Modify the other one if you change this. * - * * - ********************************************************************/ - - -/* - * Inclusion of common header files. - */ - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <stdarg.h> -#include <ctype.h> - -#ifdef HAVE_ERRNO_H -# include <errno.h> -#endif - -#ifdef HAVE_SYS_TYPES_H -# include <sys/types.h> -#endif - -#ifdef NEED_MALLOC_H -# include <malloc.h> -#endif - -#ifdef NEED_MEMORY_H -# include <memory.h> -#endif - -#ifdef HAVE_SYS_STAT_H -# include <sys/stat.h> -#endif - -#ifdef HAVE_SYS_TIME_H -# include <sys/time.h> -#endif - -#ifdef HAVE_TIME_H -# include <time.h> -#endif - -#ifdef WIN32 -# include <io.h> -# include <fcntl.h> -#endif - -#ifdef HAVE_UNISTD_H -# include <unistd.h> -#endif - -#ifdef __hpux -# if !defined(_XOPEN_SOURCE_EXTENDED) || defined(_KERNEL) -# ifdef _APP32_64BIT_OFF_T -# define OLD_APP32_64BIT_OFF_T _APP32_64BIT_OFF_T -# undef _APP32_64BIT_OFF_T -# else -# undef OLD_APP32_64BIT_OFF_T -# endif -# endif -#endif - -#ifdef HAVE_SYS_SOCKET_H -# include <sys/socket.h> -#endif - -#ifdef __hpux -# if !defined(_XOPEN_SOURCE_EXTENDED) || defined(_KERNEL) -# ifdef OLD_APP32_64BIT_OFF_T -# define _APP32_64BIT_OFF_T OLD_APP32_64BIT_OFF_T -# undef OLD_APP32_64BIT_OFF_T -# endif -# endif -#endif - - -/* - * Definition of timeval struct for platforms that don't have it. - */ - -#ifndef HAVE_STRUCT_TIMEVAL -struct timeval { - long tv_sec; - long tv_usec; -}; -#endif - - -/* - * If we have the MSG_NOSIGNAL define, make sure we use - * it as the fourth argument of function send() - */ - -#if defined(HAVE_MSG_NOSIGNAL) && defined(MSG_NOSIGNAL) -# define SEND_4TH_ARG MSG_NOSIGNAL -#else -# define SEND_4TH_ARG 0 -#endif - - -#if defined(__minix) -/* Minix doesn't support recv on TCP sockets */ -# define sread(x, y, z) \ - (ares_ssize_t) \ - read((RECV_TYPE_ARG1)(x), (RECV_TYPE_ARG2)(y), (RECV_TYPE_ARG3)(z)) - -#elif defined(HAVE_RECV) -/* - * The definitions for the return type and arguments types - * of functions recv() and send() belong and come from the - * configuration file. Do not define them in any other place. - * - * HAVE_RECV is defined if you have a function named recv() - * which is used to read incoming data from sockets. If your - * function has another name then don't define HAVE_RECV. - * - * If HAVE_RECV is defined then RECV_TYPE_ARG1, RECV_TYPE_ARG2, - * RECV_TYPE_ARG3, RECV_TYPE_ARG4 and RECV_TYPE_RETV must also - * be defined. - * - * HAVE_SEND is defined if you have a function named send() - * which is used to write outgoing data on a connected socket. - * If yours has another name then don't define HAVE_SEND. - * - * If HAVE_SEND is defined then SEND_TYPE_ARG1, SEND_QUAL_ARG2, - * SEND_TYPE_ARG2, SEND_TYPE_ARG3, SEND_TYPE_ARG4 and - * SEND_TYPE_RETV must also be defined. - */ - -# if !defined(RECV_TYPE_ARG1) || !defined(RECV_TYPE_ARG2) || \ - !defined(RECV_TYPE_ARG3) || !defined(RECV_TYPE_ARG4) || \ - !defined(RECV_TYPE_RETV) -/* */ -Error Missing_definition_of_return_and_arguments_types_of_recv -/* */ -# else -# define sread(x, y, z) \ - (ares_ssize_t) recv((RECV_TYPE_ARG1)(x), (RECV_TYPE_ARG2)(y), \ - (RECV_TYPE_ARG3)(z), (RECV_TYPE_ARG4)(0)) -# endif -#else /* HAVE_RECV */ -# ifndef sread -/* */ -Error Missing_definition_of_macro_sread -/* */ -# endif -#endif /* HAVE_RECV */ - - -#if defined(__minix) -/* Minix doesn't support send on TCP sockets */ -# define swrite(x, y, z) \ - (ares_ssize_t) \ - write((SEND_TYPE_ARG1)(x), (SEND_TYPE_ARG2)(y), (SEND_TYPE_ARG3)(z)) - -#elif defined(HAVE_SEND) -# if !defined(SEND_TYPE_ARG1) || !defined(SEND_QUAL_ARG2) || \ - !defined(SEND_TYPE_ARG2) || !defined(SEND_TYPE_ARG3) || \ - !defined(SEND_TYPE_ARG4) || !defined(SEND_TYPE_RETV) - /* */ - Error Missing_definition_of_return_and_arguments_types_of_send -/* */ -# else -# define swrite(x, y, z) \ - (ares_ssize_t) send((SEND_TYPE_ARG1)(x), (SEND_TYPE_ARG2)(y), \ - (SEND_TYPE_ARG3)(z), (SEND_TYPE_ARG4)(SEND_4TH_ARG)) -# endif -#else /* HAVE_SEND */ -# ifndef swrite - /* */ - Error Missing_definition_of_macro_swrite -/* */ -# endif -#endif /* HAVE_SEND */ - - -#if 0 -# if defined(HAVE_RECVFROM) -/* - * Currently recvfrom is only used on udp sockets. - */ -# if !defined(RECVFROM_TYPE_ARG1) || !defined(RECVFROM_TYPE_ARG2) || \ - !defined(RECVFROM_TYPE_ARG3) || !defined(RECVFROM_TYPE_ARG4) || \ - !defined(RECVFROM_TYPE_ARG5) || !defined(RECVFROM_TYPE_ARG6) || \ - !defined(RECVFROM_TYPE_RETV) - /* */ - Error Missing_definition_of_return_and_arguments_types_of_recvfrom - /* */ -# else -# define sreadfrom(s, b, bl, f, fl) \ - (ares_ssize_t) \ - recvfrom((RECVFROM_TYPE_ARG1)(s), (RECVFROM_TYPE_ARG2 *)(b), \ - (RECVFROM_TYPE_ARG3)(bl), (RECVFROM_TYPE_ARG4)(0), \ - (RECVFROM_TYPE_ARG5 *)(f), (RECVFROM_TYPE_ARG6 *)(fl)) -# endif -# else /* HAVE_RECVFROM */ -# ifndef sreadfrom - /* */ - Error Missing_definition_of_macro_sreadfrom - /* */ -# endif -# endif /* HAVE_RECVFROM */ - - -# ifdef RECVFROM_TYPE_ARG6_IS_VOID -# define RECVFROM_ARG6_T int -# else -# define RECVFROM_ARG6_T RECVFROM_TYPE_ARG6 -# endif -#endif /* if 0 */ - - -/* - * Function-like macro definition used to close a socket. - */ - -#if defined(HAVE_CLOSESOCKET) -# define sclose(x) closesocket((x)) -#elif defined(HAVE_CLOSESOCKET_CAMEL) -# define sclose(x) CloseSocket((x)) -#elif defined(HAVE_CLOSE_S) -# define sclose(x) close_s((x)) -#else -# define sclose(x) close((x)) -#endif - - -/* - * Uppercase macro versions of ANSI/ISO is*() functions/macros which - * avoid negative number inputs with argument byte codes > 127. - */ - -#define ISSPACE(x) (isspace((int)((unsigned char)x))) -#define ISDIGIT(x) (isdigit((int)((unsigned char)x))) -#define ISALNUM(x) (isalnum((int)((unsigned char)x))) -#define ISXDIGIT(x) (isxdigit((int)((unsigned char)x))) -#define ISGRAPH(x) (isgraph((int)((unsigned char)x))) -#define ISALPHA(x) (isalpha((int)((unsigned char)x))) -#define ISPRINT(x) (isprint((int)((unsigned char)x))) -#define ISUPPER(x) (isupper((int)((unsigned char)x))) -#define ISLOWER(x) (islower((int)((unsigned char)x))) -#define ISASCII(x) (((unsigned char)x) <= 127 ? 1 : 0) - -#define ISBLANK(x) \ - (int)((((unsigned char)x) == ' ') || (((unsigned char)x) == '\t')) - -#define TOLOWER(x) (tolower((int)((unsigned char)x))) - - -/* - * Macro WHILE_FALSE may be used to build single-iteration do-while loops, - * avoiding compiler warnings. Mostly intended for other macro definitions. - */ - -#define WHILE_FALSE while (0) - -#if defined(_MSC_VER) && !defined(__POCC__) -# undef WHILE_FALSE -# if (_MSC_VER < 1500) -# define WHILE_FALSE while (1, 0) -# else -# define WHILE_FALSE \ - __pragma(warning(push)) __pragma(warning(disable : 4127)) while (0) \ - __pragma(warning(pop)) -# endif -#endif - - -/* - * Macro used to include code only in debug builds. - */ - -#ifdef DEBUGBUILD -# define DEBUGF(x) x -#else -# define DEBUGF(x) \ - do { \ - } \ - WHILE_FALSE -#endif - - -/* - * Macro used to include assertion code only in debug builds. - */ - -#if defined(DEBUGBUILD) && defined(HAVE_ASSERT_H) -# define DEBUGASSERT(x) assert(x) -#else -# define DEBUGASSERT(x) \ - do { \ - } \ - WHILE_FALSE -#endif - - -/* - * Macro SOCKERRNO / SET_SOCKERRNO() returns / sets the *socket-related* errno - * (or equivalent) on this platform to hide platform details to code using it. - */ - -#ifdef USE_WINSOCK -# define SOCKERRNO ((int)WSAGetLastError()) -# define SET_SOCKERRNO(x) (WSASetLastError((int)(x))) -#else -# define SOCKERRNO (errno) -# define SET_SOCKERRNO(x) (errno = (x)) -#endif - - -/* - * Macro ERRNO / SET_ERRNO() returns / sets the NOT *socket-related* errno - * (or equivalent) on this platform to hide platform details to code using it. - */ - -#if defined(WIN32) && !defined(WATT32) -# define ERRNO ((int)GetLastError()) -# define SET_ERRNO(x) (SetLastError((DWORD)(x))) -#else -# define ERRNO (errno) -# define SET_ERRNO(x) (errno = (x)) -#endif - - -/* - * Portable error number symbolic names defined to Winsock error codes. - */ - -#ifdef USE_WINSOCK -# undef EBADF /* override definition in errno.h */ -# define EBADF WSAEBADF -# undef EINTR /* override definition in errno.h */ -# define EINTR WSAEINTR -# undef EINVAL /* override definition in errno.h */ -# define EINVAL WSAEINVAL -# undef EWOULDBLOCK /* override definition in errno.h */ -# define EWOULDBLOCK WSAEWOULDBLOCK -# undef EINPROGRESS /* override definition in errno.h */ -# define EINPROGRESS WSAEINPROGRESS -# undef EALREADY /* override definition in errno.h */ -# define EALREADY WSAEALREADY -# undef ENOTSOCK /* override definition in errno.h */ -# define ENOTSOCK WSAENOTSOCK -# undef EDESTADDRREQ /* override definition in errno.h */ -# define EDESTADDRREQ WSAEDESTADDRREQ -# undef EMSGSIZE /* override definition in errno.h */ -# define EMSGSIZE WSAEMSGSIZE -# undef EPROTOTYPE /* override definition in errno.h */ -# define EPROTOTYPE WSAEPROTOTYPE -# undef ENOPROTOOPT /* override definition in errno.h */ -# define ENOPROTOOPT WSAENOPROTOOPT -# undef EPROTONOSUPPORT /* override definition in errno.h */ -# define EPROTONOSUPPORT WSAEPROTONOSUPPORT -# define ESOCKTNOSUPPORT WSAESOCKTNOSUPPORT -# undef EOPNOTSUPP /* override definition in errno.h */ -# define EOPNOTSUPP WSAEOPNOTSUPP -# define EPFNOSUPPORT WSAEPFNOSUPPORT -# undef EAFNOSUPPORT /* override definition in errno.h */ -# define EAFNOSUPPORT WSAEAFNOSUPPORT -# undef EADDRINUSE /* override definition in errno.h */ -# define EADDRINUSE WSAEADDRINUSE -# undef EADDRNOTAVAIL /* override definition in errno.h */ -# define EADDRNOTAVAIL WSAEADDRNOTAVAIL -# undef ENETDOWN /* override definition in errno.h */ -# define ENETDOWN WSAENETDOWN -# undef ENETUNREACH /* override definition in errno.h */ -# define ENETUNREACH WSAENETUNREACH -# undef ENETRESET /* override definition in errno.h */ -# define ENETRESET WSAENETRESET -# undef ECONNABORTED /* override definition in errno.h */ -# define ECONNABORTED WSAECONNABORTED -# undef ECONNRESET /* override definition in errno.h */ -# define ECONNRESET WSAECONNRESET -# undef ENOBUFS /* override definition in errno.h */ -# define ENOBUFS WSAENOBUFS -# undef EISCONN /* override definition in errno.h */ -# define EISCONN WSAEISCONN -# undef ENOTCONN /* override definition in errno.h */ -# define ENOTCONN WSAENOTCONN -# define ESHUTDOWN WSAESHUTDOWN -# define ETOOMANYREFS WSAETOOMANYREFS -# undef ETIMEDOUT /* override definition in errno.h */ -# define ETIMEDOUT WSAETIMEDOUT -# undef ECONNREFUSED /* override definition in errno.h */ -# define ECONNREFUSED WSAECONNREFUSED -# undef ELOOP /* override definition in errno.h */ -# define ELOOP WSAELOOP -# ifndef ENAMETOOLONG /* possible previous definition in errno.h */ -# define ENAMETOOLONG WSAENAMETOOLONG -# endif -# define EHOSTDOWN WSAEHOSTDOWN -# undef EHOSTUNREACH /* override definition in errno.h */ -# define EHOSTUNREACH WSAEHOSTUNREACH -# ifndef ENOTEMPTY /* possible previous definition in errno.h */ -# define ENOTEMPTY WSAENOTEMPTY -# endif -# define EPROCLIM WSAEPROCLIM -# define EUSERS WSAEUSERS -# define EDQUOT WSAEDQUOT -# define ESTALE WSAESTALE -# define EREMOTE WSAEREMOTE -#endif - - -/* - * Actually use __32_getpwuid() on 64-bit VMS builds for getpwuid() - */ - -#if defined(__VMS) && defined(__INITIAL_POINTER_SIZE) && \ - (__INITIAL_POINTER_SIZE == 64) -# define getpwuid __32_getpwuid -#endif - - -/* - * Macro argv_item_t hides platform details to code using it. - */ - -#ifdef __VMS -# define argv_item_t __char_ptr32 -#else -# define argv_item_t char * -#endif - - -/* - * We use this ZERO_NULL to avoid picky compiler warnings, - * when assigning a NULL pointer to a function pointer var. - */ - -#define ZERO_NULL 0 - - -#endif /* __SETUP_ONCE_H */ diff --git a/contrib/libs/c-ares/src/lib/ares__buf.c b/contrib/libs/c-ares/src/lib/str/ares__buf.c index 2203662fab..b855260ab3 100644 --- a/contrib/libs/c-ares/src/lib/ares__buf.c +++ b/contrib/libs/c-ares/src/lib/str/ares__buf.c @@ -23,8 +23,6 @@ * * SPDX-License-Identifier: MIT */ -#include "ares_setup.h" -#include "ares.h" #include "ares_private.h" #include "ares__buf.h" #include <limits.h> @@ -87,7 +85,7 @@ void ares__buf_destroy(ares__buf_t *buf) static ares_bool_t ares__buf_is_const(const ares__buf_t *buf) { if (buf == NULL) { - return ARES_FALSE; + return ARES_FALSE; /* LCOV_EXCL_LINE: DefensiveCoding */ } if (buf->data != NULL && buf->alloc_buf == NULL) { @@ -107,7 +105,7 @@ void ares__buf_reclaim(ares__buf_t *buf) } if (ares__buf_is_const(buf)) { - return; + return; /* LCOV_EXCL_LINE: DefensiveCoding */ } /* Silence coverity. All lengths are zero so would bail out later but @@ -135,8 +133,6 @@ void ares__buf_reclaim(ares__buf_t *buf) if (buf->tag_offset != SIZE_MAX) { buf->tag_offset -= prefix_size; } - - return; } static ares_status_t ares__buf_ensure_space(ares__buf_t *buf, @@ -151,7 +147,7 @@ static ares_status_t ares__buf_ensure_space(ares__buf_t *buf, } if (ares__buf_is_const(buf)) { - return ARES_EFORMERR; + return ARES_EFORMERR; /* LCOV_EXCL_LINE: DefensiveCoding */ } /* When calling ares__buf_finish_str() we end up adding a null terminator, @@ -201,14 +197,14 @@ static ares_status_t ares__buf_ensure_space(ares__buf_t *buf, ares_status_t ares__buf_set_length(ares__buf_t *buf, size_t len) { if (buf == NULL || ares__buf_is_const(buf)) { - return ARES_EFORMERR; + return ARES_EFORMERR; /* LCOV_EXCL_LINE: DefensiveCoding */ } if (len >= buf->alloc_buf_len - buf->offset) { - return ARES_EFORMERR; + return ARES_EFORMERR; /* LCOV_EXCL_LINE: DefensiveCoding */ } - buf->data_len = len; + buf->data_len = len + buf->offset; return ARES_SUCCESS; } @@ -231,9 +227,9 @@ ares_status_t ares__buf_append(ares__buf_t *buf, const unsigned char *data, return ARES_SUCCESS; } -ares_status_t ares__buf_append_byte(ares__buf_t *buf, unsigned char byte) +ares_status_t ares__buf_append_byte(ares__buf_t *buf, unsigned char b) { - return ares__buf_append(buf, &byte, 1); + return ares__buf_append(buf, &b, 1); } ares_status_t ares__buf_append_be16(ares__buf_t *buf, unsigned short u16) @@ -242,12 +238,12 @@ ares_status_t ares__buf_append_be16(ares__buf_t *buf, unsigned short u16) status = ares__buf_append_byte(buf, (unsigned char)((u16 >> 8) & 0xff)); if (status != ARES_SUCCESS) { - return status; + return status; /* LCOV_EXCL_LINE: OutOfMemory */ } status = ares__buf_append_byte(buf, (unsigned char)(u16 & 0xff)); if (status != ARES_SUCCESS) { - return status; + return status; /* LCOV_EXCL_LINE: OutOfMemory */ } return ARES_SUCCESS; @@ -259,22 +255,22 @@ ares_status_t ares__buf_append_be32(ares__buf_t *buf, unsigned int u32) status = ares__buf_append_byte(buf, ((unsigned char)(u32 >> 24) & 0xff)); if (status != ARES_SUCCESS) { - return status; + return status; /* LCOV_EXCL_LINE: OutOfMemory */ } status = ares__buf_append_byte(buf, ((unsigned char)(u32 >> 16) & 0xff)); if (status != ARES_SUCCESS) { - return status; + return status; /* LCOV_EXCL_LINE: OutOfMemory */ } status = ares__buf_append_byte(buf, ((unsigned char)(u32 >> 8) & 0xff)); if (status != ARES_SUCCESS) { - return status; + return status; /* LCOV_EXCL_LINE: OutOfMemory */ } status = ares__buf_append_byte(buf, ((unsigned char)u32 & 0xff)); if (status != ARES_SUCCESS) { - return status; + return status; /* LCOV_EXCL_LINE: OutOfMemory */ } return ARES_SUCCESS; @@ -319,7 +315,7 @@ unsigned char *ares__buf_finish_bin(ares__buf_t *buf, size_t *len) /* We don't want to return NULL except on failure, may be zero-length */ if (buf->alloc_buf == NULL && ares__buf_ensure_space(buf, 1) != ARES_SUCCESS) { - return NULL; + return NULL; /* LCOV_EXCL_LINE: OutOfMemory */ } ptr = buf->alloc_buf; *len = buf->data_len; @@ -540,7 +536,7 @@ ares_status_t ares__buf_fetch_bytes_dup(ares__buf_t *buf, size_t len, *bytes = ares_malloc(null_term ? len + 1 : len); if (*bytes == NULL) { - return ARES_ENOMEM; + return ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ } memcpy(*bytes, ptr, len); @@ -561,7 +557,7 @@ ares_status_t ares__buf_fetch_str_dup(ares__buf_t *buf, size_t len, char **str) *str = ares_malloc(len + 1); if (*str == NULL) { - return ARES_ENOMEM; + return ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ } memcpy(*str, ptr, len); @@ -787,7 +783,7 @@ ares_status_t ares__buf_split(ares__buf_t *buf, const unsigned char *delims, ares_bool_t first = ARES_TRUE; if (buf == NULL || delims == NULL || delims_len == 0 || list == NULL) { - return ARES_EFORMERR; + return ARES_EFORMERR; /* LCOV_EXCL_LINE: DefensiveCoding */ } *list = ares__llist_create(ares__buf_destroy_cb); @@ -825,7 +821,7 @@ ares_status_t ares__buf_split(ares__buf_t *buf, const unsigned char *delims, /* Shouldn't be possible */ if (ptr == NULL) { - status = ARES_EFORMERR; + status = ARES_EFORMERR; /* LCOV_EXCL_LINE: DefensiveCoding */ goto done; } @@ -841,7 +837,7 @@ ares_status_t ares__buf_split(ares__buf_t *buf, const unsigned char *delims, } if (flags & ARES_BUF_SPLIT_RTRIM) { - while (len && ares__is_whitespace(ptr[len - 1], ARES_TRUE)) { + while (len > 0 && ares__is_whitespace(ptr[len - 1], ARES_TRUE)) { len--; } } @@ -934,20 +930,20 @@ ares_status_t ares__buf_set_position(ares__buf_t *buf, size_t idx) } if (idx > buf->data_len) { - return ARES_EFORMERR; + return ARES_EFORMERR; /* LCOV_EXCL_LINE: DefensiveCoding */ } buf->offset = idx; return ARES_SUCCESS; } -static ares_status_t ares__buf_parse_dns_binstr_int( - ares__buf_t *buf, size_t remaining_len, unsigned char **bin, size_t *bin_len, - ares_bool_t allow_multiple, ares_bool_t validate_printable) +ares_status_t ares__buf_parse_dns_abinstr(ares__buf_t *buf, + size_t remaining_len, + ares__dns_multistring_t **strs, + ares_bool_t validate_printable) { unsigned char len; - ares_status_t status; - ares__buf_t *binbuf = NULL; + ares_status_t status = ARES_EBADRESP; size_t orig_len = ares__buf_len(buf); if (buf == NULL) { @@ -958,15 +954,17 @@ static ares_status_t ares__buf_parse_dns_binstr_int( return ARES_EBADRESP; } - binbuf = ares__buf_create(); - if (binbuf == NULL) { - return ARES_ENOMEM; + if (strs != NULL) { + *strs = ares__dns_multistring_create(); + if (*strs == NULL) { + return ARES_ENOMEM; + } } while (orig_len - ares__buf_len(buf) < remaining_len) { status = ares__buf_fetch_bytes(buf, &len, 1); if (status != ARES_SUCCESS) { - break; + break; /* LCOV_EXCL_LINE: DefensiveCoding */ } if (len) { @@ -981,22 +979,88 @@ static ares_status_t ares__buf_parse_dns_binstr_int( } } - if (bin != NULL) { - status = ares__buf_fetch_bytes_into_buf(buf, binbuf, len); + if (strs != NULL) { + unsigned char *data = NULL; + status = ares__buf_fetch_bytes_dup(buf, len, ARES_TRUE, &data); + if (status != ARES_SUCCESS) { + break; + } + status = ares__dns_multistring_add_own(*strs, data, len); + if (status != ARES_SUCCESS) { + ares_free(data); + break; + } } else { status = ares__buf_consume(buf, len); + if (status != ARES_SUCCESS) { + break; + } } - if (status != ARES_SUCCESS) { - break; + } + } + + if (status != ARES_SUCCESS && strs != NULL) { + ares__dns_multistring_destroy(*strs); + *strs = NULL; + } + + return status; +} + +static ares_status_t + ares__buf_parse_dns_binstr_int(ares__buf_t *buf, size_t remaining_len, + unsigned char **bin, size_t *bin_len, + ares_bool_t validate_printable) +{ + unsigned char len; + ares_status_t status = ARES_EBADRESP; + ares__buf_t *binbuf = NULL; + + if (buf == NULL) { + return ARES_EFORMERR; + } + + if (remaining_len == 0) { + return ARES_EBADRESP; + } + + binbuf = ares__buf_create(); + if (binbuf == NULL) { + return ARES_ENOMEM; + } + + status = ares__buf_fetch_bytes(buf, &len, 1); + if (status != ARES_SUCCESS) { + goto done; /* LCOV_EXCL_LINE: DefensiveCoding */ + } + + remaining_len--; + + if (len > remaining_len) { + status = ARES_EBADRESP; + goto done; + } + + if (len) { + /* When used by the _str() parser, it really needs to be validated to + * be a valid printable ascii string. Do that here */ + if (validate_printable && ares__buf_len(buf) >= len) { + size_t mylen; + const char *data = (const char *)ares__buf_peek(buf, &mylen); + if (!ares__str_isprint(data, len)) { + status = ARES_EBADSTR; + goto done; } } - if (!allow_multiple) { - break; + if (bin != NULL) { + status = ares__buf_fetch_bytes_into_buf(buf, binbuf, len); + } else { + status = ares__buf_consume(buf, len); } } - +done: if (status != ARES_SUCCESS) { ares__buf_destroy(binbuf); } else { @@ -1014,20 +1078,19 @@ static ares_status_t ares__buf_parse_dns_binstr_int( } ares_status_t ares__buf_parse_dns_binstr(ares__buf_t *buf, size_t remaining_len, - unsigned char **bin, size_t *bin_len, - ares_bool_t allow_multiple) + unsigned char **bin, size_t *bin_len) { return ares__buf_parse_dns_binstr_int(buf, remaining_len, bin, bin_len, - allow_multiple, ARES_FALSE); + ARES_FALSE); } ares_status_t ares__buf_parse_dns_str(ares__buf_t *buf, size_t remaining_len, - char **str, ares_bool_t allow_multiple) + char **str) { size_t len; - return ares__buf_parse_dns_binstr_int( - buf, remaining_len, (unsigned char **)str, &len, allow_multiple, ARES_TRUE); + return ares__buf_parse_dns_binstr_int(buf, remaining_len, + (unsigned char **)str, &len, ARES_TRUE); } ares_status_t ares__buf_append_num_dec(ares__buf_t *buf, size_t num, size_t len) @@ -1049,13 +1112,13 @@ ares_status_t ares__buf_append_num_dec(ares__buf_t *buf, size_t num, size_t len) /* Silence coverity. Shouldn't be possible since we calculate it above */ if (mod == 0) { - return ARES_EFORMERR; + return ARES_EFORMERR; /* LCOV_EXCL_LINE: DefensiveCoding */ } digit /= mod; status = ares__buf_append_byte(buf, '0' + (unsigned char)(digit & 0xFF)); if (status != ARES_SUCCESS) { - return status; + return status; /* LCOV_EXCL_LINE: OutOfMemory */ } } return ARES_SUCCESS; @@ -1074,7 +1137,7 @@ ares_status_t ares__buf_append_num_hex(ares__buf_t *buf, size_t num, size_t len) ares_status_t status; status = ares__buf_append_byte(buf, hexbytes[(num >> ((i - 1) * 4)) & 0xF]); if (status != ARES_SUCCESS) { - return status; + return status; /* LCOV_EXCL_LINE: OutOfMemory */ } } return ARES_SUCCESS; @@ -1095,13 +1158,13 @@ static ares_status_t ares__buf_hexdump_line(ares__buf_t *buf, size_t idx, /* Address */ status = ares__buf_append_num_hex(buf, idx, 6); if (status != ARES_SUCCESS) { - return status; + return status; /* LCOV_EXCL_LINE: OutOfMemory */ } /* | */ status = ares__buf_append_str(buf, " | "); if (status != ARES_SUCCESS) { - return status; + return status; /* LCOV_EXCL_LINE: OutOfMemory */ } for (i = 0; i < 16; i++) { @@ -1111,19 +1174,19 @@ static ares_status_t ares__buf_hexdump_line(ares__buf_t *buf, size_t idx, status = ares__buf_append_num_hex(buf, data[i], 2); } if (status != ARES_SUCCESS) { - return status; + return status; /* LCOV_EXCL_LINE: OutOfMemory */ } status = ares__buf_append_byte(buf, ' '); if (status != ARES_SUCCESS) { - return status; + return status; /* LCOV_EXCL_LINE: OutOfMemory */ } } /* | */ status = ares__buf_append_str(buf, " | "); if (status != ARES_SUCCESS) { - return status; + return status; /* LCOV_EXCL_LINE: OutOfMemory */ } for (i = 0; i < 16; i++) { @@ -1132,7 +1195,7 @@ static ares_status_t ares__buf_hexdump_line(ares__buf_t *buf, size_t idx, } status = ares__buf_append_byte(buf, ares__isprint(data[i]) ? data[i] : '.'); if (status != ARES_SUCCESS) { - return status; + return status; /* LCOV_EXCL_LINE: OutOfMemory */ } } @@ -1149,7 +1212,7 @@ ares_status_t ares__buf_hexdump(ares__buf_t *buf, const unsigned char *data, ares_status_t status; status = ares__buf_hexdump_line(buf, i, data + i, len - i); if (status != ARES_SUCCESS) { - return status; + return status; /* LCOV_EXCL_LINE: OutOfMemory */ } } @@ -1166,7 +1229,7 @@ ares_status_t ares__buf_load_file(const char *filename, ares__buf_t *buf) ares_status_t status; if (filename == NULL || buf == NULL) { - return ARES_EFORMERR; + return ARES_EFORMERR; /* LCOV_EXCL_LINE: DefensiveCoding */ } fp = fopen(filename, "rb"); @@ -1188,39 +1251,39 @@ ares_status_t ares__buf_load_file(const char *filename, ares__buf_t *buf) /* Get length portably, fstat() is POSIX, not C */ if (fseek(fp, 0, SEEK_END) != 0) { - status = ARES_EFILE; - goto done; + status = ARES_EFILE; /* LCOV_EXCL_LINE: DefensiveCoding */ + goto done; /* LCOV_EXCL_LINE: DefensiveCoding */ } ftell_len = ftell(fp); if (ftell_len < 0) { - status = ARES_EFILE; - goto done; + status = ARES_EFILE; /* LCOV_EXCL_LINE: DefensiveCoding */ + goto done; /* LCOV_EXCL_LINE: DefensiveCoding */ } len = (size_t)ftell_len; if (fseek(fp, 0, SEEK_SET) != 0) { - status = ARES_EFILE; - goto done; + status = ARES_EFILE; /* LCOV_EXCL_LINE: DefensiveCoding */ + goto done; /* LCOV_EXCL_LINE: DefensiveCoding */ } if (len == 0) { - status = ARES_SUCCESS; - goto done; + status = ARES_SUCCESS; /* LCOV_EXCL_LINE: DefensiveCoding */ + goto done; /* LCOV_EXCL_LINE: DefensiveCoding */ } /* Read entire data into buffer */ ptr_len = len; ptr = ares__buf_append_start(buf, &ptr_len); if (ptr == NULL) { - status = ARES_ENOMEM; - goto done; + status = ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ + goto done; /* LCOV_EXCL_LINE: OutOfMemory */ } ptr_len = fread(ptr, 1, len, fp); if (ptr_len != len) { - status = ARES_EFILE; - goto done; + status = ARES_EFILE; /* LCOV_EXCL_LINE: DefensiveCoding */ + goto done; /* LCOV_EXCL_LINE: DefensiveCoding */ } ares__buf_append_finish(buf, len); diff --git a/contrib/libs/c-ares/src/lib/ares__buf.h b/contrib/libs/c-ares/src/lib/str/ares__buf.h index 4298814f7b..cb887aa27e 100644 --- a/contrib/libs/c-ares/src/lib/ares__buf.h +++ b/contrib/libs/c-ares/src/lib/str/ares__buf.h @@ -85,10 +85,10 @@ ares_status_t ares__buf_append(ares__buf_t *buf, const unsigned char *data, /*! Append a single byte to the dynamic buffer object * * \param[in] buf Initialized buffer object - * \param[in] byte Single byte to append to buffer object. + * \param[in] b Single byte to append to buffer object. * \return ARES_SUCCESS or one of the c-ares error codes */ -ares_status_t ares__buf_append_byte(ares__buf_t *buf, unsigned char byte); +ares_status_t ares__buf_append_byte(ares__buf_t *buf, unsigned char b); /*! Append a null-terminated string to the dynamic buffer object * @@ -554,13 +554,31 @@ size_t ares__buf_get_position(const ares__buf_t *buf); * \param[out] name Pointer passed by reference to be filled in with * allocated string of the parsed that must be * ares_free()'d by the caller. - * \param[in] allow_multiple ARES_TRUE if it should attempt to parse multiple - * strings back to back, and will concatenate in - * the returned str. * \return ARES_SUCCESS on success */ ares_status_t ares__buf_parse_dns_str(ares__buf_t *buf, size_t remaining_len, - char **name, ares_bool_t allow_multiple); + char **name); + +/*! Parse an array of character strings as defined in RFC1035, as binary, + * however, for convenience this does guarantee a NULL terminator (that is + * not included in the length for each value). + * + * \param[in] buf initialized buffer object + * \param[in] remaining_len maximum length that should be used for + * parsing the string, this is often less than + * the remaining buffer and is based on the RR + * record length. + * \param[out] strs Pointer passed by reference to be filled in + * with + * the array of values. + * \param[out] validate_printable Validate the strings contain only printable + * data. + * \return ARES_SUCCESS on success + */ +ares_status_t ares__buf_parse_dns_abinstr(ares__buf_t *buf, + size_t remaining_len, + ares__dns_multistring_t **strs, + ares_bool_t validate_printable); /*! Parse a character-string as defined in RFC1035, as binary, however for * convenience this does guarantee a NULL terminator (that is not included @@ -574,14 +592,10 @@ ares_status_t ares__buf_parse_dns_str(ares__buf_t *buf, size_t remaining_len, * allocated string of the parsed that must be * ares_free()'d by the caller. * \param[out] bin_len Length of returned string. - * \param[in] allow_multiple ARES_TRUE if it should attempt to parse multiple - * strings back to back, and will concatenate in - * the returned str. * \return ARES_SUCCESS on success */ ares_status_t ares__buf_parse_dns_binstr(ares__buf_t *buf, size_t remaining_len, - unsigned char **bin, size_t *bin_len, - ares_bool_t allow_multiple); + unsigned char **bin, size_t *bin_len); /*! Load data from specified file path into provided buffer. The entire file * is loaded into memory. diff --git a/contrib/libs/c-ares/src/lib/ares_str.c b/contrib/libs/c-ares/src/lib/str/ares_str.c index 44a5e452fb..ade61041eb 100644 --- a/contrib/libs/c-ares/src/lib/ares_str.c +++ b/contrib/libs/c-ares/src/lib/str/ares_str.c @@ -25,10 +25,8 @@ * SPDX-License-Identifier: MIT */ -#include "ares_setup.h" -#include "ares_str.h" -#include "ares.h" #include "ares_private.h" +#include "ares_str.h" #ifdef HAVE_STDINT_H # include <stdint.h> @@ -56,7 +54,7 @@ char *ares_strdup(const char *s1) /* Don't see how this is possible */ if (len == SIZE_MAX) { - return NULL; + return NULL; /* LCOV_EXCL_LINE: DefensiveCoding */ } out = ares_malloc(len + 1); @@ -77,7 +75,7 @@ size_t ares_strcpy(char *dest, const char *src, size_t dest_size) size_t len = 0; if (dest == NULL || dest_size == 0) { - return 0; + return 0; /* LCOV_EXCL_LINE: DefensiveCoding */ } len = ares_strlen(src); @@ -116,7 +114,7 @@ void ares__str_rtrim(char *str) size_t i; if (str == NULL) { - return; + return; /* LCOV_EXCL_LINE: DefensiveCoding */ } len = ares_strlen(str); @@ -134,7 +132,7 @@ void ares__str_ltrim(char *str) size_t len; if (str == NULL) { - return; + return; /* LCOV_EXCL_LINE: DefensiveCoding */ } for (i = 0; str[i] != 0 && ares__isspace(str[i]); i++) { @@ -262,7 +260,7 @@ ares_bool_t ares__is_hostname(const char *str) size_t i; if (str == NULL) { - return ARES_FALSE; + return ARES_FALSE; /* LCOV_EXCL_LINE: DefensiveCoding */ } for (i = 0; str[i] != 0; i++) { diff --git a/contrib/libs/c-ares/src/lib/ares_str.h b/contrib/libs/c-ares/src/lib/str/ares_str.h index 526a927a62..440758c21b 100644 --- a/contrib/libs/c-ares/src/lib/ares_str.h +++ b/contrib/libs/c-ares/src/lib/str/ares_str.h @@ -27,9 +27,6 @@ #ifndef __ARES_STR_H #define __ARES_STR_H -#include "ares_setup.h" -#include "ares.h" - char *ares_strdup(const char *s1); size_t ares_strlen(const char *str); @@ -75,5 +72,18 @@ ares_bool_t ares__is_hostname(const char *str); */ ares_bool_t ares__str_isprint(const char *str, size_t len); +/* We only care about ASCII rules */ +#define ares__isascii(x) (((unsigned char)x) <= 127) +#define ares__isdigit(x) \ + (((unsigned char)x) >= '0' && ((unsigned char)x) <= '9') +#define ares__isxdigit(x) \ + (ares__isdigit(x) || \ + (((unsigned char)x) >= 'a' && ((unsigned char)x) <= 'f') || \ + (((unsigned char)x) >= 'A' && ((unsigned char)x) <= 'F')) +#define ares__isupper(x) \ + (((unsigned char)x) >= 'A' && ((unsigned char)x) <= 'Z') +#define ares__islower(x) \ + (((unsigned char)x) >= 'a' && ((unsigned char)x) <= 'z') +#define ares__isalpha(x) (ares__islower(x) || ares__isupper(x)) #endif /* __ARES_STR_H */ diff --git a/contrib/libs/c-ares/src/lib/ares_strcasecmp.c b/contrib/libs/c-ares/src/lib/str/ares_strcasecmp.c index b91cbbe154..76b835fd8e 100644 --- a/contrib/libs/c-ares/src/lib/ares_strcasecmp.c +++ b/contrib/libs/c-ares/src/lib/str/ares_strcasecmp.c @@ -25,7 +25,7 @@ * SPDX-License-Identifier: MIT */ -#include "ares_setup.h" +#include "ares_private.h" #include "ares_strcasecmp.h" #ifndef HAVE_STRCASECMP @@ -39,8 +39,8 @@ int ares_strcasecmp(const char *a, const char *b) size_t i; for (i = 0; i < (size_t)-1; i++) { - int c1 = ISUPPER(a[i]) ? tolower(a[i]) : a[i]; - int c2 = ISUPPER(b[i]) ? tolower(b[i]) : b[i]; + int c1 = ares__tolower(a[i]); + int c2 = ares__tolower(b[i]); if (c1 != c2) { return c1 - c2; } @@ -64,8 +64,8 @@ int ares_strncasecmp(const char *a, const char *b, size_t n) size_t i; for (i = 0; i < n; i++) { - int c1 = ISUPPER(a[i]) ? tolower(a[i]) : a[i]; - int c2 = ISUPPER(b[i]) ? tolower(b[i]) : b[i]; + int c1 = ares__tolower(a[i]); + int c2 = ares__tolower(b[i]); if (c1 != c2) { return c1 - c2; } diff --git a/contrib/libs/c-ares/src/lib/ares_strcasecmp.h b/contrib/libs/c-ares/src/lib/str/ares_strcasecmp.h index 31a66be717..a8097d2219 100644 --- a/contrib/libs/c-ares/src/lib/ares_strcasecmp.h +++ b/contrib/libs/c-ares/src/lib/str/ares_strcasecmp.h @@ -27,8 +27,6 @@ #ifndef HEADER_CARES_STRCASECMP_H #define HEADER_CARES_STRCASECMP_H -#include "ares_setup.h" - #ifndef HAVE_STRCASECMP extern int ares_strcasecmp(const char *a, const char *b); #endif diff --git a/contrib/libs/c-ares/src/lib/ares_strsplit.c b/contrib/libs/c-ares/src/lib/str/ares_strsplit.c index 395bf1ebb9..dee307d779 100644 --- a/contrib/libs/c-ares/src/lib/ares_strsplit.c +++ b/contrib/libs/c-ares/src/lib/str/ares_strsplit.c @@ -23,13 +23,6 @@ * * SPDX-License-Identifier: MIT */ - -#if defined(__MVS__) -# include <strings.h> -#endif - -#include "ares_setup.h" -#include "ares.h" #include "ares_private.h" void ares__strsplit_free(char **elms, size_t num_elm) @@ -52,19 +45,19 @@ char **ares__strsplit_duplicate(char **elms, size_t num_elm) char **out; if (elms == NULL || num_elm == 0) { - return NULL; + return NULL; /* LCOV_EXCL_LINE: DefensiveCoding */ } out = ares_malloc_zero(sizeof(*elms) * num_elm); if (out == NULL) { - return NULL; + return NULL; /* LCOV_EXCL_LINE: OutOfMemory */ } for (i = 0; i < num_elm; i++) { out[i] = ares_strdup(elms[i]); if (out[i] == NULL) { - ares__strsplit_free(out, num_elm); - return NULL; + ares__strsplit_free(out, num_elm); /* LCOV_EXCL_LINE: OutOfMemory */ + return NULL; /* LCOV_EXCL_LINE: OutOfMemory */ } } @@ -82,7 +75,7 @@ char **ares__strsplit(const char *in, const char *delms, size_t *num_elm) size_t idx = 0; if (in == NULL || delms == NULL || num_elm == NULL) { - return NULL; + return NULL; /* LCOV_EXCL_LINE: DefensiveCoding */ } *num_elm = 0; @@ -108,8 +101,8 @@ char **ares__strsplit(const char *in, const char *delms, size_t *num_elm) out = ares_malloc_zero(cnt * sizeof(*out)); if (out == NULL) { - status = ARES_ENOMEM; - goto done; + status = ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ + goto done; /* LCOV_EXCL_LINE: OutOfMemory */ } for (node = ares__llist_node_first(llist); node != NULL; diff --git a/contrib/libs/c-ares/src/lib/ares_strsplit.h b/contrib/libs/c-ares/src/lib/str/ares_strsplit.h index af650eee53..ee997804f0 100644 --- a/contrib/libs/c-ares/src/lib/ares_strsplit.h +++ b/contrib/libs/c-ares/src/lib/str/ares_strsplit.h @@ -26,8 +26,6 @@ #ifndef HEADER_CARES_STRSPLIT_H #define HEADER_CARES_STRSPLIT_H -#include "ares_setup.h" - /* Split a string on delms skipping empty or duplicate elements. * * param in String to split. diff --git a/contrib/libs/c-ares/src/lib/thirdparty/apple/README.md b/contrib/libs/c-ares/src/lib/thirdparty/apple/README.md index e0915f4a43..8cef22ed7e 100644 --- a/contrib/libs/c-ares/src/lib/thirdparty/apple/README.md +++ b/contrib/libs/c-ares/src/lib/thirdparty/apple/README.md @@ -1,4 +1,18 @@ The `dnsinfo.h` header was extracted from Apple's OpenSource repository: -[https://opensource.apple.com/source/configd/configd-1109.140.1/dnsinfo/dnsinfo.h](https://opensource.apple.com/source/configd/configd-1109.140.1/dnsinfo/dnsinfo.h) +[https://opensource.apple.com/source/configd/configd-453.19/dnsinfo/dnsinfo.h](https://opensource.apple.com/source/configd/configd-453.19/dnsinfo/dnsinfo.h) -This is needed to call into `dns_configuration_copy()` and `dns_configuration_free()`. +We then had to make a few edits to this file: +1. Add `AvailabilityMacros.h` header file +2. conditionalize `reach_flags` in `dns_resolver_t` on MacOS 10.8 or higher, in + order to maintain compatibility with the last MacOS PPC release, 10.6. +3. conditionalize `_dns_configuration_ack()` on MacOS 10.8 or higher. +4. Update parameter list to `(void)` for both `dns_configuration_notify_key()` + and `dns_configuration_copy()` to sidestep compiler warnings in this old + header. + +We had tried initially to use the latest 1109.140.1 which only worked on +MacOS 11+, then downgraded to 963.50.8 for MacOS 10.8+ support, then finally +to 453.19 with additional patches. + +This is needed to call into `dns_configuration_copy()` and +`dns_configuration_free()`. diff --git a/contrib/libs/c-ares/src/lib/thirdparty/apple/dnsinfo.h b/contrib/libs/c-ares/src/lib/thirdparty/apple/dnsinfo.h index d5a0e70e2f..d92a1d8030 100644 --- a/contrib/libs/c-ares/src/lib/thirdparty/apple/dnsinfo.h +++ b/contrib/libs/c-ares/src/lib/thirdparty/apple/dnsinfo.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2006, 2008, 2009, 2011-2013, 2015-2018 Apple Inc. All rights reserved. + * Copyright (c) 2004-2006, 2008, 2009, 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -28,14 +28,15 @@ * These routines provide access to the systems DNS configuration */ -#include <os/availability.h> +#include <Availability.h> #include <sys/cdefs.h> #include <stdint.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> +#include <AvailabilityMacros.h> -#define DNSINFO_VERSION 20170629 +#define DNSINFO_VERSION 20111104 #define DEFAULT_SEARCH_ORDER 200000 /* search order for the "default" resolver domain name */ @@ -72,23 +73,17 @@ typedef struct { DNS_VAR(uint32_t, search_order); /* search_order */ DNS_VAR(uint32_t, if_index); DNS_VAR(uint32_t, flags); +#if MAC_OS_X_VERSION_MIN_REQUIRED < 1080 /* MacOS 10.8 */ + DNS_VAR(uint32_t, reserved[6]); +#else DNS_VAR(uint32_t, reach_flags); /* SCNetworkReachabilityFlags */ - DNS_VAR(uint32_t, service_identifier); - DNS_PTR(char *, cid); /* configuration identifer */ - DNS_PTR(char *, if_name); /* if_index interface name */ + DNS_VAR(uint32_t, reserved[5]); +#endif } dns_resolver_t; #pragma pack() -#define DNS_RESOLVER_FLAGS_REQUEST_A_RECORDS 0x0002 /* always requesting for A dns records in queries */ -#define DNS_RESOLVER_FLAGS_REQUEST_AAAA_RECORDS 0x0004 /* always requesting for AAAA dns records in queries */ - -#define DNS_RESOLVER_FLAGS_REQUEST_ALL_RECORDS \ - (DNS_RESOLVER_FLAGS_REQUEST_A_RECORDS | DNS_RESOLVER_FLAGS_REQUEST_AAAA_RECORDS) - -#define DNS_RESOLVER_FLAGS_SCOPED 0x1000 /* configuration is for scoped questions */ -#define DNS_RESOLVER_FLAGS_SERVICE_SPECIFIC 0x2000 /* configuration is service-specific */ -#define DNS_RESOLVER_FLAGS_SUPPLEMENTAL 0x4000 /* supplemental match configuration */ +#define DNS_RESOLVER_FLAGS_SCOPED 1 /* configuration is for scoped questions */ #pragma pack(4) @@ -97,10 +92,7 @@ typedef struct { DNS_PTR(dns_resolver_t **, resolver); DNS_VAR(int32_t, n_scoped_resolver); /* "scoped" resolver configurations */ DNS_PTR(dns_resolver_t **, scoped_resolver); - DNS_VAR(uint64_t, generation); - DNS_VAR(int32_t, n_service_specific_resolver); - DNS_PTR(dns_resolver_t **, service_specific_resolver); - DNS_VAR(uint32_t, version); + DNS_VAR(uint32_t, reserved[5]); } dns_config_t; #pragma pack() @@ -111,17 +103,19 @@ __BEGIN_DECLS * DNS configuration access APIs */ const char * -dns_configuration_notify_key (void) API_AVAILABLE(macos(10.4), ios(2.0)); +dns_configuration_notify_key (void) __OSX_AVAILABLE_STARTING(__MAC_10_4,__IPHONE_2_0); dns_config_t * -dns_configuration_copy (void) API_AVAILABLE(macos(10.4), ios(2.0)); +dns_configuration_copy (void) __OSX_AVAILABLE_STARTING(__MAC_10_4,__IPHONE_2_0); void -dns_configuration_free (dns_config_t *config) API_AVAILABLE(macos(10.4), ios(2.0)); +dns_configuration_free (dns_config_t *config) __OSX_AVAILABLE_STARTING(__MAC_10_4,__IPHONE_2_0); +#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1080 void _dns_configuration_ack (dns_config_t *config, - const char *bundle_id) API_AVAILABLE(macos(10.8), ios(6.0)); + const char *bundle_id) __OSX_AVAILABLE_STARTING(__MAC_10_8, __IPHONE_6_0); +#endif __END_DECLS diff --git a/contrib/libs/c-ares/src/lib/ares__iface_ips.c b/contrib/libs/c-ares/src/lib/util/ares__iface_ips.c index b252a7ab49..56dc257904 100644 --- a/contrib/libs/c-ares/src/lib/ares__iface_ips.c +++ b/contrib/libs/c-ares/src/lib/util/ares__iface_ips.c @@ -23,8 +23,7 @@ * * SPDX-License-Identifier: MIT */ -#include "ares_setup.h" - +#include "ares_private.h" #ifdef USE_WINSOCK # include <winsock2.h> @@ -55,9 +54,10 @@ #ifdef HAVE_NETINET_IN_H # include <netinet/in.h> #endif +#ifdef HAVE_NETDB_H +# include <netdb.h> +#endif -#include "ares.h" -#include "ares_private.h" static ares_status_t ares__iface_ips_enumerate(ares__iface_ips_t *ips, const char *name); @@ -71,51 +71,43 @@ typedef struct { } ares__iface_ip_t; struct ares__iface_ips { - ares__iface_ip_t *ips; - size_t cnt; - size_t alloc_size; + ares__array_t *ips; /*!< Type is ares__iface_ip_t */ ares__iface_ip_flags_t enum_flags; }; +static void ares__iface_ip_free_cb(void *arg) +{ + ares__iface_ip_t *ip = arg; + if (ip == NULL) { + return; + } + ares_free(ip->name); +} + static ares__iface_ips_t *ares__iface_ips_alloc(ares__iface_ip_flags_t flags) { ares__iface_ips_t *ips = ares_malloc_zero(sizeof(*ips)); if (ips == NULL) { - return NULL; + return NULL; /* LCOV_EXCL_LINE: OutOfMemory */ } - /* Prealloc 4 entries */ - ips->alloc_size = 4; - ips->ips = ares_malloc_zero(ips->alloc_size * sizeof(*ips->ips)); + ips->enum_flags = flags; + ips->ips = + ares__array_create(sizeof(ares__iface_ip_t), ares__iface_ip_free_cb); if (ips->ips == NULL) { - ares_free(ips); - return NULL; + ares_free(ips); /* LCOV_EXCL_LINE: OutOfMemory */ + return NULL; /* LCOV_EXCL_LINE: OutOfMemory */ } - ips->enum_flags = flags; return ips; } -static void ares__iface_ip_destroy(ares__iface_ip_t *ip) -{ - if (ip == NULL) { - return; - } - ares_free(ip->name); - memset(ip, 0, sizeof(*ip)); -} - void ares__iface_ips_destroy(ares__iface_ips_t *ips) { - size_t i; - if (ips == NULL) { return; } - for (i = 0; i < ips->cnt; i++) { - ares__iface_ip_destroy(&ips->ips[i]); - } - ares_free(ips->ips); + ares__array_destroy(ips->ips); ares_free(ips); } @@ -130,14 +122,16 @@ ares_status_t ares__iface_ips(ares__iface_ips_t **ips, *ips = ares__iface_ips_alloc(flags); if (*ips == NULL) { - return ARES_ENOMEM; + return ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ } status = ares__iface_ips_enumerate(*ips, name); if (status != ARES_SUCCESS) { + /* LCOV_EXCL_START: UntestablePath */ ares__iface_ips_destroy(*ips); *ips = NULL; return status; + /* LCOV_EXCL_STOP */ } return ARES_SUCCESS; @@ -148,10 +142,11 @@ static ares_status_t const char *name, const struct ares_addr *addr, unsigned char netmask, unsigned int ll_scope) { - size_t idx; + ares__iface_ip_t *ip; + ares_status_t status; if (ips == NULL || name == NULL || addr == NULL) { - return ARES_EFORMERR; + return ARES_EFORMERR; /* LCOV_EXCL_LINE: DefensiveCoding */ } /* Don't want loopback */ @@ -195,31 +190,21 @@ static ares_status_t } } - /* Allocate more ips */ - if (ips->cnt + 1 > ips->alloc_size) { - void *temp; - size_t alloc_size; - - alloc_size = ares__round_up_pow2(ips->alloc_size + 1); - temp = ares_realloc_zero(ips->ips, ips->alloc_size * sizeof(*ips->ips), - alloc_size * sizeof(*ips->ips)); - if (temp == NULL) { - return ARES_ENOMEM; - } - ips->ips = temp; - ips->alloc_size = alloc_size; + status = ares__array_insert_last((void **)&ip, ips->ips); + if (status != ARES_SUCCESS) { + return status; } - /* Add */ - idx = ips->cnt++; - - ips->ips[idx].flags = flags; - ips->ips[idx].netmask = netmask; - ips->ips[idx].ll_scope = ll_scope; - memcpy(&ips->ips[idx].addr, addr, sizeof(*addr)); - ips->ips[idx].name = ares_strdup(name); - if (ips->ips[idx].name == NULL) { - return ARES_ENOMEM; + ip->flags = flags; + ip->netmask = netmask; + if (flags & ARES_IFACE_IP_LINKLOCAL) { + ip->ll_scope = ll_scope; + } + memcpy(&ip->addr, addr, sizeof(*addr)); + ip->name = ares_strdup(name); + if (ip->name == NULL) { + ares__array_remove_last(ips->ips); + return ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ } return ARES_SUCCESS; @@ -230,51 +215,91 @@ size_t ares__iface_ips_cnt(const ares__iface_ips_t *ips) if (ips == NULL) { return 0; } - return ips->cnt; + return ares__array_len(ips->ips); } const char *ares__iface_ips_get_name(const ares__iface_ips_t *ips, size_t idx) { - if (ips == NULL || idx >= ips->cnt) { + const ares__iface_ip_t *ip; + + if (ips == NULL) { + return NULL; + } + + ip = ares__array_at_const(ips->ips, idx); + if (ip == NULL) { return NULL; } - return ips->ips[idx].name; + + return ip->name; } const struct ares_addr *ares__iface_ips_get_addr(const ares__iface_ips_t *ips, size_t idx) { - if (ips == NULL || idx >= ips->cnt) { + const ares__iface_ip_t *ip; + + if (ips == NULL) { return NULL; } - return &ips->ips[idx].addr; + + ip = ares__array_at_const(ips->ips, idx); + if (ip == NULL) { + return NULL; + } + + return &ip->addr; } ares__iface_ip_flags_t ares__iface_ips_get_flags(const ares__iface_ips_t *ips, size_t idx) { - if (ips == NULL || idx >= ips->cnt) { + const ares__iface_ip_t *ip; + + if (ips == NULL) { return 0; } - return ips->ips[idx].flags; + + ip = ares__array_at_const(ips->ips, idx); + if (ip == NULL) { + return 0; + } + + return ip->flags; } unsigned char ares__iface_ips_get_netmask(const ares__iface_ips_t *ips, size_t idx) { - if (ips == NULL || idx >= ips->cnt) { + const ares__iface_ip_t *ip; + + if (ips == NULL) { return 0; } - return ips->ips[idx].netmask; + + ip = ares__array_at_const(ips->ips, idx); + if (ip == NULL) { + return 0; + } + + return ip->netmask; } unsigned int ares__iface_ips_get_ll_scope(const ares__iface_ips_t *ips, size_t idx) { - if (ips == NULL || idx >= ips->cnt) { + const ares__iface_ip_t *ip; + + if (ips == NULL) { + return 0; + } + + ip = ares__array_at_const(ips->ips, idx); + if (ip == NULL) { return 0; } - return ips->ips[idx].ll_scope; + + return ip->ll_scope; } @@ -490,7 +515,7 @@ static ares_status_t ares__iface_ips_enumerate(ares__iface_ips_t *ips, } /* Name mismatch */ - if (strcasecmp(ifa->ifa_name, name) != 0) { + if (name != NULL && strcasecmp(ifa->ifa_name, name) != 0) { continue; } @@ -522,6 +547,9 @@ static ares_status_t ares__iface_ips_enumerate(ares__iface_ips_t *ips, unsigned int ares__if_nametoindex(const char *name) { #ifdef HAVE_IF_NAMETOINDEX + if (name == NULL) { + return 0; + } return if_nametoindex(name); #else ares_status_t status; @@ -529,6 +557,10 @@ unsigned int ares__if_nametoindex(const char *name) size_t i; unsigned int index = 0; + if (name == NULL) { + return 0; + } + status = ares__iface_ips(&ips, ARES_IFACE_IP_V6 | ARES_IFACE_IP_LINKLOCAL, name); if (status != ARES_SUCCESS) { @@ -562,7 +594,7 @@ const char *ares__if_indextoname(unsigned int index, char *name, size_t i; const char *ptr = NULL; - if (name_len < IF_NAMESIZE) { + if (name == NULL || name_len < IF_NAMESIZE) { goto done; } diff --git a/contrib/libs/c-ares/src/lib/ares__iface_ips.h b/contrib/libs/c-ares/src/lib/util/ares__iface_ips.h index 61ff736a79..61ff736a79 100644 --- a/contrib/libs/c-ares/src/lib/ares__iface_ips.h +++ b/contrib/libs/c-ares/src/lib/util/ares__iface_ips.h diff --git a/contrib/libs/c-ares/src/lib/ares__threads.c b/contrib/libs/c-ares/src/lib/util/ares__threads.c index 53c81d41b2..b47544451d 100644 --- a/contrib/libs/c-ares/src/lib/ares__threads.c +++ b/contrib/libs/c-ares/src/lib/util/ares__threads.c @@ -23,8 +23,6 @@ * * SPDX-License-Identifier: MIT */ -#include "ares_setup.h" -#include "ares.h" #include "ares_private.h" #ifdef CARES_THREADS @@ -226,25 +224,27 @@ ares__thread_mutex_t *ares__thread_mutex_create(void) } if (pthread_mutexattr_init(&attr) != 0) { - ares_free(mut); - return NULL; + ares_free(mut); /* LCOV_EXCL_LINE: UntestablePath */ + return NULL; /* LCOV_EXCL_LINE: UntestablePath */ } if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE) != 0) { - goto fail; + goto fail; /* LCOV_EXCL_LINE: UntestablePath */ } if (pthread_mutex_init(&mut->mutex, &attr) != 0) { - goto fail; + goto fail; /* LCOV_EXCL_LINE: UntestablePath */ } pthread_mutexattr_destroy(&attr); return mut; +/* LCOV_EXCL_START: UntestablePath */ fail: pthread_mutexattr_destroy(&attr); ares_free(mut); return NULL; + /* LCOV_EXCL_STOP */ } void ares__thread_mutex_destroy(ares__thread_mutex_t *mut) @@ -379,11 +379,11 @@ ares_status_t ares__thread_create(ares__thread_t **thread, thr = ares_malloc_zero(sizeof(*thr)); if (thr == NULL) { - return ARES_ENOMEM; + return ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ } if (pthread_create(&thr->thread, NULL, func, arg) != 0) { - ares_free(thr); - return ARES_ESERVFAIL; + ares_free(thr); /* LCOV_EXCL_LINE: UntestablePath */ + return ARES_ESERVFAIL; /* LCOV_EXCL_LINE: UntestablePath */ } *thread = thr; @@ -562,7 +562,7 @@ ares_status_t ares_queue_wait_empty(ares_channel_t *channel, int timeout_ms) } if (timeout_ms >= 0) { - tout = ares__tvnow(); + ares__tvnow(&tout); tout.sec += (ares_int64_t)(timeout_ms / 1000); tout.usec += (unsigned int)(timeout_ms % 1000) * 1000; } @@ -573,9 +573,10 @@ ares_status_t ares_queue_wait_empty(ares_channel_t *channel, int timeout_ms) ares__thread_cond_wait(channel->cond_empty, channel->lock); } else { ares_timeval_t tv_remaining; - ares_timeval_t tv_now = ares__tvnow(); + ares_timeval_t tv_now; unsigned long tms; + ares__tvnow(&tv_now); ares__timeval_remaining(&tv_remaining, &tv_now, &tout); tms = (unsigned long)((tv_remaining.sec * 1000) + (tv_remaining.usec / 1000)); diff --git a/contrib/libs/c-ares/src/lib/ares__threads.h b/contrib/libs/c-ares/src/lib/util/ares__threads.h index 108354dfc1..108354dfc1 100644 --- a/contrib/libs/c-ares/src/lib/ares__threads.h +++ b/contrib/libs/c-ares/src/lib/util/ares__threads.h diff --git a/contrib/libs/c-ares/src/lib/ares__timeval.c b/contrib/libs/c-ares/src/lib/util/ares__timeval.c index fae5ad7e87..e3a989dca8 100644 --- a/contrib/libs/c-ares/src/lib/ares__timeval.c +++ b/contrib/libs/c-ares/src/lib/util/ares__timeval.c @@ -24,62 +24,68 @@ * SPDX-License-Identifier: MIT */ -#include "ares_setup.h" -#include "ares.h" #include "ares_private.h" -#if defined(WIN32) && !defined(MSDOS) +#if defined(_WIN32) && !defined(MSDOS) -ares_timeval_t ares__tvnow(void) +void ares__tvnow(ares_timeval_t *now) { - /* GetTickCount64() is available on Windows Vista and higher */ - ares_timeval_t now; - ULONGLONG milliseconds = GetTickCount64(); + /* QueryPerformanceCounters() has been around since Windows 2000, though + * significant fixes were made in later versions. Documentation states + * 1 microsecond or better resolution with a rollover not less than 100 years. + * This differs from GetTickCount{64}() which has a resolution between 10 and + * 16 ms. */ + LARGE_INTEGER freq; + LARGE_INTEGER current; - now.sec = (ares_int64_t)milliseconds / 1000; - now.usec = (unsigned int)(milliseconds % 1000) * 1000; - return now; + /* Not sure how long it takes to get the frequency, I see it recommended to + * cache it */ + QueryPerformanceFrequency(&freq); + QueryPerformanceCounter(¤t); + + now->sec = current.QuadPart / freq.QuadPart; + /* We want to prevent overflows so we get the remainder, then multiply to + * microseconds before dividing */ + now->usec = (unsigned int)(((current.QuadPart % freq.QuadPart) * 1000000) / + freq.QuadPart); } #elif defined(HAVE_CLOCK_GETTIME_MONOTONIC) -ares_timeval_t ares__tvnow(void) +void ares__tvnow(ares_timeval_t *now) { /* clock_gettime() is guaranteed to be increased monotonically when the * monotonic clock is queried. Time starting point is unspecified, it * could be the system start-up time, the Epoch, or something else, * in any case the time starting point does not change once that the * system has started up. */ - ares_timeval_t now; struct timespec tsnow; if (clock_gettime(CLOCK_MONOTONIC, &tsnow) == 0) { - now.sec = (ares_int64_t)tsnow.tv_sec; - now.usec = (unsigned int)(tsnow.tv_nsec / 1000); + now->sec = (ares_int64_t)tsnow.tv_sec; + now->usec = (unsigned int)(tsnow.tv_nsec / 1000); } else { + /* LCOV_EXCL_START: FallbackCode */ struct timeval tv; (void)gettimeofday(&tv, NULL); - now.sec = (ares_int64_t)tv.tv_sec; - now.usec = (unsigned int)tv.tv_usec; + now->sec = (ares_int64_t)tv.tv_sec; + now->usec = (unsigned int)tv.tv_usec; + /* LCOV_EXCL_STOP */ } - return now; } #elif defined(HAVE_GETTIMEOFDAY) -ares_timeval_t ares__tvnow(void) +void ares__tvnow(ares_timeval_t *now) { /* gettimeofday() is not granted to be increased monotonically, due to * clock drifting and external source time synchronization it can jump * forward or backward in time. */ - ares_timeval_t now; struct timeval tv; (void)gettimeofday(&tv, NULL); - now.sec = (ares_int64_t)tv.tv_sec; - now.usec = (unsigned int)tv.tv_usec; - - return now; + now->sec = (ares_int64_t)tv.tv_sec; + now->usec = (unsigned int)tv.tv_usec; } #else diff --git a/contrib/libs/c-ares/src/lib/ares_math.c b/contrib/libs/c-ares/src/lib/util/ares_math.c index eaefd6c5de..45999bdeab 100644 --- a/contrib/libs/c-ares/src/lib/ares_math.c +++ b/contrib/libs/c-ares/src/lib/util/ares_math.c @@ -23,8 +23,7 @@ * * SPDX-License-Identifier: MIT */ -#include "ares_setup.h" -#include "ares.h" + #include "ares_private.h" /* Uses public domain code snippets from @@ -57,9 +56,23 @@ static ares_int64_t ares__round_up_pow2_u64(ares_int64_t n) return n; } +ares_bool_t ares__is_64bit(void) +{ +#ifdef _MSC_VER +# pragma warning(push) +# pragma warning(disable : 4127) +#endif + + return (sizeof(size_t) == 4) ? ARES_FALSE : ARES_TRUE; + +#ifdef _MSC_VER +# pragma warning(pop) +#endif +} + size_t ares__round_up_pow2(size_t n) { - if (sizeof(size_t) > 4) { + if (ares__is_64bit()) { return (size_t)ares__round_up_pow2_u64((ares_int64_t)n); } @@ -79,7 +92,7 @@ size_t ares__log2(size_t n) 56, 45, 25, 31, 35, 16, 9, 12, 44, 24, 15, 8, 23, 7, 6, 5 }; - if (sizeof(size_t) == 4) { + if (!ares__is_64bit()) { return tab32[(n * 0x077CB531) >> 27]; } diff --git a/contrib/libs/c-ares/src/lib/ares_rand.c b/contrib/libs/c-ares/src/lib/util/ares_rand.c index bf3a695c9c..c57bb706e6 100644 --- a/contrib/libs/c-ares/src/lib/ares_rand.c +++ b/contrib/libs/c-ares/src/lib/util/ares_rand.c @@ -24,8 +24,6 @@ * SPDX-License-Identifier: MIT */ -#include "ares_setup.h" -#include "ares.h" #include "ares_private.h" #include <stdlib.h> @@ -43,7 +41,7 @@ typedef enum { ARES_RAND_OS = 1 << 0, /* OS-provided such as RtlGenRandom or arc4random */ ARES_RAND_FILE = 1 << 1, /* OS file-backed random number generator */ - ARES_RAND_RC4 = 1 << 2, /* Internal RC4 based PRNG */ + ARES_RAND_RC4 = 1 << 2 /* Internal RC4 based PRNG */ } ares_rand_backend; #define ARES_RC4_KEY_LEN 32 /* 256 bits */ @@ -56,17 +54,20 @@ typedef struct ares_rand_rc4 { static unsigned int ares_u32_from_ptr(void *addr) { - if (sizeof(void *) == 8) { + /* LCOV_EXCL_START: FallbackCode */ + if (ares__is_64bit()) { return (unsigned int)((((ares_uint64_t)addr >> 32) & 0xFFFFFFFF) | ((ares_uint64_t)addr & 0xFFFFFFFF)); } return (unsigned int)((size_t)addr & 0xFFFFFFFF); + /* LCOV_EXCL_STOP */ } /* initialize an rc4 key as the last possible fallback. */ static void ares_rc4_generate_key(ares_rand_rc4 *rc4_state, unsigned char *key, size_t key_len) { + /* LCOV_EXCL_START: FallbackCode */ size_t i; size_t len = 0; unsigned int data; @@ -88,7 +89,7 @@ static void ares_rc4_generate_key(ares_rand_rc4 *rc4_state, unsigned char *key, memcpy(key + len, &data, sizeof(data)); len += sizeof(data); - tv = ares__tvnow(); + ares__tvnow(&tv); data = (unsigned int)((tv.sec | tv.usec) & 0xFFFFFFFF); memcpy(key + len, &data, sizeof(data)); len += sizeof(data); @@ -99,10 +100,19 @@ static void ares_rc4_generate_key(ares_rand_rc4 *rc4_state, unsigned char *key, for (i = len; i < key_len; i++) { key[i] = (unsigned char)(rand() % 256); /* LCOV_EXCL_LINE */ } + /* LCOV_EXCL_STOP */ } +#define ARES_SWAP_BYTE(a, b) \ + do { \ + unsigned char swapByte = *(a); \ + *(a) = *(b); \ + *(b) = swapByte; \ + } while (0) + static void ares_rc4_init(ares_rand_rc4 *rc4_state) { + /* LCOV_EXCL_START: FallbackCode */ unsigned char key[ARES_RC4_KEY_LEN]; size_t i; size_t j; @@ -120,6 +130,7 @@ static void ares_rc4_init(ares_rand_rc4 *rc4_state) rc4_state->i = 0; rc4_state->j = 0; + /* LCOV_EXCL_STOP */ } /* Just outputs the key schedule, no need to XOR with any data since we have @@ -127,6 +138,7 @@ static void ares_rc4_init(ares_rand_rc4 *rc4_state) static void ares_rc4_prng(ares_rand_rc4 *rc4_state, unsigned char *buf, size_t len) { + /* LCOV_EXCL_START: FallbackCode */ unsigned char *S = rc4_state->S; size_t i = rc4_state->i; size_t j = rc4_state->j; @@ -142,6 +154,7 @@ static void ares_rc4_prng(ares_rand_rc4 *rc4_state, unsigned char *buf, rc4_state->i = i; rc4_state->j = j; + /* LCOV_EXCL_STOP */ } struct ares_rand_state { @@ -187,6 +200,7 @@ static ares_bool_t ares__init_rand_engine(ares_rand_state *state) #endif #if defined(CARES_RANDOM_FILE) + /* LCOV_EXCL_START: FallbackCode */ if (!(state->bad_backends & ARES_RAND_FILE)) { state->type = ARES_RAND_FILE; state->state.rand_file = fopen(CARES_RANDOM_FILE, "rb"); @@ -195,14 +209,18 @@ static ares_bool_t ares__init_rand_engine(ares_rand_state *state) return ARES_TRUE; } } + /* LCOV_EXCL_STOP */ + /* Fall-Thru on failure to RC4 */ #endif + /* LCOV_EXCL_START: FallbackCode */ state->type = ARES_RAND_RC4; ares_rc4_init(&state->state.rc4); + /* LCOV_EXCL_STOP */ /* Currently cannot fail */ - return ARES_TRUE; + return ARES_TRUE; /* LCOV_EXCL_LINE: UntestablePath */ } ares_rand_state *ares__init_rand_state(void) @@ -215,8 +233,8 @@ ares_rand_state *ares__init_rand_state(void) } if (!ares__init_rand_engine(state)) { - ares_free(state); - return NULL; + ares_free(state); /* LCOV_EXCL_LINE: UntestablePath */ + return NULL; /* LCOV_EXCL_LINE: UntestablePath */ } return state; @@ -225,24 +243,28 @@ ares_rand_state *ares__init_rand_state(void) static void ares__clear_rand_state(ares_rand_state *state) { if (!state) { - return; + return; /* LCOV_EXCL_LINE: DefensiveCoding */ } switch (state->type) { case ARES_RAND_OS: break; + /* LCOV_EXCL_START: FallbackCode */ case ARES_RAND_FILE: fclose(state->state.rand_file); break; case ARES_RAND_RC4: break; + /* LCOV_EXCL_STOP */ } } static void ares__reinit_rand(ares_rand_state *state) { + /* LCOV_EXCL_START: UntestablePath */ ares__clear_rand_state(state); ares__init_rand_engine(state); + /* LCOV_EXCL_STOP */ } void ares__destroy_rand_state(ares_rand_state *state) @@ -296,6 +318,8 @@ static void ares__rand_bytes_fetch(ares_rand_state *state, unsigned char *buf, break; #endif + /* LCOV_EXCL_START: FallbackCode */ + case ARES_RAND_FILE: while (1) { size_t rv = fread(buf + bytes_read, 1, len - bytes_read, @@ -314,11 +338,13 @@ static void ares__rand_bytes_fetch(ares_rand_state *state, unsigned char *buf, case ARES_RAND_RC4: ares_rc4_prng(&state->state.rc4, buf, len); return; + + /* LCOV_EXCL_STOP */ } /* If we didn't return before we got here, that means we had a critical rand * failure and need to reinitialized */ - ares__reinit_rand(state); + ares__reinit_rand(state); /* LCOV_EXCL_LINE: UntestablePath */ } } diff --git a/contrib/libs/c-ares/src/lib/windows_port.c b/contrib/libs/c-ares/src/lib/windows_port.c index d5f0ad3abf..22f0dc020a 100644 --- a/contrib/libs/c-ares/src/lib/windows_port.c +++ b/contrib/libs/c-ares/src/lib/windows_port.c @@ -6,12 +6,12 @@ * SPDX-License-Identifier: MIT * */ -#include "ares_setup.h" +#include "ares_private.h" /* only do the following on windows */ -#if (defined(WIN32) || defined(WATT32)) && !defined(MSDOS) +#if defined(_WIN32) && !defined(MSDOS) # ifdef __WATCOMC__ /* diff --git a/contrib/libs/c-ares/ya.make b/contrib/libs/c-ares/ya.make index 7850b67185..864edf40a5 100644 --- a/contrib/libs/c-ares/ya.make +++ b/contrib/libs/c-ares/ya.make @@ -12,9 +12,9 @@ LICENSE( LICENSE_TEXTS(.yandex_meta/licenses.list.txt) -VERSION(1.30.0) +VERSION(1.33.0) -ORIGINAL_SOURCE(https://github.com/c-ares/c-ares/archive/v1.30.0.tar.gz) +ORIGINAL_SOURCE(https://github.com/c-ares/c-ares/archive/v1.33.0.tar.gz) PEERDIR( contrib/libs/libc_compat @@ -50,43 +50,16 @@ ENDIF() SRCS( src/lib/ares__addrinfo2hostent.c src/lib/ares__addrinfo_localhost.c - src/lib/ares__buf.c src/lib/ares__close_sockets.c src/lib/ares__hosts_file.c - src/lib/ares__htable.c - src/lib/ares__htable_asvp.c - src/lib/ares__htable_strvp.c - src/lib/ares__htable_szvp.c - src/lib/ares__htable_vpvp.c - src/lib/ares__iface_ips.c - src/lib/ares__llist.c src/lib/ares__parse_into_addrinfo.c - src/lib/ares__slist.c src/lib/ares__socket.c src/lib/ares__sortaddrinfo.c - src/lib/ares__threads.c - src/lib/ares__timeval.c src/lib/ares_android.c src/lib/ares_cancel.c - src/lib/ares_create_query.c + src/lib/ares_cookie.c src/lib/ares_data.c src/lib/ares_destroy.c - src/lib/ares_dns_mapping.c - src/lib/ares_dns_name.c - src/lib/ares_dns_parse.c - src/lib/ares_dns_record.c - src/lib/ares_dns_write.c - src/lib/ares_event_configchg.c - src/lib/ares_event_epoll.c - src/lib/ares_event_kqueue.c - src/lib/ares_event_poll.c - src/lib/ares_event_select.c - src/lib/ares_event_thread.c - src/lib/ares_event_wake_pipe.c - src/lib/ares_event_win32.c - src/lib/ares_expand_name.c - src/lib/ares_expand_string.c - src/lib/ares_fds.c src/lib/ares_free_hostent.c src/lib/ares_free_string.c src/lib/ares_freeaddrinfo.c @@ -95,42 +68,74 @@ SRCS( src/lib/ares_gethostbyaddr.c src/lib/ares_gethostbyname.c src/lib/ares_getnameinfo.c - src/lib/ares_getsock.c src/lib/ares_init.c src/lib/ares_library_init.c - src/lib/ares_math.c + src/lib/ares_metrics.c src/lib/ares_options.c - src/lib/ares_parse_a_reply.c - src/lib/ares_parse_aaaa_reply.c - src/lib/ares_parse_caa_reply.c - src/lib/ares_parse_mx_reply.c - src/lib/ares_parse_naptr_reply.c - src/lib/ares_parse_ns_reply.c - src/lib/ares_parse_ptr_reply.c - src/lib/ares_parse_soa_reply.c - src/lib/ares_parse_srv_reply.c - src/lib/ares_parse_txt_reply.c - src/lib/ares_parse_uri_reply.c src/lib/ares_platform.c src/lib/ares_process.c src/lib/ares_qcache.c src/lib/ares_query.c - src/lib/ares_rand.c src/lib/ares_search.c src/lib/ares_send.c - src/lib/ares_str.c - src/lib/ares_strcasecmp.c src/lib/ares_strerror.c - src/lib/ares_strsplit.c src/lib/ares_sysconfig.c src/lib/ares_sysconfig_files.c src/lib/ares_sysconfig_mac.c + src/lib/ares_sysconfig_win.c src/lib/ares_timeout.c src/lib/ares_update_servers.c src/lib/ares_version.c src/lib/atomic.cpp + src/lib/dsa/ares__array.c + src/lib/dsa/ares__htable.c + src/lib/dsa/ares__htable_asvp.c + src/lib/dsa/ares__htable_strvp.c + src/lib/dsa/ares__htable_szvp.c + src/lib/dsa/ares__htable_vpvp.c + src/lib/dsa/ares__llist.c + src/lib/dsa/ares__slist.c + src/lib/event/ares_event_configchg.c + src/lib/event/ares_event_epoll.c + src/lib/event/ares_event_kqueue.c + src/lib/event/ares_event_poll.c + src/lib/event/ares_event_select.c + src/lib/event/ares_event_thread.c + src/lib/event/ares_event_wake_pipe.c + src/lib/event/ares_event_win32.c src/lib/inet_net_pton.c src/lib/inet_ntop.c + src/lib/legacy/ares_create_query.c + src/lib/legacy/ares_expand_name.c + src/lib/legacy/ares_expand_string.c + src/lib/legacy/ares_fds.c + src/lib/legacy/ares_getsock.c + src/lib/legacy/ares_parse_a_reply.c + src/lib/legacy/ares_parse_aaaa_reply.c + src/lib/legacy/ares_parse_caa_reply.c + src/lib/legacy/ares_parse_mx_reply.c + src/lib/legacy/ares_parse_naptr_reply.c + src/lib/legacy/ares_parse_ns_reply.c + src/lib/legacy/ares_parse_ptr_reply.c + src/lib/legacy/ares_parse_soa_reply.c + src/lib/legacy/ares_parse_srv_reply.c + src/lib/legacy/ares_parse_txt_reply.c + src/lib/legacy/ares_parse_uri_reply.c + src/lib/record/ares_dns_mapping.c + src/lib/record/ares_dns_multistring.c + src/lib/record/ares_dns_name.c + src/lib/record/ares_dns_parse.c + src/lib/record/ares_dns_record.c + src/lib/record/ares_dns_write.c + src/lib/str/ares__buf.c + src/lib/str/ares_str.c + src/lib/str/ares_strcasecmp.c + src/lib/str/ares_strsplit.c + src/lib/util/ares__iface_ips.c + src/lib/util/ares__threads.c + src/lib/util/ares__timeval.c + src/lib/util/ares_math.c + src/lib/util/ares_rand.c src/lib/windows_port.c ) |