blob: 84f2564fc40adb17eb3290e9a9ea7d2b938a9b9c [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"
Mike Yue7e332f2019-03-13 17:15:48 +080035#include "netdutils/Stopwatch.h"
Bernie Innocenti189eb502018-10-01 23:10:18 +090036#include "netid_client.h"
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -070037
Luke Huangc68f1b92018-11-21 20:13:38 +080038#include "android-base/unique_fd.h"
39
40using android::base::unique_fd;
Mike Yue7e332f2019-03-13 17:15:48 +080041using android::netdutils::Stopwatch;
Luke Huangc68f1b92018-11-21 20:13:38 +080042
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -070043namespace {
44
Luke Huangc68f1b92018-11-21 20:13:38 +080045// Keep this in sync with CMD_BUF_SIZE in FrameworkListener.cpp.
Luke Huange92b75e2019-03-26 17:56:49 +080046constexpr size_t MAX_CMD_SIZE = 4096;
Luke Huangc68f1b92018-11-21 20:13:38 +080047
Sreeram Ramachandran9fa2b132014-06-03 12:51:08 -070048std::atomic_uint netIdForProcess(NETID_UNSET);
49std::atomic_uint netIdForResolv(NETID_UNSET);
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -070050
51typedef int (*Accept4FunctionType)(int, sockaddr*, socklen_t*, int);
52typedef int (*ConnectFunctionType)(int, const sockaddr*, socklen_t);
53typedef int (*SocketFunctionType)(int, int, int);
54typedef unsigned (*NetIdForResolvFunctionType)(unsigned);
Luke Huangc5efae92018-11-19 17:45:13 +080055typedef int (*DnsOpenProxyType)();
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -070056
57// These variables are only modified at startup (when libc.so is loaded) and never afterwards, so
58// it's okay that they are read later at runtime without a lock.
Yi Kongbdfd57e2018-07-25 13:26:10 -070059Accept4FunctionType libcAccept4 = nullptr;
60ConnectFunctionType libcConnect = nullptr;
61SocketFunctionType libcSocket = nullptr;
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -070062
Lorenzo Colitti24601da2019-02-14 00:48:36 +090063int checkSocket(int socketFd) {
64 if (socketFd < 0) {
65 return -EBADF;
66 }
67 int family;
68 socklen_t familyLen = sizeof(family);
69 if (getsockopt(socketFd, SOL_SOCKET, SO_DOMAIN, &family, &familyLen) == -1) {
70 return -errno;
71 }
72 if (!FwmarkClient::shouldSetFwmark(family)) {
73 return -EAFNOSUPPORT;
74 }
75 return 0;
76}
77
78bool shouldMarkSocket(int socketFd, const sockaddr* dst) {
79 // Only mark inet sockets that are connecting to inet destinations. This excludes, for example,
80 // inet sockets connecting to AF_UNSPEC (i.e., being disconnected), and non-inet sockets that
81 // for some reason the caller wants to attempt to connect to an inet destination.
82 return dst && FwmarkClient::shouldSetFwmark(dst->sa_family) && (checkSocket(socketFd) == 0);
83}
84
Sreeram Ramachandran31f42102014-06-20 11:51:48 -070085int closeFdAndSetErrno(int fd, int error) {
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -070086 close(fd);
Sreeram Ramachandran3a069e62014-06-22 11:02:57 -070087 errno = -error;
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -070088 return -1;
89}
90
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -070091int netdClientAccept4(int sockfd, sockaddr* addr, socklen_t* addrlen, int flags) {
92 int acceptedSocket = libcAccept4(sockfd, addr, addrlen, flags);
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -070093 if (acceptedSocket == -1) {
94 return -1;
95 }
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -070096 int family;
97 if (addr) {
98 family = addr->sa_family;
99 } else {
100 socklen_t familyLen = sizeof(family);
101 if (getsockopt(acceptedSocket, SOL_SOCKET, SO_DOMAIN, &family, &familyLen) == -1) {
Sreeram Ramachandran3a069e62014-06-22 11:02:57 -0700102 return closeFdAndSetErrno(acceptedSocket, -errno);
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -0700103 }
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -0700104 }
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -0700105 if (FwmarkClient::shouldSetFwmark(family)) {
Chenbo Feng9944ba82017-10-10 17:33:20 -0700106 FwmarkCommand command = {FwmarkCommand::ON_ACCEPT, 0, 0, 0};
Michal Karpinski4b9b78a2016-10-06 19:33:55 +0100107 if (int error = FwmarkClient().send(&command, acceptedSocket, nullptr)) {
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700108 return closeFdAndSetErrno(acceptedSocket, error);
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -0700109 }
110 }
111 return acceptedSocket;
112}
113
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -0700114int netdClientConnect(int sockfd, const sockaddr* addr, socklen_t addrlen) {
Lorenzo Colitti24601da2019-02-14 00:48:36 +0900115 const bool shouldSetFwmark = shouldMarkSocket(sockfd, addr);
Michal Karpinski4b9b78a2016-10-06 19:33:55 +0100116 if (shouldSetFwmark) {
Chenbo Feng9944ba82017-10-10 17:33:20 -0700117 FwmarkCommand command = {FwmarkCommand::ON_CONNECT, 0, 0, 0};
Michal Karpinski4b9b78a2016-10-06 19:33:55 +0100118 if (int error = FwmarkClient().send(&command, sockfd, nullptr)) {
Sreeram Ramachandran3a069e62014-06-22 11:02:57 -0700119 errno = -error;
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -0700120 return -1;
121 }
122 }
Michal Karpinski4b9b78a2016-10-06 19:33:55 +0100123 // Latency measurement does not include time of sending commands to Fwmark
124 Stopwatch s;
Hugo Benichi794c5c72016-10-31 15:07:23 +0900125 const int ret = libcConnect(sockfd, addr, addrlen);
Michal Karpinski4b9b78a2016-10-06 19:33:55 +0100126 // Save errno so it isn't clobbered by sending ON_CONNECT_COMPLETE
127 const int connectErrno = errno;
Bernie Innocenti196f1b82019-05-20 16:34:16 +0900128 const auto latencyMs = static_cast<unsigned>(s.timeTakenUs() / 1000);
Michal Karpinski4b9b78a2016-10-06 19:33:55 +0100129 // Send an ON_CONNECT_COMPLETE command that includes sockaddr and connect latency for reporting
130 if (shouldSetFwmark && FwmarkClient::shouldReportConnectComplete(addr->sa_family)) {
Hugo Benichi794c5c72016-10-31 15:07:23 +0900131 FwmarkConnectInfo connectInfo(ret == 0 ? 0 : connectErrno, latencyMs, addr);
Michal Karpinski4b9b78a2016-10-06 19:33:55 +0100132 // TODO: get the netId from the socket mark once we have continuous benchmark runs
133 FwmarkCommand command = {FwmarkCommand::ON_CONNECT_COMPLETE, /* netId (ignored) */ 0,
Chenbo Feng9944ba82017-10-10 17:33:20 -0700134 /* uid (filled in by the server) */ 0, 0};
Michal Karpinski4b9b78a2016-10-06 19:33:55 +0100135 // Ignore return value since it's only used for logging
136 FwmarkClient().send(&command, sockfd, &connectInfo);
137 }
138 errno = connectErrno;
139 return ret;
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -0700140}
141
142int netdClientSocket(int domain, int type, int protocol) {
143 int socketFd = libcSocket(domain, type, protocol);
144 if (socketFd == -1) {
145 return -1;
146 }
Lorenzo Colitti6b001262019-01-30 22:43:36 +0900147 unsigned netId = netIdForProcess & ~NETID_USE_LOCAL_NAMESERVERS;
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -0700148 if (netId != NETID_UNSET && FwmarkClient::shouldSetFwmark(domain)) {
Sreeram Ramachandrand36c49c2014-07-02 14:49:33 -0700149 if (int error = setNetworkForSocket(netId, socketFd)) {
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700150 return closeFdAndSetErrno(socketFd, error);
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -0700151 }
152 }
153 return socketFd;
154}
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700155
156unsigned getNetworkForResolv(unsigned netId) {
157 if (netId != NETID_UNSET) {
158 return netId;
159 }
Erik Kline1564d482018-03-07 17:09:35 +0900160 // Special case for DNS-over-TLS bypass; b/72345192 .
161 if ((netIdForResolv & ~NETID_USE_LOCAL_NAMESERVERS) != NETID_UNSET) {
162 return netIdForResolv;
163 }
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700164 netId = netIdForProcess;
165 if (netId != NETID_UNSET) {
166 return netId;
167 }
168 return netIdForResolv;
169}
170
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700171int setNetworkForTarget(unsigned netId, std::atomic_uint* target) {
Erik Kline1564d482018-03-07 17:09:35 +0900172 const unsigned requestedNetId = netId;
173 netId &= ~NETID_USE_LOCAL_NAMESERVERS;
174
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700175 if (netId == NETID_UNSET) {
176 *target = netId;
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700177 return 0;
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700178 }
179 // 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 -0700180 // with the netId. Call libcSocket() directly; else the socket creation (via netdClientSocket())
181 // might itself cause another check with the fwmark server, which would be wasteful.
Luke Huangc5efae92018-11-19 17:45:13 +0800182
183 const auto socketFunc = libcSocket ? libcSocket : socket;
184 int socketFd = socketFunc(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0);
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700185 if (socketFd < 0) {
Sreeram Ramachandran3a069e62014-06-22 11:02:57 -0700186 return -errno;
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700187 }
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700188 int error = setNetworkForSocket(netId, socketFd);
189 if (!error) {
Lorenzo Colitti6b001262019-01-30 22:43:36 +0900190 *target = requestedNetId;
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700191 }
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700192 close(socketFd);
193 return error;
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700194}
195
Luke Huangc5efae92018-11-19 17:45:13 +0800196int dns_open_proxy() {
197 const char* cache_mode = getenv("ANDROID_DNS_MODE");
198 const bool use_proxy = (cache_mode == NULL || strcmp(cache_mode, "local") != 0);
199 if (!use_proxy) {
200 return -1;
201 }
202
203 const auto socketFunc = libcSocket ? libcSocket : socket;
204 int s = socketFunc(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
205 if (s == -1) {
206 return -1;
207 }
208 const int one = 1;
209 setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
210
211 static const struct sockaddr_un proxy_addr = {
212 .sun_family = AF_UNIX,
213 .sun_path = "/dev/socket/dnsproxyd",
214 };
215
216 const auto connectFunc = libcConnect ? libcConnect : connect;
217 if (TEMP_FAILURE_RETRY(
218 connectFunc(s, (const struct sockaddr*) &proxy_addr, sizeof(proxy_addr))) != 0) {
219 close(s);
220 return -1;
221 }
222
223 return s;
224}
225
Luke Huangc68f1b92018-11-21 20:13:38 +0800226auto divCeil(size_t dividend, size_t divisor) {
227 return ((dividend + divisor - 1) / divisor);
228}
229
230// FrameworkListener only does only read() call, and fails if the read doesn't contain \0
231// Do single write here
232int sendData(int fd, const void* buf, size_t size) {
233 if (fd < 0) {
234 return -EBADF;
235 }
236
237 ssize_t rc = TEMP_FAILURE_RETRY(write(fd, (char*) buf, size));
238 if (rc > 0) {
239 return rc;
240 } else if (rc == 0) {
241 return -EIO;
242 } else {
243 return -errno;
244 }
245}
246
247int readData(int fd, void* buf, size_t size) {
248 if (fd < 0) {
249 return -EBADF;
250 }
251
252 size_t current = 0;
253 for (;;) {
254 ssize_t rc = TEMP_FAILURE_RETRY(read(fd, (char*) buf + current, size - current));
255 if (rc > 0) {
256 current += rc;
257 if (current == size) {
258 break;
259 }
260 } else if (rc == 0) {
261 return -EIO;
262 } else {
263 return -errno;
264 }
265 }
266 return 0;
267}
268
269bool readBE32(int fd, int32_t* result) {
270 int32_t tmp;
271 int n = TEMP_FAILURE_RETRY(read(fd, &tmp, sizeof(tmp)));
272 if (n < 0) {
273 return false;
274 }
275 *result = ntohl(tmp);
276 return true;
277}
278
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -0700279} // namespace
280
Remi NGUYEN VANeabc5da2018-04-24 18:54:58 +0900281#define CHECK_SOCKET_IS_MARKABLE(sock) \
282 do { \
283 int err; \
284 if ((err = checkSocket(sock)) != 0) { \
285 return err; \
286 } \
287 } while (false);
288
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -0700289// accept() just calls accept4(..., 0), so there's no need to handle accept() separately.
290extern "C" void netdClientInitAccept4(Accept4FunctionType* function) {
291 if (function && *function) {
292 libcAccept4 = *function;
293 *function = netdClientAccept4;
294 }
295}
296
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -0700297extern "C" void netdClientInitConnect(ConnectFunctionType* function) {
298 if (function && *function) {
299 libcConnect = *function;
300 *function = netdClientConnect;
301 }
302}
303
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -0700304extern "C" void netdClientInitSocket(SocketFunctionType* function) {
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -0700305 if (function && *function) {
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -0700306 libcSocket = *function;
307 *function = netdClientSocket;
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -0700308 }
309}
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700310
311extern "C" void netdClientInitNetIdForResolv(NetIdForResolvFunctionType* function) {
312 if (function) {
313 *function = getNetworkForResolv;
314 }
315}
316
Luke Huangc5efae92018-11-19 17:45:13 +0800317extern "C" void netdClientInitDnsOpenProxy(DnsOpenProxyType* function) {
318 if (function) {
319 *function = dns_open_proxy;
320 }
321}
322
Sreeram Ramachandran4d4c8b72014-06-20 11:59:40 -0700323extern "C" int getNetworkForSocket(unsigned* netId, int socketFd) {
324 if (!netId || socketFd < 0) {
Sreeram Ramachandran3a069e62014-06-22 11:02:57 -0700325 return -EBADF;
Sreeram Ramachandran4d4c8b72014-06-20 11:59:40 -0700326 }
327 Fwmark fwmark;
328 socklen_t fwmarkLen = sizeof(fwmark.intValue);
329 if (getsockopt(socketFd, SOL_SOCKET, SO_MARK, &fwmark.intValue, &fwmarkLen) == -1) {
Sreeram Ramachandran3a069e62014-06-22 11:02:57 -0700330 return -errno;
Sreeram Ramachandran4d4c8b72014-06-20 11:59:40 -0700331 }
332 *netId = fwmark.netId;
333 return 0;
334}
335
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700336extern "C" unsigned getNetworkForProcess() {
Lorenzo Colitti6b001262019-01-30 22:43:36 +0900337 return netIdForProcess & ~NETID_USE_LOCAL_NAMESERVERS;
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700338}
339
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700340extern "C" int setNetworkForSocket(unsigned netId, int socketFd) {
Remi NGUYEN VANeabc5da2018-04-24 18:54:58 +0900341 CHECK_SOCKET_IS_MARKABLE(socketFd);
Chenbo Feng9944ba82017-10-10 17:33:20 -0700342 FwmarkCommand command = {FwmarkCommand::SELECT_NETWORK, netId, 0, 0};
Michal Karpinski4b9b78a2016-10-06 19:33:55 +0100343 return FwmarkClient().send(&command, socketFd, nullptr);
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700344}
345
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700346extern "C" int setNetworkForProcess(unsigned netId) {
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700347 return setNetworkForTarget(netId, &netIdForProcess);
348}
349
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700350extern "C" int setNetworkForResolv(unsigned netId) {
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700351 return setNetworkForTarget(netId, &netIdForResolv);
352}
Sreeram Ramachandrand794e582014-06-19 10:03:07 -0700353
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700354extern "C" int protectFromVpn(int socketFd) {
Sreeram Ramachandrand794e582014-06-19 10:03:07 -0700355 if (socketFd < 0) {
Sreeram Ramachandran3a069e62014-06-22 11:02:57 -0700356 return -EBADF;
Sreeram Ramachandrand794e582014-06-19 10:03:07 -0700357 }
Chenbo Feng9944ba82017-10-10 17:33:20 -0700358 FwmarkCommand command = {FwmarkCommand::PROTECT_FROM_VPN, 0, 0, 0};
Michal Karpinski4b9b78a2016-10-06 19:33:55 +0100359 return FwmarkClient().send(&command, socketFd, nullptr);
Sreeram Ramachandrana69d9472014-07-11 16:27:02 -0700360}
361
362extern "C" int setNetworkForUser(uid_t uid, int socketFd) {
Remi NGUYEN VANeabc5da2018-04-24 18:54:58 +0900363 CHECK_SOCKET_IS_MARKABLE(socketFd);
Chenbo Feng9944ba82017-10-10 17:33:20 -0700364 FwmarkCommand command = {FwmarkCommand::SELECT_FOR_USER, 0, uid, 0};
Michal Karpinski4b9b78a2016-10-06 19:33:55 +0100365 return FwmarkClient().send(&command, socketFd, nullptr);
Paul Jensend1df5972015-05-06 07:29:56 -0400366}
367
368extern "C" int queryUserAccess(uid_t uid, unsigned netId) {
Chenbo Feng9944ba82017-10-10 17:33:20 -0700369 FwmarkCommand command = {FwmarkCommand::QUERY_USER_ACCESS, netId, uid, 0};
370 return FwmarkClient().send(&command, -1, nullptr);
371}
372
373extern "C" int tagSocket(int socketFd, uint32_t tag, uid_t uid) {
Remi NGUYEN VANeabc5da2018-04-24 18:54:58 +0900374 CHECK_SOCKET_IS_MARKABLE(socketFd);
Chenbo Feng9944ba82017-10-10 17:33:20 -0700375 FwmarkCommand command = {FwmarkCommand::TAG_SOCKET, 0, uid, tag};
376 return FwmarkClient().send(&command, socketFd, nullptr);
377}
378
379extern "C" int untagSocket(int socketFd) {
Remi NGUYEN VANeabc5da2018-04-24 18:54:58 +0900380 CHECK_SOCKET_IS_MARKABLE(socketFd);
Chenbo Feng9944ba82017-10-10 17:33:20 -0700381 FwmarkCommand command = {FwmarkCommand::UNTAG_SOCKET, 0, 0, 0};
382 return FwmarkClient().send(&command, socketFd, nullptr);
383}
384
385extern "C" int setCounterSet(uint32_t counterSet, uid_t uid) {
386 FwmarkCommand command = {FwmarkCommand::SET_COUNTERSET, 0, uid, counterSet};
387 return FwmarkClient().send(&command, -1, nullptr);
388}
389
390extern "C" int deleteTagData(uint32_t tag, uid_t uid) {
391 FwmarkCommand command = {FwmarkCommand::DELETE_TAGDATA, 0, uid, tag};
Michal Karpinski4b9b78a2016-10-06 19:33:55 +0100392 return FwmarkClient().send(&command, -1, nullptr);
Sreeram Ramachandrand794e582014-06-19 10:03:07 -0700393}
Luke Huangc68f1b92018-11-21 20:13:38 +0800394
Luke Huang110c54e2018-12-20 14:39:58 +0800395extern "C" int resNetworkQuery(unsigned netId, const char* dname, int ns_class, int ns_type,
396 uint32_t flags) {
Luke Huange48fbcb2018-12-17 16:37:33 +0800397 std::vector<uint8_t> buf(MAX_CMD_SIZE, 0);
398 int len = res_mkquery(ns_o_query, dname, ns_class, ns_type, nullptr, 0, nullptr, buf.data(),
399 MAX_CMD_SIZE);
Luke Huangc68f1b92018-11-21 20:13:38 +0800400
Luke Huang110c54e2018-12-20 14:39:58 +0800401 return resNetworkSend(netId, buf.data(), len, flags);
Luke Huangc68f1b92018-11-21 20:13:38 +0800402}
403
Luke Huang952d0942018-12-26 16:53:03 +0800404extern "C" int resNetworkSend(unsigned netId, const uint8_t* msg, size_t msglen, uint32_t flags) {
Luke Huangc68f1b92018-11-21 20:13:38 +0800405 // Encode
406 // Base 64 encodes every 3 bytes into 4 characters, but then adds padding to the next
407 // multiple of 4 and a \0
408 const size_t encodedLen = divCeil(msglen, 3) * 4 + 1;
Luke Huange48fbcb2018-12-17 16:37:33 +0800409 std::string encodedQuery(encodedLen - 1, 0);
Luke Huangc68f1b92018-11-21 20:13:38 +0800410 int enLen = b64_ntop(msg, msglen, encodedQuery.data(), encodedLen);
411
412 if (enLen < 0) {
413 // Unexpected behavior, encode failed
414 // b64_ntop only fails when size is too long.
415 return -EMSGSIZE;
416 }
417 // Send
418 netId = getNetworkForResolv(netId);
Luke Huang952d0942018-12-26 16:53:03 +0800419 const std::string cmd = "resnsend " + std::to_string(netId) + " " + std::to_string(flags) +
420 " " + encodedQuery + '\0';
Luke Huangc68f1b92018-11-21 20:13:38 +0800421 if (cmd.size() > MAX_CMD_SIZE) {
422 // Cmd size must less than buffer size of FrameworkListener
423 return -EMSGSIZE;
424 }
425 int fd = dns_open_proxy();
426 if (fd == -1) {
427 return -errno;
428 }
429 ssize_t rc = sendData(fd, cmd.c_str(), cmd.size());
430 if (rc < 0) {
431 close(fd);
432 return rc;
433 }
434 shutdown(fd, SHUT_WR);
435 return fd;
436}
437
Luke Huange48fbcb2018-12-17 16:37:33 +0800438extern "C" int resNetworkResult(int fd, int* rcode, uint8_t* answer, size_t anslen) {
Luke Huangc68f1b92018-11-21 20:13:38 +0800439 int32_t result = 0;
440 unique_fd ufd(fd);
441 // Read -errno/rcode
442 if (!readBE32(fd, &result)) {
443 // Unexpected behavior, read -errno/rcode fail
444 return -errno;
445 }
446 if (result < 0) {
447 // result < 0, it's -errno
448 return result;
449 }
450 // result >= 0, it's rcode
451 *rcode = result;
452
453 // Read answer
454 int32_t size = 0;
455 if (!readBE32(fd, &size)) {
456 // Unexpected behavior, read ans len fail
457 return -EREMOTEIO;
458 }
Luke Huange48fbcb2018-12-17 16:37:33 +0800459 if (anslen < static_cast<size_t>(size)) {
Luke Huangc68f1b92018-11-21 20:13:38 +0800460 // Answer buffer is too small
461 return -EMSGSIZE;
462 }
463 int rc = readData(fd, answer, size);
464 if (rc < 0) {
465 // Reading the answer failed.
466 return rc;
467 }
468 return size;
469}
470
471extern "C" void resNetworkCancel(int fd) {
472 close(fd);
Lorenzo Colitti6b001262019-01-30 22:43:36 +0900473}