blob: 44978779b12c415a1a6942e46f1d8fa31e337d9b [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 Huangc5efae92018-11-19 17:45:13 +080022#include <stdlib.h>
Dan Albertaa1be2b2015-01-06 09:36:17 -080023#include <sys/socket.h>
Luke Huangc5efae92018-11-19 17:45:13 +080024#include <sys/un.h>
Dan Albertaa1be2b2015-01-06 09:36:17 -080025#include <unistd.h>
26
27#include <atomic>
28
Sreeram Ramachandran4d4c8b72014-06-20 11:59:40 -070029#include "Fwmark.h"
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -070030#include "FwmarkClient.h"
31#include "FwmarkCommand.h"
Robin Leecc544162016-09-21 16:31:33 +090032#include "Stopwatch.h"
Bernie Innocenti189eb502018-10-01 23:10:18 +090033#include "netid_client.h"
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -070034
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -070035namespace {
36
Sreeram Ramachandran9fa2b132014-06-03 12:51:08 -070037std::atomic_uint netIdForProcess(NETID_UNSET);
38std::atomic_uint netIdForResolv(NETID_UNSET);
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -070039
40typedef int (*Accept4FunctionType)(int, sockaddr*, socklen_t*, int);
41typedef int (*ConnectFunctionType)(int, const sockaddr*, socklen_t);
42typedef int (*SocketFunctionType)(int, int, int);
43typedef unsigned (*NetIdForResolvFunctionType)(unsigned);
Luke Huangc5efae92018-11-19 17:45:13 +080044typedef int (*DnsOpenProxyType)();
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -070045
46// These variables are only modified at startup (when libc.so is loaded) and never afterwards, so
47// it's okay that they are read later at runtime without a lock.
Yi Kongbdfd57e2018-07-25 13:26:10 -070048Accept4FunctionType libcAccept4 = nullptr;
49ConnectFunctionType libcConnect = nullptr;
50SocketFunctionType libcSocket = nullptr;
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -070051
Sreeram Ramachandran31f42102014-06-20 11:51:48 -070052int closeFdAndSetErrno(int fd, int error) {
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -070053 close(fd);
Sreeram Ramachandran3a069e62014-06-22 11:02:57 -070054 errno = -error;
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -070055 return -1;
56}
57
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -070058int netdClientAccept4(int sockfd, sockaddr* addr, socklen_t* addrlen, int flags) {
59 int acceptedSocket = libcAccept4(sockfd, addr, addrlen, flags);
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -070060 if (acceptedSocket == -1) {
61 return -1;
62 }
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -070063 int family;
64 if (addr) {
65 family = addr->sa_family;
66 } else {
67 socklen_t familyLen = sizeof(family);
68 if (getsockopt(acceptedSocket, SOL_SOCKET, SO_DOMAIN, &family, &familyLen) == -1) {
Sreeram Ramachandran3a069e62014-06-22 11:02:57 -070069 return closeFdAndSetErrno(acceptedSocket, -errno);
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -070070 }
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -070071 }
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -070072 if (FwmarkClient::shouldSetFwmark(family)) {
Chenbo Feng9944ba82017-10-10 17:33:20 -070073 FwmarkCommand command = {FwmarkCommand::ON_ACCEPT, 0, 0, 0};
Michal Karpinski4b9b78a2016-10-06 19:33:55 +010074 if (int error = FwmarkClient().send(&command, acceptedSocket, nullptr)) {
Sreeram Ramachandran31f42102014-06-20 11:51:48 -070075 return closeFdAndSetErrno(acceptedSocket, error);
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -070076 }
77 }
78 return acceptedSocket;
79}
80
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -070081int netdClientConnect(int sockfd, const sockaddr* addr, socklen_t addrlen) {
Michal Karpinski4b9b78a2016-10-06 19:33:55 +010082 const bool shouldSetFwmark = (sockfd >= 0) && addr
83 && FwmarkClient::shouldSetFwmark(addr->sa_family);
84 if (shouldSetFwmark) {
Chenbo Feng9944ba82017-10-10 17:33:20 -070085 FwmarkCommand command = {FwmarkCommand::ON_CONNECT, 0, 0, 0};
Michal Karpinski4b9b78a2016-10-06 19:33:55 +010086 if (int error = FwmarkClient().send(&command, sockfd, nullptr)) {
Sreeram Ramachandran3a069e62014-06-22 11:02:57 -070087 errno = -error;
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -070088 return -1;
89 }
90 }
Michal Karpinski4b9b78a2016-10-06 19:33:55 +010091 // Latency measurement does not include time of sending commands to Fwmark
92 Stopwatch s;
Hugo Benichi794c5c72016-10-31 15:07:23 +090093 const int ret = libcConnect(sockfd, addr, addrlen);
Michal Karpinski4b9b78a2016-10-06 19:33:55 +010094 // Save errno so it isn't clobbered by sending ON_CONNECT_COMPLETE
95 const int connectErrno = errno;
96 const unsigned latencyMs = lround(s.timeTaken());
97 // Send an ON_CONNECT_COMPLETE command that includes sockaddr and connect latency for reporting
98 if (shouldSetFwmark && FwmarkClient::shouldReportConnectComplete(addr->sa_family)) {
Hugo Benichi794c5c72016-10-31 15:07:23 +090099 FwmarkConnectInfo connectInfo(ret == 0 ? 0 : connectErrno, latencyMs, addr);
Michal Karpinski4b9b78a2016-10-06 19:33:55 +0100100 // TODO: get the netId from the socket mark once we have continuous benchmark runs
101 FwmarkCommand command = {FwmarkCommand::ON_CONNECT_COMPLETE, /* netId (ignored) */ 0,
Chenbo Feng9944ba82017-10-10 17:33:20 -0700102 /* uid (filled in by the server) */ 0, 0};
Michal Karpinski4b9b78a2016-10-06 19:33:55 +0100103 // Ignore return value since it's only used for logging
104 FwmarkClient().send(&command, sockfd, &connectInfo);
105 }
106 errno = connectErrno;
107 return ret;
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -0700108}
109
110int netdClientSocket(int domain, int type, int protocol) {
111 int socketFd = libcSocket(domain, type, protocol);
112 if (socketFd == -1) {
113 return -1;
114 }
115 unsigned netId = netIdForProcess;
116 if (netId != NETID_UNSET && FwmarkClient::shouldSetFwmark(domain)) {
Sreeram Ramachandrand36c49c2014-07-02 14:49:33 -0700117 if (int error = setNetworkForSocket(netId, socketFd)) {
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700118 return closeFdAndSetErrno(socketFd, error);
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -0700119 }
120 }
121 return socketFd;
122}
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700123
124unsigned getNetworkForResolv(unsigned netId) {
125 if (netId != NETID_UNSET) {
126 return netId;
127 }
Erik Kline1564d482018-03-07 17:09:35 +0900128 // Special case for DNS-over-TLS bypass; b/72345192 .
129 if ((netIdForResolv & ~NETID_USE_LOCAL_NAMESERVERS) != NETID_UNSET) {
130 return netIdForResolv;
131 }
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700132 netId = netIdForProcess;
133 if (netId != NETID_UNSET) {
134 return netId;
135 }
136 return netIdForResolv;
137}
138
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700139int setNetworkForTarget(unsigned netId, std::atomic_uint* target) {
Erik Kline1564d482018-03-07 17:09:35 +0900140 const unsigned requestedNetId = netId;
141 netId &= ~NETID_USE_LOCAL_NAMESERVERS;
142
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700143 if (netId == NETID_UNSET) {
144 *target = netId;
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700145 return 0;
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700146 }
147 // 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 -0700148 // with the netId. Call libcSocket() directly; else the socket creation (via netdClientSocket())
149 // might itself cause another check with the fwmark server, which would be wasteful.
Luke Huangc5efae92018-11-19 17:45:13 +0800150
151 const auto socketFunc = libcSocket ? libcSocket : socket;
152 int socketFd = socketFunc(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0);
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700153 if (socketFd < 0) {
Sreeram Ramachandran3a069e62014-06-22 11:02:57 -0700154 return -errno;
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700155 }
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700156 int error = setNetworkForSocket(netId, socketFd);
157 if (!error) {
Erik Kline1564d482018-03-07 17:09:35 +0900158 *target = (target == &netIdForResolv) ? requestedNetId : netId;
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700159 }
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700160 close(socketFd);
161 return error;
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700162}
163
Remi NGUYEN VANeabc5da2018-04-24 18:54:58 +0900164int checkSocket(int socketFd) {
165 if (socketFd < 0) {
166 return -EBADF;
167 }
168 int family;
169 socklen_t familyLen = sizeof(family);
170 if (getsockopt(socketFd, SOL_SOCKET, SO_DOMAIN, &family, &familyLen) == -1) {
171 return -errno;
172 }
173 if (!FwmarkClient::shouldSetFwmark(family)) {
174 return -EAFNOSUPPORT;
175 }
176 return 0;
177}
178
Luke Huangc5efae92018-11-19 17:45:13 +0800179int dns_open_proxy() {
180 const char* cache_mode = getenv("ANDROID_DNS_MODE");
181 const bool use_proxy = (cache_mode == NULL || strcmp(cache_mode, "local") != 0);
182 if (!use_proxy) {
183 return -1;
184 }
185
186 const auto socketFunc = libcSocket ? libcSocket : socket;
187 int s = socketFunc(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
188 if (s == -1) {
189 return -1;
190 }
191 const int one = 1;
192 setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
193
194 static const struct sockaddr_un proxy_addr = {
195 .sun_family = AF_UNIX,
196 .sun_path = "/dev/socket/dnsproxyd",
197 };
198
199 const auto connectFunc = libcConnect ? libcConnect : connect;
200 if (TEMP_FAILURE_RETRY(
201 connectFunc(s, (const struct sockaddr*) &proxy_addr, sizeof(proxy_addr))) != 0) {
202 close(s);
203 return -1;
204 }
205
206 return s;
207}
208
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -0700209} // namespace
210
Remi NGUYEN VANeabc5da2018-04-24 18:54:58 +0900211#define CHECK_SOCKET_IS_MARKABLE(sock) \
212 do { \
213 int err; \
214 if ((err = checkSocket(sock)) != 0) { \
215 return err; \
216 } \
217 } while (false);
218
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -0700219// accept() just calls accept4(..., 0), so there's no need to handle accept() separately.
220extern "C" void netdClientInitAccept4(Accept4FunctionType* function) {
221 if (function && *function) {
222 libcAccept4 = *function;
223 *function = netdClientAccept4;
224 }
225}
226
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -0700227extern "C" void netdClientInitConnect(ConnectFunctionType* function) {
228 if (function && *function) {
229 libcConnect = *function;
230 *function = netdClientConnect;
231 }
232}
233
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -0700234extern "C" void netdClientInitSocket(SocketFunctionType* function) {
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -0700235 if (function && *function) {
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -0700236 libcSocket = *function;
237 *function = netdClientSocket;
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -0700238 }
239}
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700240
241extern "C" void netdClientInitNetIdForResolv(NetIdForResolvFunctionType* function) {
242 if (function) {
243 *function = getNetworkForResolv;
244 }
245}
246
Luke Huangc5efae92018-11-19 17:45:13 +0800247extern "C" void netdClientInitDnsOpenProxy(DnsOpenProxyType* function) {
248 if (function) {
249 *function = dns_open_proxy;
250 }
251}
252
Sreeram Ramachandran4d4c8b72014-06-20 11:59:40 -0700253extern "C" int getNetworkForSocket(unsigned* netId, int socketFd) {
254 if (!netId || socketFd < 0) {
Sreeram Ramachandran3a069e62014-06-22 11:02:57 -0700255 return -EBADF;
Sreeram Ramachandran4d4c8b72014-06-20 11:59:40 -0700256 }
257 Fwmark fwmark;
258 socklen_t fwmarkLen = sizeof(fwmark.intValue);
259 if (getsockopt(socketFd, SOL_SOCKET, SO_MARK, &fwmark.intValue, &fwmarkLen) == -1) {
Sreeram Ramachandran3a069e62014-06-22 11:02:57 -0700260 return -errno;
Sreeram Ramachandran4d4c8b72014-06-20 11:59:40 -0700261 }
262 *netId = fwmark.netId;
263 return 0;
264}
265
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700266extern "C" unsigned getNetworkForProcess() {
267 return netIdForProcess;
268}
269
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700270extern "C" int setNetworkForSocket(unsigned netId, int socketFd) {
Remi NGUYEN VANeabc5da2018-04-24 18:54:58 +0900271 CHECK_SOCKET_IS_MARKABLE(socketFd);
Chenbo Feng9944ba82017-10-10 17:33:20 -0700272 FwmarkCommand command = {FwmarkCommand::SELECT_NETWORK, netId, 0, 0};
Michal Karpinski4b9b78a2016-10-06 19:33:55 +0100273 return FwmarkClient().send(&command, socketFd, nullptr);
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700274}
275
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700276extern "C" int setNetworkForProcess(unsigned netId) {
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700277 return setNetworkForTarget(netId, &netIdForProcess);
278}
279
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700280extern "C" int setNetworkForResolv(unsigned netId) {
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700281 return setNetworkForTarget(netId, &netIdForResolv);
282}
Sreeram Ramachandrand794e582014-06-19 10:03:07 -0700283
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700284extern "C" int protectFromVpn(int socketFd) {
Sreeram Ramachandrand794e582014-06-19 10:03:07 -0700285 if (socketFd < 0) {
Sreeram Ramachandran3a069e62014-06-22 11:02:57 -0700286 return -EBADF;
Sreeram Ramachandrand794e582014-06-19 10:03:07 -0700287 }
Chenbo Feng9944ba82017-10-10 17:33:20 -0700288 FwmarkCommand command = {FwmarkCommand::PROTECT_FROM_VPN, 0, 0, 0};
Michal Karpinski4b9b78a2016-10-06 19:33:55 +0100289 return FwmarkClient().send(&command, socketFd, nullptr);
Sreeram Ramachandrana69d9472014-07-11 16:27:02 -0700290}
291
292extern "C" int setNetworkForUser(uid_t uid, int socketFd) {
Remi NGUYEN VANeabc5da2018-04-24 18:54:58 +0900293 CHECK_SOCKET_IS_MARKABLE(socketFd);
Chenbo Feng9944ba82017-10-10 17:33:20 -0700294 FwmarkCommand command = {FwmarkCommand::SELECT_FOR_USER, 0, uid, 0};
Michal Karpinski4b9b78a2016-10-06 19:33:55 +0100295 return FwmarkClient().send(&command, socketFd, nullptr);
Paul Jensend1df5972015-05-06 07:29:56 -0400296}
297
298extern "C" int queryUserAccess(uid_t uid, unsigned netId) {
Chenbo Feng9944ba82017-10-10 17:33:20 -0700299 FwmarkCommand command = {FwmarkCommand::QUERY_USER_ACCESS, netId, uid, 0};
300 return FwmarkClient().send(&command, -1, nullptr);
301}
302
303extern "C" int tagSocket(int socketFd, uint32_t tag, uid_t uid) {
Remi NGUYEN VANeabc5da2018-04-24 18:54:58 +0900304 CHECK_SOCKET_IS_MARKABLE(socketFd);
Chenbo Feng9944ba82017-10-10 17:33:20 -0700305 FwmarkCommand command = {FwmarkCommand::TAG_SOCKET, 0, uid, tag};
306 return FwmarkClient().send(&command, socketFd, nullptr);
307}
308
309extern "C" int untagSocket(int socketFd) {
Remi NGUYEN VANeabc5da2018-04-24 18:54:58 +0900310 CHECK_SOCKET_IS_MARKABLE(socketFd);
Chenbo Feng9944ba82017-10-10 17:33:20 -0700311 FwmarkCommand command = {FwmarkCommand::UNTAG_SOCKET, 0, 0, 0};
312 return FwmarkClient().send(&command, socketFd, nullptr);
313}
314
315extern "C" int setCounterSet(uint32_t counterSet, uid_t uid) {
316 FwmarkCommand command = {FwmarkCommand::SET_COUNTERSET, 0, uid, counterSet};
317 return FwmarkClient().send(&command, -1, nullptr);
318}
319
320extern "C" int deleteTagData(uint32_t tag, uid_t uid) {
321 FwmarkCommand command = {FwmarkCommand::DELETE_TAGDATA, 0, uid, tag};
Michal Karpinski4b9b78a2016-10-06 19:33:55 +0100322 return FwmarkClient().send(&command, -1, nullptr);
Sreeram Ramachandrand794e582014-06-19 10:03:07 -0700323}