OSDN Git Service

DO NOT MERGE Move Stopwatch into its own header
[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 #include "Stopwatch.h"
30
31 namespace {
32
33 std::atomic_uint netIdForProcess(NETID_UNSET);
34 std::atomic_uint netIdForResolv(NETID_UNSET);
35
36 typedef int (*Accept4FunctionType)(int, sockaddr*, socklen_t*, int);
37 typedef int (*ConnectFunctionType)(int, const sockaddr*, socklen_t);
38 typedef int (*SocketFunctionType)(int, int, int);
39 typedef 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.
43 Accept4FunctionType libcAccept4 = 0;
44 ConnectFunctionType libcConnect = 0;
45 SocketFunctionType libcSocket = 0;
46
47 int closeFdAndSetErrno(int fd, int error) {
48     close(fd);
49     errno = -error;
50     return -1;
51 }
52
53 int netdClientAccept4(int sockfd, sockaddr* addr, socklen_t* addrlen, int flags) {
54     int acceptedSocket = libcAccept4(sockfd, addr, addrlen, flags);
55     if (acceptedSocket == -1) {
56         return -1;
57     }
58     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) {
64             return closeFdAndSetErrno(acceptedSocket, -errno);
65         }
66     }
67     if (FwmarkClient::shouldSetFwmark(family)) {
68         FwmarkCommand command = {FwmarkCommand::ON_ACCEPT, 0, 0};
69         if (int error = FwmarkClient().send(&command, acceptedSocket)) {
70             return closeFdAndSetErrno(acceptedSocket, error);
71         }
72     }
73     return acceptedSocket;
74 }
75
76 int netdClientConnect(int sockfd, const sockaddr* addr, socklen_t addrlen) {
77     if (sockfd >= 0 && addr && FwmarkClient::shouldSetFwmark(addr->sa_family)) {
78         FwmarkCommand command = {FwmarkCommand::ON_CONNECT, 0, 0};
79         if (int error = FwmarkClient().send(&command, sockfd)) {
80             errno = -error;
81             return -1;
82         }
83     }
84     return libcConnect(sockfd, addr, addrlen);
85 }
86
87 int 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)) {
94         if (int error = setNetworkForSocket(netId, socketFd)) {
95             return closeFdAndSetErrno(socketFd, error);
96         }
97     }
98     return socketFd;
99 }
100
101 unsigned 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
112 int setNetworkForTarget(unsigned netId, std::atomic_uint* target) {
113     if (netId == NETID_UNSET) {
114         *target = netId;
115         return 0;
116     }
117     // Verify that we are allowed to use |netId|, by creating a socket and trying to have it marked
118     // 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) {
122         socketFd = libcSocket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0);
123     } else {
124         socketFd = socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0);
125     }
126     if (socketFd < 0) {
127         return -errno;
128     }
129     int error = setNetworkForSocket(netId, socketFd);
130     if (!error) {
131         *target = netId;
132     }
133     close(socketFd);
134     return error;
135 }
136
137 }  // namespace
138
139 // accept() just calls accept4(..., 0), so there's no need to handle accept() separately.
140 extern "C" void netdClientInitAccept4(Accept4FunctionType* function) {
141     if (function && *function) {
142         libcAccept4 = *function;
143         *function = netdClientAccept4;
144     }
145 }
146
147 extern "C" void netdClientInitConnect(ConnectFunctionType* function) {
148     if (function && *function) {
149         libcConnect = *function;
150         *function = netdClientConnect;
151     }
152 }
153
154 extern "C" void netdClientInitSocket(SocketFunctionType* function) {
155     if (function && *function) {
156         libcSocket = *function;
157         *function = netdClientSocket;
158     }
159 }
160
161 extern "C" void netdClientInitNetIdForResolv(NetIdForResolvFunctionType* function) {
162     if (function) {
163         *function = getNetworkForResolv;
164     }
165 }
166
167 extern "C" int getNetworkForSocket(unsigned* netId, int socketFd) {
168     if (!netId || socketFd < 0) {
169         return -EBADF;
170     }
171     Fwmark fwmark;
172     socklen_t fwmarkLen = sizeof(fwmark.intValue);
173     if (getsockopt(socketFd, SOL_SOCKET, SO_MARK, &fwmark.intValue, &fwmarkLen) == -1) {
174         return -errno;
175     }
176     *netId = fwmark.netId;
177     return 0;
178 }
179
180 extern "C" unsigned getNetworkForProcess() {
181     return netIdForProcess;
182 }
183
184 extern "C" int setNetworkForSocket(unsigned netId, int socketFd) {
185     if (socketFd < 0) {
186         return -EBADF;
187     }
188     FwmarkCommand command = {FwmarkCommand::SELECT_NETWORK, netId, 0};
189     return FwmarkClient().send(&command, socketFd);
190 }
191
192 extern "C" int setNetworkForProcess(unsigned netId) {
193     return setNetworkForTarget(netId, &netIdForProcess);
194 }
195
196 extern "C" int setNetworkForResolv(unsigned netId) {
197     return setNetworkForTarget(netId, &netIdForResolv);
198 }
199
200 extern "C" int protectFromVpn(int socketFd) {
201     if (socketFd < 0) {
202         return -EBADF;
203     }
204     FwmarkCommand command = {FwmarkCommand::PROTECT_FROM_VPN, 0, 0};
205     return FwmarkClient().send(&command, socketFd);
206 }
207
208 extern "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};
213     return FwmarkClient().send(&command, socketFd);
214 }
215
216 extern "C" int queryUserAccess(uid_t uid, unsigned netId) {
217     FwmarkCommand command = {FwmarkCommand::QUERY_USER_ACCESS, netId, uid};
218     return FwmarkClient().send(&command, -1);
219 }