• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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::__anondf6977240111::FdTraits46   static int InvalidValue() { return -1; }
47 
Freenet::internal::__anondf6977240111::FdTraits48   static void Free(int f) { ::close(f); }
49 };
50 
51 struct IfaddrsTraits {
InvalidValuenet::internal::__anondf6977240111::IfaddrsTraits52   static struct ifaddrs* InvalidValue() { return nullptr; }
53 
Freenet::internal::__anondf6977240111::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