diff options
Diffstat (limited to 'chromium/net/base/net_util_posix.cc')
-rw-r--r-- | chromium/net/base/net_util_posix.cc | 177 |
1 files changed, 142 insertions, 35 deletions
diff --git a/chromium/net/base/net_util_posix.cc b/chromium/net/base/net_util_posix.cc index 5e1042b4304..315e9ed1a23 100644 --- a/chromium/net/base/net_util_posix.cc +++ b/chromium/net/base/net_util_posix.cc @@ -4,6 +4,7 @@ #include "net/base/net_util.h" +#include <set> #include <sys/types.h> #include "base/files/file_path.h" @@ -17,11 +18,17 @@ #include "net/base/net_errors.h" #include "url/gurl.h" -#if !defined(OS_ANDROID) +#if !defined(OS_ANDROID) && !defined(OS_NACL) #include <ifaddrs.h> -#endif #include <net/if.h> #include <netinet/in.h> +#endif + +#if defined(OS_MACOSX) && !defined(OS_IOS) +#include <net/if_media.h> +#include <netinet/in_var.h> +#include <sys/ioctl.h> +#endif #if defined(OS_ANDROID) #include "net/android/network_library.h" @@ -29,42 +36,89 @@ namespace net { -bool FileURLToFilePath(const GURL& url, base::FilePath* path) { - *path = base::FilePath(); - std::string& file_path_str = const_cast<std::string&>(path->value()); - file_path_str.clear(); +namespace { - if (!url.is_valid()) - return false; +#if !defined(OS_ANDROID) - // Firefox seems to ignore the "host" of a file url if there is one. That is, - // file://foo/bar.txt maps to /bar.txt. - // TODO(dhg): This should probably take into account UNCs which could - // include a hostname other than localhost or blank - std::string old_path = url.path(); +struct NetworkInterfaceInfo { + NetworkInterfaceInfo() : permanent(true) { } - if (old_path.empty()) - return false; + bool permanent; // IPv6 has notion of temporary address. If the address is + // IPv6 and it's temporary this field will be false. + NetworkInterface interface; +}; - // GURL stores strings as percent-encoded 8-bit, this will undo if possible. - old_path = UnescapeURLComponent(old_path, - UnescapeRule::SPACES | UnescapeRule::URL_SPECIAL_CHARS); +// This method will remove permanent IPv6 addresses if a temporary address +// is available for same network interface. +void RemovePermanentIPv6AddressesWhereTemporaryExists( + std::vector<NetworkInterfaceInfo>* infos) { + if (!infos || infos->empty()) + return; - // Collapse multiple path slashes into a single path slash. - std::string new_path; - do { - new_path = old_path; - ReplaceSubstringsAfterOffset(&new_path, 0, "//", "/"); - old_path.swap(new_path); - } while (new_path != old_path); + // Build a set containing the names of interfaces with a temp IPv6 address + std::set<std::string> ifaces_with_temp_addrs; + std::vector<NetworkInterfaceInfo>::iterator i; + for (i = infos->begin(); i != infos->end(); ++i) { + if (!i->permanent && i->interface.address.size() == kIPv6AddressSize) { + ifaces_with_temp_addrs.insert(i->interface.name); + } + } - file_path_str.assign(old_path); + // If there are no such interfaces then there's no further work. + if (ifaces_with_temp_addrs.empty()) + return; - return !file_path_str.empty(); + // Search for permenent addresses belonging to same network interface. + for (i = infos->begin(); i != infos->end(); ) { + // If the address is IPv6 and it's permanent and there is temporary + // address for it, then we can remove this address. + if ((i->interface.address.size() == kIPv6AddressSize) && i->permanent && + (ifaces_with_temp_addrs.find(i->interface.name) != + ifaces_with_temp_addrs.end())) { + i = infos->erase(i); + } else { + ++i; + } + } } -bool GetNetworkList(NetworkInterfaceList* networks) { -#if defined(OS_ANDROID) +#endif + +#if defined(OS_MACOSX) && !defined(OS_IOS) + +NetworkChangeNotifier::ConnectionType GetNetworkInterfaceType( + int addr_family, const std::string& interface_name) { + NetworkChangeNotifier::ConnectionType type = + NetworkChangeNotifier::CONNECTION_UNKNOWN; + + struct ifmediareq ifmr = {}; + strncpy(ifmr.ifm_name, interface_name.c_str(), sizeof(ifmr.ifm_name) - 1); + + int s = socket(addr_family, SOCK_DGRAM, 0); + if (s == -1) { + return type; + } + + if (ioctl(s, SIOCGIFMEDIA, &ifmr) != -1) { + if (ifmr.ifm_current & IFM_IEEE80211) { + type = NetworkChangeNotifier::CONNECTION_WIFI; + } else if (ifmr.ifm_current & IFM_ETHER) { + type = NetworkChangeNotifier::CONNECTION_ETHERNET; + } + } + close(s); + return type; +} + +#endif + +} // 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()) { @@ -86,19 +140,30 @@ bool GetNetworkList(NetworkInterfaceList* networks) { CHECK(base::StringToUint(network_tokenizer.token(), &index)); networks->push_back( - NetworkInterface(name, index, address, network_prefix)); + NetworkInterface(name, name, index, + NetworkChangeNotifier::CONNECTION_UNKNOWN, + address, network_prefix)); } return true; #else // getifaddrs() may require IO operations. base::ThreadRestrictions::AssertIOAllowed(); + int ioctl_socket = -1; + if (policy & INCLUDE_ONLY_TEMP_IPV6_ADDRESS_IF_POSSIBLE) { + // we need a socket to query information about temporary address. + ioctl_socket = socket(AF_INET6, SOCK_DGRAM, 0); + DCHECK_GT(ioctl_socket, 0); + } + ifaddrs *interfaces; if (getifaddrs(&interfaces) < 0) { PLOG(ERROR) << "getifaddrs"; return false; } + std::vector<NetworkInterfaceInfo> network_infos; + // Enumerate the addresses assigned to network interfaces which are up. for (ifaddrs *interface = interfaces; interface != NULL; @@ -138,25 +203,67 @@ bool GetNetworkList(NetworkInterfaceList* networks) { continue; } + 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))) { + continue; + } + + NetworkInterfaceInfo network_info; + NetworkChangeNotifier::ConnectionType connection_type = + NetworkChangeNotifier::CONNECTION_UNKNOWN; +#if defined(OS_MACOSX) && !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) && + ioctl_socket >= 0 && addr->sa_family == AF_INET6) { + struct in6_ifreq ifr = {}; + strncpy(ifr.ifr_name, interface->ifa_name, sizeof(ifr.ifr_name) - 1); + memcpy(&ifr.ifr_ifru.ifru_addr, interface->ifa_addr, + interface->ifa_addr->sa_len); + int rv = ioctl(ioctl_socket, SIOCGIFAFLAG_IN6, &ifr); + if (rv >= 0) { + network_info.permanent = !(ifr.ifr_ifru.ifru_flags & IN6_IFF_TEMPORARY); + } + } + + connection_type = GetNetworkInterfaceType(addr->sa_family, name); +#endif + IPEndPoint address; - std::string name = interface->ifa_name; if (address.FromSockAddr(addr, addr_size)) { uint8 net_mask = 0; if (interface->ifa_netmask) { + // If not otherwise set, assume the same sa_family as ifa_addr. + if (interface->ifa_netmask->sa_family == 0) { + interface->ifa_netmask->sa_family = addr->sa_family; + } IPEndPoint netmask; if (netmask.FromSockAddr(interface->ifa_netmask, addr_size)) { net_mask = MaskPrefixLength(netmask.address()); } } + network_info.interface = NetworkInterface( + name, name, if_nametoindex(name.c_str()), + connection_type, address.address(), net_mask); - networks->push_back( - NetworkInterface(name, if_nametoindex(name.c_str()), - address.address(), net_mask)); + network_infos.push_back(NetworkInterfaceInfo(network_info)); } } - freeifaddrs(interfaces); + if (ioctl_socket >= 0) { + close(ioctl_socket); + } + if (policy & INCLUDE_ONLY_TEMP_IPV6_ADDRESS_IF_POSSIBLE) { + RemovePermanentIPv6AddressesWhereTemporaryExists(&network_infos); + } + + for (size_t i = 0; i < network_infos.size(); ++i) { + networks->push_back(network_infos[i].interface); + } return true; #endif } |