Roll src/third_party/WebKit d9c6159:8139f33 (svn 201974:201975)
[chromium-blink-merge.git] / net / base / network_interfaces_mac.cc
blob8176c6c377540fe2777c19c69abd58b395e22689
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/network_interfaces_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.h"
24 #include "net/base/network_interfaces_posix.h"
25 #include "url/gurl.h"
27 #if !defined(OS_IOS)
28 #include <net/if_media.h>
29 #include <netinet/in_var.h>
30 #include <sys/ioctl.h>
31 #endif // !OS_IOS
33 namespace net {
35 namespace {
37 #if !defined(OS_IOS)
39 // MacOSX implementation of IPAttributesGetterMac which calls ioctl on socket to
40 // retrieve IP attributes.
41 class IPAttributesGetterMacImpl : public internal::IPAttributesGetterMac {
42 public:
43 IPAttributesGetterMacImpl();
44 ~IPAttributesGetterMacImpl() override;
45 bool IsInitialized() const override;
46 bool GetIPAttributes(const char* ifname,
47 const sockaddr* sock_addr,
48 int* native_attributes) override;
50 private:
51 int ioctl_socket_;
54 IPAttributesGetterMacImpl::IPAttributesGetterMacImpl()
55 : ioctl_socket_(socket(AF_INET6, SOCK_DGRAM, 0)) {
56 DCHECK_GE(ioctl_socket_, 0);
59 bool IPAttributesGetterMacImpl::IsInitialized() const {
60 return ioctl_socket_ >= 0;
63 IPAttributesGetterMacImpl::~IPAttributesGetterMacImpl() {
64 if (ioctl_socket_ >= 0) {
65 close(ioctl_socket_);
69 bool IPAttributesGetterMacImpl::GetIPAttributes(const char* ifname,
70 const sockaddr* sock_addr,
71 int* native_attributes) {
72 struct in6_ifreq ifr = {};
73 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name) - 1);
74 memcpy(&ifr.ifr_ifru.ifru_addr, sock_addr, sock_addr->sa_len);
75 int rv = ioctl(ioctl_socket_, SIOCGIFAFLAG_IN6, &ifr);
76 if (rv >= 0) {
77 *native_attributes = ifr.ifr_ifru.ifru_flags;
79 return (rv >= 0);
82 // When returning true, the platform native IPv6 address attributes were
83 // successfully converted to net IP address attributes. Otherwise, returning
84 // false and the caller should drop the IP address which can't be used by the
85 // application layer.
86 bool TryConvertNativeToNetIPAttributes(int native_attributes,
87 int* net_attributes) {
88 // For MacOSX, we disallow addresses with attributes IN6_IFF_ANYCASE,
89 // IN6_IFF_DUPLICATED, IN6_IFF_TENTATIVE, and IN6_IFF_DETACHED as these are
90 // still progressing through duplicated address detection (DAD) or are not
91 // suitable to be used in an one-to-one communication and shouldn't be used
92 // by the application layer.
93 if (native_attributes & (IN6_IFF_ANYCAST | IN6_IFF_DUPLICATED |
94 IN6_IFF_TENTATIVE | IN6_IFF_DETACHED)) {
95 return false;
98 if (native_attributes & IN6_IFF_TEMPORARY) {
99 *net_attributes |= IP_ADDRESS_ATTRIBUTE_TEMPORARY;
102 if (native_attributes & IN6_IFF_DEPRECATED) {
103 *net_attributes |= IP_ADDRESS_ATTRIBUTE_DEPRECATED;
106 return true;
109 NetworkChangeNotifier::ConnectionType GetNetworkInterfaceType(
110 int addr_family,
111 const std::string& interface_name) {
112 NetworkChangeNotifier::ConnectionType type =
113 NetworkChangeNotifier::CONNECTION_UNKNOWN;
115 struct ifmediareq ifmr = {};
116 strncpy(ifmr.ifm_name, interface_name.c_str(), sizeof(ifmr.ifm_name) - 1);
118 int s = socket(addr_family, SOCK_DGRAM, 0);
119 if (s == -1) {
120 return type;
123 if (ioctl(s, SIOCGIFMEDIA, &ifmr) != -1) {
124 if (ifmr.ifm_current & IFM_IEEE80211) {
125 type = NetworkChangeNotifier::CONNECTION_WIFI;
126 } else if (ifmr.ifm_current & IFM_ETHER) {
127 type = NetworkChangeNotifier::CONNECTION_ETHERNET;
130 close(s);
131 return type;
134 #endif // !OS_IOS
135 } // namespace
137 namespace internal {
139 bool GetNetworkListImpl(NetworkInterfaceList* networks,
140 int policy,
141 const ifaddrs* interfaces,
142 IPAttributesGetterMac* ip_attributes_getter) {
143 // Enumerate the addresses assigned to network interfaces which are up.
144 for (const ifaddrs* interface = interfaces; interface != NULL;
145 interface = interface->ifa_next) {
146 // Skip loopback interfaces, and ones which are down.
147 if (!(IFF_RUNNING & interface->ifa_flags))
148 continue;
149 if (IFF_LOOPBACK & interface->ifa_flags)
150 continue;
151 // Skip interfaces with no address configured.
152 struct sockaddr* addr = interface->ifa_addr;
153 if (!addr)
154 continue;
156 // Skip unspecified addresses (i.e. made of zeroes) and loopback addresses
157 // configured on non-loopback interfaces.
158 if (IsLoopbackOrUnspecifiedAddress(addr))
159 continue;
161 const std::string& name = interface->ifa_name;
162 // Filter out VMware interfaces, typically named vmnet1 and vmnet8.
163 if (ShouldIgnoreInterface(name, policy)) {
164 continue;
167 NetworkChangeNotifier::ConnectionType connection_type =
168 NetworkChangeNotifier::CONNECTION_UNKNOWN;
170 int ip_attributes = IP_ADDRESS_ATTRIBUTE_NONE;
172 #if !defined(OS_IOS)
173 // Retrieve native ip attributes and convert to net version if a getter is
174 // given.
175 if (ip_attributes_getter && ip_attributes_getter->IsInitialized()) {
176 int native_attributes = 0;
177 if (addr->sa_family == AF_INET6 &&
178 ip_attributes_getter->GetIPAttributes(
179 interface->ifa_name, interface->ifa_addr, &native_attributes)) {
180 if (!TryConvertNativeToNetIPAttributes(native_attributes,
181 &ip_attributes)) {
182 continue;
187 connection_type = GetNetworkInterfaceType(addr->sa_family, name);
188 #endif // !OS_IOS
190 IPEndPoint address;
192 int addr_size = 0;
193 if (addr->sa_family == AF_INET6) {
194 addr_size = sizeof(sockaddr_in6);
195 } else if (addr->sa_family == AF_INET) {
196 addr_size = sizeof(sockaddr_in);
199 if (address.FromSockAddr(addr, addr_size)) {
200 uint8_t prefix_length = 0;
201 if (interface->ifa_netmask) {
202 // If not otherwise set, assume the same sa_family as ifa_addr.
203 if (interface->ifa_netmask->sa_family == 0) {
204 interface->ifa_netmask->sa_family = addr->sa_family;
206 IPEndPoint netmask;
207 if (netmask.FromSockAddr(interface->ifa_netmask, addr_size)) {
208 prefix_length = MaskPrefixLength(netmask.address());
211 networks->push_back(NetworkInterface(
212 name, name, if_nametoindex(name.c_str()), connection_type,
213 address.address(), prefix_length, ip_attributes));
217 return true;
220 } // namespace internal
222 bool GetNetworkList(NetworkInterfaceList* networks, int policy) {
223 if (networks == NULL)
224 return false;
226 // getifaddrs() may require IO operations.
227 base::ThreadRestrictions::AssertIOAllowed();
229 ifaddrs* interfaces;
230 if (getifaddrs(&interfaces) < 0) {
231 PLOG(ERROR) << "getifaddrs";
232 return false;
235 scoped_ptr<internal::IPAttributesGetterMac> ip_attributes_getter;
237 #if !defined(OS_IOS)
238 ip_attributes_getter.reset(new IPAttributesGetterMacImpl());
239 #endif
241 bool result = internal::GetNetworkListImpl(networks, policy, interfaces,
242 ip_attributes_getter.get());
243 freeifaddrs(interfaces);
244 return result;
247 std::string GetWifiSSID() {
248 NOTIMPLEMENTED();
249 return "";
252 } // namespace net