| 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 std::string GetWifiSSID() { | |
| 247 NOTIMPLEMENTED(); | |
| 248 return ""; | |
| 249 } | |
| 250 | |
| 251 } // namespace net | |
| OLD | NEW |