Move resolver_test.cpp from netd_integration_test to a new resolv_integration_test
1. make resolver_test.cpp as an independent integration test
2. rename libnetd_resolv_test to resolv_unit_test
Test: manually make and run:
- netd_integration_test
- resolv_integration_test
- resolv_unit_test
Test: run runtests.sh, make sure no missing test and get all pass
Test: atest resolv_integration_test
Change-Id: I29a115444d7955c5b6239df80481e29cd3f0e686
diff --git a/tests/Android.bp b/tests/Android.bp
index 5b35fdc..80f5217 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -35,16 +35,10 @@
":netd_metrics_aidl",
"binder_test.cpp",
"bpf_base_test.cpp",
- "dns_responder/dns_responder.cpp",
"netd_test.cpp",
- "resolver_test.cpp",
"netlink_listener_test.cpp",
],
- include_dirs: [
- "system/netd/resolv/include",
- "system/netd/server",
- "system/netd/tests/dns_responder",
- ],
+ include_dirs: ["system/netd/server"],
shared_libs: [
"libbase",
"libbinder",
@@ -60,7 +54,6 @@
],
static_libs: [
"libcap",
- "libnetd_test_dnsresponder",
"libnetd_test_tun_interface",
"libbpf_android",
"liblogwrap",
diff --git a/tests/benchmarks/Android.bp b/tests/benchmarks/Android.bp
index d2079c1..afed8d7 100644
--- a/tests/benchmarks/Android.bp
+++ b/tests/benchmarks/Android.bp
@@ -24,7 +24,7 @@
"system/netd/resolv/include",
"system/netd/server",
"system/netd/server/binder",
- "system/netd/tests/dns_responder",
+ "system/netd/resolv/dns_responder",
],
srcs: [
":netd_metrics_aidl",
diff --git a/tests/dns_responder/Android.bp b/tests/dns_responder/Android.bp
deleted file mode 100644
index 727d7c4..0000000
--- a/tests/dns_responder/Android.bp
+++ /dev/null
@@ -1,37 +0,0 @@
-cc_library_static {
- name: "libnetd_test_dnsresponder",
- defaults: ["netd_defaults"],
- cflags: [
- "-Wunused-parameter",
- "-Wthread-safety",
- ],
- shared_libs: [
- "libbase",
- "libbinder",
- "liblog",
- "libnetd_client",
- "libnetdaidl",
- "libnetdutils",
- "libssl",
- "netd_aidl_interface-cpp",
- ],
- static_libs: ["libutils"],
- aidl: {
- include_dirs: [
- "frameworks/native/aidl/binder",
- "system/netd/server/binder",
- ],
- },
- include_dirs: [
- "system/netd/include",
- "system/netd/resolv",
- "system/netd/server",
- "system/netd/server/binder",
- "system/netd/tests/dns_responder",
- ],
- srcs: [
- "dns_responder.cpp",
- "dns_responder_client.cpp",
- "dns_tls_frontend.cpp",
- ],
-}
diff --git a/tests/dns_responder/dns_responder.cpp b/tests/dns_responder/dns_responder.cpp
deleted file mode 100644
index 0860142..0000000
--- a/tests/dns_responder/dns_responder.cpp
+++ /dev/null
@@ -1,866 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "dns_responder.h"
-
-#include <arpa/inet.h>
-#include <fcntl.h>
-#include <netdb.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/epoll.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <iostream>
-#include <vector>
-
-#define LOG_TAG "DNSResponder"
-#include <log/log.h>
-#include <netdutils/SocketOption.h>
-
-using android::netdutils::enableSockopt;
-
-namespace test {
-
-std::string errno2str() {
- char error_msg[512] = { 0 };
- if (strerror_r(errno, error_msg, sizeof(error_msg)))
- return std::string();
- return std::string(error_msg);
-}
-
-#define APLOGI(fmt, ...) ALOGI(fmt ": [%d] %s", __VA_ARGS__, errno, errno2str().c_str())
-
-std::string str2hex(const char* buffer, size_t len) {
- std::string str(len*2, '\0');
- for (size_t i = 0 ; i < len ; ++i) {
- static const char* hex = "0123456789ABCDEF";
- uint8_t c = buffer[i];
- str[i*2] = hex[c >> 4];
- str[i*2 + 1] = hex[c & 0x0F];
- }
- return str;
-}
-
-std::string addr2str(const sockaddr* sa, socklen_t sa_len) {
- char host_str[NI_MAXHOST] = { 0 };
- int rv = getnameinfo(sa, sa_len, host_str, sizeof(host_str), nullptr, 0,
- NI_NUMERICHOST);
- if (rv == 0) return std::string(host_str);
- return std::string();
-}
-
-/* DNS struct helpers */
-
-const char* dnstype2str(unsigned dnstype) {
- static std::unordered_map<unsigned, const char*> kTypeStrs = {
- { ns_type::ns_t_a, "A" },
- { ns_type::ns_t_ns, "NS" },
- { ns_type::ns_t_md, "MD" },
- { ns_type::ns_t_mf, "MF" },
- { ns_type::ns_t_cname, "CNAME" },
- { ns_type::ns_t_soa, "SOA" },
- { ns_type::ns_t_mb, "MB" },
- { ns_type::ns_t_mb, "MG" },
- { ns_type::ns_t_mr, "MR" },
- { ns_type::ns_t_null, "NULL" },
- { ns_type::ns_t_wks, "WKS" },
- { ns_type::ns_t_ptr, "PTR" },
- { ns_type::ns_t_hinfo, "HINFO" },
- { ns_type::ns_t_minfo, "MINFO" },
- { ns_type::ns_t_mx, "MX" },
- { ns_type::ns_t_txt, "TXT" },
- { ns_type::ns_t_rp, "RP" },
- { ns_type::ns_t_afsdb, "AFSDB" },
- { ns_type::ns_t_x25, "X25" },
- { ns_type::ns_t_isdn, "ISDN" },
- { ns_type::ns_t_rt, "RT" },
- { ns_type::ns_t_nsap, "NSAP" },
- { ns_type::ns_t_nsap_ptr, "NSAP-PTR" },
- { ns_type::ns_t_sig, "SIG" },
- { ns_type::ns_t_key, "KEY" },
- { ns_type::ns_t_px, "PX" },
- { ns_type::ns_t_gpos, "GPOS" },
- { ns_type::ns_t_aaaa, "AAAA" },
- { ns_type::ns_t_loc, "LOC" },
- { ns_type::ns_t_nxt, "NXT" },
- { ns_type::ns_t_eid, "EID" },
- { ns_type::ns_t_nimloc, "NIMLOC" },
- { ns_type::ns_t_srv, "SRV" },
- { ns_type::ns_t_naptr, "NAPTR" },
- { ns_type::ns_t_kx, "KX" },
- { ns_type::ns_t_cert, "CERT" },
- { ns_type::ns_t_a6, "A6" },
- { ns_type::ns_t_dname, "DNAME" },
- { ns_type::ns_t_sink, "SINK" },
- { ns_type::ns_t_opt, "OPT" },
- { ns_type::ns_t_apl, "APL" },
- { ns_type::ns_t_tkey, "TKEY" },
- { ns_type::ns_t_tsig, "TSIG" },
- { ns_type::ns_t_ixfr, "IXFR" },
- { ns_type::ns_t_axfr, "AXFR" },
- { ns_type::ns_t_mailb, "MAILB" },
- { ns_type::ns_t_maila, "MAILA" },
- { ns_type::ns_t_any, "ANY" },
- { ns_type::ns_t_zxfr, "ZXFR" },
- };
- auto it = kTypeStrs.find(dnstype);
- static const char* kUnknownStr{ "UNKNOWN" };
- if (it == kTypeStrs.end()) return kUnknownStr;
- return it->second;
-}
-
-const char* dnsclass2str(unsigned dnsclass) {
- static std::unordered_map<unsigned, const char*> kClassStrs = {
- { ns_class::ns_c_in , "Internet" },
- { 2, "CSNet" },
- { ns_class::ns_c_chaos, "ChaosNet" },
- { ns_class::ns_c_hs, "Hesiod" },
- { ns_class::ns_c_none, "none" },
- { ns_class::ns_c_any, "any" }
- };
- auto it = kClassStrs.find(dnsclass);
- static const char* kUnknownStr{ "UNKNOWN" };
- if (it == kClassStrs.end()) return kUnknownStr;
- return it->second;
- return "unknown";
-}
-
-struct DNSName {
- std::string name;
- const char* read(const char* buffer, const char* buffer_end);
- char* write(char* buffer, const char* buffer_end) const;
- const char* toString() const;
-private:
- const char* parseField(const char* buffer, const char* buffer_end,
- bool* last);
-};
-
-const char* DNSName::toString() const {
- return name.c_str();
-}
-
-const char* DNSName::read(const char* buffer, const char* buffer_end) {
- const char* cur = buffer;
- bool last = false;
- do {
- cur = parseField(cur, buffer_end, &last);
- if (cur == nullptr) {
- ALOGI("parsing failed at line %d", __LINE__);
- return nullptr;
- }
- } while (!last);
- return cur;
-}
-
-char* DNSName::write(char* buffer, const char* buffer_end) const {
- char* buffer_cur = buffer;
- for (size_t pos = 0 ; pos < name.size() ; ) {
- size_t dot_pos = name.find('.', pos);
- if (dot_pos == std::string::npos) {
- // Sanity check, should never happen unless parseField is broken.
- ALOGI("logic error: all names are expected to end with a '.'");
- return nullptr;
- }
- size_t len = dot_pos - pos;
- if (len >= 256) {
- ALOGI("name component '%s' is %zu long, but max is 255",
- name.substr(pos, dot_pos - pos).c_str(), len);
- return nullptr;
- }
- if (buffer_cur + sizeof(uint8_t) + len > buffer_end) {
- ALOGI("buffer overflow at line %d", __LINE__);
- return nullptr;
- }
- *buffer_cur++ = len;
- buffer_cur = std::copy(std::next(name.begin(), pos),
- std::next(name.begin(), dot_pos),
- buffer_cur);
- pos = dot_pos + 1;
- }
- // Write final zero.
- *buffer_cur++ = 0;
- return buffer_cur;
-}
-
-const char* DNSName::parseField(const char* buffer, const char* buffer_end,
- bool* last) {
- if (buffer + sizeof(uint8_t) > buffer_end) {
- ALOGI("parsing failed at line %d", __LINE__);
- return nullptr;
- }
- unsigned field_type = *buffer >> 6;
- unsigned ofs = *buffer & 0x3F;
- const char* cur = buffer + sizeof(uint8_t);
- if (field_type == 0) {
- // length + name component
- if (ofs == 0) {
- *last = true;
- return cur;
- }
- if (cur + ofs > buffer_end) {
- ALOGI("parsing failed at line %d", __LINE__);
- return nullptr;
- }
- name.append(cur, ofs);
- name.push_back('.');
- return cur + ofs;
- } else if (field_type == 3) {
- ALOGI("name compression not implemented");
- return nullptr;
- }
- ALOGI("invalid name field type");
- return nullptr;
-}
-
-struct DNSQuestion {
- DNSName qname;
- unsigned qtype;
- unsigned qclass;
- const char* read(const char* buffer, const char* buffer_end);
- char* write(char* buffer, const char* buffer_end) const;
- std::string toString() const;
-};
-
-const char* DNSQuestion::read(const char* buffer, const char* buffer_end) {
- const char* cur = qname.read(buffer, buffer_end);
- if (cur == nullptr) {
- ALOGI("parsing failed at line %d", __LINE__);
- return nullptr;
- }
- if (cur + 2*sizeof(uint16_t) > buffer_end) {
- ALOGI("parsing failed at line %d", __LINE__);
- return nullptr;
- }
- qtype = ntohs(*reinterpret_cast<const uint16_t*>(cur));
- qclass = ntohs(*reinterpret_cast<const uint16_t*>(cur + sizeof(uint16_t)));
- return cur + 2*sizeof(uint16_t);
-}
-
-char* DNSQuestion::write(char* buffer, const char* buffer_end) const {
- char* buffer_cur = qname.write(buffer, buffer_end);
- if (buffer_cur == nullptr) return nullptr;
- if (buffer_cur + 2*sizeof(uint16_t) > buffer_end) {
- ALOGI("buffer overflow on line %d", __LINE__);
- return nullptr;
- }
- *reinterpret_cast<uint16_t*>(buffer_cur) = htons(qtype);
- *reinterpret_cast<uint16_t*>(buffer_cur + sizeof(uint16_t)) =
- htons(qclass);
- return buffer_cur + 2*sizeof(uint16_t);
-}
-
-std::string DNSQuestion::toString() const {
- char buffer[4096];
- int len = snprintf(buffer, sizeof(buffer), "Q<%s,%s,%s>", qname.toString(),
- dnstype2str(qtype), dnsclass2str(qclass));
- return std::string(buffer, len);
-}
-
-struct DNSRecord {
- DNSName name;
- unsigned rtype;
- unsigned rclass;
- unsigned ttl;
- std::vector<char> rdata;
- const char* read(const char* buffer, const char* buffer_end);
- char* write(char* buffer, const char* buffer_end) const;
- std::string toString() const;
-private:
- struct IntFields {
- uint16_t rtype;
- uint16_t rclass;
- uint32_t ttl;
- uint16_t rdlen;
- } __attribute__((__packed__));
-
- const char* readIntFields(const char* buffer, const char* buffer_end,
- unsigned* rdlen);
- char* writeIntFields(unsigned rdlen, char* buffer,
- const char* buffer_end) const;
-};
-
-const char* DNSRecord::read(const char* buffer, const char* buffer_end) {
- const char* cur = name.read(buffer, buffer_end);
- if (cur == nullptr) {
- ALOGI("parsing failed at line %d", __LINE__);
- return nullptr;
- }
- unsigned rdlen = 0;
- cur = readIntFields(cur, buffer_end, &rdlen);
- if (cur == nullptr) {
- ALOGI("parsing failed at line %d", __LINE__);
- return nullptr;
- }
- if (cur + rdlen > buffer_end) {
- ALOGI("parsing failed at line %d", __LINE__);
- return nullptr;
- }
- rdata.assign(cur, cur + rdlen);
- return cur + rdlen;
-}
-
-char* DNSRecord::write(char* buffer, const char* buffer_end) const {
- char* buffer_cur = name.write(buffer, buffer_end);
- if (buffer_cur == nullptr) return nullptr;
- buffer_cur = writeIntFields(rdata.size(), buffer_cur, buffer_end);
- if (buffer_cur == nullptr) return nullptr;
- if (buffer_cur + rdata.size() > buffer_end) {
- ALOGI("buffer overflow on line %d", __LINE__);
- return nullptr;
- }
- return std::copy(rdata.begin(), rdata.end(), buffer_cur);
-}
-
-std::string DNSRecord::toString() const {
- char buffer[4096];
- int len = snprintf(buffer, sizeof(buffer), "R<%s,%s,%s>", name.toString(),
- dnstype2str(rtype), dnsclass2str(rclass));
- return std::string(buffer, len);
-}
-
-const char* DNSRecord::readIntFields(const char* buffer, const char* buffer_end,
- unsigned* rdlen) {
- if (buffer + sizeof(IntFields) > buffer_end ) {
- ALOGI("parsing failed at line %d", __LINE__);
- return nullptr;
- }
- const auto& intfields = *reinterpret_cast<const IntFields*>(buffer);
- rtype = ntohs(intfields.rtype);
- rclass = ntohs(intfields.rclass);
- ttl = ntohl(intfields.ttl);
- *rdlen = ntohs(intfields.rdlen);
- return buffer + sizeof(IntFields);
-}
-
-char* DNSRecord::writeIntFields(unsigned rdlen, char* buffer,
- const char* buffer_end) const {
- if (buffer + sizeof(IntFields) > buffer_end ) {
- ALOGI("buffer overflow on line %d", __LINE__);
- return nullptr;
- }
- auto& intfields = *reinterpret_cast<IntFields*>(buffer);
- intfields.rtype = htons(rtype);
- intfields.rclass = htons(rclass);
- intfields.ttl = htonl(ttl);
- intfields.rdlen = htons(rdlen);
- return buffer + sizeof(IntFields);
-}
-
-struct DNSHeader {
- unsigned id;
- bool ra;
- uint8_t rcode;
- bool qr;
- uint8_t opcode;
- bool aa;
- bool tr;
- bool rd;
- bool ad;
- std::vector<DNSQuestion> questions;
- std::vector<DNSRecord> answers;
- std::vector<DNSRecord> authorities;
- std::vector<DNSRecord> additionals;
- const char* read(const char* buffer, const char* buffer_end);
- char* write(char* buffer, const char* buffer_end) const;
- std::string toString() const;
-
-private:
- struct Header {
- uint16_t id;
- uint8_t flags0;
- uint8_t flags1;
- uint16_t qdcount;
- uint16_t ancount;
- uint16_t nscount;
- uint16_t arcount;
- } __attribute__((__packed__));
-
- const char* readHeader(const char* buffer, const char* buffer_end,
- unsigned* qdcount, unsigned* ancount,
- unsigned* nscount, unsigned* arcount);
-};
-
-const char* DNSHeader::read(const char* buffer, const char* buffer_end) {
- unsigned qdcount;
- unsigned ancount;
- unsigned nscount;
- unsigned arcount;
- const char* cur = readHeader(buffer, buffer_end, &qdcount, &ancount,
- &nscount, &arcount);
- if (cur == nullptr) {
- ALOGI("parsing failed at line %d", __LINE__);
- return nullptr;
- }
- if (qdcount) {
- questions.resize(qdcount);
- for (unsigned i = 0 ; i < qdcount ; ++i) {
- cur = questions[i].read(cur, buffer_end);
- if (cur == nullptr) {
- ALOGI("parsing failed at line %d", __LINE__);
- return nullptr;
- }
- }
- }
- if (ancount) {
- answers.resize(ancount);
- for (unsigned i = 0 ; i < ancount ; ++i) {
- cur = answers[i].read(cur, buffer_end);
- if (cur == nullptr) {
- ALOGI("parsing failed at line %d", __LINE__);
- return nullptr;
- }
- }
- }
- if (nscount) {
- authorities.resize(nscount);
- for (unsigned i = 0 ; i < nscount ; ++i) {
- cur = authorities[i].read(cur, buffer_end);
- if (cur == nullptr) {
- ALOGI("parsing failed at line %d", __LINE__);
- return nullptr;
- }
- }
- }
- if (arcount) {
- additionals.resize(arcount);
- for (unsigned i = 0 ; i < arcount ; ++i) {
- cur = additionals[i].read(cur, buffer_end);
- if (cur == nullptr) {
- ALOGI("parsing failed at line %d", __LINE__);
- return nullptr;
- }
- }
- }
- return cur;
-}
-
-char* DNSHeader::write(char* buffer, const char* buffer_end) const {
- if (buffer + sizeof(Header) > buffer_end) {
- ALOGI("buffer overflow on line %d", __LINE__);
- return nullptr;
- }
- Header& header = *reinterpret_cast<Header*>(buffer);
- // bytes 0-1
- header.id = htons(id);
- // byte 2: 7:qr, 3-6:opcode, 2:aa, 1:tr, 0:rd
- header.flags0 = (qr << 7) | (opcode << 3) | (aa << 2) | (tr << 1) | rd;
- // byte 3: 7:ra, 6:zero, 5:ad, 4:cd, 0-3:rcode
- // Fake behavior: if the query set the "ad" bit, set it in the response too.
- // In a real server, this should be set only if the data is authentic and the
- // query contained an "ad" bit or DNSSEC extensions.
- header.flags1 = (ad << 5) | rcode;
- // rest of header
- header.qdcount = htons(questions.size());
- header.ancount = htons(answers.size());
- header.nscount = htons(authorities.size());
- header.arcount = htons(additionals.size());
- char* buffer_cur = buffer + sizeof(Header);
- for (const DNSQuestion& question : questions) {
- buffer_cur = question.write(buffer_cur, buffer_end);
- if (buffer_cur == nullptr) return nullptr;
- }
- for (const DNSRecord& answer : answers) {
- buffer_cur = answer.write(buffer_cur, buffer_end);
- if (buffer_cur == nullptr) return nullptr;
- }
- for (const DNSRecord& authority : authorities) {
- buffer_cur = authority.write(buffer_cur, buffer_end);
- if (buffer_cur == nullptr) return nullptr;
- }
- for (const DNSRecord& additional : additionals) {
- buffer_cur = additional.write(buffer_cur, buffer_end);
- if (buffer_cur == nullptr) return nullptr;
- }
- return buffer_cur;
-}
-
-std::string DNSHeader::toString() const {
- // TODO
- return std::string();
-}
-
-const char* DNSHeader::readHeader(const char* buffer, const char* buffer_end,
- unsigned* qdcount, unsigned* ancount,
- unsigned* nscount, unsigned* arcount) {
- if (buffer + sizeof(Header) > buffer_end)
- return nullptr;
- const auto& header = *reinterpret_cast<const Header*>(buffer);
- // bytes 0-1
- id = ntohs(header.id);
- // byte 2: 7:qr, 3-6:opcode, 2:aa, 1:tr, 0:rd
- qr = header.flags0 >> 7;
- opcode = (header.flags0 >> 3) & 0x0F;
- aa = (header.flags0 >> 2) & 1;
- tr = (header.flags0 >> 1) & 1;
- rd = header.flags0 & 1;
- // byte 3: 7:ra, 6:zero, 5:ad, 4:cd, 0-3:rcode
- ra = header.flags1 >> 7;
- ad = (header.flags1 >> 5) & 1;
- rcode = header.flags1 & 0xF;
- // rest of header
- *qdcount = ntohs(header.qdcount);
- *ancount = ntohs(header.ancount);
- *nscount = ntohs(header.nscount);
- *arcount = ntohs(header.arcount);
- return buffer + sizeof(Header);
-}
-
-/* DNS responder */
-
-DNSResponder::DNSResponder(std::string listen_address, std::string listen_service,
- int poll_timeout_ms, ns_rcode error_rcode)
- : listen_address_(std::move(listen_address)),
- listen_service_(std::move(listen_service)),
- poll_timeout_ms_(poll_timeout_ms),
- error_rcode_(error_rcode) {}
-
-DNSResponder::~DNSResponder() {
- stopServer();
-}
-
-void DNSResponder::addMapping(const std::string& name, ns_type type, const std::string& addr) {
- std::lock_guard lock(mappings_mutex_);
- auto it = mappings_.find(QueryKey(name, type));
- if (it != mappings_.end()) {
- ALOGI("Overwriting mapping for (%s, %s), previous address %s, new "
- "address %s",
- name.c_str(), dnstype2str(type), it->second.c_str(), addr.c_str());
- it->second = addr;
- return;
- }
- mappings_.try_emplace({name, type}, addr);
-}
-
-void DNSResponder::removeMapping(const std::string& name, ns_type type) {
- std::lock_guard lock(mappings_mutex_);
- auto it = mappings_.find(QueryKey(name, type));
- if (it != mappings_.end()) {
- ALOGI("Cannot remove mapping mapping from (%s, %s), not present", name.c_str(),
- dnstype2str(type));
- return;
- }
- mappings_.erase(it);
-}
-
-void DNSResponder::setResponseProbability(double response_probability) {
- response_probability_ = response_probability;
-}
-
-bool DNSResponder::running() const {
- return socket_ != -1;
-}
-
-bool DNSResponder::startServer() {
- if (running()) {
- ALOGI("server already running");
- return false;
- }
- addrinfo ai_hints{
- .ai_family = AF_UNSPEC,
- .ai_socktype = SOCK_DGRAM,
- .ai_flags = AI_PASSIVE
- };
- addrinfo* ai_res;
- int rv = getaddrinfo(listen_address_.c_str(), listen_service_.c_str(),
- &ai_hints, &ai_res);
- if (rv) {
- ALOGI("getaddrinfo(%s, %s) failed: %s", listen_address_.c_str(),
- listen_service_.c_str(), gai_strerror(rv));
- return false;
- }
- int s = -1;
- for (const addrinfo* ai = ai_res ; ai ; ai = ai->ai_next) {
- s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
- if (s < 0) continue;
- enableSockopt(s, SOL_SOCKET, SO_REUSEPORT).ignoreError();
- enableSockopt(s, SOL_SOCKET, SO_REUSEADDR).ignoreError();
- if (bind(s, ai->ai_addr, ai->ai_addrlen)) {
- APLOGI("bind failed for socket %d", s);
- close(s);
- s = -1;
- continue;
- }
- std::string host_str = addr2str(ai->ai_addr, ai->ai_addrlen);
- ALOGI("bound to UDP %s:%s", host_str.c_str(), listen_service_.c_str());
- break;
- }
- freeaddrinfo(ai_res);
- if (s < 0) {
- ALOGI("bind() failed");
- return false;
- }
-
- int flags = fcntl(s, F_GETFL, 0);
- if (flags < 0) flags = 0;
- if (fcntl(s, F_SETFL, flags | O_NONBLOCK) < 0) {
- APLOGI("fcntl(F_SETFL) failed for socket %d", s);
- close(s);
- return false;
- }
-
- int ep_fd = epoll_create1(EPOLL_CLOEXEC);
- if (ep_fd < 0) {
- char error_msg[512] = { 0 };
- if (strerror_r(errno, error_msg, sizeof(error_msg)))
- strncpy(error_msg, "UNKNOWN", sizeof(error_msg));
- APLOGI("epoll_create1() failed: %s", error_msg);
- close(s);
- return false;
- }
- epoll_event ev;
- ev.events = EPOLLIN;
- ev.data.fd = s;
- if (epoll_ctl(ep_fd, EPOLL_CTL_ADD, s, &ev) < 0) {
- APLOGI("epoll_ctl() failed for socket %d", s);
- close(ep_fd);
- close(s);
- return false;
- }
-
- epoll_fd_ = ep_fd;
- socket_ = s;
- {
- std::lock_guard lock(update_mutex_);
- handler_thread_ = std::thread(&DNSResponder::requestHandler, this);
- }
- ALOGI("server started successfully");
- return true;
-}
-
-bool DNSResponder::stopServer() {
- std::lock_guard lock(update_mutex_);
- if (!running()) {
- ALOGI("server not running");
- return false;
- }
- if (terminate_) {
- ALOGI("LOGIC ERROR");
- return false;
- }
- ALOGI("stopping server");
- terminate_ = true;
- handler_thread_.join();
- close(epoll_fd_);
- close(socket_);
- terminate_ = false;
- socket_ = -1;
- ALOGI("server stopped successfully");
- return true;
-}
-
-std::vector<std::pair<std::string, ns_type >> DNSResponder::queries() const {
- std::lock_guard lock(queries_mutex_);
- return queries_;
-}
-
-std::string DNSResponder::dumpQueries() const {
- std::lock_guard lock(queries_mutex_);
- std::string out;
- for (const auto& q : queries_) {
- out += "{\"" + q.first + "\", " + std::to_string(q.second) + "} ";
- }
- return out;
-}
-
-void DNSResponder::clearQueries() {
- std::lock_guard lock(queries_mutex_);
- queries_.clear();
-}
-
-void DNSResponder::requestHandler() {
- epoll_event evs[1];
- while (!terminate_) {
- int n = epoll_wait(epoll_fd_, evs, 1, poll_timeout_ms_);
- if (n == 0) continue;
- if (n < 0) {
- ALOGI("epoll_wait() failed");
- // TODO(imaipi): terminate on error.
- return;
- }
- char buffer[4096];
- sockaddr_storage sa;
- socklen_t sa_len = sizeof(sa);
- ssize_t len;
- do {
- len = recvfrom(socket_, buffer, sizeof(buffer), 0,
- (sockaddr*) &sa, &sa_len);
- } while (len < 0 && (errno == EAGAIN || errno == EINTR));
- if (len <= 0) {
- ALOGI("recvfrom() failed");
- continue;
- }
- ALOGI("read %zd bytes", len);
- char response[4096];
- size_t response_len = sizeof(response);
- if (handleDNSRequest(buffer, len, response, &response_len) &&
- response_len > 0) {
- len = sendto(socket_, response, response_len, 0,
- reinterpret_cast<const sockaddr*>(&sa), sa_len);
- std::string host_str =
- addr2str(reinterpret_cast<const sockaddr*>(&sa), sa_len);
- if (len > 0) {
- ALOGI("sent %zu bytes to %s", len, host_str.c_str());
- } else {
- APLOGI("sendto() failed for %s", host_str.c_str());
- }
- // Test that the response is actually a correct DNS message.
- const char* response_end = response + len;
- DNSHeader header;
- const char* cur = header.read(response, response_end);
- if (cur == nullptr) ALOGI("response is flawed");
-
- } else {
- ALOGI("not responding");
- }
- }
-}
-
-bool DNSResponder::handleDNSRequest(const char* buffer, ssize_t len,
- char* response, size_t* response_len)
- const {
- ALOGI("request: '%s'", str2hex(buffer, len).c_str());
- const char* buffer_end = buffer + len;
- DNSHeader header;
- const char* cur = header.read(buffer, buffer_end);
- // TODO(imaipi): for now, unparsable messages are silently dropped, fix.
- if (cur == nullptr) {
- ALOGI("failed to parse query");
- return false;
- }
- if (header.qr) {
- ALOGI("response received instead of a query");
- return false;
- }
- if (header.opcode != ns_opcode::ns_o_query) {
- ALOGI("unsupported request opcode received");
- return makeErrorResponse(&header, ns_rcode::ns_r_notimpl, response,
- response_len);
- }
- if (header.questions.empty()) {
- ALOGI("no questions present");
- return makeErrorResponse(&header, ns_rcode::ns_r_formerr, response,
- response_len);
- }
- if (!header.answers.empty()) {
- ALOGI("already %zu answers present in query", header.answers.size());
- return makeErrorResponse(&header, ns_rcode::ns_r_formerr, response,
- response_len);
- }
- if (!header.additionals.empty() && fail_on_edns_) {
- ALOGI("DNS request has an additional section (assumed EDNS). "
- "Simulating an ancient (pre-EDNS) server.");
- return makeErrorResponse(&header, ns_rcode::ns_r_formerr, response,
- response_len);
- }
- {
- std::lock_guard lock(queries_mutex_);
- for (const DNSQuestion& question : header.questions) {
- queries_.push_back(make_pair(question.qname.name,
- ns_type(question.qtype)));
- }
- }
-
- // Ignore requests with the preset probability.
- auto constexpr bound = std::numeric_limits<unsigned>::max();
- if (arc4random_uniform(bound) > bound * response_probability_) {
- if (error_rcode_ < 0) {
- ALOGI("Returning no response");
- return true;
- } else {
- ALOGI("returning RCODE %d in accordance with probability distribution",
- static_cast<int>(error_rcode_));
- return makeErrorResponse(&header, error_rcode_, response, response_len);
- }
- }
-
- for (const DNSQuestion& question : header.questions) {
- if (question.qclass != ns_class::ns_c_in &&
- question.qclass != ns_class::ns_c_any) {
- ALOGI("unsupported question class %u", question.qclass);
- return makeErrorResponse(&header, ns_rcode::ns_r_notimpl, response,
- response_len);
- }
- if (!addAnswerRecords(question, &header.answers)) {
- return makeErrorResponse(&header, ns_rcode::ns_r_servfail, response,
- response_len);
- }
- }
- header.qr = true;
- char* response_cur = header.write(response, response + *response_len);
- if (response_cur == nullptr) {
- return false;
- }
- *response_len = response_cur - response;
- return true;
-}
-
-bool DNSResponder::addAnswerRecords(const DNSQuestion& question,
- std::vector<DNSRecord>* answers) const {
- std::lock_guard guard(mappings_mutex_);
- auto it = mappings_.find(QueryKey(question.qname.name, question.qtype));
- if (it == mappings_.end()) {
- // TODO(imaipi): handle correctly
- ALOGI("no mapping found for %s %s, lazily refusing to add an answer",
- question.qname.name.c_str(), dnstype2str(question.qtype));
- return true;
- }
- ALOGI("mapping found for %s %s: %s", question.qname.name.c_str(),
- dnstype2str(question.qtype), it->second.c_str());
- DNSRecord record;
- record.name = question.qname;
- record.rtype = question.qtype;
- record.rclass = ns_class::ns_c_in;
- record.ttl = 5; // seconds
- if (question.qtype == ns_type::ns_t_a) {
- record.rdata.resize(4);
- if (inet_pton(AF_INET, it->second.c_str(), record.rdata.data()) != 1) {
- ALOGI("inet_pton(AF_INET, %s) failed", it->second.c_str());
- return false;
- }
- } else if (question.qtype == ns_type::ns_t_aaaa) {
- record.rdata.resize(16);
- if (inet_pton(AF_INET6, it->second.c_str(), record.rdata.data()) != 1) {
- ALOGI("inet_pton(AF_INET6, %s) failed", it->second.c_str());
- return false;
- }
- } else {
- ALOGI("unhandled qtype %s", dnstype2str(question.qtype));
- return false;
- }
- answers->push_back(std::move(record));
- return true;
-}
-
-bool DNSResponder::makeErrorResponse(DNSHeader* header, ns_rcode rcode,
- char* response, size_t* response_len)
- const {
- header->answers.clear();
- header->authorities.clear();
- header->additionals.clear();
- header->rcode = rcode;
- header->qr = true;
- char* response_cur = header->write(response, response + *response_len);
- if (response_cur == nullptr) return false;
- *response_len = response_cur - response;
- return true;
-}
-
-} // namespace test
diff --git a/tests/dns_responder/dns_responder.h b/tests/dns_responder/dns_responder.h
deleted file mode 100644
index e3da72d..0000000
--- a/tests/dns_responder/dns_responder.h
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless requied by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-#ifndef DNS_RESPONDER_H
-#define DNS_RESPONDER_H
-
-#include <arpa/nameser.h>
-
-#include <atomic>
-#include <mutex>
-#include <string>
-#include <thread>
-#include <unordered_map>
-#include <vector>
-
-#include <android-base/thread_annotations.h>
-
-namespace test {
-
-struct DNSHeader;
-struct DNSQuestion;
-struct DNSRecord;
-
-/*
- * Simple DNS responder, which replies to queries with the registered response
- * for that type. Class is assumed to be IN. If no response is registered, the
- * default error response code is returned.
- */
-class DNSResponder {
- public:
- DNSResponder(std::string listen_address, std::string listen_service, int poll_timeout_ms,
- ns_rcode error_rcode);
- ~DNSResponder();
- void addMapping(const std::string& name, ns_type type, const std::string& addr);
- void removeMapping(const std::string& name, ns_type type);
- void setResponseProbability(double response_probability);
- void setFailOnEdns(bool fail) { fail_on_edns_ = fail; }
- bool running() const;
- bool startServer();
- bool stopServer();
- const std::string& listen_address() const {
- return listen_address_;
- }
- const std::string& listen_service() const {
- return listen_service_;
- }
- std::vector<std::pair<std::string, ns_type>> queries() const;
- std::string dumpQueries() const;
- void clearQueries();
-
- private:
- // Key used for accessing mappings.
- struct QueryKey {
- std::string name;
- unsigned type;
-
- QueryKey(std::string n, unsigned t) : name(move(n)), type(t) {}
- bool operator == (const QueryKey& o) const {
- return name == o.name && type == o.type;
- }
- bool operator < (const QueryKey& o) const {
- if (name < o.name) return true;
- if (name > o.name) return false;
- return type < o.type;
- }
- };
-
- struct QueryKeyHash {
- size_t operator() (const QueryKey& key) const {
- return std::hash<std::string>()(key.name) +
- static_cast<size_t>(key.type);
- }
- };
-
- // DNS request handler.
- void requestHandler();
-
- // Parses and generates a response message for incoming DNS requests.
- // Returns false on parsing errors.
- bool handleDNSRequest(const char* buffer, ssize_t buffer_len,
- char* response, size_t* response_len) const;
-
- bool addAnswerRecords(const DNSQuestion& question,
- std::vector<DNSRecord>* answers) const;
-
- bool generateErrorResponse(DNSHeader* header, ns_rcode rcode,
- char* response, size_t* response_len) const;
- bool makeErrorResponse(DNSHeader* header, ns_rcode rcode, char* response,
- size_t* response_len) const;
-
-
- // Address and service to listen on, currently limited to UDP.
- const std::string listen_address_;
- const std::string listen_service_;
- // epoll_wait() timeout in ms.
- const int poll_timeout_ms_;
- // Error code to return for requests for an unknown name.
- const ns_rcode error_rcode_;
- // Probability that a valid response is being sent instead of being sent
- // instead of returning error_rcode_.
- std::atomic<double> response_probability_ = 1.0;
-
- // If true, behave like an old DNS server that doesn't support EDNS.
- // Default false.
- std::atomic<bool> fail_on_edns_ = false;
-
- // Mappings from (name, type) to registered response and the
- // mutex protecting them.
- std::unordered_map<QueryKey, std::string, QueryKeyHash> mappings_
- GUARDED_BY(mappings_mutex_);
- mutable std::mutex mappings_mutex_;
- // Query names received so far and the corresponding mutex.
- mutable std::vector<std::pair<std::string, ns_type>> queries_
- GUARDED_BY(queries_mutex_);
- mutable std::mutex queries_mutex_;
- // Socket on which the server is listening.
- int socket_ = -1;
- // File descriptor for epoll.
- int epoll_fd_ = -1;
- // Signal for request handler termination.
- std::atomic<bool> terminate_ = false;
- // Thread for handling incoming threads.
- std::thread handler_thread_ GUARDED_BY(update_mutex_);
- std::mutex update_mutex_;
-};
-
-} // namespace test
-
-#endif // DNS_RESPONDER_H
diff --git a/tests/dns_responder/dns_responder_client.cpp b/tests/dns_responder/dns_responder_client.cpp
deleted file mode 100644
index efc6d8e..0000000
--- a/tests/dns_responder/dns_responder_client.cpp
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "dns_responder_client"
-#include "dns_responder_client.h"
-
-#include <android-base/stringprintf.h>
-#include <utils/Log.h>
-
-// TODO: make this dynamic and stop depending on implementation details.
-#define TEST_OEM_NETWORK "oem29"
-#define TEST_NETID 30
-
-// TODO: move this somewhere shared.
-static const char* ANDROID_DNS_MODE = "ANDROID_DNS_MODE";
-
-using android::base::StringPrintf;
-using android::net::INetd;
-
-void DnsResponderClient::SetupMappings(unsigned num_hosts, const std::vector<std::string>& domains,
- std::vector<Mapping>* mappings) {
- mappings->resize(num_hosts * domains.size());
- auto mappings_it = mappings->begin();
- for (unsigned i = 0 ; i < num_hosts ; ++i) {
- for (const auto& domain : domains) {
- mappings_it->host = StringPrintf("host%u", i);
- mappings_it->entry = StringPrintf("%s.%s.", mappings_it->host.c_str(),
- domain.c_str());
- mappings_it->ip4 = StringPrintf("192.0.2.%u", i%253 + 1);
- mappings_it->ip6 = StringPrintf("2001:db8::%x", i%65534 + 1);
- ++mappings_it;
- }
- }
-}
-
-bool DnsResponderClient::SetResolversForNetwork(const std::vector<std::string>& servers,
- const std::vector<std::string>& domains, const std::vector<int>& params) {
- const auto rv = mNetdSrv->setResolverConfiguration(TEST_NETID, servers, domains, params,
- "", {}, {});
- return rv.isOk();
-}
-
-bool DnsResponderClient::SetResolversWithTls(const std::vector<std::string>& servers,
- const std::vector<std::string>& domains, const std::vector<int>& params,
- const std::vector<std::string>& tlsServers,
- const std::string& name, const std::vector<std::string>& fingerprints) {
- const auto rv = mNetdSrv->setResolverConfiguration(TEST_NETID, servers, domains, params,
- name, tlsServers, fingerprints);
- if (!rv.isOk()) ALOGI("SetResolversWithTls() -> %s", rv.toString8().c_str());
- return rv.isOk();
-}
-
-void DnsResponderClient::SetupDNSServers(unsigned num_servers, const std::vector<Mapping>& mappings,
- std::vector<std::unique_ptr<test::DNSResponder>>* dns,
- std::vector<std::string>* servers) {
- const char* listen_srv = "53";
- dns->resize(num_servers);
- servers->resize(num_servers);
- for (unsigned i = 0 ; i < num_servers ; ++i) {
- auto& server = (*servers)[i];
- auto& d = (*dns)[i];
- server = StringPrintf("127.0.0.%u", i + 100);
- d = std::make_unique<test::DNSResponder>(server, listen_srv, 250, ns_rcode::ns_r_servfail);
- for (const auto& mapping : mappings) {
- d->addMapping(mapping.entry.c_str(), ns_type::ns_t_a, mapping.ip4.c_str());
- d->addMapping(mapping.entry.c_str(), ns_type::ns_t_aaaa, mapping.ip6.c_str());
- }
- d->startServer();
- }
-}
-
-void DnsResponderClient::ShutdownDNSServers(std::vector<std::unique_ptr<test::DNSResponder>>* dns) {
- for (const auto& d : *dns) {
- d->stopServer();
- }
- dns->clear();
-}
-
-int DnsResponderClient::SetupOemNetwork() {
- mNetdSrv->networkDestroy(TEST_NETID);
- auto ret = mNetdSrv->networkCreatePhysical(TEST_NETID, INetd::PERMISSION_NONE);
- if (!ret.isOk()) {
- fprintf(stderr, "Creating physical network %d failed, %s\n", TEST_NETID,
- ret.toString8().string());
- return -1;
- }
- int oemNetId = TEST_NETID;
- setNetworkForProcess(oemNetId);
- if ((unsigned) oemNetId != getNetworkForProcess()) {
- return -1;
- }
- return oemNetId;
-}
-
-void DnsResponderClient::TearDownOemNetwork(int oemNetId) {
- if (oemNetId != -1) {
- mNetdSrv->networkDestroy(oemNetId);
- }
-}
-
-void DnsResponderClient::SetUp() {
- // binder setup
- auto binder = android::defaultServiceManager()->getService(android::String16("netd"));
- mNetdSrv = android::interface_cast<android::net::INetd>(binder);
-
- // Ensure resolutions go via proxy.
- setenv(ANDROID_DNS_MODE, "", 1);
- mOemNetId = SetupOemNetwork();
-}
-
-void DnsResponderClient::TearDown() {
- TearDownOemNetwork(mOemNetId);
-}
diff --git a/tests/dns_responder/dns_responder_client.h b/tests/dns_responder/dns_responder_client.h
deleted file mode 100644
index c03c1b5..0000000
--- a/tests/dns_responder/dns_responder_client.h
+++ /dev/null
@@ -1,76 +0,0 @@
-#ifndef DNS_RESPONDER_CLIENT_H
-#define DNS_RESPONDER_CLIENT_H
-
-#include <memory>
-#include <string>
-#include <vector>
-
-#include <cutils/sockets.h>
-
-#include <private/android_filesystem_config.h>
-#include <utils/StrongPointer.h>
-
-#include "android/net/INetd.h"
-#include "binder/IServiceManager.h"
-#include "NetdClient.h"
-#include "dns_responder.h"
-
-class DnsResponderClient {
-public:
- struct Mapping {
- std::string host;
- std::string entry;
- std::string ip4;
- std::string ip6;
- };
-
- virtual ~DnsResponderClient() = default;
-
- static void SetupMappings(unsigned num_hosts, const std::vector<std::string>& domains,
- std::vector<Mapping>* mappings);
-
- bool SetResolversForNetwork(const std::vector<std::string>& servers,
- const std::vector<std::string>& domains, const std::vector<int>& params);
-
- bool SetResolversForNetwork(const std::vector<std::string>& servers,
- const std::vector<std::string>& searchDomains,
- const std::string& params);
-
- bool SetResolversWithTls(const std::vector<std::string>& servers,
- const std::vector<std::string>& searchDomains,
- const std::vector<int>& params,
- const std::string& name,
- const std::vector<std::string>& fingerprints) {
- // Pass servers as both network-assigned and TLS servers. Tests can
- // determine on which server and by which protocol queries arrived.
- return SetResolversWithTls(servers, searchDomains, params,
- servers, name, fingerprints);
- }
-
- bool SetResolversWithTls(const std::vector<std::string>& servers,
- const std::vector<std::string>& searchDomains,
- const std::vector<int>& params,
- const std::vector<std::string>& tlsServers,
- const std::string& name,
- const std::vector<std::string>& fingerprints);
-
- static void SetupDNSServers(unsigned num_servers, const std::vector<Mapping>& mappings,
- std::vector<std::unique_ptr<test::DNSResponder>>* dns,
- std::vector<std::string>* servers);
-
- static void ShutdownDNSServers(std::vector<std::unique_ptr<test::DNSResponder>>* dns);
-
- int SetupOemNetwork();
-
- void TearDownOemNetwork(int oemNetId);
-
- virtual void SetUp();
-
- virtual void TearDown();
-
-public:
- android::sp<android::net::INetd> mNetdSrv = nullptr;
- int mOemNetId = -1;
-};
-
-#endif // DNS_RESPONDER_CLIENT_H
diff --git a/tests/dns_responder/dns_tls_frontend.cpp b/tests/dns_responder/dns_tls_frontend.cpp
deleted file mode 100644
index 443fb8f..0000000
--- a/tests/dns_responder/dns_tls_frontend.cpp
+++ /dev/null
@@ -1,402 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "dns_tls_frontend.h"
-
-#include <netdb.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <sys/poll.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <arpa/inet.h>
-#include <openssl/err.h>
-#include <openssl/evp.h>
-#include <openssl/ssl.h>
-#include <unistd.h>
-
-#define LOG_TAG "DnsTlsFrontend"
-#include <log/log.h>
-#include <netdutils/SocketOption.h>
-
-#include "NetdConstants.h" // SHA256_SIZE
-
-using android::netdutils::enableSockopt;
-
-namespace {
-
-// Copied from DnsTlsTransport.
-bool getSPKIDigest(const X509* cert, std::vector<uint8_t>* out) {
- int spki_len = i2d_X509_PUBKEY(X509_get_X509_PUBKEY(cert), nullptr);
- unsigned char spki[spki_len];
- unsigned char* temp = spki;
- if (spki_len != i2d_X509_PUBKEY(X509_get_X509_PUBKEY(cert), &temp)) {
- ALOGE("SPKI length mismatch");
- return false;
- }
- out->resize(SHA256_SIZE);
- unsigned int digest_len = 0;
- int ret = EVP_Digest(spki, spki_len, out->data(), &digest_len, EVP_sha256(), nullptr);
- if (ret != 1) {
- ALOGE("Server cert digest extraction failed");
- return false;
- }
- if (digest_len != out->size()) {
- ALOGE("Wrong digest length: %d", digest_len);
- return false;
- }
- return true;
-}
-
-std::string errno2str() {
- char error_msg[512] = { 0 };
- if (strerror_r(errno, error_msg, sizeof(error_msg)))
- return std::string();
- return std::string(error_msg);
-}
-
-#define APLOGI(fmt, ...) ALOGI(fmt ": [%d] %s", __VA_ARGS__, errno, errno2str().c_str())
-
-std::string addr2str(const sockaddr* sa, socklen_t sa_len) {
- char host_str[NI_MAXHOST] = { 0 };
- int rv = getnameinfo(sa, sa_len, host_str, sizeof(host_str), nullptr, 0,
- NI_NUMERICHOST);
- if (rv == 0) return std::string(host_str);
- return std::string();
-}
-
-bssl::UniquePtr<EVP_PKEY> make_private_key() {
- bssl::UniquePtr<BIGNUM> e(BN_new());
- if (!e) {
- ALOGE("BN_new failed");
- return nullptr;
- }
- if (!BN_set_word(e.get(), RSA_F4)) {
- ALOGE("BN_set_word failed");
- return nullptr;
- }
-
- bssl::UniquePtr<RSA> rsa(RSA_new());
- if (!rsa) {
- ALOGE("RSA_new failed");
- return nullptr;
- }
- if (!RSA_generate_key_ex(rsa.get(), 2048, e.get(), nullptr)) {
- ALOGE("RSA_generate_key_ex failed");
- return nullptr;
- }
-
- bssl::UniquePtr<EVP_PKEY> privkey(EVP_PKEY_new());
- if (!privkey) {
- ALOGE("EVP_PKEY_new failed");
- return nullptr;
- }
- if(!EVP_PKEY_assign_RSA(privkey.get(), rsa.get())) {
- ALOGE("EVP_PKEY_assign_RSA failed");
- return nullptr;
- }
-
- // |rsa| is now owned by |privkey|, so no need to free it.
- rsa.release();
- return privkey;
-}
-
-bssl::UniquePtr<X509> make_cert(EVP_PKEY* privkey, EVP_PKEY* parent_key) {
- bssl::UniquePtr<X509> cert(X509_new());
- if (!cert) {
- ALOGE("X509_new failed");
- return nullptr;
- }
-
- ASN1_INTEGER_set(X509_get_serialNumber(cert.get()), 1);
-
- // Set one hour expiration.
- X509_gmtime_adj(X509_get_notBefore(cert.get()), 0);
- X509_gmtime_adj(X509_get_notAfter(cert.get()), 60 * 60);
-
- X509_set_pubkey(cert.get(), privkey);
-
- if (!X509_sign(cert.get(), parent_key, EVP_sha256())) {
- ALOGE("X509_sign failed");
- return nullptr;
- }
-
- return cert;
-}
-
-}
-
-namespace test {
-
-bool DnsTlsFrontend::startServer() {
- SSL_load_error_strings();
- OpenSSL_add_ssl_algorithms();
-
- // reset queries_ to 0 every time startServer called
- // which would help us easy to check queries_ via calling waitForQueries
- queries_ = 0;
-
- ctx_.reset(SSL_CTX_new(TLS_server_method()));
- if (!ctx_) {
- ALOGE("SSL context creation failed");
- return false;
- }
-
- SSL_CTX_set_ecdh_auto(ctx_.get(), 1);
-
- // Make certificate chain
- std::vector<bssl::UniquePtr<EVP_PKEY>> keys(chain_length_);
- for (int i = 0; i < chain_length_; ++i) {
- keys[i] = make_private_key();
- }
- std::vector<bssl::UniquePtr<X509>> certs(chain_length_);
- for (int i = 0; i < chain_length_; ++i) {
- int next = std::min(i + 1, chain_length_ - 1);
- certs[i] = make_cert(keys[i].get(), keys[next].get());
- }
-
- // Install certificate chain.
- if (SSL_CTX_use_certificate(ctx_.get(), certs[0].get()) <= 0) {
- ALOGE("SSL_CTX_use_certificate failed");
- return false;
- }
- if (SSL_CTX_use_PrivateKey(ctx_.get(), keys[0].get()) <= 0 ) {
- ALOGE("SSL_CTX_use_PrivateKey failed");
- return false;
- }
- for (int i = 1; i < chain_length_; ++i) {
- if (SSL_CTX_add1_chain_cert(ctx_.get(), certs[i].get()) != 1) {
- ALOGE("SSL_CTX_add1_chain_cert failed");
- return false;
- }
- }
-
- // Report the fingerprint of the "middle" cert. For N = 2, this is the root.
- int fp_index = chain_length_ / 2;
- if (!getSPKIDigest(certs[fp_index].get(), &fingerprint_)) {
- ALOGE("getSPKIDigest failed");
- return false;
- }
-
- // Set up TCP server socket for clients.
- addrinfo frontend_ai_hints{
- .ai_family = AF_UNSPEC,
- .ai_socktype = SOCK_STREAM,
- .ai_flags = AI_PASSIVE
- };
- addrinfo* frontend_ai_res;
- int rv = getaddrinfo(listen_address_.c_str(), listen_service_.c_str(),
- &frontend_ai_hints, &frontend_ai_res);
- if (rv) {
- ALOGE("frontend getaddrinfo(%s, %s) failed: %s", listen_address_.c_str(),
- listen_service_.c_str(), gai_strerror(rv));
- return false;
- }
-
- int s = -1;
- for (const addrinfo* ai = frontend_ai_res ; ai ; ai = ai->ai_next) {
- s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
- if (s < 0) continue;
- enableSockopt(s, SOL_SOCKET, SO_REUSEPORT).ignoreError();
- enableSockopt(s, SOL_SOCKET, SO_REUSEADDR).ignoreError();
- if (bind(s, ai->ai_addr, ai->ai_addrlen)) {
- APLOGI("bind failed for socket %d", s);
- close(s);
- s = -1;
- continue;
- }
- std::string host_str = addr2str(ai->ai_addr, ai->ai_addrlen);
- ALOGI("bound to TCP %s:%s", host_str.c_str(), listen_service_.c_str());
- break;
- }
- freeaddrinfo(frontend_ai_res);
- if (s < 0) {
- ALOGE("server socket creation failed");
- return false;
- }
-
- if (listen(s, 1) < 0) {
- ALOGE("listen failed");
- return false;
- }
-
- socket_ = s;
-
- // Set up UDP client socket to backend.
- addrinfo backend_ai_hints{
- .ai_family = AF_UNSPEC,
- .ai_socktype = SOCK_DGRAM
- };
- addrinfo* backend_ai_res;
- rv = getaddrinfo(backend_address_.c_str(), backend_service_.c_str(),
- &backend_ai_hints, &backend_ai_res);
- if (rv) {
- ALOGE("backend getaddrinfo(%s, %s) failed: %s", listen_address_.c_str(),
- listen_service_.c_str(), gai_strerror(rv));
- return false;
- }
- backend_socket_ = socket(backend_ai_res->ai_family, backend_ai_res->ai_socktype,
- backend_ai_res->ai_protocol);
- if (backend_socket_ < 0) {
- ALOGE("backend socket creation failed");
- return false;
- }
- connect(backend_socket_, backend_ai_res->ai_addr, backend_ai_res->ai_addrlen);
- freeaddrinfo(backend_ai_res);
-
- {
- std::lock_guard lock(update_mutex_);
- handler_thread_ = std::thread(&DnsTlsFrontend::requestHandler, this);
- }
- ALOGI("server started successfully");
- return true;
-}
-
-void DnsTlsFrontend::requestHandler() {
- ALOGD("Request handler started");
- struct pollfd fds[1] = {{ .fd = socket_, .events = POLLIN }};
-
- while (!terminate_) {
- int poll_code = poll(fds, 1, 10 /* ms */);
- if (poll_code == 0) {
- // Timeout. Poll again.
- continue;
- } else if (poll_code < 0) {
- ALOGW("Poll failed with error %d", poll_code);
- // Error.
- break;
- }
- sockaddr_storage addr;
- socklen_t len = sizeof(addr);
-
- ALOGD("Trying to accept a client");
- int client = accept4(socket_, reinterpret_cast<sockaddr*>(&addr), &len, SOCK_CLOEXEC);
- ALOGD("Got client socket %d", client);
- if (client < 0) {
- // Stop
- break;
- }
-
- bssl::UniquePtr<SSL> ssl(SSL_new(ctx_.get()));
- SSL_set_fd(ssl.get(), client);
-
- ALOGD("Doing SSL handshake");
- bool success = false;
- if (SSL_accept(ssl.get()) <= 0) {
- ALOGI("SSL negotiation failure");
- } else {
- ALOGD("SSL handshake complete");
- success = handleOneRequest(ssl.get());
- }
-
- close(client);
-
- if (success) {
- // Increment queries_ as late as possible, because it represents
- // a query that is fully processed, and the response returned to the
- // client, including cleanup actions.
- ++queries_;
- }
- }
- ALOGD("Request handler terminating");
-}
-
-bool DnsTlsFrontend::handleOneRequest(SSL* ssl) {
- uint8_t queryHeader[2];
- if (SSL_read(ssl, &queryHeader, 2) != 2) {
- ALOGI("Not enough header bytes");
- return false;
- }
- const uint16_t qlen = (queryHeader[0] << 8) | queryHeader[1];
- uint8_t query[qlen];
- size_t qbytes = 0;
- while (qbytes < qlen) {
- int ret = SSL_read(ssl, query + qbytes, qlen - qbytes);
- if (ret <= 0) {
- ALOGI("Error while reading query");
- return false;
- }
- qbytes += ret;
- }
- int sent = send(backend_socket_, query, qlen, 0);
- if (sent != qlen) {
- ALOGI("Failed to send query");
- return false;
- }
- const int max_size = 4096;
- uint8_t recv_buffer[max_size];
- int rlen = recv(backend_socket_, recv_buffer, max_size, 0);
- if (rlen <= 0) {
- ALOGI("Failed to receive response");
- return false;
- }
- uint8_t responseHeader[2];
- responseHeader[0] = rlen >> 8;
- responseHeader[1] = rlen;
- if (SSL_write(ssl, responseHeader, 2) != 2) {
- ALOGI("Failed to write response header");
- return false;
- }
- if (SSL_write(ssl, recv_buffer, rlen) != rlen) {
- ALOGI("Failed to write response body");
- return false;
- }
- return true;
-}
-
-bool DnsTlsFrontend::stopServer() {
- std::lock_guard lock(update_mutex_);
- if (!running()) {
- ALOGI("server not running");
- return false;
- }
- if (terminate_) {
- ALOGI("LOGIC ERROR");
- return false;
- }
- ALOGI("stopping frontend");
- terminate_ = true;
- handler_thread_.join();
- close(socket_);
- close(backend_socket_);
- terminate_ = false;
- socket_ = -1;
- backend_socket_ = -1;
- ctx_.reset();
- fingerprint_.clear();
- ALOGI("frontend stopped successfully");
- return true;
-}
-
-bool DnsTlsFrontend::waitForQueries(int number, int timeoutMs) const {
- constexpr int intervalMs = 20;
- int limit = timeoutMs / intervalMs;
- for (int count = 0; count <= limit; ++count) {
- bool done = queries_ >= number;
- // Always sleep at least one more interval after we are done, to wait for
- // any immediate post-query actions that the client may take (such as
- // marking this server as reachable during validation).
- usleep(intervalMs * 1000);
- if (done) {
- // For ensuring that calls have sufficient headroom for slow machines
- ALOGD("Query arrived in %d/%d of allotted time", count, limit);
- return true;
- }
- }
- return false;
-}
-
-} // namespace test
diff --git a/tests/dns_responder/dns_tls_frontend.h b/tests/dns_responder/dns_tls_frontend.h
deleted file mode 100644
index b4630cf..0000000
--- a/tests/dns_responder/dns_tls_frontend.h
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless requied by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-#ifndef DNS_TLS_FRONTEND_H
-#define DNS_TLS_FRONTEND_H
-
-#include <arpa/nameser.h>
-
-#include <atomic>
-#include <mutex>
-#include <string>
-#include <thread>
-#include <unordered_map>
-#include <vector>
-
-#include <android-base/thread_annotations.h>
-#include <openssl/ssl.h>
-
-namespace test {
-
-/*
- * Simple DNS over TLS reverse proxy that forwards to a UDP backend.
- * Only handles a single request at a time.
- */
-class DnsTlsFrontend {
-public:
- DnsTlsFrontend(const std::string& listen_address, const std::string& listen_service,
- const std::string& backend_address, const std::string& backend_service) :
- listen_address_(listen_address), listen_service_(listen_service),
- backend_address_(backend_address), backend_service_(backend_service),
- queries_(0), terminate_(false) { }
- ~DnsTlsFrontend() {
- stopServer();
- }
- const std::string& listen_address() const {
- return listen_address_;
- }
- const std::string& listen_service() const {
- return listen_service_;
- }
- bool running() const {
- return socket_ != -1;
- }
- bool startServer();
- bool stopServer();
- int queries() const { return queries_; }
- bool waitForQueries(int number, int timeoutMs) const;
- void set_chain_length(int length) { chain_length_ = length; }
- // Represents a fingerprint from the middle of the certificate chain.
- const std::vector<uint8_t>& fingerprint() const { return fingerprint_; }
-
-private:
- void requestHandler();
- bool handleOneRequest(SSL* ssl);
-
- std::string listen_address_;
- std::string listen_service_;
- std::string backend_address_;
- std::string backend_service_;
- bssl::UniquePtr<SSL_CTX> ctx_;
- int socket_ = -1;
- int backend_socket_ = -1;
- std::atomic<int> queries_;
- std::atomic<bool> terminate_;
- std::thread handler_thread_ GUARDED_BY(update_mutex_);
- std::mutex update_mutex_;
- int chain_length_ = 1;
- std::vector<uint8_t> fingerprint_;
-};
-
-} // namespace test
-
-#endif // DNS_TLS_FRONTEND_H
diff --git a/tests/resolver_test.cpp b/tests/resolver_test.cpp
deleted file mode 100644
index 5196bba..0000000
--- a/tests/resolver_test.cpp
+++ /dev/null
@@ -1,1460 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless requied by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-#define LOG_TAG "netd_test"
-
-#include <arpa/inet.h>
-#include <netdb.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-
-#include <algorithm>
-#include <chrono>
-#include <iterator>
-#include <numeric>
-#include <thread>
-
-#include <android-base/stringprintf.h>
-#include <cutils/sockets.h>
-#include <gtest/gtest.h>
-#include <openssl/base64.h>
-#include <private/android_filesystem_config.h>
-#include <utils/Log.h>
-
-#include "NetdClient.h"
-#include "netid_client.h" // NETID_UNSET
-#include "netd_resolv/params.h" // MAX_NS
-
-#include "dns_responder.h"
-#include "dns_responder_client.h"
-#include "dns_tls_frontend.h"
-
-#include "NetdConstants.h"
-#include "ResolverStats.h"
-
-#include "android/net/INetd.h"
-#include "android/net/metrics/INetdEventListener.h"
-#include "binder/IServiceManager.h"
-#include "netdutils/SocketOption.h"
-
-// TODO: make this dynamic and stop depending on implementation details.
-#define TEST_NETID 30
-
-// Semi-public Bionic hook used by the NDK (frameworks/base/native/android/net.c)
-// Tested here for convenience.
-extern "C" int android_getaddrinfofornet(const char* hostname, const char* servname,
- const addrinfo* hints, unsigned netid, unsigned mark,
- struct addrinfo** result);
-
-using android::base::StringPrintf;
-using android::net::ResolverStats;
-using android::net::metrics::INetdEventListener;
-using android::netdutils::enableSockopt;
-
-// TODO: move into libnetdutils?
-namespace {
-ScopedAddrinfo safe_getaddrinfo(const char* node, const char* service,
- const struct addrinfo* hints) {
- addrinfo* result = nullptr;
- if (getaddrinfo(node, service, hints, &result) != 0) {
- result = nullptr; // Should already be the case, but...
- }
- return ScopedAddrinfo(result);
-}
-} // namespace
-
-// Emulates the behavior of UnorderedElementsAreArray, which currently cannot be used.
-// TODO: Use UnorderedElementsAreArray, which depends on being able to compile libgmock_host,
-// if that is not possible, improve this hacky algorithm, which is O(n**2)
-template <class A, class B>
-bool UnorderedCompareArray(const A& a, const B& b) {
- if (a.size() != b.size()) return false;
- for (const auto& a_elem : a) {
- size_t a_count = 0;
- for (const auto& a_elem2 : a) {
- if (a_elem == a_elem2) {
- ++a_count;
- }
- }
- size_t b_count = 0;
- for (const auto& b_elem : b) {
- if (a_elem == b_elem) ++b_count;
- }
- if (a_count != b_count) return false;
- }
- return true;
-}
-
-class ResolverTest : public ::testing::Test, public DnsResponderClient {
- protected:
- void SetUp() {
- // Ensure resolutions go via proxy.
- DnsResponderClient::SetUp();
-
- // If DNS reporting is off: turn it on so we run through everything.
- auto rv = mNetdSrv->getMetricsReportingLevel(&mOriginalMetricsLevel);
- ASSERT_TRUE(rv.isOk());
- if (mOriginalMetricsLevel != INetdEventListener::REPORTING_LEVEL_FULL) {
- rv = mNetdSrv->setMetricsReportingLevel(INetdEventListener::REPORTING_LEVEL_FULL);
- ASSERT_TRUE(rv.isOk());
- }
- }
-
- void TearDown() {
- if (mOriginalMetricsLevel != INetdEventListener::REPORTING_LEVEL_FULL) {
- auto rv = mNetdSrv->setMetricsReportingLevel(mOriginalMetricsLevel);
- ASSERT_TRUE(rv.isOk());
- }
-
- DnsResponderClient::TearDown();
- }
-
- bool GetResolverInfo(std::vector<std::string>* servers, std::vector<std::string>* domains,
- __res_params* params, std::vector<ResolverStats>* stats) {
- using android::net::INetd;
- std::vector<int32_t> params32;
- std::vector<int32_t> stats32;
- auto rv = mNetdSrv->getResolverInfo(TEST_NETID, servers, domains, ¶ms32, &stats32);
- if (!rv.isOk() || params32.size() != INetd::RESOLVER_PARAMS_COUNT) {
- return false;
- }
- *params = __res_params {
- .sample_validity = static_cast<uint16_t>(
- params32[INetd::RESOLVER_PARAMS_SAMPLE_VALIDITY]),
- .success_threshold = static_cast<uint8_t>(
- params32[INetd::RESOLVER_PARAMS_SUCCESS_THRESHOLD]),
- .min_samples = static_cast<uint8_t>(
- params32[INetd::RESOLVER_PARAMS_MIN_SAMPLES]),
- .max_samples = static_cast<uint8_t>(
- params32[INetd::RESOLVER_PARAMS_MAX_SAMPLES]),
- .base_timeout_msec = params32[INetd::RESOLVER_PARAMS_BASE_TIMEOUT_MSEC],
- };
- return ResolverStats::decodeAll(stats32, stats);
- }
-
- static std::string ToString(const hostent* he) {
- if (he == nullptr) return "<null>";
- char buffer[INET6_ADDRSTRLEN];
- if (!inet_ntop(he->h_addrtype, he->h_addr_list[0], buffer, sizeof(buffer))) {
- return "<invalid>";
- }
- return buffer;
- }
-
- static std::string ToString(const addrinfo* ai) {
- if (!ai)
- return "<null>";
- for (const auto* aip = ai ; aip != nullptr ; aip = aip->ai_next) {
- char host[NI_MAXHOST];
- int rv = getnameinfo(aip->ai_addr, aip->ai_addrlen, host, sizeof(host), nullptr, 0,
- NI_NUMERICHOST);
- if (rv != 0)
- return gai_strerror(rv);
- return host;
- }
- return "<invalid>";
- }
-
- static std::string ToString(const ScopedAddrinfo& ai) { return ToString(ai.get()); }
-
- size_t GetNumQueries(const test::DNSResponder& dns, const char* name) const {
- auto queries = dns.queries();
- size_t found = 0;
- for (const auto& p : queries) {
- if (p.first == name) {
- ++found;
- }
- }
- return found;
- }
-
- size_t GetNumQueriesForType(const test::DNSResponder& dns, ns_type type,
- const char* name) const {
- auto queries = dns.queries();
- size_t found = 0;
- for (const auto& p : queries) {
- if (p.second == type && p.first == name) {
- ++found;
- }
- }
- return found;
- }
-
- void RunGetAddrInfoStressTest_Binder(unsigned num_hosts, unsigned num_threads,
- unsigned num_queries) {
- std::vector<std::string> domains = { "example.com" };
- std::vector<std::unique_ptr<test::DNSResponder>> dns;
- std::vector<std::string> servers;
- std::vector<DnsResponderClient::Mapping> mappings;
- ASSERT_NO_FATAL_FAILURE(SetupMappings(num_hosts, domains, &mappings));
- ASSERT_NO_FATAL_FAILURE(SetupDNSServers(MAXNS, mappings, &dns, &servers));
-
- ASSERT_TRUE(SetResolversForNetwork(servers, domains, mDefaultParams_Binder));
-
- auto t0 = std::chrono::steady_clock::now();
- std::vector<std::thread> threads(num_threads);
- for (std::thread& thread : threads) {
- thread = std::thread([&mappings, num_queries]() {
- for (unsigned i = 0 ; i < num_queries ; ++i) {
- uint32_t ofs = arc4random_uniform(mappings.size());
- auto& mapping = mappings[ofs];
- addrinfo* result = nullptr;
- int rv = getaddrinfo(mapping.host.c_str(), nullptr, nullptr, &result);
- EXPECT_EQ(0, rv) << "error [" << rv << "] " << gai_strerror(rv);
- if (rv == 0) {
- std::string result_str = ToString(result);
- EXPECT_TRUE(result_str == mapping.ip4 || result_str == mapping.ip6)
- << "result='" << result_str << "', ip4='" << mapping.ip4
- << "', ip6='" << mapping.ip6;
- }
- if (result) {
- freeaddrinfo(result);
- result = nullptr;
- }
- }
- });
- }
-
- for (std::thread& thread : threads) {
- thread.join();
- }
- auto t1 = std::chrono::steady_clock::now();
- ALOGI("%u hosts, %u threads, %u queries, %Es", num_hosts, num_threads, num_queries,
- std::chrono::duration<double>(t1 - t0).count());
- ASSERT_NO_FATAL_FAILURE(ShutdownDNSServers(&dns));
- }
-
- const std::vector<std::string> mDefaultSearchDomains = { "example.com" };
- // <sample validity in s> <success threshold in percent> <min samples> <max samples>
- const std::vector<int> mDefaultParams_Binder = {
- 300, // SAMPLE_VALIDITY
- 25, // SUCCESS_THRESHOLD
- 8, 8, // {MIN,MAX}_SAMPLES
- 100, // BASE_TIMEOUT_MSEC
- };
-
- private:
- int mOriginalMetricsLevel;
-};
-
-TEST_F(ResolverTest, GetHostByName) {
- const char* listen_addr = "127.0.0.3";
- const char* listen_srv = "53";
- const char* host_name = "hello.example.com.";
- const char *nonexistent_host_name = "nonexistent.example.com.";
- test::DNSResponder dns(listen_addr, listen_srv, 250, ns_rcode::ns_r_servfail);
- dns.addMapping(host_name, ns_type::ns_t_a, "1.2.3.3");
- ASSERT_TRUE(dns.startServer());
- std::vector<std::string> servers = { listen_addr };
- ASSERT_TRUE(SetResolversForNetwork(servers, mDefaultSearchDomains, mDefaultParams_Binder));
-
- const hostent* result;
-
- dns.clearQueries();
- result = gethostbyname("nonexistent");
- EXPECT_EQ(1U, GetNumQueriesForType(dns, ns_type::ns_t_a, nonexistent_host_name));
- ASSERT_TRUE(result == nullptr);
- ASSERT_EQ(HOST_NOT_FOUND, h_errno);
-
- dns.clearQueries();
- result = gethostbyname("hello");
- EXPECT_EQ(1U, GetNumQueriesForType(dns, ns_type::ns_t_a, host_name));
- ASSERT_FALSE(result == nullptr);
- ASSERT_EQ(4, result->h_length);
- ASSERT_FALSE(result->h_addr_list[0] == nullptr);
- EXPECT_EQ("1.2.3.3", ToString(result));
- EXPECT_TRUE(result->h_addr_list[1] == nullptr);
-
- dns.stopServer();
-}
-
-TEST_F(ResolverTest, GetHostByName_localhost) {
- constexpr char name[] = "localhost";
- constexpr char name_camelcase[] = "LocalHost";
- constexpr char addr[] = "127.0.0.1";
- constexpr char name_ip6[] = "ip6-localhost";
- constexpr char addr_ip6[] = "::1";
- constexpr char name_ip6_dot[] = "ip6-localhost.";
- constexpr char name_ip6_fqdn[] = "ip6-localhost.example.com.";
-
- // Add a dummy nameserver which shouldn't receive any queries
- constexpr char listen_addr[] = "127.0.0.3";
- constexpr char listen_srv[] = "53";
- test::DNSResponder dns(listen_addr, listen_srv, 250, ns_rcode::ns_r_servfail);
- ASSERT_TRUE(dns.startServer());
- std::vector<std::string> servers = {listen_addr};
- ASSERT_TRUE(SetResolversForNetwork(servers, mDefaultSearchDomains, mDefaultParams_Binder));
- dns.clearQueries();
-
- // Expect no DNS queries; localhost is resolved via /etc/hosts
- const hostent* result = gethostbyname(name);
- EXPECT_TRUE(dns.queries().empty()) << dns.dumpQueries();
- ASSERT_FALSE(result == nullptr);
- ASSERT_EQ(4, result->h_length);
- ASSERT_FALSE(result->h_addr_list[0] == nullptr);
- EXPECT_EQ(addr, ToString(result));
- EXPECT_TRUE(result->h_addr_list[1] == nullptr);
-
- // Ensure the hosts file resolver ignores case of hostnames
- result = gethostbyname(name_camelcase);
- EXPECT_TRUE(dns.queries().empty()) << dns.dumpQueries();
- ASSERT_FALSE(result == nullptr);
- ASSERT_EQ(4, result->h_length);
- ASSERT_FALSE(result->h_addr_list[0] == nullptr);
- EXPECT_EQ(addr, ToString(result));
- EXPECT_TRUE(result->h_addr_list[1] == nullptr);
-
- // The hosts file also contains ip6-localhost, but gethostbyname() won't
- // return it unless the RES_USE_INET6 option is set. This would be easy to
- // change, but there's no point in changing the legacy behavior; new code
- // should be calling getaddrinfo() anyway.
- // So we check the legacy behavior, which results in amusing A-record
- // lookups for ip6-localhost, with and without search domains appended.
- dns.clearQueries();
- result = gethostbyname(name_ip6);
- EXPECT_EQ(2, dns.queries().size()) << dns.dumpQueries();
- EXPECT_EQ(1, GetNumQueriesForType(dns, ns_type::ns_t_a, name_ip6_dot)) << dns.dumpQueries();
- EXPECT_EQ(1, GetNumQueriesForType(dns, ns_type::ns_t_a, name_ip6_fqdn)) << dns.dumpQueries();
- ASSERT_TRUE(result == nullptr);
-
- // Finally, use gethostbyname2() to resolve ip6-localhost to ::1 from
- // the hosts file.
- dns.clearQueries();
- result = gethostbyname2(name_ip6, AF_INET6);
- EXPECT_TRUE(dns.queries().empty()) << dns.dumpQueries();
- ASSERT_FALSE(result == nullptr);
- ASSERT_EQ(16, result->h_length);
- ASSERT_FALSE(result->h_addr_list[0] == nullptr);
- EXPECT_EQ(addr_ip6, ToString(result));
- EXPECT_TRUE(result->h_addr_list[1] == nullptr);
-
- dns.stopServer();
-}
-
-TEST_F(ResolverTest, GetHostByName_numeric) {
- // Add a dummy nameserver which shouldn't receive any queries
- constexpr char listen_addr[] = "127.0.0.3";
- constexpr char listen_srv[] = "53";
- test::DNSResponder dns(listen_addr, listen_srv, 250, ns_rcode::ns_r_servfail);
- ASSERT_TRUE(dns.startServer());
- ASSERT_TRUE(
- SetResolversForNetwork({listen_addr}, mDefaultSearchDomains, mDefaultParams_Binder));
-
- // Numeric v4 address: expect no DNS queries
- constexpr char numeric_v4[] = "192.168.0.1";
- dns.clearQueries();
- const hostent* result = gethostbyname(numeric_v4);
- EXPECT_EQ(0, dns.queries().size());
- ASSERT_FALSE(result == nullptr);
- ASSERT_EQ(4, result->h_length); // v4
- ASSERT_FALSE(result->h_addr_list[0] == nullptr);
- EXPECT_EQ(numeric_v4, ToString(result));
- EXPECT_TRUE(result->h_addr_list[1] == nullptr);
-
- // gethostbyname() recognizes a v6 address, and fails with no DNS queries
- constexpr char numeric_v6[] = "2001:db8::42";
- dns.clearQueries();
- result = gethostbyname(numeric_v6);
- EXPECT_EQ(0, dns.queries().size());
- EXPECT_TRUE(result == nullptr);
-
- // Numeric v6 address with gethostbyname2(): succeeds with no DNS queries
- dns.clearQueries();
- result = gethostbyname2(numeric_v6, AF_INET6);
- EXPECT_EQ(0, dns.queries().size());
- ASSERT_FALSE(result == nullptr);
- ASSERT_EQ(16, result->h_length); // v6
- ASSERT_FALSE(result->h_addr_list[0] == nullptr);
- EXPECT_EQ(numeric_v6, ToString(result));
- EXPECT_TRUE(result->h_addr_list[1] == nullptr);
-
- // Numeric v6 address with scope work with getaddrinfo(),
- // but gethostbyname2() does not understand them; it issues two dns
- // queries, then fails. This hardly ever happens, there's no point
- // in fixing this. This test simply verifies the current (bogus)
- // behavior to avoid further regressions (like crashes, or leaks).
- constexpr char numeric_v6_scope[] = "fe80::1%lo";
- dns.clearQueries();
- result = gethostbyname2(numeric_v6_scope, AF_INET6);
- EXPECT_EQ(2, dns.queries().size()); // OUCH!
- ASSERT_TRUE(result == nullptr);
-
- dns.stopServer();
-}
-
-TEST_F(ResolverTest, BinderSerialization) {
- using android::net::INetd;
- std::vector<int> params_offsets = {
- INetd::RESOLVER_PARAMS_SAMPLE_VALIDITY,
- INetd::RESOLVER_PARAMS_SUCCESS_THRESHOLD,
- INetd::RESOLVER_PARAMS_MIN_SAMPLES,
- INetd::RESOLVER_PARAMS_MAX_SAMPLES,
- INetd::RESOLVER_PARAMS_BASE_TIMEOUT_MSEC,
- };
- int size = static_cast<int>(params_offsets.size());
- EXPECT_EQ(size, INetd::RESOLVER_PARAMS_COUNT);
- std::sort(params_offsets.begin(), params_offsets.end());
- for (int i = 0 ; i < size ; ++i) {
- EXPECT_EQ(params_offsets[i], i);
- }
-}
-
-TEST_F(ResolverTest, GetHostByName_Binder) {
- using android::net::INetd;
-
- std::vector<std::string> domains = { "example.com" };
- std::vector<std::unique_ptr<test::DNSResponder>> dns;
- std::vector<std::string> servers;
- std::vector<Mapping> mappings;
- ASSERT_NO_FATAL_FAILURE(SetupMappings(1, domains, &mappings));
- ASSERT_NO_FATAL_FAILURE(SetupDNSServers(4, mappings, &dns, &servers));
- ASSERT_EQ(1U, mappings.size());
- const Mapping& mapping = mappings[0];
-
- ASSERT_TRUE(SetResolversForNetwork(servers, domains, mDefaultParams_Binder));
-
- const hostent* result = gethostbyname(mapping.host.c_str());
- size_t total_queries = std::accumulate(dns.begin(), dns.end(), 0,
- [this, &mapping](size_t total, auto& d) {
- return total + GetNumQueriesForType(*d, ns_type::ns_t_a, mapping.entry.c_str());
- });
-
- EXPECT_LE(1U, total_queries);
- ASSERT_FALSE(result == nullptr);
- ASSERT_EQ(4, result->h_length);
- ASSERT_FALSE(result->h_addr_list[0] == nullptr);
- EXPECT_EQ(mapping.ip4, ToString(result));
- EXPECT_TRUE(result->h_addr_list[1] == nullptr);
-
- std::vector<std::string> res_servers;
- std::vector<std::string> res_domains;
- __res_params res_params;
- std::vector<ResolverStats> res_stats;
- ASSERT_TRUE(GetResolverInfo(&res_servers, &res_domains, &res_params, &res_stats));
- EXPECT_EQ(servers.size(), res_servers.size());
- EXPECT_EQ(domains.size(), res_domains.size());
- ASSERT_EQ(INetd::RESOLVER_PARAMS_COUNT, mDefaultParams_Binder.size());
- EXPECT_EQ(mDefaultParams_Binder[INetd::RESOLVER_PARAMS_SAMPLE_VALIDITY],
- res_params.sample_validity);
- EXPECT_EQ(mDefaultParams_Binder[INetd::RESOLVER_PARAMS_SUCCESS_THRESHOLD],
- res_params.success_threshold);
- EXPECT_EQ(mDefaultParams_Binder[INetd::RESOLVER_PARAMS_MIN_SAMPLES], res_params.min_samples);
- EXPECT_EQ(mDefaultParams_Binder[INetd::RESOLVER_PARAMS_MAX_SAMPLES], res_params.max_samples);
- EXPECT_EQ(mDefaultParams_Binder[INetd::RESOLVER_PARAMS_BASE_TIMEOUT_MSEC],
- res_params.base_timeout_msec);
- EXPECT_EQ(servers.size(), res_stats.size());
-
- EXPECT_TRUE(UnorderedCompareArray(res_servers, servers));
- EXPECT_TRUE(UnorderedCompareArray(res_domains, domains));
-
- ASSERT_NO_FATAL_FAILURE(ShutdownDNSServers(&dns));
-}
-
-TEST_F(ResolverTest, GetAddrInfo) {
- const char* listen_addr = "127.0.0.4";
- const char* listen_addr2 = "127.0.0.5";
- const char* listen_srv = "53";
- const char* host_name = "howdy.example.com.";
- test::DNSResponder dns(listen_addr, listen_srv, 250, ns_rcode::ns_r_servfail);
- dns.addMapping(host_name, ns_type::ns_t_a, "1.2.3.4");
- dns.addMapping(host_name, ns_type::ns_t_aaaa, "::1.2.3.4");
- ASSERT_TRUE(dns.startServer());
-
- test::DNSResponder dns2(listen_addr2, listen_srv, 250, ns_rcode::ns_r_servfail);
- dns2.addMapping(host_name, ns_type::ns_t_a, "1.2.3.4");
- dns2.addMapping(host_name, ns_type::ns_t_aaaa, "::1.2.3.4");
- ASSERT_TRUE(dns2.startServer());
-
- std::vector<std::string> servers = { listen_addr };
- ASSERT_TRUE(SetResolversForNetwork(servers, mDefaultSearchDomains, mDefaultParams_Binder));
- dns.clearQueries();
- dns2.clearQueries();
-
- ScopedAddrinfo result = safe_getaddrinfo("howdy", nullptr, nullptr);
- EXPECT_TRUE(result != nullptr);
- size_t found = GetNumQueries(dns, host_name);
- EXPECT_LE(1U, found);
- // Could be A or AAAA
- std::string result_str = ToString(result);
- EXPECT_TRUE(result_str == "1.2.3.4" || result_str == "::1.2.3.4")
- << ", result_str='" << result_str << "'";
-
- // Verify that the name is cached.
- size_t old_found = found;
- result = safe_getaddrinfo("howdy", nullptr, nullptr);
- EXPECT_TRUE(result != nullptr);
- found = GetNumQueries(dns, host_name);
- EXPECT_LE(1U, found);
- EXPECT_EQ(old_found, found);
- result_str = ToString(result);
- EXPECT_TRUE(result_str == "1.2.3.4" || result_str == "::1.2.3.4")
- << result_str;
-
- // Change the DNS resolver, ensure that queries are still cached.
- servers = { listen_addr2 };
- ASSERT_TRUE(SetResolversForNetwork(servers, mDefaultSearchDomains, mDefaultParams_Binder));
- dns.clearQueries();
- dns2.clearQueries();
-
- result = safe_getaddrinfo("howdy", nullptr, nullptr);
- EXPECT_TRUE(result != nullptr);
- found = GetNumQueries(dns, host_name);
- size_t found2 = GetNumQueries(dns2, host_name);
- EXPECT_EQ(0U, found);
- EXPECT_LE(0U, found2);
-
- // Could be A or AAAA
- result_str = ToString(result);
- EXPECT_TRUE(result_str == "1.2.3.4" || result_str == "::1.2.3.4")
- << ", result_str='" << result_str << "'";
-
- dns.stopServer();
- dns2.stopServer();
-}
-
-TEST_F(ResolverTest, GetAddrInfoV4) {
- constexpr char listen_addr[] = "127.0.0.5";
- constexpr char listen_srv[] = "53";
- constexpr char host_name[] = "hola.example.com.";
- test::DNSResponder dns(listen_addr, listen_srv, 250, ns_rcode::ns_r_servfail);
- dns.addMapping(host_name, ns_type::ns_t_a, "1.2.3.5");
- ASSERT_TRUE(dns.startServer());
- std::vector<std::string> servers = { listen_addr };
- ASSERT_TRUE(SetResolversForNetwork(servers, mDefaultSearchDomains, mDefaultParams_Binder));
-
- addrinfo hints = {.ai_family = AF_INET};
- ScopedAddrinfo result = safe_getaddrinfo("hola", nullptr, &hints);
- EXPECT_TRUE(result != nullptr);
- EXPECT_EQ(1U, GetNumQueries(dns, host_name));
- EXPECT_EQ("1.2.3.5", ToString(result));
-}
-
-TEST_F(ResolverTest, GetAddrInfo_localhost) {
- constexpr char name[] = "localhost";
- constexpr char addr[] = "127.0.0.1";
- constexpr char name_ip6[] = "ip6-localhost";
- constexpr char addr_ip6[] = "::1";
-
- // Add a dummy nameserver which shouldn't receive any queries
- constexpr char listen_addr[] = "127.0.0.5";
- constexpr char listen_srv[] = "53";
- test::DNSResponder dns(listen_addr, listen_srv, 250, ns_rcode::ns_r_servfail);
- ASSERT_TRUE(dns.startServer());
- std::vector<std::string> servers = {listen_addr};
- ASSERT_TRUE(SetResolversForNetwork(servers, mDefaultSearchDomains, mDefaultParams_Binder));
-
- ScopedAddrinfo result = safe_getaddrinfo(name, nullptr, nullptr);
- EXPECT_TRUE(result != nullptr);
- // Expect no DNS queries; localhost is resolved via /etc/hosts
- EXPECT_TRUE(dns.queries().empty()) << dns.dumpQueries();
- EXPECT_EQ(addr, ToString(result));
-
- result = safe_getaddrinfo(name_ip6, nullptr, nullptr);
- EXPECT_TRUE(result != nullptr);
- // Expect no DNS queries; ip6-localhost is resolved via /etc/hosts
- EXPECT_TRUE(dns.queries().empty()) << dns.dumpQueries();
- EXPECT_EQ(addr_ip6, ToString(result));
-}
-
-TEST_F(ResolverTest, GetHostByNameBrokenEdns) {
- const char* listen_addr = "127.0.0.3";
- const char* listen_srv = "53";
- const char* host_name = "edns.example.com.";
- test::DNSResponder dns(listen_addr, listen_srv, 250, ns_rcode::ns_r_servfail);
- dns.addMapping(host_name, ns_type::ns_t_a, "1.2.3.3");
- dns.setFailOnEdns(true); // This is the only change from the basic test.
- ASSERT_TRUE(dns.startServer());
- std::vector<std::string> servers = { listen_addr };
- ASSERT_TRUE(SetResolversForNetwork(servers, mDefaultSearchDomains, mDefaultParams_Binder));
-
- const hostent* result;
-
- dns.clearQueries();
- result = gethostbyname("edns");
- EXPECT_EQ(1U, GetNumQueriesForType(dns, ns_type::ns_t_a, host_name));
- ASSERT_FALSE(result == nullptr);
- ASSERT_EQ(4, result->h_length);
- ASSERT_FALSE(result->h_addr_list[0] == nullptr);
- EXPECT_EQ("1.2.3.3", ToString(result));
- EXPECT_TRUE(result->h_addr_list[1] == nullptr);
-}
-
-TEST_F(ResolverTest, GetAddrInfoBrokenEdns) {
- const char* listen_addr = "127.0.0.5";
- const char* listen_srv = "53";
- const char* host_name = "edns2.example.com.";
- test::DNSResponder dns(listen_addr, listen_srv, 250, ns_rcode::ns_r_servfail);
- dns.addMapping(host_name, ns_type::ns_t_a, "1.2.3.5");
- dns.setFailOnEdns(true); // This is the only change from the basic test.
- ASSERT_TRUE(dns.startServer());
- std::vector<std::string> servers = { listen_addr };
- ASSERT_TRUE(SetResolversForNetwork(servers, mDefaultSearchDomains, mDefaultParams_Binder));
-
- addrinfo hints = {.ai_family = AF_INET};
- ScopedAddrinfo result = safe_getaddrinfo("edns2", nullptr, &hints);
- EXPECT_TRUE(result != nullptr);
- EXPECT_EQ(1U, GetNumQueries(dns, host_name));
- EXPECT_EQ("1.2.3.5", ToString(result));
-}
-
-TEST_F(ResolverTest, MultidomainResolution) {
- std::vector<std::string> searchDomains = { "example1.com", "example2.com", "example3.com" };
- const char* listen_addr = "127.0.0.6";
- const char* listen_srv = "53";
- const char* host_name = "nihao.example2.com.";
- test::DNSResponder dns(listen_addr, listen_srv, 250, ns_rcode::ns_r_servfail);
- dns.addMapping(host_name, ns_type::ns_t_a, "1.2.3.3");
- ASSERT_TRUE(dns.startServer());
- std::vector<std::string> servers = { listen_addr };
- ASSERT_TRUE(SetResolversForNetwork(servers, searchDomains, mDefaultParams_Binder));
-
- dns.clearQueries();
- const hostent* result = gethostbyname("nihao");
- EXPECT_EQ(1U, GetNumQueriesForType(dns, ns_type::ns_t_a, host_name));
- ASSERT_FALSE(result == nullptr);
- ASSERT_EQ(4, result->h_length);
- ASSERT_FALSE(result->h_addr_list[0] == nullptr);
- EXPECT_EQ("1.2.3.3", ToString(result));
- EXPECT_TRUE(result->h_addr_list[1] == nullptr);
- dns.stopServer();
-}
-
-TEST_F(ResolverTest, GetAddrInfoV6_numeric) {
- constexpr char listen_addr0[] = "127.0.0.7";
- constexpr char listen_srv[] = "53";
- constexpr char host_name[] = "ohayou.example.com.";
- constexpr char numeric_addr[] = "fe80::1%lo";
-
- test::DNSResponder dns(listen_addr0, listen_srv, 250, ns_rcode::ns_r_servfail);
- dns.setResponseProbability(0.0);
- dns.addMapping(host_name, ns_type::ns_t_aaaa, "2001:db8::5");
- ASSERT_TRUE(dns.startServer());
- std::vector<std::string> servers = {listen_addr0};
- ASSERT_TRUE(SetResolversForNetwork(servers, mDefaultSearchDomains, mDefaultParams_Binder));
-
- addrinfo hints = {.ai_family = AF_INET6};
- ScopedAddrinfo result = safe_getaddrinfo(numeric_addr, nullptr, &hints);
- EXPECT_TRUE(result != nullptr);
- EXPECT_EQ(numeric_addr, ToString(result));
- EXPECT_TRUE(dns.queries().empty()); // Ensure no DNS queries were sent out
-
- // Now try a non-numeric hostname query with the AI_NUMERICHOST flag set.
- // We should fail without sending out a DNS query.
- hints.ai_flags |= AI_NUMERICHOST;
- result = safe_getaddrinfo(host_name, nullptr, &hints);
- EXPECT_TRUE(result == nullptr);
- EXPECT_TRUE(dns.queries().empty()); // Ensure no DNS queries were sent out
-}
-
-TEST_F(ResolverTest, GetAddrInfoV6_failing) {
- const char* listen_addr0 = "127.0.0.7";
- const char* listen_addr1 = "127.0.0.8";
- const char* listen_srv = "53";
- const char* host_name = "ohayou.example.com.";
- test::DNSResponder dns0(listen_addr0, listen_srv, 250, ns_rcode::ns_r_servfail);
- test::DNSResponder dns1(listen_addr1, listen_srv, 250, ns_rcode::ns_r_servfail);
- dns0.setResponseProbability(0.0);
- dns0.addMapping(host_name, ns_type::ns_t_aaaa, "2001:db8::5");
- dns1.addMapping(host_name, ns_type::ns_t_aaaa, "2001:db8::6");
- ASSERT_TRUE(dns0.startServer());
- ASSERT_TRUE(dns1.startServer());
- std::vector<std::string> servers = { listen_addr0, listen_addr1 };
- // <sample validity in s> <success threshold in percent> <min samples> <max samples>
- int sample_count = 8;
- const std::vector<int> params = { 300, 25, sample_count, sample_count };
- ASSERT_TRUE(SetResolversForNetwork(servers, mDefaultSearchDomains, params));
-
- // Repeatedly perform resolutions for non-existing domains until MAXNSSAMPLES resolutions have
- // reached the dns0, which is set to fail. No more requests should then arrive at that server
- // for the next sample_lifetime seconds.
- // TODO: This approach is implementation-dependent, change once metrics reporting is available.
- addrinfo hints = {.ai_family = AF_INET6};
- for (int i = 0 ; i < sample_count ; ++i) {
- std::string domain = StringPrintf("nonexistent%d", i);
- ScopedAddrinfo result = safe_getaddrinfo(domain.c_str(), nullptr, &hints);
- }
- // Due to 100% errors for all possible samples, the server should be ignored from now on and
- // only the second one used for all following queries, until NSSAMPLE_VALIDITY is reached.
- dns0.clearQueries();
- dns1.clearQueries();
- ScopedAddrinfo result = safe_getaddrinfo("ohayou", nullptr, &hints);
- EXPECT_TRUE(result != nullptr);
- EXPECT_EQ(0U, GetNumQueries(dns0, host_name));
- EXPECT_EQ(1U, GetNumQueries(dns1, host_name));
-}
-
-TEST_F(ResolverTest, GetAddrInfoV6_nonresponsive) {
- const char* listen_addr0 = "127.0.0.7";
- const char* listen_addr1 = "127.0.0.8";
- const char* listen_srv = "53";
- const char* host_name1 = "ohayou.example.com.";
- const char* host_name2 = "ciao.example.com.";
-
- // dns0 does not respond with 100% probability, while
- // dns1 responds normally, at least initially.
- test::DNSResponder dns0(listen_addr0, listen_srv, 250, static_cast<ns_rcode>(-1));
- test::DNSResponder dns1(listen_addr1, listen_srv, 250, static_cast<ns_rcode>(-1));
- dns0.setResponseProbability(0.0);
- dns0.addMapping(host_name1, ns_type::ns_t_aaaa, "2001:db8::5");
- dns1.addMapping(host_name1, ns_type::ns_t_aaaa, "2001:db8::6");
- dns0.addMapping(host_name2, ns_type::ns_t_aaaa, "2001:db8::5");
- dns1.addMapping(host_name2, ns_type::ns_t_aaaa, "2001:db8::6");
- ASSERT_TRUE(dns0.startServer());
- ASSERT_TRUE(dns1.startServer());
- std::vector<std::string> servers = {listen_addr0, listen_addr1};
- ASSERT_TRUE(SetResolversForNetwork(servers, mDefaultSearchDomains, mDefaultParams_Binder));
-
- const addrinfo hints = {.ai_family = AF_INET6};
-
- // dns0 will ignore the request, and we'll fallback to dns1 after the first
- // retry.
- ScopedAddrinfo result = safe_getaddrinfo(host_name1, nullptr, &hints);
- EXPECT_TRUE(result != nullptr);
- EXPECT_EQ(1U, GetNumQueries(dns0, host_name1));
- EXPECT_EQ(1U, GetNumQueries(dns1, host_name1));
-
- // Now make dns1 also ignore 100% requests... The resolve should alternate
- // retries between the nameservers and fail after 4 attempts.
- dns1.setResponseProbability(0.0);
- addrinfo* result2 = nullptr;
- EXPECT_EQ(EAI_NODATA, getaddrinfo(host_name2, nullptr, &hints, &result2));
- EXPECT_EQ(nullptr, result2);
- EXPECT_EQ(4U, GetNumQueries(dns0, host_name2));
- EXPECT_EQ(4U, GetNumQueries(dns1, host_name2));
-}
-
-TEST_F(ResolverTest, GetAddrInfoV6_concurrent) {
- const char* listen_addr0 = "127.0.0.9";
- const char* listen_addr1 = "127.0.0.10";
- const char* listen_addr2 = "127.0.0.11";
- const char* listen_srv = "53";
- const char* host_name = "konbanha.example.com.";
- test::DNSResponder dns0(listen_addr0, listen_srv, 250, ns_rcode::ns_r_servfail);
- test::DNSResponder dns1(listen_addr1, listen_srv, 250, ns_rcode::ns_r_servfail);
- test::DNSResponder dns2(listen_addr2, listen_srv, 250, ns_rcode::ns_r_servfail);
- dns0.addMapping(host_name, ns_type::ns_t_aaaa, "2001:db8::5");
- dns1.addMapping(host_name, ns_type::ns_t_aaaa, "2001:db8::6");
- dns2.addMapping(host_name, ns_type::ns_t_aaaa, "2001:db8::7");
- ASSERT_TRUE(dns0.startServer());
- ASSERT_TRUE(dns1.startServer());
- ASSERT_TRUE(dns2.startServer());
- const std::vector<std::string> servers = { listen_addr0, listen_addr1, listen_addr2 };
- std::vector<std::thread> threads(10);
- for (std::thread& thread : threads) {
- thread = std::thread([this, &servers]() {
- unsigned delay = arc4random_uniform(1*1000*1000); // <= 1s
- usleep(delay);
- std::vector<std::string> serverSubset;
- for (const auto& server : servers) {
- if (arc4random_uniform(2)) {
- serverSubset.push_back(server);
- }
- }
- if (serverSubset.empty()) serverSubset = servers;
- ASSERT_TRUE(SetResolversForNetwork(serverSubset, mDefaultSearchDomains,
- mDefaultParams_Binder));
- addrinfo hints = {.ai_family = AF_INET6};
- addrinfo* result = nullptr;
- int rv = getaddrinfo("konbanha", nullptr, &hints, &result);
- EXPECT_EQ(0, rv) << "error [" << rv << "] " << gai_strerror(rv);
- if (result) {
- freeaddrinfo(result);
- result = nullptr;
- }
- });
- }
- for (std::thread& thread : threads) {
- thread.join();
- }
-}
-
-TEST_F(ResolverTest, GetAddrInfoStressTest_Binder_100) {
- const unsigned num_hosts = 100;
- const unsigned num_threads = 100;
- const unsigned num_queries = 100;
- ASSERT_NO_FATAL_FAILURE(RunGetAddrInfoStressTest_Binder(num_hosts, num_threads, num_queries));
-}
-
-TEST_F(ResolverTest, GetAddrInfoStressTest_Binder_100000) {
- const unsigned num_hosts = 100000;
- const unsigned num_threads = 100;
- const unsigned num_queries = 100;
- ASSERT_NO_FATAL_FAILURE(RunGetAddrInfoStressTest_Binder(num_hosts, num_threads, num_queries));
-}
-
-TEST_F(ResolverTest, EmptySetup) {
- using android::net::INetd;
- std::vector<std::string> servers;
- std::vector<std::string> domains;
- ASSERT_TRUE(SetResolversForNetwork(servers, domains, mDefaultParams_Binder));
- std::vector<std::string> res_servers;
- std::vector<std::string> res_domains;
- __res_params res_params;
- std::vector<ResolverStats> res_stats;
- ASSERT_TRUE(GetResolverInfo(&res_servers, &res_domains, &res_params, &res_stats));
- EXPECT_EQ(0U, res_servers.size());
- EXPECT_EQ(0U, res_domains.size());
- ASSERT_EQ(INetd::RESOLVER_PARAMS_COUNT, mDefaultParams_Binder.size());
- EXPECT_EQ(mDefaultParams_Binder[INetd::RESOLVER_PARAMS_SAMPLE_VALIDITY],
- res_params.sample_validity);
- EXPECT_EQ(mDefaultParams_Binder[INetd::RESOLVER_PARAMS_SUCCESS_THRESHOLD],
- res_params.success_threshold);
- EXPECT_EQ(mDefaultParams_Binder[INetd::RESOLVER_PARAMS_MIN_SAMPLES], res_params.min_samples);
- EXPECT_EQ(mDefaultParams_Binder[INetd::RESOLVER_PARAMS_MAX_SAMPLES], res_params.max_samples);
- EXPECT_EQ(mDefaultParams_Binder[INetd::RESOLVER_PARAMS_BASE_TIMEOUT_MSEC],
- res_params.base_timeout_msec);
-}
-
-TEST_F(ResolverTest, SearchPathChange) {
- const char* listen_addr = "127.0.0.13";
- const char* listen_srv = "53";
- const char* host_name1 = "test13.domain1.org.";
- const char* host_name2 = "test13.domain2.org.";
- test::DNSResponder dns(listen_addr, listen_srv, 250, ns_rcode::ns_r_servfail);
- dns.addMapping(host_name1, ns_type::ns_t_aaaa, "2001:db8::13");
- dns.addMapping(host_name2, ns_type::ns_t_aaaa, "2001:db8::1:13");
- ASSERT_TRUE(dns.startServer());
- std::vector<std::string> servers = { listen_addr };
- std::vector<std::string> domains = { "domain1.org" };
- ASSERT_TRUE(SetResolversForNetwork(servers, domains, mDefaultParams_Binder));
-
- const addrinfo hints = {.ai_family = AF_INET6};
- ScopedAddrinfo result = safe_getaddrinfo("test13", nullptr, &hints);
- EXPECT_TRUE(result != nullptr);
- EXPECT_EQ(1U, dns.queries().size());
- EXPECT_EQ(1U, GetNumQueries(dns, host_name1));
- EXPECT_EQ("2001:db8::13", ToString(result));
-
- // Test that changing the domain search path on its own works.
- domains = { "domain2.org" };
- ASSERT_TRUE(SetResolversForNetwork(servers, domains, mDefaultParams_Binder));
- dns.clearQueries();
-
- result = safe_getaddrinfo("test13", nullptr, &hints);
- EXPECT_TRUE(result != nullptr);
- EXPECT_EQ(1U, dns.queries().size());
- EXPECT_EQ(1U, GetNumQueries(dns, host_name2));
- EXPECT_EQ("2001:db8::1:13", ToString(result));
-}
-
-TEST_F(ResolverTest, MaxServerPrune_Binder) {
- using android::net::INetd;
-
- std::vector<std::string> domains = { "example.com" };
- std::vector<std::unique_ptr<test::DNSResponder>> dns;
- std::vector<std::string> servers;
- std::vector<Mapping> mappings;
- ASSERT_NO_FATAL_FAILURE(SetupMappings(1, domains, &mappings));
- ASSERT_NO_FATAL_FAILURE(SetupDNSServers(MAXNS + 1, mappings, &dns, &servers));
-
- ASSERT_TRUE(SetResolversForNetwork(servers, domains, mDefaultParams_Binder));
-
- std::vector<std::string> res_servers;
- std::vector<std::string> res_domains;
- __res_params res_params;
- std::vector<ResolverStats> res_stats;
- ASSERT_TRUE(GetResolverInfo(&res_servers, &res_domains, &res_params, &res_stats));
- EXPECT_EQ(static_cast<size_t>(MAXNS), res_servers.size());
-
- ASSERT_NO_FATAL_FAILURE(ShutdownDNSServers(&dns));
-}
-
-static std::string base64Encode(const std::vector<uint8_t>& input) {
- size_t out_len;
- EXPECT_EQ(1, EVP_EncodedLength(&out_len, input.size()));
- // out_len includes the trailing NULL.
- uint8_t output_bytes[out_len];
- EXPECT_EQ(out_len - 1, EVP_EncodeBlock(output_bytes, input.data(), input.size()));
- return std::string(reinterpret_cast<char*>(output_bytes));
-}
-
-// Test what happens if the specified TLS server is nonexistent.
-TEST_F(ResolverTest, GetHostByName_TlsMissing) {
- const char* listen_addr = "127.0.0.3";
- const char* listen_srv = "53";
- const char* host_name = "tlsmissing.example.com.";
- test::DNSResponder dns(listen_addr, listen_srv, 250, ns_rcode::ns_r_servfail);
- dns.addMapping(host_name, ns_type::ns_t_a, "1.2.3.3");
- ASSERT_TRUE(dns.startServer());
- std::vector<std::string> servers = { listen_addr };
-
- // There's nothing listening on this address, so validation will either fail or
- /// hang. Either way, queries will continue to flow to the DNSResponder.
- ASSERT_TRUE(SetResolversWithTls(servers, mDefaultSearchDomains, mDefaultParams_Binder, "", {}));
-
- const hostent* result;
-
- result = gethostbyname("tlsmissing");
- ASSERT_FALSE(result == nullptr);
- EXPECT_EQ("1.2.3.3", ToString(result));
-
- // Clear TLS bit.
- ASSERT_TRUE(SetResolversForNetwork(servers, mDefaultSearchDomains, mDefaultParams_Binder));
- dns.stopServer();
-}
-
-// Test what happens if the specified TLS server replies with garbage.
-TEST_F(ResolverTest, GetHostByName_TlsBroken) {
- const char* listen_addr = "127.0.0.3";
- const char* listen_srv = "53";
- const char* host_name1 = "tlsbroken1.example.com.";
- const char* host_name2 = "tlsbroken2.example.com.";
- test::DNSResponder dns(listen_addr, listen_srv, 250, ns_rcode::ns_r_servfail);
- dns.addMapping(host_name1, ns_type::ns_t_a, "1.2.3.1");
- dns.addMapping(host_name2, ns_type::ns_t_a, "1.2.3.2");
- ASSERT_TRUE(dns.startServer());
- std::vector<std::string> servers = { listen_addr };
-
- // Bind the specified private DNS socket but don't respond to any client sockets yet.
- int s = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, IPPROTO_TCP);
- ASSERT_TRUE(s >= 0);
- struct sockaddr_in tlsServer = {
- .sin_family = AF_INET,
- .sin_port = htons(853),
- };
- ASSERT_TRUE(inet_pton(AF_INET, listen_addr, &tlsServer.sin_addr));
- ASSERT_TRUE(enableSockopt(s, SOL_SOCKET, SO_REUSEPORT).ok());
- ASSERT_TRUE(enableSockopt(s, SOL_SOCKET, SO_REUSEADDR).ok());
- ASSERT_FALSE(bind(s, reinterpret_cast<struct sockaddr*>(&tlsServer), sizeof(tlsServer)));
- ASSERT_FALSE(listen(s, 1));
-
- // Trigger TLS validation.
- ASSERT_TRUE(SetResolversWithTls(servers, mDefaultSearchDomains, mDefaultParams_Binder, "", {}));
-
- struct sockaddr_storage cliaddr;
- socklen_t sin_size = sizeof(cliaddr);
- int new_fd = accept4(s, reinterpret_cast<struct sockaddr *>(&cliaddr), &sin_size, SOCK_CLOEXEC);
- ASSERT_TRUE(new_fd > 0);
-
- // We've received the new file descriptor but not written to it or closed, so the
- // validation is still pending. Queries should still flow correctly because the
- // server is not used until validation succeeds.
- const hostent* result;
- result = gethostbyname("tlsbroken1");
- ASSERT_FALSE(result == nullptr);
- EXPECT_EQ("1.2.3.1", ToString(result));
-
- // Now we cause the validation to fail.
- std::string garbage = "definitely not a valid TLS ServerHello";
- write(new_fd, garbage.data(), garbage.size());
- close(new_fd);
-
- // Validation failure shouldn't interfere with lookups, because lookups won't be sent
- // to the TLS server unless validation succeeds.
- result = gethostbyname("tlsbroken2");
- ASSERT_FALSE(result == nullptr);
- EXPECT_EQ("1.2.3.2", ToString(result));
-
- // Clear TLS bit.
- ASSERT_TRUE(SetResolversForNetwork(servers, mDefaultSearchDomains, mDefaultParams_Binder));
- dns.stopServer();
- close(s);
-}
-
-TEST_F(ResolverTest, GetHostByName_Tls) {
- const char* listen_addr = "127.0.0.3";
- const char* listen_udp = "53";
- const char* listen_tls = "853";
- const char* host_name1 = "tls1.example.com.";
- const char* host_name2 = "tls2.example.com.";
- const char* host_name3 = "tls3.example.com.";
- test::DNSResponder dns(listen_addr, listen_udp, 250, ns_rcode::ns_r_servfail);
- dns.addMapping(host_name1, ns_type::ns_t_a, "1.2.3.1");
- dns.addMapping(host_name2, ns_type::ns_t_a, "1.2.3.2");
- dns.addMapping(host_name3, ns_type::ns_t_a, "1.2.3.3");
- ASSERT_TRUE(dns.startServer());
- std::vector<std::string> servers = { listen_addr };
-
- test::DnsTlsFrontend tls(listen_addr, listen_tls, listen_addr, listen_udp);
- ASSERT_TRUE(tls.startServer());
- ASSERT_TRUE(SetResolversWithTls(servers, mDefaultSearchDomains, mDefaultParams_Binder, "", {}));
-
- const hostent* result;
-
- // Wait for validation to complete.
- EXPECT_TRUE(tls.waitForQueries(1, 5000));
-
- result = gethostbyname("tls1");
- ASSERT_FALSE(result == nullptr);
- EXPECT_EQ("1.2.3.1", ToString(result));
-
- // Wait for query to get counted.
- EXPECT_TRUE(tls.waitForQueries(2, 5000));
-
- // Stop the TLS server. Since we're in opportunistic mode, queries will
- // fall back to the locally-assigned (clear text) nameservers.
- tls.stopServer();
-
- dns.clearQueries();
- result = gethostbyname("tls2");
- EXPECT_FALSE(result == nullptr);
- EXPECT_EQ("1.2.3.2", ToString(result));
- const auto queries = dns.queries();
- EXPECT_EQ(1U, queries.size());
- EXPECT_EQ("tls2.example.com.", queries[0].first);
- EXPECT_EQ(ns_t_a, queries[0].second);
-
- // Reset the resolvers without enabling TLS. Queries should still be routed
- // to the UDP endpoint.
- ASSERT_TRUE(SetResolversForNetwork(servers, mDefaultSearchDomains, mDefaultParams_Binder));
-
- result = gethostbyname("tls3");
- ASSERT_FALSE(result == nullptr);
- EXPECT_EQ("1.2.3.3", ToString(result));
-
- dns.stopServer();
-}
-
-TEST_F(ResolverTest, GetHostByName_TlsFingerprint) {
- const char* listen_addr = "127.0.0.3";
- const char* listen_udp = "53";
- const char* listen_tls = "853";
- test::DNSResponder dns(listen_addr, listen_udp, 250, ns_rcode::ns_r_servfail);
- ASSERT_TRUE(dns.startServer());
- for (int chain_length = 1; chain_length <= 3; ++chain_length) {
- std::string host_name = StringPrintf("tlsfingerprint%d.example.com.", chain_length);
- dns.addMapping(host_name, ns_type::ns_t_a, "1.2.3.1");
- std::vector<std::string> servers = { listen_addr };
-
- test::DnsTlsFrontend tls(listen_addr, listen_tls, listen_addr, listen_udp);
- tls.set_chain_length(chain_length);
- ASSERT_TRUE(tls.startServer());
- ASSERT_TRUE(SetResolversWithTls(servers, mDefaultSearchDomains, mDefaultParams_Binder, "",
- { base64Encode(tls.fingerprint()) }));
-
- const hostent* result;
-
- // Wait for validation to complete.
- EXPECT_TRUE(tls.waitForQueries(1, 5000));
-
- result = gethostbyname(StringPrintf("tlsfingerprint%d", chain_length).c_str());
- EXPECT_FALSE(result == nullptr);
- if (result) {
- EXPECT_EQ("1.2.3.1", ToString(result));
-
- // Wait for query to get counted.
- EXPECT_TRUE(tls.waitForQueries(2, 5000));
- }
-
- // Clear TLS bit to ensure revalidation.
- ASSERT_TRUE(SetResolversForNetwork(servers, mDefaultSearchDomains, mDefaultParams_Binder));
- tls.stopServer();
- }
- dns.stopServer();
-}
-
-TEST_F(ResolverTest, GetHostByName_BadTlsFingerprint) {
- const char* listen_addr = "127.0.0.3";
- const char* listen_udp = "53";
- const char* listen_tls = "853";
- const char* host_name = "badtlsfingerprint.example.com.";
- test::DNSResponder dns(listen_addr, listen_udp, 250, ns_rcode::ns_r_servfail);
- dns.addMapping(host_name, ns_type::ns_t_a, "1.2.3.1");
- ASSERT_TRUE(dns.startServer());
- std::vector<std::string> servers = { listen_addr };
-
- test::DnsTlsFrontend tls(listen_addr, listen_tls, listen_addr, listen_udp);
- ASSERT_TRUE(tls.startServer());
- std::vector<uint8_t> bad_fingerprint = tls.fingerprint();
- bad_fingerprint[5] += 1; // Corrupt the fingerprint.
- ASSERT_TRUE(SetResolversWithTls(servers, mDefaultSearchDomains, mDefaultParams_Binder, "",
- { base64Encode(bad_fingerprint) }));
-
- // The initial validation should fail at the fingerprint check before
- // issuing a query.
- EXPECT_FALSE(tls.waitForQueries(1, 500));
-
- // A fingerprint was provided and failed to match, so the query should fail.
- EXPECT_EQ(nullptr, gethostbyname("badtlsfingerprint"));
-
- // Clear TLS bit.
- ASSERT_TRUE(SetResolversForNetwork(servers, mDefaultSearchDomains, mDefaultParams_Binder));
- tls.stopServer();
- dns.stopServer();
-}
-
-// Test that we can pass two different fingerprints, and connection succeeds as long as
-// at least one of them matches the server.
-TEST_F(ResolverTest, GetHostByName_TwoTlsFingerprints) {
- const char* listen_addr = "127.0.0.3";
- const char* listen_udp = "53";
- const char* listen_tls = "853";
- const char* host_name = "twotlsfingerprints.example.com.";
- test::DNSResponder dns(listen_addr, listen_udp, 250, ns_rcode::ns_r_servfail);
- dns.addMapping(host_name, ns_type::ns_t_a, "1.2.3.1");
- ASSERT_TRUE(dns.startServer());
- std::vector<std::string> servers = { listen_addr };
-
- test::DnsTlsFrontend tls(listen_addr, listen_tls, listen_addr, listen_udp);
- ASSERT_TRUE(tls.startServer());
- std::vector<uint8_t> bad_fingerprint = tls.fingerprint();
- bad_fingerprint[5] += 1; // Corrupt the fingerprint.
- ASSERT_TRUE(SetResolversWithTls(servers, mDefaultSearchDomains, mDefaultParams_Binder, "",
- { base64Encode(bad_fingerprint), base64Encode(tls.fingerprint()) }));
-
- const hostent* result;
-
- // Wait for validation to complete.
- EXPECT_TRUE(tls.waitForQueries(1, 5000));
-
- result = gethostbyname("twotlsfingerprints");
- ASSERT_FALSE(result == nullptr);
- EXPECT_EQ("1.2.3.1", ToString(result));
-
- // Wait for query to get counted.
- EXPECT_TRUE(tls.waitForQueries(2, 5000));
-
- // Clear TLS bit.
- ASSERT_TRUE(SetResolversForNetwork(servers, mDefaultSearchDomains, mDefaultParams_Binder));
- tls.stopServer();
- dns.stopServer();
-}
-
-TEST_F(ResolverTest, GetHostByName_TlsFingerprintGoesBad) {
- const char* listen_addr = "127.0.0.3";
- const char* listen_udp = "53";
- const char* listen_tls = "853";
- const char* host_name1 = "tlsfingerprintgoesbad1.example.com.";
- const char* host_name2 = "tlsfingerprintgoesbad2.example.com.";
- test::DNSResponder dns(listen_addr, listen_udp, 250, ns_rcode::ns_r_servfail);
- dns.addMapping(host_name1, ns_type::ns_t_a, "1.2.3.1");
- dns.addMapping(host_name2, ns_type::ns_t_a, "1.2.3.2");
- ASSERT_TRUE(dns.startServer());
- std::vector<std::string> servers = { listen_addr };
-
- test::DnsTlsFrontend tls(listen_addr, listen_tls, listen_addr, listen_udp);
- ASSERT_TRUE(tls.startServer());
- ASSERT_TRUE(SetResolversWithTls(servers, mDefaultSearchDomains, mDefaultParams_Binder, "",
- { base64Encode(tls.fingerprint()) }));
-
- const hostent* result;
-
- // Wait for validation to complete.
- EXPECT_TRUE(tls.waitForQueries(1, 5000));
-
- result = gethostbyname("tlsfingerprintgoesbad1");
- ASSERT_FALSE(result == nullptr);
- EXPECT_EQ("1.2.3.1", ToString(result));
-
- // Wait for query to get counted.
- EXPECT_TRUE(tls.waitForQueries(2, 5000));
-
- // Restart the TLS server. This will generate a new certificate whose fingerprint
- // no longer matches the stored fingerprint.
- tls.stopServer();
- tls.startServer();
-
- result = gethostbyname("tlsfingerprintgoesbad2");
- ASSERT_TRUE(result == nullptr);
- EXPECT_EQ(HOST_NOT_FOUND, h_errno);
-
- // Clear TLS bit.
- ASSERT_TRUE(SetResolversForNetwork(servers, mDefaultSearchDomains, mDefaultParams_Binder));
- tls.stopServer();
- dns.stopServer();
-}
-
-TEST_F(ResolverTest, GetHostByName_TlsFailover) {
- const char* listen_addr1 = "127.0.0.3";
- const char* listen_addr2 = "127.0.0.4";
- const char* listen_udp = "53";
- const char* listen_tls = "853";
- const char* host_name1 = "tlsfailover1.example.com.";
- const char* host_name2 = "tlsfailover2.example.com.";
- test::DNSResponder dns1(listen_addr1, listen_udp, 250, ns_rcode::ns_r_servfail);
- test::DNSResponder dns2(listen_addr2, listen_udp, 250, ns_rcode::ns_r_servfail);
- dns1.addMapping(host_name1, ns_type::ns_t_a, "1.2.3.1");
- dns1.addMapping(host_name2, ns_type::ns_t_a, "1.2.3.2");
- dns2.addMapping(host_name1, ns_type::ns_t_a, "1.2.3.3");
- dns2.addMapping(host_name2, ns_type::ns_t_a, "1.2.3.4");
- ASSERT_TRUE(dns1.startServer());
- ASSERT_TRUE(dns2.startServer());
- std::vector<std::string> servers = { listen_addr1, listen_addr2 };
-
- test::DnsTlsFrontend tls1(listen_addr1, listen_tls, listen_addr1, listen_udp);
- test::DnsTlsFrontend tls2(listen_addr2, listen_tls, listen_addr2, listen_udp);
- ASSERT_TRUE(tls1.startServer());
- ASSERT_TRUE(tls2.startServer());
- ASSERT_TRUE(SetResolversWithTls(servers, mDefaultSearchDomains, mDefaultParams_Binder, "",
- { base64Encode(tls1.fingerprint()), base64Encode(tls2.fingerprint()) }));
-
- const hostent* result;
-
- // Wait for validation to complete.
- EXPECT_TRUE(tls1.waitForQueries(1, 5000));
- EXPECT_TRUE(tls2.waitForQueries(1, 5000));
-
- result = gethostbyname("tlsfailover1");
- ASSERT_FALSE(result == nullptr);
- EXPECT_EQ("1.2.3.1", ToString(result));
-
- // Wait for query to get counted.
- EXPECT_TRUE(tls1.waitForQueries(2, 5000));
- // No new queries should have reached tls2.
- EXPECT_EQ(1, tls2.queries());
-
- // Stop tls1. Subsequent queries should attempt to reach tls1, fail, and retry to tls2.
- tls1.stopServer();
-
- result = gethostbyname("tlsfailover2");
- EXPECT_EQ("1.2.3.4", ToString(result));
-
- // Wait for query to get counted.
- EXPECT_TRUE(tls2.waitForQueries(2, 5000));
-
- // No additional queries should have reached the insecure servers.
- EXPECT_EQ(2U, dns1.queries().size());
- EXPECT_EQ(2U, dns2.queries().size());
-
- // Clear TLS bit.
- ASSERT_TRUE(SetResolversForNetwork(servers, mDefaultSearchDomains, mDefaultParams_Binder));
- tls2.stopServer();
- dns1.stopServer();
- dns2.stopServer();
-}
-
-TEST_F(ResolverTest, GetHostByName_BadTlsName) {
- const char* listen_addr = "127.0.0.3";
- const char* listen_udp = "53";
- const char* listen_tls = "853";
- const char* host_name = "badtlsname.example.com.";
- test::DNSResponder dns(listen_addr, listen_udp, 250, ns_rcode::ns_r_servfail);
- dns.addMapping(host_name, ns_type::ns_t_a, "1.2.3.1");
- ASSERT_TRUE(dns.startServer());
- std::vector<std::string> servers = { listen_addr };
-
- test::DnsTlsFrontend tls(listen_addr, listen_tls, listen_addr, listen_udp);
- ASSERT_TRUE(tls.startServer());
- ASSERT_TRUE(SetResolversWithTls(servers, mDefaultSearchDomains, mDefaultParams_Binder,
- "www.example.com", {}));
-
- // The TLS server's certificate doesn't chain to a known CA, and a nonempty name was specified,
- // so the client should fail the TLS handshake before ever issuing a query.
- EXPECT_FALSE(tls.waitForQueries(1, 500));
-
- // The query should fail hard, because a name was specified.
- EXPECT_EQ(nullptr, gethostbyname("badtlsname"));
-
- // Clear TLS bit.
- ASSERT_TRUE(SetResolversForNetwork(servers, mDefaultSearchDomains, mDefaultParams_Binder));
- tls.stopServer();
- dns.stopServer();
-}
-
-TEST_F(ResolverTest, GetAddrInfo_Tls) {
- const char* listen_addr = "127.0.0.3";
- const char* listen_udp = "53";
- const char* listen_tls = "853";
- const char* host_name = "addrinfotls.example.com.";
- test::DNSResponder dns(listen_addr, listen_udp, 250, ns_rcode::ns_r_servfail);
- dns.addMapping(host_name, ns_type::ns_t_a, "1.2.3.4");
- dns.addMapping(host_name, ns_type::ns_t_aaaa, "::1.2.3.4");
- ASSERT_TRUE(dns.startServer());
- std::vector<std::string> servers = { listen_addr };
-
- test::DnsTlsFrontend tls(listen_addr, listen_tls, listen_addr, listen_udp);
- ASSERT_TRUE(tls.startServer());
- ASSERT_TRUE(SetResolversWithTls(servers, mDefaultSearchDomains, mDefaultParams_Binder, "",
- { base64Encode(tls.fingerprint()) }));
-
- // Wait for validation to complete.
- EXPECT_TRUE(tls.waitForQueries(1, 5000));
-
- dns.clearQueries();
- ScopedAddrinfo result = safe_getaddrinfo("addrinfotls", nullptr, nullptr);
- EXPECT_TRUE(result != nullptr);
- size_t found = GetNumQueries(dns, host_name);
- EXPECT_LE(1U, found);
- // Could be A or AAAA
- std::string result_str = ToString(result);
- EXPECT_TRUE(result_str == "1.2.3.4" || result_str == "::1.2.3.4")
- << ", result_str='" << result_str << "'";
- // Wait for both A and AAAA queries to get counted.
- EXPECT_TRUE(tls.waitForQueries(3, 5000));
-
- // Clear TLS bit.
- ASSERT_TRUE(SetResolversForNetwork(servers, mDefaultSearchDomains, mDefaultParams_Binder));
- tls.stopServer();
- dns.stopServer();
-}
-
-TEST_F(ResolverTest, TlsBypass) {
- const char OFF[] = "off";
- const char OPPORTUNISTIC[] = "opportunistic";
- const char STRICT[] = "strict";
-
- const char GETHOSTBYNAME[] = "gethostbyname";
- const char GETADDRINFO[] = "getaddrinfo";
- const char GETADDRINFOFORNET[] = "getaddrinfofornet";
-
- const unsigned BYPASS_NETID = NETID_USE_LOCAL_NAMESERVERS | TEST_NETID;
-
- const std::vector<uint8_t> NOOP_FINGERPRINT(SHA256_SIZE, 0U);
-
- const char ADDR4[] = "192.0.2.1";
- const char ADDR6[] = "2001:db8::1";
-
- const char cleartext_addr[] = "127.0.0.53";
- const char cleartext_port[] = "53";
- const char tls_port[] = "853";
- const std::vector<std::string> servers = { cleartext_addr };
-
- test::DNSResponder dns(cleartext_addr, cleartext_port, 250, ns_rcode::ns_r_servfail);
- ASSERT_TRUE(dns.startServer());
-
- test::DnsTlsFrontend tls(cleartext_addr, tls_port, cleartext_addr, cleartext_port);
-
- struct TestConfig {
- const std::string mode;
- const bool withWorkingTLS;
- const std::string method;
-
- std::string asHostName() const {
- return StringPrintf("%s.%s.%s.",
- mode.c_str(),
- withWorkingTLS ? "tlsOn" : "tlsOff",
- method.c_str());
- }
- } testConfigs[]{
- {OFF, false, GETHOSTBYNAME},
- {OPPORTUNISTIC, false, GETHOSTBYNAME},
- {STRICT, false, GETHOSTBYNAME},
- {OFF, true, GETHOSTBYNAME},
- {OPPORTUNISTIC, true, GETHOSTBYNAME},
- {STRICT, true, GETHOSTBYNAME},
- {OFF, false, GETADDRINFO},
- {OPPORTUNISTIC, false, GETADDRINFO},
- {STRICT, false, GETADDRINFO},
- {OFF, true, GETADDRINFO},
- {OPPORTUNISTIC, true, GETADDRINFO},
- {STRICT, true, GETADDRINFO},
- {OFF, false, GETADDRINFOFORNET},
- {OPPORTUNISTIC, false, GETADDRINFOFORNET},
- {STRICT, false, GETADDRINFOFORNET},
- {OFF, true, GETADDRINFOFORNET},
- {OPPORTUNISTIC, true, GETADDRINFOFORNET},
- {STRICT, true, GETADDRINFOFORNET},
- };
-
- for (const auto& config : testConfigs) {
- const std::string testHostName = config.asHostName();
- SCOPED_TRACE(testHostName);
-
- // Don't tempt test bugs due to caching.
- const char* host_name = testHostName.c_str();
- dns.addMapping(host_name, ns_type::ns_t_a, ADDR4);
- dns.addMapping(host_name, ns_type::ns_t_aaaa, ADDR6);
-
- if (config.withWorkingTLS) ASSERT_TRUE(tls.startServer());
-
- if (config.mode == OFF) {
- ASSERT_TRUE(SetResolversForNetwork(
- servers, mDefaultSearchDomains, mDefaultParams_Binder));
- } else if (config.mode == OPPORTUNISTIC) {
- ASSERT_TRUE(SetResolversWithTls(
- servers, mDefaultSearchDomains, mDefaultParams_Binder, "", {}));
- // Wait for validation to complete.
- if (config.withWorkingTLS) EXPECT_TRUE(tls.waitForQueries(1, 5000));
- } else if (config.mode == STRICT) {
- // We use the existence of fingerprints to trigger strict mode,
- // rather than hostname validation.
- const auto& fingerprint =
- (config.withWorkingTLS) ? tls.fingerprint() : NOOP_FINGERPRINT;
- ASSERT_TRUE(SetResolversWithTls(
- servers, mDefaultSearchDomains, mDefaultParams_Binder, "",
- { base64Encode(fingerprint) }));
- // Wait for validation to complete.
- if (config.withWorkingTLS) EXPECT_TRUE(tls.waitForQueries(1, 5000));
- } else {
- FAIL() << "Unsupported Private DNS mode: " << config.mode;
- }
-
- const int tlsQueriesBefore = tls.queries();
-
- const hostent* h_result = nullptr;
- ScopedAddrinfo ai_result;
-
- if (config.method == GETHOSTBYNAME) {
- ASSERT_EQ(0, setNetworkForResolv(BYPASS_NETID));
- h_result = gethostbyname(host_name);
-
- EXPECT_EQ(1U, GetNumQueriesForType(dns, ns_type::ns_t_a, host_name));
- ASSERT_FALSE(h_result == nullptr);
- ASSERT_EQ(4, h_result->h_length);
- ASSERT_FALSE(h_result->h_addr_list[0] == nullptr);
- EXPECT_EQ(ADDR4, ToString(h_result));
- EXPECT_TRUE(h_result->h_addr_list[1] == nullptr);
- } else if (config.method == GETADDRINFO) {
- ASSERT_EQ(0, setNetworkForResolv(BYPASS_NETID));
- ai_result = safe_getaddrinfo(host_name, nullptr, nullptr);
- EXPECT_TRUE(ai_result != nullptr);
-
- EXPECT_LE(1U, GetNumQueries(dns, host_name));
- // Could be A or AAAA
- const std::string result_str = ToString(ai_result);
- EXPECT_TRUE(result_str == ADDR4 || result_str == ADDR6)
- << ", result_str='" << result_str << "'";
- } else if (config.method == GETADDRINFOFORNET) {
- addrinfo* raw_ai_result = nullptr;
- EXPECT_EQ(0, android_getaddrinfofornet(host_name, /*servname=*/nullptr,
- /*hints=*/nullptr, BYPASS_NETID, MARK_UNSET,
- &raw_ai_result));
- ai_result.reset(raw_ai_result);
-
- EXPECT_LE(1U, GetNumQueries(dns, host_name));
- // Could be A or AAAA
- const std::string result_str = ToString(ai_result);
- EXPECT_TRUE(result_str == ADDR4 || result_str == ADDR6)
- << ", result_str='" << result_str << "'";
- } else {
- FAIL() << "Unsupported query method: " << config.method;
- }
-
- const int tlsQueriesAfter = tls.queries();
- EXPECT_EQ(0, tlsQueriesAfter - tlsQueriesBefore);
-
- // Clear per-process resolv netid.
- ASSERT_EQ(0, setNetworkForResolv(NETID_UNSET));
- tls.stopServer();
- dns.clearQueries();
- }
-
- dns.stopServer();
-}
-
-TEST_F(ResolverTest, StrictMode_NoTlsServers) {
- const std::vector<uint8_t> NOOP_FINGERPRINT(SHA256_SIZE, 0U);
- const char cleartext_addr[] = "127.0.0.53";
- const char cleartext_port[] = "53";
- const std::vector<std::string> servers = { cleartext_addr };
-
- test::DNSResponder dns(cleartext_addr, cleartext_port, 250, ns_rcode::ns_r_servfail);
- const char* host_name = "strictmode.notlsips.example.com.";
- dns.addMapping(host_name, ns_type::ns_t_a, "1.2.3.4");
- dns.addMapping(host_name, ns_type::ns_t_aaaa, "::1.2.3.4");
- ASSERT_TRUE(dns.startServer());
-
- ASSERT_TRUE(SetResolversWithTls(
- servers, mDefaultSearchDomains, mDefaultParams_Binder,
- {}, "", { base64Encode(NOOP_FINGERPRINT) }));
-
- addrinfo* ai_result = nullptr;
- EXPECT_NE(0, getaddrinfo(host_name, nullptr, nullptr, &ai_result));
- EXPECT_EQ(0U, GetNumQueries(dns, host_name));
-}
diff --git a/tests/runtests.sh b/tests/runtests.sh
index d59dd19..a221116 100755
--- a/tests/runtests.sh
+++ b/tests/runtests.sh
@@ -7,7 +7,8 @@
netdutils_test
netd_unit_test
netd_integration_test
- libnetd_resolv_test
+ resolv_integration_test
+ resolv_unit_test
"
readonly EXTENDED_TESTS="