blob: ae27620bcfa214363f0a86a0323b293bbb967921 [file] [log] [blame] [edit]
// Copyright 2023 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "dns-proxy/resolv_conf.h"
#include <set>
#include <string>
#include <vector>
#include <base/containers/contains.h>
#include <base/files/file_util.h>
#include <base/logging.h>
#include <base/strings/string_util.h>
#include <chromeos/net-base/ip_address.h>
#include "dns-proxy/dns_util.h"
namespace dns_proxy {
ResolvConf::ResolvConf() = default;
ResolvConf::~ResolvConf() = default;
bool ResolvConf::SetDNSFromLists(
const std::vector<net_base::IPAddress>& name_servers,
const std::vector<std::string>& domain_search_list) {
name_servers_.clear();
domain_search_list_.clear();
std::set<std::string> name_server_set;
std::set<std::string> domain_search_set;
// Avoid duplicated entry, but keep the order.
for (const auto& name_server : name_servers) {
std::string name_server_str = name_server.ToString();
if (!base::Contains(name_server_set, name_server_str)) {
name_servers_.push_back(name_server_str);
name_server_set.insert(name_server_str);
}
}
for (const auto& domain_search : domain_search_list) {
if (!base::Contains(domain_search_set, domain_search)) {
domain_search_list_.push_back(domain_search);
domain_search_set.insert(domain_search);
}
}
return Emit();
}
bool ResolvConf::Emit() {
if (path_.empty()) {
LOG(DFATAL) << "No path set";
return false;
}
// dns-proxy always used if set.
const auto name_servers =
!dns_proxy_addrs_.empty() ? dns_proxy_addrs_ : name_servers_;
if (name_servers.empty()) {
LOG(WARNING) << "Setting resolv.conf to []";
base::WriteFile(path_, "");
return true;
}
LOG(INFO) << "Setting resolv.conf to [" << base::JoinString(name_servers, ",")
<< "]";
std::vector<std::string> lines;
for (const auto& server : name_servers) {
const auto addr = net_base::IPAddress::CreateFromString(server);
if (!addr) {
LOG(WARNING) << "Malformed nameserver IP: " << server;
continue;
}
lines.push_back("nameserver " + addr->ToString());
}
std::vector<std::string> filtered_domain_search_list;
for (const auto& domain : domain_search_list_) {
if (IsValidDNSDomain(domain)) {
filtered_domain_search_list.push_back(domain);
} else {
LOG(WARNING) << "Malformed search domain: " << domain;
}
}
if (!filtered_domain_search_list.empty()) {
lines.push_back("search " +
base::JoinString(filtered_domain_search_list, " "));
}
// - Send queries one-at-a-time, rather than parallelizing IPv4
// and IPv6 queries for a single host.
// - Override the default 5-second request timeout and use a
// 1-second timeout instead. (NOTE: Chrome's ADNS will use
// one second, regardless of what we put here.)
// - Allow 5 attempts, rather than the default of 2.
// - For glibc, the worst case number of queries will be
// attempts * count(servers) * (count(search domains)+1)
// - For Chrome, the worst case number of queries will be
// attempts * count(servers) + 3 * glibc
// See crbug.com/224756 for supporting data.
lines.push_back("options single-request timeout:1 attempts:5");
// Newline at end of file
lines.push_back("");
const auto contents = base::JoinString(lines, "\n");
return base::WriteFile(path_, contents);
}
bool ResolvConf::SetDNSProxyAddresses(
const std::vector<std::string>& proxy_addrs) {
dns_proxy_addrs_ = proxy_addrs;
return Emit();
}
} // namespace dns_proxy