blob: 3abea16b3ee9718afc3a74184a9af5980bb6a94e [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>
Ken Chen22e5fb82020-02-25 18:05:52 +000025#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 Huang743e0312020-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;
Ken Chen22e5fb82020-02-25 18:05:52 +000054// Whether sendto(), sendmsg(), sendmmsg() in libc are shimmed or not. This property is evaluated at
Ken Chen89863932020-02-21 16:30:47 +080055// process start time and cannot change at runtime on a given device.
Ken Chen22e5fb82020-02-25 18:05:52 +000056constexpr 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 Huangc94b9c22020-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)();
Ken Chen22e5fb82020-02-25 18:05:52 +000070typedef 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;
Ken Chen22e5fb82020-02-25 18:05:52 +000079SendmmsgFunctionType 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 Chen89863932020-02-21 16:30:47 +080085 if (__system_property_get(prop_name, prop_value) > 0) {
Ken Chen22e5fb82020-02-25 18:05:52 +000086 if (strcmp(prop_value, "true") == 0) {
87 return true;
88 }
89 }
90 return false;
91}
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -070092
Maciej Żenczykowski492cc712023-08-29 14:05:04 +000093// whether to hook sendmmsg/sendmsg/sendto
94static bool redirectSendX() {
Maciej Żenczykowski815b6882020-04-02 17:05:02 -070095 static bool cached_result = propertyValueIsTrue(PROPERTY_REDIRECT_SOCKET_CALLS);
Ken Chen89863932020-02-21 16:30:47 +080096 return cached_result;
97}
98
Lorenzo Colitti24601da2019-02-14 00:48:36 +090099int checkSocket(int socketFd) {
100 if (socketFd < 0) {
101 return -EBADF;
102 }
103 int family;
104 socklen_t familyLen = sizeof(family);
105 if (getsockopt(socketFd, SOL_SOCKET, SO_DOMAIN, &family, &familyLen) == -1) {
106 return -errno;
107 }
108 if (!FwmarkClient::shouldSetFwmark(family)) {
109 return -EAFNOSUPPORT;
110 }
111 return 0;
112}
113
114bool shouldMarkSocket(int socketFd, const sockaddr* dst) {
115 // Only mark inet sockets that are connecting to inet destinations. This excludes, for example,
116 // inet sockets connecting to AF_UNSPEC (i.e., being disconnected), and non-inet sockets that
117 // for some reason the caller wants to attempt to connect to an inet destination.
118 return dst && FwmarkClient::shouldSetFwmark(dst->sa_family) && (checkSocket(socketFd) == 0);
119}
120
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700121int closeFdAndSetErrno(int fd, int error) {
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -0700122 close(fd);
Sreeram Ramachandran3a069e62014-06-22 11:02:57 -0700123 errno = -error;
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -0700124 return -1;
125}
126
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -0700127int netdClientAccept4(int sockfd, sockaddr* addr, socklen_t* addrlen, int flags) {
128 int acceptedSocket = libcAccept4(sockfd, addr, addrlen, flags);
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -0700129 if (acceptedSocket == -1) {
130 return -1;
131 }
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -0700132 int family;
133 if (addr) {
134 family = addr->sa_family;
135 } else {
136 socklen_t familyLen = sizeof(family);
137 if (getsockopt(acceptedSocket, SOL_SOCKET, SO_DOMAIN, &family, &familyLen) == -1) {
Sreeram Ramachandran3a069e62014-06-22 11:02:57 -0700138 return closeFdAndSetErrno(acceptedSocket, -errno);
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -0700139 }
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -0700140 }
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -0700141 if (FwmarkClient::shouldSetFwmark(family)) {
Chenbo Feng9944ba82017-10-10 17:33:20 -0700142 FwmarkCommand command = {FwmarkCommand::ON_ACCEPT, 0, 0, 0};
Michal Karpinski4b9b78a2016-10-06 19:33:55 +0100143 if (int error = FwmarkClient().send(&command, acceptedSocket, nullptr)) {
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700144 return closeFdAndSetErrno(acceptedSocket, error);
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -0700145 }
146 }
147 return acceptedSocket;
148}
149
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -0700150int netdClientConnect(int sockfd, const sockaddr* addr, socklen_t addrlen) {
Lorenzo Colitti24601da2019-02-14 00:48:36 +0900151 const bool shouldSetFwmark = shouldMarkSocket(sockfd, addr);
Michal Karpinski4b9b78a2016-10-06 19:33:55 +0100152 if (shouldSetFwmark) {
Maciej Żenczykowski1a1e43f2023-09-06 09:48:26 +0000153 FwmarkCommand command = {FwmarkCommand::ON_CONNECT, 0, 0, 0};
Maciej Żenczykowski492cc712023-08-29 14:05:04 +0000154 FwmarkConnectInfo connectInfo(0, 0, addr);
Maciej Żenczykowski898fe6a2023-08-31 01:58:22 +0000155 int error = FwmarkClient().send(&command, sockfd, &connectInfo);
Ken Chen89863932020-02-21 16:30:47 +0800156
157 if (error) {
Sreeram Ramachandran3a069e62014-06-22 11:02:57 -0700158 errno = -error;
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -0700159 return -1;
160 }
161 }
Michal Karpinski4b9b78a2016-10-06 19:33:55 +0100162 // Latency measurement does not include time of sending commands to Fwmark
163 Stopwatch s;
Hugo Benichi794c5c72016-10-31 15:07:23 +0900164 const int ret = libcConnect(sockfd, addr, addrlen);
Michal Karpinski4b9b78a2016-10-06 19:33:55 +0100165 // Save errno so it isn't clobbered by sending ON_CONNECT_COMPLETE
166 const int connectErrno = errno;
Bernie Innocenti196f1b82019-05-20 16:34:16 +0900167 const auto latencyMs = static_cast<unsigned>(s.timeTakenUs() / 1000);
Michal Karpinski4b9b78a2016-10-06 19:33:55 +0100168 // Send an ON_CONNECT_COMPLETE command that includes sockaddr and connect latency for reporting
markchien3a976372019-07-02 16:20:08 +0800169 if (shouldSetFwmark) {
Hugo Benichi794c5c72016-10-31 15:07:23 +0900170 FwmarkConnectInfo connectInfo(ret == 0 ? 0 : connectErrno, latencyMs, addr);
Michal Karpinski4b9b78a2016-10-06 19:33:55 +0100171 // TODO: get the netId from the socket mark once we have continuous benchmark runs
172 FwmarkCommand command = {FwmarkCommand::ON_CONNECT_COMPLETE, /* netId (ignored) */ 0,
Chenbo Feng9944ba82017-10-10 17:33:20 -0700173 /* uid (filled in by the server) */ 0, 0};
Michal Karpinski4b9b78a2016-10-06 19:33:55 +0100174 // Ignore return value since it's only used for logging
175 FwmarkClient().send(&command, sockfd, &connectInfo);
176 }
177 errno = connectErrno;
178 return ret;
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -0700179}
180
181int netdClientSocket(int domain, int type, int protocol) {
Luke Huangc94b9c22020-06-16 19:14:05 +0800182 // Block creating AF_INET/AF_INET6 socket if networking is not allowed.
183 if (FwmarkCommand::isSupportedFamily(domain) && !allowNetworkingForProcess.load()) {
184 errno = EPERM;
185 return -1;
186 }
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -0700187 int socketFd = libcSocket(domain, type, protocol);
188 if (socketFd == -1) {
Tommy Webb0e2a6f02022-09-20 19:07:31 +0000189 // When inet socket creation is blocked, change errno to avoid a SecurityException.
190 if (errno == EPERM && FwmarkCommand::isSupportedFamily(domain)) {
191 // ECONNREFUSED is not documented as a possible error result from socket(), but it
192 // provides the user with an intelligible error, and it's not EPERM.
193 errno = ECONNREFUSED;
194 }
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -0700195 return -1;
196 }
Lorenzo Colitti6b001262019-01-30 22:43:36 +0900197 unsigned netId = netIdForProcess & ~NETID_USE_LOCAL_NAMESERVERS;
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -0700198 if (netId != NETID_UNSET && FwmarkClient::shouldSetFwmark(domain)) {
Sreeram Ramachandrand36c49c2014-07-02 14:49:33 -0700199 if (int error = setNetworkForSocket(netId, socketFd)) {
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700200 return closeFdAndSetErrno(socketFd, error);
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -0700201 }
202 }
203 return socketFd;
204}
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700205
Ken Chen22e5fb82020-02-25 18:05:52 +0000206int netdClientSendmmsg(int sockfd, const mmsghdr* msgs, unsigned int msgcount, int flags) {
Maciej Żenczykowski3e5b1662020-04-02 03:05:18 -0700207 if (propertyValueIsTrue(PROPERTY_REDIRECT_SOCKET_CALLS_HOOKED) && !checkSocket(sockfd)) {
Ken Chen22e5fb82020-02-25 18:05:52 +0000208 const sockaddr* addr = nullptr;
209 if ((msgcount > 0) && (msgs != nullptr) && (msgs[0].msg_hdr.msg_name != nullptr)) {
210 addr = reinterpret_cast<const sockaddr*>(msgs[0].msg_hdr.msg_name);
211 if ((addr != nullptr) && (FwmarkCommand::isSupportedFamily(addr->sa_family))) {
212 FwmarkConnectInfo sendmmsgInfo(0, 0, addr);
213 FwmarkCommand command = {FwmarkCommand::ON_SENDMMSG, 0, 0, 0};
214 FwmarkClient().send(&command, sockfd, &sendmmsgInfo);
215 }
216 }
217 }
218 return libcSendmmsg(sockfd, msgs, msgcount, flags);
219}
220
221ssize_t netdClientSendmsg(int sockfd, const msghdr* msg, unsigned int flags) {
Maciej Żenczykowski3e5b1662020-04-02 03:05:18 -0700222 if (propertyValueIsTrue(PROPERTY_REDIRECT_SOCKET_CALLS_HOOKED) && !checkSocket(sockfd)) {
Ken Chen22e5fb82020-02-25 18:05:52 +0000223 const sockaddr* addr = nullptr;
224 if ((msg != nullptr) && (msg->msg_name != nullptr)) {
225 addr = reinterpret_cast<const sockaddr*>(msg->msg_name);
226 if ((addr != nullptr) && (FwmarkCommand::isSupportedFamily(addr->sa_family))) {
227 FwmarkConnectInfo sendmsgInfo(0, 0, addr);
228 FwmarkCommand command = {FwmarkCommand::ON_SENDMSG, 0, 0, 0};
229 FwmarkClient().send(&command, sockfd, &sendmsgInfo);
230 }
231 }
232 }
233 return libcSendmsg(sockfd, msg, flags);
234}
235
236int netdClientSendto(int sockfd, const void* buf, size_t bufsize, int flags, const sockaddr* addr,
237 socklen_t addrlen) {
Maciej Żenczykowski3e5b1662020-04-02 03:05:18 -0700238 if (propertyValueIsTrue(PROPERTY_REDIRECT_SOCKET_CALLS_HOOKED) && !checkSocket(sockfd)) {
Ken Chen22e5fb82020-02-25 18:05:52 +0000239 if ((addr != nullptr) && (FwmarkCommand::isSupportedFamily(addr->sa_family))) {
240 FwmarkConnectInfo sendtoInfo(0, 0, addr);
241 FwmarkCommand command = {FwmarkCommand::ON_SENDTO, 0, 0, 0};
242 FwmarkClient().send(&command, sockfd, &sendtoInfo);
243 }
244 }
245 return libcSendto(sockfd, buf, bufsize, flags, addr, addrlen);
246}
247
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700248unsigned getNetworkForResolv(unsigned netId) {
249 if (netId != NETID_UNSET) {
250 return netId;
251 }
Erik Kline1564d482018-03-07 17:09:35 +0900252 // Special case for DNS-over-TLS bypass; b/72345192 .
253 if ((netIdForResolv & ~NETID_USE_LOCAL_NAMESERVERS) != NETID_UNSET) {
254 return netIdForResolv;
255 }
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700256 netId = netIdForProcess;
257 if (netId != NETID_UNSET) {
258 return netId;
259 }
260 return netIdForResolv;
261}
262
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700263int setNetworkForTarget(unsigned netId, std::atomic_uint* target) {
Erik Kline1564d482018-03-07 17:09:35 +0900264 const unsigned requestedNetId = netId;
265 netId &= ~NETID_USE_LOCAL_NAMESERVERS;
266
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700267 if (netId == NETID_UNSET) {
268 *target = netId;
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700269 return 0;
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700270 }
271 // 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 -0700272 // with the netId. Call libcSocket() directly; else the socket creation (via netdClientSocket())
273 // might itself cause another check with the fwmark server, which would be wasteful.
Luke Huangc5efae92018-11-19 17:45:13 +0800274
275 const auto socketFunc = libcSocket ? libcSocket : socket;
276 int socketFd = socketFunc(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0);
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700277 if (socketFd < 0) {
Sreeram Ramachandran3a069e62014-06-22 11:02:57 -0700278 return -errno;
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700279 }
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700280 int error = setNetworkForSocket(netId, socketFd);
281 if (!error) {
Lorenzo Colitti6b001262019-01-30 22:43:36 +0900282 *target = requestedNetId;
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700283 }
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700284 close(socketFd);
285 return error;
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700286}
287
Luke Huangc5efae92018-11-19 17:45:13 +0800288int dns_open_proxy() {
289 const char* cache_mode = getenv("ANDROID_DNS_MODE");
290 const bool use_proxy = (cache_mode == NULL || strcmp(cache_mode, "local") != 0);
291 if (!use_proxy) {
Luke Huang63df9482019-05-25 18:24:03 +0800292 errno = ENOSYS;
Luke Huangc5efae92018-11-19 17:45:13 +0800293 return -1;
294 }
295
Luke Huangc94b9c22020-06-16 19:14:05 +0800296 // If networking is not allowed, dns_open_proxy should just fail here.
297 // Then eventually, the DNS related functions in local mode will get
298 // EPERM while creating socket.
299 if (!allowNetworkingForProcess.load()) {
300 errno = EPERM;
301 return -1;
302 }
Luke Huangc5efae92018-11-19 17:45:13 +0800303 const auto socketFunc = libcSocket ? libcSocket : socket;
Tommy Webb0e2a6f02022-09-20 19:07:31 +0000304
305 // If we can't create an INET6 socket, we are restricted elsewhere, e.g. in firewall chains,
306 // so we shouldn't be allowed to resolve DNS. (setNetworkForTarget does this check, too.)
307 int inetTestSocket = socketFunc(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0);
308 if (inetTestSocket < 0) {
309 // Altering the errno here seems to be optional in avoiding a SecurityException, since the
310 // essential handling happens in netdClientSocket, but we do it regardless for consistency.
311 errno = ECONNREFUSED;
312 return -1;
313 }
314 close(inetTestSocket);
315
Luke Huangc5efae92018-11-19 17:45:13 +0800316 int s = socketFunc(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
317 if (s == -1) {
318 return -1;
319 }
320 const int one = 1;
321 setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
322
323 static const struct sockaddr_un proxy_addr = {
324 .sun_family = AF_UNIX,
325 .sun_path = "/dev/socket/dnsproxyd",
326 };
327
328 const auto connectFunc = libcConnect ? libcConnect : connect;
329 if (TEMP_FAILURE_RETRY(
330 connectFunc(s, (const struct sockaddr*) &proxy_addr, sizeof(proxy_addr))) != 0) {
Luke Huang63df9482019-05-25 18:24:03 +0800331 // Store the errno for connect because we only care about why we can't connect to dnsproxyd
332 int storedErrno = errno;
Luke Huangc5efae92018-11-19 17:45:13 +0800333 close(s);
Luke Huang63df9482019-05-25 18:24:03 +0800334 errno = storedErrno;
Luke Huangc5efae92018-11-19 17:45:13 +0800335 return -1;
336 }
337
338 return s;
339}
340
Luke Huangc68f1b92018-11-21 20:13:38 +0800341auto divCeil(size_t dividend, size_t divisor) {
342 return ((dividend + divisor - 1) / divisor);
343}
344
345// FrameworkListener only does only read() call, and fails if the read doesn't contain \0
346// Do single write here
347int sendData(int fd, const void* buf, size_t size) {
348 if (fd < 0) {
349 return -EBADF;
350 }
351
352 ssize_t rc = TEMP_FAILURE_RETRY(write(fd, (char*) buf, size));
353 if (rc > 0) {
354 return rc;
355 } else if (rc == 0) {
356 return -EIO;
357 } else {
358 return -errno;
359 }
360}
361
362int readData(int fd, void* buf, size_t size) {
363 if (fd < 0) {
364 return -EBADF;
365 }
366
367 size_t current = 0;
368 for (;;) {
369 ssize_t rc = TEMP_FAILURE_RETRY(read(fd, (char*) buf + current, size - current));
370 if (rc > 0) {
371 current += rc;
372 if (current == size) {
373 break;
374 }
375 } else if (rc == 0) {
376 return -EIO;
377 } else {
378 return -errno;
379 }
380 }
381 return 0;
382}
383
384bool readBE32(int fd, int32_t* result) {
385 int32_t tmp;
Luke Huang63df9482019-05-25 18:24:03 +0800386 ssize_t n = TEMP_FAILURE_RETRY(read(fd, &tmp, sizeof(tmp)));
387 if (n < static_cast<ssize_t>(sizeof(tmp))) {
Luke Huangc68f1b92018-11-21 20:13:38 +0800388 return false;
389 }
390 *result = ntohl(tmp);
391 return true;
392}
393
Luke Huang63df9482019-05-25 18:24:03 +0800394bool readResponseCode(int fd, int* result) {
Luke Huang185098d2019-05-20 16:17:12 +0800395 char buf[4];
Luke Huang63df9482019-05-25 18:24:03 +0800396 ssize_t n = TEMP_FAILURE_RETRY(read(fd, &buf, sizeof(buf)));
397 if (n < static_cast<ssize_t>(sizeof(buf))) {
Luke Huang185098d2019-05-20 16:17:12 +0800398 return false;
399 }
400
401 // The format of response code is 3 bytes followed by a space.
402 buf[3] = '\0';
403 if (!ParseInt(buf, result)) {
404 errno = EINVAL;
405 return false;
406 }
407
408 return true;
409}
410
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -0700411} // namespace
412
Maciej Żenczykowski3e5b1662020-04-02 03:05:18 -0700413#define CHECK_SOCKET_IS_MARKABLE(sock) \
414 do { \
415 int err = checkSocket(sock); \
416 if (err) return err; \
417 } while (false)
Remi NGUYEN VANeabc5da2018-04-24 18:54:58 +0900418
Ken Chen89863932020-02-21 16:30:47 +0800419#define HOOK_ON_FUNC(remoteFunc, nativeFunc, localFunc) \
420 do { \
Maciej Żenczykowski3e5b1662020-04-02 03:05:18 -0700421 if ((remoteFunc) && *(remoteFunc)) { \
422 (nativeFunc) = *(remoteFunc); \
423 *(remoteFunc) = (localFunc); \
Ken Chen89863932020-02-21 16:30:47 +0800424 } \
425 } while (false)
426
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -0700427// accept() just calls accept4(..., 0), so there's no need to handle accept() separately.
428extern "C" void netdClientInitAccept4(Accept4FunctionType* function) {
Ken Chen89863932020-02-21 16:30:47 +0800429 HOOK_ON_FUNC(function, libcAccept4, netdClientAccept4);
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -0700430}
431
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -0700432extern "C" void netdClientInitConnect(ConnectFunctionType* function) {
Ken Chen89863932020-02-21 16:30:47 +0800433 HOOK_ON_FUNC(function, libcConnect, netdClientConnect);
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -0700434}
435
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -0700436extern "C" void netdClientInitSocket(SocketFunctionType* function) {
Ken Chen89863932020-02-21 16:30:47 +0800437 HOOK_ON_FUNC(function, libcSocket, netdClientSocket);
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -0700438}
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700439
Ken Chen22e5fb82020-02-25 18:05:52 +0000440extern "C" void netdClientInitSendmmsg(SendmmsgFunctionType* function) {
Maciej Żenczykowski492cc712023-08-29 14:05:04 +0000441 if (redirectSendX()) HOOK_ON_FUNC(function, libcSendmmsg, netdClientSendmmsg);
Ken Chen22e5fb82020-02-25 18:05:52 +0000442}
443
444extern "C" void netdClientInitSendmsg(SendmsgFunctionType* function) {
Maciej Żenczykowski492cc712023-08-29 14:05:04 +0000445 if (redirectSendX()) HOOK_ON_FUNC(function, libcSendmsg, netdClientSendmsg);
Ken Chen22e5fb82020-02-25 18:05:52 +0000446}
447
448extern "C" void netdClientInitSendto(SendtoFunctionType* function) {
Maciej Żenczykowski492cc712023-08-29 14:05:04 +0000449 if (redirectSendX()) HOOK_ON_FUNC(function, libcSendto, netdClientSendto);
Ken Chen22e5fb82020-02-25 18:05:52 +0000450}
451
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700452extern "C" void netdClientInitNetIdForResolv(NetIdForResolvFunctionType* function) {
453 if (function) {
454 *function = getNetworkForResolv;
455 }
456}
457
Luke Huangc5efae92018-11-19 17:45:13 +0800458extern "C" void netdClientInitDnsOpenProxy(DnsOpenProxyType* function) {
459 if (function) {
460 *function = dns_open_proxy;
461 }
462}
463
Sreeram Ramachandran4d4c8b72014-06-20 11:59:40 -0700464extern "C" int getNetworkForSocket(unsigned* netId, int socketFd) {
465 if (!netId || socketFd < 0) {
Sreeram Ramachandran3a069e62014-06-22 11:02:57 -0700466 return -EBADF;
Sreeram Ramachandran4d4c8b72014-06-20 11:59:40 -0700467 }
468 Fwmark fwmark;
469 socklen_t fwmarkLen = sizeof(fwmark.intValue);
470 if (getsockopt(socketFd, SOL_SOCKET, SO_MARK, &fwmark.intValue, &fwmarkLen) == -1) {
Sreeram Ramachandran3a069e62014-06-22 11:02:57 -0700471 return -errno;
Sreeram Ramachandran4d4c8b72014-06-20 11:59:40 -0700472 }
473 *netId = fwmark.netId;
474 return 0;
475}
476
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700477extern "C" unsigned getNetworkForProcess() {
Lorenzo Colitti6b001262019-01-30 22:43:36 +0900478 return netIdForProcess & ~NETID_USE_LOCAL_NAMESERVERS;
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700479}
480
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700481extern "C" int setNetworkForSocket(unsigned netId, int socketFd) {
Remi NGUYEN VANeabc5da2018-04-24 18:54:58 +0900482 CHECK_SOCKET_IS_MARKABLE(socketFd);
Chenbo Feng9944ba82017-10-10 17:33:20 -0700483 FwmarkCommand command = {FwmarkCommand::SELECT_NETWORK, netId, 0, 0};
Michal Karpinski4b9b78a2016-10-06 19:33:55 +0100484 return FwmarkClient().send(&command, socketFd, nullptr);
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700485}
486
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700487extern "C" int setNetworkForProcess(unsigned netId) {
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700488 return setNetworkForTarget(netId, &netIdForProcess);
489}
490
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700491extern "C" int setNetworkForResolv(unsigned netId) {
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700492 return setNetworkForTarget(netId, &netIdForResolv);
493}
Sreeram Ramachandrand794e582014-06-19 10:03:07 -0700494
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700495extern "C" int protectFromVpn(int socketFd) {
Maciej Żenczykowski3e5b1662020-04-02 03:05:18 -0700496 CHECK_SOCKET_IS_MARKABLE(socketFd);
Chenbo Feng9944ba82017-10-10 17:33:20 -0700497 FwmarkCommand command = {FwmarkCommand::PROTECT_FROM_VPN, 0, 0, 0};
Michal Karpinski4b9b78a2016-10-06 19:33:55 +0100498 return FwmarkClient().send(&command, socketFd, nullptr);
Sreeram Ramachandrana69d9472014-07-11 16:27:02 -0700499}
500
501extern "C" int setNetworkForUser(uid_t uid, int socketFd) {
Remi NGUYEN VANeabc5da2018-04-24 18:54:58 +0900502 CHECK_SOCKET_IS_MARKABLE(socketFd);
Chenbo Feng9944ba82017-10-10 17:33:20 -0700503 FwmarkCommand command = {FwmarkCommand::SELECT_FOR_USER, 0, uid, 0};
Michal Karpinski4b9b78a2016-10-06 19:33:55 +0100504 return FwmarkClient().send(&command, socketFd, nullptr);
Paul Jensend1df5972015-05-06 07:29:56 -0400505}
506
507extern "C" int queryUserAccess(uid_t uid, unsigned netId) {
Chenbo Feng9944ba82017-10-10 17:33:20 -0700508 FwmarkCommand command = {FwmarkCommand::QUERY_USER_ACCESS, netId, uid, 0};
509 return FwmarkClient().send(&command, -1, nullptr);
510}
511
512extern "C" int tagSocket(int socketFd, uint32_t tag, uid_t uid) {
Remi NGUYEN VANeabc5da2018-04-24 18:54:58 +0900513 CHECK_SOCKET_IS_MARKABLE(socketFd);
Chenbo Feng9944ba82017-10-10 17:33:20 -0700514 FwmarkCommand command = {FwmarkCommand::TAG_SOCKET, 0, uid, tag};
515 return FwmarkClient().send(&command, socketFd, nullptr);
516}
517
518extern "C" int untagSocket(int socketFd) {
Remi NGUYEN VANeabc5da2018-04-24 18:54:58 +0900519 CHECK_SOCKET_IS_MARKABLE(socketFd);
Chenbo Feng9944ba82017-10-10 17:33:20 -0700520 FwmarkCommand command = {FwmarkCommand::UNTAG_SOCKET, 0, 0, 0};
521 return FwmarkClient().send(&command, socketFd, nullptr);
522}
523
Luke Huang110c54e2018-12-20 14:39:58 +0800524extern "C" int resNetworkQuery(unsigned netId, const char* dname, int ns_class, int ns_type,
525 uint32_t flags) {
Luke Huange48fbcb2018-12-17 16:37:33 +0800526 std::vector<uint8_t> buf(MAX_CMD_SIZE, 0);
527 int len = res_mkquery(ns_o_query, dname, ns_class, ns_type, nullptr, 0, nullptr, buf.data(),
528 MAX_CMD_SIZE);
Luke Huangc68f1b92018-11-21 20:13:38 +0800529
Luke Huang110c54e2018-12-20 14:39:58 +0800530 return resNetworkSend(netId, buf.data(), len, flags);
Luke Huangc68f1b92018-11-21 20:13:38 +0800531}
532
Luke Huang952d0942018-12-26 16:53:03 +0800533extern "C" int resNetworkSend(unsigned netId, const uint8_t* msg, size_t msglen, uint32_t flags) {
Luke Huangc68f1b92018-11-21 20:13:38 +0800534 // Encode
535 // Base 64 encodes every 3 bytes into 4 characters, but then adds padding to the next
536 // multiple of 4 and a \0
537 const size_t encodedLen = divCeil(msglen, 3) * 4 + 1;
Luke Huange48fbcb2018-12-17 16:37:33 +0800538 std::string encodedQuery(encodedLen - 1, 0);
Luke Huangc68f1b92018-11-21 20:13:38 +0800539 int enLen = b64_ntop(msg, msglen, encodedQuery.data(), encodedLen);
540
541 if (enLen < 0) {
542 // Unexpected behavior, encode failed
543 // b64_ntop only fails when size is too long.
544 return -EMSGSIZE;
545 }
546 // Send
547 netId = getNetworkForResolv(netId);
Luke Huang952d0942018-12-26 16:53:03 +0800548 const std::string cmd = "resnsend " + std::to_string(netId) + " " + std::to_string(flags) +
549 " " + encodedQuery + '\0';
Luke Huangc68f1b92018-11-21 20:13:38 +0800550 if (cmd.size() > MAX_CMD_SIZE) {
551 // Cmd size must less than buffer size of FrameworkListener
552 return -EMSGSIZE;
553 }
554 int fd = dns_open_proxy();
555 if (fd == -1) {
556 return -errno;
557 }
558 ssize_t rc = sendData(fd, cmd.c_str(), cmd.size());
559 if (rc < 0) {
560 close(fd);
561 return rc;
562 }
563 shutdown(fd, SHUT_WR);
564 return fd;
565}
566
Luke Huange48fbcb2018-12-17 16:37:33 +0800567extern "C" int resNetworkResult(int fd, int* rcode, uint8_t* answer, size_t anslen) {
Luke Huangc68f1b92018-11-21 20:13:38 +0800568 int32_t result = 0;
569 unique_fd ufd(fd);
570 // Read -errno/rcode
571 if (!readBE32(fd, &result)) {
572 // Unexpected behavior, read -errno/rcode fail
573 return -errno;
574 }
575 if (result < 0) {
576 // result < 0, it's -errno
577 return result;
578 }
579 // result >= 0, it's rcode
580 *rcode = result;
581
582 // Read answer
583 int32_t size = 0;
584 if (!readBE32(fd, &size)) {
585 // Unexpected behavior, read ans len fail
586 return -EREMOTEIO;
587 }
Luke Huange48fbcb2018-12-17 16:37:33 +0800588 if (anslen < static_cast<size_t>(size)) {
Luke Huangc68f1b92018-11-21 20:13:38 +0800589 // Answer buffer is too small
590 return -EMSGSIZE;
591 }
592 int rc = readData(fd, answer, size);
593 if (rc < 0) {
594 // Reading the answer failed.
595 return rc;
596 }
597 return size;
598}
599
600extern "C" void resNetworkCancel(int fd) {
601 close(fd);
Lorenzo Colitti6b001262019-01-30 22:43:36 +0900602}
Luke Huang185098d2019-05-20 16:17:12 +0800603
Luke Huangc94b9c22020-06-16 19:14:05 +0800604extern "C" void setAllowNetworkingForProcess(bool allowNetworking) {
605 allowNetworkingForProcess.store(allowNetworking);
606}
607
Luke Huang63df9482019-05-25 18:24:03 +0800608extern "C" int getNetworkForDns(unsigned* dnsNetId) {
609 if (dnsNetId == nullptr) return -EFAULT;
Luke Huang185098d2019-05-20 16:17:12 +0800610 int fd = dns_open_proxy();
611 if (fd == -1) {
612 return -errno;
613 }
614 unique_fd ufd(fd);
Luke Huang63df9482019-05-25 18:24:03 +0800615 return getNetworkForDnsInternal(fd, dnsNetId);
616}
617
618int getNetworkForDnsInternal(int fd, unsigned* dnsNetId) {
619 if (fd == -1) {
620 return -EBADF;
621 }
622
623 unsigned resolvNetId = getNetworkForResolv(NETID_UNSET);
624
625 const std::string cmd = "getdnsnetid " + std::to_string(resolvNetId);
Luke Huang185098d2019-05-20 16:17:12 +0800626 ssize_t rc = sendData(fd, cmd.c_str(), cmd.size() + 1);
627 if (rc < 0) {
628 return rc;
629 }
630
631 int responseCode = 0;
632 // Read responseCode
Luke Huang63df9482019-05-25 18:24:03 +0800633 if (!readResponseCode(fd, &responseCode)) {
Luke Huang185098d2019-05-20 16:17:12 +0800634 // Unexpected behavior, read responseCode fail
635 return -errno;
636 }
637
638 if (responseCode != ResponseCode::DnsProxyQueryResult) {
639 return -EOPNOTSUPP;
640 }
641
642 int32_t result = 0;
643 // Read -errno/dnsnetid
644 if (!readBE32(fd, &result)) {
645 // Unexpected behavior, read -errno/dnsnetid fail
646 return -errno;
647 }
648
Luke Huang63df9482019-05-25 18:24:03 +0800649 *dnsNetId = result;
650
651 return 0;
Luke Huang185098d2019-05-20 16:17:12 +0800652}