Introduce netd_client, a dynamic library that talks to netd.
This library is dynamically loaded and used by bionic, to replace selected standard socket syscalls with versions that talk to netd. Implement connect() by requesting that the socket be marked with the netId of the default network and then calling through to the actual syscall. There are two escape hatches: + If the fwmark server is unavailable, it isn't an error; we proceed with the syscall. This might help at boot time (when the server isn't ready yet) and if we get rid of the fwmarkd socket entirely in future platform versions. + If the ANDROID_NO_USE_FWMARK_CLIENT environment variable is set, we don't attempt to use the fwmark server (even if it's available). This allows apps to sidestep unforseen issues in production at runtime. Change-Id: Ib6198e19dbc306521a26fcecfdf6e8424d163fc9
This commit is contained in:
parent
76202a2dfa
commit
8f95def419
5 changed files with 230 additions and 0 deletions
29
include/netd_client/FwmarkCommands.h
Normal file
29
include/netd_client/FwmarkCommands.h
Normal file
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* Copyright (C) 2014 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef NETD_CLIENT_FWMARK_COMMANDS_H
|
||||
#define NETD_CLIENT_FWMARK_COMMANDS_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
// Commands sent from clients to the fwmark server to mark sockets (i.e., set their SO_MARK).
|
||||
const uint8_t FWMARK_COMMAND_ON_CREATE = 0;
|
||||
const uint8_t FWMARK_COMMAND_ON_CONNECT = 1;
|
||||
const uint8_t FWMARK_COMMAND_ON_ACCEPT = 2;
|
||||
const uint8_t FWMARK_COMMAND_SELECT_NETWORK = 3;
|
||||
const uint8_t FWMARK_COMMAND_PROTECT_FROM_VPN = 4;
|
||||
|
||||
#endif // NETD_CLIENT_FWMARK_COMMANDS_H
|
22
libnetd_client/Android.mk
Normal file
22
libnetd_client/Android.mk
Normal file
|
@ -0,0 +1,22 @@
|
|||
# Copyright (C) 2014 The Android Open Source Project
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_MODULE := libnetd_client
|
||||
LOCAL_SRC_FILES := FwmarkClient.cpp NetdClient.cpp
|
||||
|
||||
include $(BUILD_SHARED_LIBRARY)
|
96
libnetd_client/FwmarkClient.cpp
Normal file
96
libnetd_client/FwmarkClient.cpp
Normal file
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
* Copyright (C) 2014 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "FwmarkClient.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <unistd.h>
|
||||
|
||||
namespace {
|
||||
|
||||
const sockaddr_un FWMARK_SERVER_PATH = {AF_UNIX, "/dev/socket/fwmarkd"};
|
||||
|
||||
} // namespace
|
||||
|
||||
bool FwmarkClient::shouldSetFwmark(int sockfd, const sockaddr* addr) {
|
||||
return sockfd >= 0 && addr && (addr->sa_family == AF_INET || addr->sa_family == AF_INET6) &&
|
||||
!getenv("ANDROID_NO_USE_FWMARK_CLIENT");
|
||||
}
|
||||
|
||||
FwmarkClient::FwmarkClient() : mChannel(-1) {
|
||||
}
|
||||
|
||||
FwmarkClient::~FwmarkClient() {
|
||||
if (mChannel >= 0) {
|
||||
// We don't care about errors while closing the channel, so restore any previous error.
|
||||
int error = errno;
|
||||
close(mChannel);
|
||||
errno = error;
|
||||
}
|
||||
}
|
||||
|
||||
bool FwmarkClient::send(void* data, size_t len, int fd) {
|
||||
mChannel = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
if (mChannel == -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (TEMP_FAILURE_RETRY(connect(mChannel, reinterpret_cast<const sockaddr*>(&FWMARK_SERVER_PATH),
|
||||
sizeof(FWMARK_SERVER_PATH))) == -1) {
|
||||
// If we are unable to connect to the fwmark server, assume there's no error. This protects
|
||||
// against future changes if the fwmark server goes away.
|
||||
errno = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
iovec iov;
|
||||
iov.iov_base = data;
|
||||
iov.iov_len = len;
|
||||
|
||||
msghdr message;
|
||||
memset(&message, 0, sizeof(message));
|
||||
message.msg_iov = &iov;
|
||||
message.msg_iovlen = 1;
|
||||
|
||||
union {
|
||||
cmsghdr cmh;
|
||||
char cmsg[CMSG_SPACE(sizeof(fd))];
|
||||
} cmsgu;
|
||||
|
||||
memset(cmsgu.cmsg, 0, sizeof(cmsgu.cmsg));
|
||||
message.msg_control = cmsgu.cmsg;
|
||||
message.msg_controllen = sizeof(cmsgu.cmsg);
|
||||
|
||||
cmsghdr* const cmsgh = CMSG_FIRSTHDR(&message);
|
||||
cmsgh->cmsg_len = CMSG_LEN(sizeof(fd));
|
||||
cmsgh->cmsg_level = SOL_SOCKET;
|
||||
cmsgh->cmsg_type = SCM_RIGHTS;
|
||||
memcpy(CMSG_DATA(cmsgh), &fd, sizeof(fd));
|
||||
|
||||
if (TEMP_FAILURE_RETRY(sendmsg(mChannel, &message, 0)) == -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int error = 0;
|
||||
if (TEMP_FAILURE_RETRY(recv(mChannel, &error, sizeof(error), 0)) == -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
errno = error;
|
||||
return !error;
|
||||
}
|
38
libnetd_client/FwmarkClient.h
Normal file
38
libnetd_client/FwmarkClient.h
Normal file
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Copyright (C) 2014 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef NETD_CLIENT_FWMARK_CLIENT_H
|
||||
#define NETD_CLIENT_FWMARK_CLIENT_H
|
||||
|
||||
#include <sys/socket.h>
|
||||
|
||||
class FwmarkClient {
|
||||
public:
|
||||
// Returns true if |sockfd| should be sent to the fwmark server to have its SO_MARK set.
|
||||
static bool shouldSetFwmark(int sockfd, const sockaddr* addr);
|
||||
|
||||
FwmarkClient();
|
||||
~FwmarkClient();
|
||||
|
||||
// Sends |data| to the fwmark server, along with |fd| as ancillary data using cmsg(3).
|
||||
// Returns true on success.
|
||||
bool send(void* data, size_t len, int fd);
|
||||
|
||||
private:
|
||||
int mChannel;
|
||||
};
|
||||
|
||||
#endif // NETD_CLIENT_INCLUDE_FWMARK_CLIENT_H
|
45
libnetd_client/NetdClient.cpp
Normal file
45
libnetd_client/NetdClient.cpp
Normal file
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Copyright (C) 2014 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "FwmarkClient.h"
|
||||
#include "netd_client/FwmarkCommands.h"
|
||||
|
||||
#include <sys/socket.h>
|
||||
|
||||
namespace {
|
||||
|
||||
typedef int (*ConnectFunctionType)(int, const sockaddr*, socklen_t);
|
||||
|
||||
ConnectFunctionType libcConnect = 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)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return libcConnect(sockfd, addr, addrlen);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
extern "C" void netdClientInitConnect(ConnectFunctionType* function) {
|
||||
if (function && *function) {
|
||||
libcConnect = *function;
|
||||
*function = netdClientConnect;
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue