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/test | |
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/test')
23 files changed, 7997 insertions, 7997 deletions
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() |