Home | History | Annotate | Download | only in client
      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 
     30 namespace {
     31 
     32 std::atomic_uint netIdForProcess(NETID_UNSET);
     33 std::atomic_uint netIdForResolv(NETID_UNSET);
     34 
     35 typedef int (*Accept4FunctionType)(int, sockaddr*, socklen_t*, int);
     36 typedef int (*ConnectFunctionType)(int, const sockaddr*, socklen_t);
     37 typedef int (*SocketFunctionType)(int, int, int);
     38 typedef unsigned (*NetIdForResolvFunctionType)(unsigned);
     39 
     40 // These variables are only modified at startup (when libc.so is loaded) and never afterwards, so
     41 // it's okay that they are read later at runtime without a lock.
     42 Accept4FunctionType libcAccept4 = 0;
     43 ConnectFunctionType libcConnect = 0;
     44 SocketFunctionType libcSocket = 0;
     45 
     46 int closeFdAndSetErrno(int fd, int error) {
     47     close(fd);
     48     errno = -error;
     49     return -1;
     50 }
     51 
     52 int netdClientAccept4(int sockfd, sockaddr* addr, socklen_t* addrlen, int flags) {
     53     int acceptedSocket = libcAccept4(sockfd, addr, addrlen, flags);
     54     if (acceptedSocket == -1) {
     55         return -1;
     56     }
     57     int family;
     58     if (addr) {
     59         family = addr->sa_family;
     60     } else {
     61         socklen_t familyLen = sizeof(family);
     62         if (getsockopt(acceptedSocket, SOL_SOCKET, SO_DOMAIN, &family, &familyLen) == -1) {
     63             return closeFdAndSetErrno(acceptedSocket, -errno);
     64         }
     65     }
     66     if (FwmarkClient::shouldSetFwmark(family)) {
     67         FwmarkCommand command = {FwmarkCommand::ON_ACCEPT, 0, 0};
     68         if (int error = FwmarkClient().send(&command, acceptedSocket)) {
     69             return closeFdAndSetErrno(acceptedSocket, error);
     70         }
     71     }
     72     return acceptedSocket;
     73 }
     74 
     75 int netdClientConnect(int sockfd, const sockaddr* addr, socklen_t addrlen) {
     76     if (sockfd >= 0 && addr && FwmarkClient::shouldSetFwmark(addr->sa_family)) {
     77         FwmarkCommand command = {FwmarkCommand::ON_CONNECT, 0, 0};
     78         if (int error = FwmarkClient().send(&command, sockfd)) {
     79             errno = -error;
     80             return -1;
     81         }
     82     }
     83     return libcConnect(sockfd, addr, addrlen);
     84 }
     85 
     86 int 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         if (int error = setNetworkForSocket(netId, socketFd)) {
     94             return closeFdAndSetErrno(socketFd, error);
     95         }
     96     }
     97     return socketFd;
     98 }
     99 
    100 unsigned getNetworkForResolv(unsigned netId) {
    101     if (netId != NETID_UNSET) {
    102         return netId;
    103     }
    104     netId = netIdForProcess;
    105     if (netId != NETID_UNSET) {
    106         return netId;
    107     }
    108     return netIdForResolv;
    109 }
    110 
    111 int setNetworkForTarget(unsigned netId, std::atomic_uint* target) {
    112     if (netId == NETID_UNSET) {
    113         *target = netId;
    114         return 0;
    115     }
    116     // Verify that we are allowed to use |netId|, by creating a socket and trying to have it marked
    117     // with the netId. Call libcSocket() directly; else the socket creation (via netdClientSocket())
    118     // might itself cause another check with the fwmark server, which would be wasteful.
    119     int socketFd;
    120     if (libcSocket) {
    121         socketFd = libcSocket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0);
    122     } else {
    123         socketFd = socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0);
    124     }
    125     if (socketFd < 0) {
    126         return -errno;
    127     }
    128     int error = setNetworkForSocket(netId, socketFd);
    129     if (!error) {
    130         *target = netId;
    131     }
    132     close(socketFd);
    133     return error;
    134 }
    135 
    136 }  // namespace
    137 
    138 // accept() just calls accept4(..., 0), so there's no need to handle accept() separately.
    139 extern "C" void netdClientInitAccept4(Accept4FunctionType* function) {
    140     if (function && *function) {
    141         libcAccept4 = *function;
    142         *function = netdClientAccept4;
    143     }
    144 }
    145 
    146 extern "C" void netdClientInitConnect(ConnectFunctionType* function) {
    147     if (function && *function) {
    148         libcConnect = *function;
    149         *function = netdClientConnect;
    150     }
    151 }
    152 
    153 extern "C" void netdClientInitSocket(SocketFunctionType* function) {
    154     if (function && *function) {
    155         libcSocket = *function;
    156         *function = netdClientSocket;
    157     }
    158 }
    159 
    160 extern "C" void netdClientInitNetIdForResolv(NetIdForResolvFunctionType* function) {
    161     if (function) {
    162         *function = getNetworkForResolv;
    163     }
    164 }
    165 
    166 extern "C" int getNetworkForSocket(unsigned* netId, int socketFd) {
    167     if (!netId || socketFd < 0) {
    168         return -EBADF;
    169     }
    170     Fwmark fwmark;
    171     socklen_t fwmarkLen = sizeof(fwmark.intValue);
    172     if (getsockopt(socketFd, SOL_SOCKET, SO_MARK, &fwmark.intValue, &fwmarkLen) == -1) {
    173         return -errno;
    174     }
    175     *netId = fwmark.netId;
    176     return 0;
    177 }
    178 
    179 extern "C" unsigned getNetworkForProcess() {
    180     return netIdForProcess;
    181 }
    182 
    183 extern "C" int setNetworkForSocket(unsigned netId, int socketFd) {
    184     if (socketFd < 0) {
    185         return -EBADF;
    186     }
    187     FwmarkCommand command = {FwmarkCommand::SELECT_NETWORK, netId, 0};
    188     return FwmarkClient().send(&command, socketFd);
    189 }
    190 
    191 extern "C" int setNetworkForProcess(unsigned netId) {
    192     return setNetworkForTarget(netId, &netIdForProcess);
    193 }
    194 
    195 extern "C" int setNetworkForResolv(unsigned netId) {
    196     return setNetworkForTarget(netId, &netIdForResolv);
    197 }
    198 
    199 extern "C" int protectFromVpn(int socketFd) {
    200     if (socketFd < 0) {
    201         return -EBADF;
    202     }
    203     FwmarkCommand command = {FwmarkCommand::PROTECT_FROM_VPN, 0, 0};
    204     return FwmarkClient().send(&command, socketFd);
    205 }
    206 
    207 extern "C" int setNetworkForUser(uid_t uid, int socketFd) {
    208     if (socketFd < 0) {
    209         return -EBADF;
    210     }
    211     FwmarkCommand command = {FwmarkCommand::SELECT_FOR_USER, 0, uid};
    212     return FwmarkClient().send(&command, socketFd);
    213 }
    214 
    215 extern "C" int queryUserAccess(uid_t uid, unsigned netId) {
    216     FwmarkCommand command = {FwmarkCommand::QUERY_USER_ACCESS, netId, uid};
    217     return FwmarkClient().send(&command, -1);
    218 }
    219