// 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 #include #include #include #include #include #include #include #include "base/check_op.h" #include "base/functional/bind.h" #include "build/build_config.h" #include "net/base/ip_endpoint.h" namespace net { std::unique_ptr ResolvReader::GetResState() { auto res = std::make_unique(); if (!res->IsValid()) return nullptr; return res; } std::optional> GetNameservers( const struct __res_state& res) { std::vector nameservers; if (!(res.options & RES_INIT)) return std::nullopt; #if BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_FREEBSD) union res_sockaddr_union addresses[MAXNS]; int nscount = res_getservers(const_cast(&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(&addresses[i]), sizeof addresses[i])) { return std::nullopt; } nameservers.push_back(ipe); } #elif BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_LINUX) static_assert(std::extent() >= MAXNS && std::extent() >= 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(&res.nsaddr_list[i]); addr_len = sizeof res.nsaddr_list[i]; } else if (res._u._ext.nsaddrs[i]) { addr = reinterpret_cast(res._u._ext.nsaddrs[i]); addr_len = sizeof *res._u._ext.nsaddrs[i]; } else { return std::nullopt; } if (!ipe.FromSockAddr(addr, addr_len)) return std::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(&res.nsaddr_list[i]), sizeof res.nsaddr_list[i])) { return std::nullopt; } nameservers.push_back(ipe); } #endif return nameservers; } } // namespace net