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