1 /* 2 * Copyright 2015 The WebRTC Project Authors. All rights reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11 #include <net/if.h> 12 #include <sys/ioctl.h> 13 #include <unistd.h> 14 15 #include "webrtc/base/checks.h" 16 #include "webrtc/base/ifaddrs_converter.h" 17 #include "webrtc/base/logging.h" 18 #include "webrtc/base/scoped_ptr.h" 19 20 #if !defined(WEBRTC_IOS) 21 #include <net/if_media.h> 22 #include <netinet/in_var.h> 23 #else // WEBRTC_IOS 24 #define SCOPE6_ID_MAX 16 25 26 struct in6_addrlifetime { 27 time_t ia6t_expire; /* valid lifetime expiration time */ 28 time_t ia6t_preferred; /* preferred lifetime expiration time */ 29 u_int32_t ia6t_vltime; /* valid lifetime */ 30 u_int32_t ia6t_pltime; /* prefix lifetime */ 31 }; 32 33 struct in6_ifstat { 34 u_quad_t ifs6_in_receive; /* # of total input datagram */ 35 u_quad_t ifs6_in_hdrerr; /* # of datagrams with invalid hdr */ 36 u_quad_t ifs6_in_toobig; /* # of datagrams exceeded MTU */ 37 u_quad_t ifs6_in_noroute; /* # of datagrams with no route */ 38 u_quad_t ifs6_in_addrerr; /* # of datagrams with invalid dst */ 39 u_quad_t ifs6_in_protounknown; /* # of datagrams with unknown proto */ 40 /* NOTE: increment on final dst if */ 41 u_quad_t ifs6_in_truncated; /* # of truncated datagrams */ 42 u_quad_t ifs6_in_discard; /* # of discarded datagrams */ 43 /* NOTE: fragment timeout is not here */ 44 u_quad_t ifs6_in_deliver; /* # of datagrams delivered to ULP */ 45 /* NOTE: increment on final dst if */ 46 u_quad_t ifs6_out_forward; /* # of datagrams forwarded */ 47 /* NOTE: increment on outgoing if */ 48 u_quad_t ifs6_out_request; /* # of outgoing datagrams from ULP */ 49 /* NOTE: does not include forwrads */ 50 u_quad_t ifs6_out_discard; /* # of discarded datagrams */ 51 u_quad_t ifs6_out_fragok; /* # of datagrams fragmented */ 52 u_quad_t ifs6_out_fragfail; /* # of datagrams failed on fragment */ 53 u_quad_t ifs6_out_fragcreat; /* # of fragment datagrams */ 54 /* NOTE: this is # after fragment */ 55 u_quad_t ifs6_reass_reqd; /* # of incoming fragmented packets */ 56 /* NOTE: increment on final dst if */ 57 u_quad_t ifs6_reass_ok; /* # of reassembled packets */ 58 /* NOTE: this is # after reass */ 59 /* NOTE: increment on final dst if */ 60 u_quad_t ifs6_reass_fail; /* # of reass failures */ 61 /* NOTE: may not be packet count */ 62 /* NOTE: increment on final dst if */ 63 u_quad_t ifs6_in_mcast; /* # of inbound multicast datagrams */ 64 u_quad_t ifs6_out_mcast; /* # of outbound multicast datagrams */ 65 }; 66 struct icmp6_ifstat { 67 /* 68 * Input statistics 69 */ 70 /* ipv6IfIcmpInMsgs, total # of input messages */ 71 u_quad_t ifs6_in_msg; 72 /* ipv6IfIcmpInErrors, # of input error messages */ 73 u_quad_t ifs6_in_error; 74 /* ipv6IfIcmpInDestUnreachs, # of input dest unreach errors */ 75 u_quad_t ifs6_in_dstunreach; 76 /* ipv6IfIcmpInAdminProhibs, # of input admin. prohibited errs */ 77 u_quad_t ifs6_in_adminprohib; 78 /* ipv6IfIcmpInTimeExcds, # of input time exceeded errors */ 79 u_quad_t ifs6_in_timeexceed; 80 /* ipv6IfIcmpInParmProblems, # of input parameter problem errors */ 81 u_quad_t ifs6_in_paramprob; 82 /* ipv6IfIcmpInPktTooBigs, # of input packet too big errors */ 83 u_quad_t ifs6_in_pkttoobig; 84 /* ipv6IfIcmpInEchos, # of input echo requests */ 85 u_quad_t ifs6_in_echo; 86 /* ipv6IfIcmpInEchoReplies, # of input echo replies */ 87 u_quad_t ifs6_in_echoreply; 88 /* ipv6IfIcmpInRouterSolicits, # of input router solicitations */ 89 u_quad_t ifs6_in_routersolicit; 90 /* ipv6IfIcmpInRouterAdvertisements, # of input router advertisements */ 91 u_quad_t ifs6_in_routeradvert; 92 /* ipv6IfIcmpInNeighborSolicits, # of input neighbor solicitations */ 93 u_quad_t ifs6_in_neighborsolicit; 94 /* ipv6IfIcmpInNeighborAdvertisements, # of input neighbor advs. */ 95 u_quad_t ifs6_in_neighboradvert; 96 /* ipv6IfIcmpInRedirects, # of input redirects */ 97 u_quad_t ifs6_in_redirect; 98 /* ipv6IfIcmpInGroupMembQueries, # of input MLD queries */ 99 u_quad_t ifs6_in_mldquery; 100 /* ipv6IfIcmpInGroupMembResponses, # of input MLD reports */ 101 u_quad_t ifs6_in_mldreport; 102 /* ipv6IfIcmpInGroupMembReductions, # of input MLD done */ 103 u_quad_t ifs6_in_mlddone; 104 105 /* 106 * Output statistics. We should solve unresolved routing problem... 107 */ 108 /* ipv6IfIcmpOutMsgs, total # of output messages */ 109 u_quad_t ifs6_out_msg; 110 /* ipv6IfIcmpOutErrors, # of output error messages */ 111 u_quad_t ifs6_out_error; 112 /* ipv6IfIcmpOutDestUnreachs, # of output dest unreach errors */ 113 u_quad_t ifs6_out_dstunreach; 114 /* ipv6IfIcmpOutAdminProhibs, # of output admin. prohibited errs */ 115 u_quad_t ifs6_out_adminprohib; 116 /* ipv6IfIcmpOutTimeExcds, # of output time exceeded errors */ 117 u_quad_t ifs6_out_timeexceed; 118 /* ipv6IfIcmpOutParmProblems, # of output parameter problem errors */ 119 u_quad_t ifs6_out_paramprob; 120 /* ipv6IfIcmpOutPktTooBigs, # of output packet too big errors */ 121 u_quad_t ifs6_out_pkttoobig; 122 /* ipv6IfIcmpOutEchos, # of output echo requests */ 123 u_quad_t ifs6_out_echo; 124 /* ipv6IfIcmpOutEchoReplies, # of output echo replies */ 125 u_quad_t ifs6_out_echoreply; 126 /* ipv6IfIcmpOutRouterSolicits, # of output router solicitations */ 127 u_quad_t ifs6_out_routersolicit; 128 /* ipv6IfIcmpOutRouterAdvertisements, # of output router advs. */ 129 u_quad_t ifs6_out_routeradvert; 130 /* ipv6IfIcmpOutNeighborSolicits, # of output neighbor solicitations */ 131 u_quad_t ifs6_out_neighborsolicit; 132 /* ipv6IfIcmpOutNeighborAdvertisements, # of output neighbor advs. */ 133 u_quad_t ifs6_out_neighboradvert; 134 /* ipv6IfIcmpOutRedirects, # of output redirects */ 135 u_quad_t ifs6_out_redirect; 136 /* ipv6IfIcmpOutGroupMembQueries, # of output MLD queries */ 137 u_quad_t ifs6_out_mldquery; 138 /* ipv6IfIcmpOutGroupMembResponses, # of output MLD reports */ 139 u_quad_t ifs6_out_mldreport; 140 /* ipv6IfIcmpOutGroupMembReductions, # of output MLD done */ 141 u_quad_t ifs6_out_mlddone; 142 }; 143 144 struct in6_ifreq { 145 char ifr_name[IFNAMSIZ]; 146 union { 147 struct sockaddr_in6 ifru_addr; 148 struct sockaddr_in6 ifru_dstaddr; 149 int ifru_flags; 150 int ifru_flags6; 151 int ifru_metric; 152 int ifru_intval; 153 caddr_t ifru_data; 154 struct in6_addrlifetime ifru_lifetime; 155 struct in6_ifstat ifru_stat; 156 struct icmp6_ifstat ifru_icmp6stat; 157 u_int32_t ifru_scope_id[SCOPE6_ID_MAX]; 158 } ifr_ifru; 159 }; 160 161 #define SIOCGIFAFLAG_IN6 _IOWR('i', 73, struct in6_ifreq) 162 163 #define IN6_IFF_ANYCAST 0x0001 /* anycast address */ 164 #define IN6_IFF_TENTATIVE 0x0002 /* tentative address */ 165 #define IN6_IFF_DUPLICATED 0x0004 /* DAD detected duplicate */ 166 #define IN6_IFF_DETACHED 0x0008 /* may be detached from the link */ 167 #define IN6_IFF_DEPRECATED 0x0010 /* deprecated address */ 168 #define IN6_IFF_TEMPORARY 0x0080 /* temporary (anonymous) address. */ 169 170 #endif // WEBRTC_IOS 171 172 namespace rtc { 173 174 namespace { 175 176 class IPv6AttributesGetter { 177 public: 178 IPv6AttributesGetter(); 179 virtual ~IPv6AttributesGetter(); 180 bool IsInitialized() const; 181 bool GetIPAttributes(const char* ifname, 182 const sockaddr* sock_addr, 183 int* native_attributes); 184 185 private: 186 // on MAC or IOS, we have to use ioctl with a socket to query an IPv6 187 // interface's attribute. 188 int ioctl_socket_; 189 }; 190 191 IPv6AttributesGetter::IPv6AttributesGetter() 192 : ioctl_socket_( 193 socket(AF_INET6, SOCK_DGRAM, 0 /* unspecified protocol */)) { 194 RTC_DCHECK_GE(ioctl_socket_, 0); 195 } 196 197 bool IPv6AttributesGetter::IsInitialized() const { 198 return ioctl_socket_ >= 0; 199 } 200 201 IPv6AttributesGetter::~IPv6AttributesGetter() { 202 if (!IsInitialized()) { 203 return; 204 } 205 close(ioctl_socket_); 206 } 207 208 bool IPv6AttributesGetter::GetIPAttributes(const char* ifname, 209 const sockaddr* sock_addr, 210 int* native_attributes) { 211 if (!IsInitialized()) { 212 return false; 213 } 214 215 struct in6_ifreq ifr = {}; 216 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name) - 1); 217 memcpy(&ifr.ifr_ifru.ifru_addr, sock_addr, sock_addr->sa_len); 218 int rv = ioctl(ioctl_socket_, SIOCGIFAFLAG_IN6, &ifr); 219 if (rv >= 0) { 220 *native_attributes = ifr.ifr_ifru.ifru_flags; 221 } else { 222 LOG(LS_ERROR) << "ioctl returns " << errno; 223 } 224 return (rv >= 0); 225 } 226 227 // Converts native IPv6 address attributes to net IPv6 address attributes. If 228 // it returns false, the IP address isn't suitable for one-to-one communications 229 // applications and should be ignored. 230 bool ConvertNativeToIPAttributes(int native_attributes, int* net_attributes) { 231 // For MacOSX, we disallow addresses with attributes IN6_IFF_ANYCASE, 232 // IN6_IFF_DUPLICATED, IN6_IFF_TENTATIVE, and IN6_IFF_DETACHED as these are 233 // still progressing through duplicated address detection (DAD) or are not 234 // suitable for one-to-one communication applications. 235 if (native_attributes & (IN6_IFF_ANYCAST | IN6_IFF_DUPLICATED | 236 IN6_IFF_TENTATIVE | IN6_IFF_DETACHED)) { 237 return false; 238 } 239 240 if (native_attributes & IN6_IFF_TEMPORARY) { 241 *net_attributes |= IPV6_ADDRESS_FLAG_TEMPORARY; 242 } 243 244 if (native_attributes & IN6_IFF_DEPRECATED) { 245 *net_attributes |= IPV6_ADDRESS_FLAG_DEPRECATED; 246 } 247 248 return true; 249 } 250 251 class MacIfAddrsConverter : public IfAddrsConverter { 252 public: 253 MacIfAddrsConverter() : ip_attribute_getter_(new IPv6AttributesGetter()) {} 254 ~MacIfAddrsConverter() override {} 255 256 bool ConvertNativeAttributesToIPAttributes(const struct ifaddrs* interface, 257 int* ip_attributes) override { 258 int native_attributes; 259 if (!ip_attribute_getter_->GetIPAttributes( 260 interface->ifa_name, interface->ifa_addr, &native_attributes)) { 261 return false; 262 } 263 264 if (!ConvertNativeToIPAttributes(native_attributes, ip_attributes)) { 265 return false; 266 } 267 268 return true; 269 } 270 271 private: 272 rtc::scoped_ptr<IPv6AttributesGetter> ip_attribute_getter_; 273 }; 274 275 } // namespace 276 277 IfAddrsConverter* CreateIfAddrsConverter() { 278 return new MacIfAddrsConverter(); 279 } 280 281 } // namespace rtc 282