blob: fce362e5fe331b4ca4a1827d380b4a29a0ea13b7 [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
Sreeram Ramachandran4d4c8b72014-06-20 11:59:40 -070019#include "Fwmark.h"
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -070020#include "FwmarkClient.h"
21#include "FwmarkCommand.h"
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -070022#include "resolv_netid.h"
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -070023
Sreeram Ramachandran9fa2b132014-06-03 12:51:08 -070024#include <atomic>
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -070025#include <sys/socket.h>
26#include <unistd.h>
27
28namespace {
29
Sreeram Ramachandran9fa2b132014-06-03 12:51:08 -070030std::atomic_uint netIdForProcess(NETID_UNSET);
31std::atomic_uint netIdForResolv(NETID_UNSET);
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -070032
33typedef int (*Accept4FunctionType)(int, sockaddr*, socklen_t*, int);
34typedef int (*ConnectFunctionType)(int, const sockaddr*, socklen_t);
35typedef int (*SocketFunctionType)(int, int, int);
36typedef unsigned (*NetIdForResolvFunctionType)(unsigned);
37
38// These variables are only modified at startup (when libc.so is loaded) and never afterwards, so
39// it's okay that they are read later at runtime without a lock.
40Accept4FunctionType libcAccept4 = 0;
41ConnectFunctionType libcConnect = 0;
42SocketFunctionType libcSocket = 0;
43
Sreeram Ramachandran31f42102014-06-20 11:51:48 -070044int closeFdAndSetErrno(int fd, int error) {
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -070045 close(fd);
Sreeram Ramachandran3a069e62014-06-22 11:02:57 -070046 errno = -error;
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -070047 return -1;
48}
49
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -070050int netdClientAccept4(int sockfd, sockaddr* addr, socklen_t* addrlen, int flags) {
51 int acceptedSocket = libcAccept4(sockfd, addr, addrlen, flags);
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -070052 if (acceptedSocket == -1) {
53 return -1;
54 }
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -070055 int family;
56 if (addr) {
57 family = addr->sa_family;
58 } else {
59 socklen_t familyLen = sizeof(family);
60 if (getsockopt(acceptedSocket, SOL_SOCKET, SO_DOMAIN, &family, &familyLen) == -1) {
Sreeram Ramachandran3a069e62014-06-22 11:02:57 -070061 return closeFdAndSetErrno(acceptedSocket, -errno);
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -070062 }
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -070063 }
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -070064 if (FwmarkClient::shouldSetFwmark(family)) {
Sreeram Ramachandrana69d9472014-07-11 16:27:02 -070065 FwmarkCommand command = {FwmarkCommand::ON_ACCEPT, 0, 0};
Sreeram Ramachandrand36c49c2014-07-02 14:49:33 -070066 if (int error = FwmarkClient().send(&command, sizeof(command), acceptedSocket)) {
Sreeram Ramachandran31f42102014-06-20 11:51:48 -070067 return closeFdAndSetErrno(acceptedSocket, error);
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -070068 }
69 }
70 return acceptedSocket;
71}
72
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -070073int netdClientConnect(int sockfd, const sockaddr* addr, socklen_t addrlen) {
74 if (sockfd >= 0 && addr && FwmarkClient::shouldSetFwmark(addr->sa_family)) {
Sreeram Ramachandrana69d9472014-07-11 16:27:02 -070075 FwmarkCommand command = {FwmarkCommand::ON_CONNECT, 0, 0};
Sreeram Ramachandrand36c49c2014-07-02 14:49:33 -070076 if (int error = FwmarkClient().send(&command, sizeof(command), sockfd)) {
Sreeram Ramachandran3a069e62014-06-22 11:02:57 -070077 errno = -error;
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -070078 return -1;
79 }
80 }
81 return libcConnect(sockfd, addr, addrlen);
82}
83
84int netdClientSocket(int domain, int type, int protocol) {
85 int socketFd = libcSocket(domain, type, protocol);
86 if (socketFd == -1) {
87 return -1;
88 }
89 unsigned netId = netIdForProcess;
90 if (netId != NETID_UNSET && FwmarkClient::shouldSetFwmark(domain)) {
Sreeram Ramachandrand36c49c2014-07-02 14:49:33 -070091 if (int error = setNetworkForSocket(netId, socketFd)) {
Sreeram Ramachandran31f42102014-06-20 11:51:48 -070092 return closeFdAndSetErrno(socketFd, error);
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -070093 }
94 }
95 return socketFd;
96}
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -070097
98unsigned getNetworkForResolv(unsigned netId) {
99 if (netId != NETID_UNSET) {
100 return netId;
101 }
102 netId = netIdForProcess;
103 if (netId != NETID_UNSET) {
104 return netId;
105 }
106 return netIdForResolv;
107}
108
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700109int setNetworkForTarget(unsigned netId, std::atomic_uint* target) {
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700110 if (netId == NETID_UNSET) {
111 *target = netId;
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700112 return 0;
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700113 }
114 // 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 -0700115 // with the netId. Call libcSocket() directly; else the socket creation (via netdClientSocket())
116 // might itself cause another check with the fwmark server, which would be wasteful.
117 int socketFd;
118 if (libcSocket) {
119 socketFd = libcSocket(AF_INET6, SOCK_DGRAM, 0);
120 } else {
121 socketFd = socket(AF_INET6, SOCK_DGRAM, 0);
122 }
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700123 if (socketFd < 0) {
Sreeram Ramachandran3a069e62014-06-22 11:02:57 -0700124 return -errno;
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700125 }
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700126 int error = setNetworkForSocket(netId, socketFd);
127 if (!error) {
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700128 *target = netId;
129 }
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700130 close(socketFd);
131 return error;
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700132}
133
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -0700134} // namespace
135
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -0700136// accept() just calls accept4(..., 0), so there's no need to handle accept() separately.
137extern "C" void netdClientInitAccept4(Accept4FunctionType* function) {
138 if (function && *function) {
139 libcAccept4 = *function;
140 *function = netdClientAccept4;
141 }
142}
143
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -0700144extern "C" void netdClientInitConnect(ConnectFunctionType* function) {
145 if (function && *function) {
146 libcConnect = *function;
147 *function = netdClientConnect;
148 }
149}
150
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -0700151extern "C" void netdClientInitSocket(SocketFunctionType* function) {
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -0700152 if (function && *function) {
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -0700153 libcSocket = *function;
154 *function = netdClientSocket;
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -0700155 }
156}
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700157
158extern "C" void netdClientInitNetIdForResolv(NetIdForResolvFunctionType* function) {
159 if (function) {
160 *function = getNetworkForResolv;
161 }
162}
163
Sreeram Ramachandran4d4c8b72014-06-20 11:59:40 -0700164extern "C" int getNetworkForSocket(unsigned* netId, int socketFd) {
165 if (!netId || socketFd < 0) {
Sreeram Ramachandran3a069e62014-06-22 11:02:57 -0700166 return -EBADF;
Sreeram Ramachandran4d4c8b72014-06-20 11:59:40 -0700167 }
168 Fwmark fwmark;
169 socklen_t fwmarkLen = sizeof(fwmark.intValue);
170 if (getsockopt(socketFd, SOL_SOCKET, SO_MARK, &fwmark.intValue, &fwmarkLen) == -1) {
Sreeram Ramachandran3a069e62014-06-22 11:02:57 -0700171 return -errno;
Sreeram Ramachandran4d4c8b72014-06-20 11:59:40 -0700172 }
173 *netId = fwmark.netId;
174 return 0;
175}
176
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700177extern "C" unsigned getNetworkForProcess() {
178 return netIdForProcess;
179}
180
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700181extern "C" int setNetworkForSocket(unsigned netId, int socketFd) {
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700182 if (socketFd < 0) {
Sreeram Ramachandran3a069e62014-06-22 11:02:57 -0700183 return -EBADF;
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700184 }
Sreeram Ramachandrana69d9472014-07-11 16:27:02 -0700185 FwmarkCommand command = {FwmarkCommand::SELECT_NETWORK, netId, 0};
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700186 return FwmarkClient().send(&command, sizeof(command), socketFd);
187}
188
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700189extern "C" int setNetworkForProcess(unsigned netId) {
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700190 return setNetworkForTarget(netId, &netIdForProcess);
191}
192
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700193extern "C" int setNetworkForResolv(unsigned netId) {
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700194 return setNetworkForTarget(netId, &netIdForResolv);
195}
Sreeram Ramachandrand794e582014-06-19 10:03:07 -0700196
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700197extern "C" int protectFromVpn(int socketFd) {
Sreeram Ramachandrand794e582014-06-19 10:03:07 -0700198 if (socketFd < 0) {
Sreeram Ramachandran3a069e62014-06-22 11:02:57 -0700199 return -EBADF;
Sreeram Ramachandrand794e582014-06-19 10:03:07 -0700200 }
Sreeram Ramachandrana69d9472014-07-11 16:27:02 -0700201 FwmarkCommand command = {FwmarkCommand::PROTECT_FROM_VPN, 0, 0};
202 return FwmarkClient().send(&command, sizeof(command), socketFd);
203}
204
205extern "C" int setNetworkForUser(uid_t uid, int socketFd) {
206 if (socketFd < 0) {
207 return -EBADF;
208 }
209 FwmarkCommand command = {FwmarkCommand::SELECT_FOR_USER, 0, uid};
Sreeram Ramachandrand794e582014-06-19 10:03:07 -0700210 return FwmarkClient().send(&command, sizeof(command), socketFd);
211}