blob: 821f48897db699fd689a5fa79b09c8ce8ab16283 [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 }
125 netId = netIdForProcess;
126 if (netId != NETID_UNSET) {
127 return netId;
128 }
129 return netIdForResolv;
130}
131
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700132int setNetworkForTarget(unsigned netId, std::atomic_uint* target) {
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700133 if (netId == NETID_UNSET) {
134 *target = netId;
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700135 return 0;
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700136 }
137 // 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 -0700138 // with the netId. Call libcSocket() directly; else the socket creation (via netdClientSocket())
139 // might itself cause another check with the fwmark server, which would be wasteful.
140 int socketFd;
141 if (libcSocket) {
Nick Kralevich53ea9ca2015-01-31 13:54:00 -0800142 socketFd = libcSocket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0);
Sreeram Ramachandran27560452014-05-30 19:59:51 -0700143 } else {
Nick Kralevich53ea9ca2015-01-31 13:54:00 -0800144 socketFd = socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0);
Sreeram Ramachandran27560452014-05-30 19:59:51 -0700145 }
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700146 if (socketFd < 0) {
Sreeram Ramachandran3a069e62014-06-22 11:02:57 -0700147 return -errno;
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700148 }
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700149 int error = setNetworkForSocket(netId, socketFd);
150 if (!error) {
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700151 *target = netId;
152 }
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700153 close(socketFd);
154 return error;
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700155}
156
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -0700157} // namespace
158
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -0700159// accept() just calls accept4(..., 0), so there's no need to handle accept() separately.
160extern "C" void netdClientInitAccept4(Accept4FunctionType* function) {
161 if (function && *function) {
162 libcAccept4 = *function;
163 *function = netdClientAccept4;
164 }
165}
166
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -0700167extern "C" void netdClientInitConnect(ConnectFunctionType* function) {
168 if (function && *function) {
169 libcConnect = *function;
170 *function = netdClientConnect;
171 }
172}
173
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -0700174extern "C" void netdClientInitSocket(SocketFunctionType* function) {
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -0700175 if (function && *function) {
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -0700176 libcSocket = *function;
177 *function = netdClientSocket;
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -0700178 }
179}
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700180
181extern "C" void netdClientInitNetIdForResolv(NetIdForResolvFunctionType* function) {
182 if (function) {
183 *function = getNetworkForResolv;
184 }
185}
186
Sreeram Ramachandran4d4c8b72014-06-20 11:59:40 -0700187extern "C" int getNetworkForSocket(unsigned* netId, int socketFd) {
188 if (!netId || socketFd < 0) {
Sreeram Ramachandran3a069e62014-06-22 11:02:57 -0700189 return -EBADF;
Sreeram Ramachandran4d4c8b72014-06-20 11:59:40 -0700190 }
191 Fwmark fwmark;
192 socklen_t fwmarkLen = sizeof(fwmark.intValue);
193 if (getsockopt(socketFd, SOL_SOCKET, SO_MARK, &fwmark.intValue, &fwmarkLen) == -1) {
Sreeram Ramachandran3a069e62014-06-22 11:02:57 -0700194 return -errno;
Sreeram Ramachandran4d4c8b72014-06-20 11:59:40 -0700195 }
196 *netId = fwmark.netId;
197 return 0;
198}
199
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700200extern "C" unsigned getNetworkForProcess() {
201 return netIdForProcess;
202}
203
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700204extern "C" int setNetworkForSocket(unsigned netId, int socketFd) {
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700205 if (socketFd < 0) {
Sreeram Ramachandran3a069e62014-06-22 11:02:57 -0700206 return -EBADF;
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700207 }
Chenbo Feng9944ba82017-10-10 17:33:20 -0700208 FwmarkCommand command = {FwmarkCommand::SELECT_NETWORK, netId, 0, 0};
Michal Karpinski4b9b78a2016-10-06 19:33:55 +0100209 return FwmarkClient().send(&command, socketFd, nullptr);
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700210}
211
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700212extern "C" int setNetworkForProcess(unsigned netId) {
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700213 return setNetworkForTarget(netId, &netIdForProcess);
214}
215
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700216extern "C" int setNetworkForResolv(unsigned netId) {
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700217 return setNetworkForTarget(netId, &netIdForResolv);
218}
Sreeram Ramachandrand794e582014-06-19 10:03:07 -0700219
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700220extern "C" int protectFromVpn(int socketFd) {
Sreeram Ramachandrand794e582014-06-19 10:03:07 -0700221 if (socketFd < 0) {
Sreeram Ramachandran3a069e62014-06-22 11:02:57 -0700222 return -EBADF;
Sreeram Ramachandrand794e582014-06-19 10:03:07 -0700223 }
Chenbo Feng9944ba82017-10-10 17:33:20 -0700224 FwmarkCommand command = {FwmarkCommand::PROTECT_FROM_VPN, 0, 0, 0};
Michal Karpinski4b9b78a2016-10-06 19:33:55 +0100225 return FwmarkClient().send(&command, socketFd, nullptr);
Sreeram Ramachandrana69d9472014-07-11 16:27:02 -0700226}
227
228extern "C" int setNetworkForUser(uid_t uid, int socketFd) {
229 if (socketFd < 0) {
230 return -EBADF;
231 }
Chenbo Feng9944ba82017-10-10 17:33:20 -0700232 FwmarkCommand command = {FwmarkCommand::SELECT_FOR_USER, 0, uid, 0};
Michal Karpinski4b9b78a2016-10-06 19:33:55 +0100233 return FwmarkClient().send(&command, socketFd, nullptr);
Paul Jensend1df5972015-05-06 07:29:56 -0400234}
235
236extern "C" int queryUserAccess(uid_t uid, unsigned netId) {
Chenbo Feng9944ba82017-10-10 17:33:20 -0700237 FwmarkCommand command = {FwmarkCommand::QUERY_USER_ACCESS, netId, uid, 0};
238 return FwmarkClient().send(&command, -1, nullptr);
239}
240
241extern "C" int tagSocket(int socketFd, uint32_t tag, uid_t uid) {
242 FwmarkCommand command = {FwmarkCommand::TAG_SOCKET, 0, uid, tag};
243 return FwmarkClient().send(&command, socketFd, nullptr);
244}
245
246extern "C" int untagSocket(int socketFd) {
247 FwmarkCommand command = {FwmarkCommand::UNTAG_SOCKET, 0, 0, 0};
248 return FwmarkClient().send(&command, socketFd, nullptr);
249}
250
251extern "C" int setCounterSet(uint32_t counterSet, uid_t uid) {
252 FwmarkCommand command = {FwmarkCommand::SET_COUNTERSET, 0, uid, counterSet};
253 return FwmarkClient().send(&command, -1, nullptr);
254}
255
256extern "C" int deleteTagData(uint32_t tag, uid_t uid) {
257 FwmarkCommand command = {FwmarkCommand::DELETE_TAGDATA, 0, uid, tag};
Michal Karpinski4b9b78a2016-10-06 19:33:55 +0100258 return FwmarkClient().send(&command, -1, nullptr);
Sreeram Ramachandrand794e582014-06-19 10:03:07 -0700259}