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/network_interfaces_linux.h"
7 #if !defined(OS_ANDROID)
8 #include <linux/ethtool.h>
9 #endif // !defined(OS_ANDROID)
11 #include <linux/sockios.h>
12 #include <linux/wireless.h>
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.h"
30 #include "net/base/network_interfaces_posix.h"
37 // When returning true, the platform native IPv6 address attributes were
38 // successfully converted to net IP address attributes. Otherwise, returning
39 // false and the caller should drop the IP address which can't be used by the
41 bool TryConvertNativeToNetIPAttributes(int native_attributes
,
42 int* net_attributes
) {
43 // For Linux/ChromeOS/Android, we disallow addresses with attributes
44 // IFA_F_OPTIMISTIC, IFA_F_DADFAILED, and IFA_F_TENTATIVE as these
45 // are still progressing through duplicated address detection (DAD)
46 // and shouldn't be used by the application layer until DAD process
48 if (native_attributes
& (
49 #if !defined(OS_ANDROID)
50 IFA_F_OPTIMISTIC
| IFA_F_DADFAILED
|
56 if (native_attributes
& IFA_F_TEMPORARY
) {
57 *net_attributes
|= IP_ADDRESS_ATTRIBUTE_TEMPORARY
;
60 if (native_attributes
& IFA_F_DEPRECATED
) {
61 *net_attributes
|= IP_ADDRESS_ATTRIBUTE_DEPRECATED
;
71 inline const unsigned char* GetIPAddressData(const IPAddressNumber
& ip
) {
75 // Gets the connection type for interface |ifname| by checking for wireless
76 // or ethtool extensions.
77 NetworkChangeNotifier::ConnectionType
GetInterfaceConnectionType(
78 const std::string
& ifname
) {
79 base::ScopedFD
s(socket(AF_INET
, SOCK_STREAM
, 0));
81 return NetworkChangeNotifier::CONNECTION_UNKNOWN
;
83 // Test wireless extensions for CONNECTION_WIFI
84 struct iwreq pwrq
= {};
85 strncpy(pwrq
.ifr_name
, ifname
.c_str(), IFNAMSIZ
- 1);
86 if (ioctl(s
.get(), SIOCGIWNAME
, &pwrq
) != -1)
87 return NetworkChangeNotifier::CONNECTION_WIFI
;
89 #if !defined(OS_ANDROID)
90 // Test ethtool for CONNECTION_ETHERNET
91 struct ethtool_cmd ecmd
= {};
92 ecmd
.cmd
= ETHTOOL_GSET
;
93 struct ifreq ifr
= {};
95 strncpy(ifr
.ifr_name
, ifname
.c_str(), IFNAMSIZ
- 1);
96 if (ioctl(s
.get(), SIOCETHTOOL
, &ifr
) != -1)
97 return NetworkChangeNotifier::CONNECTION_ETHERNET
;
98 #endif // !defined(OS_ANDROID)
100 return NetworkChangeNotifier::CONNECTION_UNKNOWN
;
103 std::string
GetInterfaceSSID(const std::string
& ifname
) {
104 base::ScopedFD
ioctl_socket(socket(AF_INET
, SOCK_DGRAM
, 0));
105 if (!ioctl_socket
.is_valid())
107 struct iwreq wreq
= {};
108 strncpy(wreq
.ifr_name
, ifname
.c_str(), IFNAMSIZ
- 1);
110 char ssid
[IW_ESSID_MAX_SIZE
+ 1] = {0};
111 wreq
.u
.essid
.pointer
= ssid
;
112 wreq
.u
.essid
.length
= IW_ESSID_MAX_SIZE
;
113 if (ioctl(ioctl_socket
.get(), SIOCGIWESSID
, &wreq
) != -1)
118 bool GetNetworkListImpl(
119 NetworkInterfaceList
* networks
,
121 const base::hash_set
<int>& online_links
,
122 const internal::AddressTrackerLinux::AddressMap
& address_map
,
123 GetInterfaceNameFunction get_interface_name
) {
124 std::map
<int, std::string
> ifnames
;
126 for (internal::AddressTrackerLinux::AddressMap::const_iterator it
=
128 it
!= address_map
.end(); ++it
) {
129 // Ignore addresses whose links are not online.
130 if (online_links
.find(it
->second
.ifa_index
) == online_links
.end())
133 sockaddr_storage sock_addr
;
134 socklen_t sock_len
= sizeof(sockaddr_storage
);
136 // Convert to sockaddr for next check.
137 if (!IPEndPoint(it
->first
, 0)
138 .ToSockAddr(reinterpret_cast<sockaddr
*>(&sock_addr
), &sock_len
)) {
142 // Skip unspecified addresses (i.e. made of zeroes) and loopback addresses
143 if (IsLoopbackOrUnspecifiedAddress(reinterpret_cast<sockaddr
*>(&sock_addr
)))
146 int ip_attributes
= IP_ADDRESS_ATTRIBUTE_NONE
;
148 if (it
->second
.ifa_family
== AF_INET6
) {
149 // Ignore addresses whose attributes are not actionable by
150 // the application layer.
151 if (!TryConvertNativeToNetIPAttributes(it
->second
.ifa_flags
,
156 // Find the name of this link.
157 std::map
<int, std::string
>::const_iterator itname
=
158 ifnames
.find(it
->second
.ifa_index
);
160 if (itname
== ifnames
.end()) {
161 char buffer
[IFNAMSIZ
] = {0};
162 ifname
.assign(get_interface_name(it
->second
.ifa_index
, buffer
));
163 // Ignore addresses whose interface name can't be retrieved.
166 ifnames
[it
->second
.ifa_index
] = ifname
;
168 ifname
= itname
->second
;
171 // Based on the interface name and policy, determine whether we
173 if (ShouldIgnoreInterface(ifname
, policy
))
176 NetworkChangeNotifier::ConnectionType type
=
177 GetInterfaceConnectionType(ifname
);
180 NetworkInterface(ifname
, ifname
, it
->second
.ifa_index
, type
, it
->first
,
181 it
->second
.ifa_prefixlen
, ip_attributes
));
187 std::string
GetWifiSSIDFromInterfaceListInternal(
188 const NetworkInterfaceList
& interfaces
,
189 internal::GetInterfaceSSIDFunction get_interface_ssid
) {
190 std::string connected_ssid
;
191 for (size_t i
= 0; i
< interfaces
.size(); ++i
) {
192 if (interfaces
[i
].type
!= NetworkChangeNotifier::CONNECTION_WIFI
)
194 std::string ssid
= get_interface_ssid(interfaces
[i
].name
);
196 connected_ssid
= ssid
;
197 } else if (ssid
!= connected_ssid
) {
201 return connected_ssid
;
204 } // namespace internal
206 bool GetNetworkList(NetworkInterfaceList
* networks
, int policy
) {
207 if (networks
== NULL
)
210 internal::AddressTrackerLinux tracker
;
213 return internal::GetNetworkListImpl(
214 networks
, policy
, tracker
.GetOnlineLinks(), tracker
.GetAddressMap(),
215 &internal::AddressTrackerLinux::GetInterfaceName
);
218 std::string
GetWifiSSID() {
219 NetworkInterfaceList networks
;
220 if (GetNetworkList(&networks
, INCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES
)) {
221 return internal::GetWifiSSIDFromInterfaceListInternal(
222 networks
, internal::GetInterfaceSSID
);