OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "net/base/net_util.h" | 5 #include "net/base/net_util.h" |
6 | 6 |
7 #include <set> | 7 #include <set> |
8 #include <sys/types.h> | 8 #include <sys/types.h> |
9 | 9 |
10 #include "base/files/file_path.h" | |
11 #include "base/logging.h" | |
12 #include "base/memory/scoped_ptr.h" | 10 #include "base/memory/scoped_ptr.h" |
13 #include "base/strings/string_number_conversions.h" | |
14 #include "base/strings/string_tokenizer.h" | |
15 #include "base/strings/string_util.h" | |
16 #include "base/threading/thread_restrictions.h" | |
17 #include "net/base/escape.h" | |
18 #include "net/base/ip_endpoint.h" | |
19 #include "net/base/net_errors.h" | |
20 #include "url/gurl.h" | |
21 | 11 |
22 #if !defined(OS_NACL) | 12 #if !defined(OS_NACL) |
23 #if defined(OS_MACOSX) | |
24 #include <ifaddrs.h> | |
25 #else | |
26 #include "net/base/address_tracker_linux.h" | |
27 #include "net/base/net_util_posix.h" | 13 #include "net/base/net_util_posix.h" |
28 #endif // OS_MACOSX | |
29 #include <net/if.h> | 14 #include <net/if.h> |
30 #include <netinet/in.h> | 15 #include <netinet/in.h> |
31 #endif // !defined(OS_NACL) | 16 #endif // !defined(OS_NACL) |
32 | 17 |
33 #if defined(OS_MACOSX) && !defined(OS_IOS) | |
34 #include <net/if_media.h> | |
35 #include <netinet/in_var.h> | |
36 #include <sys/ioctl.h> | |
37 #endif | |
38 | |
39 namespace net { | 18 namespace net { |
40 | 19 |
41 namespace { | 20 #if !defined(OS_NACL) |
| 21 namespace internal { |
42 | 22 |
43 // The application layer can pass |policy| defined in net_util.h to | 23 // The application layer can pass |policy| defined in net_util.h to |
44 // request filtering out certain type of interfaces. | 24 // request filtering out certain type of interfaces. |
45 bool ShouldIgnoreInterface(const std::string& name, int policy) { | 25 bool ShouldIgnoreInterface(const std::string& name, int policy) { |
46 // Filter out VMware interfaces, typically named vmnet1 and vmnet8, | 26 // Filter out VMware interfaces, typically named vmnet1 and vmnet8, |
47 // which might not be useful for use cases like WebRTC. | 27 // which might not be useful for use cases like WebRTC. |
48 if ((policy & EXCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES) && | 28 if ((policy & EXCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES) && |
49 ((name.find("vmnet") != std::string::npos) || | 29 ((name.find("vmnet") != std::string::npos) || |
50 (name.find("vnic") != std::string::npos))) { | 30 (name.find("vnic") != std::string::npos))) { |
51 return true; | 31 return true; |
(...skipping 18 matching lines...) Expand all Loading... |
70 addr_in->sin_addr.s_addr == 0) { | 50 addr_in->sin_addr.s_addr == 0) { |
71 return true; | 51 return true; |
72 } | 52 } |
73 } else { | 53 } else { |
74 // Skip non-IP addresses. | 54 // Skip non-IP addresses. |
75 return true; | 55 return true; |
76 } | 56 } |
77 return false; | 57 return false; |
78 } | 58 } |
79 | 59 |
80 #if defined(OS_MACOSX) | |
81 | |
82 struct NetworkInterfaceInfo { | |
83 NetworkInterfaceInfo() : permanent(true) { } | |
84 | |
85 bool permanent; // IPv6 has notion of temporary address. If the address is | |
86 // IPv6 and it's temporary this field will be false. | |
87 NetworkInterface interface; | |
88 }; | |
89 | |
90 // This method will remove permanent IPv6 addresses if a temporary address | |
91 // is available for same network interface. | |
92 void RemovePermanentIPv6AddressesWhereTemporaryExists( | |
93 std::vector<NetworkInterfaceInfo>* infos) { | |
94 if (!infos || infos->empty()) | |
95 return; | |
96 | |
97 // Build a set containing the names of interfaces with a temp IPv6 address | |
98 std::set<std::string> ifaces_with_temp_addrs; | |
99 std::vector<NetworkInterfaceInfo>::iterator i; | |
100 for (i = infos->begin(); i != infos->end(); ++i) { | |
101 if (!i->permanent && i->interface.address.size() == kIPv6AddressSize) { | |
102 ifaces_with_temp_addrs.insert(i->interface.name); | |
103 } | |
104 } | |
105 | |
106 // If there are no such interfaces then there's no further work. | |
107 if (ifaces_with_temp_addrs.empty()) | |
108 return; | |
109 | |
110 // Search for permenent addresses belonging to same network interface. | |
111 for (i = infos->begin(); i != infos->end(); ) { | |
112 // If the address is IPv6 and it's permanent and there is temporary | |
113 // address for it, then we can remove this address. | |
114 if ((i->interface.address.size() == kIPv6AddressSize) && i->permanent && | |
115 (ifaces_with_temp_addrs.find(i->interface.name) != | |
116 ifaces_with_temp_addrs.end())) { | |
117 i = infos->erase(i); | |
118 } else { | |
119 ++i; | |
120 } | |
121 } | |
122 } | |
123 | |
124 #if !defined(OS_IOS) | |
125 NetworkChangeNotifier::ConnectionType GetNetworkInterfaceType( | |
126 int addr_family, const std::string& interface_name) { | |
127 NetworkChangeNotifier::ConnectionType type = | |
128 NetworkChangeNotifier::CONNECTION_UNKNOWN; | |
129 | |
130 struct ifmediareq ifmr = {}; | |
131 strncpy(ifmr.ifm_name, interface_name.c_str(), sizeof(ifmr.ifm_name) - 1); | |
132 | |
133 int s = socket(addr_family, SOCK_DGRAM, 0); | |
134 if (s == -1) { | |
135 return type; | |
136 } | |
137 | |
138 if (ioctl(s, SIOCGIFMEDIA, &ifmr) != -1) { | |
139 if (ifmr.ifm_current & IFM_IEEE80211) { | |
140 type = NetworkChangeNotifier::CONNECTION_WIFI; | |
141 } else if (ifmr.ifm_current & IFM_ETHER) { | |
142 type = NetworkChangeNotifier::CONNECTION_ETHERNET; | |
143 } | |
144 } | |
145 close(s); | |
146 return type; | |
147 } | |
148 | |
149 #endif // !defined(OS_IOS) | |
150 #elif !defined(OS_NACL) // OS_MACOSX | |
151 | |
152 // Convert platform native IPv6 address attributes to net IP address | |
153 // attributes and drop ones that can't be used by the application | |
154 // layer. | |
155 bool TryConvertNativeToNetIPAttributes(int native_attributes, | |
156 int* net_attributes) { | |
157 // For Linux/ChromeOS/Android, we disallow addresses with attributes | |
158 // IFA_F_OPTIMISTIC, IFA_F_DADFAILED, and IFA_F_TENTATIVE as these | |
159 // are still progressing through duplicated address detection (DAD) | |
160 // and shouldn't be used by the application layer until DAD process | |
161 // is completed. | |
162 if (native_attributes & ( | |
163 #if !defined(OS_ANDROID) | |
164 IFA_F_OPTIMISTIC | IFA_F_DADFAILED | | |
165 #endif // !OS_ANDROID | |
166 IFA_F_TENTATIVE)) { | |
167 return false; | |
168 } | |
169 | |
170 if (native_attributes & IFA_F_TEMPORARY) { | |
171 *net_attributes |= IP_ADDRESS_ATTRIBUTE_TEMPORARY; | |
172 } | |
173 | |
174 if (native_attributes & IFA_F_DEPRECATED) { | |
175 *net_attributes |= IP_ADDRESS_ATTRIBUTE_DEPRECATED; | |
176 } | |
177 | |
178 return true; | |
179 } | |
180 #endif // OS_MACOSX | |
181 } // namespace | |
182 | |
183 namespace internal { | |
184 | |
185 #if !defined(OS_MACOSX) && !defined(OS_NACL) | |
186 | |
187 inline const unsigned char* GetIPAddressData(const IPAddressNumber& ip) { | |
188 #if defined(OS_ANDROID) | |
189 return ip.begin(); | |
190 #else | |
191 return ip.data(); | |
192 #endif | |
193 } | |
194 | |
195 bool GetNetworkListImpl( | |
196 NetworkInterfaceList* networks, | |
197 int policy, | |
198 const base::hash_set<int>& online_links, | |
199 const internal::AddressTrackerLinux::AddressMap& address_map, | |
200 GetInterfaceNameFunction get_interface_name) { | |
201 std::map<int, std::string> ifnames; | |
202 | |
203 for (internal::AddressTrackerLinux::AddressMap::const_iterator it = | |
204 address_map.begin(); | |
205 it != address_map.end(); | |
206 ++it) { | |
207 // Ignore addresses whose links are not online. | |
208 if (online_links.find(it->second.ifa_index) == online_links.end()) | |
209 continue; | |
210 | |
211 sockaddr_storage sock_addr; | |
212 socklen_t sock_len = sizeof(sockaddr_storage); | |
213 | |
214 // Convert to sockaddr for next check. | |
215 if (!IPEndPoint(it->first, 0) | |
216 .ToSockAddr(reinterpret_cast<sockaddr*>(&sock_addr), &sock_len)) { | |
217 continue; | |
218 } | |
219 | |
220 // Skip unspecified addresses (i.e. made of zeroes) and loopback addresses | |
221 if (IsLoopbackOrUnspecifiedAddress(reinterpret_cast<sockaddr*>(&sock_addr))) | |
222 continue; | |
223 | |
224 int ip_attributes = IP_ADDRESS_ATTRIBUTE_NONE; | |
225 | |
226 if (it->second.ifa_family == AF_INET6) { | |
227 // Ignore addresses whose attributes are not actionable by | |
228 // the application layer. | |
229 if (!TryConvertNativeToNetIPAttributes(it->second.ifa_flags, | |
230 &ip_attributes)) | |
231 continue; | |
232 } | |
233 | |
234 // Find the name of this link. | |
235 std::map<int, std::string>::const_iterator itname = | |
236 ifnames.find(it->second.ifa_index); | |
237 std::string ifname; | |
238 if (itname == ifnames.end()) { | |
239 char buffer[IF_NAMESIZE] = {0}; | |
240 if (get_interface_name(it->second.ifa_index, buffer)) { | |
241 ifname = ifnames[it->second.ifa_index] = buffer; | |
242 } else { | |
243 // Ignore addresses whose interface name can't be retrieved. | |
244 continue; | |
245 } | |
246 } else { | |
247 ifname = itname->second; | |
248 } | |
249 | |
250 // Based on the interface name and policy, determine whether we | |
251 // should ignore it. | |
252 if (ShouldIgnoreInterface(ifname, policy)) | |
253 continue; | |
254 | |
255 networks->push_back( | |
256 NetworkInterface(ifname, | |
257 ifname, | |
258 it->second.ifa_index, | |
259 NetworkChangeNotifier::CONNECTION_UNKNOWN, | |
260 it->first, | |
261 it->second.ifa_prefixlen, | |
262 ip_attributes)); | |
263 } | |
264 | |
265 return true; | |
266 } | |
267 #endif | |
268 | |
269 } // namespace internal | 60 } // namespace internal |
270 | 61 #else // OS_NACL |
271 bool GetNetworkList(NetworkInterfaceList* networks, int policy) { | 62 bool GetNetworkList(NetworkInterfaceList* networks, int policy) { |
272 if (networks == NULL) | |
273 return false; | |
274 #if defined(OS_NACL) | |
275 NOTIMPLEMENTED(); | 63 NOTIMPLEMENTED(); |
276 return false; | 64 return false; |
277 #elif !defined(OS_MACOSX) | |
278 | |
279 internal::AddressTrackerLinux tracker; | |
280 tracker.Init(); | |
281 | |
282 return internal::GetNetworkListImpl(networks, | |
283 policy, | |
284 tracker.GetOnlineLinks(), | |
285 tracker.GetAddressMap(), | |
286 &if_indextoname); | |
287 | |
288 #else // Only OS_MACOSX and OS_IOS will run the code below | |
289 | |
290 // getifaddrs() may require IO operations. | |
291 base::ThreadRestrictions::AssertIOAllowed(); | |
292 | |
293 #if !defined(OS_IOS) | |
294 int ioctl_socket = -1; | |
295 if (policy & INCLUDE_ONLY_TEMP_IPV6_ADDRESS_IF_POSSIBLE) { | |
296 // we need a socket to query information about temporary address. | |
297 ioctl_socket = socket(AF_INET6, SOCK_DGRAM, 0); | |
298 DCHECK_GT(ioctl_socket, 0); | |
299 } | |
300 #endif | |
301 | |
302 ifaddrs* interfaces; | |
303 if (getifaddrs(&interfaces) < 0) { | |
304 PLOG(ERROR) << "getifaddrs"; | |
305 return false; | |
306 } | |
307 | |
308 std::vector<NetworkInterfaceInfo> network_infos; | |
309 | |
310 // Enumerate the addresses assigned to network interfaces which are up. | |
311 for (ifaddrs *interface = interfaces; | |
312 interface != NULL; | |
313 interface = interface->ifa_next) { | |
314 // Skip loopback interfaces, and ones which are down. | |
315 if (!(IFF_UP & interface->ifa_flags)) | |
316 continue; | |
317 if (IFF_LOOPBACK & interface->ifa_flags) | |
318 continue; | |
319 // Skip interfaces with no address configured. | |
320 struct sockaddr* addr = interface->ifa_addr; | |
321 if (!addr) | |
322 continue; | |
323 | |
324 // Skip unspecified addresses (i.e. made of zeroes) and loopback addresses | |
325 // configured on non-loopback interfaces. | |
326 if (IsLoopbackOrUnspecifiedAddress(addr)) | |
327 continue; | |
328 | |
329 int addr_size = 0; | |
330 if (addr->sa_family == AF_INET6) { | |
331 addr_size = sizeof(sockaddr_in6); | |
332 } else if (addr->sa_family == AF_INET) { | |
333 addr_size = sizeof(sockaddr_in); | |
334 } | |
335 | |
336 const std::string& name = interface->ifa_name; | |
337 // Filter out VMware interfaces, typically named vmnet1 and vmnet8. | |
338 if (ShouldIgnoreInterface(name, policy)) { | |
339 continue; | |
340 } | |
341 | |
342 NetworkInterfaceInfo network_info; | |
343 NetworkChangeNotifier::ConnectionType connection_type = | |
344 NetworkChangeNotifier::CONNECTION_UNKNOWN; | |
345 #if !defined(OS_IOS) | |
346 // Check if this is a temporary address. Currently this is only supported | |
347 // on Mac. | |
348 if ((policy & INCLUDE_ONLY_TEMP_IPV6_ADDRESS_IF_POSSIBLE) && | |
349 ioctl_socket >= 0 && addr->sa_family == AF_INET6) { | |
350 struct in6_ifreq ifr = {}; | |
351 strncpy(ifr.ifr_name, interface->ifa_name, sizeof(ifr.ifr_name) - 1); | |
352 memcpy(&ifr.ifr_ifru.ifru_addr, interface->ifa_addr, | |
353 interface->ifa_addr->sa_len); | |
354 int rv = ioctl(ioctl_socket, SIOCGIFAFLAG_IN6, &ifr); | |
355 if (rv >= 0) { | |
356 network_info.permanent = !(ifr.ifr_ifru.ifru_flags & IN6_IFF_TEMPORARY); | |
357 } | |
358 } | |
359 | |
360 connection_type = GetNetworkInterfaceType(addr->sa_family, name); | |
361 #endif | |
362 | |
363 IPEndPoint address; | |
364 if (address.FromSockAddr(addr, addr_size)) { | |
365 uint8 net_mask = 0; | |
366 if (interface->ifa_netmask) { | |
367 // If not otherwise set, assume the same sa_family as ifa_addr. | |
368 if (interface->ifa_netmask->sa_family == 0) { | |
369 interface->ifa_netmask->sa_family = addr->sa_family; | |
370 } | |
371 IPEndPoint netmask; | |
372 if (netmask.FromSockAddr(interface->ifa_netmask, addr_size)) { | |
373 net_mask = MaskPrefixLength(netmask.address()); | |
374 } | |
375 } | |
376 network_info.interface = NetworkInterface(name, | |
377 name, | |
378 if_nametoindex(name.c_str()), | |
379 connection_type, | |
380 address.address(), | |
381 net_mask, | |
382 IP_ADDRESS_ATTRIBUTE_NONE); | |
383 | |
384 network_infos.push_back(NetworkInterfaceInfo(network_info)); | |
385 } | |
386 } | |
387 freeifaddrs(interfaces); | |
388 #if !defined(OS_IOS) | |
389 if (ioctl_socket >= 0) { | |
390 close(ioctl_socket); | |
391 } | |
392 #endif | |
393 | |
394 if (policy & INCLUDE_ONLY_TEMP_IPV6_ADDRESS_IF_POSSIBLE) { | |
395 RemovePermanentIPv6AddressesWhereTemporaryExists(&network_infos); | |
396 } | |
397 | |
398 for (size_t i = 0; i < network_infos.size(); ++i) { | |
399 networks->push_back(network_infos[i].interface); | |
400 } | |
401 return true; | |
402 #endif | |
403 } | 65 } |
| 66 #endif // OS_NACL |
404 | 67 |
405 WifiPHYLayerProtocol GetWifiPHYLayerProtocol() { | 68 WifiPHYLayerProtocol GetWifiPHYLayerProtocol() { |
406 return WIFI_PHY_LAYER_PROTOCOL_UNKNOWN; | 69 return WIFI_PHY_LAYER_PROTOCOL_UNKNOWN; |
407 } | 70 } |
408 | 71 |
409 scoped_ptr<ScopedWifiOptions> SetWifiOptions(int options) { | 72 scoped_ptr<ScopedWifiOptions> SetWifiOptions(int options) { |
410 return scoped_ptr<ScopedWifiOptions>(); | 73 return scoped_ptr<ScopedWifiOptions>(); |
411 } | 74 } |
412 | 75 |
413 | 76 |
414 } // namespace net | 77 } // namespace net |
OLD | NEW |