blob: 634480b1135b802b2036ac892ac62d8cbdd14c49 [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 Huang63df9482019-05-25 18:24:03 +080033#include <android-base/parseint.h>
34#include <android-base/unique_fd.h>
35
Sreeram Ramachandran4d4c8b72014-06-20 11:59:40 -070036#include "Fwmark.h"
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -070037#include "FwmarkClient.h"
38#include "FwmarkCommand.h"
Luke Huang63df9482019-05-25 18:24:03 +080039#include "netdclient_priv.h"
Luke Huang185098d2019-05-20 16:17:12 +080040#include "netdutils/ResponseCode.h"
Mike Yue7e332f2019-03-13 17:15:48 +080041#include "netdutils/Stopwatch.h"
Bernie Innocenti189eb502018-10-01 23:10:18 +090042#include "netid_client.h"
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -070043
Luke Huang185098d2019-05-20 16:17:12 +080044using android::base::ParseInt;
Luke Huangc68f1b92018-11-21 20:13:38 +080045using android::base::unique_fd;
Luke Huang185098d2019-05-20 16:17:12 +080046using android::netdutils::ResponseCode;
Mike Yue7e332f2019-03-13 17:15:48 +080047using android::netdutils::Stopwatch;
Luke Huangc68f1b92018-11-21 20:13:38 +080048
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -070049namespace {
50
Luke Huangc68f1b92018-11-21 20:13:38 +080051// Keep this in sync with CMD_BUF_SIZE in FrameworkListener.cpp.
Luke Huange92b75e2019-03-26 17:56:49 +080052constexpr size_t MAX_CMD_SIZE = 4096;
Praveen Moongalam Thyagarajanf24eb882019-12-18 11:59:47 -080053// Whether sendto(), sendmsg(), sendmmsg() in libc are shimmed or not. This property is evaluated at
54// process start time and is cannot change at runtime on a given device.
55constexpr char PROPERTY_REDIRECT_SOCKET_CALLS[] = "ro.vendor.redirect_socket_calls";
56// Whether some shimmed functions dispatch FwmarkCommand or not. The property can be changed by
57// System Server at runtime. Note: accept4(), socket(), connect() are always shimmed.
58constexpr char PROPERTY_REDIRECT_SOCKET_CALLS_HOOKED[] = "net.redirect_socket_calls.hooked";
Luke Huangc68f1b92018-11-21 20:13:38 +080059
Sreeram Ramachandran9fa2b132014-06-03 12:51:08 -070060std::atomic_uint netIdForProcess(NETID_UNSET);
61std::atomic_uint netIdForResolv(NETID_UNSET);
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -070062
63typedef int (*Accept4FunctionType)(int, sockaddr*, socklen_t*, int);
64typedef int (*ConnectFunctionType)(int, const sockaddr*, socklen_t);
65typedef int (*SocketFunctionType)(int, int, int);
66typedef unsigned (*NetIdForResolvFunctionType)(unsigned);
Luke Huangc5efae92018-11-19 17:45:13 +080067typedef int (*DnsOpenProxyType)();
Praveen Moongalam Thyagarajanf24eb882019-12-18 11:59:47 -080068typedef int (*SendmmsgFunctionType)(int, const mmsghdr*, unsigned int, int);
69typedef ssize_t (*SendmsgFunctionType)(int, const msghdr*, unsigned int);
70typedef int (*SendtoFunctionType)(int, const void*, size_t, int, const sockaddr*, socklen_t);
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -070071
72// These variables are only modified at startup (when libc.so is loaded) and never afterwards, so
73// it's okay that they are read later at runtime without a lock.
Yi Kongbdfd57e2018-07-25 13:26:10 -070074Accept4FunctionType libcAccept4 = nullptr;
75ConnectFunctionType libcConnect = nullptr;
76SocketFunctionType libcSocket = nullptr;
Praveen Moongalam Thyagarajanf24eb882019-12-18 11:59:47 -080077SendmmsgFunctionType libcSendmmsg = nullptr;
78SendmsgFunctionType libcSendmsg = nullptr;
79SendtoFunctionType libcSendto = nullptr;
80
81static bool propertyValueIsTrue(const char* prop_name) {
82 char prop_value[PROP_VALUE_MAX] = {0};
83 int length = __system_property_get(prop_name, prop_value);
84 if (length > 0 && length < PROP_VALUE_MAX) {
85 prop_value[length] = '\0';
86 if (strcmp(prop_value, "true") == 0) {
87 return true;
88 }
89 }
90 return false;
91}
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -070092
Lorenzo Colitti24601da2019-02-14 00:48:36 +090093int checkSocket(int socketFd) {
94 if (socketFd < 0) {
95 return -EBADF;
96 }
97 int family;
98 socklen_t familyLen = sizeof(family);
99 if (getsockopt(socketFd, SOL_SOCKET, SO_DOMAIN, &family, &familyLen) == -1) {
100 return -errno;
101 }
102 if (!FwmarkClient::shouldSetFwmark(family)) {
103 return -EAFNOSUPPORT;
104 }
105 return 0;
106}
107
108bool shouldMarkSocket(int socketFd, const sockaddr* dst) {
109 // Only mark inet sockets that are connecting to inet destinations. This excludes, for example,
110 // inet sockets connecting to AF_UNSPEC (i.e., being disconnected), and non-inet sockets that
111 // for some reason the caller wants to attempt to connect to an inet destination.
112 return dst && FwmarkClient::shouldSetFwmark(dst->sa_family) && (checkSocket(socketFd) == 0);
113}
114
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700115int closeFdAndSetErrno(int fd, int error) {
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -0700116 close(fd);
Sreeram Ramachandran3a069e62014-06-22 11:02:57 -0700117 errno = -error;
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -0700118 return -1;
119}
120
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -0700121int netdClientAccept4(int sockfd, sockaddr* addr, socklen_t* addrlen, int flags) {
122 int acceptedSocket = libcAccept4(sockfd, addr, addrlen, flags);
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -0700123 if (acceptedSocket == -1) {
124 return -1;
125 }
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -0700126 int family;
127 if (addr) {
128 family = addr->sa_family;
129 } else {
130 socklen_t familyLen = sizeof(family);
131 if (getsockopt(acceptedSocket, SOL_SOCKET, SO_DOMAIN, &family, &familyLen) == -1) {
Sreeram Ramachandran3a069e62014-06-22 11:02:57 -0700132 return closeFdAndSetErrno(acceptedSocket, -errno);
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -0700133 }
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -0700134 }
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -0700135 if (FwmarkClient::shouldSetFwmark(family)) {
Chenbo Feng9944ba82017-10-10 17:33:20 -0700136 FwmarkCommand command = {FwmarkCommand::ON_ACCEPT, 0, 0, 0};
Michal Karpinski4b9b78a2016-10-06 19:33:55 +0100137 if (int error = FwmarkClient().send(&command, acceptedSocket, nullptr)) {
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700138 return closeFdAndSetErrno(acceptedSocket, error);
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -0700139 }
140 }
141 return acceptedSocket;
142}
143
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -0700144int netdClientConnect(int sockfd, const sockaddr* addr, socklen_t addrlen) {
Lorenzo Colitti24601da2019-02-14 00:48:36 +0900145 const bool shouldSetFwmark = shouldMarkSocket(sockfd, addr);
Michal Karpinski4b9b78a2016-10-06 19:33:55 +0100146 if (shouldSetFwmark) {
Praveen Moongalam Thyagarajanf24eb882019-12-18 11:59:47 -0800147 FwmarkConnectInfo connectInfo(0, 0, addr);
Chenbo Feng9944ba82017-10-10 17:33:20 -0700148 FwmarkCommand command = {FwmarkCommand::ON_CONNECT, 0, 0, 0};
Praveen Moongalam Thyagarajanf24eb882019-12-18 11:59:47 -0800149 if (int error = FwmarkClient().send(&command, sockfd, &connectInfo)) {
Sreeram Ramachandran3a069e62014-06-22 11:02:57 -0700150 errno = -error;
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -0700151 return -1;
152 }
153 }
Michal Karpinski4b9b78a2016-10-06 19:33:55 +0100154 // Latency measurement does not include time of sending commands to Fwmark
155 Stopwatch s;
Hugo Benichi794c5c72016-10-31 15:07:23 +0900156 const int ret = libcConnect(sockfd, addr, addrlen);
Michal Karpinski4b9b78a2016-10-06 19:33:55 +0100157 // Save errno so it isn't clobbered by sending ON_CONNECT_COMPLETE
158 const int connectErrno = errno;
Bernie Innocenti196f1b82019-05-20 16:34:16 +0900159 const auto latencyMs = static_cast<unsigned>(s.timeTakenUs() / 1000);
Michal Karpinski4b9b78a2016-10-06 19:33:55 +0100160 // Send an ON_CONNECT_COMPLETE command that includes sockaddr and connect latency for reporting
markchien3a976372019-07-02 16:20:08 +0800161 if (shouldSetFwmark) {
Hugo Benichi794c5c72016-10-31 15:07:23 +0900162 FwmarkConnectInfo connectInfo(ret == 0 ? 0 : connectErrno, latencyMs, addr);
Michal Karpinski4b9b78a2016-10-06 19:33:55 +0100163 // TODO: get the netId from the socket mark once we have continuous benchmark runs
164 FwmarkCommand command = {FwmarkCommand::ON_CONNECT_COMPLETE, /* netId (ignored) */ 0,
Chenbo Feng9944ba82017-10-10 17:33:20 -0700165 /* uid (filled in by the server) */ 0, 0};
Michal Karpinski4b9b78a2016-10-06 19:33:55 +0100166 // Ignore return value since it's only used for logging
167 FwmarkClient().send(&command, sockfd, &connectInfo);
168 }
169 errno = connectErrno;
170 return ret;
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -0700171}
172
173int netdClientSocket(int domain, int type, int protocol) {
174 int socketFd = libcSocket(domain, type, protocol);
175 if (socketFd == -1) {
176 return -1;
177 }
Lorenzo Colitti6b001262019-01-30 22:43:36 +0900178 unsigned netId = netIdForProcess & ~NETID_USE_LOCAL_NAMESERVERS;
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -0700179 if (netId != NETID_UNSET && FwmarkClient::shouldSetFwmark(domain)) {
Sreeram Ramachandrand36c49c2014-07-02 14:49:33 -0700180 if (int error = setNetworkForSocket(netId, socketFd)) {
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700181 return closeFdAndSetErrno(socketFd, error);
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -0700182 }
183 }
184 return socketFd;
185}
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700186
Praveen Moongalam Thyagarajanf24eb882019-12-18 11:59:47 -0800187int netdClientSendmmsg(int sockfd, const mmsghdr* msgs, unsigned int msgcount, int flags) {
188 if (propertyValueIsTrue(PROPERTY_REDIRECT_SOCKET_CALLS_HOOKED)) {
189 const sockaddr* addr = nullptr;
190 if ((msgcount > 0) && (msgs != nullptr) && (msgs[0].msg_hdr.msg_name != nullptr)) {
191 addr = reinterpret_cast<const sockaddr*>(msgs[0].msg_hdr.msg_name);
192 if ((addr != nullptr) && (FwmarkCommand::isSupportedFamily(addr->sa_family))) {
193 FwmarkConnectInfo sendmmsgInfo(0, 0, addr);
194 FwmarkCommand command = {FwmarkCommand::ON_SENDMMSG, 0, 0, 0};
195 FwmarkClient().send(&command, sockfd, &sendmmsgInfo);
196 }
197 }
198 }
199 return libcSendmmsg(sockfd, msgs, msgcount, flags);
200}
201
202ssize_t netdClientSendmsg(int sockfd, const msghdr* msg, unsigned int flags) {
203 if (propertyValueIsTrue(PROPERTY_REDIRECT_SOCKET_CALLS_HOOKED)) {
204 const sockaddr* addr = nullptr;
205 if ((msg != nullptr) && (msg->msg_name != nullptr)) {
206 addr = reinterpret_cast<const sockaddr*>(msg->msg_name);
207 if ((addr != nullptr) && (FwmarkCommand::isSupportedFamily(addr->sa_family))) {
208 FwmarkConnectInfo sendmsgInfo(0, 0, addr);
209 FwmarkCommand command = {FwmarkCommand::ON_SENDMSG, 0, 0, 0};
210 FwmarkClient().send(&command, sockfd, &sendmsgInfo);
211 }
212 }
213 }
214 return libcSendmsg(sockfd, msg, flags);
215}
216
217int netdClientSendto(int sockfd, const void* buf, size_t bufsize, int flags, const sockaddr* addr,
218 socklen_t addrlen) {
219 if (propertyValueIsTrue(PROPERTY_REDIRECT_SOCKET_CALLS_HOOKED)) {
220 if ((addr != nullptr) && (FwmarkCommand::isSupportedFamily(addr->sa_family))) {
221 FwmarkConnectInfo sendtoInfo(0, 0, addr);
222 FwmarkCommand command = {FwmarkCommand::ON_SENDTO, 0, 0, 0};
223 FwmarkClient().send(&command, sockfd, &sendtoInfo);
224 }
225 }
226 return libcSendto(sockfd, buf, bufsize, flags, addr, addrlen);
227}
228
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700229unsigned getNetworkForResolv(unsigned netId) {
230 if (netId != NETID_UNSET) {
231 return netId;
232 }
Erik Kline1564d482018-03-07 17:09:35 +0900233 // Special case for DNS-over-TLS bypass; b/72345192 .
234 if ((netIdForResolv & ~NETID_USE_LOCAL_NAMESERVERS) != NETID_UNSET) {
235 return netIdForResolv;
236 }
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700237 netId = netIdForProcess;
238 if (netId != NETID_UNSET) {
239 return netId;
240 }
241 return netIdForResolv;
242}
243
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700244int setNetworkForTarget(unsigned netId, std::atomic_uint* target) {
Erik Kline1564d482018-03-07 17:09:35 +0900245 const unsigned requestedNetId = netId;
246 netId &= ~NETID_USE_LOCAL_NAMESERVERS;
247
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700248 if (netId == NETID_UNSET) {
249 *target = netId;
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700250 return 0;
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700251 }
252 // 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 -0700253 // with the netId. Call libcSocket() directly; else the socket creation (via netdClientSocket())
254 // might itself cause another check with the fwmark server, which would be wasteful.
Luke Huangc5efae92018-11-19 17:45:13 +0800255
256 const auto socketFunc = libcSocket ? libcSocket : socket;
257 int socketFd = socketFunc(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0);
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700258 if (socketFd < 0) {
Sreeram Ramachandran3a069e62014-06-22 11:02:57 -0700259 return -errno;
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700260 }
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700261 int error = setNetworkForSocket(netId, socketFd);
262 if (!error) {
Lorenzo Colitti6b001262019-01-30 22:43:36 +0900263 *target = requestedNetId;
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700264 }
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700265 close(socketFd);
266 return error;
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700267}
268
Luke Huangc5efae92018-11-19 17:45:13 +0800269int dns_open_proxy() {
270 const char* cache_mode = getenv("ANDROID_DNS_MODE");
271 const bool use_proxy = (cache_mode == NULL || strcmp(cache_mode, "local") != 0);
272 if (!use_proxy) {
Luke Huang63df9482019-05-25 18:24:03 +0800273 errno = ENOSYS;
Luke Huangc5efae92018-11-19 17:45:13 +0800274 return -1;
275 }
276
277 const auto socketFunc = libcSocket ? libcSocket : socket;
278 int s = socketFunc(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
279 if (s == -1) {
280 return -1;
281 }
282 const int one = 1;
283 setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
284
285 static const struct sockaddr_un proxy_addr = {
286 .sun_family = AF_UNIX,
287 .sun_path = "/dev/socket/dnsproxyd",
288 };
289
290 const auto connectFunc = libcConnect ? libcConnect : connect;
291 if (TEMP_FAILURE_RETRY(
292 connectFunc(s, (const struct sockaddr*) &proxy_addr, sizeof(proxy_addr))) != 0) {
Luke Huang63df9482019-05-25 18:24:03 +0800293 // Store the errno for connect because we only care about why we can't connect to dnsproxyd
294 int storedErrno = errno;
Luke Huangc5efae92018-11-19 17:45:13 +0800295 close(s);
Luke Huang63df9482019-05-25 18:24:03 +0800296 errno = storedErrno;
Luke Huangc5efae92018-11-19 17:45:13 +0800297 return -1;
298 }
299
300 return s;
301}
302
Luke Huangc68f1b92018-11-21 20:13:38 +0800303auto divCeil(size_t dividend, size_t divisor) {
304 return ((dividend + divisor - 1) / divisor);
305}
306
307// FrameworkListener only does only read() call, and fails if the read doesn't contain \0
308// Do single write here
309int sendData(int fd, const void* buf, size_t size) {
310 if (fd < 0) {
311 return -EBADF;
312 }
313
314 ssize_t rc = TEMP_FAILURE_RETRY(write(fd, (char*) buf, size));
315 if (rc > 0) {
316 return rc;
317 } else if (rc == 0) {
318 return -EIO;
319 } else {
320 return -errno;
321 }
322}
323
324int readData(int fd, void* buf, size_t size) {
325 if (fd < 0) {
326 return -EBADF;
327 }
328
329 size_t current = 0;
330 for (;;) {
331 ssize_t rc = TEMP_FAILURE_RETRY(read(fd, (char*) buf + current, size - current));
332 if (rc > 0) {
333 current += rc;
334 if (current == size) {
335 break;
336 }
337 } else if (rc == 0) {
338 return -EIO;
339 } else {
340 return -errno;
341 }
342 }
343 return 0;
344}
345
346bool readBE32(int fd, int32_t* result) {
347 int32_t tmp;
Luke Huang63df9482019-05-25 18:24:03 +0800348 ssize_t n = TEMP_FAILURE_RETRY(read(fd, &tmp, sizeof(tmp)));
349 if (n < static_cast<ssize_t>(sizeof(tmp))) {
Luke Huangc68f1b92018-11-21 20:13:38 +0800350 return false;
351 }
352 *result = ntohl(tmp);
353 return true;
354}
355
Luke Huang63df9482019-05-25 18:24:03 +0800356bool readResponseCode(int fd, int* result) {
Luke Huang185098d2019-05-20 16:17:12 +0800357 char buf[4];
Luke Huang63df9482019-05-25 18:24:03 +0800358 ssize_t n = TEMP_FAILURE_RETRY(read(fd, &buf, sizeof(buf)));
359 if (n < static_cast<ssize_t>(sizeof(buf))) {
Luke Huang185098d2019-05-20 16:17:12 +0800360 return false;
361 }
362
363 // The format of response code is 3 bytes followed by a space.
364 buf[3] = '\0';
365 if (!ParseInt(buf, result)) {
366 errno = EINVAL;
367 return false;
368 }
369
370 return true;
371}
372
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -0700373} // namespace
374
Remi NGUYEN VANeabc5da2018-04-24 18:54:58 +0900375#define CHECK_SOCKET_IS_MARKABLE(sock) \
376 do { \
377 int err; \
378 if ((err = checkSocket(sock)) != 0) { \
379 return err; \
380 } \
381 } while (false);
382
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -0700383// accept() just calls accept4(..., 0), so there's no need to handle accept() separately.
384extern "C" void netdClientInitAccept4(Accept4FunctionType* function) {
385 if (function && *function) {
386 libcAccept4 = *function;
387 *function = netdClientAccept4;
388 }
389}
390
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -0700391extern "C" void netdClientInitConnect(ConnectFunctionType* function) {
392 if (function && *function) {
393 libcConnect = *function;
394 *function = netdClientConnect;
395 }
396}
397
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -0700398extern "C" void netdClientInitSocket(SocketFunctionType* function) {
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -0700399 if (function && *function) {
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -0700400 libcSocket = *function;
401 *function = netdClientSocket;
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -0700402 }
403}
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700404
Praveen Moongalam Thyagarajanf24eb882019-12-18 11:59:47 -0800405extern "C" void netdClientInitSendmmsg(SendmmsgFunctionType* function) {
406 if (!propertyValueIsTrue(PROPERTY_REDIRECT_SOCKET_CALLS)) {
407 return;
408 }
409
410 if (function && *function) {
411 libcSendmmsg = *function;
412 *function = netdClientSendmmsg;
413 }
414}
415
416extern "C" void netdClientInitSendmsg(SendmsgFunctionType* function) {
417 if (!propertyValueIsTrue(PROPERTY_REDIRECT_SOCKET_CALLS)) {
418 return;
419 }
420
421 if (function && *function) {
422 libcSendmsg = *function;
423 *function = netdClientSendmsg;
424 }
425}
426
427extern "C" void netdClientInitSendto(SendtoFunctionType* function) {
428 if (!propertyValueIsTrue(PROPERTY_REDIRECT_SOCKET_CALLS)) {
429 return;
430 }
431
432 if (function && *function) {
433 libcSendto = *function;
434 *function = netdClientSendto;
435 }
436}
437
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700438extern "C" void netdClientInitNetIdForResolv(NetIdForResolvFunctionType* function) {
439 if (function) {
440 *function = getNetworkForResolv;
441 }
442}
443
Luke Huangc5efae92018-11-19 17:45:13 +0800444extern "C" void netdClientInitDnsOpenProxy(DnsOpenProxyType* function) {
445 if (function) {
446 *function = dns_open_proxy;
447 }
448}
449
Sreeram Ramachandran4d4c8b72014-06-20 11:59:40 -0700450extern "C" int getNetworkForSocket(unsigned* netId, int socketFd) {
451 if (!netId || socketFd < 0) {
Sreeram Ramachandran3a069e62014-06-22 11:02:57 -0700452 return -EBADF;
Sreeram Ramachandran4d4c8b72014-06-20 11:59:40 -0700453 }
454 Fwmark fwmark;
455 socklen_t fwmarkLen = sizeof(fwmark.intValue);
456 if (getsockopt(socketFd, SOL_SOCKET, SO_MARK, &fwmark.intValue, &fwmarkLen) == -1) {
Sreeram Ramachandran3a069e62014-06-22 11:02:57 -0700457 return -errno;
Sreeram Ramachandran4d4c8b72014-06-20 11:59:40 -0700458 }
459 *netId = fwmark.netId;
460 return 0;
461}
462
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700463extern "C" unsigned getNetworkForProcess() {
Lorenzo Colitti6b001262019-01-30 22:43:36 +0900464 return netIdForProcess & ~NETID_USE_LOCAL_NAMESERVERS;
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700465}
466
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700467extern "C" int setNetworkForSocket(unsigned netId, int socketFd) {
Remi NGUYEN VANeabc5da2018-04-24 18:54:58 +0900468 CHECK_SOCKET_IS_MARKABLE(socketFd);
Chenbo Feng9944ba82017-10-10 17:33:20 -0700469 FwmarkCommand command = {FwmarkCommand::SELECT_NETWORK, netId, 0, 0};
Michal Karpinski4b9b78a2016-10-06 19:33:55 +0100470 return FwmarkClient().send(&command, socketFd, nullptr);
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700471}
472
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700473extern "C" int setNetworkForProcess(unsigned netId) {
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700474 return setNetworkForTarget(netId, &netIdForProcess);
475}
476
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700477extern "C" int setNetworkForResolv(unsigned netId) {
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700478 return setNetworkForTarget(netId, &netIdForResolv);
479}
Sreeram Ramachandrand794e582014-06-19 10:03:07 -0700480
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700481extern "C" int protectFromVpn(int socketFd) {
Sreeram Ramachandrand794e582014-06-19 10:03:07 -0700482 if (socketFd < 0) {
Sreeram Ramachandran3a069e62014-06-22 11:02:57 -0700483 return -EBADF;
Sreeram Ramachandrand794e582014-06-19 10:03:07 -0700484 }
Chenbo Feng9944ba82017-10-10 17:33:20 -0700485 FwmarkCommand command = {FwmarkCommand::PROTECT_FROM_VPN, 0, 0, 0};
Michal Karpinski4b9b78a2016-10-06 19:33:55 +0100486 return FwmarkClient().send(&command, socketFd, nullptr);
Sreeram Ramachandrana69d9472014-07-11 16:27:02 -0700487}
488
489extern "C" int setNetworkForUser(uid_t uid, int socketFd) {
Remi NGUYEN VANeabc5da2018-04-24 18:54:58 +0900490 CHECK_SOCKET_IS_MARKABLE(socketFd);
Chenbo Feng9944ba82017-10-10 17:33:20 -0700491 FwmarkCommand command = {FwmarkCommand::SELECT_FOR_USER, 0, uid, 0};
Michal Karpinski4b9b78a2016-10-06 19:33:55 +0100492 return FwmarkClient().send(&command, socketFd, nullptr);
Paul Jensend1df5972015-05-06 07:29:56 -0400493}
494
495extern "C" int queryUserAccess(uid_t uid, unsigned netId) {
Chenbo Feng9944ba82017-10-10 17:33:20 -0700496 FwmarkCommand command = {FwmarkCommand::QUERY_USER_ACCESS, netId, uid, 0};
497 return FwmarkClient().send(&command, -1, nullptr);
498}
499
500extern "C" int tagSocket(int socketFd, uint32_t tag, uid_t uid) {
Remi NGUYEN VANeabc5da2018-04-24 18:54:58 +0900501 CHECK_SOCKET_IS_MARKABLE(socketFd);
Chenbo Feng9944ba82017-10-10 17:33:20 -0700502 FwmarkCommand command = {FwmarkCommand::TAG_SOCKET, 0, uid, tag};
503 return FwmarkClient().send(&command, socketFd, nullptr);
504}
505
506extern "C" int untagSocket(int socketFd) {
Remi NGUYEN VANeabc5da2018-04-24 18:54:58 +0900507 CHECK_SOCKET_IS_MARKABLE(socketFd);
Chenbo Feng9944ba82017-10-10 17:33:20 -0700508 FwmarkCommand command = {FwmarkCommand::UNTAG_SOCKET, 0, 0, 0};
509 return FwmarkClient().send(&command, socketFd, nullptr);
510}
511
512extern "C" int setCounterSet(uint32_t counterSet, uid_t uid) {
513 FwmarkCommand command = {FwmarkCommand::SET_COUNTERSET, 0, uid, counterSet};
514 return FwmarkClient().send(&command, -1, nullptr);
515}
516
517extern "C" int deleteTagData(uint32_t tag, uid_t uid) {
518 FwmarkCommand command = {FwmarkCommand::DELETE_TAGDATA, 0, uid, tag};
Michal Karpinski4b9b78a2016-10-06 19:33:55 +0100519 return FwmarkClient().send(&command, -1, nullptr);
Sreeram Ramachandrand794e582014-06-19 10:03:07 -0700520}
Luke Huangc68f1b92018-11-21 20:13:38 +0800521
Luke Huang110c54e2018-12-20 14:39:58 +0800522extern "C" int resNetworkQuery(unsigned netId, const char* dname, int ns_class, int ns_type,
523 uint32_t flags) {
Luke Huange48fbcb2018-12-17 16:37:33 +0800524 std::vector<uint8_t> buf(MAX_CMD_SIZE, 0);
525 int len = res_mkquery(ns_o_query, dname, ns_class, ns_type, nullptr, 0, nullptr, buf.data(),
526 MAX_CMD_SIZE);
Luke Huangc68f1b92018-11-21 20:13:38 +0800527
Luke Huang110c54e2018-12-20 14:39:58 +0800528 return resNetworkSend(netId, buf.data(), len, flags);
Luke Huangc68f1b92018-11-21 20:13:38 +0800529}
530
Luke Huang952d0942018-12-26 16:53:03 +0800531extern "C" int resNetworkSend(unsigned netId, const uint8_t* msg, size_t msglen, uint32_t flags) {
Luke Huangc68f1b92018-11-21 20:13:38 +0800532 // Encode
533 // Base 64 encodes every 3 bytes into 4 characters, but then adds padding to the next
534 // multiple of 4 and a \0
535 const size_t encodedLen = divCeil(msglen, 3) * 4 + 1;
Luke Huange48fbcb2018-12-17 16:37:33 +0800536 std::string encodedQuery(encodedLen - 1, 0);
Luke Huangc68f1b92018-11-21 20:13:38 +0800537 int enLen = b64_ntop(msg, msglen, encodedQuery.data(), encodedLen);
538
539 if (enLen < 0) {
540 // Unexpected behavior, encode failed
541 // b64_ntop only fails when size is too long.
542 return -EMSGSIZE;
543 }
544 // Send
545 netId = getNetworkForResolv(netId);
Luke Huang952d0942018-12-26 16:53:03 +0800546 const std::string cmd = "resnsend " + std::to_string(netId) + " " + std::to_string(flags) +
547 " " + encodedQuery + '\0';
Luke Huangc68f1b92018-11-21 20:13:38 +0800548 if (cmd.size() > MAX_CMD_SIZE) {
549 // Cmd size must less than buffer size of FrameworkListener
550 return -EMSGSIZE;
551 }
552 int fd = dns_open_proxy();
553 if (fd == -1) {
554 return -errno;
555 }
556 ssize_t rc = sendData(fd, cmd.c_str(), cmd.size());
557 if (rc < 0) {
558 close(fd);
559 return rc;
560 }
561 shutdown(fd, SHUT_WR);
562 return fd;
563}
564
Luke Huange48fbcb2018-12-17 16:37:33 +0800565extern "C" int resNetworkResult(int fd, int* rcode, uint8_t* answer, size_t anslen) {
Luke Huangc68f1b92018-11-21 20:13:38 +0800566 int32_t result = 0;
567 unique_fd ufd(fd);
568 // Read -errno/rcode
569 if (!readBE32(fd, &result)) {
570 // Unexpected behavior, read -errno/rcode fail
571 return -errno;
572 }
573 if (result < 0) {
574 // result < 0, it's -errno
575 return result;
576 }
577 // result >= 0, it's rcode
578 *rcode = result;
579
580 // Read answer
581 int32_t size = 0;
582 if (!readBE32(fd, &size)) {
583 // Unexpected behavior, read ans len fail
584 return -EREMOTEIO;
585 }
Luke Huange48fbcb2018-12-17 16:37:33 +0800586 if (anslen < static_cast<size_t>(size)) {
Luke Huangc68f1b92018-11-21 20:13:38 +0800587 // Answer buffer is too small
588 return -EMSGSIZE;
589 }
590 int rc = readData(fd, answer, size);
591 if (rc < 0) {
592 // Reading the answer failed.
593 return rc;
594 }
595 return size;
596}
597
598extern "C" void resNetworkCancel(int fd) {
599 close(fd);
Lorenzo Colitti6b001262019-01-30 22:43:36 +0900600}
Luke Huang185098d2019-05-20 16:17:12 +0800601
Luke Huang63df9482019-05-25 18:24:03 +0800602extern "C" int getNetworkForDns(unsigned* dnsNetId) {
603 if (dnsNetId == nullptr) return -EFAULT;
Luke Huang185098d2019-05-20 16:17:12 +0800604 int fd = dns_open_proxy();
605 if (fd == -1) {
606 return -errno;
607 }
608 unique_fd ufd(fd);
Luke Huang63df9482019-05-25 18:24:03 +0800609 return getNetworkForDnsInternal(fd, dnsNetId);
610}
611
612int getNetworkForDnsInternal(int fd, unsigned* dnsNetId) {
613 if (fd == -1) {
614 return -EBADF;
615 }
616
617 unsigned resolvNetId = getNetworkForResolv(NETID_UNSET);
618
619 const std::string cmd = "getdnsnetid " + std::to_string(resolvNetId);
Luke Huang185098d2019-05-20 16:17:12 +0800620 ssize_t rc = sendData(fd, cmd.c_str(), cmd.size() + 1);
621 if (rc < 0) {
622 return rc;
623 }
624
625 int responseCode = 0;
626 // Read responseCode
Luke Huang63df9482019-05-25 18:24:03 +0800627 if (!readResponseCode(fd, &responseCode)) {
Luke Huang185098d2019-05-20 16:17:12 +0800628 // Unexpected behavior, read responseCode fail
629 return -errno;
630 }
631
632 if (responseCode != ResponseCode::DnsProxyQueryResult) {
633 return -EOPNOTSUPP;
634 }
635
636 int32_t result = 0;
637 // Read -errno/dnsnetid
638 if (!readBE32(fd, &result)) {
639 // Unexpected behavior, read -errno/dnsnetid fail
640 return -errno;
641 }
642
Luke Huang63df9482019-05-25 18:24:03 +0800643 *dnsNetId = result;
644
645 return 0;
Luke Huang185098d2019-05-20 16:17:12 +0800646}