1f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram Ramachandran/*
2f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram Ramachandran * Copyright (C) 2014 The Android Open Source Project
3f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram Ramachandran *
4f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram Ramachandran * Licensed under the Apache License, Version 2.0 (the "License");
5f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram Ramachandran * you may not use this file except in compliance with the License.
6f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram Ramachandran * You may obtain a copy of the License at
7f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram Ramachandran *
8f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram Ramachandran *      http://www.apache.org/licenses/LICENSE-2.0
9f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram Ramachandran *
10f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram Ramachandran * Unless required by applicable law or agreed to in writing, software
11f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram Ramachandran * distributed under the License is distributed on an "AS IS" BASIS,
12f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram Ramachandran * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram Ramachandran * See the License for the specific language governing permissions and
14f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram Ramachandran * limitations under the License.
15f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram Ramachandran */
16f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram Ramachandran
17efbe05d203f2f1cc3c24ddc111be159a1ff1f292Sreeram Ramachandran#include "NetdClient.h"
18efbe05d203f2f1cc3c24ddc111be159a1ff1f292Sreeram Ramachandran
194b9b78aa02336de9291e5085401cef44c03c3bbaMichal Karpinski#include <arpa/inet.h>
20aa1be2b3d24d99f3ccb98ff4fbb2a81b63587effDan Albert#include <errno.h>
214b9b78aa02336de9291e5085401cef44c03c3bbaMichal Karpinski#include <math.h>
22aa1be2b3d24d99f3ccb98ff4fbb2a81b63587effDan Albert#include <sys/socket.h>
23aa1be2b3d24d99f3ccb98ff4fbb2a81b63587effDan Albert#include <unistd.h>
24aa1be2b3d24d99f3ccb98ff4fbb2a81b63587effDan Albert
25aa1be2b3d24d99f3ccb98ff4fbb2a81b63587effDan Albert#include <atomic>
26aa1be2b3d24d99f3ccb98ff4fbb2a81b63587effDan Albert
274d4c8b7e294d845103ecb10f968713717a3e6406Sreeram Ramachandran#include "Fwmark.h"
28f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram Ramachandran#include "FwmarkClient.h"
29f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram Ramachandran#include "FwmarkCommand.h"
30efbe05d203f2f1cc3c24ddc111be159a1ff1f292Sreeram Ramachandran#include "resolv_netid.h"
31cc544162e08dd0df271cd77a3f2c85dbaaa461e2Robin Lee#include "Stopwatch.h"
32f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram Ramachandran
33f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram Ramachandrannamespace {
34f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram Ramachandran
359fa2b130d86fa74eefdb847cf9694059205fd4cbSreeram Ramachandranstd::atomic_uint netIdForProcess(NETID_UNSET);
369fa2b130d86fa74eefdb847cf9694059205fd4cbSreeram Ramachandranstd::atomic_uint netIdForResolv(NETID_UNSET);
37f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram Ramachandran
385fc275794ab41d110abbdb7683ed9db45918985fSreeram Ramachandrantypedef int (*Accept4FunctionType)(int, sockaddr*, socklen_t*, int);
39f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram Ramachandrantypedef int (*ConnectFunctionType)(int, const sockaddr*, socklen_t);
405fc275794ab41d110abbdb7683ed9db45918985fSreeram Ramachandrantypedef int (*SocketFunctionType)(int, int, int);
41efbe05d203f2f1cc3c24ddc111be159a1ff1f292Sreeram Ramachandrantypedef unsigned (*NetIdForResolvFunctionType)(unsigned);
42f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram Ramachandran
43efbe05d203f2f1cc3c24ddc111be159a1ff1f292Sreeram Ramachandran// These variables are only modified at startup (when libc.so is loaded) and never afterwards, so
44efbe05d203f2f1cc3c24ddc111be159a1ff1f292Sreeram Ramachandran// it's okay that they are read later at runtime without a lock.
455fc275794ab41d110abbdb7683ed9db45918985fSreeram RamachandranAccept4FunctionType libcAccept4 = 0;
46f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram RamachandranConnectFunctionType libcConnect = 0;
475fc275794ab41d110abbdb7683ed9db45918985fSreeram RamachandranSocketFunctionType libcSocket = 0;
48f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram Ramachandran
4931f4210e6fc5c9b749468a2af0bac94992352010Sreeram Ramachandranint closeFdAndSetErrno(int fd, int error) {
505fc275794ab41d110abbdb7683ed9db45918985fSreeram Ramachandran    close(fd);
513a069e6a76752a0ee73c60f276ae362d1c01467fSreeram Ramachandran    errno = -error;
525fc275794ab41d110abbdb7683ed9db45918985fSreeram Ramachandran    return -1;
53f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram Ramachandran}
54f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram Ramachandran
555fc275794ab41d110abbdb7683ed9db45918985fSreeram Ramachandranint netdClientAccept4(int sockfd, sockaddr* addr, socklen_t* addrlen, int flags) {
565fc275794ab41d110abbdb7683ed9db45918985fSreeram Ramachandran    int acceptedSocket = libcAccept4(sockfd, addr, addrlen, flags);
57f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram Ramachandran    if (acceptedSocket == -1) {
58f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram Ramachandran        return -1;
59f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram Ramachandran    }
605fc275794ab41d110abbdb7683ed9db45918985fSreeram Ramachandran    int family;
615fc275794ab41d110abbdb7683ed9db45918985fSreeram Ramachandran    if (addr) {
625fc275794ab41d110abbdb7683ed9db45918985fSreeram Ramachandran        family = addr->sa_family;
635fc275794ab41d110abbdb7683ed9db45918985fSreeram Ramachandran    } else {
645fc275794ab41d110abbdb7683ed9db45918985fSreeram Ramachandran        socklen_t familyLen = sizeof(family);
655fc275794ab41d110abbdb7683ed9db45918985fSreeram Ramachandran        if (getsockopt(acceptedSocket, SOL_SOCKET, SO_DOMAIN, &family, &familyLen) == -1) {
663a069e6a76752a0ee73c60f276ae362d1c01467fSreeram Ramachandran            return closeFdAndSetErrno(acceptedSocket, -errno);
67f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram Ramachandran        }
68f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram Ramachandran    }
695fc275794ab41d110abbdb7683ed9db45918985fSreeram Ramachandran    if (FwmarkClient::shouldSetFwmark(family)) {
70a69d9472ac48d4e09f049fb740e60b7217e03861Sreeram Ramachandran        FwmarkCommand command = {FwmarkCommand::ON_ACCEPT, 0, 0};
714b9b78aa02336de9291e5085401cef44c03c3bbaMichal Karpinski        if (int error = FwmarkClient().send(&command, acceptedSocket, nullptr)) {
7231f4210e6fc5c9b749468a2af0bac94992352010Sreeram Ramachandran            return closeFdAndSetErrno(acceptedSocket, error);
73f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram Ramachandran        }
74f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram Ramachandran    }
75f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram Ramachandran    return acceptedSocket;
76f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram Ramachandran}
77f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram Ramachandran
785fc275794ab41d110abbdb7683ed9db45918985fSreeram Ramachandranint netdClientConnect(int sockfd, const sockaddr* addr, socklen_t addrlen) {
794b9b78aa02336de9291e5085401cef44c03c3bbaMichal Karpinski    const bool shouldSetFwmark = (sockfd >= 0) && addr
804b9b78aa02336de9291e5085401cef44c03c3bbaMichal Karpinski            && FwmarkClient::shouldSetFwmark(addr->sa_family);
814b9b78aa02336de9291e5085401cef44c03c3bbaMichal Karpinski    if (shouldSetFwmark) {
82a69d9472ac48d4e09f049fb740e60b7217e03861Sreeram Ramachandran        FwmarkCommand command = {FwmarkCommand::ON_CONNECT, 0, 0};
834b9b78aa02336de9291e5085401cef44c03c3bbaMichal Karpinski        if (int error = FwmarkClient().send(&command, sockfd, nullptr)) {
843a069e6a76752a0ee73c60f276ae362d1c01467fSreeram Ramachandran            errno = -error;
855fc275794ab41d110abbdb7683ed9db45918985fSreeram Ramachandran            return -1;
865fc275794ab41d110abbdb7683ed9db45918985fSreeram Ramachandran        }
875fc275794ab41d110abbdb7683ed9db45918985fSreeram Ramachandran    }
884b9b78aa02336de9291e5085401cef44c03c3bbaMichal Karpinski    // Latency measurement does not include time of sending commands to Fwmark
894b9b78aa02336de9291e5085401cef44c03c3bbaMichal Karpinski    Stopwatch s;
90794c5c714a4d4cf169769ec956845a6fb24e7ebcHugo Benichi    const int ret = libcConnect(sockfd, addr, addrlen);
914b9b78aa02336de9291e5085401cef44c03c3bbaMichal Karpinski    // Save errno so it isn't clobbered by sending ON_CONNECT_COMPLETE
924b9b78aa02336de9291e5085401cef44c03c3bbaMichal Karpinski    const int connectErrno = errno;
934b9b78aa02336de9291e5085401cef44c03c3bbaMichal Karpinski    const unsigned latencyMs = lround(s.timeTaken());
944b9b78aa02336de9291e5085401cef44c03c3bbaMichal Karpinski    // Send an ON_CONNECT_COMPLETE command that includes sockaddr and connect latency for reporting
954b9b78aa02336de9291e5085401cef44c03c3bbaMichal Karpinski    if (shouldSetFwmark && FwmarkClient::shouldReportConnectComplete(addr->sa_family)) {
96794c5c714a4d4cf169769ec956845a6fb24e7ebcHugo Benichi        FwmarkConnectInfo connectInfo(ret == 0 ? 0 : connectErrno, latencyMs, addr);
974b9b78aa02336de9291e5085401cef44c03c3bbaMichal Karpinski        // TODO: get the netId from the socket mark once we have continuous benchmark runs
984b9b78aa02336de9291e5085401cef44c03c3bbaMichal Karpinski        FwmarkCommand command = {FwmarkCommand::ON_CONNECT_COMPLETE, /* netId (ignored) */ 0,
994b9b78aa02336de9291e5085401cef44c03c3bbaMichal Karpinski                /* uid (filled in by the server) */ 0};
1004b9b78aa02336de9291e5085401cef44c03c3bbaMichal Karpinski        // Ignore return value since it's only used for logging
1014b9b78aa02336de9291e5085401cef44c03c3bbaMichal Karpinski        FwmarkClient().send(&command, sockfd, &connectInfo);
1024b9b78aa02336de9291e5085401cef44c03c3bbaMichal Karpinski    }
1034b9b78aa02336de9291e5085401cef44c03c3bbaMichal Karpinski    errno = connectErrno;
1044b9b78aa02336de9291e5085401cef44c03c3bbaMichal Karpinski    return ret;
1055fc275794ab41d110abbdb7683ed9db45918985fSreeram Ramachandran}
1065fc275794ab41d110abbdb7683ed9db45918985fSreeram Ramachandran
1075fc275794ab41d110abbdb7683ed9db45918985fSreeram Ramachandranint netdClientSocket(int domain, int type, int protocol) {
1085fc275794ab41d110abbdb7683ed9db45918985fSreeram Ramachandran    int socketFd = libcSocket(domain, type, protocol);
1095fc275794ab41d110abbdb7683ed9db45918985fSreeram Ramachandran    if (socketFd == -1) {
1105fc275794ab41d110abbdb7683ed9db45918985fSreeram Ramachandran        return -1;
1115fc275794ab41d110abbdb7683ed9db45918985fSreeram Ramachandran    }
1125fc275794ab41d110abbdb7683ed9db45918985fSreeram Ramachandran    unsigned netId = netIdForProcess;
1135fc275794ab41d110abbdb7683ed9db45918985fSreeram Ramachandran    if (netId != NETID_UNSET && FwmarkClient::shouldSetFwmark(domain)) {
114d36c49c1d66585769d33d95f0eb2c9c524b337a4Sreeram Ramachandran        if (int error = setNetworkForSocket(netId, socketFd)) {
11531f4210e6fc5c9b749468a2af0bac94992352010Sreeram Ramachandran            return closeFdAndSetErrno(socketFd, error);
1165fc275794ab41d110abbdb7683ed9db45918985fSreeram Ramachandran        }
1175fc275794ab41d110abbdb7683ed9db45918985fSreeram Ramachandran    }
1185fc275794ab41d110abbdb7683ed9db45918985fSreeram Ramachandran    return socketFd;
1195fc275794ab41d110abbdb7683ed9db45918985fSreeram Ramachandran}
120efbe05d203f2f1cc3c24ddc111be159a1ff1f292Sreeram Ramachandran
121efbe05d203f2f1cc3c24ddc111be159a1ff1f292Sreeram Ramachandranunsigned getNetworkForResolv(unsigned netId) {
122efbe05d203f2f1cc3c24ddc111be159a1ff1f292Sreeram Ramachandran    if (netId != NETID_UNSET) {
123efbe05d203f2f1cc3c24ddc111be159a1ff1f292Sreeram Ramachandran        return netId;
124efbe05d203f2f1cc3c24ddc111be159a1ff1f292Sreeram Ramachandran    }
125efbe05d203f2f1cc3c24ddc111be159a1ff1f292Sreeram Ramachandran    netId = netIdForProcess;
126efbe05d203f2f1cc3c24ddc111be159a1ff1f292Sreeram Ramachandran    if (netId != NETID_UNSET) {
127efbe05d203f2f1cc3c24ddc111be159a1ff1f292Sreeram Ramachandran        return netId;
128efbe05d203f2f1cc3c24ddc111be159a1ff1f292Sreeram Ramachandran    }
129efbe05d203f2f1cc3c24ddc111be159a1ff1f292Sreeram Ramachandran    return netIdForResolv;
130efbe05d203f2f1cc3c24ddc111be159a1ff1f292Sreeram Ramachandran}
131efbe05d203f2f1cc3c24ddc111be159a1ff1f292Sreeram Ramachandran
13231f4210e6fc5c9b749468a2af0bac94992352010Sreeram Ramachandranint setNetworkForTarget(unsigned netId, std::atomic_uint* target) {
133efbe05d203f2f1cc3c24ddc111be159a1ff1f292Sreeram Ramachandran    if (netId == NETID_UNSET) {
134efbe05d203f2f1cc3c24ddc111be159a1ff1f292Sreeram Ramachandran        *target = netId;
13531f4210e6fc5c9b749468a2af0bac94992352010Sreeram Ramachandran        return 0;
136efbe05d203f2f1cc3c24ddc111be159a1ff1f292Sreeram Ramachandran    }
137efbe05d203f2f1cc3c24ddc111be159a1ff1f292Sreeram Ramachandran    // Verify that we are allowed to use |netId|, by creating a socket and trying to have it marked
1382756045bebaac342f7cb70dad11519f896d44833Sreeram Ramachandran    // with the netId. Call libcSocket() directly; else the socket creation (via netdClientSocket())
1392756045bebaac342f7cb70dad11519f896d44833Sreeram Ramachandran    // might itself cause another check with the fwmark server, which would be wasteful.
1402756045bebaac342f7cb70dad11519f896d44833Sreeram Ramachandran    int socketFd;
1412756045bebaac342f7cb70dad11519f896d44833Sreeram Ramachandran    if (libcSocket) {
14253ea9cadf6cc5f8be1c16b5b6b660cd7366fd3f0Nick Kralevich        socketFd = libcSocket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0);
1432756045bebaac342f7cb70dad11519f896d44833Sreeram Ramachandran    } else {
14453ea9cadf6cc5f8be1c16b5b6b660cd7366fd3f0Nick Kralevich        socketFd = socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0);
1452756045bebaac342f7cb70dad11519f896d44833Sreeram Ramachandran    }
146efbe05d203f2f1cc3c24ddc111be159a1ff1f292Sreeram Ramachandran    if (socketFd < 0) {
1473a069e6a76752a0ee73c60f276ae362d1c01467fSreeram Ramachandran        return -errno;
148efbe05d203f2f1cc3c24ddc111be159a1ff1f292Sreeram Ramachandran    }
14931f4210e6fc5c9b749468a2af0bac94992352010Sreeram Ramachandran    int error = setNetworkForSocket(netId, socketFd);
15031f4210e6fc5c9b749468a2af0bac94992352010Sreeram Ramachandran    if (!error) {
151efbe05d203f2f1cc3c24ddc111be159a1ff1f292Sreeram Ramachandran        *target = netId;
152efbe05d203f2f1cc3c24ddc111be159a1ff1f292Sreeram Ramachandran    }
15331f4210e6fc5c9b749468a2af0bac94992352010Sreeram Ramachandran    close(socketFd);
15431f4210e6fc5c9b749468a2af0bac94992352010Sreeram Ramachandran    return error;
155efbe05d203f2f1cc3c24ddc111be159a1ff1f292Sreeram Ramachandran}
156efbe05d203f2f1cc3c24ddc111be159a1ff1f292Sreeram Ramachandran
157f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram Ramachandran}  // namespace
158f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram Ramachandran
1595fc275794ab41d110abbdb7683ed9db45918985fSreeram Ramachandran// accept() just calls accept4(..., 0), so there's no need to handle accept() separately.
1605fc275794ab41d110abbdb7683ed9db45918985fSreeram Ramachandranextern "C" void netdClientInitAccept4(Accept4FunctionType* function) {
1615fc275794ab41d110abbdb7683ed9db45918985fSreeram Ramachandran    if (function && *function) {
1625fc275794ab41d110abbdb7683ed9db45918985fSreeram Ramachandran        libcAccept4 = *function;
1635fc275794ab41d110abbdb7683ed9db45918985fSreeram Ramachandran        *function = netdClientAccept4;
1645fc275794ab41d110abbdb7683ed9db45918985fSreeram Ramachandran    }
1655fc275794ab41d110abbdb7683ed9db45918985fSreeram Ramachandran}
1665fc275794ab41d110abbdb7683ed9db45918985fSreeram Ramachandran
167f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram Ramachandranextern "C" void netdClientInitConnect(ConnectFunctionType* function) {
168f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram Ramachandran    if (function && *function) {
169f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram Ramachandran        libcConnect = *function;
170f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram Ramachandran        *function = netdClientConnect;
171f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram Ramachandran    }
172f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram Ramachandran}
173f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram Ramachandran
1745fc275794ab41d110abbdb7683ed9db45918985fSreeram Ramachandranextern "C" void netdClientInitSocket(SocketFunctionType* function) {
175f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram Ramachandran    if (function && *function) {
1765fc275794ab41d110abbdb7683ed9db45918985fSreeram Ramachandran        libcSocket = *function;
1775fc275794ab41d110abbdb7683ed9db45918985fSreeram Ramachandran        *function = netdClientSocket;
178f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram Ramachandran    }
179f4cfad361175a7f9ccf4d41e76a9b289c3c3da22Sreeram Ramachandran}
180efbe05d203f2f1cc3c24ddc111be159a1ff1f292Sreeram Ramachandran
181efbe05d203f2f1cc3c24ddc111be159a1ff1f292Sreeram Ramachandranextern "C" void netdClientInitNetIdForResolv(NetIdForResolvFunctionType* function) {
182efbe05d203f2f1cc3c24ddc111be159a1ff1f292Sreeram Ramachandran    if (function) {
183efbe05d203f2f1cc3c24ddc111be159a1ff1f292Sreeram Ramachandran        *function = getNetworkForResolv;
184efbe05d203f2f1cc3c24ddc111be159a1ff1f292Sreeram Ramachandran    }
185efbe05d203f2f1cc3c24ddc111be159a1ff1f292Sreeram Ramachandran}
186efbe05d203f2f1cc3c24ddc111be159a1ff1f292Sreeram Ramachandran
1874d4c8b7e294d845103ecb10f968713717a3e6406Sreeram Ramachandranextern "C" int getNetworkForSocket(unsigned* netId, int socketFd) {
1884d4c8b7e294d845103ecb10f968713717a3e6406Sreeram Ramachandran    if (!netId || socketFd < 0) {
1893a069e6a76752a0ee73c60f276ae362d1c01467fSreeram Ramachandran        return -EBADF;
1904d4c8b7e294d845103ecb10f968713717a3e6406Sreeram Ramachandran    }
1914d4c8b7e294d845103ecb10f968713717a3e6406Sreeram Ramachandran    Fwmark fwmark;
1924d4c8b7e294d845103ecb10f968713717a3e6406Sreeram Ramachandran    socklen_t fwmarkLen = sizeof(fwmark.intValue);
1934d4c8b7e294d845103ecb10f968713717a3e6406Sreeram Ramachandran    if (getsockopt(socketFd, SOL_SOCKET, SO_MARK, &fwmark.intValue, &fwmarkLen) == -1) {
1943a069e6a76752a0ee73c60f276ae362d1c01467fSreeram Ramachandran        return -errno;
1954d4c8b7e294d845103ecb10f968713717a3e6406Sreeram Ramachandran    }
1964d4c8b7e294d845103ecb10f968713717a3e6406Sreeram Ramachandran    *netId = fwmark.netId;
1974d4c8b7e294d845103ecb10f968713717a3e6406Sreeram Ramachandran    return 0;
1984d4c8b7e294d845103ecb10f968713717a3e6406Sreeram Ramachandran}
1994d4c8b7e294d845103ecb10f968713717a3e6406Sreeram Ramachandran
200efbe05d203f2f1cc3c24ddc111be159a1ff1f292Sreeram Ramachandranextern "C" unsigned getNetworkForProcess() {
201efbe05d203f2f1cc3c24ddc111be159a1ff1f292Sreeram Ramachandran    return netIdForProcess;
202efbe05d203f2f1cc3c24ddc111be159a1ff1f292Sreeram Ramachandran}
203efbe05d203f2f1cc3c24ddc111be159a1ff1f292Sreeram Ramachandran
20431f4210e6fc5c9b749468a2af0bac94992352010Sreeram Ramachandranextern "C" int setNetworkForSocket(unsigned netId, int socketFd) {
205efbe05d203f2f1cc3c24ddc111be159a1ff1f292Sreeram Ramachandran    if (socketFd < 0) {
2063a069e6a76752a0ee73c60f276ae362d1c01467fSreeram Ramachandran        return -EBADF;
207efbe05d203f2f1cc3c24ddc111be159a1ff1f292Sreeram Ramachandran    }
208a69d9472ac48d4e09f049fb740e60b7217e03861Sreeram Ramachandran    FwmarkCommand command = {FwmarkCommand::SELECT_NETWORK, netId, 0};
2094b9b78aa02336de9291e5085401cef44c03c3bbaMichal Karpinski    return FwmarkClient().send(&command, socketFd, nullptr);
210efbe05d203f2f1cc3c24ddc111be159a1ff1f292Sreeram Ramachandran}
211efbe05d203f2f1cc3c24ddc111be159a1ff1f292Sreeram Ramachandran
21231f4210e6fc5c9b749468a2af0bac94992352010Sreeram Ramachandranextern "C" int setNetworkForProcess(unsigned netId) {
213efbe05d203f2f1cc3c24ddc111be159a1ff1f292Sreeram Ramachandran    return setNetworkForTarget(netId, &netIdForProcess);
214efbe05d203f2f1cc3c24ddc111be159a1ff1f292Sreeram Ramachandran}
215efbe05d203f2f1cc3c24ddc111be159a1ff1f292Sreeram Ramachandran
21631f4210e6fc5c9b749468a2af0bac94992352010Sreeram Ramachandranextern "C" int setNetworkForResolv(unsigned netId) {
217efbe05d203f2f1cc3c24ddc111be159a1ff1f292Sreeram Ramachandran    return setNetworkForTarget(netId, &netIdForResolv);
218efbe05d203f2f1cc3c24ddc111be159a1ff1f292Sreeram Ramachandran}
219d794e580dbe1a8b4192850b0e117654401514af8Sreeram Ramachandran
22031f4210e6fc5c9b749468a2af0bac94992352010Sreeram Ramachandranextern "C" int protectFromVpn(int socketFd) {
221d794e580dbe1a8b4192850b0e117654401514af8Sreeram Ramachandran    if (socketFd < 0) {
2223a069e6a76752a0ee73c60f276ae362d1c01467fSreeram Ramachandran        return -EBADF;
223d794e580dbe1a8b4192850b0e117654401514af8Sreeram Ramachandran    }
224a69d9472ac48d4e09f049fb740e60b7217e03861Sreeram Ramachandran    FwmarkCommand command = {FwmarkCommand::PROTECT_FROM_VPN, 0, 0};
2254b9b78aa02336de9291e5085401cef44c03c3bbaMichal Karpinski    return FwmarkClient().send(&command, socketFd, nullptr);
226a69d9472ac48d4e09f049fb740e60b7217e03861Sreeram Ramachandran}
227a69d9472ac48d4e09f049fb740e60b7217e03861Sreeram Ramachandran
228a69d9472ac48d4e09f049fb740e60b7217e03861Sreeram Ramachandranextern "C" int setNetworkForUser(uid_t uid, int socketFd) {
229a69d9472ac48d4e09f049fb740e60b7217e03861Sreeram Ramachandran    if (socketFd < 0) {
230a69d9472ac48d4e09f049fb740e60b7217e03861Sreeram Ramachandran        return -EBADF;
231a69d9472ac48d4e09f049fb740e60b7217e03861Sreeram Ramachandran    }
232a69d9472ac48d4e09f049fb740e60b7217e03861Sreeram Ramachandran    FwmarkCommand command = {FwmarkCommand::SELECT_FOR_USER, 0, uid};
2334b9b78aa02336de9291e5085401cef44c03c3bbaMichal Karpinski    return FwmarkClient().send(&command, socketFd, nullptr);
234d1df597001aadd5d83c9a3d1fe8bbde2bc9256caPaul Jensen}
235d1df597001aadd5d83c9a3d1fe8bbde2bc9256caPaul Jensen
236d1df597001aadd5d83c9a3d1fe8bbde2bc9256caPaul Jensenextern "C" int queryUserAccess(uid_t uid, unsigned netId) {
237d1df597001aadd5d83c9a3d1fe8bbde2bc9256caPaul Jensen    FwmarkCommand command = {FwmarkCommand::QUERY_USER_ACCESS, netId, uid};
2384b9b78aa02336de9291e5085401cef44c03c3bbaMichal Karpinski    return FwmarkClient().send(&command, -1, nullptr);
239d794e580dbe1a8b4192850b0e117654401514af8Sreeram Ramachandran}
240