blob: eeff4113f115040ad15a383aeb9d1217fac2e9cc [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 Karpinskieced78e2016-10-06 19:33:55 +010019#include <arpa/inet.h>
Dan Albertaa1be2b2015-01-06 09:36:17 -080020#include <errno.h>
Michal Karpinskieced78e2016-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 Lee9484dab2016-09-21 16:31:33 +090031#include "Stopwatch.h"
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -070032
Devi Sandeep Endluri V V6139b842016-05-02 14:42:12 +053033#ifdef USE_WRAPPER
34#include "codeaurora/PropClientDispatch.h"
35#endif
36
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -070037namespace {
38
Sreeram Ramachandran9fa2b132014-06-03 12:51:08 -070039std::atomic_uint netIdForProcess(NETID_UNSET);
40std::atomic_uint netIdForResolv(NETID_UNSET);
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -070041
42typedef int (*Accept4FunctionType)(int, sockaddr*, socklen_t*, int);
43typedef int (*ConnectFunctionType)(int, const sockaddr*, socklen_t);
44typedef int (*SocketFunctionType)(int, int, int);
45typedef unsigned (*NetIdForResolvFunctionType)(unsigned);
46
Devi Sandeep Endluri V V6139b842016-05-02 14:42:12 +053047#ifdef USE_WRAPPER
48typedef void (*SetConnectFunc) (ConnectFunctionType*);
49#endif
50
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -070051// These variables are only modified at startup (when libc.so is loaded) and never afterwards, so
52// it's okay that they are read later at runtime without a lock.
53Accept4FunctionType libcAccept4 = 0;
54ConnectFunctionType libcConnect = 0;
55SocketFunctionType libcSocket = 0;
56
Sreeram Ramachandran31f42102014-06-20 11:51:48 -070057int closeFdAndSetErrno(int fd, int error) {
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -070058 close(fd);
Sreeram Ramachandran3a069e62014-06-22 11:02:57 -070059 errno = -error;
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -070060 return -1;
61}
62
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -070063int netdClientAccept4(int sockfd, sockaddr* addr, socklen_t* addrlen, int flags) {
64 int acceptedSocket = libcAccept4(sockfd, addr, addrlen, flags);
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -070065 if (acceptedSocket == -1) {
66 return -1;
67 }
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -070068 int family;
69 if (addr) {
70 family = addr->sa_family;
71 } else {
72 socklen_t familyLen = sizeof(family);
73 if (getsockopt(acceptedSocket, SOL_SOCKET, SO_DOMAIN, &family, &familyLen) == -1) {
Sreeram Ramachandran3a069e62014-06-22 11:02:57 -070074 return closeFdAndSetErrno(acceptedSocket, -errno);
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -070075 }
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -070076 }
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -070077 if (FwmarkClient::shouldSetFwmark(family)) {
Sreeram Ramachandrana69d9472014-07-11 16:27:02 -070078 FwmarkCommand command = {FwmarkCommand::ON_ACCEPT, 0, 0};
Michal Karpinskieced78e2016-10-06 19:33:55 +010079 if (int error = FwmarkClient().send(&command, acceptedSocket, nullptr)) {
Sreeram Ramachandran31f42102014-06-20 11:51:48 -070080 return closeFdAndSetErrno(acceptedSocket, error);
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -070081 }
82 }
83 return acceptedSocket;
84}
85
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -070086int netdClientConnect(int sockfd, const sockaddr* addr, socklen_t addrlen) {
Michal Karpinskieced78e2016-10-06 19:33:55 +010087 const bool shouldSetFwmark = (sockfd >= 0) && addr
88 && FwmarkClient::shouldSetFwmark(addr->sa_family);
89 if (shouldSetFwmark) {
Sreeram Ramachandrana69d9472014-07-11 16:27:02 -070090 FwmarkCommand command = {FwmarkCommand::ON_CONNECT, 0, 0};
Michal Karpinskieced78e2016-10-06 19:33:55 +010091 if (int error = FwmarkClient().send(&command, sockfd, nullptr)) {
Sreeram Ramachandran3a069e62014-06-22 11:02:57 -070092 errno = -error;
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -070093 return -1;
94 }
95 }
Devi Sandeep Endluri V V6139b842016-05-02 14:42:12 +053096
Michal Karpinskieced78e2016-10-06 19:33:55 +010097 // Latency measurement does not include time of sending commands to Fwmark
98 Stopwatch s;
Lalit Kansara0effbda2017-04-04 19:42:49 +053099 int ret = -1;
Devi Sandeep Endluri V V6139b842016-05-02 14:42:12 +0530100#ifdef USE_WRAPPER
101 if ( FwmarkClient::shouldSetFwmark(addr->sa_family)) {
102 if( __propClientDispatch.propConnect ) {
Lalit Kansara0effbda2017-04-04 19:42:49 +0530103 ret = __propClientDispatch.propConnect(sockfd, addr, addrlen);
Devi Sandeep Endluri V V6139b842016-05-02 14:42:12 +0530104 } else {
Lalit Kansara0effbda2017-04-04 19:42:49 +0530105 ret = libcConnect(sockfd, addr, addrlen);
Devi Sandeep Endluri V V6139b842016-05-02 14:42:12 +0530106 }
Lalit Kansara0effbda2017-04-04 19:42:49 +0530107 } else {
108 ret = libcConnect(sockfd, addr, addrlen);
Devi Sandeep Endluri V V6139b842016-05-02 14:42:12 +0530109 }
Lalit Kansara0effbda2017-04-04 19:42:49 +0530110#else
111 ret = libcConnect(sockfd, addr, addrlen);
Devi Sandeep Endluri V V6139b842016-05-02 14:42:12 +0530112#endif
Michal Karpinskieced78e2016-10-06 19:33:55 +0100113 // Save errno so it isn't clobbered by sending ON_CONNECT_COMPLETE
114 const int connectErrno = errno;
115 const unsigned latencyMs = lround(s.timeTaken());
116 // Send an ON_CONNECT_COMPLETE command that includes sockaddr and connect latency for reporting
117 if (shouldSetFwmark && FwmarkClient::shouldReportConnectComplete(addr->sa_family)) {
Hugo Benichi483afa42016-10-31 15:07:23 +0900118 FwmarkConnectInfo connectInfo(ret == 0 ? 0 : connectErrno, latencyMs, addr);
Michal Karpinskieced78e2016-10-06 19:33:55 +0100119 // TODO: get the netId from the socket mark once we have continuous benchmark runs
120 FwmarkCommand command = {FwmarkCommand::ON_CONNECT_COMPLETE, /* netId (ignored) */ 0,
121 /* uid (filled in by the server) */ 0};
122 // Ignore return value since it's only used for logging
123 FwmarkClient().send(&command, sockfd, &connectInfo);
124 }
125 errno = connectErrno;
126 return ret;
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -0700127}
128
129int netdClientSocket(int domain, int type, int protocol) {
Devi Sandeep Endluri V V6139b842016-05-02 14:42:12 +0530130
131 int socketFd;
132#ifndef USE_WRAPPER
133 socketFd = libcSocket(domain, type, protocol);
134#else
135 if( __propClientDispatch.propSocket ) {
136 socketFd = __propClientDispatch.propSocket(domain, type, protocol);
137 } else {
138 socketFd = libcSocket(domain, type, protocol);
139 }
140#endif
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -0700141 if (socketFd == -1) {
142 return -1;
143 }
144 unsigned netId = netIdForProcess;
145 if (netId != NETID_UNSET && FwmarkClient::shouldSetFwmark(domain)) {
Sreeram Ramachandrand36c49c2014-07-02 14:49:33 -0700146 if (int error = setNetworkForSocket(netId, socketFd)) {
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700147 return closeFdAndSetErrno(socketFd, error);
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -0700148 }
149 }
150 return socketFd;
151}
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700152
153unsigned getNetworkForResolv(unsigned netId) {
154 if (netId != NETID_UNSET) {
155 return netId;
156 }
157 netId = netIdForProcess;
158 if (netId != NETID_UNSET) {
159 return netId;
160 }
161 return netIdForResolv;
162}
163
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700164int setNetworkForTarget(unsigned netId, std::atomic_uint* target) {
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700165 if (netId == NETID_UNSET) {
166 *target = netId;
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700167 return 0;
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700168 }
169 // 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 -0700170 // with the netId. Call libcSocket() directly; else the socket creation (via netdClientSocket())
171 // might itself cause another check with the fwmark server, which would be wasteful.
172 int socketFd;
173 if (libcSocket) {
Nick Kralevich53ea9ca2015-01-31 13:54:00 -0800174 socketFd = libcSocket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0);
Sreeram Ramachandran27560452014-05-30 19:59:51 -0700175 } else {
Nick Kralevich53ea9ca2015-01-31 13:54:00 -0800176 socketFd = socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0);
Sreeram Ramachandran27560452014-05-30 19:59:51 -0700177 }
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700178 if (socketFd < 0) {
Sreeram Ramachandran3a069e62014-06-22 11:02:57 -0700179 return -errno;
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700180 }
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700181 int error = setNetworkForSocket(netId, socketFd);
182 if (!error) {
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700183 *target = netId;
184 }
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700185 close(socketFd);
186 return error;
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700187}
188
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -0700189} // namespace
190
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -0700191// accept() just calls accept4(..., 0), so there's no need to handle accept() separately.
192extern "C" void netdClientInitAccept4(Accept4FunctionType* function) {
193 if (function && *function) {
194 libcAccept4 = *function;
195 *function = netdClientAccept4;
196 }
197}
198
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -0700199extern "C" void netdClientInitConnect(ConnectFunctionType* function) {
200 if (function && *function) {
201 libcConnect = *function;
202 *function = netdClientConnect;
203 }
204}
205
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -0700206extern "C" void netdClientInitSocket(SocketFunctionType* function) {
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -0700207 if (function && *function) {
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -0700208 libcSocket = *function;
209 *function = netdClientSocket;
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -0700210 }
211}
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700212
213extern "C" void netdClientInitNetIdForResolv(NetIdForResolvFunctionType* function) {
214 if (function) {
215 *function = getNetworkForResolv;
216 }
217}
218
Sreeram Ramachandran4d4c8b72014-06-20 11:59:40 -0700219extern "C" int getNetworkForSocket(unsigned* netId, int socketFd) {
220 if (!netId || socketFd < 0) {
Sreeram Ramachandran3a069e62014-06-22 11:02:57 -0700221 return -EBADF;
Sreeram Ramachandran4d4c8b72014-06-20 11:59:40 -0700222 }
223 Fwmark fwmark;
224 socklen_t fwmarkLen = sizeof(fwmark.intValue);
225 if (getsockopt(socketFd, SOL_SOCKET, SO_MARK, &fwmark.intValue, &fwmarkLen) == -1) {
Sreeram Ramachandran3a069e62014-06-22 11:02:57 -0700226 return -errno;
Sreeram Ramachandran4d4c8b72014-06-20 11:59:40 -0700227 }
228 *netId = fwmark.netId;
229 return 0;
230}
231
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700232extern "C" unsigned getNetworkForProcess() {
233 return netIdForProcess;
234}
235
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700236extern "C" int setNetworkForSocket(unsigned netId, int socketFd) {
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700237 if (socketFd < 0) {
Sreeram Ramachandran3a069e62014-06-22 11:02:57 -0700238 return -EBADF;
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700239 }
Sreeram Ramachandrana69d9472014-07-11 16:27:02 -0700240 FwmarkCommand command = {FwmarkCommand::SELECT_NETWORK, netId, 0};
Michal Karpinskieced78e2016-10-06 19:33:55 +0100241 return FwmarkClient().send(&command, socketFd, nullptr);
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700242}
243
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700244extern "C" int setNetworkForProcess(unsigned netId) {
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700245 return setNetworkForTarget(netId, &netIdForProcess);
246}
247
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700248extern "C" int setNetworkForResolv(unsigned netId) {
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700249 return setNetworkForTarget(netId, &netIdForResolv);
250}
Sreeram Ramachandrand794e582014-06-19 10:03:07 -0700251
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700252extern "C" int protectFromVpn(int socketFd) {
Sreeram Ramachandrand794e582014-06-19 10:03:07 -0700253 if (socketFd < 0) {
Sreeram Ramachandran3a069e62014-06-22 11:02:57 -0700254 return -EBADF;
Sreeram Ramachandrand794e582014-06-19 10:03:07 -0700255 }
Sreeram Ramachandrana69d9472014-07-11 16:27:02 -0700256 FwmarkCommand command = {FwmarkCommand::PROTECT_FROM_VPN, 0, 0};
Michal Karpinskieced78e2016-10-06 19:33:55 +0100257 return FwmarkClient().send(&command, socketFd, nullptr);
Sreeram Ramachandrana69d9472014-07-11 16:27:02 -0700258}
259
260extern "C" int setNetworkForUser(uid_t uid, int socketFd) {
261 if (socketFd < 0) {
262 return -EBADF;
263 }
264 FwmarkCommand command = {FwmarkCommand::SELECT_FOR_USER, 0, uid};
Michal Karpinskieced78e2016-10-06 19:33:55 +0100265 return FwmarkClient().send(&command, socketFd, nullptr);
Paul Jensend1df5972015-05-06 07:29:56 -0400266}
267
268extern "C" int queryUserAccess(uid_t uid, unsigned netId) {
269 FwmarkCommand command = {FwmarkCommand::QUERY_USER_ACCESS, netId, uid};
Michal Karpinskieced78e2016-10-06 19:33:55 +0100270 return FwmarkClient().send(&command, -1, nullptr);
Sreeram Ramachandrand794e582014-06-19 10:03:07 -0700271}