NetdClient.cpp revision efbe05d203f2f1cc3c24ddc111be159a1ff1f292
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 "FwmarkClient.h" 20#include "FwmarkCommand.h" 21#include "resolv_netid.h" 22 23#include <sys/socket.h> 24#include <unistd.h> 25 26namespace { 27 28int closeFdAndRestoreErrno(int fd) { 29 int error = errno; 30 close(fd); 31 errno = error; 32 return -1; 33} 34 35typedef int (*ConnectFunctionType)(int, const sockaddr*, socklen_t); 36typedef int (*AcceptFunctionType)(int, sockaddr*, socklen_t*); 37typedef unsigned (*NetIdForResolvFunctionType)(unsigned); 38 39// These variables are only modified at startup (when libc.so is loaded) and never afterwards, so 40// it's okay that they are read later at runtime without a lock. 41ConnectFunctionType libcConnect = 0; 42AcceptFunctionType libcAccept = 0; 43 44int netdClientConnect(int sockfd, const sockaddr* addr, socklen_t addrlen) { 45 if (FwmarkClient::shouldSetFwmark(sockfd, addr)) { 46 FwmarkCommand command = {FwmarkCommand::ON_CONNECT, 0}; 47 if (!FwmarkClient().send(&command, sizeof(command), sockfd)) { 48 return -1; 49 } 50 } 51 return libcConnect(sockfd, addr, addrlen); 52} 53 54int netdClientAccept(int sockfd, sockaddr* addr, socklen_t* addrlen) { 55 int acceptedSocket = libcAccept(sockfd, addr, addrlen); 56 if (acceptedSocket == -1) { 57 return -1; 58 } 59 sockaddr socketAddress; 60 if (!addr) { 61 socklen_t socketAddressLen = sizeof(socketAddress); 62 if (getsockname(acceptedSocket, &socketAddress, &socketAddressLen) == -1) { 63 return closeFdAndRestoreErrno(acceptedSocket); 64 } 65 addr = &socketAddress; 66 } 67 if (FwmarkClient::shouldSetFwmark(acceptedSocket, addr)) { 68 FwmarkCommand command = {FwmarkCommand::ON_ACCEPT, 0}; 69 if (!FwmarkClient().send(&command, sizeof(command), acceptedSocket)) { 70 return closeFdAndRestoreErrno(acceptedSocket); 71 } 72 } 73 return acceptedSocket; 74} 75 76// TODO: Convert to C++11 std::atomic<unsigned>. 77volatile sig_atomic_t netIdForProcess = NETID_UNSET; 78volatile sig_atomic_t netIdForResolv = NETID_UNSET; 79 80unsigned getNetworkForResolv(unsigned netId) { 81 if (netId != NETID_UNSET) { 82 return netId; 83 } 84 netId = netIdForProcess; 85 if (netId != NETID_UNSET) { 86 return netId; 87 } 88 return netIdForResolv; 89} 90 91bool setNetworkForTarget(unsigned netId, volatile sig_atomic_t* target) { 92 if (netId == NETID_UNSET) { 93 *target = netId; 94 return true; 95 } 96 // Verify that we are allowed to use |netId|, by creating a socket and trying to have it marked 97 // with the netId. Don't create an AF_INET socket, because then the creation itself might cause 98 // another check with the fwmark server (see netdClientSocket()), which would be wasteful. 99 int socketFd = socket(AF_UNIX, SOCK_DGRAM, 0); 100 if (socketFd < 0) { 101 return false; 102 } 103 bool status = setNetworkForSocket(netId, socketFd); 104 closeFdAndRestoreErrno(socketFd); 105 if (status) { 106 *target = netId; 107 } 108 return status; 109} 110 111} // namespace 112 113extern "C" void netdClientInitConnect(ConnectFunctionType* function) { 114 if (function && *function) { 115 libcConnect = *function; 116 *function = netdClientConnect; 117 } 118} 119 120extern "C" void netdClientInitAccept(AcceptFunctionType* function) { 121 if (function && *function) { 122 libcAccept = *function; 123 *function = netdClientAccept; 124 } 125} 126 127extern "C" void netdClientInitNetIdForResolv(NetIdForResolvFunctionType* function) { 128 if (function) { 129 *function = getNetworkForResolv; 130 } 131} 132 133extern "C" unsigned getNetworkForProcess() { 134 return netIdForProcess; 135} 136 137extern "C" bool setNetworkForSocket(unsigned netId, int socketFd) { 138 if (socketFd < 0) { 139 errno = EBADF; 140 return false; 141 } 142 FwmarkCommand command = {FwmarkCommand::SELECT_NETWORK, netId}; 143 return FwmarkClient().send(&command, sizeof(command), socketFd); 144} 145 146extern "C" bool setNetworkForProcess(unsigned netId) { 147 return setNetworkForTarget(netId, &netIdForProcess); 148} 149 150extern "C" bool setNetworkForResolv(unsigned netId) { 151 return setNetworkForTarget(netId, &netIdForResolv); 152} 153