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