From efbe05d203f2f1cc3c24ddc111be159a1ff1f292 Mon Sep 17 00:00:00 2001 From: Sreeram Ramachandran Date: Wed, 21 May 2014 11:41:39 -0700 Subject: New network selection APIs. Continued from: https://android-review.git.corp.google.com/#/c/94977/ Change-Id: Ie0576888f50a8ce91bbb0a4794708b406eb0aa35 --- client/Android.mk | 2 +- client/NetdClient.cpp | 76 ++++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 73 insertions(+), 5 deletions(-) (limited to 'client') diff --git a/client/Android.mk b/client/Android.mk index 2a4878c4..0332deaf 100644 --- a/client/Android.mk +++ b/client/Android.mk @@ -16,7 +16,7 @@ LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) -LOCAL_C_INCLUDES := system/netd/include +LOCAL_C_INCLUDES := bionic/libc/dns/include system/netd/include LOCAL_MODULE := libnetd_client LOCAL_SRC_FILES := FwmarkClient.cpp NetdClient.cpp diff --git a/client/NetdClient.cpp b/client/NetdClient.cpp index 2e8390c8..31c2e4d2 100644 --- a/client/NetdClient.cpp +++ b/client/NetdClient.cpp @@ -14,8 +14,11 @@ * limitations under the License. */ +#include "NetdClient.h" + #include "FwmarkClient.h" #include "FwmarkCommand.h" +#include "resolv_netid.h" #include #include @@ -31,14 +34,17 @@ int closeFdAndRestoreErrno(int fd) { typedef int (*ConnectFunctionType)(int, const sockaddr*, socklen_t); typedef int (*AcceptFunctionType)(int, sockaddr*, socklen_t*); +typedef unsigned (*NetIdForResolvFunctionType)(unsigned); +// These variables are only modified at startup (when libc.so is loaded) and never afterwards, so +// it's okay that they are read later at runtime without a lock. ConnectFunctionType libcConnect = 0; AcceptFunctionType libcAccept = 0; int netdClientConnect(int sockfd, const sockaddr* addr, socklen_t addrlen) { if (FwmarkClient::shouldSetFwmark(sockfd, addr)) { - char data[] = {FWMARK_COMMAND_ON_CONNECT}; - if (!FwmarkClient().send(data, sizeof(data), sockfd)) { + FwmarkCommand command = {FwmarkCommand::ON_CONNECT, 0}; + if (!FwmarkClient().send(&command, sizeof(command), sockfd)) { return -1; } } @@ -59,14 +65,49 @@ int netdClientAccept(int sockfd, sockaddr* addr, socklen_t* addrlen) { addr = &socketAddress; } if (FwmarkClient::shouldSetFwmark(acceptedSocket, addr)) { - char data[] = {FWMARK_COMMAND_ON_ACCEPT}; - if (!FwmarkClient().send(data, sizeof(data), acceptedSocket)) { + FwmarkCommand command = {FwmarkCommand::ON_ACCEPT, 0}; + if (!FwmarkClient().send(&command, sizeof(command), acceptedSocket)) { return closeFdAndRestoreErrno(acceptedSocket); } } return acceptedSocket; } +// TODO: Convert to C++11 std::atomic. +volatile sig_atomic_t netIdForProcess = NETID_UNSET; +volatile sig_atomic_t netIdForResolv = NETID_UNSET; + +unsigned getNetworkForResolv(unsigned netId) { + if (netId != NETID_UNSET) { + return netId; + } + netId = netIdForProcess; + if (netId != NETID_UNSET) { + return netId; + } + return netIdForResolv; +} + +bool setNetworkForTarget(unsigned netId, volatile sig_atomic_t* target) { + if (netId == NETID_UNSET) { + *target = netId; + return true; + } + // Verify that we are allowed to use |netId|, by creating a socket and trying to have it marked + // with the netId. Don't create an AF_INET socket, because then the creation itself might cause + // another check with the fwmark server (see netdClientSocket()), which would be wasteful. + int socketFd = socket(AF_UNIX, SOCK_DGRAM, 0); + if (socketFd < 0) { + return false; + } + bool status = setNetworkForSocket(netId, socketFd); + closeFdAndRestoreErrno(socketFd); + if (status) { + *target = netId; + } + return status; +} + } // namespace extern "C" void netdClientInitConnect(ConnectFunctionType* function) { @@ -82,3 +123,30 @@ extern "C" void netdClientInitAccept(AcceptFunctionType* function) { *function = netdClientAccept; } } + +extern "C" void netdClientInitNetIdForResolv(NetIdForResolvFunctionType* function) { + if (function) { + *function = getNetworkForResolv; + } +} + +extern "C" unsigned getNetworkForProcess() { + return netIdForProcess; +} + +extern "C" bool setNetworkForSocket(unsigned netId, int socketFd) { + if (socketFd < 0) { + errno = EBADF; + return false; + } + FwmarkCommand command = {FwmarkCommand::SELECT_NETWORK, netId}; + return FwmarkClient().send(&command, sizeof(command), socketFd); +} + +extern "C" bool setNetworkForProcess(unsigned netId) { + return setNetworkForTarget(netId, &netIdForProcess); +} + +extern "C" bool setNetworkForResolv(unsigned netId) { + return setNetworkForTarget(netId, &netIdForResolv); +} -- cgit v1.2.3