Index: net/base/net_util_linux.cc |
diff --git a/net/base/net_util_linux.cc b/net/base/net_util_linux.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..e4e0f7f3277e9110cb944ea0714ea9136f36ea18 |
--- /dev/null |
+++ b/net/base/net_util_linux.cc |
@@ -0,0 +1,154 @@ |
+// Copyright (c) 2014 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "net/base/net_util_linux.h" |
+ |
+#include <net/if.h> |
+#include <netinet/in.h> |
+#include <set> |
+#include <sys/types.h> |
+ |
+#include "base/files/file_path.h" |
+#include "base/logging.h" |
+#include "base/memory/scoped_ptr.h" |
+#include "base/strings/string_number_conversions.h" |
+#include "base/strings/string_tokenizer.h" |
+#include "base/strings/string_util.h" |
+#include "base/threading/thread_restrictions.h" |
+#include "net/base/address_tracker_linux.h" |
+#include "net/base/escape.h" |
+#include "net/base/ip_endpoint.h" |
+#include "net/base/net_errors.h" |
+#include "net/base/net_util_posix.h" |
+#include "url/gurl.h" |
+ |
+namespace net { |
+ |
+namespace { |
+ |
+// When returning true, the platform native IPv6 address attributes were |
+// successfully converted to net IP address attributes. Otherwise, returning |
+// false and the caller should drop the IP address which can't be used by the |
+// application layer. |
+bool TryConvertNativeToNetIPAttributes(int native_attributes, |
+ int* net_attributes) { |
+ // For Linux/ChromeOS/Android, we disallow addresses with attributes |
+ // IFA_F_OPTIMISTIC, IFA_F_DADFAILED, and IFA_F_TENTATIVE as these |
+ // are still progressing through duplicated address detection (DAD) |
+ // and shouldn't be used by the application layer until DAD process |
+ // is completed. |
+ if (native_attributes & ( |
+#if !defined(OS_ANDROID) |
+ IFA_F_OPTIMISTIC | IFA_F_DADFAILED | |
+#endif // !OS_ANDROID |
+ IFA_F_TENTATIVE)) { |
+ return false; |
+ } |
+ |
+ if (native_attributes & IFA_F_TEMPORARY) { |
+ *net_attributes |= IP_ADDRESS_ATTRIBUTE_TEMPORARY; |
+ } |
+ |
+ if (native_attributes & IFA_F_DEPRECATED) { |
+ *net_attributes |= IP_ADDRESS_ATTRIBUTE_DEPRECATED; |
+ } |
+ |
+ return true; |
+} |
+ |
+} // namespace |
+ |
+namespace internal { |
+ |
+inline const unsigned char* GetIPAddressData(const IPAddressNumber& ip) { |
+#if defined(OS_ANDROID) |
+ return ip.begin(); |
+#else |
+ return ip.data(); |
+#endif |
+} |
+ |
+bool GetNetworkListImpl( |
+ NetworkInterfaceList* networks, |
+ int policy, |
+ const base::hash_set<int>& online_links, |
+ const internal::AddressTrackerLinux::AddressMap& address_map, |
+ GetInterfaceNameFunction get_interface_name) { |
+ std::map<int, std::string> ifnames; |
+ |
+ for (internal::AddressTrackerLinux::AddressMap::const_iterator it = |
+ address_map.begin(); |
+ it != address_map.end(); ++it) { |
+ // Ignore addresses whose links are not online. |
+ if (online_links.find(it->second.ifa_index) == online_links.end()) |
+ continue; |
+ |
+ sockaddr_storage sock_addr; |
+ socklen_t sock_len = sizeof(sockaddr_storage); |
+ |
+ // Convert to sockaddr for next check. |
+ if (!IPEndPoint(it->first, 0) |
+ .ToSockAddr(reinterpret_cast<sockaddr*>(&sock_addr), &sock_len)) { |
+ continue; |
+ } |
+ |
+ // Skip unspecified addresses (i.e. made of zeroes) and loopback addresses |
+ if (IsLoopbackOrUnspecifiedAddress(reinterpret_cast<sockaddr*>(&sock_addr))) |
+ continue; |
+ |
+ int ip_attributes = IP_ADDRESS_ATTRIBUTE_NONE; |
+ |
+ if (it->second.ifa_family == AF_INET6) { |
+ // Ignore addresses whose attributes are not actionable by |
+ // the application layer. |
+ if (!TryConvertNativeToNetIPAttributes(it->second.ifa_flags, |
+ &ip_attributes)) |
+ continue; |
+ } |
+ |
+ // Find the name of this link. |
+ std::map<int, std::string>::const_iterator itname = |
+ ifnames.find(it->second.ifa_index); |
+ std::string ifname; |
+ if (itname == ifnames.end()) { |
+ char buffer[IF_NAMESIZE] = {0}; |
+ if (get_interface_name(it->second.ifa_index, buffer)) { |
+ ifname = ifnames[it->second.ifa_index] = buffer; |
+ } else { |
+ // Ignore addresses whose interface name can't be retrieved. |
+ continue; |
+ } |
+ } else { |
+ ifname = itname->second; |
+ } |
+ |
+ // Based on the interface name and policy, determine whether we |
+ // should ignore it. |
+ if (ShouldIgnoreInterface(ifname, policy)) |
+ continue; |
+ |
+ networks->push_back( |
+ NetworkInterface(ifname, ifname, it->second.ifa_index, |
+ NetworkChangeNotifier::CONNECTION_UNKNOWN, it->first, |
+ it->second.ifa_prefixlen, ip_attributes)); |
+ } |
+ |
+ return true; |
+} |
+ |
+} // namespace internal |
+ |
+bool GetNetworkList(NetworkInterfaceList* networks, int policy) { |
+ if (networks == NULL) |
+ return false; |
+ |
+ internal::AddressTrackerLinux tracker; |
+ tracker.Init(); |
+ |
+ return internal::GetNetworkListImpl(networks, policy, |
+ tracker.GetOnlineLinks(), |
+ tracker.GetAddressMap(), &if_indextoname); |
+} |
+ |
+} // namespace net |