blob: 0105a0477b6c9e9468cd455c54beb9466b1c57bf [file] [log] [blame]
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -07001/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -070017#include "NetdClient.h"
18
Michal Karpinski4b9b78a2016-10-06 19:33:55 +010019#include <arpa/inet.h>
Dan Albertaa1be2b2015-01-06 09:36:17 -080020#include <errno.h>
Michal Karpinski4b9b78a2016-10-06 19:33:55 +010021#include <math.h>
Luke Huangc68f1b92018-11-21 20:13:38 +080022#include <resolv.h>
Luke Huangc5efae92018-11-19 17:45:13 +080023#include <stdlib.h>
Dan Albertaa1be2b2015-01-06 09:36:17 -080024#include <sys/socket.h>
Praveen Moongalam Thyagarajanf24eb882019-12-18 11:59:47 -080025#include <sys/system_properties.h>
Luke Huangc5efae92018-11-19 17:45:13 +080026#include <sys/un.h>
Dan Albertaa1be2b2015-01-06 09:36:17 -080027#include <unistd.h>
28
29#include <atomic>
Luke Huangc68f1b92018-11-21 20:13:38 +080030#include <string>
31#include <vector>
Dan Albertaa1be2b2015-01-06 09:36:17 -080032
Luke Huang3b56e5c2020-05-26 17:21:28 +080033#include <DnsProxydProtocol.h> // NETID_USE_LOCAL_NAMESERVERS
Luke Huang63df9482019-05-25 18:24:03 +080034#include <android-base/parseint.h>
35#include <android-base/unique_fd.h>
36
Sreeram Ramachandran4d4c8b72014-06-20 11:59:40 -070037#include "Fwmark.h"
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -070038#include "FwmarkClient.h"
39#include "FwmarkCommand.h"
Luke Huang63df9482019-05-25 18:24:03 +080040#include "netdclient_priv.h"
Luke Huang185098d2019-05-20 16:17:12 +080041#include "netdutils/ResponseCode.h"
Mike Yue7e332f2019-03-13 17:15:48 +080042#include "netdutils/Stopwatch.h"
Bernie Innocenti189eb502018-10-01 23:10:18 +090043#include "netid_client.h"
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -070044
Luke Huang185098d2019-05-20 16:17:12 +080045using android::base::ParseInt;
Luke Huangc68f1b92018-11-21 20:13:38 +080046using android::base::unique_fd;
Luke Huang185098d2019-05-20 16:17:12 +080047using android::netdutils::ResponseCode;
Mike Yue7e332f2019-03-13 17:15:48 +080048using android::netdutils::Stopwatch;
Luke Huangc68f1b92018-11-21 20:13:38 +080049
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -070050namespace {
51
Luke Huangc68f1b92018-11-21 20:13:38 +080052// Keep this in sync with CMD_BUF_SIZE in FrameworkListener.cpp.
Luke Huange92b75e2019-03-26 17:56:49 +080053constexpr size_t MAX_CMD_SIZE = 4096;
Praveen Moongalam Thyagarajanf24eb882019-12-18 11:59:47 -080054// Whether sendto(), sendmsg(), sendmmsg() in libc are shimmed or not. This property is evaluated at
Ken Chen1782aea2020-02-21 16:30:47 +080055// process start time and cannot change at runtime on a given device.
Praveen Moongalam Thyagarajanf24eb882019-12-18 11:59:47 -080056constexpr char PROPERTY_REDIRECT_SOCKET_CALLS[] = "ro.vendor.redirect_socket_calls";
57// Whether some shimmed functions dispatch FwmarkCommand or not. The property can be changed by
58// System Server at runtime. Note: accept4(), socket(), connect() are always shimmed.
59constexpr char PROPERTY_REDIRECT_SOCKET_CALLS_HOOKED[] = "net.redirect_socket_calls.hooked";
Luke Huangc68f1b92018-11-21 20:13:38 +080060
Sreeram Ramachandran9fa2b132014-06-03 12:51:08 -070061std::atomic_uint netIdForProcess(NETID_UNSET);
62std::atomic_uint netIdForResolv(NETID_UNSET);
Luke Huang86983202020-06-16 19:14:05 +080063std::atomic_bool allowNetworkingForProcess(true);
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -070064
65typedef int (*Accept4FunctionType)(int, sockaddr*, socklen_t*, int);
66typedef int (*ConnectFunctionType)(int, const sockaddr*, socklen_t);
67typedef int (*SocketFunctionType)(int, int, int);
68typedef unsigned (*NetIdForResolvFunctionType)(unsigned);
Luke Huangc5efae92018-11-19 17:45:13 +080069typedef int (*DnsOpenProxyType)();
Praveen Moongalam Thyagarajanf24eb882019-12-18 11:59:47 -080070typedef int (*SendmmsgFunctionType)(int, const mmsghdr*, unsigned int, int);
71typedef ssize_t (*SendmsgFunctionType)(int, const msghdr*, unsigned int);
72typedef int (*SendtoFunctionType)(int, const void*, size_t, int, const sockaddr*, socklen_t);
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -070073
74// These variables are only modified at startup (when libc.so is loaded) and never afterwards, so
75// it's okay that they are read later at runtime without a lock.
Yi Kongbdfd57e2018-07-25 13:26:10 -070076Accept4FunctionType libcAccept4 = nullptr;
77ConnectFunctionType libcConnect = nullptr;
78SocketFunctionType libcSocket = nullptr;
Praveen Moongalam Thyagarajanf24eb882019-12-18 11:59:47 -080079SendmmsgFunctionType libcSendmmsg = nullptr;
80SendmsgFunctionType libcSendmsg = nullptr;
81SendtoFunctionType libcSendto = nullptr;
82
83static bool propertyValueIsTrue(const char* prop_name) {
84 char prop_value[PROP_VALUE_MAX] = {0};
Ken Chen1782aea2020-02-21 16:30:47 +080085 if (__system_property_get(prop_name, prop_value) > 0) {
Praveen Moongalam Thyagarajanf24eb882019-12-18 11:59:47 -080086 if (strcmp(prop_value, "true") == 0) {
87 return true;
88 }
89 }
90 return false;
91}
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -070092
Ken Chen1782aea2020-02-21 16:30:47 +080093static bool redirectSocketCallsIsTrue() {
Maciej Żenczykowskia590f672020-04-22 04:11:41 +000094 static bool cached_result = propertyValueIsTrue(PROPERTY_REDIRECT_SOCKET_CALLS);
Ken Chen1782aea2020-02-21 16:30:47 +080095 return cached_result;
96}
97
Lorenzo Colitti24601da2019-02-14 00:48:36 +090098int checkSocket(int socketFd) {
99 if (socketFd < 0) {
100 return -EBADF;
101 }
102 int family;
103 socklen_t familyLen = sizeof(family);
104 if (getsockopt(socketFd, SOL_SOCKET, SO_DOMAIN, &family, &familyLen) == -1) {
105 return -errno;
106 }
107 if (!FwmarkClient::shouldSetFwmark(family)) {
108 return -EAFNOSUPPORT;
109 }
110 return 0;
111}
112
113bool shouldMarkSocket(int socketFd, const sockaddr* dst) {
114 // Only mark inet sockets that are connecting to inet destinations. This excludes, for example,
115 // inet sockets connecting to AF_UNSPEC (i.e., being disconnected), and non-inet sockets that
116 // for some reason the caller wants to attempt to connect to an inet destination.
117 return dst && FwmarkClient::shouldSetFwmark(dst->sa_family) && (checkSocket(socketFd) == 0);
118}
119
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700120int closeFdAndSetErrno(int fd, int error) {
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -0700121 close(fd);
Sreeram Ramachandran3a069e62014-06-22 11:02:57 -0700122 errno = -error;
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -0700123 return -1;
124}
125
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -0700126int netdClientAccept4(int sockfd, sockaddr* addr, socklen_t* addrlen, int flags) {
127 int acceptedSocket = libcAccept4(sockfd, addr, addrlen, flags);
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -0700128 if (acceptedSocket == -1) {
129 return -1;
130 }
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -0700131 int family;
132 if (addr) {
133 family = addr->sa_family;
134 } else {
135 socklen_t familyLen = sizeof(family);
136 if (getsockopt(acceptedSocket, SOL_SOCKET, SO_DOMAIN, &family, &familyLen) == -1) {
Sreeram Ramachandran3a069e62014-06-22 11:02:57 -0700137 return closeFdAndSetErrno(acceptedSocket, -errno);
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -0700138 }
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -0700139 }
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -0700140 if (FwmarkClient::shouldSetFwmark(family)) {
Chenbo Feng9944ba82017-10-10 17:33:20 -0700141 FwmarkCommand command = {FwmarkCommand::ON_ACCEPT, 0, 0, 0};
Michal Karpinski4b9b78a2016-10-06 19:33:55 +0100142 if (int error = FwmarkClient().send(&command, acceptedSocket, nullptr)) {
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700143 return closeFdAndSetErrno(acceptedSocket, error);
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -0700144 }
145 }
146 return acceptedSocket;
147}
148
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -0700149int netdClientConnect(int sockfd, const sockaddr* addr, socklen_t addrlen) {
Lorenzo Colitti24601da2019-02-14 00:48:36 +0900150 const bool shouldSetFwmark = shouldMarkSocket(sockfd, addr);
Michal Karpinski4b9b78a2016-10-06 19:33:55 +0100151 if (shouldSetFwmark) {
Chenbo Feng9944ba82017-10-10 17:33:20 -0700152 FwmarkCommand command = {FwmarkCommand::ON_CONNECT, 0, 0, 0};
Ken Chen1782aea2020-02-21 16:30:47 +0800153 int error;
154 if (redirectSocketCallsIsTrue()) {
155 FwmarkConnectInfo connectInfo(0, 0, addr);
156 error = FwmarkClient().send(&command, sockfd, &connectInfo);
157 } else {
158 error = FwmarkClient().send(&command, sockfd, nullptr);
159 }
160
161 if (error) {
Sreeram Ramachandran3a069e62014-06-22 11:02:57 -0700162 errno = -error;
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -0700163 return -1;
164 }
165 }
Michal Karpinski4b9b78a2016-10-06 19:33:55 +0100166 // Latency measurement does not include time of sending commands to Fwmark
167 Stopwatch s;
Hugo Benichi794c5c72016-10-31 15:07:23 +0900168 const int ret = libcConnect(sockfd, addr, addrlen);
Michal Karpinski4b9b78a2016-10-06 19:33:55 +0100169 // Save errno so it isn't clobbered by sending ON_CONNECT_COMPLETE
170 const int connectErrno = errno;
Bernie Innocenti196f1b82019-05-20 16:34:16 +0900171 const auto latencyMs = static_cast<unsigned>(s.timeTakenUs() / 1000);
Michal Karpinski4b9b78a2016-10-06 19:33:55 +0100172 // Send an ON_CONNECT_COMPLETE command that includes sockaddr and connect latency for reporting
markchien3a976372019-07-02 16:20:08 +0800173 if (shouldSetFwmark) {
Hugo Benichi794c5c72016-10-31 15:07:23 +0900174 FwmarkConnectInfo connectInfo(ret == 0 ? 0 : connectErrno, latencyMs, addr);
Michal Karpinski4b9b78a2016-10-06 19:33:55 +0100175 // TODO: get the netId from the socket mark once we have continuous benchmark runs
176 FwmarkCommand command = {FwmarkCommand::ON_CONNECT_COMPLETE, /* netId (ignored) */ 0,
Chenbo Feng9944ba82017-10-10 17:33:20 -0700177 /* uid (filled in by the server) */ 0, 0};
Michal Karpinski4b9b78a2016-10-06 19:33:55 +0100178 // Ignore return value since it's only used for logging
179 FwmarkClient().send(&command, sockfd, &connectInfo);
180 }
181 errno = connectErrno;
182 return ret;
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -0700183}
184
185int netdClientSocket(int domain, int type, int protocol) {
Luke Huang86983202020-06-16 19:14:05 +0800186 // Block creating AF_INET/AF_INET6 socket if networking is not allowed.
187 if (FwmarkCommand::isSupportedFamily(domain) && !allowNetworkingForProcess.load()) {
188 errno = EPERM;
189 return -1;
190 }
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -0700191 int socketFd = libcSocket(domain, type, protocol);
192 if (socketFd == -1) {
193 return -1;
194 }
Lorenzo Colitti6b001262019-01-30 22:43:36 +0900195 unsigned netId = netIdForProcess & ~NETID_USE_LOCAL_NAMESERVERS;
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -0700196 if (netId != NETID_UNSET && FwmarkClient::shouldSetFwmark(domain)) {
Sreeram Ramachandrand36c49c2014-07-02 14:49:33 -0700197 if (int error = setNetworkForSocket(netId, socketFd)) {
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700198 return closeFdAndSetErrno(socketFd, error);
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -0700199 }
200 }
201 return socketFd;
202}
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700203
Praveen Moongalam Thyagarajanf24eb882019-12-18 11:59:47 -0800204int netdClientSendmmsg(int sockfd, const mmsghdr* msgs, unsigned int msgcount, int flags) {
Treehugger Robot1b966652020-04-07 05:50:41 +0000205 if (propertyValueIsTrue(PROPERTY_REDIRECT_SOCKET_CALLS_HOOKED) && !checkSocket(sockfd)) {
Praveen Moongalam Thyagarajanf24eb882019-12-18 11:59:47 -0800206 const sockaddr* addr = nullptr;
207 if ((msgcount > 0) && (msgs != nullptr) && (msgs[0].msg_hdr.msg_name != nullptr)) {
208 addr = reinterpret_cast<const sockaddr*>(msgs[0].msg_hdr.msg_name);
209 if ((addr != nullptr) && (FwmarkCommand::isSupportedFamily(addr->sa_family))) {
210 FwmarkConnectInfo sendmmsgInfo(0, 0, addr);
211 FwmarkCommand command = {FwmarkCommand::ON_SENDMMSG, 0, 0, 0};
212 FwmarkClient().send(&command, sockfd, &sendmmsgInfo);
213 }
214 }
215 }
216 return libcSendmmsg(sockfd, msgs, msgcount, flags);
217}
218
219ssize_t netdClientSendmsg(int sockfd, const msghdr* msg, unsigned int flags) {
Treehugger Robot1b966652020-04-07 05:50:41 +0000220 if (propertyValueIsTrue(PROPERTY_REDIRECT_SOCKET_CALLS_HOOKED) && !checkSocket(sockfd)) {
Praveen Moongalam Thyagarajanf24eb882019-12-18 11:59:47 -0800221 const sockaddr* addr = nullptr;
222 if ((msg != nullptr) && (msg->msg_name != nullptr)) {
223 addr = reinterpret_cast<const sockaddr*>(msg->msg_name);
224 if ((addr != nullptr) && (FwmarkCommand::isSupportedFamily(addr->sa_family))) {
225 FwmarkConnectInfo sendmsgInfo(0, 0, addr);
226 FwmarkCommand command = {FwmarkCommand::ON_SENDMSG, 0, 0, 0};
227 FwmarkClient().send(&command, sockfd, &sendmsgInfo);
228 }
229 }
230 }
231 return libcSendmsg(sockfd, msg, flags);
232}
233
234int netdClientSendto(int sockfd, const void* buf, size_t bufsize, int flags, const sockaddr* addr,
235 socklen_t addrlen) {
Treehugger Robot1b966652020-04-07 05:50:41 +0000236 if (propertyValueIsTrue(PROPERTY_REDIRECT_SOCKET_CALLS_HOOKED) && !checkSocket(sockfd)) {
Praveen Moongalam Thyagarajanf24eb882019-12-18 11:59:47 -0800237 if ((addr != nullptr) && (FwmarkCommand::isSupportedFamily(addr->sa_family))) {
238 FwmarkConnectInfo sendtoInfo(0, 0, addr);
239 FwmarkCommand command = {FwmarkCommand::ON_SENDTO, 0, 0, 0};
240 FwmarkClient().send(&command, sockfd, &sendtoInfo);
241 }
242 }
243 return libcSendto(sockfd, buf, bufsize, flags, addr, addrlen);
244}
245
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700246unsigned getNetworkForResolv(unsigned netId) {
247 if (netId != NETID_UNSET) {
248 return netId;
249 }
Erik Kline1564d482018-03-07 17:09:35 +0900250 // Special case for DNS-over-TLS bypass; b/72345192 .
251 if ((netIdForResolv & ~NETID_USE_LOCAL_NAMESERVERS) != NETID_UNSET) {
252 return netIdForResolv;
253 }
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700254 netId = netIdForProcess;
255 if (netId != NETID_UNSET) {
256 return netId;
257 }
258 return netIdForResolv;
259}
260
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700261int setNetworkForTarget(unsigned netId, std::atomic_uint* target) {
Erik Kline1564d482018-03-07 17:09:35 +0900262 const unsigned requestedNetId = netId;
263 netId &= ~NETID_USE_LOCAL_NAMESERVERS;
264
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700265 if (netId == NETID_UNSET) {
266 *target = netId;
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700267 return 0;
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700268 }
269 // Verify that we are allowed to use |netId|, by creating a socket and trying to have it marked
Sreeram Ramachandran27560452014-05-30 19:59:51 -0700270 // with the netId. Call libcSocket() directly; else the socket creation (via netdClientSocket())
271 // might itself cause another check with the fwmark server, which would be wasteful.
Luke Huangc5efae92018-11-19 17:45:13 +0800272
273 const auto socketFunc = libcSocket ? libcSocket : socket;
274 int socketFd = socketFunc(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0);
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700275 if (socketFd < 0) {
Sreeram Ramachandran3a069e62014-06-22 11:02:57 -0700276 return -errno;
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700277 }
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700278 int error = setNetworkForSocket(netId, socketFd);
279 if (!error) {
Lorenzo Colitti6b001262019-01-30 22:43:36 +0900280 *target = requestedNetId;
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700281 }
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700282 close(socketFd);
283 return error;
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700284}
285
Luke Huangc5efae92018-11-19 17:45:13 +0800286int dns_open_proxy() {
287 const char* cache_mode = getenv("ANDROID_DNS_MODE");
288 const bool use_proxy = (cache_mode == NULL || strcmp(cache_mode, "local") != 0);
289 if (!use_proxy) {
Luke Huang63df9482019-05-25 18:24:03 +0800290 errno = ENOSYS;
Luke Huangc5efae92018-11-19 17:45:13 +0800291 return -1;
292 }
293
Luke Huang86983202020-06-16 19:14:05 +0800294 // If networking is not allowed, dns_open_proxy should just fail here.
295 // Then eventually, the DNS related functions in local mode will get
296 // EPERM while creating socket.
297 if (!allowNetworkingForProcess.load()) {
298 errno = EPERM;
299 return -1;
300 }
Luke Huangc5efae92018-11-19 17:45:13 +0800301 const auto socketFunc = libcSocket ? libcSocket : socket;
302 int s = socketFunc(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
303 if (s == -1) {
304 return -1;
305 }
306 const int one = 1;
307 setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
308
309 static const struct sockaddr_un proxy_addr = {
310 .sun_family = AF_UNIX,
311 .sun_path = "/dev/socket/dnsproxyd",
312 };
313
314 const auto connectFunc = libcConnect ? libcConnect : connect;
315 if (TEMP_FAILURE_RETRY(
316 connectFunc(s, (const struct sockaddr*) &proxy_addr, sizeof(proxy_addr))) != 0) {
Luke Huang63df9482019-05-25 18:24:03 +0800317 // Store the errno for connect because we only care about why we can't connect to dnsproxyd
318 int storedErrno = errno;
Luke Huangc5efae92018-11-19 17:45:13 +0800319 close(s);
Luke Huang63df9482019-05-25 18:24:03 +0800320 errno = storedErrno;
Luke Huangc5efae92018-11-19 17:45:13 +0800321 return -1;
322 }
323
324 return s;
325}
326
Luke Huangc68f1b92018-11-21 20:13:38 +0800327auto divCeil(size_t dividend, size_t divisor) {
328 return ((dividend + divisor - 1) / divisor);
329}
330
331// FrameworkListener only does only read() call, and fails if the read doesn't contain \0
332// Do single write here
333int sendData(int fd, const void* buf, size_t size) {
334 if (fd < 0) {
335 return -EBADF;
336 }
337
338 ssize_t rc = TEMP_FAILURE_RETRY(write(fd, (char*) buf, size));
339 if (rc > 0) {
340 return rc;
341 } else if (rc == 0) {
342 return -EIO;
343 } else {
344 return -errno;
345 }
346}
347
348int readData(int fd, void* buf, size_t size) {
349 if (fd < 0) {
350 return -EBADF;
351 }
352
353 size_t current = 0;
354 for (;;) {
355 ssize_t rc = TEMP_FAILURE_RETRY(read(fd, (char*) buf + current, size - current));
356 if (rc > 0) {
357 current += rc;
358 if (current == size) {
359 break;
360 }
361 } else if (rc == 0) {
362 return -EIO;
363 } else {
364 return -errno;
365 }
366 }
367 return 0;
368}
369
370bool readBE32(int fd, int32_t* result) {
371 int32_t tmp;
Luke Huang63df9482019-05-25 18:24:03 +0800372 ssize_t n = TEMP_FAILURE_RETRY(read(fd, &tmp, sizeof(tmp)));
373 if (n < static_cast<ssize_t>(sizeof(tmp))) {
Luke Huangc68f1b92018-11-21 20:13:38 +0800374 return false;
375 }
376 *result = ntohl(tmp);
377 return true;
378}
379
Luke Huang63df9482019-05-25 18:24:03 +0800380bool readResponseCode(int fd, int* result) {
Luke Huang185098d2019-05-20 16:17:12 +0800381 char buf[4];
Luke Huang63df9482019-05-25 18:24:03 +0800382 ssize_t n = TEMP_FAILURE_RETRY(read(fd, &buf, sizeof(buf)));
383 if (n < static_cast<ssize_t>(sizeof(buf))) {
Luke Huang185098d2019-05-20 16:17:12 +0800384 return false;
385 }
386
387 // The format of response code is 3 bytes followed by a space.
388 buf[3] = '\0';
389 if (!ParseInt(buf, result)) {
390 errno = EINVAL;
391 return false;
392 }
393
394 return true;
395}
396
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -0700397} // namespace
398
Treehugger Robot1b966652020-04-07 05:50:41 +0000399#define CHECK_SOCKET_IS_MARKABLE(sock) \
400 do { \
401 int err = checkSocket(sock); \
402 if (err) return err; \
403 } while (false)
Remi NGUYEN VANeabc5da2018-04-24 18:54:58 +0900404
Ken Chen1782aea2020-02-21 16:30:47 +0800405#define HOOK_ON_FUNC(remoteFunc, nativeFunc, localFunc) \
406 do { \
Treehugger Robot1b966652020-04-07 05:50:41 +0000407 if ((remoteFunc) && *(remoteFunc)) { \
408 (nativeFunc) = *(remoteFunc); \
409 *(remoteFunc) = (localFunc); \
Ken Chen1782aea2020-02-21 16:30:47 +0800410 } \
411 } while (false)
412
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -0700413// accept() just calls accept4(..., 0), so there's no need to handle accept() separately.
414extern "C" void netdClientInitAccept4(Accept4FunctionType* function) {
Ken Chen1782aea2020-02-21 16:30:47 +0800415 HOOK_ON_FUNC(function, libcAccept4, netdClientAccept4);
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -0700416}
417
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -0700418extern "C" void netdClientInitConnect(ConnectFunctionType* function) {
Ken Chen1782aea2020-02-21 16:30:47 +0800419 HOOK_ON_FUNC(function, libcConnect, netdClientConnect);
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -0700420}
421
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -0700422extern "C" void netdClientInitSocket(SocketFunctionType* function) {
Ken Chen1782aea2020-02-21 16:30:47 +0800423 HOOK_ON_FUNC(function, libcSocket, netdClientSocket);
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -0700424}
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700425
Praveen Moongalam Thyagarajanf24eb882019-12-18 11:59:47 -0800426extern "C" void netdClientInitSendmmsg(SendmmsgFunctionType* function) {
427 if (!propertyValueIsTrue(PROPERTY_REDIRECT_SOCKET_CALLS)) {
428 return;
429 }
Ken Chen1782aea2020-02-21 16:30:47 +0800430 HOOK_ON_FUNC(function, libcSendmmsg, netdClientSendmmsg);
Praveen Moongalam Thyagarajanf24eb882019-12-18 11:59:47 -0800431}
432
433extern "C" void netdClientInitSendmsg(SendmsgFunctionType* function) {
434 if (!propertyValueIsTrue(PROPERTY_REDIRECT_SOCKET_CALLS)) {
435 return;
436 }
Ken Chen1782aea2020-02-21 16:30:47 +0800437 HOOK_ON_FUNC(function, libcSendmsg, netdClientSendmsg);
Praveen Moongalam Thyagarajanf24eb882019-12-18 11:59:47 -0800438}
439
440extern "C" void netdClientInitSendto(SendtoFunctionType* function) {
441 if (!propertyValueIsTrue(PROPERTY_REDIRECT_SOCKET_CALLS)) {
442 return;
443 }
Ken Chen1782aea2020-02-21 16:30:47 +0800444 HOOK_ON_FUNC(function, libcSendto, netdClientSendto);
Praveen Moongalam Thyagarajanf24eb882019-12-18 11:59:47 -0800445}
446
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700447extern "C" void netdClientInitNetIdForResolv(NetIdForResolvFunctionType* function) {
448 if (function) {
449 *function = getNetworkForResolv;
450 }
451}
452
Luke Huangc5efae92018-11-19 17:45:13 +0800453extern "C" void netdClientInitDnsOpenProxy(DnsOpenProxyType* function) {
454 if (function) {
455 *function = dns_open_proxy;
456 }
457}
458
Sreeram Ramachandran4d4c8b72014-06-20 11:59:40 -0700459extern "C" int getNetworkForSocket(unsigned* netId, int socketFd) {
460 if (!netId || socketFd < 0) {
Sreeram Ramachandran3a069e62014-06-22 11:02:57 -0700461 return -EBADF;
Sreeram Ramachandran4d4c8b72014-06-20 11:59:40 -0700462 }
463 Fwmark fwmark;
464 socklen_t fwmarkLen = sizeof(fwmark.intValue);
465 if (getsockopt(socketFd, SOL_SOCKET, SO_MARK, &fwmark.intValue, &fwmarkLen) == -1) {
Sreeram Ramachandran3a069e62014-06-22 11:02:57 -0700466 return -errno;
Sreeram Ramachandran4d4c8b72014-06-20 11:59:40 -0700467 }
468 *netId = fwmark.netId;
469 return 0;
470}
471
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700472extern "C" unsigned getNetworkForProcess() {
Lorenzo Colitti6b001262019-01-30 22:43:36 +0900473 return netIdForProcess & ~NETID_USE_LOCAL_NAMESERVERS;
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700474}
475
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700476extern "C" int setNetworkForSocket(unsigned netId, int socketFd) {
Remi NGUYEN VANeabc5da2018-04-24 18:54:58 +0900477 CHECK_SOCKET_IS_MARKABLE(socketFd);
Chenbo Feng9944ba82017-10-10 17:33:20 -0700478 FwmarkCommand command = {FwmarkCommand::SELECT_NETWORK, netId, 0, 0};
Michal Karpinski4b9b78a2016-10-06 19:33:55 +0100479 return FwmarkClient().send(&command, socketFd, nullptr);
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700480}
481
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700482extern "C" int setNetworkForProcess(unsigned netId) {
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700483 return setNetworkForTarget(netId, &netIdForProcess);
484}
485
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700486extern "C" int setNetworkForResolv(unsigned netId) {
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700487 return setNetworkForTarget(netId, &netIdForResolv);
488}
Sreeram Ramachandrand794e582014-06-19 10:03:07 -0700489
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700490extern "C" int protectFromVpn(int socketFd) {
Treehugger Robot1b966652020-04-07 05:50:41 +0000491 CHECK_SOCKET_IS_MARKABLE(socketFd);
Chenbo Feng9944ba82017-10-10 17:33:20 -0700492 FwmarkCommand command = {FwmarkCommand::PROTECT_FROM_VPN, 0, 0, 0};
Michal Karpinski4b9b78a2016-10-06 19:33:55 +0100493 return FwmarkClient().send(&command, socketFd, nullptr);
Sreeram Ramachandrana69d9472014-07-11 16:27:02 -0700494}
495
496extern "C" int setNetworkForUser(uid_t uid, int socketFd) {
Remi NGUYEN VANeabc5da2018-04-24 18:54:58 +0900497 CHECK_SOCKET_IS_MARKABLE(socketFd);
Chenbo Feng9944ba82017-10-10 17:33:20 -0700498 FwmarkCommand command = {FwmarkCommand::SELECT_FOR_USER, 0, uid, 0};
Michal Karpinski4b9b78a2016-10-06 19:33:55 +0100499 return FwmarkClient().send(&command, socketFd, nullptr);
Paul Jensend1df5972015-05-06 07:29:56 -0400500}
501
502extern "C" int queryUserAccess(uid_t uid, unsigned netId) {
Chenbo Feng9944ba82017-10-10 17:33:20 -0700503 FwmarkCommand command = {FwmarkCommand::QUERY_USER_ACCESS, netId, uid, 0};
504 return FwmarkClient().send(&command, -1, nullptr);
505}
506
507extern "C" int tagSocket(int socketFd, uint32_t tag, uid_t uid) {
Remi NGUYEN VANeabc5da2018-04-24 18:54:58 +0900508 CHECK_SOCKET_IS_MARKABLE(socketFd);
Chenbo Feng9944ba82017-10-10 17:33:20 -0700509 FwmarkCommand command = {FwmarkCommand::TAG_SOCKET, 0, uid, tag};
510 return FwmarkClient().send(&command, socketFd, nullptr);
511}
512
513extern "C" int untagSocket(int socketFd) {
Remi NGUYEN VANeabc5da2018-04-24 18:54:58 +0900514 CHECK_SOCKET_IS_MARKABLE(socketFd);
Chenbo Feng9944ba82017-10-10 17:33:20 -0700515 FwmarkCommand command = {FwmarkCommand::UNTAG_SOCKET, 0, 0, 0};
516 return FwmarkClient().send(&command, socketFd, nullptr);
517}
518
519extern "C" int setCounterSet(uint32_t counterSet, uid_t uid) {
520 FwmarkCommand command = {FwmarkCommand::SET_COUNTERSET, 0, uid, counterSet};
521 return FwmarkClient().send(&command, -1, nullptr);
522}
523
524extern "C" int deleteTagData(uint32_t tag, uid_t uid) {
525 FwmarkCommand command = {FwmarkCommand::DELETE_TAGDATA, 0, uid, tag};
Michal Karpinski4b9b78a2016-10-06 19:33:55 +0100526 return FwmarkClient().send(&command, -1, nullptr);
Sreeram Ramachandrand794e582014-06-19 10:03:07 -0700527}
Luke Huangc68f1b92018-11-21 20:13:38 +0800528
Luke Huang110c54e2018-12-20 14:39:58 +0800529extern "C" int resNetworkQuery(unsigned netId, const char* dname, int ns_class, int ns_type,
530 uint32_t flags) {
Luke Huange48fbcb2018-12-17 16:37:33 +0800531 std::vector<uint8_t> buf(MAX_CMD_SIZE, 0);
532 int len = res_mkquery(ns_o_query, dname, ns_class, ns_type, nullptr, 0, nullptr, buf.data(),
533 MAX_CMD_SIZE);
Luke Huangc68f1b92018-11-21 20:13:38 +0800534
Luke Huang110c54e2018-12-20 14:39:58 +0800535 return resNetworkSend(netId, buf.data(), len, flags);
Luke Huangc68f1b92018-11-21 20:13:38 +0800536}
537
Luke Huang952d0942018-12-26 16:53:03 +0800538extern "C" int resNetworkSend(unsigned netId, const uint8_t* msg, size_t msglen, uint32_t flags) {
Luke Huangc68f1b92018-11-21 20:13:38 +0800539 // Encode
540 // Base 64 encodes every 3 bytes into 4 characters, but then adds padding to the next
541 // multiple of 4 and a \0
542 const size_t encodedLen = divCeil(msglen, 3) * 4 + 1;
Luke Huange48fbcb2018-12-17 16:37:33 +0800543 std::string encodedQuery(encodedLen - 1, 0);
Luke Huangc68f1b92018-11-21 20:13:38 +0800544 int enLen = b64_ntop(msg, msglen, encodedQuery.data(), encodedLen);
545
546 if (enLen < 0) {
547 // Unexpected behavior, encode failed
548 // b64_ntop only fails when size is too long.
549 return -EMSGSIZE;
550 }
551 // Send
552 netId = getNetworkForResolv(netId);
Luke Huang952d0942018-12-26 16:53:03 +0800553 const std::string cmd = "resnsend " + std::to_string(netId) + " " + std::to_string(flags) +
554 " " + encodedQuery + '\0';
Luke Huangc68f1b92018-11-21 20:13:38 +0800555 if (cmd.size() > MAX_CMD_SIZE) {
556 // Cmd size must less than buffer size of FrameworkListener
557 return -EMSGSIZE;
558 }
559 int fd = dns_open_proxy();
560 if (fd == -1) {
561 return -errno;
562 }
563 ssize_t rc = sendData(fd, cmd.c_str(), cmd.size());
564 if (rc < 0) {
565 close(fd);
566 return rc;
567 }
568 shutdown(fd, SHUT_WR);
569 return fd;
570}
571
Luke Huange48fbcb2018-12-17 16:37:33 +0800572extern "C" int resNetworkResult(int fd, int* rcode, uint8_t* answer, size_t anslen) {
Luke Huangc68f1b92018-11-21 20:13:38 +0800573 int32_t result = 0;
574 unique_fd ufd(fd);
575 // Read -errno/rcode
576 if (!readBE32(fd, &result)) {
577 // Unexpected behavior, read -errno/rcode fail
578 return -errno;
579 }
580 if (result < 0) {
581 // result < 0, it's -errno
582 return result;
583 }
584 // result >= 0, it's rcode
585 *rcode = result;
586
587 // Read answer
588 int32_t size = 0;
589 if (!readBE32(fd, &size)) {
590 // Unexpected behavior, read ans len fail
591 return -EREMOTEIO;
592 }
Luke Huange48fbcb2018-12-17 16:37:33 +0800593 if (anslen < static_cast<size_t>(size)) {
Luke Huangc68f1b92018-11-21 20:13:38 +0800594 // Answer buffer is too small
595 return -EMSGSIZE;
596 }
597 int rc = readData(fd, answer, size);
598 if (rc < 0) {
599 // Reading the answer failed.
600 return rc;
601 }
602 return size;
603}
604
605extern "C" void resNetworkCancel(int fd) {
606 close(fd);
Lorenzo Colitti6b001262019-01-30 22:43:36 +0900607}
Luke Huang185098d2019-05-20 16:17:12 +0800608
Luke Huang86983202020-06-16 19:14:05 +0800609extern "C" void setAllowNetworkingForProcess(bool allowNetworking) {
610 allowNetworkingForProcess.store(allowNetworking);
611}
612
Luke Huang63df9482019-05-25 18:24:03 +0800613extern "C" int getNetworkForDns(unsigned* dnsNetId) {
614 if (dnsNetId == nullptr) return -EFAULT;
Luke Huang185098d2019-05-20 16:17:12 +0800615 int fd = dns_open_proxy();
616 if (fd == -1) {
617 return -errno;
618 }
619 unique_fd ufd(fd);
Luke Huang63df9482019-05-25 18:24:03 +0800620 return getNetworkForDnsInternal(fd, dnsNetId);
621}
622
623int getNetworkForDnsInternal(int fd, unsigned* dnsNetId) {
624 if (fd == -1) {
625 return -EBADF;
626 }
627
628 unsigned resolvNetId = getNetworkForResolv(NETID_UNSET);
629
630 const std::string cmd = "getdnsnetid " + std::to_string(resolvNetId);
Luke Huang185098d2019-05-20 16:17:12 +0800631 ssize_t rc = sendData(fd, cmd.c_str(), cmd.size() + 1);
632 if (rc < 0) {
633 return rc;
634 }
635
636 int responseCode = 0;
637 // Read responseCode
Luke Huang63df9482019-05-25 18:24:03 +0800638 if (!readResponseCode(fd, &responseCode)) {
Luke Huang185098d2019-05-20 16:17:12 +0800639 // Unexpected behavior, read responseCode fail
640 return -errno;
641 }
642
643 if (responseCode != ResponseCode::DnsProxyQueryResult) {
644 return -EOPNOTSUPP;
645 }
646
647 int32_t result = 0;
648 // Read -errno/dnsnetid
649 if (!readBE32(fd, &result)) {
650 // Unexpected behavior, read -errno/dnsnetid fail
651 return -errno;
652 }
653
Luke Huang63df9482019-05-25 18:24:03 +0800654 *dnsNetId = result;
655
656 return 0;
Luke Huang185098d2019-05-20 16:17:12 +0800657}