diff options
author | dvshkurko <dvshkurko@yandex-team.ru> | 2022-02-10 16:45:52 +0300 |
---|---|---|
committer | Daniil Cherednik <dcherednik@yandex-team.ru> | 2022-02-10 16:45:52 +0300 |
commit | c768a99151e47c3a4bb7b92c514d256abd301c4d (patch) | |
tree | 1a2c5ffcf89eb53ecd79dbc9bc0a195c27404d0c /contrib/libs/c-ares | |
parent | 321ee9bce31ec6e238be26dbcbe539cffa2c3309 (diff) | |
download | ydb-c768a99151e47c3a4bb7b92c514d256abd301c4d.tar.gz |
Restoring authorship annotation for <dvshkurko@yandex-team.ru>. Commit 2 of 2.
Diffstat (limited to 'contrib/libs/c-ares')
51 files changed, 9021 insertions, 9021 deletions
diff --git a/contrib/libs/c-ares/CHANGES b/contrib/libs/c-ares/CHANGES index a0ad09fd31..f6652caaa0 100644 --- a/contrib/libs/c-ares/CHANGES +++ b/contrib/libs/c-ares/CHANGES @@ -554,242 +554,242 @@ Brad House (24 Dec 2019) Daniel Stenberg (24 Oct 2018) - ares_library_init_android.3: minor syntax edits, fixed AVAILABILITY -Version 1.15.0 (23 Oct 2018) - -Brad House (23 Oct 2018) -- last minute 1.15.0 addition - -- [Ben Noordhuis brought this change] - - Report ARES_ENOTFOUND for .onion domain names as per RFC7686. (#228) - - Quoting RFC 7686: - - Name Resolution APIs and Libraries (...) MUST either respond - to requests for .onion names by resolving them according to - [tor-rendezvous] or by responding with NXDOMAIN. - - A legacy client may inadvertently attempt to resolve a .onion - name through the DNS. This causes a disclosure that the client - is attempting to use Tor to reach a specific service. Malicious - resolvers could be engineered to capture and record such leaks, - which might have very adverse consequences for the well-being - of the user. - - Bug: #196 - Fix By: Ben Noordhuis @bnoordhuis - -- prepare for c-ares 1.15.0 release - -- AIX Build Fix - - AIX attempts to include both nameser_compat.h and onameser_compat.h. It appears - the proper fix is to define _USE_IRS so that only nameser_compat.h is used. - - Bug: #224 - Fix By: Brad House (@bradh352) - -- Fix crash in ares_dup() due to new ARES_OPT_RESOLVCONF - - ares_dup() calls ares_init_options() by making its own fake option - mask since the original mask isn't stored but ARES_OPT_RESOLVCONF - was always set, instead of conditionally set. This caused a crash - because ares_strdup() isn't NULL-safe if no custom path was set. - - Made ares_dup() set ARES_OPT_RESOLVCONF conditionally. - - Fix By: Brad House (@bradh352) - -- [Sarat Addepalli brought this change] - - Add ares_init_options() configurability for path to resolv.conf file - - Add resolvconf_path to end of struct ares_options with ARES_OPT_RESOLVCONF option - so on Unix-like systems a custom path can be specified. If no path is specified, - /etc/resolv.conf is used like normal. - - Fix By: Sarat Addepalli @SirR4T - Fixes Bug: #220 - Review By: Brad House @bradh352 - -- remove stale variables - -- fix prototype name for ares_strsplit_free() - -- add missing prototype - -- simplify ares_strsplit() and create ares_strsplit_free() helper function - -- missing ares_strsplit.h from HHEADERS for inclusion in distribution - -- [Ruslan Baratov brought this change] - - Add CARES_BUILD_TOOLS CMake option (#214) - - Add ability to exclude building of tools (adig, ahost, acountry) in CMake. This should also close #200. - - Fix By: Ruslan Baratov (@ruslo) - Bug: #200 - -- [flyingdutchman23 brought this change] - - Style. Whitespace cleanup. (#213) - - Small whitespace cleanups. - - Fix By: @flyingdutchman23 - -- [John Schember brought this change] - - Android: Support for domain search suffix (#211) - - Fixes issue #207. Uses LinkProperties.getDomains() to get a list of search domains and adds them to the suffix list. This also adds a new helper function to split strings into an array based on multiple delimiters replacing multiple other functions for dealing with string splitting. - - Submitter: John Schember (@user-none) - Fixes: #207 - Approved-by: Brad House (@bradh352) - -- [afalin brought this change] - - Improve DNS suffixes extracting from WinNT registry (#202) - - Join all global and connection specific suffix lists. Use 'HKLM\Software\Policies\Microsoft\Windows NT\DNSClient\SearchList', 'HKLM\System\CurrentControlSet\Services\Tcpip\Parameters\Domain' as global suffix lists. - - Fix By: @afalin - -- Be consistent with indention in CMakeLists.txt - - The imported TRANSFORM_MAKEFILE_INC function from curl used space indention - but the rest of the file used tabs. Go ahead and make it tabs for - consistency as well. - - Committed By: Brad House - -- [flyingdutchman23 brought this change] - - Fix modern gcc warning: argument to 'sizeof' in 'strncpy' call is the same expression as the source - - Silence warning about using src to determine number of bytes to copy. - In this case it doesn't matter whether it is `src` or `dest`. So there - is no functionality change. - - Bug: #210 - Fix By: @flyingdutchman23 - -- [Andi Schnebinger brought this change] - - fix stringop-overflow warning of GCC (#201) - - When using a modern GCC to compile c-ares, there is a stringop-overflow warning. - This patch simply silences the false-positive warning, there is no actual code flaw. - - Bug: https://github.com/c-ares/c-ares/pull/201 - Fixed By: Andi Schnebinger @Iniesta8 - -GitHub (18 May 2018) -- [David Drysdale brought this change] - - travis: do coverage in "coverage" build (#195) - - Fixes #194, a mistake from commit a255081f2c3c ("travis: Only do - coverage/distcheck on normal build") - -Brad House (17 May 2018) -- [Brad Spencer brought this change] - - Apply the IPv6 server blacklist to all nameserver sources, not just Windows (#193) - - For #164, I mentioned that it seemed like the IPv6 nameserver blacklist should apply to all OSes. In a mailing list post, @bradh352 agreed and suggested that I file a PR to make it so. - - This moves the blacklist check from being Windows-specific to being a general feature of config_nameservers(), no matter the nameserver source. It also simplifies the ares_ipv6_server_blacklisted() implementation to not parse and re-parse the blacklisted IPv6 addresses from strings on every check. I think they're almost as easy to read as a sequence of hex bytes in an array initializer, and it's definitely less work on each trip through the code. - - Fix By: Brad Spencer @b-spencer - PR: https://github.com/c-ares/c-ares/pull/193 - -- [Brad Spencer brought this change] - - Fix warnings emitted by MSVC when using -W4 (#192) - - These changes fix a few warnings emitted by recent versions of MSVC when compiling with -W4. Half of the changes are in Windows-specific code, and the other half should be safe no matter the compiler or OS. - - The allocation function change is probably the only one that needs explanation. MSVC gives warnings about the function pointers not being stable across DLL boundaries or something to that effect, so for Windows, I've made them be called indirectly, which at least made the compiler happy. I can't say I've tested every linking combination on Windows with them before or after the change, but it seems harmless. - - Fix By: Brad Spencer @b-spencer - PR: https://github.com/c-ares/c-ares/pull/192 - -- [David Hotham brought this change] - - Prevent changing name servers while queries are outstanding (#191) - - Changing name servers doesn't work, per #41. Better to return an error code than to crash. - - Fix-by: David Hotham @dimbleby - -David Drysdale (15 May 2018) -- [Tobias Nießen brought this change] - - Fix comment in ares_rules.h (#189) - -Brad House (6 May 2018) -- [Brad Spencer brought this change] - - Harden and rationalize c-ares timeout computation (#187) - - * Harden and rationalize c-ares timeout computation - * Remove the rand() part of the timeout calculation completely. - - When c-ares sends a DNS query, it computes the timeout for that request as follows: - - timeplus = channel->timeout << (query->try_count / channel->nservers); - timeplus = (timeplus * (9 + (rand () & 7))) / 16; - I see two issues with this code. Firstly, when either try_count or channel->timeout are large enough, this can end up as an illegal shift. - - Secondly, the algorithm for adding the random timeout (added in 2009) is surprising. The original commit that introduced this algorithm says it was done to avoid a "packet storm". But, the algorithm appears to only reduce the timeout by an amount proportional to the scaled timeout's magnitude. It isn't clear to me that, for example, cutting a 30 second timeout almost in half to roughly 17 seconds is appropriate. Even with the default timeout of 5000 ms, this algorithm computes values between 2812 ms and 5000 ms, which is enough to cause a slightly latent DNS response to get spuriously dropped. - - If preventing the timers from all expiring at the same time really is desirable, then it seems better to extend the timeout by a small factor so that the application gets at least the timeout it asked for, and maybe a little more. In my experience, this is common practice for timeouts: applications expect that a timeout will happen at or after the designated time (but not before), allowing for delay in detecting and reporting the timeout. Furthermore, it seems like the timeout shouldn't be extended by very much (we don't want a 30 second timeout changing into a 45 second timeout, either). - - Consider also the documentation of channel->timeout in ares_init_options(): - - The number of milliseconds each name server is given to respond to a query on the first try. (After the first try, the timeout algorithm becomes more complicated, but scales linearly with the value of timeout.) The default is five seconds. - - In the current implementation, even the first try does not use the value that the user supplies; it will use anywhere between 56% and 100% of that value. - - The attached patch attempts to address all of these concerns without trying to make the algorithm much more sophisticated. After performing a safe shift, this patch simply adds a small random timeout to the computed value of between 0 ms and 511 ms. I could see limiting the random amount to be no greater than a proportion of the configured magnitude, but I can't see scaling the random with the overall computed timeout. As far as I understand, the goal is just to schedule retries "not at the same exact time", so a small difference seems sufficient. - - UPDATE: randomization removed. - - Closes PR #187 - Fix by: Brad Spencer - -- distribute ares_android.h - - Distribute ares_android.h when a release distribution package is - created. - - Reported By: Andrey Khranovsky - Bug: https://c-ares.haxx.se/mail/c-ares-archive-2018-04/0000.shtml - -- ares_set_servers_csv() on failure should not leave channel in a bad state - - If bad data is passed to ares_set_servers_csv() or - ares_set_servers_ports_csv() it will clear the existing channel - configured DNS servers, then a call to ares_send() will fail due - to a bad malloc which may have undefined behavior. - - The fix now only clears existing servers on success. An additional - sanity check was added in ares_send() to ensure nservers >= 1 or - will result in ARES_ESERVFAIL. - - Bug: https://c-ares.haxx.se/mail/c-ares-archive-2018-03/0000.shtml - Reported-by: Francisco Sedano Crippa - -- docs: Not all manpages are listed - - Some docs aren't installed or not showing up on - https://c-ares.haxx.se/docs.html - due to not being listed in Makefile.inc. Add missing docs and - ensure docs are alphabetized. - +Version 1.15.0 (23 Oct 2018) + +Brad House (23 Oct 2018) +- last minute 1.15.0 addition + +- [Ben Noordhuis brought this change] + + Report ARES_ENOTFOUND for .onion domain names as per RFC7686. (#228) + + Quoting RFC 7686: + + Name Resolution APIs and Libraries (...) MUST either respond + to requests for .onion names by resolving them according to + [tor-rendezvous] or by responding with NXDOMAIN. + + A legacy client may inadvertently attempt to resolve a .onion + name through the DNS. This causes a disclosure that the client + is attempting to use Tor to reach a specific service. Malicious + resolvers could be engineered to capture and record such leaks, + which might have very adverse consequences for the well-being + of the user. + + Bug: #196 + Fix By: Ben Noordhuis @bnoordhuis + +- prepare for c-ares 1.15.0 release + +- AIX Build Fix + + AIX attempts to include both nameser_compat.h and onameser_compat.h. It appears + the proper fix is to define _USE_IRS so that only nameser_compat.h is used. + + Bug: #224 + Fix By: Brad House (@bradh352) + +- Fix crash in ares_dup() due to new ARES_OPT_RESOLVCONF + + ares_dup() calls ares_init_options() by making its own fake option + mask since the original mask isn't stored but ARES_OPT_RESOLVCONF + was always set, instead of conditionally set. This caused a crash + because ares_strdup() isn't NULL-safe if no custom path was set. + + Made ares_dup() set ARES_OPT_RESOLVCONF conditionally. + + Fix By: Brad House (@bradh352) + +- [Sarat Addepalli brought this change] + + Add ares_init_options() configurability for path to resolv.conf file + + Add resolvconf_path to end of struct ares_options with ARES_OPT_RESOLVCONF option + so on Unix-like systems a custom path can be specified. If no path is specified, + /etc/resolv.conf is used like normal. + + Fix By: Sarat Addepalli @SirR4T + Fixes Bug: #220 + Review By: Brad House @bradh352 + +- remove stale variables + +- fix prototype name for ares_strsplit_free() + +- add missing prototype + +- simplify ares_strsplit() and create ares_strsplit_free() helper function + +- missing ares_strsplit.h from HHEADERS for inclusion in distribution + +- [Ruslan Baratov brought this change] + + Add CARES_BUILD_TOOLS CMake option (#214) + + Add ability to exclude building of tools (adig, ahost, acountry) in CMake. This should also close #200. + + Fix By: Ruslan Baratov (@ruslo) + Bug: #200 + +- [flyingdutchman23 brought this change] + + Style. Whitespace cleanup. (#213) + + Small whitespace cleanups. + + Fix By: @flyingdutchman23 + +- [John Schember brought this change] + + Android: Support for domain search suffix (#211) + + Fixes issue #207. Uses LinkProperties.getDomains() to get a list of search domains and adds them to the suffix list. This also adds a new helper function to split strings into an array based on multiple delimiters replacing multiple other functions for dealing with string splitting. + + Submitter: John Schember (@user-none) + Fixes: #207 + Approved-by: Brad House (@bradh352) + +- [afalin brought this change] + + Improve DNS suffixes extracting from WinNT registry (#202) + + Join all global and connection specific suffix lists. Use 'HKLM\Software\Policies\Microsoft\Windows NT\DNSClient\SearchList', 'HKLM\System\CurrentControlSet\Services\Tcpip\Parameters\Domain' as global suffix lists. + + Fix By: @afalin + +- Be consistent with indention in CMakeLists.txt + + The imported TRANSFORM_MAKEFILE_INC function from curl used space indention + but the rest of the file used tabs. Go ahead and make it tabs for + consistency as well. + + Committed By: Brad House + +- [flyingdutchman23 brought this change] + + Fix modern gcc warning: argument to 'sizeof' in 'strncpy' call is the same expression as the source + + Silence warning about using src to determine number of bytes to copy. + In this case it doesn't matter whether it is `src` or `dest`. So there + is no functionality change. + + Bug: #210 + Fix By: @flyingdutchman23 + +- [Andi Schnebinger brought this change] + + fix stringop-overflow warning of GCC (#201) + + When using a modern GCC to compile c-ares, there is a stringop-overflow warning. + This patch simply silences the false-positive warning, there is no actual code flaw. + + Bug: https://github.com/c-ares/c-ares/pull/201 + Fixed By: Andi Schnebinger @Iniesta8 + +GitHub (18 May 2018) +- [David Drysdale brought this change] + + travis: do coverage in "coverage" build (#195) + + Fixes #194, a mistake from commit a255081f2c3c ("travis: Only do + coverage/distcheck on normal build") + +Brad House (17 May 2018) +- [Brad Spencer brought this change] + + Apply the IPv6 server blacklist to all nameserver sources, not just Windows (#193) + + For #164, I mentioned that it seemed like the IPv6 nameserver blacklist should apply to all OSes. In a mailing list post, @bradh352 agreed and suggested that I file a PR to make it so. + + This moves the blacklist check from being Windows-specific to being a general feature of config_nameservers(), no matter the nameserver source. It also simplifies the ares_ipv6_server_blacklisted() implementation to not parse and re-parse the blacklisted IPv6 addresses from strings on every check. I think they're almost as easy to read as a sequence of hex bytes in an array initializer, and it's definitely less work on each trip through the code. + + Fix By: Brad Spencer @b-spencer + PR: https://github.com/c-ares/c-ares/pull/193 + +- [Brad Spencer brought this change] + + Fix warnings emitted by MSVC when using -W4 (#192) + + These changes fix a few warnings emitted by recent versions of MSVC when compiling with -W4. Half of the changes are in Windows-specific code, and the other half should be safe no matter the compiler or OS. + + The allocation function change is probably the only one that needs explanation. MSVC gives warnings about the function pointers not being stable across DLL boundaries or something to that effect, so for Windows, I've made them be called indirectly, which at least made the compiler happy. I can't say I've tested every linking combination on Windows with them before or after the change, but it seems harmless. + + Fix By: Brad Spencer @b-spencer + PR: https://github.com/c-ares/c-ares/pull/192 + +- [David Hotham brought this change] + + Prevent changing name servers while queries are outstanding (#191) + + Changing name servers doesn't work, per #41. Better to return an error code than to crash. + + Fix-by: David Hotham @dimbleby + +David Drysdale (15 May 2018) +- [Tobias Nießen brought this change] + + Fix comment in ares_rules.h (#189) + +Brad House (6 May 2018) +- [Brad Spencer brought this change] + + Harden and rationalize c-ares timeout computation (#187) + + * Harden and rationalize c-ares timeout computation + * Remove the rand() part of the timeout calculation completely. + + When c-ares sends a DNS query, it computes the timeout for that request as follows: + + timeplus = channel->timeout << (query->try_count / channel->nservers); + timeplus = (timeplus * (9 + (rand () & 7))) / 16; + I see two issues with this code. Firstly, when either try_count or channel->timeout are large enough, this can end up as an illegal shift. + + Secondly, the algorithm for adding the random timeout (added in 2009) is surprising. The original commit that introduced this algorithm says it was done to avoid a "packet storm". But, the algorithm appears to only reduce the timeout by an amount proportional to the scaled timeout's magnitude. It isn't clear to me that, for example, cutting a 30 second timeout almost in half to roughly 17 seconds is appropriate. Even with the default timeout of 5000 ms, this algorithm computes values between 2812 ms and 5000 ms, which is enough to cause a slightly latent DNS response to get spuriously dropped. + + If preventing the timers from all expiring at the same time really is desirable, then it seems better to extend the timeout by a small factor so that the application gets at least the timeout it asked for, and maybe a little more. In my experience, this is common practice for timeouts: applications expect that a timeout will happen at or after the designated time (but not before), allowing for delay in detecting and reporting the timeout. Furthermore, it seems like the timeout shouldn't be extended by very much (we don't want a 30 second timeout changing into a 45 second timeout, either). + + Consider also the documentation of channel->timeout in ares_init_options(): + + The number of milliseconds each name server is given to respond to a query on the first try. (After the first try, the timeout algorithm becomes more complicated, but scales linearly with the value of timeout.) The default is five seconds. + + In the current implementation, even the first try does not use the value that the user supplies; it will use anywhere between 56% and 100% of that value. + + The attached patch attempts to address all of these concerns without trying to make the algorithm much more sophisticated. After performing a safe shift, this patch simply adds a small random timeout to the computed value of between 0 ms and 511 ms. I could see limiting the random amount to be no greater than a proportion of the configured magnitude, but I can't see scaling the random with the overall computed timeout. As far as I understand, the goal is just to schedule retries "not at the same exact time", so a small difference seems sufficient. + + UPDATE: randomization removed. + + Closes PR #187 + Fix by: Brad Spencer + +- distribute ares_android.h + + Distribute ares_android.h when a release distribution package is + created. + + Reported By: Andrey Khranovsky + Bug: https://c-ares.haxx.se/mail/c-ares-archive-2018-04/0000.shtml + +- ares_set_servers_csv() on failure should not leave channel in a bad state + + If bad data is passed to ares_set_servers_csv() or + ares_set_servers_ports_csv() it will clear the existing channel + configured DNS servers, then a call to ares_send() will fail due + to a bad malloc which may have undefined behavior. + + The fix now only clears existing servers on success. An additional + sanity check was added in ares_send() to ensure nservers >= 1 or + will result in ARES_ESERVFAIL. + + Bug: https://c-ares.haxx.se/mail/c-ares-archive-2018-03/0000.shtml + Reported-by: Francisco Sedano Crippa + +- docs: Not all manpages are listed + + Some docs aren't installed or not showing up on + https://c-ares.haxx.se/docs.html + due to not being listed in Makefile.inc. Add missing docs and + ensure docs are alphabetized. + Version 1.14.0 (16 Feb 2018) Daniel Stenberg (16 Feb 2018) diff --git a/contrib/libs/c-ares/RELEASE-NOTES b/contrib/libs/c-ares/RELEASE-NOTES index a4cad95883..7a9d75fe78 100644 --- a/contrib/libs/c-ares/RELEASE-NOTES +++ b/contrib/libs/c-ares/RELEASE-NOTES @@ -9,7 +9,7 @@ Changes: o Allow TXT records on CHAOS qclass. Used for retriving things like version.bind, version.server, authoris.bind, hostname.bind, and id.server. [3] - + Bug fixes: o Fix Windows Unicode incompatibilities with ares_getaddrinfo() [1] o Silence false cast-align compiler warnings due to valid casts of diff --git a/contrib/libs/c-ares/RELEASE-PROCEDURE.md b/contrib/libs/c-ares/RELEASE-PROCEDURE.md index 5688ca8db0..b2fe58639b 100644 --- a/contrib/libs/c-ares/RELEASE-PROCEDURE.md +++ b/contrib/libs/c-ares/RELEASE-PROCEDURE.md @@ -1,53 +1,53 @@ -c-ares release procedure - how to do a release -============================================== - -in the source code repo ------------------------ - -- edit `RELEASE-NOTES` to be accurate - -- edit `Makefile.am`'s `CARES_VERSION_INFO`, and `CMakeLists.txt`'s - `CARES_LIB_VERSIONINFO` set to the same value to denote the current shared - object versioning. - -- 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.haxx.se/download/ - -- update `ares_version.h` for the next version - -in the c-ares-www repo ----------------------- - -- edit `index.t` (version number and date), - -- edit `changelog.t` (add the new release in there) - -- 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 - -inform ------- - -- send an email to the c-ares mailing list. Insert the RELEASE-NOTES into the - mail. - -celebrate ---------- - -- suitable beverage intake is encouraged for the festivities +c-ares release procedure - how to do a release +============================================== + +in the source code repo +----------------------- + +- edit `RELEASE-NOTES` to be accurate + +- edit `Makefile.am`'s `CARES_VERSION_INFO`, and `CMakeLists.txt`'s + `CARES_LIB_VERSIONINFO` set to the same value to denote the current shared + object versioning. + +- 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.haxx.se/download/ + +- update `ares_version.h` for the next version + +in the c-ares-www repo +---------------------- + +- edit `index.t` (version number and date), + +- edit `changelog.t` (add the new release in there) + +- 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 + +inform +------ + +- send an email to the c-ares mailing list. Insert the RELEASE-NOTES into the + mail. + +celebrate +--------- + +- suitable beverage intake is encouraged for the festivities diff --git a/contrib/libs/c-ares/acountry/ya.make b/contrib/libs/c-ares/acountry/ya.make index 6498a62c0e..58b533d30c 100644 --- a/contrib/libs/c-ares/acountry/ya.make +++ b/contrib/libs/c-ares/acountry/ya.make @@ -1,35 +1,35 @@ -# Generated by devtools/yamaker. - -PROGRAM(acountry) - +# Generated by devtools/yamaker. + +PROGRAM(acountry) + OWNER(max42 g:cpp-contrib) - -LICENSE(MIT) - -PEERDIR( - contrib/libs/c-ares -) - -ADDINCL( - contrib/libs/c-ares -) - -NO_COMPILER_WARNINGS() - + +LICENSE(MIT) + +PEERDIR( + contrib/libs/c-ares +) + +ADDINCL( + contrib/libs/c-ares +) + +NO_COMPILER_WARNINGS() + CFLAGS( -DHAVE_CONFIG_H ) -SRCDIR(contrib/libs/c-ares) - -IF (NOT DLL_FOR) - CFLAGS( - -DCARES_STATICLIB - ) -ENDIF() - -SRCS( - acountry.c -) - -END() +SRCDIR(contrib/libs/c-ares) + +IF (NOT DLL_FOR) + CFLAGS( + -DCARES_STATICLIB + ) +ENDIF() + +SRCS( + acountry.c +) + +END() diff --git a/contrib/libs/c-ares/adig/ya.make b/contrib/libs/c-ares/adig/ya.make index 11a0b23f38..1c8404ebee 100644 --- a/contrib/libs/c-ares/adig/ya.make +++ b/contrib/libs/c-ares/adig/ya.make @@ -1,35 +1,35 @@ -# Generated by devtools/yamaker. - -PROGRAM(adig) - +# Generated by devtools/yamaker. + +PROGRAM(adig) + OWNER(max42 g:cpp-contrib) - -LICENSE(MIT) - -PEERDIR( - contrib/libs/c-ares -) - -ADDINCL( - contrib/libs/c-ares -) - -NO_COMPILER_WARNINGS() - + +LICENSE(MIT) + +PEERDIR( + contrib/libs/c-ares +) + +ADDINCL( + contrib/libs/c-ares +) + +NO_COMPILER_WARNINGS() + CFLAGS( -DHAVE_CONFIG_H ) -SRCDIR(contrib/libs/c-ares) - -IF (NOT DLL_FOR) - CFLAGS( - -DCARES_STATICLIB - ) -ENDIF() - -SRCS( - adig.c -) - -END() +SRCDIR(contrib/libs/c-ares) + +IF (NOT DLL_FOR) + CFLAGS( + -DCARES_STATICLIB + ) +ENDIF() + +SRCS( + adig.c +) + +END() diff --git a/contrib/libs/c-ares/ahost/ya.make b/contrib/libs/c-ares/ahost/ya.make index 955acf5247..299e3f211c 100644 --- a/contrib/libs/c-ares/ahost/ya.make +++ b/contrib/libs/c-ares/ahost/ya.make @@ -1,35 +1,35 @@ -# Generated by devtools/yamaker. - -PROGRAM(ahost) - +# Generated by devtools/yamaker. + +PROGRAM(ahost) + OWNER(max42 g:cpp-contrib) - -LICENSE(MIT) - -PEERDIR( - contrib/libs/c-ares -) - -ADDINCL( - contrib/libs/c-ares -) - -NO_COMPILER_WARNINGS() - + +LICENSE(MIT) + +PEERDIR( + contrib/libs/c-ares +) + +ADDINCL( + contrib/libs/c-ares +) + +NO_COMPILER_WARNINGS() + CFLAGS( -DHAVE_CONFIG_H ) -SRCDIR(contrib/libs/c-ares) - -IF (NOT DLL_FOR) - CFLAGS( - -DCARES_STATICLIB - ) -ENDIF() - -SRCS( - ahost.c -) - -END() +SRCDIR(contrib/libs/c-ares) + +IF (NOT DLL_FOR) + CFLAGS( + -DCARES_STATICLIB + ) +ENDIF() + +SRCS( + ahost.c +) + +END() diff --git a/contrib/libs/c-ares/ares.h b/contrib/libs/c-ares/ares.h index 97ff396ed9..3f8a6954d0 100644 --- a/contrib/libs/c-ares/ares.h +++ b/contrib/libs/c-ares/ares.h @@ -167,7 +167,7 @@ extern "C" { #define ARES_OPT_ROTATE (1 << 14) #define ARES_OPT_EDNSPSZ (1 << 15) #define ARES_OPT_NOROTATE (1 << 16) -#define ARES_OPT_RESOLVCONF (1 << 17) +#define ARES_OPT_RESOLVCONF (1 << 17) #define ARES_OPT_MAXTIMEOUTMS (1 << 18) #define ARES_OPT_JITTER (1 << 19) @@ -281,7 +281,7 @@ struct ares_options { struct apattern *sortlist; int nsort; int ednspsz; - char *resolvconf_path; + char *resolvconf_path; }; struct hostent; diff --git a/contrib/libs/c-ares/ares_android.c b/contrib/libs/c-ares/ares_android.c index 750a855665..5b00b8065c 100644 --- a/contrib/libs/c-ares/ares_android.c +++ b/contrib/libs/c-ares/ares_android.c @@ -30,8 +30,8 @@ static jmethodID android_cm_active_net_mid = NULL; static jmethodID android_cm_link_props_mid = NULL; /* LinkProperties.getDnsServers */ static jmethodID android_lp_dns_servers_mid = NULL; -/* LinkProperties.getDomains */ -static jmethodID android_lp_domains_mid = NULL; +/* LinkProperties.getDomains */ +static jmethodID android_lp_domains_mid = NULL; /* List.size */ static jmethodID android_list_size_mid = NULL; /* List.get */ @@ -141,12 +141,12 @@ int ares_library_init_android(jobject connectivity_manager) if (android_lp_dns_servers_mid == NULL) goto cleanup; - /* getDomains in API 21. */ - android_lp_domains_mid = jni_get_method_id(env, obj_cls, "getDomains", - "()Ljava/lang/String;"); - if (android_lp_domains_mid == NULL) - goto cleanup; - + /* getDomains in API 21. */ + android_lp_domains_mid = jni_get_method_id(env, obj_cls, "getDomains", + "()Ljava/lang/String;"); + if (android_lp_domains_mid == NULL) + goto cleanup; + (*env)->DeleteLocalRef(env, obj_cls); obj_cls = jni_get_class(env, "java/util/List"); if (obj_cls == NULL) @@ -181,7 +181,7 @@ cleanup: android_cm_active_net_mid = NULL; android_cm_link_props_mid = NULL; android_lp_dns_servers_mid = NULL; - android_lp_domains_mid = NULL; + android_lp_domains_mid = NULL; android_list_size_mid = NULL; android_list_get_mid = NULL; android_ia_host_addr_mid = NULL; @@ -222,7 +222,7 @@ void ares_library_cleanup_android(void) android_cm_active_net_mid = NULL; android_cm_link_props_mid = NULL; android_lp_dns_servers_mid = NULL; - android_lp_domains_mid = NULL; + android_lp_domains_mid = NULL; android_list_size_mid = NULL; android_list_get_mid = NULL; android_ia_host_addr_mid = NULL; @@ -351,93 +351,93 @@ done: (*android_jvm)->DetachCurrentThread(android_jvm); return dns_list; } - -char *ares_get_android_search_domains_list(void) -{ - JNIEnv *env = NULL; - jobject active_network = NULL; - jobject link_properties = NULL; - jstring domains = NULL; - const char *domain; - int res; - char *domain_list = NULL; - int need_detatch = 0; - - if (android_jvm == NULL || android_connectivity_manager == NULL) - { - return NULL; - } - - if (android_cm_active_net_mid == NULL || android_cm_link_props_mid == NULL || - android_lp_domains_mid == NULL) - { - return NULL; - } - - 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); - need_detatch = 1; - } - if (res != JNI_OK || env == NULL) - goto done; - - /* JNI below is equivalent to this Java code. - import android.content.Context; - import android.net.ConnectivityManager; - import android.net.LinkProperties; - - ConnectivityManager cm = (ConnectivityManager)this.getApplicationContext() - .getSystemService(Context.CONNECTIVITY_SERVICE); - Network an = cm.getActiveNetwork(); - LinkProperties lp = cm.getLinkProperties(an); - String domains = lp.getDomains(); - for (String domain: domains.split(",")) { - String d = domain; - } - - Note: The JNI ConnectivityManager object and all method IDs were previously - initialized in ares_library_init_android. - */ - - active_network = (*env)->CallObjectMethod(env, android_connectivity_manager, - android_cm_active_net_mid); - if (active_network == NULL) - goto done; - - link_properties = - (*env)->CallObjectMethod(env, android_connectivity_manager, - android_cm_link_props_mid, active_network); - if (link_properties == NULL) - goto done; - - /* Get the domains. It is a common separated list of domains to search. */ - domains = (*env)->CallObjectMethod(env, link_properties, - android_lp_domains_mid); - if (domains == NULL) - goto done; - - /* Split on , */ - domain = (*env)->GetStringUTFChars(env, domains, 0); - domain_list = ares_strdup(domain); - (*env)->ReleaseStringUTFChars(env, domains, domain); - (*env)->DeleteLocalRef(env, domains); - -done: - if ((*env)->ExceptionOccurred(env)) - (*env)->ExceptionClear(env); - - if (link_properties != NULL) - (*env)->DeleteLocalRef(env, link_properties); - if (active_network != NULL) - (*env)->DeleteLocalRef(env, active_network); - - if (need_detatch) - (*android_jvm)->DetachCurrentThread(android_jvm); - return domain_list; -} + +char *ares_get_android_search_domains_list(void) +{ + JNIEnv *env = NULL; + jobject active_network = NULL; + jobject link_properties = NULL; + jstring domains = NULL; + const char *domain; + int res; + char *domain_list = NULL; + int need_detatch = 0; + + if (android_jvm == NULL || android_connectivity_manager == NULL) + { + return NULL; + } + + if (android_cm_active_net_mid == NULL || android_cm_link_props_mid == NULL || + android_lp_domains_mid == NULL) + { + return NULL; + } + + 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); + need_detatch = 1; + } + if (res != JNI_OK || env == NULL) + goto done; + + /* JNI below is equivalent to this Java code. + import android.content.Context; + import android.net.ConnectivityManager; + import android.net.LinkProperties; + + ConnectivityManager cm = (ConnectivityManager)this.getApplicationContext() + .getSystemService(Context.CONNECTIVITY_SERVICE); + Network an = cm.getActiveNetwork(); + LinkProperties lp = cm.getLinkProperties(an); + String domains = lp.getDomains(); + for (String domain: domains.split(",")) { + String d = domain; + } + + Note: The JNI ConnectivityManager object and all method IDs were previously + initialized in ares_library_init_android. + */ + + active_network = (*env)->CallObjectMethod(env, android_connectivity_manager, + android_cm_active_net_mid); + if (active_network == NULL) + goto done; + + link_properties = + (*env)->CallObjectMethod(env, android_connectivity_manager, + android_cm_link_props_mid, active_network); + if (link_properties == NULL) + goto done; + + /* Get the domains. It is a common separated list of domains to search. */ + domains = (*env)->CallObjectMethod(env, link_properties, + android_lp_domains_mid); + if (domains == NULL) + goto done; + + /* Split on , */ + domain = (*env)->GetStringUTFChars(env, domains, 0); + domain_list = ares_strdup(domain); + (*env)->ReleaseStringUTFChars(env, domains, domain); + (*env)->DeleteLocalRef(env, domains); + +done: + if ((*env)->ExceptionOccurred(env)) + (*env)->ExceptionClear(env); + + if (link_properties != NULL) + (*env)->DeleteLocalRef(env, link_properties); + if (active_network != NULL) + (*env)->DeleteLocalRef(env, active_network); + + if (need_detatch) + (*android_jvm)->DetachCurrentThread(android_jvm); + return domain_list; +} #else /* warning: ISO C forbids an empty translation unit */ typedef int dummy_make_iso_compilers_happy; diff --git a/contrib/libs/c-ares/ares_android.h b/contrib/libs/c-ares/ares_android.h index 99ca0223b6..93fb75f585 100644 --- a/contrib/libs/c-ares/ares_android.h +++ b/contrib/libs/c-ares/ares_android.h @@ -19,7 +19,7 @@ #if defined(ANDROID) || defined(__ANDROID__) char **ares_get_android_server_list(size_t max_servers, size_t *num_servers); -char *ares_get_android_search_domains_list(void); +char *ares_get_android_search_domains_list(void); void ares_library_cleanup_android(void); #endif diff --git a/contrib/libs/c-ares/ares_config.h b/contrib/libs/c-ares/ares_config.h index 13b9922074..6695a6ad21 100644 --- a/contrib/libs/c-ares/ares_config.h +++ b/contrib/libs/c-ares/ares_config.h @@ -122,10 +122,10 @@ #undef HAVE_GETSERVBYPORT_R #endif -#if defined(__ANDROID__) -#undef HAVE_GETSERVBYPORT_R -#endif - +#if defined(__ANDROID__) +#undef HAVE_GETSERVBYPORT_R +#endif + /* Define to 1 if you have the `gettimeofday' function. */ #define HAVE_GETTIMEOFDAY 1 @@ -254,8 +254,8 @@ /* Define to 1 if you have the strcmpi function. */ /* #undef HAVE_STRCMPI */ -/* Potential ares_malloc/ares_free mismatch in ares_strdup.c/ares_strsplit.c. */ -/* #undef HAVE_STRDUP */ +/* Potential ares_malloc/ares_free mismatch in ares_strdup.c/ares_strsplit.c. */ +/* #undef HAVE_STRDUP */ /* Define to 1 if you have the stricmp function. */ /* #undef HAVE_STRICMP */ @@ -370,7 +370,7 @@ #define PACKAGE_NAME "c-ares" /* Define to the full name and version of this package. */ -#define PACKAGE_STRING "c-ares 1.15.0" +#define PACKAGE_STRING "c-ares 1.15.0" /* Define to the one symbol short name of this package. */ #define PACKAGE_TARNAME "c-ares" @@ -379,7 +379,7 @@ #define PACKAGE_URL "" /* Define to the version of this package. */ -#define PACKAGE_VERSION "1.15.0" +#define PACKAGE_VERSION "1.15.0" /* a suitable file/device to read random data from */ #define RANDOM_FILE "/dev/urandom" @@ -491,7 +491,7 @@ /* #undef USE_BLOCKING_SOCKETS */ /* Version number of package */ -#define VERSION "1.15.0" +#define VERSION "1.15.0" /* Define to avoid automatic inclusion of winsock.h */ /* #undef WIN32_LEAN_AND_MEAN */ diff --git a/contrib/libs/c-ares/ares_create_query.c b/contrib/libs/c-ares/ares_create_query.c index d60e1f25ef..9efce17cfa 100644 --- a/contrib/libs/c-ares/ares_create_query.c +++ b/contrib/libs/c-ares/ares_create_query.c @@ -98,10 +98,10 @@ int ares_create_query(const char *name, int dnsclass, int type, *buflenp = 0; *bufp = NULL; - /* Per RFC 7686, reject queries for ".onion" domain names with NXDOMAIN. */ - if (ares__is_onion_domain(name)) - return ARES_ENOTFOUND; - + /* Per RFC 7686, reject queries for ".onion" domain names with NXDOMAIN. */ + if (ares__is_onion_domain(name)) + return ARES_ENOTFOUND; + /* Allocate a memory area for the maximum size this packet might need. +2 * is for the length byte and zero termination if no dots or ecscaping is * used. @@ -192,7 +192,7 @@ int ares_create_query(const char *name, int dnsclass, int type, * specified in RFC 1035 ("To simplify implementations, the total length of * a domain name (i.e., label octets and label length octets) is restricted * to 255 octets or less."). */ - if (buflen > (size_t)(MAXCDNAME + HFIXEDSZ + QFIXEDSZ + + if (buflen > (size_t)(MAXCDNAME + HFIXEDSZ + QFIXEDSZ + (max_udp_size ? EDNSFIXEDSZ : 0))) { ares_free (buf); return ARES_EBADNAME; diff --git a/contrib/libs/c-ares/ares_destroy.c b/contrib/libs/c-ares/ares_destroy.c index 97427d41da..fed2009ab3 100644 --- a/contrib/libs/c-ares/ares_destroy.c +++ b/contrib/libs/c-ares/ares_destroy.c @@ -36,8 +36,8 @@ void ares_destroy_options(struct ares_options *options) ares_free(options->sortlist); if(options->lookups) ares_free(options->lookups); - if(options->resolvconf_path) - ares_free(options->resolvconf_path); + if(options->resolvconf_path) + ares_free(options->resolvconf_path); } void ares_destroy(ares_channel channel) @@ -46,7 +46,7 @@ void ares_destroy(ares_channel channel) struct query *query; struct list_node* list_head; struct list_node* list_node; - + if (!channel) return; @@ -87,9 +87,9 @@ void ares_destroy(ares_channel channel) if (channel->lookups) ares_free(channel->lookups); - if (channel->resolvconf_path) - ares_free(channel->resolvconf_path); - + if (channel->resolvconf_path) + ares_free(channel->resolvconf_path); + ares_free(channel); } diff --git a/contrib/libs/c-ares/ares_gethostbyname.c b/contrib/libs/c-ares/ares_gethostbyname.c index a3b58be74f..ecd03e7931 100644 --- a/contrib/libs/c-ares/ares_gethostbyname.c +++ b/contrib/libs/c-ares/ares_gethostbyname.c @@ -95,13 +95,13 @@ void ares_gethostbyname(ares_channel channel, const char *name, int family, return; } - /* Per RFC 7686, reject queries for ".onion" domain names with NXDOMAIN. */ - if (ares__is_onion_domain(name)) - { - callback(arg, ARES_ENOTFOUND, 0, NULL); - return; - } - + /* Per RFC 7686, reject queries for ".onion" domain names with NXDOMAIN. */ + if (ares__is_onion_domain(name)) + { + callback(arg, ARES_ENOTFOUND, 0, NULL); + return; + } + if (fake_hostent(name, family, callback, arg)) return; diff --git a/contrib/libs/c-ares/ares_getnameinfo.c b/contrib/libs/c-ares/ares_getnameinfo.c index b63bfe9819..53f91ca845 100644 --- a/contrib/libs/c-ares/ares_getnameinfo.c +++ b/contrib/libs/c-ares/ares_getnameinfo.c @@ -440,14 +440,14 @@ STATIC_TESTABLE char *ares_striendstr(const char *s1, const char *s2) } return (char *)c1_begin; } - -int ares__is_onion_domain(const char *name) -{ - if (ares_striendstr(name, ".onion")) - return 1; - - if (ares_striendstr(name, ".onion.")) - return 1; - - return 0; -} + +int ares__is_onion_domain(const char *name) +{ + if (ares_striendstr(name, ".onion")) + return 1; + + if (ares_striendstr(name, ".onion.")) + return 1; + + return 0; +} diff --git a/contrib/libs/c-ares/ares_init.c b/contrib/libs/c-ares/ares_init.c index 70d49b94e3..e06265c6a2 100644 --- a/contrib/libs/c-ares/ares_init.c +++ b/contrib/libs/c-ares/ares_init.c @@ -172,7 +172,7 @@ int ares_init_options(ares_channel *channelptr, struct ares_options *options, channel->sock_config_cb_data = NULL; channel->sock_funcs = NULL; channel->sock_func_cb_data = NULL; - channel->resolvconf_path = NULL; + channel->resolvconf_path = NULL; channel->last_server = 0; channel->last_timeout_processed = (time_t)now.tv_sec; @@ -240,14 +240,14 @@ done: /* Something failed; clean up memory we may have allocated. */ if (channel->servers) ares_free(channel->servers); - if (channel->ndomains != -1) - ares_strsplit_free(channel->domains, channel->ndomains); + if (channel->ndomains != -1) + ares_strsplit_free(channel->domains, channel->ndomains); if (channel->sortlist) ares_free(channel->sortlist); if(channel->lookups) ares_free(channel->lookups); - if(channel->resolvconf_path) - ares_free(channel->resolvconf_path); + if(channel->resolvconf_path) + ares_free(channel->resolvconf_path); ares_free(channel); return status; } @@ -301,7 +301,7 @@ int ares_dup(ares_channel *dest, ares_channel src) (*dest)->sock_func_cb_data = src->sock_func_cb_data; strncpy((*dest)->local_dev_name, src->local_dev_name, - sizeof((*dest)->local_dev_name)); + sizeof((*dest)->local_dev_name)); (*dest)->local_ip4 = src->local_ip4; memcpy((*dest)->local_ip6, src->local_ip6, sizeof(src->local_ip6)); @@ -357,9 +357,9 @@ int ares_save_options(ares_channel channel, struct ares_options *options, ARES_OPT_JITTER); (*optmask) |= (channel->rotate ? ARES_OPT_ROTATE : ARES_OPT_NOROTATE); - if (channel->resolvconf_path) - (*optmask) |= ARES_OPT_RESOLVCONF; - + if (channel->resolvconf_path) + (*optmask) |= ARES_OPT_RESOLVCONF; + /* Copy easy stuff */ options->flags = channel->flags; @@ -435,13 +435,13 @@ int ares_save_options(ares_channel channel, struct ares_options *options, } options->nsort = channel->nsort; - /* copy path for resolv.conf file */ - if (channel->resolvconf_path) { - options->resolvconf_path = ares_strdup(channel->resolvconf_path); - if (!options->resolvconf_path) - return ARES_ENOMEM; - } - + /* copy path for resolv.conf file */ + if (channel->resolvconf_path) { + options->resolvconf_path = ares_strdup(channel->resolvconf_path); + if (!options->resolvconf_path) + return ARES_ENOMEM; + } + return ARES_SUCCESS; } @@ -557,14 +557,14 @@ static int init_by_options(ares_channel channel, channel->nsort = options->nsort; } - /* Set path for resolv.conf file, if given. */ - if ((optmask & ARES_OPT_RESOLVCONF) && !channel->resolvconf_path) - { - channel->resolvconf_path = ares_strdup(options->resolvconf_path); - if (!channel->resolvconf_path && options->resolvconf_path) - return ARES_ENOMEM; - } - + /* Set path for resolv.conf file, if given. */ + if ((optmask & ARES_OPT_RESOLVCONF) && !channel->resolvconf_path) + { + channel->resolvconf_path = ares_strdup(options->resolvconf_path); + if (!channel->resolvconf_path && options->resolvconf_path) + return ARES_ENOMEM; + } + channel->optmask = optmask; return ARES_SUCCESS; @@ -1211,7 +1211,7 @@ static int get_DNS_AdaptersAddresses(char **outptr) /* Allocate room for another address, if necessary, else skip. */ if(addressesIndex == addressesSize) { const size_t newSize = addressesSize + 4; - Address * const newMem = + Address * const newMem = (Address*)ares_realloc(addresses, sizeof(Address) * newSize); if(newMem == NULL) { continue; @@ -1231,7 +1231,7 @@ static int get_DNS_AdaptersAddresses(char **outptr) } else { - addresses[addressesIndex].metric = (ULONG)-1; + addresses[addressesIndex].metric = (ULONG)-1; } /* Record insertion index to make qsort stable */ @@ -1268,12 +1268,12 @@ static int get_DNS_AdaptersAddresses(char **outptr) /* Save the address as the next element in addresses. */ addresses[addressesIndex].metric = getBestRouteMetric(&ipaaEntry->Luid, - (SOCKADDR_INET*)(namesrvr.sa), + (SOCKADDR_INET*)(namesrvr.sa), ipaaEntry->Ipv6Metric); } else { - addresses[addressesIndex].metric = (ULONG)-1; + addresses[addressesIndex].metric = (ULONG)-1; } /* Record insertion index to make qsort stable */ @@ -1318,7 +1318,7 @@ static int get_DNS_AdaptersAddresses(char **outptr) done: ares_free(addresses); - + if (ipaa) ares_free(ipaa); @@ -1369,7 +1369,7 @@ static int get_DNS_Windows(char **outptr) * * Returns 1 and sets *outptr when returning a dynamically allocated string. * - * Implementation supports Windows Server 2003 and newer + * Implementation supports Windows Server 2003 and newer */ static int get_SuffixList_Windows(char **outptr) { @@ -1388,80 +1388,80 @@ static int get_SuffixList_Windows(char **outptr) 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; - } + 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); } - 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; - } + 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, + if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, WIN_NS_NT_KEY "\\" INTERFACES_KEY, 0, KEY_READ, &hKey) == ERROR_SUCCESS) { - for(;;) + 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; + 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)) + 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; + 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(hKeyEnum); } - RegCloseKey(hKey); + RegCloseKey(hKey); } - + return *outptr != NULL; } @@ -1558,7 +1558,7 @@ static int init_by_resolv_conf(ares_channel channel) #elif defined(ANDROID) || defined(__ANDROID__) unsigned int i; char **dns_servers; - char *domains; + char *domains; size_t num_servers; /* Use the Android connectivity manager to get a list @@ -1583,12 +1583,12 @@ static int init_by_resolv_conf(ares_channel channel) } ares_free(dns_servers); } - if (channel->ndomains == -1) - { - domains = ares_get_android_search_domains_list(); - set_search(channel, domains); - ares_free(domains); - } + if (channel->ndomains == -1) + { + domains = ares_get_android_search_domains_list(); + set_search(channel, domains); + ares_free(domains); + } # ifdef HAVE___SYSTEM_PROPERTY_GET /* Old way using the system property still in place as @@ -1679,7 +1679,7 @@ static int init_by_resolv_conf(ares_channel channel) size_t linesize; int error; int update_domains; - const char *resolvconf_path; + const char *resolvconf_path; /* Don't read resolv.conf and friends if we don't have to */ if (ARES_CONFIG_CHECK(channel)) @@ -1688,14 +1688,14 @@ static int init_by_resolv_conf(ares_channel channel) /* Only update search domains if they're not already specified */ update_domains = (channel->ndomains == -1); - /* Support path for resolvconf filename set by ares_init_options */ - if(channel->resolvconf_path) { - resolvconf_path = channel->resolvconf_path; - } else { - resolvconf_path = PATH_RESOLV_CONF; - } - - fp = fopen(resolvconf_path, "r"); + /* Support path for resolvconf filename set by ares_init_options */ + if(channel->resolvconf_path) { + resolvconf_path = channel->resolvconf_path; + } else { + resolvconf_path = PATH_RESOLV_CONF; + } + + fp = fopen(resolvconf_path, "r"); if (fp) { while ((status = ares__read_line(fp, &line, &linesize)) == ARES_SUCCESS) { @@ -1706,10 +1706,10 @@ static int init_by_resolv_conf(ares_channel channel) else if ((p = try_config(line, "search", ';')) && update_domains) status = set_search(channel, p); else if ((p = try_config(line, "nameserver", ';')) && - channel->nservers == -1) + channel->nservers == -1) status = config_nameserver(&servers, &nservers, p); else if ((p = try_config(line, "sortlist", ';')) && - channel->nsort == -1) + channel->nsort == -1) status = config_sortlist(&sortlist, &nsort, p); else if ((p = try_config(line, "options", ';'))) status = set_options(channel, p); @@ -1729,7 +1729,7 @@ static int init_by_resolv_conf(ares_channel channel) break; default: DEBUGF(fprintf(stderr, "fopen() failed with error: %d %s\n", - error, strerror(error))); + error, strerror(error))); DEBUGF(fprintf(stderr, "Error opening file: %s\n", PATH_RESOLV_CONF)); status = ARES_EFILE; } @@ -1997,11 +1997,11 @@ static int init_by_defaults(ares_channel channel) ares_free(channel->lookups); channel->lookups = NULL; } - - if(channel->resolvconf_path) { - ares_free(channel->resolvconf_path); - channel->resolvconf_path = NULL; - } + + if(channel->resolvconf_path) { + ares_free(channel->resolvconf_path); + channel->resolvconf_path = NULL; + } } if(hostname) @@ -2071,76 +2071,76 @@ static int config_lookup(ares_channel channel, const char *str, #endif /* !WIN32 & !WATT32 & !ANDROID & !__ANDROID__ & !CARES_USE_LIBRESOLV */ #ifndef WATT32 -/* Validate that the ip address matches the subnet (network base and network - * mask) specified. Addresses are specified in standard Network Byte Order as - * 16 bytes, and the netmask is 0 to 128 (bits). - */ -static int ares_ipv6_subnet_matches(const unsigned char netbase[16], - unsigned char netmask, - const unsigned char ipaddr[16]) -{ - unsigned char mask[16] = { 0 }; - unsigned char i; - - /* Misuse */ - if (netmask > 128) - return 0; - - /* Quickly set whole bytes */ - memset(mask, 0xFF, netmask / 8); - - /* Set remaining bits */ - if(netmask % 8) { - mask[netmask / 8] = (unsigned char)(0xff << (8 - (netmask % 8))); - } - - for (i=0; i<16; i++) { - if ((netbase[i] & mask[i]) != (ipaddr[i] & mask[i])) - return 0; - } - - return 1; -} - -/* Return true iff the IPv6 ipaddr is blacklisted. */ -static int ares_ipv6_server_blacklisted(const unsigned char ipaddr[16]) -{ - /* A list of blacklisted IPv6 subnets. */ - const struct { - const unsigned char netbase[16]; - unsigned char netmask; - } blacklist[] = { - /* fec0::/10 was deprecated by [RFC3879] in September 2004. Formerly a - * Site-Local scoped address prefix. These are never valid DNS servers, - * but are known to be returned at least sometimes on Windows and Android. - */ - { - { - 0xfe, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - }, - 10 - } - }; - size_t i; - - /* See if ipaddr matches any of the entries in the blacklist. */ - for (i = 0; i < sizeof(blacklist) / sizeof(blacklist[0]); ++i) { - if (ares_ipv6_subnet_matches( - blacklist[i].netbase, blacklist[i].netmask, ipaddr)) - return 1; - } - return 0; -} - -/* Add the IPv4 or IPv6 nameservers in str (separated by commas) to the - * servers list, updating servers and nservers as required. - * - * This will silently ignore blacklisted IPv6 nameservers as detected by - * ares_ipv6_server_blacklisted(). - * - * Returns an error code on failure, else ARES_SUCCESS. - */ +/* Validate that the ip address matches the subnet (network base and network + * mask) specified. Addresses are specified in standard Network Byte Order as + * 16 bytes, and the netmask is 0 to 128 (bits). + */ +static int ares_ipv6_subnet_matches(const unsigned char netbase[16], + unsigned char netmask, + const unsigned char ipaddr[16]) +{ + unsigned char mask[16] = { 0 }; + unsigned char i; + + /* Misuse */ + if (netmask > 128) + return 0; + + /* Quickly set whole bytes */ + memset(mask, 0xFF, netmask / 8); + + /* Set remaining bits */ + if(netmask % 8) { + mask[netmask / 8] = (unsigned char)(0xff << (8 - (netmask % 8))); + } + + for (i=0; i<16; i++) { + if ((netbase[i] & mask[i]) != (ipaddr[i] & mask[i])) + return 0; + } + + return 1; +} + +/* Return true iff the IPv6 ipaddr is blacklisted. */ +static int ares_ipv6_server_blacklisted(const unsigned char ipaddr[16]) +{ + /* A list of blacklisted IPv6 subnets. */ + const struct { + const unsigned char netbase[16]; + unsigned char netmask; + } blacklist[] = { + /* fec0::/10 was deprecated by [RFC3879] in September 2004. Formerly a + * Site-Local scoped address prefix. These are never valid DNS servers, + * but are known to be returned at least sometimes on Windows and Android. + */ + { + { + 0xfe, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, + 10 + } + }; + size_t i; + + /* See if ipaddr matches any of the entries in the blacklist. */ + for (i = 0; i < sizeof(blacklist) / sizeof(blacklist[0]); ++i) { + if (ares_ipv6_subnet_matches( + blacklist[i].netbase, blacklist[i].netmask, ipaddr)) + return 1; + } + return 0; +} + +/* Add the IPv4 or IPv6 nameservers in str (separated by commas) to the + * servers list, updating servers and nservers as required. + * + * This will silently ignore blacklisted IPv6 nameservers as detected by + * ares_ipv6_server_blacklisted(). + * + * Returns an error code on failure, else ARES_SUCCESS. + */ static int config_nameserver(struct server_state **servers, int *nservers, char *str) { @@ -2175,10 +2175,10 @@ static int config_nameserver(struct server_state **servers, int *nservers, /* Convert textual address to binary format. */ if (ares_inet_pton(AF_INET, txtaddr, &host.addrV4) == 1) host.family = AF_INET; - else if (ares_inet_pton(AF_INET6, txtaddr, &host.addrV6) == 1 - /* Silently skip blacklisted IPv6 servers. */ - && !ares_ipv6_server_blacklisted( - (const unsigned char *)&host.addrV6)) + else if (ares_inet_pton(AF_INET6, txtaddr, &host.addrV6) == 1 + /* Silently skip blacklisted IPv6 servers. */ + && !ares_ipv6_server_blacklisted( + (const unsigned char *)&host.addrV6)) host.family = AF_INET6; else continue; @@ -2301,22 +2301,22 @@ static int config_sortlist(struct apattern **sortlist, int *nsort, static int set_search(ares_channel channel, const char *str) { - size_t cnt; + size_t cnt; if(channel->ndomains != -1) { /* LCOV_EXCL_START: all callers check ndomains == -1 */ /* if we already have some domains present, free them first */ - ares_strsplit_free(channel->domains, channel->ndomains); + ares_strsplit_free(channel->domains, channel->ndomains); channel->domains = NULL; channel->ndomains = -1; } /* LCOV_EXCL_STOP */ channel->domains = ares_strsplit(str, ", ", 1, &cnt); - channel->ndomains = (int)cnt; - if (channel->domains == NULL || channel->ndomains == 0) { - channel->domains = NULL; - channel->ndomains = -1; - } + channel->ndomains = (int)cnt; + if (channel->domains == NULL || channel->ndomains == 0) { + channel->domains = NULL; + channel->ndomains = -1; + } return ARES_SUCCESS; } diff --git a/contrib/libs/c-ares/ares_library_init.c b/contrib/libs/c-ares/ares_library_init.c index 982312f7fd..3c7ad37200 100644 --- a/contrib/libs/c-ares/ares_library_init.c +++ b/contrib/libs/c-ares/ares_library_init.c @@ -43,19 +43,19 @@ static unsigned int ares_initialized; static int ares_init_flags; /* library-private global vars with visibility across the whole library */ -#if defined(WIN32) -/* We need indirections to handle Windows DLL rules. */ -static void *default_malloc(size_t size) { return malloc(size); } -static void *default_realloc(void *p, size_t size) { return realloc(p, size); } -static void default_free(void *p) { free(p); } -#else -# define default_malloc malloc -# define default_realloc realloc -# define default_free free -#endif -void *(*ares_malloc)(size_t size) = default_malloc; -void *(*ares_realloc)(void *ptr, size_t size) = default_realloc; -void (*ares_free)(void *ptr) = default_free; +#if defined(WIN32) +/* We need indirections to handle Windows DLL rules. */ +static void *default_malloc(size_t size) { return malloc(size); } +static void *default_realloc(void *p, size_t size) { return realloc(p, size); } +static void default_free(void *p) { free(p); } +#else +# define default_malloc malloc +# define default_realloc realloc +# define default_free free +#endif +void *(*ares_malloc)(size_t size) = default_malloc; +void *(*ares_realloc)(void *ptr, size_t size) = default_realloc; +void (*ares_free)(void *ptr) = default_free; #ifdef USE_WINSOCK static HMODULE hnd_iphlpapi; diff --git a/contrib/libs/c-ares/ares_options.c b/contrib/libs/c-ares/ares_options.c index aff083c292..de49de4625 100644 --- a/contrib/libs/c-ares/ares_options.c +++ b/contrib/libs/c-ares/ares_options.c @@ -153,9 +153,9 @@ int ares_set_servers(ares_channel channel, if (!channel) return ARES_ENODATA; - if (!ares__is_list_empty(&channel->all_queries)) - return ARES_ENOTIMP; - + if (!ares__is_list_empty(&channel->all_queries)) + return ARES_ENOTIMP; + ares__destroy_servers_state(channel); for (srvr = servers; srvr; srvr = srvr->next) @@ -205,9 +205,9 @@ int ares_set_servers_ports(ares_channel channel, if (!channel) return ARES_ENODATA; - if (!ares__is_list_empty(&channel->all_queries)) - return ARES_ENOTIMP; - + if (!ares__is_list_empty(&channel->all_queries)) + return ARES_ENOTIMP; + ares__destroy_servers_state(channel); for (srvr = servers; srvr; srvr = srvr->next) diff --git a/contrib/libs/c-ares/ares_parse_ptr_reply.c b/contrib/libs/c-ares/ares_parse_ptr_reply.c index 0c08dfb933..0e2b064bb4 100644 --- a/contrib/libs/c-ares/ares_parse_ptr_reply.c +++ b/contrib/libs/c-ares/ares_parse_ptr_reply.c @@ -57,7 +57,7 @@ int ares_parse_ptr_reply(const unsigned char *abuf, int alen, const void *addr, int aliascnt = 0; int alias_alloc = 8; char ** aliases; - size_t rr_data_len; + size_t rr_data_len; /* Set *host to NULL for all failure cases. */ *host = NULL; @@ -133,15 +133,15 @@ int ares_parse_ptr_reply(const unsigned char *abuf, int alen, const void *addr, if (hostname) ares_free(hostname); hostname = rr_data; - rr_data_len = strlen(rr_data)+1; - aliases[aliascnt] = ares_malloc(rr_data_len * sizeof(char)); + rr_data_len = strlen(rr_data)+1; + aliases[aliascnt] = ares_malloc(rr_data_len * sizeof(char)); if (!aliases[aliascnt]) { ares_free(rr_name); status = ARES_ENOMEM; break; } - strncpy(aliases[aliascnt], rr_data, rr_data_len); + strncpy(aliases[aliascnt], rr_data, rr_data_len); aliascnt++; if (aliascnt >= alias_alloc) { char **ptr; diff --git a/contrib/libs/c-ares/ares_private.h b/contrib/libs/c-ares/ares_private.h index 3c40da8ed1..3312ed1932 100644 --- a/contrib/libs/c-ares/ares_private.h +++ b/contrib/libs/c-ares/ares_private.h @@ -57,19 +57,19 @@ #if defined(WIN32) && !defined(WATT32) -#define WIN_NS_9X "System\\CurrentControlSet\\Services\\VxD\\MSTCP" -#define WIN_NS_NT_KEY "System\\CurrentControlSet\\Services\\Tcpip\\Parameters" -#define WIN_DNSCLIENT "Software\\Policies\\Microsoft\\System\\DNSClient" -#define WIN_NT_DNSCLIENT "Software\\Policies\\Microsoft\\Windows NT\\DNSClient" -#define NAMESERVER "NameServer" -#define DHCPNAMESERVER "DhcpNameServer" -#define DATABASEPATH "DatabasePath" -#define WIN_PATH_HOSTS "\\hosts" -#define SEARCHLIST_KEY "SearchList" +#define WIN_NS_9X "System\\CurrentControlSet\\Services\\VxD\\MSTCP" +#define WIN_NS_NT_KEY "System\\CurrentControlSet\\Services\\Tcpip\\Parameters" +#define WIN_DNSCLIENT "Software\\Policies\\Microsoft\\System\\DNSClient" +#define WIN_NT_DNSCLIENT "Software\\Policies\\Microsoft\\Windows NT\\DNSClient" +#define NAMESERVER "NameServer" +#define DHCPNAMESERVER "DhcpNameServer" +#define DATABASEPATH "DatabasePath" +#define WIN_PATH_HOSTS "\\hosts" +#define SEARCHLIST_KEY "SearchList" #define PRIMARYDNSSUFFIX_KEY "PrimaryDNSSuffix" -#define INTERFACES_KEY "Interfaces" -#define DOMAIN_KEY "Domain" -#define DHCPDOMAIN_KEY "DhcpDomain" +#define INTERFACES_KEY "Interfaces" +#define DOMAIN_KEY "Domain" +#define DHCPDOMAIN_KEY "DhcpDomain" #elif defined(WATT32) @@ -106,7 +106,7 @@ #endif #include "ares_strdup.h" -#include "ares_strsplit.h" +#include "ares_strsplit.h" #ifndef HAVE_STRCASECMP # include "ares_strcasecmp.h" @@ -333,14 +333,14 @@ struct ares_channeldata { const struct ares_socket_functions * sock_funcs; void *sock_func_cb_data; - - /* Path for resolv.conf file, configurable via ares_options */ - char *resolvconf_path; + + /* Path for resolv.conf file, configurable via ares_options */ + char *resolvconf_path; }; -/* Does the domain end in ".onion" or ".onion."? Case-insensitive. */ -int ares__is_onion_domain(const char *name); - +/* Does the domain end in ".onion" or ".onion."? Case-insensitive. */ +int ares__is_onion_domain(const char *name); + /* Memory management functions */ extern void *(*ares_malloc)(size_t size); extern void *(*ares_realloc)(void *ptr, size_t size); diff --git a/contrib/libs/c-ares/ares_process.c b/contrib/libs/c-ares/ares_process.c index 034cd2c4ae..25095d0f05 100644 --- a/contrib/libs/c-ares/ares_process.c +++ b/contrib/libs/c-ares/ares_process.c @@ -53,7 +53,7 @@ #include <assert.h> #include <fcntl.h> -#include <limits.h> +#include <limits.h> #include "ares.h" #include "ares_dns.h" @@ -872,32 +872,32 @@ void ares__send_query(ares_channel channel, struct query *query, return; } } - - /* For each trip through the entire server list, double the channel's - * assigned timeout, avoiding overflow. If channel->timeout is negative, - * leave it as-is, even though that should be impossible here. - */ - timeplus = channel->timeout; - { - /* How many times do we want to double it? Presume sane values here. */ - const int shift = query->try_count / channel->nservers; - - /* Is there enough room to shift timeplus left that many times? - * - * To find out, confirm that all of the bits we'll shift away are zero. - * Stop considering a shift if we get to the point where we could shift - * a 1 into the sign bit (i.e. when shift is within two of the bit - * count). - * - * This has the side benefit of leaving negative numbers unchanged. - */ - if(shift <= (int)(sizeof(int) * CHAR_BIT - 1) - && (timeplus >> (sizeof(int) * CHAR_BIT - 1 - shift)) == 0) - { - timeplus <<= shift; - } - } - + + /* For each trip through the entire server list, double the channel's + * assigned timeout, avoiding overflow. If channel->timeout is negative, + * leave it as-is, even though that should be impossible here. + */ + timeplus = channel->timeout; + { + /* How many times do we want to double it? Presume sane values here. */ + const int shift = query->try_count / channel->nservers; + + /* Is there enough room to shift timeplus left that many times? + * + * To find out, confirm that all of the bits we'll shift away are zero. + * Stop considering a shift if we get to the point where we could shift + * a 1 into the sign bit (i.e. when shift is within two of the bit + * count). + * + * This has the side benefit of leaving negative numbers unchanged. + */ + if(shift <= (int)(sizeof(int) * CHAR_BIT - 1) + && (timeplus >> (sizeof(int) * CHAR_BIT - 1 - shift)) == 0) + { + timeplus <<= shift; + } + } + if (channel->maxtimeout != -1 && timeplus > channel->maxtimeout) timeplus = channel->maxtimeout; diff --git a/contrib/libs/c-ares/ares_rules.h b/contrib/libs/c-ares/ares_rules.h index 628b80b1b7..cac23cf2e3 100644 --- a/contrib/libs/c-ares/ares_rules.h +++ b/contrib/libs/c-ares/ares_rules.h @@ -83,7 +83,7 @@ /* * Verify that the size previously defined and expected for - * ares_socklen_t is actually the same as the one reported + * ares_socklen_t is actually the same as the one reported * by sizeof() at compile time. */ diff --git a/contrib/libs/c-ares/ares_search.c b/contrib/libs/c-ares/ares_search.c index 4f5268dfe3..c4b0424f5b 100644 --- a/contrib/libs/c-ares/ares_search.c +++ b/contrib/libs/c-ares/ares_search.c @@ -52,13 +52,13 @@ void ares_search(ares_channel channel, const char *name, int dnsclass, const char *p; int status, ndots; - /* Per RFC 7686, reject queries for ".onion" domain names with NXDOMAIN. */ - if (ares__is_onion_domain(name)) - { - callback(arg, ARES_ENOTFOUND, 0, NULL, 0); - return; - } - + /* Per RFC 7686, reject queries for ".onion" domain names with NXDOMAIN. */ + if (ares__is_onion_domain(name)) + { + callback(arg, ARES_ENOTFOUND, 0, NULL, 0); + return; + } + /* If name only yields one domain to search, then we don't have * to keep extra state, so just do an ares_query(). */ diff --git a/contrib/libs/c-ares/ares_send.c b/contrib/libs/c-ares/ares_send.c index cc87a9dfa7..f4f1f95119 100644 --- a/contrib/libs/c-ares/ares_send.c +++ b/contrib/libs/c-ares/ares_send.c @@ -60,12 +60,12 @@ void ares_send(ares_channel channel, const unsigned char *qbuf, int qlen, callback(arg, ARES_ENOMEM, 0, NULL, 0); return; } - if (channel->nservers < 1) - { - ares_free(query); - callback(arg, ARES_ESERVFAIL, 0, NULL, 0); - return; - } + if (channel->nservers < 1) + { + ares_free(query); + callback(arg, ARES_ESERVFAIL, 0, NULL, 0); + return; + } query->server_info = ares_malloc(channel->nservers * sizeof(query->server_info[0])); if (!query->server_info) diff --git a/contrib/libs/c-ares/ares_strsplit.c b/contrib/libs/c-ares/ares_strsplit.c index 1a4ba444f9..b57a30f2a9 100644 --- a/contrib/libs/c-ares/ares_strsplit.c +++ b/contrib/libs/c-ares/ares_strsplit.c @@ -1,174 +1,174 @@ -/* Copyright (C) 2018 by John Schember <john@nachtimwald.com> - * - * Permission to use, copy, modify, and distribute this - * software and its documentation for any purpose and without - * fee is hereby granted, provided that the above copyright - * notice appear in all copies and that both that copyright - * notice and this permission notice appear in supporting - * documentation, and that the name of M.I.T. not be used in - * advertising or publicity pertaining to distribution of the - * software without specific, written prior permission. - * M.I.T. makes no representations about the suitability of - * this software for any purpose. It is provided "as is" - * without express or implied warranty. - */ - -#include "ares_setup.h" -#include "ares_strsplit.h" -#include "ares.h" -#include "ares_private.h" - -static int list_contains(char * const *list, size_t num_elem, const char *str, int insensitive) -{ - size_t len; - size_t i; - - len = strlen(str); - for (i=0; i<num_elem; i++) - { - if (insensitive) - { -#ifdef WIN32 - if (strnicmp(list[i], str, len) == 0) -#else - if (strncasecmp(list[i], str, len) == 0) -#endif - return 1; - } - else - { - if (strncmp(list[i], str, len) == 0) - return 1; - } - } - - return 0; -} - -static int is_delim(char c, const char *delims, size_t num_delims) -{ - size_t i; - - for (i=0; i<num_delims; i++) - { - if (c == delims[i]) - return 1; - } - return 0; -} - - -void ares_strsplit_free(char **elms, size_t num_elm) -{ - size_t i; - - if (elms == NULL) - return; - - for (i=0; i<num_elm; i++) - ares_free(elms[i]); - ares_free(elms); -} - - -char **ares_strsplit(const char *in, const char *delms, int make_set, size_t *num_elm) -{ - char *parsestr; - char **temp; - char **out; - size_t cnt; - size_t nelms; - size_t in_len; - size_t num_delims; - size_t i; - - if (in == NULL || delms == NULL || num_elm == NULL) - return NULL; - - *num_elm = 0; - - in_len = strlen(in); - num_delims = strlen(delms); - - /* Figure out how many elements. */ - nelms = 1; - for (i=0; i<in_len; i++) - { - if (is_delim(in[i], delms, num_delims)) - { - nelms++; - } - } - - /* Copy of input so we can cut it up. */ - parsestr = ares_strdup(in); - if (parsestr == NULL) - return NULL; - - /* Temporary array to store locations of start of each element - * within parsestr. */ - temp = ares_malloc(nelms * sizeof(*temp)); - if (temp == NULL) - { - ares_free(parsestr); - return NULL; - } - temp[0] = parsestr; - cnt = 1; - for (i=0; i<in_len && cnt<nelms; i++) - { - if (!is_delim(parsestr[i], delms, num_delims)) - continue; - - /* Replace sep with NULL. */ - parsestr[i] = '\0'; - /* Add the pointer to the array of elements */ - temp[cnt] = parsestr+i+1; - cnt++; - } - - /* Copy each element to our output array. */ - out = ares_malloc(nelms * sizeof(*out)); - if (out == NULL) - { - ares_free(parsestr); - ares_free(temp); - return NULL; - } - - nelms = 0; - for (i=0; i<cnt; i++) - { - if (temp[i][0] == '\0') - continue; - - if (make_set && list_contains(out, nelms, temp[i], 1)) - continue; - - out[nelms] = ares_strdup(temp[i]); - if (out[nelms] == NULL) - { - ares_strsplit_free(out, nelms); - ares_free(parsestr); - ares_free(temp); - return NULL; - } - nelms++; - } - - - /* If there are no elements don't return an empty allocated - * array. */ - if (nelms == 0) - { - ares_strsplit_free(out, nelms); - out = NULL; - } - - /* Get the true number of elements (recalculated because of make_set) */ - *num_elm = nelms; - - ares_free(parsestr); - ares_free(temp); - return out; -} +/* Copyright (C) 2018 by John Schember <john@nachtimwald.com> + * + * Permission to use, copy, modify, and distribute this + * software and its documentation for any purpose and without + * fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting + * documentation, and that the name of M.I.T. not be used in + * advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" + * without express or implied warranty. + */ + +#include "ares_setup.h" +#include "ares_strsplit.h" +#include "ares.h" +#include "ares_private.h" + +static int list_contains(char * const *list, size_t num_elem, const char *str, int insensitive) +{ + size_t len; + size_t i; + + len = strlen(str); + for (i=0; i<num_elem; i++) + { + if (insensitive) + { +#ifdef WIN32 + if (strnicmp(list[i], str, len) == 0) +#else + if (strncasecmp(list[i], str, len) == 0) +#endif + return 1; + } + else + { + if (strncmp(list[i], str, len) == 0) + return 1; + } + } + + return 0; +} + +static int is_delim(char c, const char *delims, size_t num_delims) +{ + size_t i; + + for (i=0; i<num_delims; i++) + { + if (c == delims[i]) + return 1; + } + return 0; +} + + +void ares_strsplit_free(char **elms, size_t num_elm) +{ + size_t i; + + if (elms == NULL) + return; + + for (i=0; i<num_elm; i++) + ares_free(elms[i]); + ares_free(elms); +} + + +char **ares_strsplit(const char *in, const char *delms, int make_set, size_t *num_elm) +{ + char *parsestr; + char **temp; + char **out; + size_t cnt; + size_t nelms; + size_t in_len; + size_t num_delims; + size_t i; + + if (in == NULL || delms == NULL || num_elm == NULL) + return NULL; + + *num_elm = 0; + + in_len = strlen(in); + num_delims = strlen(delms); + + /* Figure out how many elements. */ + nelms = 1; + for (i=0; i<in_len; i++) + { + if (is_delim(in[i], delms, num_delims)) + { + nelms++; + } + } + + /* Copy of input so we can cut it up. */ + parsestr = ares_strdup(in); + if (parsestr == NULL) + return NULL; + + /* Temporary array to store locations of start of each element + * within parsestr. */ + temp = ares_malloc(nelms * sizeof(*temp)); + if (temp == NULL) + { + ares_free(parsestr); + return NULL; + } + temp[0] = parsestr; + cnt = 1; + for (i=0; i<in_len && cnt<nelms; i++) + { + if (!is_delim(parsestr[i], delms, num_delims)) + continue; + + /* Replace sep with NULL. */ + parsestr[i] = '\0'; + /* Add the pointer to the array of elements */ + temp[cnt] = parsestr+i+1; + cnt++; + } + + /* Copy each element to our output array. */ + out = ares_malloc(nelms * sizeof(*out)); + if (out == NULL) + { + ares_free(parsestr); + ares_free(temp); + return NULL; + } + + nelms = 0; + for (i=0; i<cnt; i++) + { + if (temp[i][0] == '\0') + continue; + + if (make_set && list_contains(out, nelms, temp[i], 1)) + continue; + + out[nelms] = ares_strdup(temp[i]); + if (out[nelms] == NULL) + { + ares_strsplit_free(out, nelms); + ares_free(parsestr); + ares_free(temp); + return NULL; + } + nelms++; + } + + + /* If there are no elements don't return an empty allocated + * array. */ + if (nelms == 0) + { + ares_strsplit_free(out, nelms); + out = NULL; + } + + /* Get the true number of elements (recalculated because of make_set) */ + *num_elm = nelms; + + ares_free(parsestr); + ares_free(temp); + return out; +} diff --git a/contrib/libs/c-ares/ares_strsplit.h b/contrib/libs/c-ares/ares_strsplit.h index 93f7948a77..e00fd14dd5 100644 --- a/contrib/libs/c-ares/ares_strsplit.h +++ b/contrib/libs/c-ares/ares_strsplit.h @@ -1,43 +1,43 @@ -#ifndef HEADER_CARES_STRSPLIT_H -#define HEADER_CARES_STRSPLIT_H - -/* Copyright (C) 2018 by John Schember <john@nachtimwald.com> - * - * Permission to use, copy, modify, and distribute this - * software and its documentation for any purpose and without - * fee is hereby granted, provided that the above copyright - * notice appear in all copies and that both that copyright - * notice and this permission notice appear in supporting - * documentation, and that the name of M.I.T. not be used in - * advertising or publicity pertaining to distribution of the - * software without specific, written prior permission. - * M.I.T. makes no representations about the suitability of - * this software for any purpose. It is provided "as is" - * without express or implied warranty. - */ - -#include "ares_setup.h" - -/* Split a string on delem skipping empty elements. - * - * param in String to split. - * param delims String of characters to treat as a delimitor. - * Each character in the string is a delimitor so - * there can be multiple delimitors to split on. - * E.g. ", " will split on all comma's and spaces. - * param make_set Have the list be a Set where there are no - * duplicate entries. 1 for true, 0 or false. - * param num_elm Return parameter of the number of elements - * in the result array. - * - * returns an allocated array of allocated string elements. - * - */ -char **ares_strsplit(const char *in, const char *delms, int make_set, size_t *num_elm); - -/* Frees the result returned from ares_strsplit(). */ -void ares_strsplit_free(char **elms, size_t num_elm); - - -#endif /* HEADER_CARES_STRSPLIT_H */ - +#ifndef HEADER_CARES_STRSPLIT_H +#define HEADER_CARES_STRSPLIT_H + +/* Copyright (C) 2018 by John Schember <john@nachtimwald.com> + * + * Permission to use, copy, modify, and distribute this + * software and its documentation for any purpose and without + * fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting + * documentation, and that the name of M.I.T. not be used in + * advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" + * without express or implied warranty. + */ + +#include "ares_setup.h" + +/* Split a string on delem skipping empty elements. + * + * param in String to split. + * param delims String of characters to treat as a delimitor. + * Each character in the string is a delimitor so + * there can be multiple delimitors to split on. + * E.g. ", " will split on all comma's and spaces. + * param make_set Have the list be a Set where there are no + * duplicate entries. 1 for true, 0 or false. + * param num_elm Return parameter of the number of elements + * in the result array. + * + * returns an allocated array of allocated string elements. + * + */ +char **ares_strsplit(const char *in, const char *delms, int make_set, size_t *num_elm); + +/* Frees the result returned from ares_strsplit(). */ +void ares_strsplit_free(char **elms, size_t num_elm); + + +#endif /* HEADER_CARES_STRSPLIT_H */ + diff --git a/contrib/libs/c-ares/config-win32.h b/contrib/libs/c-ares/config-win32.h index f1737636e8..da7eba44d8 100644 --- a/contrib/libs/c-ares/config-win32.h +++ b/contrib/libs/c-ares/config-win32.h @@ -251,7 +251,7 @@ # define _CRT_NONSTDC_NO_DEPRECATE 1 #endif -/* Set the Target to Vista. However, any symbols required above Win2000 +/* Set the Target to Vista. However, any symbols required above Win2000 * should be loaded via LoadLibrary() */ #if defined(_MSC_VER) && (_MSC_VER >= 1500) # define VS2008_MIN_TARGET 0x0600 diff --git a/contrib/libs/c-ares/inet_ntop.c b/contrib/libs/c-ares/inet_ntop.c index a3617d8c15..1935a871ce 100644 --- a/contrib/libs/c-ares/inet_ntop.c +++ b/contrib/libs/c-ares/inet_ntop.c @@ -180,7 +180,7 @@ inet_ntop6(const unsigned char *src, char *dst, size_t size) tp += sprintf(tp, "%x", words[i]); } /* Was it a trailing run of 0x00's? */ - if (best.base != -1 && (best.base + best.len) == (NS_IN6ADDRSZ / NS_INT16SZ)) + if (best.base != -1 && (best.base + best.len) == (NS_IN6ADDRSZ / NS_INT16SZ)) *tp++ = ':'; *tp++ = '\0'; diff --git a/contrib/libs/c-ares/test/ares-test-init.cc b/contrib/libs/c-ares/test/ares-test-init.cc index d20a1e7e6f..842b0e15ac 100644 --- a/contrib/libs/c-ares/test/ares-test-init.cc +++ b/contrib/libs/c-ares/test/ares-test-init.cc @@ -1,247 +1,247 @@ -#include "ares-test.h" - -// library initialization is only needed for windows builds -#ifdef WIN32 -#define EXPECTED_NONINIT ARES_ENOTINITIALIZED -#else -#define EXPECTED_NONINIT ARES_SUCCESS -#endif - -namespace ares { -namespace test { - -TEST(LibraryInit, Basic) { - EXPECT_EQ(EXPECTED_NONINIT, ares_library_initialized()); - EXPECT_EQ(ARES_SUCCESS, ares_library_init(ARES_LIB_INIT_ALL)); - EXPECT_EQ(ARES_SUCCESS, ares_library_initialized()); - ares_library_cleanup(); - EXPECT_EQ(EXPECTED_NONINIT, ares_library_initialized()); -} - -TEST(LibraryInit, UnexpectedCleanup) { - EXPECT_EQ(EXPECTED_NONINIT, ares_library_initialized()); - ares_library_cleanup(); - EXPECT_EQ(EXPECTED_NONINIT, ares_library_initialized()); -} - -TEST(LibraryInit, DISABLED_InvalidParam) { - // TODO: police flags argument to ares_library_init() - EXPECT_EQ(ARES_EBADQUERY, ares_library_init(ARES_LIB_INIT_ALL << 2)); - EXPECT_EQ(EXPECTED_NONINIT, ares_library_initialized()); - ares_library_cleanup(); -} - -TEST(LibraryInit, Nested) { - EXPECT_EQ(EXPECTED_NONINIT, ares_library_initialized()); - EXPECT_EQ(ARES_SUCCESS, ares_library_init(ARES_LIB_INIT_ALL)); - EXPECT_EQ(ARES_SUCCESS, ares_library_initialized()); - EXPECT_EQ(ARES_SUCCESS, ares_library_init(ARES_LIB_INIT_ALL)); - EXPECT_EQ(ARES_SUCCESS, ares_library_initialized()); - ares_library_cleanup(); - EXPECT_EQ(ARES_SUCCESS, ares_library_initialized()); - ares_library_cleanup(); - EXPECT_EQ(EXPECTED_NONINIT, ares_library_initialized()); -} - -TEST(LibraryInit, BasicChannelInit) { - EXPECT_EQ(ARES_SUCCESS, ares_library_init(ARES_LIB_INIT_ALL)); - ares_channel channel = nullptr; - EXPECT_EQ(ARES_SUCCESS, ares_init(&channel)); - EXPECT_NE(nullptr, channel); - ares_destroy(channel); - ares_library_cleanup(); -} - -TEST_F(LibraryTest, OptionsChannelInit) { - struct ares_options opts = {0}; - int optmask = 0; - opts.flags = ARES_FLAG_USEVC | ARES_FLAG_PRIMARY; - optmask |= ARES_OPT_FLAGS; - opts.timeout = 2000; - optmask |= ARES_OPT_TIMEOUTMS; - opts.tries = 2; - optmask |= ARES_OPT_TRIES; - opts.ndots = 4; - optmask |= ARES_OPT_NDOTS; - opts.udp_port = 54; - optmask |= ARES_OPT_UDP_PORT; - opts.tcp_port = 54; - optmask |= ARES_OPT_TCP_PORT; - opts.socket_send_buffer_size = 514; - optmask |= ARES_OPT_SOCK_SNDBUF; - opts.socket_receive_buffer_size = 514; - optmask |= ARES_OPT_SOCK_RCVBUF; - opts.ednspsz = 1280; - optmask |= ARES_OPT_EDNSPSZ; - opts.nservers = 2; - opts.servers = (struct in_addr *)malloc(opts.nservers * sizeof(struct in_addr)); - opts.servers[0].s_addr = htonl(0x01020304); - opts.servers[1].s_addr = htonl(0x02030405); - optmask |= ARES_OPT_SERVERS; - opts.ndomains = 2; - opts.domains = (char **)malloc(opts.ndomains * sizeof(char *)); - opts.domains[0] = strdup("example.com"); - opts.domains[1] = strdup("example2.com"); - optmask |= ARES_OPT_DOMAINS; - opts.lookups = strdup("b"); - optmask |= ARES_OPT_LOOKUPS; - optmask |= ARES_OPT_ROTATE; - opts.resolvconf_path = strdup("/etc/resolv.conf"); - optmask |= ARES_OPT_RESOLVCONF; - - ares_channel channel = nullptr; - EXPECT_EQ(ARES_SUCCESS, ares_init_options(&channel, &opts, optmask)); - EXPECT_NE(nullptr, channel); - - ares_channel channel2 = nullptr; - EXPECT_EQ(ARES_SUCCESS, ares_dup(&channel2, channel)); - - struct ares_options opts2 = {0}; - int optmask2 = 0; - EXPECT_EQ(ARES_SUCCESS, ares_save_options(channel2, &opts2, &optmask2)); - - // Note that not all opts-settable fields are saved (e.g. - // ednspsz, socket_{send,receive}_buffer_size). - EXPECT_EQ(opts.flags, opts2.flags); - EXPECT_EQ(opts.timeout, opts2.timeout); - EXPECT_EQ(opts.tries, opts2.tries); - EXPECT_EQ(opts.ndots, opts2.ndots); - EXPECT_EQ(opts.udp_port, opts2.udp_port); - EXPECT_EQ(opts.tcp_port, opts2.tcp_port); - EXPECT_EQ(1, opts2.nservers); // Truncated by ARES_FLAG_PRIMARY - EXPECT_EQ(opts.servers[0].s_addr, opts2.servers[0].s_addr); - EXPECT_EQ(opts.ndomains, opts2.ndomains); - EXPECT_EQ(std::string(opts.domains[0]), std::string(opts2.domains[0])); - EXPECT_EQ(std::string(opts.domains[1]), std::string(opts2.domains[1])); - EXPECT_EQ(std::string(opts.lookups), std::string(opts2.lookups)); - EXPECT_EQ(std::string(opts.resolvconf_path), std::string(opts2.resolvconf_path)); - - ares_destroy_options(&opts); - ares_destroy_options(&opts2); - ares_destroy(channel); - ares_destroy(channel2); -} - -TEST_F(LibraryTest, ChannelAllocFail) { - ares_channel channel; - for (int ii = 1; ii <= 25; ii++) { - ClearFails(); - SetAllocFail(ii); - channel = nullptr; - int rc = ares_init(&channel); - // The number of allocations depends on local environment, so don't expect ENOMEM. - if (rc == ARES_ENOMEM) { - EXPECT_EQ(nullptr, channel); - } else { - ares_destroy(channel); - } - } -} - -TEST_F(LibraryTest, OptionsChannelAllocFail) { - struct ares_options opts = {0}; - int optmask = 0; - opts.flags = ARES_FLAG_USEVC; - optmask |= ARES_OPT_FLAGS; - opts.timeout = 2; - optmask |= ARES_OPT_TIMEOUT; - opts.tries = 2; - optmask |= ARES_OPT_TRIES; - opts.ndots = 4; - optmask |= ARES_OPT_NDOTS; - opts.udp_port = 54; - optmask |= ARES_OPT_UDP_PORT; - opts.tcp_port = 54; - optmask |= ARES_OPT_TCP_PORT; - opts.socket_send_buffer_size = 514; - optmask |= ARES_OPT_SOCK_SNDBUF; - opts.socket_receive_buffer_size = 514; - optmask |= ARES_OPT_SOCK_RCVBUF; - opts.ednspsz = 1280; - optmask |= ARES_OPT_EDNSPSZ; - opts.nservers = 2; - opts.servers = (struct in_addr *)malloc(opts.nservers * sizeof(struct in_addr)); - opts.servers[0].s_addr = htonl(0x01020304); - opts.servers[1].s_addr = htonl(0x02030405); - optmask |= ARES_OPT_SERVERS; - opts.ndomains = 2; - opts.domains = (char **)malloc(opts.ndomains * sizeof(char *)); - opts.domains[0] = strdup("example.com"); - opts.domains[1] = strdup("example2.com"); - optmask |= ARES_OPT_DOMAINS; - opts.lookups = strdup("b"); - optmask |= ARES_OPT_LOOKUPS; - optmask |= ARES_OPT_ROTATE; - opts.resolvconf_path = strdup("/etc/resolv.conf"); - optmask |= ARES_OPT_RESOLVCONF; - - ares_channel channel = nullptr; - for (int ii = 1; ii <= 8; ii++) { - ClearFails(); - SetAllocFail(ii); - int rc = ares_init_options(&channel, &opts, optmask); - if (rc == ARES_ENOMEM) { - EXPECT_EQ(nullptr, channel); - } else { - EXPECT_EQ(ARES_SUCCESS, rc); - ares_destroy(channel); - channel = nullptr; - } - } - ClearFails(); - - EXPECT_EQ(ARES_SUCCESS, ares_init_options(&channel, &opts, optmask)); - EXPECT_NE(nullptr, channel); - - // Add some servers and a sortlist for flavour. - EXPECT_EQ(ARES_SUCCESS, - ares_set_servers_csv(channel, "1.2.3.4,0102:0304:0506:0708:0910:1112:1314:1516,2.3.4.5")); - EXPECT_EQ(ARES_SUCCESS, ares_set_sortlist(channel, "1.2.3.4 2.3.4.5")); - - ares_channel channel2 = nullptr; - for (int ii = 1; ii <= 18; ii++) { - ClearFails(); - SetAllocFail(ii); - EXPECT_EQ(ARES_ENOMEM, ares_dup(&channel2, channel)) << ii; - EXPECT_EQ(nullptr, channel2) << ii; - } - - struct ares_options opts2; - int optmask2 = 0; - for (int ii = 1; ii <= 6; ii++) { - memset(&opts2, 0, sizeof(opts2)); - ClearFails(); - SetAllocFail(ii); - EXPECT_EQ(ARES_ENOMEM, ares_save_options(channel, &opts2, &optmask2)) << ii; - // May still have allocations even after ARES_ENOMEM return code. - ares_destroy_options(&opts2); - } - ares_destroy_options(&opts); - ares_destroy(channel); -} - -TEST_F(LibraryTest, FailChannelInit) { - EXPECT_EQ(ARES_SUCCESS, - ares_library_init_mem(ARES_LIB_INIT_ALL, - &LibraryTest::amalloc, - &LibraryTest::afree, - &LibraryTest::arealloc)); - SetAllocFail(1); - ares_channel channel = nullptr; - EXPECT_EQ(ARES_ENOMEM, ares_init(&channel)); - EXPECT_EQ(nullptr, channel); - ares_library_cleanup(); -} - -#ifndef WIN32 -TEST_F(LibraryTest, EnvInit) { - ares_channel channel = nullptr; - EnvValue v1("LOCALDOMAIN", "this.is.local"); - EnvValue v2("RES_OPTIONS", "options debug ndots:3 retry:3 rotate retrans:2"); - EXPECT_EQ(ARES_SUCCESS, ares_init(&channel)); - ares_destroy(channel); -} - +#include "ares-test.h" + +// library initialization is only needed for windows builds +#ifdef WIN32 +#define EXPECTED_NONINIT ARES_ENOTINITIALIZED +#else +#define EXPECTED_NONINIT ARES_SUCCESS +#endif + +namespace ares { +namespace test { + +TEST(LibraryInit, Basic) { + EXPECT_EQ(EXPECTED_NONINIT, ares_library_initialized()); + EXPECT_EQ(ARES_SUCCESS, ares_library_init(ARES_LIB_INIT_ALL)); + EXPECT_EQ(ARES_SUCCESS, ares_library_initialized()); + ares_library_cleanup(); + EXPECT_EQ(EXPECTED_NONINIT, ares_library_initialized()); +} + +TEST(LibraryInit, UnexpectedCleanup) { + EXPECT_EQ(EXPECTED_NONINIT, ares_library_initialized()); + ares_library_cleanup(); + EXPECT_EQ(EXPECTED_NONINIT, ares_library_initialized()); +} + +TEST(LibraryInit, DISABLED_InvalidParam) { + // TODO: police flags argument to ares_library_init() + EXPECT_EQ(ARES_EBADQUERY, ares_library_init(ARES_LIB_INIT_ALL << 2)); + EXPECT_EQ(EXPECTED_NONINIT, ares_library_initialized()); + ares_library_cleanup(); +} + +TEST(LibraryInit, Nested) { + EXPECT_EQ(EXPECTED_NONINIT, ares_library_initialized()); + EXPECT_EQ(ARES_SUCCESS, ares_library_init(ARES_LIB_INIT_ALL)); + EXPECT_EQ(ARES_SUCCESS, ares_library_initialized()); + EXPECT_EQ(ARES_SUCCESS, ares_library_init(ARES_LIB_INIT_ALL)); + EXPECT_EQ(ARES_SUCCESS, ares_library_initialized()); + ares_library_cleanup(); + EXPECT_EQ(ARES_SUCCESS, ares_library_initialized()); + ares_library_cleanup(); + EXPECT_EQ(EXPECTED_NONINIT, ares_library_initialized()); +} + +TEST(LibraryInit, BasicChannelInit) { + EXPECT_EQ(ARES_SUCCESS, ares_library_init(ARES_LIB_INIT_ALL)); + ares_channel channel = nullptr; + EXPECT_EQ(ARES_SUCCESS, ares_init(&channel)); + EXPECT_NE(nullptr, channel); + ares_destroy(channel); + ares_library_cleanup(); +} + +TEST_F(LibraryTest, OptionsChannelInit) { + struct ares_options opts = {0}; + int optmask = 0; + opts.flags = ARES_FLAG_USEVC | ARES_FLAG_PRIMARY; + optmask |= ARES_OPT_FLAGS; + opts.timeout = 2000; + optmask |= ARES_OPT_TIMEOUTMS; + opts.tries = 2; + optmask |= ARES_OPT_TRIES; + opts.ndots = 4; + optmask |= ARES_OPT_NDOTS; + opts.udp_port = 54; + optmask |= ARES_OPT_UDP_PORT; + opts.tcp_port = 54; + optmask |= ARES_OPT_TCP_PORT; + opts.socket_send_buffer_size = 514; + optmask |= ARES_OPT_SOCK_SNDBUF; + opts.socket_receive_buffer_size = 514; + optmask |= ARES_OPT_SOCK_RCVBUF; + opts.ednspsz = 1280; + optmask |= ARES_OPT_EDNSPSZ; + opts.nservers = 2; + opts.servers = (struct in_addr *)malloc(opts.nservers * sizeof(struct in_addr)); + opts.servers[0].s_addr = htonl(0x01020304); + opts.servers[1].s_addr = htonl(0x02030405); + optmask |= ARES_OPT_SERVERS; + opts.ndomains = 2; + opts.domains = (char **)malloc(opts.ndomains * sizeof(char *)); + opts.domains[0] = strdup("example.com"); + opts.domains[1] = strdup("example2.com"); + optmask |= ARES_OPT_DOMAINS; + opts.lookups = strdup("b"); + optmask |= ARES_OPT_LOOKUPS; + optmask |= ARES_OPT_ROTATE; + opts.resolvconf_path = strdup("/etc/resolv.conf"); + optmask |= ARES_OPT_RESOLVCONF; + + ares_channel channel = nullptr; + EXPECT_EQ(ARES_SUCCESS, ares_init_options(&channel, &opts, optmask)); + EXPECT_NE(nullptr, channel); + + ares_channel channel2 = nullptr; + EXPECT_EQ(ARES_SUCCESS, ares_dup(&channel2, channel)); + + struct ares_options opts2 = {0}; + int optmask2 = 0; + EXPECT_EQ(ARES_SUCCESS, ares_save_options(channel2, &opts2, &optmask2)); + + // Note that not all opts-settable fields are saved (e.g. + // ednspsz, socket_{send,receive}_buffer_size). + EXPECT_EQ(opts.flags, opts2.flags); + EXPECT_EQ(opts.timeout, opts2.timeout); + EXPECT_EQ(opts.tries, opts2.tries); + EXPECT_EQ(opts.ndots, opts2.ndots); + EXPECT_EQ(opts.udp_port, opts2.udp_port); + EXPECT_EQ(opts.tcp_port, opts2.tcp_port); + EXPECT_EQ(1, opts2.nservers); // Truncated by ARES_FLAG_PRIMARY + EXPECT_EQ(opts.servers[0].s_addr, opts2.servers[0].s_addr); + EXPECT_EQ(opts.ndomains, opts2.ndomains); + EXPECT_EQ(std::string(opts.domains[0]), std::string(opts2.domains[0])); + EXPECT_EQ(std::string(opts.domains[1]), std::string(opts2.domains[1])); + EXPECT_EQ(std::string(opts.lookups), std::string(opts2.lookups)); + EXPECT_EQ(std::string(opts.resolvconf_path), std::string(opts2.resolvconf_path)); + + ares_destroy_options(&opts); + ares_destroy_options(&opts2); + ares_destroy(channel); + ares_destroy(channel2); +} + +TEST_F(LibraryTest, ChannelAllocFail) { + ares_channel channel; + for (int ii = 1; ii <= 25; ii++) { + ClearFails(); + SetAllocFail(ii); + channel = nullptr; + int rc = ares_init(&channel); + // The number of allocations depends on local environment, so don't expect ENOMEM. + if (rc == ARES_ENOMEM) { + EXPECT_EQ(nullptr, channel); + } else { + ares_destroy(channel); + } + } +} + +TEST_F(LibraryTest, OptionsChannelAllocFail) { + struct ares_options opts = {0}; + int optmask = 0; + opts.flags = ARES_FLAG_USEVC; + optmask |= ARES_OPT_FLAGS; + opts.timeout = 2; + optmask |= ARES_OPT_TIMEOUT; + opts.tries = 2; + optmask |= ARES_OPT_TRIES; + opts.ndots = 4; + optmask |= ARES_OPT_NDOTS; + opts.udp_port = 54; + optmask |= ARES_OPT_UDP_PORT; + opts.tcp_port = 54; + optmask |= ARES_OPT_TCP_PORT; + opts.socket_send_buffer_size = 514; + optmask |= ARES_OPT_SOCK_SNDBUF; + opts.socket_receive_buffer_size = 514; + optmask |= ARES_OPT_SOCK_RCVBUF; + opts.ednspsz = 1280; + optmask |= ARES_OPT_EDNSPSZ; + opts.nservers = 2; + opts.servers = (struct in_addr *)malloc(opts.nservers * sizeof(struct in_addr)); + opts.servers[0].s_addr = htonl(0x01020304); + opts.servers[1].s_addr = htonl(0x02030405); + optmask |= ARES_OPT_SERVERS; + opts.ndomains = 2; + opts.domains = (char **)malloc(opts.ndomains * sizeof(char *)); + opts.domains[0] = strdup("example.com"); + opts.domains[1] = strdup("example2.com"); + optmask |= ARES_OPT_DOMAINS; + opts.lookups = strdup("b"); + optmask |= ARES_OPT_LOOKUPS; + optmask |= ARES_OPT_ROTATE; + opts.resolvconf_path = strdup("/etc/resolv.conf"); + optmask |= ARES_OPT_RESOLVCONF; + + ares_channel channel = nullptr; + for (int ii = 1; ii <= 8; ii++) { + ClearFails(); + SetAllocFail(ii); + int rc = ares_init_options(&channel, &opts, optmask); + if (rc == ARES_ENOMEM) { + EXPECT_EQ(nullptr, channel); + } else { + EXPECT_EQ(ARES_SUCCESS, rc); + ares_destroy(channel); + channel = nullptr; + } + } + ClearFails(); + + EXPECT_EQ(ARES_SUCCESS, ares_init_options(&channel, &opts, optmask)); + EXPECT_NE(nullptr, channel); + + // Add some servers and a sortlist for flavour. + EXPECT_EQ(ARES_SUCCESS, + ares_set_servers_csv(channel, "1.2.3.4,0102:0304:0506:0708:0910:1112:1314:1516,2.3.4.5")); + EXPECT_EQ(ARES_SUCCESS, ares_set_sortlist(channel, "1.2.3.4 2.3.4.5")); + + ares_channel channel2 = nullptr; + for (int ii = 1; ii <= 18; ii++) { + ClearFails(); + SetAllocFail(ii); + EXPECT_EQ(ARES_ENOMEM, ares_dup(&channel2, channel)) << ii; + EXPECT_EQ(nullptr, channel2) << ii; + } + + struct ares_options opts2; + int optmask2 = 0; + for (int ii = 1; ii <= 6; ii++) { + memset(&opts2, 0, sizeof(opts2)); + ClearFails(); + SetAllocFail(ii); + EXPECT_EQ(ARES_ENOMEM, ares_save_options(channel, &opts2, &optmask2)) << ii; + // May still have allocations even after ARES_ENOMEM return code. + ares_destroy_options(&opts2); + } + ares_destroy_options(&opts); + ares_destroy(channel); +} + +TEST_F(LibraryTest, FailChannelInit) { + EXPECT_EQ(ARES_SUCCESS, + ares_library_init_mem(ARES_LIB_INIT_ALL, + &LibraryTest::amalloc, + &LibraryTest::afree, + &LibraryTest::arealloc)); + SetAllocFail(1); + ares_channel channel = nullptr; + EXPECT_EQ(ARES_ENOMEM, ares_init(&channel)); + EXPECT_EQ(nullptr, channel); + ares_library_cleanup(); +} + +#ifndef WIN32 +TEST_F(LibraryTest, EnvInit) { + ares_channel channel = nullptr; + EnvValue v1("LOCALDOMAIN", "this.is.local"); + EnvValue v2("RES_OPTIONS", "options debug ndots:3 retry:3 rotate retrans:2"); + EXPECT_EQ(ARES_SUCCESS, ares_init(&channel)); + ares_destroy(channel); +} + TEST_F(LibraryTest, EnvInitYt) { ares_channel channel = nullptr; EnvValue v1("LOCALDOMAIN", "this.is.local"); @@ -268,233 +268,233 @@ TEST_F(LibraryTest, EnvInitYtTimeouts) { ares_destroy(channel); } -TEST_F(LibraryTest, EnvInitAllocFail) { - ares_channel channel; - EnvValue v1("LOCALDOMAIN", "this.is.local"); - EnvValue v2("RES_OPTIONS", "options debug ndots:3 retry:3 rotate retrans:2"); - for (int ii = 1; ii <= 10; ii++) { - ClearFails(); - SetAllocFail(ii); - channel = nullptr; - int rc = ares_init(&channel); - if (rc == ARES_SUCCESS) { - ares_destroy(channel); - } else { - EXPECT_EQ(ARES_ENOMEM, rc); - } - } -} -#endif - -TEST_F(DefaultChannelTest, SetAddresses) { - ares_set_local_ip4(channel_, 0x01020304); - byte addr6[16] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, - 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10}; - ares_set_local_ip6(channel_, addr6); - ares_set_local_dev(channel_, "dummy"); -} - -TEST_F(DefaultChannelTest, SetSortlistFailures) { - EXPECT_EQ(ARES_ENODATA, ares_set_sortlist(nullptr, "1.2.3.4")); - EXPECT_EQ(ARES_SUCCESS, ares_set_sortlist(channel_, "xyzzy ; lwk")); - EXPECT_EQ(ARES_SUCCESS, ares_set_sortlist(channel_, "xyzzy ; 0x123")); -} - -TEST_F(DefaultChannelTest, SetSortlistVariants) { - EXPECT_EQ(ARES_SUCCESS, ares_set_sortlist(channel_, "1.2.3.4")); - EXPECT_EQ(ARES_SUCCESS, ares_set_sortlist(channel_, "1.2.3.4 ; 2.3.4.5")); - EXPECT_EQ(ARES_SUCCESS, ares_set_sortlist(channel_, "129.1.1.1")); - EXPECT_EQ(ARES_SUCCESS, ares_set_sortlist(channel_, "192.1.1.1")); - EXPECT_EQ(ARES_SUCCESS, ares_set_sortlist(channel_, "224.1.1.1")); - EXPECT_EQ(ARES_SUCCESS, ares_set_sortlist(channel_, "225.1.1.1")); -} - -TEST_F(DefaultChannelTest, SetSortlistAllocFail) { - for (int ii = 1; ii <= 3; ii++) { - ClearFails(); - SetAllocFail(ii); - EXPECT_EQ(ARES_ENOMEM, ares_set_sortlist(channel_, "12.13.0.0/16 1234::5678/40 1.2.3.4")) << ii; - } -} - -#ifdef USE_WINSOCK -TEST(Init, NoLibraryInit) { - ares_channel channel = nullptr; - EXPECT_EQ(ARES_ENOTINITIALIZED, ares_init(&channel)); -} -#endif - -#ifdef HAVE_CONTAINER -// These tests rely on the ability of non-root users to create a chroot -// using Linux namespaces. - - -// The library uses a variety of information sources to initialize a channel, -// in particular to determine: -// - search: the search domains to use -// - servers: the name servers to use -// - lookup: whether to check files or DNS or both (e.g. "fb") -// - options: various resolver options -// - sortlist: the order of preference for IP addresses -// -// The first source from the following list is used: -// - init_by_options(): explicitly specified values in struct ares_options -// - init_by_environment(): values from the environment: -// - LOCALDOMAIN -> search (single value) -// - RES_OPTIONS -> options -// - init_by_resolv_conf(): values from various config files: -// - /etc/resolv.conf -> search, lookup, servers, sortlist, options -// - /etc/nsswitch.conf -> lookup -// - /etc/host.conf -> lookup -// - /etc/svc.conf -> lookup -// - init_by_defaults(): fallback values: -// - gethostname(3) -> domain -// - "fb" -> lookup - -NameContentList filelist = { - {"/etc/resolv.conf", "nameserver 1.2.3.4\n" - "sortlist 1.2.3.4/16 2.3.4.5\n" - "search first.com second.com\n"}, - {"/etc/hosts", "3.4.5.6 ahostname.com\n"}, - {"/etc/nsswitch.conf", "hosts: files\n"}}; -CONTAINED_TEST_F(LibraryTest, ContainerChannelInit, - "myhostname", "mydomainname.org", filelist) { - ares_channel channel = nullptr; - EXPECT_EQ(ARES_SUCCESS, ares_init(&channel)); - std::vector<std::string> actual = GetNameServers(channel); - std::vector<std::string> expected = {"1.2.3.4"}; - EXPECT_EQ(expected, actual); - - struct ares_options opts; - int optmask = 0; - ares_save_options(channel, &opts, &optmask); - EXPECT_EQ(2, opts.ndomains); - EXPECT_EQ(std::string("first.com"), std::string(opts.domains[0])); - EXPECT_EQ(std::string("second.com"), std::string(opts.domains[1])); - ares_destroy_options(&opts); - - HostResult result; - ares_gethostbyname(channel, "ahostname.com", AF_INET, HostCallback, &result); - ProcessWork(channel, NoExtraFDs, nullptr); - EXPECT_TRUE(result.done_); - std::stringstream ss; - ss << result.host_; - EXPECT_EQ("{'ahostname.com' aliases=[] addrs=[3.4.5.6]}", ss.str()); - - ares_destroy(channel); - return HasFailure(); -} - -CONTAINED_TEST_F(LibraryTest, ContainerSortlistOptionInit, - "myhostname", "mydomainname.org", filelist) { - ares_channel channel = nullptr; - struct ares_options opts = {0}; - int optmask = 0; - optmask |= ARES_OPT_SORTLIST; - opts.nsort = 0; - // Explicitly specifying an empty sortlist in the options should override the - // environment. - EXPECT_EQ(ARES_SUCCESS, ares_init_options(&channel, &opts, optmask)); - ares_save_options(channel, &opts, &optmask); - EXPECT_EQ(0, opts.nsort); - EXPECT_EQ(nullptr, opts.sortlist); - EXPECT_EQ(ARES_OPT_SORTLIST, (optmask & ARES_OPT_SORTLIST)); - ares_destroy_options(&opts); - - ares_destroy(channel); - return HasFailure(); -} - -NameContentList fullresolv = { - {"/etc/resolv.conf", " nameserver 1.2.3.4 \n" - "search first.com second.com\n" - "lookup bind\n" - "options debug ndots:5\n" - "sortlist 1.2.3.4/16 2.3.4.5\n"}}; -CONTAINED_TEST_F(LibraryTest, ContainerFullResolvInit, - "myhostname", "mydomainname.org", fullresolv) { - ares_channel channel = nullptr; - EXPECT_EQ(ARES_SUCCESS, ares_init(&channel)); - - struct ares_options opts; - int optmask = 0; - ares_save_options(channel, &opts, &optmask); - EXPECT_EQ(std::string("b"), std::string(opts.lookups)); - EXPECT_EQ(5, opts.ndots); - ares_destroy_options(&opts); - - ares_destroy(channel); - return HasFailure(); -} - -// Allow path for resolv.conf to be configurable -NameContentList myresolvconf = { - {"/tmp/myresolv.cnf", " nameserver 1.2.3.4 \n" - "search first.com second.com\n" - "lookup bind\n" - "options debug ndots:5\n" - "sortlist 1.2.3.4/16 2.3.4.5\n"}}; -CONTAINED_TEST_F(LibraryTest, ContainerMyResolvConfInit, - "myhostname", "mydomain.org", myresolvconf) { - char filename[] = "/tmp/myresolv.cnf"; - ares_channel channel = nullptr; - struct ares_options options = {0}; - options.resolvconf_path = strdup(filename); - int optmask = ARES_OPT_RESOLVCONF; - EXPECT_EQ(ARES_SUCCESS, ares_init_options(&channel, &options, optmask)); - - optmask = 0; - free(options.resolvconf_path); - options.resolvconf_path = NULL; - - EXPECT_EQ(ARES_SUCCESS, ares_save_options(channel, &options, &optmask)); - EXPECT_EQ(ARES_OPT_RESOLVCONF, (optmask & ARES_OPT_RESOLVCONF)); - EXPECT_EQ(std::string(filename), std::string(options.resolvconf_path)); - - ares_destroy_options(&options); - ares_destroy(channel); - return HasFailure(); -} - -NameContentList hostconf = { - {"/etc/resolv.conf", "nameserver 1.2.3.4\n" - "sortlist1.2.3.4\n" // malformed line - "search first.com second.com\n"}, - {"/etc/host.conf", "order bind hosts\n"}}; -CONTAINED_TEST_F(LibraryTest, ContainerHostConfInit, - "myhostname", "mydomainname.org", hostconf) { - ares_channel channel = nullptr; - EXPECT_EQ(ARES_SUCCESS, ares_init(&channel)); - - struct ares_options opts; - int optmask = 0; - ares_save_options(channel, &opts, &optmask); - EXPECT_EQ(std::string("bf"), std::string(opts.lookups)); - ares_destroy_options(&opts); - - ares_destroy(channel); - return HasFailure(); -} - -NameContentList svcconf = { - {"/etc/resolv.conf", "nameserver 1.2.3.4\n" - "search first.com second.com\n"}, - {"/etc/svc.conf", "hosts= bind\n"}}; -CONTAINED_TEST_F(LibraryTest, ContainerSvcConfInit, - "myhostname", "mydomainname.org", svcconf) { - ares_channel channel = nullptr; - EXPECT_EQ(ARES_SUCCESS, ares_init(&channel)); - - struct ares_options opts; - int optmask = 0; - ares_save_options(channel, &opts, &optmask); - EXPECT_EQ(std::string("b"), std::string(opts.lookups)); - ares_destroy_options(&opts); - - ares_destroy(channel); - return HasFailure(); -} - +TEST_F(LibraryTest, EnvInitAllocFail) { + ares_channel channel; + EnvValue v1("LOCALDOMAIN", "this.is.local"); + EnvValue v2("RES_OPTIONS", "options debug ndots:3 retry:3 rotate retrans:2"); + for (int ii = 1; ii <= 10; ii++) { + ClearFails(); + SetAllocFail(ii); + channel = nullptr; + int rc = ares_init(&channel); + if (rc == ARES_SUCCESS) { + ares_destroy(channel); + } else { + EXPECT_EQ(ARES_ENOMEM, rc); + } + } +} +#endif + +TEST_F(DefaultChannelTest, SetAddresses) { + ares_set_local_ip4(channel_, 0x01020304); + byte addr6[16] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10}; + ares_set_local_ip6(channel_, addr6); + ares_set_local_dev(channel_, "dummy"); +} + +TEST_F(DefaultChannelTest, SetSortlistFailures) { + EXPECT_EQ(ARES_ENODATA, ares_set_sortlist(nullptr, "1.2.3.4")); + EXPECT_EQ(ARES_SUCCESS, ares_set_sortlist(channel_, "xyzzy ; lwk")); + EXPECT_EQ(ARES_SUCCESS, ares_set_sortlist(channel_, "xyzzy ; 0x123")); +} + +TEST_F(DefaultChannelTest, SetSortlistVariants) { + EXPECT_EQ(ARES_SUCCESS, ares_set_sortlist(channel_, "1.2.3.4")); + EXPECT_EQ(ARES_SUCCESS, ares_set_sortlist(channel_, "1.2.3.4 ; 2.3.4.5")); + EXPECT_EQ(ARES_SUCCESS, ares_set_sortlist(channel_, "129.1.1.1")); + EXPECT_EQ(ARES_SUCCESS, ares_set_sortlist(channel_, "192.1.1.1")); + EXPECT_EQ(ARES_SUCCESS, ares_set_sortlist(channel_, "224.1.1.1")); + EXPECT_EQ(ARES_SUCCESS, ares_set_sortlist(channel_, "225.1.1.1")); +} + +TEST_F(DefaultChannelTest, SetSortlistAllocFail) { + for (int ii = 1; ii <= 3; ii++) { + ClearFails(); + SetAllocFail(ii); + EXPECT_EQ(ARES_ENOMEM, ares_set_sortlist(channel_, "12.13.0.0/16 1234::5678/40 1.2.3.4")) << ii; + } +} + +#ifdef USE_WINSOCK +TEST(Init, NoLibraryInit) { + ares_channel channel = nullptr; + EXPECT_EQ(ARES_ENOTINITIALIZED, ares_init(&channel)); +} +#endif + +#ifdef HAVE_CONTAINER +// These tests rely on the ability of non-root users to create a chroot +// using Linux namespaces. + + +// The library uses a variety of information sources to initialize a channel, +// in particular to determine: +// - search: the search domains to use +// - servers: the name servers to use +// - lookup: whether to check files or DNS or both (e.g. "fb") +// - options: various resolver options +// - sortlist: the order of preference for IP addresses +// +// The first source from the following list is used: +// - init_by_options(): explicitly specified values in struct ares_options +// - init_by_environment(): values from the environment: +// - LOCALDOMAIN -> search (single value) +// - RES_OPTIONS -> options +// - init_by_resolv_conf(): values from various config files: +// - /etc/resolv.conf -> search, lookup, servers, sortlist, options +// - /etc/nsswitch.conf -> lookup +// - /etc/host.conf -> lookup +// - /etc/svc.conf -> lookup +// - init_by_defaults(): fallback values: +// - gethostname(3) -> domain +// - "fb" -> lookup + +NameContentList filelist = { + {"/etc/resolv.conf", "nameserver 1.2.3.4\n" + "sortlist 1.2.3.4/16 2.3.4.5\n" + "search first.com second.com\n"}, + {"/etc/hosts", "3.4.5.6 ahostname.com\n"}, + {"/etc/nsswitch.conf", "hosts: files\n"}}; +CONTAINED_TEST_F(LibraryTest, ContainerChannelInit, + "myhostname", "mydomainname.org", filelist) { + ares_channel channel = nullptr; + EXPECT_EQ(ARES_SUCCESS, ares_init(&channel)); + std::vector<std::string> actual = GetNameServers(channel); + std::vector<std::string> expected = {"1.2.3.4"}; + EXPECT_EQ(expected, actual); + + struct ares_options opts; + int optmask = 0; + ares_save_options(channel, &opts, &optmask); + EXPECT_EQ(2, opts.ndomains); + EXPECT_EQ(std::string("first.com"), std::string(opts.domains[0])); + EXPECT_EQ(std::string("second.com"), std::string(opts.domains[1])); + ares_destroy_options(&opts); + + HostResult result; + ares_gethostbyname(channel, "ahostname.com", AF_INET, HostCallback, &result); + ProcessWork(channel, NoExtraFDs, nullptr); + EXPECT_TRUE(result.done_); + std::stringstream ss; + ss << result.host_; + EXPECT_EQ("{'ahostname.com' aliases=[] addrs=[3.4.5.6]}", ss.str()); + + ares_destroy(channel); + return HasFailure(); +} + +CONTAINED_TEST_F(LibraryTest, ContainerSortlistOptionInit, + "myhostname", "mydomainname.org", filelist) { + ares_channel channel = nullptr; + struct ares_options opts = {0}; + int optmask = 0; + optmask |= ARES_OPT_SORTLIST; + opts.nsort = 0; + // Explicitly specifying an empty sortlist in the options should override the + // environment. + EXPECT_EQ(ARES_SUCCESS, ares_init_options(&channel, &opts, optmask)); + ares_save_options(channel, &opts, &optmask); + EXPECT_EQ(0, opts.nsort); + EXPECT_EQ(nullptr, opts.sortlist); + EXPECT_EQ(ARES_OPT_SORTLIST, (optmask & ARES_OPT_SORTLIST)); + ares_destroy_options(&opts); + + ares_destroy(channel); + return HasFailure(); +} + +NameContentList fullresolv = { + {"/etc/resolv.conf", " nameserver 1.2.3.4 \n" + "search first.com second.com\n" + "lookup bind\n" + "options debug ndots:5\n" + "sortlist 1.2.3.4/16 2.3.4.5\n"}}; +CONTAINED_TEST_F(LibraryTest, ContainerFullResolvInit, + "myhostname", "mydomainname.org", fullresolv) { + ares_channel channel = nullptr; + EXPECT_EQ(ARES_SUCCESS, ares_init(&channel)); + + struct ares_options opts; + int optmask = 0; + ares_save_options(channel, &opts, &optmask); + EXPECT_EQ(std::string("b"), std::string(opts.lookups)); + EXPECT_EQ(5, opts.ndots); + ares_destroy_options(&opts); + + ares_destroy(channel); + return HasFailure(); +} + +// Allow path for resolv.conf to be configurable +NameContentList myresolvconf = { + {"/tmp/myresolv.cnf", " nameserver 1.2.3.4 \n" + "search first.com second.com\n" + "lookup bind\n" + "options debug ndots:5\n" + "sortlist 1.2.3.4/16 2.3.4.5\n"}}; +CONTAINED_TEST_F(LibraryTest, ContainerMyResolvConfInit, + "myhostname", "mydomain.org", myresolvconf) { + char filename[] = "/tmp/myresolv.cnf"; + ares_channel channel = nullptr; + struct ares_options options = {0}; + options.resolvconf_path = strdup(filename); + int optmask = ARES_OPT_RESOLVCONF; + EXPECT_EQ(ARES_SUCCESS, ares_init_options(&channel, &options, optmask)); + + optmask = 0; + free(options.resolvconf_path); + options.resolvconf_path = NULL; + + EXPECT_EQ(ARES_SUCCESS, ares_save_options(channel, &options, &optmask)); + EXPECT_EQ(ARES_OPT_RESOLVCONF, (optmask & ARES_OPT_RESOLVCONF)); + EXPECT_EQ(std::string(filename), std::string(options.resolvconf_path)); + + ares_destroy_options(&options); + ares_destroy(channel); + return HasFailure(); +} + +NameContentList hostconf = { + {"/etc/resolv.conf", "nameserver 1.2.3.4\n" + "sortlist1.2.3.4\n" // malformed line + "search first.com second.com\n"}, + {"/etc/host.conf", "order bind hosts\n"}}; +CONTAINED_TEST_F(LibraryTest, ContainerHostConfInit, + "myhostname", "mydomainname.org", hostconf) { + ares_channel channel = nullptr; + EXPECT_EQ(ARES_SUCCESS, ares_init(&channel)); + + struct ares_options opts; + int optmask = 0; + ares_save_options(channel, &opts, &optmask); + EXPECT_EQ(std::string("bf"), std::string(opts.lookups)); + ares_destroy_options(&opts); + + ares_destroy(channel); + return HasFailure(); +} + +NameContentList svcconf = { + {"/etc/resolv.conf", "nameserver 1.2.3.4\n" + "search first.com second.com\n"}, + {"/etc/svc.conf", "hosts= bind\n"}}; +CONTAINED_TEST_F(LibraryTest, ContainerSvcConfInit, + "myhostname", "mydomainname.org", svcconf) { + ares_channel channel = nullptr; + EXPECT_EQ(ARES_SUCCESS, ares_init(&channel)); + + struct ares_options opts; + int optmask = 0; + ares_save_options(channel, &opts, &optmask); + EXPECT_EQ(std::string("b"), std::string(opts.lookups)); + ares_destroy_options(&opts); + + ares_destroy(channel); + return HasFailure(); +} + NameContentList malformedresolvconflookup = { {"/etc/resolv.conf", "nameserver 1.2.3.4\n" "lookup garbage\n"}}; // malformed line @@ -513,191 +513,191 @@ CONTAINED_TEST_F(LibraryTest, ContainerMalformedResolvConfLookup, return HasFailure(); } -// Failures when expected config filenames are inaccessible. -class MakeUnreadable { - public: - explicit MakeUnreadable(const std::string& filename) - : filename_(filename) { - chmod(filename_.c_str(), 0000); - } - ~MakeUnreadable() { chmod(filename_.c_str(), 0644); } - private: - std::string filename_; -}; - -CONTAINED_TEST_F(LibraryTest, ContainerResolvConfNotReadable, - "myhostname", "mydomainname.org", filelist) { - ares_channel channel = nullptr; - MakeUnreadable hide("/etc/resolv.conf"); - // Unavailable /etc/resolv.conf falls back to defaults - EXPECT_EQ(ARES_SUCCESS, ares_init(&channel)); - return HasFailure(); -} -CONTAINED_TEST_F(LibraryTest, ContainerNsswitchConfNotReadable, - "myhostname", "mydomainname.org", filelist) { - ares_channel channel = nullptr; - // Unavailable /etc/nsswitch.conf falls back to defaults. - MakeUnreadable hide("/etc/nsswitch.conf"); - EXPECT_EQ(ARES_SUCCESS, ares_init(&channel)); - - struct ares_options opts; - int optmask = 0; - ares_save_options(channel, &opts, &optmask); - EXPECT_EQ(std::string("fb"), std::string(opts.lookups)); - ares_destroy_options(&opts); - - ares_destroy(channel); - return HasFailure(); -} -CONTAINED_TEST_F(LibraryTest, ContainerHostConfNotReadable, - "myhostname", "mydomainname.org", hostconf) { - ares_channel channel = nullptr; - // Unavailable /etc/host.conf falls back to defaults. - MakeUnreadable hide("/etc/host.conf"); - EXPECT_EQ(ARES_SUCCESS, ares_init(&channel)); - ares_destroy(channel); - return HasFailure(); -} -CONTAINED_TEST_F(LibraryTest, ContainerSvcConfNotReadable, - "myhostname", "mydomainname.org", svcconf) { - ares_channel channel = nullptr; - // Unavailable /etc/svc.conf falls back to defaults. - MakeUnreadable hide("/etc/svc.conf"); - EXPECT_EQ(ARES_SUCCESS, ares_init(&channel)); - ares_destroy(channel); - return HasFailure(); -} - -NameContentList rotateenv = { - {"/etc/resolv.conf", "nameserver 1.2.3.4\n" - "search first.com second.com\n" - "options rotate\n"}}; -CONTAINED_TEST_F(LibraryTest, ContainerRotateInit, - "myhostname", "mydomainname.org", rotateenv) { - ares_channel channel = nullptr; - EXPECT_EQ(ARES_SUCCESS, ares_init(&channel)); - - struct ares_options opts; - int optmask = 0; - ares_save_options(channel, &opts, &optmask); - EXPECT_EQ(ARES_OPT_ROTATE, (optmask & ARES_OPT_ROTATE)); - ares_destroy_options(&opts); - - ares_destroy(channel); - return HasFailure(); -} - -CONTAINED_TEST_F(LibraryTest, ContainerRotateOverride, - "myhostname", "mydomainname.org", rotateenv) { - ares_channel channel = nullptr; - struct ares_options opts = {0}; - int optmask = ARES_OPT_NOROTATE; - EXPECT_EQ(ARES_SUCCESS, ares_init_options(&channel, &opts, optmask)); - - optmask = 0; - ares_save_options(channel, &opts, &optmask); - EXPECT_EQ(ARES_OPT_NOROTATE, (optmask & ARES_OPT_NOROTATE)); - ares_destroy_options(&opts); - - ares_destroy(channel); - return HasFailure(); -} - -// Test that blacklisted IPv6 resolves are ignored. They're filtered from any -// source, so resolv.conf is as good as any. -NameContentList blacklistedIpv6 = { - {"/etc/resolv.conf", " nameserver 254.192.1.1\n" // 0xfe.0xc0.0x01.0x01 - " nameserver fec0::dead\n" // Blacklisted - " nameserver ffc0::c001\n" // Not blacklisted - " domain first.com\n"}, - {"/etc/nsswitch.conf", "hosts: files\n"}}; -CONTAINED_TEST_F(LibraryTest, ContainerBlacklistedIpv6, - "myhostname", "mydomainname.org", blacklistedIpv6) { - ares_channel channel = nullptr; - EXPECT_EQ(ARES_SUCCESS, ares_init(&channel)); - std::vector<std::string> actual = GetNameServers(channel); - std::vector<std::string> expected = { - "254.192.1.1", - "ffc0:0000:0000:0000:0000:0000:0000:c001" - }; - EXPECT_EQ(expected, actual); - - struct ares_options opts; - int optmask = 0; - ares_save_options(channel, &opts, &optmask); - EXPECT_EQ(1, opts.ndomains); - EXPECT_EQ(std::string("first.com"), std::string(opts.domains[0])); - ares_destroy_options(&opts); - - ares_destroy(channel); - return HasFailure(); -} - -NameContentList multiresolv = { - {"/etc/resolv.conf", " nameserver 1::2 ; ;;\n" - " domain first.com\n"}, - {"/etc/nsswitch.conf", "hosts: files\n"}}; -CONTAINED_TEST_F(LibraryTest, ContainerMultiResolvInit, - "myhostname", "mydomainname.org", multiresolv) { - ares_channel channel = nullptr; - EXPECT_EQ(ARES_SUCCESS, ares_init(&channel)); - std::vector<std::string> actual = GetNameServers(channel); - std::vector<std::string> expected = {"0001:0000:0000:0000:0000:0000:0000:0002"}; - EXPECT_EQ(expected, actual); - - struct ares_options opts; - int optmask = 0; - ares_save_options(channel, &opts, &optmask); - EXPECT_EQ(1, opts.ndomains); - EXPECT_EQ(std::string("first.com"), std::string(opts.domains[0])); - ares_destroy_options(&opts); - - ares_destroy(channel); - return HasFailure(); -} - -NameContentList systemdresolv = { - {"/etc/resolv.conf", "nameserver 1.2.3.4\n" - "domain first.com\n"}, - {"/etc/nsswitch.conf", "hosts: junk resolve files\n"}}; -CONTAINED_TEST_F(LibraryTest, ContainerSystemdResolvInit, - "myhostname", "mydomainname.org", systemdresolv) { - ares_channel channel = nullptr; - EXPECT_EQ(ARES_SUCCESS, ares_init(&channel)); - - struct ares_options opts; - int optmask = 0; - ares_save_options(channel, &opts, &optmask); - EXPECT_EQ(std::string("bf"), std::string(opts.lookups)); - ares_destroy_options(&opts); - - ares_destroy(channel); - return HasFailure(); -} - -NameContentList empty = {}; // no files -CONTAINED_TEST_F(LibraryTest, ContainerEmptyInit, - "host.domain.org", "domain.org", empty) { - ares_channel channel = nullptr; - EXPECT_EQ(ARES_SUCCESS, ares_init(&channel)); - std::vector<std::string> actual = GetNameServers(channel); - std::vector<std::string> expected = {"127.0.0.1"}; - EXPECT_EQ(expected, actual); - - struct ares_options opts; - int optmask = 0; - ares_save_options(channel, &opts, &optmask); - EXPECT_EQ(1, opts.ndomains); - EXPECT_EQ(std::string("domain.org"), std::string(opts.domains[0])); - EXPECT_EQ(std::string("fb"), std::string(opts.lookups)); - ares_destroy_options(&opts); - - - ares_destroy(channel); - return HasFailure(); -} - -#endif - -} // namespace test -} // namespace ares +// Failures when expected config filenames are inaccessible. +class MakeUnreadable { + public: + explicit MakeUnreadable(const std::string& filename) + : filename_(filename) { + chmod(filename_.c_str(), 0000); + } + ~MakeUnreadable() { chmod(filename_.c_str(), 0644); } + private: + std::string filename_; +}; + +CONTAINED_TEST_F(LibraryTest, ContainerResolvConfNotReadable, + "myhostname", "mydomainname.org", filelist) { + ares_channel channel = nullptr; + MakeUnreadable hide("/etc/resolv.conf"); + // Unavailable /etc/resolv.conf falls back to defaults + EXPECT_EQ(ARES_SUCCESS, ares_init(&channel)); + return HasFailure(); +} +CONTAINED_TEST_F(LibraryTest, ContainerNsswitchConfNotReadable, + "myhostname", "mydomainname.org", filelist) { + ares_channel channel = nullptr; + // Unavailable /etc/nsswitch.conf falls back to defaults. + MakeUnreadable hide("/etc/nsswitch.conf"); + EXPECT_EQ(ARES_SUCCESS, ares_init(&channel)); + + struct ares_options opts; + int optmask = 0; + ares_save_options(channel, &opts, &optmask); + EXPECT_EQ(std::string("fb"), std::string(opts.lookups)); + ares_destroy_options(&opts); + + ares_destroy(channel); + return HasFailure(); +} +CONTAINED_TEST_F(LibraryTest, ContainerHostConfNotReadable, + "myhostname", "mydomainname.org", hostconf) { + ares_channel channel = nullptr; + // Unavailable /etc/host.conf falls back to defaults. + MakeUnreadable hide("/etc/host.conf"); + EXPECT_EQ(ARES_SUCCESS, ares_init(&channel)); + ares_destroy(channel); + return HasFailure(); +} +CONTAINED_TEST_F(LibraryTest, ContainerSvcConfNotReadable, + "myhostname", "mydomainname.org", svcconf) { + ares_channel channel = nullptr; + // Unavailable /etc/svc.conf falls back to defaults. + MakeUnreadable hide("/etc/svc.conf"); + EXPECT_EQ(ARES_SUCCESS, ares_init(&channel)); + ares_destroy(channel); + return HasFailure(); +} + +NameContentList rotateenv = { + {"/etc/resolv.conf", "nameserver 1.2.3.4\n" + "search first.com second.com\n" + "options rotate\n"}}; +CONTAINED_TEST_F(LibraryTest, ContainerRotateInit, + "myhostname", "mydomainname.org", rotateenv) { + ares_channel channel = nullptr; + EXPECT_EQ(ARES_SUCCESS, ares_init(&channel)); + + struct ares_options opts; + int optmask = 0; + ares_save_options(channel, &opts, &optmask); + EXPECT_EQ(ARES_OPT_ROTATE, (optmask & ARES_OPT_ROTATE)); + ares_destroy_options(&opts); + + ares_destroy(channel); + return HasFailure(); +} + +CONTAINED_TEST_F(LibraryTest, ContainerRotateOverride, + "myhostname", "mydomainname.org", rotateenv) { + ares_channel channel = nullptr; + struct ares_options opts = {0}; + int optmask = ARES_OPT_NOROTATE; + EXPECT_EQ(ARES_SUCCESS, ares_init_options(&channel, &opts, optmask)); + + optmask = 0; + ares_save_options(channel, &opts, &optmask); + EXPECT_EQ(ARES_OPT_NOROTATE, (optmask & ARES_OPT_NOROTATE)); + ares_destroy_options(&opts); + + ares_destroy(channel); + return HasFailure(); +} + +// Test that blacklisted IPv6 resolves are ignored. They're filtered from any +// source, so resolv.conf is as good as any. +NameContentList blacklistedIpv6 = { + {"/etc/resolv.conf", " nameserver 254.192.1.1\n" // 0xfe.0xc0.0x01.0x01 + " nameserver fec0::dead\n" // Blacklisted + " nameserver ffc0::c001\n" // Not blacklisted + " domain first.com\n"}, + {"/etc/nsswitch.conf", "hosts: files\n"}}; +CONTAINED_TEST_F(LibraryTest, ContainerBlacklistedIpv6, + "myhostname", "mydomainname.org", blacklistedIpv6) { + ares_channel channel = nullptr; + EXPECT_EQ(ARES_SUCCESS, ares_init(&channel)); + std::vector<std::string> actual = GetNameServers(channel); + std::vector<std::string> expected = { + "254.192.1.1", + "ffc0:0000:0000:0000:0000:0000:0000:c001" + }; + EXPECT_EQ(expected, actual); + + struct ares_options opts; + int optmask = 0; + ares_save_options(channel, &opts, &optmask); + EXPECT_EQ(1, opts.ndomains); + EXPECT_EQ(std::string("first.com"), std::string(opts.domains[0])); + ares_destroy_options(&opts); + + ares_destroy(channel); + return HasFailure(); +} + +NameContentList multiresolv = { + {"/etc/resolv.conf", " nameserver 1::2 ; ;;\n" + " domain first.com\n"}, + {"/etc/nsswitch.conf", "hosts: files\n"}}; +CONTAINED_TEST_F(LibraryTest, ContainerMultiResolvInit, + "myhostname", "mydomainname.org", multiresolv) { + ares_channel channel = nullptr; + EXPECT_EQ(ARES_SUCCESS, ares_init(&channel)); + std::vector<std::string> actual = GetNameServers(channel); + std::vector<std::string> expected = {"0001:0000:0000:0000:0000:0000:0000:0002"}; + EXPECT_EQ(expected, actual); + + struct ares_options opts; + int optmask = 0; + ares_save_options(channel, &opts, &optmask); + EXPECT_EQ(1, opts.ndomains); + EXPECT_EQ(std::string("first.com"), std::string(opts.domains[0])); + ares_destroy_options(&opts); + + ares_destroy(channel); + return HasFailure(); +} + +NameContentList systemdresolv = { + {"/etc/resolv.conf", "nameserver 1.2.3.4\n" + "domain first.com\n"}, + {"/etc/nsswitch.conf", "hosts: junk resolve files\n"}}; +CONTAINED_TEST_F(LibraryTest, ContainerSystemdResolvInit, + "myhostname", "mydomainname.org", systemdresolv) { + ares_channel channel = nullptr; + EXPECT_EQ(ARES_SUCCESS, ares_init(&channel)); + + struct ares_options opts; + int optmask = 0; + ares_save_options(channel, &opts, &optmask); + EXPECT_EQ(std::string("bf"), std::string(opts.lookups)); + ares_destroy_options(&opts); + + ares_destroy(channel); + return HasFailure(); +} + +NameContentList empty = {}; // no files +CONTAINED_TEST_F(LibraryTest, ContainerEmptyInit, + "host.domain.org", "domain.org", empty) { + ares_channel channel = nullptr; + EXPECT_EQ(ARES_SUCCESS, ares_init(&channel)); + std::vector<std::string> actual = GetNameServers(channel); + std::vector<std::string> expected = {"127.0.0.1"}; + EXPECT_EQ(expected, actual); + + struct ares_options opts; + int optmask = 0; + ares_save_options(channel, &opts, &optmask); + EXPECT_EQ(1, opts.ndomains); + EXPECT_EQ(std::string("domain.org"), std::string(opts.domains[0])); + EXPECT_EQ(std::string("fb"), std::string(opts.lookups)); + ares_destroy_options(&opts); + + + ares_destroy(channel); + return HasFailure(); +} + +#endif + +} // namespace test +} // namespace ares diff --git a/contrib/libs/c-ares/test/ares-test-internal.cc b/contrib/libs/c-ares/test/ares-test-internal.cc index 26e91e73e8..96d4edece5 100644 --- a/contrib/libs/c-ares/test/ares-test-internal.cc +++ b/contrib/libs/c-ares/test/ares-test-internal.cc @@ -1,361 +1,361 @@ -#include "ares-test.h" -#include "dns-proto.h" - -#include <stdio.h> - -#ifdef HAVE_UNISTD_H -#include <unistd.h> -#endif -#include <fcntl.h> - -extern "C" { -// Remove command-line defines of package variables for the test project... -#undef PACKAGE_NAME -#undef PACKAGE_BUGREPORT -#undef PACKAGE_STRING -#undef PACKAGE_TARNAME -// ... so we can include the library's config without symbol redefinitions. -#include "ares_setup.h" -#include "ares_nowarn.h" -#include "ares_inet_net_pton.h" -#include "ares_data.h" -#include "ares_private.h" -#include "bitncmp.h" - -#ifdef HAVE_ARPA_INET_H -#include <arpa/inet.h> -#endif -#ifdef HAVE_SYS_UIO_H -# include <sys/uio.h> -#endif -} - -#include <string> -#include <vector> - -namespace ares { -namespace test { - -#ifndef CARES_SYMBOL_HIDING -void CheckPtoN4(int size, unsigned int value, const char *input) { - struct in_addr a4; - a4.s_addr = 0; - uint32_t expected = htonl(value); - EXPECT_EQ(size, ares_inet_net_pton(AF_INET, input, &a4, sizeof(a4))) - << " for input " << input; - EXPECT_EQ(expected, a4.s_addr) << " for input " << input; -} -#endif - -TEST_F(LibraryTest, InetPtoN) { - struct in_addr a4; - struct in6_addr a6; - -#ifndef CARES_SYMBOL_HIDING - uint32_t expected; - - CheckPtoN4(4 * 8, 0x01020304, "1.2.3.4"); - CheckPtoN4(4 * 8, 0x81010101, "129.1.1.1"); - CheckPtoN4(4 * 8, 0xC0010101, "192.1.1.1"); - CheckPtoN4(4 * 8, 0xE0010101, "224.1.1.1"); - CheckPtoN4(4 * 8, 0xE1010101, "225.1.1.1"); - CheckPtoN4(4, 0xE0000000, "224"); - CheckPtoN4(4 * 8, 0xFD000000, "253"); - CheckPtoN4(4 * 8, 0xF0010101, "240.1.1.1"); - CheckPtoN4(4 * 8, 0x02030405, "02.3.4.5"); - CheckPtoN4(3 * 8, 0x01020304, "1.2.3.4/24"); - CheckPtoN4(3 * 8, 0x01020300, "1.2.3/24"); - CheckPtoN4(2 * 8, 0xa0000000, "0xa"); - CheckPtoN4(0, 0x02030405, "2.3.4.5/000"); - CheckPtoN4(1 * 8, 0x01020000, "1.2/8"); - CheckPtoN4(2 * 8, 0x01020000, "0x0102/16"); - CheckPtoN4(4 * 8, 0x02030405, "02.3.4.5"); - - EXPECT_EQ(16 * 8, ares_inet_net_pton(AF_INET6, "::", &a6, sizeof(a6))); - EXPECT_EQ(16 * 8, ares_inet_net_pton(AF_INET6, "::1", &a6, sizeof(a6))); - EXPECT_EQ(16 * 8, ares_inet_net_pton(AF_INET6, "1234:5678::", &a6, sizeof(a6))); - EXPECT_EQ(16 * 8, ares_inet_net_pton(AF_INET6, "12:34::ff", &a6, sizeof(a6))); - EXPECT_EQ(16 * 8, ares_inet_net_pton(AF_INET6, "12:34::ffff:1.2.3.4", &a6, sizeof(a6))); - EXPECT_EQ(23, ares_inet_net_pton(AF_INET6, "12:34::ffff:1.2.3.4/23", &a6, sizeof(a6))); - EXPECT_EQ(3 * 8, ares_inet_net_pton(AF_INET6, "12:34::ff/24", &a6, sizeof(a6))); - EXPECT_EQ(0, ares_inet_net_pton(AF_INET6, "12:34::ff/0", &a6, sizeof(a6))); - EXPECT_EQ(16 * 8, ares_inet_net_pton(AF_INET6, "12:34::ffff:0.2", &a6, sizeof(a6))); - EXPECT_EQ(16 * 8, ares_inet_net_pton(AF_INET6, "1234:1234:1234:1234:1234:1234:1234:1234", &a6, sizeof(a6))); - - // Various malformed versions - EXPECT_EQ(-1, ares_inet_net_pton(AF_INET, "", &a4, sizeof(a4))); - EXPECT_EQ(-1, ares_inet_net_pton(AF_INET, " ", &a4, sizeof(a4))); - EXPECT_EQ(-1, ares_inet_net_pton(AF_INET, "0x", &a4, sizeof(a4))); - EXPECT_EQ(-1, ares_inet_net_pton(AF_INET, "0x ", &a4, sizeof(a4))); - EXPECT_EQ(-1, ares_inet_net_pton(AF_INET, "x0", &a4, sizeof(a4))); - EXPECT_EQ(-1, ares_inet_net_pton(AF_INET, "0xXYZZY", &a4, sizeof(a4))); - EXPECT_EQ(-1, ares_inet_net_pton(AF_INET, "xyzzy", &a4, sizeof(a4))); - EXPECT_EQ(-1, ares_inet_net_pton(AF_INET+AF_INET6, "1.2.3.4", &a4, sizeof(a4))); - EXPECT_EQ(-1, ares_inet_net_pton(AF_INET, "257.2.3.4", &a4, sizeof(a4))); - EXPECT_EQ(-1, ares_inet_net_pton(AF_INET, "002.3.4.x", &a4, sizeof(a4))); - EXPECT_EQ(-1, ares_inet_net_pton(AF_INET, "00.3.4.x", &a4, sizeof(a4))); - EXPECT_EQ(-1, ares_inet_net_pton(AF_INET, "2.3.4.x", &a4, sizeof(a4))); - EXPECT_EQ(-1, ares_inet_net_pton(AF_INET, "2.3.4.5.6", &a4, sizeof(a4))); - EXPECT_EQ(-1, ares_inet_net_pton(AF_INET, "2.3.4.5.6/12", &a4, sizeof(a4))); - EXPECT_EQ(-1, ares_inet_net_pton(AF_INET, "2.3.4:5", &a4, sizeof(a4))); - EXPECT_EQ(-1, ares_inet_net_pton(AF_INET, "2.3.4.5/120", &a4, sizeof(a4))); - EXPECT_EQ(-1, ares_inet_net_pton(AF_INET, "2.3.4.5/1x", &a4, sizeof(a4))); - EXPECT_EQ(-1, ares_inet_net_pton(AF_INET, "2.3.4.5/x", &a4, sizeof(a4))); - EXPECT_EQ(-1, ares_inet_net_pton(AF_INET6, "12:34::ff/240", &a6, sizeof(a6))); - EXPECT_EQ(-1, ares_inet_net_pton(AF_INET6, "12:34::ff/02", &a6, sizeof(a6))); - EXPECT_EQ(-1, ares_inet_net_pton(AF_INET6, "12:34::ff/2y", &a6, sizeof(a6))); - EXPECT_EQ(-1, ares_inet_net_pton(AF_INET6, "12:34::ff/y", &a6, sizeof(a6))); - EXPECT_EQ(-1, ares_inet_net_pton(AF_INET6, "12:34::ff/", &a6, sizeof(a6))); - EXPECT_EQ(-1, ares_inet_net_pton(AF_INET6, "", &a6, sizeof(a6))); - EXPECT_EQ(-1, ares_inet_net_pton(AF_INET6, ":x", &a6, sizeof(a6))); - EXPECT_EQ(-1, ares_inet_net_pton(AF_INET6, ":", &a6, sizeof(a6))); - EXPECT_EQ(-1, ares_inet_net_pton(AF_INET6, ": :1234", &a6, sizeof(a6))); - EXPECT_EQ(-1, ares_inet_net_pton(AF_INET6, "::12345", &a6, sizeof(a6))); - EXPECT_EQ(-1, ares_inet_net_pton(AF_INET6, "1234::2345:3456::0011", &a6, sizeof(a6))); - EXPECT_EQ(-1, ares_inet_net_pton(AF_INET6, "1234:1234:1234:1234:1234:1234:1234:1234:", &a6, sizeof(a6))); - EXPECT_EQ(-1, ares_inet_net_pton(AF_INET6, "1234:1234:1234:1234:1234:1234:1234:1234::", &a6, sizeof(a6))); - EXPECT_EQ(-1, ares_inet_net_pton(AF_INET6, "1234:1234:1234:1234:1234:1234:1234:1.2.3.4", &a6, sizeof(a6))); - EXPECT_EQ(-1, ares_inet_net_pton(AF_INET6, ":1234:1234:1234:1234:1234:1234:1234:1234", &a6, sizeof(a6))); - EXPECT_EQ(-1, ares_inet_net_pton(AF_INET6, ":1234:1234:1234:1234:1234:1234:1234:1234:", &a6, sizeof(a6))); - EXPECT_EQ(-1, ares_inet_net_pton(AF_INET6, "1234:1234:1234:1234:1234:1234:1234:1234:5678", &a6, sizeof(a6))); - // TODO(drysdale): check whether the next two tests should give -1. - EXPECT_EQ(0, ares_inet_net_pton(AF_INET6, "1234:1234:1234:1234:1234:1234:1234:1234:5678:5678", &a6, sizeof(a6))); - EXPECT_EQ(0, ares_inet_net_pton(AF_INET6, "1234:1234:1234:1234:1234:1234:1234:1234:5678:5678:5678", &a6, sizeof(a6))); - EXPECT_EQ(-1, ares_inet_net_pton(AF_INET6, "12:34::ffff:257.2.3.4", &a6, sizeof(a6))); - EXPECT_EQ(-1, ares_inet_net_pton(AF_INET6, "12:34::ffff:002.2.3.4", &a6, sizeof(a6))); - EXPECT_EQ(-1, ares_inet_net_pton(AF_INET6, "12:34::ffff:1.2.3.4.5.6", &a6, sizeof(a6))); - EXPECT_EQ(-1, ares_inet_net_pton(AF_INET6, "12:34::ffff:1.2.3.4.5", &a6, sizeof(a6))); - EXPECT_EQ(-1, ares_inet_net_pton(AF_INET6, "12:34::ffff:1.2.3.z", &a6, sizeof(a6))); - EXPECT_EQ(-1, ares_inet_net_pton(AF_INET6, "12:34::ffff:1.2.3001.4", &a6, sizeof(a6))); - EXPECT_EQ(-1, ares_inet_net_pton(AF_INET6, "12:34::ffff:1.2.3..4", &a6, sizeof(a6))); - EXPECT_EQ(-1, ares_inet_net_pton(AF_INET6, "12:34::ffff:1.2.3.", &a6, sizeof(a6))); - - // Hex constants are allowed. - EXPECT_EQ(4 * 8, ares_inet_net_pton(AF_INET, "0x01020304", &a4, sizeof(a4))); - expected = htonl(0x01020304); - EXPECT_EQ(expected, a4.s_addr); - EXPECT_EQ(4 * 8, ares_inet_net_pton(AF_INET, "0x0a0b0c0d", &a4, sizeof(a4))); - expected = htonl(0x0a0b0c0d); - EXPECT_EQ(expected, a4.s_addr); - EXPECT_EQ(4 * 8, ares_inet_net_pton(AF_INET, "0x0A0B0C0D", &a4, sizeof(a4))); - expected = htonl(0x0a0b0c0d); - EXPECT_EQ(expected, a4.s_addr); - EXPECT_EQ(-1, ares_inet_net_pton(AF_INET, "0x0xyz", &a4, sizeof(a4))); - EXPECT_EQ(4 * 8, ares_inet_net_pton(AF_INET, "0x1122334", &a4, sizeof(a4))); - expected = htonl(0x11223340); - EXPECT_EQ(expected, a4.s_addr); // huh? - - // No room, no room. - EXPECT_EQ(-1, ares_inet_net_pton(AF_INET, "1.2.3.4", &a4, sizeof(a4) - 1)); - EXPECT_EQ(-1, ares_inet_net_pton(AF_INET6, "12:34::ff", &a6, sizeof(a6) - 1)); - EXPECT_EQ(-1, ares_inet_net_pton(AF_INET, "0x01020304", &a4, 2)); - EXPECT_EQ(-1, ares_inet_net_pton(AF_INET, "0x01020304", &a4, 0)); - EXPECT_EQ(-1, ares_inet_net_pton(AF_INET, "0x0a0b0c0d", &a4, 0)); - EXPECT_EQ(-1, ares_inet_net_pton(AF_INET, "0x0xyz", &a4, 0)); - EXPECT_EQ(-1, ares_inet_net_pton(AF_INET, "0x1122334", &a4, sizeof(a4) - 1)); - EXPECT_EQ(-1, ares_inet_net_pton(AF_INET, "253", &a4, sizeof(a4) - 1)); -#endif - - EXPECT_EQ(1, ares_inet_pton(AF_INET, "1.2.3.4", &a4)); - EXPECT_EQ(1, ares_inet_pton(AF_INET6, "12:34::ff", &a6)); - EXPECT_EQ(1, ares_inet_pton(AF_INET6, "12:34::ffff:1.2.3.4", &a6)); - EXPECT_EQ(0, ares_inet_pton(AF_INET, "xyzzy", &a4)); - EXPECT_EQ(-1, ares_inet_pton(AF_INET+AF_INET6, "1.2.3.4", &a4)); -} - -TEST_F(LibraryTest, FreeCorruptData) { - // ares_free_data(p) expects that there is a type field and a marker - // field in the memory before p. Feed it incorrect versions of each. - struct ares_data *data = (struct ares_data *)malloc(sizeof(struct ares_data)); - void* p = &(data->data); - - // Invalid type - data->type = (ares_datatype)99; - data->mark = ARES_DATATYPE_MARK; - ares_free_data(p); - - // Invalid marker - data->type = (ares_datatype)ARES_DATATYPE_MX_REPLY; - data->mark = ARES_DATATYPE_MARK + 1; - ares_free_data(p); - - // Null pointer - ares_free_data(nullptr); - - free(data); -} - -#ifndef CARES_SYMBOL_HIDING -TEST_F(LibraryTest, FreeLongChain) { - struct ares_addr_node *data = nullptr; - for (int ii = 0; ii < 100000; ii++) { - struct ares_addr_node *prev = (struct ares_addr_node*)ares_malloc_data(ARES_DATATYPE_ADDR_NODE); - prev->next = data; - data = prev; - } - - ares_free_data(data); -} - -TEST(LibraryInit, StrdupFailures) { - EXPECT_EQ(ARES_SUCCESS, ares_library_init(ARES_LIB_INIT_ALL)); - char* copy = ares_strdup("string"); - EXPECT_NE(nullptr, copy); - ares_free(copy); - ares_library_cleanup(); -} - -TEST_F(LibraryTest, StrdupFailures) { - SetAllocFail(1); - char* copy = ares_strdup("string"); - EXPECT_EQ(nullptr, copy); -} - -TEST_F(LibraryTest, MallocDataFail) { - EXPECT_EQ(nullptr, ares_malloc_data((ares_datatype)99)); - SetAllocSizeFail(sizeof(struct ares_data)); - EXPECT_EQ(nullptr, ares_malloc_data(ARES_DATATYPE_MX_REPLY)); -} - -TEST(Misc, Bitncmp) { - byte a[4] = {0x80, 0x01, 0x02, 0x03}; - byte b[4] = {0x80, 0x01, 0x02, 0x04}; - byte c[4] = {0x01, 0xFF, 0x80, 0x02}; - EXPECT_GT(0, ares__bitncmp(a, b, sizeof(a)*8)); - EXPECT_LT(0, ares__bitncmp(b, a, sizeof(a)*8)); - EXPECT_EQ(0, ares__bitncmp(a, a, sizeof(a)*8)); - - for (int ii = 1; ii < (3*8+5); ii++) { - EXPECT_EQ(0, ares__bitncmp(a, b, ii)); - EXPECT_EQ(0, ares__bitncmp(b, a, ii)); - EXPECT_LT(0, ares__bitncmp(a, c, ii)); - EXPECT_GT(0, ares__bitncmp(c, a, ii)); - } - - // Last byte differs at 5th bit - EXPECT_EQ(0, ares__bitncmp(a, b, 3*8 + 3)); - EXPECT_EQ(0, ares__bitncmp(a, b, 3*8 + 4)); - EXPECT_EQ(0, ares__bitncmp(a, b, 3*8 + 5)); - EXPECT_GT(0, ares__bitncmp(a, b, 3*8 + 6)); - EXPECT_GT(0, ares__bitncmp(a, b, 3*8 + 7)); -} - -TEST_F(LibraryTest, Casts) { - ares_ssize_t ssz = 100; - unsigned int u = 100; - int i = 100; - long l = 100; - - unsigned int ru = aresx_sztoui(ssz); - EXPECT_EQ(u, ru); - int ri = aresx_sztosi(ssz); - EXPECT_EQ(i, ri); - - ri = aresx_sltosi(l); - EXPECT_EQ(l, (long)ri); -} - -TEST_F(LibraryTest, ReadLine) { - TempFile temp("abcde\n0123456789\nXYZ\n012345678901234567890\n\n"); - FILE *fp = fopen(temp.filename(), "r"); - size_t bufsize = 4; - char *buf = (char *)ares_malloc(bufsize); - - EXPECT_EQ(ARES_SUCCESS, ares__read_line(fp, &buf, &bufsize)); - EXPECT_EQ("abcde", std::string(buf)); - EXPECT_EQ(ARES_SUCCESS, ares__read_line(fp, &buf, &bufsize)); - EXPECT_EQ("0123456789", std::string(buf)); - EXPECT_EQ(ARES_SUCCESS, ares__read_line(fp, &buf, &bufsize)); - EXPECT_EQ("XYZ", std::string(buf)); - SetAllocFail(1); - EXPECT_EQ(ARES_ENOMEM, ares__read_line(fp, &buf, &bufsize)); - EXPECT_EQ(nullptr, buf); - - fclose(fp); - ares_free(buf); -} - -TEST_F(LibraryTest, ReadLineNoBuf) { - TempFile temp("abcde\n0123456789\nXYZ\n012345678901234567890"); - FILE *fp = fopen(temp.filename(), "r"); - size_t bufsize = 0; - char *buf = nullptr; - - SetAllocFail(1); - EXPECT_EQ(ARES_ENOMEM, ares__read_line(fp, &buf, &bufsize)); - - EXPECT_EQ(ARES_SUCCESS, ares__read_line(fp, &buf, &bufsize)); - EXPECT_EQ("abcde", std::string(buf)); - EXPECT_EQ(ARES_SUCCESS, ares__read_line(fp, &buf, &bufsize)); - EXPECT_EQ("0123456789", std::string(buf)); - EXPECT_EQ(ARES_SUCCESS, ares__read_line(fp, &buf, &bufsize)); - EXPECT_EQ("XYZ", std::string(buf)); - EXPECT_EQ(ARES_SUCCESS, ares__read_line(fp, &buf, &bufsize)); - EXPECT_EQ("012345678901234567890", std::string(buf)); - - fclose(fp); - ares_free(buf); -} - -TEST(Misc, GetHostent) { - TempFile hostsfile("1.2.3.4 example.com \n" - " 2.3.4.5\tgoogle.com www.google.com\twww2.google.com\n" - "#comment\n" - "4.5.6.7\n" - "1.3.5.7 \n" - "::1 ipv6.com"); - struct hostent *host = nullptr; - FILE *fp = fopen(hostsfile.filename(), "r"); - ASSERT_NE(nullptr, fp); - EXPECT_EQ(ARES_EBADFAMILY, ares__get_hostent(fp, AF_INET+AF_INET6, &host)); - rewind(fp); - - EXPECT_EQ(ARES_SUCCESS, ares__get_hostent(fp, AF_INET, &host)); - ASSERT_NE(nullptr, host); - std::stringstream ss1; - ss1 << HostEnt(host); - EXPECT_EQ("{'example.com' aliases=[] addrs=[1.2.3.4]}", ss1.str()); - ares_free_hostent(host); - host = nullptr; - - EXPECT_EQ(ARES_SUCCESS, ares__get_hostent(fp, AF_INET, &host)); - ASSERT_NE(nullptr, host); - std::stringstream ss2; - ss2 << HostEnt(host); - EXPECT_EQ("{'google.com' aliases=[www.google.com, www2.google.com] addrs=[2.3.4.5]}", ss2.str()); - ares_free_hostent(host); - host = nullptr; - - EXPECT_EQ(ARES_EOF, ares__get_hostent(fp, AF_INET, &host)); - - rewind(fp); - EXPECT_EQ(ARES_SUCCESS, ares__get_hostent(fp, AF_INET6, &host)); - ASSERT_NE(nullptr, host); - std::stringstream ss3; - ss3 << HostEnt(host); - EXPECT_EQ("{'ipv6.com' aliases=[] addrs=[0000:0000:0000:0000:0000:0000:0000:0001]}", ss3.str()); - ares_free_hostent(host); - host = nullptr; - EXPECT_EQ(ARES_EOF, ares__get_hostent(fp, AF_INET6, &host)); - fclose(fp); -} - -TEST_F(LibraryTest, GetHostentAllocFail) { - TempFile hostsfile("1.2.3.4 example.com alias1 alias2\n"); - struct hostent *host = nullptr; - FILE *fp = fopen(hostsfile.filename(), "r"); - ASSERT_NE(nullptr, fp); - - for (int ii = 1; ii <= 8; ii++) { - rewind(fp); - ClearFails(); - SetAllocFail(ii); - host = nullptr; - EXPECT_EQ(ARES_ENOMEM, ares__get_hostent(fp, AF_INET, &host)) << ii; - } - fclose(fp); -} - +#include "ares-test.h" +#include "dns-proto.h" + +#include <stdio.h> + +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#include <fcntl.h> + +extern "C" { +// Remove command-line defines of package variables for the test project... +#undef PACKAGE_NAME +#undef PACKAGE_BUGREPORT +#undef PACKAGE_STRING +#undef PACKAGE_TARNAME +// ... so we can include the library's config without symbol redefinitions. +#include "ares_setup.h" +#include "ares_nowarn.h" +#include "ares_inet_net_pton.h" +#include "ares_data.h" +#include "ares_private.h" +#include "bitncmp.h" + +#ifdef HAVE_ARPA_INET_H +#include <arpa/inet.h> +#endif +#ifdef HAVE_SYS_UIO_H +# include <sys/uio.h> +#endif +} + +#include <string> +#include <vector> + +namespace ares { +namespace test { + +#ifndef CARES_SYMBOL_HIDING +void CheckPtoN4(int size, unsigned int value, const char *input) { + struct in_addr a4; + a4.s_addr = 0; + uint32_t expected = htonl(value); + EXPECT_EQ(size, ares_inet_net_pton(AF_INET, input, &a4, sizeof(a4))) + << " for input " << input; + EXPECT_EQ(expected, a4.s_addr) << " for input " << input; +} +#endif + +TEST_F(LibraryTest, InetPtoN) { + struct in_addr a4; + struct in6_addr a6; + +#ifndef CARES_SYMBOL_HIDING + uint32_t expected; + + CheckPtoN4(4 * 8, 0x01020304, "1.2.3.4"); + CheckPtoN4(4 * 8, 0x81010101, "129.1.1.1"); + CheckPtoN4(4 * 8, 0xC0010101, "192.1.1.1"); + CheckPtoN4(4 * 8, 0xE0010101, "224.1.1.1"); + CheckPtoN4(4 * 8, 0xE1010101, "225.1.1.1"); + CheckPtoN4(4, 0xE0000000, "224"); + CheckPtoN4(4 * 8, 0xFD000000, "253"); + CheckPtoN4(4 * 8, 0xF0010101, "240.1.1.1"); + CheckPtoN4(4 * 8, 0x02030405, "02.3.4.5"); + CheckPtoN4(3 * 8, 0x01020304, "1.2.3.4/24"); + CheckPtoN4(3 * 8, 0x01020300, "1.2.3/24"); + CheckPtoN4(2 * 8, 0xa0000000, "0xa"); + CheckPtoN4(0, 0x02030405, "2.3.4.5/000"); + CheckPtoN4(1 * 8, 0x01020000, "1.2/8"); + CheckPtoN4(2 * 8, 0x01020000, "0x0102/16"); + CheckPtoN4(4 * 8, 0x02030405, "02.3.4.5"); + + EXPECT_EQ(16 * 8, ares_inet_net_pton(AF_INET6, "::", &a6, sizeof(a6))); + EXPECT_EQ(16 * 8, ares_inet_net_pton(AF_INET6, "::1", &a6, sizeof(a6))); + EXPECT_EQ(16 * 8, ares_inet_net_pton(AF_INET6, "1234:5678::", &a6, sizeof(a6))); + EXPECT_EQ(16 * 8, ares_inet_net_pton(AF_INET6, "12:34::ff", &a6, sizeof(a6))); + EXPECT_EQ(16 * 8, ares_inet_net_pton(AF_INET6, "12:34::ffff:1.2.3.4", &a6, sizeof(a6))); + EXPECT_EQ(23, ares_inet_net_pton(AF_INET6, "12:34::ffff:1.2.3.4/23", &a6, sizeof(a6))); + EXPECT_EQ(3 * 8, ares_inet_net_pton(AF_INET6, "12:34::ff/24", &a6, sizeof(a6))); + EXPECT_EQ(0, ares_inet_net_pton(AF_INET6, "12:34::ff/0", &a6, sizeof(a6))); + EXPECT_EQ(16 * 8, ares_inet_net_pton(AF_INET6, "12:34::ffff:0.2", &a6, sizeof(a6))); + EXPECT_EQ(16 * 8, ares_inet_net_pton(AF_INET6, "1234:1234:1234:1234:1234:1234:1234:1234", &a6, sizeof(a6))); + + // Various malformed versions + EXPECT_EQ(-1, ares_inet_net_pton(AF_INET, "", &a4, sizeof(a4))); + EXPECT_EQ(-1, ares_inet_net_pton(AF_INET, " ", &a4, sizeof(a4))); + EXPECT_EQ(-1, ares_inet_net_pton(AF_INET, "0x", &a4, sizeof(a4))); + EXPECT_EQ(-1, ares_inet_net_pton(AF_INET, "0x ", &a4, sizeof(a4))); + EXPECT_EQ(-1, ares_inet_net_pton(AF_INET, "x0", &a4, sizeof(a4))); + EXPECT_EQ(-1, ares_inet_net_pton(AF_INET, "0xXYZZY", &a4, sizeof(a4))); + EXPECT_EQ(-1, ares_inet_net_pton(AF_INET, "xyzzy", &a4, sizeof(a4))); + EXPECT_EQ(-1, ares_inet_net_pton(AF_INET+AF_INET6, "1.2.3.4", &a4, sizeof(a4))); + EXPECT_EQ(-1, ares_inet_net_pton(AF_INET, "257.2.3.4", &a4, sizeof(a4))); + EXPECT_EQ(-1, ares_inet_net_pton(AF_INET, "002.3.4.x", &a4, sizeof(a4))); + EXPECT_EQ(-1, ares_inet_net_pton(AF_INET, "00.3.4.x", &a4, sizeof(a4))); + EXPECT_EQ(-1, ares_inet_net_pton(AF_INET, "2.3.4.x", &a4, sizeof(a4))); + EXPECT_EQ(-1, ares_inet_net_pton(AF_INET, "2.3.4.5.6", &a4, sizeof(a4))); + EXPECT_EQ(-1, ares_inet_net_pton(AF_INET, "2.3.4.5.6/12", &a4, sizeof(a4))); + EXPECT_EQ(-1, ares_inet_net_pton(AF_INET, "2.3.4:5", &a4, sizeof(a4))); + EXPECT_EQ(-1, ares_inet_net_pton(AF_INET, "2.3.4.5/120", &a4, sizeof(a4))); + EXPECT_EQ(-1, ares_inet_net_pton(AF_INET, "2.3.4.5/1x", &a4, sizeof(a4))); + EXPECT_EQ(-1, ares_inet_net_pton(AF_INET, "2.3.4.5/x", &a4, sizeof(a4))); + EXPECT_EQ(-1, ares_inet_net_pton(AF_INET6, "12:34::ff/240", &a6, sizeof(a6))); + EXPECT_EQ(-1, ares_inet_net_pton(AF_INET6, "12:34::ff/02", &a6, sizeof(a6))); + EXPECT_EQ(-1, ares_inet_net_pton(AF_INET6, "12:34::ff/2y", &a6, sizeof(a6))); + EXPECT_EQ(-1, ares_inet_net_pton(AF_INET6, "12:34::ff/y", &a6, sizeof(a6))); + EXPECT_EQ(-1, ares_inet_net_pton(AF_INET6, "12:34::ff/", &a6, sizeof(a6))); + EXPECT_EQ(-1, ares_inet_net_pton(AF_INET6, "", &a6, sizeof(a6))); + EXPECT_EQ(-1, ares_inet_net_pton(AF_INET6, ":x", &a6, sizeof(a6))); + EXPECT_EQ(-1, ares_inet_net_pton(AF_INET6, ":", &a6, sizeof(a6))); + EXPECT_EQ(-1, ares_inet_net_pton(AF_INET6, ": :1234", &a6, sizeof(a6))); + EXPECT_EQ(-1, ares_inet_net_pton(AF_INET6, "::12345", &a6, sizeof(a6))); + EXPECT_EQ(-1, ares_inet_net_pton(AF_INET6, "1234::2345:3456::0011", &a6, sizeof(a6))); + EXPECT_EQ(-1, ares_inet_net_pton(AF_INET6, "1234:1234:1234:1234:1234:1234:1234:1234:", &a6, sizeof(a6))); + EXPECT_EQ(-1, ares_inet_net_pton(AF_INET6, "1234:1234:1234:1234:1234:1234:1234:1234::", &a6, sizeof(a6))); + EXPECT_EQ(-1, ares_inet_net_pton(AF_INET6, "1234:1234:1234:1234:1234:1234:1234:1.2.3.4", &a6, sizeof(a6))); + EXPECT_EQ(-1, ares_inet_net_pton(AF_INET6, ":1234:1234:1234:1234:1234:1234:1234:1234", &a6, sizeof(a6))); + EXPECT_EQ(-1, ares_inet_net_pton(AF_INET6, ":1234:1234:1234:1234:1234:1234:1234:1234:", &a6, sizeof(a6))); + EXPECT_EQ(-1, ares_inet_net_pton(AF_INET6, "1234:1234:1234:1234:1234:1234:1234:1234:5678", &a6, sizeof(a6))); + // TODO(drysdale): check whether the next two tests should give -1. + EXPECT_EQ(0, ares_inet_net_pton(AF_INET6, "1234:1234:1234:1234:1234:1234:1234:1234:5678:5678", &a6, sizeof(a6))); + EXPECT_EQ(0, ares_inet_net_pton(AF_INET6, "1234:1234:1234:1234:1234:1234:1234:1234:5678:5678:5678", &a6, sizeof(a6))); + EXPECT_EQ(-1, ares_inet_net_pton(AF_INET6, "12:34::ffff:257.2.3.4", &a6, sizeof(a6))); + EXPECT_EQ(-1, ares_inet_net_pton(AF_INET6, "12:34::ffff:002.2.3.4", &a6, sizeof(a6))); + EXPECT_EQ(-1, ares_inet_net_pton(AF_INET6, "12:34::ffff:1.2.3.4.5.6", &a6, sizeof(a6))); + EXPECT_EQ(-1, ares_inet_net_pton(AF_INET6, "12:34::ffff:1.2.3.4.5", &a6, sizeof(a6))); + EXPECT_EQ(-1, ares_inet_net_pton(AF_INET6, "12:34::ffff:1.2.3.z", &a6, sizeof(a6))); + EXPECT_EQ(-1, ares_inet_net_pton(AF_INET6, "12:34::ffff:1.2.3001.4", &a6, sizeof(a6))); + EXPECT_EQ(-1, ares_inet_net_pton(AF_INET6, "12:34::ffff:1.2.3..4", &a6, sizeof(a6))); + EXPECT_EQ(-1, ares_inet_net_pton(AF_INET6, "12:34::ffff:1.2.3.", &a6, sizeof(a6))); + + // Hex constants are allowed. + EXPECT_EQ(4 * 8, ares_inet_net_pton(AF_INET, "0x01020304", &a4, sizeof(a4))); + expected = htonl(0x01020304); + EXPECT_EQ(expected, a4.s_addr); + EXPECT_EQ(4 * 8, ares_inet_net_pton(AF_INET, "0x0a0b0c0d", &a4, sizeof(a4))); + expected = htonl(0x0a0b0c0d); + EXPECT_EQ(expected, a4.s_addr); + EXPECT_EQ(4 * 8, ares_inet_net_pton(AF_INET, "0x0A0B0C0D", &a4, sizeof(a4))); + expected = htonl(0x0a0b0c0d); + EXPECT_EQ(expected, a4.s_addr); + EXPECT_EQ(-1, ares_inet_net_pton(AF_INET, "0x0xyz", &a4, sizeof(a4))); + EXPECT_EQ(4 * 8, ares_inet_net_pton(AF_INET, "0x1122334", &a4, sizeof(a4))); + expected = htonl(0x11223340); + EXPECT_EQ(expected, a4.s_addr); // huh? + + // No room, no room. + EXPECT_EQ(-1, ares_inet_net_pton(AF_INET, "1.2.3.4", &a4, sizeof(a4) - 1)); + EXPECT_EQ(-1, ares_inet_net_pton(AF_INET6, "12:34::ff", &a6, sizeof(a6) - 1)); + EXPECT_EQ(-1, ares_inet_net_pton(AF_INET, "0x01020304", &a4, 2)); + EXPECT_EQ(-1, ares_inet_net_pton(AF_INET, "0x01020304", &a4, 0)); + EXPECT_EQ(-1, ares_inet_net_pton(AF_INET, "0x0a0b0c0d", &a4, 0)); + EXPECT_EQ(-1, ares_inet_net_pton(AF_INET, "0x0xyz", &a4, 0)); + EXPECT_EQ(-1, ares_inet_net_pton(AF_INET, "0x1122334", &a4, sizeof(a4) - 1)); + EXPECT_EQ(-1, ares_inet_net_pton(AF_INET, "253", &a4, sizeof(a4) - 1)); +#endif + + EXPECT_EQ(1, ares_inet_pton(AF_INET, "1.2.3.4", &a4)); + EXPECT_EQ(1, ares_inet_pton(AF_INET6, "12:34::ff", &a6)); + EXPECT_EQ(1, ares_inet_pton(AF_INET6, "12:34::ffff:1.2.3.4", &a6)); + EXPECT_EQ(0, ares_inet_pton(AF_INET, "xyzzy", &a4)); + EXPECT_EQ(-1, ares_inet_pton(AF_INET+AF_INET6, "1.2.3.4", &a4)); +} + +TEST_F(LibraryTest, FreeCorruptData) { + // ares_free_data(p) expects that there is a type field and a marker + // field in the memory before p. Feed it incorrect versions of each. + struct ares_data *data = (struct ares_data *)malloc(sizeof(struct ares_data)); + void* p = &(data->data); + + // Invalid type + data->type = (ares_datatype)99; + data->mark = ARES_DATATYPE_MARK; + ares_free_data(p); + + // Invalid marker + data->type = (ares_datatype)ARES_DATATYPE_MX_REPLY; + data->mark = ARES_DATATYPE_MARK + 1; + ares_free_data(p); + + // Null pointer + ares_free_data(nullptr); + + free(data); +} + +#ifndef CARES_SYMBOL_HIDING +TEST_F(LibraryTest, FreeLongChain) { + struct ares_addr_node *data = nullptr; + for (int ii = 0; ii < 100000; ii++) { + struct ares_addr_node *prev = (struct ares_addr_node*)ares_malloc_data(ARES_DATATYPE_ADDR_NODE); + prev->next = data; + data = prev; + } + + ares_free_data(data); +} + +TEST(LibraryInit, StrdupFailures) { + EXPECT_EQ(ARES_SUCCESS, ares_library_init(ARES_LIB_INIT_ALL)); + char* copy = ares_strdup("string"); + EXPECT_NE(nullptr, copy); + ares_free(copy); + ares_library_cleanup(); +} + +TEST_F(LibraryTest, StrdupFailures) { + SetAllocFail(1); + char* copy = ares_strdup("string"); + EXPECT_EQ(nullptr, copy); +} + +TEST_F(LibraryTest, MallocDataFail) { + EXPECT_EQ(nullptr, ares_malloc_data((ares_datatype)99)); + SetAllocSizeFail(sizeof(struct ares_data)); + EXPECT_EQ(nullptr, ares_malloc_data(ARES_DATATYPE_MX_REPLY)); +} + +TEST(Misc, Bitncmp) { + byte a[4] = {0x80, 0x01, 0x02, 0x03}; + byte b[4] = {0x80, 0x01, 0x02, 0x04}; + byte c[4] = {0x01, 0xFF, 0x80, 0x02}; + EXPECT_GT(0, ares__bitncmp(a, b, sizeof(a)*8)); + EXPECT_LT(0, ares__bitncmp(b, a, sizeof(a)*8)); + EXPECT_EQ(0, ares__bitncmp(a, a, sizeof(a)*8)); + + for (int ii = 1; ii < (3*8+5); ii++) { + EXPECT_EQ(0, ares__bitncmp(a, b, ii)); + EXPECT_EQ(0, ares__bitncmp(b, a, ii)); + EXPECT_LT(0, ares__bitncmp(a, c, ii)); + EXPECT_GT(0, ares__bitncmp(c, a, ii)); + } + + // Last byte differs at 5th bit + EXPECT_EQ(0, ares__bitncmp(a, b, 3*8 + 3)); + EXPECT_EQ(0, ares__bitncmp(a, b, 3*8 + 4)); + EXPECT_EQ(0, ares__bitncmp(a, b, 3*8 + 5)); + EXPECT_GT(0, ares__bitncmp(a, b, 3*8 + 6)); + EXPECT_GT(0, ares__bitncmp(a, b, 3*8 + 7)); +} + +TEST_F(LibraryTest, Casts) { + ares_ssize_t ssz = 100; + unsigned int u = 100; + int i = 100; + long l = 100; + + unsigned int ru = aresx_sztoui(ssz); + EXPECT_EQ(u, ru); + int ri = aresx_sztosi(ssz); + EXPECT_EQ(i, ri); + + ri = aresx_sltosi(l); + EXPECT_EQ(l, (long)ri); +} + +TEST_F(LibraryTest, ReadLine) { + TempFile temp("abcde\n0123456789\nXYZ\n012345678901234567890\n\n"); + FILE *fp = fopen(temp.filename(), "r"); + size_t bufsize = 4; + char *buf = (char *)ares_malloc(bufsize); + + EXPECT_EQ(ARES_SUCCESS, ares__read_line(fp, &buf, &bufsize)); + EXPECT_EQ("abcde", std::string(buf)); + EXPECT_EQ(ARES_SUCCESS, ares__read_line(fp, &buf, &bufsize)); + EXPECT_EQ("0123456789", std::string(buf)); + EXPECT_EQ(ARES_SUCCESS, ares__read_line(fp, &buf, &bufsize)); + EXPECT_EQ("XYZ", std::string(buf)); + SetAllocFail(1); + EXPECT_EQ(ARES_ENOMEM, ares__read_line(fp, &buf, &bufsize)); + EXPECT_EQ(nullptr, buf); + + fclose(fp); + ares_free(buf); +} + +TEST_F(LibraryTest, ReadLineNoBuf) { + TempFile temp("abcde\n0123456789\nXYZ\n012345678901234567890"); + FILE *fp = fopen(temp.filename(), "r"); + size_t bufsize = 0; + char *buf = nullptr; + + SetAllocFail(1); + EXPECT_EQ(ARES_ENOMEM, ares__read_line(fp, &buf, &bufsize)); + + EXPECT_EQ(ARES_SUCCESS, ares__read_line(fp, &buf, &bufsize)); + EXPECT_EQ("abcde", std::string(buf)); + EXPECT_EQ(ARES_SUCCESS, ares__read_line(fp, &buf, &bufsize)); + EXPECT_EQ("0123456789", std::string(buf)); + EXPECT_EQ(ARES_SUCCESS, ares__read_line(fp, &buf, &bufsize)); + EXPECT_EQ("XYZ", std::string(buf)); + EXPECT_EQ(ARES_SUCCESS, ares__read_line(fp, &buf, &bufsize)); + EXPECT_EQ("012345678901234567890", std::string(buf)); + + fclose(fp); + ares_free(buf); +} + +TEST(Misc, GetHostent) { + TempFile hostsfile("1.2.3.4 example.com \n" + " 2.3.4.5\tgoogle.com www.google.com\twww2.google.com\n" + "#comment\n" + "4.5.6.7\n" + "1.3.5.7 \n" + "::1 ipv6.com"); + struct hostent *host = nullptr; + FILE *fp = fopen(hostsfile.filename(), "r"); + ASSERT_NE(nullptr, fp); + EXPECT_EQ(ARES_EBADFAMILY, ares__get_hostent(fp, AF_INET+AF_INET6, &host)); + rewind(fp); + + EXPECT_EQ(ARES_SUCCESS, ares__get_hostent(fp, AF_INET, &host)); + ASSERT_NE(nullptr, host); + std::stringstream ss1; + ss1 << HostEnt(host); + EXPECT_EQ("{'example.com' aliases=[] addrs=[1.2.3.4]}", ss1.str()); + ares_free_hostent(host); + host = nullptr; + + EXPECT_EQ(ARES_SUCCESS, ares__get_hostent(fp, AF_INET, &host)); + ASSERT_NE(nullptr, host); + std::stringstream ss2; + ss2 << HostEnt(host); + EXPECT_EQ("{'google.com' aliases=[www.google.com, www2.google.com] addrs=[2.3.4.5]}", ss2.str()); + ares_free_hostent(host); + host = nullptr; + + EXPECT_EQ(ARES_EOF, ares__get_hostent(fp, AF_INET, &host)); + + rewind(fp); + EXPECT_EQ(ARES_SUCCESS, ares__get_hostent(fp, AF_INET6, &host)); + ASSERT_NE(nullptr, host); + std::stringstream ss3; + ss3 << HostEnt(host); + EXPECT_EQ("{'ipv6.com' aliases=[] addrs=[0000:0000:0000:0000:0000:0000:0000:0001]}", ss3.str()); + ares_free_hostent(host); + host = nullptr; + EXPECT_EQ(ARES_EOF, ares__get_hostent(fp, AF_INET6, &host)); + fclose(fp); +} + +TEST_F(LibraryTest, GetHostentAllocFail) { + TempFile hostsfile("1.2.3.4 example.com alias1 alias2\n"); + struct hostent *host = nullptr; + FILE *fp = fopen(hostsfile.filename(), "r"); + ASSERT_NE(nullptr, fp); + + for (int ii = 1; ii <= 8; ii++) { + rewind(fp); + ClearFails(); + SetAllocFail(ii); + host = nullptr; + EXPECT_EQ(ARES_ENOMEM, ares__get_hostent(fp, AF_INET, &host)) << ii; + } + fclose(fp); +} + TEST_F(DefaultChannelTest, GetAddrInfoHostsPositive) { TempFile hostsfile("1.2.3.4 example.com \n" " 2.3.4.5\tgoogle.com www.google.com\twww2.google.com\n" @@ -457,135 +457,135 @@ TEST_F(LibraryTest, GetAddrInfoAllocFail) { fclose(fp); } -TEST(Misc, OnionDomain) { - EXPECT_EQ(0, ares__is_onion_domain("onion.no")); - EXPECT_EQ(0, ares__is_onion_domain(".onion.no")); - EXPECT_EQ(1, ares__is_onion_domain(".onion")); - EXPECT_EQ(1, ares__is_onion_domain(".onion.")); - EXPECT_EQ(1, ares__is_onion_domain("yes.onion")); - EXPECT_EQ(1, ares__is_onion_domain("yes.onion.")); - EXPECT_EQ(1, ares__is_onion_domain("YES.ONION")); - EXPECT_EQ(1, ares__is_onion_domain("YES.ONION.")); -} -#endif - -#ifdef CARES_EXPOSE_STATICS -// These tests access internal static functions from the library, which -// are only exposed when CARES_EXPOSE_STATICS has been configured. As such -// they are tightly couple to the internal library implementation details. -extern "C" char *ares_striendstr(const char*, const char*); -TEST_F(LibraryTest, Striendstr) { - EXPECT_EQ(nullptr, ares_striendstr("abc", "12345")); - EXPECT_NE(nullptr, ares_striendstr("abc12345", "12345")); - EXPECT_NE(nullptr, ares_striendstr("abcxyzzy", "XYZZY")); - EXPECT_NE(nullptr, ares_striendstr("xyzzy", "XYZZY")); - EXPECT_EQ(nullptr, ares_striendstr("xyxzy", "XYZZY")); - EXPECT_NE(nullptr, ares_striendstr("", "")); - const char *str = "plugh"; - EXPECT_NE(nullptr, ares_striendstr(str, str)); -} +TEST(Misc, OnionDomain) { + EXPECT_EQ(0, ares__is_onion_domain("onion.no")); + EXPECT_EQ(0, ares__is_onion_domain(".onion.no")); + EXPECT_EQ(1, ares__is_onion_domain(".onion")); + EXPECT_EQ(1, ares__is_onion_domain(".onion.")); + EXPECT_EQ(1, ares__is_onion_domain("yes.onion")); + EXPECT_EQ(1, ares__is_onion_domain("yes.onion.")); + EXPECT_EQ(1, ares__is_onion_domain("YES.ONION")); + EXPECT_EQ(1, ares__is_onion_domain("YES.ONION.")); +} +#endif + +#ifdef CARES_EXPOSE_STATICS +// These tests access internal static functions from the library, which +// are only exposed when CARES_EXPOSE_STATICS has been configured. As such +// they are tightly couple to the internal library implementation details. +extern "C" char *ares_striendstr(const char*, const char*); +TEST_F(LibraryTest, Striendstr) { + EXPECT_EQ(nullptr, ares_striendstr("abc", "12345")); + EXPECT_NE(nullptr, ares_striendstr("abc12345", "12345")); + EXPECT_NE(nullptr, ares_striendstr("abcxyzzy", "XYZZY")); + EXPECT_NE(nullptr, ares_striendstr("xyzzy", "XYZZY")); + EXPECT_EQ(nullptr, ares_striendstr("xyxzy", "XYZZY")); + EXPECT_NE(nullptr, ares_striendstr("", "")); + const char *str = "plugh"; + EXPECT_NE(nullptr, ares_striendstr(str, str)); +} extern "C" int ares__single_domain(ares_channel, const char*, char**); -TEST_F(DefaultChannelTest, SingleDomain) { - TempFile aliases("www www.google.com\n"); - EnvValue with_env("HOSTALIASES", aliases.filename()); - - SetAllocSizeFail(128); - char *ptr = nullptr; +TEST_F(DefaultChannelTest, SingleDomain) { + TempFile aliases("www www.google.com\n"); + EnvValue with_env("HOSTALIASES", aliases.filename()); + + SetAllocSizeFail(128); + char *ptr = nullptr; EXPECT_EQ(ARES_ENOMEM, ares__single_domain(channel_, "www", &ptr)); - - channel_->flags |= ARES_FLAG_NOSEARCH|ARES_FLAG_NOALIASES; + + channel_->flags |= ARES_FLAG_NOSEARCH|ARES_FLAG_NOALIASES; EXPECT_EQ(ARES_SUCCESS, ares__single_domain(channel_, "www", &ptr)); - EXPECT_EQ("www", std::string(ptr)); - ares_free(ptr); - ptr = nullptr; - - SetAllocFail(1); + EXPECT_EQ("www", std::string(ptr)); + ares_free(ptr); + ptr = nullptr; + + SetAllocFail(1); EXPECT_EQ(ARES_ENOMEM, ares__single_domain(channel_, "www", &ptr)); - EXPECT_EQ(nullptr, ptr); -} -#endif - -TEST_F(DefaultChannelTest, SaveInvalidChannel) { - int saved = channel_->nservers; - channel_->nservers = -1; - struct ares_options opts; - int optmask = 0; - EXPECT_EQ(ARES_ENODATA, ares_save_options(channel_, &opts, &optmask)); - channel_->nservers = saved; -} - -// Need to put this in own function due to nested lambda bug -// in VS2013. (C2888) -static int configure_socket(ares_socket_t s) { - // transposed from ares-process, simplified non-block setter. -#if defined(USE_BLOCKING_SOCKETS) - return 0; /* returns success */ -#elif defined(HAVE_FCNTL_O_NONBLOCK) - /* most recent unix versions */ - int flags; - flags = fcntl(s, F_GETFL, 0); - return fcntl(s, F_SETFL, flags | O_NONBLOCK); -#elif defined(HAVE_IOCTL_FIONBIO) - /* older unix versions */ - int flags = 1; - return ioctl(s, FIONBIO, &flags); -#elif defined(HAVE_IOCTLSOCKET_FIONBIO) -#ifdef WATT32 - char flags = 1; -#else - /* Windows */ - unsigned long flags = 1UL; -#endif - return ioctlsocket(s, FIONBIO, &flags); -#elif defined(HAVE_IOCTLSOCKET_CAMEL_FIONBIO) - /* Amiga */ - long flags = 1L; - return IoctlSocket(s, FIONBIO, flags); -#elif defined(HAVE_SETSOCKOPT_SO_NONBLOCK) - /* BeOS */ - long b = 1L; - return setsockopt(s, SOL_SOCKET, SO_NONBLOCK, &b, sizeof(b)); -#else -# error "no non-blocking method was found/used/set" -#endif -} - -// TODO: This should not really be in this file, but we need ares config -// flags, and here they are available. -const struct ares_socket_functions VirtualizeIO::default_functions = { - [](int af, int type, int protocol, void *) -> ares_socket_t { - auto s = ::socket(af, type, protocol); - if (s == ARES_SOCKET_BAD) { - return s; - } - if (configure_socket(s) != 0) { - sclose(s); - return ares_socket_t(-1); - } - return s; - }, - [](ares_socket_t s, void * p) { - return :: sclose(s); - }, - [](ares_socket_t s, const struct sockaddr * addr, socklen_t len, void *) { - return ::connect(s, addr, len); - }, - [](ares_socket_t s, void * dst, size_t len, int flags, struct sockaddr * addr, socklen_t * alen, void *) -> ares_ssize_t { -#ifdef HAVE_RECVFROM - return ::recvfrom(s, reinterpret_cast<RECV_TYPE_ARG2>(dst), len, flags, addr, alen); -#else - return sread(s, dst, len); -#endif - }, - [](ares_socket_t s, const struct iovec * vec, int len, void *) { + EXPECT_EQ(nullptr, ptr); +} +#endif + +TEST_F(DefaultChannelTest, SaveInvalidChannel) { + int saved = channel_->nservers; + channel_->nservers = -1; + struct ares_options opts; + int optmask = 0; + EXPECT_EQ(ARES_ENODATA, ares_save_options(channel_, &opts, &optmask)); + channel_->nservers = saved; +} + +// Need to put this in own function due to nested lambda bug +// in VS2013. (C2888) +static int configure_socket(ares_socket_t s) { + // transposed from ares-process, simplified non-block setter. +#if defined(USE_BLOCKING_SOCKETS) + return 0; /* returns success */ +#elif defined(HAVE_FCNTL_O_NONBLOCK) + /* most recent unix versions */ + int flags; + flags = fcntl(s, F_GETFL, 0); + return fcntl(s, F_SETFL, flags | O_NONBLOCK); +#elif defined(HAVE_IOCTL_FIONBIO) + /* older unix versions */ + int flags = 1; + return ioctl(s, FIONBIO, &flags); +#elif defined(HAVE_IOCTLSOCKET_FIONBIO) +#ifdef WATT32 + char flags = 1; +#else + /* Windows */ + unsigned long flags = 1UL; +#endif + return ioctlsocket(s, FIONBIO, &flags); +#elif defined(HAVE_IOCTLSOCKET_CAMEL_FIONBIO) + /* Amiga */ + long flags = 1L; + return IoctlSocket(s, FIONBIO, flags); +#elif defined(HAVE_SETSOCKOPT_SO_NONBLOCK) + /* BeOS */ + long b = 1L; + return setsockopt(s, SOL_SOCKET, SO_NONBLOCK, &b, sizeof(b)); +#else +# error "no non-blocking method was found/used/set" +#endif +} + +// TODO: This should not really be in this file, but we need ares config +// flags, and here they are available. +const struct ares_socket_functions VirtualizeIO::default_functions = { + [](int af, int type, int protocol, void *) -> ares_socket_t { + auto s = ::socket(af, type, protocol); + if (s == ARES_SOCKET_BAD) { + return s; + } + if (configure_socket(s) != 0) { + sclose(s); + return ares_socket_t(-1); + } + return s; + }, + [](ares_socket_t s, void * p) { + return :: sclose(s); + }, + [](ares_socket_t s, const struct sockaddr * addr, socklen_t len, void *) { + return ::connect(s, addr, len); + }, + [](ares_socket_t s, void * dst, size_t len, int flags, struct sockaddr * addr, socklen_t * alen, void *) -> ares_ssize_t { +#ifdef HAVE_RECVFROM + return ::recvfrom(s, reinterpret_cast<RECV_TYPE_ARG2>(dst), len, flags, addr, alen); +#else + return sread(s, dst, len); +#endif + }, + [](ares_socket_t s, const struct iovec * vec, int len, void *) { #ifndef HAVE_WRITEV - return ares_writev(s, vec, len); -#else - return :: writev(s, vec, len); -#endif - } -}; - - -} // namespace test -} // namespace ares + return ares_writev(s, vec, len); +#else + return :: writev(s, vec, len); +#endif + } +}; + + +} // namespace test +} // namespace ares diff --git a/contrib/libs/c-ares/test/ares-test-live.cc b/contrib/libs/c-ares/test/ares-test-live.cc index b5de37734e..5510163e95 100644 --- a/contrib/libs/c-ares/test/ares-test-live.cc +++ b/contrib/libs/c-ares/test/ares-test-live.cc @@ -1,23 +1,23 @@ -// This file includes tests that attempt to do real lookups -// of DNS names using the local machine's live infrastructure. -// As a result, we don't check the results very closely, to allow -// for varying local configurations. - -#include "ares-test.h" - -#ifdef HAVE_NETDB_H -#include <netdb.h> -#endif - -namespace ares { -namespace test { - -// Use the address of Google's public DNS servers as example addresses that are -// likely to be accessible everywhere/everywhen. -unsigned char gdns_addr4[4] = {0x08, 0x08, 0x08, 0x08}; -unsigned char gdns_addr6[16] = {0x20, 0x01, 0x48, 0x60, 0x48, 0x60, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x88}; - +// This file includes tests that attempt to do real lookups +// of DNS names using the local machine's live infrastructure. +// As a result, we don't check the results very closely, to allow +// for varying local configurations. + +#include "ares-test.h" + +#ifdef HAVE_NETDB_H +#include <netdb.h> +#endif + +namespace ares { +namespace test { + +// Use the address of Google's public DNS servers as example addresses that are +// likely to be accessible everywhere/everywhen. +unsigned char gdns_addr4[4] = {0x08, 0x08, 0x08, 0x08}; +unsigned char gdns_addr6[16] = {0x20, 0x01, 0x48, 0x60, 0x48, 0x60, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x88}; + MATCHER_P(IncludesAtLeastNumAddresses, n, "") { if(!arg) return false; @@ -82,620 +82,620 @@ MATCHER_P(IncludesAddrType, addrtype, "") { //EXPECT_THAT(result.ai_, IncludesAddrType(AF_INET)); //} -VIRT_NONVIRT_TEST_F(DefaultChannelTest, DISABLED_LiveGetHostByNameV4) { - HostResult result; - ares_gethostbyname(channel_, "www.google.com.", AF_INET, HostCallback, &result); - Process(); - EXPECT_TRUE(result.done_); - EXPECT_EQ(ARES_SUCCESS, result.status_); - EXPECT_LT(0, (int)result.host_.addrs_.size()); - EXPECT_EQ(AF_INET, result.host_.addrtype_); -} - -VIRT_NONVIRT_TEST_F(DefaultChannelTest, DISABLED_LiveGetHostByNameV6) { - HostResult result; - ares_gethostbyname(channel_, "www.google.com.", AF_INET6, HostCallback, &result); - Process(); - EXPECT_TRUE(result.done_); - EXPECT_EQ(ARES_SUCCESS, result.status_); - EXPECT_LT(0, (int)result.host_.addrs_.size()); - EXPECT_EQ(AF_INET6, result.host_.addrtype_); -} - -VIRT_NONVIRT_TEST_F(DefaultChannelTest, DISABLED_LiveGetHostByAddrV4) { - HostResult result; - ares_gethostbyaddr(channel_, gdns_addr4, sizeof(gdns_addr4), AF_INET, HostCallback, &result); - Process(); - EXPECT_TRUE(result.done_); - EXPECT_EQ(ARES_SUCCESS, result.status_); - EXPECT_LT(0, (int)result.host_.addrs_.size()); - EXPECT_EQ(AF_INET, result.host_.addrtype_); -} - -VIRT_NONVIRT_TEST_F(DefaultChannelTest, DISABLED_LiveGetHostByAddrV6) { - HostResult result; - ares_gethostbyaddr(channel_, gdns_addr6, sizeof(gdns_addr6), AF_INET6, HostCallback, &result); - Process(); - EXPECT_TRUE(result.done_); - EXPECT_EQ(ARES_SUCCESS, result.status_); - EXPECT_LT(0, (int)result.host_.addrs_.size()); - EXPECT_EQ(AF_INET6, result.host_.addrtype_); -} - -VIRT_NONVIRT_TEST_F(DefaultChannelTest, LiveGetHostByNameFile) { - struct hostent *host = nullptr; - - // Still need a channel even to query /etc/hosts. - EXPECT_EQ(ARES_ENOTFOUND, - ares_gethostbyname_file(nullptr, "localhost", AF_INET, &host)); - - int rc = ares_gethostbyname_file(channel_, "bogus.mcname", AF_INET, &host); - EXPECT_EQ(nullptr, host); - EXPECT_EQ(ARES_ENOTFOUND, rc); - - rc = ares_gethostbyname_file(channel_, "localhost", AF_INET, &host); - if (rc == ARES_SUCCESS) { - EXPECT_NE(nullptr, host); - ares_free_hostent(host); - } -} - -TEST_P(DefaultChannelModeTest, LiveGetLocalhostByNameV4) { - HostResult result; - ares_gethostbyname(channel_, "localhost", AF_INET, HostCallback, &result); - Process(); - EXPECT_TRUE(result.done_); - if ((result.status_ != ARES_ENOTFOUND) && (result.status_ != ARES_ECONNREFUSED)) { - EXPECT_EQ(ARES_SUCCESS, result.status_); - EXPECT_EQ(1, (int)result.host_.addrs_.size()); - EXPECT_EQ(AF_INET, result.host_.addrtype_); - EXPECT_NE(std::string::npos, result.host_.name_.find("localhost")); - } -} - -TEST_P(DefaultChannelModeTest, LiveGetLocalhostByNameV6) { - HostResult result; - ares_gethostbyname(channel_, "localhost", AF_INET6, HostCallback, &result); - Process(); - EXPECT_TRUE(result.done_); - if (result.status_ == ARES_SUCCESS) { - EXPECT_EQ(1, (int)result.host_.addrs_.size()); - EXPECT_EQ(AF_INET6, result.host_.addrtype_); - std::stringstream ss; - ss << HostEnt(result.host_); - EXPECT_NE(std::string::npos, result.host_.name_.find("localhost")); - } -} - -TEST_P(DefaultChannelModeTest, LiveGetLocalhostByNameIPV4) { - HostResult result; - ares_gethostbyname(channel_, "127.0.0.1", AF_INET, HostCallback, &result); - Process(); - EXPECT_TRUE(result.done_); - EXPECT_EQ(ARES_SUCCESS, result.status_); - EXPECT_EQ(1, (int)result.host_.addrs_.size()); - EXPECT_EQ(AF_INET, result.host_.addrtype_); - std::stringstream ss; - ss << HostEnt(result.host_); - EXPECT_EQ("{'127.0.0.1' aliases=[] addrs=[127.0.0.1]}", ss.str()); -} - -TEST_P(DefaultChannelModeTest, LiveGetLocalhostByNameIPV6) { - HostResult result; - ares_gethostbyname(channel_, "::1", AF_INET6, HostCallback, &result); - Process(); - EXPECT_TRUE(result.done_); - if (result.status_ != ARES_ENOTFOUND) { - EXPECT_EQ(ARES_SUCCESS, result.status_); - EXPECT_EQ(1, (int)result.host_.addrs_.size()); - EXPECT_EQ(AF_INET6, result.host_.addrtype_); - std::stringstream ss; - ss << HostEnt(result.host_); - EXPECT_EQ("{'::1' aliases=[] addrs=[0000:0000:0000:0000:0000:0000:0000:0001]}", ss.str()); - } -} - -TEST_P(DefaultChannelModeTest, LiveGetLocalhostFailFamily) { - HostResult result; - ares_gethostbyname(channel_, "127.0.0.1", AF_INET+AF_INET6, HostCallback, &result); - Process(); - EXPECT_TRUE(result.done_); - EXPECT_EQ(ARES_ENOTIMP, result.status_); -} - -TEST_P(DefaultChannelModeTest, LiveGetLocalhostByAddrV4) { - HostResult result; - struct in_addr addr; - addr.s_addr = htonl(INADDR_LOOPBACK); - ares_gethostbyaddr(channel_, &addr, sizeof(addr), AF_INET, HostCallback, &result); - Process(); - EXPECT_TRUE(result.done_); - if (result.status_ != ARES_ENOTFOUND) { - EXPECT_EQ(ARES_SUCCESS, result.status_); - EXPECT_LT(0, (int)result.host_.addrs_.size()); - EXPECT_EQ(AF_INET, result.host_.addrtype_); +VIRT_NONVIRT_TEST_F(DefaultChannelTest, DISABLED_LiveGetHostByNameV4) { + HostResult result; + ares_gethostbyname(channel_, "www.google.com.", AF_INET, HostCallback, &result); + Process(); + EXPECT_TRUE(result.done_); + EXPECT_EQ(ARES_SUCCESS, result.status_); + EXPECT_LT(0, (int)result.host_.addrs_.size()); + EXPECT_EQ(AF_INET, result.host_.addrtype_); +} + +VIRT_NONVIRT_TEST_F(DefaultChannelTest, DISABLED_LiveGetHostByNameV6) { + HostResult result; + ares_gethostbyname(channel_, "www.google.com.", AF_INET6, HostCallback, &result); + Process(); + EXPECT_TRUE(result.done_); + EXPECT_EQ(ARES_SUCCESS, result.status_); + EXPECT_LT(0, (int)result.host_.addrs_.size()); + EXPECT_EQ(AF_INET6, result.host_.addrtype_); +} + +VIRT_NONVIRT_TEST_F(DefaultChannelTest, DISABLED_LiveGetHostByAddrV4) { + HostResult result; + ares_gethostbyaddr(channel_, gdns_addr4, sizeof(gdns_addr4), AF_INET, HostCallback, &result); + Process(); + EXPECT_TRUE(result.done_); + EXPECT_EQ(ARES_SUCCESS, result.status_); + EXPECT_LT(0, (int)result.host_.addrs_.size()); + EXPECT_EQ(AF_INET, result.host_.addrtype_); +} + +VIRT_NONVIRT_TEST_F(DefaultChannelTest, DISABLED_LiveGetHostByAddrV6) { + HostResult result; + ares_gethostbyaddr(channel_, gdns_addr6, sizeof(gdns_addr6), AF_INET6, HostCallback, &result); + Process(); + EXPECT_TRUE(result.done_); + EXPECT_EQ(ARES_SUCCESS, result.status_); + EXPECT_LT(0, (int)result.host_.addrs_.size()); + EXPECT_EQ(AF_INET6, result.host_.addrtype_); +} + +VIRT_NONVIRT_TEST_F(DefaultChannelTest, LiveGetHostByNameFile) { + struct hostent *host = nullptr; + + // Still need a channel even to query /etc/hosts. + EXPECT_EQ(ARES_ENOTFOUND, + ares_gethostbyname_file(nullptr, "localhost", AF_INET, &host)); + + int rc = ares_gethostbyname_file(channel_, "bogus.mcname", AF_INET, &host); + EXPECT_EQ(nullptr, host); + EXPECT_EQ(ARES_ENOTFOUND, rc); + + rc = ares_gethostbyname_file(channel_, "localhost", AF_INET, &host); + if (rc == ARES_SUCCESS) { + EXPECT_NE(nullptr, host); + ares_free_hostent(host); + } +} + +TEST_P(DefaultChannelModeTest, LiveGetLocalhostByNameV4) { + HostResult result; + ares_gethostbyname(channel_, "localhost", AF_INET, HostCallback, &result); + Process(); + EXPECT_TRUE(result.done_); + if ((result.status_ != ARES_ENOTFOUND) && (result.status_ != ARES_ECONNREFUSED)) { + EXPECT_EQ(ARES_SUCCESS, result.status_); + EXPECT_EQ(1, (int)result.host_.addrs_.size()); + EXPECT_EQ(AF_INET, result.host_.addrtype_); + EXPECT_NE(std::string::npos, result.host_.name_.find("localhost")); + } +} + +TEST_P(DefaultChannelModeTest, LiveGetLocalhostByNameV6) { + HostResult result; + ares_gethostbyname(channel_, "localhost", AF_INET6, HostCallback, &result); + Process(); + EXPECT_TRUE(result.done_); + if (result.status_ == ARES_SUCCESS) { + EXPECT_EQ(1, (int)result.host_.addrs_.size()); + EXPECT_EQ(AF_INET6, result.host_.addrtype_); + std::stringstream ss; + ss << HostEnt(result.host_); + EXPECT_NE(std::string::npos, result.host_.name_.find("localhost")); + } +} + +TEST_P(DefaultChannelModeTest, LiveGetLocalhostByNameIPV4) { + HostResult result; + ares_gethostbyname(channel_, "127.0.0.1", AF_INET, HostCallback, &result); + Process(); + EXPECT_TRUE(result.done_); + EXPECT_EQ(ARES_SUCCESS, result.status_); + EXPECT_EQ(1, (int)result.host_.addrs_.size()); + EXPECT_EQ(AF_INET, result.host_.addrtype_); + std::stringstream ss; + ss << HostEnt(result.host_); + EXPECT_EQ("{'127.0.0.1' aliases=[] addrs=[127.0.0.1]}", ss.str()); +} + +TEST_P(DefaultChannelModeTest, LiveGetLocalhostByNameIPV6) { + HostResult result; + ares_gethostbyname(channel_, "::1", AF_INET6, HostCallback, &result); + Process(); + EXPECT_TRUE(result.done_); + if (result.status_ != ARES_ENOTFOUND) { + EXPECT_EQ(ARES_SUCCESS, result.status_); + EXPECT_EQ(1, (int)result.host_.addrs_.size()); + EXPECT_EQ(AF_INET6, result.host_.addrtype_); + std::stringstream ss; + ss << HostEnt(result.host_); + EXPECT_EQ("{'::1' aliases=[] addrs=[0000:0000:0000:0000:0000:0000:0000:0001]}", ss.str()); + } +} + +TEST_P(DefaultChannelModeTest, LiveGetLocalhostFailFamily) { + HostResult result; + ares_gethostbyname(channel_, "127.0.0.1", AF_INET+AF_INET6, HostCallback, &result); + Process(); + EXPECT_TRUE(result.done_); + EXPECT_EQ(ARES_ENOTIMP, result.status_); +} + +TEST_P(DefaultChannelModeTest, LiveGetLocalhostByAddrV4) { + HostResult result; + struct in_addr addr; + addr.s_addr = htonl(INADDR_LOOPBACK); + ares_gethostbyaddr(channel_, &addr, sizeof(addr), AF_INET, HostCallback, &result); + Process(); + EXPECT_TRUE(result.done_); + if (result.status_ != ARES_ENOTFOUND) { + EXPECT_EQ(ARES_SUCCESS, result.status_); + EXPECT_LT(0, (int)result.host_.addrs_.size()); + EXPECT_EQ(AF_INET, result.host_.addrtype_); // oddly, travis does not resolve to localhost, but a random hostname starting with travis-job if (result.host_.name_.find("travis-job") == std::string::npos) { EXPECT_NE(std::string::npos, result.host_.name_.find("localhost")); } - } -} - -TEST_P(DefaultChannelModeTest, LiveGetLocalhostByAddrV6) { - HostResult result; - struct in6_addr addr; - memset(&addr, 0, sizeof(addr)); - addr.s6_addr[15] = 1; // in6addr_loopback - ares_gethostbyaddr(channel_, &addr, sizeof(addr), AF_INET6, HostCallback, &result); - Process(); - EXPECT_TRUE(result.done_); - if (result.status_ != ARES_ENOTFOUND) { - EXPECT_EQ(ARES_SUCCESS, result.status_); - EXPECT_LT(0, (int)result.host_.addrs_.size()); - EXPECT_EQ(AF_INET6, result.host_.addrtype_); + } +} + +TEST_P(DefaultChannelModeTest, LiveGetLocalhostByAddrV6) { + HostResult result; + struct in6_addr addr; + memset(&addr, 0, sizeof(addr)); + addr.s6_addr[15] = 1; // in6addr_loopback + ares_gethostbyaddr(channel_, &addr, sizeof(addr), AF_INET6, HostCallback, &result); + Process(); + EXPECT_TRUE(result.done_); + if (result.status_ != ARES_ENOTFOUND) { + EXPECT_EQ(ARES_SUCCESS, result.status_); + EXPECT_LT(0, (int)result.host_.addrs_.size()); + EXPECT_EQ(AF_INET6, result.host_.addrtype_); const std::string& name = result.host_.name_; EXPECT_TRUE(std::string::npos != name.find("localhost") || std::string::npos != name.find("ip6-loopback")); - } -} - -TEST_P(DefaultChannelModeTest, LiveGetHostByAddrFailFamily) { - HostResult result; - unsigned char addr[4] = {8, 8, 8, 8}; - ares_gethostbyaddr(channel_, addr, sizeof(addr), AF_INET6+AF_INET, - HostCallback, &result); - EXPECT_TRUE(result.done_); - EXPECT_EQ(ARES_ENOTIMP, result.status_); -} - -TEST_P(DefaultChannelModeTest, LiveGetHostByAddrFailAddrSize) { - HostResult result; - unsigned char addr[4] = {8, 8, 8, 8}; - ares_gethostbyaddr(channel_, addr, sizeof(addr) - 1, AF_INET, - HostCallback, &result); - EXPECT_TRUE(result.done_); - EXPECT_EQ(ARES_ENOTIMP, result.status_); -} - -TEST_P(DefaultChannelModeTest, LiveGetHostByAddrFailAlloc) { - HostResult result; - unsigned char addr[4] = {8, 8, 8, 8}; - SetAllocFail(1); - ares_gethostbyaddr(channel_, addr, sizeof(addr), AF_INET, - HostCallback, &result); - EXPECT_TRUE(result.done_); - EXPECT_EQ(ARES_ENOMEM, result.status_); -} - -INSTANTIATE_TEST_CASE_P(Modes, DefaultChannelModeTest, - ::testing::Values("f", "b", "fb", "bf")); - -VIRT_NONVIRT_TEST_F(DefaultChannelTest, DISABLED_LiveSearchA) { - SearchResult result; - ares_search(channel_, "www.youtube.com.", ns_c_in, ns_t_a, - SearchCallback, &result); - Process(); - EXPECT_TRUE(result.done_); - EXPECT_EQ(ARES_SUCCESS, result.status_); -} - -VIRT_NONVIRT_TEST_F(DefaultChannelTest, LiveSearchEmptyA) { - SearchResult result; - ares_search(channel_, "", ns_c_in, ns_t_a, - SearchCallback, &result); - Process(); - EXPECT_TRUE(result.done_); - EXPECT_NE(ARES_SUCCESS, result.status_); -} - -VIRT_NONVIRT_TEST_F(DefaultChannelTest, DISABLED_LiveSearchNS) { - SearchResult result; - ares_search(channel_, "google.com.", ns_c_in, ns_t_ns, - SearchCallback, &result); - Process(); - EXPECT_TRUE(result.done_); - EXPECT_EQ(ARES_SUCCESS, result.status_); -} - -VIRT_NONVIRT_TEST_F(DefaultChannelTest, DISABLED_LiveSearchMX) { - SearchResult result; - ares_search(channel_, "google.com.", ns_c_in, ns_t_mx, - SearchCallback, &result); - Process(); - EXPECT_TRUE(result.done_); - EXPECT_EQ(ARES_SUCCESS, result.status_); -} - -VIRT_NONVIRT_TEST_F(DefaultChannelTest, DISABLED_LiveSearchTXT) { - SearchResult result; - ares_search(channel_, "google.com.", ns_c_in, ns_t_txt, - SearchCallback, &result); - Process(); - EXPECT_TRUE(result.done_); - EXPECT_EQ(ARES_SUCCESS, result.status_); -} - -VIRT_NONVIRT_TEST_F(DefaultChannelTest, DISABLED_LiveSearchSOA) { - SearchResult result; - ares_search(channel_, "google.com.", ns_c_in, ns_t_soa, - SearchCallback, &result); - Process(); - EXPECT_TRUE(result.done_); - EXPECT_EQ(ARES_SUCCESS, result.status_); -} - -VIRT_NONVIRT_TEST_F(DefaultChannelTest, DISABLED_LiveSearchSRV) { - SearchResult result; - ares_search(channel_, "_imap._tcp.gmail.com.", ns_c_in, ns_t_srv, - SearchCallback, &result); - Process(); - EXPECT_TRUE(result.done_); - EXPECT_EQ(ARES_SUCCESS, result.status_); -} - -VIRT_NONVIRT_TEST_F(DefaultChannelTest, DISABLED_LiveSearchANY) { - SearchResult result; - ares_search(channel_, "google.com.", ns_c_in, ns_t_any, - SearchCallback, &result); - Process(); - EXPECT_TRUE(result.done_); - EXPECT_EQ(ARES_SUCCESS, result.status_); -} - -VIRT_NONVIRT_TEST_F(DefaultChannelTest, LiveGetNameInfoV4) { - NameInfoResult result; - struct sockaddr_in sockaddr; - memset(&sockaddr, 0, sizeof(sockaddr)); - sockaddr.sin_family = AF_INET; - sockaddr.sin_port = htons(53); - sockaddr.sin_addr.s_addr = htonl(0x08080808); - ares_getnameinfo(channel_, (const struct sockaddr*)&sockaddr, sizeof(sockaddr), - ARES_NI_LOOKUPHOST|ARES_NI_LOOKUPSERVICE|ARES_NI_UDP, - NameInfoCallback, &result); - Process(); - EXPECT_TRUE(result.done_); - EXPECT_EQ(ARES_SUCCESS, result.status_); - if (verbose) std::cerr << "8.8.8.8:53 => " << result.node_ << "/" << result.service_ << std::endl; -} - -VIRT_NONVIRT_TEST_F(DefaultChannelTest, LiveGetNameInfoV4NoPort) { - NameInfoResult result; - struct sockaddr_in sockaddr; - memset(&sockaddr, 0, sizeof(sockaddr)); - sockaddr.sin_family = AF_INET; - sockaddr.sin_port = htons(0); - sockaddr.sin_addr.s_addr = htonl(0x08080808); - ares_getnameinfo(channel_, (const struct sockaddr*)&sockaddr, sizeof(sockaddr), - ARES_NI_LOOKUPHOST|ARES_NI_LOOKUPSERVICE|ARES_NI_UDP, - NameInfoCallback, &result); - Process(); - EXPECT_TRUE(result.done_); - EXPECT_EQ(ARES_SUCCESS, result.status_); - if (verbose) std::cerr << "8.8.8.8:0 => " << result.node_ << "/" << result.service_ << std::endl; -} - -VIRT_NONVIRT_TEST_F(DefaultChannelTest, LiveGetNameInfoV4UnassignedPort) { - NameInfoResult result; - struct sockaddr_in sockaddr; - memset(&sockaddr, 0, sizeof(sockaddr)); - sockaddr.sin_family = AF_INET; - sockaddr.sin_port = htons(4); // Unassigned at IANA - sockaddr.sin_addr.s_addr = htonl(0x08080808); - ares_getnameinfo(channel_, (const struct sockaddr*)&sockaddr, sizeof(sockaddr), - ARES_NI_LOOKUPHOST|ARES_NI_LOOKUPSERVICE|ARES_NI_UDP, - NameInfoCallback, &result); - Process(); - EXPECT_TRUE(result.done_); - EXPECT_EQ(ARES_SUCCESS, result.status_); - if (verbose) std::cerr << "8.8.8.8:4 => " << result.node_ << "/" << result.service_ << std::endl; -} - -VIRT_NONVIRT_TEST_F(DefaultChannelTest, LiveGetNameInfoV6Both) { - NameInfoResult result; - struct sockaddr_in6 sockaddr; - memset(&sockaddr, 0, sizeof(sockaddr)); - sockaddr.sin6_family = AF_INET6; - sockaddr.sin6_port = htons(53); - memcpy(sockaddr.sin6_addr.s6_addr, gdns_addr6, 16); - ares_getnameinfo(channel_, (const struct sockaddr*)&sockaddr, sizeof(sockaddr), - ARES_NI_TCP|ARES_NI_LOOKUPHOST|ARES_NI_LOOKUPSERVICE|ARES_NI_NOFQDN, - NameInfoCallback, &result); - Process(); - EXPECT_TRUE(result.done_); - EXPECT_EQ(ARES_SUCCESS, result.status_); - if (verbose) std::cerr << "[2001:4860:4860::8888]:53 => " << result.node_ << "/" << result.service_ << std::endl; -} - -VIRT_NONVIRT_TEST_F(DefaultChannelTest, LiveGetNameInfoV6Neither) { - NameInfoResult result; - struct sockaddr_in6 sockaddr; - memset(&sockaddr, 0, sizeof(sockaddr)); - sockaddr.sin6_family = AF_INET6; - sockaddr.sin6_port = htons(53); - memcpy(sockaddr.sin6_addr.s6_addr, gdns_addr6, 16); - ares_getnameinfo(channel_, (const struct sockaddr*)&sockaddr, sizeof(sockaddr), - ARES_NI_TCP|ARES_NI_NOFQDN, // Neither specified => assume lookup host. - NameInfoCallback, &result); - Process(); - EXPECT_TRUE(result.done_); - EXPECT_EQ(ARES_SUCCESS, result.status_); - if (verbose) std::cerr << "[2001:4860:4860::8888]:53 => " << result.node_ << "/" << result.service_ << std::endl; -} - -VIRT_NONVIRT_TEST_F(DefaultChannelTest, LiveGetNameInfoV4Numeric) { - NameInfoResult result; - struct sockaddr_in sockaddr; - memset(&sockaddr, 0, sizeof(sockaddr)); - sockaddr.sin_family = AF_INET; - sockaddr.sin_port = htons(53); - sockaddr.sin_addr.s_addr = htonl(0x08080808); - ares_getnameinfo(channel_, (const struct sockaddr*)&sockaddr, sizeof(sockaddr), - ARES_NI_LOOKUPHOST|ARES_NI_LOOKUPSERVICE|ARES_NI_TCP|ARES_NI_NUMERICHOST, - NameInfoCallback, &result); - Process(); - EXPECT_TRUE(result.done_); - EXPECT_EQ(ARES_SUCCESS, result.status_); - EXPECT_EQ("8.8.8.8", result.node_); - if (verbose) std::cerr << "8.8.8.8:53 => " << result.node_ << "/" << result.service_ << std::endl; -} - -VIRT_NONVIRT_TEST_F(DefaultChannelTest, LiveGetNameInfoV6Numeric) { - NameInfoResult result; - struct sockaddr_in6 sockaddr; - memset(&sockaddr, 0, sizeof(sockaddr)); - sockaddr.sin6_family = AF_INET6; - sockaddr.sin6_port = htons(53); - memcpy(sockaddr.sin6_addr.s6_addr, gdns_addr6, 16); - ares_getnameinfo(channel_, (const struct sockaddr*)&sockaddr, sizeof(sockaddr), - ARES_NI_LOOKUPHOST|ARES_NI_LOOKUPSERVICE|ARES_NI_DCCP|ARES_NI_NUMERICHOST, - NameInfoCallback, &result); - Process(); - EXPECT_TRUE(result.done_); - EXPECT_EQ(ARES_SUCCESS, result.status_); - EXPECT_EQ("2001:4860:4860::8888%0", result.node_); - if (verbose) std::cerr << "[2001:4860:4860::8888]:53 => " << result.node_ << "/" << result.service_ << std::endl; -} - -VIRT_NONVIRT_TEST_F(DefaultChannelTest, LiveGetNameInfoV6LinkLocal) { - NameInfoResult result; - struct sockaddr_in6 sockaddr; - memset(&sockaddr, 0, sizeof(sockaddr)); - sockaddr.sin6_family = AF_INET6; - sockaddr.sin6_port = htons(53); - unsigned char addr6[16] = {0xfe, 0x80, 0x01, 0x02, 0x01, 0x02, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x04}; - memcpy(sockaddr.sin6_addr.s6_addr, addr6, 16); - ares_getnameinfo(channel_, (const struct sockaddr*)&sockaddr, sizeof(sockaddr), - ARES_NI_LOOKUPHOST|ARES_NI_LOOKUPSERVICE|ARES_NI_DCCP|ARES_NI_NUMERICHOST, - NameInfoCallback, &result); - Process(); - EXPECT_TRUE(result.done_); - EXPECT_EQ(ARES_SUCCESS, result.status_); - EXPECT_EQ("fe80:102:102::304%0", result.node_); - if (verbose) std::cerr << "[fe80:102:102::304]:53 => " << result.node_ << "/" << result.service_ << std::endl; -} - -VIRT_NONVIRT_TEST_F(DefaultChannelTest, LiveGetNameInfoV4NotFound) { - NameInfoResult result; - struct sockaddr_in sockaddr; - memset(&sockaddr, 0, sizeof(sockaddr)); - sockaddr.sin_family = AF_INET; - sockaddr.sin_port = htons(4); // Port 4 unassigned at IANA - // RFC5737 says 192.0.2.0 should not be used publically. - sockaddr.sin_addr.s_addr = htonl(0xC0000200); - ares_getnameinfo(channel_, (const struct sockaddr*)&sockaddr, sizeof(sockaddr), - ARES_NI_LOOKUPHOST|ARES_NI_LOOKUPSERVICE|ARES_NI_UDP, - NameInfoCallback, &result); - Process(); - EXPECT_TRUE(result.done_); - EXPECT_EQ(ARES_SUCCESS, result.status_); - EXPECT_EQ("192.0.2.0", result.node_); - if (verbose) std::cerr << "192.0.2.0:53 => " << result.node_ << "/" << result.service_ << std::endl; -} - -VIRT_NONVIRT_TEST_F(DefaultChannelTest, LiveGetNameInfoV4NotFoundFail) { - NameInfoResult result; - struct sockaddr_in sockaddr; - memset(&sockaddr, 0, sizeof(sockaddr)); - sockaddr.sin_family = AF_INET; - sockaddr.sin_port = htons(53); - // RFC5737 says 192.0.2.0 should not be used publically. - sockaddr.sin_addr.s_addr = htonl(0xC0000200); - ares_getnameinfo(channel_, (const struct sockaddr*)&sockaddr, sizeof(sockaddr), - ARES_NI_LOOKUPHOST|ARES_NI_LOOKUPSERVICE|ARES_NI_UDP|ARES_NI_NAMEREQD, - NameInfoCallback, &result); - Process(); - EXPECT_TRUE(result.done_); - EXPECT_EQ(ARES_ENOTFOUND, result.status_); -} - -VIRT_NONVIRT_TEST_F(DefaultChannelTest, LiveGetNameInfoV6NotFound) { - NameInfoResult result; - struct sockaddr_in6 sockaddr; - memset(&sockaddr, 0, sizeof(sockaddr)); - sockaddr.sin6_family = AF_INET6; - sockaddr.sin6_port = htons(53); - // 2001:db8::/32 is only supposed to be used in documentation. - unsigned char addr6[16] = {0x20, 0x01, 0x0d, 0xb8, 0x01, 0x02, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x04}; - memcpy(sockaddr.sin6_addr.s6_addr, addr6, 16); - ares_getnameinfo(channel_, (const struct sockaddr*)&sockaddr, sizeof(sockaddr), - ARES_NI_LOOKUPHOST|ARES_NI_LOOKUPSERVICE|ARES_NI_UDP, - NameInfoCallback, &result); - Process(); - EXPECT_TRUE(result.done_); - EXPECT_EQ(ARES_SUCCESS, result.status_); - EXPECT_EQ("2001:db8:102::304%0", result.node_); - if (verbose) std::cerr << "[2001:db8:102::304]:53 => " << result.node_ << "/" << result.service_ << std::endl; -} - -VIRT_NONVIRT_TEST_F(DefaultChannelTest, LiveGetNameInvalidFamily) { - NameInfoResult result; - struct sockaddr_in6 sockaddr; - memset(&sockaddr, 0, sizeof(sockaddr)); - sockaddr.sin6_family = AF_INET6 + AF_INET; - sockaddr.sin6_port = htons(53); - memcpy(sockaddr.sin6_addr.s6_addr, gdns_addr6, 16); - ares_getnameinfo(channel_, (const struct sockaddr*)&sockaddr, sizeof(sockaddr), - ARES_NI_LOOKUPHOST|ARES_NI_LOOKUPSERVICE|ARES_NI_UDP, - NameInfoCallback, &result); - Process(); - EXPECT_TRUE(result.done_); - EXPECT_EQ(ARES_ENOTIMP, result.status_); -} - -VIRT_NONVIRT_TEST_F(DefaultChannelTest, LiveGetNameInvalidFlags) { - NameInfoResult result; - struct sockaddr_in6 sockaddr; - memset(&sockaddr, 0, sizeof(sockaddr)); - sockaddr.sin6_family = AF_INET6; - sockaddr.sin6_port = htons(53); - memcpy(sockaddr.sin6_addr.s6_addr, gdns_addr6, 16); - // Ask for both a name-required, and a numeric host. - ares_getnameinfo(channel_, (const struct sockaddr*)&sockaddr, sizeof(sockaddr), - ARES_NI_LOOKUPHOST|ARES_NI_LOOKUPSERVICE|ARES_NI_UDP|ARES_NI_NUMERICHOST|ARES_NI_NAMEREQD, - NameInfoCallback, &result); - Process(); - EXPECT_TRUE(result.done_); - EXPECT_EQ(ARES_EBADFLAGS, result.status_); -} - -VIRT_NONVIRT_TEST_F(DefaultChannelTest, LiveGetServiceInfo) { - NameInfoResult result; - struct sockaddr_in sockaddr; - memset(&sockaddr, 0, sizeof(sockaddr)); - sockaddr.sin_family = AF_INET; - sockaddr.sin_port = htons(53); - sockaddr.sin_addr.s_addr = htonl(0x08080808); - // Just look up service info - ares_getnameinfo(channel_, (const struct sockaddr*)&sockaddr, sizeof(sockaddr), - ARES_NI_LOOKUPSERVICE|ARES_NI_SCTP, - NameInfoCallback, &result); - Process(); - EXPECT_TRUE(result.done_); - EXPECT_EQ(ARES_SUCCESS, result.status_); - EXPECT_EQ("", result.node_); -} - -VIRT_NONVIRT_TEST_F(DefaultChannelTest, LiveGetServiceInfoNumeric) { - NameInfoResult result; - struct sockaddr_in sockaddr; - memset(&sockaddr, 0, sizeof(sockaddr)); - sockaddr.sin_family = AF_INET; - sockaddr.sin_port = htons(53); - sockaddr.sin_addr.s_addr = htonl(0x08080808); - // Just look up service info - ares_getnameinfo(channel_, (const struct sockaddr*)&sockaddr, sizeof(sockaddr), - ARES_NI_LOOKUPSERVICE|ARES_NI_SCTP|ARES_NI_NUMERICSERV, - NameInfoCallback, &result); - Process(); - EXPECT_TRUE(result.done_); - EXPECT_EQ(ARES_SUCCESS, result.status_); - EXPECT_EQ("", result.node_); - EXPECT_EQ("53", result.service_); -} - -VIRT_NONVIRT_TEST_F(DefaultChannelTest, LiveGetNameInfoAllocFail) { - NameInfoResult result; - struct sockaddr_in sockaddr; - memset(&sockaddr, 0, sizeof(sockaddr)); - sockaddr.sin_family = AF_INET; - sockaddr.sin_port = htons(53); - sockaddr.sin_addr.s_addr = htonl(0x08080808); - SetAllocFail(1); - ares_getnameinfo(channel_, (const struct sockaddr*)&sockaddr, sizeof(sockaddr), - ARES_NI_LOOKUPHOST|ARES_NI_LOOKUPSERVICE|ARES_NI_UDP, - NameInfoCallback, &result); - Process(); - EXPECT_TRUE(result.done_); - EXPECT_EQ(ARES_ENOMEM, result.status_); -} - -VIRT_NONVIRT_TEST_F(DefaultChannelTest, DISABLED_GetSock) { - ares_socket_t socks[3] = {ARES_SOCKET_BAD, ARES_SOCKET_BAD, ARES_SOCKET_BAD}; - int bitmask = ares_getsock(channel_, socks, 3); - EXPECT_EQ(0, bitmask); - bitmask = ares_getsock(channel_, nullptr, 0); - EXPECT_EQ(0, bitmask); - - // Ask again with a pending query. - HostResult result; - ares_gethostbyname(channel_, "www.google.com.", AF_INET, HostCallback, &result); - bitmask = ares_getsock(channel_, socks, 3); - EXPECT_NE(0, bitmask); - bitmask = ares_getsock(channel_, nullptr, 0); - EXPECT_EQ(0, bitmask); - - Process(); -} - -TEST_F(LibraryTest, DISABLED_GetTCPSock) { - ares_channel channel; - struct ares_options opts = {0}; - opts.tcp_port = 53; - opts.flags = ARES_FLAG_USEVC; - int optmask = ARES_OPT_TCP_PORT | ARES_OPT_FLAGS; - EXPECT_EQ(ARES_SUCCESS, ares_init_options(&channel, &opts, optmask)); - EXPECT_NE(nullptr, channel); - - ares_socket_t socks[3] = {ARES_SOCKET_BAD, ARES_SOCKET_BAD, ARES_SOCKET_BAD}; - int bitmask = ares_getsock(channel, socks, 3); - EXPECT_EQ(0, bitmask); - bitmask = ares_getsock(channel, nullptr, 0); - EXPECT_EQ(0, bitmask); - - // Ask again with a pending query. - HostResult result; - ares_gethostbyname(channel, "www.google.com.", AF_INET, HostCallback, &result); - bitmask = ares_getsock(channel, socks, 3); - EXPECT_NE(0, bitmask); - bitmask = ares_getsock(channel, nullptr, 0); - EXPECT_EQ(0, bitmask); - - ProcessWork(channel, NoExtraFDs, nullptr); - - ares_destroy(channel); -} - -TEST_F(DefaultChannelTest, VerifySocketFunctionCallback) { - VirtualizeIO vio(channel_); - - auto my_functions = VirtualizeIO::default_functions; - size_t count = 0; - - my_functions.asocket = [](int af, int type, int protocol, void * p) { - EXPECT_NE(nullptr, p); - (*reinterpret_cast<size_t *>(p))++; - return ::socket(af, type, protocol); - }; - - ares_set_socket_functions(channel_, &my_functions, &count); - - { - count = 0; - HostResult result; - ares_gethostbyname(channel_, "www.google.com.", AF_INET, HostCallback, &result); - Process(); - EXPECT_TRUE(result.done_); - EXPECT_NE(0, count); - } - - { - count = 0; - ares_channel copy; - EXPECT_EQ(ARES_SUCCESS, ares_dup(©, channel_)); - - HostResult result; - ares_gethostbyname(copy, "www.google.com.", AF_INET, HostCallback, &result); - ProcessWork(copy, NoExtraFDs, nullptr); - EXPECT_TRUE(result.done_); - ares_destroy(copy); - EXPECT_NE(0, count); - } - -} - + } +} + +TEST_P(DefaultChannelModeTest, LiveGetHostByAddrFailFamily) { + HostResult result; + unsigned char addr[4] = {8, 8, 8, 8}; + ares_gethostbyaddr(channel_, addr, sizeof(addr), AF_INET6+AF_INET, + HostCallback, &result); + EXPECT_TRUE(result.done_); + EXPECT_EQ(ARES_ENOTIMP, result.status_); +} + +TEST_P(DefaultChannelModeTest, LiveGetHostByAddrFailAddrSize) { + HostResult result; + unsigned char addr[4] = {8, 8, 8, 8}; + ares_gethostbyaddr(channel_, addr, sizeof(addr) - 1, AF_INET, + HostCallback, &result); + EXPECT_TRUE(result.done_); + EXPECT_EQ(ARES_ENOTIMP, result.status_); +} + +TEST_P(DefaultChannelModeTest, LiveGetHostByAddrFailAlloc) { + HostResult result; + unsigned char addr[4] = {8, 8, 8, 8}; + SetAllocFail(1); + ares_gethostbyaddr(channel_, addr, sizeof(addr), AF_INET, + HostCallback, &result); + EXPECT_TRUE(result.done_); + EXPECT_EQ(ARES_ENOMEM, result.status_); +} + +INSTANTIATE_TEST_CASE_P(Modes, DefaultChannelModeTest, + ::testing::Values("f", "b", "fb", "bf")); + +VIRT_NONVIRT_TEST_F(DefaultChannelTest, DISABLED_LiveSearchA) { + SearchResult result; + ares_search(channel_, "www.youtube.com.", ns_c_in, ns_t_a, + SearchCallback, &result); + Process(); + EXPECT_TRUE(result.done_); + EXPECT_EQ(ARES_SUCCESS, result.status_); +} + +VIRT_NONVIRT_TEST_F(DefaultChannelTest, LiveSearchEmptyA) { + SearchResult result; + ares_search(channel_, "", ns_c_in, ns_t_a, + SearchCallback, &result); + Process(); + EXPECT_TRUE(result.done_); + EXPECT_NE(ARES_SUCCESS, result.status_); +} + +VIRT_NONVIRT_TEST_F(DefaultChannelTest, DISABLED_LiveSearchNS) { + SearchResult result; + ares_search(channel_, "google.com.", ns_c_in, ns_t_ns, + SearchCallback, &result); + Process(); + EXPECT_TRUE(result.done_); + EXPECT_EQ(ARES_SUCCESS, result.status_); +} + +VIRT_NONVIRT_TEST_F(DefaultChannelTest, DISABLED_LiveSearchMX) { + SearchResult result; + ares_search(channel_, "google.com.", ns_c_in, ns_t_mx, + SearchCallback, &result); + Process(); + EXPECT_TRUE(result.done_); + EXPECT_EQ(ARES_SUCCESS, result.status_); +} + +VIRT_NONVIRT_TEST_F(DefaultChannelTest, DISABLED_LiveSearchTXT) { + SearchResult result; + ares_search(channel_, "google.com.", ns_c_in, ns_t_txt, + SearchCallback, &result); + Process(); + EXPECT_TRUE(result.done_); + EXPECT_EQ(ARES_SUCCESS, result.status_); +} + +VIRT_NONVIRT_TEST_F(DefaultChannelTest, DISABLED_LiveSearchSOA) { + SearchResult result; + ares_search(channel_, "google.com.", ns_c_in, ns_t_soa, + SearchCallback, &result); + Process(); + EXPECT_TRUE(result.done_); + EXPECT_EQ(ARES_SUCCESS, result.status_); +} + +VIRT_NONVIRT_TEST_F(DefaultChannelTest, DISABLED_LiveSearchSRV) { + SearchResult result; + ares_search(channel_, "_imap._tcp.gmail.com.", ns_c_in, ns_t_srv, + SearchCallback, &result); + Process(); + EXPECT_TRUE(result.done_); + EXPECT_EQ(ARES_SUCCESS, result.status_); +} + +VIRT_NONVIRT_TEST_F(DefaultChannelTest, DISABLED_LiveSearchANY) { + SearchResult result; + ares_search(channel_, "google.com.", ns_c_in, ns_t_any, + SearchCallback, &result); + Process(); + EXPECT_TRUE(result.done_); + EXPECT_EQ(ARES_SUCCESS, result.status_); +} + +VIRT_NONVIRT_TEST_F(DefaultChannelTest, LiveGetNameInfoV4) { + NameInfoResult result; + struct sockaddr_in sockaddr; + memset(&sockaddr, 0, sizeof(sockaddr)); + sockaddr.sin_family = AF_INET; + sockaddr.sin_port = htons(53); + sockaddr.sin_addr.s_addr = htonl(0x08080808); + ares_getnameinfo(channel_, (const struct sockaddr*)&sockaddr, sizeof(sockaddr), + ARES_NI_LOOKUPHOST|ARES_NI_LOOKUPSERVICE|ARES_NI_UDP, + NameInfoCallback, &result); + Process(); + EXPECT_TRUE(result.done_); + EXPECT_EQ(ARES_SUCCESS, result.status_); + if (verbose) std::cerr << "8.8.8.8:53 => " << result.node_ << "/" << result.service_ << std::endl; +} + +VIRT_NONVIRT_TEST_F(DefaultChannelTest, LiveGetNameInfoV4NoPort) { + NameInfoResult result; + struct sockaddr_in sockaddr; + memset(&sockaddr, 0, sizeof(sockaddr)); + sockaddr.sin_family = AF_INET; + sockaddr.sin_port = htons(0); + sockaddr.sin_addr.s_addr = htonl(0x08080808); + ares_getnameinfo(channel_, (const struct sockaddr*)&sockaddr, sizeof(sockaddr), + ARES_NI_LOOKUPHOST|ARES_NI_LOOKUPSERVICE|ARES_NI_UDP, + NameInfoCallback, &result); + Process(); + EXPECT_TRUE(result.done_); + EXPECT_EQ(ARES_SUCCESS, result.status_); + if (verbose) std::cerr << "8.8.8.8:0 => " << result.node_ << "/" << result.service_ << std::endl; +} + +VIRT_NONVIRT_TEST_F(DefaultChannelTest, LiveGetNameInfoV4UnassignedPort) { + NameInfoResult result; + struct sockaddr_in sockaddr; + memset(&sockaddr, 0, sizeof(sockaddr)); + sockaddr.sin_family = AF_INET; + sockaddr.sin_port = htons(4); // Unassigned at IANA + sockaddr.sin_addr.s_addr = htonl(0x08080808); + ares_getnameinfo(channel_, (const struct sockaddr*)&sockaddr, sizeof(sockaddr), + ARES_NI_LOOKUPHOST|ARES_NI_LOOKUPSERVICE|ARES_NI_UDP, + NameInfoCallback, &result); + Process(); + EXPECT_TRUE(result.done_); + EXPECT_EQ(ARES_SUCCESS, result.status_); + if (verbose) std::cerr << "8.8.8.8:4 => " << result.node_ << "/" << result.service_ << std::endl; +} + +VIRT_NONVIRT_TEST_F(DefaultChannelTest, LiveGetNameInfoV6Both) { + NameInfoResult result; + struct sockaddr_in6 sockaddr; + memset(&sockaddr, 0, sizeof(sockaddr)); + sockaddr.sin6_family = AF_INET6; + sockaddr.sin6_port = htons(53); + memcpy(sockaddr.sin6_addr.s6_addr, gdns_addr6, 16); + ares_getnameinfo(channel_, (const struct sockaddr*)&sockaddr, sizeof(sockaddr), + ARES_NI_TCP|ARES_NI_LOOKUPHOST|ARES_NI_LOOKUPSERVICE|ARES_NI_NOFQDN, + NameInfoCallback, &result); + Process(); + EXPECT_TRUE(result.done_); + EXPECT_EQ(ARES_SUCCESS, result.status_); + if (verbose) std::cerr << "[2001:4860:4860::8888]:53 => " << result.node_ << "/" << result.service_ << std::endl; +} + +VIRT_NONVIRT_TEST_F(DefaultChannelTest, LiveGetNameInfoV6Neither) { + NameInfoResult result; + struct sockaddr_in6 sockaddr; + memset(&sockaddr, 0, sizeof(sockaddr)); + sockaddr.sin6_family = AF_INET6; + sockaddr.sin6_port = htons(53); + memcpy(sockaddr.sin6_addr.s6_addr, gdns_addr6, 16); + ares_getnameinfo(channel_, (const struct sockaddr*)&sockaddr, sizeof(sockaddr), + ARES_NI_TCP|ARES_NI_NOFQDN, // Neither specified => assume lookup host. + NameInfoCallback, &result); + Process(); + EXPECT_TRUE(result.done_); + EXPECT_EQ(ARES_SUCCESS, result.status_); + if (verbose) std::cerr << "[2001:4860:4860::8888]:53 => " << result.node_ << "/" << result.service_ << std::endl; +} + +VIRT_NONVIRT_TEST_F(DefaultChannelTest, LiveGetNameInfoV4Numeric) { + NameInfoResult result; + struct sockaddr_in sockaddr; + memset(&sockaddr, 0, sizeof(sockaddr)); + sockaddr.sin_family = AF_INET; + sockaddr.sin_port = htons(53); + sockaddr.sin_addr.s_addr = htonl(0x08080808); + ares_getnameinfo(channel_, (const struct sockaddr*)&sockaddr, sizeof(sockaddr), + ARES_NI_LOOKUPHOST|ARES_NI_LOOKUPSERVICE|ARES_NI_TCP|ARES_NI_NUMERICHOST, + NameInfoCallback, &result); + Process(); + EXPECT_TRUE(result.done_); + EXPECT_EQ(ARES_SUCCESS, result.status_); + EXPECT_EQ("8.8.8.8", result.node_); + if (verbose) std::cerr << "8.8.8.8:53 => " << result.node_ << "/" << result.service_ << std::endl; +} + +VIRT_NONVIRT_TEST_F(DefaultChannelTest, LiveGetNameInfoV6Numeric) { + NameInfoResult result; + struct sockaddr_in6 sockaddr; + memset(&sockaddr, 0, sizeof(sockaddr)); + sockaddr.sin6_family = AF_INET6; + sockaddr.sin6_port = htons(53); + memcpy(sockaddr.sin6_addr.s6_addr, gdns_addr6, 16); + ares_getnameinfo(channel_, (const struct sockaddr*)&sockaddr, sizeof(sockaddr), + ARES_NI_LOOKUPHOST|ARES_NI_LOOKUPSERVICE|ARES_NI_DCCP|ARES_NI_NUMERICHOST, + NameInfoCallback, &result); + Process(); + EXPECT_TRUE(result.done_); + EXPECT_EQ(ARES_SUCCESS, result.status_); + EXPECT_EQ("2001:4860:4860::8888%0", result.node_); + if (verbose) std::cerr << "[2001:4860:4860::8888]:53 => " << result.node_ << "/" << result.service_ << std::endl; +} + +VIRT_NONVIRT_TEST_F(DefaultChannelTest, LiveGetNameInfoV6LinkLocal) { + NameInfoResult result; + struct sockaddr_in6 sockaddr; + memset(&sockaddr, 0, sizeof(sockaddr)); + sockaddr.sin6_family = AF_INET6; + sockaddr.sin6_port = htons(53); + unsigned char addr6[16] = {0xfe, 0x80, 0x01, 0x02, 0x01, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x04}; + memcpy(sockaddr.sin6_addr.s6_addr, addr6, 16); + ares_getnameinfo(channel_, (const struct sockaddr*)&sockaddr, sizeof(sockaddr), + ARES_NI_LOOKUPHOST|ARES_NI_LOOKUPSERVICE|ARES_NI_DCCP|ARES_NI_NUMERICHOST, + NameInfoCallback, &result); + Process(); + EXPECT_TRUE(result.done_); + EXPECT_EQ(ARES_SUCCESS, result.status_); + EXPECT_EQ("fe80:102:102::304%0", result.node_); + if (verbose) std::cerr << "[fe80:102:102::304]:53 => " << result.node_ << "/" << result.service_ << std::endl; +} + +VIRT_NONVIRT_TEST_F(DefaultChannelTest, LiveGetNameInfoV4NotFound) { + NameInfoResult result; + struct sockaddr_in sockaddr; + memset(&sockaddr, 0, sizeof(sockaddr)); + sockaddr.sin_family = AF_INET; + sockaddr.sin_port = htons(4); // Port 4 unassigned at IANA + // RFC5737 says 192.0.2.0 should not be used publically. + sockaddr.sin_addr.s_addr = htonl(0xC0000200); + ares_getnameinfo(channel_, (const struct sockaddr*)&sockaddr, sizeof(sockaddr), + ARES_NI_LOOKUPHOST|ARES_NI_LOOKUPSERVICE|ARES_NI_UDP, + NameInfoCallback, &result); + Process(); + EXPECT_TRUE(result.done_); + EXPECT_EQ(ARES_SUCCESS, result.status_); + EXPECT_EQ("192.0.2.0", result.node_); + if (verbose) std::cerr << "192.0.2.0:53 => " << result.node_ << "/" << result.service_ << std::endl; +} + +VIRT_NONVIRT_TEST_F(DefaultChannelTest, LiveGetNameInfoV4NotFoundFail) { + NameInfoResult result; + struct sockaddr_in sockaddr; + memset(&sockaddr, 0, sizeof(sockaddr)); + sockaddr.sin_family = AF_INET; + sockaddr.sin_port = htons(53); + // RFC5737 says 192.0.2.0 should not be used publically. + sockaddr.sin_addr.s_addr = htonl(0xC0000200); + ares_getnameinfo(channel_, (const struct sockaddr*)&sockaddr, sizeof(sockaddr), + ARES_NI_LOOKUPHOST|ARES_NI_LOOKUPSERVICE|ARES_NI_UDP|ARES_NI_NAMEREQD, + NameInfoCallback, &result); + Process(); + EXPECT_TRUE(result.done_); + EXPECT_EQ(ARES_ENOTFOUND, result.status_); +} + +VIRT_NONVIRT_TEST_F(DefaultChannelTest, LiveGetNameInfoV6NotFound) { + NameInfoResult result; + struct sockaddr_in6 sockaddr; + memset(&sockaddr, 0, sizeof(sockaddr)); + sockaddr.sin6_family = AF_INET6; + sockaddr.sin6_port = htons(53); + // 2001:db8::/32 is only supposed to be used in documentation. + unsigned char addr6[16] = {0x20, 0x01, 0x0d, 0xb8, 0x01, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x04}; + memcpy(sockaddr.sin6_addr.s6_addr, addr6, 16); + ares_getnameinfo(channel_, (const struct sockaddr*)&sockaddr, sizeof(sockaddr), + ARES_NI_LOOKUPHOST|ARES_NI_LOOKUPSERVICE|ARES_NI_UDP, + NameInfoCallback, &result); + Process(); + EXPECT_TRUE(result.done_); + EXPECT_EQ(ARES_SUCCESS, result.status_); + EXPECT_EQ("2001:db8:102::304%0", result.node_); + if (verbose) std::cerr << "[2001:db8:102::304]:53 => " << result.node_ << "/" << result.service_ << std::endl; +} + +VIRT_NONVIRT_TEST_F(DefaultChannelTest, LiveGetNameInvalidFamily) { + NameInfoResult result; + struct sockaddr_in6 sockaddr; + memset(&sockaddr, 0, sizeof(sockaddr)); + sockaddr.sin6_family = AF_INET6 + AF_INET; + sockaddr.sin6_port = htons(53); + memcpy(sockaddr.sin6_addr.s6_addr, gdns_addr6, 16); + ares_getnameinfo(channel_, (const struct sockaddr*)&sockaddr, sizeof(sockaddr), + ARES_NI_LOOKUPHOST|ARES_NI_LOOKUPSERVICE|ARES_NI_UDP, + NameInfoCallback, &result); + Process(); + EXPECT_TRUE(result.done_); + EXPECT_EQ(ARES_ENOTIMP, result.status_); +} + +VIRT_NONVIRT_TEST_F(DefaultChannelTest, LiveGetNameInvalidFlags) { + NameInfoResult result; + struct sockaddr_in6 sockaddr; + memset(&sockaddr, 0, sizeof(sockaddr)); + sockaddr.sin6_family = AF_INET6; + sockaddr.sin6_port = htons(53); + memcpy(sockaddr.sin6_addr.s6_addr, gdns_addr6, 16); + // Ask for both a name-required, and a numeric host. + ares_getnameinfo(channel_, (const struct sockaddr*)&sockaddr, sizeof(sockaddr), + ARES_NI_LOOKUPHOST|ARES_NI_LOOKUPSERVICE|ARES_NI_UDP|ARES_NI_NUMERICHOST|ARES_NI_NAMEREQD, + NameInfoCallback, &result); + Process(); + EXPECT_TRUE(result.done_); + EXPECT_EQ(ARES_EBADFLAGS, result.status_); +} + +VIRT_NONVIRT_TEST_F(DefaultChannelTest, LiveGetServiceInfo) { + NameInfoResult result; + struct sockaddr_in sockaddr; + memset(&sockaddr, 0, sizeof(sockaddr)); + sockaddr.sin_family = AF_INET; + sockaddr.sin_port = htons(53); + sockaddr.sin_addr.s_addr = htonl(0x08080808); + // Just look up service info + ares_getnameinfo(channel_, (const struct sockaddr*)&sockaddr, sizeof(sockaddr), + ARES_NI_LOOKUPSERVICE|ARES_NI_SCTP, + NameInfoCallback, &result); + Process(); + EXPECT_TRUE(result.done_); + EXPECT_EQ(ARES_SUCCESS, result.status_); + EXPECT_EQ("", result.node_); +} + +VIRT_NONVIRT_TEST_F(DefaultChannelTest, LiveGetServiceInfoNumeric) { + NameInfoResult result; + struct sockaddr_in sockaddr; + memset(&sockaddr, 0, sizeof(sockaddr)); + sockaddr.sin_family = AF_INET; + sockaddr.sin_port = htons(53); + sockaddr.sin_addr.s_addr = htonl(0x08080808); + // Just look up service info + ares_getnameinfo(channel_, (const struct sockaddr*)&sockaddr, sizeof(sockaddr), + ARES_NI_LOOKUPSERVICE|ARES_NI_SCTP|ARES_NI_NUMERICSERV, + NameInfoCallback, &result); + Process(); + EXPECT_TRUE(result.done_); + EXPECT_EQ(ARES_SUCCESS, result.status_); + EXPECT_EQ("", result.node_); + EXPECT_EQ("53", result.service_); +} + +VIRT_NONVIRT_TEST_F(DefaultChannelTest, LiveGetNameInfoAllocFail) { + NameInfoResult result; + struct sockaddr_in sockaddr; + memset(&sockaddr, 0, sizeof(sockaddr)); + sockaddr.sin_family = AF_INET; + sockaddr.sin_port = htons(53); + sockaddr.sin_addr.s_addr = htonl(0x08080808); + SetAllocFail(1); + ares_getnameinfo(channel_, (const struct sockaddr*)&sockaddr, sizeof(sockaddr), + ARES_NI_LOOKUPHOST|ARES_NI_LOOKUPSERVICE|ARES_NI_UDP, + NameInfoCallback, &result); + Process(); + EXPECT_TRUE(result.done_); + EXPECT_EQ(ARES_ENOMEM, result.status_); +} + +VIRT_NONVIRT_TEST_F(DefaultChannelTest, DISABLED_GetSock) { + ares_socket_t socks[3] = {ARES_SOCKET_BAD, ARES_SOCKET_BAD, ARES_SOCKET_BAD}; + int bitmask = ares_getsock(channel_, socks, 3); + EXPECT_EQ(0, bitmask); + bitmask = ares_getsock(channel_, nullptr, 0); + EXPECT_EQ(0, bitmask); + + // Ask again with a pending query. + HostResult result; + ares_gethostbyname(channel_, "www.google.com.", AF_INET, HostCallback, &result); + bitmask = ares_getsock(channel_, socks, 3); + EXPECT_NE(0, bitmask); + bitmask = ares_getsock(channel_, nullptr, 0); + EXPECT_EQ(0, bitmask); + + Process(); +} + +TEST_F(LibraryTest, DISABLED_GetTCPSock) { + ares_channel channel; + struct ares_options opts = {0}; + opts.tcp_port = 53; + opts.flags = ARES_FLAG_USEVC; + int optmask = ARES_OPT_TCP_PORT | ARES_OPT_FLAGS; + EXPECT_EQ(ARES_SUCCESS, ares_init_options(&channel, &opts, optmask)); + EXPECT_NE(nullptr, channel); + + ares_socket_t socks[3] = {ARES_SOCKET_BAD, ARES_SOCKET_BAD, ARES_SOCKET_BAD}; + int bitmask = ares_getsock(channel, socks, 3); + EXPECT_EQ(0, bitmask); + bitmask = ares_getsock(channel, nullptr, 0); + EXPECT_EQ(0, bitmask); + + // Ask again with a pending query. + HostResult result; + ares_gethostbyname(channel, "www.google.com.", AF_INET, HostCallback, &result); + bitmask = ares_getsock(channel, socks, 3); + EXPECT_NE(0, bitmask); + bitmask = ares_getsock(channel, nullptr, 0); + EXPECT_EQ(0, bitmask); + + ProcessWork(channel, NoExtraFDs, nullptr); + + ares_destroy(channel); +} + +TEST_F(DefaultChannelTest, VerifySocketFunctionCallback) { + VirtualizeIO vio(channel_); + + auto my_functions = VirtualizeIO::default_functions; + size_t count = 0; + + my_functions.asocket = [](int af, int type, int protocol, void * p) { + EXPECT_NE(nullptr, p); + (*reinterpret_cast<size_t *>(p))++; + return ::socket(af, type, protocol); + }; + + ares_set_socket_functions(channel_, &my_functions, &count); + + { + count = 0; + HostResult result; + ares_gethostbyname(channel_, "www.google.com.", AF_INET, HostCallback, &result); + Process(); + EXPECT_TRUE(result.done_); + EXPECT_NE(0, count); + } + + { + count = 0; + ares_channel copy; + EXPECT_EQ(ARES_SUCCESS, ares_dup(©, channel_)); + + HostResult result; + ares_gethostbyname(copy, "www.google.com.", AF_INET, HostCallback, &result); + ProcessWork(copy, NoExtraFDs, nullptr); + EXPECT_TRUE(result.done_); + ares_destroy(copy); + EXPECT_NE(0, count); + } + +} + TEST_F(DefaultChannelTest, LiveSetServers) { struct ares_addr_node server1; struct ares_addr_node server2; @@ -705,7 +705,7 @@ TEST_F(DefaultChannelTest, LiveSetServers) { server2.next = nullptr; server2.family = AF_INET; server2.addr.addr4.s_addr = htonl(0x02030405); - + // Change not allowed while request is pending HostResult result; ares_gethostbyname(channel_, "www.google.com.", AF_INET, HostCallback, &result); @@ -745,5 +745,5 @@ TEST_F(DefaultChannelTest, LiveSetServersCSV) { } -} // namespace test -} // namespace ares +} // namespace test +} // namespace ares diff --git a/contrib/libs/c-ares/test/ares-test-misc.cc b/contrib/libs/c-ares/test/ares-test-misc.cc index b42987ef39..6fc28a8f97 100644 --- a/contrib/libs/c-ares/test/ares-test-misc.cc +++ b/contrib/libs/c-ares/test/ares-test-misc.cc @@ -1,282 +1,282 @@ -#include "ares-test.h" -#include "dns-proto.h" - -#include <string> -#include <vector> - -namespace ares { -namespace test { - -TEST_F(DefaultChannelTest, GetServers) { - std::vector<std::string> servers = GetNameServers(channel_); - if (verbose) { - for (const std::string& server : servers) { - std::cerr << "Nameserver: " << server << std::endl; - } - } -} - -TEST_F(DefaultChannelTest, GetServersFailures) { - EXPECT_EQ(ARES_SUCCESS, - ares_set_servers_csv(channel_, "1.2.3.4,2.3.4.5")); - struct ares_addr_node* servers = nullptr; - SetAllocFail(1); - EXPECT_EQ(ARES_ENOMEM, ares_get_servers(channel_, &servers)); - SetAllocFail(2); - EXPECT_EQ(ARES_ENOMEM, ares_get_servers(channel_, &servers)); - EXPECT_EQ(ARES_ENODATA, ares_get_servers(nullptr, &servers)); -} - +#include "ares-test.h" +#include "dns-proto.h" + +#include <string> +#include <vector> + +namespace ares { +namespace test { + +TEST_F(DefaultChannelTest, GetServers) { + std::vector<std::string> servers = GetNameServers(channel_); + if (verbose) { + for (const std::string& server : servers) { + std::cerr << "Nameserver: " << server << std::endl; + } + } +} + +TEST_F(DefaultChannelTest, GetServersFailures) { + EXPECT_EQ(ARES_SUCCESS, + ares_set_servers_csv(channel_, "1.2.3.4,2.3.4.5")); + struct ares_addr_node* servers = nullptr; + SetAllocFail(1); + EXPECT_EQ(ARES_ENOMEM, ares_get_servers(channel_, &servers)); + SetAllocFail(2); + EXPECT_EQ(ARES_ENOMEM, ares_get_servers(channel_, &servers)); + EXPECT_EQ(ARES_ENODATA, ares_get_servers(nullptr, &servers)); +} + TEST_F(DefaultChannelTest, SetServers) { - EXPECT_EQ(ARES_SUCCESS, ares_set_servers(channel_, nullptr)); - std::vector<std::string> empty; - EXPECT_EQ(empty, GetNameServers(channel_)); - - struct ares_addr_node server1; - struct ares_addr_node server2; - server1.next = &server2; - server1.family = AF_INET; - server1.addr.addr4.s_addr = htonl(0x01020304); - server2.next = nullptr; - server2.family = AF_INET; - server2.addr.addr4.s_addr = htonl(0x02030405); - EXPECT_EQ(ARES_ENODATA, ares_set_servers(nullptr, &server1)); - - EXPECT_EQ(ARES_SUCCESS, ares_set_servers(channel_, &server1)); - std::vector<std::string> expected = {"1.2.3.4", "2.3.4.5"}; - EXPECT_EQ(expected, GetNameServers(channel_)); -} - + EXPECT_EQ(ARES_SUCCESS, ares_set_servers(channel_, nullptr)); + std::vector<std::string> empty; + EXPECT_EQ(empty, GetNameServers(channel_)); + + struct ares_addr_node server1; + struct ares_addr_node server2; + server1.next = &server2; + server1.family = AF_INET; + server1.addr.addr4.s_addr = htonl(0x01020304); + server2.next = nullptr; + server2.family = AF_INET; + server2.addr.addr4.s_addr = htonl(0x02030405); + EXPECT_EQ(ARES_ENODATA, ares_set_servers(nullptr, &server1)); + + EXPECT_EQ(ARES_SUCCESS, ares_set_servers(channel_, &server1)); + std::vector<std::string> expected = {"1.2.3.4", "2.3.4.5"}; + EXPECT_EQ(expected, GetNameServers(channel_)); +} + TEST_F(DefaultChannelTest, SetServersPorts) { - EXPECT_EQ(ARES_SUCCESS, ares_set_servers_ports(channel_, nullptr)); - std::vector<std::string> empty; - EXPECT_EQ(empty, GetNameServers(channel_)); - - struct ares_addr_port_node server1; - struct ares_addr_port_node server2; - server1.next = &server2; - server1.family = AF_INET; - server1.addr.addr4.s_addr = htonl(0x01020304); - server1.udp_port = 111; - server1.tcp_port = 111; - server2.next = nullptr; - server2.family = AF_INET; - server2.addr.addr4.s_addr = htonl(0x02030405); - server2.udp_port = 0; - server2.tcp_port = 0;; - EXPECT_EQ(ARES_ENODATA, ares_set_servers_ports(nullptr, &server1)); - - EXPECT_EQ(ARES_SUCCESS, ares_set_servers_ports(channel_, &server1)); - std::vector<std::string> expected = {"1.2.3.4:111", "2.3.4.5"}; - EXPECT_EQ(expected, GetNameServers(channel_)); -} - + EXPECT_EQ(ARES_SUCCESS, ares_set_servers_ports(channel_, nullptr)); + std::vector<std::string> empty; + EXPECT_EQ(empty, GetNameServers(channel_)); + + struct ares_addr_port_node server1; + struct ares_addr_port_node server2; + server1.next = &server2; + server1.family = AF_INET; + server1.addr.addr4.s_addr = htonl(0x01020304); + server1.udp_port = 111; + server1.tcp_port = 111; + server2.next = nullptr; + server2.family = AF_INET; + server2.addr.addr4.s_addr = htonl(0x02030405); + server2.udp_port = 0; + server2.tcp_port = 0;; + EXPECT_EQ(ARES_ENODATA, ares_set_servers_ports(nullptr, &server1)); + + EXPECT_EQ(ARES_SUCCESS, ares_set_servers_ports(channel_, &server1)); + std::vector<std::string> expected = {"1.2.3.4:111", "2.3.4.5"}; + EXPECT_EQ(expected, GetNameServers(channel_)); +} + TEST_F(DefaultChannelTest, SetServersCSV) { - EXPECT_EQ(ARES_ENODATA, ares_set_servers_csv(nullptr, "1.2.3.4")); - EXPECT_EQ(ARES_ENODATA, ares_set_servers_csv(nullptr, "xyzzy,plugh")); - EXPECT_EQ(ARES_ENODATA, ares_set_servers_csv(nullptr, "256.1.2.3")); - EXPECT_EQ(ARES_ENODATA, ares_set_servers_csv(nullptr, "1.2.3.4.5")); - EXPECT_EQ(ARES_ENODATA, ares_set_servers_csv(nullptr, "1:2:3:4:5")); - - EXPECT_EQ(ARES_SUCCESS, - ares_set_servers_csv(channel_, "1.2.3.4,0102:0304:0506:0708:0910:1112:1314:1516,2.3.4.5")); - std::vector<std::string> expected = {"1.2.3.4", "0102:0304:0506:0708:0910:1112:1314:1516", "2.3.4.5"}; - EXPECT_EQ(expected, GetNameServers(channel_)); - - // Same, with spaces - EXPECT_EQ(ARES_EBADSTR, - ares_set_servers_csv(channel_, "1.2.3.4 , 0102:0304:0506:0708:0910:1112:1314:1516, 2.3.4.5")); - - // Same, with ports - EXPECT_EQ(ARES_SUCCESS, - ares_set_servers_csv(channel_, "1.2.3.4:54,[0102:0304:0506:0708:0910:1112:1314:1516]:80,2.3.4.5:55")); - EXPECT_EQ(expected, GetNameServers(channel_)); - EXPECT_EQ(ARES_SUCCESS, - ares_set_servers_ports_csv(channel_, "1.2.3.4:54,[0102:0304:0506:0708:0910:1112:1314:1516]:80,2.3.4.5:55")); - std::vector<std::string> expected2 = {"1.2.3.4:54", "[0102:0304:0506:0708:0910:1112:1314:1516]:80", "2.3.4.5:55"}; - EXPECT_EQ(expected2, GetNameServers(channel_)); - - // Should survive duplication - ares_channel channel2; - EXPECT_EQ(ARES_SUCCESS, ares_dup(&channel2, channel_)); - EXPECT_EQ(expected2, GetNameServers(channel2)); - ares_destroy(channel2); - - // Allocation failure cases - for (int fail = 1; fail <= 5; fail++) { - SetAllocFail(fail); - EXPECT_EQ(ARES_ENOMEM, - ares_set_servers_csv(channel_, "1.2.3.4,0102:0304:0506:0708:0910:1112:1314:1516,2.3.4.5")); - } - - // Blank servers - EXPECT_EQ(ARES_SUCCESS, ares_set_servers_csv(channel_, "")); - std::vector<std::string> none; - EXPECT_EQ(none, GetNameServers(channel_)); - - EXPECT_EQ(ARES_EBADSTR, ares_set_servers_csv(channel_, "2.3.4.5,1.2.3.4:,3.4.5.6")); - EXPECT_EQ(ARES_EBADSTR, ares_set_servers_csv(channel_, "2.3.4.5,1.2.3.4:Z,3.4.5.6")); -} - + EXPECT_EQ(ARES_ENODATA, ares_set_servers_csv(nullptr, "1.2.3.4")); + EXPECT_EQ(ARES_ENODATA, ares_set_servers_csv(nullptr, "xyzzy,plugh")); + EXPECT_EQ(ARES_ENODATA, ares_set_servers_csv(nullptr, "256.1.2.3")); + EXPECT_EQ(ARES_ENODATA, ares_set_servers_csv(nullptr, "1.2.3.4.5")); + EXPECT_EQ(ARES_ENODATA, ares_set_servers_csv(nullptr, "1:2:3:4:5")); + + EXPECT_EQ(ARES_SUCCESS, + ares_set_servers_csv(channel_, "1.2.3.4,0102:0304:0506:0708:0910:1112:1314:1516,2.3.4.5")); + std::vector<std::string> expected = {"1.2.3.4", "0102:0304:0506:0708:0910:1112:1314:1516", "2.3.4.5"}; + EXPECT_EQ(expected, GetNameServers(channel_)); + + // Same, with spaces + EXPECT_EQ(ARES_EBADSTR, + ares_set_servers_csv(channel_, "1.2.3.4 , 0102:0304:0506:0708:0910:1112:1314:1516, 2.3.4.5")); + + // Same, with ports + EXPECT_EQ(ARES_SUCCESS, + ares_set_servers_csv(channel_, "1.2.3.4:54,[0102:0304:0506:0708:0910:1112:1314:1516]:80,2.3.4.5:55")); + EXPECT_EQ(expected, GetNameServers(channel_)); + EXPECT_EQ(ARES_SUCCESS, + ares_set_servers_ports_csv(channel_, "1.2.3.4:54,[0102:0304:0506:0708:0910:1112:1314:1516]:80,2.3.4.5:55")); + std::vector<std::string> expected2 = {"1.2.3.4:54", "[0102:0304:0506:0708:0910:1112:1314:1516]:80", "2.3.4.5:55"}; + EXPECT_EQ(expected2, GetNameServers(channel_)); + + // Should survive duplication + ares_channel channel2; + EXPECT_EQ(ARES_SUCCESS, ares_dup(&channel2, channel_)); + EXPECT_EQ(expected2, GetNameServers(channel2)); + ares_destroy(channel2); + + // Allocation failure cases + for (int fail = 1; fail <= 5; fail++) { + SetAllocFail(fail); + EXPECT_EQ(ARES_ENOMEM, + ares_set_servers_csv(channel_, "1.2.3.4,0102:0304:0506:0708:0910:1112:1314:1516,2.3.4.5")); + } + + // Blank servers + EXPECT_EQ(ARES_SUCCESS, ares_set_servers_csv(channel_, "")); + std::vector<std::string> none; + EXPECT_EQ(none, GetNameServers(channel_)); + + EXPECT_EQ(ARES_EBADSTR, ares_set_servers_csv(channel_, "2.3.4.5,1.2.3.4:,3.4.5.6")); + EXPECT_EQ(ARES_EBADSTR, ares_set_servers_csv(channel_, "2.3.4.5,1.2.3.4:Z,3.4.5.6")); +} + TEST_F(DefaultChannelTest, TimeoutValue) { - struct timeval tinfo; - tinfo.tv_sec = 0; - tinfo.tv_usec = 0; - struct timeval tmax; - tmax.tv_sec = 0; - tmax.tv_usec = 10; - struct timeval* pt; - - // No timers => get max back. - pt = ares_timeout(channel_, &tmax, &tinfo); - EXPECT_EQ(&tmax, pt); - EXPECT_EQ(0, pt->tv_sec); - EXPECT_EQ(10, pt->tv_usec); - - pt = ares_timeout(channel_, nullptr, &tinfo); - EXPECT_EQ(nullptr, pt); - - HostResult result; - ares_gethostbyname(channel_, "www.google.com.", AF_INET, HostCallback, &result); - - // Now there's a timer running. - pt = ares_timeout(channel_, &tmax, &tinfo); - EXPECT_EQ(&tmax, pt); - EXPECT_EQ(0, pt->tv_sec); - EXPECT_EQ(10, pt->tv_usec); - - tmax.tv_sec = 100; - pt = ares_timeout(channel_, &tmax, &tinfo); - EXPECT_EQ(&tinfo, pt); - - pt = ares_timeout(channel_, nullptr, &tinfo); - EXPECT_EQ(&tinfo, pt); - - Process(); -} - -TEST_F(LibraryTest, InetNtoP) { - struct in_addr addr; - addr.s_addr = htonl(0x01020304); - char buffer[256]; - EXPECT_EQ(buffer, ares_inet_ntop(AF_INET, &addr, buffer, sizeof(buffer))); - EXPECT_EQ("1.2.3.4", std::string(buffer)); -} - -TEST_F(LibraryTest, Mkquery) { - byte* p; - int len; - ares_mkquery("example.com", ns_c_in, ns_t_a, 0x1234, 0, &p, &len); - std::vector<byte> data(p, p + len); - ares_free_string(p); - - std::string actual = PacketToString(data); - DNSPacket pkt; - pkt.set_qid(0x1234).add_question(new DNSQuestion("example.com", ns_t_a)); - std::string expected = PacketToString(pkt.data()); - EXPECT_EQ(expected, actual); -} - -TEST_F(LibraryTest, CreateQuery) { - byte* p; - int len; - EXPECT_EQ(ARES_SUCCESS, - ares_create_query("exam\\@le.com", ns_c_in, ns_t_a, 0x1234, 0, - &p, &len, 0)); - std::vector<byte> data(p, p + len); - ares_free_string(p); - - std::string actual = PacketToString(data); - DNSPacket pkt; - pkt.set_qid(0x1234).add_question(new DNSQuestion("exam@le.com", ns_t_a)); - std::string expected = PacketToString(pkt.data()); - EXPECT_EQ(expected, actual); -} - -TEST_F(LibraryTest, CreateQueryTrailingEscapedDot) { - byte* p; - int len; - EXPECT_EQ(ARES_SUCCESS, - ares_create_query("example.com\\.", ns_c_in, ns_t_a, 0x1234, 0, - &p, &len, 0)); - std::vector<byte> data(p, p + len); - ares_free_string(p); - - std::string actual = PacketToString(data); - EXPECT_EQ("REQ QRY Q:{'example.com\\.' IN A}", actual); -} - -TEST_F(LibraryTest, CreateQueryNameTooLong) { - byte* p; - int len; - EXPECT_EQ(ARES_EBADNAME, - ares_create_query( - "a1234567890123456789.b1234567890123456789.c1234567890123456789.d1234567890123456789." - "a1234567890123456789.b1234567890123456789.c1234567890123456789.d1234567890123456789." - "a1234567890123456789.b1234567890123456789.c1234567890123456789.d1234567890123456789." - "x1234567890123456789.y1234567890123456789.", - ns_c_in, ns_t_a, 0x1234, 0, &p, &len, 0)); -} - -TEST_F(LibraryTest, CreateQueryFailures) { - byte* p; - int len; - // RC1035 has a 255 byte limit on names. - std::string longname; - for (int ii = 0; ii < 17; ii++) { - longname += "fedcba9876543210"; - } - p = nullptr; - EXPECT_EQ(ARES_EBADNAME, - ares_create_query(longname.c_str(), ns_c_in, ns_t_a, 0x1234, 0, - &p, &len, 0)); - if (p) ares_free_string(p); - - SetAllocFail(1); - - p = nullptr; - EXPECT_EQ(ARES_ENOMEM, - ares_create_query("example.com", ns_c_in, ns_t_a, 0x1234, 0, - &p, &len, 0)); - if (p) ares_free_string(p); - - // 63-char limit on a single label - std::string longlabel = "a.a123456789b123456789c123456789d123456789e123456789f123456789g123456789.org"; - p = nullptr; - EXPECT_EQ(ARES_EBADNAME, - ares_create_query(longlabel.c_str(), ns_c_in, ns_t_a, 0x1234, 0, - &p, &len, 0)); - if (p) ares_free_string(p); - - // Empty non-terminal label - p = nullptr; - EXPECT_EQ(ARES_EBADNAME, - ares_create_query("example..com", ns_c_in, ns_t_a, 0x1234, 0, - &p, &len, 0)); - if (p) ares_free_string(p); -} - -TEST_F(LibraryTest, CreateQueryOnionDomain) { - byte* p; - int len; - EXPECT_EQ(ARES_ENOTFOUND, - ares_create_query("dontleak.onion", ns_c_in, ns_t_a, 0x1234, 0, - &p, &len, 0)); -} - -TEST_F(DefaultChannelTest, HostByNameOnionDomain) { - HostResult result; - ares_gethostbyname(channel_, "dontleak.onion", AF_INET, HostCallback, &result); - EXPECT_TRUE(result.done_); - EXPECT_EQ(ARES_ENOTFOUND, result.status_); -} - -TEST_F(DefaultChannelTest, HostByNameFileOnionDomain) { - struct hostent *h; - EXPECT_EQ(ARES_ENOTFOUND, - ares_gethostbyname_file(channel_, "dontleak.onion", AF_INET, &h)); -} - + struct timeval tinfo; + tinfo.tv_sec = 0; + tinfo.tv_usec = 0; + struct timeval tmax; + tmax.tv_sec = 0; + tmax.tv_usec = 10; + struct timeval* pt; + + // No timers => get max back. + pt = ares_timeout(channel_, &tmax, &tinfo); + EXPECT_EQ(&tmax, pt); + EXPECT_EQ(0, pt->tv_sec); + EXPECT_EQ(10, pt->tv_usec); + + pt = ares_timeout(channel_, nullptr, &tinfo); + EXPECT_EQ(nullptr, pt); + + HostResult result; + ares_gethostbyname(channel_, "www.google.com.", AF_INET, HostCallback, &result); + + // Now there's a timer running. + pt = ares_timeout(channel_, &tmax, &tinfo); + EXPECT_EQ(&tmax, pt); + EXPECT_EQ(0, pt->tv_sec); + EXPECT_EQ(10, pt->tv_usec); + + tmax.tv_sec = 100; + pt = ares_timeout(channel_, &tmax, &tinfo); + EXPECT_EQ(&tinfo, pt); + + pt = ares_timeout(channel_, nullptr, &tinfo); + EXPECT_EQ(&tinfo, pt); + + Process(); +} + +TEST_F(LibraryTest, InetNtoP) { + struct in_addr addr; + addr.s_addr = htonl(0x01020304); + char buffer[256]; + EXPECT_EQ(buffer, ares_inet_ntop(AF_INET, &addr, buffer, sizeof(buffer))); + EXPECT_EQ("1.2.3.4", std::string(buffer)); +} + +TEST_F(LibraryTest, Mkquery) { + byte* p; + int len; + ares_mkquery("example.com", ns_c_in, ns_t_a, 0x1234, 0, &p, &len); + std::vector<byte> data(p, p + len); + ares_free_string(p); + + std::string actual = PacketToString(data); + DNSPacket pkt; + pkt.set_qid(0x1234).add_question(new DNSQuestion("example.com", ns_t_a)); + std::string expected = PacketToString(pkt.data()); + EXPECT_EQ(expected, actual); +} + +TEST_F(LibraryTest, CreateQuery) { + byte* p; + int len; + EXPECT_EQ(ARES_SUCCESS, + ares_create_query("exam\\@le.com", ns_c_in, ns_t_a, 0x1234, 0, + &p, &len, 0)); + std::vector<byte> data(p, p + len); + ares_free_string(p); + + std::string actual = PacketToString(data); + DNSPacket pkt; + pkt.set_qid(0x1234).add_question(new DNSQuestion("exam@le.com", ns_t_a)); + std::string expected = PacketToString(pkt.data()); + EXPECT_EQ(expected, actual); +} + +TEST_F(LibraryTest, CreateQueryTrailingEscapedDot) { + byte* p; + int len; + EXPECT_EQ(ARES_SUCCESS, + ares_create_query("example.com\\.", ns_c_in, ns_t_a, 0x1234, 0, + &p, &len, 0)); + std::vector<byte> data(p, p + len); + ares_free_string(p); + + std::string actual = PacketToString(data); + EXPECT_EQ("REQ QRY Q:{'example.com\\.' IN A}", actual); +} + +TEST_F(LibraryTest, CreateQueryNameTooLong) { + byte* p; + int len; + EXPECT_EQ(ARES_EBADNAME, + ares_create_query( + "a1234567890123456789.b1234567890123456789.c1234567890123456789.d1234567890123456789." + "a1234567890123456789.b1234567890123456789.c1234567890123456789.d1234567890123456789." + "a1234567890123456789.b1234567890123456789.c1234567890123456789.d1234567890123456789." + "x1234567890123456789.y1234567890123456789.", + ns_c_in, ns_t_a, 0x1234, 0, &p, &len, 0)); +} + +TEST_F(LibraryTest, CreateQueryFailures) { + byte* p; + int len; + // RC1035 has a 255 byte limit on names. + std::string longname; + for (int ii = 0; ii < 17; ii++) { + longname += "fedcba9876543210"; + } + p = nullptr; + EXPECT_EQ(ARES_EBADNAME, + ares_create_query(longname.c_str(), ns_c_in, ns_t_a, 0x1234, 0, + &p, &len, 0)); + if (p) ares_free_string(p); + + SetAllocFail(1); + + p = nullptr; + EXPECT_EQ(ARES_ENOMEM, + ares_create_query("example.com", ns_c_in, ns_t_a, 0x1234, 0, + &p, &len, 0)); + if (p) ares_free_string(p); + + // 63-char limit on a single label + std::string longlabel = "a.a123456789b123456789c123456789d123456789e123456789f123456789g123456789.org"; + p = nullptr; + EXPECT_EQ(ARES_EBADNAME, + ares_create_query(longlabel.c_str(), ns_c_in, ns_t_a, 0x1234, 0, + &p, &len, 0)); + if (p) ares_free_string(p); + + // Empty non-terminal label + p = nullptr; + EXPECT_EQ(ARES_EBADNAME, + ares_create_query("example..com", ns_c_in, ns_t_a, 0x1234, 0, + &p, &len, 0)); + if (p) ares_free_string(p); +} + +TEST_F(LibraryTest, CreateQueryOnionDomain) { + byte* p; + int len; + EXPECT_EQ(ARES_ENOTFOUND, + ares_create_query("dontleak.onion", ns_c_in, ns_t_a, 0x1234, 0, + &p, &len, 0)); +} + +TEST_F(DefaultChannelTest, HostByNameOnionDomain) { + HostResult result; + ares_gethostbyname(channel_, "dontleak.onion", AF_INET, HostCallback, &result); + EXPECT_TRUE(result.done_); + EXPECT_EQ(ARES_ENOTFOUND, result.status_); +} + +TEST_F(DefaultChannelTest, HostByNameFileOnionDomain) { + struct hostent *h; + EXPECT_EQ(ARES_ENOTFOUND, + ares_gethostbyname_file(channel_, "dontleak.onion", AF_INET, &h)); +} + TEST_F(DefaultChannelTest, GetAddrinfoOnionDomain) { AddrInfoResult result; struct ares_addrinfo_hints hints = {}; @@ -286,241 +286,241 @@ TEST_F(DefaultChannelTest, GetAddrinfoOnionDomain) { EXPECT_EQ(ARES_ENOTFOUND, result.status_); } -// Interesting question: should tacking on a search domain let the query -// through? It seems safer to reject it because "supersecret.onion.search" -// still leaks information about the query to malicious resolvers. -TEST_F(DefaultChannelTest, SearchOnionDomain) { - SearchResult result; - ares_search(channel_, "dontleak.onion", ns_c_in, ns_t_a, - SearchCallback, &result); - EXPECT_TRUE(result.done_); - EXPECT_EQ(ARES_ENOTFOUND, result.status_); -} - -TEST_F(DefaultChannelTest, SendFailure) { - unsigned char buf[2]; - SearchResult result; - ares_send(channel_, buf, sizeof(buf), SearchCallback, &result); - EXPECT_TRUE(result.done_); - EXPECT_EQ(ARES_EBADQUERY, result.status_); -} - -std::string ExpandName(const std::vector<byte>& data, int offset, - long *enclen) { - char *name = nullptr; - int rc = ares_expand_name(data.data() + offset, data.data(), data.size(), - &name, enclen); - EXPECT_EQ(ARES_SUCCESS, rc); - std::string result; - if (rc == ARES_SUCCESS) { - result = name; - } else { - result = "<error>"; - } - ares_free_string(name); - return result; -} - -TEST_F(LibraryTest, ExpandName) { - long enclen; - std::vector<byte> data1 = {1, 'a', 2, 'b', 'c', 3, 'd', 'e', 'f', 0}; - EXPECT_EQ("a.bc.def", ExpandName(data1, 0, &enclen)); - EXPECT_EQ(data1.size(), enclen); - - std::vector<byte> data2 = {0}; - EXPECT_EQ("", ExpandName(data2, 0, &enclen)); - EXPECT_EQ(1, enclen); - - // Complete name indirection - std::vector<byte> data3 = {0x12, 0x23, - 3, 'd', 'e', 'f', 0, - 0xC0, 2}; - EXPECT_EQ("def", ExpandName(data3, 2, &enclen)); - EXPECT_EQ(5, enclen); - EXPECT_EQ("def", ExpandName(data3, 7, &enclen)); - EXPECT_EQ(2, enclen); - - // One label then indirection - std::vector<byte> data4 = {0x12, 0x23, - 3, 'd', 'e', 'f', 0, - 1, 'a', 0xC0, 2}; - EXPECT_EQ("def", ExpandName(data4, 2, &enclen)); - EXPECT_EQ(5, enclen); - EXPECT_EQ("a.def", ExpandName(data4, 7, &enclen)); - EXPECT_EQ(4, enclen); - - // Two labels then indirection - std::vector<byte> data5 = {0x12, 0x23, - 3, 'd', 'e', 'f', 0, - 1, 'a', 1, 'b', 0xC0, 2}; - EXPECT_EQ("def", ExpandName(data5, 2, &enclen)); - EXPECT_EQ(5, enclen); - EXPECT_EQ("a.b.def", ExpandName(data5, 7, &enclen)); - EXPECT_EQ(6, enclen); - - // Empty name, indirection to empty name - std::vector<byte> data6 = {0x12, 0x23, - 0, - 0xC0, 2}; - EXPECT_EQ("", ExpandName(data6, 2, &enclen)); - EXPECT_EQ(1, enclen); - EXPECT_EQ("", ExpandName(data6, 3, &enclen)); - EXPECT_EQ(2, enclen); -} - -TEST_F(LibraryTest, ExpandNameFailure) { - std::vector<byte> data1 = {0x03, 'c', 'o', 'm', 0x00}; - char *name = nullptr; - long enclen; - SetAllocFail(1); - EXPECT_EQ(ARES_ENOMEM, - ares_expand_name(data1.data(), data1.data(), data1.size(), - &name, &enclen)); - - // Empty packet - EXPECT_EQ(ARES_EBADNAME, - ares_expand_name(data1.data(), data1.data(), 0, &name, &enclen)); - - // Start beyond enclosing data - EXPECT_EQ(ARES_EBADNAME, - ares_expand_name(data1.data() + data1.size(), data1.data(), data1.size(), - &name, &enclen)); - - // Length beyond size of enclosing data - std::vector<byte> data2a = {0x13, 'c', 'o', 'm', 0x00}; - EXPECT_EQ(ARES_EBADNAME, - ares_expand_name(data2a.data(), data2a.data(), data2a.size(), - &name, &enclen)); - std::vector<byte> data2b = {0x1}; - EXPECT_EQ(ARES_EBADNAME, - ares_expand_name(data2b.data(), data2b.data(), data2b.size(), - &name, &enclen)); - std::vector<byte> data2c = {0xC0}; - EXPECT_EQ(ARES_EBADNAME, - ares_expand_name(data2c.data(), data2c.data(), data2c.size(), - &name, &enclen)); - - // Indirection beyond enclosing data - std::vector<byte> data3a = {0xC0, 0x02}; - EXPECT_EQ(ARES_EBADNAME, - ares_expand_name(data3a.data(), data3a.data(), data3a.size(), - &name, &enclen)); - std::vector<byte> data3b = {0xC0, 0x0A, 'c', 'o', 'm', 0x00}; - EXPECT_EQ(ARES_EBADNAME, - ares_expand_name(data3b.data(), data3b.data(), data3b.size(), - &name, &enclen)); - - // Invalid top bits in label length - std::vector<byte> data4 = {0x03, 'c', 'o', 'm', 0x00, 0x80, 0x00}; - EXPECT_EQ(ARES_EBADNAME, - ares_expand_name(data4.data() + 5, data4.data(), data4.size(), - &name, &enclen)); - - // Label too long: 64-byte label, with invalid top 2 bits of length (01). - std::vector<byte> data5 = {0x40, - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', - 0x00}; - EXPECT_EQ(ARES_EBADNAME, - ares_expand_name(data5.data(), data5.data(), data5.size(), - &name, &enclen)) << name; - - // Incomplete indirect length - std::vector<byte> data6 = {0x03, 'c', 'o', 'm', 0x00, 0xC0}; - EXPECT_EQ(ARES_EBADNAME, - ares_expand_name(data6.data() + 5, data6.data(), data6.size(), - &name, &enclen)); - - // Indirection loops - std::vector<byte> data7 = {0xC0, 0x02, 0xC0, 0x00}; - EXPECT_EQ(ARES_EBADNAME, - ares_expand_name(data7.data(), data7.data(), data7.size(), - &name, &enclen)); - std::vector<byte> data8 = {3, 'd', 'e', 'f', 0xC0, 0x08, 0x00, 0x00, - 3, 'a', 'b', 'c', 0xC0, 0x00}; - EXPECT_EQ(ARES_EBADNAME, - ares_expand_name(data8.data(), data8.data(), data8.size(), - &name, &enclen)); - std::vector<byte> data9 = {0x12, 0x23, // start 2 bytes in - 3, 'd', 'e', 'f', 0xC0, 0x02}; - EXPECT_EQ(ARES_EBADNAME, - ares_expand_name(data9.data() + 2, data9.data(), data9.size(), - &name, &enclen)); -} - -TEST_F(LibraryTest, CreateEDNSQuery) { - byte* p; - int len; - EXPECT_EQ(ARES_SUCCESS, - ares_create_query("example.com", ns_c_in, ns_t_a, 0x1234, 0, - &p, &len, 1280)); - std::vector<byte> data(p, p + len); - ares_free_string(p); - - std::string actual = PacketToString(data); - DNSPacket pkt; - pkt.set_qid(0x1234).add_question(new DNSQuestion("example.com", ns_t_a)) - .add_additional(new DNSOptRR(0, 1280)); - std::string expected = PacketToString(pkt.data()); - EXPECT_EQ(expected, actual); -} - -TEST_F(LibraryTest, CreateRootQuery) { - byte* p; - int len; - ares_create_query(".", ns_c_in, ns_t_a, 0x1234, 0, &p, &len, 0); - std::vector<byte> data(p, p + len); - ares_free_string(p); - - std::string actual = PacketToString(data); - DNSPacket pkt; - pkt.set_qid(0x1234).add_question(new DNSQuestion("", ns_t_a)); - std::string expected = PacketToString(pkt.data()); - EXPECT_EQ(expected, actual); -} - -TEST_F(LibraryTest, Version) { - // Assume linked to same version - EXPECT_EQ(std::string(ARES_VERSION_STR), - std::string(ares_version(nullptr))); - int version; - ares_version(&version); - EXPECT_EQ(ARES_VERSION, version); -} - -TEST_F(LibraryTest, Strerror) { - EXPECT_EQ("Successful completion", - std::string(ares_strerror(ARES_SUCCESS))); - EXPECT_EQ("DNS query cancelled", - std::string(ares_strerror(ARES_ECANCELLED))); - EXPECT_EQ("unknown", - std::string(ares_strerror(99))); -} - -TEST_F(LibraryTest, ExpandString) { - std::vector<byte> s1 = { 3, 'a', 'b', 'c'}; - char* result = nullptr; - long len; - EXPECT_EQ(ARES_SUCCESS, - ares_expand_string(s1.data(), s1.data(), s1.size(), - (unsigned char**)&result, &len)); - EXPECT_EQ("abc", std::string(result)); - EXPECT_EQ(1 + 3, len); // amount of data consumed includes 1 byte len - ares_free_string(result); - result = nullptr; - EXPECT_EQ(ARES_EBADSTR, - ares_expand_string(s1.data() + 1, s1.data(), s1.size(), - (unsigned char**)&result, &len)); - EXPECT_EQ(ARES_EBADSTR, - ares_expand_string(s1.data() + 4, s1.data(), s1.size(), - (unsigned char**)&result, &len)); - SetAllocSizeFail(3 + 1); - EXPECT_EQ(ARES_ENOMEM, - ares_expand_string(s1.data(), s1.data(), s1.size(), - (unsigned char**)&result, &len)); -} - -} // namespace test -} // namespace ares +// Interesting question: should tacking on a search domain let the query +// through? It seems safer to reject it because "supersecret.onion.search" +// still leaks information about the query to malicious resolvers. +TEST_F(DefaultChannelTest, SearchOnionDomain) { + SearchResult result; + ares_search(channel_, "dontleak.onion", ns_c_in, ns_t_a, + SearchCallback, &result); + EXPECT_TRUE(result.done_); + EXPECT_EQ(ARES_ENOTFOUND, result.status_); +} + +TEST_F(DefaultChannelTest, SendFailure) { + unsigned char buf[2]; + SearchResult result; + ares_send(channel_, buf, sizeof(buf), SearchCallback, &result); + EXPECT_TRUE(result.done_); + EXPECT_EQ(ARES_EBADQUERY, result.status_); +} + +std::string ExpandName(const std::vector<byte>& data, int offset, + long *enclen) { + char *name = nullptr; + int rc = ares_expand_name(data.data() + offset, data.data(), data.size(), + &name, enclen); + EXPECT_EQ(ARES_SUCCESS, rc); + std::string result; + if (rc == ARES_SUCCESS) { + result = name; + } else { + result = "<error>"; + } + ares_free_string(name); + return result; +} + +TEST_F(LibraryTest, ExpandName) { + long enclen; + std::vector<byte> data1 = {1, 'a', 2, 'b', 'c', 3, 'd', 'e', 'f', 0}; + EXPECT_EQ("a.bc.def", ExpandName(data1, 0, &enclen)); + EXPECT_EQ(data1.size(), enclen); + + std::vector<byte> data2 = {0}; + EXPECT_EQ("", ExpandName(data2, 0, &enclen)); + EXPECT_EQ(1, enclen); + + // Complete name indirection + std::vector<byte> data3 = {0x12, 0x23, + 3, 'd', 'e', 'f', 0, + 0xC0, 2}; + EXPECT_EQ("def", ExpandName(data3, 2, &enclen)); + EXPECT_EQ(5, enclen); + EXPECT_EQ("def", ExpandName(data3, 7, &enclen)); + EXPECT_EQ(2, enclen); + + // One label then indirection + std::vector<byte> data4 = {0x12, 0x23, + 3, 'd', 'e', 'f', 0, + 1, 'a', 0xC0, 2}; + EXPECT_EQ("def", ExpandName(data4, 2, &enclen)); + EXPECT_EQ(5, enclen); + EXPECT_EQ("a.def", ExpandName(data4, 7, &enclen)); + EXPECT_EQ(4, enclen); + + // Two labels then indirection + std::vector<byte> data5 = {0x12, 0x23, + 3, 'd', 'e', 'f', 0, + 1, 'a', 1, 'b', 0xC0, 2}; + EXPECT_EQ("def", ExpandName(data5, 2, &enclen)); + EXPECT_EQ(5, enclen); + EXPECT_EQ("a.b.def", ExpandName(data5, 7, &enclen)); + EXPECT_EQ(6, enclen); + + // Empty name, indirection to empty name + std::vector<byte> data6 = {0x12, 0x23, + 0, + 0xC0, 2}; + EXPECT_EQ("", ExpandName(data6, 2, &enclen)); + EXPECT_EQ(1, enclen); + EXPECT_EQ("", ExpandName(data6, 3, &enclen)); + EXPECT_EQ(2, enclen); +} + +TEST_F(LibraryTest, ExpandNameFailure) { + std::vector<byte> data1 = {0x03, 'c', 'o', 'm', 0x00}; + char *name = nullptr; + long enclen; + SetAllocFail(1); + EXPECT_EQ(ARES_ENOMEM, + ares_expand_name(data1.data(), data1.data(), data1.size(), + &name, &enclen)); + + // Empty packet + EXPECT_EQ(ARES_EBADNAME, + ares_expand_name(data1.data(), data1.data(), 0, &name, &enclen)); + + // Start beyond enclosing data + EXPECT_EQ(ARES_EBADNAME, + ares_expand_name(data1.data() + data1.size(), data1.data(), data1.size(), + &name, &enclen)); + + // Length beyond size of enclosing data + std::vector<byte> data2a = {0x13, 'c', 'o', 'm', 0x00}; + EXPECT_EQ(ARES_EBADNAME, + ares_expand_name(data2a.data(), data2a.data(), data2a.size(), + &name, &enclen)); + std::vector<byte> data2b = {0x1}; + EXPECT_EQ(ARES_EBADNAME, + ares_expand_name(data2b.data(), data2b.data(), data2b.size(), + &name, &enclen)); + std::vector<byte> data2c = {0xC0}; + EXPECT_EQ(ARES_EBADNAME, + ares_expand_name(data2c.data(), data2c.data(), data2c.size(), + &name, &enclen)); + + // Indirection beyond enclosing data + std::vector<byte> data3a = {0xC0, 0x02}; + EXPECT_EQ(ARES_EBADNAME, + ares_expand_name(data3a.data(), data3a.data(), data3a.size(), + &name, &enclen)); + std::vector<byte> data3b = {0xC0, 0x0A, 'c', 'o', 'm', 0x00}; + EXPECT_EQ(ARES_EBADNAME, + ares_expand_name(data3b.data(), data3b.data(), data3b.size(), + &name, &enclen)); + + // Invalid top bits in label length + std::vector<byte> data4 = {0x03, 'c', 'o', 'm', 0x00, 0x80, 0x00}; + EXPECT_EQ(ARES_EBADNAME, + ares_expand_name(data4.data() + 5, data4.data(), data4.size(), + &name, &enclen)); + + // Label too long: 64-byte label, with invalid top 2 bits of length (01). + std::vector<byte> data5 = {0x40, + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', + 0x00}; + EXPECT_EQ(ARES_EBADNAME, + ares_expand_name(data5.data(), data5.data(), data5.size(), + &name, &enclen)) << name; + + // Incomplete indirect length + std::vector<byte> data6 = {0x03, 'c', 'o', 'm', 0x00, 0xC0}; + EXPECT_EQ(ARES_EBADNAME, + ares_expand_name(data6.data() + 5, data6.data(), data6.size(), + &name, &enclen)); + + // Indirection loops + std::vector<byte> data7 = {0xC0, 0x02, 0xC0, 0x00}; + EXPECT_EQ(ARES_EBADNAME, + ares_expand_name(data7.data(), data7.data(), data7.size(), + &name, &enclen)); + std::vector<byte> data8 = {3, 'd', 'e', 'f', 0xC0, 0x08, 0x00, 0x00, + 3, 'a', 'b', 'c', 0xC0, 0x00}; + EXPECT_EQ(ARES_EBADNAME, + ares_expand_name(data8.data(), data8.data(), data8.size(), + &name, &enclen)); + std::vector<byte> data9 = {0x12, 0x23, // start 2 bytes in + 3, 'd', 'e', 'f', 0xC0, 0x02}; + EXPECT_EQ(ARES_EBADNAME, + ares_expand_name(data9.data() + 2, data9.data(), data9.size(), + &name, &enclen)); +} + +TEST_F(LibraryTest, CreateEDNSQuery) { + byte* p; + int len; + EXPECT_EQ(ARES_SUCCESS, + ares_create_query("example.com", ns_c_in, ns_t_a, 0x1234, 0, + &p, &len, 1280)); + std::vector<byte> data(p, p + len); + ares_free_string(p); + + std::string actual = PacketToString(data); + DNSPacket pkt; + pkt.set_qid(0x1234).add_question(new DNSQuestion("example.com", ns_t_a)) + .add_additional(new DNSOptRR(0, 1280)); + std::string expected = PacketToString(pkt.data()); + EXPECT_EQ(expected, actual); +} + +TEST_F(LibraryTest, CreateRootQuery) { + byte* p; + int len; + ares_create_query(".", ns_c_in, ns_t_a, 0x1234, 0, &p, &len, 0); + std::vector<byte> data(p, p + len); + ares_free_string(p); + + std::string actual = PacketToString(data); + DNSPacket pkt; + pkt.set_qid(0x1234).add_question(new DNSQuestion("", ns_t_a)); + std::string expected = PacketToString(pkt.data()); + EXPECT_EQ(expected, actual); +} + +TEST_F(LibraryTest, Version) { + // Assume linked to same version + EXPECT_EQ(std::string(ARES_VERSION_STR), + std::string(ares_version(nullptr))); + int version; + ares_version(&version); + EXPECT_EQ(ARES_VERSION, version); +} + +TEST_F(LibraryTest, Strerror) { + EXPECT_EQ("Successful completion", + std::string(ares_strerror(ARES_SUCCESS))); + EXPECT_EQ("DNS query cancelled", + std::string(ares_strerror(ARES_ECANCELLED))); + EXPECT_EQ("unknown", + std::string(ares_strerror(99))); +} + +TEST_F(LibraryTest, ExpandString) { + std::vector<byte> s1 = { 3, 'a', 'b', 'c'}; + char* result = nullptr; + long len; + EXPECT_EQ(ARES_SUCCESS, + ares_expand_string(s1.data(), s1.data(), s1.size(), + (unsigned char**)&result, &len)); + EXPECT_EQ("abc", std::string(result)); + EXPECT_EQ(1 + 3, len); // amount of data consumed includes 1 byte len + ares_free_string(result); + result = nullptr; + EXPECT_EQ(ARES_EBADSTR, + ares_expand_string(s1.data() + 1, s1.data(), s1.size(), + (unsigned char**)&result, &len)); + EXPECT_EQ(ARES_EBADSTR, + ares_expand_string(s1.data() + 4, s1.data(), s1.size(), + (unsigned char**)&result, &len)); + SetAllocSizeFail(3 + 1); + EXPECT_EQ(ARES_ENOMEM, + ares_expand_string(s1.data(), s1.data(), s1.size(), + (unsigned char**)&result, &len)); +} + +} // namespace test +} // namespace ares diff --git a/contrib/libs/c-ares/test/ares-test-mock.cc b/contrib/libs/c-ares/test/ares-test-mock.cc index fdae07fef6..80e9fc02b0 100644 --- a/contrib/libs/c-ares/test/ares-test-mock.cc +++ b/contrib/libs/c-ares/test/ares-test-mock.cc @@ -1,941 +1,941 @@ -#include "ares-test.h" -#include "dns-proto.h" - -#include <sstream> -#include <vector> - -using testing::InvokeWithoutArgs; -using testing::DoAll; - -namespace ares { -namespace test { - -TEST_P(MockChannelTest, Basic) { - std::vector<byte> reply = { - 0x00, 0x00, // qid - 0x84, // response + query + AA + not-TC + not-RD - 0x00, // not-RA + not-Z + not-AD + not-CD + rc=NoError - 0x00, 0x01, // 1 question - 0x00, 0x01, // 1 answer RRs - 0x00, 0x00, // 0 authority RRs - 0x00, 0x00, // 0 additional RRs - // Question - 0x03, 'w', 'w', 'w', - 0x06, 'g', 'o', 'o', 'g', 'l', 'e', - 0x03, 'c', 'o', 'm', - 0x00, - 0x00, 0x01, // type A - 0x00, 0x01, // class IN - // Answer - 0x03, 'w', 'w', 'w', - 0x06, 'g', 'o', 'o', 'g', 'l', 'e', - 0x03, 'c', 'o', 'm', - 0x00, - 0x00, 0x01, // type A - 0x00, 0x01, // class IN - 0x00, 0x00, 0x01, 0x00, // TTL - 0x00, 0x04, // rdata length - 0x01, 0x02, 0x03, 0x04 - }; - - ON_CALL(server_, OnRequest("www.google.com", ns_t_a)) - .WillByDefault(SetReplyData(&server_, reply)); - - HostResult result; - ares_gethostbyname(channel_, "www.google.com.", AF_INET, HostCallback, &result); - Process(); - EXPECT_TRUE(result.done_); - std::stringstream ss; - ss << result.host_; - EXPECT_EQ("{'www.google.com' aliases=[] addrs=[1.2.3.4]}", ss.str()); -} - -// UDP only so mock server doesn't get confused by concatenated requests +#include "ares-test.h" +#include "dns-proto.h" + +#include <sstream> +#include <vector> + +using testing::InvokeWithoutArgs; +using testing::DoAll; + +namespace ares { +namespace test { + +TEST_P(MockChannelTest, Basic) { + std::vector<byte> reply = { + 0x00, 0x00, // qid + 0x84, // response + query + AA + not-TC + not-RD + 0x00, // not-RA + not-Z + not-AD + not-CD + rc=NoError + 0x00, 0x01, // 1 question + 0x00, 0x01, // 1 answer RRs + 0x00, 0x00, // 0 authority RRs + 0x00, 0x00, // 0 additional RRs + // Question + 0x03, 'w', 'w', 'w', + 0x06, 'g', 'o', 'o', 'g', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + 0x00, 0x01, // type A + 0x00, 0x01, // class IN + // Answer + 0x03, 'w', 'w', 'w', + 0x06, 'g', 'o', 'o', 'g', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + 0x00, 0x01, // type A + 0x00, 0x01, // class IN + 0x00, 0x00, 0x01, 0x00, // TTL + 0x00, 0x04, // rdata length + 0x01, 0x02, 0x03, 0x04 + }; + + ON_CALL(server_, OnRequest("www.google.com", ns_t_a)) + .WillByDefault(SetReplyData(&server_, reply)); + + HostResult result; + ares_gethostbyname(channel_, "www.google.com.", AF_INET, HostCallback, &result); + Process(); + EXPECT_TRUE(result.done_); + std::stringstream ss; + ss << result.host_; + EXPECT_EQ("{'www.google.com' aliases=[] addrs=[1.2.3.4]}", ss.str()); +} + +// UDP only so mock server doesn't get confused by concatenated requests TEST_P(MockUDPChannelTest, GetHostByNameParallelLookups) { - DNSPacket rsp1; - rsp1.set_response().set_aa() - .add_question(new DNSQuestion("www.google.com", ns_t_a)) - .add_answer(new DNSARR("www.google.com", 100, {2, 3, 4, 5})); - ON_CALL(server_, OnRequest("www.google.com", ns_t_a)) - .WillByDefault(SetReply(&server_, &rsp1)); - DNSPacket rsp2; - rsp2.set_response().set_aa() - .add_question(new DNSQuestion("www.example.com", ns_t_a)) - .add_answer(new DNSARR("www.example.com", 100, {1, 2, 3, 4})); - ON_CALL(server_, OnRequest("www.example.com", ns_t_a)) - .WillByDefault(SetReply(&server_, &rsp2)); - - HostResult result1; - ares_gethostbyname(channel_, "www.google.com.", AF_INET, HostCallback, &result1); - HostResult result2; - ares_gethostbyname(channel_, "www.example.com.", AF_INET, HostCallback, &result2); - HostResult result3; - ares_gethostbyname(channel_, "www.google.com.", AF_INET, HostCallback, &result3); - Process(); - EXPECT_TRUE(result1.done_); - EXPECT_TRUE(result2.done_); - EXPECT_TRUE(result3.done_); - std::stringstream ss1; - ss1 << result1.host_; - EXPECT_EQ("{'www.google.com' aliases=[] addrs=[2.3.4.5]}", ss1.str()); - std::stringstream ss2; - ss2 << result2.host_; - EXPECT_EQ("{'www.example.com' aliases=[] addrs=[1.2.3.4]}", ss2.str()); - std::stringstream ss3; - ss3 << result3.host_; - EXPECT_EQ("{'www.google.com' aliases=[] addrs=[2.3.4.5]}", ss3.str()); -} - -// UDP to TCP specific test -TEST_P(MockUDPChannelTest, TruncationRetry) { - DNSPacket rsptruncated; - rsptruncated.set_response().set_aa().set_tc() - .add_question(new DNSQuestion("www.google.com", ns_t_a)); - DNSPacket rspok; - rspok.set_response() - .add_question(new DNSQuestion("www.google.com", ns_t_a)) - .add_answer(new DNSARR("www.google.com", 100, {1, 2, 3, 4})); - EXPECT_CALL(server_, OnRequest("www.google.com", ns_t_a)) - .WillOnce(SetReply(&server_, &rsptruncated)) - .WillOnce(SetReply(&server_, &rspok)); - HostResult result; - ares_gethostbyname(channel_, "www.google.com.", AF_INET, HostCallback, &result); - Process(); - EXPECT_TRUE(result.done_); - std::stringstream ss; - ss << result.host_; - EXPECT_EQ("{'www.google.com' aliases=[] addrs=[1.2.3.4]}", ss.str()); -} - -static int sock_cb_count = 0; -static int SocketConnectCallback(ares_socket_t fd, int type, void *data) { - int rc = *(int*)data; - if (verbose) std::cerr << "SocketConnectCallback(" << fd << ") invoked" << std::endl; - sock_cb_count++; - return rc; -} - -TEST_P(MockChannelTest, SockCallback) { - DNSPacket rsp; - rsp.set_response().set_aa() - .add_question(new DNSQuestion("www.google.com", ns_t_a)) - .add_answer(new DNSARR("www.google.com", 100, {2, 3, 4, 5})); - EXPECT_CALL(server_, OnRequest("www.google.com", ns_t_a)) - .WillOnce(SetReply(&server_, &rsp)); - - // Get notified of new sockets - int rc = ARES_SUCCESS; - ares_set_socket_callback(channel_, SocketConnectCallback, &rc); - - HostResult result; - sock_cb_count = 0; - ares_gethostbyname(channel_, "www.google.com.", AF_INET, HostCallback, &result); - Process(); - EXPECT_EQ(1, sock_cb_count); - EXPECT_TRUE(result.done_); - std::stringstream ss; - ss << result.host_; - EXPECT_EQ("{'www.google.com' aliases=[] addrs=[2.3.4.5]}", ss.str()); -} - -TEST_P(MockChannelTest, SockFailCallback) { - // Notification of new sockets gives an error. - int rc = -1; - ares_set_socket_callback(channel_, SocketConnectCallback, &rc); - - HostResult result; - sock_cb_count = 0; - ares_gethostbyname(channel_, "www.google.com.", AF_INET, HostCallback, &result); - Process(); - EXPECT_LT(1, sock_cb_count); - EXPECT_TRUE(result.done_); - EXPECT_EQ(ARES_ECONNREFUSED, result.status_); -} - -static int sock_config_cb_count = 0; -static int SocketConfigureCallback(ares_socket_t fd, int type, void *data) { - int rc = *(int*)data; - if (verbose) std::cerr << "SocketConfigureCallback(" << fd << ") invoked" << std::endl; - sock_config_cb_count++; - return rc; -} - -TEST_P(MockChannelTest, SockConfigureCallback) { - DNSPacket rsp; - rsp.set_response().set_aa() - .add_question(new DNSQuestion("www.google.com", ns_t_a)) - .add_answer(new DNSARR("www.google.com", 100, {2, 3, 4, 5})); - EXPECT_CALL(server_, OnRequest("www.google.com", ns_t_a)) - .WillOnce(SetReply(&server_, &rsp)); - - // Get notified of new sockets - int rc = ARES_SUCCESS; - ares_set_socket_configure_callback(channel_, SocketConfigureCallback, &rc); - - HostResult result; - sock_config_cb_count = 0; - ares_gethostbyname(channel_, "www.google.com.", AF_INET, HostCallback, &result); - Process(); - EXPECT_EQ(1, sock_config_cb_count); - EXPECT_TRUE(result.done_); - std::stringstream ss; - ss << result.host_; - EXPECT_EQ("{'www.google.com' aliases=[] addrs=[2.3.4.5]}", ss.str()); -} - -TEST_P(MockChannelTest, SockConfigureFailCallback) { - // Notification of new sockets gives an error. - int rc = -1; - ares_set_socket_configure_callback(channel_, SocketConfigureCallback, &rc); - - HostResult result; - sock_config_cb_count = 0; - ares_gethostbyname(channel_, "www.google.com.", AF_INET, HostCallback, &result); - Process(); - EXPECT_LT(1, sock_config_cb_count); - EXPECT_TRUE(result.done_); - EXPECT_EQ(ARES_ECONNREFUSED, result.status_); -} - -// TCP only to prevent retries -TEST_P(MockTCPChannelTest, MalformedResponse) { - std::vector<byte> one = {0x01}; - EXPECT_CALL(server_, OnRequest("www.google.com", ns_t_a)) - .WillOnce(SetReplyData(&server_, one)); - - HostResult result; - ares_gethostbyname(channel_, "www.google.com.", AF_INET, HostCallback, &result); - Process(); - EXPECT_TRUE(result.done_); - EXPECT_EQ(ARES_ETIMEOUT, result.status_); -} - -TEST_P(MockTCPChannelTest, FormErrResponse) { - DNSPacket rsp; - rsp.set_response().set_aa() - .add_question(new DNSQuestion("www.google.com", ns_t_a)); - rsp.set_rcode(ns_r_formerr); - EXPECT_CALL(server_, OnRequest("www.google.com", ns_t_a)) - .WillOnce(SetReply(&server_, &rsp)); - HostResult result; - ares_gethostbyname(channel_, "www.google.com.", AF_INET, HostCallback, &result); - Process(); - EXPECT_TRUE(result.done_); - EXPECT_EQ(ARES_EFORMERR, result.status_); -} - -TEST_P(MockTCPChannelTest, ServFailResponse) { - DNSPacket rsp; - rsp.set_response().set_aa() - .add_question(new DNSQuestion("www.google.com", ns_t_a)); - rsp.set_rcode(ns_r_servfail); - EXPECT_CALL(server_, OnRequest("www.google.com", ns_t_a)) - .WillOnce(SetReply(&server_, &rsp)); - HostResult result; - ares_gethostbyname(channel_, "www.google.com.", AF_INET, HostCallback, &result); - Process(); - EXPECT_TRUE(result.done_); - // ARES_FLAG_NOCHECKRESP not set, so SERVFAIL consumed - EXPECT_EQ(ARES_ECONNREFUSED, result.status_); -} - -TEST_P(MockTCPChannelTest, NotImplResponse) { - DNSPacket rsp; - rsp.set_response().set_aa() - .add_question(new DNSQuestion("www.google.com", ns_t_a)); - rsp.set_rcode(ns_r_notimpl); - EXPECT_CALL(server_, OnRequest("www.google.com", ns_t_a)) - .WillOnce(SetReply(&server_, &rsp)); - HostResult result; - ares_gethostbyname(channel_, "www.google.com.", AF_INET, HostCallback, &result); - Process(); - EXPECT_TRUE(result.done_); - // ARES_FLAG_NOCHECKRESP not set, so NOTIMPL consumed - EXPECT_EQ(ARES_ECONNREFUSED, result.status_); -} - -TEST_P(MockTCPChannelTest, RefusedResponse) { - DNSPacket rsp; - rsp.set_response().set_aa() - .add_question(new DNSQuestion("www.google.com", ns_t_a)); - rsp.set_rcode(ns_r_refused); - EXPECT_CALL(server_, OnRequest("www.google.com", ns_t_a)) - .WillOnce(SetReply(&server_, &rsp)); - HostResult result; - ares_gethostbyname(channel_, "www.google.com.", AF_INET, HostCallback, &result); - Process(); - EXPECT_TRUE(result.done_); - // ARES_FLAG_NOCHECKRESP not set, so REFUSED consumed - EXPECT_EQ(ARES_ECONNREFUSED, result.status_); -} - -TEST_P(MockTCPChannelTest, YXDomainResponse) { - DNSPacket rsp; - rsp.set_response().set_aa() - .add_question(new DNSQuestion("www.google.com", ns_t_a)); - rsp.set_rcode(ns_r_yxdomain); - EXPECT_CALL(server_, OnRequest("www.google.com", ns_t_a)) - .WillOnce(SetReply(&server_, &rsp)); - HostResult result; - ares_gethostbyname(channel_, "www.google.com.", AF_INET, HostCallback, &result); - Process(); - EXPECT_TRUE(result.done_); - EXPECT_EQ(ARES_ENODATA, result.status_); -} - -class MockExtraOptsTest - : public MockChannelOptsTest, - public ::testing::WithParamInterface< std::pair<int, bool> > { - public: - MockExtraOptsTest() - : MockChannelOptsTest(1, GetParam().first, GetParam().second, - FillOptions(&opts_), - ARES_OPT_SOCK_SNDBUF|ARES_OPT_SOCK_RCVBUF) {} - static struct ares_options* FillOptions(struct ares_options * opts) { - memset(opts, 0, sizeof(struct ares_options)); - // Set a few options that affect socket communications - opts->socket_send_buffer_size = 514; - opts->socket_receive_buffer_size = 514; - return opts; - } - private: - struct ares_options opts_; -}; - -TEST_P(MockExtraOptsTest, SimpleQuery) { - ares_set_local_ip4(channel_, 0x7F000001); - byte addr6[16] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}; - ares_set_local_ip6(channel_, addr6); - ares_set_local_dev(channel_, "dummy"); - - DNSPacket rsp; - rsp.set_response().set_aa() - .add_question(new DNSQuestion("www.google.com", ns_t_a)) - .add_answer(new DNSARR("www.google.com", 100, {2, 3, 4, 5})); - ON_CALL(server_, OnRequest("www.google.com", ns_t_a)) - .WillByDefault(SetReply(&server_, &rsp)); - - HostResult result; - ares_gethostbyname(channel_, "www.google.com.", AF_INET, HostCallback, &result); - Process(); - EXPECT_TRUE(result.done_); - std::stringstream ss; - ss << result.host_; - EXPECT_EQ("{'www.google.com' aliases=[] addrs=[2.3.4.5]}", ss.str()); -} - -class MockFlagsChannelOptsTest - : public MockChannelOptsTest, - public ::testing::WithParamInterface< std::pair<int, bool> > { - public: - MockFlagsChannelOptsTest(int flags) - : MockChannelOptsTest(1, GetParam().first, GetParam().second, - FillOptions(&opts_, flags), ARES_OPT_FLAGS) {} - static struct ares_options* FillOptions(struct ares_options * opts, int flags) { - memset(opts, 0, sizeof(struct ares_options)); - opts->flags = flags; - return opts; - } - private: - struct ares_options opts_; -}; - -class MockNoCheckRespChannelTest : public MockFlagsChannelOptsTest { - public: - MockNoCheckRespChannelTest() : MockFlagsChannelOptsTest(ARES_FLAG_NOCHECKRESP) {} -}; - -TEST_P(MockNoCheckRespChannelTest, ServFailResponse) { - DNSPacket rsp; - rsp.set_response().set_aa() - .add_question(new DNSQuestion("www.google.com", ns_t_a)); - rsp.set_rcode(ns_r_servfail); - ON_CALL(server_, OnRequest("www.google.com", ns_t_a)) - .WillByDefault(SetReply(&server_, &rsp)); - HostResult result; - ares_gethostbyname(channel_, "www.google.com.", AF_INET, HostCallback, &result); - Process(); - EXPECT_TRUE(result.done_); - EXPECT_EQ(ARES_ESERVFAIL, result.status_); -} - -TEST_P(MockNoCheckRespChannelTest, NotImplResponse) { - DNSPacket rsp; - rsp.set_response().set_aa() - .add_question(new DNSQuestion("www.google.com", ns_t_a)); - rsp.set_rcode(ns_r_notimpl); - ON_CALL(server_, OnRequest("www.google.com", ns_t_a)) - .WillByDefault(SetReply(&server_, &rsp)); - HostResult result; - ares_gethostbyname(channel_, "www.google.com.", AF_INET, HostCallback, &result); - Process(); - EXPECT_TRUE(result.done_); - EXPECT_EQ(ARES_ENOTIMP, result.status_); -} - -TEST_P(MockNoCheckRespChannelTest, RefusedResponse) { - DNSPacket rsp; - rsp.set_response().set_aa() - .add_question(new DNSQuestion("www.google.com", ns_t_a)); - rsp.set_rcode(ns_r_refused); - ON_CALL(server_, OnRequest("www.google.com", ns_t_a)) - .WillByDefault(SetReply(&server_, &rsp)); - HostResult result; - ares_gethostbyname(channel_, "www.google.com.", AF_INET, HostCallback, &result); - Process(); - EXPECT_TRUE(result.done_); - EXPECT_EQ(ARES_EREFUSED, result.status_); -} - -class MockEDNSChannelTest : public MockFlagsChannelOptsTest { - public: - MockEDNSChannelTest() : MockFlagsChannelOptsTest(ARES_FLAG_EDNS) {} -}; - -TEST_P(MockEDNSChannelTest, RetryWithoutEDNS) { - DNSPacket rspfail; - rspfail.set_response().set_aa().set_rcode(ns_r_servfail) - .add_question(new DNSQuestion("www.google.com", ns_t_a)); - DNSPacket rspok; - rspok.set_response() - .add_question(new DNSQuestion("www.google.com", ns_t_a)) - .add_answer(new DNSARR("www.google.com", 100, {1, 2, 3, 4})); - EXPECT_CALL(server_, OnRequest("www.google.com", ns_t_a)) - .WillOnce(SetReply(&server_, &rspfail)) - .WillOnce(SetReply(&server_, &rspok)); - HostResult result; - ares_gethostbyname(channel_, "www.google.com.", AF_INET, HostCallback, &result); - Process(); - EXPECT_TRUE(result.done_); - std::stringstream ss; - ss << result.host_; - EXPECT_EQ("{'www.google.com' aliases=[] addrs=[1.2.3.4]}", ss.str()); -} - -TEST_P(MockChannelTest, SearchDomains) { - DNSPacket nofirst; - nofirst.set_response().set_aa().set_rcode(ns_r_nxdomain) - .add_question(new DNSQuestion("www.first.com", ns_t_a)); - ON_CALL(server_, OnRequest("www.first.com", ns_t_a)) - .WillByDefault(SetReply(&server_, &nofirst)); - DNSPacket nosecond; - nosecond.set_response().set_aa().set_rcode(ns_r_nxdomain) - .add_question(new DNSQuestion("www.second.org", ns_t_a)); - ON_CALL(server_, OnRequest("www.second.org", ns_t_a)) - .WillByDefault(SetReply(&server_, &nosecond)); - DNSPacket yesthird; - yesthird.set_response().set_aa() - .add_question(new DNSQuestion("www.third.gov", ns_t_a)) - .add_answer(new DNSARR("www.third.gov", 0x0200, {2, 3, 4, 5})); - ON_CALL(server_, OnRequest("www.third.gov", ns_t_a)) - .WillByDefault(SetReply(&server_, &yesthird)); - - HostResult result; - ares_gethostbyname(channel_, "www", AF_INET, HostCallback, &result); - Process(); - EXPECT_TRUE(result.done_); - std::stringstream ss; - ss << result.host_; - EXPECT_EQ("{'www.third.gov' aliases=[] addrs=[2.3.4.5]}", ss.str()); -} - -// Relies on retries so is UDP-only -TEST_P(MockUDPChannelTest, SearchDomainsWithResentReply) { - DNSPacket nofirst; - nofirst.set_response().set_aa().set_rcode(ns_r_nxdomain) - .add_question(new DNSQuestion("www.first.com", ns_t_a)); - EXPECT_CALL(server_, OnRequest("www.first.com", ns_t_a)) - .WillOnce(SetReply(&server_, &nofirst)); - DNSPacket nosecond; - nosecond.set_response().set_aa().set_rcode(ns_r_nxdomain) - .add_question(new DNSQuestion("www.second.org", ns_t_a)); - EXPECT_CALL(server_, OnRequest("www.second.org", ns_t_a)) - .WillOnce(SetReply(&server_, &nosecond)); - DNSPacket yesthird; - yesthird.set_response().set_aa() - .add_question(new DNSQuestion("www.third.gov", ns_t_a)) - .add_answer(new DNSARR("www.third.gov", 0x0200, {2, 3, 4, 5})); - // Before sending the real answer, resend an earlier reply - EXPECT_CALL(server_, OnRequest("www.third.gov", ns_t_a)) - .WillOnce(DoAll(SetReply(&server_, &nofirst), - SetReplyQID(&server_, 123))) - .WillOnce(DoAll(SetReply(&server_, &yesthird), - SetReplyQID(&server_, -1))); - - HostResult result; - ares_gethostbyname(channel_, "www", AF_INET, HostCallback, &result); - Process(); - EXPECT_TRUE(result.done_); - std::stringstream ss; - ss << result.host_; - EXPECT_EQ("{'www.third.gov' aliases=[] addrs=[2.3.4.5]}", ss.str()); -} - -TEST_P(MockChannelTest, SearchDomainsBare) { - DNSPacket nofirst; - nofirst.set_response().set_aa().set_rcode(ns_r_nxdomain) - .add_question(new DNSQuestion("www.first.com", ns_t_a)); - ON_CALL(server_, OnRequest("www.first.com", ns_t_a)) - .WillByDefault(SetReply(&server_, &nofirst)); - DNSPacket nosecond; - nosecond.set_response().set_aa().set_rcode(ns_r_nxdomain) - .add_question(new DNSQuestion("www.second.org", ns_t_a)); - ON_CALL(server_, OnRequest("www.second.org", ns_t_a)) - .WillByDefault(SetReply(&server_, &nosecond)); - DNSPacket nothird; - nothird.set_response().set_aa().set_rcode(ns_r_nxdomain) - .add_question(new DNSQuestion("www.third.gov", ns_t_a)); - ON_CALL(server_, OnRequest("www.third.gov", ns_t_a)) - .WillByDefault(SetReply(&server_, ¬hird)); - DNSPacket yesbare; - yesbare.set_response().set_aa() - .add_question(new DNSQuestion("www", ns_t_a)) - .add_answer(new DNSARR("www", 0x0200, {2, 3, 4, 5})); - ON_CALL(server_, OnRequest("www", ns_t_a)) - .WillByDefault(SetReply(&server_, &yesbare)); - - HostResult result; - ares_gethostbyname(channel_, "www", AF_INET, HostCallback, &result); - Process(); - EXPECT_TRUE(result.done_); - std::stringstream ss; - ss << result.host_; - EXPECT_EQ("{'www' aliases=[] addrs=[2.3.4.5]}", ss.str()); -} - -TEST_P(MockChannelTest, SearchNoDataThenSuccess) { - // First two search domains recognize the name but have no A records. - DNSPacket nofirst; - nofirst.set_response().set_aa() - .add_question(new DNSQuestion("www.first.com", ns_t_a)); - ON_CALL(server_, OnRequest("www.first.com", ns_t_a)) - .WillByDefault(SetReply(&server_, &nofirst)); - DNSPacket nosecond; - nosecond.set_response().set_aa() - .add_question(new DNSQuestion("www.second.org", ns_t_a)); - ON_CALL(server_, OnRequest("www.second.org", ns_t_a)) - .WillByDefault(SetReply(&server_, &nosecond)); - DNSPacket yesthird; - yesthird.set_response().set_aa() - .add_question(new DNSQuestion("www.third.gov", ns_t_a)) - .add_answer(new DNSARR("www.third.gov", 0x0200, {2, 3, 4, 5})); - ON_CALL(server_, OnRequest("www.third.gov", ns_t_a)) - .WillByDefault(SetReply(&server_, &yesthird)); - - HostResult result; - ares_gethostbyname(channel_, "www", AF_INET, HostCallback, &result); - Process(); - EXPECT_TRUE(result.done_); - std::stringstream ss; - ss << result.host_; - EXPECT_EQ("{'www.third.gov' aliases=[] addrs=[2.3.4.5]}", ss.str()); -} - -TEST_P(MockChannelTest, SearchNoDataThenNoDataBare) { - // First two search domains recognize the name but have no A records. - DNSPacket nofirst; - nofirst.set_response().set_aa() - .add_question(new DNSQuestion("www.first.com", ns_t_a)); - ON_CALL(server_, OnRequest("www.first.com", ns_t_a)) - .WillByDefault(SetReply(&server_, &nofirst)); - DNSPacket nosecond; - nosecond.set_response().set_aa() - .add_question(new DNSQuestion("www.second.org", ns_t_a)); - ON_CALL(server_, OnRequest("www.second.org", ns_t_a)) - .WillByDefault(SetReply(&server_, &nosecond)); - DNSPacket nothird; - nothird.set_response().set_aa() - .add_question(new DNSQuestion("www.third.gov", ns_t_a)); - ON_CALL(server_, OnRequest("www.third.gov", ns_t_a)) - .WillByDefault(SetReply(&server_, ¬hird)); - DNSPacket nobare; - nobare.set_response().set_aa() - .add_question(new DNSQuestion("www", ns_t_a)); - ON_CALL(server_, OnRequest("www", ns_t_a)) - .WillByDefault(SetReply(&server_, &nobare)); - - HostResult result; - ares_gethostbyname(channel_, "www", AF_INET, HostCallback, &result); - Process(); - EXPECT_TRUE(result.done_); - EXPECT_EQ(ARES_ENODATA, result.status_); -} - -TEST_P(MockChannelTest, SearchNoDataThenFail) { - // First two search domains recognize the name but have no A records. - DNSPacket nofirst; - nofirst.set_response().set_aa() - .add_question(new DNSQuestion("www.first.com", ns_t_a)); - ON_CALL(server_, OnRequest("www.first.com", ns_t_a)) - .WillByDefault(SetReply(&server_, &nofirst)); - DNSPacket nosecond; - nosecond.set_response().set_aa() - .add_question(new DNSQuestion("www.second.org", ns_t_a)); - ON_CALL(server_, OnRequest("www.second.org", ns_t_a)) - .WillByDefault(SetReply(&server_, &nosecond)); - DNSPacket nothird; - nothird.set_response().set_aa() - .add_question(new DNSQuestion("www.third.gov", ns_t_a)); - ON_CALL(server_, OnRequest("www.third.gov", ns_t_a)) - .WillByDefault(SetReply(&server_, ¬hird)); - DNSPacket nobare; - nobare.set_response().set_aa().set_rcode(ns_r_nxdomain) - .add_question(new DNSQuestion("www", ns_t_a)); - ON_CALL(server_, OnRequest("www", ns_t_a)) - .WillByDefault(SetReply(&server_, &nobare)); - - HostResult result; - ares_gethostbyname(channel_, "www", AF_INET, HostCallback, &result); - Process(); - EXPECT_TRUE(result.done_); - EXPECT_EQ(ARES_ENODATA, result.status_); -} - -TEST_P(MockChannelTest, SearchAllocFailure) { - SearchResult result; - SetAllocFail(1); - ares_search(channel_, "fully.qualified.", ns_c_in, ns_t_a, SearchCallback, &result); - /* Already done */ - EXPECT_TRUE(result.done_); - EXPECT_EQ(ARES_ENOMEM, result.status_); -} - -TEST_P(MockChannelTest, SearchHighNdots) { - DNSPacket nobare; - nobare.set_response().set_aa().set_rcode(ns_r_nxdomain) - .add_question(new DNSQuestion("a.b.c.w.w.w", ns_t_a)); - ON_CALL(server_, OnRequest("a.b.c.w.w.w", ns_t_a)) - .WillByDefault(SetReply(&server_, &nobare)); - DNSPacket yesfirst; - yesfirst.set_response().set_aa() - .add_question(new DNSQuestion("a.b.c.w.w.w.first.com", ns_t_a)) - .add_answer(new DNSARR("a.b.c.w.w.w.first.com", 0x0200, {2, 3, 4, 5})); - ON_CALL(server_, OnRequest("a.b.c.w.w.w.first.com", ns_t_a)) - .WillByDefault(SetReply(&server_, &yesfirst)); - - SearchResult result; - ares_search(channel_, "a.b.c.w.w.w", ns_c_in, ns_t_a, SearchCallback, &result); - Process(); - EXPECT_TRUE(result.done_); - EXPECT_EQ(ARES_SUCCESS, result.status_); - std::stringstream ss; - ss << PacketToString(result.data_); - EXPECT_EQ("RSP QRY AA NOERROR Q:{'a.b.c.w.w.w.first.com' IN A} " - "A:{'a.b.c.w.w.w.first.com' IN A TTL=512 2.3.4.5}", - ss.str()); -} - -TEST_P(MockChannelTest, UnspecifiedFamilyV6) { - DNSPacket rsp6; - rsp6.set_response().set_aa() - .add_question(new DNSQuestion("example.com", ns_t_aaaa)) - .add_answer(new DNSAaaaRR("example.com", 100, - {0x21, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03})); - ON_CALL(server_, OnRequest("example.com", ns_t_aaaa)) - .WillByDefault(SetReply(&server_, &rsp6)); - - HostResult result; - ares_gethostbyname(channel_, "example.com.", AF_UNSPEC, HostCallback, &result); - Process(); - EXPECT_TRUE(result.done_); - std::stringstream ss; - ss << result.host_; - // Default to IPv6 when both are available. - EXPECT_EQ("{'example.com' aliases=[] addrs=[2121:0000:0000:0000:0000:0000:0000:0303]}", ss.str()); -} - -TEST_P(MockChannelTest, UnspecifiedFamilyV4) { - DNSPacket rsp6; - rsp6.set_response().set_aa() - .add_question(new DNSQuestion("example.com", ns_t_aaaa)); - ON_CALL(server_, OnRequest("example.com", ns_t_aaaa)) - .WillByDefault(SetReply(&server_, &rsp6)); - DNSPacket rsp4; - rsp4.set_response().set_aa() - .add_question(new DNSQuestion("example.com", ns_t_a)) - .add_answer(new DNSARR("example.com", 100, {2, 3, 4, 5})); - ON_CALL(server_, OnRequest("example.com", ns_t_a)) - .WillByDefault(SetReply(&server_, &rsp4)); - - HostResult result; - ares_gethostbyname(channel_, "example.com.", AF_UNSPEC, HostCallback, &result); - Process(); - EXPECT_TRUE(result.done_); - std::stringstream ss; - ss << result.host_; - EXPECT_EQ("{'example.com' aliases=[] addrs=[2.3.4.5]}", ss.str()); -} - -TEST_P(MockChannelTest, UnspecifiedFamilyNoData) { - DNSPacket rsp6; - rsp6.set_response().set_aa() - .add_question(new DNSQuestion("example.com", ns_t_aaaa)) - .add_answer(new DNSCnameRR("example.com", 100, "elsewhere.com")); - ON_CALL(server_, OnRequest("example.com", ns_t_aaaa)) - .WillByDefault(SetReply(&server_, &rsp6)); - DNSPacket rsp4; - rsp4.set_response().set_aa() - .add_question(new DNSQuestion("example.com", ns_t_a)); - ON_CALL(server_, OnRequest("example.com", ns_t_a)) - .WillByDefault(SetReply(&server_, &rsp4)); - - HostResult result; - ares_gethostbyname(channel_, "example.com.", AF_UNSPEC, HostCallback, &result); - Process(); - EXPECT_TRUE(result.done_); - std::stringstream ss; - ss << result.host_; - EXPECT_EQ("{'' aliases=[] addrs=[]}", ss.str()); -} - -TEST_P(MockChannelTest, UnspecifiedFamilyCname6A4) { - DNSPacket rsp6; - rsp6.set_response().set_aa() - .add_question(new DNSQuestion("example.com", ns_t_aaaa)) - .add_answer(new DNSCnameRR("example.com", 100, "elsewhere.com")); - ON_CALL(server_, OnRequest("example.com", ns_t_aaaa)) - .WillByDefault(SetReply(&server_, &rsp6)); - DNSPacket rsp4; - rsp4.set_response().set_aa() - .add_question(new DNSQuestion("example.com", ns_t_a)) - .add_answer(new DNSARR("example.com", 100, {1, 2, 3, 4})); - ON_CALL(server_, OnRequest("example.com", ns_t_a)) - .WillByDefault(SetReply(&server_, &rsp4)); - - HostResult result; - ares_gethostbyname(channel_, "example.com.", AF_UNSPEC, HostCallback, &result); - Process(); - EXPECT_TRUE(result.done_); - std::stringstream ss; - ss << result.host_; - EXPECT_EQ("{'example.com' aliases=[] addrs=[1.2.3.4]}", ss.str()); -} - -TEST_P(MockChannelTest, ExplicitIP) { - HostResult result; - ares_gethostbyname(channel_, "1.2.3.4", AF_INET, HostCallback, &result); - EXPECT_TRUE(result.done_); // Immediate return - EXPECT_EQ(ARES_SUCCESS, result.status_); - std::stringstream ss; - ss << result.host_; - EXPECT_EQ("{'1.2.3.4' aliases=[] addrs=[1.2.3.4]}", ss.str()); -} - -TEST_P(MockChannelTest, ExplicitIPAllocFail) { - HostResult result; - SetAllocSizeFail(strlen("1.2.3.4") + 1); - ares_gethostbyname(channel_, "1.2.3.4", AF_INET, HostCallback, &result); - EXPECT_TRUE(result.done_); // Immediate return - EXPECT_EQ(ARES_ENOMEM, result.status_); -} - -TEST_P(MockChannelTest, SortListV4) { - DNSPacket rsp; - rsp.set_response().set_aa() - .add_question(new DNSQuestion("example.com", ns_t_a)) - .add_answer(new DNSARR("example.com", 100, {22, 23, 24, 25})) - .add_answer(new DNSARR("example.com", 100, {12, 13, 14, 15})) - .add_answer(new DNSARR("example.com", 100, {2, 3, 4, 5})); - ON_CALL(server_, OnRequest("example.com", ns_t_a)) - .WillByDefault(SetReply(&server_, &rsp)); - - { - EXPECT_EQ(ARES_SUCCESS, ares_set_sortlist(channel_, "12.13.0.0/255.255.0.0 1234::5678")); - HostResult result; - ares_gethostbyname(channel_, "example.com.", AF_INET, HostCallback, &result); - Process(); - EXPECT_TRUE(result.done_); - std::stringstream ss; - ss << result.host_; - EXPECT_EQ("{'example.com' aliases=[] addrs=[12.13.14.15, 22.23.24.25, 2.3.4.5]}", ss.str()); - } - { - EXPECT_EQ(ARES_SUCCESS, ares_set_sortlist(channel_, "2.3.0.0/16 130.140.150.160/26")); - HostResult result; - ares_gethostbyname(channel_, "example.com.", AF_INET, HostCallback, &result); - Process(); - EXPECT_TRUE(result.done_); - std::stringstream ss; - ss << result.host_; - EXPECT_EQ("{'example.com' aliases=[] addrs=[2.3.4.5, 22.23.24.25, 12.13.14.15]}", ss.str()); - } - struct ares_options options; - memset(&options, 0, sizeof(options)); - int optmask = 0; - EXPECT_EQ(ARES_SUCCESS, ares_save_options(channel_, &options, &optmask)); - EXPECT_TRUE((optmask & ARES_OPT_SORTLIST) == ARES_OPT_SORTLIST); - ares_destroy_options(&options); -} - -TEST_P(MockChannelTest, SortListV6) { - DNSPacket rsp; - rsp.set_response().set_aa() - .add_question(new DNSQuestion("example.com", ns_t_aaaa)) - .add_answer(new DNSAaaaRR("example.com", 100, - {0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02})) - .add_answer(new DNSAaaaRR("example.com", 100, - {0x21, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03})); - ON_CALL(server_, OnRequest("example.com", ns_t_aaaa)) - .WillByDefault(SetReply(&server_, &rsp)); - - { - ares_set_sortlist(channel_, "1111::/16 2.3.0.0/255.255.0.0"); - HostResult result; - ares_gethostbyname(channel_, "example.com.", AF_INET6, HostCallback, &result); - Process(); - EXPECT_TRUE(result.done_); - std::stringstream ss; - ss << result.host_; - EXPECT_EQ("{'example.com' aliases=[] addrs=[1111:0000:0000:0000:0000:0000:0000:0202, " - "2121:0000:0000:0000:0000:0000:0000:0303]}", ss.str()); - } - { - ares_set_sortlist(channel_, "2121::/8"); - HostResult result; - ares_gethostbyname(channel_, "example.com.", AF_INET6, HostCallback, &result); - Process(); - EXPECT_TRUE(result.done_); - std::stringstream ss; - ss << result.host_; - EXPECT_EQ("{'example.com' aliases=[] addrs=[2121:0000:0000:0000:0000:0000:0000:0303, " - "1111:0000:0000:0000:0000:0000:0000:0202]}", ss.str()); - } -} - -// Relies on retries so is UDP-only -TEST_P(MockUDPChannelTest, SearchDomainsAllocFail) { - DNSPacket nofirst; - nofirst.set_response().set_aa().set_rcode(ns_r_nxdomain) - .add_question(new DNSQuestion("www.first.com", ns_t_a)); - ON_CALL(server_, OnRequest("www.first.com", ns_t_a)) - .WillByDefault(SetReply(&server_, &nofirst)); - DNSPacket nosecond; - nosecond.set_response().set_aa().set_rcode(ns_r_nxdomain) - .add_question(new DNSQuestion("www.second.org", ns_t_a)); - ON_CALL(server_, OnRequest("www.second.org", ns_t_a)) - .WillByDefault(SetReply(&server_, &nosecond)); - DNSPacket yesthird; - yesthird.set_response().set_aa() - .add_question(new DNSQuestion("www.third.gov", ns_t_a)) - .add_answer(new DNSARR("www.third.gov", 0x0200, {2, 3, 4, 5})); - ON_CALL(server_, OnRequest("www.third.gov", ns_t_a)) - .WillByDefault(SetReply(&server_, &yesthird)); - - // Fail a variety of different memory allocations, and confirm - // that the operation either fails with ENOMEM or succeeds - // with the expected result. - const int kCount = 34; - HostResult results[kCount]; - for (int ii = 1; ii <= kCount; ii++) { - HostResult* result = &(results[ii - 1]); - ClearFails(); - SetAllocFail(ii); - ares_gethostbyname(channel_, "www", AF_INET, HostCallback, result); - Process(); - EXPECT_TRUE(result->done_); - if (result->status_ == ARES_SUCCESS) { - std::stringstream ss; - ss << result->host_; - EXPECT_EQ("{'www.third.gov' aliases=[] addrs=[2.3.4.5]}", ss.str()) << " failed alloc #" << ii; - if (verbose) std::cerr << "Succeeded despite failure of alloc #" << ii << std::endl; - } - } - - // Explicitly destroy the channel now, so that the HostResult objects - // are still valid (in case any pending work refers to them). - ares_destroy(channel_); - channel_ = nullptr; -} - -// Relies on retries so is UDP-only -TEST_P(MockUDPChannelTest, Resend) { - std::vector<byte> nothing; - DNSPacket reply; - reply.set_response().set_aa() - .add_question(new DNSQuestion("www.google.com", ns_t_a)) - .add_answer(new DNSARR("www.google.com", 0x0100, {0x01, 0x02, 0x03, 0x04})); - - EXPECT_CALL(server_, OnRequest("www.google.com", ns_t_a)) - .WillOnce(SetReplyData(&server_, nothing)) - .WillOnce(SetReplyData(&server_, nothing)) - .WillOnce(SetReply(&server_, &reply)); - - HostResult result; - ares_gethostbyname(channel_, "www.google.com.", AF_INET, HostCallback, &result); - Process(); - EXPECT_TRUE(result.done_); - EXPECT_EQ(2, result.timeouts_); - std::stringstream ss; - ss << result.host_; - EXPECT_EQ("{'www.google.com' aliases=[] addrs=[1.2.3.4]}", ss.str()); -} - -TEST_P(MockChannelTest, CancelImmediate) { - HostResult result; - ares_gethostbyname(channel_, "www.google.com.", AF_INET, HostCallback, &result); - ares_cancel(channel_); - EXPECT_TRUE(result.done_); - EXPECT_EQ(ARES_ECANCELLED, result.status_); - EXPECT_EQ(0, result.timeouts_); -} - -TEST_P(MockChannelTest, CancelImmediateGetHostByAddr) { - HostResult result; - struct in_addr addr; - addr.s_addr = htonl(0x08080808); - - ares_gethostbyaddr(channel_, &addr, sizeof(addr), AF_INET, HostCallback, &result); - ares_cancel(channel_); - EXPECT_TRUE(result.done_); - EXPECT_EQ(ARES_ECANCELLED, result.status_); - EXPECT_EQ(0, result.timeouts_); -} - -// Relies on retries so is UDP-only -TEST_P(MockUDPChannelTest, CancelLater) { - std::vector<byte> nothing; - - // On second request, cancel the channel. - EXPECT_CALL(server_, OnRequest("www.google.com", ns_t_a)) - .WillOnce(SetReplyData(&server_, nothing)) - .WillOnce(CancelChannel(&server_, channel_)); - - HostResult result; - ares_gethostbyname(channel_, "www.google.com.", AF_INET, HostCallback, &result); - Process(); - EXPECT_TRUE(result.done_); - EXPECT_EQ(ARES_ECANCELLED, result.status_); - EXPECT_EQ(0, result.timeouts_); -} - -TEST_P(MockChannelTest, GetHostByNameDestroyAbsolute) { - HostResult result; - ares_gethostbyname(channel_, "www.google.com.", AF_INET, HostCallback, &result); - - ares_destroy(channel_); - channel_ = nullptr; - - EXPECT_TRUE(result.done_); // Synchronous - EXPECT_EQ(ARES_EDESTRUCTION, result.status_); - EXPECT_EQ(0, result.timeouts_); -} - -TEST_P(MockChannelTest, GetHostByNameDestroyRelative) { - HostResult result; - ares_gethostbyname(channel_, "www", AF_INET, HostCallback, &result); - - ares_destroy(channel_); - channel_ = nullptr; - - EXPECT_TRUE(result.done_); // Synchronous - EXPECT_EQ(ARES_EDESTRUCTION, result.status_); - EXPECT_EQ(0, result.timeouts_); -} - + DNSPacket rsp1; + rsp1.set_response().set_aa() + .add_question(new DNSQuestion("www.google.com", ns_t_a)) + .add_answer(new DNSARR("www.google.com", 100, {2, 3, 4, 5})); + ON_CALL(server_, OnRequest("www.google.com", ns_t_a)) + .WillByDefault(SetReply(&server_, &rsp1)); + DNSPacket rsp2; + rsp2.set_response().set_aa() + .add_question(new DNSQuestion("www.example.com", ns_t_a)) + .add_answer(new DNSARR("www.example.com", 100, {1, 2, 3, 4})); + ON_CALL(server_, OnRequest("www.example.com", ns_t_a)) + .WillByDefault(SetReply(&server_, &rsp2)); + + HostResult result1; + ares_gethostbyname(channel_, "www.google.com.", AF_INET, HostCallback, &result1); + HostResult result2; + ares_gethostbyname(channel_, "www.example.com.", AF_INET, HostCallback, &result2); + HostResult result3; + ares_gethostbyname(channel_, "www.google.com.", AF_INET, HostCallback, &result3); + Process(); + EXPECT_TRUE(result1.done_); + EXPECT_TRUE(result2.done_); + EXPECT_TRUE(result3.done_); + std::stringstream ss1; + ss1 << result1.host_; + EXPECT_EQ("{'www.google.com' aliases=[] addrs=[2.3.4.5]}", ss1.str()); + std::stringstream ss2; + ss2 << result2.host_; + EXPECT_EQ("{'www.example.com' aliases=[] addrs=[1.2.3.4]}", ss2.str()); + std::stringstream ss3; + ss3 << result3.host_; + EXPECT_EQ("{'www.google.com' aliases=[] addrs=[2.3.4.5]}", ss3.str()); +} + +// UDP to TCP specific test +TEST_P(MockUDPChannelTest, TruncationRetry) { + DNSPacket rsptruncated; + rsptruncated.set_response().set_aa().set_tc() + .add_question(new DNSQuestion("www.google.com", ns_t_a)); + DNSPacket rspok; + rspok.set_response() + .add_question(new DNSQuestion("www.google.com", ns_t_a)) + .add_answer(new DNSARR("www.google.com", 100, {1, 2, 3, 4})); + EXPECT_CALL(server_, OnRequest("www.google.com", ns_t_a)) + .WillOnce(SetReply(&server_, &rsptruncated)) + .WillOnce(SetReply(&server_, &rspok)); + HostResult result; + ares_gethostbyname(channel_, "www.google.com.", AF_INET, HostCallback, &result); + Process(); + EXPECT_TRUE(result.done_); + std::stringstream ss; + ss << result.host_; + EXPECT_EQ("{'www.google.com' aliases=[] addrs=[1.2.3.4]}", ss.str()); +} + +static int sock_cb_count = 0; +static int SocketConnectCallback(ares_socket_t fd, int type, void *data) { + int rc = *(int*)data; + if (verbose) std::cerr << "SocketConnectCallback(" << fd << ") invoked" << std::endl; + sock_cb_count++; + return rc; +} + +TEST_P(MockChannelTest, SockCallback) { + DNSPacket rsp; + rsp.set_response().set_aa() + .add_question(new DNSQuestion("www.google.com", ns_t_a)) + .add_answer(new DNSARR("www.google.com", 100, {2, 3, 4, 5})); + EXPECT_CALL(server_, OnRequest("www.google.com", ns_t_a)) + .WillOnce(SetReply(&server_, &rsp)); + + // Get notified of new sockets + int rc = ARES_SUCCESS; + ares_set_socket_callback(channel_, SocketConnectCallback, &rc); + + HostResult result; + sock_cb_count = 0; + ares_gethostbyname(channel_, "www.google.com.", AF_INET, HostCallback, &result); + Process(); + EXPECT_EQ(1, sock_cb_count); + EXPECT_TRUE(result.done_); + std::stringstream ss; + ss << result.host_; + EXPECT_EQ("{'www.google.com' aliases=[] addrs=[2.3.4.5]}", ss.str()); +} + +TEST_P(MockChannelTest, SockFailCallback) { + // Notification of new sockets gives an error. + int rc = -1; + ares_set_socket_callback(channel_, SocketConnectCallback, &rc); + + HostResult result; + sock_cb_count = 0; + ares_gethostbyname(channel_, "www.google.com.", AF_INET, HostCallback, &result); + Process(); + EXPECT_LT(1, sock_cb_count); + EXPECT_TRUE(result.done_); + EXPECT_EQ(ARES_ECONNREFUSED, result.status_); +} + +static int sock_config_cb_count = 0; +static int SocketConfigureCallback(ares_socket_t fd, int type, void *data) { + int rc = *(int*)data; + if (verbose) std::cerr << "SocketConfigureCallback(" << fd << ") invoked" << std::endl; + sock_config_cb_count++; + return rc; +} + +TEST_P(MockChannelTest, SockConfigureCallback) { + DNSPacket rsp; + rsp.set_response().set_aa() + .add_question(new DNSQuestion("www.google.com", ns_t_a)) + .add_answer(new DNSARR("www.google.com", 100, {2, 3, 4, 5})); + EXPECT_CALL(server_, OnRequest("www.google.com", ns_t_a)) + .WillOnce(SetReply(&server_, &rsp)); + + // Get notified of new sockets + int rc = ARES_SUCCESS; + ares_set_socket_configure_callback(channel_, SocketConfigureCallback, &rc); + + HostResult result; + sock_config_cb_count = 0; + ares_gethostbyname(channel_, "www.google.com.", AF_INET, HostCallback, &result); + Process(); + EXPECT_EQ(1, sock_config_cb_count); + EXPECT_TRUE(result.done_); + std::stringstream ss; + ss << result.host_; + EXPECT_EQ("{'www.google.com' aliases=[] addrs=[2.3.4.5]}", ss.str()); +} + +TEST_P(MockChannelTest, SockConfigureFailCallback) { + // Notification of new sockets gives an error. + int rc = -1; + ares_set_socket_configure_callback(channel_, SocketConfigureCallback, &rc); + + HostResult result; + sock_config_cb_count = 0; + ares_gethostbyname(channel_, "www.google.com.", AF_INET, HostCallback, &result); + Process(); + EXPECT_LT(1, sock_config_cb_count); + EXPECT_TRUE(result.done_); + EXPECT_EQ(ARES_ECONNREFUSED, result.status_); +} + +// TCP only to prevent retries +TEST_P(MockTCPChannelTest, MalformedResponse) { + std::vector<byte> one = {0x01}; + EXPECT_CALL(server_, OnRequest("www.google.com", ns_t_a)) + .WillOnce(SetReplyData(&server_, one)); + + HostResult result; + ares_gethostbyname(channel_, "www.google.com.", AF_INET, HostCallback, &result); + Process(); + EXPECT_TRUE(result.done_); + EXPECT_EQ(ARES_ETIMEOUT, result.status_); +} + +TEST_P(MockTCPChannelTest, FormErrResponse) { + DNSPacket rsp; + rsp.set_response().set_aa() + .add_question(new DNSQuestion("www.google.com", ns_t_a)); + rsp.set_rcode(ns_r_formerr); + EXPECT_CALL(server_, OnRequest("www.google.com", ns_t_a)) + .WillOnce(SetReply(&server_, &rsp)); + HostResult result; + ares_gethostbyname(channel_, "www.google.com.", AF_INET, HostCallback, &result); + Process(); + EXPECT_TRUE(result.done_); + EXPECT_EQ(ARES_EFORMERR, result.status_); +} + +TEST_P(MockTCPChannelTest, ServFailResponse) { + DNSPacket rsp; + rsp.set_response().set_aa() + .add_question(new DNSQuestion("www.google.com", ns_t_a)); + rsp.set_rcode(ns_r_servfail); + EXPECT_CALL(server_, OnRequest("www.google.com", ns_t_a)) + .WillOnce(SetReply(&server_, &rsp)); + HostResult result; + ares_gethostbyname(channel_, "www.google.com.", AF_INET, HostCallback, &result); + Process(); + EXPECT_TRUE(result.done_); + // ARES_FLAG_NOCHECKRESP not set, so SERVFAIL consumed + EXPECT_EQ(ARES_ECONNREFUSED, result.status_); +} + +TEST_P(MockTCPChannelTest, NotImplResponse) { + DNSPacket rsp; + rsp.set_response().set_aa() + .add_question(new DNSQuestion("www.google.com", ns_t_a)); + rsp.set_rcode(ns_r_notimpl); + EXPECT_CALL(server_, OnRequest("www.google.com", ns_t_a)) + .WillOnce(SetReply(&server_, &rsp)); + HostResult result; + ares_gethostbyname(channel_, "www.google.com.", AF_INET, HostCallback, &result); + Process(); + EXPECT_TRUE(result.done_); + // ARES_FLAG_NOCHECKRESP not set, so NOTIMPL consumed + EXPECT_EQ(ARES_ECONNREFUSED, result.status_); +} + +TEST_P(MockTCPChannelTest, RefusedResponse) { + DNSPacket rsp; + rsp.set_response().set_aa() + .add_question(new DNSQuestion("www.google.com", ns_t_a)); + rsp.set_rcode(ns_r_refused); + EXPECT_CALL(server_, OnRequest("www.google.com", ns_t_a)) + .WillOnce(SetReply(&server_, &rsp)); + HostResult result; + ares_gethostbyname(channel_, "www.google.com.", AF_INET, HostCallback, &result); + Process(); + EXPECT_TRUE(result.done_); + // ARES_FLAG_NOCHECKRESP not set, so REFUSED consumed + EXPECT_EQ(ARES_ECONNREFUSED, result.status_); +} + +TEST_P(MockTCPChannelTest, YXDomainResponse) { + DNSPacket rsp; + rsp.set_response().set_aa() + .add_question(new DNSQuestion("www.google.com", ns_t_a)); + rsp.set_rcode(ns_r_yxdomain); + EXPECT_CALL(server_, OnRequest("www.google.com", ns_t_a)) + .WillOnce(SetReply(&server_, &rsp)); + HostResult result; + ares_gethostbyname(channel_, "www.google.com.", AF_INET, HostCallback, &result); + Process(); + EXPECT_TRUE(result.done_); + EXPECT_EQ(ARES_ENODATA, result.status_); +} + +class MockExtraOptsTest + : public MockChannelOptsTest, + public ::testing::WithParamInterface< std::pair<int, bool> > { + public: + MockExtraOptsTest() + : MockChannelOptsTest(1, GetParam().first, GetParam().second, + FillOptions(&opts_), + ARES_OPT_SOCK_SNDBUF|ARES_OPT_SOCK_RCVBUF) {} + static struct ares_options* FillOptions(struct ares_options * opts) { + memset(opts, 0, sizeof(struct ares_options)); + // Set a few options that affect socket communications + opts->socket_send_buffer_size = 514; + opts->socket_receive_buffer_size = 514; + return opts; + } + private: + struct ares_options opts_; +}; + +TEST_P(MockExtraOptsTest, SimpleQuery) { + ares_set_local_ip4(channel_, 0x7F000001); + byte addr6[16] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}; + ares_set_local_ip6(channel_, addr6); + ares_set_local_dev(channel_, "dummy"); + + DNSPacket rsp; + rsp.set_response().set_aa() + .add_question(new DNSQuestion("www.google.com", ns_t_a)) + .add_answer(new DNSARR("www.google.com", 100, {2, 3, 4, 5})); + ON_CALL(server_, OnRequest("www.google.com", ns_t_a)) + .WillByDefault(SetReply(&server_, &rsp)); + + HostResult result; + ares_gethostbyname(channel_, "www.google.com.", AF_INET, HostCallback, &result); + Process(); + EXPECT_TRUE(result.done_); + std::stringstream ss; + ss << result.host_; + EXPECT_EQ("{'www.google.com' aliases=[] addrs=[2.3.4.5]}", ss.str()); +} + +class MockFlagsChannelOptsTest + : public MockChannelOptsTest, + public ::testing::WithParamInterface< std::pair<int, bool> > { + public: + MockFlagsChannelOptsTest(int flags) + : MockChannelOptsTest(1, GetParam().first, GetParam().second, + FillOptions(&opts_, flags), ARES_OPT_FLAGS) {} + static struct ares_options* FillOptions(struct ares_options * opts, int flags) { + memset(opts, 0, sizeof(struct ares_options)); + opts->flags = flags; + return opts; + } + private: + struct ares_options opts_; +}; + +class MockNoCheckRespChannelTest : public MockFlagsChannelOptsTest { + public: + MockNoCheckRespChannelTest() : MockFlagsChannelOptsTest(ARES_FLAG_NOCHECKRESP) {} +}; + +TEST_P(MockNoCheckRespChannelTest, ServFailResponse) { + DNSPacket rsp; + rsp.set_response().set_aa() + .add_question(new DNSQuestion("www.google.com", ns_t_a)); + rsp.set_rcode(ns_r_servfail); + ON_CALL(server_, OnRequest("www.google.com", ns_t_a)) + .WillByDefault(SetReply(&server_, &rsp)); + HostResult result; + ares_gethostbyname(channel_, "www.google.com.", AF_INET, HostCallback, &result); + Process(); + EXPECT_TRUE(result.done_); + EXPECT_EQ(ARES_ESERVFAIL, result.status_); +} + +TEST_P(MockNoCheckRespChannelTest, NotImplResponse) { + DNSPacket rsp; + rsp.set_response().set_aa() + .add_question(new DNSQuestion("www.google.com", ns_t_a)); + rsp.set_rcode(ns_r_notimpl); + ON_CALL(server_, OnRequest("www.google.com", ns_t_a)) + .WillByDefault(SetReply(&server_, &rsp)); + HostResult result; + ares_gethostbyname(channel_, "www.google.com.", AF_INET, HostCallback, &result); + Process(); + EXPECT_TRUE(result.done_); + EXPECT_EQ(ARES_ENOTIMP, result.status_); +} + +TEST_P(MockNoCheckRespChannelTest, RefusedResponse) { + DNSPacket rsp; + rsp.set_response().set_aa() + .add_question(new DNSQuestion("www.google.com", ns_t_a)); + rsp.set_rcode(ns_r_refused); + ON_CALL(server_, OnRequest("www.google.com", ns_t_a)) + .WillByDefault(SetReply(&server_, &rsp)); + HostResult result; + ares_gethostbyname(channel_, "www.google.com.", AF_INET, HostCallback, &result); + Process(); + EXPECT_TRUE(result.done_); + EXPECT_EQ(ARES_EREFUSED, result.status_); +} + +class MockEDNSChannelTest : public MockFlagsChannelOptsTest { + public: + MockEDNSChannelTest() : MockFlagsChannelOptsTest(ARES_FLAG_EDNS) {} +}; + +TEST_P(MockEDNSChannelTest, RetryWithoutEDNS) { + DNSPacket rspfail; + rspfail.set_response().set_aa().set_rcode(ns_r_servfail) + .add_question(new DNSQuestion("www.google.com", ns_t_a)); + DNSPacket rspok; + rspok.set_response() + .add_question(new DNSQuestion("www.google.com", ns_t_a)) + .add_answer(new DNSARR("www.google.com", 100, {1, 2, 3, 4})); + EXPECT_CALL(server_, OnRequest("www.google.com", ns_t_a)) + .WillOnce(SetReply(&server_, &rspfail)) + .WillOnce(SetReply(&server_, &rspok)); + HostResult result; + ares_gethostbyname(channel_, "www.google.com.", AF_INET, HostCallback, &result); + Process(); + EXPECT_TRUE(result.done_); + std::stringstream ss; + ss << result.host_; + EXPECT_EQ("{'www.google.com' aliases=[] addrs=[1.2.3.4]}", ss.str()); +} + +TEST_P(MockChannelTest, SearchDomains) { + DNSPacket nofirst; + nofirst.set_response().set_aa().set_rcode(ns_r_nxdomain) + .add_question(new DNSQuestion("www.first.com", ns_t_a)); + ON_CALL(server_, OnRequest("www.first.com", ns_t_a)) + .WillByDefault(SetReply(&server_, &nofirst)); + DNSPacket nosecond; + nosecond.set_response().set_aa().set_rcode(ns_r_nxdomain) + .add_question(new DNSQuestion("www.second.org", ns_t_a)); + ON_CALL(server_, OnRequest("www.second.org", ns_t_a)) + .WillByDefault(SetReply(&server_, &nosecond)); + DNSPacket yesthird; + yesthird.set_response().set_aa() + .add_question(new DNSQuestion("www.third.gov", ns_t_a)) + .add_answer(new DNSARR("www.third.gov", 0x0200, {2, 3, 4, 5})); + ON_CALL(server_, OnRequest("www.third.gov", ns_t_a)) + .WillByDefault(SetReply(&server_, &yesthird)); + + HostResult result; + ares_gethostbyname(channel_, "www", AF_INET, HostCallback, &result); + Process(); + EXPECT_TRUE(result.done_); + std::stringstream ss; + ss << result.host_; + EXPECT_EQ("{'www.third.gov' aliases=[] addrs=[2.3.4.5]}", ss.str()); +} + +// Relies on retries so is UDP-only +TEST_P(MockUDPChannelTest, SearchDomainsWithResentReply) { + DNSPacket nofirst; + nofirst.set_response().set_aa().set_rcode(ns_r_nxdomain) + .add_question(new DNSQuestion("www.first.com", ns_t_a)); + EXPECT_CALL(server_, OnRequest("www.first.com", ns_t_a)) + .WillOnce(SetReply(&server_, &nofirst)); + DNSPacket nosecond; + nosecond.set_response().set_aa().set_rcode(ns_r_nxdomain) + .add_question(new DNSQuestion("www.second.org", ns_t_a)); + EXPECT_CALL(server_, OnRequest("www.second.org", ns_t_a)) + .WillOnce(SetReply(&server_, &nosecond)); + DNSPacket yesthird; + yesthird.set_response().set_aa() + .add_question(new DNSQuestion("www.third.gov", ns_t_a)) + .add_answer(new DNSARR("www.third.gov", 0x0200, {2, 3, 4, 5})); + // Before sending the real answer, resend an earlier reply + EXPECT_CALL(server_, OnRequest("www.third.gov", ns_t_a)) + .WillOnce(DoAll(SetReply(&server_, &nofirst), + SetReplyQID(&server_, 123))) + .WillOnce(DoAll(SetReply(&server_, &yesthird), + SetReplyQID(&server_, -1))); + + HostResult result; + ares_gethostbyname(channel_, "www", AF_INET, HostCallback, &result); + Process(); + EXPECT_TRUE(result.done_); + std::stringstream ss; + ss << result.host_; + EXPECT_EQ("{'www.third.gov' aliases=[] addrs=[2.3.4.5]}", ss.str()); +} + +TEST_P(MockChannelTest, SearchDomainsBare) { + DNSPacket nofirst; + nofirst.set_response().set_aa().set_rcode(ns_r_nxdomain) + .add_question(new DNSQuestion("www.first.com", ns_t_a)); + ON_CALL(server_, OnRequest("www.first.com", ns_t_a)) + .WillByDefault(SetReply(&server_, &nofirst)); + DNSPacket nosecond; + nosecond.set_response().set_aa().set_rcode(ns_r_nxdomain) + .add_question(new DNSQuestion("www.second.org", ns_t_a)); + ON_CALL(server_, OnRequest("www.second.org", ns_t_a)) + .WillByDefault(SetReply(&server_, &nosecond)); + DNSPacket nothird; + nothird.set_response().set_aa().set_rcode(ns_r_nxdomain) + .add_question(new DNSQuestion("www.third.gov", ns_t_a)); + ON_CALL(server_, OnRequest("www.third.gov", ns_t_a)) + .WillByDefault(SetReply(&server_, ¬hird)); + DNSPacket yesbare; + yesbare.set_response().set_aa() + .add_question(new DNSQuestion("www", ns_t_a)) + .add_answer(new DNSARR("www", 0x0200, {2, 3, 4, 5})); + ON_CALL(server_, OnRequest("www", ns_t_a)) + .WillByDefault(SetReply(&server_, &yesbare)); + + HostResult result; + ares_gethostbyname(channel_, "www", AF_INET, HostCallback, &result); + Process(); + EXPECT_TRUE(result.done_); + std::stringstream ss; + ss << result.host_; + EXPECT_EQ("{'www' aliases=[] addrs=[2.3.4.5]}", ss.str()); +} + +TEST_P(MockChannelTest, SearchNoDataThenSuccess) { + // First two search domains recognize the name but have no A records. + DNSPacket nofirst; + nofirst.set_response().set_aa() + .add_question(new DNSQuestion("www.first.com", ns_t_a)); + ON_CALL(server_, OnRequest("www.first.com", ns_t_a)) + .WillByDefault(SetReply(&server_, &nofirst)); + DNSPacket nosecond; + nosecond.set_response().set_aa() + .add_question(new DNSQuestion("www.second.org", ns_t_a)); + ON_CALL(server_, OnRequest("www.second.org", ns_t_a)) + .WillByDefault(SetReply(&server_, &nosecond)); + DNSPacket yesthird; + yesthird.set_response().set_aa() + .add_question(new DNSQuestion("www.third.gov", ns_t_a)) + .add_answer(new DNSARR("www.third.gov", 0x0200, {2, 3, 4, 5})); + ON_CALL(server_, OnRequest("www.third.gov", ns_t_a)) + .WillByDefault(SetReply(&server_, &yesthird)); + + HostResult result; + ares_gethostbyname(channel_, "www", AF_INET, HostCallback, &result); + Process(); + EXPECT_TRUE(result.done_); + std::stringstream ss; + ss << result.host_; + EXPECT_EQ("{'www.third.gov' aliases=[] addrs=[2.3.4.5]}", ss.str()); +} + +TEST_P(MockChannelTest, SearchNoDataThenNoDataBare) { + // First two search domains recognize the name but have no A records. + DNSPacket nofirst; + nofirst.set_response().set_aa() + .add_question(new DNSQuestion("www.first.com", ns_t_a)); + ON_CALL(server_, OnRequest("www.first.com", ns_t_a)) + .WillByDefault(SetReply(&server_, &nofirst)); + DNSPacket nosecond; + nosecond.set_response().set_aa() + .add_question(new DNSQuestion("www.second.org", ns_t_a)); + ON_CALL(server_, OnRequest("www.second.org", ns_t_a)) + .WillByDefault(SetReply(&server_, &nosecond)); + DNSPacket nothird; + nothird.set_response().set_aa() + .add_question(new DNSQuestion("www.third.gov", ns_t_a)); + ON_CALL(server_, OnRequest("www.third.gov", ns_t_a)) + .WillByDefault(SetReply(&server_, ¬hird)); + DNSPacket nobare; + nobare.set_response().set_aa() + .add_question(new DNSQuestion("www", ns_t_a)); + ON_CALL(server_, OnRequest("www", ns_t_a)) + .WillByDefault(SetReply(&server_, &nobare)); + + HostResult result; + ares_gethostbyname(channel_, "www", AF_INET, HostCallback, &result); + Process(); + EXPECT_TRUE(result.done_); + EXPECT_EQ(ARES_ENODATA, result.status_); +} + +TEST_P(MockChannelTest, SearchNoDataThenFail) { + // First two search domains recognize the name but have no A records. + DNSPacket nofirst; + nofirst.set_response().set_aa() + .add_question(new DNSQuestion("www.first.com", ns_t_a)); + ON_CALL(server_, OnRequest("www.first.com", ns_t_a)) + .WillByDefault(SetReply(&server_, &nofirst)); + DNSPacket nosecond; + nosecond.set_response().set_aa() + .add_question(new DNSQuestion("www.second.org", ns_t_a)); + ON_CALL(server_, OnRequest("www.second.org", ns_t_a)) + .WillByDefault(SetReply(&server_, &nosecond)); + DNSPacket nothird; + nothird.set_response().set_aa() + .add_question(new DNSQuestion("www.third.gov", ns_t_a)); + ON_CALL(server_, OnRequest("www.third.gov", ns_t_a)) + .WillByDefault(SetReply(&server_, ¬hird)); + DNSPacket nobare; + nobare.set_response().set_aa().set_rcode(ns_r_nxdomain) + .add_question(new DNSQuestion("www", ns_t_a)); + ON_CALL(server_, OnRequest("www", ns_t_a)) + .WillByDefault(SetReply(&server_, &nobare)); + + HostResult result; + ares_gethostbyname(channel_, "www", AF_INET, HostCallback, &result); + Process(); + EXPECT_TRUE(result.done_); + EXPECT_EQ(ARES_ENODATA, result.status_); +} + +TEST_P(MockChannelTest, SearchAllocFailure) { + SearchResult result; + SetAllocFail(1); + ares_search(channel_, "fully.qualified.", ns_c_in, ns_t_a, SearchCallback, &result); + /* Already done */ + EXPECT_TRUE(result.done_); + EXPECT_EQ(ARES_ENOMEM, result.status_); +} + +TEST_P(MockChannelTest, SearchHighNdots) { + DNSPacket nobare; + nobare.set_response().set_aa().set_rcode(ns_r_nxdomain) + .add_question(new DNSQuestion("a.b.c.w.w.w", ns_t_a)); + ON_CALL(server_, OnRequest("a.b.c.w.w.w", ns_t_a)) + .WillByDefault(SetReply(&server_, &nobare)); + DNSPacket yesfirst; + yesfirst.set_response().set_aa() + .add_question(new DNSQuestion("a.b.c.w.w.w.first.com", ns_t_a)) + .add_answer(new DNSARR("a.b.c.w.w.w.first.com", 0x0200, {2, 3, 4, 5})); + ON_CALL(server_, OnRequest("a.b.c.w.w.w.first.com", ns_t_a)) + .WillByDefault(SetReply(&server_, &yesfirst)); + + SearchResult result; + ares_search(channel_, "a.b.c.w.w.w", ns_c_in, ns_t_a, SearchCallback, &result); + Process(); + EXPECT_TRUE(result.done_); + EXPECT_EQ(ARES_SUCCESS, result.status_); + std::stringstream ss; + ss << PacketToString(result.data_); + EXPECT_EQ("RSP QRY AA NOERROR Q:{'a.b.c.w.w.w.first.com' IN A} " + "A:{'a.b.c.w.w.w.first.com' IN A TTL=512 2.3.4.5}", + ss.str()); +} + +TEST_P(MockChannelTest, UnspecifiedFamilyV6) { + DNSPacket rsp6; + rsp6.set_response().set_aa() + .add_question(new DNSQuestion("example.com", ns_t_aaaa)) + .add_answer(new DNSAaaaRR("example.com", 100, + {0x21, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03})); + ON_CALL(server_, OnRequest("example.com", ns_t_aaaa)) + .WillByDefault(SetReply(&server_, &rsp6)); + + HostResult result; + ares_gethostbyname(channel_, "example.com.", AF_UNSPEC, HostCallback, &result); + Process(); + EXPECT_TRUE(result.done_); + std::stringstream ss; + ss << result.host_; + // Default to IPv6 when both are available. + EXPECT_EQ("{'example.com' aliases=[] addrs=[2121:0000:0000:0000:0000:0000:0000:0303]}", ss.str()); +} + +TEST_P(MockChannelTest, UnspecifiedFamilyV4) { + DNSPacket rsp6; + rsp6.set_response().set_aa() + .add_question(new DNSQuestion("example.com", ns_t_aaaa)); + ON_CALL(server_, OnRequest("example.com", ns_t_aaaa)) + .WillByDefault(SetReply(&server_, &rsp6)); + DNSPacket rsp4; + rsp4.set_response().set_aa() + .add_question(new DNSQuestion("example.com", ns_t_a)) + .add_answer(new DNSARR("example.com", 100, {2, 3, 4, 5})); + ON_CALL(server_, OnRequest("example.com", ns_t_a)) + .WillByDefault(SetReply(&server_, &rsp4)); + + HostResult result; + ares_gethostbyname(channel_, "example.com.", AF_UNSPEC, HostCallback, &result); + Process(); + EXPECT_TRUE(result.done_); + std::stringstream ss; + ss << result.host_; + EXPECT_EQ("{'example.com' aliases=[] addrs=[2.3.4.5]}", ss.str()); +} + +TEST_P(MockChannelTest, UnspecifiedFamilyNoData) { + DNSPacket rsp6; + rsp6.set_response().set_aa() + .add_question(new DNSQuestion("example.com", ns_t_aaaa)) + .add_answer(new DNSCnameRR("example.com", 100, "elsewhere.com")); + ON_CALL(server_, OnRequest("example.com", ns_t_aaaa)) + .WillByDefault(SetReply(&server_, &rsp6)); + DNSPacket rsp4; + rsp4.set_response().set_aa() + .add_question(new DNSQuestion("example.com", ns_t_a)); + ON_CALL(server_, OnRequest("example.com", ns_t_a)) + .WillByDefault(SetReply(&server_, &rsp4)); + + HostResult result; + ares_gethostbyname(channel_, "example.com.", AF_UNSPEC, HostCallback, &result); + Process(); + EXPECT_TRUE(result.done_); + std::stringstream ss; + ss << result.host_; + EXPECT_EQ("{'' aliases=[] addrs=[]}", ss.str()); +} + +TEST_P(MockChannelTest, UnspecifiedFamilyCname6A4) { + DNSPacket rsp6; + rsp6.set_response().set_aa() + .add_question(new DNSQuestion("example.com", ns_t_aaaa)) + .add_answer(new DNSCnameRR("example.com", 100, "elsewhere.com")); + ON_CALL(server_, OnRequest("example.com", ns_t_aaaa)) + .WillByDefault(SetReply(&server_, &rsp6)); + DNSPacket rsp4; + rsp4.set_response().set_aa() + .add_question(new DNSQuestion("example.com", ns_t_a)) + .add_answer(new DNSARR("example.com", 100, {1, 2, 3, 4})); + ON_CALL(server_, OnRequest("example.com", ns_t_a)) + .WillByDefault(SetReply(&server_, &rsp4)); + + HostResult result; + ares_gethostbyname(channel_, "example.com.", AF_UNSPEC, HostCallback, &result); + Process(); + EXPECT_TRUE(result.done_); + std::stringstream ss; + ss << result.host_; + EXPECT_EQ("{'example.com' aliases=[] addrs=[1.2.3.4]}", ss.str()); +} + +TEST_P(MockChannelTest, ExplicitIP) { + HostResult result; + ares_gethostbyname(channel_, "1.2.3.4", AF_INET, HostCallback, &result); + EXPECT_TRUE(result.done_); // Immediate return + EXPECT_EQ(ARES_SUCCESS, result.status_); + std::stringstream ss; + ss << result.host_; + EXPECT_EQ("{'1.2.3.4' aliases=[] addrs=[1.2.3.4]}", ss.str()); +} + +TEST_P(MockChannelTest, ExplicitIPAllocFail) { + HostResult result; + SetAllocSizeFail(strlen("1.2.3.4") + 1); + ares_gethostbyname(channel_, "1.2.3.4", AF_INET, HostCallback, &result); + EXPECT_TRUE(result.done_); // Immediate return + EXPECT_EQ(ARES_ENOMEM, result.status_); +} + +TEST_P(MockChannelTest, SortListV4) { + DNSPacket rsp; + rsp.set_response().set_aa() + .add_question(new DNSQuestion("example.com", ns_t_a)) + .add_answer(new DNSARR("example.com", 100, {22, 23, 24, 25})) + .add_answer(new DNSARR("example.com", 100, {12, 13, 14, 15})) + .add_answer(new DNSARR("example.com", 100, {2, 3, 4, 5})); + ON_CALL(server_, OnRequest("example.com", ns_t_a)) + .WillByDefault(SetReply(&server_, &rsp)); + + { + EXPECT_EQ(ARES_SUCCESS, ares_set_sortlist(channel_, "12.13.0.0/255.255.0.0 1234::5678")); + HostResult result; + ares_gethostbyname(channel_, "example.com.", AF_INET, HostCallback, &result); + Process(); + EXPECT_TRUE(result.done_); + std::stringstream ss; + ss << result.host_; + EXPECT_EQ("{'example.com' aliases=[] addrs=[12.13.14.15, 22.23.24.25, 2.3.4.5]}", ss.str()); + } + { + EXPECT_EQ(ARES_SUCCESS, ares_set_sortlist(channel_, "2.3.0.0/16 130.140.150.160/26")); + HostResult result; + ares_gethostbyname(channel_, "example.com.", AF_INET, HostCallback, &result); + Process(); + EXPECT_TRUE(result.done_); + std::stringstream ss; + ss << result.host_; + EXPECT_EQ("{'example.com' aliases=[] addrs=[2.3.4.5, 22.23.24.25, 12.13.14.15]}", ss.str()); + } + struct ares_options options; + memset(&options, 0, sizeof(options)); + int optmask = 0; + EXPECT_EQ(ARES_SUCCESS, ares_save_options(channel_, &options, &optmask)); + EXPECT_TRUE((optmask & ARES_OPT_SORTLIST) == ARES_OPT_SORTLIST); + ares_destroy_options(&options); +} + +TEST_P(MockChannelTest, SortListV6) { + DNSPacket rsp; + rsp.set_response().set_aa() + .add_question(new DNSQuestion("example.com", ns_t_aaaa)) + .add_answer(new DNSAaaaRR("example.com", 100, + {0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02})) + .add_answer(new DNSAaaaRR("example.com", 100, + {0x21, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03})); + ON_CALL(server_, OnRequest("example.com", ns_t_aaaa)) + .WillByDefault(SetReply(&server_, &rsp)); + + { + ares_set_sortlist(channel_, "1111::/16 2.3.0.0/255.255.0.0"); + HostResult result; + ares_gethostbyname(channel_, "example.com.", AF_INET6, HostCallback, &result); + Process(); + EXPECT_TRUE(result.done_); + std::stringstream ss; + ss << result.host_; + EXPECT_EQ("{'example.com' aliases=[] addrs=[1111:0000:0000:0000:0000:0000:0000:0202, " + "2121:0000:0000:0000:0000:0000:0000:0303]}", ss.str()); + } + { + ares_set_sortlist(channel_, "2121::/8"); + HostResult result; + ares_gethostbyname(channel_, "example.com.", AF_INET6, HostCallback, &result); + Process(); + EXPECT_TRUE(result.done_); + std::stringstream ss; + ss << result.host_; + EXPECT_EQ("{'example.com' aliases=[] addrs=[2121:0000:0000:0000:0000:0000:0000:0303, " + "1111:0000:0000:0000:0000:0000:0000:0202]}", ss.str()); + } +} + +// Relies on retries so is UDP-only +TEST_P(MockUDPChannelTest, SearchDomainsAllocFail) { + DNSPacket nofirst; + nofirst.set_response().set_aa().set_rcode(ns_r_nxdomain) + .add_question(new DNSQuestion("www.first.com", ns_t_a)); + ON_CALL(server_, OnRequest("www.first.com", ns_t_a)) + .WillByDefault(SetReply(&server_, &nofirst)); + DNSPacket nosecond; + nosecond.set_response().set_aa().set_rcode(ns_r_nxdomain) + .add_question(new DNSQuestion("www.second.org", ns_t_a)); + ON_CALL(server_, OnRequest("www.second.org", ns_t_a)) + .WillByDefault(SetReply(&server_, &nosecond)); + DNSPacket yesthird; + yesthird.set_response().set_aa() + .add_question(new DNSQuestion("www.third.gov", ns_t_a)) + .add_answer(new DNSARR("www.third.gov", 0x0200, {2, 3, 4, 5})); + ON_CALL(server_, OnRequest("www.third.gov", ns_t_a)) + .WillByDefault(SetReply(&server_, &yesthird)); + + // Fail a variety of different memory allocations, and confirm + // that the operation either fails with ENOMEM or succeeds + // with the expected result. + const int kCount = 34; + HostResult results[kCount]; + for (int ii = 1; ii <= kCount; ii++) { + HostResult* result = &(results[ii - 1]); + ClearFails(); + SetAllocFail(ii); + ares_gethostbyname(channel_, "www", AF_INET, HostCallback, result); + Process(); + EXPECT_TRUE(result->done_); + if (result->status_ == ARES_SUCCESS) { + std::stringstream ss; + ss << result->host_; + EXPECT_EQ("{'www.third.gov' aliases=[] addrs=[2.3.4.5]}", ss.str()) << " failed alloc #" << ii; + if (verbose) std::cerr << "Succeeded despite failure of alloc #" << ii << std::endl; + } + } + + // Explicitly destroy the channel now, so that the HostResult objects + // are still valid (in case any pending work refers to them). + ares_destroy(channel_); + channel_ = nullptr; +} + +// Relies on retries so is UDP-only +TEST_P(MockUDPChannelTest, Resend) { + std::vector<byte> nothing; + DNSPacket reply; + reply.set_response().set_aa() + .add_question(new DNSQuestion("www.google.com", ns_t_a)) + .add_answer(new DNSARR("www.google.com", 0x0100, {0x01, 0x02, 0x03, 0x04})); + + EXPECT_CALL(server_, OnRequest("www.google.com", ns_t_a)) + .WillOnce(SetReplyData(&server_, nothing)) + .WillOnce(SetReplyData(&server_, nothing)) + .WillOnce(SetReply(&server_, &reply)); + + HostResult result; + ares_gethostbyname(channel_, "www.google.com.", AF_INET, HostCallback, &result); + Process(); + EXPECT_TRUE(result.done_); + EXPECT_EQ(2, result.timeouts_); + std::stringstream ss; + ss << result.host_; + EXPECT_EQ("{'www.google.com' aliases=[] addrs=[1.2.3.4]}", ss.str()); +} + +TEST_P(MockChannelTest, CancelImmediate) { + HostResult result; + ares_gethostbyname(channel_, "www.google.com.", AF_INET, HostCallback, &result); + ares_cancel(channel_); + EXPECT_TRUE(result.done_); + EXPECT_EQ(ARES_ECANCELLED, result.status_); + EXPECT_EQ(0, result.timeouts_); +} + +TEST_P(MockChannelTest, CancelImmediateGetHostByAddr) { + HostResult result; + struct in_addr addr; + addr.s_addr = htonl(0x08080808); + + ares_gethostbyaddr(channel_, &addr, sizeof(addr), AF_INET, HostCallback, &result); + ares_cancel(channel_); + EXPECT_TRUE(result.done_); + EXPECT_EQ(ARES_ECANCELLED, result.status_); + EXPECT_EQ(0, result.timeouts_); +} + +// Relies on retries so is UDP-only +TEST_P(MockUDPChannelTest, CancelLater) { + std::vector<byte> nothing; + + // On second request, cancel the channel. + EXPECT_CALL(server_, OnRequest("www.google.com", ns_t_a)) + .WillOnce(SetReplyData(&server_, nothing)) + .WillOnce(CancelChannel(&server_, channel_)); + + HostResult result; + ares_gethostbyname(channel_, "www.google.com.", AF_INET, HostCallback, &result); + Process(); + EXPECT_TRUE(result.done_); + EXPECT_EQ(ARES_ECANCELLED, result.status_); + EXPECT_EQ(0, result.timeouts_); +} + +TEST_P(MockChannelTest, GetHostByNameDestroyAbsolute) { + HostResult result; + ares_gethostbyname(channel_, "www.google.com.", AF_INET, HostCallback, &result); + + ares_destroy(channel_); + channel_ = nullptr; + + EXPECT_TRUE(result.done_); // Synchronous + EXPECT_EQ(ARES_EDESTRUCTION, result.status_); + EXPECT_EQ(0, result.timeouts_); +} + +TEST_P(MockChannelTest, GetHostByNameDestroyRelative) { + HostResult result; + ares_gethostbyname(channel_, "www", AF_INET, HostCallback, &result); + + ares_destroy(channel_); + channel_ = nullptr; + + EXPECT_TRUE(result.done_); // Synchronous + EXPECT_EQ(ARES_EDESTRUCTION, result.status_); + EXPECT_EQ(0, result.timeouts_); +} + TEST_P(MockChannelTest, GetHostByNameCNAMENoData) { DNSPacket response; response.set_response().set_aa() @@ -951,223 +951,223 @@ TEST_P(MockChannelTest, GetHostByNameCNAMENoData) { EXPECT_EQ(ARES_ENODATA, result.status_); } -TEST_P(MockChannelTest, GetHostByAddrDestroy) { - unsigned char gdns_addr4[4] = {0x08, 0x08, 0x08, 0x08}; - HostResult result; - ares_gethostbyaddr(channel_, gdns_addr4, sizeof(gdns_addr4), AF_INET, HostCallback, &result); - - ares_destroy(channel_); - channel_ = nullptr; - - EXPECT_TRUE(result.done_); // Synchronous - EXPECT_EQ(ARES_EDESTRUCTION, result.status_); - EXPECT_EQ(0, result.timeouts_); -} - -#ifndef WIN32 -TEST_P(MockChannelTest, HostAlias) { - DNSPacket reply; - reply.set_response().set_aa() - .add_question(new DNSQuestion("www.google.com", ns_t_a)) - .add_answer(new DNSARR("www.google.com", 0x0100, {0x01, 0x02, 0x03, 0x04})); - ON_CALL(server_, OnRequest("www.google.com", ns_t_a)) - .WillByDefault(SetReply(&server_, &reply)); - - TempFile aliases("\n\n# www commentedout\nwww www.google.com\n"); - EnvValue with_env("HOSTALIASES", aliases.filename()); - - HostResult result; - ares_gethostbyname(channel_, "www", AF_INET, HostCallback, &result); - Process(); - EXPECT_TRUE(result.done_); - std::stringstream ss; - ss << result.host_; - EXPECT_EQ("{'www.google.com' aliases=[] addrs=[1.2.3.4]}", ss.str()); -} - -TEST_P(MockChannelTest, HostAliasMissing) { - DNSPacket yesfirst; - yesfirst.set_response().set_aa() - .add_question(new DNSQuestion("www.first.com", ns_t_a)) - .add_answer(new DNSARR("www.first.com", 0x0200, {2, 3, 4, 5})); - ON_CALL(server_, OnRequest("www.first.com", ns_t_a)) - .WillByDefault(SetReply(&server_, &yesfirst)); - - TempFile aliases("\n\n# www commentedout\nww www.google.com\n"); - EnvValue with_env("HOSTALIASES", aliases.filename()); - HostResult result; - ares_gethostbyname(channel_, "www", AF_INET, HostCallback, &result); - Process(); - EXPECT_TRUE(result.done_); - std::stringstream ss; - ss << result.host_; - EXPECT_EQ("{'www.first.com' aliases=[] addrs=[2.3.4.5]}", ss.str()); -} - -TEST_P(MockChannelTest, HostAliasMissingFile) { - DNSPacket yesfirst; - yesfirst.set_response().set_aa() - .add_question(new DNSQuestion("www.first.com", ns_t_a)) - .add_answer(new DNSARR("www.first.com", 0x0200, {2, 3, 4, 5})); - ON_CALL(server_, OnRequest("www.first.com", ns_t_a)) - .WillByDefault(SetReply(&server_, &yesfirst)); - - EnvValue with_env("HOSTALIASES", "bogus.mcfile"); - HostResult result; - ares_gethostbyname(channel_, "www", AF_INET, HostCallback, &result); - Process(); - EXPECT_TRUE(result.done_); - std::stringstream ss; - ss << result.host_; - EXPECT_EQ("{'www.first.com' aliases=[] addrs=[2.3.4.5]}", ss.str()); -} - -TEST_P(MockChannelTest, HostAliasUnreadable) { - TempFile aliases("www www.google.com\n"); - chmod(aliases.filename(), 0); - EnvValue with_env("HOSTALIASES", aliases.filename()); - - HostResult result; - ares_gethostbyname(channel_, "www", AF_INET, HostCallback, &result); - EXPECT_TRUE(result.done_); - EXPECT_EQ(ARES_EFILE, result.status_); - chmod(aliases.filename(), 0777); -} -#endif - -class MockMultiServerChannelTest - : public MockChannelOptsTest, - public ::testing::WithParamInterface< std::pair<int, bool> > { - public: - MockMultiServerChannelTest(bool rotate) - : MockChannelOptsTest(3, GetParam().first, GetParam().second, nullptr, rotate ? ARES_OPT_ROTATE : ARES_OPT_NOROTATE) {} - void CheckExample() { - HostResult result; - ares_gethostbyname(channel_, "www.example.com.", AF_INET, HostCallback, &result); - Process(); - EXPECT_TRUE(result.done_); - std::stringstream ss; - ss << result.host_; - EXPECT_EQ("{'www.example.com' aliases=[] addrs=[2.3.4.5]}", ss.str()); - } -}; - -class RotateMultiMockTest : public MockMultiServerChannelTest { - public: - RotateMultiMockTest() : MockMultiServerChannelTest(true) {} -}; - -class NoRotateMultiMockTest : public MockMultiServerChannelTest { - public: - NoRotateMultiMockTest() : MockMultiServerChannelTest(false) {} -}; - - -TEST_P(RotateMultiMockTest, ThirdServer) { - struct ares_options opts = {0}; - int optmask = 0; - EXPECT_EQ(ARES_SUCCESS, ares_save_options(channel_, &opts, &optmask)); - EXPECT_EQ(0, (optmask & ARES_OPT_NOROTATE)); - ares_destroy_options(&opts); - - DNSPacket servfailrsp; - servfailrsp.set_response().set_aa().set_rcode(ns_r_servfail) - .add_question(new DNSQuestion("www.example.com", ns_t_a)); - DNSPacket notimplrsp; - notimplrsp.set_response().set_aa().set_rcode(ns_r_notimpl) - .add_question(new DNSQuestion("www.example.com", ns_t_a)); - DNSPacket okrsp; - okrsp.set_response().set_aa() - .add_question(new DNSQuestion("www.example.com", ns_t_a)) - .add_answer(new DNSARR("www.example.com", 100, {2,3,4,5})); - - EXPECT_CALL(*servers_[0], OnRequest("www.example.com", ns_t_a)) - .WillOnce(SetReply(servers_[0].get(), &servfailrsp)); - EXPECT_CALL(*servers_[1], OnRequest("www.example.com", ns_t_a)) - .WillOnce(SetReply(servers_[1].get(), ¬implrsp)); - EXPECT_CALL(*servers_[2], OnRequest("www.example.com", ns_t_a)) - .WillOnce(SetReply(servers_[2].get(), &okrsp)); - CheckExample(); - - // Second time around, starts from server [1]. - EXPECT_CALL(*servers_[1], OnRequest("www.example.com", ns_t_a)) - .WillOnce(SetReply(servers_[1].get(), &servfailrsp)); - EXPECT_CALL(*servers_[2], OnRequest("www.example.com", ns_t_a)) - .WillOnce(SetReply(servers_[2].get(), ¬implrsp)); - EXPECT_CALL(*servers_[0], OnRequest("www.example.com", ns_t_a)) - .WillOnce(SetReply(servers_[0].get(), &okrsp)); - CheckExample(); - - // Third time around, starts from server [2]. - EXPECT_CALL(*servers_[2], OnRequest("www.example.com", ns_t_a)) - .WillOnce(SetReply(servers_[2].get(), &servfailrsp)); - EXPECT_CALL(*servers_[0], OnRequest("www.example.com", ns_t_a)) - .WillOnce(SetReply(servers_[0].get(), ¬implrsp)); - EXPECT_CALL(*servers_[1], OnRequest("www.example.com", ns_t_a)) - .WillOnce(SetReply(servers_[1].get(), &okrsp)); - CheckExample(); -} - -TEST_P(NoRotateMultiMockTest, ThirdServer) { - struct ares_options opts = {0}; - int optmask = 0; - EXPECT_EQ(ARES_SUCCESS, ares_save_options(channel_, &opts, &optmask)); - EXPECT_EQ(ARES_OPT_NOROTATE, (optmask & ARES_OPT_NOROTATE)); - ares_destroy_options(&opts); - - DNSPacket servfailrsp; - servfailrsp.set_response().set_aa().set_rcode(ns_r_servfail) - .add_question(new DNSQuestion("www.example.com", ns_t_a)); - DNSPacket notimplrsp; - notimplrsp.set_response().set_aa().set_rcode(ns_r_notimpl) - .add_question(new DNSQuestion("www.example.com", ns_t_a)); - DNSPacket okrsp; - okrsp.set_response().set_aa() - .add_question(new DNSQuestion("www.example.com", ns_t_a)) - .add_answer(new DNSARR("www.example.com", 100, {2,3,4,5})); - - EXPECT_CALL(*servers_[0], OnRequest("www.example.com", ns_t_a)) - .WillOnce(SetReply(servers_[0].get(), &servfailrsp)); - EXPECT_CALL(*servers_[1], OnRequest("www.example.com", ns_t_a)) - .WillOnce(SetReply(servers_[1].get(), ¬implrsp)); - EXPECT_CALL(*servers_[2], OnRequest("www.example.com", ns_t_a)) - .WillOnce(SetReply(servers_[2].get(), &okrsp)); - CheckExample(); - - // Second time around, still starts from server [0]. - EXPECT_CALL(*servers_[0], OnRequest("www.example.com", ns_t_a)) - .WillOnce(SetReply(servers_[0].get(), &servfailrsp)); - EXPECT_CALL(*servers_[1], OnRequest("www.example.com", ns_t_a)) - .WillOnce(SetReply(servers_[1].get(), ¬implrsp)); - EXPECT_CALL(*servers_[2], OnRequest("www.example.com", ns_t_a)) - .WillOnce(SetReply(servers_[2].get(), &okrsp)); - CheckExample(); - - // Third time around, still starts from server [0]. - EXPECT_CALL(*servers_[0], OnRequest("www.example.com", ns_t_a)) - .WillOnce(SetReply(servers_[0].get(), &servfailrsp)); - EXPECT_CALL(*servers_[1], OnRequest("www.example.com", ns_t_a)) - .WillOnce(SetReply(servers_[1].get(), ¬implrsp)); - EXPECT_CALL(*servers_[2], OnRequest("www.example.com", ns_t_a)) - .WillOnce(SetReply(servers_[2].get(), &okrsp)); - CheckExample(); -} - -INSTANTIATE_TEST_CASE_P(AddressFamilies, MockChannelTest, ::testing::ValuesIn(ares::test::families_modes)); - -INSTANTIATE_TEST_CASE_P(AddressFamilies, MockUDPChannelTest, ::testing::ValuesIn(ares::test::families)); - -INSTANTIATE_TEST_CASE_P(AddressFamilies, MockTCPChannelTest, ::testing::ValuesIn(ares::test::families)); - -INSTANTIATE_TEST_CASE_P(AddressFamilies, MockExtraOptsTest, ::testing::ValuesIn(ares::test::families_modes)); - -INSTANTIATE_TEST_CASE_P(AddressFamilies, MockNoCheckRespChannelTest, ::testing::ValuesIn(ares::test::families_modes)); - -INSTANTIATE_TEST_CASE_P(AddressFamilies, MockEDNSChannelTest, ::testing::ValuesIn(ares::test::families_modes)); - -INSTANTIATE_TEST_CASE_P(TransportModes, RotateMultiMockTest, ::testing::ValuesIn(ares::test::families_modes)); - -INSTANTIATE_TEST_CASE_P(TransportModes, NoRotateMultiMockTest, ::testing::ValuesIn(ares::test::families_modes)); - -} // namespace test -} // namespace ares +TEST_P(MockChannelTest, GetHostByAddrDestroy) { + unsigned char gdns_addr4[4] = {0x08, 0x08, 0x08, 0x08}; + HostResult result; + ares_gethostbyaddr(channel_, gdns_addr4, sizeof(gdns_addr4), AF_INET, HostCallback, &result); + + ares_destroy(channel_); + channel_ = nullptr; + + EXPECT_TRUE(result.done_); // Synchronous + EXPECT_EQ(ARES_EDESTRUCTION, result.status_); + EXPECT_EQ(0, result.timeouts_); +} + +#ifndef WIN32 +TEST_P(MockChannelTest, HostAlias) { + DNSPacket reply; + reply.set_response().set_aa() + .add_question(new DNSQuestion("www.google.com", ns_t_a)) + .add_answer(new DNSARR("www.google.com", 0x0100, {0x01, 0x02, 0x03, 0x04})); + ON_CALL(server_, OnRequest("www.google.com", ns_t_a)) + .WillByDefault(SetReply(&server_, &reply)); + + TempFile aliases("\n\n# www commentedout\nwww www.google.com\n"); + EnvValue with_env("HOSTALIASES", aliases.filename()); + + HostResult result; + ares_gethostbyname(channel_, "www", AF_INET, HostCallback, &result); + Process(); + EXPECT_TRUE(result.done_); + std::stringstream ss; + ss << result.host_; + EXPECT_EQ("{'www.google.com' aliases=[] addrs=[1.2.3.4]}", ss.str()); +} + +TEST_P(MockChannelTest, HostAliasMissing) { + DNSPacket yesfirst; + yesfirst.set_response().set_aa() + .add_question(new DNSQuestion("www.first.com", ns_t_a)) + .add_answer(new DNSARR("www.first.com", 0x0200, {2, 3, 4, 5})); + ON_CALL(server_, OnRequest("www.first.com", ns_t_a)) + .WillByDefault(SetReply(&server_, &yesfirst)); + + TempFile aliases("\n\n# www commentedout\nww www.google.com\n"); + EnvValue with_env("HOSTALIASES", aliases.filename()); + HostResult result; + ares_gethostbyname(channel_, "www", AF_INET, HostCallback, &result); + Process(); + EXPECT_TRUE(result.done_); + std::stringstream ss; + ss << result.host_; + EXPECT_EQ("{'www.first.com' aliases=[] addrs=[2.3.4.5]}", ss.str()); +} + +TEST_P(MockChannelTest, HostAliasMissingFile) { + DNSPacket yesfirst; + yesfirst.set_response().set_aa() + .add_question(new DNSQuestion("www.first.com", ns_t_a)) + .add_answer(new DNSARR("www.first.com", 0x0200, {2, 3, 4, 5})); + ON_CALL(server_, OnRequest("www.first.com", ns_t_a)) + .WillByDefault(SetReply(&server_, &yesfirst)); + + EnvValue with_env("HOSTALIASES", "bogus.mcfile"); + HostResult result; + ares_gethostbyname(channel_, "www", AF_INET, HostCallback, &result); + Process(); + EXPECT_TRUE(result.done_); + std::stringstream ss; + ss << result.host_; + EXPECT_EQ("{'www.first.com' aliases=[] addrs=[2.3.4.5]}", ss.str()); +} + +TEST_P(MockChannelTest, HostAliasUnreadable) { + TempFile aliases("www www.google.com\n"); + chmod(aliases.filename(), 0); + EnvValue with_env("HOSTALIASES", aliases.filename()); + + HostResult result; + ares_gethostbyname(channel_, "www", AF_INET, HostCallback, &result); + EXPECT_TRUE(result.done_); + EXPECT_EQ(ARES_EFILE, result.status_); + chmod(aliases.filename(), 0777); +} +#endif + +class MockMultiServerChannelTest + : public MockChannelOptsTest, + public ::testing::WithParamInterface< std::pair<int, bool> > { + public: + MockMultiServerChannelTest(bool rotate) + : MockChannelOptsTest(3, GetParam().first, GetParam().second, nullptr, rotate ? ARES_OPT_ROTATE : ARES_OPT_NOROTATE) {} + void CheckExample() { + HostResult result; + ares_gethostbyname(channel_, "www.example.com.", AF_INET, HostCallback, &result); + Process(); + EXPECT_TRUE(result.done_); + std::stringstream ss; + ss << result.host_; + EXPECT_EQ("{'www.example.com' aliases=[] addrs=[2.3.4.5]}", ss.str()); + } +}; + +class RotateMultiMockTest : public MockMultiServerChannelTest { + public: + RotateMultiMockTest() : MockMultiServerChannelTest(true) {} +}; + +class NoRotateMultiMockTest : public MockMultiServerChannelTest { + public: + NoRotateMultiMockTest() : MockMultiServerChannelTest(false) {} +}; + + +TEST_P(RotateMultiMockTest, ThirdServer) { + struct ares_options opts = {0}; + int optmask = 0; + EXPECT_EQ(ARES_SUCCESS, ares_save_options(channel_, &opts, &optmask)); + EXPECT_EQ(0, (optmask & ARES_OPT_NOROTATE)); + ares_destroy_options(&opts); + + DNSPacket servfailrsp; + servfailrsp.set_response().set_aa().set_rcode(ns_r_servfail) + .add_question(new DNSQuestion("www.example.com", ns_t_a)); + DNSPacket notimplrsp; + notimplrsp.set_response().set_aa().set_rcode(ns_r_notimpl) + .add_question(new DNSQuestion("www.example.com", ns_t_a)); + DNSPacket okrsp; + okrsp.set_response().set_aa() + .add_question(new DNSQuestion("www.example.com", ns_t_a)) + .add_answer(new DNSARR("www.example.com", 100, {2,3,4,5})); + + EXPECT_CALL(*servers_[0], OnRequest("www.example.com", ns_t_a)) + .WillOnce(SetReply(servers_[0].get(), &servfailrsp)); + EXPECT_CALL(*servers_[1], OnRequest("www.example.com", ns_t_a)) + .WillOnce(SetReply(servers_[1].get(), ¬implrsp)); + EXPECT_CALL(*servers_[2], OnRequest("www.example.com", ns_t_a)) + .WillOnce(SetReply(servers_[2].get(), &okrsp)); + CheckExample(); + + // Second time around, starts from server [1]. + EXPECT_CALL(*servers_[1], OnRequest("www.example.com", ns_t_a)) + .WillOnce(SetReply(servers_[1].get(), &servfailrsp)); + EXPECT_CALL(*servers_[2], OnRequest("www.example.com", ns_t_a)) + .WillOnce(SetReply(servers_[2].get(), ¬implrsp)); + EXPECT_CALL(*servers_[0], OnRequest("www.example.com", ns_t_a)) + .WillOnce(SetReply(servers_[0].get(), &okrsp)); + CheckExample(); + + // Third time around, starts from server [2]. + EXPECT_CALL(*servers_[2], OnRequest("www.example.com", ns_t_a)) + .WillOnce(SetReply(servers_[2].get(), &servfailrsp)); + EXPECT_CALL(*servers_[0], OnRequest("www.example.com", ns_t_a)) + .WillOnce(SetReply(servers_[0].get(), ¬implrsp)); + EXPECT_CALL(*servers_[1], OnRequest("www.example.com", ns_t_a)) + .WillOnce(SetReply(servers_[1].get(), &okrsp)); + CheckExample(); +} + +TEST_P(NoRotateMultiMockTest, ThirdServer) { + struct ares_options opts = {0}; + int optmask = 0; + EXPECT_EQ(ARES_SUCCESS, ares_save_options(channel_, &opts, &optmask)); + EXPECT_EQ(ARES_OPT_NOROTATE, (optmask & ARES_OPT_NOROTATE)); + ares_destroy_options(&opts); + + DNSPacket servfailrsp; + servfailrsp.set_response().set_aa().set_rcode(ns_r_servfail) + .add_question(new DNSQuestion("www.example.com", ns_t_a)); + DNSPacket notimplrsp; + notimplrsp.set_response().set_aa().set_rcode(ns_r_notimpl) + .add_question(new DNSQuestion("www.example.com", ns_t_a)); + DNSPacket okrsp; + okrsp.set_response().set_aa() + .add_question(new DNSQuestion("www.example.com", ns_t_a)) + .add_answer(new DNSARR("www.example.com", 100, {2,3,4,5})); + + EXPECT_CALL(*servers_[0], OnRequest("www.example.com", ns_t_a)) + .WillOnce(SetReply(servers_[0].get(), &servfailrsp)); + EXPECT_CALL(*servers_[1], OnRequest("www.example.com", ns_t_a)) + .WillOnce(SetReply(servers_[1].get(), ¬implrsp)); + EXPECT_CALL(*servers_[2], OnRequest("www.example.com", ns_t_a)) + .WillOnce(SetReply(servers_[2].get(), &okrsp)); + CheckExample(); + + // Second time around, still starts from server [0]. + EXPECT_CALL(*servers_[0], OnRequest("www.example.com", ns_t_a)) + .WillOnce(SetReply(servers_[0].get(), &servfailrsp)); + EXPECT_CALL(*servers_[1], OnRequest("www.example.com", ns_t_a)) + .WillOnce(SetReply(servers_[1].get(), ¬implrsp)); + EXPECT_CALL(*servers_[2], OnRequest("www.example.com", ns_t_a)) + .WillOnce(SetReply(servers_[2].get(), &okrsp)); + CheckExample(); + + // Third time around, still starts from server [0]. + EXPECT_CALL(*servers_[0], OnRequest("www.example.com", ns_t_a)) + .WillOnce(SetReply(servers_[0].get(), &servfailrsp)); + EXPECT_CALL(*servers_[1], OnRequest("www.example.com", ns_t_a)) + .WillOnce(SetReply(servers_[1].get(), ¬implrsp)); + EXPECT_CALL(*servers_[2], OnRequest("www.example.com", ns_t_a)) + .WillOnce(SetReply(servers_[2].get(), &okrsp)); + CheckExample(); +} + +INSTANTIATE_TEST_CASE_P(AddressFamilies, MockChannelTest, ::testing::ValuesIn(ares::test::families_modes)); + +INSTANTIATE_TEST_CASE_P(AddressFamilies, MockUDPChannelTest, ::testing::ValuesIn(ares::test::families)); + +INSTANTIATE_TEST_CASE_P(AddressFamilies, MockTCPChannelTest, ::testing::ValuesIn(ares::test::families)); + +INSTANTIATE_TEST_CASE_P(AddressFamilies, MockExtraOptsTest, ::testing::ValuesIn(ares::test::families_modes)); + +INSTANTIATE_TEST_CASE_P(AddressFamilies, MockNoCheckRespChannelTest, ::testing::ValuesIn(ares::test::families_modes)); + +INSTANTIATE_TEST_CASE_P(AddressFamilies, MockEDNSChannelTest, ::testing::ValuesIn(ares::test::families_modes)); + +INSTANTIATE_TEST_CASE_P(TransportModes, RotateMultiMockTest, ::testing::ValuesIn(ares::test::families_modes)); + +INSTANTIATE_TEST_CASE_P(TransportModes, NoRotateMultiMockTest, ::testing::ValuesIn(ares::test::families_modes)); + +} // namespace test +} // namespace ares diff --git a/contrib/libs/c-ares/test/ares-test-ns.cc b/contrib/libs/c-ares/test/ares-test-ns.cc index 77ebdcc2e2..c3c455214d 100644 --- a/contrib/libs/c-ares/test/ares-test-ns.cc +++ b/contrib/libs/c-ares/test/ares-test-ns.cc @@ -1,199 +1,199 @@ -#include "ares-test.h" - -#ifdef HAVE_CONTAINER - -#include <sys/mount.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> - -#include <iostream> -#include <functional> -#include <string> -#include <sstream> -#include <vector> - -namespace ares { -namespace test { - -namespace { - -struct ContainerInfo { - ContainerFilesystem* fs_; - std::string hostname_; - std::string domainname_; - VoidToIntFn fn_; -}; - -int EnterContainer(void *data) { - ContainerInfo *container = (ContainerInfo*)data; - - if (verbose) { - std::cerr << "Running function in container {chroot='" - << container->fs_->root() << "', hostname='" << container->hostname_ - << "', domainname='" << container->domainname_ << "'}" - << std::endl; - } - - // Ensure we are apparently root before continuing. - int count = 10; - while (getuid() != 0 && count > 0) { - usleep(100000); - count--; - } - if (getuid() != 0) { - std::cerr << "Child in user namespace has uid " << getuid() << std::endl; - return -1; - } - if (!container->fs_->mountpt().empty()) { - // We want to bind mount this inside the specified directory. - std::string innerdir = container->fs_->root() + container->fs_->mountpt(); - if (verbose) std::cerr << " mount --bind " << container->fs_->mountpt() - << " " << innerdir << std::endl; - int rc = mount(container->fs_->mountpt().c_str(), innerdir.c_str(), - "none", MS_BIND, 0); - if (rc != 0) { - std::cerr << "Warning: failed to bind mount " << container->fs_->mountpt() << " at " - << innerdir << ", errno=" << errno << std::endl; - } - } - - // Move into the specified directory. - if (chdir(container->fs_->root().c_str()) != 0) { - std::cerr << "Failed to chdir('" << container->fs_->root() - << "'), errno=" << errno << std::endl; - return -1; - } - // And make it the new root directory; - char buffer[PATH_MAX + 1]; - if (getcwd(buffer, PATH_MAX) == NULL) { - std::cerr << "failed to retrieve cwd, errno=" << errno << std::endl; - return -1; - } - buffer[PATH_MAX] = '\0'; - if (chroot(buffer) != 0) { - std::cerr << "chroot('" << buffer << "') failed, errno=" << errno << std::endl; - return -1; - } - - // Set host/domainnames if specified - if (!container->hostname_.empty()) { - if (sethostname(container->hostname_.c_str(), - container->hostname_.size()) != 0) { - std::cerr << "Failed to sethostname('" << container->hostname_ - << "'), errno=" << errno << std::endl; - return -1; - } - } - if (!container->domainname_.empty()) { - if (setdomainname(container->domainname_.c_str(), - container->domainname_.size()) != 0) { - std::cerr << "Failed to setdomainname('" << container->domainname_ - << "'), errno=" << errno << std::endl; - return -1; - } - } - - return container->fn_(); -} - -} // namespace - -// Run a function while: -// - chroot()ed into a particular directory -// - having a specified hostname/domainname - -int RunInContainer(ContainerFilesystem* fs, const std::string& hostname, - const std::string& domainname, VoidToIntFn fn) { - const int stack_size = 1024 * 1024; - std::vector<byte> stack(stack_size, 0); - ContainerInfo container = {fs, hostname, domainname, fn}; - - // Start a child process in a new user and UTS namespace - pid_t child = clone(EnterContainer, stack.data() + stack_size, - CLONE_VM|CLONE_NEWNS|CLONE_NEWUSER|CLONE_NEWUTS|SIGCHLD, - (void *)&container); - if (child < 0) { - std::cerr << "Failed to clone(), errno=" << errno << std::endl; - return -1; - } - - // Build the UID map that makes us look like root inside the namespace. - std::stringstream mapfiless; - mapfiless << "/proc/" << child << "/uid_map"; - std::string mapfile = mapfiless.str(); - int fd = open(mapfile.c_str(), O_CREAT|O_WRONLY|O_TRUNC, 0644); - if (fd < 0) { - std::cerr << "Failed to create '" << mapfile << "'" << std::endl; - return -1; - } - std::stringstream contentss; - contentss << "0 " << getuid() << " 1" << std::endl; - std::string content = contentss.str(); - int rc = write(fd, content.c_str(), content.size()); - if (rc != (int)content.size()) { - std::cerr << "Failed to write uid map to '" << mapfile << "'" << std::endl; - } - close(fd); - - // Wait for the child process and retrieve its status. - int status; - waitpid(child, &status, 0); - if (rc <= 0) { - std::cerr << "Failed to waitpid(" << child << ")" << std::endl; - return -1; - } - if (!WIFEXITED(status)) { - std::cerr << "Child " << child << " did not exit normally" << std::endl; - return -1; - } - return status; -} - -ContainerFilesystem::ContainerFilesystem(NameContentList files, const std::string& mountpt) { - rootdir_ = TempNam(nullptr, "ares-chroot"); - mkdir(rootdir_.c_str(), 0755); - dirs_.push_front(rootdir_); - for (const auto& nc : files) { - std::string fullpath = rootdir_ + nc.first; - int idx = fullpath.rfind('/'); - std::string dir = fullpath.substr(0, idx); - EnsureDirExists(dir); - files_.push_back(std::unique_ptr<TransientFile>( - new TransientFile(fullpath, nc.second))); - } - if (!mountpt.empty()) { - char buffer[PATH_MAX + 1]; - if (realpath(mountpt.c_str(), buffer)) { - mountpt_ = buffer; - std::string fullpath = rootdir_ + mountpt_; - EnsureDirExists(fullpath); - } - } -} - -ContainerFilesystem::~ContainerFilesystem() { - files_.clear(); - for (const std::string& dir : dirs_) { - rmdir(dir.c_str()); - } -} - -void ContainerFilesystem::EnsureDirExists(const std::string& dir) { - if (std::find(dirs_.begin(), dirs_.end(), dir) != dirs_.end()) { - return; - } - size_t idx = dir.rfind('/'); - if (idx != std::string::npos) { - std::string prevdir = dir.substr(0, idx); - EnsureDirExists(prevdir); - } - // Ensure this directory is in the list before its ancestors. - mkdir(dir.c_str(), 0755); - dirs_.push_front(dir); -} - -} // namespace test -} // namespace ares - -#endif +#include "ares-test.h" + +#ifdef HAVE_CONTAINER + +#include <sys/mount.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> + +#include <iostream> +#include <functional> +#include <string> +#include <sstream> +#include <vector> + +namespace ares { +namespace test { + +namespace { + +struct ContainerInfo { + ContainerFilesystem* fs_; + std::string hostname_; + std::string domainname_; + VoidToIntFn fn_; +}; + +int EnterContainer(void *data) { + ContainerInfo *container = (ContainerInfo*)data; + + if (verbose) { + std::cerr << "Running function in container {chroot='" + << container->fs_->root() << "', hostname='" << container->hostname_ + << "', domainname='" << container->domainname_ << "'}" + << std::endl; + } + + // Ensure we are apparently root before continuing. + int count = 10; + while (getuid() != 0 && count > 0) { + usleep(100000); + count--; + } + if (getuid() != 0) { + std::cerr << "Child in user namespace has uid " << getuid() << std::endl; + return -1; + } + if (!container->fs_->mountpt().empty()) { + // We want to bind mount this inside the specified directory. + std::string innerdir = container->fs_->root() + container->fs_->mountpt(); + if (verbose) std::cerr << " mount --bind " << container->fs_->mountpt() + << " " << innerdir << std::endl; + int rc = mount(container->fs_->mountpt().c_str(), innerdir.c_str(), + "none", MS_BIND, 0); + if (rc != 0) { + std::cerr << "Warning: failed to bind mount " << container->fs_->mountpt() << " at " + << innerdir << ", errno=" << errno << std::endl; + } + } + + // Move into the specified directory. + if (chdir(container->fs_->root().c_str()) != 0) { + std::cerr << "Failed to chdir('" << container->fs_->root() + << "'), errno=" << errno << std::endl; + return -1; + } + // And make it the new root directory; + char buffer[PATH_MAX + 1]; + if (getcwd(buffer, PATH_MAX) == NULL) { + std::cerr << "failed to retrieve cwd, errno=" << errno << std::endl; + return -1; + } + buffer[PATH_MAX] = '\0'; + if (chroot(buffer) != 0) { + std::cerr << "chroot('" << buffer << "') failed, errno=" << errno << std::endl; + return -1; + } + + // Set host/domainnames if specified + if (!container->hostname_.empty()) { + if (sethostname(container->hostname_.c_str(), + container->hostname_.size()) != 0) { + std::cerr << "Failed to sethostname('" << container->hostname_ + << "'), errno=" << errno << std::endl; + return -1; + } + } + if (!container->domainname_.empty()) { + if (setdomainname(container->domainname_.c_str(), + container->domainname_.size()) != 0) { + std::cerr << "Failed to setdomainname('" << container->domainname_ + << "'), errno=" << errno << std::endl; + return -1; + } + } + + return container->fn_(); +} + +} // namespace + +// Run a function while: +// - chroot()ed into a particular directory +// - having a specified hostname/domainname + +int RunInContainer(ContainerFilesystem* fs, const std::string& hostname, + const std::string& domainname, VoidToIntFn fn) { + const int stack_size = 1024 * 1024; + std::vector<byte> stack(stack_size, 0); + ContainerInfo container = {fs, hostname, domainname, fn}; + + // Start a child process in a new user and UTS namespace + pid_t child = clone(EnterContainer, stack.data() + stack_size, + CLONE_VM|CLONE_NEWNS|CLONE_NEWUSER|CLONE_NEWUTS|SIGCHLD, + (void *)&container); + if (child < 0) { + std::cerr << "Failed to clone(), errno=" << errno << std::endl; + return -1; + } + + // Build the UID map that makes us look like root inside the namespace. + std::stringstream mapfiless; + mapfiless << "/proc/" << child << "/uid_map"; + std::string mapfile = mapfiless.str(); + int fd = open(mapfile.c_str(), O_CREAT|O_WRONLY|O_TRUNC, 0644); + if (fd < 0) { + std::cerr << "Failed to create '" << mapfile << "'" << std::endl; + return -1; + } + std::stringstream contentss; + contentss << "0 " << getuid() << " 1" << std::endl; + std::string content = contentss.str(); + int rc = write(fd, content.c_str(), content.size()); + if (rc != (int)content.size()) { + std::cerr << "Failed to write uid map to '" << mapfile << "'" << std::endl; + } + close(fd); + + // Wait for the child process and retrieve its status. + int status; + waitpid(child, &status, 0); + if (rc <= 0) { + std::cerr << "Failed to waitpid(" << child << ")" << std::endl; + return -1; + } + if (!WIFEXITED(status)) { + std::cerr << "Child " << child << " did not exit normally" << std::endl; + return -1; + } + return status; +} + +ContainerFilesystem::ContainerFilesystem(NameContentList files, const std::string& mountpt) { + rootdir_ = TempNam(nullptr, "ares-chroot"); + mkdir(rootdir_.c_str(), 0755); + dirs_.push_front(rootdir_); + for (const auto& nc : files) { + std::string fullpath = rootdir_ + nc.first; + int idx = fullpath.rfind('/'); + std::string dir = fullpath.substr(0, idx); + EnsureDirExists(dir); + files_.push_back(std::unique_ptr<TransientFile>( + new TransientFile(fullpath, nc.second))); + } + if (!mountpt.empty()) { + char buffer[PATH_MAX + 1]; + if (realpath(mountpt.c_str(), buffer)) { + mountpt_ = buffer; + std::string fullpath = rootdir_ + mountpt_; + EnsureDirExists(fullpath); + } + } +} + +ContainerFilesystem::~ContainerFilesystem() { + files_.clear(); + for (const std::string& dir : dirs_) { + rmdir(dir.c_str()); + } +} + +void ContainerFilesystem::EnsureDirExists(const std::string& dir) { + if (std::find(dirs_.begin(), dirs_.end(), dir) != dirs_.end()) { + return; + } + size_t idx = dir.rfind('/'); + if (idx != std::string::npos) { + std::string prevdir = dir.substr(0, idx); + EnsureDirExists(prevdir); + } + // Ensure this directory is in the list before its ancestors. + mkdir(dir.c_str(), 0755); + dirs_.push_front(dir); +} + +} // namespace test +} // namespace ares + +#endif diff --git a/contrib/libs/c-ares/test/ares-test-parse-a.cc b/contrib/libs/c-ares/test/ares-test-parse-a.cc index 65bc822c05..7f6a987c13 100644 --- a/contrib/libs/c-ares/test/ares-test-parse-a.cc +++ b/contrib/libs/c-ares/test/ares-test-parse-a.cc @@ -1,41 +1,41 @@ -#include "ares-test.h" -#include "dns-proto.h" - -#include <sstream> -#include <vector> - -namespace ares { -namespace test { - -TEST_F(LibraryTest, ParseAReplyOK) { - DNSPacket pkt; - pkt.set_qid(0x1234).set_response().set_aa() - .add_question(new DNSQuestion("example.com", ns_t_a)) +#include "ares-test.h" +#include "dns-proto.h" + +#include <sstream> +#include <vector> + +namespace ares { +namespace test { + +TEST_F(LibraryTest, ParseAReplyOK) { + DNSPacket pkt; + pkt.set_qid(0x1234).set_response().set_aa() + .add_question(new DNSQuestion("example.com", ns_t_a)) .add_answer(new DNSARR("example.com", 0x01020304, {2,3,4,5})) .add_answer(new DNSAaaaRR("example.com", 0x01020304, {0,0,0,0,0,0,0,0,0,0,0,0,2,3,4,5})); - std::vector<byte> data = { - 0x12, 0x34, // qid - 0x84, // response + query + AA + not-TC + not-RD - 0x00, // not-RA + not-Z + not-AD + not-CD + rc=NoError - 0x00, 0x01, // num questions + std::vector<byte> data = { + 0x12, 0x34, // qid + 0x84, // response + query + AA + not-TC + not-RD + 0x00, // not-RA + not-Z + not-AD + not-CD + rc=NoError + 0x00, 0x01, // num questions 0x00, 0x02, // num answer RRs - 0x00, 0x00, // num authority RRs - 0x00, 0x00, // num additional RRs - // Question - 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', - 0x03, 'c', 'o', 'm', - 0x00, - 0x00, 0x01, // type A - 0x00, 0x01, // class IN - // Answer 1 - 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', - 0x03, 'c', 'o', 'm', - 0x00, - 0x00, 0x01, // RR type - 0x00, 0x01, // class IN - 0x01, 0x02, 0x03, 0x04, // TTL - 0x00, 0x04, // rdata length - 0x02, 0x03, 0x04, 0x05, + 0x00, 0x00, // num authority RRs + 0x00, 0x00, // num additional RRs + // Question + 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + 0x00, 0x01, // type A + 0x00, 0x01, // class IN + // Answer 1 + 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + 0x00, 0x01, // RR type + 0x00, 0x01, // class IN + 0x01, 0x02, 0x03, 0x04, // TTL + 0x00, 0x04, // rdata length + 0x02, 0x03, 0x04, 0x05, // Answer 2 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 0x03, 'c', 'o', 'm', @@ -45,334 +45,334 @@ TEST_F(LibraryTest, ParseAReplyOK) { 0x01, 0x02, 0x03, 0x04, // TTL 0x00, 0x10, // rdata length 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0x04, 0x05, - }; - EXPECT_EQ(data, pkt.data()); - struct hostent *host = nullptr; - struct ares_addrttl info[5]; - int count = 5; - EXPECT_EQ(ARES_SUCCESS, ares_parse_a_reply(data.data(), data.size(), - &host, info, &count)); - EXPECT_EQ(1, count); - EXPECT_EQ(0x01020304, info[0].ttl); - unsigned long expected_addr = htonl(0x02030405); - EXPECT_EQ(expected_addr, info[0].ipaddr.s_addr); - EXPECT_EQ("2.3.4.5", AddressToString(&(info[0].ipaddr), 4)); - ASSERT_NE(nullptr, host); - std::stringstream ss; - ss << HostEnt(host); - EXPECT_EQ("{'example.com' aliases=[] addrs=[2.3.4.5]}", ss.str()); - ares_free_hostent(host); - - // Repeat without providing a hostent - EXPECT_EQ(ARES_SUCCESS, ares_parse_a_reply(data.data(), data.size(), - nullptr, info, &count)); - EXPECT_EQ(1, count); - EXPECT_EQ(0x01020304, info[0].ttl); - EXPECT_EQ(expected_addr, info[0].ipaddr.s_addr); - EXPECT_EQ("2.3.4.5", AddressToString(&(info[0].ipaddr), 4)); -} - -TEST_F(LibraryTest, ParseMalformedAReply) { - std::vector<byte> data = { - 0x12, 0x34, // [0:2) qid - 0x84, // [2] response + query + AA + not-TC + not-RD - 0x00, // [3] not-RA + not-Z + not-AD + not-CD + rc=NoError - 0x00, 0x01, // [4:6) num questions + }; + EXPECT_EQ(data, pkt.data()); + struct hostent *host = nullptr; + struct ares_addrttl info[5]; + int count = 5; + EXPECT_EQ(ARES_SUCCESS, ares_parse_a_reply(data.data(), data.size(), + &host, info, &count)); + EXPECT_EQ(1, count); + EXPECT_EQ(0x01020304, info[0].ttl); + unsigned long expected_addr = htonl(0x02030405); + EXPECT_EQ(expected_addr, info[0].ipaddr.s_addr); + EXPECT_EQ("2.3.4.5", AddressToString(&(info[0].ipaddr), 4)); + ASSERT_NE(nullptr, host); + std::stringstream ss; + ss << HostEnt(host); + EXPECT_EQ("{'example.com' aliases=[] addrs=[2.3.4.5]}", ss.str()); + ares_free_hostent(host); + + // Repeat without providing a hostent + EXPECT_EQ(ARES_SUCCESS, ares_parse_a_reply(data.data(), data.size(), + nullptr, info, &count)); + EXPECT_EQ(1, count); + EXPECT_EQ(0x01020304, info[0].ttl); + EXPECT_EQ(expected_addr, info[0].ipaddr.s_addr); + EXPECT_EQ("2.3.4.5", AddressToString(&(info[0].ipaddr), 4)); +} + +TEST_F(LibraryTest, ParseMalformedAReply) { + std::vector<byte> data = { + 0x12, 0x34, // [0:2) qid + 0x84, // [2] response + query + AA + not-TC + not-RD + 0x00, // [3] not-RA + not-Z + not-AD + not-CD + rc=NoError + 0x00, 0x01, // [4:6) num questions 0x00, 0x02, // [6:8) num answer RRs - 0x00, 0x00, // [8:10) num authority RRs - 0x00, 0x00, // [10:12) num additional RRs - // Question - 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', // [12:20) - 0x03, 'c', 'o', 'm', // [20,24) - 0x00, // [24] - 0x00, 0x01, // [25:26) type A - 0x00, 0x01, // [27:29) class IN - // Answer 1 - 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', // [29:37) - 0x03, 'c', 'o', 'm', // [37:41) - 0x00, // [41] - 0x00, 0x01, // [42:44) RR type - 0x00, 0x01, // [44:46) class IN - 0x01, 0x02, 0x03, 0x04, // [46:50) TTL - 0x00, 0x04, // [50:52) rdata length - 0x02, 0x03, 0x04, 0x05, // [52,56) - }; - struct hostent *host = nullptr; - struct ares_addrttl info[2]; - int count = 2; - - // Invalid RR-len. - std::vector<byte> invalid_rrlen(data); - invalid_rrlen[51] = 180; - EXPECT_EQ(ARES_EBADRESP, ares_parse_a_reply(invalid_rrlen.data(), invalid_rrlen.size(), - &host, info, &count)); - - // Truncate mid-question. - EXPECT_EQ(ARES_EBADRESP, ares_parse_a_reply(data.data(), 26, - &host, info, &count)); - - // Truncate mid-answer. - EXPECT_EQ(ARES_EBADRESP, ares_parse_a_reply(data.data(), 42, - &host, info, &count)); -} - -TEST_F(LibraryTest, ParseAReplyNoData) { - DNSPacket pkt; - pkt.set_qid(0x1234).set_response().set_aa() - .add_question(new DNSQuestion("example.com", ns_t_a)); - std::vector<byte> data = pkt.data(); - struct hostent *host = nullptr; - struct ares_addrttl info[2]; - int count = 2; - EXPECT_EQ(ARES_ENODATA, ares_parse_a_reply(data.data(), data.size(), - &host, info, &count)); - EXPECT_EQ(0, count); - EXPECT_EQ(nullptr, host); - - // Again but with a CNAME. - pkt.add_answer(new DNSCnameRR("example.com", 200, "c.example.com")); + 0x00, 0x00, // [8:10) num authority RRs + 0x00, 0x00, // [10:12) num additional RRs + // Question + 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', // [12:20) + 0x03, 'c', 'o', 'm', // [20,24) + 0x00, // [24] + 0x00, 0x01, // [25:26) type A + 0x00, 0x01, // [27:29) class IN + // Answer 1 + 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', // [29:37) + 0x03, 'c', 'o', 'm', // [37:41) + 0x00, // [41] + 0x00, 0x01, // [42:44) RR type + 0x00, 0x01, // [44:46) class IN + 0x01, 0x02, 0x03, 0x04, // [46:50) TTL + 0x00, 0x04, // [50:52) rdata length + 0x02, 0x03, 0x04, 0x05, // [52,56) + }; + struct hostent *host = nullptr; + struct ares_addrttl info[2]; + int count = 2; + + // Invalid RR-len. + std::vector<byte> invalid_rrlen(data); + invalid_rrlen[51] = 180; + EXPECT_EQ(ARES_EBADRESP, ares_parse_a_reply(invalid_rrlen.data(), invalid_rrlen.size(), + &host, info, &count)); + + // Truncate mid-question. + EXPECT_EQ(ARES_EBADRESP, ares_parse_a_reply(data.data(), 26, + &host, info, &count)); + + // Truncate mid-answer. + EXPECT_EQ(ARES_EBADRESP, ares_parse_a_reply(data.data(), 42, + &host, info, &count)); +} + +TEST_F(LibraryTest, ParseAReplyNoData) { + DNSPacket pkt; + pkt.set_qid(0x1234).set_response().set_aa() + .add_question(new DNSQuestion("example.com", ns_t_a)); + std::vector<byte> data = pkt.data(); + struct hostent *host = nullptr; + struct ares_addrttl info[2]; + int count = 2; + EXPECT_EQ(ARES_ENODATA, ares_parse_a_reply(data.data(), data.size(), + &host, info, &count)); + EXPECT_EQ(0, count); + EXPECT_EQ(nullptr, host); + + // Again but with a CNAME. + pkt.add_answer(new DNSCnameRR("example.com", 200, "c.example.com")); data = pkt.data(); // Expect success as per https://github.com/c-ares/c-ares/commit/2c63440127feed70ccefb148b8f938a2df6c15f8 EXPECT_EQ(ARES_SUCCESS, ares_parse_a_reply(data.data(), data.size(), - &host, info, &count)); - EXPECT_EQ(0, count); + &host, info, &count)); + EXPECT_EQ(0, count); EXPECT_NE(nullptr, host); std::stringstream ss; ss << HostEnt(host); EXPECT_EQ("{'c.example.com' aliases=[example.com] addrs=[]}", ss.str()); ares_free_hostent(host); -} - -TEST_F(LibraryTest, ParseAReplyVariantA) { - DNSPacket pkt; - pkt.set_qid(6366).set_rd().set_ra() - .add_question(new DNSQuestion("mit.edu", ns_t_a)) - .add_answer(new DNSARR("mit.edu", 52, {18,7,22,69})) - .add_auth(new DNSNsRR("mit.edu", 292, "W20NS.mit.edu")) - .add_auth(new DNSNsRR("mit.edu", 292, "BITSY.mit.edu")) - .add_auth(new DNSNsRR("mit.edu", 292, "STRAWB.mit.edu")) - .add_additional(new DNSARR("STRAWB.mit.edu", 292, {18,71,0,151})); - struct hostent *host = nullptr; - struct ares_addrttl info[2]; - int count = 2; - std::vector<byte> data = pkt.data(); - EXPECT_EQ(ARES_SUCCESS, ares_parse_a_reply(data.data(), data.size(), - &host, info, &count)); - EXPECT_EQ(1, count); - EXPECT_EQ("18.7.22.69", AddressToString(&(info[0].ipaddr), 4)); - EXPECT_EQ(52, info[0].ttl); - ares_free_hostent(host); -} - -TEST_F(LibraryTest, ParseAReplyJustCname) { - DNSPacket pkt; - pkt.set_qid(6366).set_rd().set_ra() - .add_question(new DNSQuestion("mit.edu", ns_t_a)) - .add_answer(new DNSCnameRR("mit.edu", 52, "other.mit.edu")); - struct hostent *host = nullptr; - struct ares_addrttl info[2]; - int count = 2; - std::vector<byte> data = pkt.data(); - EXPECT_EQ(ARES_SUCCESS, ares_parse_a_reply(data.data(), data.size(), - &host, info, &count)); - EXPECT_EQ(0, count); - ASSERT_NE(nullptr, host); - std::stringstream ss; - ss << HostEnt(host); - EXPECT_EQ("{'other.mit.edu' aliases=[mit.edu] addrs=[]}", ss.str()); - ares_free_hostent(host); -} - -TEST_F(LibraryTest, ParseAReplyVariantCname) { - DNSPacket pkt; - pkt.set_qid(6366).set_rd().set_ra() - .add_question(new DNSQuestion("query.example.com", ns_t_a)) - .add_answer(new DNSCnameRR("query.example.com", 200, "redirect.query.example.com")) - .add_answer(new DNSARR("redirect.query.example.com", 300, {129,97,123,22})) - .add_auth(new DNSNsRR("example.com", 218, "aa.ns1.example.com")) - .add_auth(new DNSNsRR("example.com", 218, "ns2.example.com")) - .add_auth(new DNSNsRR("example.com", 218, "ns3.example.com")) - .add_auth(new DNSNsRR("example.com", 218, "ns4.example.com")) - .add_additional(new DNSARR("aa.ns1.example.com", 218, {129,97,1,1})) - .add_additional(new DNSARR("ns2.example.com", 218, {129,97,1,2})) - .add_additional(new DNSARR("ns3.example.com", 218, {129,97,1,3})) - .add_additional(new DNSARR("ns4.example.com", 218, {129,97,1,4})); - struct hostent *host = nullptr; - struct ares_addrttl info[2]; - int count = 2; - std::vector<byte> data = pkt.data(); - EXPECT_EQ(ARES_SUCCESS, ares_parse_a_reply(data.data(), data.size(), - &host, info, &count)); - EXPECT_EQ(1, count); - EXPECT_EQ("129.97.123.22", AddressToString(&(info[0].ipaddr), 4)); - // TTL is reduced to match CNAME's. - EXPECT_EQ(200, info[0].ttl); - ares_free_hostent(host); - - // Repeat parsing without places to put the results. - count = 0; - EXPECT_EQ(ARES_SUCCESS, ares_parse_a_reply(data.data(), data.size(), - nullptr, info, &count)); -} - -TEST_F(LibraryTest, ParseAReplyVariantCnameChain) { - DNSPacket pkt; - pkt.set_qid(6366).set_rd().set_ra() - .add_question(new DNSQuestion("c1.localhost", ns_t_a)) - .add_answer(new DNSCnameRR("c1.localhost", 604800, "c2.localhost")) - .add_answer(new DNSCnameRR("c2.localhost", 604800, "c3.localhost")) - .add_answer(new DNSCnameRR("c3.localhost", 604800, "c4.localhost")) - .add_answer(new DNSARR("c4.localhost", 604800, {8,8,8,8})) - .add_auth(new DNSNsRR("localhost", 604800, "localhost")) - .add_additional(new DNSARR("localhost", 604800, {127,0,0,1})) - .add_additional(new DNSAaaaRR("localhost", 604800, - {0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01})); - struct hostent *host = nullptr; - struct ares_addrttl info[2]; - int count = 2; - std::vector<byte> data = pkt.data(); - EXPECT_EQ(ARES_SUCCESS, ares_parse_a_reply(data.data(), data.size(), - &host, info, &count)); - EXPECT_EQ(1, count); - EXPECT_EQ("8.8.8.8", AddressToString(&(info[0].ipaddr), 4)); - EXPECT_EQ(604800, info[0].ttl); - ares_free_hostent(host); -} - -TEST_F(LibraryTest, DISABLED_ParseAReplyVariantCnameLast) { - DNSPacket pkt; - pkt.set_qid(6366).set_rd().set_ra() - .add_question(new DNSQuestion("query.example.com", ns_t_a)) - .add_answer(new DNSARR("redirect.query.example.com", 300, {129,97,123,221})) - .add_answer(new DNSARR("redirect.query.example.com", 300, {129,97,123,222})) - .add_answer(new DNSARR("redirect.query.example.com", 300, {129,97,123,223})) - .add_answer(new DNSARR("redirect.query.example.com", 300, {129,97,123,224})) - .add_answer(new DNSCnameRR("query.example.com", 60, "redirect.query.example.com")) - .add_additional(new DNSTxtRR("query.example.com", 60, {"text record"})); - struct hostent *host = nullptr; - struct ares_addrttl info[8]; - int count = 8; - std::vector<byte> data = pkt.data(); - EXPECT_EQ(ARES_SUCCESS, ares_parse_a_reply(data.data(), data.size(), - &host, info, &count)); - EXPECT_EQ(4, count); - EXPECT_EQ("129.97.123.221", AddressToString(&(info[0].ipaddr), 4)); - EXPECT_EQ("129.97.123.222", AddressToString(&(info[1].ipaddr), 4)); - EXPECT_EQ("129.97.123.223", AddressToString(&(info[2].ipaddr), 4)); - EXPECT_EQ("129.97.123.224", AddressToString(&(info[3].ipaddr), 4)); - EXPECT_EQ(300, info[0].ttl); - EXPECT_EQ(300, info[1].ttl); - EXPECT_EQ(300, info[2].ttl); - EXPECT_EQ(300, info[3].ttl); - ares_free_hostent(host); -} - -TEST_F(LibraryTest, ParseAReplyErrors) { - DNSPacket pkt; - pkt.set_qid(0x1234).set_response().set_aa() - .add_question(new DNSQuestion("example.com", ns_t_a)) - .add_answer(new DNSARR("example.com", 100, {0x02, 0x03, 0x04, 0x05})); - std::vector<byte> data; - - struct hostent *host = nullptr; - struct ares_addrttl info[2]; - int count = 2; - - // No question. - pkt.questions_.clear(); - data = pkt.data(); - EXPECT_EQ(ARES_EBADRESP, ares_parse_a_reply(data.data(), data.size(), - &host, info, &count)); - EXPECT_EQ(nullptr, host); - pkt.add_question(new DNSQuestion("example.com", ns_t_a)); - - // Question != answer - pkt.questions_.clear(); - pkt.add_question(new DNSQuestion("Axample.com", ns_t_a)); - data = pkt.data(); - EXPECT_EQ(ARES_ENODATA, ares_parse_a_reply(data.data(), data.size(), - &host, info, &count)); - EXPECT_EQ(nullptr, host); - pkt.questions_.clear(); - pkt.add_question(new DNSQuestion("example.com", ns_t_a)); - -#ifdef DISABLED - // Not a response. - pkt.set_response(false); - data = pkt.data(); - EXPECT_EQ(ARES_EBADRESP, ares_parse_a_reply(data.data(), data.size(), - &host, info, &count)); - EXPECT_EQ(nullptr, host); - pkt.set_response(true); - - // Bad return code. - pkt.set_rcode(ns_r_formerr); - data = pkt.data(); - EXPECT_EQ(ARES_ENODATA, ares_parse_a_reply(data.data(), data.size(), - &host, info, &count)); - EXPECT_EQ(nullptr, host); - pkt.set_rcode(ns_r_noerror); -#endif - - // Two questions - pkt.add_question(new DNSQuestion("example.com", ns_t_a)); - data = pkt.data(); - EXPECT_EQ(ARES_EBADRESP, ares_parse_a_reply(data.data(), data.size(), - &host, info, &count)); - EXPECT_EQ(nullptr, host); - pkt.questions_.clear(); - pkt.add_question(new DNSQuestion("example.com", ns_t_a)); - - // Wrong sort of answer. - pkt.answers_.clear(); - pkt.add_answer(new DNSMxRR("example.com", 100, 100, "mx1.example.com")); - data = pkt.data(); - EXPECT_EQ(ARES_ENODATA, ares_parse_a_reply(data.data(), data.size(), - &host, info, &count)); - EXPECT_EQ(nullptr, host); - pkt.answers_.clear(); - pkt.add_answer(new DNSARR("example.com", 100, {0x02, 0x03, 0x04, 0x05})); - - // No answer. - pkt.answers_.clear(); - data = pkt.data(); - EXPECT_EQ(ARES_ENODATA, ares_parse_a_reply(data.data(), data.size(), - &host, info, &count)); - EXPECT_EQ(nullptr, host); - pkt.add_answer(new DNSARR("example.com", 100, {0x02, 0x03, 0x04, 0x05})); - - // Truncated packets. - data = pkt.data(); - for (size_t len = 1; len < data.size(); len++) { - EXPECT_EQ(ARES_EBADRESP, ares_parse_a_reply(data.data(), len, - &host, info, &count)); - EXPECT_EQ(nullptr, host); - EXPECT_EQ(ARES_EBADRESP, ares_parse_a_reply(data.data(), len, - nullptr, info, &count)); - } -} - -TEST_F(LibraryTest, ParseAReplyAllocFail) { - DNSPacket pkt; - pkt.set_qid(0x1234).set_response().set_aa() - .add_question(new DNSQuestion("example.com", ns_t_a)) - .add_answer(new DNSCnameRR("example.com", 300, "c.example.com")) - .add_answer(new DNSARR("c.example.com", 500, {0x02, 0x03, 0x04, 0x05})); - std::vector<byte> data = pkt.data(); - - struct hostent *host = nullptr; - struct ares_addrttl info[2]; - int count = 2; - - for (int ii = 1; ii <= 8; ii++) { - ClearFails(); - SetAllocFail(ii); - EXPECT_EQ(ARES_ENOMEM, ares_parse_a_reply(data.data(), data.size(), - &host, info, &count)) << ii; - EXPECT_EQ(nullptr, host); - } -} - -} // namespace test -} // namespace ares +} + +TEST_F(LibraryTest, ParseAReplyVariantA) { + DNSPacket pkt; + pkt.set_qid(6366).set_rd().set_ra() + .add_question(new DNSQuestion("mit.edu", ns_t_a)) + .add_answer(new DNSARR("mit.edu", 52, {18,7,22,69})) + .add_auth(new DNSNsRR("mit.edu", 292, "W20NS.mit.edu")) + .add_auth(new DNSNsRR("mit.edu", 292, "BITSY.mit.edu")) + .add_auth(new DNSNsRR("mit.edu", 292, "STRAWB.mit.edu")) + .add_additional(new DNSARR("STRAWB.mit.edu", 292, {18,71,0,151})); + struct hostent *host = nullptr; + struct ares_addrttl info[2]; + int count = 2; + std::vector<byte> data = pkt.data(); + EXPECT_EQ(ARES_SUCCESS, ares_parse_a_reply(data.data(), data.size(), + &host, info, &count)); + EXPECT_EQ(1, count); + EXPECT_EQ("18.7.22.69", AddressToString(&(info[0].ipaddr), 4)); + EXPECT_EQ(52, info[0].ttl); + ares_free_hostent(host); +} + +TEST_F(LibraryTest, ParseAReplyJustCname) { + DNSPacket pkt; + pkt.set_qid(6366).set_rd().set_ra() + .add_question(new DNSQuestion("mit.edu", ns_t_a)) + .add_answer(new DNSCnameRR("mit.edu", 52, "other.mit.edu")); + struct hostent *host = nullptr; + struct ares_addrttl info[2]; + int count = 2; + std::vector<byte> data = pkt.data(); + EXPECT_EQ(ARES_SUCCESS, ares_parse_a_reply(data.data(), data.size(), + &host, info, &count)); + EXPECT_EQ(0, count); + ASSERT_NE(nullptr, host); + std::stringstream ss; + ss << HostEnt(host); + EXPECT_EQ("{'other.mit.edu' aliases=[mit.edu] addrs=[]}", ss.str()); + ares_free_hostent(host); +} + +TEST_F(LibraryTest, ParseAReplyVariantCname) { + DNSPacket pkt; + pkt.set_qid(6366).set_rd().set_ra() + .add_question(new DNSQuestion("query.example.com", ns_t_a)) + .add_answer(new DNSCnameRR("query.example.com", 200, "redirect.query.example.com")) + .add_answer(new DNSARR("redirect.query.example.com", 300, {129,97,123,22})) + .add_auth(new DNSNsRR("example.com", 218, "aa.ns1.example.com")) + .add_auth(new DNSNsRR("example.com", 218, "ns2.example.com")) + .add_auth(new DNSNsRR("example.com", 218, "ns3.example.com")) + .add_auth(new DNSNsRR("example.com", 218, "ns4.example.com")) + .add_additional(new DNSARR("aa.ns1.example.com", 218, {129,97,1,1})) + .add_additional(new DNSARR("ns2.example.com", 218, {129,97,1,2})) + .add_additional(new DNSARR("ns3.example.com", 218, {129,97,1,3})) + .add_additional(new DNSARR("ns4.example.com", 218, {129,97,1,4})); + struct hostent *host = nullptr; + struct ares_addrttl info[2]; + int count = 2; + std::vector<byte> data = pkt.data(); + EXPECT_EQ(ARES_SUCCESS, ares_parse_a_reply(data.data(), data.size(), + &host, info, &count)); + EXPECT_EQ(1, count); + EXPECT_EQ("129.97.123.22", AddressToString(&(info[0].ipaddr), 4)); + // TTL is reduced to match CNAME's. + EXPECT_EQ(200, info[0].ttl); + ares_free_hostent(host); + + // Repeat parsing without places to put the results. + count = 0; + EXPECT_EQ(ARES_SUCCESS, ares_parse_a_reply(data.data(), data.size(), + nullptr, info, &count)); +} + +TEST_F(LibraryTest, ParseAReplyVariantCnameChain) { + DNSPacket pkt; + pkt.set_qid(6366).set_rd().set_ra() + .add_question(new DNSQuestion("c1.localhost", ns_t_a)) + .add_answer(new DNSCnameRR("c1.localhost", 604800, "c2.localhost")) + .add_answer(new DNSCnameRR("c2.localhost", 604800, "c3.localhost")) + .add_answer(new DNSCnameRR("c3.localhost", 604800, "c4.localhost")) + .add_answer(new DNSARR("c4.localhost", 604800, {8,8,8,8})) + .add_auth(new DNSNsRR("localhost", 604800, "localhost")) + .add_additional(new DNSARR("localhost", 604800, {127,0,0,1})) + .add_additional(new DNSAaaaRR("localhost", 604800, + {0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01})); + struct hostent *host = nullptr; + struct ares_addrttl info[2]; + int count = 2; + std::vector<byte> data = pkt.data(); + EXPECT_EQ(ARES_SUCCESS, ares_parse_a_reply(data.data(), data.size(), + &host, info, &count)); + EXPECT_EQ(1, count); + EXPECT_EQ("8.8.8.8", AddressToString(&(info[0].ipaddr), 4)); + EXPECT_EQ(604800, info[0].ttl); + ares_free_hostent(host); +} + +TEST_F(LibraryTest, DISABLED_ParseAReplyVariantCnameLast) { + DNSPacket pkt; + pkt.set_qid(6366).set_rd().set_ra() + .add_question(new DNSQuestion("query.example.com", ns_t_a)) + .add_answer(new DNSARR("redirect.query.example.com", 300, {129,97,123,221})) + .add_answer(new DNSARR("redirect.query.example.com", 300, {129,97,123,222})) + .add_answer(new DNSARR("redirect.query.example.com", 300, {129,97,123,223})) + .add_answer(new DNSARR("redirect.query.example.com", 300, {129,97,123,224})) + .add_answer(new DNSCnameRR("query.example.com", 60, "redirect.query.example.com")) + .add_additional(new DNSTxtRR("query.example.com", 60, {"text record"})); + struct hostent *host = nullptr; + struct ares_addrttl info[8]; + int count = 8; + std::vector<byte> data = pkt.data(); + EXPECT_EQ(ARES_SUCCESS, ares_parse_a_reply(data.data(), data.size(), + &host, info, &count)); + EXPECT_EQ(4, count); + EXPECT_EQ("129.97.123.221", AddressToString(&(info[0].ipaddr), 4)); + EXPECT_EQ("129.97.123.222", AddressToString(&(info[1].ipaddr), 4)); + EXPECT_EQ("129.97.123.223", AddressToString(&(info[2].ipaddr), 4)); + EXPECT_EQ("129.97.123.224", AddressToString(&(info[3].ipaddr), 4)); + EXPECT_EQ(300, info[0].ttl); + EXPECT_EQ(300, info[1].ttl); + EXPECT_EQ(300, info[2].ttl); + EXPECT_EQ(300, info[3].ttl); + ares_free_hostent(host); +} + +TEST_F(LibraryTest, ParseAReplyErrors) { + DNSPacket pkt; + pkt.set_qid(0x1234).set_response().set_aa() + .add_question(new DNSQuestion("example.com", ns_t_a)) + .add_answer(new DNSARR("example.com", 100, {0x02, 0x03, 0x04, 0x05})); + std::vector<byte> data; + + struct hostent *host = nullptr; + struct ares_addrttl info[2]; + int count = 2; + + // No question. + pkt.questions_.clear(); + data = pkt.data(); + EXPECT_EQ(ARES_EBADRESP, ares_parse_a_reply(data.data(), data.size(), + &host, info, &count)); + EXPECT_EQ(nullptr, host); + pkt.add_question(new DNSQuestion("example.com", ns_t_a)); + + // Question != answer + pkt.questions_.clear(); + pkt.add_question(new DNSQuestion("Axample.com", ns_t_a)); + data = pkt.data(); + EXPECT_EQ(ARES_ENODATA, ares_parse_a_reply(data.data(), data.size(), + &host, info, &count)); + EXPECT_EQ(nullptr, host); + pkt.questions_.clear(); + pkt.add_question(new DNSQuestion("example.com", ns_t_a)); + +#ifdef DISABLED + // Not a response. + pkt.set_response(false); + data = pkt.data(); + EXPECT_EQ(ARES_EBADRESP, ares_parse_a_reply(data.data(), data.size(), + &host, info, &count)); + EXPECT_EQ(nullptr, host); + pkt.set_response(true); + + // Bad return code. + pkt.set_rcode(ns_r_formerr); + data = pkt.data(); + EXPECT_EQ(ARES_ENODATA, ares_parse_a_reply(data.data(), data.size(), + &host, info, &count)); + EXPECT_EQ(nullptr, host); + pkt.set_rcode(ns_r_noerror); +#endif + + // Two questions + pkt.add_question(new DNSQuestion("example.com", ns_t_a)); + data = pkt.data(); + EXPECT_EQ(ARES_EBADRESP, ares_parse_a_reply(data.data(), data.size(), + &host, info, &count)); + EXPECT_EQ(nullptr, host); + pkt.questions_.clear(); + pkt.add_question(new DNSQuestion("example.com", ns_t_a)); + + // Wrong sort of answer. + pkt.answers_.clear(); + pkt.add_answer(new DNSMxRR("example.com", 100, 100, "mx1.example.com")); + data = pkt.data(); + EXPECT_EQ(ARES_ENODATA, ares_parse_a_reply(data.data(), data.size(), + &host, info, &count)); + EXPECT_EQ(nullptr, host); + pkt.answers_.clear(); + pkt.add_answer(new DNSARR("example.com", 100, {0x02, 0x03, 0x04, 0x05})); + + // No answer. + pkt.answers_.clear(); + data = pkt.data(); + EXPECT_EQ(ARES_ENODATA, ares_parse_a_reply(data.data(), data.size(), + &host, info, &count)); + EXPECT_EQ(nullptr, host); + pkt.add_answer(new DNSARR("example.com", 100, {0x02, 0x03, 0x04, 0x05})); + + // Truncated packets. + data = pkt.data(); + for (size_t len = 1; len < data.size(); len++) { + EXPECT_EQ(ARES_EBADRESP, ares_parse_a_reply(data.data(), len, + &host, info, &count)); + EXPECT_EQ(nullptr, host); + EXPECT_EQ(ARES_EBADRESP, ares_parse_a_reply(data.data(), len, + nullptr, info, &count)); + } +} + +TEST_F(LibraryTest, ParseAReplyAllocFail) { + DNSPacket pkt; + pkt.set_qid(0x1234).set_response().set_aa() + .add_question(new DNSQuestion("example.com", ns_t_a)) + .add_answer(new DNSCnameRR("example.com", 300, "c.example.com")) + .add_answer(new DNSARR("c.example.com", 500, {0x02, 0x03, 0x04, 0x05})); + std::vector<byte> data = pkt.data(); + + struct hostent *host = nullptr; + struct ares_addrttl info[2]; + int count = 2; + + for (int ii = 1; ii <= 8; ii++) { + ClearFails(); + SetAllocFail(ii); + EXPECT_EQ(ARES_ENOMEM, ares_parse_a_reply(data.data(), data.size(), + &host, info, &count)) << ii; + EXPECT_EQ(nullptr, host); + } +} + +} // namespace test +} // namespace ares diff --git a/contrib/libs/c-ares/test/ares-test-parse-aaaa.cc b/contrib/libs/c-ares/test/ares-test-parse-aaaa.cc index 9a12378387..1314c837a6 100644 --- a/contrib/libs/c-ares/test/ares-test-parse-aaaa.cc +++ b/contrib/libs/c-ares/test/ares-test-parse-aaaa.cc @@ -1,192 +1,192 @@ -#include "ares-test.h" -#include "dns-proto.h" - -#include <sstream> -#include <vector> - -namespace ares { -namespace test { - -TEST_F(LibraryTest, ParseAaaaReplyOK) { - DNSPacket pkt; - pkt.set_qid(0x1234).set_response().set_aa() - .add_question(new DNSQuestion("example.com", ns_t_aaaa)) - .add_answer(new DNSAaaaRR("example.com", 100, - {0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, +#include "ares-test.h" +#include "dns-proto.h" + +#include <sstream> +#include <vector> + +namespace ares { +namespace test { + +TEST_F(LibraryTest, ParseAaaaReplyOK) { + DNSPacket pkt; + pkt.set_qid(0x1234).set_response().set_aa() + .add_question(new DNSQuestion("example.com", ns_t_aaaa)) + .add_answer(new DNSAaaaRR("example.com", 100, + {0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x04})) .add_answer(new DNSARR("example.com", 0x01020304, {2,3,4,5})); - std::vector<byte> data = pkt.data(); - struct hostent *host = nullptr; - struct ares_addr6ttl info[5]; - int count = 5; - EXPECT_EQ(ARES_SUCCESS, ares_parse_aaaa_reply(data.data(), data.size(), - &host, info, &count)); - EXPECT_EQ(1, count); - EXPECT_EQ(100, info[0].ttl); - EXPECT_EQ(0x01, info[0].ip6addr._S6_un._S6_u8[0]); - EXPECT_EQ(0x02, info[0].ip6addr._S6_un._S6_u8[4]); - ASSERT_NE(nullptr, host); - std::stringstream ss; - ss << HostEnt(host); - EXPECT_EQ("{'example.com' aliases=[] addrs=[0101:0101:0202:0202:0303:0303:0404:0404]}", ss.str()); - ares_free_hostent(host); - - // Repeat without providing places to put the results - count = 0; - EXPECT_EQ(ARES_SUCCESS, ares_parse_aaaa_reply(data.data(), data.size(), - nullptr, info, &count)); -} - -TEST_F(LibraryTest, ParseAaaaReplyCname) { - DNSPacket pkt; - pkt.set_qid(0x1234).set_response().set_aa() - .add_question(new DNSQuestion("example.com", ns_t_aaaa)) - .add_answer(new DNSCnameRR("example.com", 50, "c.example.com")) - .add_answer(new DNSAaaaRR("c.example.com", 100, - {0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, - 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x04})); - std::vector<byte> data = pkt.data(); - struct hostent *host = nullptr; - struct ares_addr6ttl info[5]; - int count = 5; - EXPECT_EQ(ARES_SUCCESS, ares_parse_aaaa_reply(data.data(), data.size(), - &host, info, &count)); - EXPECT_EQ(1, count); - // CNAME TTL overrides AAAA TTL. - EXPECT_EQ(50, info[0].ttl); - EXPECT_EQ(0x01, info[0].ip6addr._S6_un._S6_u8[0]); - EXPECT_EQ(0x02, info[0].ip6addr._S6_un._S6_u8[4]); - ASSERT_NE(nullptr, host); - std::stringstream ss; - ss << HostEnt(host); - EXPECT_EQ("{'c.example.com' aliases=[example.com] addrs=[0101:0101:0202:0202:0303:0303:0404:0404]}", ss.str()); - ares_free_hostent(host); - - // Repeat without providing a hostent - count = 5; - EXPECT_EQ(ARES_SUCCESS, ares_parse_aaaa_reply(data.data(), data.size(), - nullptr, info, &count)); - EXPECT_EQ(1, count); - EXPECT_EQ(50, info[0].ttl); - EXPECT_EQ(0x01, info[0].ip6addr._S6_un._S6_u8[0]); - EXPECT_EQ(0x02, info[0].ip6addr._S6_un._S6_u8[4]); -} - -TEST_F(LibraryTest, ParseAaaaReplyNoData) { - DNSPacket pkt; - pkt.set_qid(0x1234).set_response().set_aa() - .add_question(new DNSQuestion("example.com", ns_t_aaaa)); - std::vector<byte> data = pkt.data(); - struct hostent *host = nullptr; - struct ares_addr6ttl info[2]; - int count = 2; - EXPECT_EQ(ARES_ENODATA, ares_parse_aaaa_reply(data.data(), data.size(), - &host, info, &count)); - EXPECT_EQ(0, count); - EXPECT_EQ(nullptr, host); - - // Again but with a CNAME. - pkt.add_answer(new DNSCnameRR("example.com", 200, "c.example.com")); - EXPECT_EQ(ARES_ENODATA, ares_parse_aaaa_reply(data.data(), data.size(), - &host, info, &count)); - EXPECT_EQ(0, count); - EXPECT_EQ(nullptr, host); -} - -TEST_F(LibraryTest, ParseAaaaReplyErrors) { - DNSPacket pkt; - pkt.set_qid(0x1234).set_response().set_aa() - .add_question(new DNSQuestion("example.com", ns_t_aaaa)) - .add_answer(new DNSAaaaRR("example.com", 100, - {0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, - 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x04})); - std::vector<byte> data; - - struct hostent *host = nullptr; - struct ares_addr6ttl info[2]; - int count = 2; - - // No question. - pkt.questions_.clear(); - data = pkt.data(); - EXPECT_EQ(ARES_EBADRESP, ares_parse_aaaa_reply(data.data(), data.size(), - &host, info, &count)); - EXPECT_EQ(nullptr, host); - pkt.add_question(new DNSQuestion("example.com", ns_t_aaaa)); - - // Question != answer - pkt.questions_.clear(); - pkt.add_question(new DNSQuestion("Axample.com", ns_t_aaaa)); - data = pkt.data(); - EXPECT_EQ(ARES_ENODATA, ares_parse_aaaa_reply(data.data(), data.size(), - &host, info, &count)); - EXPECT_EQ(nullptr, host); - pkt.questions_.clear(); - pkt.add_question(new DNSQuestion("example.com", ns_t_aaaa)); - - // Two questions. - pkt.add_question(new DNSQuestion("example.com", ns_t_aaaa)); - data = pkt.data(); - EXPECT_EQ(ARES_EBADRESP, ares_parse_aaaa_reply(data.data(), data.size(), - &host, info, &count)); - EXPECT_EQ(nullptr, host); - pkt.questions_.clear(); - pkt.add_question(new DNSQuestion("example.com", ns_t_aaaa)); - - // Wrong sort of answer. - pkt.answers_.clear(); - pkt.add_answer(new DNSMxRR("example.com", 100, 100, "mx1.example.com")); - data = pkt.data(); - EXPECT_EQ(ARES_ENODATA, ares_parse_aaaa_reply(data.data(), data.size(), - &host, info, &count)); - EXPECT_EQ(nullptr, host); - pkt.answers_.clear(); - pkt.add_answer(new DNSAaaaRR("example.com", 100, - {0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, - 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x04})); - - // No answer. - pkt.answers_.clear(); - data = pkt.data(); - EXPECT_EQ(ARES_ENODATA, ares_parse_aaaa_reply(data.data(), data.size(), - &host, info, &count)); - EXPECT_EQ(nullptr, host); - pkt.add_answer(new DNSAaaaRR("example.com", 100, - {0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, - 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x04})); - - // Truncated packets. - data = pkt.data(); - for (size_t len = 1; len < data.size(); len++) { - EXPECT_EQ(ARES_EBADRESP, ares_parse_aaaa_reply(data.data(), len, - &host, info, &count)); - EXPECT_EQ(nullptr, host); - EXPECT_EQ(ARES_EBADRESP, ares_parse_aaaa_reply(data.data(), len, - nullptr, info, &count)); - } -} - -TEST_F(LibraryTest, ParseAaaaReplyAllocFail) { - DNSPacket pkt; - pkt.set_qid(0x1234).set_response().set_aa() - .add_question(new DNSQuestion("example.com", ns_t_aaaa)) - .add_answer(new DNSCnameRR("example.com", 300, "c.example.com")) - .add_answer(new DNSAaaaRR("c.example.com", 100, - {0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, - 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x04})); - std::vector<byte> data = pkt.data(); - struct hostent *host = nullptr; - struct ares_addr6ttl info[2]; - int count = 2; - - for (int ii = 1; ii <= 8; ii++) { - ClearFails(); - SetAllocFail(ii); - EXPECT_EQ(ARES_ENOMEM, ares_parse_aaaa_reply(data.data(), data.size(), - &host, info, &count)) << ii; - EXPECT_EQ(nullptr, host); - } -} - -} // namespace test -} // namespace ares + std::vector<byte> data = pkt.data(); + struct hostent *host = nullptr; + struct ares_addr6ttl info[5]; + int count = 5; + EXPECT_EQ(ARES_SUCCESS, ares_parse_aaaa_reply(data.data(), data.size(), + &host, info, &count)); + EXPECT_EQ(1, count); + EXPECT_EQ(100, info[0].ttl); + EXPECT_EQ(0x01, info[0].ip6addr._S6_un._S6_u8[0]); + EXPECT_EQ(0x02, info[0].ip6addr._S6_un._S6_u8[4]); + ASSERT_NE(nullptr, host); + std::stringstream ss; + ss << HostEnt(host); + EXPECT_EQ("{'example.com' aliases=[] addrs=[0101:0101:0202:0202:0303:0303:0404:0404]}", ss.str()); + ares_free_hostent(host); + + // Repeat without providing places to put the results + count = 0; + EXPECT_EQ(ARES_SUCCESS, ares_parse_aaaa_reply(data.data(), data.size(), + nullptr, info, &count)); +} + +TEST_F(LibraryTest, ParseAaaaReplyCname) { + DNSPacket pkt; + pkt.set_qid(0x1234).set_response().set_aa() + .add_question(new DNSQuestion("example.com", ns_t_aaaa)) + .add_answer(new DNSCnameRR("example.com", 50, "c.example.com")) + .add_answer(new DNSAaaaRR("c.example.com", 100, + {0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, + 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x04})); + std::vector<byte> data = pkt.data(); + struct hostent *host = nullptr; + struct ares_addr6ttl info[5]; + int count = 5; + EXPECT_EQ(ARES_SUCCESS, ares_parse_aaaa_reply(data.data(), data.size(), + &host, info, &count)); + EXPECT_EQ(1, count); + // CNAME TTL overrides AAAA TTL. + EXPECT_EQ(50, info[0].ttl); + EXPECT_EQ(0x01, info[0].ip6addr._S6_un._S6_u8[0]); + EXPECT_EQ(0x02, info[0].ip6addr._S6_un._S6_u8[4]); + ASSERT_NE(nullptr, host); + std::stringstream ss; + ss << HostEnt(host); + EXPECT_EQ("{'c.example.com' aliases=[example.com] addrs=[0101:0101:0202:0202:0303:0303:0404:0404]}", ss.str()); + ares_free_hostent(host); + + // Repeat without providing a hostent + count = 5; + EXPECT_EQ(ARES_SUCCESS, ares_parse_aaaa_reply(data.data(), data.size(), + nullptr, info, &count)); + EXPECT_EQ(1, count); + EXPECT_EQ(50, info[0].ttl); + EXPECT_EQ(0x01, info[0].ip6addr._S6_un._S6_u8[0]); + EXPECT_EQ(0x02, info[0].ip6addr._S6_un._S6_u8[4]); +} + +TEST_F(LibraryTest, ParseAaaaReplyNoData) { + DNSPacket pkt; + pkt.set_qid(0x1234).set_response().set_aa() + .add_question(new DNSQuestion("example.com", ns_t_aaaa)); + std::vector<byte> data = pkt.data(); + struct hostent *host = nullptr; + struct ares_addr6ttl info[2]; + int count = 2; + EXPECT_EQ(ARES_ENODATA, ares_parse_aaaa_reply(data.data(), data.size(), + &host, info, &count)); + EXPECT_EQ(0, count); + EXPECT_EQ(nullptr, host); + + // Again but with a CNAME. + pkt.add_answer(new DNSCnameRR("example.com", 200, "c.example.com")); + EXPECT_EQ(ARES_ENODATA, ares_parse_aaaa_reply(data.data(), data.size(), + &host, info, &count)); + EXPECT_EQ(0, count); + EXPECT_EQ(nullptr, host); +} + +TEST_F(LibraryTest, ParseAaaaReplyErrors) { + DNSPacket pkt; + pkt.set_qid(0x1234).set_response().set_aa() + .add_question(new DNSQuestion("example.com", ns_t_aaaa)) + .add_answer(new DNSAaaaRR("example.com", 100, + {0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, + 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x04})); + std::vector<byte> data; + + struct hostent *host = nullptr; + struct ares_addr6ttl info[2]; + int count = 2; + + // No question. + pkt.questions_.clear(); + data = pkt.data(); + EXPECT_EQ(ARES_EBADRESP, ares_parse_aaaa_reply(data.data(), data.size(), + &host, info, &count)); + EXPECT_EQ(nullptr, host); + pkt.add_question(new DNSQuestion("example.com", ns_t_aaaa)); + + // Question != answer + pkt.questions_.clear(); + pkt.add_question(new DNSQuestion("Axample.com", ns_t_aaaa)); + data = pkt.data(); + EXPECT_EQ(ARES_ENODATA, ares_parse_aaaa_reply(data.data(), data.size(), + &host, info, &count)); + EXPECT_EQ(nullptr, host); + pkt.questions_.clear(); + pkt.add_question(new DNSQuestion("example.com", ns_t_aaaa)); + + // Two questions. + pkt.add_question(new DNSQuestion("example.com", ns_t_aaaa)); + data = pkt.data(); + EXPECT_EQ(ARES_EBADRESP, ares_parse_aaaa_reply(data.data(), data.size(), + &host, info, &count)); + EXPECT_EQ(nullptr, host); + pkt.questions_.clear(); + pkt.add_question(new DNSQuestion("example.com", ns_t_aaaa)); + + // Wrong sort of answer. + pkt.answers_.clear(); + pkt.add_answer(new DNSMxRR("example.com", 100, 100, "mx1.example.com")); + data = pkt.data(); + EXPECT_EQ(ARES_ENODATA, ares_parse_aaaa_reply(data.data(), data.size(), + &host, info, &count)); + EXPECT_EQ(nullptr, host); + pkt.answers_.clear(); + pkt.add_answer(new DNSAaaaRR("example.com", 100, + {0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, + 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x04})); + + // No answer. + pkt.answers_.clear(); + data = pkt.data(); + EXPECT_EQ(ARES_ENODATA, ares_parse_aaaa_reply(data.data(), data.size(), + &host, info, &count)); + EXPECT_EQ(nullptr, host); + pkt.add_answer(new DNSAaaaRR("example.com", 100, + {0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, + 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x04})); + + // Truncated packets. + data = pkt.data(); + for (size_t len = 1; len < data.size(); len++) { + EXPECT_EQ(ARES_EBADRESP, ares_parse_aaaa_reply(data.data(), len, + &host, info, &count)); + EXPECT_EQ(nullptr, host); + EXPECT_EQ(ARES_EBADRESP, ares_parse_aaaa_reply(data.data(), len, + nullptr, info, &count)); + } +} + +TEST_F(LibraryTest, ParseAaaaReplyAllocFail) { + DNSPacket pkt; + pkt.set_qid(0x1234).set_response().set_aa() + .add_question(new DNSQuestion("example.com", ns_t_aaaa)) + .add_answer(new DNSCnameRR("example.com", 300, "c.example.com")) + .add_answer(new DNSAaaaRR("c.example.com", 100, + {0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, + 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x04})); + std::vector<byte> data = pkt.data(); + struct hostent *host = nullptr; + struct ares_addr6ttl info[2]; + int count = 2; + + for (int ii = 1; ii <= 8; ii++) { + ClearFails(); + SetAllocFail(ii); + EXPECT_EQ(ARES_ENOMEM, ares_parse_aaaa_reply(data.data(), data.size(), + &host, info, &count)) << ii; + EXPECT_EQ(nullptr, host); + } +} + +} // namespace test +} // namespace ares diff --git a/contrib/libs/c-ares/test/ares-test-parse-mx.cc b/contrib/libs/c-ares/test/ares-test-parse-mx.cc index 56ce266f6d..37324a6d4c 100644 --- a/contrib/libs/c-ares/test/ares-test-parse-mx.cc +++ b/contrib/libs/c-ares/test/ares-test-parse-mx.cc @@ -1,141 +1,141 @@ -#include "ares-test.h" -#include "dns-proto.h" - -#include <sstream> -#include <vector> - -namespace ares { -namespace test { - -TEST_F(LibraryTest, ParseMxReplyOK) { - DNSPacket pkt; - pkt.set_qid(0x1234).set_response().set_aa() - .add_question(new DNSQuestion("example.com", ns_t_mx)) - .add_answer(new DNSMxRR("example.com", 100, 100, "mx1.example.com")) - .add_answer(new DNSMxRR("example.com", 100, 200, "mx2.example.com")); - std::vector<byte> data = pkt.data(); - - struct ares_mx_reply* mx = nullptr; - EXPECT_EQ(ARES_SUCCESS, ares_parse_mx_reply(data.data(), data.size(), &mx)); - ASSERT_NE(nullptr, mx); - EXPECT_EQ("mx1.example.com", std::string(mx->host)); - EXPECT_EQ(100, mx->priority); - - struct ares_mx_reply* mx2 = mx->next; - ASSERT_NE(nullptr, mx2); - EXPECT_EQ("mx2.example.com", std::string(mx2->host)); - EXPECT_EQ(200, mx2->priority); - EXPECT_EQ(nullptr, mx2->next); - - ares_free_data(mx); -} - -TEST_F(LibraryTest, ParseMxReplyMalformed) { - std::vector<byte> data = { - 0x12, 0x34, // qid - 0x84, // response + query + AA + not-TC + not-RD - 0x00, // not-RA + not-Z + not-AD + not-CD + rc=NoError - 0x00, 0x01, // num questions - 0x00, 0x01, // num answer RRs - 0x00, 0x00, // num authority RRs - 0x00, 0x00, // num additional RRs - // Question - 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', - 0x03, 'c', 'o', 'm', - 0x00, - 0x00, 0x0F, // type MX - 0x00, 0x01, // class IN - // Answer 1 - 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', - 0x03, 'c', 'o', 'm', - 0x00, - 0x00, 0x0F, // RR type - 0x00, 0x01, // class IN - 0x01, 0x02, 0x03, 0x04, // TTL - 0x00, 0x01, // rdata length -- too short - 0x02, - }; - - struct ares_mx_reply* mx = nullptr; - EXPECT_EQ(ARES_EBADRESP, ares_parse_mx_reply(data.data(), data.size(), &mx)); - ASSERT_EQ(nullptr, mx); -} - - -TEST_F(LibraryTest, ParseMxReplyErrors) { - DNSPacket pkt; - pkt.set_qid(0x1234).set_response().set_aa() - .add_question(new DNSQuestion("example.com", ns_t_mx)) - .add_answer(new DNSMxRR("example.com", 100, 100, "mx1.example.com")); - std::vector<byte> data; - struct ares_mx_reply* mx = nullptr; - - // No question. - pkt.questions_.clear(); - data = pkt.data(); - EXPECT_EQ(ARES_EBADRESP, ares_parse_mx_reply(data.data(), data.size(), &mx)); - EXPECT_EQ(nullptr, mx); - pkt.add_question(new DNSQuestion("example.com", ns_t_mx)); - -#ifdef DISABLED - // Question != answer - pkt.questions_.clear(); - pkt.add_question(new DNSQuestion("Axample.com", ns_t_mx)); - data = pkt.data(); - EXPECT_EQ(ARES_EBADRESP, ares_parse_mx_reply(data.data(), data.size(), &mx)); - pkt.questions_.clear(); - pkt.add_question(new DNSQuestion("example.com", ns_t_mx)); -#endif - - // Two questions. - pkt.add_question(new DNSQuestion("example.com", ns_t_mx)); - data = pkt.data(); - EXPECT_EQ(ARES_EBADRESP, ares_parse_mx_reply(data.data(), data.size(), &mx)); - EXPECT_EQ(nullptr, mx); - pkt.questions_.clear(); - pkt.add_question(new DNSQuestion("example.com", ns_t_mx)); - - // Wrong sort of answer. - // TODO(drysdale): check if this should be ARES_ENODATA? - pkt.answers_.clear(); - pkt.add_answer(new DNSSrvRR("example.abc.def.com", 180, 0, 10, 8160, "example.abc.def.com")); - data = pkt.data(); - EXPECT_EQ(ARES_SUCCESS, ares_parse_mx_reply(data.data(), data.size(), &mx)); - EXPECT_EQ(nullptr, mx); - pkt.answers_.clear(); - pkt.add_answer(new DNSMxRR("example.com", 100, 100, "mx1.example.com")); - - // No answer. - pkt.answers_.clear(); - data = pkt.data(); - EXPECT_EQ(ARES_ENODATA, ares_parse_mx_reply(data.data(), data.size(), &mx)); - EXPECT_EQ(nullptr, mx); - pkt.add_answer(new DNSMxRR("example.com", 100, 100, "mx1.example.com")); - - // Truncated packets. - data = pkt.data(); - for (size_t len = 1; len < data.size(); len++) { - int rc = ares_parse_mx_reply(data.data(), len, &mx); - EXPECT_EQ(nullptr, mx); - EXPECT_TRUE(rc == ARES_EBADRESP || rc == ARES_EBADNAME); - } -} - -TEST_F(LibraryTest, ParseMxReplyAllocFail) { - DNSPacket pkt; - pkt.set_qid(0x1234).set_response().set_aa() - .add_question(new DNSQuestion("example.com", ns_t_mx)) - .add_answer(new DNSCnameRR("example.com", 300, "c.example.com")) - .add_answer(new DNSMxRR("c.example.com", 100, 100, "mx1.example.com")); - std::vector<byte> data = pkt.data(); - struct ares_mx_reply* mx = nullptr; - - for (int ii = 1; ii <= 5; ii++) { - ClearFails(); - SetAllocFail(ii); - EXPECT_EQ(ARES_ENOMEM, ares_parse_mx_reply(data.data(), data.size(), &mx)) << ii; - } -} - -} // namespace test -} // namespace ares +#include "ares-test.h" +#include "dns-proto.h" + +#include <sstream> +#include <vector> + +namespace ares { +namespace test { + +TEST_F(LibraryTest, ParseMxReplyOK) { + DNSPacket pkt; + pkt.set_qid(0x1234).set_response().set_aa() + .add_question(new DNSQuestion("example.com", ns_t_mx)) + .add_answer(new DNSMxRR("example.com", 100, 100, "mx1.example.com")) + .add_answer(new DNSMxRR("example.com", 100, 200, "mx2.example.com")); + std::vector<byte> data = pkt.data(); + + struct ares_mx_reply* mx = nullptr; + EXPECT_EQ(ARES_SUCCESS, ares_parse_mx_reply(data.data(), data.size(), &mx)); + ASSERT_NE(nullptr, mx); + EXPECT_EQ("mx1.example.com", std::string(mx->host)); + EXPECT_EQ(100, mx->priority); + + struct ares_mx_reply* mx2 = mx->next; + ASSERT_NE(nullptr, mx2); + EXPECT_EQ("mx2.example.com", std::string(mx2->host)); + EXPECT_EQ(200, mx2->priority); + EXPECT_EQ(nullptr, mx2->next); + + ares_free_data(mx); +} + +TEST_F(LibraryTest, ParseMxReplyMalformed) { + std::vector<byte> data = { + 0x12, 0x34, // qid + 0x84, // response + query + AA + not-TC + not-RD + 0x00, // not-RA + not-Z + not-AD + not-CD + rc=NoError + 0x00, 0x01, // num questions + 0x00, 0x01, // num answer RRs + 0x00, 0x00, // num authority RRs + 0x00, 0x00, // num additional RRs + // Question + 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + 0x00, 0x0F, // type MX + 0x00, 0x01, // class IN + // Answer 1 + 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + 0x00, 0x0F, // RR type + 0x00, 0x01, // class IN + 0x01, 0x02, 0x03, 0x04, // TTL + 0x00, 0x01, // rdata length -- too short + 0x02, + }; + + struct ares_mx_reply* mx = nullptr; + EXPECT_EQ(ARES_EBADRESP, ares_parse_mx_reply(data.data(), data.size(), &mx)); + ASSERT_EQ(nullptr, mx); +} + + +TEST_F(LibraryTest, ParseMxReplyErrors) { + DNSPacket pkt; + pkt.set_qid(0x1234).set_response().set_aa() + .add_question(new DNSQuestion("example.com", ns_t_mx)) + .add_answer(new DNSMxRR("example.com", 100, 100, "mx1.example.com")); + std::vector<byte> data; + struct ares_mx_reply* mx = nullptr; + + // No question. + pkt.questions_.clear(); + data = pkt.data(); + EXPECT_EQ(ARES_EBADRESP, ares_parse_mx_reply(data.data(), data.size(), &mx)); + EXPECT_EQ(nullptr, mx); + pkt.add_question(new DNSQuestion("example.com", ns_t_mx)); + +#ifdef DISABLED + // Question != answer + pkt.questions_.clear(); + pkt.add_question(new DNSQuestion("Axample.com", ns_t_mx)); + data = pkt.data(); + EXPECT_EQ(ARES_EBADRESP, ares_parse_mx_reply(data.data(), data.size(), &mx)); + pkt.questions_.clear(); + pkt.add_question(new DNSQuestion("example.com", ns_t_mx)); +#endif + + // Two questions. + pkt.add_question(new DNSQuestion("example.com", ns_t_mx)); + data = pkt.data(); + EXPECT_EQ(ARES_EBADRESP, ares_parse_mx_reply(data.data(), data.size(), &mx)); + EXPECT_EQ(nullptr, mx); + pkt.questions_.clear(); + pkt.add_question(new DNSQuestion("example.com", ns_t_mx)); + + // Wrong sort of answer. + // TODO(drysdale): check if this should be ARES_ENODATA? + pkt.answers_.clear(); + pkt.add_answer(new DNSSrvRR("example.abc.def.com", 180, 0, 10, 8160, "example.abc.def.com")); + data = pkt.data(); + EXPECT_EQ(ARES_SUCCESS, ares_parse_mx_reply(data.data(), data.size(), &mx)); + EXPECT_EQ(nullptr, mx); + pkt.answers_.clear(); + pkt.add_answer(new DNSMxRR("example.com", 100, 100, "mx1.example.com")); + + // No answer. + pkt.answers_.clear(); + data = pkt.data(); + EXPECT_EQ(ARES_ENODATA, ares_parse_mx_reply(data.data(), data.size(), &mx)); + EXPECT_EQ(nullptr, mx); + pkt.add_answer(new DNSMxRR("example.com", 100, 100, "mx1.example.com")); + + // Truncated packets. + data = pkt.data(); + for (size_t len = 1; len < data.size(); len++) { + int rc = ares_parse_mx_reply(data.data(), len, &mx); + EXPECT_EQ(nullptr, mx); + EXPECT_TRUE(rc == ARES_EBADRESP || rc == ARES_EBADNAME); + } +} + +TEST_F(LibraryTest, ParseMxReplyAllocFail) { + DNSPacket pkt; + pkt.set_qid(0x1234).set_response().set_aa() + .add_question(new DNSQuestion("example.com", ns_t_mx)) + .add_answer(new DNSCnameRR("example.com", 300, "c.example.com")) + .add_answer(new DNSMxRR("c.example.com", 100, 100, "mx1.example.com")); + std::vector<byte> data = pkt.data(); + struct ares_mx_reply* mx = nullptr; + + for (int ii = 1; ii <= 5; ii++) { + ClearFails(); + SetAllocFail(ii); + EXPECT_EQ(ARES_ENOMEM, ares_parse_mx_reply(data.data(), data.size(), &mx)) << ii; + } +} + +} // namespace test +} // namespace ares diff --git a/contrib/libs/c-ares/test/ares-test-parse-naptr.cc b/contrib/libs/c-ares/test/ares-test-parse-naptr.cc index 109c2a2604..3238a1923d 100644 --- a/contrib/libs/c-ares/test/ares-test-parse-naptr.cc +++ b/contrib/libs/c-ares/test/ares-test-parse-naptr.cc @@ -1,148 +1,148 @@ -#include "ares-test.h" -#include "dns-proto.h" - -#include <sstream> -#include <vector> - -namespace ares { -namespace test { - -TEST_F(LibraryTest, ParseNaptrReplyOK) { - DNSPacket pkt; - pkt.set_qid(0x1234).set_response().set_aa() - .add_question(new DNSQuestion("example.com", ns_t_naptr)) - .add_answer(new DNSNaptrRR("example.com", 100, - 10, 20, "SP", "service", "regexp", "replace")) - .add_answer(new DNSNaptrRR("example.com", 0x0010, - 11, 21, "SP", "service2", "regexp2", "replace2")); - std::vector<byte> data = pkt.data(); - - struct ares_naptr_reply* naptr = nullptr; - EXPECT_EQ(ARES_SUCCESS, ares_parse_naptr_reply(data.data(), data.size(), &naptr)); - ASSERT_NE(nullptr, naptr); - EXPECT_EQ("SP", std::string((char*)naptr->flags)); - EXPECT_EQ("service", std::string((char*)naptr->service)); - EXPECT_EQ("regexp", std::string((char*)naptr->regexp)); - EXPECT_EQ("replace", std::string((char*)naptr->replacement)); - EXPECT_EQ(10, naptr->order); - EXPECT_EQ(20, naptr->preference); - - struct ares_naptr_reply* naptr2 = naptr->next; - ASSERT_NE(nullptr, naptr2); - EXPECT_EQ("SP", std::string((char*)naptr2->flags)); - EXPECT_EQ("service2", std::string((char*)naptr2->service)); - EXPECT_EQ("regexp2", std::string((char*)naptr2->regexp)); - EXPECT_EQ("replace2", std::string((char*)naptr2->replacement)); - EXPECT_EQ(11, naptr2->order); - EXPECT_EQ(21, naptr2->preference); - EXPECT_EQ(nullptr, naptr2->next); - - ares_free_data(naptr); -} - -TEST_F(LibraryTest, ParseNaptrReplyErrors) { - DNSPacket pkt; - pkt.set_qid(0x1234).set_response().set_aa() - .add_question(new DNSQuestion("example.com", ns_t_naptr)) - .add_answer(new DNSNaptrRR("example.com", 100, - 10, 20, "SP", "service", "regexp", "replace")); - std::vector<byte> data; - struct ares_naptr_reply* naptr = nullptr; - - // No question. - pkt.questions_.clear(); - data = pkt.data(); - EXPECT_EQ(ARES_EBADRESP, ares_parse_naptr_reply(data.data(), data.size(), &naptr)); - pkt.add_question(new DNSQuestion("example.com", ns_t_naptr)); - -#ifdef DISABLED - // Question != answer - pkt.questions_.clear(); - pkt.add_question(new DNSQuestion("Axample.com", ns_t_naptr)); - data = pkt.data(); - EXPECT_EQ(ARES_ENODATA, ares_parse_naptr_reply(data.data(), data.size(), &naptr)); - pkt.questions_.clear(); - pkt.add_question(new DNSQuestion("example.com", ns_t_naptr)); -#endif - - // Two questions - pkt.add_question(new DNSQuestion("example.com", ns_t_naptr)); - data = pkt.data(); - EXPECT_EQ(ARES_EBADRESP, ares_parse_naptr_reply(data.data(), data.size(), &naptr)); - pkt.questions_.clear(); - pkt.add_question(new DNSQuestion("example.com", ns_t_naptr)); - - // Wrong sort of answer. - pkt.answers_.clear(); - pkt.add_answer(new DNSMxRR("example.com", 100, 100, "mx1.example.com")); - data = pkt.data(); - EXPECT_EQ(ARES_SUCCESS, ares_parse_naptr_reply(data.data(), data.size(), &naptr)); - EXPECT_EQ(nullptr, naptr); - pkt.answers_.clear(); - pkt.add_answer(new DNSNaptrRR("example.com", 100, - 10, 20, "SP", "service", "regexp", "replace")); - - // No answer. - pkt.answers_.clear(); - data = pkt.data(); - EXPECT_EQ(ARES_ENODATA, ares_parse_naptr_reply(data.data(), data.size(), &naptr)); - pkt.add_answer(new DNSNaptrRR("example.com", 100, - 10, 20, "SP", "service", "regexp", "replace")); - - // Truncated packets. - data = pkt.data(); - for (size_t len = 1; len < data.size(); len++) { - int rc = ares_parse_naptr_reply(data.data(), len, &naptr); - EXPECT_TRUE(rc == ARES_EBADRESP || rc == ARES_EBADNAME); - } -} - -TEST_F(LibraryTest, ParseNaptrReplyTooShort) { - std::vector<byte> data = { - 0x12, 0x34, // qid - 0x84, // response + query + AA + not-TC + not-RD - 0x00, // not-RA + not-Z + not-AD + not-CD + rc=NoError - 0x00, 0x01, // num questions - 0x00, 0x01, // num answer RRs - 0x00, 0x00, // num authority RRs - 0x00, 0x00, // num additional RRs - // Question - 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', - 0x03, 'c', 'o', 'm', - 0x00, - 0x00, 0x23, // type NAPTR - 0x00, 0x01, // class IN - // Answer 1 - 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', - 0x03, 'c', 'o', 'm', - 0x00, - 0x00, 0x23, // RR type - 0x00, 0x01, // class IN - 0x01, 0x02, 0x03, 0x04, // TTL - 0x00, 0x01, // rdata length - 0x00, // Too short: expect 2 x int16 and 3 x name (min 1 byte each) - }; - struct ares_naptr_reply* naptr = nullptr; - EXPECT_EQ(ARES_EBADRESP, ares_parse_naptr_reply(data.data(), data.size(), &naptr)); -} - -TEST_F(LibraryTest, ParseNaptrReplyAllocFail) { - DNSPacket pkt; - pkt.set_qid(0x1234).set_response().set_aa() - .add_question(new DNSQuestion("example.com", ns_t_naptr)) - .add_answer(new DNSNaptrRR("example.com", 100, - 10, 20, "SP", "service", "regexp", "replace")) - .add_answer(new DNSNaptrRR("example.com", 0x0010, - 11, 21, "SP", "service2", "regexp2", "replace2")); - std::vector<byte> data = pkt.data(); - struct ares_naptr_reply* naptr = nullptr; - - for (int ii = 1; ii <= 13; ii++) { - ClearFails(); - SetAllocFail(ii); - EXPECT_EQ(ARES_ENOMEM, ares_parse_naptr_reply(data.data(), data.size(), &naptr)); - } -} - -} // namespace test -} // namespace ares +#include "ares-test.h" +#include "dns-proto.h" + +#include <sstream> +#include <vector> + +namespace ares { +namespace test { + +TEST_F(LibraryTest, ParseNaptrReplyOK) { + DNSPacket pkt; + pkt.set_qid(0x1234).set_response().set_aa() + .add_question(new DNSQuestion("example.com", ns_t_naptr)) + .add_answer(new DNSNaptrRR("example.com", 100, + 10, 20, "SP", "service", "regexp", "replace")) + .add_answer(new DNSNaptrRR("example.com", 0x0010, + 11, 21, "SP", "service2", "regexp2", "replace2")); + std::vector<byte> data = pkt.data(); + + struct ares_naptr_reply* naptr = nullptr; + EXPECT_EQ(ARES_SUCCESS, ares_parse_naptr_reply(data.data(), data.size(), &naptr)); + ASSERT_NE(nullptr, naptr); + EXPECT_EQ("SP", std::string((char*)naptr->flags)); + EXPECT_EQ("service", std::string((char*)naptr->service)); + EXPECT_EQ("regexp", std::string((char*)naptr->regexp)); + EXPECT_EQ("replace", std::string((char*)naptr->replacement)); + EXPECT_EQ(10, naptr->order); + EXPECT_EQ(20, naptr->preference); + + struct ares_naptr_reply* naptr2 = naptr->next; + ASSERT_NE(nullptr, naptr2); + EXPECT_EQ("SP", std::string((char*)naptr2->flags)); + EXPECT_EQ("service2", std::string((char*)naptr2->service)); + EXPECT_EQ("regexp2", std::string((char*)naptr2->regexp)); + EXPECT_EQ("replace2", std::string((char*)naptr2->replacement)); + EXPECT_EQ(11, naptr2->order); + EXPECT_EQ(21, naptr2->preference); + EXPECT_EQ(nullptr, naptr2->next); + + ares_free_data(naptr); +} + +TEST_F(LibraryTest, ParseNaptrReplyErrors) { + DNSPacket pkt; + pkt.set_qid(0x1234).set_response().set_aa() + .add_question(new DNSQuestion("example.com", ns_t_naptr)) + .add_answer(new DNSNaptrRR("example.com", 100, + 10, 20, "SP", "service", "regexp", "replace")); + std::vector<byte> data; + struct ares_naptr_reply* naptr = nullptr; + + // No question. + pkt.questions_.clear(); + data = pkt.data(); + EXPECT_EQ(ARES_EBADRESP, ares_parse_naptr_reply(data.data(), data.size(), &naptr)); + pkt.add_question(new DNSQuestion("example.com", ns_t_naptr)); + +#ifdef DISABLED + // Question != answer + pkt.questions_.clear(); + pkt.add_question(new DNSQuestion("Axample.com", ns_t_naptr)); + data = pkt.data(); + EXPECT_EQ(ARES_ENODATA, ares_parse_naptr_reply(data.data(), data.size(), &naptr)); + pkt.questions_.clear(); + pkt.add_question(new DNSQuestion("example.com", ns_t_naptr)); +#endif + + // Two questions + pkt.add_question(new DNSQuestion("example.com", ns_t_naptr)); + data = pkt.data(); + EXPECT_EQ(ARES_EBADRESP, ares_parse_naptr_reply(data.data(), data.size(), &naptr)); + pkt.questions_.clear(); + pkt.add_question(new DNSQuestion("example.com", ns_t_naptr)); + + // Wrong sort of answer. + pkt.answers_.clear(); + pkt.add_answer(new DNSMxRR("example.com", 100, 100, "mx1.example.com")); + data = pkt.data(); + EXPECT_EQ(ARES_SUCCESS, ares_parse_naptr_reply(data.data(), data.size(), &naptr)); + EXPECT_EQ(nullptr, naptr); + pkt.answers_.clear(); + pkt.add_answer(new DNSNaptrRR("example.com", 100, + 10, 20, "SP", "service", "regexp", "replace")); + + // No answer. + pkt.answers_.clear(); + data = pkt.data(); + EXPECT_EQ(ARES_ENODATA, ares_parse_naptr_reply(data.data(), data.size(), &naptr)); + pkt.add_answer(new DNSNaptrRR("example.com", 100, + 10, 20, "SP", "service", "regexp", "replace")); + + // Truncated packets. + data = pkt.data(); + for (size_t len = 1; len < data.size(); len++) { + int rc = ares_parse_naptr_reply(data.data(), len, &naptr); + EXPECT_TRUE(rc == ARES_EBADRESP || rc == ARES_EBADNAME); + } +} + +TEST_F(LibraryTest, ParseNaptrReplyTooShort) { + std::vector<byte> data = { + 0x12, 0x34, // qid + 0x84, // response + query + AA + not-TC + not-RD + 0x00, // not-RA + not-Z + not-AD + not-CD + rc=NoError + 0x00, 0x01, // num questions + 0x00, 0x01, // num answer RRs + 0x00, 0x00, // num authority RRs + 0x00, 0x00, // num additional RRs + // Question + 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + 0x00, 0x23, // type NAPTR + 0x00, 0x01, // class IN + // Answer 1 + 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + 0x00, 0x23, // RR type + 0x00, 0x01, // class IN + 0x01, 0x02, 0x03, 0x04, // TTL + 0x00, 0x01, // rdata length + 0x00, // Too short: expect 2 x int16 and 3 x name (min 1 byte each) + }; + struct ares_naptr_reply* naptr = nullptr; + EXPECT_EQ(ARES_EBADRESP, ares_parse_naptr_reply(data.data(), data.size(), &naptr)); +} + +TEST_F(LibraryTest, ParseNaptrReplyAllocFail) { + DNSPacket pkt; + pkt.set_qid(0x1234).set_response().set_aa() + .add_question(new DNSQuestion("example.com", ns_t_naptr)) + .add_answer(new DNSNaptrRR("example.com", 100, + 10, 20, "SP", "service", "regexp", "replace")) + .add_answer(new DNSNaptrRR("example.com", 0x0010, + 11, 21, "SP", "service2", "regexp2", "replace2")); + std::vector<byte> data = pkt.data(); + struct ares_naptr_reply* naptr = nullptr; + + for (int ii = 1; ii <= 13; ii++) { + ClearFails(); + SetAllocFail(ii); + EXPECT_EQ(ARES_ENOMEM, ares_parse_naptr_reply(data.data(), data.size(), &naptr)); + } +} + +} // namespace test +} // namespace ares diff --git a/contrib/libs/c-ares/test/ares-test-parse-ns.cc b/contrib/libs/c-ares/test/ares-test-parse-ns.cc index 55d031857f..cd65318969 100644 --- a/contrib/libs/c-ares/test/ares-test-parse-ns.cc +++ b/contrib/libs/c-ares/test/ares-test-parse-ns.cc @@ -1,119 +1,119 @@ -#include "ares-test.h" -#include "dns-proto.h" - -#include <sstream> -#include <vector> - -namespace ares { -namespace test { - -TEST_F(LibraryTest, ParseNsReplyOK) { - DNSPacket pkt; - pkt.set_qid(0x1234).set_response().set_aa() - .add_question(new DNSQuestion("example.com", ns_t_ns)) - .add_answer(new DNSNsRR("example.com", 100, "ns.example.com")); - std::vector<byte> data = pkt.data(); - - struct hostent *host = nullptr; - EXPECT_EQ(ARES_SUCCESS, ares_parse_ns_reply(data.data(), data.size(), &host)); - ASSERT_NE(nullptr, host); - std::stringstream ss; - ss << HostEnt(host); - EXPECT_EQ("{'example.com' aliases=[ns.example.com] addrs=[]}", ss.str()); - ares_free_hostent(host); -} - -TEST_F(LibraryTest, ParseNsReplyMultiple) { - DNSPacket pkt; - pkt.set_qid(10501).set_response().set_rd().set_ra() - .add_question(new DNSQuestion("google.com", ns_t_ns)) - .add_answer(new DNSNsRR("google.com", 59, "ns1.google.com")) - .add_answer(new DNSNsRR("google.com", 59, "ns2.google.com")) - .add_answer(new DNSNsRR("google.com", 59, "ns3.google.com")) - .add_answer(new DNSNsRR("google.com", 59, "ns4.google.com")) - .add_additional(new DNSARR("ns4.google.com", 247, {216,239,38,10})) - .add_additional(new DNSARR("ns2.google.com", 247, {216,239,34,10})) - .add_additional(new DNSARR("ns1.google.com", 247, {216,239,32,10})) - .add_additional(new DNSARR("ns3.google.com", 247, {216,239,36,10})); - std::vector<byte> data = pkt.data(); - - struct hostent *host = nullptr; - EXPECT_EQ(ARES_SUCCESS, ares_parse_ns_reply(data.data(), data.size(), &host)); - ASSERT_NE(nullptr, host); - std::stringstream ss; - ss << HostEnt(host); - EXPECT_EQ("{'google.com' aliases=[ns1.google.com, ns2.google.com, ns3.google.com, ns4.google.com] addrs=[]}", ss.str()); - ares_free_hostent(host); -} - -TEST_F(LibraryTest, ParseNsReplyErrors) { - DNSPacket pkt; - pkt.set_qid(0x1234).set_response().set_aa() - .add_question(new DNSQuestion("example.com", ns_t_ns)) - .add_answer(new DNSNsRR("example.com", 100, "ns.example.com")); - std::vector<byte> data; - struct hostent *host = nullptr; - - // No question. - pkt.questions_.clear(); - data = pkt.data(); - EXPECT_EQ(ARES_EBADRESP, ares_parse_ns_reply(data.data(), data.size(), &host)); - pkt.add_question(new DNSQuestion("example.com", ns_t_ns)); - -#ifdef DISABLED - // Question != answer - pkt.questions_.clear(); - pkt.add_question(new DNSQuestion("Axample.com", ns_t_ns)); - data = pkt.data(); - EXPECT_EQ(ARES_ENODATA, ares_parse_ns_reply(data.data(), data.size(), &host)); - pkt.questions_.clear(); - pkt.add_question(new DNSQuestion("example.com", ns_t_ns)); -#endif - - // Two questions. - pkt.add_question(new DNSQuestion("example.com", ns_t_ns)); - data = pkt.data(); - EXPECT_EQ(ARES_EBADRESP, ares_parse_ns_reply(data.data(), data.size(), &host)); - pkt.questions_.clear(); - pkt.add_question(new DNSQuestion("example.com", ns_t_ns)); - - // Wrong sort of answer. - pkt.answers_.clear(); - pkt.add_answer(new DNSMxRR("example.com", 100, 100, "mx1.example.com")); - data = pkt.data(); - EXPECT_EQ(ARES_ENODATA, ares_parse_ns_reply(data.data(), data.size(), &host)); - pkt.answers_.clear(); - pkt.add_answer(new DNSNsRR("example.com", 100, "ns.example.com")); - - // No answer. - pkt.answers_.clear(); - data = pkt.data(); - EXPECT_EQ(ARES_ENODATA, ares_parse_ns_reply(data.data(), data.size(), &host)); - pkt.add_answer(new DNSNsRR("example.com", 100, "ns.example.com")); - - // Truncated packets. - data = pkt.data(); - for (size_t len = 1; len < data.size(); len++) { - EXPECT_EQ(ARES_EBADRESP, ares_parse_ns_reply(data.data(), len, &host)); - } -} - -TEST_F(LibraryTest, ParseNsReplyAllocFail) { - DNSPacket pkt; - pkt.set_qid(0x1234).set_response().set_aa() - .add_question(new DNSQuestion("example.com", ns_t_ns)) - .add_answer(new DNSCnameRR("example.com", 300, "c.example.com")) - .add_answer(new DNSNsRR("c.example.com", 100, "ns.example.com")); - std::vector<byte> data = pkt.data(); - struct hostent *host = nullptr; - - for (int ii = 1; ii <= 8; ii++) { - ClearFails(); - SetAllocFail(ii); - EXPECT_EQ(ARES_ENOMEM, ares_parse_ns_reply(data.data(), data.size(), &host)) << ii; - } -} - - -} // namespace test -} // namespace ares +#include "ares-test.h" +#include "dns-proto.h" + +#include <sstream> +#include <vector> + +namespace ares { +namespace test { + +TEST_F(LibraryTest, ParseNsReplyOK) { + DNSPacket pkt; + pkt.set_qid(0x1234).set_response().set_aa() + .add_question(new DNSQuestion("example.com", ns_t_ns)) + .add_answer(new DNSNsRR("example.com", 100, "ns.example.com")); + std::vector<byte> data = pkt.data(); + + struct hostent *host = nullptr; + EXPECT_EQ(ARES_SUCCESS, ares_parse_ns_reply(data.data(), data.size(), &host)); + ASSERT_NE(nullptr, host); + std::stringstream ss; + ss << HostEnt(host); + EXPECT_EQ("{'example.com' aliases=[ns.example.com] addrs=[]}", ss.str()); + ares_free_hostent(host); +} + +TEST_F(LibraryTest, ParseNsReplyMultiple) { + DNSPacket pkt; + pkt.set_qid(10501).set_response().set_rd().set_ra() + .add_question(new DNSQuestion("google.com", ns_t_ns)) + .add_answer(new DNSNsRR("google.com", 59, "ns1.google.com")) + .add_answer(new DNSNsRR("google.com", 59, "ns2.google.com")) + .add_answer(new DNSNsRR("google.com", 59, "ns3.google.com")) + .add_answer(new DNSNsRR("google.com", 59, "ns4.google.com")) + .add_additional(new DNSARR("ns4.google.com", 247, {216,239,38,10})) + .add_additional(new DNSARR("ns2.google.com", 247, {216,239,34,10})) + .add_additional(new DNSARR("ns1.google.com", 247, {216,239,32,10})) + .add_additional(new DNSARR("ns3.google.com", 247, {216,239,36,10})); + std::vector<byte> data = pkt.data(); + + struct hostent *host = nullptr; + EXPECT_EQ(ARES_SUCCESS, ares_parse_ns_reply(data.data(), data.size(), &host)); + ASSERT_NE(nullptr, host); + std::stringstream ss; + ss << HostEnt(host); + EXPECT_EQ("{'google.com' aliases=[ns1.google.com, ns2.google.com, ns3.google.com, ns4.google.com] addrs=[]}", ss.str()); + ares_free_hostent(host); +} + +TEST_F(LibraryTest, ParseNsReplyErrors) { + DNSPacket pkt; + pkt.set_qid(0x1234).set_response().set_aa() + .add_question(new DNSQuestion("example.com", ns_t_ns)) + .add_answer(new DNSNsRR("example.com", 100, "ns.example.com")); + std::vector<byte> data; + struct hostent *host = nullptr; + + // No question. + pkt.questions_.clear(); + data = pkt.data(); + EXPECT_EQ(ARES_EBADRESP, ares_parse_ns_reply(data.data(), data.size(), &host)); + pkt.add_question(new DNSQuestion("example.com", ns_t_ns)); + +#ifdef DISABLED + // Question != answer + pkt.questions_.clear(); + pkt.add_question(new DNSQuestion("Axample.com", ns_t_ns)); + data = pkt.data(); + EXPECT_EQ(ARES_ENODATA, ares_parse_ns_reply(data.data(), data.size(), &host)); + pkt.questions_.clear(); + pkt.add_question(new DNSQuestion("example.com", ns_t_ns)); +#endif + + // Two questions. + pkt.add_question(new DNSQuestion("example.com", ns_t_ns)); + data = pkt.data(); + EXPECT_EQ(ARES_EBADRESP, ares_parse_ns_reply(data.data(), data.size(), &host)); + pkt.questions_.clear(); + pkt.add_question(new DNSQuestion("example.com", ns_t_ns)); + + // Wrong sort of answer. + pkt.answers_.clear(); + pkt.add_answer(new DNSMxRR("example.com", 100, 100, "mx1.example.com")); + data = pkt.data(); + EXPECT_EQ(ARES_ENODATA, ares_parse_ns_reply(data.data(), data.size(), &host)); + pkt.answers_.clear(); + pkt.add_answer(new DNSNsRR("example.com", 100, "ns.example.com")); + + // No answer. + pkt.answers_.clear(); + data = pkt.data(); + EXPECT_EQ(ARES_ENODATA, ares_parse_ns_reply(data.data(), data.size(), &host)); + pkt.add_answer(new DNSNsRR("example.com", 100, "ns.example.com")); + + // Truncated packets. + data = pkt.data(); + for (size_t len = 1; len < data.size(); len++) { + EXPECT_EQ(ARES_EBADRESP, ares_parse_ns_reply(data.data(), len, &host)); + } +} + +TEST_F(LibraryTest, ParseNsReplyAllocFail) { + DNSPacket pkt; + pkt.set_qid(0x1234).set_response().set_aa() + .add_question(new DNSQuestion("example.com", ns_t_ns)) + .add_answer(new DNSCnameRR("example.com", 300, "c.example.com")) + .add_answer(new DNSNsRR("c.example.com", 100, "ns.example.com")); + std::vector<byte> data = pkt.data(); + struct hostent *host = nullptr; + + for (int ii = 1; ii <= 8; ii++) { + ClearFails(); + SetAllocFail(ii); + EXPECT_EQ(ARES_ENOMEM, ares_parse_ns_reply(data.data(), data.size(), &host)) << ii; + } +} + + +} // namespace test +} // namespace ares diff --git a/contrib/libs/c-ares/test/ares-test-parse-ptr.cc b/contrib/libs/c-ares/test/ares-test-parse-ptr.cc index 7b1a86bac0..75f74c16f7 100644 --- a/contrib/libs/c-ares/test/ares-test-parse-ptr.cc +++ b/contrib/libs/c-ares/test/ares-test-parse-ptr.cc @@ -1,249 +1,249 @@ -#include "ares-test.h" -#include "dns-proto.h" - -#include <sstream> -#include <vector> - -namespace ares { -namespace test { - -TEST_F(LibraryTest, ParsePtrReplyOK) { - byte addrv4[4] = {0x10, 0x20, 0x30, 0x40}; - DNSPacket pkt; - pkt.set_qid(0x1234).set_response().set_aa() - .add_question(new DNSQuestion("64.48.32.16.in-addr.arpa", ns_t_ptr)) - .add_answer(new DNSPtrRR("64.48.32.16.in-addr.arpa", 100, "other.com")); - std::vector<byte> data = pkt.data(); - - struct hostent *host = nullptr; - EXPECT_EQ(ARES_SUCCESS, ares_parse_ptr_reply(data.data(), data.size(), - addrv4, sizeof(addrv4), AF_INET, &host, NULL)); - ASSERT_NE(nullptr, host); - std::stringstream ss; - ss << HostEnt(host); - EXPECT_EQ("{'other.com' aliases=[other.com] addrs=[16.32.48.64]}", ss.str()); - ares_free_hostent(host); -} - -TEST_F(LibraryTest, ParsePtrReplyCname) { - byte addrv4[4] = {0x10, 0x20, 0x30, 0x40}; - DNSPacket pkt; - pkt.set_qid(0x1234).set_response().set_aa() - .add_question(new DNSQuestion("64.48.32.16.in-addr.arpa", ns_t_ptr)) - .add_answer(new DNSCnameRR("64.48.32.16.in-addr.arpa", 50, "64.48.32.8.in-addr.arpa")) - .add_answer(new DNSPtrRR("64.48.32.8.in-addr.arpa", 100, "other.com")); - std::vector<byte> data = pkt.data(); - - struct hostent *host = nullptr; - EXPECT_EQ(ARES_SUCCESS, ares_parse_ptr_reply(data.data(), data.size(), - addrv4, sizeof(addrv4), AF_INET, &host, NULL)); - ASSERT_NE(nullptr, host); - std::stringstream ss; - ss << HostEnt(host); - EXPECT_EQ("{'other.com' aliases=[other.com] addrs=[16.32.48.64]}", ss.str()); - ares_free_hostent(host); -} - - -struct DNSMalformedCnameRR : public DNSCnameRR { - DNSMalformedCnameRR(const std::string& name, int ttl, const std::string& other) - : DNSCnameRR(name, ttl, other) {} - std::vector<byte> data() const { - std::vector<byte> data = DNSRR::data(); - std::vector<byte> encname = EncodeString(other_); - encname[0] = encname[0] + 63; // invalid label length - int len = encname.size(); - PushInt16(&data, len); - data.insert(data.end(), encname.begin(), encname.end()); - return data; - } -}; - -TEST_F(LibraryTest, ParsePtrReplyMalformedCname) { - byte addrv4[4] = {0x10, 0x20, 0x30, 0x40}; - DNSPacket pkt; - pkt.set_qid(0x1234).set_response().set_aa() - .add_question(new DNSQuestion("64.48.32.16.in-addr.arpa", ns_t_ptr)) - .add_answer(new DNSMalformedCnameRR("64.48.32.16.in-addr.arpa", 50, "64.48.32.8.in-addr.arpa")) - .add_answer(new DNSPtrRR("64.48.32.8.in-addr.arpa", 100, "other.com")); - std::vector<byte> data = pkt.data(); - - struct hostent *host = nullptr; - EXPECT_EQ(ARES_EBADRESP, ares_parse_ptr_reply(data.data(), data.size(), - addrv4, sizeof(addrv4), AF_INET, &host, NULL)); - ASSERT_EQ(nullptr, host); -} - -TEST_F(LibraryTest, ParseManyPtrReply) { - byte addrv4[4] = {0x10, 0x20, 0x30, 0x40}; - DNSPacket pkt; - pkt.set_qid(0x1234).set_response().set_aa() - .add_question(new DNSQuestion("64.48.32.16.in-addr.arpa", ns_t_ptr)) - .add_answer(new DNSPtrRR("64.48.32.16.in-addr.arpa", 100, "main.com")) - .add_answer(new DNSPtrRR("64.48.32.16.in-addr.arpa", 100, "other1.com")) - .add_answer(new DNSPtrRR("64.48.32.16.in-addr.arpa", 100, "other2.com")) - .add_answer(new DNSPtrRR("64.48.32.16.in-addr.arpa", 100, "other3.com")) - .add_answer(new DNSPtrRR("64.48.32.16.in-addr.arpa", 100, "other4.com")) - .add_answer(new DNSPtrRR("64.48.32.16.in-addr.arpa", 100, "other5.com")) - .add_answer(new DNSPtrRR("64.48.32.16.in-addr.arpa", 100, "other6.com")) - .add_answer(new DNSPtrRR("64.48.32.16.in-addr.arpa", 100, "other7.com")) - .add_answer(new DNSPtrRR("64.48.32.16.in-addr.arpa", 100, "other8.com")) - .add_answer(new DNSPtrRR("64.48.32.16.in-addr.arpa", 100, "other9.com")); - std::vector<byte> data = pkt.data(); - - struct hostent *host = nullptr; - EXPECT_EQ(ARES_SUCCESS, ares_parse_ptr_reply(data.data(), data.size(), - addrv4, sizeof(addrv4), AF_INET, &host, NULL)); - ASSERT_NE(nullptr, host); - ares_free_hostent(host); -} - -TEST_F(LibraryTest, ParsePtrReplyAdditional) { - byte addrv4[4] = {0x10, 0x20, 0x30, 0x40}; - DNSPacket pkt; - pkt.set_qid(0x1234).set_response().set_aa() - .add_question(new DNSQuestion("64.48.32.16.in-addr.arpa", ns_t_ptr)) - .add_answer(new DNSPtrRR("64.48.32.16.in-addr.arpa", 55, "other.com")) - .add_auth(new DNSNsRR("16.in-addr.arpa", 234, "ns1.other.com")) - .add_auth(new DNSNsRR("16.in-addr.arpa", 234, "bb.ns2.other.com")) - .add_auth(new DNSNsRR("16.in-addr.arpa", 234, "ns3.other.com")) - .add_additional(new DNSARR("ns1.other.com", 229, {10,20,30,41})) - .add_additional(new DNSARR("bb.ns2.other.com", 229, {10,20,30,42})) - .add_additional(new DNSARR("ns3.other.com", 229, {10,20,30,43})); - std::vector<byte> data = pkt.data(); - - struct hostent *host = nullptr; - EXPECT_EQ(ARES_SUCCESS, ares_parse_ptr_reply(data.data(), data.size(), - addrv4, sizeof(addrv4), AF_INET, &host, NULL)); - ASSERT_NE(nullptr, host); - std::stringstream ss; - ss << HostEnt(host); - EXPECT_EQ("{'other.com' aliases=[other.com] addrs=[16.32.48.64]}", ss.str()); - ares_free_hostent(host); -} - -TEST_F(LibraryTest, ParsePtrReplyErrors) { - byte addrv4[4] = {0x10, 0x20, 0x30, 0x40}; - DNSPacket pkt; - pkt.set_qid(0x1234).set_response().set_aa() - .add_question(new DNSQuestion("64.48.32.16.in-addr.arpa", ns_t_ptr)) - .add_answer(new DNSPtrRR("64.48.32.16.in-addr.arpa", 100, "other.com")); - std::vector<byte> data; - struct hostent *host = nullptr; - - // No question. - pkt.questions_.clear(); - data = pkt.data(); - EXPECT_EQ(ARES_EBADRESP, ares_parse_ptr_reply(data.data(), data.size(), - addrv4, sizeof(addrv4), AF_INET, &host, NULL)); - pkt.add_question(new DNSQuestion("64.48.32.16.in-addr.arpa", ns_t_ptr)); - - // Question != answer - pkt.questions_.clear(); - pkt.add_question(new DNSQuestion("99.48.32.16.in-addr.arpa", ns_t_ptr)); - data = pkt.data(); - EXPECT_EQ(ARES_ENODATA, ares_parse_ptr_reply(data.data(), data.size(), - addrv4, sizeof(addrv4), AF_INET, &host, NULL)); - EXPECT_EQ(nullptr, host); - pkt.questions_.clear(); - pkt.add_question(new DNSQuestion("64.48.32.16.in-addr.arpa", ns_t_ptr)); - - // Two questions. - pkt.add_question(new DNSQuestion("64.48.32.16.in-addr.arpa", ns_t_ptr)); - data = pkt.data(); - EXPECT_EQ(ARES_EBADRESP, ares_parse_ptr_reply(data.data(), data.size(), - addrv4, sizeof(addrv4), AF_INET, &host, NULL)); - EXPECT_EQ(nullptr, host); - pkt.questions_.clear(); - pkt.add_question(new DNSQuestion("64.48.32.16.in-addr.arpa", ns_t_ptr)); - - // Wrong sort of answer. - pkt.answers_.clear(); - pkt.add_answer(new DNSMxRR("example.com", 100, 100, "mx1.example.com")); - data = pkt.data(); - EXPECT_EQ(ARES_ENODATA, ares_parse_ptr_reply(data.data(), data.size(), - addrv4, sizeof(addrv4), AF_INET, &host, NULL)); - EXPECT_EQ(nullptr, host); - pkt.answers_.clear(); - pkt.add_answer(new DNSPtrRR("64.48.32.16.in-addr.arpa", 100, "other.com")); - - // No answer. - pkt.answers_.clear(); - data = pkt.data(); - EXPECT_EQ(ARES_ENODATA, ares_parse_ptr_reply(data.data(), data.size(), - addrv4, sizeof(addrv4), AF_INET, &host, NULL)); - EXPECT_EQ(nullptr, host); - pkt.add_answer(new DNSPtrRR("64.48.32.16.in-addr.arpa", 100, "other.com")); - - // Truncated packets. - data = pkt.data(); - for (size_t len = 1; len < data.size(); len++) { - EXPECT_EQ(ARES_EBADRESP, ares_parse_ptr_reply(data.data(), len, - addrv4, sizeof(addrv4), AF_INET, &host, NULL)); - EXPECT_EQ(nullptr, host); - } - - // Truncated packets with CNAME. - pkt.add_answer(new DNSCnameRR("64.48.32.16.in-addr.arpa", 50, "64.48.32.8.in-addr.arpa")); - data = pkt.data(); - for (size_t len = 1; len < data.size(); len++) { - EXPECT_EQ(ARES_EBADRESP, ares_parse_ptr_reply(data.data(), len, - addrv4, sizeof(addrv4), AF_INET, &host, NULL)); - EXPECT_EQ(nullptr, host); - } -} - -TEST_F(LibraryTest, ParsePtrReplyAllocFailSome) { - byte addrv4[4] = {0x10, 0x20, 0x30, 0x40}; - DNSPacket pkt; - pkt.set_qid(0x1234).set_response().set_aa() - .add_question(new DNSQuestion("64.48.32.16.in-addr.arpa", ns_t_ptr)) - .add_answer(new DNSPtrRR("64.48.32.16.in-addr.arpa", 100, "main.com")) - .add_answer(new DNSPtrRR("64.48.32.16.in-addr.arpa", 100, "other1.com")) - .add_answer(new DNSPtrRR("64.48.32.16.in-addr.arpa", 100, "other2.com")) - .add_answer(new DNSPtrRR("64.48.32.16.in-addr.arpa", 100, "other3.com")); - std::vector<byte> data = pkt.data(); - struct hostent *host = nullptr; - - for (int ii = 1; ii <= 18; ii++) { - ClearFails(); - SetAllocFail(ii); - EXPECT_EQ(ARES_ENOMEM, ares_parse_ptr_reply(data.data(), data.size(), - addrv4, sizeof(addrv4), AF_INET, &host, NULL)) << ii; - } -} - -TEST_F(LibraryTest, ParsePtrReplyAllocFailMany) { - byte addrv4[4] = {0x10, 0x20, 0x30, 0x40}; - DNSPacket pkt; - pkt.set_qid(0x1234).set_response().set_aa() - .add_question(new DNSQuestion("64.48.32.16.in-addr.arpa", ns_t_ptr)) - .add_answer(new DNSPtrRR("64.48.32.16.in-addr.arpa", 100, "main.com")) - .add_answer(new DNSPtrRR("64.48.32.16.in-addr.arpa", 100, "other1.com")) - .add_answer(new DNSPtrRR("64.48.32.16.in-addr.arpa", 100, "other2.com")) - .add_answer(new DNSPtrRR("64.48.32.16.in-addr.arpa", 100, "other3.com")) - .add_answer(new DNSPtrRR("64.48.32.16.in-addr.arpa", 100, "other4.com")) - .add_answer(new DNSPtrRR("64.48.32.16.in-addr.arpa", 100, "other5.com")) - .add_answer(new DNSPtrRR("64.48.32.16.in-addr.arpa", 100, "other6.com")) - .add_answer(new DNSPtrRR("64.48.32.16.in-addr.arpa", 100, "other7.com")) - .add_answer(new DNSPtrRR("64.48.32.16.in-addr.arpa", 100, "other8.com")) - .add_answer(new DNSPtrRR("64.48.32.16.in-addr.arpa", 100, "other9.com")); - std::vector<byte> data = pkt.data(); - struct hostent *host = nullptr; - - for (int ii = 1; ii <= 63; ii++) { - ClearFails(); - SetAllocFail(ii); - int rc = ares_parse_ptr_reply(data.data(), data.size(), - addrv4, sizeof(addrv4), AF_INET, &host, NULL); - if (rc != ARES_ENOMEM) { - EXPECT_EQ(ARES_SUCCESS, rc); - ares_free_hostent(host); - host = nullptr; - } - } -} - - -} // namespace test -} // namespace ares +#include "ares-test.h" +#include "dns-proto.h" + +#include <sstream> +#include <vector> + +namespace ares { +namespace test { + +TEST_F(LibraryTest, ParsePtrReplyOK) { + byte addrv4[4] = {0x10, 0x20, 0x30, 0x40}; + DNSPacket pkt; + pkt.set_qid(0x1234).set_response().set_aa() + .add_question(new DNSQuestion("64.48.32.16.in-addr.arpa", ns_t_ptr)) + .add_answer(new DNSPtrRR("64.48.32.16.in-addr.arpa", 100, "other.com")); + std::vector<byte> data = pkt.data(); + + struct hostent *host = nullptr; + EXPECT_EQ(ARES_SUCCESS, ares_parse_ptr_reply(data.data(), data.size(), + addrv4, sizeof(addrv4), AF_INET, &host, NULL)); + ASSERT_NE(nullptr, host); + std::stringstream ss; + ss << HostEnt(host); + EXPECT_EQ("{'other.com' aliases=[other.com] addrs=[16.32.48.64]}", ss.str()); + ares_free_hostent(host); +} + +TEST_F(LibraryTest, ParsePtrReplyCname) { + byte addrv4[4] = {0x10, 0x20, 0x30, 0x40}; + DNSPacket pkt; + pkt.set_qid(0x1234).set_response().set_aa() + .add_question(new DNSQuestion("64.48.32.16.in-addr.arpa", ns_t_ptr)) + .add_answer(new DNSCnameRR("64.48.32.16.in-addr.arpa", 50, "64.48.32.8.in-addr.arpa")) + .add_answer(new DNSPtrRR("64.48.32.8.in-addr.arpa", 100, "other.com")); + std::vector<byte> data = pkt.data(); + + struct hostent *host = nullptr; + EXPECT_EQ(ARES_SUCCESS, ares_parse_ptr_reply(data.data(), data.size(), + addrv4, sizeof(addrv4), AF_INET, &host, NULL)); + ASSERT_NE(nullptr, host); + std::stringstream ss; + ss << HostEnt(host); + EXPECT_EQ("{'other.com' aliases=[other.com] addrs=[16.32.48.64]}", ss.str()); + ares_free_hostent(host); +} + + +struct DNSMalformedCnameRR : public DNSCnameRR { + DNSMalformedCnameRR(const std::string& name, int ttl, const std::string& other) + : DNSCnameRR(name, ttl, other) {} + std::vector<byte> data() const { + std::vector<byte> data = DNSRR::data(); + std::vector<byte> encname = EncodeString(other_); + encname[0] = encname[0] + 63; // invalid label length + int len = encname.size(); + PushInt16(&data, len); + data.insert(data.end(), encname.begin(), encname.end()); + return data; + } +}; + +TEST_F(LibraryTest, ParsePtrReplyMalformedCname) { + byte addrv4[4] = {0x10, 0x20, 0x30, 0x40}; + DNSPacket pkt; + pkt.set_qid(0x1234).set_response().set_aa() + .add_question(new DNSQuestion("64.48.32.16.in-addr.arpa", ns_t_ptr)) + .add_answer(new DNSMalformedCnameRR("64.48.32.16.in-addr.arpa", 50, "64.48.32.8.in-addr.arpa")) + .add_answer(new DNSPtrRR("64.48.32.8.in-addr.arpa", 100, "other.com")); + std::vector<byte> data = pkt.data(); + + struct hostent *host = nullptr; + EXPECT_EQ(ARES_EBADRESP, ares_parse_ptr_reply(data.data(), data.size(), + addrv4, sizeof(addrv4), AF_INET, &host, NULL)); + ASSERT_EQ(nullptr, host); +} + +TEST_F(LibraryTest, ParseManyPtrReply) { + byte addrv4[4] = {0x10, 0x20, 0x30, 0x40}; + DNSPacket pkt; + pkt.set_qid(0x1234).set_response().set_aa() + .add_question(new DNSQuestion("64.48.32.16.in-addr.arpa", ns_t_ptr)) + .add_answer(new DNSPtrRR("64.48.32.16.in-addr.arpa", 100, "main.com")) + .add_answer(new DNSPtrRR("64.48.32.16.in-addr.arpa", 100, "other1.com")) + .add_answer(new DNSPtrRR("64.48.32.16.in-addr.arpa", 100, "other2.com")) + .add_answer(new DNSPtrRR("64.48.32.16.in-addr.arpa", 100, "other3.com")) + .add_answer(new DNSPtrRR("64.48.32.16.in-addr.arpa", 100, "other4.com")) + .add_answer(new DNSPtrRR("64.48.32.16.in-addr.arpa", 100, "other5.com")) + .add_answer(new DNSPtrRR("64.48.32.16.in-addr.arpa", 100, "other6.com")) + .add_answer(new DNSPtrRR("64.48.32.16.in-addr.arpa", 100, "other7.com")) + .add_answer(new DNSPtrRR("64.48.32.16.in-addr.arpa", 100, "other8.com")) + .add_answer(new DNSPtrRR("64.48.32.16.in-addr.arpa", 100, "other9.com")); + std::vector<byte> data = pkt.data(); + + struct hostent *host = nullptr; + EXPECT_EQ(ARES_SUCCESS, ares_parse_ptr_reply(data.data(), data.size(), + addrv4, sizeof(addrv4), AF_INET, &host, NULL)); + ASSERT_NE(nullptr, host); + ares_free_hostent(host); +} + +TEST_F(LibraryTest, ParsePtrReplyAdditional) { + byte addrv4[4] = {0x10, 0x20, 0x30, 0x40}; + DNSPacket pkt; + pkt.set_qid(0x1234).set_response().set_aa() + .add_question(new DNSQuestion("64.48.32.16.in-addr.arpa", ns_t_ptr)) + .add_answer(new DNSPtrRR("64.48.32.16.in-addr.arpa", 55, "other.com")) + .add_auth(new DNSNsRR("16.in-addr.arpa", 234, "ns1.other.com")) + .add_auth(new DNSNsRR("16.in-addr.arpa", 234, "bb.ns2.other.com")) + .add_auth(new DNSNsRR("16.in-addr.arpa", 234, "ns3.other.com")) + .add_additional(new DNSARR("ns1.other.com", 229, {10,20,30,41})) + .add_additional(new DNSARR("bb.ns2.other.com", 229, {10,20,30,42})) + .add_additional(new DNSARR("ns3.other.com", 229, {10,20,30,43})); + std::vector<byte> data = pkt.data(); + + struct hostent *host = nullptr; + EXPECT_EQ(ARES_SUCCESS, ares_parse_ptr_reply(data.data(), data.size(), + addrv4, sizeof(addrv4), AF_INET, &host, NULL)); + ASSERT_NE(nullptr, host); + std::stringstream ss; + ss << HostEnt(host); + EXPECT_EQ("{'other.com' aliases=[other.com] addrs=[16.32.48.64]}", ss.str()); + ares_free_hostent(host); +} + +TEST_F(LibraryTest, ParsePtrReplyErrors) { + byte addrv4[4] = {0x10, 0x20, 0x30, 0x40}; + DNSPacket pkt; + pkt.set_qid(0x1234).set_response().set_aa() + .add_question(new DNSQuestion("64.48.32.16.in-addr.arpa", ns_t_ptr)) + .add_answer(new DNSPtrRR("64.48.32.16.in-addr.arpa", 100, "other.com")); + std::vector<byte> data; + struct hostent *host = nullptr; + + // No question. + pkt.questions_.clear(); + data = pkt.data(); + EXPECT_EQ(ARES_EBADRESP, ares_parse_ptr_reply(data.data(), data.size(), + addrv4, sizeof(addrv4), AF_INET, &host, NULL)); + pkt.add_question(new DNSQuestion("64.48.32.16.in-addr.arpa", ns_t_ptr)); + + // Question != answer + pkt.questions_.clear(); + pkt.add_question(new DNSQuestion("99.48.32.16.in-addr.arpa", ns_t_ptr)); + data = pkt.data(); + EXPECT_EQ(ARES_ENODATA, ares_parse_ptr_reply(data.data(), data.size(), + addrv4, sizeof(addrv4), AF_INET, &host, NULL)); + EXPECT_EQ(nullptr, host); + pkt.questions_.clear(); + pkt.add_question(new DNSQuestion("64.48.32.16.in-addr.arpa", ns_t_ptr)); + + // Two questions. + pkt.add_question(new DNSQuestion("64.48.32.16.in-addr.arpa", ns_t_ptr)); + data = pkt.data(); + EXPECT_EQ(ARES_EBADRESP, ares_parse_ptr_reply(data.data(), data.size(), + addrv4, sizeof(addrv4), AF_INET, &host, NULL)); + EXPECT_EQ(nullptr, host); + pkt.questions_.clear(); + pkt.add_question(new DNSQuestion("64.48.32.16.in-addr.arpa", ns_t_ptr)); + + // Wrong sort of answer. + pkt.answers_.clear(); + pkt.add_answer(new DNSMxRR("example.com", 100, 100, "mx1.example.com")); + data = pkt.data(); + EXPECT_EQ(ARES_ENODATA, ares_parse_ptr_reply(data.data(), data.size(), + addrv4, sizeof(addrv4), AF_INET, &host, NULL)); + EXPECT_EQ(nullptr, host); + pkt.answers_.clear(); + pkt.add_answer(new DNSPtrRR("64.48.32.16.in-addr.arpa", 100, "other.com")); + + // No answer. + pkt.answers_.clear(); + data = pkt.data(); + EXPECT_EQ(ARES_ENODATA, ares_parse_ptr_reply(data.data(), data.size(), + addrv4, sizeof(addrv4), AF_INET, &host, NULL)); + EXPECT_EQ(nullptr, host); + pkt.add_answer(new DNSPtrRR("64.48.32.16.in-addr.arpa", 100, "other.com")); + + // Truncated packets. + data = pkt.data(); + for (size_t len = 1; len < data.size(); len++) { + EXPECT_EQ(ARES_EBADRESP, ares_parse_ptr_reply(data.data(), len, + addrv4, sizeof(addrv4), AF_INET, &host, NULL)); + EXPECT_EQ(nullptr, host); + } + + // Truncated packets with CNAME. + pkt.add_answer(new DNSCnameRR("64.48.32.16.in-addr.arpa", 50, "64.48.32.8.in-addr.arpa")); + data = pkt.data(); + for (size_t len = 1; len < data.size(); len++) { + EXPECT_EQ(ARES_EBADRESP, ares_parse_ptr_reply(data.data(), len, + addrv4, sizeof(addrv4), AF_INET, &host, NULL)); + EXPECT_EQ(nullptr, host); + } +} + +TEST_F(LibraryTest, ParsePtrReplyAllocFailSome) { + byte addrv4[4] = {0x10, 0x20, 0x30, 0x40}; + DNSPacket pkt; + pkt.set_qid(0x1234).set_response().set_aa() + .add_question(new DNSQuestion("64.48.32.16.in-addr.arpa", ns_t_ptr)) + .add_answer(new DNSPtrRR("64.48.32.16.in-addr.arpa", 100, "main.com")) + .add_answer(new DNSPtrRR("64.48.32.16.in-addr.arpa", 100, "other1.com")) + .add_answer(new DNSPtrRR("64.48.32.16.in-addr.arpa", 100, "other2.com")) + .add_answer(new DNSPtrRR("64.48.32.16.in-addr.arpa", 100, "other3.com")); + std::vector<byte> data = pkt.data(); + struct hostent *host = nullptr; + + for (int ii = 1; ii <= 18; ii++) { + ClearFails(); + SetAllocFail(ii); + EXPECT_EQ(ARES_ENOMEM, ares_parse_ptr_reply(data.data(), data.size(), + addrv4, sizeof(addrv4), AF_INET, &host, NULL)) << ii; + } +} + +TEST_F(LibraryTest, ParsePtrReplyAllocFailMany) { + byte addrv4[4] = {0x10, 0x20, 0x30, 0x40}; + DNSPacket pkt; + pkt.set_qid(0x1234).set_response().set_aa() + .add_question(new DNSQuestion("64.48.32.16.in-addr.arpa", ns_t_ptr)) + .add_answer(new DNSPtrRR("64.48.32.16.in-addr.arpa", 100, "main.com")) + .add_answer(new DNSPtrRR("64.48.32.16.in-addr.arpa", 100, "other1.com")) + .add_answer(new DNSPtrRR("64.48.32.16.in-addr.arpa", 100, "other2.com")) + .add_answer(new DNSPtrRR("64.48.32.16.in-addr.arpa", 100, "other3.com")) + .add_answer(new DNSPtrRR("64.48.32.16.in-addr.arpa", 100, "other4.com")) + .add_answer(new DNSPtrRR("64.48.32.16.in-addr.arpa", 100, "other5.com")) + .add_answer(new DNSPtrRR("64.48.32.16.in-addr.arpa", 100, "other6.com")) + .add_answer(new DNSPtrRR("64.48.32.16.in-addr.arpa", 100, "other7.com")) + .add_answer(new DNSPtrRR("64.48.32.16.in-addr.arpa", 100, "other8.com")) + .add_answer(new DNSPtrRR("64.48.32.16.in-addr.arpa", 100, "other9.com")); + std::vector<byte> data = pkt.data(); + struct hostent *host = nullptr; + + for (int ii = 1; ii <= 63; ii++) { + ClearFails(); + SetAllocFail(ii); + int rc = ares_parse_ptr_reply(data.data(), data.size(), + addrv4, sizeof(addrv4), AF_INET, &host, NULL); + if (rc != ARES_ENOMEM) { + EXPECT_EQ(ARES_SUCCESS, rc); + ares_free_hostent(host); + host = nullptr; + } + } +} + + +} // namespace test +} // namespace ares diff --git a/contrib/libs/c-ares/test/ares-test-parse-soa.cc b/contrib/libs/c-ares/test/ares-test-parse-soa.cc index e6f5dcdab7..c0ffaaed50 100644 --- a/contrib/libs/c-ares/test/ares-test-parse-soa.cc +++ b/contrib/libs/c-ares/test/ares-test-parse-soa.cc @@ -1,108 +1,108 @@ -#include "ares-test.h" -#include "dns-proto.h" - -#include <sstream> -#include <vector> - -namespace ares { -namespace test { - -TEST_F(LibraryTest, ParseSoaReplyOK) { - DNSPacket pkt; - pkt.set_qid(0x1234).set_response().set_aa() - .add_question(new DNSQuestion("example.com", ns_t_soa)) - .add_answer(new DNSSoaRR("example.com", 100, - "soa1.example.com", "fred.example.com", - 1, 2, 3, 4, 5)); - std::vector<byte> data = pkt.data(); - - struct ares_soa_reply* soa = nullptr; - EXPECT_EQ(ARES_SUCCESS, ares_parse_soa_reply(data.data(), data.size(), &soa)); - ASSERT_NE(nullptr, soa); - EXPECT_EQ("soa1.example.com", std::string(soa->nsname)); - EXPECT_EQ("fred.example.com", std::string(soa->hostmaster)); - EXPECT_EQ(1, soa->serial); - EXPECT_EQ(2, soa->refresh); - EXPECT_EQ(3, soa->retry); - EXPECT_EQ(4, soa->expire); - EXPECT_EQ(5, soa->minttl); - ares_free_data(soa); -} - -TEST_F(LibraryTest, ParseSoaReplyErrors) { - DNSPacket pkt; - pkt.set_qid(0x1234).set_response().set_aa() - .add_question(new DNSQuestion("example.com", ns_t_soa)) - .add_answer(new DNSSoaRR("example.com", 100, - "soa1.example.com", "fred.example.com", - 1, 2, 3, 4, 5)); - std::vector<byte> data; - struct ares_soa_reply* soa = nullptr; - - // No question. - pkt.questions_.clear(); - data = pkt.data(); - EXPECT_EQ(ARES_EBADRESP, ares_parse_soa_reply(data.data(), data.size(), &soa)); - pkt.add_question(new DNSQuestion("example.com", ns_t_soa)); - -#ifdef DISABLED - // Question != answer - pkt.questions_.clear(); - pkt.add_question(new DNSQuestion("Axample.com", ns_t_soa)); - data = pkt.data(); +#include "ares-test.h" +#include "dns-proto.h" + +#include <sstream> +#include <vector> + +namespace ares { +namespace test { + +TEST_F(LibraryTest, ParseSoaReplyOK) { + DNSPacket pkt; + pkt.set_qid(0x1234).set_response().set_aa() + .add_question(new DNSQuestion("example.com", ns_t_soa)) + .add_answer(new DNSSoaRR("example.com", 100, + "soa1.example.com", "fred.example.com", + 1, 2, 3, 4, 5)); + std::vector<byte> data = pkt.data(); + + struct ares_soa_reply* soa = nullptr; + EXPECT_EQ(ARES_SUCCESS, ares_parse_soa_reply(data.data(), data.size(), &soa)); + ASSERT_NE(nullptr, soa); + EXPECT_EQ("soa1.example.com", std::string(soa->nsname)); + EXPECT_EQ("fred.example.com", std::string(soa->hostmaster)); + EXPECT_EQ(1, soa->serial); + EXPECT_EQ(2, soa->refresh); + EXPECT_EQ(3, soa->retry); + EXPECT_EQ(4, soa->expire); + EXPECT_EQ(5, soa->minttl); + ares_free_data(soa); +} + +TEST_F(LibraryTest, ParseSoaReplyErrors) { + DNSPacket pkt; + pkt.set_qid(0x1234).set_response().set_aa() + .add_question(new DNSQuestion("example.com", ns_t_soa)) + .add_answer(new DNSSoaRR("example.com", 100, + "soa1.example.com", "fred.example.com", + 1, 2, 3, 4, 5)); + std::vector<byte> data; + struct ares_soa_reply* soa = nullptr; + + // No question. + pkt.questions_.clear(); + data = pkt.data(); EXPECT_EQ(ARES_EBADRESP, ares_parse_soa_reply(data.data(), data.size(), &soa)); - pkt.questions_.clear(); - pkt.add_question(new DNSQuestion("example.com", ns_t_soa)); -#endif - - // Two questions - pkt.add_question(new DNSQuestion("example.com", ns_t_soa)); - data = pkt.data(); - EXPECT_EQ(ARES_EBADRESP, ares_parse_soa_reply(data.data(), data.size(), &soa)); - pkt.questions_.clear(); - pkt.add_question(new DNSQuestion("example.com", ns_t_soa)); - - // Wrong sort of answer. - pkt.answers_.clear(); - pkt.add_answer(new DNSMxRR("example.com", 100, 100, "mx1.example.com")); - data = pkt.data(); - EXPECT_EQ(ARES_EBADRESP, ares_parse_soa_reply(data.data(), data.size(), &soa)); - pkt.answers_.clear(); - pkt.add_answer(new DNSSoaRR("example.com", 100, - "soa1.example.com", "fred.example.com", - 1, 2, 3, 4, 5)); - - // No answer. - pkt.answers_.clear(); - data = pkt.data(); - EXPECT_EQ(ARES_EBADRESP, ares_parse_soa_reply(data.data(), data.size(), &soa)); - pkt.add_answer(new DNSSoaRR("example.com", 100, - "soa1.example.com", "fred.example.com", - 1, 2, 3, 4, 5)); - - // Truncated packets. - data = pkt.data(); - for (size_t len = 1; len < data.size(); len++) { - EXPECT_EQ(ARES_EBADRESP, ares_parse_soa_reply(data.data(), len, &soa)); - } -} - -TEST_F(LibraryTest, ParseSoaReplyAllocFail) { - DNSPacket pkt; - pkt.set_qid(0x1234).set_response().set_aa() - .add_question(new DNSQuestion("example.com", ns_t_soa)) - .add_answer(new DNSSoaRR("example.com", 100, - "soa1.example.com", "fred.example.com", - 1, 2, 3, 4, 5)); - std::vector<byte> data = pkt.data(); - struct ares_soa_reply* soa = nullptr; - - for (int ii = 1; ii <= 5; ii++) { - ClearFails(); - SetAllocFail(ii); - EXPECT_EQ(ARES_ENOMEM, ares_parse_soa_reply(data.data(), data.size(), &soa)) << ii; - } -} - -} // namespace test -} // namespace ares + pkt.add_question(new DNSQuestion("example.com", ns_t_soa)); + +#ifdef DISABLED + // Question != answer + pkt.questions_.clear(); + pkt.add_question(new DNSQuestion("Axample.com", ns_t_soa)); + data = pkt.data(); + EXPECT_EQ(ARES_EBADRESP, ares_parse_soa_reply(data.data(), data.size(), &soa)); + pkt.questions_.clear(); + pkt.add_question(new DNSQuestion("example.com", ns_t_soa)); +#endif + + // Two questions + pkt.add_question(new DNSQuestion("example.com", ns_t_soa)); + data = pkt.data(); + EXPECT_EQ(ARES_EBADRESP, ares_parse_soa_reply(data.data(), data.size(), &soa)); + pkt.questions_.clear(); + pkt.add_question(new DNSQuestion("example.com", ns_t_soa)); + + // Wrong sort of answer. + pkt.answers_.clear(); + pkt.add_answer(new DNSMxRR("example.com", 100, 100, "mx1.example.com")); + data = pkt.data(); + EXPECT_EQ(ARES_EBADRESP, ares_parse_soa_reply(data.data(), data.size(), &soa)); + pkt.answers_.clear(); + pkt.add_answer(new DNSSoaRR("example.com", 100, + "soa1.example.com", "fred.example.com", + 1, 2, 3, 4, 5)); + + // No answer. + pkt.answers_.clear(); + data = pkt.data(); + EXPECT_EQ(ARES_EBADRESP, ares_parse_soa_reply(data.data(), data.size(), &soa)); + pkt.add_answer(new DNSSoaRR("example.com", 100, + "soa1.example.com", "fred.example.com", + 1, 2, 3, 4, 5)); + + // Truncated packets. + data = pkt.data(); + for (size_t len = 1; len < data.size(); len++) { + EXPECT_EQ(ARES_EBADRESP, ares_parse_soa_reply(data.data(), len, &soa)); + } +} + +TEST_F(LibraryTest, ParseSoaReplyAllocFail) { + DNSPacket pkt; + pkt.set_qid(0x1234).set_response().set_aa() + .add_question(new DNSQuestion("example.com", ns_t_soa)) + .add_answer(new DNSSoaRR("example.com", 100, + "soa1.example.com", "fred.example.com", + 1, 2, 3, 4, 5)); + std::vector<byte> data = pkt.data(); + struct ares_soa_reply* soa = nullptr; + + for (int ii = 1; ii <= 5; ii++) { + ClearFails(); + SetAllocFail(ii); + EXPECT_EQ(ARES_ENOMEM, ares_parse_soa_reply(data.data(), data.size(), &soa)) << ii; + } +} + +} // namespace test +} // namespace ares diff --git a/contrib/libs/c-ares/test/ares-test-parse-srv.cc b/contrib/libs/c-ares/test/ares-test-parse-srv.cc index d3e3183d03..cc651d6d4e 100644 --- a/contrib/libs/c-ares/test/ares-test-parse-srv.cc +++ b/contrib/libs/c-ares/test/ares-test-parse-srv.cc @@ -1,288 +1,288 @@ -#include "ares-test.h" -#include "dns-proto.h" - -#include <sstream> -#include <vector> - -namespace ares { -namespace test { - -TEST_F(LibraryTest, ParseSrvReplyOK) { - DNSPacket pkt; - pkt.set_qid(0x1234).set_response().set_aa() - .add_question(new DNSQuestion("example.com", ns_t_srv)) - .add_answer(new DNSSrvRR("example.com", 100, 10, 20, 30, "srv.example.com")) - .add_answer(new DNSSrvRR("example.com", 100, 11, 21, 31, "srv2.example.com")); - std::vector<byte> data = pkt.data(); - - struct ares_srv_reply* srv = nullptr; - EXPECT_EQ(ARES_SUCCESS, ares_parse_srv_reply(data.data(), data.size(), &srv)); - ASSERT_NE(nullptr, srv); - - EXPECT_EQ("srv.example.com", std::string(srv->host)); - EXPECT_EQ(10, srv->priority); - EXPECT_EQ(20, srv->weight); - EXPECT_EQ(30, srv->port); - - struct ares_srv_reply* srv2 = srv->next; - ASSERT_NE(nullptr, srv2); - EXPECT_EQ("srv2.example.com", std::string(srv2->host)); - EXPECT_EQ(11, srv2->priority); - EXPECT_EQ(21, srv2->weight); - EXPECT_EQ(31, srv2->port); - EXPECT_EQ(nullptr, srv2->next); - - ares_free_data(srv); -} - -TEST_F(LibraryTest, ParseSrvReplySingle) { - DNSPacket pkt; - pkt.set_qid(0x1234).set_response().set_aa() - .add_question(new DNSQuestion("example.abc.def.com", ns_t_srv)) - .add_answer(new DNSSrvRR("example.abc.def.com", 180, 0, 10, 8160, "example.abc.def.com")) - .add_auth(new DNSNsRR("abc.def.com", 44, "else1.where.com")) - .add_auth(new DNSNsRR("abc.def.com", 44, "else2.where.com")) - .add_auth(new DNSNsRR("abc.def.com", 44, "else3.where.com")) - .add_auth(new DNSNsRR("abc.def.com", 44, "else4.where.com")) - .add_auth(new DNSNsRR("abc.def.com", 44, "else5.where.com")) - .add_additional(new DNSARR("else2.where.com", 42, {172,19,0,1})) - .add_additional(new DNSARR("else5.where.com", 42, {172,19,0,2})); - std::vector<byte> data = pkt.data(); - - struct ares_srv_reply* srv = nullptr; - EXPECT_EQ(ARES_SUCCESS, ares_parse_srv_reply(data.data(), data.size(), &srv)); - ASSERT_NE(nullptr, srv); - - EXPECT_EQ("example.abc.def.com", std::string(srv->host)); - EXPECT_EQ(0, srv->priority); - EXPECT_EQ(10, srv->weight); - EXPECT_EQ(8160, srv->port); - EXPECT_EQ(nullptr, srv->next); - - ares_free_data(srv); -} - -TEST_F(LibraryTest, ParseSrvReplyMalformed) { - std::vector<byte> data = { - 0x12, 0x34, // qid - 0x84, // response + query + AA + not-TC + not-RD - 0x00, // not-RA + not-Z + not-AD + not-CD + rc=NoError - 0x00, 0x01, // num questions - 0x00, 0x01, // num answer RRs - 0x00, 0x00, // num authority RRs - 0x00, 0x00, // num additional RRs - // Question - 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', - 0x03, 'c', 'o', 'm', - 0x00, - 0x00, 0x21, // type SRV - 0x00, 0x01, // class IN - // Answer 1 - 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', - 0x03, 'c', 'o', 'm', - 0x00, - 0x00, 0x21, // RR type - 0x00, 0x01, // class IN - 0x01, 0x02, 0x03, 0x04, // TTL - 0x00, 0x04, // rdata length -- too short - 0x02, 0x03, 0x04, 0x05, - }; - - struct ares_srv_reply* srv = nullptr; - EXPECT_EQ(ARES_EBADRESP, ares_parse_srv_reply(data.data(), data.size(), &srv)); - ASSERT_EQ(nullptr, srv); -} - -TEST_F(LibraryTest, ParseSrvReplyMultiple) { - DNSPacket pkt; - pkt.set_qid(0x1234).set_response().set_ra().set_rd() - .add_question(new DNSQuestion("srv.example.com", ns_t_srv)) - .add_answer(new DNSSrvRR("srv.example.com", 300, 0, 5, 6789, "a1.srv.example.com")) - .add_answer(new DNSSrvRR("srv.example.com", 300, 0, 5, 4567, "a2.srv.example.com")) - .add_answer(new DNSSrvRR("srv.example.com", 300, 0, 5, 5678, "a3.srv.example.com")) - .add_auth(new DNSNsRR("example.com", 300, "ns1.example.com")) - .add_auth(new DNSNsRR("example.com", 300, "ns2.example.com")) - .add_auth(new DNSNsRR("example.com", 300, "ns3.example.com")) - .add_additional(new DNSARR("a1.srv.example.com", 300, {172,19,1,1})) - .add_additional(new DNSARR("a2.srv.example.com", 300, {172,19,1,2})) - .add_additional(new DNSARR("a3.srv.example.com", 300, {172,19,1,3})) - .add_additional(new DNSARR("n1.example.com", 300, {172,19,0,1})) - .add_additional(new DNSARR("n2.example.com", 300, {172,19,0,2})) - .add_additional(new DNSARR("n3.example.com", 300, {172,19,0,3})); - std::vector<byte> data = pkt.data(); - - struct ares_srv_reply* srv0 = nullptr; - EXPECT_EQ(ARES_SUCCESS, ares_parse_srv_reply(data.data(), data.size(), &srv0)); - ASSERT_NE(nullptr, srv0); - struct ares_srv_reply* srv = srv0; - - EXPECT_EQ("a1.srv.example.com", std::string(srv->host)); - EXPECT_EQ(0, srv->priority); - EXPECT_EQ(5, srv->weight); - EXPECT_EQ(6789, srv->port); - EXPECT_NE(nullptr, srv->next); - srv = srv->next; - - EXPECT_EQ("a2.srv.example.com", std::string(srv->host)); - EXPECT_EQ(0, srv->priority); - EXPECT_EQ(5, srv->weight); - EXPECT_EQ(4567, srv->port); - EXPECT_NE(nullptr, srv->next); - srv = srv->next; - - EXPECT_EQ("a3.srv.example.com", std::string(srv->host)); - EXPECT_EQ(0, srv->priority); - EXPECT_EQ(5, srv->weight); - EXPECT_EQ(5678, srv->port); - EXPECT_EQ(nullptr, srv->next); - - ares_free_data(srv0); -} - -TEST_F(LibraryTest, ParseSrvReplyCname) { - DNSPacket pkt; - pkt.set_qid(0x1234).set_response().set_aa() - .add_question(new DNSQuestion("example.abc.def.com", ns_t_srv)) - .add_answer(new DNSCnameRR("example.abc.def.com", 300, "cname.abc.def.com")) - .add_answer(new DNSSrvRR("cname.abc.def.com", 300, 0, 10, 1234, "srv.abc.def.com")) - .add_auth(new DNSNsRR("abc.def.com", 44, "else1.where.com")) - .add_auth(new DNSNsRR("abc.def.com", 44, "else2.where.com")) - .add_auth(new DNSNsRR("abc.def.com", 44, "else3.where.com")) - .add_additional(new DNSARR("example.abc.def.com", 300, {172,19,0,1})) - .add_additional(new DNSARR("else1.where.com", 42, {172,19,0,1})) - .add_additional(new DNSARR("else2.where.com", 42, {172,19,0,2})) - .add_additional(new DNSARR("else3.where.com", 42, {172,19,0,3})); - std::vector<byte> data = pkt.data(); - - struct ares_srv_reply* srv = nullptr; - EXPECT_EQ(ARES_SUCCESS, ares_parse_srv_reply(data.data(), data.size(), &srv)); - ASSERT_NE(nullptr, srv); - - EXPECT_EQ("srv.abc.def.com", std::string(srv->host)); - EXPECT_EQ(0, srv->priority); - EXPECT_EQ(10, srv->weight); - EXPECT_EQ(1234, srv->port); - EXPECT_EQ(nullptr, srv->next); - - ares_free_data(srv); -} - -TEST_F(LibraryTest, ParseSrvReplyCnameMultiple) { - DNSPacket pkt; - pkt.set_qid(0x1234).set_response().set_ra().set_rd() - .add_question(new DNSQuestion("query.example.com", ns_t_srv)) - .add_answer(new DNSCnameRR("query.example.com", 300, "srv.example.com")) - .add_answer(new DNSSrvRR("srv.example.com", 300, 0, 5, 6789, "a1.srv.example.com")) - .add_answer(new DNSSrvRR("srv.example.com", 300, 0, 5, 4567, "a2.srv.example.com")) - .add_answer(new DNSSrvRR("srv.example.com", 300, 0, 5, 5678, "a3.srv.example.com")) - .add_auth(new DNSNsRR("example.com", 300, "ns1.example.com")) - .add_auth(new DNSNsRR("example.com", 300, "ns2.example.com")) - .add_auth(new DNSNsRR("example.com", 300, "ns3.example.com")) - .add_additional(new DNSARR("a1.srv.example.com", 300, {172,19,1,1})) - .add_additional(new DNSARR("a2.srv.example.com", 300, {172,19,1,2})) - .add_additional(new DNSARR("a3.srv.example.com", 300, {172,19,1,3})) - .add_additional(new DNSARR("n1.example.com", 300, {172,19,0,1})) - .add_additional(new DNSARR("n2.example.com", 300, {172,19,0,2})) - .add_additional(new DNSARR("n3.example.com", 300, {172,19,0,3})); - std::vector<byte> data = pkt.data(); - - struct ares_srv_reply* srv0 = nullptr; - EXPECT_EQ(ARES_SUCCESS, ares_parse_srv_reply(data.data(), data.size(), &srv0)); - ASSERT_NE(nullptr, srv0); - struct ares_srv_reply* srv = srv0; - - EXPECT_EQ("a1.srv.example.com", std::string(srv->host)); - EXPECT_EQ(0, srv->priority); - EXPECT_EQ(5, srv->weight); - EXPECT_EQ(6789, srv->port); - EXPECT_NE(nullptr, srv->next); - srv = srv->next; - - EXPECT_EQ("a2.srv.example.com", std::string(srv->host)); - EXPECT_EQ(0, srv->priority); - EXPECT_EQ(5, srv->weight); - EXPECT_EQ(4567, srv->port); - EXPECT_NE(nullptr, srv->next); - srv = srv->next; - - EXPECT_EQ("a3.srv.example.com", std::string(srv->host)); - EXPECT_EQ(0, srv->priority); - EXPECT_EQ(5, srv->weight); - EXPECT_EQ(5678, srv->port); - EXPECT_EQ(nullptr, srv->next); - - ares_free_data(srv0); -} - -TEST_F(LibraryTest, ParseSrvReplyErrors) { - DNSPacket pkt; - pkt.set_qid(0x1234).set_response().set_aa() - .add_question(new DNSQuestion("example.abc.def.com", ns_t_srv)) - .add_answer(new DNSSrvRR("example.abc.def.com", 180, 0, 10, 8160, "example.abc.def.com")); - std::vector<byte> data; - struct ares_srv_reply* srv = nullptr; - - // No question. - pkt.questions_.clear(); - data = pkt.data(); - EXPECT_EQ(ARES_EBADRESP, ares_parse_srv_reply(data.data(), data.size(), &srv)); - pkt.add_question(new DNSQuestion("example.abc.def.com", ns_t_srv)); - -#ifdef DISABLED - // Question != answer - pkt.questions_.clear(); - pkt.add_question(new DNSQuestion("Axample.com", ns_t_srv)); - data = pkt.data(); - EXPECT_EQ(ARES_ENODATA, ares_parse_srv_reply(data.data(), data.size(), &srv)); - pkt.questions_.clear(); - pkt.add_question(new DNSQuestion("example.com", ns_t_srv)); -#endif - - // Two questions. - pkt.add_question(new DNSQuestion("example.abc.def.com", ns_t_srv)); - data = pkt.data(); - EXPECT_EQ(ARES_EBADRESP, ares_parse_srv_reply(data.data(), data.size(), &srv)); - pkt.questions_.clear(); - pkt.add_question(new DNSQuestion("64.48.32.16.in-addr.arpa", ns_t_ptr)); - - // Wrong sort of answer. - pkt.answers_.clear(); - pkt.add_answer(new DNSMxRR("example.com", 100, 100, "mx1.example.com")); - data = pkt.data(); - EXPECT_EQ(ARES_SUCCESS, ares_parse_srv_reply(data.data(), data.size(), &srv)); - EXPECT_EQ(nullptr, srv); - pkt.answers_.clear(); - pkt.add_answer(new DNSSrvRR("example.abc.def.com", 180, 0, 10, 8160, "example.abc.def.com")); - - // No answer. - pkt.answers_.clear(); - data = pkt.data(); - EXPECT_EQ(ARES_ENODATA, ares_parse_srv_reply(data.data(), data.size(), &srv)); - pkt.add_answer(new DNSSrvRR("example.abc.def.com", 180, 0, 10, 8160, "example.abc.def.com")); - - // Truncated packets. - data = pkt.data(); - for (size_t len = 1; len < data.size(); len++) { - int rc = ares_parse_srv_reply(data.data(), len, &srv); - EXPECT_TRUE(rc == ARES_EBADRESP || rc == ARES_EBADNAME); - } -} - -TEST_F(LibraryTest, ParseSrvReplyAllocFail) { - DNSPacket pkt; - pkt.set_qid(0x1234).set_response().set_aa() - .add_question(new DNSQuestion("example.abc.def.com", ns_t_srv)) - .add_answer(new DNSCnameRR("example.com", 300, "c.example.com")) - .add_answer(new DNSSrvRR("example.abc.def.com", 180, 0, 10, 8160, "example.abc.def.com")); - std::vector<byte> data = pkt.data(); - struct ares_srv_reply* srv = nullptr; - - for (int ii = 1; ii <= 5; ii++) { - ClearFails(); - SetAllocFail(ii); - EXPECT_EQ(ARES_ENOMEM, ares_parse_srv_reply(data.data(), data.size(), &srv)) << ii; - } -} - -} // namespace test -} // namespace ares +#include "ares-test.h" +#include "dns-proto.h" + +#include <sstream> +#include <vector> + +namespace ares { +namespace test { + +TEST_F(LibraryTest, ParseSrvReplyOK) { + DNSPacket pkt; + pkt.set_qid(0x1234).set_response().set_aa() + .add_question(new DNSQuestion("example.com", ns_t_srv)) + .add_answer(new DNSSrvRR("example.com", 100, 10, 20, 30, "srv.example.com")) + .add_answer(new DNSSrvRR("example.com", 100, 11, 21, 31, "srv2.example.com")); + std::vector<byte> data = pkt.data(); + + struct ares_srv_reply* srv = nullptr; + EXPECT_EQ(ARES_SUCCESS, ares_parse_srv_reply(data.data(), data.size(), &srv)); + ASSERT_NE(nullptr, srv); + + EXPECT_EQ("srv.example.com", std::string(srv->host)); + EXPECT_EQ(10, srv->priority); + EXPECT_EQ(20, srv->weight); + EXPECT_EQ(30, srv->port); + + struct ares_srv_reply* srv2 = srv->next; + ASSERT_NE(nullptr, srv2); + EXPECT_EQ("srv2.example.com", std::string(srv2->host)); + EXPECT_EQ(11, srv2->priority); + EXPECT_EQ(21, srv2->weight); + EXPECT_EQ(31, srv2->port); + EXPECT_EQ(nullptr, srv2->next); + + ares_free_data(srv); +} + +TEST_F(LibraryTest, ParseSrvReplySingle) { + DNSPacket pkt; + pkt.set_qid(0x1234).set_response().set_aa() + .add_question(new DNSQuestion("example.abc.def.com", ns_t_srv)) + .add_answer(new DNSSrvRR("example.abc.def.com", 180, 0, 10, 8160, "example.abc.def.com")) + .add_auth(new DNSNsRR("abc.def.com", 44, "else1.where.com")) + .add_auth(new DNSNsRR("abc.def.com", 44, "else2.where.com")) + .add_auth(new DNSNsRR("abc.def.com", 44, "else3.where.com")) + .add_auth(new DNSNsRR("abc.def.com", 44, "else4.where.com")) + .add_auth(new DNSNsRR("abc.def.com", 44, "else5.where.com")) + .add_additional(new DNSARR("else2.where.com", 42, {172,19,0,1})) + .add_additional(new DNSARR("else5.where.com", 42, {172,19,0,2})); + std::vector<byte> data = pkt.data(); + + struct ares_srv_reply* srv = nullptr; + EXPECT_EQ(ARES_SUCCESS, ares_parse_srv_reply(data.data(), data.size(), &srv)); + ASSERT_NE(nullptr, srv); + + EXPECT_EQ("example.abc.def.com", std::string(srv->host)); + EXPECT_EQ(0, srv->priority); + EXPECT_EQ(10, srv->weight); + EXPECT_EQ(8160, srv->port); + EXPECT_EQ(nullptr, srv->next); + + ares_free_data(srv); +} + +TEST_F(LibraryTest, ParseSrvReplyMalformed) { + std::vector<byte> data = { + 0x12, 0x34, // qid + 0x84, // response + query + AA + not-TC + not-RD + 0x00, // not-RA + not-Z + not-AD + not-CD + rc=NoError + 0x00, 0x01, // num questions + 0x00, 0x01, // num answer RRs + 0x00, 0x00, // num authority RRs + 0x00, 0x00, // num additional RRs + // Question + 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + 0x00, 0x21, // type SRV + 0x00, 0x01, // class IN + // Answer 1 + 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + 0x00, 0x21, // RR type + 0x00, 0x01, // class IN + 0x01, 0x02, 0x03, 0x04, // TTL + 0x00, 0x04, // rdata length -- too short + 0x02, 0x03, 0x04, 0x05, + }; + + struct ares_srv_reply* srv = nullptr; + EXPECT_EQ(ARES_EBADRESP, ares_parse_srv_reply(data.data(), data.size(), &srv)); + ASSERT_EQ(nullptr, srv); +} + +TEST_F(LibraryTest, ParseSrvReplyMultiple) { + DNSPacket pkt; + pkt.set_qid(0x1234).set_response().set_ra().set_rd() + .add_question(new DNSQuestion("srv.example.com", ns_t_srv)) + .add_answer(new DNSSrvRR("srv.example.com", 300, 0, 5, 6789, "a1.srv.example.com")) + .add_answer(new DNSSrvRR("srv.example.com", 300, 0, 5, 4567, "a2.srv.example.com")) + .add_answer(new DNSSrvRR("srv.example.com", 300, 0, 5, 5678, "a3.srv.example.com")) + .add_auth(new DNSNsRR("example.com", 300, "ns1.example.com")) + .add_auth(new DNSNsRR("example.com", 300, "ns2.example.com")) + .add_auth(new DNSNsRR("example.com", 300, "ns3.example.com")) + .add_additional(new DNSARR("a1.srv.example.com", 300, {172,19,1,1})) + .add_additional(new DNSARR("a2.srv.example.com", 300, {172,19,1,2})) + .add_additional(new DNSARR("a3.srv.example.com", 300, {172,19,1,3})) + .add_additional(new DNSARR("n1.example.com", 300, {172,19,0,1})) + .add_additional(new DNSARR("n2.example.com", 300, {172,19,0,2})) + .add_additional(new DNSARR("n3.example.com", 300, {172,19,0,3})); + std::vector<byte> data = pkt.data(); + + struct ares_srv_reply* srv0 = nullptr; + EXPECT_EQ(ARES_SUCCESS, ares_parse_srv_reply(data.data(), data.size(), &srv0)); + ASSERT_NE(nullptr, srv0); + struct ares_srv_reply* srv = srv0; + + EXPECT_EQ("a1.srv.example.com", std::string(srv->host)); + EXPECT_EQ(0, srv->priority); + EXPECT_EQ(5, srv->weight); + EXPECT_EQ(6789, srv->port); + EXPECT_NE(nullptr, srv->next); + srv = srv->next; + + EXPECT_EQ("a2.srv.example.com", std::string(srv->host)); + EXPECT_EQ(0, srv->priority); + EXPECT_EQ(5, srv->weight); + EXPECT_EQ(4567, srv->port); + EXPECT_NE(nullptr, srv->next); + srv = srv->next; + + EXPECT_EQ("a3.srv.example.com", std::string(srv->host)); + EXPECT_EQ(0, srv->priority); + EXPECT_EQ(5, srv->weight); + EXPECT_EQ(5678, srv->port); + EXPECT_EQ(nullptr, srv->next); + + ares_free_data(srv0); +} + +TEST_F(LibraryTest, ParseSrvReplyCname) { + DNSPacket pkt; + pkt.set_qid(0x1234).set_response().set_aa() + .add_question(new DNSQuestion("example.abc.def.com", ns_t_srv)) + .add_answer(new DNSCnameRR("example.abc.def.com", 300, "cname.abc.def.com")) + .add_answer(new DNSSrvRR("cname.abc.def.com", 300, 0, 10, 1234, "srv.abc.def.com")) + .add_auth(new DNSNsRR("abc.def.com", 44, "else1.where.com")) + .add_auth(new DNSNsRR("abc.def.com", 44, "else2.where.com")) + .add_auth(new DNSNsRR("abc.def.com", 44, "else3.where.com")) + .add_additional(new DNSARR("example.abc.def.com", 300, {172,19,0,1})) + .add_additional(new DNSARR("else1.where.com", 42, {172,19,0,1})) + .add_additional(new DNSARR("else2.where.com", 42, {172,19,0,2})) + .add_additional(new DNSARR("else3.where.com", 42, {172,19,0,3})); + std::vector<byte> data = pkt.data(); + + struct ares_srv_reply* srv = nullptr; + EXPECT_EQ(ARES_SUCCESS, ares_parse_srv_reply(data.data(), data.size(), &srv)); + ASSERT_NE(nullptr, srv); + + EXPECT_EQ("srv.abc.def.com", std::string(srv->host)); + EXPECT_EQ(0, srv->priority); + EXPECT_EQ(10, srv->weight); + EXPECT_EQ(1234, srv->port); + EXPECT_EQ(nullptr, srv->next); + + ares_free_data(srv); +} + +TEST_F(LibraryTest, ParseSrvReplyCnameMultiple) { + DNSPacket pkt; + pkt.set_qid(0x1234).set_response().set_ra().set_rd() + .add_question(new DNSQuestion("query.example.com", ns_t_srv)) + .add_answer(new DNSCnameRR("query.example.com", 300, "srv.example.com")) + .add_answer(new DNSSrvRR("srv.example.com", 300, 0, 5, 6789, "a1.srv.example.com")) + .add_answer(new DNSSrvRR("srv.example.com", 300, 0, 5, 4567, "a2.srv.example.com")) + .add_answer(new DNSSrvRR("srv.example.com", 300, 0, 5, 5678, "a3.srv.example.com")) + .add_auth(new DNSNsRR("example.com", 300, "ns1.example.com")) + .add_auth(new DNSNsRR("example.com", 300, "ns2.example.com")) + .add_auth(new DNSNsRR("example.com", 300, "ns3.example.com")) + .add_additional(new DNSARR("a1.srv.example.com", 300, {172,19,1,1})) + .add_additional(new DNSARR("a2.srv.example.com", 300, {172,19,1,2})) + .add_additional(new DNSARR("a3.srv.example.com", 300, {172,19,1,3})) + .add_additional(new DNSARR("n1.example.com", 300, {172,19,0,1})) + .add_additional(new DNSARR("n2.example.com", 300, {172,19,0,2})) + .add_additional(new DNSARR("n3.example.com", 300, {172,19,0,3})); + std::vector<byte> data = pkt.data(); + + struct ares_srv_reply* srv0 = nullptr; + EXPECT_EQ(ARES_SUCCESS, ares_parse_srv_reply(data.data(), data.size(), &srv0)); + ASSERT_NE(nullptr, srv0); + struct ares_srv_reply* srv = srv0; + + EXPECT_EQ("a1.srv.example.com", std::string(srv->host)); + EXPECT_EQ(0, srv->priority); + EXPECT_EQ(5, srv->weight); + EXPECT_EQ(6789, srv->port); + EXPECT_NE(nullptr, srv->next); + srv = srv->next; + + EXPECT_EQ("a2.srv.example.com", std::string(srv->host)); + EXPECT_EQ(0, srv->priority); + EXPECT_EQ(5, srv->weight); + EXPECT_EQ(4567, srv->port); + EXPECT_NE(nullptr, srv->next); + srv = srv->next; + + EXPECT_EQ("a3.srv.example.com", std::string(srv->host)); + EXPECT_EQ(0, srv->priority); + EXPECT_EQ(5, srv->weight); + EXPECT_EQ(5678, srv->port); + EXPECT_EQ(nullptr, srv->next); + + ares_free_data(srv0); +} + +TEST_F(LibraryTest, ParseSrvReplyErrors) { + DNSPacket pkt; + pkt.set_qid(0x1234).set_response().set_aa() + .add_question(new DNSQuestion("example.abc.def.com", ns_t_srv)) + .add_answer(new DNSSrvRR("example.abc.def.com", 180, 0, 10, 8160, "example.abc.def.com")); + std::vector<byte> data; + struct ares_srv_reply* srv = nullptr; + + // No question. + pkt.questions_.clear(); + data = pkt.data(); + EXPECT_EQ(ARES_EBADRESP, ares_parse_srv_reply(data.data(), data.size(), &srv)); + pkt.add_question(new DNSQuestion("example.abc.def.com", ns_t_srv)); + +#ifdef DISABLED + // Question != answer + pkt.questions_.clear(); + pkt.add_question(new DNSQuestion("Axample.com", ns_t_srv)); + data = pkt.data(); + EXPECT_EQ(ARES_ENODATA, ares_parse_srv_reply(data.data(), data.size(), &srv)); + pkt.questions_.clear(); + pkt.add_question(new DNSQuestion("example.com", ns_t_srv)); +#endif + + // Two questions. + pkt.add_question(new DNSQuestion("example.abc.def.com", ns_t_srv)); + data = pkt.data(); + EXPECT_EQ(ARES_EBADRESP, ares_parse_srv_reply(data.data(), data.size(), &srv)); + pkt.questions_.clear(); + pkt.add_question(new DNSQuestion("64.48.32.16.in-addr.arpa", ns_t_ptr)); + + // Wrong sort of answer. + pkt.answers_.clear(); + pkt.add_answer(new DNSMxRR("example.com", 100, 100, "mx1.example.com")); + data = pkt.data(); + EXPECT_EQ(ARES_SUCCESS, ares_parse_srv_reply(data.data(), data.size(), &srv)); + EXPECT_EQ(nullptr, srv); + pkt.answers_.clear(); + pkt.add_answer(new DNSSrvRR("example.abc.def.com", 180, 0, 10, 8160, "example.abc.def.com")); + + // No answer. + pkt.answers_.clear(); + data = pkt.data(); + EXPECT_EQ(ARES_ENODATA, ares_parse_srv_reply(data.data(), data.size(), &srv)); + pkt.add_answer(new DNSSrvRR("example.abc.def.com", 180, 0, 10, 8160, "example.abc.def.com")); + + // Truncated packets. + data = pkt.data(); + for (size_t len = 1; len < data.size(); len++) { + int rc = ares_parse_srv_reply(data.data(), len, &srv); + EXPECT_TRUE(rc == ARES_EBADRESP || rc == ARES_EBADNAME); + } +} + +TEST_F(LibraryTest, ParseSrvReplyAllocFail) { + DNSPacket pkt; + pkt.set_qid(0x1234).set_response().set_aa() + .add_question(new DNSQuestion("example.abc.def.com", ns_t_srv)) + .add_answer(new DNSCnameRR("example.com", 300, "c.example.com")) + .add_answer(new DNSSrvRR("example.abc.def.com", 180, 0, 10, 8160, "example.abc.def.com")); + std::vector<byte> data = pkt.data(); + struct ares_srv_reply* srv = nullptr; + + for (int ii = 1; ii <= 5; ii++) { + ClearFails(); + SetAllocFail(ii); + EXPECT_EQ(ARES_ENOMEM, ares_parse_srv_reply(data.data(), data.size(), &srv)) << ii; + } +} + +} // namespace test +} // namespace ares diff --git a/contrib/libs/c-ares/test/ares-test-parse-txt.cc b/contrib/libs/c-ares/test/ares-test-parse-txt.cc index 80a9dad7d1..8aaaaa3b47 100644 --- a/contrib/libs/c-ares/test/ares-test-parse-txt.cc +++ b/contrib/libs/c-ares/test/ares-test-parse-txt.cc @@ -1,266 +1,266 @@ -#include "ares-test.h" -#include "dns-proto.h" - -#include <sstream> -#include <vector> - -namespace ares { -namespace test { - -TEST_F(LibraryTest, ParseTxtReplyOK) { - DNSPacket pkt; - std::string expected1 = "txt1.example.com"; - std::string expected2a = "txt2a"; - std::string expected2b("ABC\0ABC", 7); - pkt.set_qid(0x1234).set_response().set_aa() - .add_question(new DNSQuestion("example.com", ns_t_mx)) - .add_answer(new DNSTxtRR("example.com", 100, {expected1})) - .add_answer(new DNSTxtRR("example.com", 100, {expected2a, expected2b})); - std::vector<byte> data = pkt.data(); - - struct ares_txt_reply* txt = nullptr; - EXPECT_EQ(ARES_SUCCESS, ares_parse_txt_reply(data.data(), data.size(), &txt)); - ASSERT_NE(nullptr, txt); - EXPECT_EQ(std::vector<byte>(expected1.data(), expected1.data() + expected1.size()), - std::vector<byte>(txt->txt, txt->txt + txt->length)); - - struct ares_txt_reply* txt2 = txt->next; - ASSERT_NE(nullptr, txt2); - EXPECT_EQ(std::vector<byte>(expected2a.data(), expected2a.data() + expected2a.size()), - std::vector<byte>(txt2->txt, txt2->txt + txt2->length)); - - struct ares_txt_reply* txt3 = txt2->next; - ASSERT_NE(nullptr, txt3); - EXPECT_EQ(std::vector<byte>(expected2b.data(), expected2b.data() + expected2b.size()), - std::vector<byte>(txt3->txt, txt3->txt + txt3->length)); - EXPECT_EQ(nullptr, txt3->next); - - ares_free_data(txt); -} - -TEST_F(LibraryTest, ParseTxtExtReplyOK) { - DNSPacket pkt; - std::string expected1 = "txt1.example.com"; - std::string expected2a = "txt2a"; - std::string expected2b("ABC\0ABC", 7); - pkt.set_qid(0x1234).set_response().set_aa() - .add_question(new DNSQuestion("example.com", ns_t_mx)) - .add_answer(new DNSTxtRR("example.com", 100, {expected1})) - .add_answer(new DNSTxtRR("example.com", 100, {expected2a, expected2b})); - std::vector<byte> data = pkt.data(); - - struct ares_txt_ext* txt = nullptr; - EXPECT_EQ(ARES_SUCCESS, ares_parse_txt_reply_ext(data.data(), data.size(), &txt)); - ASSERT_NE(nullptr, txt); - EXPECT_EQ(std::vector<byte>(expected1.data(), expected1.data() + expected1.size()), - std::vector<byte>(txt->txt, txt->txt + txt->length)); - EXPECT_EQ(1, txt->record_start); - - struct ares_txt_ext* txt2 = txt->next; - ASSERT_NE(nullptr, txt2); - EXPECT_EQ(std::vector<byte>(expected2a.data(), expected2a.data() + expected2a.size()), - std::vector<byte>(txt2->txt, txt2->txt + txt2->length)); - EXPECT_EQ(1, txt2->record_start); - - struct ares_txt_ext* txt3 = txt2->next; - ASSERT_NE(nullptr, txt3); - EXPECT_EQ(std::vector<byte>(expected2b.data(), expected2b.data() + expected2b.size()), - std::vector<byte>(txt3->txt, txt3->txt + txt3->length)); - EXPECT_EQ(nullptr, txt3->next); - EXPECT_EQ(0, txt3->record_start); - - ares_free_data(txt); -} - -TEST_F(LibraryTest, ParseTxtMalformedReply1) { - std::vector<byte> data = { - 0x12, 0x34, // qid - 0x84, // response + query + AA + not-TC + not-RD - 0x00, // not-RA + not-Z + not-AD + not-CD + rc=NoError - 0x00, 0x01, // num questions - 0x00, 0x01, // num answer RRs - 0x00, 0x00, // num authority RRs - 0x00, 0x00, // num additional RRs - // Question - 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', - 0x03, 'c', 'o', 'm', - 0x00, - 0x00, 0x10, // type TXT - 0x00, 0x01, // class IN - // Answer 1 - 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', - 0x03, 'c', 'o', 'm', - 0x00, - 0x00, 0x10, // RR type - 0x00, 0x01, // class IN - 0x01, 0x02, 0x03, 0x04, // TTL - 0x00, 0x03, // rdata length - 0x12, 'a', 'b', // invalid length - }; - - struct ares_txt_reply* txt = nullptr; - EXPECT_EQ(ARES_EBADRESP, ares_parse_txt_reply(data.data(), data.size(), &txt)); - ASSERT_EQ(nullptr, txt); -} - -TEST_F(LibraryTest, ParseTxtMalformedReply2) { - std::vector<byte> data = { - 0x12, 0x34, // qid - 0x84, // response + query + AA + not-TC + not-RD - 0x00, // not-RA + not-Z + not-AD + not-CD + rc=NoError - 0x00, 0x01, // num questions - 0x00, 0x01, // num answer RRs - 0x00, 0x00, // num authority RRs - 0x00, 0x00, // num additional RRs - // Question - 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', - 0x03, 'c', 'o', 'm', - 0x00, - 0x00, 0x10, // type TXT - 0x00, 0x01, // class IN - // Answer 1 - 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', - 0x03, 'c', 'o', 'm', - 0x00, - 0x00, 0x10, // RR type - // truncated - }; - - struct ares_txt_reply* txt = nullptr; - EXPECT_EQ(ARES_EBADRESP, ares_parse_txt_reply(data.data(), data.size(), &txt)); - ASSERT_EQ(nullptr, txt); -} - -TEST_F(LibraryTest, ParseTxtMalformedReply3) { - std::vector<byte> data = { - 0x12, 0x34, // qid - 0x84, // response + query + AA + not-TC + not-RD - 0x00, // not-RA + not-Z + not-AD + not-CD + rc=NoError - 0x00, 0x01, // num questions - 0x00, 0x01, // num answer RRs - 0x00, 0x00, // num authority RRs - 0x00, 0x00, // num additional RRs - // Question - 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', - 0x03, 'c', 'o', 'm', - 0x00, - 0x00, 0x10, // type TXT - 0x00, 0x01, // class IN - // Answer 1 - 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', - 0x03, 'c', 'o', 'm', - 0x00, - 0x00, 0x10, // RR type - 0x00, 0x01, // class IN - 0x01, 0x02, 0x03, 0x04, // TTL - 0x00, 0x13, // rdata length INVALID - 0x02, 'a', 'b', - }; - - struct ares_txt_reply* txt = nullptr; - EXPECT_EQ(ARES_EBADRESP, ares_parse_txt_reply(data.data(), data.size(), &txt)); - ASSERT_EQ(nullptr, txt); -} - -TEST_F(LibraryTest, ParseTxtMalformedReply4) { - std::vector<byte> data = { - 0x12, 0x34, // qid - 0x84, // response + query + AA + not-TC + not-RD - 0x00, // not-RA + not-Z + not-AD + not-CD + rc=NoError - 0x00, 0x01, // num questions - 0x00, 0x01, // num answer RRs - 0x00, 0x00, // num authority RRs - 0x00, 0x00, // num additional RRs - // Question - 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', - 0x03, 'c', 'o', 'm', - 0x00, - 0x00, 0x10, // type TXT - 0x00, // TRUNCATED - }; - - struct ares_txt_reply* txt = nullptr; - EXPECT_EQ(ARES_EBADRESP, ares_parse_txt_reply(data.data(), data.size(), &txt)); - ASSERT_EQ(nullptr, txt); -} - -TEST_F(LibraryTest, ParseTxtReplyErrors) { - DNSPacket pkt; - std::string expected1 = "txt1.example.com"; - std::string expected2a = "txt2a"; - std::string expected2b = "txt2b"; - pkt.set_qid(0x1234).set_response().set_aa() - .add_question(new DNSQuestion("example.com", ns_t_mx)) - .add_answer(new DNSTxtRR("example.com", 100, {expected1})) - .add_answer(new DNSTxtRR("example.com", 100, {expected1})) - .add_answer(new DNSTxtRR("example.com", 100, {expected2a, expected2b})); - std::vector<byte> data = pkt.data(); - struct ares_txt_reply* txt = nullptr; - - // No question. - pkt.questions_.clear(); - data = pkt.data(); - txt = nullptr; - EXPECT_EQ(ARES_EBADRESP, ares_parse_txt_reply(data.data(), data.size(), &txt)); - EXPECT_EQ(nullptr, txt); - pkt.add_question(new DNSQuestion("example.com", ns_t_mx)); - -#ifdef DISABLED - // Question != answer - pkt.questions_.clear(); - pkt.add_question(new DNSQuestion("Axample.com", ns_t_txt)); - data = pkt.data(); - EXPECT_EQ(ARES_ENODATA, ares_parse_txt_reply(data.data(), data.size(), &txt)); - pkt.questions_.clear(); - pkt.add_question(new DNSQuestion("example.com", ns_t_txt)); -#endif - - // Two questions. - pkt.add_question(new DNSQuestion("example.com", ns_t_mx)); - data = pkt.data(); - txt = nullptr; - EXPECT_EQ(ARES_EBADRESP, ares_parse_txt_reply(data.data(), data.size(), &txt)); - EXPECT_EQ(nullptr, txt); - pkt.questions_.clear(); - pkt.add_question(new DNSQuestion("example.com", ns_t_mx)); - - // No answer. - pkt.answers_.clear(); - data = pkt.data(); - txt = nullptr; - EXPECT_EQ(ARES_ENODATA, ares_parse_txt_reply(data.data(), data.size(), &txt)); - EXPECT_EQ(nullptr, txt); - pkt.add_answer(new DNSTxtRR("example.com", 100, {expected1})); - - // Truncated packets. - for (size_t len = 1; len < data.size(); len++) { - txt = nullptr; - EXPECT_NE(ARES_SUCCESS, ares_parse_txt_reply(data.data(), len, &txt)); - EXPECT_EQ(nullptr, txt); - } -} - -TEST_F(LibraryTest, ParseTxtReplyAllocFail) { - DNSPacket pkt; - std::string expected1 = "txt1.example.com"; - std::string expected2a = "txt2a"; - std::string expected2b = "txt2b"; - pkt.set_qid(0x1234).set_response().set_aa() - .add_question(new DNSQuestion("example.com", ns_t_mx)) - .add_answer(new DNSCnameRR("example.com", 300, "c.example.com")) - .add_answer(new DNSTxtRR("c.example.com", 100, {expected1})) - .add_answer(new DNSTxtRR("c.example.com", 100, {expected1})) - .add_answer(new DNSTxtRR("c.example.com", 100, {expected2a, expected2b})); - std::vector<byte> data = pkt.data(); - struct ares_txt_reply* txt = nullptr; - - for (int ii = 1; ii <= 13; ii++) { - ClearFails(); - SetAllocFail(ii); - EXPECT_EQ(ARES_ENOMEM, ares_parse_txt_reply(data.data(), data.size(), &txt)) << ii; - } -} - - -} // namespace test -} // namespace ares +#include "ares-test.h" +#include "dns-proto.h" + +#include <sstream> +#include <vector> + +namespace ares { +namespace test { + +TEST_F(LibraryTest, ParseTxtReplyOK) { + DNSPacket pkt; + std::string expected1 = "txt1.example.com"; + std::string expected2a = "txt2a"; + std::string expected2b("ABC\0ABC", 7); + pkt.set_qid(0x1234).set_response().set_aa() + .add_question(new DNSQuestion("example.com", ns_t_mx)) + .add_answer(new DNSTxtRR("example.com", 100, {expected1})) + .add_answer(new DNSTxtRR("example.com", 100, {expected2a, expected2b})); + std::vector<byte> data = pkt.data(); + + struct ares_txt_reply* txt = nullptr; + EXPECT_EQ(ARES_SUCCESS, ares_parse_txt_reply(data.data(), data.size(), &txt)); + ASSERT_NE(nullptr, txt); + EXPECT_EQ(std::vector<byte>(expected1.data(), expected1.data() + expected1.size()), + std::vector<byte>(txt->txt, txt->txt + txt->length)); + + struct ares_txt_reply* txt2 = txt->next; + ASSERT_NE(nullptr, txt2); + EXPECT_EQ(std::vector<byte>(expected2a.data(), expected2a.data() + expected2a.size()), + std::vector<byte>(txt2->txt, txt2->txt + txt2->length)); + + struct ares_txt_reply* txt3 = txt2->next; + ASSERT_NE(nullptr, txt3); + EXPECT_EQ(std::vector<byte>(expected2b.data(), expected2b.data() + expected2b.size()), + std::vector<byte>(txt3->txt, txt3->txt + txt3->length)); + EXPECT_EQ(nullptr, txt3->next); + + ares_free_data(txt); +} + +TEST_F(LibraryTest, ParseTxtExtReplyOK) { + DNSPacket pkt; + std::string expected1 = "txt1.example.com"; + std::string expected2a = "txt2a"; + std::string expected2b("ABC\0ABC", 7); + pkt.set_qid(0x1234).set_response().set_aa() + .add_question(new DNSQuestion("example.com", ns_t_mx)) + .add_answer(new DNSTxtRR("example.com", 100, {expected1})) + .add_answer(new DNSTxtRR("example.com", 100, {expected2a, expected2b})); + std::vector<byte> data = pkt.data(); + + struct ares_txt_ext* txt = nullptr; + EXPECT_EQ(ARES_SUCCESS, ares_parse_txt_reply_ext(data.data(), data.size(), &txt)); + ASSERT_NE(nullptr, txt); + EXPECT_EQ(std::vector<byte>(expected1.data(), expected1.data() + expected1.size()), + std::vector<byte>(txt->txt, txt->txt + txt->length)); + EXPECT_EQ(1, txt->record_start); + + struct ares_txt_ext* txt2 = txt->next; + ASSERT_NE(nullptr, txt2); + EXPECT_EQ(std::vector<byte>(expected2a.data(), expected2a.data() + expected2a.size()), + std::vector<byte>(txt2->txt, txt2->txt + txt2->length)); + EXPECT_EQ(1, txt2->record_start); + + struct ares_txt_ext* txt3 = txt2->next; + ASSERT_NE(nullptr, txt3); + EXPECT_EQ(std::vector<byte>(expected2b.data(), expected2b.data() + expected2b.size()), + std::vector<byte>(txt3->txt, txt3->txt + txt3->length)); + EXPECT_EQ(nullptr, txt3->next); + EXPECT_EQ(0, txt3->record_start); + + ares_free_data(txt); +} + +TEST_F(LibraryTest, ParseTxtMalformedReply1) { + std::vector<byte> data = { + 0x12, 0x34, // qid + 0x84, // response + query + AA + not-TC + not-RD + 0x00, // not-RA + not-Z + not-AD + not-CD + rc=NoError + 0x00, 0x01, // num questions + 0x00, 0x01, // num answer RRs + 0x00, 0x00, // num authority RRs + 0x00, 0x00, // num additional RRs + // Question + 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + 0x00, 0x10, // type TXT + 0x00, 0x01, // class IN + // Answer 1 + 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + 0x00, 0x10, // RR type + 0x00, 0x01, // class IN + 0x01, 0x02, 0x03, 0x04, // TTL + 0x00, 0x03, // rdata length + 0x12, 'a', 'b', // invalid length + }; + + struct ares_txt_reply* txt = nullptr; + EXPECT_EQ(ARES_EBADRESP, ares_parse_txt_reply(data.data(), data.size(), &txt)); + ASSERT_EQ(nullptr, txt); +} + +TEST_F(LibraryTest, ParseTxtMalformedReply2) { + std::vector<byte> data = { + 0x12, 0x34, // qid + 0x84, // response + query + AA + not-TC + not-RD + 0x00, // not-RA + not-Z + not-AD + not-CD + rc=NoError + 0x00, 0x01, // num questions + 0x00, 0x01, // num answer RRs + 0x00, 0x00, // num authority RRs + 0x00, 0x00, // num additional RRs + // Question + 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + 0x00, 0x10, // type TXT + 0x00, 0x01, // class IN + // Answer 1 + 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + 0x00, 0x10, // RR type + // truncated + }; + + struct ares_txt_reply* txt = nullptr; + EXPECT_EQ(ARES_EBADRESP, ares_parse_txt_reply(data.data(), data.size(), &txt)); + ASSERT_EQ(nullptr, txt); +} + +TEST_F(LibraryTest, ParseTxtMalformedReply3) { + std::vector<byte> data = { + 0x12, 0x34, // qid + 0x84, // response + query + AA + not-TC + not-RD + 0x00, // not-RA + not-Z + not-AD + not-CD + rc=NoError + 0x00, 0x01, // num questions + 0x00, 0x01, // num answer RRs + 0x00, 0x00, // num authority RRs + 0x00, 0x00, // num additional RRs + // Question + 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + 0x00, 0x10, // type TXT + 0x00, 0x01, // class IN + // Answer 1 + 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + 0x00, 0x10, // RR type + 0x00, 0x01, // class IN + 0x01, 0x02, 0x03, 0x04, // TTL + 0x00, 0x13, // rdata length INVALID + 0x02, 'a', 'b', + }; + + struct ares_txt_reply* txt = nullptr; + EXPECT_EQ(ARES_EBADRESP, ares_parse_txt_reply(data.data(), data.size(), &txt)); + ASSERT_EQ(nullptr, txt); +} + +TEST_F(LibraryTest, ParseTxtMalformedReply4) { + std::vector<byte> data = { + 0x12, 0x34, // qid + 0x84, // response + query + AA + not-TC + not-RD + 0x00, // not-RA + not-Z + not-AD + not-CD + rc=NoError + 0x00, 0x01, // num questions + 0x00, 0x01, // num answer RRs + 0x00, 0x00, // num authority RRs + 0x00, 0x00, // num additional RRs + // Question + 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + 0x00, 0x10, // type TXT + 0x00, // TRUNCATED + }; + + struct ares_txt_reply* txt = nullptr; + EXPECT_EQ(ARES_EBADRESP, ares_parse_txt_reply(data.data(), data.size(), &txt)); + ASSERT_EQ(nullptr, txt); +} + +TEST_F(LibraryTest, ParseTxtReplyErrors) { + DNSPacket pkt; + std::string expected1 = "txt1.example.com"; + std::string expected2a = "txt2a"; + std::string expected2b = "txt2b"; + pkt.set_qid(0x1234).set_response().set_aa() + .add_question(new DNSQuestion("example.com", ns_t_mx)) + .add_answer(new DNSTxtRR("example.com", 100, {expected1})) + .add_answer(new DNSTxtRR("example.com", 100, {expected1})) + .add_answer(new DNSTxtRR("example.com", 100, {expected2a, expected2b})); + std::vector<byte> data = pkt.data(); + struct ares_txt_reply* txt = nullptr; + + // No question. + pkt.questions_.clear(); + data = pkt.data(); + txt = nullptr; + EXPECT_EQ(ARES_EBADRESP, ares_parse_txt_reply(data.data(), data.size(), &txt)); + EXPECT_EQ(nullptr, txt); + pkt.add_question(new DNSQuestion("example.com", ns_t_mx)); + +#ifdef DISABLED + // Question != answer + pkt.questions_.clear(); + pkt.add_question(new DNSQuestion("Axample.com", ns_t_txt)); + data = pkt.data(); + EXPECT_EQ(ARES_ENODATA, ares_parse_txt_reply(data.data(), data.size(), &txt)); + pkt.questions_.clear(); + pkt.add_question(new DNSQuestion("example.com", ns_t_txt)); +#endif + + // Two questions. + pkt.add_question(new DNSQuestion("example.com", ns_t_mx)); + data = pkt.data(); + txt = nullptr; + EXPECT_EQ(ARES_EBADRESP, ares_parse_txt_reply(data.data(), data.size(), &txt)); + EXPECT_EQ(nullptr, txt); + pkt.questions_.clear(); + pkt.add_question(new DNSQuestion("example.com", ns_t_mx)); + + // No answer. + pkt.answers_.clear(); + data = pkt.data(); + txt = nullptr; + EXPECT_EQ(ARES_ENODATA, ares_parse_txt_reply(data.data(), data.size(), &txt)); + EXPECT_EQ(nullptr, txt); + pkt.add_answer(new DNSTxtRR("example.com", 100, {expected1})); + + // Truncated packets. + for (size_t len = 1; len < data.size(); len++) { + txt = nullptr; + EXPECT_NE(ARES_SUCCESS, ares_parse_txt_reply(data.data(), len, &txt)); + EXPECT_EQ(nullptr, txt); + } +} + +TEST_F(LibraryTest, ParseTxtReplyAllocFail) { + DNSPacket pkt; + std::string expected1 = "txt1.example.com"; + std::string expected2a = "txt2a"; + std::string expected2b = "txt2b"; + pkt.set_qid(0x1234).set_response().set_aa() + .add_question(new DNSQuestion("example.com", ns_t_mx)) + .add_answer(new DNSCnameRR("example.com", 300, "c.example.com")) + .add_answer(new DNSTxtRR("c.example.com", 100, {expected1})) + .add_answer(new DNSTxtRR("c.example.com", 100, {expected1})) + .add_answer(new DNSTxtRR("c.example.com", 100, {expected2a, expected2b})); + std::vector<byte> data = pkt.data(); + struct ares_txt_reply* txt = nullptr; + + for (int ii = 1; ii <= 13; ii++) { + ClearFails(); + SetAllocFail(ii); + EXPECT_EQ(ARES_ENOMEM, ares_parse_txt_reply(data.data(), data.size(), &txt)) << ii; + } +} + + +} // namespace test +} // namespace ares diff --git a/contrib/libs/c-ares/test/ares-test-parse.cc b/contrib/libs/c-ares/test/ares-test-parse.cc index 95744c3eb5..4c54fc9902 100644 --- a/contrib/libs/c-ares/test/ares-test-parse.cc +++ b/contrib/libs/c-ares/test/ares-test-parse.cc @@ -1,219 +1,219 @@ -#include "ares-test.h" -#include "dns-proto.h" - -#include <sstream> -#include <vector> - -namespace ares { -namespace test { - -TEST_F(LibraryTest, ParseRootName) { - DNSPacket pkt; - pkt.set_qid(0x1234).set_response().set_aa() - .add_question(new DNSQuestion(".", ns_t_a)) - .add_answer(new DNSARR(".", 100, {0x02, 0x03, 0x04, 0x05})); - std::vector<byte> data = pkt.data(); - - struct hostent *host = nullptr; - struct ares_addrttl info[2]; - int count = 2; - EXPECT_EQ(ARES_SUCCESS, ares_parse_a_reply(data.data(), data.size(), - &host, info, &count)); - EXPECT_EQ(1, count); - std::stringstream ss; - ss << HostEnt(host); - EXPECT_EQ("{'' aliases=[] addrs=[2.3.4.5]}", ss.str()); - ares_free_hostent(host); -} - -TEST_F(LibraryTest, ParseIndirectRootName) { - std::vector<byte> data = { - 0x12, 0x34, // qid - 0x84, // response + query + AA + not-TC + not-RD - 0x00, // not-RA + not-Z + not-AD + not-CD + rc=NoError - 0x00, 0x01, // num questions - 0x00, 0x01, // num answer RRs - 0x00, 0x00, // num authority RRs - 0x00, 0x00, // num additional RRs - // Question - 0xC0, 0x04, // weird: pointer to a random zero earlier in the message - 0x00, 0x01, // type A - 0x00, 0x01, // class IN - // Answer 1 - 0xC0, 0x04, - 0x00, 0x01, // RR type - 0x00, 0x01, // class IN - 0x01, 0x02, 0x03, 0x04, // TTL - 0x00, 0x04, // rdata length - 0x02, 0x03, 0x04, 0x05, - }; - - struct hostent *host = nullptr; - struct ares_addrttl info[2]; - int count = 2; - EXPECT_EQ(ARES_SUCCESS, ares_parse_a_reply(data.data(), data.size(), - &host, info, &count)); - EXPECT_EQ(1, count); - std::stringstream ss; - ss << HostEnt(host); - EXPECT_EQ("{'' aliases=[] addrs=[2.3.4.5]}", ss.str()); - ares_free_hostent(host); -} - -TEST_F(LibraryTest, ParseEscapedName) { - std::vector<byte> data = { - 0x12, 0x34, // qid - 0x84, // response + query + AA + not-TC + not-RD - 0x00, // not-RA + not-Z + not-AD + not-CD + rc=NoError - 0x00, 0x01, // num questions - 0x00, 0x01, // num answer RRs - 0x00, 0x00, // num authority RRs - 0x00, 0x00, // num additional RRs - // Question - 0x05, 'a', '\\', 'b', '.', 'c', - 0x03, 'c', 'o', 'm', - 0x00, - 0x00, 0x01, // type A - 0x00, 0x01, // class IN - // Answer 1 - 0x05, 'a', '\\', 'b', '.', 'c', - 0x03, 'c', 'o', 'm', - 0x00, - 0x00, 0x01, // RR type - 0x00, 0x01, // class IN - 0x01, 0x02, 0x03, 0x04, // TTL - 0x00, 0x04, // rdata length - 0x02, 0x03, 0x04, 0x05, - }; - struct hostent *host = nullptr; - struct ares_addrttl info[2]; - int count = 2; - EXPECT_EQ(ARES_SUCCESS, ares_parse_a_reply(data.data(), data.size(), - &host, info, &count)); - EXPECT_EQ(1, count); - HostEnt hent(host); - std::stringstream ss; - ss << hent; - // The printable name is expanded with escapes. - EXPECT_EQ(11, hent.name_.size()); - EXPECT_EQ('a', hent.name_[0]); - EXPECT_EQ('\\', hent.name_[1]); - EXPECT_EQ('\\', hent.name_[2]); - EXPECT_EQ('b', hent.name_[3]); - EXPECT_EQ('\\', hent.name_[4]); - EXPECT_EQ('.', hent.name_[5]); - EXPECT_EQ('c', hent.name_[6]); - ares_free_hostent(host); -} - -TEST_F(LibraryTest, ParsePartialCompressedName) { - std::vector<byte> data = { - 0x12, 0x34, // qid - 0x84, // response + query + AA + not-TC + not-RD - 0x00, // not-RA + not-Z + not-AD + not-CD + rc=NoError - 0x00, 0x01, // num questions - 0x00, 0x01, // num answer RRs - 0x00, 0x00, // num authority RRs - 0x00, 0x00, // num additional RRs - // Question - 0x03, 'w', 'w', 'w', - 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', - 0x03, 'c', 'o', 'm', - 0x00, - 0x00, 0x01, // type A - 0x00, 0x01, // class IN - // Answer 1 - 0x03, 'w', 'w', 'w', - 0xc0, 0x10, // offset 16 - 0x00, 0x01, // RR type - 0x00, 0x01, // class IN - 0x01, 0x02, 0x03, 0x04, // TTL - 0x00, 0x04, // rdata length - 0x02, 0x03, 0x04, 0x05, - }; - struct hostent *host = nullptr; - struct ares_addrttl info[2]; - int count = 2; - EXPECT_EQ(ARES_SUCCESS, ares_parse_a_reply(data.data(), data.size(), - &host, info, &count)); - ASSERT_NE(nullptr, host); - std::stringstream ss; - ss << HostEnt(host); - EXPECT_EQ("{'www.example.com' aliases=[] addrs=[2.3.4.5]}", ss.str()); - ares_free_hostent(host); -} - -TEST_F(LibraryTest, ParseFullyCompressedName) { - std::vector<byte> data = { - 0x12, 0x34, // qid - 0x84, // response + query + AA + not-TC + not-RD - 0x00, // not-RA + not-Z + not-AD + not-CD + rc=NoError - 0x00, 0x01, // num questions - 0x00, 0x01, // num answer RRs - 0x00, 0x00, // num authority RRs - 0x00, 0x00, // num additional RRs - // Question - 0x03, 'w', 'w', 'w', - 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', - 0x03, 'c', 'o', 'm', - 0x00, - 0x00, 0x01, // type A - 0x00, 0x01, // class IN - // Answer 1 - 0xc0, 0x0c, // offset 12 - 0x00, 0x01, // RR type - 0x00, 0x01, // class IN - 0x01, 0x02, 0x03, 0x04, // TTL - 0x00, 0x04, // rdata length - 0x02, 0x03, 0x04, 0x05, - }; - struct hostent *host = nullptr; - struct ares_addrttl info[2]; - int count = 2; - EXPECT_EQ(ARES_SUCCESS, ares_parse_a_reply(data.data(), data.size(), - &host, info, &count)); - ASSERT_NE(nullptr, host); - std::stringstream ss; - ss << HostEnt(host); - EXPECT_EQ("{'www.example.com' aliases=[] addrs=[2.3.4.5]}", ss.str()); - ares_free_hostent(host); -} - -TEST_F(LibraryTest, ParseFullyCompressedName2) { - std::vector<byte> data = { - 0x12, 0x34, // qid - 0x84, // response + query + AA + not-TC + not-RD - 0x00, // not-RA + not-Z + not-AD + not-CD + rc=NoError - 0x00, 0x01, // num questions - 0x00, 0x01, // num answer RRs - 0x00, 0x00, // num authority RRs - 0x00, 0x00, // num additional RRs - // Question - 0xC0, 0x12, // pointer to later in message - 0x00, 0x01, // type A - 0x00, 0x01, // class IN - // Answer 1 - 0x03, 'w', 'w', 'w', - 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', - 0x03, 'c', 'o', 'm', - 0x00, - 0x00, 0x01, // RR type - 0x00, 0x01, // class IN - 0x01, 0x02, 0x03, 0x04, // TTL - 0x00, 0x04, // rdata length - 0x02, 0x03, 0x04, 0x05, - }; - struct hostent *host = nullptr; - struct ares_addrttl info[2]; - int count = 2; - EXPECT_EQ(ARES_SUCCESS, ares_parse_a_reply(data.data(), data.size(), - &host, info, &count)); - ASSERT_NE(nullptr, host); - std::stringstream ss; - ss << HostEnt(host); - EXPECT_EQ("{'www.example.com' aliases=[] addrs=[2.3.4.5]}", ss.str()); - ares_free_hostent(host); -} - -} // namespace test -} // namespace ares +#include "ares-test.h" +#include "dns-proto.h" + +#include <sstream> +#include <vector> + +namespace ares { +namespace test { + +TEST_F(LibraryTest, ParseRootName) { + DNSPacket pkt; + pkt.set_qid(0x1234).set_response().set_aa() + .add_question(new DNSQuestion(".", ns_t_a)) + .add_answer(new DNSARR(".", 100, {0x02, 0x03, 0x04, 0x05})); + std::vector<byte> data = pkt.data(); + + struct hostent *host = nullptr; + struct ares_addrttl info[2]; + int count = 2; + EXPECT_EQ(ARES_SUCCESS, ares_parse_a_reply(data.data(), data.size(), + &host, info, &count)); + EXPECT_EQ(1, count); + std::stringstream ss; + ss << HostEnt(host); + EXPECT_EQ("{'' aliases=[] addrs=[2.3.4.5]}", ss.str()); + ares_free_hostent(host); +} + +TEST_F(LibraryTest, ParseIndirectRootName) { + std::vector<byte> data = { + 0x12, 0x34, // qid + 0x84, // response + query + AA + not-TC + not-RD + 0x00, // not-RA + not-Z + not-AD + not-CD + rc=NoError + 0x00, 0x01, // num questions + 0x00, 0x01, // num answer RRs + 0x00, 0x00, // num authority RRs + 0x00, 0x00, // num additional RRs + // Question + 0xC0, 0x04, // weird: pointer to a random zero earlier in the message + 0x00, 0x01, // type A + 0x00, 0x01, // class IN + // Answer 1 + 0xC0, 0x04, + 0x00, 0x01, // RR type + 0x00, 0x01, // class IN + 0x01, 0x02, 0x03, 0x04, // TTL + 0x00, 0x04, // rdata length + 0x02, 0x03, 0x04, 0x05, + }; + + struct hostent *host = nullptr; + struct ares_addrttl info[2]; + int count = 2; + EXPECT_EQ(ARES_SUCCESS, ares_parse_a_reply(data.data(), data.size(), + &host, info, &count)); + EXPECT_EQ(1, count); + std::stringstream ss; + ss << HostEnt(host); + EXPECT_EQ("{'' aliases=[] addrs=[2.3.4.5]}", ss.str()); + ares_free_hostent(host); +} + +TEST_F(LibraryTest, ParseEscapedName) { + std::vector<byte> data = { + 0x12, 0x34, // qid + 0x84, // response + query + AA + not-TC + not-RD + 0x00, // not-RA + not-Z + not-AD + not-CD + rc=NoError + 0x00, 0x01, // num questions + 0x00, 0x01, // num answer RRs + 0x00, 0x00, // num authority RRs + 0x00, 0x00, // num additional RRs + // Question + 0x05, 'a', '\\', 'b', '.', 'c', + 0x03, 'c', 'o', 'm', + 0x00, + 0x00, 0x01, // type A + 0x00, 0x01, // class IN + // Answer 1 + 0x05, 'a', '\\', 'b', '.', 'c', + 0x03, 'c', 'o', 'm', + 0x00, + 0x00, 0x01, // RR type + 0x00, 0x01, // class IN + 0x01, 0x02, 0x03, 0x04, // TTL + 0x00, 0x04, // rdata length + 0x02, 0x03, 0x04, 0x05, + }; + struct hostent *host = nullptr; + struct ares_addrttl info[2]; + int count = 2; + EXPECT_EQ(ARES_SUCCESS, ares_parse_a_reply(data.data(), data.size(), + &host, info, &count)); + EXPECT_EQ(1, count); + HostEnt hent(host); + std::stringstream ss; + ss << hent; + // The printable name is expanded with escapes. + EXPECT_EQ(11, hent.name_.size()); + EXPECT_EQ('a', hent.name_[0]); + EXPECT_EQ('\\', hent.name_[1]); + EXPECT_EQ('\\', hent.name_[2]); + EXPECT_EQ('b', hent.name_[3]); + EXPECT_EQ('\\', hent.name_[4]); + EXPECT_EQ('.', hent.name_[5]); + EXPECT_EQ('c', hent.name_[6]); + ares_free_hostent(host); +} + +TEST_F(LibraryTest, ParsePartialCompressedName) { + std::vector<byte> data = { + 0x12, 0x34, // qid + 0x84, // response + query + AA + not-TC + not-RD + 0x00, // not-RA + not-Z + not-AD + not-CD + rc=NoError + 0x00, 0x01, // num questions + 0x00, 0x01, // num answer RRs + 0x00, 0x00, // num authority RRs + 0x00, 0x00, // num additional RRs + // Question + 0x03, 'w', 'w', 'w', + 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + 0x00, 0x01, // type A + 0x00, 0x01, // class IN + // Answer 1 + 0x03, 'w', 'w', 'w', + 0xc0, 0x10, // offset 16 + 0x00, 0x01, // RR type + 0x00, 0x01, // class IN + 0x01, 0x02, 0x03, 0x04, // TTL + 0x00, 0x04, // rdata length + 0x02, 0x03, 0x04, 0x05, + }; + struct hostent *host = nullptr; + struct ares_addrttl info[2]; + int count = 2; + EXPECT_EQ(ARES_SUCCESS, ares_parse_a_reply(data.data(), data.size(), + &host, info, &count)); + ASSERT_NE(nullptr, host); + std::stringstream ss; + ss << HostEnt(host); + EXPECT_EQ("{'www.example.com' aliases=[] addrs=[2.3.4.5]}", ss.str()); + ares_free_hostent(host); +} + +TEST_F(LibraryTest, ParseFullyCompressedName) { + std::vector<byte> data = { + 0x12, 0x34, // qid + 0x84, // response + query + AA + not-TC + not-RD + 0x00, // not-RA + not-Z + not-AD + not-CD + rc=NoError + 0x00, 0x01, // num questions + 0x00, 0x01, // num answer RRs + 0x00, 0x00, // num authority RRs + 0x00, 0x00, // num additional RRs + // Question + 0x03, 'w', 'w', 'w', + 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + 0x00, 0x01, // type A + 0x00, 0x01, // class IN + // Answer 1 + 0xc0, 0x0c, // offset 12 + 0x00, 0x01, // RR type + 0x00, 0x01, // class IN + 0x01, 0x02, 0x03, 0x04, // TTL + 0x00, 0x04, // rdata length + 0x02, 0x03, 0x04, 0x05, + }; + struct hostent *host = nullptr; + struct ares_addrttl info[2]; + int count = 2; + EXPECT_EQ(ARES_SUCCESS, ares_parse_a_reply(data.data(), data.size(), + &host, info, &count)); + ASSERT_NE(nullptr, host); + std::stringstream ss; + ss << HostEnt(host); + EXPECT_EQ("{'www.example.com' aliases=[] addrs=[2.3.4.5]}", ss.str()); + ares_free_hostent(host); +} + +TEST_F(LibraryTest, ParseFullyCompressedName2) { + std::vector<byte> data = { + 0x12, 0x34, // qid + 0x84, // response + query + AA + not-TC + not-RD + 0x00, // not-RA + not-Z + not-AD + not-CD + rc=NoError + 0x00, 0x01, // num questions + 0x00, 0x01, // num answer RRs + 0x00, 0x00, // num authority RRs + 0x00, 0x00, // num additional RRs + // Question + 0xC0, 0x12, // pointer to later in message + 0x00, 0x01, // type A + 0x00, 0x01, // class IN + // Answer 1 + 0x03, 'w', 'w', 'w', + 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + 0x00, 0x01, // RR type + 0x00, 0x01, // class IN + 0x01, 0x02, 0x03, 0x04, // TTL + 0x00, 0x04, // rdata length + 0x02, 0x03, 0x04, 0x05, + }; + struct hostent *host = nullptr; + struct ares_addrttl info[2]; + int count = 2; + EXPECT_EQ(ARES_SUCCESS, ares_parse_a_reply(data.data(), data.size(), + &host, info, &count)); + ASSERT_NE(nullptr, host); + std::stringstream ss; + ss << HostEnt(host); + EXPECT_EQ("{'www.example.com' aliases=[] addrs=[2.3.4.5]}", ss.str()); + ares_free_hostent(host); +} + +} // namespace test +} // namespace ares diff --git a/contrib/libs/c-ares/test/ares-test.cc b/contrib/libs/c-ares/test/ares-test.cc index 90d05013f0..ec4b460549 100644 --- a/contrib/libs/c-ares/test/ares-test.cc +++ b/contrib/libs/c-ares/test/ares-test.cc @@ -1,570 +1,570 @@ -#include "ares-test.h" +#include "ares-test.h" #include "ares-test-ai.h" -#include "dns-proto.h" - -// Include ares internal files for DNS protocol details -#include "nameser.h" -#include "ares_dns.h" - -#ifdef HAVE_NETDB_H -#include <netdb.h> -#endif -#ifdef HAVE_NETINET_TCP_H -#include <netinet/tcp.h> -#endif -#include <stdio.h> -#include <stdlib.h> - -#include <functional> -#include <sstream> - -#ifdef WIN32 -#define BYTE_CAST (char *) -#define mkdir_(d, p) mkdir(d) -#else -#define BYTE_CAST -#define mkdir_(d, p) mkdir(d, p) -#endif - -namespace ares { -namespace test { - -bool verbose = false; -int mock_port = 5300; - -const std::vector<int> both_families = {AF_INET, AF_INET6}; -const std::vector<int> ipv4_family = {AF_INET}; -const std::vector<int> ipv6_family = {AF_INET6}; - -const std::vector<std::pair<int, bool>> both_families_both_modes = { - std::make_pair<int, bool>(AF_INET, false), - std::make_pair<int, bool>(AF_INET, true), - std::make_pair<int, bool>(AF_INET6, false), - std::make_pair<int, bool>(AF_INET6, true) -}; -const std::vector<std::pair<int, bool>> ipv4_family_both_modes = { - std::make_pair<int, bool>(AF_INET, false), - std::make_pair<int, bool>(AF_INET, true) -}; -const std::vector<std::pair<int, bool>> ipv6_family_both_modes = { - std::make_pair<int, bool>(AF_INET6, false), - std::make_pair<int, bool>(AF_INET6, true) -}; - -// Which parameters to use in tests -std::vector<int> families = both_families; -std::vector<std::pair<int, bool>> families_modes = both_families_both_modes; - -unsigned long long LibraryTest::fails_ = 0; -std::map<size_t, int> LibraryTest::size_fails_; - -void ProcessWork(ares_channel channel, - std::function<std::set<int>()> get_extrafds, - std::function<void(int)> process_extra) { - int nfds, count; - fd_set readers, writers; - struct timeval tv; - while (true) { - // Retrieve the set of file descriptors that the library wants us to monitor. - FD_ZERO(&readers); - FD_ZERO(&writers); - nfds = ares_fds(channel, &readers, &writers); - if (nfds == 0) // no work left to do in the library - return; - - // Add in the extra FDs if present. - std::set<int> extrafds = get_extrafds(); - for (int extrafd : extrafds) { - FD_SET(extrafd, &readers); - if (extrafd >= nfds) { - nfds = extrafd + 1; - } - } - - // Wait for activity or timeout. - tv.tv_sec = 0; - tv.tv_usec = 100000; // 100ms - count = select(nfds, &readers, &writers, nullptr, &tv); - if (count < 0) { - fprintf(stderr, "select() failed, errno %d\n", errno); - return; - } - - // Let the library process any activity. - ares_process(channel, &readers, &writers); - - // Let the provided callback process any activity on the extra FD. - for (int extrafd : extrafds) { - if (FD_ISSET(extrafd, &readers)) { - process_extra(extrafd); - } - } - } -} - -// static -void LibraryTest::SetAllocFail(int nth) { - assert(nth > 0); - assert(nth <= (int)(8 * sizeof(fails_))); - fails_ |= (1LL << (nth - 1)); -} - -// static -void LibraryTest::SetAllocSizeFail(size_t size) { - size_fails_[size]++; -} - -// static -void LibraryTest::ClearFails() { - fails_ = 0; - size_fails_.clear(); -} - - -// static -bool LibraryTest::ShouldAllocFail(size_t size) { - bool fail = (fails_ & 0x01); - fails_ >>= 1; - if (size_fails_[size] > 0) { - size_fails_[size]--; - fail = true; - } - return fail; -} - -// static -void* LibraryTest::amalloc(size_t size) { - if (ShouldAllocFail(size)) { - if (verbose) std::cerr << "Failing malloc(" << size << ") request" << std::endl; - return nullptr; - } else { - return malloc(size); - } -} - -// static -void* LibraryTest::arealloc(void *ptr, size_t size) { - if (ShouldAllocFail(size)) { - if (verbose) std::cerr << "Failing realloc(" << ptr << ", " << size << ") request" << std::endl; - return nullptr; - } else { - return realloc(ptr, size); - } -} - -// static -void LibraryTest::afree(void *ptr) { - free(ptr); -} - -std::set<int> NoExtraFDs() { - return std::set<int>(); -} - -void DefaultChannelTest::Process() { - ProcessWork(channel_, NoExtraFDs, nullptr); -} - -void DefaultChannelModeTest::Process() { - ProcessWork(channel_, NoExtraFDs, nullptr); -} - -MockServer::MockServer(int family, int port, int tcpport) - : udpport_(port), tcpport_(tcpport ? tcpport : udpport_), qid_(-1) { - // Create a TCP socket to receive data on. - tcpfd_ = socket(family, SOCK_STREAM, 0); - EXPECT_NE(-1, tcpfd_); - int optval = 1; - setsockopt(tcpfd_, SOL_SOCKET, SO_REUSEADDR, - BYTE_CAST &optval , sizeof(int)); - // Send TCP data right away. - setsockopt(tcpfd_, IPPROTO_TCP, TCP_NODELAY, - BYTE_CAST &optval , sizeof(int)); - - // Create a UDP socket to receive data on. - udpfd_ = socket(family, SOCK_DGRAM, 0); - EXPECT_NE(-1, udpfd_); - - // Bind the sockets to the given port. - if (family == AF_INET) { - struct sockaddr_in addr; - memset(&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_addr.s_addr = htonl(INADDR_ANY); - addr.sin_port = htons(tcpport_); - int tcprc = bind(tcpfd_, (struct sockaddr*)&addr, sizeof(addr)); - EXPECT_EQ(0, tcprc) << "Failed to bind AF_INET to TCP port " << tcpport_; - addr.sin_port = htons(udpport_); - int udprc = bind(udpfd_, (struct sockaddr*)&addr, sizeof(addr)); - EXPECT_EQ(0, udprc) << "Failed to bind AF_INET to UDP port " << udpport_; - } else { - EXPECT_EQ(AF_INET6, family); - struct sockaddr_in6 addr; - memset(&addr, 0, sizeof(addr)); - addr.sin6_family = AF_INET6; - memset(&addr.sin6_addr, 0, sizeof(addr.sin6_addr)); // in6addr_any - addr.sin6_port = htons(tcpport_); - int tcprc = bind(tcpfd_, (struct sockaddr*)&addr, sizeof(addr)); - EXPECT_EQ(0, tcprc) << "Failed to bind AF_INET6 to TCP port " << tcpport_; - addr.sin6_port = htons(udpport_); - int udprc = bind(udpfd_, (struct sockaddr*)&addr, sizeof(addr)); - EXPECT_EQ(0, udprc) << "Failed to bind AF_INET6 to UDP port " << udpport_; - } - if (verbose) std::cerr << "Configured " - << (family == AF_INET ? "IPv4" : "IPv6") - << " mock server with TCP socket " << tcpfd_ - << " on port " << tcpport_ - << " and UDP socket " << udpfd_ - << " on port " << udpport_ << std::endl; - - // For TCP, also need to listen for connections. - EXPECT_EQ(0, listen(tcpfd_, 5)) << "Failed to listen for TCP connections"; -} - -MockServer::~MockServer() { - for (int fd : connfds_) { - sclose(fd); - } - sclose(tcpfd_); - sclose(udpfd_); -} - -void MockServer::ProcessFD(int fd) { - if (fd != tcpfd_ && fd != udpfd_ && connfds_.find(fd) == connfds_.end()) { - // Not one of our FDs. - return; - } - if (fd == tcpfd_) { - int connfd = accept(tcpfd_, NULL, NULL); - if (connfd < 0) { - std::cerr << "Error accepting connection on fd " << fd << std::endl; - } else { - connfds_.insert(connfd); - } - return; - } - - // Activity on a data-bearing file descriptor. - struct sockaddr_storage addr; - socklen_t addrlen = sizeof(addr); - byte buffer[2048]; - int len = recvfrom(fd, BYTE_CAST buffer, sizeof(buffer), 0, - (struct sockaddr *)&addr, &addrlen); - byte* data = buffer; - if (fd != udpfd_) { - if (len == 0) { - connfds_.erase(std::find(connfds_.begin(), connfds_.end(), fd)); - sclose(fd); - return; - } - if (len < 2) { - std::cerr << "Packet too short (" << len << ")" << std::endl; - return; - } - int tcplen = (data[0] << 8) + data[1]; - data += 2; - len -= 2; - if (tcplen != len) { - std::cerr << "Warning: TCP length " << tcplen - << " doesn't match remaining data length " << len << std::endl; - } - } - - // Assume the packet is a well-formed DNS request and extract the request - // details. - if (len < NS_HFIXEDSZ) { - std::cerr << "Packet too short (" << len << ")" << std::endl; - return; - } - int qid = DNS_HEADER_QID(data); - if (DNS_HEADER_QR(data) != 0) { - std::cerr << "Not a request" << std::endl; - return; - } - if (DNS_HEADER_OPCODE(data) != ns_o_query) { - std::cerr << "Not a query (opcode " << DNS_HEADER_OPCODE(data) - << ")" << std::endl; - return; - } - if (DNS_HEADER_QDCOUNT(data) != 1) { - std::cerr << "Unexpected question count (" << DNS_HEADER_QDCOUNT(data) - << ")" << std::endl; - return; - } - byte* question = data + 12; - int qlen = len - 12; - - char *name = nullptr; - long enclen; - ares_expand_name(question, data, len, &name, &enclen); - if (!name) { - std::cerr << "Failed to retrieve name" << std::endl; - return; - } - qlen -= enclen; - question += enclen; - std::string namestr(name); - ares_free_string(name); - - if (qlen < 4) { - std::cerr << "Unexpected question size (" << qlen - << " bytes after name)" << std::endl; - return; - } - if (DNS_QUESTION_CLASS(question) != ns_c_in) { - std::cerr << "Unexpected question class (" << DNS_QUESTION_CLASS(question) - << ")" << std::endl; - return; - } - int rrtype = DNS_QUESTION_TYPE(question); - - if (verbose) { - std::vector<byte> req(data, data + len); - std::cerr << "received " << (fd == udpfd_ ? "UDP" : "TCP") << " request " << PacketToString(req) - << " on port " << (fd == udpfd_ ? udpport_ : tcpport_) << std::endl; - std::cerr << "ProcessRequest(" << qid << ", '" << namestr - << "', " << RRTypeToString(rrtype) << ")" << std::endl; - } - ProcessRequest(fd, &addr, addrlen, qid, namestr, rrtype); -} - -std::set<int> MockServer::fds() const { - std::set<int> result = connfds_; - result.insert(tcpfd_); - result.insert(udpfd_); - return result; -} - -void MockServer::ProcessRequest(int fd, struct sockaddr_storage* addr, int addrlen, - int qid, const std::string& name, int rrtype) { - // Before processing, let gMock know the request is happening. - OnRequest(name, rrtype); - - if (reply_.size() == 0) { - return; - } - - // Make a local copy of the current pending reply. - std::vector<byte> reply = reply_; - - if (qid_ >= 0) { - // Use the explicitly specified query ID. - qid = qid_; - } - if (reply.size() >= 2) { - // Overwrite the query ID if space to do so. - reply[0] = (byte)((qid >> 8) & 0xff); - reply[1] = (byte)(qid & 0xff); - } - if (verbose) std::cerr << "sending reply " << PacketToString(reply) - << " on port " << ((fd == udpfd_) ? udpport_ : tcpport_) << std::endl; - - // Prefix with 2-byte length if TCP. - if (fd != udpfd_) { - int len = reply.size(); - std::vector<byte> vlen = {(byte)((len & 0xFF00) >> 8), (byte)(len & 0xFF)}; - reply.insert(reply.begin(), vlen.begin(), vlen.end()); - // Also, don't bother with the destination address. - addr = nullptr; - addrlen = 0; - } - - int rc = sendto(fd, BYTE_CAST reply.data(), reply.size(), 0, - (struct sockaddr *)addr, addrlen); - if (rc < static_cast<int>(reply.size())) { - std::cerr << "Failed to send full reply, rc=" << rc << std::endl; - } -} - -// static -MockChannelOptsTest::NiceMockServers MockChannelOptsTest::BuildServers(int count, int family, int base_port) { - NiceMockServers servers; - assert(count > 0); - for (int ii = 0; ii < count; ii++) { - std::unique_ptr<NiceMockServer> server(new NiceMockServer(family, base_port + ii)); - servers.push_back(std::move(server)); - } - return servers; -} - -MockChannelOptsTest::MockChannelOptsTest(int count, - int family, - bool force_tcp, - struct ares_options* givenopts, - int optmask) - : servers_(BuildServers(count, family, mock_port)), - server_(*servers_[0].get()), channel_(nullptr) { - // Set up channel options. - struct ares_options opts; - if (givenopts) { - memcpy(&opts, givenopts, sizeof(opts)); - } else { - memset(&opts, 0, sizeof(opts)); - } - - // Point the library at the first mock server by default (overridden below). - opts.udp_port = mock_port; - optmask |= ARES_OPT_UDP_PORT; - opts.tcp_port = mock_port; - optmask |= ARES_OPT_TCP_PORT; - - // If not already overridden, set short-ish timeouts. - if (!(optmask & (ARES_OPT_TIMEOUTMS|ARES_OPT_TIMEOUT))) { - opts.timeout = 1500; - optmask |= ARES_OPT_TIMEOUTMS; - } - // If not already overridden, set 3 retries. - if (!(optmask & ARES_OPT_TRIES)) { - opts.tries = 3; - optmask |= ARES_OPT_TRIES; - } - // If not already overridden, set search domains. - const char *domains[3] = {"first.com", "second.org", "third.gov"}; - if (!(optmask & ARES_OPT_DOMAINS)) { - opts.ndomains = 3; - opts.domains = (char**)domains; - optmask |= ARES_OPT_DOMAINS; - } - if (force_tcp) { - opts.flags |= ARES_FLAG_USEVC; - optmask |= ARES_OPT_FLAGS; - } - - EXPECT_EQ(ARES_SUCCESS, ares_init_options(&channel_, &opts, optmask)); - EXPECT_NE(nullptr, channel_); - - // Set up servers after construction so we can set individual ports - struct ares_addr_port_node* prev = nullptr; - struct ares_addr_port_node* first = nullptr; - for (const auto& server : servers_) { - struct ares_addr_port_node* node = (struct ares_addr_port_node*)malloc(sizeof(*node)); - if (prev) { - prev->next = node; - } else { - first = node; - } - node->next = nullptr; - node->family = family; - node->udp_port = server->udpport(); - node->tcp_port = server->tcpport(); - if (family == AF_INET) { - node->addr.addr4.s_addr = htonl(0x7F000001); - } else { - memset(&node->addr.addr6, 0, sizeof(node->addr.addr6)); - node->addr.addr6._S6_un._S6_u8[15] = 1; - } - prev = node; - } - EXPECT_EQ(ARES_SUCCESS, ares_set_servers_ports(channel_, first)); - - while (first) { - prev = first; - first = first->next; - free(prev); - } - if (verbose) { - std::cerr << "Configured library with servers:"; - std::vector<std::string> servers = GetNameServers(channel_); - for (const auto& server : servers) { - std::cerr << " " << server; - } - std::cerr << std::endl; - } -} - -MockChannelOptsTest::~MockChannelOptsTest() { - if (channel_) { - ares_destroy(channel_); - } - channel_ = nullptr; -} - -std::set<int> MockChannelOptsTest::fds() const { - std::set<int> fds; - for (const auto& server : servers_) { - std::set<int> serverfds = server->fds(); - fds.insert(serverfds.begin(), serverfds.end()); - } - return fds; -} - -void MockChannelOptsTest::ProcessFD(int fd) { - for (auto& server : servers_) { - server->ProcessFD(fd); - } -} - -void MockChannelOptsTest::Process() { - using namespace std::placeholders; - ProcessWork(channel_, - std::bind(&MockChannelOptsTest::fds, this), - std::bind(&MockChannelOptsTest::ProcessFD, this, _1)); -} - -std::ostream& operator<<(std::ostream& os, const HostResult& result) { - os << '{'; - if (result.done_) { - os << StatusToString(result.status_) << " " << result.host_; - } else { - os << "(incomplete)"; - } - os << '}'; - return os; -} - -HostEnt::HostEnt(const struct hostent *hostent) : addrtype_(-1) { - if (!hostent) - return; - if (hostent->h_name) - name_ = hostent->h_name; - if (hostent->h_aliases) { - char** palias = hostent->h_aliases; - while (*palias != nullptr) { - aliases_.push_back(*palias); - palias++; - } - } - addrtype_ = hostent->h_addrtype; - if (hostent->h_addr_list) { - char** paddr = hostent->h_addr_list; - while (*paddr != nullptr) { - std::string addr = AddressToString(*paddr, hostent->h_length); - addrs_.push_back(addr); - paddr++; - } - } -} - -std::ostream& operator<<(std::ostream& os, const HostEnt& host) { - os << '{'; - os << "'" << host.name_ << "' " - << "aliases=["; - for (size_t ii = 0; ii < host.aliases_.size(); ii++) { - if (ii > 0) os << ", "; - os << host.aliases_[ii]; - } - os << "] "; - os << "addrs=["; - for (size_t ii = 0; ii < host.addrs_.size(); ii++) { - if (ii > 0) os << ", "; - os << host.addrs_[ii]; - } - os << "]"; - os << '}'; - return os; -} - -void HostCallback(void *data, int status, int timeouts, - struct hostent *hostent) { - EXPECT_NE(nullptr, data); - HostResult* result = reinterpret_cast<HostResult*>(data); - result->done_ = true; - result->status_ = status; - result->timeouts_ = timeouts; - result->host_ = HostEnt(hostent); - if (verbose) std::cerr << "HostCallback(" << *result << ")" << std::endl; -} - +#include "dns-proto.h" + +// Include ares internal files for DNS protocol details +#include "nameser.h" +#include "ares_dns.h" + +#ifdef HAVE_NETDB_H +#include <netdb.h> +#endif +#ifdef HAVE_NETINET_TCP_H +#include <netinet/tcp.h> +#endif +#include <stdio.h> +#include <stdlib.h> + +#include <functional> +#include <sstream> + +#ifdef WIN32 +#define BYTE_CAST (char *) +#define mkdir_(d, p) mkdir(d) +#else +#define BYTE_CAST +#define mkdir_(d, p) mkdir(d, p) +#endif + +namespace ares { +namespace test { + +bool verbose = false; +int mock_port = 5300; + +const std::vector<int> both_families = {AF_INET, AF_INET6}; +const std::vector<int> ipv4_family = {AF_INET}; +const std::vector<int> ipv6_family = {AF_INET6}; + +const std::vector<std::pair<int, bool>> both_families_both_modes = { + std::make_pair<int, bool>(AF_INET, false), + std::make_pair<int, bool>(AF_INET, true), + std::make_pair<int, bool>(AF_INET6, false), + std::make_pair<int, bool>(AF_INET6, true) +}; +const std::vector<std::pair<int, bool>> ipv4_family_both_modes = { + std::make_pair<int, bool>(AF_INET, false), + std::make_pair<int, bool>(AF_INET, true) +}; +const std::vector<std::pair<int, bool>> ipv6_family_both_modes = { + std::make_pair<int, bool>(AF_INET6, false), + std::make_pair<int, bool>(AF_INET6, true) +}; + +// Which parameters to use in tests +std::vector<int> families = both_families; +std::vector<std::pair<int, bool>> families_modes = both_families_both_modes; + +unsigned long long LibraryTest::fails_ = 0; +std::map<size_t, int> LibraryTest::size_fails_; + +void ProcessWork(ares_channel channel, + std::function<std::set<int>()> get_extrafds, + std::function<void(int)> process_extra) { + int nfds, count; + fd_set readers, writers; + struct timeval tv; + while (true) { + // Retrieve the set of file descriptors that the library wants us to monitor. + FD_ZERO(&readers); + FD_ZERO(&writers); + nfds = ares_fds(channel, &readers, &writers); + if (nfds == 0) // no work left to do in the library + return; + + // Add in the extra FDs if present. + std::set<int> extrafds = get_extrafds(); + for (int extrafd : extrafds) { + FD_SET(extrafd, &readers); + if (extrafd >= nfds) { + nfds = extrafd + 1; + } + } + + // Wait for activity or timeout. + tv.tv_sec = 0; + tv.tv_usec = 100000; // 100ms + count = select(nfds, &readers, &writers, nullptr, &tv); + if (count < 0) { + fprintf(stderr, "select() failed, errno %d\n", errno); + return; + } + + // Let the library process any activity. + ares_process(channel, &readers, &writers); + + // Let the provided callback process any activity on the extra FD. + for (int extrafd : extrafds) { + if (FD_ISSET(extrafd, &readers)) { + process_extra(extrafd); + } + } + } +} + +// static +void LibraryTest::SetAllocFail(int nth) { + assert(nth > 0); + assert(nth <= (int)(8 * sizeof(fails_))); + fails_ |= (1LL << (nth - 1)); +} + +// static +void LibraryTest::SetAllocSizeFail(size_t size) { + size_fails_[size]++; +} + +// static +void LibraryTest::ClearFails() { + fails_ = 0; + size_fails_.clear(); +} + + +// static +bool LibraryTest::ShouldAllocFail(size_t size) { + bool fail = (fails_ & 0x01); + fails_ >>= 1; + if (size_fails_[size] > 0) { + size_fails_[size]--; + fail = true; + } + return fail; +} + +// static +void* LibraryTest::amalloc(size_t size) { + if (ShouldAllocFail(size)) { + if (verbose) std::cerr << "Failing malloc(" << size << ") request" << std::endl; + return nullptr; + } else { + return malloc(size); + } +} + +// static +void* LibraryTest::arealloc(void *ptr, size_t size) { + if (ShouldAllocFail(size)) { + if (verbose) std::cerr << "Failing realloc(" << ptr << ", " << size << ") request" << std::endl; + return nullptr; + } else { + return realloc(ptr, size); + } +} + +// static +void LibraryTest::afree(void *ptr) { + free(ptr); +} + +std::set<int> NoExtraFDs() { + return std::set<int>(); +} + +void DefaultChannelTest::Process() { + ProcessWork(channel_, NoExtraFDs, nullptr); +} + +void DefaultChannelModeTest::Process() { + ProcessWork(channel_, NoExtraFDs, nullptr); +} + +MockServer::MockServer(int family, int port, int tcpport) + : udpport_(port), tcpport_(tcpport ? tcpport : udpport_), qid_(-1) { + // Create a TCP socket to receive data on. + tcpfd_ = socket(family, SOCK_STREAM, 0); + EXPECT_NE(-1, tcpfd_); + int optval = 1; + setsockopt(tcpfd_, SOL_SOCKET, SO_REUSEADDR, + BYTE_CAST &optval , sizeof(int)); + // Send TCP data right away. + setsockopt(tcpfd_, IPPROTO_TCP, TCP_NODELAY, + BYTE_CAST &optval , sizeof(int)); + + // Create a UDP socket to receive data on. + udpfd_ = socket(family, SOCK_DGRAM, 0); + EXPECT_NE(-1, udpfd_); + + // Bind the sockets to the given port. + if (family == AF_INET) { + struct sockaddr_in addr; + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = htonl(INADDR_ANY); + addr.sin_port = htons(tcpport_); + int tcprc = bind(tcpfd_, (struct sockaddr*)&addr, sizeof(addr)); + EXPECT_EQ(0, tcprc) << "Failed to bind AF_INET to TCP port " << tcpport_; + addr.sin_port = htons(udpport_); + int udprc = bind(udpfd_, (struct sockaddr*)&addr, sizeof(addr)); + EXPECT_EQ(0, udprc) << "Failed to bind AF_INET to UDP port " << udpport_; + } else { + EXPECT_EQ(AF_INET6, family); + struct sockaddr_in6 addr; + memset(&addr, 0, sizeof(addr)); + addr.sin6_family = AF_INET6; + memset(&addr.sin6_addr, 0, sizeof(addr.sin6_addr)); // in6addr_any + addr.sin6_port = htons(tcpport_); + int tcprc = bind(tcpfd_, (struct sockaddr*)&addr, sizeof(addr)); + EXPECT_EQ(0, tcprc) << "Failed to bind AF_INET6 to TCP port " << tcpport_; + addr.sin6_port = htons(udpport_); + int udprc = bind(udpfd_, (struct sockaddr*)&addr, sizeof(addr)); + EXPECT_EQ(0, udprc) << "Failed to bind AF_INET6 to UDP port " << udpport_; + } + if (verbose) std::cerr << "Configured " + << (family == AF_INET ? "IPv4" : "IPv6") + << " mock server with TCP socket " << tcpfd_ + << " on port " << tcpport_ + << " and UDP socket " << udpfd_ + << " on port " << udpport_ << std::endl; + + // For TCP, also need to listen for connections. + EXPECT_EQ(0, listen(tcpfd_, 5)) << "Failed to listen for TCP connections"; +} + +MockServer::~MockServer() { + for (int fd : connfds_) { + sclose(fd); + } + sclose(tcpfd_); + sclose(udpfd_); +} + +void MockServer::ProcessFD(int fd) { + if (fd != tcpfd_ && fd != udpfd_ && connfds_.find(fd) == connfds_.end()) { + // Not one of our FDs. + return; + } + if (fd == tcpfd_) { + int connfd = accept(tcpfd_, NULL, NULL); + if (connfd < 0) { + std::cerr << "Error accepting connection on fd " << fd << std::endl; + } else { + connfds_.insert(connfd); + } + return; + } + + // Activity on a data-bearing file descriptor. + struct sockaddr_storage addr; + socklen_t addrlen = sizeof(addr); + byte buffer[2048]; + int len = recvfrom(fd, BYTE_CAST buffer, sizeof(buffer), 0, + (struct sockaddr *)&addr, &addrlen); + byte* data = buffer; + if (fd != udpfd_) { + if (len == 0) { + connfds_.erase(std::find(connfds_.begin(), connfds_.end(), fd)); + sclose(fd); + return; + } + if (len < 2) { + std::cerr << "Packet too short (" << len << ")" << std::endl; + return; + } + int tcplen = (data[0] << 8) + data[1]; + data += 2; + len -= 2; + if (tcplen != len) { + std::cerr << "Warning: TCP length " << tcplen + << " doesn't match remaining data length " << len << std::endl; + } + } + + // Assume the packet is a well-formed DNS request and extract the request + // details. + if (len < NS_HFIXEDSZ) { + std::cerr << "Packet too short (" << len << ")" << std::endl; + return; + } + int qid = DNS_HEADER_QID(data); + if (DNS_HEADER_QR(data) != 0) { + std::cerr << "Not a request" << std::endl; + return; + } + if (DNS_HEADER_OPCODE(data) != ns_o_query) { + std::cerr << "Not a query (opcode " << DNS_HEADER_OPCODE(data) + << ")" << std::endl; + return; + } + if (DNS_HEADER_QDCOUNT(data) != 1) { + std::cerr << "Unexpected question count (" << DNS_HEADER_QDCOUNT(data) + << ")" << std::endl; + return; + } + byte* question = data + 12; + int qlen = len - 12; + + char *name = nullptr; + long enclen; + ares_expand_name(question, data, len, &name, &enclen); + if (!name) { + std::cerr << "Failed to retrieve name" << std::endl; + return; + } + qlen -= enclen; + question += enclen; + std::string namestr(name); + ares_free_string(name); + + if (qlen < 4) { + std::cerr << "Unexpected question size (" << qlen + << " bytes after name)" << std::endl; + return; + } + if (DNS_QUESTION_CLASS(question) != ns_c_in) { + std::cerr << "Unexpected question class (" << DNS_QUESTION_CLASS(question) + << ")" << std::endl; + return; + } + int rrtype = DNS_QUESTION_TYPE(question); + + if (verbose) { + std::vector<byte> req(data, data + len); + std::cerr << "received " << (fd == udpfd_ ? "UDP" : "TCP") << " request " << PacketToString(req) + << " on port " << (fd == udpfd_ ? udpport_ : tcpport_) << std::endl; + std::cerr << "ProcessRequest(" << qid << ", '" << namestr + << "', " << RRTypeToString(rrtype) << ")" << std::endl; + } + ProcessRequest(fd, &addr, addrlen, qid, namestr, rrtype); +} + +std::set<int> MockServer::fds() const { + std::set<int> result = connfds_; + result.insert(tcpfd_); + result.insert(udpfd_); + return result; +} + +void MockServer::ProcessRequest(int fd, struct sockaddr_storage* addr, int addrlen, + int qid, const std::string& name, int rrtype) { + // Before processing, let gMock know the request is happening. + OnRequest(name, rrtype); + + if (reply_.size() == 0) { + return; + } + + // Make a local copy of the current pending reply. + std::vector<byte> reply = reply_; + + if (qid_ >= 0) { + // Use the explicitly specified query ID. + qid = qid_; + } + if (reply.size() >= 2) { + // Overwrite the query ID if space to do so. + reply[0] = (byte)((qid >> 8) & 0xff); + reply[1] = (byte)(qid & 0xff); + } + if (verbose) std::cerr << "sending reply " << PacketToString(reply) + << " on port " << ((fd == udpfd_) ? udpport_ : tcpport_) << std::endl; + + // Prefix with 2-byte length if TCP. + if (fd != udpfd_) { + int len = reply.size(); + std::vector<byte> vlen = {(byte)((len & 0xFF00) >> 8), (byte)(len & 0xFF)}; + reply.insert(reply.begin(), vlen.begin(), vlen.end()); + // Also, don't bother with the destination address. + addr = nullptr; + addrlen = 0; + } + + int rc = sendto(fd, BYTE_CAST reply.data(), reply.size(), 0, + (struct sockaddr *)addr, addrlen); + if (rc < static_cast<int>(reply.size())) { + std::cerr << "Failed to send full reply, rc=" << rc << std::endl; + } +} + +// static +MockChannelOptsTest::NiceMockServers MockChannelOptsTest::BuildServers(int count, int family, int base_port) { + NiceMockServers servers; + assert(count > 0); + for (int ii = 0; ii < count; ii++) { + std::unique_ptr<NiceMockServer> server(new NiceMockServer(family, base_port + ii)); + servers.push_back(std::move(server)); + } + return servers; +} + +MockChannelOptsTest::MockChannelOptsTest(int count, + int family, + bool force_tcp, + struct ares_options* givenopts, + int optmask) + : servers_(BuildServers(count, family, mock_port)), + server_(*servers_[0].get()), channel_(nullptr) { + // Set up channel options. + struct ares_options opts; + if (givenopts) { + memcpy(&opts, givenopts, sizeof(opts)); + } else { + memset(&opts, 0, sizeof(opts)); + } + + // Point the library at the first mock server by default (overridden below). + opts.udp_port = mock_port; + optmask |= ARES_OPT_UDP_PORT; + opts.tcp_port = mock_port; + optmask |= ARES_OPT_TCP_PORT; + + // If not already overridden, set short-ish timeouts. + if (!(optmask & (ARES_OPT_TIMEOUTMS|ARES_OPT_TIMEOUT))) { + opts.timeout = 1500; + optmask |= ARES_OPT_TIMEOUTMS; + } + // If not already overridden, set 3 retries. + if (!(optmask & ARES_OPT_TRIES)) { + opts.tries = 3; + optmask |= ARES_OPT_TRIES; + } + // If not already overridden, set search domains. + const char *domains[3] = {"first.com", "second.org", "third.gov"}; + if (!(optmask & ARES_OPT_DOMAINS)) { + opts.ndomains = 3; + opts.domains = (char**)domains; + optmask |= ARES_OPT_DOMAINS; + } + if (force_tcp) { + opts.flags |= ARES_FLAG_USEVC; + optmask |= ARES_OPT_FLAGS; + } + + EXPECT_EQ(ARES_SUCCESS, ares_init_options(&channel_, &opts, optmask)); + EXPECT_NE(nullptr, channel_); + + // Set up servers after construction so we can set individual ports + struct ares_addr_port_node* prev = nullptr; + struct ares_addr_port_node* first = nullptr; + for (const auto& server : servers_) { + struct ares_addr_port_node* node = (struct ares_addr_port_node*)malloc(sizeof(*node)); + if (prev) { + prev->next = node; + } else { + first = node; + } + node->next = nullptr; + node->family = family; + node->udp_port = server->udpport(); + node->tcp_port = server->tcpport(); + if (family == AF_INET) { + node->addr.addr4.s_addr = htonl(0x7F000001); + } else { + memset(&node->addr.addr6, 0, sizeof(node->addr.addr6)); + node->addr.addr6._S6_un._S6_u8[15] = 1; + } + prev = node; + } + EXPECT_EQ(ARES_SUCCESS, ares_set_servers_ports(channel_, first)); + + while (first) { + prev = first; + first = first->next; + free(prev); + } + if (verbose) { + std::cerr << "Configured library with servers:"; + std::vector<std::string> servers = GetNameServers(channel_); + for (const auto& server : servers) { + std::cerr << " " << server; + } + std::cerr << std::endl; + } +} + +MockChannelOptsTest::~MockChannelOptsTest() { + if (channel_) { + ares_destroy(channel_); + } + channel_ = nullptr; +} + +std::set<int> MockChannelOptsTest::fds() const { + std::set<int> fds; + for (const auto& server : servers_) { + std::set<int> serverfds = server->fds(); + fds.insert(serverfds.begin(), serverfds.end()); + } + return fds; +} + +void MockChannelOptsTest::ProcessFD(int fd) { + for (auto& server : servers_) { + server->ProcessFD(fd); + } +} + +void MockChannelOptsTest::Process() { + using namespace std::placeholders; + ProcessWork(channel_, + std::bind(&MockChannelOptsTest::fds, this), + std::bind(&MockChannelOptsTest::ProcessFD, this, _1)); +} + +std::ostream& operator<<(std::ostream& os, const HostResult& result) { + os << '{'; + if (result.done_) { + os << StatusToString(result.status_) << " " << result.host_; + } else { + os << "(incomplete)"; + } + os << '}'; + return os; +} + +HostEnt::HostEnt(const struct hostent *hostent) : addrtype_(-1) { + if (!hostent) + return; + if (hostent->h_name) + name_ = hostent->h_name; + if (hostent->h_aliases) { + char** palias = hostent->h_aliases; + while (*palias != nullptr) { + aliases_.push_back(*palias); + palias++; + } + } + addrtype_ = hostent->h_addrtype; + if (hostent->h_addr_list) { + char** paddr = hostent->h_addr_list; + while (*paddr != nullptr) { + std::string addr = AddressToString(*paddr, hostent->h_length); + addrs_.push_back(addr); + paddr++; + } + } +} + +std::ostream& operator<<(std::ostream& os, const HostEnt& host) { + os << '{'; + os << "'" << host.name_ << "' " + << "aliases=["; + for (size_t ii = 0; ii < host.aliases_.size(); ii++) { + if (ii > 0) os << ", "; + os << host.aliases_[ii]; + } + os << "] "; + os << "addrs=["; + for (size_t ii = 0; ii < host.addrs_.size(); ii++) { + if (ii > 0) os << ", "; + os << host.addrs_[ii]; + } + os << "]"; + os << '}'; + return os; +} + +void HostCallback(void *data, int status, int timeouts, + struct hostent *hostent) { + EXPECT_NE(nullptr, data); + HostResult* result = reinterpret_cast<HostResult*>(data); + result->done_ = true; + result->status_ = status; + result->timeouts_ = timeouts; + result->host_ = HostEnt(hostent); + if (verbose) std::cerr << "HostCallback(" << *result << ")" << std::endl; +} + std::ostream& operator<<(std::ostream& os, const AddrInfoResult& result) { os << '{'; if (result.done_ && result.ai_) { @@ -638,135 +638,135 @@ void AddrInfoCallback(void *data, int status, int timeouts, if (verbose) std::cerr << "AddrInfoCallback(" << *result << ")" << std::endl; } -std::ostream& operator<<(std::ostream& os, const SearchResult& result) { - os << '{'; - if (result.done_) { - os << StatusToString(result.status_) << " " << PacketToString(result.data_); - } else { - os << "(incomplete)"; - } - os << '}'; - return os; -} - -void SearchCallback(void *data, int status, int timeouts, - unsigned char *abuf, int alen) { - EXPECT_NE(nullptr, data); - SearchResult* result = reinterpret_cast<SearchResult*>(data); - result->done_ = true; - result->status_ = status; - result->timeouts_ = timeouts; - result->data_.assign(abuf, abuf + alen); - if (verbose) std::cerr << "SearchCallback(" << *result << ")" << std::endl; -} - -std::ostream& operator<<(std::ostream& os, const NameInfoResult& result) { - os << '{'; - if (result.done_) { - os << StatusToString(result.status_) << " " << result.node_ << " " << result.service_; - } else { - os << "(incomplete)"; - } - os << '}'; - return os; -} - -void NameInfoCallback(void *data, int status, int timeouts, - char *node, char *service) { - EXPECT_NE(nullptr, data); - NameInfoResult* result = reinterpret_cast<NameInfoResult*>(data); - result->done_ = true; - result->status_ = status; - result->timeouts_ = timeouts; - result->node_ = std::string(node ? node : ""); - result->service_ = std::string(service ? service : ""); - if (verbose) std::cerr << "NameInfoCallback(" << *result << ")" << std::endl; -} - -std::vector<std::string> GetNameServers(ares_channel channel) { - struct ares_addr_port_node* servers = nullptr; - EXPECT_EQ(ARES_SUCCESS, ares_get_servers_ports(channel, &servers)); - struct ares_addr_port_node* server = servers; - std::vector<std::string> results; - while (server) { - std::stringstream ss; - switch (server->family) { - case AF_INET: - ss << AddressToString((char*)&server->addr.addr4, 4); - break; - case AF_INET6: - if (server->udp_port != 0) { - ss << '['; - } - ss << AddressToString((char*)&server->addr.addr6, 16); - if (server->udp_port != 0) { - ss << ']'; - } - break; - default: - results.push_back("<unknown family>"); - break; - } - if (server->udp_port != 0) { - ss << ":" << server->udp_port; - } - results.push_back(ss.str()); - server = server->next; - } - if (servers) ares_free_data(servers); - return results; -} - -TransientDir::TransientDir(const std::string& dirname) : dirname_(dirname) { - if (mkdir_(dirname_.c_str(), 0755) != 0) { - std::cerr << "Failed to create subdirectory '" << dirname_ << "'" << std::endl; - } -} - -TransientDir::~TransientDir() { - rmdir(dirname_.c_str()); -} - -TransientFile::TransientFile(const std::string& filename, - const std::string& contents) - : filename_(filename) { - FILE *f = fopen(filename.c_str(), "w"); - if (f == nullptr) { - std::cerr << "Error: failed to create '" << filename << "'" << std::endl; - return; - } - int rc = fwrite(contents.data(), 1, contents.size(), f); - if (rc != (int)contents.size()) { - std::cerr << "Error: failed to write contents of '" << filename << "'" << std::endl; - } - fclose(f); -} - -TransientFile::~TransientFile() { - unlink(filename_.c_str()); -} - -std::string TempNam(const char *dir, const char *prefix) { - char *p = tempnam(dir, prefix); - std::string result(p); - free(p); - return result; -} - -TempFile::TempFile(const std::string& contents) - : TransientFile(TempNam(nullptr, "ares"), contents) { - -} - -VirtualizeIO::VirtualizeIO(ares_channel c) - : channel_(c) -{ - ares_set_socket_functions(channel_, &default_functions, 0); -} - -VirtualizeIO::~VirtualizeIO() { - ares_set_socket_functions(channel_, 0, 0); -} - -} // namespace test -} // namespace ares +std::ostream& operator<<(std::ostream& os, const SearchResult& result) { + os << '{'; + if (result.done_) { + os << StatusToString(result.status_) << " " << PacketToString(result.data_); + } else { + os << "(incomplete)"; + } + os << '}'; + return os; +} + +void SearchCallback(void *data, int status, int timeouts, + unsigned char *abuf, int alen) { + EXPECT_NE(nullptr, data); + SearchResult* result = reinterpret_cast<SearchResult*>(data); + result->done_ = true; + result->status_ = status; + result->timeouts_ = timeouts; + result->data_.assign(abuf, abuf + alen); + if (verbose) std::cerr << "SearchCallback(" << *result << ")" << std::endl; +} + +std::ostream& operator<<(std::ostream& os, const NameInfoResult& result) { + os << '{'; + if (result.done_) { + os << StatusToString(result.status_) << " " << result.node_ << " " << result.service_; + } else { + os << "(incomplete)"; + } + os << '}'; + return os; +} + +void NameInfoCallback(void *data, int status, int timeouts, + char *node, char *service) { + EXPECT_NE(nullptr, data); + NameInfoResult* result = reinterpret_cast<NameInfoResult*>(data); + result->done_ = true; + result->status_ = status; + result->timeouts_ = timeouts; + result->node_ = std::string(node ? node : ""); + result->service_ = std::string(service ? service : ""); + if (verbose) std::cerr << "NameInfoCallback(" << *result << ")" << std::endl; +} + +std::vector<std::string> GetNameServers(ares_channel channel) { + struct ares_addr_port_node* servers = nullptr; + EXPECT_EQ(ARES_SUCCESS, ares_get_servers_ports(channel, &servers)); + struct ares_addr_port_node* server = servers; + std::vector<std::string> results; + while (server) { + std::stringstream ss; + switch (server->family) { + case AF_INET: + ss << AddressToString((char*)&server->addr.addr4, 4); + break; + case AF_INET6: + if (server->udp_port != 0) { + ss << '['; + } + ss << AddressToString((char*)&server->addr.addr6, 16); + if (server->udp_port != 0) { + ss << ']'; + } + break; + default: + results.push_back("<unknown family>"); + break; + } + if (server->udp_port != 0) { + ss << ":" << server->udp_port; + } + results.push_back(ss.str()); + server = server->next; + } + if (servers) ares_free_data(servers); + return results; +} + +TransientDir::TransientDir(const std::string& dirname) : dirname_(dirname) { + if (mkdir_(dirname_.c_str(), 0755) != 0) { + std::cerr << "Failed to create subdirectory '" << dirname_ << "'" << std::endl; + } +} + +TransientDir::~TransientDir() { + rmdir(dirname_.c_str()); +} + +TransientFile::TransientFile(const std::string& filename, + const std::string& contents) + : filename_(filename) { + FILE *f = fopen(filename.c_str(), "w"); + if (f == nullptr) { + std::cerr << "Error: failed to create '" << filename << "'" << std::endl; + return; + } + int rc = fwrite(contents.data(), 1, contents.size(), f); + if (rc != (int)contents.size()) { + std::cerr << "Error: failed to write contents of '" << filename << "'" << std::endl; + } + fclose(f); +} + +TransientFile::~TransientFile() { + unlink(filename_.c_str()); +} + +std::string TempNam(const char *dir, const char *prefix) { + char *p = tempnam(dir, prefix); + std::string result(p); + free(p); + return result; +} + +TempFile::TempFile(const std::string& contents) + : TransientFile(TempNam(nullptr, "ares"), contents) { + +} + +VirtualizeIO::VirtualizeIO(ares_channel c) + : channel_(c) +{ + ares_set_socket_functions(channel_, &default_functions, 0); +} + +VirtualizeIO::~VirtualizeIO() { + ares_set_socket_functions(channel_, 0, 0); +} + +} // namespace test +} // namespace ares diff --git a/contrib/libs/c-ares/test/ares-test.h b/contrib/libs/c-ares/test/ares-test.h index a905702aef..fd3bc31c27 100644 --- a/contrib/libs/c-ares/test/ares-test.h +++ b/contrib/libs/c-ares/test/ares-test.h @@ -1,281 +1,281 @@ -// -*- mode: c++ -*- -#ifndef ARES_TEST_H -#define ARES_TEST_H - -#include "dns-proto.h" -// Include ares internal file for DNS protocol constants -#include "nameser.h" - -#include "ares_setup.h" -#include "ares.h" - -#include "gtest/gtest.h" -#include "gmock/gmock.h" - -#if defined(HAVE_USER_NAMESPACE) && defined(HAVE_UTS_NAMESPACE) -#define HAVE_CONTAINER -#endif - -#include <functional> -#include <list> -#include <map> -#include <memory> -#include <set> -#include <string> -#include <utility> -#include <vector> - -namespace ares { - -typedef unsigned char byte; - -namespace test { - -extern bool verbose; -extern int mock_port; -extern const std::vector<int> both_families; -extern const std::vector<int> ipv4_family; -extern const std::vector<int> ipv6_family; - -extern const std::vector<std::pair<int, bool>> both_families_both_modes; -extern const std::vector<std::pair<int, bool>> ipv4_family_both_modes; -extern const std::vector<std::pair<int, bool>> ipv6_family_both_modes; - -// Which parameters to use in tests -extern std::vector<int> families; -extern std::vector<std::pair<int, bool>> families_modes; - -// Process all pending work on ares-owned file descriptors, plus -// optionally the given set-of-FDs + work function. -void ProcessWork(ares_channel channel, - std::function<std::set<int>()> get_extrafds, - std::function<void(int)> process_extra); -std::set<int> NoExtraFDs(); - -// Test fixture that ensures library initialization, and allows -// memory allocations to be failed. -class LibraryTest : public ::testing::Test { - public: - LibraryTest() { - EXPECT_EQ(ARES_SUCCESS, - ares_library_init_mem(ARES_LIB_INIT_ALL, - &LibraryTest::amalloc, - &LibraryTest::afree, - &LibraryTest::arealloc)); - } - ~LibraryTest() { - ares_library_cleanup(); - ClearFails(); - } - // Set the n-th malloc call (of any size) from the library to fail. - // (nth == 1 means the next call) - static void SetAllocFail(int nth); - // Set the next malloc call for the given size to fail. - static void SetAllocSizeFail(size_t size); - // Remove any pending alloc failures. - static void ClearFails(); - - static void *amalloc(size_t size); - static void* arealloc(void *ptr, size_t size); - static void afree(void *ptr); - private: - static bool ShouldAllocFail(size_t size); - static unsigned long long fails_; - static std::map<size_t, int> size_fails_; -}; - -// Test fixture that uses a default channel. -class DefaultChannelTest : public LibraryTest { - public: - DefaultChannelTest() : channel_(nullptr) { - EXPECT_EQ(ARES_SUCCESS, ares_init(&channel_)); - EXPECT_NE(nullptr, channel_); - } - - ~DefaultChannelTest() { - ares_destroy(channel_); - channel_ = nullptr; - } - - // Process all pending work on ares-owned file descriptors. - void Process(); - - protected: - ares_channel channel_; -}; - -// Test fixture that uses a default channel with the specified lookup mode. -class DefaultChannelModeTest - : public LibraryTest, - public ::testing::WithParamInterface<std::string> { - public: - DefaultChannelModeTest() : channel_(nullptr) { - struct ares_options opts = {0}; - opts.lookups = strdup(GetParam().c_str()); - int optmask = ARES_OPT_LOOKUPS; - EXPECT_EQ(ARES_SUCCESS, ares_init_options(&channel_, &opts, optmask)); - EXPECT_NE(nullptr, channel_); - free(opts.lookups); - } - - ~DefaultChannelModeTest() { - ares_destroy(channel_); - channel_ = nullptr; - } - - // Process all pending work on ares-owned file descriptors. - void Process(); - - protected: - ares_channel channel_; -}; - -// Mock DNS server to allow responses to be scripted by tests. -class MockServer { - public: - MockServer(int family, int port, int tcpport = 0); - ~MockServer(); - - // Mock method indicating the processing of a particular <name, RRtype> - // request. - MOCK_METHOD2(OnRequest, void(const std::string& name, int rrtype)); - - // Set the reply to be sent next; the query ID field will be overwritten - // with the value from the request. - void SetReplyData(const std::vector<byte>& reply) { reply_ = reply; } - void SetReply(const DNSPacket* reply) { SetReplyData(reply->data()); } - void SetReplyQID(int qid) { qid_ = qid; } - - // The set of file descriptors that the server handles. - std::set<int> fds() const; - - // Process activity on a file descriptor. - void ProcessFD(int fd); - - // Ports the server is responding to - int udpport() const { return udpport_; } - int tcpport() const { return tcpport_; } - - private: - void ProcessRequest(int fd, struct sockaddr_storage* addr, int addrlen, - int qid, const std::string& name, int rrtype); - - int udpport_; - int tcpport_; - int udpfd_; - int tcpfd_; - std::set<int> connfds_; - std::vector<byte> reply_; - int qid_; -}; - -// Test fixture that uses a mock DNS server. -class MockChannelOptsTest : public LibraryTest { - public: - MockChannelOptsTest(int count, int family, bool force_tcp, struct ares_options* givenopts, int optmask); - ~MockChannelOptsTest(); - - // Process all pending work on ares-owned and mock-server-owned file descriptors. - void Process(); - - protected: - // NiceMockServer doesn't complain about uninteresting calls. - typedef testing::NiceMock<MockServer> NiceMockServer; - typedef std::vector< std::unique_ptr<NiceMockServer> > NiceMockServers; - - std::set<int> fds() const; - void ProcessFD(int fd); - - static NiceMockServers BuildServers(int count, int family, int base_port); - - NiceMockServers servers_; - // Convenience reference to first server. - NiceMockServer& server_; - ares_channel channel_; -}; - -class MockChannelTest - : public MockChannelOptsTest, - public ::testing::WithParamInterface< std::pair<int, bool> > { - public: - MockChannelTest() : MockChannelOptsTest(1, GetParam().first, GetParam().second, nullptr, 0) {} -}; - -class MockUDPChannelTest - : public MockChannelOptsTest, - public ::testing::WithParamInterface<int> { - public: - MockUDPChannelTest() : MockChannelOptsTest(1, GetParam(), false, nullptr, 0) {} -}; - -class MockTCPChannelTest - : public MockChannelOptsTest, - public ::testing::WithParamInterface<int> { - public: - MockTCPChannelTest() : MockChannelOptsTest(1, GetParam(), true, nullptr, 0) {} -}; - -// gMock action to set the reply for a mock server. -ACTION_P2(SetReplyData, mockserver, data) { - mockserver->SetReplyData(data); -} -ACTION_P2(SetReply, mockserver, reply) { - mockserver->SetReply(reply); -} -ACTION_P2(SetReplyQID, mockserver, qid) { - mockserver->SetReplyQID(qid); -} -// gMock action to cancel a channel. -ACTION_P2(CancelChannel, mockserver, channel) { - ares_cancel(channel); -} - -// C++ wrapper for struct hostent. -struct HostEnt { - HostEnt() : addrtype_(-1) {} - HostEnt(const struct hostent* hostent); - std::string name_; - std::vector<std::string> aliases_; - int addrtype_; // AF_INET or AF_INET6 - std::vector<std::string> addrs_; -}; -std::ostream& operator<<(std::ostream& os, const HostEnt& result); - -// Structure that describes the result of an ares_host_callback invocation. -struct HostResult { - // Whether the callback has been invoked. - bool done_; - // Explicitly provided result information. - int status_; - int timeouts_; - // Contents of the hostent structure, if provided. - HostEnt host_; -}; -std::ostream& operator<<(std::ostream& os, const HostResult& result); - -// Structure that describes the result of an ares_callback invocation. -struct SearchResult { - // Whether the callback has been invoked. - bool done_; - // Explicitly provided result information. - int status_; - int timeouts_; - std::vector<byte> data_; -}; -std::ostream& operator<<(std::ostream& os, const SearchResult& result); - -// Structure that describes the result of an ares_nameinfo_callback invocation. -struct NameInfoResult { - // Whether the callback has been invoked. - bool done_; - // Explicitly provided result information. - int status_; - int timeouts_; - std::string node_; - std::string service_; -}; -std::ostream& operator<<(std::ostream& os, const NameInfoResult& result); - +// -*- mode: c++ -*- +#ifndef ARES_TEST_H +#define ARES_TEST_H + +#include "dns-proto.h" +// Include ares internal file for DNS protocol constants +#include "nameser.h" + +#include "ares_setup.h" +#include "ares.h" + +#include "gtest/gtest.h" +#include "gmock/gmock.h" + +#if defined(HAVE_USER_NAMESPACE) && defined(HAVE_UTS_NAMESPACE) +#define HAVE_CONTAINER +#endif + +#include <functional> +#include <list> +#include <map> +#include <memory> +#include <set> +#include <string> +#include <utility> +#include <vector> + +namespace ares { + +typedef unsigned char byte; + +namespace test { + +extern bool verbose; +extern int mock_port; +extern const std::vector<int> both_families; +extern const std::vector<int> ipv4_family; +extern const std::vector<int> ipv6_family; + +extern const std::vector<std::pair<int, bool>> both_families_both_modes; +extern const std::vector<std::pair<int, bool>> ipv4_family_both_modes; +extern const std::vector<std::pair<int, bool>> ipv6_family_both_modes; + +// Which parameters to use in tests +extern std::vector<int> families; +extern std::vector<std::pair<int, bool>> families_modes; + +// Process all pending work on ares-owned file descriptors, plus +// optionally the given set-of-FDs + work function. +void ProcessWork(ares_channel channel, + std::function<std::set<int>()> get_extrafds, + std::function<void(int)> process_extra); +std::set<int> NoExtraFDs(); + +// Test fixture that ensures library initialization, and allows +// memory allocations to be failed. +class LibraryTest : public ::testing::Test { + public: + LibraryTest() { + EXPECT_EQ(ARES_SUCCESS, + ares_library_init_mem(ARES_LIB_INIT_ALL, + &LibraryTest::amalloc, + &LibraryTest::afree, + &LibraryTest::arealloc)); + } + ~LibraryTest() { + ares_library_cleanup(); + ClearFails(); + } + // Set the n-th malloc call (of any size) from the library to fail. + // (nth == 1 means the next call) + static void SetAllocFail(int nth); + // Set the next malloc call for the given size to fail. + static void SetAllocSizeFail(size_t size); + // Remove any pending alloc failures. + static void ClearFails(); + + static void *amalloc(size_t size); + static void* arealloc(void *ptr, size_t size); + static void afree(void *ptr); + private: + static bool ShouldAllocFail(size_t size); + static unsigned long long fails_; + static std::map<size_t, int> size_fails_; +}; + +// Test fixture that uses a default channel. +class DefaultChannelTest : public LibraryTest { + public: + DefaultChannelTest() : channel_(nullptr) { + EXPECT_EQ(ARES_SUCCESS, ares_init(&channel_)); + EXPECT_NE(nullptr, channel_); + } + + ~DefaultChannelTest() { + ares_destroy(channel_); + channel_ = nullptr; + } + + // Process all pending work on ares-owned file descriptors. + void Process(); + + protected: + ares_channel channel_; +}; + +// Test fixture that uses a default channel with the specified lookup mode. +class DefaultChannelModeTest + : public LibraryTest, + public ::testing::WithParamInterface<std::string> { + public: + DefaultChannelModeTest() : channel_(nullptr) { + struct ares_options opts = {0}; + opts.lookups = strdup(GetParam().c_str()); + int optmask = ARES_OPT_LOOKUPS; + EXPECT_EQ(ARES_SUCCESS, ares_init_options(&channel_, &opts, optmask)); + EXPECT_NE(nullptr, channel_); + free(opts.lookups); + } + + ~DefaultChannelModeTest() { + ares_destroy(channel_); + channel_ = nullptr; + } + + // Process all pending work on ares-owned file descriptors. + void Process(); + + protected: + ares_channel channel_; +}; + +// Mock DNS server to allow responses to be scripted by tests. +class MockServer { + public: + MockServer(int family, int port, int tcpport = 0); + ~MockServer(); + + // Mock method indicating the processing of a particular <name, RRtype> + // request. + MOCK_METHOD2(OnRequest, void(const std::string& name, int rrtype)); + + // Set the reply to be sent next; the query ID field will be overwritten + // with the value from the request. + void SetReplyData(const std::vector<byte>& reply) { reply_ = reply; } + void SetReply(const DNSPacket* reply) { SetReplyData(reply->data()); } + void SetReplyQID(int qid) { qid_ = qid; } + + // The set of file descriptors that the server handles. + std::set<int> fds() const; + + // Process activity on a file descriptor. + void ProcessFD(int fd); + + // Ports the server is responding to + int udpport() const { return udpport_; } + int tcpport() const { return tcpport_; } + + private: + void ProcessRequest(int fd, struct sockaddr_storage* addr, int addrlen, + int qid, const std::string& name, int rrtype); + + int udpport_; + int tcpport_; + int udpfd_; + int tcpfd_; + std::set<int> connfds_; + std::vector<byte> reply_; + int qid_; +}; + +// Test fixture that uses a mock DNS server. +class MockChannelOptsTest : public LibraryTest { + public: + MockChannelOptsTest(int count, int family, bool force_tcp, struct ares_options* givenopts, int optmask); + ~MockChannelOptsTest(); + + // Process all pending work on ares-owned and mock-server-owned file descriptors. + void Process(); + + protected: + // NiceMockServer doesn't complain about uninteresting calls. + typedef testing::NiceMock<MockServer> NiceMockServer; + typedef std::vector< std::unique_ptr<NiceMockServer> > NiceMockServers; + + std::set<int> fds() const; + void ProcessFD(int fd); + + static NiceMockServers BuildServers(int count, int family, int base_port); + + NiceMockServers servers_; + // Convenience reference to first server. + NiceMockServer& server_; + ares_channel channel_; +}; + +class MockChannelTest + : public MockChannelOptsTest, + public ::testing::WithParamInterface< std::pair<int, bool> > { + public: + MockChannelTest() : MockChannelOptsTest(1, GetParam().first, GetParam().second, nullptr, 0) {} +}; + +class MockUDPChannelTest + : public MockChannelOptsTest, + public ::testing::WithParamInterface<int> { + public: + MockUDPChannelTest() : MockChannelOptsTest(1, GetParam(), false, nullptr, 0) {} +}; + +class MockTCPChannelTest + : public MockChannelOptsTest, + public ::testing::WithParamInterface<int> { + public: + MockTCPChannelTest() : MockChannelOptsTest(1, GetParam(), true, nullptr, 0) {} +}; + +// gMock action to set the reply for a mock server. +ACTION_P2(SetReplyData, mockserver, data) { + mockserver->SetReplyData(data); +} +ACTION_P2(SetReply, mockserver, reply) { + mockserver->SetReply(reply); +} +ACTION_P2(SetReplyQID, mockserver, qid) { + mockserver->SetReplyQID(qid); +} +// gMock action to cancel a channel. +ACTION_P2(CancelChannel, mockserver, channel) { + ares_cancel(channel); +} + +// C++ wrapper for struct hostent. +struct HostEnt { + HostEnt() : addrtype_(-1) {} + HostEnt(const struct hostent* hostent); + std::string name_; + std::vector<std::string> aliases_; + int addrtype_; // AF_INET or AF_INET6 + std::vector<std::string> addrs_; +}; +std::ostream& operator<<(std::ostream& os, const HostEnt& result); + +// Structure that describes the result of an ares_host_callback invocation. +struct HostResult { + // Whether the callback has been invoked. + bool done_; + // Explicitly provided result information. + int status_; + int timeouts_; + // Contents of the hostent structure, if provided. + HostEnt host_; +}; +std::ostream& operator<<(std::ostream& os, const HostResult& result); + +// Structure that describes the result of an ares_callback invocation. +struct SearchResult { + // Whether the callback has been invoked. + bool done_; + // Explicitly provided result information. + int status_; + int timeouts_; + std::vector<byte> data_; +}; +std::ostream& operator<<(std::ostream& os, const SearchResult& result); + +// Structure that describes the result of an ares_nameinfo_callback invocation. +struct NameInfoResult { + // Whether the callback has been invoked. + bool done_; + // Explicitly provided result information. + int status_; + int timeouts_; + std::string node_; + std::string service_; +}; +std::ostream& operator<<(std::ostream& os, const NameInfoResult& result); + struct AddrInfoDeleter { void operator() (ares_addrinfo *ptr) { if (ptr) ares_freeaddrinfo(ptr); @@ -300,51 +300,51 @@ struct AddrInfoResult { }; std::ostream& operator<<(std::ostream& os, const AddrInfoResult& result); -// Standard implementation of ares callbacks that fill out the corresponding -// structures. -void HostCallback(void *data, int status, int timeouts, - struct hostent *hostent); -void SearchCallback(void *data, int status, int timeouts, - unsigned char *abuf, int alen); -void NameInfoCallback(void *data, int status, int timeouts, - char *node, char *service); +// Standard implementation of ares callbacks that fill out the corresponding +// structures. +void HostCallback(void *data, int status, int timeouts, + struct hostent *hostent); +void SearchCallback(void *data, int status, int timeouts, + unsigned char *abuf, int alen); +void NameInfoCallback(void *data, int status, int timeouts, + char *node, char *service); void AddrInfoCallback(void *data, int status, int timeouts, struct ares_addrinfo *res); - -// Retrieve the name servers used by a channel. -std::vector<std::string> GetNameServers(ares_channel channel); - - -// RAII class to temporarily create a directory of a given name. -class TransientDir { - public: - TransientDir(const std::string& dirname); - ~TransientDir(); - - private: - std::string dirname_; -}; - -// C++ wrapper around tempnam() -std::string TempNam(const char *dir, const char *prefix); - -// RAII class to temporarily create file of a given name and contents. -class TransientFile { - public: - TransientFile(const std::string &filename, const std::string &contents); - ~TransientFile(); - - protected: - std::string filename_; -}; - -// RAII class for a temporary file with the given contents. -class TempFile : public TransientFile { - public: - TempFile(const std::string& contents); - const char* filename() const { return filename_.c_str(); } -}; - + +// Retrieve the name servers used by a channel. +std::vector<std::string> GetNameServers(ares_channel channel); + + +// RAII class to temporarily create a directory of a given name. +class TransientDir { + public: + TransientDir(const std::string& dirname); + ~TransientDir(); + + private: + std::string dirname_; +}; + +// C++ wrapper around tempnam() +std::string TempNam(const char *dir, const char *prefix); + +// RAII class to temporarily create file of a given name and contents. +class TransientFile { + public: + TransientFile(const std::string &filename, const std::string &contents); + ~TransientFile(); + + protected: + std::string filename_; +}; + +// RAII class for a temporary file with the given contents. +class TempFile : public TransientFile { + public: + TempFile(const std::string& contents); + const char* filename() const { return filename_.c_str(); } +}; + #ifdef _WIN32 extern "C" { @@ -379,111 +379,111 @@ static int unsetenv(const char *name) } /* extern "C" */ #endif -// RAII class for a temporary environment variable value. -class EnvValue { - public: - EnvValue(const char *name, const char *value) : name_(name), restore_(false) { - char *original = getenv(name); - if (original) { - restore_ = true; - original_ = original; - } - setenv(name_.c_str(), value, 1); - } - ~EnvValue() { - if (restore_) { - setenv(name_.c_str(), original_.c_str(), 1); - } else { - unsetenv(name_.c_str()); - } - } - private: - std::string name_; - bool restore_; - std::string original_; -}; - - -#ifdef HAVE_CONTAINER -// Linux-specific functionality for running code in a container, implemented -// in ares-test-ns.cc -typedef std::function<int(void)> VoidToIntFn; -typedef std::vector<std::pair<std::string, std::string>> NameContentList; - -class ContainerFilesystem { - public: - ContainerFilesystem(NameContentList files, const std::string& mountpt); - ~ContainerFilesystem(); - std::string root() const { return rootdir_; }; - std::string mountpt() const { return mountpt_; }; - private: - void EnsureDirExists(const std::string& dir); - std::string rootdir_; - std::string mountpt_; - std::list<std::string> dirs_; - std::vector<std::unique_ptr<TransientFile>> files_; -}; - -int RunInContainer(ContainerFilesystem* fs, const std::string& hostname, - const std::string& domainname, VoidToIntFn fn); - -#define ICLASS_NAME(casename, testname) Contained##casename##_##testname -#define CONTAINED_TEST_F(casename, testname, hostname, domainname, files) \ - class ICLASS_NAME(casename, testname) : public casename { \ - public: \ - ICLASS_NAME(casename, testname)() {} \ - static int InnerTestBody(); \ - }; \ - TEST_F(ICLASS_NAME(casename, testname), _) { \ - ContainerFilesystem chroot(files, ".."); \ - VoidToIntFn fn(ICLASS_NAME(casename, testname)::InnerTestBody); \ - EXPECT_EQ(0, RunInContainer(&chroot, hostname, domainname, fn)); \ - } \ - int ICLASS_NAME(casename, testname)::InnerTestBody() - -#endif - -/* Assigns virtual IO functions to a channel. These functions simply call - * the actual system functions. - */ -class VirtualizeIO { -public: - VirtualizeIO(ares_channel); - ~VirtualizeIO(); - - static const ares_socket_functions default_functions; -private: - ares_channel channel_; -}; - -/* - * Slightly white-box macro to generate two runs for a given test case: - * One with no modifications, and one with all IO functions set to use - * the virtual io structure. - * Since no magic socket setup or anything is done in the latter case - * this should probably only be used for test with very vanilla IO - * requirements. - */ -#define VCLASS_NAME(casename, testname) Virt##casename##_##testname -#define VIRT_NONVIRT_TEST_F(casename, testname) \ - class VCLASS_NAME(casename, testname) : public casename { \ - public: \ - VCLASS_NAME(casename, testname)() {} \ - void InnerTestBody(); \ - }; \ - GTEST_TEST_(casename, testname, VCLASS_NAME(casename, testname), \ - ::testing::internal::GetTypeId<casename>()) { \ - InnerTestBody(); \ - } \ - GTEST_TEST_(casename, testname##_virtualized, \ - VCLASS_NAME(casename, testname), \ - ::testing::internal::GetTypeId<casename>()) { \ - VirtualizeIO vio(channel_); \ - InnerTestBody(); \ - } \ - void VCLASS_NAME(casename, testname)::InnerTestBody() - -} // namespace test -} // namespace ares - -#endif +// RAII class for a temporary environment variable value. +class EnvValue { + public: + EnvValue(const char *name, const char *value) : name_(name), restore_(false) { + char *original = getenv(name); + if (original) { + restore_ = true; + original_ = original; + } + setenv(name_.c_str(), value, 1); + } + ~EnvValue() { + if (restore_) { + setenv(name_.c_str(), original_.c_str(), 1); + } else { + unsetenv(name_.c_str()); + } + } + private: + std::string name_; + bool restore_; + std::string original_; +}; + + +#ifdef HAVE_CONTAINER +// Linux-specific functionality for running code in a container, implemented +// in ares-test-ns.cc +typedef std::function<int(void)> VoidToIntFn; +typedef std::vector<std::pair<std::string, std::string>> NameContentList; + +class ContainerFilesystem { + public: + ContainerFilesystem(NameContentList files, const std::string& mountpt); + ~ContainerFilesystem(); + std::string root() const { return rootdir_; }; + std::string mountpt() const { return mountpt_; }; + private: + void EnsureDirExists(const std::string& dir); + std::string rootdir_; + std::string mountpt_; + std::list<std::string> dirs_; + std::vector<std::unique_ptr<TransientFile>> files_; +}; + +int RunInContainer(ContainerFilesystem* fs, const std::string& hostname, + const std::string& domainname, VoidToIntFn fn); + +#define ICLASS_NAME(casename, testname) Contained##casename##_##testname +#define CONTAINED_TEST_F(casename, testname, hostname, domainname, files) \ + class ICLASS_NAME(casename, testname) : public casename { \ + public: \ + ICLASS_NAME(casename, testname)() {} \ + static int InnerTestBody(); \ + }; \ + TEST_F(ICLASS_NAME(casename, testname), _) { \ + ContainerFilesystem chroot(files, ".."); \ + VoidToIntFn fn(ICLASS_NAME(casename, testname)::InnerTestBody); \ + EXPECT_EQ(0, RunInContainer(&chroot, hostname, domainname, fn)); \ + } \ + int ICLASS_NAME(casename, testname)::InnerTestBody() + +#endif + +/* Assigns virtual IO functions to a channel. These functions simply call + * the actual system functions. + */ +class VirtualizeIO { +public: + VirtualizeIO(ares_channel); + ~VirtualizeIO(); + + static const ares_socket_functions default_functions; +private: + ares_channel channel_; +}; + +/* + * Slightly white-box macro to generate two runs for a given test case: + * One with no modifications, and one with all IO functions set to use + * the virtual io structure. + * Since no magic socket setup or anything is done in the latter case + * this should probably only be used for test with very vanilla IO + * requirements. + */ +#define VCLASS_NAME(casename, testname) Virt##casename##_##testname +#define VIRT_NONVIRT_TEST_F(casename, testname) \ + class VCLASS_NAME(casename, testname) : public casename { \ + public: \ + VCLASS_NAME(casename, testname)() {} \ + void InnerTestBody(); \ + }; \ + GTEST_TEST_(casename, testname, VCLASS_NAME(casename, testname), \ + ::testing::internal::GetTypeId<casename>()) { \ + InnerTestBody(); \ + } \ + GTEST_TEST_(casename, testname##_virtualized, \ + VCLASS_NAME(casename, testname), \ + ::testing::internal::GetTypeId<casename>()) { \ + VirtualizeIO vio(channel_); \ + InnerTestBody(); \ + } \ + void VCLASS_NAME(casename, testname)::InnerTestBody() + +} // namespace test +} // namespace ares + +#endif diff --git a/contrib/libs/c-ares/test/config.h b/contrib/libs/c-ares/test/config.h index ce02fa3963..787575c8e0 100644 --- a/contrib/libs/c-ares/test/config.h +++ b/contrib/libs/c-ares/test/config.h @@ -1,81 +1,81 @@ -/* config.h. Generated from config.h.in by configure. */ -/* config.h.in. Generated from configure.ac by autoheader. */ - -/* 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 1 - -/* Define to 1 if you have the <inttypes.h> header file. */ -#define HAVE_INTTYPES_H 1 - -/* Define to 1 if you have the <memory.h> header file. */ -#define HAVE_MEMORY_H 1 - -/* Define to 1 if you have the <netdb.h> header file. */ -#define HAVE_NETDB_H 1 - -/* Define to 1 if you have the <netinet/tcp.h> header file. */ -#define HAVE_NETINET_TCP_H 1 - -/* Define if you have POSIX threads libraries and header files. */ -#define HAVE_PTHREAD 1 - -/* Have PTHREAD_PRIO_INHERIT. */ -#define HAVE_PTHREAD_PRIO_INHERIT 1 - -/* Define to 1 if you have the <stdint.h> header file. */ -#define HAVE_STDINT_H 1 - -/* Define to 1 if you have the <stdlib.h> header file. */ -#define HAVE_STDLIB_H 1 - -/* Define to 1 if you have the <strings.h> header file. */ -#define HAVE_STRINGS_H 1 - -/* Define to 1 if you have the <string.h> header file. */ -#define HAVE_STRING_H 1 - -/* Define to 1 if you have the <sys/stat.h> header file. */ -#define HAVE_SYS_STAT_H 1 - -/* Define to 1 if you have the <sys/types.h> header file. */ -#define HAVE_SYS_TYPES_H 1 - -/* Define to 1 if you have the <unistd.h> header file. */ -#define HAVE_UNISTD_H 1 - -/* Whether user namespaces are available */ -#define HAVE_USER_NAMESPACE 1 - -/* Whether UTS namespaces are available */ -#define HAVE_UTS_NAMESPACE 1 - -/* Define to the sub-directory where libtool stores uninstalled libraries. */ -#define LT_OBJDIR ".libs/" - -/* Define to the address where bug reports for this package should be sent. */ -#define PACKAGE_BUGREPORT "-" - -/* Define to the full name of this package. */ -#define PACKAGE_NAME "c-ares-test" - -/* Define to the full name and version of this package. */ -#define PACKAGE_STRING "c-ares-test -" - -/* Define to the one symbol short name of this package. */ -#define PACKAGE_TARNAME "c-ares-test" - -/* Define to the home page for this package. */ -#define PACKAGE_URL "" - -/* Define to the version of this package. */ -#define PACKAGE_VERSION "-" - -/* Define to necessary symbol if this constant uses a non-standard name on - your system. */ -/* #undef PTHREAD_CREATE_JOINABLE */ - -/* Define to 1 if you have the ANSI C header files. */ -#define STDC_HEADERS 1 +/* config.h. Generated from config.h.in by configure. */ +/* config.h.in. Generated from configure.ac by autoheader. */ + +/* 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 1 + +/* Define to 1 if you have the <inttypes.h> header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the <memory.h> header file. */ +#define HAVE_MEMORY_H 1 + +/* Define to 1 if you have the <netdb.h> header file. */ +#define HAVE_NETDB_H 1 + +/* Define to 1 if you have the <netinet/tcp.h> header file. */ +#define HAVE_NETINET_TCP_H 1 + +/* Define if you have POSIX threads libraries and header files. */ +#define HAVE_PTHREAD 1 + +/* Have PTHREAD_PRIO_INHERIT. */ +#define HAVE_PTHREAD_PRIO_INHERIT 1 + +/* Define to 1 if you have the <stdint.h> header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the <stdlib.h> header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the <strings.h> header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the <string.h> header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the <sys/stat.h> header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the <sys/types.h> header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the <unistd.h> header file. */ +#define HAVE_UNISTD_H 1 + +/* Whether user namespaces are available */ +#define HAVE_USER_NAMESPACE 1 + +/* Whether UTS namespaces are available */ +#define HAVE_UTS_NAMESPACE 1 + +/* Define to the sub-directory where libtool stores uninstalled libraries. */ +#define LT_OBJDIR ".libs/" + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "-" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "c-ares-test" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "c-ares-test -" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "c-ares-test" + +/* Define to the home page for this package. */ +#define PACKAGE_URL "" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "-" + +/* Define to necessary symbol if this constant uses a non-standard name on + your system. */ +/* #undef PTHREAD_CREATE_JOINABLE */ + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 diff --git a/contrib/libs/c-ares/test/dns-proto-test.cc b/contrib/libs/c-ares/test/dns-proto-test.cc index 2d9a9ec34d..0c36a0c922 100644 --- a/contrib/libs/c-ares/test/dns-proto-test.cc +++ b/contrib/libs/c-ares/test/dns-proto-test.cc @@ -1,131 +1,131 @@ -#include "ares-test.h" -#include "dns-proto.h" - -#include <vector> - -namespace ares { -namespace test { - -TEST(DNSProto, EncodeQuestions) { - DNSPacket pkt; - pkt.set_qid(0x1234).set_response().set_aa() - .add_question(new DNSQuestion("example.com.", ns_t_a)) - .add_question(new DNSQuestion("www.example.com", ns_t_aaaa, ns_c_chaos)); - - std::vector<byte> data = { - 0x12, 0x34, // qid - 0x84, // response + query + AA + not-TC + not-RD - 0x00, // not-RA + not-Z + not-AD + not-CD + rc=NoError - 0x00, 0x02, // num questions - 0x00, 0x00, // num answer RRs - 0x00, 0x00, // num authority RRs - 0x00, 0x00, // num additional RRs - // Question 1 - 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', - 0x03, 'c', 'o', 'm', - 0x00, - 0x00, 0x01, // type A - 0x00, 0x01, // class IN - // Question 2 - 0x03, 'w', 'w', 'w', - 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', - 0x03, 'c', 'o', 'm', - 0x00, - 0x00, 0x1C, // type AAAA = 28 - 0x00, 0x03, // class CHAOS = 3 - }; - EXPECT_EQ(data, pkt.data()); -} - -TEST(DNSProto, EncodeSingleNameAnswers) { - DNSPacket pkt; - pkt.qid_ = 0x1234; - pkt.response_ = true; - pkt.aa_ = true; - pkt.opcode_ = ns_o_query; - pkt.add_answer(new DNSCnameRR("example.com", 0x01020304, "other.com.")); - pkt.add_auth(new DNSPtrRR("www.example.com", 0x01020304, "www.other.com")); - - std::vector<byte> data = { - 0x12, 0x34, // qid - 0x84, // response + query + AA + not-TC + not-RD - 0x00, // not-RA + not-Z + not-AD + not-CD + rc=NoError - 0x00, 0x00, // num questions - 0x00, 0x01, // num answer RRs - 0x00, 0x01, // num authority RRs - 0x00, 0x00, // num additional RRs - // Answer 1 - 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', - 0x03, 'c', 'o', 'm', - 0x00, - 0x00, 0x05, // RR type - 0x00, 0x01, // class IN - 0x01, 0x02, 0x03, 0x04, // TTL - 0x00, 0x0B, // rdata length - 0x05, 'o', 't', 'h', 'e', 'r', - 0x03, 'c', 'o', 'm', - 0x00, - // Authority 1 - 0x03, 'w', 'w', 'w', - 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', - 0x03, 'c', 'o', 'm', - 0x00, - 0x00, 0x0c, // RR type - 0x00, 0x01, // class IN - 0x01, 0x02, 0x03, 0x04, // TTL - 0x00, 0x0F, // rdata length - 0x03, 'w', 'w', 'w', - 0x05, 'o', 't', 'h', 'e', 'r', - 0x03, 'c', 'o', 'm', - 0x00, - }; - EXPECT_EQ(data, pkt.data()); -} - -TEST(DNSProto, EncodeAddressAnswers) { - DNSPacket pkt; - pkt.qid_ = 0x1234; - pkt.response_ = true; - pkt.aa_ = true; - pkt.opcode_ = ns_o_query; - std::vector<byte> addrv4 = {0x02, 0x03, 0x04, 0x05}; - pkt.add_answer(new DNSARR("example.com", 0x01020304, addrv4)); - byte addrv6[16] = {0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, - 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x04}; - pkt.add_additional(new DNSAaaaRR("www.example.com", 0x01020304, addrv6, 16)); - - std::vector<byte> data = { - 0x12, 0x34, // qid - 0x84, // response + query + AA + not-TC + not-RD - 0x00, // not-RA + not-Z + not-AD + not-CD + rc=NoError - 0x00, 0x00, // num questions - 0x00, 0x01, // num answer RRs - 0x00, 0x00, // num authority RRs - 0x00, 0x01, // num additional RRs - // Answer 1 - 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', - 0x03, 'c', 'o', 'm', - 0x00, - 0x00, 0x01, // RR type - 0x00, 0x01, // class IN - 0x01, 0x02, 0x03, 0x04, // TTL - 0x00, 0x04, // rdata length - 0x02, 0x03, 0x04, 0x05, - // Additional 1 - 0x03, 'w', 'w', 'w', - 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', - 0x03, 'c', 'o', 'm', - 0x00, - 0x00, 0x1c, // RR type - 0x00, 0x01, // class IN - 0x01, 0x02, 0x03, 0x04, // TTL - 0x00, 0x10, // rdata length - 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, - 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x04 - }; - EXPECT_EQ(data, pkt.data()); -} - - -} // namespace test -} // namespace ares +#include "ares-test.h" +#include "dns-proto.h" + +#include <vector> + +namespace ares { +namespace test { + +TEST(DNSProto, EncodeQuestions) { + DNSPacket pkt; + pkt.set_qid(0x1234).set_response().set_aa() + .add_question(new DNSQuestion("example.com.", ns_t_a)) + .add_question(new DNSQuestion("www.example.com", ns_t_aaaa, ns_c_chaos)); + + std::vector<byte> data = { + 0x12, 0x34, // qid + 0x84, // response + query + AA + not-TC + not-RD + 0x00, // not-RA + not-Z + not-AD + not-CD + rc=NoError + 0x00, 0x02, // num questions + 0x00, 0x00, // num answer RRs + 0x00, 0x00, // num authority RRs + 0x00, 0x00, // num additional RRs + // Question 1 + 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + 0x00, 0x01, // type A + 0x00, 0x01, // class IN + // Question 2 + 0x03, 'w', 'w', 'w', + 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + 0x00, 0x1C, // type AAAA = 28 + 0x00, 0x03, // class CHAOS = 3 + }; + EXPECT_EQ(data, pkt.data()); +} + +TEST(DNSProto, EncodeSingleNameAnswers) { + DNSPacket pkt; + pkt.qid_ = 0x1234; + pkt.response_ = true; + pkt.aa_ = true; + pkt.opcode_ = ns_o_query; + pkt.add_answer(new DNSCnameRR("example.com", 0x01020304, "other.com.")); + pkt.add_auth(new DNSPtrRR("www.example.com", 0x01020304, "www.other.com")); + + std::vector<byte> data = { + 0x12, 0x34, // qid + 0x84, // response + query + AA + not-TC + not-RD + 0x00, // not-RA + not-Z + not-AD + not-CD + rc=NoError + 0x00, 0x00, // num questions + 0x00, 0x01, // num answer RRs + 0x00, 0x01, // num authority RRs + 0x00, 0x00, // num additional RRs + // Answer 1 + 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + 0x00, 0x05, // RR type + 0x00, 0x01, // class IN + 0x01, 0x02, 0x03, 0x04, // TTL + 0x00, 0x0B, // rdata length + 0x05, 'o', 't', 'h', 'e', 'r', + 0x03, 'c', 'o', 'm', + 0x00, + // Authority 1 + 0x03, 'w', 'w', 'w', + 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + 0x00, 0x0c, // RR type + 0x00, 0x01, // class IN + 0x01, 0x02, 0x03, 0x04, // TTL + 0x00, 0x0F, // rdata length + 0x03, 'w', 'w', 'w', + 0x05, 'o', 't', 'h', 'e', 'r', + 0x03, 'c', 'o', 'm', + 0x00, + }; + EXPECT_EQ(data, pkt.data()); +} + +TEST(DNSProto, EncodeAddressAnswers) { + DNSPacket pkt; + pkt.qid_ = 0x1234; + pkt.response_ = true; + pkt.aa_ = true; + pkt.opcode_ = ns_o_query; + std::vector<byte> addrv4 = {0x02, 0x03, 0x04, 0x05}; + pkt.add_answer(new DNSARR("example.com", 0x01020304, addrv4)); + byte addrv6[16] = {0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, + 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x04}; + pkt.add_additional(new DNSAaaaRR("www.example.com", 0x01020304, addrv6, 16)); + + std::vector<byte> data = { + 0x12, 0x34, // qid + 0x84, // response + query + AA + not-TC + not-RD + 0x00, // not-RA + not-Z + not-AD + not-CD + rc=NoError + 0x00, 0x00, // num questions + 0x00, 0x01, // num answer RRs + 0x00, 0x00, // num authority RRs + 0x00, 0x01, // num additional RRs + // Answer 1 + 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + 0x00, 0x01, // RR type + 0x00, 0x01, // class IN + 0x01, 0x02, 0x03, 0x04, // TTL + 0x00, 0x04, // rdata length + 0x02, 0x03, 0x04, 0x05, + // Additional 1 + 0x03, 'w', 'w', 'w', + 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + 0x00, 0x1c, // RR type + 0x00, 0x01, // class IN + 0x01, 0x02, 0x03, 0x04, // TTL + 0x00, 0x10, // rdata length + 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, + 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x04 + }; + EXPECT_EQ(data, pkt.data()); +} + + +} // namespace test +} // namespace ares diff --git a/contrib/libs/c-ares/test/dns-proto.cc b/contrib/libs/c-ares/test/dns-proto.cc index 7f50be3534..d2fa8b15be 100644 --- a/contrib/libs/c-ares/test/dns-proto.cc +++ b/contrib/libs/c-ares/test/dns-proto.cc @@ -1,638 +1,638 @@ -#include "dns-proto.h" - -// Include ares internal file for DNS protocol details -#include "ares_setup.h" -#include "ares.h" -#include "ares_dns.h" - -#include <stdio.h> -#include <stdlib.h> - -#include <sstream> - -namespace ares { - -std::string HexDump(std::vector<byte> data) { - std::stringstream ss; - for (size_t ii = 0; ii < data.size(); ii++) { - char buffer[2 + 1]; - sprintf(buffer, "%02x", data[ii]); - ss << buffer; - } - return ss.str(); -} - -std::string HexDump(const byte *data, int len) { - return HexDump(std::vector<byte>(data, data + len)); -} - -std::string HexDump(const char *data, int len) { - return HexDump(reinterpret_cast<const byte*>(data), len); -} - -std::string StatusToString(int status) { - switch (status) { - case ARES_SUCCESS: return "ARES_SUCCESS"; - case ARES_ENODATA: return "ARES_ENODATA"; - case ARES_EFORMERR: return "ARES_EFORMERR"; - case ARES_ESERVFAIL: return "ARES_ESERVFAIL"; - case ARES_ENOTFOUND: return "ARES_ENOTFOUND"; - case ARES_ENOTIMP: return "ARES_ENOTIMP"; - case ARES_EREFUSED: return "ARES_EREFUSED"; - case ARES_EBADQUERY: return "ARES_EBADQUERY"; - case ARES_EBADNAME: return "ARES_EBADNAME"; - case ARES_EBADFAMILY: return "ARES_EBADFAMILY"; - case ARES_EBADRESP: return "ARES_EBADRESP"; - case ARES_ECONNREFUSED: return "ARES_ECONNREFUSED"; - case ARES_ETIMEOUT: return "ARES_ETIMEOUT"; - case ARES_EOF: return "ARES_EOF"; - case ARES_EFILE: return "ARES_EFILE"; - case ARES_ENOMEM: return "ARES_ENOMEM"; - case ARES_EDESTRUCTION: return "ARES_EDESTRUCTION"; - case ARES_EBADSTR: return "ARES_EBADSTR"; - case ARES_EBADFLAGS: return "ARES_EBADFLAGS"; - case ARES_ENONAME: return "ARES_ENONAME"; - case ARES_EBADHINTS: return "ARES_EBADHINTS"; - case ARES_ENOTINITIALIZED: return "ARES_ENOTINITIALIZED"; - case ARES_ELOADIPHLPAPI: return "ARES_ELOADIPHLPAPI"; - case ARES_EADDRGETNETWORKPARAMS: return "ARES_EADDRGETNETWORKPARAMS"; - case ARES_ECANCELLED: return "ARES_ECANCELLED"; - default: return "UNKNOWN"; - } -} - -std::string RcodeToString(int rcode) { - switch (rcode) { - case ns_r_noerror: return "NOERROR"; - case ns_r_formerr: return "FORMERR"; - case ns_r_servfail: return "SERVFAIL"; - case ns_r_nxdomain: return "NXDOMAIN"; - case ns_r_notimpl: return "NOTIMPL"; - case ns_r_refused: return "REFUSED"; - case ns_r_yxdomain: return "YXDOMAIN"; - case ns_r_yxrrset: return "YXRRSET"; - case ns_r_nxrrset: return "NXRRSET"; - case ns_r_notauth: return "NOTAUTH"; - case ns_r_notzone: return "NOTZONE"; - case ns_r_badsig: return "BADSIG"; - case ns_r_badkey: return "BADKEY"; - case ns_r_badtime: return "BADTIME"; - default: return "UNKNOWN"; - } -} - -std::string RRTypeToString(int rrtype) { - switch (rrtype) { - case ns_t_a: return "A"; - case ns_t_ns: return "NS"; - case ns_t_md: return "MD"; - case ns_t_mf: return "MF"; - case ns_t_cname: return "CNAME"; - case ns_t_soa: return "SOA"; - case ns_t_mb: return "MB"; - case ns_t_mg: return "MG"; - case ns_t_mr: return "MR"; - case ns_t_null: return "NULL"; - case ns_t_wks: return "WKS"; - case ns_t_ptr: return "PTR"; - case ns_t_hinfo: return "HINFO"; - case ns_t_minfo: return "MINFO"; - case ns_t_mx: return "MX"; - case ns_t_txt: return "TXT"; - case ns_t_rp: return "RP"; - case ns_t_afsdb: return "AFSDB"; - case ns_t_x25: return "X25"; - case ns_t_isdn: return "ISDN"; - case ns_t_rt: return "RT"; - case ns_t_nsap: return "NSAP"; - case ns_t_nsap_ptr: return "NSAP_PTR"; - case ns_t_sig: return "SIG"; - case ns_t_key: return "KEY"; - case ns_t_px: return "PX"; - case ns_t_gpos: return "GPOS"; - case ns_t_aaaa: return "AAAA"; - case ns_t_loc: return "LOC"; - case ns_t_nxt: return "NXT"; - case ns_t_eid: return "EID"; - case ns_t_nimloc: return "NIMLOC"; - case ns_t_srv: return "SRV"; - case ns_t_atma: return "ATMA"; - case ns_t_naptr: return "NAPTR"; - case ns_t_kx: return "KX"; - case ns_t_cert: return "CERT"; - case ns_t_a6: return "A6"; - case ns_t_dname: return "DNAME"; - case ns_t_sink: return "SINK"; - case ns_t_opt: return "OPT"; - case ns_t_apl: return "APL"; - case ns_t_ds: return "DS"; - case ns_t_sshfp: return "SSHFP"; - case ns_t_rrsig: return "RRSIG"; - case ns_t_nsec: return "NSEC"; - case ns_t_dnskey: return "DNSKEY"; - case ns_t_tkey: return "TKEY"; - case ns_t_tsig: return "TSIG"; - case ns_t_ixfr: return "IXFR"; - case ns_t_axfr: return "AXFR"; - case ns_t_mailb: return "MAILB"; - case ns_t_maila: return "MAILA"; - case ns_t_any: return "ANY"; - case ns_t_zxfr: return "ZXFR"; - case ns_t_max: return "MAX"; - default: return "UNKNOWN"; - } -} - -std::string ClassToString(int qclass) { - switch (qclass) { - case ns_c_in: return "IN"; - case ns_c_chaos: return "CHAOS"; - case ns_c_hs: return "HESIOD"; - case ns_c_none: return "NONE"; - case ns_c_any: return "ANY"; - default: return "UNKNOWN"; - } -} - -std::string AddressToString(const void* vaddr, int len) { - const byte* addr = reinterpret_cast<const byte*>(vaddr); - std::stringstream ss; - if (len == 4) { - char buffer[4*4 + 3 + 1]; - sprintf(buffer, "%u.%u.%u.%u", - (unsigned char)addr[0], - (unsigned char)addr[1], - (unsigned char)addr[2], - (unsigned char)addr[3]); - ss << buffer; - } else if (len == 16) { - for (int ii = 0; ii < 16; ii+=2) { - if (ii > 0) ss << ':'; - char buffer[4 + 1]; - sprintf(buffer, "%02x%02x", (unsigned char)addr[ii], (unsigned char)addr[ii+1]); - ss << buffer; - } - } else { - ss << "!" << HexDump(addr, len) << "!"; - } - return ss.str(); -} - -std::string PacketToString(const std::vector<byte>& packet) { - const byte* data = packet.data(); - int len = packet.size(); - std::stringstream ss; - if (len < NS_HFIXEDSZ) { - ss << "(too short, len " << len << ")"; - return ss.str(); - } - ss << ((DNS_HEADER_QR(data) == 0) ? "REQ " : "RSP "); - switch (DNS_HEADER_OPCODE(data)) { - case ns_o_query: ss << "QRY "; break; - case ns_o_iquery: ss << "IQRY "; break; - case ns_o_status: ss << "STATUS "; break; - case ns_o_notify: ss << "NOTIFY "; break; - case ns_o_update: ss << "UPDATE "; break; - default: ss << "UNKNOWN(" << DNS_HEADER_OPCODE(data) << ") "; break; - } - if (DNS_HEADER_AA(data)) ss << "AA "; - if (DNS_HEADER_TC(data)) ss << "TC "; - if (DNS_HEADER_RD(data)) ss << "RD "; - if (DNS_HEADER_RA(data)) ss << "RA "; - if (DNS_HEADER_Z(data)) ss << "Z "; - if (DNS_HEADER_QR(data) == 1) ss << RcodeToString(DNS_HEADER_RCODE(data)); - - int nquestions = DNS_HEADER_QDCOUNT(data); - int nanswers = DNS_HEADER_ANCOUNT(data); - int nauths = DNS_HEADER_NSCOUNT(data); - int nadds = DNS_HEADER_ARCOUNT(data); - - const byte* pq = data + NS_HFIXEDSZ; - len -= NS_HFIXEDSZ; - for (int ii = 0; ii < nquestions; ii++) { - ss << " Q:" << QuestionToString(packet, &pq, &len); - } - const byte* prr = pq; - for (int ii = 0; ii < nanswers; ii++) { - ss << " A:" << RRToString(packet, &prr, &len); - } - for (int ii = 0; ii < nauths; ii++) { - ss << " AUTH:" << RRToString(packet, &prr, &len); - } - for (int ii = 0; ii < nadds; ii++) { - ss << " ADD:" << RRToString(packet, &prr, &len); - } - return ss.str(); -} - -std::string QuestionToString(const std::vector<byte>& packet, - const byte** data, int* len) { - std::stringstream ss; - ss << "{"; - if (*len < NS_QFIXEDSZ) { - ss << "(too short, len " << *len << ")"; - return ss.str(); - } - - char *name = nullptr; - long enclen; - int rc = ares_expand_name(*data, packet.data(), packet.size(), &name, &enclen); - if (rc != ARES_SUCCESS) { - ss << "(error from ares_expand_name)"; - return ss.str(); - } - if (enclen > *len) { - ss << "(error, encoded name len " << enclen << "bigger than remaining data " << *len << " bytes)"; - return ss.str(); - } - *len -= enclen; - *data += enclen; - ss << "'" << name << "' "; - ares_free_string(name); - if (*len < NS_QFIXEDSZ) { - ss << "(too short, len left " << *len << ")"; - return ss.str(); - } - ss << ClassToString(DNS_QUESTION_CLASS(*data)) << " "; - ss << RRTypeToString(DNS_QUESTION_TYPE(*data)); - *data += NS_QFIXEDSZ; - *len -= NS_QFIXEDSZ; - ss << "}"; - return ss.str(); -} - -std::string RRToString(const std::vector<byte>& packet, - const byte** data, int* len) { - std::stringstream ss; - ss << "{"; - if (*len < NS_RRFIXEDSZ) { - ss << "too short, len " << *len << ")"; - return ss.str(); - } - - char *name = nullptr; - long enclen; - int rc = ares_expand_name(*data, packet.data(), packet.size(), &name, &enclen); - if (rc != ARES_SUCCESS) { - ss << "(error from ares_expand_name)"; - return ss.str(); - } - if (enclen > *len) { - ss << "(error, encoded name len " << enclen << "bigger than remaining data " << *len << " bytes)"; - return ss.str(); - } - *len -= enclen; - *data += enclen; - ss << "'" << name << "' "; - ares_free_string(name); - name = nullptr; - - if (*len < NS_RRFIXEDSZ) { - ss << "(too short, len left " << *len << ")"; - return ss.str(); - } - int rrtype = DNS_RR_TYPE(*data); - if (rrtype == ns_t_opt) { - ss << "MAXUDP=" << DNS_RR_CLASS(*data) << " "; - ss << RRTypeToString(rrtype) << " "; - ss << "RCODE2=" << DNS_RR_TTL(*data); - } else { - ss << ClassToString(DNS_RR_CLASS(*data)) << " "; - ss << RRTypeToString(rrtype) << " "; - ss << "TTL=" << DNS_RR_TTL(*data); - } - int rdatalen = DNS_RR_LEN(*data); - - *data += NS_RRFIXEDSZ; - *len -= NS_RRFIXEDSZ; - if (*len < rdatalen) { - ss << "(RR too long at " << rdatalen << ", len left " << *len << ")"; - } else { - switch (rrtype) { - case ns_t_a: - case ns_t_aaaa: - ss << " " << AddressToString(*data, rdatalen); - break; - case ns_t_txt: { - const byte* p = *data; - while (p < (*data + rdatalen)) { - int len = *p++; - if ((p + len) <= (*data + rdatalen)) { - std::string txt(p, p + len); - ss << " " << len << ":'" << txt << "'"; - } else { - ss << "(string too long)"; - } - p += len; - } - break; - } - case ns_t_cname: - case ns_t_ns: - case ns_t_ptr: { - int rc = ares_expand_name(*data, packet.data(), packet.size(), &name, &enclen); - if (rc != ARES_SUCCESS) { - ss << "(error from ares_expand_name)"; - break; - } - ss << " '" << name << "'"; - ares_free_string(name); - break; - } - case ns_t_mx: - if (rdatalen > 2) { - int rc = ares_expand_name(*data + 2, packet.data(), packet.size(), &name, &enclen); - if (rc != ARES_SUCCESS) { - ss << "(error from ares_expand_name)"; - break; - } - ss << " " << DNS__16BIT(*data) << " '" << name << "'"; - ares_free_string(name); - } else { - ss << "(RR too short)"; - } - break; - case ns_t_srv: { - if (rdatalen > 6) { - const byte* p = *data; - unsigned long prio = DNS__16BIT(p); - unsigned long weight = DNS__16BIT(p + 2); - unsigned long port = DNS__16BIT(p + 4); - p += 6; - int rc = ares_expand_name(p, packet.data(), packet.size(), &name, &enclen); - if (rc != ARES_SUCCESS) { - ss << "(error from ares_expand_name)"; - break; - } - ss << prio << " " << weight << " " << port << " '" << name << "'"; - ares_free_string(name); - } else { - ss << "(RR too short)"; - } - break; - } - case ns_t_soa: { - const byte* p = *data; - int rc = ares_expand_name(p, packet.data(), packet.size(), &name, &enclen); - if (rc != ARES_SUCCESS) { - ss << "(error from ares_expand_name)"; - break; - } - ss << " '" << name << "'"; - ares_free_string(name); - p += enclen; - rc = ares_expand_name(p, packet.data(), packet.size(), &name, &enclen); - if (rc != ARES_SUCCESS) { - ss << "(error from ares_expand_name)"; - break; - } - ss << " '" << name << "'"; - ares_free_string(name); - p += enclen; - if ((p + 20) <= (*data + rdatalen)) { - unsigned long serial = DNS__32BIT(p); - unsigned long refresh = DNS__32BIT(p + 4); - unsigned long retry = DNS__32BIT(p + 8); - unsigned long expire = DNS__32BIT(p + 12); - unsigned long minimum = DNS__32BIT(p + 16); - ss << " " << serial << " " << refresh << " " << retry << " " << expire << " " << minimum; - } else { - ss << "(RR too short)"; - } - break; - } - case ns_t_naptr: { - if (rdatalen > 7) { - const byte* p = *data; - unsigned long order = DNS__16BIT(p); - unsigned long pref = DNS__16BIT(p + 2); - p += 4; - ss << order << " " << pref; - - int len = *p++; - std::string flags(p, p + len); - ss << " " << flags; - p += len; - - len = *p++; - std::string service(p, p + len); - ss << " '" << service << "'"; - p += len; - - len = *p++; - std::string regexp(p, p + len); - ss << " '" << regexp << "'"; - p += len; - - int rc = ares_expand_name(p, packet.data(), packet.size(), &name, &enclen); - if (rc != ARES_SUCCESS) { - ss << "(error from ares_expand_name)"; - break; - } - ss << " '" << name << "'"; - ares_free_string(name); - } else { - ss << "(RR too short)"; - } - break; - } - default: - ss << " " << HexDump(*data, rdatalen); - break; - } - } - *data += rdatalen; - *len -= rdatalen; - - ss << "}"; - return ss.str(); -} - -void PushInt32(std::vector<byte>* data, int value) { - data->push_back((value & 0xff000000) >> 24); - data->push_back((value & 0x00ff0000) >> 16); - data->push_back((value & 0x0000ff00) >> 8); - data->push_back(value & 0x000000ff); -} - -void PushInt16(std::vector<byte>* data, int value) { - data->push_back((value & 0xff00) >> 8); - data->push_back(value & 0x00ff); -} - -std::vector<byte> EncodeString(const std::string& name) { - std::vector<byte> data; - std::stringstream ss(name); - std::string label; - // TODO: cope with escapes - while (std::getline(ss, label, '.')) { - data.push_back(label.length()); - data.insert(data.end(), label.begin(), label.end()); - } - data.push_back(0); - return data; -} - -std::vector<byte> DNSQuestion::data() const { - std::vector<byte> data; - std::vector<byte> encname = EncodeString(name_); - data.insert(data.end(), encname.begin(), encname.end()); - PushInt16(&data, rrtype_); - PushInt16(&data, qclass_); - return data; -} - -std::vector<byte> DNSRR::data() const { - std::vector<byte> data = DNSQuestion::data(); - PushInt32(&data, ttl_); - return data; -} - -std::vector<byte> DNSSingleNameRR::data() const { - std::vector<byte> data = DNSRR::data(); - std::vector<byte> encname = EncodeString(other_); - int len = encname.size(); - PushInt16(&data, len); - data.insert(data.end(), encname.begin(), encname.end()); - return data; -} - -std::vector<byte> DNSTxtRR::data() const { - std::vector<byte> data = DNSRR::data(); - int len = 0; - for (const std::string& txt : txt_) { - len += (1 + txt.size()); - } - PushInt16(&data, len); - for (const std::string& txt : txt_) { - data.push_back(txt.size()); - data.insert(data.end(), txt.begin(), txt.end()); - } - return data; -} - -std::vector<byte> DNSMxRR::data() const { - std::vector<byte> data = DNSRR::data(); - std::vector<byte> encname = EncodeString(other_); - int len = 2 + encname.size(); - PushInt16(&data, len); - PushInt16(&data, pref_); - data.insert(data.end(), encname.begin(), encname.end()); - return data; -} - -std::vector<byte> DNSSrvRR::data() const { - std::vector<byte> data = DNSRR::data(); - std::vector<byte> encname = EncodeString(target_); - int len = 6 + encname.size(); - PushInt16(&data, len); - PushInt16(&data, prio_); - PushInt16(&data, weight_); - PushInt16(&data, port_); - data.insert(data.end(), encname.begin(), encname.end()); - return data; -} - -std::vector<byte> DNSAddressRR::data() const { - std::vector<byte> data = DNSRR::data(); - int len = addr_.size(); - PushInt16(&data, len); - data.insert(data.end(), addr_.begin(), addr_.end()); - return data; -} - -std::vector<byte> DNSSoaRR::data() const { - std::vector<byte> data = DNSRR::data(); - std::vector<byte> encname1 = EncodeString(nsname_); - std::vector<byte> encname2 = EncodeString(rname_); - int len = encname1.size() + encname2.size() + 5*4; - PushInt16(&data, len); - data.insert(data.end(), encname1.begin(), encname1.end()); - data.insert(data.end(), encname2.begin(), encname2.end()); - PushInt32(&data, serial_); - PushInt32(&data, refresh_); - PushInt32(&data, retry_); - PushInt32(&data, expire_); - PushInt32(&data, minimum_); - return data; -} - -std::vector<byte> DNSOptRR::data() const { - std::vector<byte> data = DNSRR::data(); - int len = 0; - for (const DNSOption& opt : opts_) { - len += (4 + opt.data_.size()); - } - PushInt16(&data, len); - for (const DNSOption& opt : opts_) { - PushInt16(&data, opt.code_); - PushInt16(&data, opt.data_.size()); - data.insert(data.end(), opt.data_.begin(), opt.data_.end()); - } - return data; -} - -std::vector<byte> DNSNaptrRR::data() const { - std::vector<byte> data = DNSRR::data(); - std::vector<byte> encname = EncodeString(replacement_); - int len = (4 + 1 + flags_.size() + 1 + service_.size() + 1 + regexp_.size() + encname.size()); - PushInt16(&data, len); - PushInt16(&data, order_); - PushInt16(&data, pref_); - data.push_back(flags_.size()); - data.insert(data.end(), flags_.begin(), flags_.end()); - data.push_back(service_.size()); - data.insert(data.end(), service_.begin(), service_.end()); - data.push_back(regexp_.size()); - data.insert(data.end(), regexp_.begin(), regexp_.end()); - data.insert(data.end(), encname.begin(), encname.end()); - return data; -} - -std::vector<byte> DNSPacket::data() const { - std::vector<byte> data; - PushInt16(&data, qid_); - byte b = 0x00; - if (response_) b |= 0x80; - b |= ((opcode_ & 0x0f) << 3); - if (aa_) b |= 0x04; - if (tc_) b |= 0x02; - if (rd_) b |= 0x01; - data.push_back(b); - b = 0x00; - if (ra_) b |= 0x80; - if (z_) b |= 0x40; - if (ad_) b |= 0x20; - if (cd_) b |= 0x10; - b |= (rcode_ & 0x0f); - data.push_back(b); - - int count = questions_.size(); - PushInt16(&data, count); - count = answers_.size(); - PushInt16(&data, count); - count = auths_.size(); - PushInt16(&data, count); - count = adds_.size(); - PushInt16(&data, count); - - for (const std::unique_ptr<DNSQuestion>& question : questions_) { - std::vector<byte> qdata = question->data(); - data.insert(data.end(), qdata.begin(), qdata.end()); - } - for (const std::unique_ptr<DNSRR>& rr : answers_) { - std::vector<byte> rrdata = rr->data(); - data.insert(data.end(), rrdata.begin(), rrdata.end()); - } - for (const std::unique_ptr<DNSRR>& rr : auths_) { - std::vector<byte> rrdata = rr->data(); - data.insert(data.end(), rrdata.begin(), rrdata.end()); - } - for (const std::unique_ptr<DNSRR>& rr : adds_) { - std::vector<byte> rrdata = rr->data(); - data.insert(data.end(), rrdata.begin(), rrdata.end()); - } - return data; -} - -} // namespace ares +#include "dns-proto.h" + +// Include ares internal file for DNS protocol details +#include "ares_setup.h" +#include "ares.h" +#include "ares_dns.h" + +#include <stdio.h> +#include <stdlib.h> + +#include <sstream> + +namespace ares { + +std::string HexDump(std::vector<byte> data) { + std::stringstream ss; + for (size_t ii = 0; ii < data.size(); ii++) { + char buffer[2 + 1]; + sprintf(buffer, "%02x", data[ii]); + ss << buffer; + } + return ss.str(); +} + +std::string HexDump(const byte *data, int len) { + return HexDump(std::vector<byte>(data, data + len)); +} + +std::string HexDump(const char *data, int len) { + return HexDump(reinterpret_cast<const byte*>(data), len); +} + +std::string StatusToString(int status) { + switch (status) { + case ARES_SUCCESS: return "ARES_SUCCESS"; + case ARES_ENODATA: return "ARES_ENODATA"; + case ARES_EFORMERR: return "ARES_EFORMERR"; + case ARES_ESERVFAIL: return "ARES_ESERVFAIL"; + case ARES_ENOTFOUND: return "ARES_ENOTFOUND"; + case ARES_ENOTIMP: return "ARES_ENOTIMP"; + case ARES_EREFUSED: return "ARES_EREFUSED"; + case ARES_EBADQUERY: return "ARES_EBADQUERY"; + case ARES_EBADNAME: return "ARES_EBADNAME"; + case ARES_EBADFAMILY: return "ARES_EBADFAMILY"; + case ARES_EBADRESP: return "ARES_EBADRESP"; + case ARES_ECONNREFUSED: return "ARES_ECONNREFUSED"; + case ARES_ETIMEOUT: return "ARES_ETIMEOUT"; + case ARES_EOF: return "ARES_EOF"; + case ARES_EFILE: return "ARES_EFILE"; + case ARES_ENOMEM: return "ARES_ENOMEM"; + case ARES_EDESTRUCTION: return "ARES_EDESTRUCTION"; + case ARES_EBADSTR: return "ARES_EBADSTR"; + case ARES_EBADFLAGS: return "ARES_EBADFLAGS"; + case ARES_ENONAME: return "ARES_ENONAME"; + case ARES_EBADHINTS: return "ARES_EBADHINTS"; + case ARES_ENOTINITIALIZED: return "ARES_ENOTINITIALIZED"; + case ARES_ELOADIPHLPAPI: return "ARES_ELOADIPHLPAPI"; + case ARES_EADDRGETNETWORKPARAMS: return "ARES_EADDRGETNETWORKPARAMS"; + case ARES_ECANCELLED: return "ARES_ECANCELLED"; + default: return "UNKNOWN"; + } +} + +std::string RcodeToString(int rcode) { + switch (rcode) { + case ns_r_noerror: return "NOERROR"; + case ns_r_formerr: return "FORMERR"; + case ns_r_servfail: return "SERVFAIL"; + case ns_r_nxdomain: return "NXDOMAIN"; + case ns_r_notimpl: return "NOTIMPL"; + case ns_r_refused: return "REFUSED"; + case ns_r_yxdomain: return "YXDOMAIN"; + case ns_r_yxrrset: return "YXRRSET"; + case ns_r_nxrrset: return "NXRRSET"; + case ns_r_notauth: return "NOTAUTH"; + case ns_r_notzone: return "NOTZONE"; + case ns_r_badsig: return "BADSIG"; + case ns_r_badkey: return "BADKEY"; + case ns_r_badtime: return "BADTIME"; + default: return "UNKNOWN"; + } +} + +std::string RRTypeToString(int rrtype) { + switch (rrtype) { + case ns_t_a: return "A"; + case ns_t_ns: return "NS"; + case ns_t_md: return "MD"; + case ns_t_mf: return "MF"; + case ns_t_cname: return "CNAME"; + case ns_t_soa: return "SOA"; + case ns_t_mb: return "MB"; + case ns_t_mg: return "MG"; + case ns_t_mr: return "MR"; + case ns_t_null: return "NULL"; + case ns_t_wks: return "WKS"; + case ns_t_ptr: return "PTR"; + case ns_t_hinfo: return "HINFO"; + case ns_t_minfo: return "MINFO"; + case ns_t_mx: return "MX"; + case ns_t_txt: return "TXT"; + case ns_t_rp: return "RP"; + case ns_t_afsdb: return "AFSDB"; + case ns_t_x25: return "X25"; + case ns_t_isdn: return "ISDN"; + case ns_t_rt: return "RT"; + case ns_t_nsap: return "NSAP"; + case ns_t_nsap_ptr: return "NSAP_PTR"; + case ns_t_sig: return "SIG"; + case ns_t_key: return "KEY"; + case ns_t_px: return "PX"; + case ns_t_gpos: return "GPOS"; + case ns_t_aaaa: return "AAAA"; + case ns_t_loc: return "LOC"; + case ns_t_nxt: return "NXT"; + case ns_t_eid: return "EID"; + case ns_t_nimloc: return "NIMLOC"; + case ns_t_srv: return "SRV"; + case ns_t_atma: return "ATMA"; + case ns_t_naptr: return "NAPTR"; + case ns_t_kx: return "KX"; + case ns_t_cert: return "CERT"; + case ns_t_a6: return "A6"; + case ns_t_dname: return "DNAME"; + case ns_t_sink: return "SINK"; + case ns_t_opt: return "OPT"; + case ns_t_apl: return "APL"; + case ns_t_ds: return "DS"; + case ns_t_sshfp: return "SSHFP"; + case ns_t_rrsig: return "RRSIG"; + case ns_t_nsec: return "NSEC"; + case ns_t_dnskey: return "DNSKEY"; + case ns_t_tkey: return "TKEY"; + case ns_t_tsig: return "TSIG"; + case ns_t_ixfr: return "IXFR"; + case ns_t_axfr: return "AXFR"; + case ns_t_mailb: return "MAILB"; + case ns_t_maila: return "MAILA"; + case ns_t_any: return "ANY"; + case ns_t_zxfr: return "ZXFR"; + case ns_t_max: return "MAX"; + default: return "UNKNOWN"; + } +} + +std::string ClassToString(int qclass) { + switch (qclass) { + case ns_c_in: return "IN"; + case ns_c_chaos: return "CHAOS"; + case ns_c_hs: return "HESIOD"; + case ns_c_none: return "NONE"; + case ns_c_any: return "ANY"; + default: return "UNKNOWN"; + } +} + +std::string AddressToString(const void* vaddr, int len) { + const byte* addr = reinterpret_cast<const byte*>(vaddr); + std::stringstream ss; + if (len == 4) { + char buffer[4*4 + 3 + 1]; + sprintf(buffer, "%u.%u.%u.%u", + (unsigned char)addr[0], + (unsigned char)addr[1], + (unsigned char)addr[2], + (unsigned char)addr[3]); + ss << buffer; + } else if (len == 16) { + for (int ii = 0; ii < 16; ii+=2) { + if (ii > 0) ss << ':'; + char buffer[4 + 1]; + sprintf(buffer, "%02x%02x", (unsigned char)addr[ii], (unsigned char)addr[ii+1]); + ss << buffer; + } + } else { + ss << "!" << HexDump(addr, len) << "!"; + } + return ss.str(); +} + +std::string PacketToString(const std::vector<byte>& packet) { + const byte* data = packet.data(); + int len = packet.size(); + std::stringstream ss; + if (len < NS_HFIXEDSZ) { + ss << "(too short, len " << len << ")"; + return ss.str(); + } + ss << ((DNS_HEADER_QR(data) == 0) ? "REQ " : "RSP "); + switch (DNS_HEADER_OPCODE(data)) { + case ns_o_query: ss << "QRY "; break; + case ns_o_iquery: ss << "IQRY "; break; + case ns_o_status: ss << "STATUS "; break; + case ns_o_notify: ss << "NOTIFY "; break; + case ns_o_update: ss << "UPDATE "; break; + default: ss << "UNKNOWN(" << DNS_HEADER_OPCODE(data) << ") "; break; + } + if (DNS_HEADER_AA(data)) ss << "AA "; + if (DNS_HEADER_TC(data)) ss << "TC "; + if (DNS_HEADER_RD(data)) ss << "RD "; + if (DNS_HEADER_RA(data)) ss << "RA "; + if (DNS_HEADER_Z(data)) ss << "Z "; + if (DNS_HEADER_QR(data) == 1) ss << RcodeToString(DNS_HEADER_RCODE(data)); + + int nquestions = DNS_HEADER_QDCOUNT(data); + int nanswers = DNS_HEADER_ANCOUNT(data); + int nauths = DNS_HEADER_NSCOUNT(data); + int nadds = DNS_HEADER_ARCOUNT(data); + + const byte* pq = data + NS_HFIXEDSZ; + len -= NS_HFIXEDSZ; + for (int ii = 0; ii < nquestions; ii++) { + ss << " Q:" << QuestionToString(packet, &pq, &len); + } + const byte* prr = pq; + for (int ii = 0; ii < nanswers; ii++) { + ss << " A:" << RRToString(packet, &prr, &len); + } + for (int ii = 0; ii < nauths; ii++) { + ss << " AUTH:" << RRToString(packet, &prr, &len); + } + for (int ii = 0; ii < nadds; ii++) { + ss << " ADD:" << RRToString(packet, &prr, &len); + } + return ss.str(); +} + +std::string QuestionToString(const std::vector<byte>& packet, + const byte** data, int* len) { + std::stringstream ss; + ss << "{"; + if (*len < NS_QFIXEDSZ) { + ss << "(too short, len " << *len << ")"; + return ss.str(); + } + + char *name = nullptr; + long enclen; + int rc = ares_expand_name(*data, packet.data(), packet.size(), &name, &enclen); + if (rc != ARES_SUCCESS) { + ss << "(error from ares_expand_name)"; + return ss.str(); + } + if (enclen > *len) { + ss << "(error, encoded name len " << enclen << "bigger than remaining data " << *len << " bytes)"; + return ss.str(); + } + *len -= enclen; + *data += enclen; + ss << "'" << name << "' "; + ares_free_string(name); + if (*len < NS_QFIXEDSZ) { + ss << "(too short, len left " << *len << ")"; + return ss.str(); + } + ss << ClassToString(DNS_QUESTION_CLASS(*data)) << " "; + ss << RRTypeToString(DNS_QUESTION_TYPE(*data)); + *data += NS_QFIXEDSZ; + *len -= NS_QFIXEDSZ; + ss << "}"; + return ss.str(); +} + +std::string RRToString(const std::vector<byte>& packet, + const byte** data, int* len) { + std::stringstream ss; + ss << "{"; + if (*len < NS_RRFIXEDSZ) { + ss << "too short, len " << *len << ")"; + return ss.str(); + } + + char *name = nullptr; + long enclen; + int rc = ares_expand_name(*data, packet.data(), packet.size(), &name, &enclen); + if (rc != ARES_SUCCESS) { + ss << "(error from ares_expand_name)"; + return ss.str(); + } + if (enclen > *len) { + ss << "(error, encoded name len " << enclen << "bigger than remaining data " << *len << " bytes)"; + return ss.str(); + } + *len -= enclen; + *data += enclen; + ss << "'" << name << "' "; + ares_free_string(name); + name = nullptr; + + if (*len < NS_RRFIXEDSZ) { + ss << "(too short, len left " << *len << ")"; + return ss.str(); + } + int rrtype = DNS_RR_TYPE(*data); + if (rrtype == ns_t_opt) { + ss << "MAXUDP=" << DNS_RR_CLASS(*data) << " "; + ss << RRTypeToString(rrtype) << " "; + ss << "RCODE2=" << DNS_RR_TTL(*data); + } else { + ss << ClassToString(DNS_RR_CLASS(*data)) << " "; + ss << RRTypeToString(rrtype) << " "; + ss << "TTL=" << DNS_RR_TTL(*data); + } + int rdatalen = DNS_RR_LEN(*data); + + *data += NS_RRFIXEDSZ; + *len -= NS_RRFIXEDSZ; + if (*len < rdatalen) { + ss << "(RR too long at " << rdatalen << ", len left " << *len << ")"; + } else { + switch (rrtype) { + case ns_t_a: + case ns_t_aaaa: + ss << " " << AddressToString(*data, rdatalen); + break; + case ns_t_txt: { + const byte* p = *data; + while (p < (*data + rdatalen)) { + int len = *p++; + if ((p + len) <= (*data + rdatalen)) { + std::string txt(p, p + len); + ss << " " << len << ":'" << txt << "'"; + } else { + ss << "(string too long)"; + } + p += len; + } + break; + } + case ns_t_cname: + case ns_t_ns: + case ns_t_ptr: { + int rc = ares_expand_name(*data, packet.data(), packet.size(), &name, &enclen); + if (rc != ARES_SUCCESS) { + ss << "(error from ares_expand_name)"; + break; + } + ss << " '" << name << "'"; + ares_free_string(name); + break; + } + case ns_t_mx: + if (rdatalen > 2) { + int rc = ares_expand_name(*data + 2, packet.data(), packet.size(), &name, &enclen); + if (rc != ARES_SUCCESS) { + ss << "(error from ares_expand_name)"; + break; + } + ss << " " << DNS__16BIT(*data) << " '" << name << "'"; + ares_free_string(name); + } else { + ss << "(RR too short)"; + } + break; + case ns_t_srv: { + if (rdatalen > 6) { + const byte* p = *data; + unsigned long prio = DNS__16BIT(p); + unsigned long weight = DNS__16BIT(p + 2); + unsigned long port = DNS__16BIT(p + 4); + p += 6; + int rc = ares_expand_name(p, packet.data(), packet.size(), &name, &enclen); + if (rc != ARES_SUCCESS) { + ss << "(error from ares_expand_name)"; + break; + } + ss << prio << " " << weight << " " << port << " '" << name << "'"; + ares_free_string(name); + } else { + ss << "(RR too short)"; + } + break; + } + case ns_t_soa: { + const byte* p = *data; + int rc = ares_expand_name(p, packet.data(), packet.size(), &name, &enclen); + if (rc != ARES_SUCCESS) { + ss << "(error from ares_expand_name)"; + break; + } + ss << " '" << name << "'"; + ares_free_string(name); + p += enclen; + rc = ares_expand_name(p, packet.data(), packet.size(), &name, &enclen); + if (rc != ARES_SUCCESS) { + ss << "(error from ares_expand_name)"; + break; + } + ss << " '" << name << "'"; + ares_free_string(name); + p += enclen; + if ((p + 20) <= (*data + rdatalen)) { + unsigned long serial = DNS__32BIT(p); + unsigned long refresh = DNS__32BIT(p + 4); + unsigned long retry = DNS__32BIT(p + 8); + unsigned long expire = DNS__32BIT(p + 12); + unsigned long minimum = DNS__32BIT(p + 16); + ss << " " << serial << " " << refresh << " " << retry << " " << expire << " " << minimum; + } else { + ss << "(RR too short)"; + } + break; + } + case ns_t_naptr: { + if (rdatalen > 7) { + const byte* p = *data; + unsigned long order = DNS__16BIT(p); + unsigned long pref = DNS__16BIT(p + 2); + p += 4; + ss << order << " " << pref; + + int len = *p++; + std::string flags(p, p + len); + ss << " " << flags; + p += len; + + len = *p++; + std::string service(p, p + len); + ss << " '" << service << "'"; + p += len; + + len = *p++; + std::string regexp(p, p + len); + ss << " '" << regexp << "'"; + p += len; + + int rc = ares_expand_name(p, packet.data(), packet.size(), &name, &enclen); + if (rc != ARES_SUCCESS) { + ss << "(error from ares_expand_name)"; + break; + } + ss << " '" << name << "'"; + ares_free_string(name); + } else { + ss << "(RR too short)"; + } + break; + } + default: + ss << " " << HexDump(*data, rdatalen); + break; + } + } + *data += rdatalen; + *len -= rdatalen; + + ss << "}"; + return ss.str(); +} + +void PushInt32(std::vector<byte>* data, int value) { + data->push_back((value & 0xff000000) >> 24); + data->push_back((value & 0x00ff0000) >> 16); + data->push_back((value & 0x0000ff00) >> 8); + data->push_back(value & 0x000000ff); +} + +void PushInt16(std::vector<byte>* data, int value) { + data->push_back((value & 0xff00) >> 8); + data->push_back(value & 0x00ff); +} + +std::vector<byte> EncodeString(const std::string& name) { + std::vector<byte> data; + std::stringstream ss(name); + std::string label; + // TODO: cope with escapes + while (std::getline(ss, label, '.')) { + data.push_back(label.length()); + data.insert(data.end(), label.begin(), label.end()); + } + data.push_back(0); + return data; +} + +std::vector<byte> DNSQuestion::data() const { + std::vector<byte> data; + std::vector<byte> encname = EncodeString(name_); + data.insert(data.end(), encname.begin(), encname.end()); + PushInt16(&data, rrtype_); + PushInt16(&data, qclass_); + return data; +} + +std::vector<byte> DNSRR::data() const { + std::vector<byte> data = DNSQuestion::data(); + PushInt32(&data, ttl_); + return data; +} + +std::vector<byte> DNSSingleNameRR::data() const { + std::vector<byte> data = DNSRR::data(); + std::vector<byte> encname = EncodeString(other_); + int len = encname.size(); + PushInt16(&data, len); + data.insert(data.end(), encname.begin(), encname.end()); + return data; +} + +std::vector<byte> DNSTxtRR::data() const { + std::vector<byte> data = DNSRR::data(); + int len = 0; + for (const std::string& txt : txt_) { + len += (1 + txt.size()); + } + PushInt16(&data, len); + for (const std::string& txt : txt_) { + data.push_back(txt.size()); + data.insert(data.end(), txt.begin(), txt.end()); + } + return data; +} + +std::vector<byte> DNSMxRR::data() const { + std::vector<byte> data = DNSRR::data(); + std::vector<byte> encname = EncodeString(other_); + int len = 2 + encname.size(); + PushInt16(&data, len); + PushInt16(&data, pref_); + data.insert(data.end(), encname.begin(), encname.end()); + return data; +} + +std::vector<byte> DNSSrvRR::data() const { + std::vector<byte> data = DNSRR::data(); + std::vector<byte> encname = EncodeString(target_); + int len = 6 + encname.size(); + PushInt16(&data, len); + PushInt16(&data, prio_); + PushInt16(&data, weight_); + PushInt16(&data, port_); + data.insert(data.end(), encname.begin(), encname.end()); + return data; +} + +std::vector<byte> DNSAddressRR::data() const { + std::vector<byte> data = DNSRR::data(); + int len = addr_.size(); + PushInt16(&data, len); + data.insert(data.end(), addr_.begin(), addr_.end()); + return data; +} + +std::vector<byte> DNSSoaRR::data() const { + std::vector<byte> data = DNSRR::data(); + std::vector<byte> encname1 = EncodeString(nsname_); + std::vector<byte> encname2 = EncodeString(rname_); + int len = encname1.size() + encname2.size() + 5*4; + PushInt16(&data, len); + data.insert(data.end(), encname1.begin(), encname1.end()); + data.insert(data.end(), encname2.begin(), encname2.end()); + PushInt32(&data, serial_); + PushInt32(&data, refresh_); + PushInt32(&data, retry_); + PushInt32(&data, expire_); + PushInt32(&data, minimum_); + return data; +} + +std::vector<byte> DNSOptRR::data() const { + std::vector<byte> data = DNSRR::data(); + int len = 0; + for (const DNSOption& opt : opts_) { + len += (4 + opt.data_.size()); + } + PushInt16(&data, len); + for (const DNSOption& opt : opts_) { + PushInt16(&data, opt.code_); + PushInt16(&data, opt.data_.size()); + data.insert(data.end(), opt.data_.begin(), opt.data_.end()); + } + return data; +} + +std::vector<byte> DNSNaptrRR::data() const { + std::vector<byte> data = DNSRR::data(); + std::vector<byte> encname = EncodeString(replacement_); + int len = (4 + 1 + flags_.size() + 1 + service_.size() + 1 + regexp_.size() + encname.size()); + PushInt16(&data, len); + PushInt16(&data, order_); + PushInt16(&data, pref_); + data.push_back(flags_.size()); + data.insert(data.end(), flags_.begin(), flags_.end()); + data.push_back(service_.size()); + data.insert(data.end(), service_.begin(), service_.end()); + data.push_back(regexp_.size()); + data.insert(data.end(), regexp_.begin(), regexp_.end()); + data.insert(data.end(), encname.begin(), encname.end()); + return data; +} + +std::vector<byte> DNSPacket::data() const { + std::vector<byte> data; + PushInt16(&data, qid_); + byte b = 0x00; + if (response_) b |= 0x80; + b |= ((opcode_ & 0x0f) << 3); + if (aa_) b |= 0x04; + if (tc_) b |= 0x02; + if (rd_) b |= 0x01; + data.push_back(b); + b = 0x00; + if (ra_) b |= 0x80; + if (z_) b |= 0x40; + if (ad_) b |= 0x20; + if (cd_) b |= 0x10; + b |= (rcode_ & 0x0f); + data.push_back(b); + + int count = questions_.size(); + PushInt16(&data, count); + count = answers_.size(); + PushInt16(&data, count); + count = auths_.size(); + PushInt16(&data, count); + count = adds_.size(); + PushInt16(&data, count); + + for (const std::unique_ptr<DNSQuestion>& question : questions_) { + std::vector<byte> qdata = question->data(); + data.insert(data.end(), qdata.begin(), qdata.end()); + } + for (const std::unique_ptr<DNSRR>& rr : answers_) { + std::vector<byte> rrdata = rr->data(); + data.insert(data.end(), rrdata.begin(), rrdata.end()); + } + for (const std::unique_ptr<DNSRR>& rr : auths_) { + std::vector<byte> rrdata = rr->data(); + data.insert(data.end(), rrdata.begin(), rrdata.end()); + } + for (const std::unique_ptr<DNSRR>& rr : adds_) { + std::vector<byte> rrdata = rr->data(); + data.insert(data.end(), rrdata.begin(), rrdata.end()); + } + return data; +} + +} // namespace ares diff --git a/contrib/libs/c-ares/test/dns-proto.h b/contrib/libs/c-ares/test/dns-proto.h index 9fcb850153..346711dfe9 100644 --- a/contrib/libs/c-ares/test/dns-proto.h +++ b/contrib/libs/c-ares/test/dns-proto.h @@ -1,242 +1,242 @@ -// -*- mode: c++ -*- -#ifndef DNS_PROTO_H -#define DNS_PROTO_H -// Utilities for processing DNS packet contents - -// Include ares internal file for DNS protocol constants -#include "nameser.h" - -#include <memory> -#include <string> -#include <vector> - -namespace ares { - -typedef unsigned char byte; - -std::string HexDump(std::vector<byte> data); -std::string HexDump(const byte *data, int len); -std::string HexDump(const char *data, int len); - -std::string StatusToString(int status); -std::string RcodeToString(int rcode); -std::string RRTypeToString(int rrtype); -std::string ClassToString(int qclass); -std::string AddressToString(const void* addr, int len); - -// Convert DNS protocol data to strings. -// Note that these functions are not defensive; they assume -// a validly formatted input, and so should not be used on -// externally-determined inputs. -std::string PacketToString(const std::vector<byte>& packet); -std::string QuestionToString(const std::vector<byte>& packet, - const byte** data, int* len); -std::string RRToString(const std::vector<byte>& packet, - const byte** data, int* len); - - -// Manipulate DNS protocol data. -void PushInt32(std::vector<byte>* data, int value); -void PushInt16(std::vector<byte>* data, int value); -std::vector<byte> EncodeString(const std::string& name); - -struct DNSQuestion { - DNSQuestion(const std::string& name, ns_type rrtype, ns_class qclass) - : name_(name), rrtype_(rrtype), qclass_(qclass) {} - DNSQuestion(const std::string& name, ns_type rrtype) - : name_(name), rrtype_(rrtype), qclass_(ns_c_in) {} - virtual ~DNSQuestion() {} - virtual std::vector<byte> data() const; - std::string name_; - ns_type rrtype_; - ns_class qclass_; -}; - -struct DNSRR : public DNSQuestion { - DNSRR(const std::string& name, ns_type rrtype, ns_class qclass, int ttl) - : DNSQuestion(name, rrtype, qclass), ttl_(ttl) {} - DNSRR(const std::string& name, ns_type rrtype, int ttl) - : DNSQuestion(name, rrtype), ttl_(ttl) {} - virtual ~DNSRR() {} - virtual std::vector<byte> data() const = 0; - int ttl_; -}; - -struct DNSAddressRR : public DNSRR { - DNSAddressRR(const std::string& name, ns_type rrtype, int ttl, - const byte* addr, int addrlen) - : DNSRR(name, rrtype, ttl), addr_(addr, addr + addrlen) {} - DNSAddressRR(const std::string& name, ns_type rrtype, int ttl, - const std::vector<byte>& addr) - : DNSRR(name, rrtype, ttl), addr_(addr) {} - virtual std::vector<byte> data() const; - std::vector<byte> addr_; -}; - -struct DNSARR : public DNSAddressRR { - DNSARR(const std::string& name, int ttl, const byte* addr, int addrlen) - : DNSAddressRR(name, ns_t_a, ttl, addr, addrlen) {} - DNSARR(const std::string& name, int ttl, const std::vector<byte>& addr) - : DNSAddressRR(name, ns_t_a, ttl, addr) {} -}; - -struct DNSAaaaRR : public DNSAddressRR { - DNSAaaaRR(const std::string& name, int ttl, const byte* addr, int addrlen) - : DNSAddressRR(name, ns_t_aaaa, ttl, addr, addrlen) {} - DNSAaaaRR(const std::string& name, int ttl, const std::vector<byte>& addr) - : DNSAddressRR(name, ns_t_aaaa, ttl, addr) {} -}; - -struct DNSSingleNameRR : public DNSRR { - DNSSingleNameRR(const std::string& name, ns_type rrtype, int ttl, - const std::string& other) - : DNSRR(name, rrtype, ttl), other_(other) {} - virtual std::vector<byte> data() const; - std::string other_; -}; - -struct DNSCnameRR : public DNSSingleNameRR { - DNSCnameRR(const std::string& name, int ttl, const std::string& other) - : DNSSingleNameRR(name, ns_t_cname, ttl, other) {} -}; - -struct DNSNsRR : public DNSSingleNameRR { - DNSNsRR(const std::string& name, int ttl, const std::string& other) - : DNSSingleNameRR(name, ns_t_ns, ttl, other) {} -}; - -struct DNSPtrRR : public DNSSingleNameRR { - DNSPtrRR(const std::string& name, int ttl, const std::string& other) - : DNSSingleNameRR(name, ns_t_ptr, ttl, other) {} -}; - -struct DNSTxtRR : public DNSRR { - DNSTxtRR(const std::string& name, int ttl, const std::vector<std::string>& txt) - : DNSRR(name, ns_t_txt, ttl), txt_(txt) {} - virtual std::vector<byte> data() const; - std::vector<std::string> txt_; -}; - -struct DNSMxRR : public DNSRR { - DNSMxRR(const std::string& name, int ttl, int pref, const std::string& other) - : DNSRR(name, ns_t_mx, ttl), pref_(pref), other_(other) {} - virtual std::vector<byte> data() const; - int pref_; - std::string other_; -}; - -struct DNSSrvRR : public DNSRR { - DNSSrvRR(const std::string& name, int ttl, - int prio, int weight, int port, const std::string& target) - : DNSRR(name, ns_t_srv, ttl), prio_(prio), weight_(weight), port_(port), target_(target) {} - virtual std::vector<byte> data() const; - int prio_; - int weight_; - int port_; - std::string target_; -}; - -struct DNSSoaRR : public DNSRR { - DNSSoaRR(const std::string& name, int ttl, - const std::string& nsname, const std::string& rname, - int serial, int refresh, int retry, int expire, int minimum) - : DNSRR(name, ns_t_soa, ttl), nsname_(nsname), rname_(rname), - serial_(serial), refresh_(refresh), retry_(retry), - expire_(expire), minimum_(minimum) {} - virtual std::vector<byte> data() const; - std::string nsname_; - std::string rname_; - int serial_; - int refresh_; - int retry_; - int expire_; - int minimum_; -}; - -struct DNSNaptrRR : public DNSRR { - DNSNaptrRR(const std::string& name, int ttl, - int order, int pref, - const std::string& flags, - const std::string& service, - const std::string& regexp, - const std::string& replacement) - : DNSRR(name, ns_t_naptr, ttl), order_(order), pref_(pref), - flags_(flags), service_(service), regexp_(regexp), replacement_(replacement) {} - virtual std::vector<byte> data() const; - int order_; - int pref_; - std::string flags_; - std::string service_; - std::string regexp_; - std::string replacement_; -}; - -struct DNSOption { - int code_; - std::vector<byte> data_; -}; - -struct DNSOptRR : public DNSRR { - DNSOptRR(int extrcode, int udpsize) - : DNSRR("", ns_t_opt, static_cast<ns_class>(udpsize), extrcode) {} - virtual std::vector<byte> data() const; - std::vector<DNSOption> opts_; -}; - -struct DNSPacket { - DNSPacket() - : qid_(0), response_(false), opcode_(ns_o_query), - aa_(false), tc_(false), rd_(false), ra_(false), - z_(false), ad_(false), cd_(false), rcode_(ns_r_noerror) {} - // Convenience functions that take ownership of given pointers. - DNSPacket& add_question(DNSQuestion *q) { - questions_.push_back(std::unique_ptr<DNSQuestion>(q)); - return *this; - } - DNSPacket& add_answer(DNSRR *q) { - answers_.push_back(std::unique_ptr<DNSRR>(q)); - return *this; - } - DNSPacket& add_auth(DNSRR *q) { - auths_.push_back(std::unique_ptr<DNSRR>(q)); - return *this; - } - DNSPacket& add_additional(DNSRR *q) { - adds_.push_back(std::unique_ptr<DNSRR>(q)); - return *this; - } - // Chainable setters. - DNSPacket& set_qid(int qid) { qid_ = qid; return *this; } - DNSPacket& set_response(bool v = true) { response_ = v; return *this; } - DNSPacket& set_aa(bool v = true) { aa_ = v; return *this; } - DNSPacket& set_tc(bool v = true) { tc_ = v; return *this; } - DNSPacket& set_rd(bool v = true) { rd_ = v; return *this; } - DNSPacket& set_ra(bool v = true) { ra_ = v; return *this; } - DNSPacket& set_z(bool v = true) { z_ = v; return *this; } - DNSPacket& set_ad(bool v = true) { ad_ = v; return *this; } - DNSPacket& set_cd(bool v = true) { cd_ = v; return *this; } - DNSPacket& set_rcode(ns_rcode rcode) { rcode_ = rcode; return *this; } - - // Return the encoded packet. - std::vector<byte> data() const; - - int qid_; - bool response_; - ns_opcode opcode_; - bool aa_; - bool tc_; - bool rd_; - bool ra_; - bool z_; - bool ad_; - bool cd_; - ns_rcode rcode_; - std::vector<std::unique_ptr<DNSQuestion>> questions_; - std::vector<std::unique_ptr<DNSRR>> answers_; - std::vector<std::unique_ptr<DNSRR>> auths_; - std::vector<std::unique_ptr<DNSRR>> adds_; -}; - -} // namespace ares - -#endif +// -*- mode: c++ -*- +#ifndef DNS_PROTO_H +#define DNS_PROTO_H +// Utilities for processing DNS packet contents + +// Include ares internal file for DNS protocol constants +#include "nameser.h" + +#include <memory> +#include <string> +#include <vector> + +namespace ares { + +typedef unsigned char byte; + +std::string HexDump(std::vector<byte> data); +std::string HexDump(const byte *data, int len); +std::string HexDump(const char *data, int len); + +std::string StatusToString(int status); +std::string RcodeToString(int rcode); +std::string RRTypeToString(int rrtype); +std::string ClassToString(int qclass); +std::string AddressToString(const void* addr, int len); + +// Convert DNS protocol data to strings. +// Note that these functions are not defensive; they assume +// a validly formatted input, and so should not be used on +// externally-determined inputs. +std::string PacketToString(const std::vector<byte>& packet); +std::string QuestionToString(const std::vector<byte>& packet, + const byte** data, int* len); +std::string RRToString(const std::vector<byte>& packet, + const byte** data, int* len); + + +// Manipulate DNS protocol data. +void PushInt32(std::vector<byte>* data, int value); +void PushInt16(std::vector<byte>* data, int value); +std::vector<byte> EncodeString(const std::string& name); + +struct DNSQuestion { + DNSQuestion(const std::string& name, ns_type rrtype, ns_class qclass) + : name_(name), rrtype_(rrtype), qclass_(qclass) {} + DNSQuestion(const std::string& name, ns_type rrtype) + : name_(name), rrtype_(rrtype), qclass_(ns_c_in) {} + virtual ~DNSQuestion() {} + virtual std::vector<byte> data() const; + std::string name_; + ns_type rrtype_; + ns_class qclass_; +}; + +struct DNSRR : public DNSQuestion { + DNSRR(const std::string& name, ns_type rrtype, ns_class qclass, int ttl) + : DNSQuestion(name, rrtype, qclass), ttl_(ttl) {} + DNSRR(const std::string& name, ns_type rrtype, int ttl) + : DNSQuestion(name, rrtype), ttl_(ttl) {} + virtual ~DNSRR() {} + virtual std::vector<byte> data() const = 0; + int ttl_; +}; + +struct DNSAddressRR : public DNSRR { + DNSAddressRR(const std::string& name, ns_type rrtype, int ttl, + const byte* addr, int addrlen) + : DNSRR(name, rrtype, ttl), addr_(addr, addr + addrlen) {} + DNSAddressRR(const std::string& name, ns_type rrtype, int ttl, + const std::vector<byte>& addr) + : DNSRR(name, rrtype, ttl), addr_(addr) {} + virtual std::vector<byte> data() const; + std::vector<byte> addr_; +}; + +struct DNSARR : public DNSAddressRR { + DNSARR(const std::string& name, int ttl, const byte* addr, int addrlen) + : DNSAddressRR(name, ns_t_a, ttl, addr, addrlen) {} + DNSARR(const std::string& name, int ttl, const std::vector<byte>& addr) + : DNSAddressRR(name, ns_t_a, ttl, addr) {} +}; + +struct DNSAaaaRR : public DNSAddressRR { + DNSAaaaRR(const std::string& name, int ttl, const byte* addr, int addrlen) + : DNSAddressRR(name, ns_t_aaaa, ttl, addr, addrlen) {} + DNSAaaaRR(const std::string& name, int ttl, const std::vector<byte>& addr) + : DNSAddressRR(name, ns_t_aaaa, ttl, addr) {} +}; + +struct DNSSingleNameRR : public DNSRR { + DNSSingleNameRR(const std::string& name, ns_type rrtype, int ttl, + const std::string& other) + : DNSRR(name, rrtype, ttl), other_(other) {} + virtual std::vector<byte> data() const; + std::string other_; +}; + +struct DNSCnameRR : public DNSSingleNameRR { + DNSCnameRR(const std::string& name, int ttl, const std::string& other) + : DNSSingleNameRR(name, ns_t_cname, ttl, other) {} +}; + +struct DNSNsRR : public DNSSingleNameRR { + DNSNsRR(const std::string& name, int ttl, const std::string& other) + : DNSSingleNameRR(name, ns_t_ns, ttl, other) {} +}; + +struct DNSPtrRR : public DNSSingleNameRR { + DNSPtrRR(const std::string& name, int ttl, const std::string& other) + : DNSSingleNameRR(name, ns_t_ptr, ttl, other) {} +}; + +struct DNSTxtRR : public DNSRR { + DNSTxtRR(const std::string& name, int ttl, const std::vector<std::string>& txt) + : DNSRR(name, ns_t_txt, ttl), txt_(txt) {} + virtual std::vector<byte> data() const; + std::vector<std::string> txt_; +}; + +struct DNSMxRR : public DNSRR { + DNSMxRR(const std::string& name, int ttl, int pref, const std::string& other) + : DNSRR(name, ns_t_mx, ttl), pref_(pref), other_(other) {} + virtual std::vector<byte> data() const; + int pref_; + std::string other_; +}; + +struct DNSSrvRR : public DNSRR { + DNSSrvRR(const std::string& name, int ttl, + int prio, int weight, int port, const std::string& target) + : DNSRR(name, ns_t_srv, ttl), prio_(prio), weight_(weight), port_(port), target_(target) {} + virtual std::vector<byte> data() const; + int prio_; + int weight_; + int port_; + std::string target_; +}; + +struct DNSSoaRR : public DNSRR { + DNSSoaRR(const std::string& name, int ttl, + const std::string& nsname, const std::string& rname, + int serial, int refresh, int retry, int expire, int minimum) + : DNSRR(name, ns_t_soa, ttl), nsname_(nsname), rname_(rname), + serial_(serial), refresh_(refresh), retry_(retry), + expire_(expire), minimum_(minimum) {} + virtual std::vector<byte> data() const; + std::string nsname_; + std::string rname_; + int serial_; + int refresh_; + int retry_; + int expire_; + int minimum_; +}; + +struct DNSNaptrRR : public DNSRR { + DNSNaptrRR(const std::string& name, int ttl, + int order, int pref, + const std::string& flags, + const std::string& service, + const std::string& regexp, + const std::string& replacement) + : DNSRR(name, ns_t_naptr, ttl), order_(order), pref_(pref), + flags_(flags), service_(service), regexp_(regexp), replacement_(replacement) {} + virtual std::vector<byte> data() const; + int order_; + int pref_; + std::string flags_; + std::string service_; + std::string regexp_; + std::string replacement_; +}; + +struct DNSOption { + int code_; + std::vector<byte> data_; +}; + +struct DNSOptRR : public DNSRR { + DNSOptRR(int extrcode, int udpsize) + : DNSRR("", ns_t_opt, static_cast<ns_class>(udpsize), extrcode) {} + virtual std::vector<byte> data() const; + std::vector<DNSOption> opts_; +}; + +struct DNSPacket { + DNSPacket() + : qid_(0), response_(false), opcode_(ns_o_query), + aa_(false), tc_(false), rd_(false), ra_(false), + z_(false), ad_(false), cd_(false), rcode_(ns_r_noerror) {} + // Convenience functions that take ownership of given pointers. + DNSPacket& add_question(DNSQuestion *q) { + questions_.push_back(std::unique_ptr<DNSQuestion>(q)); + return *this; + } + DNSPacket& add_answer(DNSRR *q) { + answers_.push_back(std::unique_ptr<DNSRR>(q)); + return *this; + } + DNSPacket& add_auth(DNSRR *q) { + auths_.push_back(std::unique_ptr<DNSRR>(q)); + return *this; + } + DNSPacket& add_additional(DNSRR *q) { + adds_.push_back(std::unique_ptr<DNSRR>(q)); + return *this; + } + // Chainable setters. + DNSPacket& set_qid(int qid) { qid_ = qid; return *this; } + DNSPacket& set_response(bool v = true) { response_ = v; return *this; } + DNSPacket& set_aa(bool v = true) { aa_ = v; return *this; } + DNSPacket& set_tc(bool v = true) { tc_ = v; return *this; } + DNSPacket& set_rd(bool v = true) { rd_ = v; return *this; } + DNSPacket& set_ra(bool v = true) { ra_ = v; return *this; } + DNSPacket& set_z(bool v = true) { z_ = v; return *this; } + DNSPacket& set_ad(bool v = true) { ad_ = v; return *this; } + DNSPacket& set_cd(bool v = true) { cd_ = v; return *this; } + DNSPacket& set_rcode(ns_rcode rcode) { rcode_ = rcode; return *this; } + + // Return the encoded packet. + std::vector<byte> data() const; + + int qid_; + bool response_; + ns_opcode opcode_; + bool aa_; + bool tc_; + bool rd_; + bool ra_; + bool z_; + bool ad_; + bool cd_; + ns_rcode rcode_; + std::vector<std::unique_ptr<DNSQuestion>> questions_; + std::vector<std::unique_ptr<DNSRR>> answers_; + std::vector<std::unique_ptr<DNSRR>> auths_; + std::vector<std::unique_ptr<DNSRR>> adds_; +}; + +} // namespace ares + +#endif diff --git a/contrib/libs/c-ares/test/ya.make b/contrib/libs/c-ares/test/ya.make index fb81afa54e..ef42eab230 100644 --- a/contrib/libs/c-ares/test/ya.make +++ b/contrib/libs/c-ares/test/ya.make @@ -1,60 +1,60 @@ -# Generated by devtools/yamaker. - +# Generated by devtools/yamaker. + GTEST(arestest) - + OWNER(max42 g:cpp-contrib) - -LICENSE(MIT) - -SIZE(MEDIUM) - -TAG(ya:external) - -REQUIREMENTS(network:full) - -PEERDIR( - contrib/libs/c-ares -) - -ADDINCL( - contrib/libs/c-ares - contrib/libs/c-ares/test -) - -NO_COMPILER_WARNINGS() - + +LICENSE(MIT) + +SIZE(MEDIUM) + +TAG(ya:external) + +REQUIREMENTS(network:full) + +PEERDIR( + contrib/libs/c-ares +) + +ADDINCL( + contrib/libs/c-ares + contrib/libs/c-ares/test +) + +NO_COMPILER_WARNINGS() + CFLAGS( -DHAVE_CONFIG_H ) -IF (NOT DLL_FOR) - CFLAGS( - -DCARES_STATICLIB - ) -ENDIF() - -SRCS( - ares-test-init.cc - ares-test-internal.cc - ares-test-live.cc - ares-test-misc.cc +IF (NOT DLL_FOR) + CFLAGS( + -DCARES_STATICLIB + ) +ENDIF() + +SRCS( + ares-test-init.cc + ares-test-internal.cc + ares-test-live.cc + ares-test-misc.cc ares-test-mock-ai.cc - ares-test-mock.cc - ares-test-ns.cc - ares-test-parse-a.cc - ares-test-parse-aaaa.cc - ares-test-parse-mx.cc - ares-test-parse-naptr.cc - ares-test-parse-ns.cc - ares-test-parse-ptr.cc + ares-test-mock.cc + ares-test-ns.cc + ares-test-parse-a.cc + ares-test-parse-aaaa.cc + ares-test-parse-mx.cc + ares-test-parse-naptr.cc + ares-test-parse-ns.cc + ares-test-parse-ptr.cc ares-test-parse-soa-any.cc - ares-test-parse-soa.cc - ares-test-parse-srv.cc - ares-test-parse-txt.cc - ares-test-parse.cc - ares-test.cc - dns-proto-test.cc - dns-proto.cc -) - -END() + ares-test-parse-soa.cc + ares-test-parse-srv.cc + ares-test-parse-txt.cc + ares-test-parse.cc + ares-test.cc + dns-proto-test.cc + dns-proto.cc +) + +END() diff --git a/contrib/libs/c-ares/ya.make b/contrib/libs/c-ares/ya.make index 29d591935e..bd35762e44 100644 --- a/contrib/libs/c-ares/ya.make +++ b/contrib/libs/c-ares/ya.make @@ -1,5 +1,5 @@ # Generated by devtools/yamaker from nixpkgs e392df43c9f302d4a0892caaadcad3cd693edf9e. - + LIBRARY() OWNER( @@ -8,7 +8,7 @@ OWNER( ) VERSION(1.16.1) - + ORIGINAL_SOURCE(https://c-ares.haxx.se/download/c-ares-1.16.1.tar.gz) LICENSE( @@ -30,12 +30,12 @@ ADDINCL( NO_COMPILER_WARNINGS() -CFLAGS( - -DCARES_BUILDING_LIBRARY - -DCARES_SYMBOL_HIDING +CFLAGS( + -DCARES_BUILDING_LIBRARY + -DCARES_SYMBOL_HIDING -DHAVE_CONFIG_H -) - +) + IF (NOT DLL_FOR) CFLAGS( -DCARES_STATICLIB @@ -97,7 +97,7 @@ SRCS( ares_strcasecmp.c ares_strdup.c ares_strerror.c - ares_strsplit.c + ares_strsplit.c ares_timeout.c ares_version.c ares_writev.c @@ -111,10 +111,10 @@ SRCS( CHECK_CONFIG_H(ares_setup.h) END() - -RECURSE( - acountry - adig - ahost - test -) + +RECURSE( + acountry + adig + ahost + test +) |