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
26namespace {
27
28struct netlinkrequest {
29  nlmsghdr header;
30  ifaddrmsg msg;
31};
32
33const int kMaxReadSize = 4096;
34
35}  // namespace
36
37namespace rtc {
38
39int 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
50int 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
67int 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
86int 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
118int 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
135int 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
209void 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