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