OSDN Git Service

am e25a378f: am 6a834abb: Merge "Reset connections whenever an address goes away...
[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 "Fwmark.h"
20 #include "FwmarkClient.h"
21 #include "FwmarkCommand.h"
22 #include "resolv_netid.h"
23
24 #include <atomic>
25 #include <sys/socket.h>
26 #include <unistd.h>
27
28 namespace {
29
30 std::atomic_uint netIdForProcess(NETID_UNSET);
31 std::atomic_uint netIdForResolv(NETID_UNSET);
32
33 typedef int (*Accept4FunctionType)(int, sockaddr*, socklen_t*, int);
34 typedef int (*ConnectFunctionType)(int, const sockaddr*, socklen_t);
35 typedef int (*SocketFunctionType)(int, int, int);
36 typedef 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.
40 Accept4FunctionType libcAccept4 = 0;
41 ConnectFunctionType libcConnect = 0;
42 SocketFunctionType libcSocket = 0;
43
44 int closeFdAndSetErrno(int fd, int error) {
45     close(fd);
46     errno = -error;
47     return -1;
48 }
49
50 int netdClientAccept4(int sockfd, sockaddr* addr, socklen_t* addrlen, int flags) {
51     int acceptedSocket = libcAccept4(sockfd, addr, addrlen, flags);
52     if (acceptedSocket == -1) {
53         return -1;
54     }
55     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) {
61             return closeFdAndSetErrno(acceptedSocket, -errno);
62         }
63     }
64     if (FwmarkClient::shouldSetFwmark(family)) {
65         FwmarkCommand command = {FwmarkCommand::ON_ACCEPT, 0, 0};
66         if (int error = FwmarkClient().send(&command, sizeof(command), acceptedSocket)) {
67             return closeFdAndSetErrno(acceptedSocket, error);
68         }
69     }
70     return acceptedSocket;
71 }
72
73 int 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, 0};
76         if (int error = FwmarkClient().send(&command, sizeof(command), sockfd)) {
77             errno = -error;
78             return -1;
79         }
80     }
81     return libcConnect(sockfd, addr, addrlen);
82 }
83
84 int 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)) {
91         if (int error = setNetworkForSocket(netId, socketFd)) {
92             return closeFdAndSetErrno(socketFd, error);
93         }
94     }
95     return socketFd;
96 }
97
98 unsigned 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
109 int setNetworkForTarget(unsigned netId, std::atomic_uint* target) {
110     if (netId == NETID_UNSET) {
111         *target = netId;
112         return 0;
113     }
114     // Verify that we are allowed to use |netId|, by creating a socket and trying to have it marked
115     // 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     }
123     if (socketFd < 0) {
124         return -errno;
125     }
126     int error = setNetworkForSocket(netId, socketFd);
127     if (!error) {
128         *target = netId;
129     }
130     close(socketFd);
131     return error;
132 }
133
134 }  // namespace
135
136 // accept() just calls accept4(..., 0), so there's no need to handle accept() separately.
137 extern "C" void netdClientInitAccept4(Accept4FunctionType* function) {
138     if (function && *function) {
139         libcAccept4 = *function;
140         *function = netdClientAccept4;
141     }
142 }
143
144 extern "C" void netdClientInitConnect(ConnectFunctionType* function) {
145     if (function && *function) {
146         libcConnect = *function;
147         *function = netdClientConnect;
148     }
149 }
150
151 extern "C" void netdClientInitSocket(SocketFunctionType* function) {
152     if (function && *function) {
153         libcSocket = *function;
154         *function = netdClientSocket;
155     }
156 }
157
158 extern "C" void netdClientInitNetIdForResolv(NetIdForResolvFunctionType* function) {
159     if (function) {
160         *function = getNetworkForResolv;
161     }
162 }
163
164 extern "C" int getNetworkForSocket(unsigned* netId, int socketFd) {
165     if (!netId || socketFd < 0) {
166         return -EBADF;
167     }
168     Fwmark fwmark;
169     socklen_t fwmarkLen = sizeof(fwmark.intValue);
170     if (getsockopt(socketFd, SOL_SOCKET, SO_MARK, &fwmark.intValue, &fwmarkLen) == -1) {
171         return -errno;
172     }
173     *netId = fwmark.netId;
174     return 0;
175 }
176
177 extern "C" unsigned getNetworkForProcess() {
178     return netIdForProcess;
179 }
180
181 extern "C" int setNetworkForSocket(unsigned netId, int socketFd) {
182     if (socketFd < 0) {
183         return -EBADF;
184     }
185     FwmarkCommand command = {FwmarkCommand::SELECT_NETWORK, netId, 0};
186     return FwmarkClient().send(&command, sizeof(command), socketFd);
187 }
188
189 extern "C" int setNetworkForProcess(unsigned netId) {
190     return setNetworkForTarget(netId, &netIdForProcess);
191 }
192
193 extern "C" int setNetworkForResolv(unsigned netId) {
194     return setNetworkForTarget(netId, &netIdForResolv);
195 }
196
197 extern "C" int protectFromVpn(int socketFd) {
198     if (socketFd < 0) {
199         return -EBADF;
200     }
201     FwmarkCommand command = {FwmarkCommand::PROTECT_FROM_VPN, 0, 0};
202     return FwmarkClient().send(&command, sizeof(command), socketFd);
203 }
204
205 extern "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};
210     return FwmarkClient().send(&command, sizeof(command), socketFd);
211 }