blob: faf1484b23ba74f586fab593ae7ab2605238c806 [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>
Luke Huangc5efae92018-11-19 17:45:13 +080025#include <sys/un.h>
Dan Albertaa1be2b2015-01-06 09:36:17 -080026#include <unistd.h>
27
28#include <atomic>
Luke Huangc68f1b92018-11-21 20:13:38 +080029#include <string>
30#include <vector>
Dan Albertaa1be2b2015-01-06 09:36:17 -080031
Sreeram Ramachandran4d4c8b72014-06-20 11:59:40 -070032#include "Fwmark.h"
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -070033#include "FwmarkClient.h"
34#include "FwmarkCommand.h"
Luke Huang711b7772019-05-23 06:14:42 -070035#include "netdutils/ResponseCode.h"
Mike Yue7e332f2019-03-13 17:15:48 +080036#include "netdutils/Stopwatch.h"
Bernie Innocenti189eb502018-10-01 23:10:18 +090037#include "netid_client.h"
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -070038
Luke Huang711b7772019-05-23 06:14:42 -070039#include <android-base/parseint.h>
Luke Huangc68f1b92018-11-21 20:13:38 +080040#include "android-base/unique_fd.h"
41
Luke Huang711b7772019-05-23 06:14:42 -070042using android::base::ParseInt;
Luke Huangc68f1b92018-11-21 20:13:38 +080043using android::base::unique_fd;
Luke Huang711b7772019-05-23 06:14:42 -070044using android::netdutils::ResponseCode;
Mike Yue7e332f2019-03-13 17:15:48 +080045using android::netdutils::Stopwatch;
Luke Huangc68f1b92018-11-21 20:13:38 +080046
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -070047namespace {
48
Luke Huangc68f1b92018-11-21 20:13:38 +080049// Keep this in sync with CMD_BUF_SIZE in FrameworkListener.cpp.
Luke Huange92b75e2019-03-26 17:56:49 +080050constexpr size_t MAX_CMD_SIZE = 4096;
Luke Huangc68f1b92018-11-21 20:13:38 +080051
Sreeram Ramachandran9fa2b132014-06-03 12:51:08 -070052std::atomic_uint netIdForProcess(NETID_UNSET);
53std::atomic_uint netIdForResolv(NETID_UNSET);
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -070054
55typedef int (*Accept4FunctionType)(int, sockaddr*, socklen_t*, int);
56typedef int (*ConnectFunctionType)(int, const sockaddr*, socklen_t);
57typedef int (*SocketFunctionType)(int, int, int);
58typedef unsigned (*NetIdForResolvFunctionType)(unsigned);
Luke Huangc5efae92018-11-19 17:45:13 +080059typedef int (*DnsOpenProxyType)();
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -070060
61// These variables are only modified at startup (when libc.so is loaded) and never afterwards, so
62// it's okay that they are read later at runtime without a lock.
Yi Kongbdfd57e2018-07-25 13:26:10 -070063Accept4FunctionType libcAccept4 = nullptr;
64ConnectFunctionType libcConnect = nullptr;
65SocketFunctionType libcSocket = nullptr;
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -070066
Lorenzo Colitti24601da2019-02-14 00:48:36 +090067int checkSocket(int socketFd) {
68 if (socketFd < 0) {
69 return -EBADF;
70 }
71 int family;
72 socklen_t familyLen = sizeof(family);
73 if (getsockopt(socketFd, SOL_SOCKET, SO_DOMAIN, &family, &familyLen) == -1) {
74 return -errno;
75 }
76 if (!FwmarkClient::shouldSetFwmark(family)) {
77 return -EAFNOSUPPORT;
78 }
79 return 0;
80}
81
82bool shouldMarkSocket(int socketFd, const sockaddr* dst) {
83 // Only mark inet sockets that are connecting to inet destinations. This excludes, for example,
84 // inet sockets connecting to AF_UNSPEC (i.e., being disconnected), and non-inet sockets that
85 // for some reason the caller wants to attempt to connect to an inet destination.
86 return dst && FwmarkClient::shouldSetFwmark(dst->sa_family) && (checkSocket(socketFd) == 0);
87}
88
Sreeram Ramachandran31f42102014-06-20 11:51:48 -070089int closeFdAndSetErrno(int fd, int error) {
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -070090 close(fd);
Sreeram Ramachandran3a069e62014-06-22 11:02:57 -070091 errno = -error;
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -070092 return -1;
93}
94
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -070095int netdClientAccept4(int sockfd, sockaddr* addr, socklen_t* addrlen, int flags) {
96 int acceptedSocket = libcAccept4(sockfd, addr, addrlen, flags);
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -070097 if (acceptedSocket == -1) {
98 return -1;
99 }
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -0700100 int family;
101 if (addr) {
102 family = addr->sa_family;
103 } else {
104 socklen_t familyLen = sizeof(family);
105 if (getsockopt(acceptedSocket, SOL_SOCKET, SO_DOMAIN, &family, &familyLen) == -1) {
Sreeram Ramachandran3a069e62014-06-22 11:02:57 -0700106 return closeFdAndSetErrno(acceptedSocket, -errno);
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -0700107 }
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -0700108 }
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -0700109 if (FwmarkClient::shouldSetFwmark(family)) {
Chenbo Feng9944ba82017-10-10 17:33:20 -0700110 FwmarkCommand command = {FwmarkCommand::ON_ACCEPT, 0, 0, 0};
Michal Karpinski4b9b78a2016-10-06 19:33:55 +0100111 if (int error = FwmarkClient().send(&command, acceptedSocket, nullptr)) {
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700112 return closeFdAndSetErrno(acceptedSocket, error);
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -0700113 }
114 }
115 return acceptedSocket;
116}
117
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -0700118int netdClientConnect(int sockfd, const sockaddr* addr, socklen_t addrlen) {
Lorenzo Colitti24601da2019-02-14 00:48:36 +0900119 const bool shouldSetFwmark = shouldMarkSocket(sockfd, addr);
Michal Karpinski4b9b78a2016-10-06 19:33:55 +0100120 if (shouldSetFwmark) {
Chenbo Feng9944ba82017-10-10 17:33:20 -0700121 FwmarkCommand command = {FwmarkCommand::ON_CONNECT, 0, 0, 0};
Michal Karpinski4b9b78a2016-10-06 19:33:55 +0100122 if (int error = FwmarkClient().send(&command, sockfd, nullptr)) {
Sreeram Ramachandran3a069e62014-06-22 11:02:57 -0700123 errno = -error;
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -0700124 return -1;
125 }
126 }
Michal Karpinski4b9b78a2016-10-06 19:33:55 +0100127 // Latency measurement does not include time of sending commands to Fwmark
128 Stopwatch s;
Hugo Benichi794c5c72016-10-31 15:07:23 +0900129 const int ret = libcConnect(sockfd, addr, addrlen);
Michal Karpinski4b9b78a2016-10-06 19:33:55 +0100130 // Save errno so it isn't clobbered by sending ON_CONNECT_COMPLETE
131 const int connectErrno = errno;
132 const unsigned latencyMs = lround(s.timeTaken());
133 // Send an ON_CONNECT_COMPLETE command that includes sockaddr and connect latency for reporting
134 if (shouldSetFwmark && FwmarkClient::shouldReportConnectComplete(addr->sa_family)) {
Hugo Benichi794c5c72016-10-31 15:07:23 +0900135 FwmarkConnectInfo connectInfo(ret == 0 ? 0 : connectErrno, latencyMs, addr);
Michal Karpinski4b9b78a2016-10-06 19:33:55 +0100136 // TODO: get the netId from the socket mark once we have continuous benchmark runs
137 FwmarkCommand command = {FwmarkCommand::ON_CONNECT_COMPLETE, /* netId (ignored) */ 0,
Chenbo Feng9944ba82017-10-10 17:33:20 -0700138 /* uid (filled in by the server) */ 0, 0};
Michal Karpinski4b9b78a2016-10-06 19:33:55 +0100139 // Ignore return value since it's only used for logging
140 FwmarkClient().send(&command, sockfd, &connectInfo);
141 }
142 errno = connectErrno;
143 return ret;
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -0700144}
145
146int netdClientSocket(int domain, int type, int protocol) {
147 int socketFd = libcSocket(domain, type, protocol);
148 if (socketFd == -1) {
149 return -1;
150 }
Lorenzo Colitti6b001262019-01-30 22:43:36 +0900151 unsigned netId = netIdForProcess & ~NETID_USE_LOCAL_NAMESERVERS;
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -0700152 if (netId != NETID_UNSET && FwmarkClient::shouldSetFwmark(domain)) {
Sreeram Ramachandrand36c49c2014-07-02 14:49:33 -0700153 if (int error = setNetworkForSocket(netId, socketFd)) {
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700154 return closeFdAndSetErrno(socketFd, error);
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -0700155 }
156 }
157 return socketFd;
158}
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700159
160unsigned getNetworkForResolv(unsigned netId) {
161 if (netId != NETID_UNSET) {
162 return netId;
163 }
Erik Kline1564d482018-03-07 17:09:35 +0900164 // Special case for DNS-over-TLS bypass; b/72345192 .
165 if ((netIdForResolv & ~NETID_USE_LOCAL_NAMESERVERS) != NETID_UNSET) {
166 return netIdForResolv;
167 }
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700168 netId = netIdForProcess;
169 if (netId != NETID_UNSET) {
170 return netId;
171 }
172 return netIdForResolv;
173}
174
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700175int setNetworkForTarget(unsigned netId, std::atomic_uint* target) {
Erik Kline1564d482018-03-07 17:09:35 +0900176 const unsigned requestedNetId = netId;
177 netId &= ~NETID_USE_LOCAL_NAMESERVERS;
178
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700179 if (netId == NETID_UNSET) {
180 *target = netId;
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700181 return 0;
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700182 }
183 // 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 -0700184 // with the netId. Call libcSocket() directly; else the socket creation (via netdClientSocket())
185 // might itself cause another check with the fwmark server, which would be wasteful.
Luke Huangc5efae92018-11-19 17:45:13 +0800186
187 const auto socketFunc = libcSocket ? libcSocket : socket;
188 int socketFd = socketFunc(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0);
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700189 if (socketFd < 0) {
Sreeram Ramachandran3a069e62014-06-22 11:02:57 -0700190 return -errno;
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700191 }
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700192 int error = setNetworkForSocket(netId, socketFd);
193 if (!error) {
Lorenzo Colitti6b001262019-01-30 22:43:36 +0900194 *target = requestedNetId;
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700195 }
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700196 close(socketFd);
197 return error;
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700198}
199
Luke Huangc5efae92018-11-19 17:45:13 +0800200int dns_open_proxy() {
201 const char* cache_mode = getenv("ANDROID_DNS_MODE");
202 const bool use_proxy = (cache_mode == NULL || strcmp(cache_mode, "local") != 0);
203 if (!use_proxy) {
204 return -1;
205 }
206
207 const auto socketFunc = libcSocket ? libcSocket : socket;
208 int s = socketFunc(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
209 if (s == -1) {
210 return -1;
211 }
212 const int one = 1;
213 setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
214
215 static const struct sockaddr_un proxy_addr = {
216 .sun_family = AF_UNIX,
217 .sun_path = "/dev/socket/dnsproxyd",
218 };
219
220 const auto connectFunc = libcConnect ? libcConnect : connect;
221 if (TEMP_FAILURE_RETRY(
222 connectFunc(s, (const struct sockaddr*) &proxy_addr, sizeof(proxy_addr))) != 0) {
223 close(s);
224 return -1;
225 }
226
227 return s;
228}
229
Luke Huangc68f1b92018-11-21 20:13:38 +0800230auto divCeil(size_t dividend, size_t divisor) {
231 return ((dividend + divisor - 1) / divisor);
232}
233
234// FrameworkListener only does only read() call, and fails if the read doesn't contain \0
235// Do single write here
236int sendData(int fd, const void* buf, size_t size) {
237 if (fd < 0) {
238 return -EBADF;
239 }
240
241 ssize_t rc = TEMP_FAILURE_RETRY(write(fd, (char*) buf, size));
242 if (rc > 0) {
243 return rc;
244 } else if (rc == 0) {
245 return -EIO;
246 } else {
247 return -errno;
248 }
249}
250
251int readData(int fd, void* buf, size_t size) {
252 if (fd < 0) {
253 return -EBADF;
254 }
255
256 size_t current = 0;
257 for (;;) {
258 ssize_t rc = TEMP_FAILURE_RETRY(read(fd, (char*) buf + current, size - current));
259 if (rc > 0) {
260 current += rc;
261 if (current == size) {
262 break;
263 }
264 } else if (rc == 0) {
265 return -EIO;
266 } else {
267 return -errno;
268 }
269 }
270 return 0;
271}
272
273bool readBE32(int fd, int32_t* result) {
274 int32_t tmp;
275 int n = TEMP_FAILURE_RETRY(read(fd, &tmp, sizeof(tmp)));
276 if (n < 0) {
277 return false;
278 }
279 *result = ntohl(tmp);
280 return true;
281}
282
Luke Huang711b7772019-05-23 06:14:42 -0700283bool readResonseCode(int fd, int* result) {
284 char buf[4];
285 int n = TEMP_FAILURE_RETRY(read(fd, &buf, sizeof(buf)));
286 if (n < 0) {
287 return false;
288 }
289
290 // The format of response code is 3 bytes followed by a space.
291 buf[3] = '\0';
292 if (!ParseInt(buf, result)) {
293 errno = EINVAL;
294 return false;
295 }
296
297 return true;
298}
299
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -0700300} // namespace
301
Remi NGUYEN VANeabc5da2018-04-24 18:54:58 +0900302#define CHECK_SOCKET_IS_MARKABLE(sock) \
303 do { \
304 int err; \
305 if ((err = checkSocket(sock)) != 0) { \
306 return err; \
307 } \
308 } while (false);
309
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -0700310// accept() just calls accept4(..., 0), so there's no need to handle accept() separately.
311extern "C" void netdClientInitAccept4(Accept4FunctionType* function) {
312 if (function && *function) {
313 libcAccept4 = *function;
314 *function = netdClientAccept4;
315 }
316}
317
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -0700318extern "C" void netdClientInitConnect(ConnectFunctionType* function) {
319 if (function && *function) {
320 libcConnect = *function;
321 *function = netdClientConnect;
322 }
323}
324
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -0700325extern "C" void netdClientInitSocket(SocketFunctionType* function) {
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -0700326 if (function && *function) {
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -0700327 libcSocket = *function;
328 *function = netdClientSocket;
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -0700329 }
330}
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700331
332extern "C" void netdClientInitNetIdForResolv(NetIdForResolvFunctionType* function) {
333 if (function) {
334 *function = getNetworkForResolv;
335 }
336}
337
Luke Huangc5efae92018-11-19 17:45:13 +0800338extern "C" void netdClientInitDnsOpenProxy(DnsOpenProxyType* function) {
339 if (function) {
340 *function = dns_open_proxy;
341 }
342}
343
Sreeram Ramachandran4d4c8b72014-06-20 11:59:40 -0700344extern "C" int getNetworkForSocket(unsigned* netId, int socketFd) {
345 if (!netId || socketFd < 0) {
Sreeram Ramachandran3a069e62014-06-22 11:02:57 -0700346 return -EBADF;
Sreeram Ramachandran4d4c8b72014-06-20 11:59:40 -0700347 }
348 Fwmark fwmark;
349 socklen_t fwmarkLen = sizeof(fwmark.intValue);
350 if (getsockopt(socketFd, SOL_SOCKET, SO_MARK, &fwmark.intValue, &fwmarkLen) == -1) {
Sreeram Ramachandran3a069e62014-06-22 11:02:57 -0700351 return -errno;
Sreeram Ramachandran4d4c8b72014-06-20 11:59:40 -0700352 }
353 *netId = fwmark.netId;
354 return 0;
355}
356
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700357extern "C" unsigned getNetworkForProcess() {
Lorenzo Colitti6b001262019-01-30 22:43:36 +0900358 return netIdForProcess & ~NETID_USE_LOCAL_NAMESERVERS;
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700359}
360
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700361extern "C" int setNetworkForSocket(unsigned netId, int socketFd) {
Remi NGUYEN VANeabc5da2018-04-24 18:54:58 +0900362 CHECK_SOCKET_IS_MARKABLE(socketFd);
Chenbo Feng9944ba82017-10-10 17:33:20 -0700363 FwmarkCommand command = {FwmarkCommand::SELECT_NETWORK, netId, 0, 0};
Michal Karpinski4b9b78a2016-10-06 19:33:55 +0100364 return FwmarkClient().send(&command, socketFd, nullptr);
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700365}
366
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700367extern "C" int setNetworkForProcess(unsigned netId) {
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700368 return setNetworkForTarget(netId, &netIdForProcess);
369}
370
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700371extern "C" int setNetworkForResolv(unsigned netId) {
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700372 return setNetworkForTarget(netId, &netIdForResolv);
373}
Sreeram Ramachandrand794e582014-06-19 10:03:07 -0700374
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700375extern "C" int protectFromVpn(int socketFd) {
Sreeram Ramachandrand794e582014-06-19 10:03:07 -0700376 if (socketFd < 0) {
Sreeram Ramachandran3a069e62014-06-22 11:02:57 -0700377 return -EBADF;
Sreeram Ramachandrand794e582014-06-19 10:03:07 -0700378 }
Chenbo Feng9944ba82017-10-10 17:33:20 -0700379 FwmarkCommand command = {FwmarkCommand::PROTECT_FROM_VPN, 0, 0, 0};
Michal Karpinski4b9b78a2016-10-06 19:33:55 +0100380 return FwmarkClient().send(&command, socketFd, nullptr);
Sreeram Ramachandrana69d9472014-07-11 16:27:02 -0700381}
382
383extern "C" int setNetworkForUser(uid_t uid, int socketFd) {
Remi NGUYEN VANeabc5da2018-04-24 18:54:58 +0900384 CHECK_SOCKET_IS_MARKABLE(socketFd);
Chenbo Feng9944ba82017-10-10 17:33:20 -0700385 FwmarkCommand command = {FwmarkCommand::SELECT_FOR_USER, 0, uid, 0};
Michal Karpinski4b9b78a2016-10-06 19:33:55 +0100386 return FwmarkClient().send(&command, socketFd, nullptr);
Paul Jensend1df5972015-05-06 07:29:56 -0400387}
388
389extern "C" int queryUserAccess(uid_t uid, unsigned netId) {
Chenbo Feng9944ba82017-10-10 17:33:20 -0700390 FwmarkCommand command = {FwmarkCommand::QUERY_USER_ACCESS, netId, uid, 0};
391 return FwmarkClient().send(&command, -1, nullptr);
392}
393
394extern "C" int tagSocket(int socketFd, uint32_t tag, uid_t uid) {
Remi NGUYEN VANeabc5da2018-04-24 18:54:58 +0900395 CHECK_SOCKET_IS_MARKABLE(socketFd);
Chenbo Feng9944ba82017-10-10 17:33:20 -0700396 FwmarkCommand command = {FwmarkCommand::TAG_SOCKET, 0, uid, tag};
397 return FwmarkClient().send(&command, socketFd, nullptr);
398}
399
400extern "C" int untagSocket(int socketFd) {
Remi NGUYEN VANeabc5da2018-04-24 18:54:58 +0900401 CHECK_SOCKET_IS_MARKABLE(socketFd);
Chenbo Feng9944ba82017-10-10 17:33:20 -0700402 FwmarkCommand command = {FwmarkCommand::UNTAG_SOCKET, 0, 0, 0};
403 return FwmarkClient().send(&command, socketFd, nullptr);
404}
405
406extern "C" int setCounterSet(uint32_t counterSet, uid_t uid) {
407 FwmarkCommand command = {FwmarkCommand::SET_COUNTERSET, 0, uid, counterSet};
408 return FwmarkClient().send(&command, -1, nullptr);
409}
410
411extern "C" int deleteTagData(uint32_t tag, uid_t uid) {
412 FwmarkCommand command = {FwmarkCommand::DELETE_TAGDATA, 0, uid, tag};
Michal Karpinski4b9b78a2016-10-06 19:33:55 +0100413 return FwmarkClient().send(&command, -1, nullptr);
Sreeram Ramachandrand794e582014-06-19 10:03:07 -0700414}
Luke Huangc68f1b92018-11-21 20:13:38 +0800415
Luke Huang110c54e2018-12-20 14:39:58 +0800416extern "C" int resNetworkQuery(unsigned netId, const char* dname, int ns_class, int ns_type,
417 uint32_t flags) {
Luke Huange48fbcb2018-12-17 16:37:33 +0800418 std::vector<uint8_t> buf(MAX_CMD_SIZE, 0);
419 int len = res_mkquery(ns_o_query, dname, ns_class, ns_type, nullptr, 0, nullptr, buf.data(),
420 MAX_CMD_SIZE);
Luke Huangc68f1b92018-11-21 20:13:38 +0800421
Luke Huang110c54e2018-12-20 14:39:58 +0800422 return resNetworkSend(netId, buf.data(), len, flags);
Luke Huangc68f1b92018-11-21 20:13:38 +0800423}
424
Luke Huang952d0942018-12-26 16:53:03 +0800425extern "C" int resNetworkSend(unsigned netId, const uint8_t* msg, size_t msglen, uint32_t flags) {
Luke Huangc68f1b92018-11-21 20:13:38 +0800426 // Encode
427 // Base 64 encodes every 3 bytes into 4 characters, but then adds padding to the next
428 // multiple of 4 and a \0
429 const size_t encodedLen = divCeil(msglen, 3) * 4 + 1;
Luke Huange48fbcb2018-12-17 16:37:33 +0800430 std::string encodedQuery(encodedLen - 1, 0);
Luke Huangc68f1b92018-11-21 20:13:38 +0800431 int enLen = b64_ntop(msg, msglen, encodedQuery.data(), encodedLen);
432
433 if (enLen < 0) {
434 // Unexpected behavior, encode failed
435 // b64_ntop only fails when size is too long.
436 return -EMSGSIZE;
437 }
438 // Send
439 netId = getNetworkForResolv(netId);
Luke Huang952d0942018-12-26 16:53:03 +0800440 const std::string cmd = "resnsend " + std::to_string(netId) + " " + std::to_string(flags) +
441 " " + encodedQuery + '\0';
Luke Huangc68f1b92018-11-21 20:13:38 +0800442 if (cmd.size() > MAX_CMD_SIZE) {
443 // Cmd size must less than buffer size of FrameworkListener
444 return -EMSGSIZE;
445 }
446 int fd = dns_open_proxy();
447 if (fd == -1) {
448 return -errno;
449 }
450 ssize_t rc = sendData(fd, cmd.c_str(), cmd.size());
451 if (rc < 0) {
452 close(fd);
453 return rc;
454 }
455 shutdown(fd, SHUT_WR);
456 return fd;
457}
458
Luke Huange48fbcb2018-12-17 16:37:33 +0800459extern "C" int resNetworkResult(int fd, int* rcode, uint8_t* answer, size_t anslen) {
Luke Huangc68f1b92018-11-21 20:13:38 +0800460 int32_t result = 0;
461 unique_fd ufd(fd);
462 // Read -errno/rcode
463 if (!readBE32(fd, &result)) {
464 // Unexpected behavior, read -errno/rcode fail
465 return -errno;
466 }
467 if (result < 0) {
468 // result < 0, it's -errno
469 return result;
470 }
471 // result >= 0, it's rcode
472 *rcode = result;
473
474 // Read answer
475 int32_t size = 0;
476 if (!readBE32(fd, &size)) {
477 // Unexpected behavior, read ans len fail
478 return -EREMOTEIO;
479 }
Luke Huange48fbcb2018-12-17 16:37:33 +0800480 if (anslen < static_cast<size_t>(size)) {
Luke Huangc68f1b92018-11-21 20:13:38 +0800481 // Answer buffer is too small
482 return -EMSGSIZE;
483 }
484 int rc = readData(fd, answer, size);
485 if (rc < 0) {
486 // Reading the answer failed.
487 return rc;
488 }
489 return size;
490}
491
492extern "C" void resNetworkCancel(int fd) {
493 close(fd);
Lorenzo Colitti6b001262019-01-30 22:43:36 +0900494}
Luke Huang711b7772019-05-23 06:14:42 -0700495
496extern "C" int getNetworkForDns() {
497 int fd = dns_open_proxy();
498 if (fd == -1) {
499 return -errno;
500 }
501 unique_fd ufd(fd);
502 unsigned dnsNetId = getNetworkForResolv(NETID_UNSET);
503 const std::string cmd = "getdnsnetid " + std::to_string(dnsNetId);
504 ssize_t rc = sendData(fd, cmd.c_str(), cmd.size() + 1);
505 if (rc < 0) {
506 return rc;
507 }
508
509 int responseCode = 0;
510 // Read responseCode
511 if (!readResonseCode(fd, &responseCode)) {
512 // Unexpected behavior, read responseCode fail
513 return -errno;
514 }
515
516 if (responseCode != ResponseCode::DnsProxyQueryResult) {
517 return -EOPNOTSUPP;
518 }
519
520 int32_t result = 0;
521 // Read -errno/dnsnetid
522 if (!readBE32(fd, &result)) {
523 // Unexpected behavior, read -errno/dnsnetid fail
524 return -errno;
525 }
526
527 return result;
528}