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 #include <errno.h>
14 #include <linux/netlink.h>
15 #include <linux/rtnetlink.h>
16 #include <net/if.h>
17 #include <netinet/in.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <sys/ioctl.h>
21 #include <sys/socket.h>
22 #include <sys/types.h>
23 #include <sys/utsname.h>
24 #include <unistd.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 
set_ifname(struct ifaddrs * ifaddr,int interface)39 int set_ifname(struct ifaddrs* ifaddr, int interface) {
40   char buf[IFNAMSIZ] = {0};
41   char* name = if_indextoname(interface, buf);
42   if (name == nullptr) {
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 
set_flags(struct ifaddrs * ifaddr)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 
set_addresses(struct ifaddrs * ifaddr,ifaddrmsg * msg,void * data,size_t len)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 
make_prefixes(struct ifaddrs * ifaddr,int family,int prefixlen)86 int make_prefixes(struct ifaddrs* ifaddr, int family, int prefixlen) {
87   char* prefix = nullptr;
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 
populate_ifaddrs(struct ifaddrs * ifaddr,ifaddrmsg * msg,void * bytes,size_t len)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 
getifaddrs(struct ifaddrs ** result)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 = nullptr;
153   struct ifaddrs* current = nullptr;
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 = nullptr;
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 
freeifaddrs(struct ifaddrs * addrs)209 void freeifaddrs(struct ifaddrs* addrs) {
210   struct ifaddrs* last = nullptr;
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