1 // Copyright (c) 2019 The Chromium Authors. All rights reserved.
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/address_info.h"
6 
7 #include "base/logging.h"
8 #include "base/notreached.h"
9 #include "base/sys_byteorder.h"
10 #include "net/base/address_list.h"
11 #include "net/base/net_errors.h"
12 #include "net/base/sys_addrinfo.h"
13 
14 namespace net {
15 
16 namespace {
17 
Next(const addrinfo * ai)18 const addrinfo* Next(const addrinfo* ai) {
19   return ai->ai_next;
20 }
21 
22 }  // namespace
23 
24 //// iterator
25 
const_iterator(const addrinfo * ai)26 AddressInfo::const_iterator::const_iterator(const addrinfo* ai) : ai_(ai) {}
27 
operator !=(const AddressInfo::const_iterator & o) const28 bool AddressInfo::const_iterator::operator!=(
29     const AddressInfo::const_iterator& o) const {
30   return ai_ != o.ai_;
31 }
32 
operator ++()33 AddressInfo::const_iterator& AddressInfo::const_iterator::operator++() {
34   ai_ = Next(ai_);
35   return *this;
36 }
37 
operator ->() const38 const addrinfo* AddressInfo::const_iterator::operator->() const {
39   return ai_;
40 }
41 
operator *() const42 const addrinfo& AddressInfo::const_iterator::operator*() const {
43   return *ai_;
44 }
45 
46 //// constructors
47 
Get(const std::string & host,const addrinfo & hints,std::unique_ptr<AddrInfoGetter> getter)48 AddressInfo::AddressInfoAndResult AddressInfo::Get(
49     const std::string& host,
50     const addrinfo& hints,
51     std::unique_ptr<AddrInfoGetter> getter) {
52   if (getter == nullptr)
53     getter = std::make_unique<AddrInfoGetter>();
54   int err = OK;
55   int os_error = 0;
56   addrinfo* ai = getter->getaddrinfo(host, &hints, &os_error);
57 
58   if (!ai) {
59     err = ERR_NAME_NOT_RESOLVED;
60 
61     // If the call to getaddrinfo() failed because of a system error, report
62     // it separately from ERR_NAME_NOT_RESOLVED.
63 #if defined(OS_WIN)
64     if (os_error != WSAHOST_NOT_FOUND && os_error != WSANO_DATA)
65       err = ERR_NAME_RESOLUTION_FAILED;
66 #elif defined(OS_ANDROID)
67     // Workaround for Android's getaddrinfo leaving ai==nullptr without an
68     // error.
69     // http://crbug.com/134142
70     err = ERR_NAME_NOT_RESOLVED;
71 #elif defined(OS_POSIX) && !defined(OS_FREEBSD) && !defined(OS_DRAGONFLY)
72     if (os_error != EAI_NONAME && os_error != EAI_NODATA)
73       err = ERR_NAME_RESOLUTION_FAILED;
74 #endif
75 
76     return AddressInfoAndResult(base::Optional<AddressInfo>(), err, os_error);
77   }
78 
79   return AddressInfoAndResult(
80       base::Optional<AddressInfo>(AddressInfo(ai, std::move(getter))), OK, 0);
81 }
82 
AddressInfo(AddressInfo && other)83 AddressInfo::AddressInfo(AddressInfo&& other)
84     : ai_(other.ai_), getter_(std::move(other.getter_)) {
85   other.ai_ = nullptr;
86 }
87 
operator =(AddressInfo && other)88 AddressInfo& AddressInfo::operator=(AddressInfo&& other) {
89   ai_ = other.ai_;
90   other.ai_ = nullptr;
91   getter_ = std::move(other.getter_);
92   return *this;
93 }
94 
~AddressInfo()95 AddressInfo::~AddressInfo() {
96   if (ai_)
97     getter_->freeaddrinfo(ai_);
98 }
99 
100 //// public methods
101 
begin() const102 AddressInfo::const_iterator AddressInfo::begin() const {
103   return const_iterator(ai_);
104 }
105 
end() const106 AddressInfo::const_iterator AddressInfo::end() const {
107   return const_iterator(nullptr);
108 }
109 
GetCanonicalName() const110 base::Optional<std::string> AddressInfo::GetCanonicalName() const {
111   return (ai_->ai_canonname != nullptr)
112              ? base::Optional<std::string>(std::string(ai_->ai_canonname))
113              : base::Optional<std::string>();
114 }
115 
IsAllLocalhostOfOneFamily() const116 bool AddressInfo::IsAllLocalhostOfOneFamily() const {
117   bool saw_v4_localhost = false;
118   bool saw_v6_localhost = false;
119   const auto* ai = ai_;
120   for (; ai != nullptr; ai = Next(ai)) {
121     switch (ai->ai_family) {
122       case AF_INET: {
123         const struct sockaddr_in* addr_in =
124             reinterpret_cast<struct sockaddr_in*>(ai->ai_addr);
125         if ((base::NetToHost32(addr_in->sin_addr.s_addr) & 0xff000000) ==
126             0x7f000000)
127           saw_v4_localhost = true;
128         else
129           return false;
130         break;
131       }
132       case AF_INET6: {
133         const struct sockaddr_in6* addr_in6 =
134             reinterpret_cast<struct sockaddr_in6*>(ai->ai_addr);
135         if (IN6_IS_ADDR_LOOPBACK(&addr_in6->sin6_addr))
136           saw_v6_localhost = true;
137         else
138           return false;
139         break;
140       }
141       default:
142         NOTREACHED();
143         return false;
144     }
145   }
146 
147   return saw_v4_localhost != saw_v6_localhost;
148 }
149 
CreateAddressList() const150 AddressList AddressInfo::CreateAddressList() const {
151   AddressList list;
152   auto canonical_name = GetCanonicalName();
153   if (canonical_name)
154     list.set_canonical_name(*canonical_name);
155   for (auto&& ai : *this) {
156     IPEndPoint ipe;
157     // NOTE: Ignoring non-INET* families.
158     if (ipe.FromSockAddr(ai.ai_addr, ai.ai_addrlen))
159       list.push_back(ipe);
160     else
161       DLOG(WARNING) << "Unknown family found in addrinfo: " << ai.ai_family;
162   }
163   return list;
164 }
165 
166 //// private methods
167 
AddressInfo(addrinfo * ai,std::unique_ptr<AddrInfoGetter> getter)168 AddressInfo::AddressInfo(addrinfo* ai, std::unique_ptr<AddrInfoGetter> getter)
169     : ai_(ai), getter_(std::move(getter)) {}
170 
171 //// AddrInfoGetter
172 
173 AddrInfoGetter::AddrInfoGetter() = default;
174 AddrInfoGetter::~AddrInfoGetter() = default;
175 
getaddrinfo(const std::string & host,const addrinfo * hints,int * out_os_error)176 addrinfo* AddrInfoGetter::getaddrinfo(const std::string& host,
177                                       const addrinfo* hints,
178                                       int* out_os_error) {
179   addrinfo* ai;
180   *out_os_error = ::getaddrinfo(host.c_str(), nullptr, hints, &ai);
181 
182   if (*out_os_error) {
183 #if defined(OS_WIN)
184     *out_os_error = WSAGetLastError();
185 #endif
186     return nullptr;
187   }
188 
189   return ai;
190 }
191 
freeaddrinfo(addrinfo * ai)192 void AddrInfoGetter::freeaddrinfo(addrinfo* ai) {
193   ::freeaddrinfo(ai);
194 }
195 
196 }  // namespace net
197