• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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