xref: /aosp_15_r20/external/cronet/net/base/network_interfaces_getifaddrs_android.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2022 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 // Taken from WebRTC's own implementation.
6 // https://webrtc.googlesource.com/src/+/4cad08ff199a46087f8ffe91ef89af60a4dc8df9/rtc_base/ifaddrs_android.cc
7 
8 #include "build/build_config.h"
9 
10 #if BUILDFLAG(IS_ANDROID)
11 
12 #include "net/base/network_interfaces_getifaddrs_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 #include "base/scoped_generic.h"
28 
29 namespace net::internal {
30 
31 namespace {
32 
33 struct netlinkrequest {
34   nlmsghdr header;
35   ifaddrmsg msg;
36 };
37 
38 const int kMaxReadSize = 4096;
39 
40 struct FdTraits {
InvalidValuenet::internal::__anon63e9041e0111::FdTraits41   static int InvalidValue() { return -1; }
42 
Freenet::internal::__anon63e9041e0111::FdTraits43   static void Free(int f) { ::close(f); }
44 };
45 
46 struct IfaddrsTraits {
InvalidValuenet::internal::__anon63e9041e0111::IfaddrsTraits47   static struct ifaddrs* InvalidValue() { return nullptr; }
48 
Freenet::internal::__anon63e9041e0111::IfaddrsTraits49   static void Free(struct ifaddrs* ifaddrs) { Freeifaddrs(ifaddrs); }
50 };
51 
set_ifname(struct ifaddrs * ifaddr,int interface)52 int set_ifname(struct ifaddrs* ifaddr, int interface) {
53   char buf[IFNAMSIZ] = {0};
54   char* name = if_indextoname(interface, buf);
55   if (name == nullptr) {
56     return -1;
57   }
58   ifaddr->ifa_name = new char[strlen(name) + 1];
59   strncpy(ifaddr->ifa_name, name, strlen(name) + 1);
60   return 0;
61 }
62 
set_flags(struct ifaddrs * ifaddr)63 int set_flags(struct ifaddrs* ifaddr) {
64   int fd = socket(AF_INET, SOCK_DGRAM, 0);
65   if (fd == -1) {
66     return -1;
67   }
68   ifreq ifr;
69   memset(&ifr, 0, sizeof(ifr));
70   strncpy(ifr.ifr_name, ifaddr->ifa_name, IFNAMSIZ - 1);
71   int rc = ioctl(fd, SIOCGIFFLAGS, &ifr);
72   close(fd);
73   if (rc == -1) {
74     return -1;
75   }
76   ifaddr->ifa_flags = ifr.ifr_flags;
77   return 0;
78 }
79 
set_addresses(struct ifaddrs * ifaddr,ifaddrmsg * msg,void * data,size_t len)80 int set_addresses(struct ifaddrs* ifaddr,
81                   ifaddrmsg* msg,
82                   void* data,
83                   size_t len) {
84   if (msg->ifa_family == AF_INET) {
85     sockaddr_in* sa = new sockaddr_in;
86     sa->sin_family = AF_INET;
87     memcpy(&sa->sin_addr, data, len);
88     ifaddr->ifa_addr = reinterpret_cast<sockaddr*>(sa);
89   } else if (msg->ifa_family == AF_INET6) {
90     sockaddr_in6* sa = new sockaddr_in6;
91     sa->sin6_family = AF_INET6;
92     sa->sin6_scope_id = msg->ifa_index;
93     memcpy(&sa->sin6_addr, data, len);
94     ifaddr->ifa_addr = reinterpret_cast<sockaddr*>(sa);
95   } else {
96     return -1;
97   }
98   return 0;
99 }
100 
make_prefixes(struct ifaddrs * ifaddr,int family,int prefixlen)101 int make_prefixes(struct ifaddrs* ifaddr, int family, int prefixlen) {
102   char* prefix = nullptr;
103   if (family == AF_INET) {
104     sockaddr_in* mask = new sockaddr_in;
105     mask->sin_family = AF_INET;
106     memset(&mask->sin_addr, 0, sizeof(in_addr));
107     ifaddr->ifa_netmask = reinterpret_cast<sockaddr*>(mask);
108     if (prefixlen > 32) {
109       prefixlen = 32;
110     }
111     prefix = reinterpret_cast<char*>(&mask->sin_addr);
112   } else if (family == AF_INET6) {
113     sockaddr_in6* mask = new sockaddr_in6;
114     mask->sin6_family = AF_INET6;
115     memset(&mask->sin6_addr, 0, sizeof(in6_addr));
116     ifaddr->ifa_netmask = reinterpret_cast<sockaddr*>(mask);
117     if (prefixlen > 128) {
118       prefixlen = 128;
119     }
120     prefix = reinterpret_cast<char*>(&mask->sin6_addr);
121   } else {
122     return -1;
123   }
124   for (int i = 0; i < (prefixlen / 8); i++) {
125     *prefix++ = 0xFF;
126   }
127   char remainder = 0xff;
128   remainder <<= (8 - prefixlen % 8);
129   *prefix = remainder;
130   return 0;
131 }
132 
populate_ifaddrs(struct ifaddrs * ifaddr,ifaddrmsg * msg,void * bytes,size_t len)133 int populate_ifaddrs(struct ifaddrs* ifaddr,
134                      ifaddrmsg* msg,
135                      void* bytes,
136                      size_t len) {
137   if (set_ifname(ifaddr, msg->ifa_index) != 0) {
138     return -1;
139   }
140   if (set_flags(ifaddr) != 0) {
141     return -1;
142   }
143   if (set_addresses(ifaddr, msg, bytes, len) != 0) {
144     return -1;
145   }
146   if (make_prefixes(ifaddr, msg->ifa_family, msg->ifa_prefixlen) != 0) {
147     return -1;
148   }
149   return 0;
150 }
151 
152 }  // namespace
153 
Getifaddrs(struct ifaddrs ** result)154 int Getifaddrs(struct ifaddrs** result) {
155   int fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
156   if (fd < 0) {
157     *result = nullptr;
158     return -1;
159   }
160 
161   base::ScopedGeneric<int, FdTraits> scoped_fd(fd);
162   base::ScopedGeneric<struct ifaddrs*, IfaddrsTraits> scoped_ifaddrs;
163 
164   netlinkrequest ifaddr_request;
165   memset(&ifaddr_request, 0, sizeof(ifaddr_request));
166   ifaddr_request.header.nlmsg_flags = NLM_F_ROOT | NLM_F_REQUEST;
167   ifaddr_request.header.nlmsg_type = RTM_GETADDR;
168   ifaddr_request.header.nlmsg_len = NLMSG_LENGTH(sizeof(ifaddrmsg));
169 
170   ssize_t count = send(fd, &ifaddr_request, ifaddr_request.header.nlmsg_len, 0);
171   if (static_cast<size_t>(count) != ifaddr_request.header.nlmsg_len) {
172     close(fd);
173     return -1;
174   }
175   struct ifaddrs* current = nullptr;
176   char buf[kMaxReadSize];
177   ssize_t amount_read = recv(fd, &buf, kMaxReadSize, 0);
178   while (amount_read > 0) {
179     nlmsghdr* header = reinterpret_cast<nlmsghdr*>(&buf[0]);
180     size_t header_size = static_cast<size_t>(amount_read);
181     for (; NLMSG_OK(header, header_size);
182          header = NLMSG_NEXT(header, header_size)) {
183       switch (header->nlmsg_type) {
184         case NLMSG_DONE:
185           // Success. Return.
186           *result = scoped_ifaddrs.release();
187           return 0;
188         case NLMSG_ERROR:
189           *result = nullptr;
190           return -1;
191         case RTM_NEWADDR: {
192           ifaddrmsg* address_msg =
193               reinterpret_cast<ifaddrmsg*>(NLMSG_DATA(header));
194           rtattr* rta = IFA_RTA(address_msg);
195           ssize_t payload_len = IFA_PAYLOAD(header);
196           while (RTA_OK(rta, payload_len)) {
197             if ((address_msg->ifa_family == AF_INET &&
198                  rta->rta_type == IFA_LOCAL) ||
199                 (address_msg->ifa_family == AF_INET6 &&
200                  rta->rta_type == IFA_ADDRESS)) {
201               ifaddrs* newest = new ifaddrs;
202               memset(newest, 0, sizeof(ifaddrs));
203               if (current) {
204                 current->ifa_next = newest;
205               } else {
206                 scoped_ifaddrs.reset(newest);
207               }
208               if (populate_ifaddrs(newest, address_msg, RTA_DATA(rta),
209                                    RTA_PAYLOAD(rta)) != 0) {
210                 *result = nullptr;
211                 return -1;
212               }
213               current = newest;
214             }
215             rta = RTA_NEXT(rta, payload_len);
216           }
217           break;
218         }
219       }
220     }
221     amount_read = recv(fd, &buf, kMaxReadSize, 0);
222   }
223   *result = nullptr;
224   return -1;
225 }
226 
Freeifaddrs(struct ifaddrs * addrs)227 void Freeifaddrs(struct ifaddrs* addrs) {
228   struct ifaddrs* last = nullptr;
229   struct ifaddrs* cursor = addrs;
230   while (cursor) {
231     delete[] cursor->ifa_name;
232     delete cursor->ifa_addr;
233     delete cursor->ifa_netmask;
234     last = cursor;
235     cursor = cursor->ifa_next;
236     delete last;
237   }
238 }
239 
240 }  // namespace net::internal
241 
242 #endif  // BUILDFLAG(IS_ANDROID)
243