PlzNavigate: Improvements to RFHM commit logic.
[chromium-blink-merge.git] / net / base / net_util_linux.cc
blob8342597032d567c57d723de2f9cfdad16ae97c6a
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 #if defined(OS_ANDROID)
72 return ip.begin();
73 #else
74 return ip.data();
75 #endif
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;
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;
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)
103 return NetworkChangeNotifier::CONNECTION_UNKNOWN;
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);
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 "";
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;
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;
136 sockaddr_storage sock_addr;
137 socklen_t sock_len = sizeof(sockaddr_storage);
139 // Convert to sockaddr for next check.
140 if (!IPEndPoint(it->first, 0)
141 .ToSockAddr(reinterpret_cast<sockaddr*>(&sock_addr), &sock_len)) {
142 continue;
145 // Skip unspecified addresses (i.e. made of zeroes) and loopback addresses
146 if (IsLoopbackOrUnspecifiedAddress(reinterpret_cast<sockaddr*>(&sock_addr)))
147 continue;
149 int ip_attributes = IP_ADDRESS_ATTRIBUTE_NONE;
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;
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;
174 // Based on the interface name and policy, determine whether we
175 // should ignore it.
176 if (ShouldIgnoreInterface(ifname, policy))
177 continue;
179 NetworkChangeNotifier::ConnectionType type =
180 GetInterfaceConnectionType(ifname);
182 networks->push_back(
183 NetworkInterface(ifname, ifname, it->second.ifa_index, type, it->first,
184 it->second.ifa_prefixlen, ip_attributes));
187 return true;
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 "";
204 return connected_ssid;
207 } // namespace internal
209 bool GetNetworkList(NetworkInterfaceList* networks, int policy) {
210 if (networks == NULL)
211 return false;
213 internal::AddressTrackerLinux tracker;
214 tracker.Init();
216 return internal::GetNetworkListImpl(
217 networks, policy, tracker.GetOnlineLinks(), tracker.GetAddressMap(),
218 &internal::AddressTrackerLinux::GetInterfaceName);
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);
227 return "";
230 } // namespace net