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