From 5da3201a05b5b81ab7841ab3503aacd5995b1c99 Mon Sep 17 00:00:00 2001 From: David Drysdale Date: Tue, 12 Jan 2016 10:16:20 +0000 Subject: [PATCH] test: More tests Include tests of internal functions, based on the value of the CARES_SYMBOL_HIDING macro; need to configure the library with --disable-symbol-hiding to enable these tests. --- test/ares-test-init.cc | 6 ++ test/ares-test-internal.cc | 93 +++++++++++++++++++++++++--- test/ares-test-live.cc | 47 +++++++++++--- test/ares-test-misc.cc | 121 ++++++++++++++++++++++++++++++++++++- test/ares-test-parse.cc | 15 ++++- test/configure.ac | 2 +- test/dns-proto.cc | 1 - 7 files changed, 261 insertions(+), 24 deletions(-) diff --git a/test/ares-test-init.cc b/test/ares-test-init.cc index 1439784..03f2748 100644 --- a/test/ares-test-init.cc +++ b/test/ares-test-init.cc @@ -19,6 +19,12 @@ TEST(LibraryInit, Basic) { 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)); diff --git a/test/ares-test-internal.cc b/test/ares-test-internal.cc index 3bda6f0..84543ed 100644 --- a/test/ares-test-internal.cc +++ b/test/ares-test-internal.cc @@ -2,9 +2,22 @@ #include "dns-proto.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_config.h" #include "ares_nowarn.h" #include "ares_inet_net_pton.h" +#include "ares_data.h" #include "bitncmp.h" +char *ares_strdup(const char*); + +#ifdef HAVE_ARPA_INET_H +#include +#endif } #include @@ -16,13 +29,15 @@ namespace test { TEST_F(LibraryTest, InetPtoN) { struct in_addr a4; struct in6_addr a6; -#ifdef DISABLED - EXPECT_EQ(1, ares_inet_net_pton(AF_INET, "1.2.3.4", &a4, sizeof(a4))); - EXPECT_EQ(1, ares_inet_net_pton(AF_INET6, "12:34::ff", &a6, sizeof(a6))); - EXPECT_EQ(1, ares_inet_net_pton(AF_INET6, "12:34::ffff:1.2.3.4", &a6, sizeof(a6))); - EXPECT_EQ(0, ares_inet_net_pton(AF_INET, "xyzzy", &a4, sizeof(a4))); + +#ifndef CARES_SYMBOL_HIDING + EXPECT_EQ(4 * 8, ares_inet_net_pton(AF_INET, "1.2.3.4", &a4, sizeof(a4))); + 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(-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))); #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)); @@ -30,27 +45,87 @@ TEST_F(LibraryTest, InetPtoN) { EXPECT_EQ(-1, ares_inet_pton(AF_INET+AF_INET6, "1.2.3.4", &a4)); } -#ifdef DISABLED +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(LibraryInit, StrdupFailures) { + EXPECT_EQ(ARES_SUCCESS, ares_library_init(ARES_LIB_INIT_ALL)); + char* copy = ares_strdup("string"); + EXPECT_NE(nullptr, copy); + 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}; - EXPECT_EQ(-1, ares__bitncmp(a, b, sizeof(a)*8)); - EXPECT_EQ(1, ares__bitncmp(b, a, sizeof(a)*8)); + 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) { 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); } #endif - } // namespace test } // namespace ares diff --git a/test/ares-test-live.cc b/test/ares-test-live.cc index 7d4b85c..486fa45 100644 --- a/test/ares-test-live.cc +++ b/test/ares-test-live.cc @@ -13,6 +13,7 @@ TEST_F(DefaultChannelTest, LiveGetHostByNameV4) { 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_); } @@ -22,6 +23,7 @@ TEST_F(DefaultChannelTest, LiveGetHostByNameV6) { 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_); } @@ -32,6 +34,7 @@ TEST_F(DefaultChannelTest, LiveGetHostByAddrV4) { ares_gethostbyaddr(channel_, addr, sizeof(addr), 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_); } @@ -43,16 +46,46 @@ TEST_F(DefaultChannelTest, LiveGetHostByAddrV6) { ares_gethostbyaddr(channel_, addr, sizeof(addr), 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_); } +TEST_F(DefaultChannelTest, 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_F(DefaultChannelTest, 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_F(DefaultChannelTest, 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_); +} + TEST_F(DefaultChannelTest, LiveSearchA) { SearchResult result; ares_search(channel_, "www.facebook.com.", ns_c_in, ns_t_a, SearchCallback, &result); Process(); EXPECT_TRUE(result.done_); + EXPECT_EQ(ARES_SUCCESS, result.status_); } TEST_F(DefaultChannelTest, LiveSearchNS) { @@ -61,6 +94,7 @@ TEST_F(DefaultChannelTest, LiveSearchNS) { SearchCallback, &result); Process(); EXPECT_TRUE(result.done_); + EXPECT_EQ(ARES_SUCCESS, result.status_); } TEST_F(DefaultChannelTest, LiveSearchMX) { @@ -69,6 +103,7 @@ TEST_F(DefaultChannelTest, LiveSearchMX) { SearchCallback, &result); Process(); EXPECT_TRUE(result.done_); + EXPECT_EQ(ARES_SUCCESS, result.status_); } TEST_F(DefaultChannelTest, LiveSearchTXT) { @@ -77,6 +112,7 @@ TEST_F(DefaultChannelTest, LiveSearchTXT) { SearchCallback, &result); Process(); EXPECT_TRUE(result.done_); + EXPECT_EQ(ARES_SUCCESS, result.status_); } TEST_F(DefaultChannelTest, LiveSearchSOA) { @@ -85,6 +121,7 @@ TEST_F(DefaultChannelTest, LiveSearchSOA) { SearchCallback, &result); Process(); EXPECT_TRUE(result.done_); + EXPECT_EQ(ARES_SUCCESS, result.status_); } TEST_F(DefaultChannelTest, LiveSearchANY) { @@ -93,6 +130,7 @@ TEST_F(DefaultChannelTest, LiveSearchANY) { SearchCallback, &result); Process(); EXPECT_TRUE(result.done_); + EXPECT_EQ(ARES_SUCCESS, result.status_); } TEST_F(DefaultChannelTest, LiveGetNameInfo) { @@ -107,14 +145,7 @@ TEST_F(DefaultChannelTest, LiveGetNameInfo) { NameInfoCallback, &result); Process(); EXPECT_TRUE(result.done_); - -CARES_EXTERN void ares_getnameinfo(ares_channel channel, - const struct sockaddr *sa, - ares_socklen_t salen, - int flags, - ares_nameinfo_callback callback, - void *arg); - + EXPECT_EQ(ARES_SUCCESS, result.status_); } } // namespace test diff --git a/test/ares-test-misc.cc b/test/ares-test-misc.cc index a9583db..ddec015 100644 --- a/test/ares-test-misc.cc +++ b/test/ares-test-misc.cc @@ -26,7 +26,7 @@ std::vector GetNameServers(ares_channel channel) { } server = server->next; } - ares_free_data(servers); + if (servers) ares_free_data(servers); return results; } @@ -39,6 +39,17 @@ TEST_F(DefaultChannelTest, GetServers) { } } +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 empty; @@ -79,6 +90,19 @@ TEST_F(DefaultChannelTest, SetServersCSV) { 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_)); + + // 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 none; + EXPECT_EQ(none, GetNameServers(channel_)); + } TEST_F(DefaultChannelTest, TimeoutValue) { @@ -143,7 +167,9 @@ TEST_F(LibraryTest, Mkquery) { TEST_F(LibraryTest, CreateQuery) { byte* p; int len; - ares_create_query("exam\\@le.com", ns_c_in, ns_t_a, 0x1234, 0, &p, &len, 0); + EXPECT_EQ(ARES_SUCCESS, + ares_create_query("exam\\@le.com", ns_c_in, ns_t_a, 0x1234, 0, + &p, &len, 0)); std::vector data(p, p + len); ares_free_string(p); @@ -154,10 +180,95 @@ TEST_F(LibraryTest, CreateQuery) { EXPECT_EQ(expected, actual); } +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"; + } + EXPECT_EQ(ARES_EBADNAME, + ares_create_query(longname.c_str(), ns_c_in, ns_t_a, 0x1234, 0, + &p, &len, 0)); + SetAllocFail(1); + EXPECT_EQ(ARES_ENOMEM, + ares_create_query("example.com", ns_c_in, ns_t_a, 0x1234, 0, + &p, &len, 0)); + + // 63-char limit on a single label + std::string longlabel = "a.a123456789b123456789c123456789d123456789e123456789f123456789g123456789.org"; + EXPECT_EQ(ARES_EBADNAME, + ares_create_query(longlabel.c_str(), ns_c_in, ns_t_a, 0x1234, 0, + &p, &len, 0)); + // Empty non-terminal label + EXPECT_EQ(ARES_EBADNAME, + ares_create_query("example..com", ns_c_in, ns_t_a, 0x1234, 0, + &p, &len, 0)); +} + +TEST_F(LibraryTest, ExpandNameFailure) { + std::vector 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)); + + // 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 data2 = {0x13, 'c', 'o', 'm', 0x00}; + EXPECT_EQ(ARES_EBADNAME, + ares_expand_name(data2.data(), data2.data(), data2.size(), + &name, &enclen)); + + // Indirection beyond enclosing data + std::vector data3 = {0xCA, 'c', 'o', 'm', 0x00}; + EXPECT_EQ(ARES_EBADNAME, + ares_expand_name(data3.data(), data3.data(), data3.size(), + &name, &enclen)); + + // Invalid top bits in label length + std::vector 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 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 data6 = {0x03, 'c', 'o', 'm', 0x00, 0xC0}; + EXPECT_EQ(ARES_EBADNAME, + ares_expand_name(data6.data() + 5, data6.data(), data6.size(), + &name, &enclen)); + + // Indirection loop + std::vector data7 = {0xC0, 0x02, 0xC0, 0x00}; + EXPECT_EQ(ARES_EBADNAME, + ares_expand_name(data7.data(), data7.data(), data7.size(), + &name, &enclen)); +} + TEST_F(LibraryTest, CreateEDNSQuery) { byte* p; int len; - ares_create_query("example.com", ns_c_in, ns_t_a, 0x1234, 0, &p, &len, 1280); + EXPECT_EQ(ARES_SUCCESS, + ares_create_query("example.com", ns_c_in, ns_t_a, 0x1234, 0, + &p, &len, 1280)); std::vector data(p, p + len); ares_free_string(p); @@ -216,6 +327,10 @@ TEST_F(LibraryTest, ExpandString) { 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 diff --git a/test/ares-test-parse.cc b/test/ares-test-parse.cc index 39fd4cb..2057b49 100644 --- a/test/ares-test-parse.cc +++ b/test/ares-test-parse.cc @@ -411,7 +411,9 @@ TEST_F(LibraryTest, ParseNaptrReplyOK) { pkt.set_qid(0x1234).set_response().set_aa() .add_question(new DNSQuestion("example.com", ns_t_soa)) .add_answer(new DNSNaptrRR("example.com", 0x01020304, - 10, 20, "SP", "service", "regexp", "replace")); + 10, 20, "SP", "service", "regexp", "replace")) + .add_answer(new DNSNaptrRR("example.com", 0x0010, + 11, 21, "SP", "service2", "regexp2", "replace2")); std::vector data = pkt.data(); struct ares_naptr_reply* naptr = nullptr; @@ -423,7 +425,16 @@ TEST_F(LibraryTest, ParseNaptrReplyOK) { EXPECT_EQ("replace", std::string((char*)naptr->replacement)); EXPECT_EQ(10, naptr->order); EXPECT_EQ(20, naptr->preference); - EXPECT_EQ(nullptr, naptr->next); + + 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); } diff --git a/test/configure.ac b/test/configure.ac index 9a89157..743d825 100644 --- a/test/configure.ac +++ b/test/configure.ac @@ -3,7 +3,7 @@ AC_INIT([c-ares-test],[-],[-]) AC_CONFIG_SRCDIR([ares-test.cc]) AC_CONFIG_MACRO_DIR([../m4]) -AM_INIT_AUTOMAKE() +AM_INIT_AUTOMAKE([no-define]) dnl Checks for programs. AC_PROG_CXX diff --git a/test/dns-proto.cc b/test/dns-proto.cc index 89582e1..d6fe86a 100644 --- a/test/dns-proto.cc +++ b/test/dns-proto.cc @@ -369,7 +369,6 @@ std::string RRToString(const std::vector& packet, ares_expand_name(p, packet.data(), packet.size(), &name, &enclen); ss << " '" << name << "'"; free(name); - p += enclen; break; } default: