OLD | NEW |
| (Empty) |
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. | |
4 | |
5 #include "net/base/net_util_mac.h" | |
6 | |
7 #include <ifaddrs.h> | |
8 #include <net/if.h> | |
9 #include <netinet/in.h> | |
10 #include <set> | |
11 #include <sys/types.h> | |
12 | |
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" | |
25 | |
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 | |
31 | |
32 namespace net { | |
33 | |
34 namespace { | |
35 | |
36 #if !defined(OS_IOS) | |
37 | |
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; | |
48 | |
49 private: | |
50 int ioctl_socket_; | |
51 }; | |
52 | |
53 IPAttributesGetterMacImpl::IPAttributesGetterMacImpl() | |
54 : ioctl_socket_(socket(AF_INET6, SOCK_DGRAM, 0)) { | |
55 DCHECK_GE(ioctl_socket_, 0); | |
56 } | |
57 | |
58 bool IPAttributesGetterMacImpl::IsInitialized() const { | |
59 return ioctl_socket_ >= 0; | |
60 } | |
61 | |
62 IPAttributesGetterMacImpl::~IPAttributesGetterMacImpl() { | |
63 if (ioctl_socket_ >= 0) { | |
64 close(ioctl_socket_); | |
65 } | |
66 } | |
67 | |
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; | |
77 } | |
78 return (rv >= 0); | |
79 } | |
80 | |
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; | |
95 } | |
96 | |
97 if (native_attributes & IN6_IFF_TEMPORARY) { | |
98 *net_attributes |= IP_ADDRESS_ATTRIBUTE_TEMPORARY; | |
99 } | |
100 | |
101 if (native_attributes & IN6_IFF_DEPRECATED) { | |
102 *net_attributes |= IP_ADDRESS_ATTRIBUTE_DEPRECATED; | |
103 } | |
104 | |
105 return true; | |
106 } | |
107 | |
108 NetworkChangeNotifier::ConnectionType GetNetworkInterfaceType( | |
109 int addr_family, | |
110 const std::string& interface_name) { | |
111 NetworkChangeNotifier::ConnectionType type = | |
112 NetworkChangeNotifier::CONNECTION_UNKNOWN; | |
113 | |
114 struct ifmediareq ifmr = {}; | |
115 strncpy(ifmr.ifm_name, interface_name.c_str(), sizeof(ifmr.ifm_name) - 1); | |
116 | |
117 int s = socket(addr_family, SOCK_DGRAM, 0); | |
118 if (s == -1) { | |
119 return type; | |
120 } | |
121 | |
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; | |
127 } | |
128 } | |
129 close(s); | |
130 return type; | |
131 } | |
132 | |
133 #endif // !OS_IOS | |
134 } // namespace | |
135 | |
136 namespace internal { | |
137 | |
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; | |
154 | |
155 // Skip unspecified addresses (i.e. made of zeroes) and loopback addresses | |
156 // configured on non-loopback interfaces. | |
157 if (IsLoopbackOrUnspecifiedAddress(addr)) | |
158 continue; | |
159 | |
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; | |
164 } | |
165 | |
166 NetworkChangeNotifier::ConnectionType connection_type = | |
167 NetworkChangeNotifier::CONNECTION_UNKNOWN; | |
168 | |
169 int ip_attributes = IP_ADDRESS_ATTRIBUTE_NONE; | |
170 | |
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; | |
182 } | |
183 } | |
184 } | |
185 | |
186 connection_type = GetNetworkInterfaceType(addr->sa_family, name); | |
187 #endif // !OS_IOS | |
188 | |
189 IPEndPoint address; | |
190 | |
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); | |
196 } | |
197 | |
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; | |
204 } | |
205 IPEndPoint netmask; | |
206 if (netmask.FromSockAddr(interface->ifa_netmask, addr_size)) { | |
207 prefix_length = MaskPrefixLength(netmask.address()); | |
208 } | |
209 } | |
210 networks->push_back(NetworkInterface( | |
211 name, name, if_nametoindex(name.c_str()), connection_type, | |
212 address.address(), prefix_length, ip_attributes)); | |
213 } | |
214 } | |
215 | |
216 return true; | |
217 } | |
218 | |
219 } // namespace internal | |
220 | |
221 bool GetNetworkList(NetworkInterfaceList* networks, int policy) { | |
222 if (networks == NULL) | |
223 return false; | |
224 | |
225 // getifaddrs() may require IO operations. | |
226 base::ThreadRestrictions::AssertIOAllowed(); | |
227 | |
228 ifaddrs* interfaces; | |
229 if (getifaddrs(&interfaces) < 0) { | |
230 PLOG(ERROR) << "getifaddrs"; | |
231 return false; | |
232 } | |
233 | |
234 scoped_ptr<internal::IPAttributesGetterMac> ip_attributes_getter; | |
235 | |
236 #if !defined(OS_IOS) | |
237 ip_attributes_getter.reset(new IPAttributesGetterMacImpl()); | |
238 #endif | |
239 | |
240 bool result = internal::GetNetworkListImpl(networks, policy, interfaces, | |
241 ip_attributes_getter.get()); | |
242 freeifaddrs(interfaces); | |
243 return result; | |
244 } | |
245 | |
246 std::string GetWifiSSID() { | |
247 NOTIMPLEMENTED(); | |
248 return ""; | |
249 } | |
250 | |
251 } // namespace net | |
OLD | NEW |