NetdClient.cpp revision 4d4c8b7e294d845103ecb10f968713717a3e6406
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
28namespace {
29
30std::atomic_uint netIdForProcess(NETID_UNSET);
31std::atomic_uint netIdForResolv(NETID_UNSET);
32
33typedef int (*Accept4FunctionType)(int, sockaddr*, socklen_t*, int);
34typedef int (*ConnectFunctionType)(int, const sockaddr*, socklen_t);
35typedef int (*SocketFunctionType)(int, int, int);
36typedef 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.
40Accept4FunctionType libcAccept4 = 0;
41ConnectFunctionType libcConnect = 0;
42SocketFunctionType libcSocket = 0;
43
44int closeFdAndSetErrno(int fd, int error) {
45    close(fd);
46    errno = error;
47    return -1;
48}
49
50int 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};
66        int error = FwmarkClient().send(&command, sizeof(command), acceptedSocket);
67        if (error) {
68            return closeFdAndSetErrno(acceptedSocket, error);
69        }
70    }
71    return acceptedSocket;
72}
73
74int netdClientConnect(int sockfd, const sockaddr* addr, socklen_t addrlen) {
75    if (sockfd >= 0 && addr && FwmarkClient::shouldSetFwmark(addr->sa_family)) {
76        FwmarkCommand command = {FwmarkCommand::ON_CONNECT, 0};
77        int error = FwmarkClient().send(&command, sizeof(command), sockfd);
78        if (error) {
79            errno = error;
80            return -1;
81        }
82    }
83    return libcConnect(sockfd, addr, addrlen);
84}
85
86int 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        int error = setNetworkForSocket(netId, socketFd);
94        if (error) {
95            return closeFdAndSetErrno(socketFd, error);
96        }
97    }
98    return socketFd;
99}
100
101unsigned 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
112int 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, 0);
123    } else {
124        socketFd = socket(AF_INET6, SOCK_DGRAM, 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.
140extern "C" void netdClientInitAccept4(Accept4FunctionType* function) {
141    if (function && *function) {
142        libcAccept4 = *function;
143        *function = netdClientAccept4;
144    }
145}
146
147extern "C" void netdClientInitConnect(ConnectFunctionType* function) {
148    if (function && *function) {
149        libcConnect = *function;
150        *function = netdClientConnect;
151    }
152}
153
154extern "C" void netdClientInitSocket(SocketFunctionType* function) {
155    if (function && *function) {
156        libcSocket = *function;
157        *function = netdClientSocket;
158    }
159}
160
161extern "C" void netdClientInitNetIdForResolv(NetIdForResolvFunctionType* function) {
162    if (function) {
163        *function = getNetworkForResolv;
164    }
165}
166
167extern "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
180extern "C" unsigned getNetworkForProcess() {
181    return netIdForProcess;
182}
183
184extern "C" int setNetworkForSocket(unsigned netId, int socketFd) {
185    if (socketFd < 0) {
186        return EBADF;
187    }
188    FwmarkCommand command = {FwmarkCommand::SELECT_NETWORK, netId};
189    return FwmarkClient().send(&command, sizeof(command), socketFd);
190}
191
192extern "C" int setNetworkForProcess(unsigned netId) {
193    return setNetworkForTarget(netId, &netIdForProcess);
194}
195
196extern "C" int setNetworkForResolv(unsigned netId) {
197    return setNetworkForTarget(netId, &netIdForResolv);
198}
199
200extern "C" int protectFromVpn(int socketFd) {
201    if (socketFd < 0) {
202        return EBADF;
203    }
204    FwmarkCommand command = {FwmarkCommand::PROTECT_FROM_VPN, 0};
205    return FwmarkClient().send(&command, sizeof(command), socketFd);
206}
207