Home | History | Annotate | Download | only in base
      1 /*
      2  *  Copyright 2012 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 #if defined(WEBRTC_ANDROID)
     12 #include "webrtc/base/ifaddrs-android.h"
     13 #include <stdlib.h>
     14 #include <string.h>
     15 #include <sys/types.h>
     16 #include <sys/socket.h>
     17 #include <sys/utsname.h>
     18 #include <sys/ioctl.h>
     19 #include <netinet/in.h>
     20 #include <net/if.h>
     21 #include <unistd.h>
     22 #include <errno.h>
     23 #include <linux/netlink.h>
     24 #include <linux/rtnetlink.h>
     25 
     26 namespace {
     27 
     28 struct netlinkrequest {
     29   nlmsghdr header;
     30   ifaddrmsg msg;
     31 };
     32 
     33 const int kMaxReadSize = 4096;
     34 
     35 }  // namespace
     36 
     37 namespace rtc {
     38 
     39 int set_ifname(struct ifaddrs* ifaddr, int interface) {
     40   char buf[IFNAMSIZ] = {0};
     41   char* name = if_indextoname(interface, buf);
     42   if (name == NULL) {
     43     return -1;
     44   }
     45   ifaddr->ifa_name = new char[strlen(name) + 1];
     46   strncpy(ifaddr->ifa_name, name, strlen(name) + 1);
     47   return 0;
     48 }
     49 
     50 int set_flags(struct ifaddrs* ifaddr) {
     51   int fd = socket(AF_INET, SOCK_DGRAM, 0);
     52   if (fd == -1) {
     53     return -1;
     54   }
     55   ifreq ifr;
     56   memset(&ifr, 0, sizeof(ifr));
     57   strncpy(ifr.ifr_name, ifaddr->ifa_name, IFNAMSIZ - 1);
     58   int rc = ioctl(fd, SIOCGIFFLAGS, &ifr);
     59   close(fd);
     60   if (rc == -1) {
     61     return -1;
     62   }
     63   ifaddr->ifa_flags = ifr.ifr_flags;
     64   return 0;
     65 }
     66 
     67 int set_addresses(struct ifaddrs* ifaddr, ifaddrmsg* msg, void* data,
     68                   size_t len) {
     69   if (msg->ifa_family == AF_INET) {
     70     sockaddr_in* sa = new sockaddr_in;
     71     sa->sin_family = AF_INET;
     72     memcpy(&sa->sin_addr, data, len);
     73     ifaddr->ifa_addr = reinterpret_cast<sockaddr*>(sa);
     74   } else if (msg->ifa_family == AF_INET6) {
     75     sockaddr_in6* sa = new sockaddr_in6;
     76     sa->sin6_family = AF_INET6;
     77     sa->sin6_scope_id = msg->ifa_index;
     78     memcpy(&sa->sin6_addr, data, len);
     79     ifaddr->ifa_addr = reinterpret_cast<sockaddr*>(sa);
     80   } else {
     81     return -1;
     82   }
     83   return 0;
     84 }
     85 
     86 int make_prefixes(struct ifaddrs* ifaddr, int family, int prefixlen) {
     87   char* prefix = NULL;
     88   if (family == AF_INET) {
     89     sockaddr_in* mask = new sockaddr_in;
     90     mask->sin_family = AF_INET;
     91     memset(&mask->sin_addr, 0, sizeof(in_addr));
     92     ifaddr->ifa_netmask = reinterpret_cast<sockaddr*>(mask);
     93     if (prefixlen > 32) {
     94       prefixlen = 32;
     95     }
     96     prefix = reinterpret_cast<char*>(&mask->sin_addr);
     97   } else if (family == AF_INET6) {
     98     sockaddr_in6* mask = new sockaddr_in6;
     99     mask->sin6_family = AF_INET6;
    100     memset(&mask->sin6_addr, 0, sizeof(in6_addr));
    101     ifaddr->ifa_netmask = reinterpret_cast<sockaddr*>(mask);
    102     if (prefixlen > 128) {
    103       prefixlen = 128;
    104     }
    105     prefix = reinterpret_cast<char*>(&mask->sin6_addr);
    106   } else {
    107     return -1;
    108   }
    109   for (int i = 0; i < (prefixlen / 8); i++) {
    110     *prefix++ = 0xFF;
    111   }
    112   char remainder = 0xff;
    113   remainder <<= (8 - prefixlen % 8);
    114   *prefix = remainder;
    115   return 0;
    116 }
    117 
    118 int populate_ifaddrs(struct ifaddrs* ifaddr, ifaddrmsg* msg, void* bytes,
    119                      size_t len) {
    120   if (set_ifname(ifaddr, msg->ifa_index) != 0) {
    121     return -1;
    122   }
    123   if (set_flags(ifaddr) != 0) {
    124     return -1;
    125   }
    126   if (set_addresses(ifaddr, msg, bytes, len) != 0) {
    127     return -1;
    128   }
    129   if (make_prefixes(ifaddr, msg->ifa_family, msg->ifa_prefixlen) != 0) {
    130     return -1;
    131   }
    132   return 0;
    133 }
    134 
    135 int getifaddrs(struct ifaddrs** result) {
    136   int fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
    137   if (fd < 0) {
    138     return -1;
    139   }
    140 
    141   netlinkrequest ifaddr_request;
    142   memset(&ifaddr_request, 0, sizeof(ifaddr_request));
    143   ifaddr_request.header.nlmsg_flags = NLM_F_ROOT | NLM_F_REQUEST;
    144   ifaddr_request.header.nlmsg_type = RTM_GETADDR;
    145   ifaddr_request.header.nlmsg_len = NLMSG_LENGTH(sizeof(ifaddrmsg));
    146 
    147   ssize_t count = send(fd, &ifaddr_request, ifaddr_request.header.nlmsg_len, 0);
    148   if (static_cast<size_t>(count) != ifaddr_request.header.nlmsg_len) {
    149     close(fd);
    150     return -1;
    151   }
    152   struct ifaddrs* start = NULL;
    153   struct ifaddrs* current = NULL;
    154   char buf[kMaxReadSize];
    155   ssize_t amount_read = recv(fd, &buf, kMaxReadSize, 0);
    156   while (amount_read > 0) {
    157     nlmsghdr* header = reinterpret_cast<nlmsghdr*>(&buf[0]);
    158     size_t header_size = static_cast<size_t>(amount_read);
    159     for ( ; NLMSG_OK(header, header_size);
    160           header = NLMSG_NEXT(header, header_size)) {
    161       switch (header->nlmsg_type) {
    162         case NLMSG_DONE:
    163           // Success. Return.
    164           *result = start;
    165           close(fd);
    166           return 0;
    167         case NLMSG_ERROR:
    168           close(fd);
    169           freeifaddrs(start);
    170           return -1;
    171         case RTM_NEWADDR: {
    172           ifaddrmsg* address_msg =
    173               reinterpret_cast<ifaddrmsg*>(NLMSG_DATA(header));
    174           rtattr* rta = IFA_RTA(address_msg);
    175           ssize_t payload_len = IFA_PAYLOAD(header);
    176           while (RTA_OK(rta, payload_len)) {
    177             if (rta->rta_type == IFA_ADDRESS) {
    178               int family = address_msg->ifa_family;
    179               if (family == AF_INET || family == AF_INET6) {
    180                 ifaddrs* newest = new ifaddrs;
    181                 memset(newest, 0, sizeof(ifaddrs));
    182                 if (current) {
    183                   current->ifa_next = newest;
    184                 } else {
    185                   start = newest;
    186                 }
    187                 if (populate_ifaddrs(newest, address_msg, RTA_DATA(rta),
    188                                      RTA_PAYLOAD(rta)) != 0) {
    189                   freeifaddrs(start);
    190                   *result = NULL;
    191                   return -1;
    192                 }
    193                 current = newest;
    194               }
    195             }
    196             rta = RTA_NEXT(rta, payload_len);
    197           }
    198           break;
    199         }
    200       }
    201     }
    202     amount_read = recv(fd, &buf, kMaxReadSize, 0);
    203   }
    204   close(fd);
    205   freeifaddrs(start);
    206   return -1;
    207 }
    208 
    209 void freeifaddrs(struct ifaddrs* addrs) {
    210   struct ifaddrs* last = NULL;
    211   struct ifaddrs* cursor = addrs;
    212   while (cursor) {
    213     delete[] cursor->ifa_name;
    214     delete cursor->ifa_addr;
    215     delete cursor->ifa_netmask;
    216     last = cursor;
    217     cursor = cursor->ifa_next;
    218     delete last;
    219   }
    220 }
    221 
    222 }  // namespace rtc
    223 #endif  // defined(WEBRTC_ANDROID)
    224