Add connectivity check for Android feedback.
[chromium-blink-merge.git] / net / base / net_util_linux.cc
blob2e28b7d24bb302f089c965cba5523cec07be9b4e
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/net_util_linux.h"
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>
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"
32 namespace net {
34 namespace {
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;
55 if (native_attributes & IFA_F_TEMPORARY) {
56 *net_attributes |= IP_ADDRESS_ATTRIBUTE_TEMPORARY;
59 if (native_attributes & IFA_F_DEPRECATED) {
60 *net_attributes |= IP_ADDRESS_ATTRIBUTE_DEPRECATED;
63 return true;
66 } // namespace
68 namespace internal {
70 inline const unsigned char* GetIPAddressData(const IPAddressNumber& ip) {
71 return ip.data();
74 // Gets the connection type for interface |ifname| by checking for wireless
75 // or ethtool extensions.
76 NetworkChangeNotifier::ConnectionType GetInterfaceConnectionType(
77 const std::string& ifname) {
78 base::ScopedFD s(socket(AF_INET, SOCK_STREAM, 0));
79 if (!s.is_valid())
80 return NetworkChangeNotifier::CONNECTION_UNKNOWN;
82 // Test wireless extensions for CONNECTION_WIFI
83 struct iwreq pwrq = {};
84 strncpy(pwrq.ifr_name, ifname.c_str(), IFNAMSIZ - 1);
85 if (ioctl(s.get(), SIOCGIWNAME, &pwrq) != -1)
86 return NetworkChangeNotifier::CONNECTION_WIFI;
88 #if !defined(OS_ANDROID)
89 // Test ethtool for CONNECTION_ETHERNET
90 struct ethtool_cmd ecmd = {};
91 ecmd.cmd = ETHTOOL_GSET;
92 struct ifreq ifr = {};
93 ifr.ifr_data = &ecmd;
94 strncpy(ifr.ifr_name, ifname.c_str(), IFNAMSIZ - 1);
95 if (ioctl(s.get(), SIOCETHTOOL, &ifr) != -1)
96 return NetworkChangeNotifier::CONNECTION_ETHERNET;
97 #endif // !defined(OS_ANDROID)
99 return NetworkChangeNotifier::CONNECTION_UNKNOWN;
102 std::string GetInterfaceSSID(const std::string& ifname) {
103 base::ScopedFD ioctl_socket(socket(AF_INET, SOCK_DGRAM, 0));
104 if (!ioctl_socket.is_valid())
105 return "";
106 struct iwreq wreq = {};
107 strncpy(wreq.ifr_name, ifname.c_str(), IFNAMSIZ - 1);
109 char ssid[IW_ESSID_MAX_SIZE + 1] = {0};
110 wreq.u.essid.pointer = ssid;
111 wreq.u.essid.length = IW_ESSID_MAX_SIZE;
112 if (ioctl(ioctl_socket.get(), SIOCGIWESSID, &wreq) != -1)
113 return ssid;
114 return "";
117 bool GetNetworkListImpl(
118 NetworkInterfaceList* networks,
119 int policy,
120 const base::hash_set<int>& online_links,
121 const internal::AddressTrackerLinux::AddressMap& address_map,
122 GetInterfaceNameFunction get_interface_name) {
123 std::map<int, std::string> ifnames;
125 for (internal::AddressTrackerLinux::AddressMap::const_iterator it =
126 address_map.begin();
127 it != address_map.end(); ++it) {
128 // Ignore addresses whose links are not online.
129 if (online_links.find(it->second.ifa_index) == online_links.end())
130 continue;
132 sockaddr_storage sock_addr;
133 socklen_t sock_len = sizeof(sockaddr_storage);
135 // Convert to sockaddr for next check.
136 if (!IPEndPoint(it->first, 0)
137 .ToSockAddr(reinterpret_cast<sockaddr*>(&sock_addr), &sock_len)) {
138 continue;
141 // Skip unspecified addresses (i.e. made of zeroes) and loopback addresses
142 if (IsLoopbackOrUnspecifiedAddress(reinterpret_cast<sockaddr*>(&sock_addr)))
143 continue;
145 int ip_attributes = IP_ADDRESS_ATTRIBUTE_NONE;
147 if (it->second.ifa_family == AF_INET6) {
148 // Ignore addresses whose attributes are not actionable by
149 // the application layer.
150 if (!TryConvertNativeToNetIPAttributes(it->second.ifa_flags,
151 &ip_attributes))
152 continue;
155 // Find the name of this link.
156 std::map<int, std::string>::const_iterator itname =
157 ifnames.find(it->second.ifa_index);
158 std::string ifname;
159 if (itname == ifnames.end()) {
160 char buffer[IFNAMSIZ] = {0};
161 ifname.assign(get_interface_name(it->second.ifa_index, buffer));
162 // Ignore addresses whose interface name can't be retrieved.
163 if (ifname.empty())
164 continue;
165 ifnames[it->second.ifa_index] = ifname;
166 } else {
167 ifname = itname->second;
170 // Based on the interface name and policy, determine whether we
171 // should ignore it.
172 if (ShouldIgnoreInterface(ifname, policy))
173 continue;
175 NetworkChangeNotifier::ConnectionType type =
176 GetInterfaceConnectionType(ifname);
178 networks->push_back(
179 NetworkInterface(ifname, ifname, it->second.ifa_index, type, it->first,
180 it->second.ifa_prefixlen, ip_attributes));
183 return true;
186 std::string GetWifiSSIDFromInterfaceListInternal(
187 const NetworkInterfaceList& interfaces,
188 internal::GetInterfaceSSIDFunction get_interface_ssid) {
189 std::string connected_ssid;
190 for (size_t i = 0; i < interfaces.size(); ++i) {
191 if (interfaces[i].type != NetworkChangeNotifier::CONNECTION_WIFI)
192 return "";
193 std::string ssid = get_interface_ssid(interfaces[i].name);
194 if (i == 0) {
195 connected_ssid = ssid;
196 } else if (ssid != connected_ssid) {
197 return "";
200 return connected_ssid;
203 } // namespace internal
205 bool GetNetworkList(NetworkInterfaceList* networks, int policy) {
206 if (networks == NULL)
207 return false;
209 internal::AddressTrackerLinux tracker;
210 tracker.Init();
212 return internal::GetNetworkListImpl(
213 networks, policy, tracker.GetOnlineLinks(), tracker.GetAddressMap(),
214 &internal::AddressTrackerLinux::GetInterfaceName);
217 std::string GetWifiSSID() {
218 NetworkInterfaceList networks;
219 if (GetNetworkList(&networks, INCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES)) {
220 return internal::GetWifiSSIDFromInterfaceListInternal(
221 networks, internal::GetInterfaceSSID);
223 return "";
226 } // namespace net