• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
17 #include "NetdClient.h"
18 
19 #include <errno.h>
20 #include <sys/socket.h>
21 #include <unistd.h>
22 
23 #include <atomic>
24 
25 #include "Fwmark.h"
26 #include "FwmarkClient.h"
27 #include "FwmarkCommand.h"
28 #include "resolv_netid.h"
29 
30 namespace {
31 
32 std::atomic_uint netIdForProcess(NETID_UNSET);
33 std::atomic_uint netIdForResolv(NETID_UNSET);
34 
35 typedef int (*Accept4FunctionType)(int, sockaddr*, socklen_t*, int);
36 typedef int (*ConnectFunctionType)(int, const sockaddr*, socklen_t);
37 typedef int (*SocketFunctionType)(int, int, int);
38 typedef unsigned (*NetIdForResolvFunctionType)(unsigned);
39 
40 // These variables are only modified at startup (when libc.so is loaded) and never afterwards, so
41 // it's okay that they are read later at runtime without a lock.
42 Accept4FunctionType libcAccept4 = 0;
43 ConnectFunctionType libcConnect = 0;
44 SocketFunctionType libcSocket = 0;
45 
closeFdAndSetErrno(int fd,int error)46 int closeFdAndSetErrno(int fd, int error) {
47     close(fd);
48     errno = -error;
49     return -1;
50 }
51 
netdClientAccept4(int sockfd,sockaddr * addr,socklen_t * addrlen,int flags)52 int netdClientAccept4(int sockfd, sockaddr* addr, socklen_t* addrlen, int flags) {
53     int acceptedSocket = libcAccept4(sockfd, addr, addrlen, flags);
54     if (acceptedSocket == -1) {
55         return -1;
56     }
57     int family;
58     if (addr) {
59         family = addr->sa_family;
60     } else {
61         socklen_t familyLen = sizeof(family);
62         if (getsockopt(acceptedSocket, SOL_SOCKET, SO_DOMAIN, &family, &familyLen) == -1) {
63             return closeFdAndSetErrno(acceptedSocket, -errno);
64         }
65     }
66     if (FwmarkClient::shouldSetFwmark(family)) {
67         FwmarkCommand command = {FwmarkCommand::ON_ACCEPT, 0, 0};
68         if (int error = FwmarkClient().send(&command, acceptedSocket)) {
69             return closeFdAndSetErrno(acceptedSocket, error);
70         }
71     }
72     return acceptedSocket;
73 }
74 
netdClientConnect(int sockfd,const sockaddr * addr,socklen_t addrlen)75 int netdClientConnect(int sockfd, const sockaddr* addr, socklen_t addrlen) {
76     if (sockfd >= 0 && addr && FwmarkClient::shouldSetFwmark(addr->sa_family)) {
77         FwmarkCommand command = {FwmarkCommand::ON_CONNECT, 0, 0};
78         if (int error = FwmarkClient().send(&command, sockfd)) {
79             errno = -error;
80             return -1;
81         }
82     }
83     return libcConnect(sockfd, addr, addrlen);
84 }
85 
netdClientSocket(int domain,int type,int protocol)86 int netdClientSocket(int domain, int type, int protocol) {
87     int socketFd = libcSocket(domain, type, protocol);
88     if (socketFd == -1) {
89         return -1;
90     }
91     unsigned netId = netIdForProcess;
92     if (netId != NETID_UNSET && FwmarkClient::shouldSetFwmark(domain)) {
93         if (int error = setNetworkForSocket(netId, socketFd)) {
94             return closeFdAndSetErrno(socketFd, error);
95         }
96     }
97     return socketFd;
98 }
99 
getNetworkForResolv(unsigned netId)100 unsigned 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 
setNetworkForTarget(unsigned netId,std::atomic_uint * target)111 int setNetworkForTarget(unsigned netId, std::atomic_uint* target) {
112     if (netId == NETID_UNSET) {
113         *target = netId;
114         return 0;
115     }
116     // Verify that we are allowed to use |netId|, by creating a socket and trying to have it marked
117     // 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 | SOCK_CLOEXEC, 0);
122     } else {
123         socketFd = socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0);
124     }
125     if (socketFd < 0) {
126         return -errno;
127     }
128     int error = setNetworkForSocket(netId, socketFd);
129     if (!error) {
130         *target = netId;
131     }
132     close(socketFd);
133     return error;
134 }
135 
136 }  // namespace
137 
138 // accept() just calls accept4(..., 0), so there's no need to handle accept() separately.
netdClientInitAccept4(Accept4FunctionType * function)139 extern "C" void netdClientInitAccept4(Accept4FunctionType* function) {
140     if (function && *function) {
141         libcAccept4 = *function;
142         *function = netdClientAccept4;
143     }
144 }
145 
netdClientInitConnect(ConnectFunctionType * function)146 extern "C" void netdClientInitConnect(ConnectFunctionType* function) {
147     if (function && *function) {
148         libcConnect = *function;
149         *function = netdClientConnect;
150     }
151 }
152 
netdClientInitSocket(SocketFunctionType * function)153 extern "C" void netdClientInitSocket(SocketFunctionType* function) {
154     if (function && *function) {
155         libcSocket = *function;
156         *function = netdClientSocket;
157     }
158 }
159 
netdClientInitNetIdForResolv(NetIdForResolvFunctionType * function)160 extern "C" void netdClientInitNetIdForResolv(NetIdForResolvFunctionType* function) {
161     if (function) {
162         *function = getNetworkForResolv;
163     }
164 }
165 
getNetworkForSocket(unsigned * netId,int socketFd)166 extern "C" int getNetworkForSocket(unsigned* netId, int socketFd) {
167     if (!netId || socketFd < 0) {
168         return -EBADF;
169     }
170     Fwmark fwmark;
171     socklen_t fwmarkLen = sizeof(fwmark.intValue);
172     if (getsockopt(socketFd, SOL_SOCKET, SO_MARK, &fwmark.intValue, &fwmarkLen) == -1) {
173         return -errno;
174     }
175     *netId = fwmark.netId;
176     return 0;
177 }
178 
getNetworkForProcess()179 extern "C" unsigned getNetworkForProcess() {
180     return netIdForProcess;
181 }
182 
setNetworkForSocket(unsigned netId,int socketFd)183 extern "C" int setNetworkForSocket(unsigned netId, int socketFd) {
184     if (socketFd < 0) {
185         return -EBADF;
186     }
187     FwmarkCommand command = {FwmarkCommand::SELECT_NETWORK, netId, 0};
188     return FwmarkClient().send(&command, socketFd);
189 }
190 
setNetworkForProcess(unsigned netId)191 extern "C" int setNetworkForProcess(unsigned netId) {
192     return setNetworkForTarget(netId, &netIdForProcess);
193 }
194 
setNetworkForResolv(unsigned netId)195 extern "C" int setNetworkForResolv(unsigned netId) {
196     return setNetworkForTarget(netId, &netIdForResolv);
197 }
198 
protectFromVpn(int socketFd)199 extern "C" int protectFromVpn(int socketFd) {
200     if (socketFd < 0) {
201         return -EBADF;
202     }
203     FwmarkCommand command = {FwmarkCommand::PROTECT_FROM_VPN, 0, 0};
204     return FwmarkClient().send(&command, socketFd);
205 }
206 
setNetworkForUser(uid_t uid,int socketFd)207 extern "C" int setNetworkForUser(uid_t uid, int socketFd) {
208     if (socketFd < 0) {
209         return -EBADF;
210     }
211     FwmarkCommand command = {FwmarkCommand::SELECT_FOR_USER, 0, uid};
212     return FwmarkClient().send(&command, socketFd);
213 }
214 
queryUserAccess(uid_t uid,unsigned netId)215 extern "C" int queryUserAccess(uid_t uid, unsigned netId) {
216     FwmarkCommand command = {FwmarkCommand::QUERY_USER_ACCESS, netId, uid};
217     return FwmarkClient().send(&command, -1);
218 }
219