1 | // Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file |
2 | // for details. All rights reserved. Use of this source code is governed by a |
3 | // BSD-style license that can be found in the LICENSE file. |
4 | |
5 | #if defined(ANDROID) && __ANDROID_API__ < 24 |
6 | |
7 | #include "bin/ifaddrs-android.h" |
8 | |
9 | #include <errno.h> |
10 | #include <linux/netlink.h> |
11 | #include <linux/rtnetlink.h> |
12 | #include <net/if.h> |
13 | #include <netinet/in.h> |
14 | #include <stdlib.h> |
15 | #include <string.h> |
16 | #include <sys/ioctl.h> |
17 | #include <sys/socket.h> |
18 | #include <sys/types.h> |
19 | #include <sys/utsname.h> |
20 | #include <unistd.h> |
21 | |
22 | #include "bin/fdutils.h" |
23 | #include "platform/signal_blocker.h" |
24 | |
25 | namespace dart { |
26 | namespace bin { |
27 | |
28 | const int kMaxReadSize = 2048; |
29 | |
30 | static bool SetIfName(struct ifaddrs* ifaddr, int interface) { |
31 | char buf[IFNAMSIZ] = {0}; |
32 | char* name = if_indextoname(interface, buf); |
33 | if (name == NULL) { |
34 | return false; |
35 | } |
36 | ifaddr->ifa_name = new char[strlen(name) + 1]; |
37 | strncpy(ifaddr->ifa_name, name, strlen(name) + 1); |
38 | return true; |
39 | } |
40 | |
41 | static void SetFlags(struct ifaddrs* ifaddr, int flag) { |
42 | ifaddr->ifa_flags = flag; |
43 | } |
44 | |
45 | static void SetAddresses(struct ifaddrs* ifaddr, |
46 | int family, |
47 | int index, |
48 | void* data, |
49 | size_t len) { |
50 | if (family == AF_INET6) { |
51 | sockaddr_in6* socketaddr = new sockaddr_in6; |
52 | socketaddr->sin6_family = AF_INET6; |
53 | socketaddr->sin6_scope_id = index; |
54 | memmove(&socketaddr->sin6_addr, data, len); |
55 | ifaddr->ifa_addr = reinterpret_cast<sockaddr*>(socketaddr); |
56 | return; |
57 | } |
58 | ASSERT(family == AF_INET); |
59 | sockaddr_in* socketaddr = new sockaddr_in; |
60 | socketaddr->sin_family = AF_INET; |
61 | memmove(&socketaddr->sin_addr, data, len); |
62 | ifaddr->ifa_addr = reinterpret_cast<sockaddr*>(socketaddr); |
63 | } |
64 | |
65 | static void SetNetmask(struct ifaddrs* ifaddr, int family) { |
66 | if (family == AF_INET6) { |
67 | sockaddr_in6* mask = new sockaddr_in6; |
68 | mask->sin6_family = AF_INET6; |
69 | memset(&mask->sin6_addr, 0, sizeof(mask->sin6_addr)); |
70 | ifaddr->ifa_netmask = reinterpret_cast<sockaddr*>(mask); |
71 | return; |
72 | } |
73 | ASSERT(family == AF_INET); |
74 | sockaddr_in* mask = new sockaddr_in; |
75 | mask->sin_family = AF_INET; |
76 | memset(&mask->sin_addr, 0, sizeof(mask->sin_addr)); |
77 | ifaddr->ifa_netmask = reinterpret_cast<sockaddr*>(mask); |
78 | } |
79 | |
80 | static bool SetIfAddrsFromAddrMsg(struct ifaddrs* ifaddr, |
81 | ifaddrmsg* msg, |
82 | void* bytes, |
83 | size_t len, |
84 | nlmsghdr* header) { |
85 | SetAddresses(ifaddr, msg->ifa_family, msg->ifa_index, bytes, len); |
86 | SetNetmask(ifaddr, msg->ifa_family); |
87 | SetFlags(ifaddr, msg->ifa_flags); |
88 | return SetIfName(ifaddr, msg->ifa_index); |
89 | } |
90 | |
91 | static bool SetIfAddrsFromInfoMsg(struct ifaddrs* ifaddr, |
92 | ifinfomsg* ifi, |
93 | void* bytes, |
94 | size_t len, |
95 | nlmsghdr* header) { |
96 | SetAddresses(ifaddr, ifi->ifi_family, ifi->ifi_index, bytes, len); |
97 | SetNetmask(ifaddr, ifi->ifi_family); |
98 | SetFlags(ifaddr, ifi->ifi_flags); |
99 | return SetIfName(ifaddr, ifi->ifi_index); |
100 | } |
101 | |
102 | static int SendRequest() { |
103 | int file_descriptor = |
104 | NO_RETRY_EXPECTED(socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE)); |
105 | if (file_descriptor < 0) { |
106 | return -1; |
107 | } |
108 | nlmsghdr header; |
109 | memset(&header, 0, sizeof(header)); |
110 | header.nlmsg_flags = NLM_F_ROOT | NLM_F_REQUEST; |
111 | header.nlmsg_type = RTM_GETADDR; |
112 | header.nlmsg_len = NLMSG_LENGTH(sizeof(ifaddrmsg)); |
113 | ssize_t num = |
114 | TEMP_FAILURE_RETRY(send(file_descriptor, &header, header.nlmsg_len, 0)); |
115 | if (static_cast<size_t>(num) != header.nlmsg_len) { |
116 | FDUtils::SaveErrorAndClose(file_descriptor); |
117 | return -1; |
118 | } |
119 | return file_descriptor; |
120 | } |
121 | |
122 | static int FailAndExit(int fd, ifaddrs* head) { |
123 | FDUtils::SaveErrorAndClose(fd); |
124 | freeifaddrs(head); |
125 | return -1; |
126 | } |
127 | |
128 | int getifaddrs(struct ifaddrs** result) { |
129 | int file_descriptor = SendRequest(); |
130 | if (file_descriptor < 0) { |
131 | return -1; |
132 | } |
133 | struct ifaddrs* head = NULL; |
134 | struct ifaddrs* cur = NULL; |
135 | char buf[kMaxReadSize]; |
136 | ssize_t amount_read; |
137 | while (true) { |
138 | amount_read = |
139 | TEMP_FAILURE_RETRY(recv(file_descriptor, &buf, kMaxReadSize, 0)); |
140 | if (amount_read <= 0) { |
141 | break; |
142 | } |
143 | nlmsghdr* header = reinterpret_cast<nlmsghdr*>(&buf[0]); |
144 | size_t header_size = static_cast<size_t>(amount_read); |
145 | for (; NLMSG_OK(header, header_size); |
146 | header = NLMSG_NEXT(header, header_size)) { |
147 | switch (header->nlmsg_type) { |
148 | case RTM_NEWADDR: { |
149 | ifaddrmsg* address_msg = |
150 | reinterpret_cast<ifaddrmsg*>(NLMSG_DATA(header)); |
151 | ssize_t payload_len = IFA_PAYLOAD(header); |
152 | for (rtattr* rta = IFA_RTA(address_msg); RTA_OK(rta, payload_len); |
153 | rta = RTA_NEXT(rta, payload_len)) { |
154 | if (rta->rta_type != IFA_ADDRESS) { |
155 | continue; |
156 | } |
157 | int family = address_msg->ifa_family; |
158 | if (family != AF_INET && family != AF_INET6) { |
159 | continue; |
160 | } |
161 | ifaddrs* next = new ifaddrs; |
162 | memset(next, 0, sizeof(*next)); |
163 | if (cur != NULL) { |
164 | cur->ifa_next = next; |
165 | } else { |
166 | head = next; |
167 | } |
168 | if (!SetIfAddrsFromAddrMsg(next, address_msg, RTA_DATA(rta), |
169 | RTA_PAYLOAD(rta), header)) { |
170 | return FailAndExit(file_descriptor, head); |
171 | } |
172 | cur = next; |
173 | } |
174 | break; |
175 | } |
176 | case RTM_NEWLINK: { |
177 | ifinfomsg* ifi = reinterpret_cast<ifinfomsg*>(NLMSG_DATA(header)); |
178 | ssize_t payload_len = IFLA_PAYLOAD(header); |
179 | for (rtattr* rta = IFLA_RTA(ifi); RTA_OK(rta, payload_len); |
180 | rta = RTA_NEXT(rta, payload_len)) { |
181 | if (rta->rta_type != IFA_ADDRESS) { |
182 | continue; |
183 | } |
184 | int family = ifi->ifi_family; |
185 | if (family != AF_INET && family != AF_INET6) { |
186 | continue; |
187 | } |
188 | ifaddrs* next = new ifaddrs; |
189 | memset(next, 0, sizeof(*next)); |
190 | if (cur != NULL) { |
191 | cur->ifa_next = next; |
192 | } else { |
193 | head = next; |
194 | } |
195 | if (!SetIfAddrsFromInfoMsg(next, ifi, RTA_DATA(rta), |
196 | RTA_PAYLOAD(rta), header)) { |
197 | return FailAndExit(file_descriptor, head); |
198 | } |
199 | cur = next; |
200 | } |
201 | break; |
202 | } |
203 | case NLMSG_DONE: |
204 | *result = head; |
205 | FDUtils::SaveErrorAndClose(file_descriptor); |
206 | return 0; |
207 | case NLMSG_ERROR: |
208 | return FailAndExit(file_descriptor, head); |
209 | } |
210 | } |
211 | } |
212 | return FailAndExit(file_descriptor, head); |
213 | } |
214 | |
215 | void freeifaddrs(struct ifaddrs* addrs) { |
216 | int err = errno; |
217 | struct ifaddrs* previous = NULL; |
218 | while (addrs != NULL) { |
219 | delete[] addrs->ifa_name; |
220 | delete addrs->ifa_addr; |
221 | delete addrs->ifa_netmask; |
222 | previous = addrs; |
223 | addrs = addrs->ifa_next; |
224 | delete previous; |
225 | } |
226 | errno = err; |
227 | } |
228 | |
229 | } // namespace bin |
230 | } // namespace dart |
231 | |
232 | #endif // defined(ANDROID) && __ANDROID_API__ < 24 |
233 | |