xref: /aosp_15_r20/external/webrtc/rtc_base/ifaddrs_android.cc (revision d9f758449e529ab9291ac668be2861e7a55c2422)
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