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_linux.h" | |
6 | |
7 #if !defined(OS_ANDROID) | |
8 #include <linux/ethtool.h> | |
9 #endif // !defined(OS_ANDROID) | |
10 #include <linux/if.h> | |
11 #include <linux/sockios.h> | |
12 #include <linux/wireless.h> | |
13 #include <set> | |
14 #include <sys/ioctl.h> | |
15 #include <sys/types.h> | |
16 | |
17 #include "base/files/file_path.h" | |
18 #include "base/files/scoped_file.h" | |
19 #include "base/logging.h" | |
20 #include "base/memory/scoped_ptr.h" | |
21 #include "base/strings/string_number_conversions.h" | |
22 #include "base/strings/string_tokenizer.h" | |
23 #include "base/strings/string_util.h" | |
24 #include "base/threading/thread_restrictions.h" | |
25 #include "net/base/address_tracker_linux.h" | |
26 #include "net/base/escape.h" | |
27 #include "net/base/ip_endpoint.h" | |
28 #include "net/base/net_errors.h" | |
29 #include "net/base/net_util_posix.h" | |
30 #include "url/gurl.h" | |
31 | |
32 namespace net { | |
33 | |
34 namespace { | |
35 | |
36 // When returning true, the platform native IPv6 address attributes were | |
37 // successfully converted to net IP address attributes. Otherwise, returning | |
38 // false and the caller should drop the IP address which can't be used by the | |
39 // application layer. | |
40 bool TryConvertNativeToNetIPAttributes(int native_attributes, | |
41 int* net_attributes) { | |
42 // For Linux/ChromeOS/Android, we disallow addresses with attributes | |
43 // IFA_F_OPTIMISTIC, IFA_F_DADFAILED, and IFA_F_TENTATIVE as these | |
44 // are still progressing through duplicated address detection (DAD) | |
45 // and shouldn't be used by the application layer until DAD process | |
46 // is completed. | |
47 if (native_attributes & ( | |
48 #if !defined(OS_ANDROID) | |
49 IFA_F_OPTIMISTIC | IFA_F_DADFAILED | | |
50 #endif // !OS_ANDROID | |
51 IFA_F_TENTATIVE)) { | |
52 return false; | |
53 } | |
54 | |
55 if (native_attributes & IFA_F_TEMPORARY) { | |
56 *net_attributes |= IP_ADDRESS_ATTRIBUTE_TEMPORARY; | |
57 } | |
58 | |
59 if (native_attributes & IFA_F_DEPRECATED) { | |
60 *net_attributes |= IP_ADDRESS_ATTRIBUTE_DEPRECATED; | |
61 } | |
62 | |
63 return true; | |
64 } | |
65 | |
66 } // namespace | |
67 | |
68 namespace internal { | |
69 | |
70 inline const unsigned char* GetIPAddressData(const IPAddressNumber& ip) { | |
71 #if defined(OS_ANDROID) | |
72 return ip.begin(); | |
73 #else | |
74 return ip.data(); | |
75 #endif | |
76 } | |
77 | |
78 // Gets the connection type for interface |ifname| by checking for wireless | |
79 // or ethtool extensions. | |
80 NetworkChangeNotifier::ConnectionType GetInterfaceConnectionType( | |
81 const std::string& ifname) { | |
82 base::ScopedFD s(socket(AF_INET, SOCK_STREAM, 0)); | |
83 if (!s.is_valid()) | |
84 return NetworkChangeNotifier::CONNECTION_UNKNOWN; | |
85 | |
86 // Test wireless extensions for CONNECTION_WIFI | |
87 struct iwreq pwrq = {}; | |
88 strncpy(pwrq.ifr_name, ifname.c_str(), IFNAMSIZ - 1); | |
89 if (ioctl(s.get(), SIOCGIWNAME, &pwrq) != -1) | |
90 return NetworkChangeNotifier::CONNECTION_WIFI; | |
91 | |
92 #if !defined(OS_ANDROID) | |
93 // Test ethtool for CONNECTION_ETHERNET | |
94 struct ethtool_cmd ecmd = {}; | |
95 ecmd.cmd = ETHTOOL_GSET; | |
96 struct ifreq ifr = {}; | |
97 ifr.ifr_data = &ecmd; | |
98 strncpy(ifr.ifr_name, ifname.c_str(), IFNAMSIZ - 1); | |
99 if (ioctl(s.get(), SIOCETHTOOL, &ifr) != -1) | |
100 return NetworkChangeNotifier::CONNECTION_ETHERNET; | |
101 #endif // !defined(OS_ANDROID) | |
102 | |
103 return NetworkChangeNotifier::CONNECTION_UNKNOWN; | |
104 } | |
105 | |
106 std::string GetInterfaceSSID(const std::string& ifname) { | |
107 base::ScopedFD ioctl_socket(socket(AF_INET, SOCK_DGRAM, 0)); | |
108 if (!ioctl_socket.is_valid()) | |
109 return ""; | |
110 struct iwreq wreq = {}; | |
111 strncpy(wreq.ifr_name, ifname.c_str(), IFNAMSIZ - 1); | |
112 | |
113 char ssid[IW_ESSID_MAX_SIZE + 1] = {0}; | |
114 wreq.u.essid.pointer = ssid; | |
115 wreq.u.essid.length = IW_ESSID_MAX_SIZE; | |
116 if (ioctl(ioctl_socket.get(), SIOCGIWESSID, &wreq) != -1) | |
117 return ssid; | |
118 return ""; | |
119 } | |
120 | |
121 bool GetNetworkListImpl( | |
122 NetworkInterfaceList* networks, | |
123 int policy, | |
124 const base::hash_set<int>& online_links, | |
125 const internal::AddressTrackerLinux::AddressMap& address_map, | |
126 GetInterfaceNameFunction get_interface_name) { | |
127 std::map<int, std::string> ifnames; | |
128 | |
129 for (internal::AddressTrackerLinux::AddressMap::const_iterator it = | |
130 address_map.begin(); | |
131 it != address_map.end(); ++it) { | |
132 // Ignore addresses whose links are not online. | |
133 if (online_links.find(it->second.ifa_index) == online_links.end()) | |
134 continue; | |
135 | |
136 sockaddr_storage sock_addr; | |
137 socklen_t sock_len = sizeof(sockaddr_storage); | |
138 | |
139 // Convert to sockaddr for next check. | |
140 if (!IPEndPoint(it->first, 0) | |
141 .ToSockAddr(reinterpret_cast<sockaddr*>(&sock_addr), &sock_len)) { | |
142 continue; | |
143 } | |
144 | |
145 // Skip unspecified addresses (i.e. made of zeroes) and loopback addresses | |
146 if (IsLoopbackOrUnspecifiedAddress(reinterpret_cast<sockaddr*>(&sock_addr))) | |
147 continue; | |
148 | |
149 int ip_attributes = IP_ADDRESS_ATTRIBUTE_NONE; | |
150 | |
151 if (it->second.ifa_family == AF_INET6) { | |
152 // Ignore addresses whose attributes are not actionable by | |
153 // the application layer. | |
154 if (!TryConvertNativeToNetIPAttributes(it->second.ifa_flags, | |
155 &ip_attributes)) | |
156 continue; | |
157 } | |
158 | |
159 // Find the name of this link. | |
160 std::map<int, std::string>::const_iterator itname = | |
161 ifnames.find(it->second.ifa_index); | |
162 std::string ifname; | |
163 if (itname == ifnames.end()) { | |
164 char buffer[IFNAMSIZ] = {0}; | |
165 ifname.assign(get_interface_name(it->second.ifa_index, buffer)); | |
166 // Ignore addresses whose interface name can't be retrieved. | |
167 if (ifname.empty()) | |
168 continue; | |
169 ifnames[it->second.ifa_index] = ifname; | |
170 } else { | |
171 ifname = itname->second; | |
172 } | |
173 | |
174 // Based on the interface name and policy, determine whether we | |
175 // should ignore it. | |
176 if (ShouldIgnoreInterface(ifname, policy)) | |
177 continue; | |
178 | |
179 NetworkChangeNotifier::ConnectionType type = | |
180 GetInterfaceConnectionType(ifname); | |
181 | |
182 networks->push_back( | |
183 NetworkInterface(ifname, ifname, it->second.ifa_index, type, it->first, | |
184 it->second.ifa_prefixlen, ip_attributes)); | |
185 } | |
186 | |
187 return true; | |
188 } | |
189 | |
190 std::string GetWifiSSIDFromInterfaceListInternal( | |
191 const NetworkInterfaceList& interfaces, | |
192 internal::GetInterfaceSSIDFunction get_interface_ssid) { | |
193 std::string connected_ssid; | |
194 for (size_t i = 0; i < interfaces.size(); ++i) { | |
195 if (interfaces[i].type != NetworkChangeNotifier::CONNECTION_WIFI) | |
196 return ""; | |
197 std::string ssid = get_interface_ssid(interfaces[i].name); | |
198 if (i == 0) { | |
199 connected_ssid = ssid; | |
200 } else if (ssid != connected_ssid) { | |
201 return ""; | |
202 } | |
203 } | |
204 return connected_ssid; | |
205 } | |
206 | |
207 } // namespace internal | |
208 | |
209 bool GetNetworkList(NetworkInterfaceList* networks, int policy) { | |
210 if (networks == NULL) | |
211 return false; | |
212 | |
213 internal::AddressTrackerLinux tracker; | |
214 tracker.Init(); | |
215 | |
216 return internal::GetNetworkListImpl( | |
217 networks, policy, tracker.GetOnlineLinks(), tracker.GetAddressMap(), | |
218 &internal::AddressTrackerLinux::GetInterfaceName); | |
219 } | |
220 | |
221 std::string GetWifiSSID() { | |
222 NetworkInterfaceList networks; | |
223 if (GetNetworkList(&networks, net::INCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES)) { | |
224 return internal::GetWifiSSIDFromInterfaceListInternal( | |
225 networks, internal::GetInterfaceSSID); | |
226 } | |
227 return ""; | |
228 } | |
229 | |
230 } // namespace net | |
OLD | NEW |