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