blob: fbbc9e75315a93c456cf9337c8113c5bc8f39a63 [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.
45Accept4FunctionType libcAccept4 = 0;
46ConnectFunctionType libcConnect = 0;
47SocketFunctionType libcSocket = 0;
48
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
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -0700164} // namespace
165
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -0700166// accept() just calls accept4(..., 0), so there's no need to handle accept() separately.
167extern "C" void netdClientInitAccept4(Accept4FunctionType* function) {
168 if (function && *function) {
169 libcAccept4 = *function;
170 *function = netdClientAccept4;
171 }
172}
173
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -0700174extern "C" void netdClientInitConnect(ConnectFunctionType* function) {
175 if (function && *function) {
176 libcConnect = *function;
177 *function = netdClientConnect;
178 }
179}
180
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -0700181extern "C" void netdClientInitSocket(SocketFunctionType* function) {
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -0700182 if (function && *function) {
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -0700183 libcSocket = *function;
184 *function = netdClientSocket;
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -0700185 }
186}
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700187
188extern "C" void netdClientInitNetIdForResolv(NetIdForResolvFunctionType* function) {
189 if (function) {
190 *function = getNetworkForResolv;
191 }
192}
193
Sreeram Ramachandran4d4c8b72014-06-20 11:59:40 -0700194extern "C" int getNetworkForSocket(unsigned* netId, int socketFd) {
195 if (!netId || socketFd < 0) {
Sreeram Ramachandran3a069e62014-06-22 11:02:57 -0700196 return -EBADF;
Sreeram Ramachandran4d4c8b72014-06-20 11:59:40 -0700197 }
198 Fwmark fwmark;
199 socklen_t fwmarkLen = sizeof(fwmark.intValue);
200 if (getsockopt(socketFd, SOL_SOCKET, SO_MARK, &fwmark.intValue, &fwmarkLen) == -1) {
Sreeram Ramachandran3a069e62014-06-22 11:02:57 -0700201 return -errno;
Sreeram Ramachandran4d4c8b72014-06-20 11:59:40 -0700202 }
203 *netId = fwmark.netId;
204 return 0;
205}
206
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700207extern "C" unsigned getNetworkForProcess() {
208 return netIdForProcess;
209}
210
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700211extern "C" int setNetworkForSocket(unsigned netId, int socketFd) {
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700212 if (socketFd < 0) {
Sreeram Ramachandran3a069e62014-06-22 11:02:57 -0700213 return -EBADF;
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700214 }
Chenbo Feng9944ba82017-10-10 17:33:20 -0700215 FwmarkCommand command = {FwmarkCommand::SELECT_NETWORK, netId, 0, 0};
Michal Karpinski4b9b78a2016-10-06 19:33:55 +0100216 return FwmarkClient().send(&command, socketFd, nullptr);
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700217}
218
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700219extern "C" int setNetworkForProcess(unsigned netId) {
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700220 return setNetworkForTarget(netId, &netIdForProcess);
221}
222
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700223extern "C" int setNetworkForResolv(unsigned netId) {
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700224 return setNetworkForTarget(netId, &netIdForResolv);
225}
Sreeram Ramachandrand794e582014-06-19 10:03:07 -0700226
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700227extern "C" int protectFromVpn(int socketFd) {
Sreeram Ramachandrand794e582014-06-19 10:03:07 -0700228 if (socketFd < 0) {
Sreeram Ramachandran3a069e62014-06-22 11:02:57 -0700229 return -EBADF;
Sreeram Ramachandrand794e582014-06-19 10:03:07 -0700230 }
Chenbo Feng9944ba82017-10-10 17:33:20 -0700231 FwmarkCommand command = {FwmarkCommand::PROTECT_FROM_VPN, 0, 0, 0};
Michal Karpinski4b9b78a2016-10-06 19:33:55 +0100232 return FwmarkClient().send(&command, socketFd, nullptr);
Sreeram Ramachandrana69d9472014-07-11 16:27:02 -0700233}
234
235extern "C" int setNetworkForUser(uid_t uid, int socketFd) {
236 if (socketFd < 0) {
237 return -EBADF;
238 }
Chenbo Feng9944ba82017-10-10 17:33:20 -0700239 FwmarkCommand command = {FwmarkCommand::SELECT_FOR_USER, 0, uid, 0};
Michal Karpinski4b9b78a2016-10-06 19:33:55 +0100240 return FwmarkClient().send(&command, socketFd, nullptr);
Paul Jensend1df5972015-05-06 07:29:56 -0400241}
242
243extern "C" int queryUserAccess(uid_t uid, unsigned netId) {
Chenbo Feng9944ba82017-10-10 17:33:20 -0700244 FwmarkCommand command = {FwmarkCommand::QUERY_USER_ACCESS, netId, uid, 0};
245 return FwmarkClient().send(&command, -1, nullptr);
246}
247
248extern "C" int tagSocket(int socketFd, uint32_t tag, uid_t uid) {
249 FwmarkCommand command = {FwmarkCommand::TAG_SOCKET, 0, uid, tag};
250 return FwmarkClient().send(&command, socketFd, nullptr);
251}
252
253extern "C" int untagSocket(int socketFd) {
254 FwmarkCommand command = {FwmarkCommand::UNTAG_SOCKET, 0, 0, 0};
255 return FwmarkClient().send(&command, socketFd, nullptr);
256}
257
258extern "C" int setCounterSet(uint32_t counterSet, uid_t uid) {
259 FwmarkCommand command = {FwmarkCommand::SET_COUNTERSET, 0, uid, counterSet};
260 return FwmarkClient().send(&command, -1, nullptr);
261}
262
263extern "C" int deleteTagData(uint32_t tag, uid_t uid) {
264 FwmarkCommand command = {FwmarkCommand::DELETE_TAGDATA, 0, uid, tag};
Michal Karpinski4b9b78a2016-10-06 19:33:55 +0100265 return FwmarkClient().send(&command, -1, nullptr);
Sreeram Ramachandrand794e582014-06-19 10:03:07 -0700266}