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