Roll src/third_party/WebKit 8121bc6:918aba1 (svn 188871:188878)
[chromium-blink-merge.git] / net / base / net_util_mac.cc
blob5dd46307789b37f7b17593970d643a88924e7809
1 // Copyright (c) 2014 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.
5 #include "net/base/net_util_mac.h"
7 #include <ifaddrs.h>
8 #include <net/if.h>
9 #include <netinet/in.h>
10 #include <set>
11 #include <sys/types.h>
13 #include "base/files/file_path.h"
14 #include "base/logging.h"
15 #include "base/memory/scoped_ptr.h"
16 #include "base/strings/string_number_conversions.h"
17 #include "base/strings/string_tokenizer.h"
18 #include "base/strings/string_util.h"
19 #include "base/threading/thread_restrictions.h"
20 #include "net/base/escape.h"
21 #include "net/base/ip_endpoint.h"
22 #include "net/base/net_errors.h"
23 #include "net/base/net_util_posix.h"
24 #include "url/gurl.h"
26 #if !defined(OS_IOS)
27 #include <net/if_media.h>
28 #include <netinet/in_var.h>
29 #include <sys/ioctl.h>
30 #endif // !OS_IOS
32 namespace net {
34 namespace {
36 #if !defined(OS_IOS)
38 // MacOSX implementation of IPAttributesGetterMac which calls ioctl on socket to
39 // retrieve IP attributes.
40 class IPAttributesGetterMacImpl : public internal::IPAttributesGetterMac {
41 public:
42 IPAttributesGetterMacImpl();
43 ~IPAttributesGetterMacImpl() override;
44 bool IsInitialized() const override;
45 bool GetIPAttributes(const char* ifname,
46 const sockaddr* sock_addr,
47 int* native_attributes) override;
49 private:
50 int ioctl_socket_;
53 IPAttributesGetterMacImpl::IPAttributesGetterMacImpl()
54 : ioctl_socket_(socket(AF_INET6, SOCK_DGRAM, 0)) {
55 DCHECK_GE(ioctl_socket_, 0);
58 bool IPAttributesGetterMacImpl::IsInitialized() const {
59 return ioctl_socket_ >= 0;
62 IPAttributesGetterMacImpl::~IPAttributesGetterMacImpl() {
63 if (ioctl_socket_ >= 0) {
64 close(ioctl_socket_);
68 bool IPAttributesGetterMacImpl::GetIPAttributes(const char* ifname,
69 const sockaddr* sock_addr,
70 int* native_attributes) {
71 struct in6_ifreq ifr = {};
72 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name) - 1);
73 memcpy(&ifr.ifr_ifru.ifru_addr, sock_addr, sock_addr->sa_len);
74 int rv = ioctl(ioctl_socket_, SIOCGIFAFLAG_IN6, &ifr);
75 if (rv >= 0) {
76 *native_attributes = ifr.ifr_ifru.ifru_flags;
78 return (rv >= 0);
81 // When returning true, the platform native IPv6 address attributes were
82 // successfully converted to net IP address attributes. Otherwise, returning
83 // false and the caller should drop the IP address which can't be used by the
84 // application layer.
85 bool TryConvertNativeToNetIPAttributes(int native_attributes,
86 int* net_attributes) {
87 // For MacOSX, we disallow addresses with attributes IN6_IFF_ANYCASE,
88 // IN6_IFF_DUPLICATED, IN6_IFF_TENTATIVE, and IN6_IFF_DETACHED as these are
89 // still progressing through duplicated address detection (DAD) or are not
90 // suitable to be used in an one-to-one communication and shouldn't be used
91 // by the application layer.
92 if (native_attributes & (IN6_IFF_ANYCAST | IN6_IFF_DUPLICATED |
93 IN6_IFF_TENTATIVE | IN6_IFF_DETACHED)) {
94 return false;
97 if (native_attributes & IN6_IFF_TEMPORARY) {
98 *net_attributes |= IP_ADDRESS_ATTRIBUTE_TEMPORARY;
101 if (native_attributes & IN6_IFF_DEPRECATED) {
102 *net_attributes |= IP_ADDRESS_ATTRIBUTE_DEPRECATED;
105 return true;
108 NetworkChangeNotifier::ConnectionType GetNetworkInterfaceType(
109 int addr_family,
110 const std::string& interface_name) {
111 NetworkChangeNotifier::ConnectionType type =
112 NetworkChangeNotifier::CONNECTION_UNKNOWN;
114 struct ifmediareq ifmr = {};
115 strncpy(ifmr.ifm_name, interface_name.c_str(), sizeof(ifmr.ifm_name) - 1);
117 int s = socket(addr_family, SOCK_DGRAM, 0);
118 if (s == -1) {
119 return type;
122 if (ioctl(s, SIOCGIFMEDIA, &ifmr) != -1) {
123 if (ifmr.ifm_current & IFM_IEEE80211) {
124 type = NetworkChangeNotifier::CONNECTION_WIFI;
125 } else if (ifmr.ifm_current & IFM_ETHER) {
126 type = NetworkChangeNotifier::CONNECTION_ETHERNET;
129 close(s);
130 return type;
133 #endif // !OS_IOS
134 } // namespace
136 namespace internal {
138 bool GetNetworkListImpl(NetworkInterfaceList* networks,
139 int policy,
140 const ifaddrs* interfaces,
141 IPAttributesGetterMac* ip_attributes_getter) {
142 // Enumerate the addresses assigned to network interfaces which are up.
143 for (const ifaddrs* interface = interfaces; interface != NULL;
144 interface = interface->ifa_next) {
145 // Skip loopback interfaces, and ones which are down.
146 if (!(IFF_RUNNING & interface->ifa_flags))
147 continue;
148 if (IFF_LOOPBACK & interface->ifa_flags)
149 continue;
150 // Skip interfaces with no address configured.
151 struct sockaddr* addr = interface->ifa_addr;
152 if (!addr)
153 continue;
155 // Skip unspecified addresses (i.e. made of zeroes) and loopback addresses
156 // configured on non-loopback interfaces.
157 if (IsLoopbackOrUnspecifiedAddress(addr))
158 continue;
160 const std::string& name = interface->ifa_name;
161 // Filter out VMware interfaces, typically named vmnet1 and vmnet8.
162 if (ShouldIgnoreInterface(name, policy)) {
163 continue;
166 NetworkChangeNotifier::ConnectionType connection_type =
167 NetworkChangeNotifier::CONNECTION_UNKNOWN;
169 int ip_attributes = IP_ADDRESS_ATTRIBUTE_NONE;
171 #if !defined(OS_IOS)
172 // Retrieve native ip attributes and convert to net version if a getter is
173 // given.
174 if (ip_attributes_getter && ip_attributes_getter->IsInitialized()) {
175 int native_attributes = 0;
176 if (addr->sa_family == AF_INET6 &&
177 ip_attributes_getter->GetIPAttributes(
178 interface->ifa_name, interface->ifa_addr, &native_attributes)) {
179 if (!TryConvertNativeToNetIPAttributes(native_attributes,
180 &ip_attributes)) {
181 continue;
186 connection_type = GetNetworkInterfaceType(addr->sa_family, name);
187 #endif // !OS_IOS
189 IPEndPoint address;
191 int addr_size = 0;
192 if (addr->sa_family == AF_INET6) {
193 addr_size = sizeof(sockaddr_in6);
194 } else if (addr->sa_family == AF_INET) {
195 addr_size = sizeof(sockaddr_in);
198 if (address.FromSockAddr(addr, addr_size)) {
199 uint8 prefix_length = 0;
200 if (interface->ifa_netmask) {
201 // If not otherwise set, assume the same sa_family as ifa_addr.
202 if (interface->ifa_netmask->sa_family == 0) {
203 interface->ifa_netmask->sa_family = addr->sa_family;
205 IPEndPoint netmask;
206 if (netmask.FromSockAddr(interface->ifa_netmask, addr_size)) {
207 prefix_length = MaskPrefixLength(netmask.address());
210 networks->push_back(NetworkInterface(
211 name, name, if_nametoindex(name.c_str()), connection_type,
212 address.address(), prefix_length, ip_attributes));
216 return true;
219 } // namespace internal
221 bool GetNetworkList(NetworkInterfaceList* networks, int policy) {
222 if (networks == NULL)
223 return false;
225 // getifaddrs() may require IO operations.
226 base::ThreadRestrictions::AssertIOAllowed();
228 ifaddrs* interfaces;
229 if (getifaddrs(&interfaces) < 0) {
230 PLOG(ERROR) << "getifaddrs";
231 return false;
234 scoped_ptr<internal::IPAttributesGetterMac> ip_attributes_getter;
236 #if !defined(OS_IOS)
237 ip_attributes_getter.reset(new IPAttributesGetterMacImpl());
238 #endif
240 bool result = internal::GetNetworkListImpl(networks, policy, interfaces,
241 ip_attributes_getter.get());
242 freeifaddrs(interfaces);
243 return result;
246 } // namespace net