1 // Copyright 2017 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.
4
5 #include "net/base/network_interfaces_getifaddrs.h"
6
7 #include <ifaddrs.h>
8 #include <net/if.h>
9 #include <netinet/in.h>
10 #include <sys/types.h>
11
12 #include <memory>
13 #include <set>
14
15 #include "base/files/file_path.h"
16 #include "base/logging.h"
17 #include "base/posix/eintr_wrapper.h"
18 #include "base/strings/string_number_conversions.h"
19 #include "base/strings/string_tokenizer.h"
20 #include "base/strings/string_util.h"
21 #include "base/threading/scoped_blocking_call.h"
22 #include "build/build_config.h"
23 #include "net/base/ip_endpoint.h"
24 #include "net/base/net_errors.h"
25 #include "net/base/network_interfaces_posix.h"
26
27 #if defined(OS_MACOSX) && !defined(OS_IOS)
28 #include <net/if_media.h>
29 #include <netinet/in_var.h>
30 #include <sys/ioctl.h>
31 #endif // !OS_IOS
32
33 namespace net {
34 namespace internal {
35
36 #if defined(OS_MACOSX) && !defined(OS_IOS)
37
38 // MacOSX implementation of IPAttributesGetter which calls ioctl() on socket to
39 // retrieve IP attributes.
40 class IPAttributesGetterMac : public internal::IPAttributesGetter {
41 public:
42 IPAttributesGetterMac();
43 ~IPAttributesGetterMac() override;
44 bool IsInitialized() const override;
45 bool GetAddressAttributes(const ifaddrs* if_addr, int* attributes) override;
46 NetworkChangeNotifier::ConnectionType GetNetworkInterfaceType(
47 const ifaddrs* if_addr) override;
48
49 private:
50 int ioctl_socket_;
51 };
52
IPAttributesGetterMac()53 IPAttributesGetterMac::IPAttributesGetterMac()
54 : ioctl_socket_(socket(AF_INET6, SOCK_DGRAM, 0)) {
55 DCHECK_GE(ioctl_socket_, 0);
56 }
57
~IPAttributesGetterMac()58 IPAttributesGetterMac::~IPAttributesGetterMac() {
59 if (IsInitialized()) {
60 PCHECK(IGNORE_EINTR(close(ioctl_socket_)) == 0);
61 }
62 }
63
IsInitialized() const64 bool IPAttributesGetterMac::IsInitialized() const {
65 return ioctl_socket_ >= 0;
66 }
67
AddressFlagsToNetAddressAttributes(int flags)68 int AddressFlagsToNetAddressAttributes(int flags) {
69 int result = 0;
70 if (flags & IN6_IFF_TEMPORARY) {
71 result |= IP_ADDRESS_ATTRIBUTE_TEMPORARY;
72 }
73 if (flags & IN6_IFF_DEPRECATED) {
74 result |= IP_ADDRESS_ATTRIBUTE_DEPRECATED;
75 }
76 if (flags & IN6_IFF_ANYCAST) {
77 result |= IP_ADDRESS_ATTRIBUTE_ANYCAST;
78 }
79 if (flags & IN6_IFF_TENTATIVE) {
80 result |= IP_ADDRESS_ATTRIBUTE_TENTATIVE;
81 }
82 if (flags & IN6_IFF_DUPLICATED) {
83 result |= IP_ADDRESS_ATTRIBUTE_DUPLICATED;
84 }
85 if (flags & IN6_IFF_DETACHED) {
86 result |= IP_ADDRESS_ATTRIBUTE_DETACHED;
87 }
88 return result;
89 }
90
GetAddressAttributes(const ifaddrs * if_addr,int * attributes)91 bool IPAttributesGetterMac::GetAddressAttributes(const ifaddrs* if_addr,
92 int* attributes) {
93 struct in6_ifreq ifr = {};
94 strncpy(ifr.ifr_name, if_addr->ifa_name, sizeof(ifr.ifr_name) - 1);
95 memcpy(&ifr.ifr_ifru.ifru_addr, if_addr->ifa_addr, if_addr->ifa_addr->sa_len);
96 int rv = ioctl(ioctl_socket_, SIOCGIFAFLAG_IN6, &ifr);
97 if (rv >= 0) {
98 *attributes = AddressFlagsToNetAddressAttributes(ifr.ifr_ifru.ifru_flags);
99 }
100 return (rv >= 0);
101 }
102
103 NetworkChangeNotifier::ConnectionType
GetNetworkInterfaceType(const ifaddrs * if_addr)104 IPAttributesGetterMac::GetNetworkInterfaceType(const ifaddrs* if_addr) {
105 if (!IsInitialized())
106 return NetworkChangeNotifier::CONNECTION_UNKNOWN;
107
108 struct ifmediareq ifmr = {};
109 strncpy(ifmr.ifm_name, if_addr->ifa_name, sizeof(ifmr.ifm_name) - 1);
110
111 if (ioctl(ioctl_socket_, SIOCGIFMEDIA, &ifmr) != -1) {
112 if (ifmr.ifm_current & IFM_IEEE80211) {
113 return NetworkChangeNotifier::CONNECTION_WIFI;
114 }
115 if (ifmr.ifm_current & IFM_ETHER) {
116 return NetworkChangeNotifier::CONNECTION_ETHERNET;
117 }
118 }
119
120 return NetworkChangeNotifier::CONNECTION_UNKNOWN;
121 }
122
123 #endif // defined(OS_MACOSX) && !defined(OS_IOS)
124
IfaddrsToNetworkInterfaceList(int policy,const ifaddrs * interfaces,IPAttributesGetter * ip_attributes_getter,NetworkInterfaceList * networks)125 bool IfaddrsToNetworkInterfaceList(int policy,
126 const ifaddrs* interfaces,
127 IPAttributesGetter* ip_attributes_getter,
128 NetworkInterfaceList* networks) {
129 // Enumerate the addresses assigned to network interfaces which are up.
130 for (const ifaddrs* interface = interfaces; interface != NULL;
131 interface = interface->ifa_next) {
132 // Skip loopback interfaces, and ones which are down.
133 if (!(IFF_RUNNING & interface->ifa_flags))
134 continue;
135 if (IFF_LOOPBACK & interface->ifa_flags)
136 continue;
137 // Skip interfaces with no address configured.
138 struct sockaddr* addr = interface->ifa_addr;
139 if (!addr)
140 continue;
141
142 // Skip unspecified addresses (i.e. made of zeroes) and loopback addresses
143 // configured on non-loopback interfaces.
144 if (IsLoopbackOrUnspecifiedAddress(addr))
145 continue;
146
147 std::string name = interface->ifa_name;
148 // Filter out VMware interfaces, typically named vmnet1 and vmnet8.
149 if (ShouldIgnoreInterface(name, policy)) {
150 continue;
151 }
152
153 NetworkChangeNotifier::ConnectionType connection_type =
154 NetworkChangeNotifier::CONNECTION_UNKNOWN;
155
156 int ip_attributes = IP_ADDRESS_ATTRIBUTE_NONE;
157
158 // Retrieve native ip attributes and convert to net version if a getter is
159 // given.
160 if (ip_attributes_getter && ip_attributes_getter->IsInitialized()) {
161 if (addr->sa_family == AF_INET6 &&
162 ip_attributes_getter->GetAddressAttributes(interface,
163 &ip_attributes)) {
164 // Disallow addresses with attributes ANYCASE, DUPLICATED, TENTATIVE,
165 // and DETACHED as these are still progressing through duplicated
166 // address detection (DAD) or are not suitable to be used in an
167 // one-to-one communication and shouldn't be used by the application
168 // layer.
169 if (ip_attributes &
170 (IP_ADDRESS_ATTRIBUTE_ANYCAST | IP_ADDRESS_ATTRIBUTE_DUPLICATED |
171 IP_ADDRESS_ATTRIBUTE_TENTATIVE | IP_ADDRESS_ATTRIBUTE_DETACHED)) {
172 continue;
173 }
174 }
175
176 connection_type =
177 ip_attributes_getter->GetNetworkInterfaceType(interface);
178 }
179
180 IPEndPoint address;
181
182 int addr_size = 0;
183 if (addr->sa_family == AF_INET6) {
184 addr_size = sizeof(sockaddr_in6);
185 } else if (addr->sa_family == AF_INET) {
186 addr_size = sizeof(sockaddr_in);
187 }
188
189 if (address.FromSockAddr(addr, addr_size)) {
190 uint8_t prefix_length = 0;
191 if (interface->ifa_netmask) {
192 // If not otherwise set, assume the same sa_family as ifa_addr.
193 if (interface->ifa_netmask->sa_family == 0) {
194 interface->ifa_netmask->sa_family = addr->sa_family;
195 }
196 IPEndPoint netmask;
197 if (netmask.FromSockAddr(interface->ifa_netmask, addr_size)) {
198 prefix_length = MaskPrefixLength(netmask.address());
199 }
200 }
201 networks->push_back(NetworkInterface(
202 name, name, if_nametoindex(name.c_str()), connection_type,
203 address.address(), prefix_length, ip_attributes));
204 }
205 }
206
207 return true;
208 }
209
210 } // namespace internal
211
GetNetworkList(NetworkInterfaceList * networks,int policy)212 bool GetNetworkList(NetworkInterfaceList* networks, int policy) {
213 if (networks == NULL)
214 return false;
215
216 // getifaddrs() may require IO operations.
217 base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
218 base::BlockingType::MAY_BLOCK);
219
220 ifaddrs* interfaces;
221 if (getifaddrs(&interfaces) < 0) {
222 PLOG(ERROR) << "getifaddrs";
223 return false;
224 }
225
226 std::unique_ptr<internal::IPAttributesGetter> ip_attributes_getter;
227
228 #if defined(OS_MACOSX) && !defined(OS_IOS)
229 ip_attributes_getter = std::make_unique<internal::IPAttributesGetterMac>();
230 #endif
231
232 bool result = internal::IfaddrsToNetworkInterfaceList(
233 policy, interfaces, ip_attributes_getter.get(), networks);
234 freeifaddrs(interfaces);
235 return result;
236 }
237
GetWifiSSID()238 std::string GetWifiSSID() {
239 NOTIMPLEMENTED();
240 return std::string();
241 }
242
243 } // namespace net
244