2 #include "ares-test-ai.h"
5 // Include ares internal files for DNS protocol details
12 #ifdef HAVE_NETINET_TCP_H
13 #include <netinet/tcp.h>
22 #define BYTE_CAST (char *)
23 #define mkdir_(d, p) mkdir(d)
26 #define mkdir_(d, p) mkdir(d, p)
33 static constexpr int dynamic_port = 0;
34 int mock_port = dynamic_port;
36 const std::vector<int> both_families = {AF_INET, AF_INET6};
37 const std::vector<int> ipv4_family = {AF_INET};
38 const std::vector<int> ipv6_family = {AF_INET6};
40 const std::vector<std::pair<int, bool>> both_families_both_modes = {
41 std::make_pair<int, bool>(AF_INET, false),
42 std::make_pair<int, bool>(AF_INET, true),
43 std::make_pair<int, bool>(AF_INET6, false),
44 std::make_pair<int, bool>(AF_INET6, true)
46 const std::vector<std::pair<int, bool>> ipv4_family_both_modes = {
47 std::make_pair<int, bool>(AF_INET, false),
48 std::make_pair<int, bool>(AF_INET, true)
50 const std::vector<std::pair<int, bool>> ipv6_family_both_modes = {
51 std::make_pair<int, bool>(AF_INET6, false),
52 std::make_pair<int, bool>(AF_INET6, true)
55 // Which parameters to use in tests
56 std::vector<int> families = both_families;
57 std::vector<std::pair<int, bool>> families_modes = both_families_both_modes;
59 unsigned long long LibraryTest::fails_ = 0;
60 std::map<size_t, int> LibraryTest::size_fails_;
62 void ProcessWork(ares_channel channel,
63 std::function<std::set<int>()> get_extrafds,
64 std::function<void(int)> process_extra) {
66 fd_set readers, writers;
69 // Retrieve the set of file descriptors that the library wants us to monitor.
72 nfds = ares_fds(channel, &readers, &writers);
73 if (nfds == 0) // no work left to do in the library
76 // Add in the extra FDs if present.
77 std::set<int> extrafds = get_extrafds();
78 for (int extrafd : extrafds) {
79 FD_SET(extrafd, &readers);
80 if (extrafd >= nfds) {
85 // Wait for activity or timeout.
87 tv.tv_usec = 100000; // 100ms
88 count = select(nfds, &readers, &writers, nullptr, &tv);
90 fprintf(stderr, "select() failed, errno %d\n", errno);
94 // Let the library process any activity.
95 ares_process(channel, &readers, &writers);
97 // Let the provided callback process any activity on the extra FD.
98 for (int extrafd : extrafds) {
99 if (FD_ISSET(extrafd, &readers)) {
100 process_extra(extrafd);
107 void LibraryTest::SetAllocFail(int nth) {
109 assert(nth <= (int)(8 * sizeof(fails_)));
110 fails_ |= (1LL << (nth - 1));
114 void LibraryTest::SetAllocSizeFail(size_t size) {
119 void LibraryTest::ClearFails() {
126 bool LibraryTest::ShouldAllocFail(size_t size) {
127 bool fail = (fails_ & 0x01);
129 if (size_fails_[size] > 0) {
137 void* LibraryTest::amalloc(size_t size) {
138 if (ShouldAllocFail(size)) {
139 if (verbose) std::cerr << "Failing malloc(" << size << ") request" << std::endl;
147 void* LibraryTest::arealloc(void *ptr, size_t size) {
148 if (ShouldAllocFail(size)) {
149 if (verbose) std::cerr << "Failing realloc(" << ptr << ", " << size << ") request" << std::endl;
152 return realloc(ptr, size);
157 void LibraryTest::afree(void *ptr) {
161 std::set<int> NoExtraFDs() {
162 return std::set<int>();
165 void DefaultChannelTest::Process() {
166 ProcessWork(channel_, NoExtraFDs, nullptr);
169 void DefaultChannelModeTest::Process() {
170 ProcessWork(channel_, NoExtraFDs, nullptr);
173 MockServer::MockServer(int family, int port)
174 : udpport_(port), tcpport_(port), qid_(-1) {
175 // Create a TCP socket to receive data on.
176 tcpfd_ = socket(family, SOCK_STREAM, 0);
177 EXPECT_NE(-1, tcpfd_);
179 setsockopt(tcpfd_, SOL_SOCKET, SO_REUSEADDR,
180 BYTE_CAST &optval , sizeof(int));
181 // Send TCP data right away.
182 setsockopt(tcpfd_, IPPROTO_TCP, TCP_NODELAY,
183 BYTE_CAST &optval , sizeof(int));
185 // Create a UDP socket to receive data on.
186 udpfd_ = socket(family, SOCK_DGRAM, 0);
187 EXPECT_NE(-1, udpfd_);
189 // Bind the sockets to the given port.
190 if (family == AF_INET) {
191 struct sockaddr_in addr;
192 memset(&addr, 0, sizeof(addr));
193 addr.sin_family = AF_INET;
194 addr.sin_addr.s_addr = htonl(INADDR_ANY);
195 addr.sin_port = htons(tcpport_);
196 int tcprc = bind(tcpfd_, (struct sockaddr*)&addr, sizeof(addr));
197 EXPECT_EQ(0, tcprc) << "Failed to bind AF_INET to TCP port " << tcpport_;
198 addr.sin_port = htons(udpport_);
199 int udprc = bind(udpfd_, (struct sockaddr*)&addr, sizeof(addr));
200 EXPECT_EQ(0, udprc) << "Failed to bind AF_INET to UDP port " << udpport_;
201 // retrieve system-assigned port
202 if (udpport_ == dynamic_port) {
203 ares_socklen_t len = sizeof(addr);
204 auto result = getsockname(udpfd_, (struct sockaddr*)&addr, &len);
205 EXPECT_EQ(0, result);
206 udpport_ = ntohs(addr.sin_port);
207 EXPECT_NE(dynamic_port, udpport_);
209 if (tcpport_ == dynamic_port) {
210 ares_socklen_t len = sizeof(addr);
211 auto result = getsockname(tcpfd_, (struct sockaddr*)&addr, &len);
212 EXPECT_EQ(0, result);
213 tcpport_ = ntohs(addr.sin_port);
214 EXPECT_NE(dynamic_port, tcpport_);
217 EXPECT_EQ(AF_INET6, family);
218 struct sockaddr_in6 addr;
219 memset(&addr, 0, sizeof(addr));
220 addr.sin6_family = AF_INET6;
221 memset(&addr.sin6_addr, 0, sizeof(addr.sin6_addr)); // in6addr_any
222 addr.sin6_port = htons(tcpport_);
223 int tcprc = bind(tcpfd_, (struct sockaddr*)&addr, sizeof(addr));
224 EXPECT_EQ(0, tcprc) << "Failed to bind AF_INET6 to TCP port " << tcpport_;
225 addr.sin6_port = htons(udpport_);
226 int udprc = bind(udpfd_, (struct sockaddr*)&addr, sizeof(addr));
227 EXPECT_EQ(0, udprc) << "Failed to bind AF_INET6 to UDP port " << udpport_;
228 // retrieve system-assigned port
229 if (udpport_ == dynamic_port) {
230 ares_socklen_t len = sizeof(addr);
231 auto result = getsockname(udpfd_, (struct sockaddr*)&addr, &len);
232 EXPECT_EQ(0, result);
233 udpport_ = ntohs(addr.sin6_port);
234 EXPECT_NE(dynamic_port, udpport_);
236 if (tcpport_ == dynamic_port) {
237 ares_socklen_t len = sizeof(addr);
238 auto result = getsockname(tcpfd_, (struct sockaddr*)&addr, &len);
239 EXPECT_EQ(0, result);
240 tcpport_ = ntohs(addr.sin6_port);
241 EXPECT_NE(dynamic_port, tcpport_);
244 if (verbose) std::cerr << "Configured "
245 << (family == AF_INET ? "IPv4" : "IPv6")
246 << " mock server with TCP socket " << tcpfd_
247 << " on port " << tcpport_
248 << " and UDP socket " << udpfd_
249 << " on port " << udpport_ << std::endl;
251 // For TCP, also need to listen for connections.
252 EXPECT_EQ(0, listen(tcpfd_, 5)) << "Failed to listen for TCP connections";
255 MockServer::~MockServer() {
256 for (int fd : connfds_) {
263 void MockServer::ProcessFD(int fd) {
264 if (fd != tcpfd_ && fd != udpfd_ && connfds_.find(fd) == connfds_.end()) {
265 // Not one of our FDs.
269 int connfd = accept(tcpfd_, NULL, NULL);
271 std::cerr << "Error accepting connection on fd " << fd << std::endl;
273 connfds_.insert(connfd);
278 // Activity on a data-bearing file descriptor.
279 struct sockaddr_storage addr;
280 socklen_t addrlen = sizeof(addr);
282 int len = recvfrom(fd, BYTE_CAST buffer, sizeof(buffer), 0,
283 (struct sockaddr *)&addr, &addrlen);
287 connfds_.erase(std::find(connfds_.begin(), connfds_.end(), fd));
292 std::cerr << "Packet too short (" << len << ")" << std::endl;
295 int tcplen = (data[0] << 8) + data[1];
299 std::cerr << "Warning: TCP length " << tcplen
300 << " doesn't match remaining data length " << len << std::endl;
304 // Assume the packet is a well-formed DNS request and extract the request
306 if (len < NS_HFIXEDSZ) {
307 std::cerr << "Packet too short (" << len << ")" << std::endl;
310 int qid = DNS_HEADER_QID(data);
311 if (DNS_HEADER_QR(data) != 0) {
312 std::cerr << "Not a request" << std::endl;
315 if (DNS_HEADER_OPCODE(data) != ns_o_query) {
316 std::cerr << "Not a query (opcode " << DNS_HEADER_OPCODE(data)
320 if (DNS_HEADER_QDCOUNT(data) != 1) {
321 std::cerr << "Unexpected question count (" << DNS_HEADER_QDCOUNT(data)
325 byte* question = data + 12;
328 char *name = nullptr;
330 ares_expand_name(question, data, len, &name, &enclen);
332 std::cerr << "Failed to retrieve name" << std::endl;
337 std::string namestr(name);
338 ares_free_string(name);
341 std::cerr << "Unexpected question size (" << qlen
342 << " bytes after name)" << std::endl;
345 if (DNS_QUESTION_CLASS(question) != ns_c_in) {
346 std::cerr << "Unexpected question class (" << DNS_QUESTION_CLASS(question)
350 int rrtype = DNS_QUESTION_TYPE(question);
353 std::vector<byte> req(data, data + len);
354 std::cerr << "received " << (fd == udpfd_ ? "UDP" : "TCP") << " request " << PacketToString(req)
355 << " on port " << (fd == udpfd_ ? udpport_ : tcpport_) << std::endl;
356 std::cerr << "ProcessRequest(" << qid << ", '" << namestr
357 << "', " << RRTypeToString(rrtype) << ")" << std::endl;
359 ProcessRequest(fd, &addr, addrlen, qid, namestr, rrtype);
362 std::set<int> MockServer::fds() const {
363 std::set<int> result = connfds_;
364 result.insert(tcpfd_);
365 result.insert(udpfd_);
369 void MockServer::ProcessRequest(int fd, struct sockaddr_storage* addr, int addrlen,
370 int qid, const std::string& name, int rrtype) {
371 // Before processing, let gMock know the request is happening.
372 OnRequest(name, rrtype);
374 if (reply_.size() == 0) {
378 // Make a local copy of the current pending reply.
379 std::vector<byte> reply = reply_;
382 // Use the explicitly specified query ID.
385 if (reply.size() >= 2) {
386 // Overwrite the query ID if space to do so.
387 reply[0] = (byte)((qid >> 8) & 0xff);
388 reply[1] = (byte)(qid & 0xff);
390 if (verbose) std::cerr << "sending reply " << PacketToString(reply)
391 << " on port " << ((fd == udpfd_) ? udpport_ : tcpport_) << std::endl;
393 // Prefix with 2-byte length if TCP.
395 int len = reply.size();
396 std::vector<byte> vlen = {(byte)((len & 0xFF00) >> 8), (byte)(len & 0xFF)};
397 reply.insert(reply.begin(), vlen.begin(), vlen.end());
398 // Also, don't bother with the destination address.
403 int rc = sendto(fd, BYTE_CAST reply.data(), reply.size(), 0,
404 (struct sockaddr *)addr, addrlen);
405 if (rc < static_cast<int>(reply.size())) {
406 std::cerr << "Failed to send full reply, rc=" << rc << std::endl;
411 MockChannelOptsTest::NiceMockServers MockChannelOptsTest::BuildServers(int count, int family, int base_port) {
412 NiceMockServers servers;
414 for (int ii = 0; ii < count; ii++) {
415 int port = base_port == dynamic_port ? dynamic_port : base_port + ii;
416 std::unique_ptr<NiceMockServer> server(new NiceMockServer(family, port));
417 servers.push_back(std::move(server));
422 MockChannelOptsTest::MockChannelOptsTest(int count,
425 struct ares_options* givenopts,
427 : servers_(BuildServers(count, family, mock_port)),
428 server_(*servers_[0].get()), channel_(nullptr) {
429 // Set up channel options.
430 struct ares_options opts;
432 memcpy(&opts, givenopts, sizeof(opts));
434 memset(&opts, 0, sizeof(opts));
437 // Point the library at the first mock server by default (overridden below).
438 opts.udp_port = server_.udpport();
439 optmask |= ARES_OPT_UDP_PORT;
440 opts.tcp_port = server_.tcpport();
441 optmask |= ARES_OPT_TCP_PORT;
443 // If not already overridden, set short-ish timeouts.
444 if (!(optmask & (ARES_OPT_TIMEOUTMS|ARES_OPT_TIMEOUT))) {
446 optmask |= ARES_OPT_TIMEOUTMS;
448 // If not already overridden, set 3 retries.
449 if (!(optmask & ARES_OPT_TRIES)) {
451 optmask |= ARES_OPT_TRIES;
453 // If not already overridden, set search domains.
454 const char *domains[3] = {"first.com", "second.org", "third.gov"};
455 if (!(optmask & ARES_OPT_DOMAINS)) {
457 opts.domains = (char**)domains;
458 optmask |= ARES_OPT_DOMAINS;
461 opts.flags |= ARES_FLAG_USEVC;
462 optmask |= ARES_OPT_FLAGS;
465 EXPECT_EQ(ARES_SUCCESS, ares_init_options(&channel_, &opts, optmask));
466 EXPECT_NE(nullptr, channel_);
468 // Set up servers after construction so we can set individual ports
469 struct ares_addr_port_node* prev = nullptr;
470 struct ares_addr_port_node* first = nullptr;
471 for (const auto& server : servers_) {
472 struct ares_addr_port_node* node = (struct ares_addr_port_node*)malloc(sizeof(*node));
478 node->next = nullptr;
479 node->family = family;
480 node->udp_port = server->udpport();
481 node->tcp_port = server->tcpport();
482 if (family == AF_INET) {
483 node->addr.addr4.s_addr = htonl(0x7F000001);
485 memset(&node->addr.addr6, 0, sizeof(node->addr.addr6));
486 node->addr.addr6._S6_un._S6_u8[15] = 1;
490 EXPECT_EQ(ARES_SUCCESS, ares_set_servers_ports(channel_, first));
498 std::cerr << "Configured library with servers:";
499 std::vector<std::string> servers = GetNameServers(channel_);
500 for (const auto& server : servers) {
501 std::cerr << " " << server;
503 std::cerr << std::endl;
507 MockChannelOptsTest::~MockChannelOptsTest() {
509 ares_destroy(channel_);
514 std::set<int> MockChannelOptsTest::fds() const {
516 for (const auto& server : servers_) {
517 std::set<int> serverfds = server->fds();
518 fds.insert(serverfds.begin(), serverfds.end());
523 void MockChannelOptsTest::ProcessFD(int fd) {
524 for (auto& server : servers_) {
525 server->ProcessFD(fd);
529 void MockChannelOptsTest::Process() {
530 using namespace std::placeholders;
531 ProcessWork(channel_,
532 std::bind(&MockChannelOptsTest::fds, this),
533 std::bind(&MockChannelOptsTest::ProcessFD, this, _1));
536 std::ostream& operator<<(std::ostream& os, const HostResult& result) {
539 os << StatusToString(result.status_) << " " << result.host_;
541 os << "(incomplete)";
547 HostEnt::HostEnt(const struct hostent *hostent) : addrtype_(-1) {
551 name_ = hostent->h_name;
552 if (hostent->h_aliases) {
553 char** palias = hostent->h_aliases;
554 while (*palias != nullptr) {
555 aliases_.push_back(*palias);
559 addrtype_ = hostent->h_addrtype;
560 if (hostent->h_addr_list) {
561 char** paddr = hostent->h_addr_list;
562 while (*paddr != nullptr) {
563 std::string addr = AddressToString(*paddr, hostent->h_length);
564 addrs_.push_back(addr);
570 std::ostream& operator<<(std::ostream& os, const HostEnt& host) {
572 os << "'" << host.name_ << "' "
574 for (size_t ii = 0; ii < host.aliases_.size(); ii++) {
575 if (ii > 0) os << ", ";
576 os << host.aliases_[ii];
580 for (size_t ii = 0; ii < host.addrs_.size(); ii++) {
581 if (ii > 0) os << ", ";
582 os << host.addrs_[ii];
589 void HostCallback(void *data, int status, int timeouts,
590 struct hostent *hostent) {
591 EXPECT_NE(nullptr, data);
592 HostResult* result = reinterpret_cast<HostResult*>(data);
593 result->done_ = true;
594 result->status_ = status;
595 result->timeouts_ = timeouts;
596 result->host_ = HostEnt(hostent);
597 if (verbose) std::cerr << "HostCallback(" << *result << ")" << std::endl;
600 std::ostream& operator<<(std::ostream& os, const AddrInfoResult& result) {
602 if (result.done_ && result.ai_) {
603 os << StatusToString(result.status_) << " " << result.ai_;
605 os << "(incomplete)";
611 std::ostream& operator<<(std::ostream& os, const AddrInfo& ai) {
618 struct ares_addrinfo_cname *next_cname = ai->cnames;
620 if(next_cname->alias) {
621 os << next_cname->alias << "->";
623 if(next_cname->name) {
624 os << next_cname->name;
626 if((next_cname = next_cname->next))
632 struct ares_addrinfo_node *next = ai->nodes;
634 //if(next->ai_canonname) {
635 //os << "'" << next->ai_canonname << "' ";
637 unsigned short port = 0;
639 if(next->ai_family == AF_INET) {
640 sockaddr_in* sin = (sockaddr_in*)next->ai_addr;
641 port = ntohs(sin->sin_port);
642 os << AddressToString(&sin->sin_addr, 4);
644 else if (next->ai_family == AF_INET6) {
645 sockaddr_in6* sin = (sockaddr_in6*)next->ai_addr;
646 port = ntohs(sin->sin6_port);
647 os << "[" << AddressToString(&sin->sin6_addr, 16) << "]";
650 os << "unknown family";
655 if((next = next->ai_next))
662 void AddrInfoCallback(void *data, int status, int timeouts,
663 struct ares_addrinfo *ai) {
664 EXPECT_NE(nullptr, data);
665 AddrInfoResult* result = reinterpret_cast<AddrInfoResult*>(data);
666 result->done_ = true;
667 result->status_ = status;
668 result->timeouts_= timeouts;
669 result->ai_ = AddrInfo(ai);
670 if (verbose) std::cerr << "AddrInfoCallback(" << *result << ")" << std::endl;
673 std::ostream& operator<<(std::ostream& os, const SearchResult& result) {
676 os << StatusToString(result.status_) << " " << PacketToString(result.data_);
678 os << "(incomplete)";
684 void SearchCallback(void *data, int status, int timeouts,
685 unsigned char *abuf, int alen) {
686 EXPECT_NE(nullptr, data);
687 SearchResult* result = reinterpret_cast<SearchResult*>(data);
688 result->done_ = true;
689 result->status_ = status;
690 result->timeouts_ = timeouts;
691 result->data_.assign(abuf, abuf + alen);
692 if (verbose) std::cerr << "SearchCallback(" << *result << ")" << std::endl;
695 std::ostream& operator<<(std::ostream& os, const NameInfoResult& result) {
698 os << StatusToString(result.status_) << " " << result.node_ << " " << result.service_;
700 os << "(incomplete)";
706 void NameInfoCallback(void *data, int status, int timeouts,
707 char *node, char *service) {
708 EXPECT_NE(nullptr, data);
709 NameInfoResult* result = reinterpret_cast<NameInfoResult*>(data);
710 result->done_ = true;
711 result->status_ = status;
712 result->timeouts_ = timeouts;
713 result->node_ = std::string(node ? node : "");
714 result->service_ = std::string(service ? service : "");
715 if (verbose) std::cerr << "NameInfoCallback(" << *result << ")" << std::endl;
718 std::vector<std::string> GetNameServers(ares_channel channel) {
719 struct ares_addr_port_node* servers = nullptr;
720 EXPECT_EQ(ARES_SUCCESS, ares_get_servers_ports(channel, &servers));
721 struct ares_addr_port_node* server = servers;
722 std::vector<std::string> results;
724 std::stringstream ss;
725 switch (server->family) {
727 ss << AddressToString((char*)&server->addr.addr4, 4);
730 if (server->udp_port != 0) {
733 ss << AddressToString((char*)&server->addr.addr6, 16);
734 if (server->udp_port != 0) {
739 results.push_back("<unknown family>");
742 if (server->udp_port != 0) {
743 ss << ":" << server->udp_port;
745 results.push_back(ss.str());
746 server = server->next;
748 if (servers) ares_free_data(servers);
752 TransientDir::TransientDir(const std::string& dirname) : dirname_(dirname) {
753 if (mkdir_(dirname_.c_str(), 0755) != 0) {
754 std::cerr << "Failed to create subdirectory '" << dirname_ << "'" << std::endl;
758 TransientDir::~TransientDir() {
759 rmdir(dirname_.c_str());
762 TransientFile::TransientFile(const std::string& filename,
763 const std::string& contents)
764 : filename_(filename) {
765 FILE *f = fopen(filename.c_str(), "w");
767 std::cerr << "Error: failed to create '" << filename << "'" << std::endl;
770 int rc = fwrite(contents.data(), 1, contents.size(), f);
771 if (rc != (int)contents.size()) {
772 std::cerr << "Error: failed to write contents of '" << filename << "'" << std::endl;
777 TransientFile::~TransientFile() {
778 unlink(filename_.c_str());
781 std::string TempNam(const char *dir, const char *prefix) {
782 char *p = tempnam(dir, prefix);
783 std::string result(p);
788 TempFile::TempFile(const std::string& contents)
789 : TransientFile(TempNam(nullptr, "ares"), contents) {
793 VirtualizeIO::VirtualizeIO(ares_channel c)
796 ares_set_socket_functions(channel_, &default_functions, 0);
799 VirtualizeIO::~VirtualizeIO() {
800 ares_set_socket_functions(channel_, 0, 0);