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