1 // Copyright 2021 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #ifdef UNSAFE_BUFFERS_BUILD
6 // TODO(crbug.com/40284755): Remove this and spanify to fix the errors.
7 #pragma allow_unsafe_buffers
8 #endif
9
10 #include "net/dns/public/resolv_reader.h"
11
12 #include <netinet/in.h>
13 #include <resolv.h>
14 #include <sys/types.h>
15
16 #include <memory>
17 #include <optional>
18 #include <type_traits>
19 #include <utility>
20 #include <vector>
21
22 #include "base/check_op.h"
23 #include "base/functional/bind.h"
24 #include "build/build_config.h"
25 #include "net/base/ip_endpoint.h"
26
27 namespace net {
28
GetResState()29 std::unique_ptr<ScopedResState> ResolvReader::GetResState() {
30 auto res = std::make_unique<ScopedResState>();
31 if (!res->IsValid())
32 return nullptr;
33 return res;
34 }
35
GetNameservers(const struct __res_state & res)36 std::optional<std::vector<IPEndPoint>> GetNameservers(
37 const struct __res_state& res) {
38 std::vector<IPEndPoint> nameservers;
39
40 if (!(res.options & RES_INIT))
41 return std::nullopt;
42
43 #if BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_FREEBSD)
44 union res_sockaddr_union addresses[MAXNS];
45 int nscount = res_getservers(const_cast<res_state>(&res), addresses, MAXNS);
46 DCHECK_GE(nscount, 0);
47 DCHECK_LE(nscount, MAXNS);
48 for (int i = 0; i < nscount; ++i) {
49 IPEndPoint ipe;
50 if (!ipe.FromSockAddr(
51 reinterpret_cast<const struct sockaddr*>(&addresses[i]),
52 sizeof addresses[i])) {
53 return std::nullopt;
54 }
55 nameservers.push_back(ipe);
56 }
57 #elif BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_LINUX)
58 static_assert(std::extent<decltype(res.nsaddr_list)>() >= MAXNS &&
59 std::extent<decltype(res._u._ext.nsaddrs)>() >= MAXNS,
60 "incompatible libresolv res_state");
61 DCHECK_LE(res.nscount, MAXNS);
62 // Initially, glibc stores IPv6 in |_ext.nsaddrs| and IPv4 in |nsaddr_list|.
63 // In res_send.c:res_nsend, it merges |nsaddr_list| into |nsaddrs|,
64 // but we have to combine the two arrays ourselves.
65 for (int i = 0; i < res.nscount; ++i) {
66 IPEndPoint ipe;
67 const struct sockaddr* addr = nullptr;
68 size_t addr_len = 0;
69 if (res.nsaddr_list[i].sin_family) { // The indicator used by res_nsend.
70 addr = reinterpret_cast<const struct sockaddr*>(&res.nsaddr_list[i]);
71 addr_len = sizeof res.nsaddr_list[i];
72 } else if (res._u._ext.nsaddrs[i]) {
73 addr = reinterpret_cast<const struct sockaddr*>(res._u._ext.nsaddrs[i]);
74 addr_len = sizeof *res._u._ext.nsaddrs[i];
75 } else {
76 return std::nullopt;
77 }
78 if (!ipe.FromSockAddr(addr, addr_len))
79 return std::nullopt;
80 nameservers.push_back(ipe);
81 }
82 #else // !(BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_APPLE)
83 // || BUILDFLAG(IS_FREEBSD))
84 DCHECK_LE(res.nscount, MAXNS);
85 for (int i = 0; i < res.nscount; ++i) {
86 IPEndPoint ipe;
87 if (!ipe.FromSockAddr(
88 reinterpret_cast<const struct sockaddr*>(&res.nsaddr_list[i]),
89 sizeof res.nsaddr_list[i])) {
90 return std::nullopt;
91 }
92 nameservers.push_back(ipe);
93 }
94 #endif
95
96 return nameservers;
97 }
98
99 } // namespace net
100