/* MIT License * * Copyright (c) The c-ares project and its contributors * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice (including the next * paragraph) shall be included in all copies or substantial portions of the * Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * SPDX-License-Identifier: MIT */ #include "ares-test.h" #include "dns-proto.h" #include #ifdef HAVE_UNISTD_H #include #endif #include #ifdef HAVE_SYS_IOCTL_H # include #endif 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_private.h" #include "ares_inet_net_pton.h" #include "ares_data.h" #include "str/ares_strsplit.h" #include "dsa/ares_htable.h" #ifdef HAVE_ARPA_INET_H #include #endif #ifdef HAVE_SYS_UIO_H # include #endif } #include #include 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; } TEST_F(LibraryTest, Strsplit) { using std::vector; using std::string; size_t n; struct { vector inputs; vector delimiters; vector> expected; } data = { { "", " ", " ", "example.com, example.co", " a, b, A,c, d, e,,,D,e,e,E", }, { ", ", ", ", ", ", ", ", ", " }, { {}, {}, {}, { "example.com", "example.co" }, { "a", "b", "c", "d", "e" }, }, }; for(size_t i = 0; i < data.inputs.size(); i++) { char **out = ares_strsplit(data.inputs.at(i).c_str(), data.delimiters.at(i).c_str(), &n); if(data.expected.at(i).size() == 0) { EXPECT_EQ(out, nullptr); } else { EXPECT_EQ(n, data.expected.at(i).size()); for(size_t j = 0; j < n && j < data.expected.at(i).size(); j++) { EXPECT_STREQ(out[j], data.expected.at(i).at(j).c_str()); } } ares_strsplit_free(out, n); } } TEST_F(LibraryTest, InetNetPtoN) { uint32_t expected; struct in_addr a4; struct in6_addr a6; 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))); EXPECT_EQ(2, ares_inet_net_pton(AF_INET6, "0::00:00:00/2", &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))); EXPECT_EQ(-1, ares_inet_net_pton(AF_INET6, "1234:1234:1234:1234:1234:1234:1234:1234:5678:5678", &a6, sizeof(a6))); EXPECT_EQ(-1, 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: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)); } 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_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, 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.")); } TEST_F(LibraryTest, CatDomain) { char *s; ares_cat_domain("foo", "example.net", &s); EXPECT_STREQ("foo.example.net", s); ares_free(s); ares_cat_domain("foo", ".", &s); EXPECT_STREQ("foo.", s); ares_free(s); ares_cat_domain("foo", "example.net.", &s); EXPECT_STREQ("foo.example.net.", s); ares_free(s); } TEST_F(LibraryTest, SlistMisuse) { EXPECT_EQ(NULL, ares_slist_create(NULL, NULL, NULL)); ares_slist_replace_destructor(NULL, NULL); EXPECT_EQ(NULL, ares_slist_insert(NULL, NULL)); EXPECT_EQ(NULL, ares_slist_node_find(NULL, NULL)); EXPECT_EQ(NULL, ares_slist_node_first(NULL)); EXPECT_EQ(NULL, ares_slist_node_last(NULL)); EXPECT_EQ(NULL, ares_slist_node_next(NULL)); EXPECT_EQ(NULL, ares_slist_node_prev(NULL)); EXPECT_EQ(NULL, ares_slist_node_val(NULL)); EXPECT_EQ((size_t)0, ares_slist_len(NULL)); EXPECT_EQ(NULL, ares_slist_node_parent(NULL)); EXPECT_EQ(NULL, ares_slist_first_val(NULL)); EXPECT_EQ(NULL, ares_slist_last_val(NULL)); EXPECT_EQ(NULL, ares_slist_node_claim(NULL)); } TEST_F(LibraryTest, IfaceIPs) { ares_status_t status; ares_iface_ips_t *ips = NULL; size_t i; status = ares_iface_ips(&ips, ARES_IFACE_IP_DEFAULT, NULL); EXPECT_TRUE(status == ARES_SUCCESS || status == ARES_ENOTIMP); /* Not implemented, can't run tests */ if (status == ARES_ENOTIMP) return; EXPECT_NE(nullptr, ips); for (i=0; idata); // Invalid type data->type = (ares_datatype)ARES_DATATYPE_LAST; 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); } 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(FileChannelTest, GetAddrInfoHostsPositive) { 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"); EnvValue with_env("CARES_HOSTS", hostsfile.filename()); struct ares_addrinfo_hints hints = {0, 0, 0, 0}; AddrInfoResult result = {}; hints.ai_family = AF_INET; hints.ai_flags = ARES_AI_CANONNAME | ARES_AI_ENVHOSTS | ARES_AI_NOSORT; ares_getaddrinfo(channel_, "example.com", NULL, &hints, AddrInfoCallback, &result); Process(); EXPECT_TRUE(result.done_); std::stringstream ss; ss << result.ai_; EXPECT_EQ("{example.com addr=[1.2.3.4]}", ss.str()); } TEST_F(FileChannelTest, GetAddrInfoHostsSpaces) { 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"); EnvValue with_env("CARES_HOSTS", hostsfile.filename()); struct ares_addrinfo_hints hints = {0, 0, 0, 0}; AddrInfoResult result = {}; hints.ai_family = AF_INET; hints.ai_flags = ARES_AI_CANONNAME | ARES_AI_ENVHOSTS | ARES_AI_NOSORT; ares_getaddrinfo(channel_, "google.com", NULL, &hints, AddrInfoCallback, &result); Process(); EXPECT_TRUE(result.done_); std::stringstream ss; ss << result.ai_; EXPECT_EQ("{www.google.com->google.com, www2.google.com->google.com addr=[2.3.4.5]}", ss.str()); } TEST_F(FileChannelTest, GetAddrInfoHostsByALias) { 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"); EnvValue with_env("CARES_HOSTS", hostsfile.filename()); struct ares_addrinfo_hints hints = {0, 0, 0, 0}; AddrInfoResult result = {}; hints.ai_family = AF_INET; hints.ai_flags = ARES_AI_CANONNAME | ARES_AI_ENVHOSTS | ARES_AI_NOSORT; ares_getaddrinfo(channel_, "www2.google.com", NULL, &hints, AddrInfoCallback, &result); Process(); EXPECT_TRUE(result.done_); std::stringstream ss; ss << result.ai_; EXPECT_EQ("{www.google.com->google.com, www2.google.com->google.com addr=[2.3.4.5]}", ss.str()); } TEST_F(FileChannelTest, GetAddrInfoHostsIPV6) { 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"); EnvValue with_env("CARES_HOSTS", hostsfile.filename()); struct ares_addrinfo_hints hints = {0, 0, 0, 0}; AddrInfoResult result = {}; hints.ai_family = AF_INET6; hints.ai_flags = ARES_AI_CANONNAME | ARES_AI_ENVHOSTS | ARES_AI_NOSORT; ares_getaddrinfo(channel_, "ipv6.com", NULL, &hints, AddrInfoCallback, &result); Process(); EXPECT_TRUE(result.done_); std::stringstream ss; ss << result.ai_; EXPECT_EQ("{ipv6.com addr=[[0000:0000:0000:0000:0000:0000:0000:0001]]}", ss.str()); } TEST_F(FileChannelTest, GetAddrInfoAllocFail) { TempFile hostsfile("1.2.3.4 example.com alias1 alias2\n"); EnvValue with_env("CARES_HOSTS", hostsfile.filename()); struct ares_addrinfo_hints hints; memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_INET; // 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; AddrInfoResult results[kCount]; for (int ii = 1; ii <= kCount; ii++) { AddrInfoResult* result = &(results[ii - 1]); ClearFails(); SetAllocFail(ii); ares_getaddrinfo(channel_, "example.com", NULL, &hints, AddrInfoCallback, result); Process(); EXPECT_TRUE(result->done_); if (result->status_ == ARES_SUCCESS) { std::stringstream ss; ss << result->ai_; EXPECT_EQ("{alias1->example.com, alias2->example.com addr=[1.2.3.4]}", ss.str()) << " failed alloc #" << ii; if (verbose) std::cerr << "Succeeded despite failure of alloc #" << ii << std::endl; } } } TEST_F(LibraryTest, DNSRecord) { ares_dns_record_t *dnsrec = NULL; ares_dns_rr_t *rr = NULL; struct in_addr addr; struct ares_in6_addr addr6; unsigned char *msg = NULL; size_t msglen = 0; size_t qdcount = 0; size_t ancount = 0; size_t nscount = 0; size_t arcount = 0; EXPECT_EQ(ARES_SUCCESS, ares_dns_record_create(&dnsrec, 0x1234, ARES_FLAG_QR|ARES_FLAG_AA|ARES_FLAG_RD|ARES_FLAG_RA, ARES_OPCODE_QUERY, ARES_RCODE_NOERROR)); /* == Question == */ EXPECT_EQ(ARES_SUCCESS, ares_dns_record_query_add(dnsrec, "example.com", ARES_REC_TYPE_ANY, ARES_CLASS_IN)); /* == Answer == */ /* A */ EXPECT_EQ(ARES_SUCCESS, ares_dns_record_rr_add(&rr, dnsrec, ARES_SECTION_ANSWER, "example.com", ARES_REC_TYPE_A, ARES_CLASS_IN, 300)); EXPECT_LT(0, ares_inet_pton(AF_INET, "1.1.1.1", &addr)); EXPECT_EQ(ARES_SUCCESS, ares_dns_rr_set_addr(rr, ARES_RR_A_ADDR, &addr)); /* AAAA */ EXPECT_EQ(ARES_SUCCESS, ares_dns_record_rr_add(&rr, dnsrec, ARES_SECTION_ANSWER, "example.com", ARES_REC_TYPE_AAAA, ARES_CLASS_IN, 300)); EXPECT_LT(0, ares_inet_pton(AF_INET6, "2600::4", &addr6)); EXPECT_EQ(ARES_SUCCESS, ares_dns_rr_set_addr6(rr, ARES_RR_AAAA_ADDR, &addr6)); /* MX */ EXPECT_EQ(ARES_SUCCESS, ares_dns_record_rr_add(&rr, dnsrec, ARES_SECTION_ANSWER, "example.com", ARES_REC_TYPE_MX, ARES_CLASS_IN, 3600)); EXPECT_EQ(ARES_SUCCESS, ares_dns_rr_set_u16(rr, ARES_RR_MX_PREFERENCE, 10)); EXPECT_EQ(ARES_SUCCESS, ares_dns_rr_set_str(rr, ARES_RR_MX_EXCHANGE, "mail.example.com")); /* CNAME */ EXPECT_EQ(ARES_SUCCESS, ares_dns_record_rr_add(&rr, dnsrec, ARES_SECTION_ANSWER, "example.com", ARES_REC_TYPE_CNAME, ARES_CLASS_IN, 3600)); EXPECT_EQ(ARES_SUCCESS, ares_dns_rr_set_str(rr, ARES_RR_CNAME_CNAME, "b.example.com")); /* TXT */ EXPECT_EQ(ARES_SUCCESS, ares_dns_record_rr_add(&rr, dnsrec, ARES_SECTION_ANSWER, "example.com", ARES_REC_TYPE_TXT, ARES_CLASS_IN, 3600)); const char txt1[] = "blah=here blah=there anywhere"; const char txt2[] = "some other record"; EXPECT_EQ(ARES_SUCCESS, ares_dns_rr_add_abin(rr, ARES_RR_TXT_DATA, (unsigned char *)txt1, sizeof(txt1)-1)); EXPECT_EQ(ARES_SUCCESS, ares_dns_rr_add_abin(rr, ARES_RR_TXT_DATA, (unsigned char *)txt2, sizeof(txt2)-1)); /* SIG */ EXPECT_EQ(ARES_SUCCESS, ares_dns_record_rr_add(&rr, dnsrec, ARES_SECTION_ANSWER, "example.com", ARES_REC_TYPE_SIG, ARES_CLASS_ANY, 0)); EXPECT_EQ(ARES_SUCCESS, ares_dns_rr_set_u16(rr, ARES_RR_SIG_TYPE_COVERED, ARES_REC_TYPE_TXT)); EXPECT_EQ(ARES_SUCCESS, ares_dns_rr_set_u8(rr, ARES_RR_SIG_ALGORITHM, 1)); EXPECT_EQ(ARES_SUCCESS, ares_dns_rr_set_u8(rr, ARES_RR_SIG_LABELS, 1)); EXPECT_EQ(ARES_SUCCESS, ares_dns_rr_set_u32(rr, ARES_RR_SIG_ORIGINAL_TTL, 3200)); EXPECT_EQ(ARES_SUCCESS, ares_dns_rr_set_u32(rr, ARES_RR_SIG_EXPIRATION, (unsigned int)time(NULL))); EXPECT_EQ(ARES_SUCCESS, ares_dns_rr_set_u32(rr, ARES_RR_SIG_INCEPTION, (unsigned int)time(NULL) - (86400 * 365))); EXPECT_EQ(ARES_SUCCESS, ares_dns_rr_set_u16(rr, ARES_RR_SIG_KEY_TAG, 0x1234)); EXPECT_EQ(ARES_SUCCESS, ares_dns_rr_set_str(rr, ARES_RR_SIG_SIGNERS_NAME, "signer.example.com")); const unsigned char sig[] = { 0xd2, 0xab, 0xde, 0x24, 0x0d, 0x7c, 0xd3, 0xee, 0x6b, 0x4b, 0x28, 0xc5, 0x4d, 0xf0, 0x34, 0xb9, 0x79, 0x83, 0xa1, 0xd1, 0x6e, 0x8a, 0x41, 0x0e, 0x45, 0x61, 0xcb, 0x10, 0x66, 0x18, 0xe9, 0x71 }; EXPECT_EQ(ARES_SUCCESS, ares_dns_rr_set_bin(rr, ARES_RR_SIG_SIGNATURE, sig, sizeof(sig))); /* == Authority == */ /* NS */ EXPECT_EQ(ARES_SUCCESS, ares_dns_record_rr_add(&rr, dnsrec, ARES_SECTION_AUTHORITY, "example.com", ARES_REC_TYPE_NS, ARES_CLASS_IN, 38400)); EXPECT_EQ(ARES_SUCCESS, ares_dns_rr_set_str(rr, ARES_RR_NS_NSDNAME, "ns1.example.com")); EXPECT_EQ(ARES_SUCCESS, ares_dns_record_rr_add(&rr, dnsrec, ARES_SECTION_AUTHORITY, "example.com", ARES_REC_TYPE_NS, ARES_CLASS_IN, 38400)); EXPECT_EQ(ARES_SUCCESS, ares_dns_rr_set_str(rr, ARES_RR_NS_NSDNAME, "ns2.example.com")); /* SOA */ EXPECT_EQ(ARES_SUCCESS, ares_dns_record_rr_add(&rr, dnsrec, ARES_SECTION_AUTHORITY, "example.com", ARES_REC_TYPE_SOA, ARES_CLASS_IN, 86400)); EXPECT_EQ(ARES_SUCCESS, ares_dns_rr_set_str(rr, ARES_RR_SOA_MNAME, "ns1.example.com")); EXPECT_EQ(ARES_SUCCESS, ares_dns_rr_set_str(rr, ARES_RR_SOA_RNAME, "tech\\.support.example.com")); EXPECT_EQ(ARES_SUCCESS, ares_dns_rr_set_u32(rr, ARES_RR_SOA_SERIAL, 2023110701)); EXPECT_EQ(ARES_SUCCESS, ares_dns_rr_set_u32(rr, ARES_RR_SOA_REFRESH, 28800)); EXPECT_EQ(ARES_SUCCESS, ares_dns_rr_set_u32(rr, ARES_RR_SOA_RETRY, 7200)); EXPECT_EQ(ARES_SUCCESS, ares_dns_rr_set_u32(rr, ARES_RR_SOA_EXPIRE, 604800)); EXPECT_EQ(ARES_SUCCESS, ares_dns_rr_set_u32(rr, ARES_RR_SOA_MINIMUM, 86400)); /* == Additional */ /* OPT */ EXPECT_EQ(ARES_SUCCESS, ares_dns_record_rr_add(&rr, dnsrec, ARES_SECTION_ADDITIONAL, "", ARES_REC_TYPE_OPT, ARES_CLASS_IN, 0)); EXPECT_EQ(ARES_SUCCESS, ares_dns_rr_set_u16(rr, ARES_RR_OPT_UDP_SIZE, 1280)); EXPECT_EQ(ARES_SUCCESS, ares_dns_rr_set_u8(rr, ARES_RR_OPT_VERSION, 0)); EXPECT_EQ(ARES_SUCCESS, ares_dns_rr_set_u16(rr, ARES_RR_OPT_FLAGS, 0)); unsigned char optval[] = { 'c', '-', 'a', 'r', 'e', 's' }; EXPECT_EQ(ARES_SUCCESS, ares_dns_rr_set_opt(rr, ARES_RR_OPT_OPTIONS, 3 /* NSID */, optval, sizeof(optval))); /* PTR -- doesn't make sense, but ok */ EXPECT_EQ(ARES_SUCCESS, ares_dns_record_rr_add(&rr, dnsrec, ARES_SECTION_ADDITIONAL, "example.com", ARES_REC_TYPE_PTR, ARES_CLASS_IN, 300)); EXPECT_EQ(ARES_SUCCESS, ares_dns_rr_set_str(rr, ARES_RR_PTR_DNAME, "b.example.com")); /* HINFO */ EXPECT_EQ(ARES_SUCCESS, ares_dns_record_rr_add(&rr, dnsrec, ARES_SECTION_ADDITIONAL, "example.com", ARES_REC_TYPE_HINFO, ARES_CLASS_IN, 300)); EXPECT_EQ(ARES_SUCCESS, ares_dns_rr_set_str(rr, ARES_RR_HINFO_CPU, "Virtual")); EXPECT_EQ(ARES_SUCCESS, ares_dns_rr_set_str(rr, ARES_RR_HINFO_OS, "Linux")); /* SRV */ EXPECT_EQ(ARES_SUCCESS, ares_dns_record_rr_add(&rr, dnsrec, ARES_SECTION_ADDITIONAL, "_ldap.example.com", ARES_REC_TYPE_SRV, ARES_CLASS_IN, 300)); EXPECT_EQ(ARES_SUCCESS, ares_dns_rr_set_u16(rr, ARES_RR_SRV_PRIORITY, 100)); EXPECT_EQ(ARES_SUCCESS, ares_dns_rr_set_u16(rr, ARES_RR_SRV_WEIGHT, 1)); EXPECT_EQ(ARES_SUCCESS, ares_dns_rr_set_u16(rr, ARES_RR_SRV_PORT, 389)); EXPECT_EQ(ARES_SUCCESS, ares_dns_rr_set_str(rr, ARES_RR_SRV_TARGET, "ldap.example.com")); /* TLSA */ EXPECT_EQ(ARES_SUCCESS, ares_dns_record_rr_add(&rr, dnsrec, ARES_SECTION_ADDITIONAL, "_443._tcp.example.com", ARES_REC_TYPE_TLSA, ARES_CLASS_IN, 86400)); EXPECT_EQ(ARES_SUCCESS, ares_dns_rr_set_u8(rr, ARES_RR_TLSA_CERT_USAGE, ARES_TLSA_USAGE_CA)); EXPECT_EQ(ARES_SUCCESS, ares_dns_rr_set_u8(rr, ARES_RR_TLSA_SELECTOR, ARES_TLSA_SELECTOR_FULL)); EXPECT_EQ(ARES_SUCCESS, ares_dns_rr_set_u8(rr, ARES_RR_TLSA_MATCH, ARES_TLSA_MATCH_SHA256)); const unsigned char tlsa[] = { 0xd2, 0xab, 0xde, 0x24, 0x0d, 0x7c, 0xd3, 0xee, 0x6b, 0x4b, 0x28, 0xc5, 0x4d, 0xf0, 0x34, 0xb9, 0x79, 0x83, 0xa1, 0xd1, 0x6e, 0x8a, 0x41, 0x0e, 0x45, 0x61, 0xcb, 0x10, 0x66, 0x18, 0xe9, 0x71 }; EXPECT_EQ(ARES_SUCCESS, ares_dns_rr_set_bin(rr, ARES_RR_TLSA_DATA, tlsa, sizeof(tlsa))); /* SVCB */ EXPECT_EQ(ARES_SUCCESS, ares_dns_record_rr_add(&rr, dnsrec, ARES_SECTION_ADDITIONAL, "_1234._bar.example.com", ARES_REC_TYPE_SVCB, ARES_CLASS_IN, 300)); EXPECT_EQ(ARES_SUCCESS, ares_dns_rr_set_u16(rr, ARES_RR_SVCB_PRIORITY, 1)); EXPECT_EQ(ARES_SUCCESS, ares_dns_rr_set_str(rr, ARES_RR_SVCB_TARGET, "svc1.example.net")); /* IPV6 hint is a list of IPV6 addresses in network byte order, concatenated */ struct ares_addr svcb_addr; svcb_addr.family = AF_UNSPEC; size_t svcb_ipv6hint_len = 0; const unsigned char *svcb_ipv6hint = (const unsigned char *)ares_dns_pton("2001:db8::1", &svcb_addr, &svcb_ipv6hint_len); EXPECT_EQ(ARES_SUCCESS, ares_dns_rr_set_opt(rr, ARES_RR_SVCB_PARAMS, ARES_SVCB_PARAM_IPV6HINT, svcb_ipv6hint, svcb_ipv6hint_len)); /* Port is 16bit big endian format */ unsigned short svcb_port = htons(1234); EXPECT_EQ(ARES_SUCCESS, ares_dns_rr_set_opt(rr, ARES_RR_SVCB_PARAMS, ARES_SVCB_PARAM_PORT, (const unsigned char *)&svcb_port, sizeof(svcb_port))); /* HTTPS */ EXPECT_EQ(ARES_SUCCESS, ares_dns_record_rr_add(&rr, dnsrec, ARES_SECTION_ADDITIONAL, "example.com", ARES_REC_TYPE_HTTPS, ARES_CLASS_IN, 300)); EXPECT_EQ(ARES_SUCCESS, ares_dns_rr_set_u16(rr, ARES_RR_HTTPS_PRIORITY, 1)); EXPECT_EQ(ARES_SUCCESS, ares_dns_rr_set_str(rr, ARES_RR_HTTPS_TARGET, "")); /* In DNS string format which is 1 octet length indicator followed by string */ const unsigned char https_alpn[] = { 0x02, 'h', '3' }; EXPECT_EQ(ARES_SUCCESS, ares_dns_rr_set_opt(rr, ARES_RR_HTTPS_PARAMS, ARES_SVCB_PARAM_ALPN, https_alpn, sizeof(https_alpn))); /* URI */ EXPECT_EQ(ARES_SUCCESS, ares_dns_record_rr_add(&rr, dnsrec, ARES_SECTION_ADDITIONAL, "_ftp._tcp.example.com", ARES_REC_TYPE_URI, ARES_CLASS_IN, 3600)); EXPECT_EQ(ARES_SUCCESS, ares_dns_rr_set_u16(rr, ARES_RR_URI_PRIORITY, 10)); EXPECT_EQ(ARES_SUCCESS, ares_dns_rr_set_u16(rr, ARES_RR_URI_WEIGHT, 1)); EXPECT_EQ(ARES_SUCCESS, ares_dns_rr_set_str(rr, ARES_RR_URI_TARGET, "ftp://ftp.example.com/public")); /* CAA */ EXPECT_EQ(ARES_SUCCESS, ares_dns_record_rr_add(&rr, dnsrec, ARES_SECTION_ADDITIONAL, "example.com", ARES_REC_TYPE_CAA, ARES_CLASS_IN, 86400)); EXPECT_EQ(ARES_SUCCESS, ares_dns_rr_set_u8(rr, ARES_RR_CAA_CRITICAL, 0)); EXPECT_EQ(ARES_SUCCESS, ares_dns_rr_set_str(rr, ARES_RR_CAA_TAG, "issue")); unsigned char caa[] = "letsencrypt.org"; EXPECT_EQ(ARES_SUCCESS, ares_dns_rr_set_bin(rr, ARES_RR_CAA_VALUE, caa, sizeof(caa))); /* NAPTR */ EXPECT_EQ(ARES_SUCCESS, ares_dns_record_rr_add(&rr, dnsrec, ARES_SECTION_ADDITIONAL, "example.com", ARES_REC_TYPE_NAPTR, ARES_CLASS_IN, 86400)); EXPECT_EQ(ARES_SUCCESS, ares_dns_rr_set_u16(rr, ARES_RR_NAPTR_ORDER, 100)); EXPECT_EQ(ARES_SUCCESS, ares_dns_rr_set_u16(rr, ARES_RR_NAPTR_PREFERENCE, 10)); EXPECT_EQ(ARES_SUCCESS, ares_dns_rr_set_str(rr, ARES_RR_NAPTR_FLAGS, "S")); EXPECT_EQ(ARES_SUCCESS, ares_dns_rr_set_str(rr, ARES_RR_NAPTR_SERVICES, "SIP+D2U")); EXPECT_EQ(ARES_SUCCESS, ares_dns_rr_set_str(rr, ARES_RR_NAPTR_REGEXP, "!^.*$!sip:customer-service@example.com!")); EXPECT_EQ(ARES_SUCCESS, ares_dns_rr_set_str(rr, ARES_RR_NAPTR_REPLACEMENT, "_sip._udp.example.com.")); /* RAW_RR */ EXPECT_EQ(ARES_SUCCESS, ares_dns_record_rr_add(&rr, dnsrec, ARES_SECTION_ADDITIONAL, "", ARES_REC_TYPE_RAW_RR, ARES_CLASS_IN, 0)); EXPECT_EQ(ARES_SUCCESS, ares_dns_rr_set_u16(rr, ARES_RR_RAW_RR_TYPE, 65432)); unsigned char data[] = { 0x00 }; EXPECT_EQ(ARES_SUCCESS, ares_dns_rr_set_bin(rr, ARES_RR_RAW_RR_DATA, data, sizeof(data))); qdcount = ares_dns_record_query_cnt(dnsrec); ancount = ares_dns_record_rr_cnt(dnsrec, ARES_SECTION_ANSWER); nscount = ares_dns_record_rr_cnt(dnsrec, ARES_SECTION_AUTHORITY); arcount = ares_dns_record_rr_cnt(dnsrec, ARES_SECTION_ADDITIONAL); /* Write */ EXPECT_EQ(ARES_SUCCESS, ares_dns_write(dnsrec, &msg, &msglen)); ares_buf_t *hexdump = ares_buf_create(); EXPECT_EQ(ARES_SUCCESS, ares_buf_hexdump(hexdump, msg, msglen)); char *hexdata = ares_buf_finish_str(hexdump, NULL); //printf("HEXDUMP\n%s", hexdata); ares_free(hexdata); ares_dns_record_destroy(dnsrec); dnsrec = NULL; /* Parse */ EXPECT_EQ(ARES_SUCCESS, ares_dns_parse(msg, msglen, 0, &dnsrec)); ares_free_string(msg); msg = NULL; /* Re-write */ EXPECT_EQ(ARES_SUCCESS, ares_dns_write(dnsrec, &msg, &msglen)); EXPECT_EQ(qdcount, ares_dns_record_query_cnt(dnsrec)); EXPECT_EQ(ancount, ares_dns_record_rr_cnt(dnsrec, ARES_SECTION_ANSWER)); EXPECT_EQ(nscount, ares_dns_record_rr_cnt(dnsrec, ARES_SECTION_AUTHORITY)); EXPECT_EQ(arcount, ares_dns_record_rr_cnt(dnsrec, ARES_SECTION_ADDITIONAL)); /* Iterate and print */ ares_buf_t *printmsg = ares_buf_create(); ares_buf_append_str(printmsg, ";; ->>HEADER<<- opcode: "); ares_buf_append_str(printmsg, ares_dns_opcode_tostr(ares_dns_record_get_opcode(dnsrec))); ares_buf_append_str(printmsg, ", status: "); ares_buf_append_str(printmsg, ares_dns_rcode_tostr(ares_dns_record_get_rcode(dnsrec))); ares_buf_append_str(printmsg, ", id: "); ares_buf_append_num_dec(printmsg, (size_t)ares_dns_record_get_id(dnsrec), 0); ares_buf_append_str(printmsg, "\n;; flags: "); ares_buf_append_num_hex(printmsg, (size_t)ares_dns_record_get_flags(dnsrec), 0); ares_buf_append_str(printmsg, "; QUERY: "); ares_buf_append_num_dec(printmsg, ares_dns_record_query_cnt(dnsrec), 0); ares_buf_append_str(printmsg, ", ANSWER: "); ares_buf_append_num_dec(printmsg, ares_dns_record_rr_cnt(dnsrec, ARES_SECTION_ANSWER), 0); ares_buf_append_str(printmsg, ", AUTHORITY: "); ares_buf_append_num_dec(printmsg, ares_dns_record_rr_cnt(dnsrec, ARES_SECTION_AUTHORITY), 0); ares_buf_append_str(printmsg, ", ADDITIONAL: "); ares_buf_append_num_dec(printmsg, ares_dns_record_rr_cnt(dnsrec, ARES_SECTION_ADDITIONAL), 0); ares_buf_append_str(printmsg, "\n\n"); ares_buf_append_str(printmsg, ";; QUESTION SECTION:\n"); for (size_t i = 0; i < ares_dns_record_query_cnt(dnsrec); i++) { const char *name; ares_dns_rec_type_t qtype; ares_dns_class_t qclass; ares_dns_record_query_get(dnsrec, i, &name, &qtype, &qclass); ares_buf_append_str(printmsg, ";"); ares_buf_append_str(printmsg, name); ares_buf_append_str(printmsg, ".\t\t\t"); ares_buf_append_str(printmsg, ares_dns_class_tostr(qclass)); ares_buf_append_str(printmsg, "\t"); ares_buf_append_str(printmsg, ares_dns_rec_type_tostr(qtype)); ares_buf_append_str(printmsg, "\n"); } ares_buf_append_str(printmsg, "\n"); for (size_t i = ARES_SECTION_ANSWER; i < ARES_SECTION_ADDITIONAL + 1; i++) { ares_buf_append_str(printmsg, ";; "); ares_buf_append_str(printmsg, ares_dns_section_tostr((ares_dns_section_t)i)); ares_buf_append_str(printmsg, " SECTION:\n"); for (size_t j = 0; j < ares_dns_record_rr_cnt(dnsrec, (ares_dns_section_t)i); j++) { rr = ares_dns_record_rr_get(dnsrec, (ares_dns_section_t)i, j); ares_buf_append_str(printmsg, ares_dns_rr_get_name(rr)); ares_buf_append_str(printmsg, ".\t\t\t"); ares_buf_append_str(printmsg, ares_dns_class_tostr(ares_dns_rr_get_class(rr))); ares_buf_append_str(printmsg, "\t"); ares_buf_append_str(printmsg, ares_dns_rec_type_tostr(ares_dns_rr_get_type(rr))); ares_buf_append_str(printmsg, "\t"); ares_buf_append_num_dec(printmsg, ares_dns_rr_get_ttl(rr), 0); ares_buf_append_str(printmsg, "\t"); size_t keys_cnt; const ares_dns_rr_key_t *keys = ares_dns_rr_get_keys(ares_dns_rr_get_type(rr), &keys_cnt); for (size_t k = 0; kid = id; m->buf = ares_buf_create(); ares_buf_append_be32(m->buf, id); } static void array_member_destroy(void *mb) { array_member_t *m = (array_member_t *)mb; ares_buf_destroy(m->buf); } static int array_sort_cmp(const void *data1, const void *data2) { const array_member_t *m1 = (const array_member_t *)data1; const array_member_t *m2 = (const array_member_t *)data2; if (m1->id > m2->id) return 1; if (m1->id < m2->id) return -1; return 0; } TEST_F(LibraryTest, Array) { ares_array_t *a = NULL; array_member_t *m = NULL; array_member_t mbuf; unsigned int cnt = 0; unsigned int removed = 0; void *ptr = NULL; size_t i; a = ares_array_create(sizeof(array_member_t), array_member_destroy); EXPECT_NE(nullptr, a); /* Try to sort with no elements, should break out */ EXPECT_EQ(ARES_SUCCESS, ares_array_sort(a, array_sort_cmp)); /* Add 8 elements */ for ( ; cnt < 8 ; cnt++) { EXPECT_EQ(ARES_SUCCESS, ares_array_insert_last(&ptr, a)); array_member_init(ptr, cnt+1); } /* Insert at invalid index */ EXPECT_NE(ARES_SUCCESS, ares_array_insert_at(&ptr, a, 12345678)); /* Verify count */ EXPECT_EQ(cnt, ares_array_len(a)); /* Remove the first 2 elements */ EXPECT_EQ(ARES_SUCCESS, ares_array_remove_first(a)); EXPECT_EQ(ARES_SUCCESS, ares_array_remove_first(a)); removed += 2; /* Verify count */ EXPECT_EQ(cnt-removed, ares_array_len(a)); /* Verify id of first element */ m = (array_member_t *)ares_array_first(a); EXPECT_NE(nullptr, m); EXPECT_EQ(3, m->id); /* Add 100 total elements, this should force a shift of memory at some * to make sure moves are working */ for ( ; cnt < 100 ; cnt++) { EXPECT_EQ(ARES_SUCCESS, ares_array_insert_last(&ptr, a)); array_member_init(ptr, cnt+1); } /* Verify count */ EXPECT_EQ(cnt-removed, ares_array_len(a)); /* Remove 2 from the end */ EXPECT_EQ(ARES_SUCCESS, ares_array_remove_last(a)); EXPECT_EQ(ARES_SUCCESS, ares_array_remove_last(a)); removed += 2; /* Verify count */ EXPECT_EQ(cnt-removed, ares_array_len(a)); /* Verify expected id of last member */ m = (array_member_t *)ares_array_last(a); EXPECT_NE(nullptr, m); EXPECT_EQ(cnt-2, m->id); /* Remove 3 middle members */ EXPECT_EQ(ARES_SUCCESS, ares_array_remove_at(a, ares_array_len(a)/2)); EXPECT_EQ(ARES_SUCCESS, ares_array_remove_at(a, ares_array_len(a)/2)); EXPECT_EQ(ARES_SUCCESS, ares_array_remove_at(a, ares_array_len(a)/2)); removed += 3; /* Verify count */ EXPECT_EQ(cnt-removed, ares_array_len(a)); /* Claim a middle member then re-add it at the same position */ i = ares_array_len(a) / 2; EXPECT_EQ(ARES_SUCCESS, ares_array_claim_at(&mbuf, sizeof(mbuf), a, i)); EXPECT_EQ(ARES_SUCCESS, ares_array_insert_at(&ptr, a, i)); array_member_init(ptr, mbuf.id); array_member_destroy((void *)&mbuf); /* Verify count */ EXPECT_EQ(cnt-removed, ares_array_len(a)); /* Iterate across the array, make sure each entry is greater than the last and * the data in the buffer matches the id in the array */ unsigned int last_id = 0; for (i=0; iid, last_id); last_id = m->id; unsigned int bufval = 0; ares_buf_tag(m->buf); EXPECT_EQ(ARES_SUCCESS, ares_buf_fetch_be32(m->buf, &bufval)); ares_buf_tag_rollback(m->buf); EXPECT_EQ(bufval, m->id); } /* add a new element in the middle to the beginning with a high id */ EXPECT_EQ(ARES_SUCCESS, ares_array_insert_at(&ptr, a, ares_array_len(a)/2)); array_member_init(ptr, 100000); /* Sort the array */ EXPECT_EQ(ARES_SUCCESS, ares_array_sort(a, array_sort_cmp)); /* Iterate across the array, make sure each entry is greater than the last and * the data in the buffer matches the id in the array */ last_id = 0; for (i=0; iid, last_id); last_id = m->id; unsigned int bufval = 0; ares_buf_tag(m->buf); EXPECT_EQ(ARES_SUCCESS, ares_buf_fetch_be32(m->buf, &bufval)); ares_buf_tag_rollback(m->buf); EXPECT_EQ(bufval, m->id); } ares_array_destroy(a); } TEST_F(LibraryTest, HtableVpvp) { ares_llist_t *l = NULL; ares_htable_vpvp_t *h = NULL; ares_llist_node_t *n = NULL; size_t i; #define VPVP_TABLE_SIZE 1000 l = ares_llist_create(NULL); EXPECT_NE((void *)NULL, l); h = ares_htable_vpvp_create(NULL, ares_free); EXPECT_NE((void *)NULL, h); for (i=0; is = (ares_socket_t)i+1; EXPECT_NE((void *)NULL, ares_llist_insert_last(l, a)); EXPECT_TRUE(ares_htable_asvp_insert(h, a->s, a)); } EXPECT_EQ(ASVP_TABLE_SIZE, ares_llist_len(l)); EXPECT_EQ(ASVP_TABLE_SIZE, ares_htable_asvp_num_keys(h)); n = ares_llist_node_first(l); EXPECT_NE((void *)NULL, n); while (n != NULL) { ares_llist_node_t *next = ares_llist_node_next(n); test_htable_asvp_t *a = (test_htable_asvp_t *)ares_llist_node_val(n); EXPECT_NE((void *)NULL, a); EXPECT_EQ(a, ares_htable_asvp_get_direct(h, a->s)); EXPECT_TRUE(ares_htable_asvp_get(h, a->s, NULL)); EXPECT_TRUE(ares_htable_asvp_remove(h, a->s)); ares_llist_node_destroy(n); n = next; } EXPECT_EQ(0, ares_llist_len(l)); EXPECT_EQ(0, ares_htable_asvp_num_keys(h)); ares_llist_destroy(l); ares_htable_asvp_destroy(h); } typedef struct { size_t s; } test_htable_szvp_t; TEST_F(LibraryTest, HtableSzvp) { ares_llist_t *l = NULL; ares_htable_szvp_t *h = NULL; ares_llist_node_t *n = NULL; size_t i; #define SZVP_TABLE_SIZE 1000 l = ares_llist_create(NULL); EXPECT_NE((void *)NULL, l); h = ares_htable_szvp_create(ares_free); EXPECT_NE((void *)NULL, h); for (i=0; is = i+1; EXPECT_NE((void *)NULL, ares_llist_insert_last(l, s)); EXPECT_TRUE(ares_htable_szvp_insert(h, s->s, s)); } EXPECT_EQ(SZVP_TABLE_SIZE, ares_llist_len(l)); EXPECT_EQ(SZVP_TABLE_SIZE, ares_htable_szvp_num_keys(h)); n = ares_llist_node_first(l); EXPECT_NE((void *)NULL, n); while (n != NULL) { ares_llist_node_t *next = ares_llist_node_next(n); test_htable_szvp_t *s = (test_htable_szvp_t *)ares_llist_node_val(n); EXPECT_NE((void *)NULL, s); EXPECT_EQ(s, ares_htable_szvp_get_direct(h, s->s)); EXPECT_TRUE(ares_htable_szvp_get(h, s->s, NULL)); EXPECT_TRUE(ares_htable_szvp_remove(h, s->s)); ares_llist_node_destroy(n); n = next; } EXPECT_EQ(0, ares_llist_len(l)); EXPECT_EQ(0, ares_htable_szvp_num_keys(h)); ares_llist_destroy(l); ares_htable_szvp_destroy(h); } typedef struct { char s[32]; } test_htable_vpstr_t; TEST_F(LibraryTest, HtableVpstr) { ares_llist_t *l = NULL; ares_htable_vpstr_t *h = NULL; ares_llist_node_t *n = NULL; size_t i; #define VPSTR_TABLE_SIZE 1000 l = ares_llist_create(ares_free); EXPECT_NE((void *)NULL, l); h = ares_htable_vpstr_create(); EXPECT_NE((void *)NULL, h); for (i=0; is, sizeof(s->s), "%d", (int)i); EXPECT_NE((void *)NULL, ares_llist_insert_last(l, s)); EXPECT_TRUE(ares_htable_vpstr_insert(h, s, s->s)); } EXPECT_EQ(VPSTR_TABLE_SIZE, ares_llist_len(l)); EXPECT_EQ(VPSTR_TABLE_SIZE, ares_htable_vpstr_num_keys(h)); n = ares_llist_node_first(l); EXPECT_NE((void *)NULL, n); while (n != NULL) { ares_llist_node_t *next = ares_llist_node_next(n); test_htable_vpstr_t *s = (test_htable_vpstr_t *)ares_llist_node_val(n); EXPECT_NE((void *)NULL, s); EXPECT_STREQ(s->s, ares_htable_vpstr_get_direct(h, s)); EXPECT_TRUE(ares_htable_vpstr_get(h, s, NULL)); EXPECT_TRUE(ares_htable_vpstr_remove(h, s)); ares_llist_node_destroy(n); n = next; } EXPECT_EQ(0, ares_llist_len(l)); EXPECT_EQ(0, ares_htable_vpstr_num_keys(h)); ares_llist_destroy(l); ares_htable_vpstr_destroy(h); } typedef struct { char s[32]; } test_htable_strvp_t; TEST_F(LibraryTest, HtableStrvp) { ares_llist_t *l = NULL; ares_htable_strvp_t *h = NULL; ares_llist_node_t *n = NULL; size_t i; #define STRVP_TABLE_SIZE 1000 l = ares_llist_create(NULL); EXPECT_NE((void *)NULL, l); h = ares_htable_strvp_create(ares_free); EXPECT_NE((void *)NULL, h); for (i=0; is, sizeof(s->s), "%d", (int)i); EXPECT_NE((void *)NULL, ares_llist_insert_last(l, s)); EXPECT_TRUE(ares_htable_strvp_insert(h, s->s, s)); } EXPECT_EQ(STRVP_TABLE_SIZE, ares_llist_len(l)); EXPECT_EQ(STRVP_TABLE_SIZE, ares_htable_strvp_num_keys(h)); n = ares_llist_node_first(l); EXPECT_NE((void *)NULL, n); while (n != NULL) { ares_llist_node_t *next = ares_llist_node_next(n); test_htable_strvp_t *s = (test_htable_strvp_t *)ares_llist_node_val(n); EXPECT_NE((void *)NULL, s); EXPECT_EQ(s, ares_htable_strvp_get_direct(h, s->s)); EXPECT_TRUE(ares_htable_strvp_get(h, s->s, NULL)); EXPECT_TRUE(ares_htable_strvp_remove(h, s->s)); ares_llist_node_destroy(n); n = next; } EXPECT_EQ(0, ares_llist_len(l)); EXPECT_EQ(0, ares_htable_strvp_num_keys(h)); ares_llist_destroy(l); ares_htable_strvp_destroy(h); } TEST_F(LibraryTest, HtableDict) { ares_htable_dict_t *h = NULL; size_t i; char **keys; size_t nkeys; #define DICT_TABLE_SIZE 1000 h = ares_htable_dict_create(); EXPECT_NE((void *)NULL, h); for (i=0; iservers; channel_->servers = NULL; struct ares_options opts; int optmask = 0; EXPECT_EQ(ARES_ENODATA, ares_save_options(channel_, &opts, &optmask)); channel_->servers = 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, (long)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; }, NULL, NULL, NULL, NULL }; } // namespace test } // namespace ares