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"
9 #include <netinet/in.h>
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"
28 #include <net/if_media.h>
29 #include <netinet/in_var.h>
30 #include <sys/ioctl.h>
39 // MacOSX implementation of IPAttributesGetterMac which calls ioctl on socket to
40 // retrieve IP attributes.
41 class IPAttributesGetterMacImpl
: public internal::IPAttributesGetterMac
{
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
;
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) {
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
);
77 *native_attributes
= ifr
.ifr_ifru
.ifru_flags
;
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
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
)) {
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
;
109 NetworkChangeNotifier::ConnectionType
GetNetworkInterfaceType(
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);
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
;
139 bool GetNetworkListImpl(NetworkInterfaceList
* networks
,
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
))
149 if (IFF_LOOPBACK
& interface
->ifa_flags
)
151 // Skip interfaces with no address configured.
152 struct sockaddr
* addr
= interface
->ifa_addr
;
156 // Skip unspecified addresses (i.e. made of zeroes) and loopback addresses
157 // configured on non-loopback interfaces.
158 if (IsLoopbackOrUnspecifiedAddress(addr
))
161 const std::string
& name
= interface
->ifa_name
;
162 // Filter out VMware interfaces, typically named vmnet1 and vmnet8.
163 if (ShouldIgnoreInterface(name
, policy
)) {
167 NetworkChangeNotifier::ConnectionType connection_type
=
168 NetworkChangeNotifier::CONNECTION_UNKNOWN
;
170 int ip_attributes
= IP_ADDRESS_ATTRIBUTE_NONE
;
173 // Retrieve native ip attributes and convert to net version if a getter is
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
,
187 connection_type
= GetNetworkInterfaceType(addr
->sa_family
, name
);
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
;
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
));
220 } // namespace internal
222 bool GetNetworkList(NetworkInterfaceList
* networks
, int policy
) {
223 if (networks
== NULL
)
226 // getifaddrs() may require IO operations.
227 base::ThreadRestrictions::AssertIOAllowed();
230 if (getifaddrs(&interfaces
) < 0) {
231 PLOG(ERROR
) << "getifaddrs";
235 scoped_ptr
<internal::IPAttributesGetterMac
> ip_attributes_getter
;
238 ip_attributes_getter
.reset(new IPAttributesGetterMacImpl());
241 bool result
= internal::GetNetworkListImpl(networks
, policy
, interfaces
,
242 ip_attributes_getter
.get());
243 freeifaddrs(interfaces
);
247 std::string
GetWifiSSID() {