blob: 3fd985e5ec8df044f1a3a74dae8e39768773fd4f [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>
Dan Albertaa1be2b2015-01-06 09:36:17 -080022#include <sys/socket.h>
23#include <unistd.h>
24
25#include <atomic>
26
Sreeram Ramachandran4d4c8b72014-06-20 11:59:40 -070027#include "Fwmark.h"
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -070028#include "FwmarkClient.h"
29#include "FwmarkCommand.h"
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -070030#include "resolv_netid.h"
Robin Leecc544162016-09-21 16:31:33 +090031#include "Stopwatch.h"
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -070032
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -070033namespace {
34
Sreeram Ramachandran9fa2b132014-06-03 12:51:08 -070035std::atomic_uint netIdForProcess(NETID_UNSET);
36std::atomic_uint netIdForResolv(NETID_UNSET);
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -070037
38typedef int (*Accept4FunctionType)(int, sockaddr*, socklen_t*, int);
39typedef int (*ConnectFunctionType)(int, const sockaddr*, socklen_t);
40typedef int (*SocketFunctionType)(int, int, int);
41typedef unsigned (*NetIdForResolvFunctionType)(unsigned);
42
43// These variables are only modified at startup (when libc.so is loaded) and never afterwards, so
44// it's okay that they are read later at runtime without a lock.
Yi Kongbdfd57e2018-07-25 13:26:10 -070045Accept4FunctionType libcAccept4 = nullptr;
46ConnectFunctionType libcConnect = nullptr;
47SocketFunctionType libcSocket = nullptr;
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -070048
Sreeram Ramachandran31f42102014-06-20 11:51:48 -070049int closeFdAndSetErrno(int fd, int error) {
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -070050 close(fd);
Sreeram Ramachandran3a069e62014-06-22 11:02:57 -070051 errno = -error;
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -070052 return -1;
53}
54
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -070055int netdClientAccept4(int sockfd, sockaddr* addr, socklen_t* addrlen, int flags) {
56 int acceptedSocket = libcAccept4(sockfd, addr, addrlen, flags);
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -070057 if (acceptedSocket == -1) {
58 return -1;
59 }
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -070060 int family;
61 if (addr) {
62 family = addr->sa_family;
63 } else {
64 socklen_t familyLen = sizeof(family);
65 if (getsockopt(acceptedSocket, SOL_SOCKET, SO_DOMAIN, &family, &familyLen) == -1) {
Sreeram Ramachandran3a069e62014-06-22 11:02:57 -070066 return closeFdAndSetErrno(acceptedSocket, -errno);
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -070067 }
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -070068 }
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -070069 if (FwmarkClient::shouldSetFwmark(family)) {
Chenbo Feng9944ba82017-10-10 17:33:20 -070070 FwmarkCommand command = {FwmarkCommand::ON_ACCEPT, 0, 0, 0};
Michal Karpinski4b9b78a2016-10-06 19:33:55 +010071 if (int error = FwmarkClient().send(&command, acceptedSocket, nullptr)) {
Sreeram Ramachandran31f42102014-06-20 11:51:48 -070072 return closeFdAndSetErrno(acceptedSocket, error);
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -070073 }
74 }
75 return acceptedSocket;
76}
77
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -070078int netdClientConnect(int sockfd, const sockaddr* addr, socklen_t addrlen) {
Michal Karpinski4b9b78a2016-10-06 19:33:55 +010079 const bool shouldSetFwmark = (sockfd >= 0) && addr
80 && FwmarkClient::shouldSetFwmark(addr->sa_family);
81 if (shouldSetFwmark) {
Chenbo Feng9944ba82017-10-10 17:33:20 -070082 FwmarkCommand command = {FwmarkCommand::ON_CONNECT, 0, 0, 0};
Michal Karpinski4b9b78a2016-10-06 19:33:55 +010083 if (int error = FwmarkClient().send(&command, sockfd, nullptr)) {
Sreeram Ramachandran3a069e62014-06-22 11:02:57 -070084 errno = -error;
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -070085 return -1;
86 }
87 }
Michal Karpinski4b9b78a2016-10-06 19:33:55 +010088 // Latency measurement does not include time of sending commands to Fwmark
89 Stopwatch s;
Hugo Benichi794c5c72016-10-31 15:07:23 +090090 const int ret = libcConnect(sockfd, addr, addrlen);
Michal Karpinski4b9b78a2016-10-06 19:33:55 +010091 // Save errno so it isn't clobbered by sending ON_CONNECT_COMPLETE
92 const int connectErrno = errno;
93 const unsigned latencyMs = lround(s.timeTaken());
94 // Send an ON_CONNECT_COMPLETE command that includes sockaddr and connect latency for reporting
95 if (shouldSetFwmark && FwmarkClient::shouldReportConnectComplete(addr->sa_family)) {
Hugo Benichi794c5c72016-10-31 15:07:23 +090096 FwmarkConnectInfo connectInfo(ret == 0 ? 0 : connectErrno, latencyMs, addr);
Michal Karpinski4b9b78a2016-10-06 19:33:55 +010097 // TODO: get the netId from the socket mark once we have continuous benchmark runs
98 FwmarkCommand command = {FwmarkCommand::ON_CONNECT_COMPLETE, /* netId (ignored) */ 0,
Chenbo Feng9944ba82017-10-10 17:33:20 -070099 /* uid (filled in by the server) */ 0, 0};
Michal Karpinski4b9b78a2016-10-06 19:33:55 +0100100 // Ignore return value since it's only used for logging
101 FwmarkClient().send(&command, sockfd, &connectInfo);
102 }
103 errno = connectErrno;
104 return ret;
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -0700105}
106
107int netdClientSocket(int domain, int type, int protocol) {
108 int socketFd = libcSocket(domain, type, protocol);
109 if (socketFd == -1) {
110 return -1;
111 }
112 unsigned netId = netIdForProcess;
113 if (netId != NETID_UNSET && FwmarkClient::shouldSetFwmark(domain)) {
Sreeram Ramachandrand36c49c2014-07-02 14:49:33 -0700114 if (int error = setNetworkForSocket(netId, socketFd)) {
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700115 return closeFdAndSetErrno(socketFd, error);
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -0700116 }
117 }
118 return socketFd;
119}
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700120
121unsigned getNetworkForResolv(unsigned netId) {
122 if (netId != NETID_UNSET) {
123 return netId;
124 }
Erik Kline1564d482018-03-07 17:09:35 +0900125 // Special case for DNS-over-TLS bypass; b/72345192 .
126 if ((netIdForResolv & ~NETID_USE_LOCAL_NAMESERVERS) != NETID_UNSET) {
127 return netIdForResolv;
128 }
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700129 netId = netIdForProcess;
130 if (netId != NETID_UNSET) {
131 return netId;
132 }
133 return netIdForResolv;
134}
135
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700136int setNetworkForTarget(unsigned netId, std::atomic_uint* target) {
Erik Kline1564d482018-03-07 17:09:35 +0900137 const unsigned requestedNetId = netId;
138 netId &= ~NETID_USE_LOCAL_NAMESERVERS;
139
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700140 if (netId == NETID_UNSET) {
141 *target = netId;
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700142 return 0;
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700143 }
144 // 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 -0700145 // with the netId. Call libcSocket() directly; else the socket creation (via netdClientSocket())
146 // might itself cause another check with the fwmark server, which would be wasteful.
147 int socketFd;
148 if (libcSocket) {
Nick Kralevich53ea9ca2015-01-31 13:54:00 -0800149 socketFd = libcSocket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0);
Sreeram Ramachandran27560452014-05-30 19:59:51 -0700150 } else {
Nick Kralevich53ea9ca2015-01-31 13:54:00 -0800151 socketFd = socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0);
Sreeram Ramachandran27560452014-05-30 19:59:51 -0700152 }
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
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -0700179} // namespace
180
Remi NGUYEN VANeabc5da2018-04-24 18:54:58 +0900181#define CHECK_SOCKET_IS_MARKABLE(sock) \
182 do { \
183 int err; \
184 if ((err = checkSocket(sock)) != 0) { \
185 return err; \
186 } \
187 } while (false);
188
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -0700189// accept() just calls accept4(..., 0), so there's no need to handle accept() separately.
190extern "C" void netdClientInitAccept4(Accept4FunctionType* function) {
191 if (function && *function) {
192 libcAccept4 = *function;
193 *function = netdClientAccept4;
194 }
195}
196
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -0700197extern "C" void netdClientInitConnect(ConnectFunctionType* function) {
198 if (function && *function) {
199 libcConnect = *function;
200 *function = netdClientConnect;
201 }
202}
203
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -0700204extern "C" void netdClientInitSocket(SocketFunctionType* function) {
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -0700205 if (function && *function) {
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -0700206 libcSocket = *function;
207 *function = netdClientSocket;
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -0700208 }
209}
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700210
211extern "C" void netdClientInitNetIdForResolv(NetIdForResolvFunctionType* function) {
212 if (function) {
213 *function = getNetworkForResolv;
214 }
215}
216
Sreeram Ramachandran4d4c8b72014-06-20 11:59:40 -0700217extern "C" int getNetworkForSocket(unsigned* netId, int socketFd) {
218 if (!netId || socketFd < 0) {
Sreeram Ramachandran3a069e62014-06-22 11:02:57 -0700219 return -EBADF;
Sreeram Ramachandran4d4c8b72014-06-20 11:59:40 -0700220 }
221 Fwmark fwmark;
222 socklen_t fwmarkLen = sizeof(fwmark.intValue);
223 if (getsockopt(socketFd, SOL_SOCKET, SO_MARK, &fwmark.intValue, &fwmarkLen) == -1) {
Sreeram Ramachandran3a069e62014-06-22 11:02:57 -0700224 return -errno;
Sreeram Ramachandran4d4c8b72014-06-20 11:59:40 -0700225 }
226 *netId = fwmark.netId;
227 return 0;
228}
229
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700230extern "C" unsigned getNetworkForProcess() {
231 return netIdForProcess;
232}
233
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700234extern "C" int setNetworkForSocket(unsigned netId, int socketFd) {
Remi NGUYEN VANeabc5da2018-04-24 18:54:58 +0900235 CHECK_SOCKET_IS_MARKABLE(socketFd);
Chenbo Feng9944ba82017-10-10 17:33:20 -0700236 FwmarkCommand command = {FwmarkCommand::SELECT_NETWORK, netId, 0, 0};
Michal Karpinski4b9b78a2016-10-06 19:33:55 +0100237 return FwmarkClient().send(&command, socketFd, nullptr);
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700238}
239
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700240extern "C" int setNetworkForProcess(unsigned netId) {
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700241 return setNetworkForTarget(netId, &netIdForProcess);
242}
243
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700244extern "C" int setNetworkForResolv(unsigned netId) {
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700245 return setNetworkForTarget(netId, &netIdForResolv);
246}
Sreeram Ramachandrand794e582014-06-19 10:03:07 -0700247
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700248extern "C" int protectFromVpn(int socketFd) {
Sreeram Ramachandrand794e582014-06-19 10:03:07 -0700249 if (socketFd < 0) {
Sreeram Ramachandran3a069e62014-06-22 11:02:57 -0700250 return -EBADF;
Sreeram Ramachandrand794e582014-06-19 10:03:07 -0700251 }
Chenbo Feng9944ba82017-10-10 17:33:20 -0700252 FwmarkCommand command = {FwmarkCommand::PROTECT_FROM_VPN, 0, 0, 0};
Michal Karpinski4b9b78a2016-10-06 19:33:55 +0100253 return FwmarkClient().send(&command, socketFd, nullptr);
Sreeram Ramachandrana69d9472014-07-11 16:27:02 -0700254}
255
256extern "C" int setNetworkForUser(uid_t uid, int socketFd) {
Remi NGUYEN VANeabc5da2018-04-24 18:54:58 +0900257 CHECK_SOCKET_IS_MARKABLE(socketFd);
Chenbo Feng9944ba82017-10-10 17:33:20 -0700258 FwmarkCommand command = {FwmarkCommand::SELECT_FOR_USER, 0, uid, 0};
Michal Karpinski4b9b78a2016-10-06 19:33:55 +0100259 return FwmarkClient().send(&command, socketFd, nullptr);
Paul Jensend1df5972015-05-06 07:29:56 -0400260}
261
262extern "C" int queryUserAccess(uid_t uid, unsigned netId) {
Chenbo Feng9944ba82017-10-10 17:33:20 -0700263 FwmarkCommand command = {FwmarkCommand::QUERY_USER_ACCESS, netId, uid, 0};
264 return FwmarkClient().send(&command, -1, nullptr);
265}
266
267extern "C" int tagSocket(int socketFd, uint32_t tag, uid_t uid) {
Remi NGUYEN VANeabc5da2018-04-24 18:54:58 +0900268 CHECK_SOCKET_IS_MARKABLE(socketFd);
Chenbo Feng9944ba82017-10-10 17:33:20 -0700269 FwmarkCommand command = {FwmarkCommand::TAG_SOCKET, 0, uid, tag};
270 return FwmarkClient().send(&command, socketFd, nullptr);
271}
272
273extern "C" int untagSocket(int socketFd) {
Remi NGUYEN VANeabc5da2018-04-24 18:54:58 +0900274 CHECK_SOCKET_IS_MARKABLE(socketFd);
Chenbo Feng9944ba82017-10-10 17:33:20 -0700275 FwmarkCommand command = {FwmarkCommand::UNTAG_SOCKET, 0, 0, 0};
276 return FwmarkClient().send(&command, socketFd, nullptr);
277}
278
279extern "C" int setCounterSet(uint32_t counterSet, uid_t uid) {
280 FwmarkCommand command = {FwmarkCommand::SET_COUNTERSET, 0, uid, counterSet};
281 return FwmarkClient().send(&command, -1, nullptr);
282}
283
284extern "C" int deleteTagData(uint32_t tag, uid_t uid) {
285 FwmarkCommand command = {FwmarkCommand::DELETE_TAGDATA, 0, uid, tag};
Michal Karpinski4b9b78a2016-10-06 19:33:55 +0100286 return FwmarkClient().send(&command, -1, nullptr);
Sreeram Ramachandrand794e582014-06-19 10:03:07 -0700287}