OSDN Git Service

netd: Trap dns calls
[android-x86/system-netd.git] / client / NetdClient.cpp
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 #ifdef USE_WRAPPER
31 #include "codeaurora/PropClientDispatch.h"
32 #endif
33
34 namespace {
35
36 std::atomic_uint netIdForProcess(NETID_UNSET);
37 std::atomic_uint netIdForResolv(NETID_UNSET);
38
39 typedef int (*Accept4FunctionType)(int, sockaddr*, socklen_t*, int);
40 typedef int (*ConnectFunctionType)(int, const sockaddr*, socklen_t);
41 typedef int (*SocketFunctionType)(int, int, int);
42 typedef unsigned (*NetIdForResolvFunctionType)(unsigned);
43
44 #ifdef USE_WRAPPER
45 typedef void (*SetConnectFunc) (ConnectFunctionType*);
46 #endif
47
48 // These variables are only modified at startup (when libc.so is loaded) and never afterwards, so
49 // it's okay that they are read later at runtime without a lock.
50 Accept4FunctionType libcAccept4 = 0;
51 ConnectFunctionType libcConnect = 0;
52 SocketFunctionType libcSocket = 0;
53
54 int closeFdAndSetErrno(int fd, int error) {
55     close(fd);
56     errno = -error;
57     return -1;
58 }
59
60 int netdClientAccept4(int sockfd, sockaddr* addr, socklen_t* addrlen, int flags) {
61     int acceptedSocket = libcAccept4(sockfd, addr, addrlen, flags);
62     if (acceptedSocket == -1) {
63         return -1;
64     }
65     int family;
66     if (addr) {
67         family = addr->sa_family;
68     } else {
69         socklen_t familyLen = sizeof(family);
70         if (getsockopt(acceptedSocket, SOL_SOCKET, SO_DOMAIN, &family, &familyLen) == -1) {
71             return closeFdAndSetErrno(acceptedSocket, -errno);
72         }
73     }
74     if (FwmarkClient::shouldSetFwmark(family)) {
75         FwmarkCommand command = {FwmarkCommand::ON_ACCEPT, 0, 0};
76         if (int error = FwmarkClient().send(&command, acceptedSocket)) {
77             return closeFdAndSetErrno(acceptedSocket, error);
78         }
79     }
80     return acceptedSocket;
81 }
82
83 int netdClientConnect(int sockfd, const sockaddr* addr, socklen_t addrlen) {
84     if (sockfd >= 0 && addr && FwmarkClient::shouldSetFwmark(addr->sa_family)) {
85         FwmarkCommand command = {FwmarkCommand::ON_CONNECT, 0, 0};
86         if (int error = FwmarkClient().send(&command, sockfd)) {
87             errno = -error;
88             return -1;
89         }
90     }
91
92 #ifdef USE_WRAPPER
93     if ( FwmarkClient::shouldSetFwmark(addr->sa_family)) {
94         if( __propClientDispatch.propConnect ) {
95             return __propClientDispatch.propConnect(sockfd, addr, addrlen);
96         } else {
97             return libcConnect(sockfd, addr, addrlen);
98         }
99     }
100 #endif
101     return libcConnect(sockfd, addr, addrlen);
102 }
103
104 int netdClientSocket(int domain, int type, int protocol) {
105
106     int socketFd;
107 #ifndef USE_WRAPPER
108     socketFd = libcSocket(domain, type, protocol);
109 #else
110     if( __propClientDispatch.propSocket ) {
111         socketFd = __propClientDispatch.propSocket(domain, type, protocol);
112     } else {
113         socketFd = libcSocket(domain, type, protocol);
114     }
115 #endif
116     if (socketFd == -1) {
117         return -1;
118     }
119     unsigned netId = netIdForProcess;
120     if (netId != NETID_UNSET && FwmarkClient::shouldSetFwmark(domain)) {
121         if (int error = setNetworkForSocket(netId, socketFd)) {
122             return closeFdAndSetErrno(socketFd, error);
123         }
124     }
125     return socketFd;
126 }
127
128 unsigned getNetworkForResolv(unsigned netId) {
129     if (netId != NETID_UNSET) {
130         return netId;
131     }
132     netId = netIdForProcess;
133     if (netId != NETID_UNSET) {
134         return netId;
135     }
136     return netIdForResolv;
137 }
138
139 int setNetworkForTarget(unsigned netId, std::atomic_uint* target) {
140     if (netId == NETID_UNSET) {
141         *target = netId;
142         return 0;
143     }
144     // Verify that we are allowed to use |netId|, by creating a socket and trying to have it marked
145     // with the netId. Call libcSocket() directly; else the socket creation (via netdClientSocket())
146     // might itself cause another check with the fwmark server, which would be wasteful.
147     int socketFd;
148     if (libcSocket) {
149         socketFd = libcSocket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0);
150     } else {
151         socketFd = socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0);
152     }
153     if (socketFd < 0) {
154         return -errno;
155     }
156     int error = setNetworkForSocket(netId, socketFd);
157     if (!error) {
158         *target = netId;
159     }
160     close(socketFd);
161     return error;
162 }
163
164 }  // namespace
165
166 // accept() just calls accept4(..., 0), so there's no need to handle accept() separately.
167 extern "C" void netdClientInitAccept4(Accept4FunctionType* function) {
168     if (function && *function) {
169         libcAccept4 = *function;
170         *function = netdClientAccept4;
171     }
172 }
173
174 extern "C" void netdClientInitConnect(ConnectFunctionType* function) {
175     if (function && *function) {
176         libcConnect = *function;
177         *function = netdClientConnect;
178     }
179 }
180
181 extern "C" void netdClientInitSocket(SocketFunctionType* function) {
182     if (function && *function) {
183         libcSocket = *function;
184         *function = netdClientSocket;
185     }
186 }
187
188 extern "C" void netdClientInitNetIdForResolv(NetIdForResolvFunctionType* function) {
189     if (function) {
190         *function = getNetworkForResolv;
191     }
192 }
193
194 extern "C" int getNetworkForSocket(unsigned* netId, int socketFd) {
195     if (!netId || socketFd < 0) {
196         return -EBADF;
197     }
198     Fwmark fwmark;
199     socklen_t fwmarkLen = sizeof(fwmark.intValue);
200     if (getsockopt(socketFd, SOL_SOCKET, SO_MARK, &fwmark.intValue, &fwmarkLen) == -1) {
201         return -errno;
202     }
203     *netId = fwmark.netId;
204     return 0;
205 }
206
207 extern "C" unsigned getNetworkForProcess() {
208     return netIdForProcess;
209 }
210
211 extern "C" int setNetworkForSocket(unsigned netId, int socketFd) {
212     if (socketFd < 0) {
213         return -EBADF;
214     }
215     FwmarkCommand command = {FwmarkCommand::SELECT_NETWORK, netId, 0};
216     return FwmarkClient().send(&command, socketFd);
217 }
218
219 extern "C" int setNetworkForProcess(unsigned netId) {
220     return setNetworkForTarget(netId, &netIdForProcess);
221 }
222
223 extern "C" int setNetworkForResolv(unsigned netId) {
224     return setNetworkForTarget(netId, &netIdForResolv);
225 }
226
227 extern "C" int protectFromVpn(int socketFd) {
228     if (socketFd < 0) {
229         return -EBADF;
230     }
231     FwmarkCommand command = {FwmarkCommand::PROTECT_FROM_VPN, 0, 0};
232     return FwmarkClient().send(&command, socketFd);
233 }
234
235 extern "C" int setNetworkForUser(uid_t uid, int socketFd) {
236     if (socketFd < 0) {
237         return -EBADF;
238     }
239     FwmarkCommand command = {FwmarkCommand::SELECT_FOR_USER, 0, uid};
240     return FwmarkClient().send(&command, socketFd);
241 }
242
243 extern "C" int queryUserAccess(uid_t uid, unsigned netId) {
244     FwmarkCommand command = {FwmarkCommand::QUERY_USER_ACCESS, netId, uid};
245     return FwmarkClient().send(&command, -1);
246 }