95 lines
2.9 KiB
C++
95 lines
2.9 KiB
C++
// Copyright 2021 The Chromium Authors
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
#include "net/dns/public/resolv_reader.h"
|
|
|
|
#include <netinet/in.h>
|
|
#include <resolv.h>
|
|
#include <sys/types.h>
|
|
|
|
#include <memory>
|
|
#include <type_traits>
|
|
#include <utility>
|
|
#include <vector>
|
|
|
|
#include "base/check_op.h"
|
|
#include "base/functional/bind.h"
|
|
#include "build/build_config.h"
|
|
#include "net/base/ip_endpoint.h"
|
|
#include "third_party/abseil-cpp/absl/types/optional.h"
|
|
|
|
namespace net {
|
|
|
|
std::unique_ptr<ScopedResState> ResolvReader::GetResState() {
|
|
auto res = std::make_unique<ScopedResState>();
|
|
if (!res->IsValid())
|
|
return nullptr;
|
|
return res;
|
|
}
|
|
|
|
absl::optional<std::vector<IPEndPoint>> GetNameservers(
|
|
const struct __res_state& res) {
|
|
std::vector<IPEndPoint> nameservers;
|
|
|
|
if (!(res.options & RES_INIT))
|
|
return absl::nullopt;
|
|
|
|
#if BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_FREEBSD)
|
|
union res_sockaddr_union addresses[MAXNS];
|
|
int nscount = res_getservers(const_cast<res_state>(&res), addresses, MAXNS);
|
|
DCHECK_GE(nscount, 0);
|
|
DCHECK_LE(nscount, MAXNS);
|
|
for (int i = 0; i < nscount; ++i) {
|
|
IPEndPoint ipe;
|
|
if (!ipe.FromSockAddr(
|
|
reinterpret_cast<const struct sockaddr*>(&addresses[i]),
|
|
sizeof addresses[i])) {
|
|
return absl::nullopt;
|
|
}
|
|
nameservers.push_back(ipe);
|
|
}
|
|
#elif BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_LINUX)
|
|
static_assert(std::extent<decltype(res.nsaddr_list)>() >= MAXNS &&
|
|
std::extent<decltype(res._u._ext.nsaddrs)>() >= MAXNS,
|
|
"incompatible libresolv res_state");
|
|
DCHECK_LE(res.nscount, MAXNS);
|
|
// Initially, glibc stores IPv6 in |_ext.nsaddrs| and IPv4 in |nsaddr_list|.
|
|
// In res_send.c:res_nsend, it merges |nsaddr_list| into |nsaddrs|,
|
|
// but we have to combine the two arrays ourselves.
|
|
for (int i = 0; i < res.nscount; ++i) {
|
|
IPEndPoint ipe;
|
|
const struct sockaddr* addr = nullptr;
|
|
size_t addr_len = 0;
|
|
if (res.nsaddr_list[i].sin_family) { // The indicator used by res_nsend.
|
|
addr = reinterpret_cast<const struct sockaddr*>(&res.nsaddr_list[i]);
|
|
addr_len = sizeof res.nsaddr_list[i];
|
|
} else if (res._u._ext.nsaddrs[i]) {
|
|
addr = reinterpret_cast<const struct sockaddr*>(res._u._ext.nsaddrs[i]);
|
|
addr_len = sizeof *res._u._ext.nsaddrs[i];
|
|
} else {
|
|
return absl::nullopt;
|
|
}
|
|
if (!ipe.FromSockAddr(addr, addr_len))
|
|
return absl::nullopt;
|
|
nameservers.push_back(ipe);
|
|
}
|
|
#else // !(BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_APPLE)
|
|
// || BUILDFLAG(IS_FREEBSD))
|
|
DCHECK_LE(res.nscount, MAXNS);
|
|
for (int i = 0; i < res.nscount; ++i) {
|
|
IPEndPoint ipe;
|
|
if (!ipe.FromSockAddr(
|
|
reinterpret_cast<const struct sockaddr*>(&res.nsaddr_list[i]),
|
|
sizeof res.nsaddr_list[i])) {
|
|
return absl::nullopt;
|
|
}
|
|
nameservers.push_back(ipe);
|
|
}
|
|
#endif
|
|
|
|
return nameservers;
|
|
}
|
|
|
|
} // namespace net
|