diff options
-rw-r--r-- | include/netd_client/FwmarkCommands.h | 29 | ||||
-rw-r--r-- | libnetd_client/Android.mk | 22 | ||||
-rw-r--r-- | libnetd_client/FwmarkClient.cpp | 96 | ||||
-rw-r--r-- | libnetd_client/FwmarkClient.h | 38 | ||||
-rw-r--r-- | libnetd_client/NetdClient.cpp | 45 |
5 files changed, 230 insertions, 0 deletions
diff --git a/include/netd_client/FwmarkCommands.h b/include/netd_client/FwmarkCommands.h new file mode 100644 index 0000000..0d22f02 --- /dev/null +++ b/include/netd_client/FwmarkCommands.h @@ -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 diff --git a/libnetd_client/Android.mk b/libnetd_client/Android.mk new file mode 100644 index 0000000..2b75626 --- /dev/null +++ b/libnetd_client/Android.mk @@ -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) diff --git a/libnetd_client/FwmarkClient.cpp b/libnetd_client/FwmarkClient.cpp new file mode 100644 index 0000000..e360b4e --- /dev/null +++ b/libnetd_client/FwmarkClient.cpp @@ -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; +} diff --git a/libnetd_client/FwmarkClient.h b/libnetd_client/FwmarkClient.h new file mode 100644 index 0000000..4cf0cc0 --- /dev/null +++ b/libnetd_client/FwmarkClient.h @@ -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 diff --git a/libnetd_client/NetdClient.cpp b/libnetd_client/NetdClient.cpp new file mode 100644 index 0000000..1d8501a --- /dev/null +++ b/libnetd_client/NetdClient.cpp @@ -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; + } +} |