blob: 558634715caec990e69d8a959c846f739380ec25 [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"
Robin Leecc544162016-09-21 16:31:33 +090035#include "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;
41
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -070042namespace {
43
Luke Huangc68f1b92018-11-21 20:13:38 +080044// Keep this in sync with CMD_BUF_SIZE in FrameworkListener.cpp.
45constexpr size_t MAX_CMD_SIZE = 1024;
46
Sreeram Ramachandran9fa2b132014-06-03 12:51:08 -070047std::atomic_uint netIdForProcess(NETID_UNSET);
48std::atomic_uint netIdForResolv(NETID_UNSET);
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -070049
50typedef int (*Accept4FunctionType)(int, sockaddr*, socklen_t*, int);
51typedef int (*ConnectFunctionType)(int, const sockaddr*, socklen_t);
52typedef int (*SocketFunctionType)(int, int, int);
53typedef unsigned (*NetIdForResolvFunctionType)(unsigned);
Luke Huangc5efae92018-11-19 17:45:13 +080054typedef int (*DnsOpenProxyType)();
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -070055
56// These variables are only modified at startup (when libc.so is loaded) and never afterwards, so
57// it's okay that they are read later at runtime without a lock.
Yi Kongbdfd57e2018-07-25 13:26:10 -070058Accept4FunctionType libcAccept4 = nullptr;
59ConnectFunctionType libcConnect = nullptr;
60SocketFunctionType libcSocket = nullptr;
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -070061
Sreeram Ramachandran31f42102014-06-20 11:51:48 -070062int closeFdAndSetErrno(int fd, int error) {
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -070063 close(fd);
Sreeram Ramachandran3a069e62014-06-22 11:02:57 -070064 errno = -error;
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -070065 return -1;
66}
67
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -070068int netdClientAccept4(int sockfd, sockaddr* addr, socklen_t* addrlen, int flags) {
69 int acceptedSocket = libcAccept4(sockfd, addr, addrlen, flags);
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -070070 if (acceptedSocket == -1) {
71 return -1;
72 }
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -070073 int family;
74 if (addr) {
75 family = addr->sa_family;
76 } else {
77 socklen_t familyLen = sizeof(family);
78 if (getsockopt(acceptedSocket, SOL_SOCKET, SO_DOMAIN, &family, &familyLen) == -1) {
Sreeram Ramachandran3a069e62014-06-22 11:02:57 -070079 return closeFdAndSetErrno(acceptedSocket, -errno);
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -070080 }
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -070081 }
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -070082 if (FwmarkClient::shouldSetFwmark(family)) {
Chenbo Feng9944ba82017-10-10 17:33:20 -070083 FwmarkCommand command = {FwmarkCommand::ON_ACCEPT, 0, 0, 0};
Michal Karpinski4b9b78a2016-10-06 19:33:55 +010084 if (int error = FwmarkClient().send(&command, acceptedSocket, nullptr)) {
Sreeram Ramachandran31f42102014-06-20 11:51:48 -070085 return closeFdAndSetErrno(acceptedSocket, error);
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -070086 }
87 }
88 return acceptedSocket;
89}
90
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -070091int netdClientConnect(int sockfd, const sockaddr* addr, socklen_t addrlen) {
Michal Karpinski4b9b78a2016-10-06 19:33:55 +010092 const bool shouldSetFwmark = (sockfd >= 0) && addr
93 && FwmarkClient::shouldSetFwmark(addr->sa_family);
94 if (shouldSetFwmark) {
Chenbo Feng9944ba82017-10-10 17:33:20 -070095 FwmarkCommand command = {FwmarkCommand::ON_CONNECT, 0, 0, 0};
Michal Karpinski4b9b78a2016-10-06 19:33:55 +010096 if (int error = FwmarkClient().send(&command, sockfd, nullptr)) {
Sreeram Ramachandran3a069e62014-06-22 11:02:57 -070097 errno = -error;
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -070098 return -1;
99 }
100 }
Michal Karpinski4b9b78a2016-10-06 19:33:55 +0100101 // Latency measurement does not include time of sending commands to Fwmark
102 Stopwatch s;
Hugo Benichi794c5c72016-10-31 15:07:23 +0900103 const int ret = libcConnect(sockfd, addr, addrlen);
Michal Karpinski4b9b78a2016-10-06 19:33:55 +0100104 // Save errno so it isn't clobbered by sending ON_CONNECT_COMPLETE
105 const int connectErrno = errno;
106 const unsigned latencyMs = lround(s.timeTaken());
107 // Send an ON_CONNECT_COMPLETE command that includes sockaddr and connect latency for reporting
108 if (shouldSetFwmark && FwmarkClient::shouldReportConnectComplete(addr->sa_family)) {
Hugo Benichi794c5c72016-10-31 15:07:23 +0900109 FwmarkConnectInfo connectInfo(ret == 0 ? 0 : connectErrno, latencyMs, addr);
Michal Karpinski4b9b78a2016-10-06 19:33:55 +0100110 // TODO: get the netId from the socket mark once we have continuous benchmark runs
111 FwmarkCommand command = {FwmarkCommand::ON_CONNECT_COMPLETE, /* netId (ignored) */ 0,
Chenbo Feng9944ba82017-10-10 17:33:20 -0700112 /* uid (filled in by the server) */ 0, 0};
Michal Karpinski4b9b78a2016-10-06 19:33:55 +0100113 // Ignore return value since it's only used for logging
114 FwmarkClient().send(&command, sockfd, &connectInfo);
115 }
116 errno = connectErrno;
117 return ret;
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -0700118}
119
120int netdClientSocket(int domain, int type, int protocol) {
121 int socketFd = libcSocket(domain, type, protocol);
122 if (socketFd == -1) {
123 return -1;
124 }
125 unsigned netId = netIdForProcess;
126 if (netId != NETID_UNSET && FwmarkClient::shouldSetFwmark(domain)) {
Sreeram Ramachandrand36c49c2014-07-02 14:49:33 -0700127 if (int error = setNetworkForSocket(netId, socketFd)) {
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700128 return closeFdAndSetErrno(socketFd, error);
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -0700129 }
130 }
131 return socketFd;
132}
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700133
134unsigned getNetworkForResolv(unsigned netId) {
135 if (netId != NETID_UNSET) {
136 return netId;
137 }
Erik Kline1564d482018-03-07 17:09:35 +0900138 // Special case for DNS-over-TLS bypass; b/72345192 .
139 if ((netIdForResolv & ~NETID_USE_LOCAL_NAMESERVERS) != NETID_UNSET) {
140 return netIdForResolv;
141 }
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700142 netId = netIdForProcess;
143 if (netId != NETID_UNSET) {
144 return netId;
145 }
146 return netIdForResolv;
147}
148
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700149int setNetworkForTarget(unsigned netId, std::atomic_uint* target) {
Erik Kline1564d482018-03-07 17:09:35 +0900150 const unsigned requestedNetId = netId;
151 netId &= ~NETID_USE_LOCAL_NAMESERVERS;
152
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700153 if (netId == NETID_UNSET) {
154 *target = netId;
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700155 return 0;
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700156 }
157 // 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 -0700158 // with the netId. Call libcSocket() directly; else the socket creation (via netdClientSocket())
159 // might itself cause another check with the fwmark server, which would be wasteful.
Luke Huangc5efae92018-11-19 17:45:13 +0800160
161 const auto socketFunc = libcSocket ? libcSocket : socket;
162 int socketFd = socketFunc(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0);
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700163 if (socketFd < 0) {
Sreeram Ramachandran3a069e62014-06-22 11:02:57 -0700164 return -errno;
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700165 }
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700166 int error = setNetworkForSocket(netId, socketFd);
167 if (!error) {
Erik Kline1564d482018-03-07 17:09:35 +0900168 *target = (target == &netIdForResolv) ? requestedNetId : netId;
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700169 }
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700170 close(socketFd);
171 return error;
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700172}
173
Remi NGUYEN VANeabc5da2018-04-24 18:54:58 +0900174int checkSocket(int socketFd) {
175 if (socketFd < 0) {
176 return -EBADF;
177 }
178 int family;
179 socklen_t familyLen = sizeof(family);
180 if (getsockopt(socketFd, SOL_SOCKET, SO_DOMAIN, &family, &familyLen) == -1) {
181 return -errno;
182 }
183 if (!FwmarkClient::shouldSetFwmark(family)) {
184 return -EAFNOSUPPORT;
185 }
186 return 0;
187}
188
Luke Huangc5efae92018-11-19 17:45:13 +0800189int dns_open_proxy() {
190 const char* cache_mode = getenv("ANDROID_DNS_MODE");
191 const bool use_proxy = (cache_mode == NULL || strcmp(cache_mode, "local") != 0);
192 if (!use_proxy) {
193 return -1;
194 }
195
196 const auto socketFunc = libcSocket ? libcSocket : socket;
197 int s = socketFunc(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
198 if (s == -1) {
199 return -1;
200 }
201 const int one = 1;
202 setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
203
204 static const struct sockaddr_un proxy_addr = {
205 .sun_family = AF_UNIX,
206 .sun_path = "/dev/socket/dnsproxyd",
207 };
208
209 const auto connectFunc = libcConnect ? libcConnect : connect;
210 if (TEMP_FAILURE_RETRY(
211 connectFunc(s, (const struct sockaddr*) &proxy_addr, sizeof(proxy_addr))) != 0) {
212 close(s);
213 return -1;
214 }
215
216 return s;
217}
218
Luke Huangc68f1b92018-11-21 20:13:38 +0800219auto divCeil(size_t dividend, size_t divisor) {
220 return ((dividend + divisor - 1) / divisor);
221}
222
223// FrameworkListener only does only read() call, and fails if the read doesn't contain \0
224// Do single write here
225int sendData(int fd, const void* buf, size_t size) {
226 if (fd < 0) {
227 return -EBADF;
228 }
229
230 ssize_t rc = TEMP_FAILURE_RETRY(write(fd, (char*) buf, size));
231 if (rc > 0) {
232 return rc;
233 } else if (rc == 0) {
234 return -EIO;
235 } else {
236 return -errno;
237 }
238}
239
240int readData(int fd, void* buf, size_t size) {
241 if (fd < 0) {
242 return -EBADF;
243 }
244
245 size_t current = 0;
246 for (;;) {
247 ssize_t rc = TEMP_FAILURE_RETRY(read(fd, (char*) buf + current, size - current));
248 if (rc > 0) {
249 current += rc;
250 if (current == size) {
251 break;
252 }
253 } else if (rc == 0) {
254 return -EIO;
255 } else {
256 return -errno;
257 }
258 }
259 return 0;
260}
261
262bool readBE32(int fd, int32_t* result) {
263 int32_t tmp;
264 int n = TEMP_FAILURE_RETRY(read(fd, &tmp, sizeof(tmp)));
265 if (n < 0) {
266 return false;
267 }
268 *result = ntohl(tmp);
269 return true;
270}
271
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -0700272} // namespace
273
Remi NGUYEN VANeabc5da2018-04-24 18:54:58 +0900274#define CHECK_SOCKET_IS_MARKABLE(sock) \
275 do { \
276 int err; \
277 if ((err = checkSocket(sock)) != 0) { \
278 return err; \
279 } \
280 } while (false);
281
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -0700282// accept() just calls accept4(..., 0), so there's no need to handle accept() separately.
283extern "C" void netdClientInitAccept4(Accept4FunctionType* function) {
284 if (function && *function) {
285 libcAccept4 = *function;
286 *function = netdClientAccept4;
287 }
288}
289
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -0700290extern "C" void netdClientInitConnect(ConnectFunctionType* function) {
291 if (function && *function) {
292 libcConnect = *function;
293 *function = netdClientConnect;
294 }
295}
296
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -0700297extern "C" void netdClientInitSocket(SocketFunctionType* function) {
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -0700298 if (function && *function) {
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -0700299 libcSocket = *function;
300 *function = netdClientSocket;
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -0700301 }
302}
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700303
304extern "C" void netdClientInitNetIdForResolv(NetIdForResolvFunctionType* function) {
305 if (function) {
306 *function = getNetworkForResolv;
307 }
308}
309
Luke Huangc5efae92018-11-19 17:45:13 +0800310extern "C" void netdClientInitDnsOpenProxy(DnsOpenProxyType* function) {
311 if (function) {
312 *function = dns_open_proxy;
313 }
314}
315
Sreeram Ramachandran4d4c8b72014-06-20 11:59:40 -0700316extern "C" int getNetworkForSocket(unsigned* netId, int socketFd) {
317 if (!netId || socketFd < 0) {
Sreeram Ramachandran3a069e62014-06-22 11:02:57 -0700318 return -EBADF;
Sreeram Ramachandran4d4c8b72014-06-20 11:59:40 -0700319 }
320 Fwmark fwmark;
321 socklen_t fwmarkLen = sizeof(fwmark.intValue);
322 if (getsockopt(socketFd, SOL_SOCKET, SO_MARK, &fwmark.intValue, &fwmarkLen) == -1) {
Sreeram Ramachandran3a069e62014-06-22 11:02:57 -0700323 return -errno;
Sreeram Ramachandran4d4c8b72014-06-20 11:59:40 -0700324 }
325 *netId = fwmark.netId;
326 return 0;
327}
328
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700329extern "C" unsigned getNetworkForProcess() {
330 return netIdForProcess;
331}
332
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700333extern "C" int setNetworkForSocket(unsigned netId, int socketFd) {
Remi NGUYEN VANeabc5da2018-04-24 18:54:58 +0900334 CHECK_SOCKET_IS_MARKABLE(socketFd);
Chenbo Feng9944ba82017-10-10 17:33:20 -0700335 FwmarkCommand command = {FwmarkCommand::SELECT_NETWORK, netId, 0, 0};
Michal Karpinski4b9b78a2016-10-06 19:33:55 +0100336 return FwmarkClient().send(&command, socketFd, nullptr);
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700337}
338
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700339extern "C" int setNetworkForProcess(unsigned netId) {
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700340 return setNetworkForTarget(netId, &netIdForProcess);
341}
342
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700343extern "C" int setNetworkForResolv(unsigned netId) {
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700344 return setNetworkForTarget(netId, &netIdForResolv);
345}
Sreeram Ramachandrand794e582014-06-19 10:03:07 -0700346
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700347extern "C" int protectFromVpn(int socketFd) {
Sreeram Ramachandrand794e582014-06-19 10:03:07 -0700348 if (socketFd < 0) {
Sreeram Ramachandran3a069e62014-06-22 11:02:57 -0700349 return -EBADF;
Sreeram Ramachandrand794e582014-06-19 10:03:07 -0700350 }
Chenbo Feng9944ba82017-10-10 17:33:20 -0700351 FwmarkCommand command = {FwmarkCommand::PROTECT_FROM_VPN, 0, 0, 0};
Michal Karpinski4b9b78a2016-10-06 19:33:55 +0100352 return FwmarkClient().send(&command, socketFd, nullptr);
Sreeram Ramachandrana69d9472014-07-11 16:27:02 -0700353}
354
355extern "C" int setNetworkForUser(uid_t uid, int socketFd) {
Remi NGUYEN VANeabc5da2018-04-24 18:54:58 +0900356 CHECK_SOCKET_IS_MARKABLE(socketFd);
Chenbo Feng9944ba82017-10-10 17:33:20 -0700357 FwmarkCommand command = {FwmarkCommand::SELECT_FOR_USER, 0, uid, 0};
Michal Karpinski4b9b78a2016-10-06 19:33:55 +0100358 return FwmarkClient().send(&command, socketFd, nullptr);
Paul Jensend1df5972015-05-06 07:29:56 -0400359}
360
361extern "C" int queryUserAccess(uid_t uid, unsigned netId) {
Chenbo Feng9944ba82017-10-10 17:33:20 -0700362 FwmarkCommand command = {FwmarkCommand::QUERY_USER_ACCESS, netId, uid, 0};
363 return FwmarkClient().send(&command, -1, nullptr);
364}
365
366extern "C" int tagSocket(int socketFd, uint32_t tag, uid_t uid) {
Remi NGUYEN VANeabc5da2018-04-24 18:54:58 +0900367 CHECK_SOCKET_IS_MARKABLE(socketFd);
Chenbo Feng9944ba82017-10-10 17:33:20 -0700368 FwmarkCommand command = {FwmarkCommand::TAG_SOCKET, 0, uid, tag};
369 return FwmarkClient().send(&command, socketFd, nullptr);
370}
371
372extern "C" int untagSocket(int socketFd) {
Remi NGUYEN VANeabc5da2018-04-24 18:54:58 +0900373 CHECK_SOCKET_IS_MARKABLE(socketFd);
Chenbo Feng9944ba82017-10-10 17:33:20 -0700374 FwmarkCommand command = {FwmarkCommand::UNTAG_SOCKET, 0, 0, 0};
375 return FwmarkClient().send(&command, socketFd, nullptr);
376}
377
378extern "C" int setCounterSet(uint32_t counterSet, uid_t uid) {
379 FwmarkCommand command = {FwmarkCommand::SET_COUNTERSET, 0, uid, counterSet};
380 return FwmarkClient().send(&command, -1, nullptr);
381}
382
383extern "C" int deleteTagData(uint32_t tag, uid_t uid) {
384 FwmarkCommand command = {FwmarkCommand::DELETE_TAGDATA, 0, uid, tag};
Michal Karpinski4b9b78a2016-10-06 19:33:55 +0100385 return FwmarkClient().send(&command, -1, nullptr);
Sreeram Ramachandrand794e582014-06-19 10:03:07 -0700386}
Luke Huangc68f1b92018-11-21 20:13:38 +0800387
Luke Huang110c54e2018-12-20 14:39:58 +0800388extern "C" int resNetworkQuery(unsigned netId, const char* dname, int ns_class, int ns_type,
389 uint32_t flags) {
Luke Huange48fbcb2018-12-17 16:37:33 +0800390 std::vector<uint8_t> buf(MAX_CMD_SIZE, 0);
391 int len = res_mkquery(ns_o_query, dname, ns_class, ns_type, nullptr, 0, nullptr, buf.data(),
392 MAX_CMD_SIZE);
Luke Huangc68f1b92018-11-21 20:13:38 +0800393
Luke Huang110c54e2018-12-20 14:39:58 +0800394 return resNetworkSend(netId, buf.data(), len, flags);
Luke Huangc68f1b92018-11-21 20:13:38 +0800395}
396
Luke Huang110c54e2018-12-20 14:39:58 +0800397extern "C" int resNetworkSend(unsigned netId, const uint8_t* msg, size_t msglen, uint32_t) {
Luke Huangc68f1b92018-11-21 20:13:38 +0800398 // Encode
399 // Base 64 encodes every 3 bytes into 4 characters, but then adds padding to the next
400 // multiple of 4 and a \0
401 const size_t encodedLen = divCeil(msglen, 3) * 4 + 1;
Luke Huange48fbcb2018-12-17 16:37:33 +0800402 std::string encodedQuery(encodedLen - 1, 0);
Luke Huangc68f1b92018-11-21 20:13:38 +0800403 int enLen = b64_ntop(msg, msglen, encodedQuery.data(), encodedLen);
404
405 if (enLen < 0) {
406 // Unexpected behavior, encode failed
407 // b64_ntop only fails when size is too long.
408 return -EMSGSIZE;
409 }
410 // Send
411 netId = getNetworkForResolv(netId);
412 const std::string cmd = "resnsend " + encodedQuery + " " + std::to_string(netId) + '\0';
413 if (cmd.size() > MAX_CMD_SIZE) {
414 // Cmd size must less than buffer size of FrameworkListener
415 return -EMSGSIZE;
416 }
417 int fd = dns_open_proxy();
418 if (fd == -1) {
419 return -errno;
420 }
421 ssize_t rc = sendData(fd, cmd.c_str(), cmd.size());
422 if (rc < 0) {
423 close(fd);
424 return rc;
425 }
426 shutdown(fd, SHUT_WR);
427 return fd;
428}
429
Luke Huange48fbcb2018-12-17 16:37:33 +0800430extern "C" int resNetworkResult(int fd, int* rcode, uint8_t* answer, size_t anslen) {
Luke Huangc68f1b92018-11-21 20:13:38 +0800431 int32_t result = 0;
432 unique_fd ufd(fd);
433 // Read -errno/rcode
434 if (!readBE32(fd, &result)) {
435 // Unexpected behavior, read -errno/rcode fail
436 return -errno;
437 }
438 if (result < 0) {
439 // result < 0, it's -errno
440 return result;
441 }
442 // result >= 0, it's rcode
443 *rcode = result;
444
445 // Read answer
446 int32_t size = 0;
447 if (!readBE32(fd, &size)) {
448 // Unexpected behavior, read ans len fail
449 return -EREMOTEIO;
450 }
Luke Huange48fbcb2018-12-17 16:37:33 +0800451 if (anslen < static_cast<size_t>(size)) {
Luke Huangc68f1b92018-11-21 20:13:38 +0800452 // Answer buffer is too small
453 return -EMSGSIZE;
454 }
455 int rc = readData(fd, answer, size);
456 if (rc < 0) {
457 // Reading the answer failed.
458 return rc;
459 }
460 return size;
461}
462
463extern "C" void resNetworkCancel(int fd) {
464 close(fd);
465}