1 /*
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
17 #include "NetdClient.h"
18
19 #include <arpa/inet.h>
20 #include <errno.h>
21 #include <math.h>
22 #include <resolv.h>
23 #include <stdlib.h>
24 #include <sys/socket.h>
25 #include <sys/system_properties.h>
26 #include <sys/un.h>
27 #include <unistd.h>
28
29 #include <atomic>
30 #include <string>
31 #include <vector>
32
33 #include <DnsProxydProtocol.h> // NETID_USE_LOCAL_NAMESERVERS
34 #include <android-base/parseint.h>
35 #include <android-base/unique_fd.h>
36
37 #include "Fwmark.h"
38 #include "FwmarkClient.h"
39 #include "FwmarkCommand.h"
40 #include "netdclient_priv.h"
41 #include "netdutils/ResponseCode.h"
42 #include "netdutils/Stopwatch.h"
43 #include "netid_client.h"
44
45 using android::base::ParseInt;
46 using android::base::unique_fd;
47 using android::netdutils::ResponseCode;
48 using android::netdutils::Stopwatch;
49
50 namespace {
51
52 // Keep this in sync with CMD_BUF_SIZE in FrameworkListener.cpp.
53 constexpr size_t MAX_CMD_SIZE = 4096;
54 // Whether sendto(), sendmsg(), sendmmsg() in libc are shimmed or not. This property is evaluated at
55 // process start time and cannot change at runtime on a given device.
56 constexpr 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.
59 constexpr char PROPERTY_REDIRECT_SOCKET_CALLS_HOOKED[] = "net.redirect_socket_calls.hooked";
60
61 std::atomic_uint netIdForProcess(NETID_UNSET);
62 std::atomic_uint netIdForResolv(NETID_UNSET);
63 std::atomic_bool allowNetworkingForProcess(true);
64
65 typedef int (*Accept4FunctionType)(int, sockaddr*, socklen_t*, int);
66 typedef int (*ConnectFunctionType)(int, const sockaddr*, socklen_t);
67 typedef int (*SocketFunctionType)(int, int, int);
68 typedef unsigned (*NetIdForResolvFunctionType)(unsigned);
69 typedef int (*DnsOpenProxyType)();
70 typedef int (*SendmmsgFunctionType)(int, const mmsghdr*, unsigned int, int);
71 typedef ssize_t (*SendmsgFunctionType)(int, const msghdr*, unsigned int);
72 typedef int (*SendtoFunctionType)(int, const void*, size_t, int, const sockaddr*, socklen_t);
73
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.
76 Accept4FunctionType libcAccept4 = nullptr;
77 ConnectFunctionType libcConnect = nullptr;
78 SocketFunctionType libcSocket = nullptr;
79 SendmmsgFunctionType libcSendmmsg = nullptr;
80 SendmsgFunctionType libcSendmsg = nullptr;
81 SendtoFunctionType libcSendto = nullptr;
82
propertyValueIsTrue(const char * prop_name)83 static bool propertyValueIsTrue(const char* prop_name) {
84 char prop_value[PROP_VALUE_MAX] = {0};
85 if (__system_property_get(prop_name, prop_value) > 0) {
86 if (strcmp(prop_value, "true") == 0) {
87 return true;
88 }
89 }
90 return false;
91 }
92
93 // whether to hook sendmmsg/sendmsg/sendto
redirectSendX()94 static bool redirectSendX() {
95 static bool cached_result = propertyValueIsTrue(PROPERTY_REDIRECT_SOCKET_CALLS);
96 return cached_result;
97 }
98
checkSocket(int socketFd)99 int 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
shouldMarkSocket(int socketFd,const sockaddr * dst)114 bool 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
closeFdAndSetErrno(int fd,int error)121 int closeFdAndSetErrno(int fd, int error) {
122 close(fd);
123 errno = -error;
124 return -1;
125 }
126
netdClientAccept4(int sockfd,sockaddr * addr,socklen_t * addrlen,int flags)127 int netdClientAccept4(int sockfd, sockaddr* addr, socklen_t* addrlen, int flags) {
128 int acceptedSocket = libcAccept4(sockfd, addr, addrlen, flags);
129 if (acceptedSocket == -1) {
130 return -1;
131 }
132 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) {
138 return closeFdAndSetErrno(acceptedSocket, -errno);
139 }
140 }
141 if (FwmarkClient::shouldSetFwmark(family)) {
142 FwmarkCommand command = {FwmarkCommand::ON_ACCEPT, 0, 0, 0};
143 if (int error = FwmarkClient().send(&command, acceptedSocket, nullptr)) {
144 return closeFdAndSetErrno(acceptedSocket, error);
145 }
146 }
147 return acceptedSocket;
148 }
149
netdClientConnect(int sockfd,const sockaddr * addr,socklen_t addrlen)150 int netdClientConnect(int sockfd, const sockaddr* addr, socklen_t addrlen) {
151 const bool shouldSetFwmark = shouldMarkSocket(sockfd, addr);
152 if (shouldSetFwmark) {
153 FwmarkCommand command = {FwmarkCommand::ON_CONNECT, 0, 0, 0};
154 FwmarkConnectInfo connectInfo(0, 0, addr);
155 int error = FwmarkClient().send(&command, sockfd, &connectInfo);
156
157 if (error) {
158 errno = -error;
159 return -1;
160 }
161 }
162 // Latency measurement does not include time of sending commands to Fwmark
163 Stopwatch s;
164 const int ret = libcConnect(sockfd, addr, addrlen);
165 // Save errno so it isn't clobbered by sending ON_CONNECT_COMPLETE
166 const int connectErrno = errno;
167 const auto latencyMs = static_cast<unsigned>(s.timeTakenUs() / 1000);
168 // Send an ON_CONNECT_COMPLETE command that includes sockaddr and connect latency for reporting
169 if (shouldSetFwmark) {
170 FwmarkConnectInfo connectInfo(ret == 0 ? 0 : connectErrno, latencyMs, addr);
171 // TODO: get the netId from the socket mark once we have continuous benchmark runs
172 FwmarkCommand command = {FwmarkCommand::ON_CONNECT_COMPLETE, /* netId (ignored) */ 0,
173 /* uid (filled in by the server) */ 0, 0};
174 // Ignore return value since it's only used for logging
175 FwmarkClient().send(&command, sockfd, &connectInfo);
176 }
177 errno = connectErrno;
178 return ret;
179 }
180
netdClientSocket(int domain,int type,int protocol)181 int netdClientSocket(int domain, int type, int protocol) {
182 // 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 }
187 int socketFd = libcSocket(domain, type, protocol);
188 if (socketFd == -1) {
189 return -1;
190 }
191 unsigned netId = netIdForProcess & ~NETID_USE_LOCAL_NAMESERVERS;
192 if (netId != NETID_UNSET && FwmarkClient::shouldSetFwmark(domain)) {
193 if (int error = setNetworkForSocket(netId, socketFd)) {
194 return closeFdAndSetErrno(socketFd, error);
195 }
196 }
197 return socketFd;
198 }
199
netdClientSendmmsg(int sockfd,const mmsghdr * msgs,unsigned int msgcount,int flags)200 int netdClientSendmmsg(int sockfd, const mmsghdr* msgs, unsigned int msgcount, int flags) {
201 if (propertyValueIsTrue(PROPERTY_REDIRECT_SOCKET_CALLS_HOOKED) && !checkSocket(sockfd)) {
202 const sockaddr* addr = nullptr;
203 if ((msgcount > 0) && (msgs != nullptr) && (msgs[0].msg_hdr.msg_name != nullptr)) {
204 addr = reinterpret_cast<const sockaddr*>(msgs[0].msg_hdr.msg_name);
205 if ((addr != nullptr) && (FwmarkCommand::isSupportedFamily(addr->sa_family))) {
206 FwmarkConnectInfo sendmmsgInfo(0, 0, addr);
207 FwmarkCommand command = {FwmarkCommand::ON_SENDMMSG, 0, 0, 0};
208 FwmarkClient().send(&command, sockfd, &sendmmsgInfo);
209 }
210 }
211 }
212 return libcSendmmsg(sockfd, msgs, msgcount, flags);
213 }
214
netdClientSendmsg(int sockfd,const msghdr * msg,unsigned int flags)215 ssize_t netdClientSendmsg(int sockfd, const msghdr* msg, unsigned int flags) {
216 if (propertyValueIsTrue(PROPERTY_REDIRECT_SOCKET_CALLS_HOOKED) && !checkSocket(sockfd)) {
217 const sockaddr* addr = nullptr;
218 if ((msg != nullptr) && (msg->msg_name != nullptr)) {
219 addr = reinterpret_cast<const sockaddr*>(msg->msg_name);
220 if ((addr != nullptr) && (FwmarkCommand::isSupportedFamily(addr->sa_family))) {
221 FwmarkConnectInfo sendmsgInfo(0, 0, addr);
222 FwmarkCommand command = {FwmarkCommand::ON_SENDMSG, 0, 0, 0};
223 FwmarkClient().send(&command, sockfd, &sendmsgInfo);
224 }
225 }
226 }
227 return libcSendmsg(sockfd, msg, flags);
228 }
229
netdClientSendto(int sockfd,const void * buf,size_t bufsize,int flags,const sockaddr * addr,socklen_t addrlen)230 int netdClientSendto(int sockfd, const void* buf, size_t bufsize, int flags, const sockaddr* addr,
231 socklen_t addrlen) {
232 if (propertyValueIsTrue(PROPERTY_REDIRECT_SOCKET_CALLS_HOOKED) && !checkSocket(sockfd)) {
233 if ((addr != nullptr) && (FwmarkCommand::isSupportedFamily(addr->sa_family))) {
234 FwmarkConnectInfo sendtoInfo(0, 0, addr);
235 FwmarkCommand command = {FwmarkCommand::ON_SENDTO, 0, 0, 0};
236 FwmarkClient().send(&command, sockfd, &sendtoInfo);
237 }
238 }
239 return libcSendto(sockfd, buf, bufsize, flags, addr, addrlen);
240 }
241
getNetworkForResolv(unsigned netId)242 unsigned getNetworkForResolv(unsigned netId) {
243 if (netId != NETID_UNSET) {
244 return netId;
245 }
246 // Special case for DNS-over-TLS bypass; b/72345192 .
247 if ((netIdForResolv & ~NETID_USE_LOCAL_NAMESERVERS) != NETID_UNSET) {
248 return netIdForResolv;
249 }
250 netId = netIdForProcess;
251 if (netId != NETID_UNSET) {
252 return netId;
253 }
254 return netIdForResolv;
255 }
256
setNetworkForTarget(unsigned netId,std::atomic_uint * target)257 int setNetworkForTarget(unsigned netId, std::atomic_uint* target) {
258 const unsigned requestedNetId = netId;
259 netId &= ~NETID_USE_LOCAL_NAMESERVERS;
260
261 if (netId == NETID_UNSET) {
262 *target = netId;
263 return 0;
264 }
265 // Verify that we are allowed to use |netId|, by creating a socket and trying to have it marked
266 // with the netId. Call libcSocket() directly; else the socket creation (via netdClientSocket())
267 // might itself cause another check with the fwmark server, which would be wasteful.
268
269 const auto socketFunc = libcSocket ? libcSocket : socket;
270 int socketFd = socketFunc(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0);
271 if (socketFd < 0) {
272 return -errno;
273 }
274 int error = setNetworkForSocket(netId, socketFd);
275 if (!error) {
276 *target = requestedNetId;
277 }
278 close(socketFd);
279 return error;
280 }
281
dns_open_proxy()282 int dns_open_proxy() {
283 const char* cache_mode = getenv("ANDROID_DNS_MODE");
284 const bool use_proxy = (cache_mode == NULL || strcmp(cache_mode, "local") != 0);
285 if (!use_proxy) {
286 errno = ENOSYS;
287 return -1;
288 }
289
290 // If networking is not allowed, dns_open_proxy should just fail here.
291 // Then eventually, the DNS related functions in local mode will get
292 // EPERM while creating socket.
293 if (!allowNetworkingForProcess.load()) {
294 errno = EPERM;
295 return -1;
296 }
297 const auto socketFunc = libcSocket ? libcSocket : socket;
298 int s = socketFunc(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
299 if (s == -1) {
300 return -1;
301 }
302 const int one = 1;
303 setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
304
305 static const struct sockaddr_un proxy_addr = {
306 .sun_family = AF_UNIX,
307 .sun_path = "/dev/socket/dnsproxyd",
308 };
309
310 const auto connectFunc = libcConnect ? libcConnect : connect;
311 if (TEMP_FAILURE_RETRY(
312 connectFunc(s, (const struct sockaddr*) &proxy_addr, sizeof(proxy_addr))) != 0) {
313 // Store the errno for connect because we only care about why we can't connect to dnsproxyd
314 int storedErrno = errno;
315 close(s);
316 errno = storedErrno;
317 return -1;
318 }
319
320 return s;
321 }
322
divCeil(size_t dividend,size_t divisor)323 auto divCeil(size_t dividend, size_t divisor) {
324 return ((dividend + divisor - 1) / divisor);
325 }
326
327 // FrameworkListener only does only read() call, and fails if the read doesn't contain \0
328 // Do single write here
sendData(int fd,const void * buf,size_t size)329 int sendData(int fd, const void* buf, size_t size) {
330 if (fd < 0) {
331 return -EBADF;
332 }
333
334 ssize_t rc = TEMP_FAILURE_RETRY(write(fd, (char*) buf, size));
335 if (rc > 0) {
336 return rc;
337 } else if (rc == 0) {
338 return -EIO;
339 } else {
340 return -errno;
341 }
342 }
343
readData(int fd,void * buf,size_t size)344 int readData(int fd, void* buf, size_t size) {
345 if (fd < 0) {
346 return -EBADF;
347 }
348
349 size_t current = 0;
350 for (;;) {
351 ssize_t rc = TEMP_FAILURE_RETRY(read(fd, (char*) buf + current, size - current));
352 if (rc > 0) {
353 current += rc;
354 if (current == size) {
355 break;
356 }
357 } else if (rc == 0) {
358 return -EIO;
359 } else {
360 return -errno;
361 }
362 }
363 return 0;
364 }
365
readBE32(int fd,int32_t * result)366 bool readBE32(int fd, int32_t* result) {
367 int32_t tmp;
368 ssize_t n = TEMP_FAILURE_RETRY(read(fd, &tmp, sizeof(tmp)));
369 if (n < static_cast<ssize_t>(sizeof(tmp))) {
370 return false;
371 }
372 *result = ntohl(tmp);
373 return true;
374 }
375
readResponseCode(int fd,int * result)376 bool readResponseCode(int fd, int* result) {
377 char buf[4];
378 ssize_t n = TEMP_FAILURE_RETRY(read(fd, &buf, sizeof(buf)));
379 if (n < static_cast<ssize_t>(sizeof(buf))) {
380 return false;
381 }
382
383 // The format of response code is 3 bytes followed by a space.
384 buf[3] = '\0';
385 if (!ParseInt(buf, result)) {
386 errno = EINVAL;
387 return false;
388 }
389
390 return true;
391 }
392
393 } // namespace
394
395 #define CHECK_SOCKET_IS_MARKABLE(sock) \
396 do { \
397 int err = checkSocket(sock); \
398 if (err) return err; \
399 } while (false)
400
401 #define HOOK_ON_FUNC(remoteFunc, nativeFunc, localFunc) \
402 do { \
403 if ((remoteFunc) && *(remoteFunc)) { \
404 (nativeFunc) = *(remoteFunc); \
405 *(remoteFunc) = (localFunc); \
406 } \
407 } while (false)
408
409 // accept() just calls accept4(..., 0), so there's no need to handle accept() separately.
netdClientInitAccept4(Accept4FunctionType * function)410 extern "C" void netdClientInitAccept4(Accept4FunctionType* function) {
411 HOOK_ON_FUNC(function, libcAccept4, netdClientAccept4);
412 }
413
netdClientInitConnect(ConnectFunctionType * function)414 extern "C" void netdClientInitConnect(ConnectFunctionType* function) {
415 HOOK_ON_FUNC(function, libcConnect, netdClientConnect);
416 }
417
netdClientInitSocket(SocketFunctionType * function)418 extern "C" void netdClientInitSocket(SocketFunctionType* function) {
419 HOOK_ON_FUNC(function, libcSocket, netdClientSocket);
420 }
421
netdClientInitSendmmsg(SendmmsgFunctionType * function)422 extern "C" void netdClientInitSendmmsg(SendmmsgFunctionType* function) {
423 if (redirectSendX()) HOOK_ON_FUNC(function, libcSendmmsg, netdClientSendmmsg);
424 }
425
netdClientInitSendmsg(SendmsgFunctionType * function)426 extern "C" void netdClientInitSendmsg(SendmsgFunctionType* function) {
427 if (redirectSendX()) HOOK_ON_FUNC(function, libcSendmsg, netdClientSendmsg);
428 }
429
netdClientInitSendto(SendtoFunctionType * function)430 extern "C" void netdClientInitSendto(SendtoFunctionType* function) {
431 if (redirectSendX()) HOOK_ON_FUNC(function, libcSendto, netdClientSendto);
432 }
433
netdClientInitNetIdForResolv(NetIdForResolvFunctionType * function)434 extern "C" void netdClientInitNetIdForResolv(NetIdForResolvFunctionType* function) {
435 if (function) {
436 *function = getNetworkForResolv;
437 }
438 }
439
netdClientInitDnsOpenProxy(DnsOpenProxyType * function)440 extern "C" void netdClientInitDnsOpenProxy(DnsOpenProxyType* function) {
441 if (function) {
442 *function = dns_open_proxy;
443 }
444 }
445
getNetworkForSocket(unsigned * netId,int socketFd)446 extern "C" int getNetworkForSocket(unsigned* netId, int socketFd) {
447 if (!netId || socketFd < 0) {
448 return -EBADF;
449 }
450 Fwmark fwmark;
451 socklen_t fwmarkLen = sizeof(fwmark.intValue);
452 if (getsockopt(socketFd, SOL_SOCKET, SO_MARK, &fwmark.intValue, &fwmarkLen) == -1) {
453 return -errno;
454 }
455 *netId = fwmark.netId;
456 return 0;
457 }
458
getNetworkForProcess()459 extern "C" unsigned getNetworkForProcess() {
460 return netIdForProcess & ~NETID_USE_LOCAL_NAMESERVERS;
461 }
462
setNetworkForSocket(unsigned netId,int socketFd)463 extern "C" int setNetworkForSocket(unsigned netId, int socketFd) {
464 CHECK_SOCKET_IS_MARKABLE(socketFd);
465 FwmarkCommand command = {FwmarkCommand::SELECT_NETWORK, netId, 0, 0};
466 return FwmarkClient().send(&command, socketFd, nullptr);
467 }
468
setNetworkForProcess(unsigned netId)469 extern "C" int setNetworkForProcess(unsigned netId) {
470 return setNetworkForTarget(netId, &netIdForProcess);
471 }
472
setNetworkForResolv(unsigned netId)473 extern "C" int setNetworkForResolv(unsigned netId) {
474 return setNetworkForTarget(netId, &netIdForResolv);
475 }
476
protectFromVpn(int socketFd)477 extern "C" int protectFromVpn(int socketFd) {
478 CHECK_SOCKET_IS_MARKABLE(socketFd);
479 FwmarkCommand command = {FwmarkCommand::PROTECT_FROM_VPN, 0, 0, 0};
480 return FwmarkClient().send(&command, socketFd, nullptr);
481 }
482
setNetworkForUser(uid_t uid,int socketFd)483 extern "C" int setNetworkForUser(uid_t uid, int socketFd) {
484 CHECK_SOCKET_IS_MARKABLE(socketFd);
485 FwmarkCommand command = {FwmarkCommand::SELECT_FOR_USER, 0, uid, 0};
486 return FwmarkClient().send(&command, socketFd, nullptr);
487 }
488
queryUserAccess(uid_t uid,unsigned netId)489 extern "C" int queryUserAccess(uid_t uid, unsigned netId) {
490 FwmarkCommand command = {FwmarkCommand::QUERY_USER_ACCESS, netId, uid, 0};
491 return FwmarkClient().send(&command, -1, nullptr);
492 }
493
tagSocket(int socketFd,uint32_t tag,uid_t uid)494 extern "C" int tagSocket(int socketFd, uint32_t tag, uid_t uid) {
495 CHECK_SOCKET_IS_MARKABLE(socketFd);
496 FwmarkCommand command = {FwmarkCommand::TAG_SOCKET, 0, uid, tag};
497 return FwmarkClient().send(&command, socketFd, nullptr);
498 }
499
untagSocket(int socketFd)500 extern "C" int untagSocket(int socketFd) {
501 CHECK_SOCKET_IS_MARKABLE(socketFd);
502 FwmarkCommand command = {FwmarkCommand::UNTAG_SOCKET, 0, 0, 0};
503 return FwmarkClient().send(&command, socketFd, nullptr);
504 }
505
resNetworkQuery(unsigned netId,const char * dname,int ns_class,int ns_type,uint32_t flags)506 extern "C" int resNetworkQuery(unsigned netId, const char* dname, int ns_class, int ns_type,
507 uint32_t flags) {
508 std::vector<uint8_t> buf(MAX_CMD_SIZE, 0);
509 int len = res_mkquery(ns_o_query, dname, ns_class, ns_type, nullptr, 0, nullptr, buf.data(),
510 MAX_CMD_SIZE);
511
512 return resNetworkSend(netId, buf.data(), len, flags);
513 }
514
resNetworkSend(unsigned netId,const uint8_t * msg,size_t msglen,uint32_t flags)515 extern "C" int resNetworkSend(unsigned netId, const uint8_t* msg, size_t msglen, uint32_t flags) {
516 // Encode
517 // Base 64 encodes every 3 bytes into 4 characters, but then adds padding to the next
518 // multiple of 4 and a \0
519 const size_t encodedLen = divCeil(msglen, 3) * 4 + 1;
520 std::string encodedQuery(encodedLen - 1, 0);
521 int enLen = b64_ntop(msg, msglen, encodedQuery.data(), encodedLen);
522
523 if (enLen < 0) {
524 // Unexpected behavior, encode failed
525 // b64_ntop only fails when size is too long.
526 return -EMSGSIZE;
527 }
528 // Send
529 netId = getNetworkForResolv(netId);
530 const std::string cmd = "resnsend " + std::to_string(netId) + " " + std::to_string(flags) +
531 " " + encodedQuery + '\0';
532 if (cmd.size() > MAX_CMD_SIZE) {
533 // Cmd size must less than buffer size of FrameworkListener
534 return -EMSGSIZE;
535 }
536 int fd = dns_open_proxy();
537 if (fd == -1) {
538 return -errno;
539 }
540 ssize_t rc = sendData(fd, cmd.c_str(), cmd.size());
541 if (rc < 0) {
542 close(fd);
543 return rc;
544 }
545 shutdown(fd, SHUT_WR);
546 return fd;
547 }
548
resNetworkResult(int fd,int * rcode,uint8_t * answer,size_t anslen)549 extern "C" int resNetworkResult(int fd, int* rcode, uint8_t* answer, size_t anslen) {
550 int32_t result = 0;
551 unique_fd ufd(fd);
552 // Read -errno/rcode
553 if (!readBE32(fd, &result)) {
554 // Unexpected behavior, read -errno/rcode fail
555 return -errno;
556 }
557 if (result < 0) {
558 // result < 0, it's -errno
559 return result;
560 }
561 // result >= 0, it's rcode
562 *rcode = result;
563
564 // Read answer
565 int32_t size = 0;
566 if (!readBE32(fd, &size)) {
567 // Unexpected behavior, read ans len fail
568 return -EREMOTEIO;
569 }
570 if (anslen < static_cast<size_t>(size)) {
571 // Answer buffer is too small
572 return -EMSGSIZE;
573 }
574 int rc = readData(fd, answer, size);
575 if (rc < 0) {
576 // Reading the answer failed.
577 return rc;
578 }
579 return size;
580 }
581
resNetworkCancel(int fd)582 extern "C" void resNetworkCancel(int fd) {
583 close(fd);
584 }
585
setAllowNetworkingForProcess(bool allowNetworking)586 extern "C" void setAllowNetworkingForProcess(bool allowNetworking) {
587 allowNetworkingForProcess.store(allowNetworking);
588 }
589
getNetworkForDns(unsigned * dnsNetId)590 extern "C" int getNetworkForDns(unsigned* dnsNetId) {
591 if (dnsNetId == nullptr) return -EFAULT;
592 int fd = dns_open_proxy();
593 if (fd == -1) {
594 return -errno;
595 }
596 unique_fd ufd(fd);
597 return getNetworkForDnsInternal(fd, dnsNetId);
598 }
599
getNetworkForDnsInternal(int fd,unsigned * dnsNetId)600 int getNetworkForDnsInternal(int fd, unsigned* dnsNetId) {
601 if (fd == -1) {
602 return -EBADF;
603 }
604
605 unsigned resolvNetId = getNetworkForResolv(NETID_UNSET);
606
607 const std::string cmd = "getdnsnetid " + std::to_string(resolvNetId);
608 ssize_t rc = sendData(fd, cmd.c_str(), cmd.size() + 1);
609 if (rc < 0) {
610 return rc;
611 }
612
613 int responseCode = 0;
614 // Read responseCode
615 if (!readResponseCode(fd, &responseCode)) {
616 // Unexpected behavior, read responseCode fail
617 return -errno;
618 }
619
620 if (responseCode != ResponseCode::DnsProxyQueryResult) {
621 return -EOPNOTSUPP;
622 }
623
624 int32_t result = 0;
625 // Read -errno/dnsnetid
626 if (!readBE32(fd, &result)) {
627 // Unexpected behavior, read -errno/dnsnetid fail
628 return -errno;
629 }
630
631 *dnsNetId = result;
632
633 return 0;
634 }
635