Home | History | Annotate | Download | only in base
      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