/*************************************************************************** * libancillary - black magic on Unix domain sockets * (C) Nicolas George ***************************************************************************/ /* * fastd Android port * Copyright (c) 2014-2015, Haofeng "Rick" Lei * All rights reserved. */ /* * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* libancillary code from: * http://www.normalesup.org/~george/comp/libancillary/ * with minor indent/style adjusts to fit fastd project */ /* vim: set noexpandtab ts=8 sw=8 sts=8 */ /** \file Android specific methods for communicating with GUI */ #ifdef __ANDROID__ #include "fastd.h" #include /** declare a work buffer for sending/receiving \e n handles */ #define ANCIL_FD_BUFFER(n) \ struct { \ struct cmsghdr h; \ int fd[n]; \ } /** receive \e n_fds handles from unix domain socket \e sock and store in \e fds */ static int ancil_recv_fds_with_buffer(int sock, int *fds, unsigned n_fds, void *buffer) { struct msghdr msghdr; char nothing; struct iovec nothing_ptr; struct cmsghdr *cmsg; int i; nothing_ptr.iov_base = ¬hing; nothing_ptr.iov_len = 1; msghdr.msg_name = NULL; msghdr.msg_namelen = 0; msghdr.msg_iov = ¬hing_ptr; msghdr.msg_iovlen = 1; msghdr.msg_flags = 0; msghdr.msg_control = buffer; msghdr.msg_controllen = sizeof(struct cmsghdr) + sizeof(int) * n_fds; cmsg = CMSG_FIRSTHDR(&msghdr); cmsg->cmsg_len = msghdr.msg_controllen; cmsg->cmsg_level = SOL_SOCKET; cmsg->cmsg_type = SCM_RIGHTS; for (i = 0; i < n_fds; i++) { ((int *)CMSG_DATA(cmsg))[i] = -1; } if (recvmsg(sock, &msghdr, 0) < 0) { return(-1); } for (i = 0; i < n_fds; i++) { fds[i] = ((int *)CMSG_DATA(cmsg))[i]; } n_fds = (cmsg->cmsg_len - sizeof(struct cmsghdr)) / sizeof(int); return n_fds; } /** shortcut for receiving only one \e fd from \e sock */ static int ancil_recv_fd(int sock, int *fd) { ANCIL_FD_BUFFER(1) buffer; return ancil_recv_fds_with_buffer(sock, fd, 1, &buffer) == 1 ? 0 : -1; } /** send \e n_fds handles in \e fds to unix domain socket \e sock */ static int ancil_send_fds_with_buffer(int sock, const int *fds, unsigned n_fds, void *buffer) { struct msghdr msghdr; char nothing = '!'; struct iovec nothing_ptr; struct cmsghdr *cmsg; int i; nothing_ptr.iov_base = ¬hing; nothing_ptr.iov_len = 1; msghdr.msg_name = NULL; msghdr.msg_namelen = 0; msghdr.msg_iov = ¬hing_ptr; msghdr.msg_iovlen = 1; msghdr.msg_flags = 0; msghdr.msg_control = buffer; msghdr.msg_controllen = sizeof(struct cmsghdr) + sizeof(int) * n_fds; cmsg = CMSG_FIRSTHDR(&msghdr); cmsg->cmsg_len = msghdr.msg_controllen; cmsg->cmsg_level = SOL_SOCKET; cmsg->cmsg_type = SCM_RIGHTS; for (i = 0; i < n_fds; i++) { ((int *)CMSG_DATA(cmsg))[i] = fds[i]; } return sendmsg(sock, &msghdr, 0) >= 0 ? 0 : -1; } /** shortcut for sending only one \e fd to \e sock */ static int ancil_send_fd(int sock, int fd) { ANCIL_FD_BUFFER(1) buffer; return ancil_send_fds_with_buffer(sock, &fd, 1, &buffer); } /* * libancillary end */ /** name of unix domain socket for communication with Android FastdVpnService */ #define CTRL_SOCK_NAME "fastd_tun_sock" /** message sent by Android FastdVpnService to indicate successful protection of socket */ #define PROTECT_OK 'X' /** message sent by Android FastdVpnService when protecting socket failed */ #define PROTECT_ERROR 'E' /** establish the unix domain socket with Android GUI */ static void init_ctrl_sock(void) { /* Must keep consistent with FastdVpnService */ struct sockaddr_un addr; if ((ctx.android_ctrl_sock_fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { exit_errno("could not create unix domain socket"); } memset(&addr, 0, sizeof(addr)); addr.sun_family = AF_UNIX; addr.sun_path[0] = 0; /* Linux's abstract unix domain socket name */ strncpy(addr.sun_path + 1, CTRL_SOCK_NAME, sizeof(addr.sun_path) - 2); int socklen = offsetof(struct sockaddr_un, sun_path) + strlen(CTRL_SOCK_NAME) + 1; if (connect(ctx.android_ctrl_sock_fd, (struct sockaddr*)&addr, socklen) == -1) { exit_errno("could not connect to Android LocalServerSocket"); } } /** receive TUN fd from Android GUI; this is the only way to open TUN device on non-rooted Android */ int fastd_android_receive_tunfd(void) { init_ctrl_sock(); int handle; if (ancil_recv_fd(ctx.android_ctrl_sock_fd, &handle)) { pr_error("could not receive TUN handle from Android"); return -1; } pr_debug("received fd: %u", handle); return handle; } /** send fastd pid to Android GUI for later signal sending (HUP, TERM etc) */ void fastd_android_send_pid(void) { char pid[20]; snprintf(pid, sizeof(pid), "%u", (unsigned)getpid()); if (write(ctx.android_ctrl_sock_fd, pid, strlen(pid)) != strlen(pid)) { exit_errno("send pid"); } } /** report \e fd to Android GUI to be protected (i.e. not to be routed via TUN) */ bool fastd_android_protect_socket(int fd) { if (!conf.android_integration) { /* rooted/non-GUI mode */ return true; } pr_debug("sending fd to protect"); if (ancil_send_fd(ctx.android_ctrl_sock_fd, fd) == -1) { exit_errno("could not send handle to Android for protecting"); } char buf[20]; if (read(ctx.android_ctrl_sock_fd, buf, sizeof(buf)) == -1) { exit_errno("read ack"); } return buf[0] == PROTECT_OK; } #endif /* __ANDROID__ */