blob: 91d630dab5af17656d7923617bee8f0054c7b7ee [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
Dan Albertaa1be2b2015-01-06 09:36:17 -080019#include <errno.h>
20#include <sys/socket.h>
21#include <unistd.h>
22
23#include <atomic>
24
Sreeram Ramachandran4d4c8b72014-06-20 11:59:40 -070025#include "Fwmark.h"
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -070026#include "FwmarkClient.h"
27#include "FwmarkCommand.h"
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -070028#include "resolv_netid.h"
Robin Leecc544162016-09-21 16:31:33 +090029#include "Stopwatch.h"
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -070030
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -070031namespace {
32
Sreeram Ramachandran9fa2b132014-06-03 12:51:08 -070033std::atomic_uint netIdForProcess(NETID_UNSET);
34std::atomic_uint netIdForResolv(NETID_UNSET);
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -070035
36typedef int (*Accept4FunctionType)(int, sockaddr*, socklen_t*, int);
37typedef int (*ConnectFunctionType)(int, const sockaddr*, socklen_t);
38typedef int (*SocketFunctionType)(int, int, int);
39typedef unsigned (*NetIdForResolvFunctionType)(unsigned);
40
41// These variables are only modified at startup (when libc.so is loaded) and never afterwards, so
42// it's okay that they are read later at runtime without a lock.
43Accept4FunctionType libcAccept4 = 0;
44ConnectFunctionType libcConnect = 0;
45SocketFunctionType libcSocket = 0;
46
Sreeram Ramachandran31f42102014-06-20 11:51:48 -070047int closeFdAndSetErrno(int fd, int error) {
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -070048 close(fd);
Sreeram Ramachandran3a069e62014-06-22 11:02:57 -070049 errno = -error;
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -070050 return -1;
51}
52
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -070053int netdClientAccept4(int sockfd, sockaddr* addr, socklen_t* addrlen, int flags) {
54 int acceptedSocket = libcAccept4(sockfd, addr, addrlen, flags);
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -070055 if (acceptedSocket == -1) {
56 return -1;
57 }
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -070058 int family;
59 if (addr) {
60 family = addr->sa_family;
61 } else {
62 socklen_t familyLen = sizeof(family);
63 if (getsockopt(acceptedSocket, SOL_SOCKET, SO_DOMAIN, &family, &familyLen) == -1) {
Sreeram Ramachandran3a069e62014-06-22 11:02:57 -070064 return closeFdAndSetErrno(acceptedSocket, -errno);
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -070065 }
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -070066 }
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -070067 if (FwmarkClient::shouldSetFwmark(family)) {
Sreeram Ramachandrana69d9472014-07-11 16:27:02 -070068 FwmarkCommand command = {FwmarkCommand::ON_ACCEPT, 0, 0};
Paul Jensend1df5972015-05-06 07:29:56 -040069 if (int error = FwmarkClient().send(&command, acceptedSocket)) {
Sreeram Ramachandran31f42102014-06-20 11:51:48 -070070 return closeFdAndSetErrno(acceptedSocket, error);
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -070071 }
72 }
73 return acceptedSocket;
74}
75
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -070076int netdClientConnect(int sockfd, const sockaddr* addr, socklen_t addrlen) {
77 if (sockfd >= 0 && addr && FwmarkClient::shouldSetFwmark(addr->sa_family)) {
Sreeram Ramachandrana69d9472014-07-11 16:27:02 -070078 FwmarkCommand command = {FwmarkCommand::ON_CONNECT, 0, 0};
Paul Jensend1df5972015-05-06 07:29:56 -040079 if (int error = FwmarkClient().send(&command, sockfd)) {
Sreeram Ramachandran3a069e62014-06-22 11:02:57 -070080 errno = -error;
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -070081 return -1;
82 }
83 }
84 return libcConnect(sockfd, addr, addrlen);
85}
86
87int netdClientSocket(int domain, int type, int protocol) {
88 int socketFd = libcSocket(domain, type, protocol);
89 if (socketFd == -1) {
90 return -1;
91 }
92 unsigned netId = netIdForProcess;
93 if (netId != NETID_UNSET && FwmarkClient::shouldSetFwmark(domain)) {
Sreeram Ramachandrand36c49c2014-07-02 14:49:33 -070094 if (int error = setNetworkForSocket(netId, socketFd)) {
Sreeram Ramachandran31f42102014-06-20 11:51:48 -070095 return closeFdAndSetErrno(socketFd, error);
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -070096 }
97 }
98 return socketFd;
99}
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700100
101unsigned getNetworkForResolv(unsigned netId) {
102 if (netId != NETID_UNSET) {
103 return netId;
104 }
105 netId = netIdForProcess;
106 if (netId != NETID_UNSET) {
107 return netId;
108 }
109 return netIdForResolv;
110}
111
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700112int setNetworkForTarget(unsigned netId, std::atomic_uint* target) {
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700113 if (netId == NETID_UNSET) {
114 *target = netId;
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700115 return 0;
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700116 }
117 // 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 -0700118 // with the netId. Call libcSocket() directly; else the socket creation (via netdClientSocket())
119 // might itself cause another check with the fwmark server, which would be wasteful.
120 int socketFd;
121 if (libcSocket) {
Nick Kralevich53ea9ca2015-01-31 13:54:00 -0800122 socketFd = libcSocket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0);
Sreeram Ramachandran27560452014-05-30 19:59:51 -0700123 } else {
Nick Kralevich53ea9ca2015-01-31 13:54:00 -0800124 socketFd = socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0);
Sreeram Ramachandran27560452014-05-30 19:59:51 -0700125 }
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700126 if (socketFd < 0) {
Sreeram Ramachandran3a069e62014-06-22 11:02:57 -0700127 return -errno;
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700128 }
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700129 int error = setNetworkForSocket(netId, socketFd);
130 if (!error) {
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700131 *target = netId;
132 }
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700133 close(socketFd);
134 return error;
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700135}
136
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -0700137} // namespace
138
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -0700139// accept() just calls accept4(..., 0), so there's no need to handle accept() separately.
140extern "C" void netdClientInitAccept4(Accept4FunctionType* function) {
141 if (function && *function) {
142 libcAccept4 = *function;
143 *function = netdClientAccept4;
144 }
145}
146
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -0700147extern "C" void netdClientInitConnect(ConnectFunctionType* function) {
148 if (function && *function) {
149 libcConnect = *function;
150 *function = netdClientConnect;
151 }
152}
153
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -0700154extern "C" void netdClientInitSocket(SocketFunctionType* function) {
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -0700155 if (function && *function) {
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -0700156 libcSocket = *function;
157 *function = netdClientSocket;
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -0700158 }
159}
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700160
161extern "C" void netdClientInitNetIdForResolv(NetIdForResolvFunctionType* function) {
162 if (function) {
163 *function = getNetworkForResolv;
164 }
165}
166
Sreeram Ramachandran4d4c8b72014-06-20 11:59:40 -0700167extern "C" int getNetworkForSocket(unsigned* netId, int socketFd) {
168 if (!netId || socketFd < 0) {
Sreeram Ramachandran3a069e62014-06-22 11:02:57 -0700169 return -EBADF;
Sreeram Ramachandran4d4c8b72014-06-20 11:59:40 -0700170 }
171 Fwmark fwmark;
172 socklen_t fwmarkLen = sizeof(fwmark.intValue);
173 if (getsockopt(socketFd, SOL_SOCKET, SO_MARK, &fwmark.intValue, &fwmarkLen) == -1) {
Sreeram Ramachandran3a069e62014-06-22 11:02:57 -0700174 return -errno;
Sreeram Ramachandran4d4c8b72014-06-20 11:59:40 -0700175 }
176 *netId = fwmark.netId;
177 return 0;
178}
179
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700180extern "C" unsigned getNetworkForProcess() {
181 return netIdForProcess;
182}
183
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700184extern "C" int setNetworkForSocket(unsigned netId, int socketFd) {
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700185 if (socketFd < 0) {
Sreeram Ramachandran3a069e62014-06-22 11:02:57 -0700186 return -EBADF;
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700187 }
Sreeram Ramachandrana69d9472014-07-11 16:27:02 -0700188 FwmarkCommand command = {FwmarkCommand::SELECT_NETWORK, netId, 0};
Paul Jensend1df5972015-05-06 07:29:56 -0400189 return FwmarkClient().send(&command, socketFd);
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700190}
191
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700192extern "C" int setNetworkForProcess(unsigned netId) {
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700193 return setNetworkForTarget(netId, &netIdForProcess);
194}
195
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700196extern "C" int setNetworkForResolv(unsigned netId) {
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700197 return setNetworkForTarget(netId, &netIdForResolv);
198}
Sreeram Ramachandrand794e582014-06-19 10:03:07 -0700199
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700200extern "C" int protectFromVpn(int socketFd) {
Sreeram Ramachandrand794e582014-06-19 10:03:07 -0700201 if (socketFd < 0) {
Sreeram Ramachandran3a069e62014-06-22 11:02:57 -0700202 return -EBADF;
Sreeram Ramachandrand794e582014-06-19 10:03:07 -0700203 }
Sreeram Ramachandrana69d9472014-07-11 16:27:02 -0700204 FwmarkCommand command = {FwmarkCommand::PROTECT_FROM_VPN, 0, 0};
Paul Jensend1df5972015-05-06 07:29:56 -0400205 return FwmarkClient().send(&command, socketFd);
Sreeram Ramachandrana69d9472014-07-11 16:27:02 -0700206}
207
208extern "C" int setNetworkForUser(uid_t uid, int socketFd) {
209 if (socketFd < 0) {
210 return -EBADF;
211 }
212 FwmarkCommand command = {FwmarkCommand::SELECT_FOR_USER, 0, uid};
Paul Jensend1df5972015-05-06 07:29:56 -0400213 return FwmarkClient().send(&command, socketFd);
214}
215
216extern "C" int queryUserAccess(uid_t uid, unsigned netId) {
217 FwmarkCommand command = {FwmarkCommand::QUERY_USER_ACCESS, netId, uid};
218 return FwmarkClient().send(&command, -1);
Sreeram Ramachandrand794e582014-06-19 10:03:07 -0700219}