You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
188 lines
6.1 KiB
188 lines
6.1 KiB
/* |
|
* 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_client.h" |
|
|
|
#include <android-base/stringprintf.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"; |
|
|
|
// The only response code used in this class. See |
|
// frameworks/base/services/java/com/android/server/NetworkManagementService.java |
|
// for others. |
|
static constexpr int ResponseCodeOK = 200; |
|
|
|
using android::base::StringPrintf; |
|
|
|
static int netdCommand(const char* sockname, const char* command) { |
|
int sock = socket_local_client(sockname, |
|
ANDROID_SOCKET_NAMESPACE_RESERVED, |
|
SOCK_STREAM); |
|
if (sock < 0) { |
|
perror("Error connecting"); |
|
return -1; |
|
} |
|
|
|
// FrameworkListener expects the whole command in one read. |
|
char buffer[256]; |
|
int nwritten = snprintf(buffer, sizeof(buffer), "0 %s", command); |
|
if (write(sock, buffer, nwritten + 1) < 0) { |
|
perror("Error sending netd command"); |
|
close(sock); |
|
return -1; |
|
} |
|
|
|
int nread = read(sock, buffer, sizeof(buffer)); |
|
if (nread < 0) { |
|
perror("Error reading response"); |
|
close(sock); |
|
return -1; |
|
} |
|
close(sock); |
|
return atoi(buffer); |
|
} |
|
|
|
static bool expectNetdResult(int expected, const char* sockname, const char* format, ...) { |
|
char command[256]; |
|
va_list args; |
|
va_start(args, format); |
|
vsnprintf(command, sizeof(command), format, args); |
|
va_end(args); |
|
int result = netdCommand(sockname, command); |
|
if (expected != result) { |
|
return false; |
|
} |
|
return (200 <= expected && expected < 300); |
|
} |
|
|
|
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) { |
|
auto rv = mNetdSrv->setResolverConfiguration(TEST_NETID, servers, domains, params); |
|
return rv.isOk(); |
|
} |
|
|
|
bool DnsResponderClient::SetResolversForNetwork(const std::vector<std::string>& searchDomains, |
|
const std::vector<std::string>& servers, const std::string& params) { |
|
std::string cmd = StringPrintf("resolver setnetdns %d \"", mOemNetId); |
|
if (!searchDomains.empty()) { |
|
cmd += searchDomains[0].c_str(); |
|
for (size_t i = 1 ; i < searchDomains.size() ; ++i) { |
|
cmd += " "; |
|
cmd += searchDomains[i]; |
|
} |
|
} |
|
cmd += "\""; |
|
|
|
for (const auto& str : servers) { |
|
cmd += " "; |
|
cmd += str; |
|
} |
|
|
|
if (!params.empty()) { |
|
cmd += " --params \""; |
|
cmd += params; |
|
cmd += "\""; |
|
} |
|
|
|
int rv = netdCommand("netd", cmd.c_str()); |
|
if (rv != ResponseCodeOK) { |
|
return false; |
|
} |
|
return true; |
|
} |
|
|
|
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, 1.0); |
|
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() { |
|
netdCommand("netd", "network destroy " TEST_OEM_NETWORK); |
|
if (!expectNetdResult(ResponseCodeOK, "netd", |
|
"network create %s", TEST_OEM_NETWORK)) { |
|
return -1; |
|
} |
|
int oemNetId = TEST_NETID; |
|
setNetworkForProcess(oemNetId); |
|
if ((unsigned) oemNetId != getNetworkForProcess()) { |
|
return -1; |
|
} |
|
return oemNetId; |
|
} |
|
|
|
void DnsResponderClient::TearDownOemNetwork(int oemNetId) { |
|
if (oemNetId != -1) { |
|
expectNetdResult(ResponseCodeOK, "netd", |
|
"network destroy %s", TEST_OEM_NETWORK); |
|
} |
|
} |
|
|
|
void DnsResponderClient::SetUp() { |
|
// Ensure resolutions go via proxy. |
|
setenv(ANDROID_DNS_MODE, "", 1); |
|
mOemNetId = SetupOemNetwork(); |
|
|
|
// binder setup |
|
auto binder = android::defaultServiceManager()->getService(android::String16("netd")); |
|
mNetdSrv = android::interface_cast<android::net::INetd>(binder); |
|
} |
|
|
|
void DnsResponderClient::TearDown() { |
|
TearDownOemNetwork(mOemNetId); |
|
}
|
|
|