1 /*
2  *  Copyright 2008 The WebRTC Project Authors. All rights reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10 
11 #include "rtc_base/net_helpers.h"
12 
13 #if defined(WEBRTC_WIN)
14 #include <ws2spi.h>
15 #include <ws2tcpip.h>
16 
17 #include "rtc_base/win32.h"
18 #endif
19 #if defined(WEBRTC_POSIX) && !defined(__native_client__)
20 #if defined(WEBRTC_ANDROID)
21 #include "rtc_base/ifaddrs_android.h"
22 #else
23 #include <ifaddrs.h>
24 #endif
25 #endif  // defined(WEBRTC_POSIX) && !defined(__native_client__)
26 
27 #include "api/task_queue/task_queue_base.h"
28 #include "rtc_base/logging.h"
29 #include "rtc_base/signal_thread.h"
30 #include "rtc_base/task_queue.h"
31 #include "rtc_base/task_utils/to_queued_task.h"
32 #include "rtc_base/third_party/sigslot/sigslot.h"  // for signal_with_thread...
33 
34 namespace rtc {
35 
ResolveHostname(const std::string & hostname,int family,std::vector<IPAddress> * addresses)36 int ResolveHostname(const std::string& hostname,
37                     int family,
38                     std::vector<IPAddress>* addresses) {
39 #ifdef __native_client__
40   RTC_NOTREACHED();
41   RTC_LOG(LS_WARNING) << "ResolveHostname() is not implemented for NaCl";
42   return -1;
43 #else   // __native_client__
44   if (!addresses) {
45     return -1;
46   }
47   addresses->clear();
48   struct addrinfo* result = nullptr;
49   struct addrinfo hints = {0};
50   hints.ai_family = family;
51   // |family| here will almost always be AF_UNSPEC, because |family| comes from
52   // AsyncResolver::addr_.family(), which comes from a SocketAddress constructed
53   // with a hostname. When a SocketAddress is constructed with a hostname, its
54   // family is AF_UNSPEC. However, if someday in the future we construct
55   // a SocketAddress with both a hostname and a family other than AF_UNSPEC,
56   // then it would be possible to get a specific family value here.
57 
58   // The behavior of AF_UNSPEC is roughly "get both ipv4 and ipv6", as
59   // documented by the various operating systems:
60   // Linux: http://man7.org/linux/man-pages/man3/getaddrinfo.3.html
61   // Windows: https://msdn.microsoft.com/en-us/library/windows/desktop/
62   // ms738520(v=vs.85).aspx
63   // Mac: https://developer.apple.com/legacy/library/documentation/Darwin/
64   // Reference/ManPages/man3/getaddrinfo.3.html
65   // Android (source code, not documentation):
66   // https://android.googlesource.com/platform/bionic/+/
67   // 7e0bfb511e85834d7c6cb9631206b62f82701d60/libc/netbsd/net/getaddrinfo.c#1657
68   hints.ai_flags = AI_ADDRCONFIG;
69   int ret = getaddrinfo(hostname.c_str(), nullptr, &hints, &result);
70   if (ret != 0) {
71     return ret;
72   }
73   struct addrinfo* cursor = result;
74   for (; cursor; cursor = cursor->ai_next) {
75     if (family == AF_UNSPEC || cursor->ai_family == family) {
76       IPAddress ip;
77       if (IPFromAddrInfo(cursor, &ip)) {
78         addresses->push_back(ip);
79       }
80     }
81   }
82   freeaddrinfo(result);
83   return 0;
84 #endif  // !__native_client__
85 }
86 
AsyncResolver()87 AsyncResolver::AsyncResolver() : error_(-1) {}
88 
~AsyncResolver()89 AsyncResolver::~AsyncResolver() {
90   RTC_DCHECK_RUN_ON(&sequence_checker_);
91 }
92 
Start(const SocketAddress & addr)93 void AsyncResolver::Start(const SocketAddress& addr) {
94   RTC_DCHECK_RUN_ON(&sequence_checker_);
95   RTC_DCHECK(!destroy_called_);
96   addr_ = addr;
97   webrtc::TaskQueueBase* current_task_queue = webrtc::TaskQueueBase::Current();
98   popup_thread_ = Thread::Create();
99   popup_thread_->Start();
100   popup_thread_->PostTask(webrtc::ToQueuedTask(
101       [this, flag = safety_.flag(), addr, current_task_queue] {
102         std::vector<IPAddress> addresses;
103         int error =
104             ResolveHostname(addr.hostname().c_str(), addr.family(), &addresses);
105         current_task_queue->PostTask(webrtc::ToQueuedTask(
106             std::move(flag), [this, error, addresses = std::move(addresses)] {
107               RTC_DCHECK_RUN_ON(&sequence_checker_);
108               ResolveDone(std::move(addresses), error);
109             }));
110       }));
111 }
112 
GetResolvedAddress(int family,SocketAddress * addr) const113 bool AsyncResolver::GetResolvedAddress(int family, SocketAddress* addr) const {
114   RTC_DCHECK_RUN_ON(&sequence_checker_);
115   RTC_DCHECK(!destroy_called_);
116   if (error_ != 0 || addresses_.empty())
117     return false;
118 
119   *addr = addr_;
120   for (size_t i = 0; i < addresses_.size(); ++i) {
121     if (family == addresses_[i].family()) {
122       addr->SetResolvedIP(addresses_[i]);
123       return true;
124     }
125   }
126   return false;
127 }
128 
GetError() const129 int AsyncResolver::GetError() const {
130   RTC_DCHECK_RUN_ON(&sequence_checker_);
131   RTC_DCHECK(!destroy_called_);
132   return error_;
133 }
134 
Destroy(bool wait)135 void AsyncResolver::Destroy(bool wait) {
136   // Some callers have trouble guaranteeing that Destroy is called on the
137   // sequence guarded by |sequence_checker_|.
138   // RTC_DCHECK_RUN_ON(&sequence_checker_);
139   RTC_DCHECK(!destroy_called_);
140   destroy_called_ = true;
141   MaybeSelfDestruct();
142 }
143 
addresses() const144 const std::vector<IPAddress>& AsyncResolver::addresses() const {
145   RTC_DCHECK_RUN_ON(&sequence_checker_);
146   RTC_DCHECK(!destroy_called_);
147   return addresses_;
148 }
149 
ResolveDone(std::vector<IPAddress> addresses,int error)150 void AsyncResolver::ResolveDone(std::vector<IPAddress> addresses, int error) {
151   addresses_ = addresses;
152   error_ = error;
153   recursion_check_ = true;
154   SignalDone(this);
155   MaybeSelfDestruct();
156 }
157 
MaybeSelfDestruct()158 void AsyncResolver::MaybeSelfDestruct() {
159   if (!recursion_check_) {
160     delete this;
161   } else {
162     recursion_check_ = false;
163   }
164 }
165 
inet_ntop(int af,const void * src,char * dst,socklen_t size)166 const char* inet_ntop(int af, const void* src, char* dst, socklen_t size) {
167 #if defined(WEBRTC_WIN)
168   return win32_inet_ntop(af, src, dst, size);
169 #else
170   return ::inet_ntop(af, src, dst, size);
171 #endif
172 }
173 
inet_pton(int af,const char * src,void * dst)174 int inet_pton(int af, const char* src, void* dst) {
175 #if defined(WEBRTC_WIN)
176   return win32_inet_pton(af, src, dst);
177 #else
178   return ::inet_pton(af, src, dst);
179 #endif
180 }
181 
HasIPv4Enabled()182 bool HasIPv4Enabled() {
183 #if defined(WEBRTC_POSIX) && !defined(__native_client__)
184   bool has_ipv4 = false;
185   struct ifaddrs* ifa;
186   if (getifaddrs(&ifa) < 0) {
187     return false;
188   }
189   for (struct ifaddrs* cur = ifa; cur != nullptr; cur = cur->ifa_next) {
190     if (cur->ifa_addr->sa_family == AF_INET) {
191       has_ipv4 = true;
192       break;
193     }
194   }
195   freeifaddrs(ifa);
196   return has_ipv4;
197 #else
198   return true;
199 #endif
200 }
201 
HasIPv6Enabled()202 bool HasIPv6Enabled() {
203 #if defined(WINUWP)
204   // WinUWP always has IPv6 capability.
205   return true;
206 #elif defined(WEBRTC_WIN)
207   if (IsWindowsVistaOrLater()) {
208     return true;
209   }
210   if (!IsWindowsXpOrLater()) {
211     return false;
212   }
213   DWORD protbuff_size = 4096;
214   std::unique_ptr<char[]> protocols;
215   LPWSAPROTOCOL_INFOW protocol_infos = nullptr;
216   int requested_protocols[2] = {AF_INET6, 0};
217 
218   int err = 0;
219   int ret = 0;
220   // Check for protocols in a do-while loop until we provide a buffer large
221   // enough. (WSCEnumProtocols sets protbuff_size to its desired value).
222   // It is extremely unlikely that this will loop more than once.
223   do {
224     protocols.reset(new char[protbuff_size]);
225     protocol_infos = reinterpret_cast<LPWSAPROTOCOL_INFOW>(protocols.get());
226     ret = WSCEnumProtocols(requested_protocols, protocol_infos, &protbuff_size,
227                            &err);
228   } while (ret == SOCKET_ERROR && err == WSAENOBUFS);
229 
230   if (ret == SOCKET_ERROR) {
231     return false;
232   }
233 
234   // Even if ret is positive, check specifically for IPv6.
235   // Non-IPv6 enabled WinXP will still return a RAW protocol.
236   for (int i = 0; i < ret; ++i) {
237     if (protocol_infos[i].iAddressFamily == AF_INET6) {
238       return true;
239     }
240   }
241   return false;
242 #elif defined(WEBRTC_POSIX) && !defined(__native_client__)
243   bool has_ipv6 = false;
244   struct ifaddrs* ifa;
245   if (getifaddrs(&ifa) < 0) {
246     return false;
247   }
248   for (struct ifaddrs* cur = ifa; cur != nullptr; cur = cur->ifa_next) {
249     if (cur->ifa_addr->sa_family == AF_INET6) {
250       has_ipv6 = true;
251       break;
252     }
253   }
254   freeifaddrs(ifa);
255   return has_ipv6;
256 #else
257   return true;
258 #endif
259 }
260 }  // namespace rtc
261