| Index: net/base/net_util_posix.cc
|
| diff --git a/net/base/net_util_posix.cc b/net/base/net_util_posix.cc
|
| index 73704cde69de5b5697acf1a5d621a5d880d5c1da..a2fa6cdf2ce7c1c871c4415911fe04c6b2d51602 100644
|
| --- a/net/base/net_util_posix.cc
|
| +++ b/net/base/net_util_posix.cc
|
| @@ -19,11 +19,16 @@
|
| #include "net/base/net_errors.h"
|
| #include "url/gurl.h"
|
|
|
| -#if !defined(OS_ANDROID) && !defined(OS_NACL)
|
| +#if !defined(OS_NACL)
|
| +#if defined(OS_MACOSX)
|
| #include <ifaddrs.h>
|
| +#else
|
| +#include "net/base/address_tracker_linux.h"
|
| +#include "net/base/net_util_posix.h"
|
| +#endif // OS_MACOSX
|
| #include <net/if.h>
|
| #include <netinet/in.h>
|
| -#endif
|
| +#endif // !defined(OS_NACL)
|
|
|
| #if defined(OS_MACOSX) && !defined(OS_IOS)
|
| #include <net/if_media.h>
|
| @@ -31,15 +36,48 @@
|
| #include <sys/ioctl.h>
|
| #endif
|
|
|
| -#if defined(OS_ANDROID)
|
| -#include "net/android/network_library.h"
|
| -#endif
|
| -
|
| namespace net {
|
|
|
| namespace {
|
|
|
| -#if !defined(OS_ANDROID)
|
| +// The application layer can pass |policy| defined in net_util.h to
|
| +// request filtering out certain type of interfaces.
|
| +bool ShouldIgnoreInterface(const std::string& name, int policy) {
|
| + // Filter out VMware interfaces, typically named vmnet1 and vmnet8,
|
| + // which might not be useful for use cases like WebRTC.
|
| + if ((policy & EXCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES) &&
|
| + ((name.find("vmnet") != std::string::npos) ||
|
| + (name.find("vnic") != std::string::npos))) {
|
| + return true;
|
| + }
|
| +
|
| + return false;
|
| +}
|
| +
|
| +// Check if the address is unspecified (i.e. made of zeroes) or loopback.
|
| +bool IsLoopbackOrUnspecifiedAddress(const sockaddr* addr) {
|
| + if (addr->sa_family == AF_INET6) {
|
| + const struct sockaddr_in6* addr_in6 =
|
| + reinterpret_cast<const struct sockaddr_in6*>(addr);
|
| + const struct in6_addr* sin6_addr = &addr_in6->sin6_addr;
|
| + if (IN6_IS_ADDR_LOOPBACK(sin6_addr) || IN6_IS_ADDR_UNSPECIFIED(sin6_addr)) {
|
| + return true;
|
| + }
|
| + } else if (addr->sa_family == AF_INET) {
|
| + const struct sockaddr_in* addr_in =
|
| + reinterpret_cast<const struct sockaddr_in*>(addr);
|
| + if (addr_in->sin_addr.s_addr == INADDR_LOOPBACK ||
|
| + addr_in->sin_addr.s_addr == 0) {
|
| + return true;
|
| + }
|
| + } else {
|
| + // Skip non-IP addresses.
|
| + return true;
|
| + }
|
| + return false;
|
| +}
|
| +
|
| +#if defined(OS_MACOSX)
|
|
|
| struct NetworkInterfaceInfo {
|
| NetworkInterfaceInfo() : permanent(true) { }
|
| @@ -83,10 +121,7 @@ void RemovePermanentIPv6AddressesWhereTemporaryExists(
|
| }
|
| }
|
|
|
| -#endif
|
| -
|
| -#if defined(OS_MACOSX) && !defined(OS_IOS)
|
| -
|
| +#if !defined(OS_IOS)
|
| NetworkChangeNotifier::ConnectionType GetNetworkInterfaceType(
|
| int addr_family, const std::string& interface_name) {
|
| NetworkChangeNotifier::ConnectionType type =
|
| @@ -111,50 +146,151 @@ NetworkChangeNotifier::ConnectionType GetNetworkInterfaceType(
|
| return type;
|
| }
|
|
|
| -#endif
|
| +#endif // !defined(OS_IOS)
|
| +#elif !defined(OS_NACL) // OS_MACOSX
|
| +
|
| +// Convert platform native IPv6 address attributes to net IP address
|
| +// attributes and drop ones that 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;
|
| +}
|
| +#endif // OS_MACOSX
|
| } // namespace
|
|
|
| -bool GetNetworkList(NetworkInterfaceList* networks, int policy) {
|
| -#if defined(OS_NACL)
|
| - NOTIMPLEMENTED();
|
| - return false;
|
| -#elif defined(OS_ANDROID)
|
| - std::string network_list = android::GetNetworkList();
|
| - base::StringTokenizer network_interfaces(network_list, "\n");
|
| - while (network_interfaces.GetNext()) {
|
| - std::string network_item = network_interfaces.token();
|
| - base::StringTokenizer network_tokenizer(network_item, "\t");
|
| - CHECK(network_tokenizer.GetNext());
|
| - std::string name = network_tokenizer.token();
|
| -
|
| - CHECK(network_tokenizer.GetNext());
|
| - std::string interface_address = network_tokenizer.token();
|
| - IPAddressNumber address;
|
| - size_t network_prefix = 0;
|
| - CHECK(ParseCIDRBlock(network_tokenizer.token(),
|
| - &address,
|
| - &network_prefix));
|
| -
|
| - CHECK(network_tokenizer.GetNext());
|
| - uint32 index = 0;
|
| - CHECK(base::StringToUint(network_tokenizer.token(), &index));
|
| +namespace internal {
|
| +
|
| +#if !defined(OS_MACOSX) && !defined(OS_NACL)
|
| +
|
| +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(name,
|
| - name,
|
| - index,
|
| + NetworkInterface(ifname,
|
| + ifname,
|
| + it->second.ifa_index,
|
| NetworkChangeNotifier::CONNECTION_UNKNOWN,
|
| - address,
|
| - network_prefix,
|
| - IP_ADDRESS_ATTRIBUTE_NONE));
|
| + it->first,
|
| + it->second.ifa_prefixlen,
|
| + ip_attributes));
|
| }
|
| +
|
| return true;
|
| -#else
|
| +}
|
| +#endif
|
| +
|
| +} // namespace internal
|
| +
|
| +bool GetNetworkList(NetworkInterfaceList* networks, int policy) {
|
| + if (networks == NULL)
|
| + return false;
|
| +#if defined(OS_NACL)
|
| + NOTIMPLEMENTED();
|
| + return false;
|
| +#elif !defined(OS_MACOSX)
|
| +
|
| + internal::AddressTrackerLinux tracker;
|
| + tracker.Init();
|
| +
|
| + return internal::GetNetworkListImpl(networks,
|
| + policy,
|
| + tracker.GetOnlineLinks(),
|
| + tracker.GetAddressMap(),
|
| + &if_indextoname);
|
| +
|
| +#else // Only OS_MACOSX and OS_IOS will run the code below
|
| +
|
| // getifaddrs() may require IO operations.
|
| base::ThreadRestrictions::AssertIOAllowed();
|
|
|
| -#if defined(OS_MACOSX) && !defined(OS_IOS)
|
| +#if !defined(OS_IOS)
|
| int ioctl_socket = -1;
|
| if (policy & INCLUDE_ONLY_TEMP_IPV6_ADDRESS_IF_POSSIBLE) {
|
| // we need a socket to query information about temporary address.
|
| @@ -163,7 +299,7 @@ bool GetNetworkList(NetworkInterfaceList* networks, int policy) {
|
| }
|
| #endif
|
|
|
| - ifaddrs *interfaces;
|
| + ifaddrs* interfaces;
|
| if (getifaddrs(&interfaces) < 0) {
|
| PLOG(ERROR) << "getifaddrs";
|
| return false;
|
| @@ -187,41 +323,26 @@ bool GetNetworkList(NetworkInterfaceList* networks, int policy) {
|
|
|
| // Skip unspecified addresses (i.e. made of zeroes) and loopback addresses
|
| // configured on non-loopback interfaces.
|
| + if (IsLoopbackOrUnspecifiedAddress(addr))
|
| + continue;
|
| +
|
| int addr_size = 0;
|
| if (addr->sa_family == AF_INET6) {
|
| - struct sockaddr_in6* addr_in6 =
|
| - reinterpret_cast<struct sockaddr_in6*>(addr);
|
| - struct in6_addr* sin6_addr = &addr_in6->sin6_addr;
|
| - addr_size = sizeof(*addr_in6);
|
| - if (IN6_IS_ADDR_LOOPBACK(sin6_addr) ||
|
| - IN6_IS_ADDR_UNSPECIFIED(sin6_addr)) {
|
| - continue;
|
| - }
|
| + addr_size = sizeof(sockaddr_in6);
|
| } else if (addr->sa_family == AF_INET) {
|
| - struct sockaddr_in* addr_in =
|
| - reinterpret_cast<struct sockaddr_in*>(addr);
|
| - addr_size = sizeof(*addr_in);
|
| - if (addr_in->sin_addr.s_addr == INADDR_LOOPBACK ||
|
| - addr_in->sin_addr.s_addr == 0) {
|
| - continue;
|
| - }
|
| - } else {
|
| - // Skip non-IP addresses.
|
| - continue;
|
| + addr_size = sizeof(sockaddr_in);
|
| }
|
|
|
| const std::string& name = interface->ifa_name;
|
| // Filter out VMware interfaces, typically named vmnet1 and vmnet8.
|
| - if ((policy & EXCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES) &&
|
| - ((name.find("vmnet") != std::string::npos) ||
|
| - (name.find("vnic") != std::string::npos))) {
|
| + if (ShouldIgnoreInterface(name, policy)) {
|
| continue;
|
| }
|
|
|
| NetworkInterfaceInfo network_info;
|
| NetworkChangeNotifier::ConnectionType connection_type =
|
| NetworkChangeNotifier::CONNECTION_UNKNOWN;
|
| -#if defined(OS_MACOSX) && !defined(OS_IOS)
|
| +#if !defined(OS_IOS)
|
| // Check if this is a temporary address. Currently this is only supported
|
| // on Mac.
|
| if ((policy & INCLUDE_ONLY_TEMP_IPV6_ADDRESS_IF_POSSIBLE) &&
|
| @@ -264,7 +385,7 @@ bool GetNetworkList(NetworkInterfaceList* networks, int policy) {
|
| }
|
| }
|
| freeifaddrs(interfaces);
|
| -#if defined(OS_MACOSX) && !defined(OS_IOS)
|
| +#if !defined(OS_IOS)
|
| if (ioctl_socket >= 0) {
|
| close(ioctl_socket);
|
| }
|
|
|