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 <arpa/inet.h>
     20 #include <errno.h>
     21 #include <math.h>
     22 #include <sys/socket.h>
     23 #include <unistd.h>
     24 
     25 #include <atomic>
     26 
     27 #include "Fwmark.h"
     28 #include "FwmarkClient.h"
     29 #include "FwmarkCommand.h"
     30 #include "resolv_netid.h"
     31 #include "Stopwatch.h"
     32 
     33 namespace {
     34 
     35 std::atomic_uint netIdForProcess(NETID_UNSET);
     36 std::atomic_uint netIdForResolv(NETID_UNSET);
     37 
     38 typedef int (*Accept4FunctionType)(int, sockaddr*, socklen_t*, int);
     39 typedef int (*ConnectFunctionType)(int, const sockaddr*, socklen_t);
     40 typedef int (*SocketFunctionType)(int, int, int);
     41 typedef unsigned (*NetIdForResolvFunctionType)(unsigned);
     42 
     43 // These variables are only modified at startup (when libc.so is loaded) and never afterwards, so
     44 // it's okay that they are read later at runtime without a lock.
     45 Accept4FunctionType libcAccept4 = 0;
     46 ConnectFunctionType libcConnect = 0;
     47 SocketFunctionType libcSocket = 0;
     48 
     49 int closeFdAndSetErrno(int fd, int error) {
     50     close(fd);
     51     errno = -error;
     52     return -1;
     53 }
     54 
     55 int netdClientAccept4(int sockfd, sockaddr* addr, socklen_t* addrlen, int flags) {
     56     int acceptedSocket = libcAccept4(sockfd, addr, addrlen, flags);
     57     if (acceptedSocket == -1) {
     58         return -1;
     59     }
     60     int family;
     61     if (addr) {
     62         family = addr->sa_family;
     63     } else {
     64         socklen_t familyLen = sizeof(family);
     65         if (getsockopt(acceptedSocket, SOL_SOCKET, SO_DOMAIN, &family, &familyLen) == -1) {
     66             return closeFdAndSetErrno(acceptedSocket, -errno);
     67         }
     68     }
     69     if (FwmarkClient::shouldSetFwmark(family)) {
     70         FwmarkCommand command = {FwmarkCommand::ON_ACCEPT, 0, 0, 0};
     71         if (int error = FwmarkClient().send(&command, acceptedSocket, nullptr)) {
     72             return closeFdAndSetErrno(acceptedSocket, error);
     73         }
     74     }
     75     return acceptedSocket;
     76 }
     77 
     78 int netdClientConnect(int sockfd, const sockaddr* addr, socklen_t addrlen) {
     79     const bool shouldSetFwmark = (sockfd >= 0) && addr
     80             && FwmarkClient::shouldSetFwmark(addr->sa_family);
     81     if (shouldSetFwmark) {
     82         FwmarkCommand command = {FwmarkCommand::ON_CONNECT, 0, 0, 0};
     83         if (int error = FwmarkClient().send(&command, sockfd, nullptr)) {
     84             errno = -error;
     85             return -1;
     86         }
     87     }
     88     // Latency measurement does not include time of sending commands to Fwmark
     89     Stopwatch s;
     90     const int ret = libcConnect(sockfd, addr, addrlen);
     91     // Save errno so it isn't clobbered by sending ON_CONNECT_COMPLETE
     92     const int connectErrno = errno;
     93     const unsigned latencyMs = lround(s.timeTaken());
     94     // Send an ON_CONNECT_COMPLETE command that includes sockaddr and connect latency for reporting
     95     if (shouldSetFwmark && FwmarkClient::shouldReportConnectComplete(addr->sa_family)) {
     96         FwmarkConnectInfo connectInfo(ret == 0 ? 0 : connectErrno, latencyMs, addr);
     97         // TODO: get the netId from the socket mark once we have continuous benchmark runs
     98         FwmarkCommand command = {FwmarkCommand::ON_CONNECT_COMPLETE, /* netId (ignored) */ 0,
     99                                  /* uid (filled in by the server) */ 0, 0};
    100         // Ignore return value since it's only used for logging
    101         FwmarkClient().send(&command, sockfd, &connectInfo);
    102     }
    103     errno = connectErrno;
    104     return ret;
    105 }
    106 
    107 int netdClientSocket(int domain, int type, int protocol) {
    108     int socketFd = libcSocket(domain, type, protocol);
    109     if (socketFd == -1) {
    110         return -1;
    111     }
    112     unsigned netId = netIdForProcess;
    113     if (netId != NETID_UNSET && FwmarkClient::shouldSetFwmark(domain)) {
    114         if (int error = setNetworkForSocket(netId, socketFd)) {
    115             return closeFdAndSetErrno(socketFd, error);
    116         }
    117     }
    118     return socketFd;
    119 }
    120 
    121 unsigned getNetworkForResolv(unsigned netId) {
    122     if (netId != NETID_UNSET) {
    123         return netId;
    124     }
    125     // Special case for DNS-over-TLS bypass; b/72345192 .
    126     if ((netIdForResolv & ~NETID_USE_LOCAL_NAMESERVERS) != NETID_UNSET) {
    127         return netIdForResolv;
    128     }
    129     netId = netIdForProcess;
    130     if (netId != NETID_UNSET) {
    131         return netId;
    132     }
    133     return netIdForResolv;
    134 }
    135 
    136 int setNetworkForTarget(unsigned netId, std::atomic_uint* target) {
    137     const unsigned requestedNetId = netId;
    138     netId &= ~NETID_USE_LOCAL_NAMESERVERS;
    139 
    140     if (netId == NETID_UNSET) {
    141         *target = netId;
    142         return 0;
    143     }
    144     // Verify that we are allowed to use |netId|, by creating a socket and trying to have it marked
    145     // with the netId. Call libcSocket() directly; else the socket creation (via netdClientSocket())
    146     // might itself cause another check with the fwmark server, which would be wasteful.
    147     int socketFd;
    148     if (libcSocket) {
    149         socketFd = libcSocket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0);
    150     } else {
    151         socketFd = socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0);
    152     }
    153     if (socketFd < 0) {
    154         return -errno;
    155     }
    156     int error = setNetworkForSocket(netId, socketFd);
    157     if (!error) {
    158         *target = (target == &netIdForResolv) ? requestedNetId : netId;
    159     }
    160     close(socketFd);
    161     return error;
    162 }
    163 
    164 }  // namespace
    165 
    166 // accept() just calls accept4(..., 0), so there's no need to handle accept() separately.
    167 extern "C" void netdClientInitAccept4(Accept4FunctionType* function) {
    168     if (function && *function) {
    169         libcAccept4 = *function;
    170         *function = netdClientAccept4;
    171     }
    172 }
    173 
    174 extern "C" void netdClientInitConnect(ConnectFunctionType* function) {
    175     if (function && *function) {
    176         libcConnect = *function;
    177         *function = netdClientConnect;
    178     }
    179 }
    180 
    181 extern "C" void netdClientInitSocket(SocketFunctionType* function) {
    182     if (function && *function) {
    183         libcSocket = *function;
    184         *function = netdClientSocket;
    185     }
    186 }
    187 
    188 extern "C" void netdClientInitNetIdForResolv(NetIdForResolvFunctionType* function) {
    189     if (function) {
    190         *function = getNetworkForResolv;
    191     }
    192 }
    193 
    194 extern "C" int getNetworkForSocket(unsigned* netId, int socketFd) {
    195     if (!netId || socketFd < 0) {
    196         return -EBADF;
    197     }
    198     Fwmark fwmark;
    199     socklen_t fwmarkLen = sizeof(fwmark.intValue);
    200     if (getsockopt(socketFd, SOL_SOCKET, SO_MARK, &fwmark.intValue, &fwmarkLen) == -1) {
    201         return -errno;
    202     }
    203     *netId = fwmark.netId;
    204     return 0;
    205 }
    206 
    207 extern "C" unsigned getNetworkForProcess() {
    208     return netIdForProcess;
    209 }
    210 
    211 extern "C" int setNetworkForSocket(unsigned netId, int socketFd) {
    212     if (socketFd < 0) {
    213         return -EBADF;
    214     }
    215     FwmarkCommand command = {FwmarkCommand::SELECT_NETWORK, netId, 0, 0};
    216     return FwmarkClient().send(&command, socketFd, nullptr);
    217 }
    218 
    219 extern "C" int setNetworkForProcess(unsigned netId) {
    220     return setNetworkForTarget(netId, &netIdForProcess);
    221 }
    222 
    223 extern "C" int setNetworkForResolv(unsigned netId) {
    224     return setNetworkForTarget(netId, &netIdForResolv);
    225 }
    226 
    227 extern "C" int protectFromVpn(int socketFd) {
    228     if (socketFd < 0) {
    229         return -EBADF;
    230     }
    231     FwmarkCommand command = {FwmarkCommand::PROTECT_FROM_VPN, 0, 0, 0};
    232     return FwmarkClient().send(&command, socketFd, nullptr);
    233 }
    234 
    235 extern "C" int setNetworkForUser(uid_t uid, int socketFd) {
    236     if (socketFd < 0) {
    237         return -EBADF;
    238     }
    239     FwmarkCommand command = {FwmarkCommand::SELECT_FOR_USER, 0, uid, 0};
    240     return FwmarkClient().send(&command, socketFd, nullptr);
    241 }
    242 
    243 extern "C" int queryUserAccess(uid_t uid, unsigned netId) {
    244     FwmarkCommand command = {FwmarkCommand::QUERY_USER_ACCESS, netId, uid, 0};
    245     return FwmarkClient().send(&command, -1, nullptr);
    246 }
    247 
    248 extern "C" int tagSocket(int socketFd, uint32_t tag, uid_t uid) {
    249     FwmarkCommand command = {FwmarkCommand::TAG_SOCKET, 0, uid, tag};
    250     return FwmarkClient().send(&command, socketFd, nullptr);
    251 }
    252 
    253 extern "C" int untagSocket(int socketFd) {
    254     FwmarkCommand command = {FwmarkCommand::UNTAG_SOCKET, 0, 0, 0};
    255     return FwmarkClient().send(&command, socketFd, nullptr);
    256 }
    257 
    258 extern "C" int setCounterSet(uint32_t counterSet, uid_t uid) {
    259     FwmarkCommand command = {FwmarkCommand::SET_COUNTERSET, 0, uid, counterSet};
    260     return FwmarkClient().send(&command, -1, nullptr);
    261 }
    262 
    263 extern "C" int deleteTagData(uint32_t tag, uid_t uid) {
    264     FwmarkCommand command = {FwmarkCommand::DELETE_TAGDATA, 0, uid, tag};
    265     return FwmarkClient().send(&command, -1, nullptr);
    266 }
    267