blob: 8a54354d1a6a91254a891f97c1447e89108c72ca [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 Ramachandranf4cfad32014-05-21 08:54:07 -070019#include "FwmarkClient.h"
20#include "FwmarkCommand.h"
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -070021#include "resolv_netid.h"
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -070022
Sreeram Ramachandran9fa2b132014-06-03 12:51:08 -070023#include <atomic>
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -070024#include <sys/socket.h>
25#include <unistd.h>
26
27namespace {
28
Sreeram Ramachandran9fa2b132014-06-03 12:51:08 -070029std::atomic_uint netIdForProcess(NETID_UNSET);
30std::atomic_uint netIdForResolv(NETID_UNSET);
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -070031
32typedef int (*Accept4FunctionType)(int, sockaddr*, socklen_t*, int);
33typedef int (*ConnectFunctionType)(int, const sockaddr*, socklen_t);
34typedef int (*SocketFunctionType)(int, int, int);
35typedef unsigned (*NetIdForResolvFunctionType)(unsigned);
36
37// These variables are only modified at startup (when libc.so is loaded) and never afterwards, so
38// it's okay that they are read later at runtime without a lock.
39Accept4FunctionType libcAccept4 = 0;
40ConnectFunctionType libcConnect = 0;
41SocketFunctionType libcSocket = 0;
42
Sreeram Ramachandran31f42102014-06-20 11:51:48 -070043int closeFdAndSetErrno(int fd, int error) {
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -070044 close(fd);
45 errno = error;
46 return -1;
47}
48
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -070049int netdClientAccept4(int sockfd, sockaddr* addr, socklen_t* addrlen, int flags) {
50 int acceptedSocket = libcAccept4(sockfd, addr, addrlen, flags);
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -070051 if (acceptedSocket == -1) {
52 return -1;
53 }
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -070054 int family;
55 if (addr) {
56 family = addr->sa_family;
57 } else {
58 socklen_t familyLen = sizeof(family);
59 if (getsockopt(acceptedSocket, SOL_SOCKET, SO_DOMAIN, &family, &familyLen) == -1) {
Sreeram Ramachandran31f42102014-06-20 11:51:48 -070060 return closeFdAndSetErrno(acceptedSocket, errno);
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -070061 }
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -070062 }
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -070063 if (FwmarkClient::shouldSetFwmark(family)) {
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -070064 FwmarkCommand command = {FwmarkCommand::ON_ACCEPT, 0};
Sreeram Ramachandran31f42102014-06-20 11:51:48 -070065 int error = FwmarkClient().send(&command, sizeof(command), acceptedSocket);
66 if (error) {
67 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)) {
75 FwmarkCommand command = {FwmarkCommand::ON_CONNECT, 0};
Sreeram Ramachandran31f42102014-06-20 11:51:48 -070076 int error = FwmarkClient().send(&command, sizeof(command), sockfd);
77 if (error) {
78 errno = error;
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -070079 return -1;
80 }
81 }
82 return libcConnect(sockfd, addr, addrlen);
83}
84
85int netdClientSocket(int domain, int type, int protocol) {
86 int socketFd = libcSocket(domain, type, protocol);
87 if (socketFd == -1) {
88 return -1;
89 }
90 unsigned netId = netIdForProcess;
91 if (netId != NETID_UNSET && FwmarkClient::shouldSetFwmark(domain)) {
Sreeram Ramachandran31f42102014-06-20 11:51:48 -070092 int error = setNetworkForSocket(netId, socketFd);
93 if (error) {
94 return closeFdAndSetErrno(socketFd, error);
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -070095 }
96 }
97 return socketFd;
98}
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -070099
100unsigned getNetworkForResolv(unsigned netId) {
101 if (netId != NETID_UNSET) {
102 return netId;
103 }
104 netId = netIdForProcess;
105 if (netId != NETID_UNSET) {
106 return netId;
107 }
108 return netIdForResolv;
109}
110
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700111int setNetworkForTarget(unsigned netId, std::atomic_uint* target) {
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700112 if (netId == NETID_UNSET) {
113 *target = netId;
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700114 return 0;
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700115 }
116 // 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 -0700117 // with the netId. Call libcSocket() directly; else the socket creation (via netdClientSocket())
118 // might itself cause another check with the fwmark server, which would be wasteful.
119 int socketFd;
120 if (libcSocket) {
121 socketFd = libcSocket(AF_INET6, SOCK_DGRAM, 0);
122 } else {
123 socketFd = socket(AF_INET6, SOCK_DGRAM, 0);
124 }
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700125 if (socketFd < 0) {
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700126 return errno;
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700127 }
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700128 int error = setNetworkForSocket(netId, socketFd);
129 if (!error) {
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700130 *target = netId;
131 }
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700132 close(socketFd);
133 return error;
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700134}
135
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -0700136} // namespace
137
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -0700138// accept() just calls accept4(..., 0), so there's no need to handle accept() separately.
139extern "C" void netdClientInitAccept4(Accept4FunctionType* function) {
140 if (function && *function) {
141 libcAccept4 = *function;
142 *function = netdClientAccept4;
143 }
144}
145
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -0700146extern "C" void netdClientInitConnect(ConnectFunctionType* function) {
147 if (function && *function) {
148 libcConnect = *function;
149 *function = netdClientConnect;
150 }
151}
152
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -0700153extern "C" void netdClientInitSocket(SocketFunctionType* function) {
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -0700154 if (function && *function) {
Sreeram Ramachandran5fc27572014-05-21 13:08:34 -0700155 libcSocket = *function;
156 *function = netdClientSocket;
Sreeram Ramachandranf4cfad32014-05-21 08:54:07 -0700157 }
158}
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700159
160extern "C" void netdClientInitNetIdForResolv(NetIdForResolvFunctionType* function) {
161 if (function) {
162 *function = getNetworkForResolv;
163 }
164}
165
166extern "C" unsigned getNetworkForProcess() {
167 return netIdForProcess;
168}
169
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700170extern "C" int setNetworkForSocket(unsigned netId, int socketFd) {
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700171 if (socketFd < 0) {
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700172 return EBADF;
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700173 }
174 FwmarkCommand command = {FwmarkCommand::SELECT_NETWORK, netId};
175 return FwmarkClient().send(&command, sizeof(command), socketFd);
176}
177
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700178extern "C" int setNetworkForProcess(unsigned netId) {
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700179 return setNetworkForTarget(netId, &netIdForProcess);
180}
181
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700182extern "C" int setNetworkForResolv(unsigned netId) {
Sreeram Ramachandranefbe05d2014-05-21 11:41:39 -0700183 return setNetworkForTarget(netId, &netIdForResolv);
184}
Sreeram Ramachandrand794e582014-06-19 10:03:07 -0700185
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700186extern "C" int protectFromVpn(int socketFd) {
Sreeram Ramachandrand794e582014-06-19 10:03:07 -0700187 if (socketFd < 0) {
Sreeram Ramachandran31f42102014-06-20 11:51:48 -0700188 return EBADF;
Sreeram Ramachandrand794e582014-06-19 10:03:07 -0700189 }
190 FwmarkCommand command = {FwmarkCommand::PROTECT_FROM_VPN, 0};
191 return FwmarkClient().send(&command, sizeof(command), socketFd);
192}