OLD | NEW |
(Empty) | |
| 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. |
| 4 |
| 5 #include "net/base/net_util_mac.h" |
| 6 |
| 7 #include <ifaddrs.h> |
| 8 #include <net/if.h> |
| 9 #include <netinet/in.h> |
| 10 #include <set> |
| 11 #include <sys/types.h> |
| 12 |
| 13 #include "base/files/file_path.h" |
| 14 #include "base/logging.h" |
| 15 #include "base/memory/scoped_ptr.h" |
| 16 #include "base/strings/string_number_conversions.h" |
| 17 #include "base/strings/string_tokenizer.h" |
| 18 #include "base/strings/string_util.h" |
| 19 #include "base/threading/thread_restrictions.h" |
| 20 #include "net/base/escape.h" |
| 21 #include "net/base/ip_endpoint.h" |
| 22 #include "net/base/net_errors.h" |
| 23 #include "net/base/net_util_posix.h" |
| 24 #include "url/gurl.h" |
| 25 |
| 26 #if !defined(OS_IOS) |
| 27 #include <net/if_media.h> |
| 28 #include <netinet/in_var.h> |
| 29 #include <sys/ioctl.h> |
| 30 #endif // !OS_IOS |
| 31 |
| 32 namespace net { |
| 33 |
| 34 namespace { |
| 35 |
| 36 #if !defined(OS_IOS) |
| 37 |
| 38 // MacOSX implementation of IPAttributesGetterMac which calls ioctl on socket to |
| 39 // retrieve IP attributes. |
| 40 class IPAttributesGetterMacImpl : public internal::IPAttributesGetterMac { |
| 41 public: |
| 42 IPAttributesGetterMacImpl(); |
| 43 ~IPAttributesGetterMacImpl() override; |
| 44 bool IsInitialized() const override; |
| 45 bool GetIPAttributes(const char* ifname, |
| 46 const sockaddr* sock_addr, |
| 47 int* native_attributes) override; |
| 48 |
| 49 private: |
| 50 int ioctl_socket_; |
| 51 }; |
| 52 |
| 53 IPAttributesGetterMacImpl::IPAttributesGetterMacImpl() |
| 54 : ioctl_socket_(socket(AF_INET6, SOCK_DGRAM, 0)) { |
| 55 DCHECK_GE(ioctl_socket_, 0); |
| 56 } |
| 57 |
| 58 bool IPAttributesGetterMacImpl::IsInitialized() const { |
| 59 return ioctl_socket_ >= 0; |
| 60 } |
| 61 |
| 62 IPAttributesGetterMacImpl::~IPAttributesGetterMacImpl() { |
| 63 if (ioctl_socket_ >= 0) { |
| 64 close(ioctl_socket_); |
| 65 } |
| 66 } |
| 67 |
| 68 bool IPAttributesGetterMacImpl::GetIPAttributes(const char* ifname, |
| 69 const sockaddr* sock_addr, |
| 70 int* native_attributes) { |
| 71 struct in6_ifreq ifr = {}; |
| 72 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name) - 1); |
| 73 memcpy(&ifr.ifr_ifru.ifru_addr, sock_addr, sock_addr->sa_len); |
| 74 int rv = ioctl(ioctl_socket_, SIOCGIFAFLAG_IN6, &ifr); |
| 75 if (rv >= 0) { |
| 76 *native_attributes = ifr.ifr_ifru.ifru_flags; |
| 77 } |
| 78 return (rv >= 0); |
| 79 } |
| 80 |
| 81 // When returning true, the platform native IPv6 address attributes were |
| 82 // successfully converted to net IP address attributes. Otherwise, returning |
| 83 // false and the caller should drop the IP address which can't be used by the |
| 84 // application layer. |
| 85 bool TryConvertNativeToNetIPAttributes(int native_attributes, |
| 86 int* net_attributes) { |
| 87 // For MacOSX, we disallow addresses with attributes IN6_IFF_ANYCASE, |
| 88 // IN6_IFF_DUPLICATED, IN6_IFF_TENTATIVE, and IN6_IFF_DETACHED as these are |
| 89 // still progressing through duplicated address detection (DAD) or are not |
| 90 // suitable to be used in an one-to-one communication and shouldn't be used |
| 91 // by the application layer. |
| 92 if (native_attributes & (IN6_IFF_ANYCAST | IN6_IFF_DUPLICATED | |
| 93 IN6_IFF_TENTATIVE | IN6_IFF_DETACHED)) { |
| 94 return false; |
| 95 } |
| 96 |
| 97 if (native_attributes & IN6_IFF_TEMPORARY) { |
| 98 *net_attributes |= IP_ADDRESS_ATTRIBUTE_TEMPORARY; |
| 99 } |
| 100 |
| 101 if (native_attributes & IN6_IFF_DEPRECATED) { |
| 102 *net_attributes |= IP_ADDRESS_ATTRIBUTE_DEPRECATED; |
| 103 } |
| 104 |
| 105 return true; |
| 106 } |
| 107 |
| 108 NetworkChangeNotifier::ConnectionType GetNetworkInterfaceType( |
| 109 int addr_family, |
| 110 const std::string& interface_name) { |
| 111 NetworkChangeNotifier::ConnectionType type = |
| 112 NetworkChangeNotifier::CONNECTION_UNKNOWN; |
| 113 |
| 114 struct ifmediareq ifmr = {}; |
| 115 strncpy(ifmr.ifm_name, interface_name.c_str(), sizeof(ifmr.ifm_name) - 1); |
| 116 |
| 117 int s = socket(addr_family, SOCK_DGRAM, 0); |
| 118 if (s == -1) { |
| 119 return type; |
| 120 } |
| 121 |
| 122 if (ioctl(s, SIOCGIFMEDIA, &ifmr) != -1) { |
| 123 if (ifmr.ifm_current & IFM_IEEE80211) { |
| 124 type = NetworkChangeNotifier::CONNECTION_WIFI; |
| 125 } else if (ifmr.ifm_current & IFM_ETHER) { |
| 126 type = NetworkChangeNotifier::CONNECTION_ETHERNET; |
| 127 } |
| 128 } |
| 129 close(s); |
| 130 return type; |
| 131 } |
| 132 |
| 133 #endif // !OS_IOS |
| 134 } // namespace |
| 135 |
| 136 namespace internal { |
| 137 |
| 138 bool GetNetworkListImpl(NetworkInterfaceList* networks, |
| 139 int policy, |
| 140 const ifaddrs* interfaces, |
| 141 IPAttributesGetterMac* ip_attributes_getter) { |
| 142 // Enumerate the addresses assigned to network interfaces which are up. |
| 143 for (const ifaddrs* interface = interfaces; interface != NULL; |
| 144 interface = interface->ifa_next) { |
| 145 // Skip loopback interfaces, and ones which are down. |
| 146 if (!(IFF_RUNNING & interface->ifa_flags)) |
| 147 continue; |
| 148 if (IFF_LOOPBACK & interface->ifa_flags) |
| 149 continue; |
| 150 // Skip interfaces with no address configured. |
| 151 struct sockaddr* addr = interface->ifa_addr; |
| 152 if (!addr) |
| 153 continue; |
| 154 |
| 155 // Skip unspecified addresses (i.e. made of zeroes) and loopback addresses |
| 156 // configured on non-loopback interfaces. |
| 157 if (IsLoopbackOrUnspecifiedAddress(addr)) |
| 158 continue; |
| 159 |
| 160 const std::string& name = interface->ifa_name; |
| 161 // Filter out VMware interfaces, typically named vmnet1 and vmnet8. |
| 162 if (ShouldIgnoreInterface(name, policy)) { |
| 163 continue; |
| 164 } |
| 165 |
| 166 NetworkChangeNotifier::ConnectionType connection_type = |
| 167 NetworkChangeNotifier::CONNECTION_UNKNOWN; |
| 168 |
| 169 int ip_attributes = IP_ADDRESS_ATTRIBUTE_NONE; |
| 170 |
| 171 #if !defined(OS_IOS) |
| 172 // Retrieve native ip attributes and convert to net version if a getter is |
| 173 // given. |
| 174 if (ip_attributes_getter && ip_attributes_getter->IsInitialized()) { |
| 175 int native_attributes = 0; |
| 176 if (addr->sa_family == AF_INET6 && |
| 177 ip_attributes_getter->GetIPAttributes( |
| 178 interface->ifa_name, interface->ifa_addr, &native_attributes)) { |
| 179 if (!TryConvertNativeToNetIPAttributes(native_attributes, |
| 180 &ip_attributes)) { |
| 181 continue; |
| 182 } |
| 183 } |
| 184 } |
| 185 |
| 186 connection_type = GetNetworkInterfaceType(addr->sa_family, name); |
| 187 #endif // !OS_IOS |
| 188 |
| 189 IPEndPoint address; |
| 190 |
| 191 int addr_size = 0; |
| 192 if (addr->sa_family == AF_INET6) { |
| 193 addr_size = sizeof(sockaddr_in6); |
| 194 } else if (addr->sa_family == AF_INET) { |
| 195 addr_size = sizeof(sockaddr_in); |
| 196 } |
| 197 |
| 198 if (address.FromSockAddr(addr, addr_size)) { |
| 199 uint8 prefix_length = 0; |
| 200 if (interface->ifa_netmask) { |
| 201 // If not otherwise set, assume the same sa_family as ifa_addr. |
| 202 if (interface->ifa_netmask->sa_family == 0) { |
| 203 interface->ifa_netmask->sa_family = addr->sa_family; |
| 204 } |
| 205 IPEndPoint netmask; |
| 206 if (netmask.FromSockAddr(interface->ifa_netmask, addr_size)) { |
| 207 prefix_length = MaskPrefixLength(netmask.address()); |
| 208 } |
| 209 } |
| 210 networks->push_back(NetworkInterface( |
| 211 name, name, if_nametoindex(name.c_str()), connection_type, |
| 212 address.address(), prefix_length, ip_attributes)); |
| 213 } |
| 214 } |
| 215 |
| 216 return true; |
| 217 } |
| 218 |
| 219 } // namespace internal |
| 220 |
| 221 bool GetNetworkList(NetworkInterfaceList* networks, int policy) { |
| 222 if (networks == NULL) |
| 223 return false; |
| 224 |
| 225 // getifaddrs() may require IO operations. |
| 226 base::ThreadRestrictions::AssertIOAllowed(); |
| 227 |
| 228 ifaddrs* interfaces; |
| 229 if (getifaddrs(&interfaces) < 0) { |
| 230 PLOG(ERROR) << "getifaddrs"; |
| 231 return false; |
| 232 } |
| 233 |
| 234 scoped_ptr<internal::IPAttributesGetterMac> ip_attributes_getter; |
| 235 |
| 236 #if !defined(OS_IOS) |
| 237 ip_attributes_getter.reset(new IPAttributesGetterMacImpl()); |
| 238 #endif |
| 239 |
| 240 bool result = internal::GetNetworkListImpl(networks, policy, interfaces, |
| 241 ip_attributes_getter.get()); |
| 242 freeifaddrs(interfaces); |
| 243 return result; |
| 244 } |
| 245 |
| 246 } // namespace net |
OLD | NEW |