From fd4015fac21e1856f54f882ea8cf793c7326605d Mon Sep 17 00:00:00 2001 From: Max Lv Date: Wed, 22 Jul 2015 18:06:28 +0800 Subject: [PATCH 1/2] add unix socket --- build.sh | 2 +- project/plugins.sbt | 2 +- .../java/com/github/shadowsocks/System.java | 1 + src/main/jni/Android.mk | 25 +++- src/main/jni/badvpn/tun2socks/tun2socks.c | 50 ++++++- src/main/jni/libancillary/API | 139 ++++++++++++++++++ src/main/jni/libancillary/COPYING | 21 +++ src/main/jni/libancillary/Makefile | 73 +++++++++ src/main/jni/libancillary/ancillary.h | 131 +++++++++++++++++ src/main/jni/libancillary/fd_recv.c | 98 ++++++++++++ src/main/jni/libancillary/fd_send.c | 92 ++++++++++++ src/main/jni/libancillary/test.c | 112 ++++++++++++++ src/main/jni/system.cpp | 38 +++++ .../shadowsocks/ShadowsocksVpnService.scala | 23 ++- 14 files changed, 795 insertions(+), 12 deletions(-) create mode 100644 src/main/jni/libancillary/API create mode 100644 src/main/jni/libancillary/COPYING create mode 100644 src/main/jni/libancillary/Makefile create mode 100644 src/main/jni/libancillary/ancillary.h create mode 100644 src/main/jni/libancillary/fd_recv.c create mode 100644 src/main/jni/libancillary/fd_send.c create mode 100644 src/main/jni/libancillary/test.c diff --git a/build.sh b/build.sh index 14cfaff686..8c4b249a32 100755 --- a/build.sh +++ b/build.sh @@ -8,7 +8,7 @@ try pushd src/main # Build try $ANDROID_NDK_HOME/ndk-build clean -try $ANDROID_NDK_HOME/ndk-build +try $ANDROID_NDK_HOME/ndk-build -j8 # copy executables rm -rf assets/armeabi-v7a diff --git a/project/plugins.sbt b/project/plugins.sbt index f0bdca0f54..def59e024c 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -1,6 +1,6 @@ resolvers += Resolver.url("scalasbt releases", new URL("http://scalasbt.artifactoryonline.com/scalasbt/sbt-plugin-snapshots"))(Resolver.ivyStylePatterns) -addSbtPlugin("com.hanhuy.sbt" % "android-sdk-plugin" % "1.4.0") +addSbtPlugin("com.hanhuy.sbt" % "android-sdk-plugin" % "1.4.6") resolvers += Resolver.sbtPluginRepo("snapshots") diff --git a/src/main/java/com/github/shadowsocks/System.java b/src/main/java/com/github/shadowsocks/System.java index 0f17bcaf1c..0dd47f595d 100755 --- a/src/main/java/com/github/shadowsocks/System.java +++ b/src/main/java/com/github/shadowsocks/System.java @@ -45,4 +45,5 @@ public class System { public static native void exec(String cmd); public static native String getABI(); + public static native int sendfd(int fd); } diff --git a/src/main/jni/Android.mk b/src/main/jni/Android.mk index 6def7020ef..13fa8e6ed4 100755 --- a/src/main/jni/Android.mk +++ b/src/main/jni/Android.mk @@ -110,6 +110,21 @@ LOCAL_CFLAGS := -O2 -I$(LOCAL_PATH)/libevent \ include $(BUILD_STATIC_LIBRARY) +######################################################## +## libancillary +######################################################## + +include $(CLEAR_VARS) + +ANCILLARY_SOURCE := fd_recv.c fd_send.c + +LOCAL_MODULE := libancillary +LOCAL_CFLAGS += -O2 -I$(LOCAL_PATH)/libancillary + +LOCAL_SRC_FILES := $(addprefix libancillary/, $(ANCILLARY_SOURCE)) + +include $(BUILD_STATIC_LIBRARY) + ######################################################## ## libipset ######################################################## @@ -287,12 +302,13 @@ include $(CLEAR_VARS) LOCAL_MODULE:= system -LOCAL_SRC_FILES:= \ - system.cpp +LOCAL_C_INCLUDES:= $(LOCAL_PATH)/libancillary + +LOCAL_SRC_FILES:= system.cpp LOCAL_LDLIBS := -ldl -llog -LOCAL_STATIC_LIBRARIES := cpufeatures +LOCAL_STATIC_LIBRARIES := cpufeatures libancillary include $(BUILD_SHARED_LIBRARY) @@ -309,7 +325,10 @@ LOCAL_CFLAGS += -DBADVPN_LITTLE_ENDIAN -DBADVPN_THREAD_SAFE LOCAL_CFLAGS += -DNDEBUG -DANDROID # LOCAL_CFLAGS += -DTUN2SOCKS_JNI +LOCAL_STATIC_LIBRARIES := libancillary + LOCAL_C_INCLUDES:= \ + $(LOCAL_PATH)/libancillary \ $(LOCAL_PATH)/badvpn/lwip/src/include/ipv4 \ $(LOCAL_PATH)/badvpn/lwip/src/include/ipv6 \ $(LOCAL_PATH)/badvpn/lwip/src/include \ diff --git a/src/main/jni/badvpn/tun2socks/tun2socks.c b/src/main/jni/badvpn/tun2socks/tun2socks.c index 1818630e1d..34d6cf2fc8 100644 --- a/src/main/jni/badvpn/tun2socks/tun2socks.c +++ b/src/main/jni/badvpn/tun2socks/tun2socks.c @@ -71,9 +71,13 @@ #include #ifdef ANDROID + +#include + #include #include #include + BAVL connections_tree; typedef struct { BAddr local_addr; @@ -408,7 +412,6 @@ int main (int argc, char **argv) prctl(PR_SET_NAME, "com.github.shadowsocks"); } - // handle --help and --version if (options.help) { print_version(); @@ -490,11 +493,54 @@ int main (int argc, char **argv) #ifdef ANDROID // use supplied file descriptor + + int sock, fd; + struct sockaddr_un addr; + + if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { + BLog(BLOG_ERROR, "socket() failed: %s (socket sock = %d)\n", strerror(errno), sock); + goto fail2; + } + + memset(&addr, 0, sizeof(addr)); + addr.sun_family = AF_UNIX; + strncpy(addr.sun_path, "/data/data/com.github.shadowsocks/sock_path", sizeof(addr.sun_path)-1); + + if (bind(sock, (struct sockaddr*)&addr, sizeof(addr)) == -1) { + BLog(BLOG_ERROR, "bind() failed: %s (sock = %d)\n", strerror(errno), sock); + close(sock); + goto fail2; + } + + if (listen(sock, 5) == -1) { + BLog(BLOG_ERROR, "listen() failed: %s (sock = %d)\n", strerror(errno), sock); + close(sock); + goto fail2; + } + + for (;;) { + int sock2; + struct sockaddr_un remote; + int t = sizeof(remote); + if ((sock2 = accept(sock, (struct sockaddr *)&remote, &t)) == -1) { + BLog(BLOG_ERROR, "accept() failed: %s (sock = %d)\n", strerror(errno), sock); + continue; + } + if (ancil_recv_fd(sock2, &fd)) { + BLog(BLOG_ERROR, "ancil_recv_fd: %s (sock = %d)\n", strerror(errno), sock2); + close(sock2); + } else { + close(sock2); + BLog(BLOG_INFO, "received fd = %d", fd); + break; + } + } + close(sock); struct BTap_init_data init_data; init_data.dev_type = BTAP_DEV_TUN; init_data.init_type = BTAP_INIT_FD; - init_data.init.fd.fd = options.tun_fd; + init_data.init.fd.fd = fd; init_data.init.fd.mtu = options.tun_mtu; if (!BTap_Init2(&device, &ss, init_data, device_error_handler, NULL)) { diff --git a/src/main/jni/libancillary/API b/src/main/jni/libancillary/API new file mode 100644 index 0000000000..b558995a07 --- /dev/null +++ b/src/main/jni/libancillary/API @@ -0,0 +1,139 @@ + This library provide an easy interface to the black magic that can be done + on Unix domain sockets, like passing file descriptors from one process to + another. + + Programs that uses this library should include the ancillary.h header file. + Nothing else is required. + + All functions of this library require the following header: + + #include + + At this time, the only ancillary data defined by the Single Unix + Specification (v3) is file descriptors. + +Passing file descriptors + + int ancil_send_fd(socket, file_descriptor) + int socket: the Unix socket + int file_descriptor: the file descriptor + Return value: 0 for success, -1 for failure. + + Sends one file descriptor on a socket. + In case of failure, errno is set; the possible values are the ones of the + sendmsg(2) system call. + + + int ancil_recv_fd(socket, file_descriptor) + int socket: the Unix socket + int *file_descriptor: pointer to the returned file descriptor + Return value: 0 for success, -1 for failure + + Receives one file descriptor from a socket. + In case of success, the file descriptor is stored in the integer pointed + to by file_descriptor. + In case of failure, errno is set; the possible values are the ones of the + recvmsg(2) system call. + The behavior is undefined if the recv_fd does not match a send_fd* on the + other side. + + + int ancil_send_fds(socket, file_descriptors, num_file_descriptors) + int socket: the Unix socket + const int *file_descriptors: array of file descriptors + unsigned num_file_descriptors: number of file descriptors + Return value: 0 for success, -1 for failure + + Sends several file descriptors on a socket. + In case of failure, errno is set; the possible values are the ones of the + sendmsg(2) system call. + The maximum number of file descriptors that can be sent using this + function is ANCIL_MAX_N_FDS; the behavior is undefined in case of + overflow, probably a stack corruption. + + + int ancil_recv_fds(socket, file_descriptors, num_file_descriptors) + int socket: the Unix socket + int *file_descriptors: return array of file descriptors + unsigned num_file_descriptors: number of file descriptors + Return value: number of received fd for success, -1 for failure + + Receives several file descriptors from a socket, no more than + num_file_descriptors. + In case of success, the received file descriptors are stored in the array + pointed to by file_descriptors. + In case of failure, errno is set; the possible values are the ones of the + recvmsg(2) system call. + The maximum number of file descriptors that can be received using this + function is ANCIL_MAX_N_FDS; the behavior is undefined in case of + overflow, probably a stack corruption. + The behavior is undefined if the recv_fds does not match a send_fd* on + the other side, or if the number of received file descriptors is more than + num_file_descriptors. + + + int ancil_send_fds_with_buffer(socket, fds, num, buffer) + int socket: the Unix socket + const int *fds: array of file descriptors + unsigned num: number of file descriptors + void *buffer: buffer to hold the system data structures + Return value: 0 for success, -1 for failure + + Sends several file descriptors on a socket. + In case of failure, errno is set; the possible values are the ones of the + sendmsg(2) system call. + The buffer argument must point to a memory area large enough to hold the + system data structures, see ANCIL_FD_BUFFER. + + + int ancil_send_fds_with_buffer(socket, fds, num, buffer) + int socket: the Unix socket + int *fds: return array of file descriptors + unsigned num: number of file descriptors + void *buffer: buffer to hold the system data structures + Return value: number of received fd for success, -1 for failure + + Receives several file descriptors from a socket, no more than + num_file_descriptors. + In case of success, the received file descriptors are stored in the array + pointed to by file_descriptors. + In case of failure, errno is set; the possible values are the ones of the + recvmsg(2) system call. + The behavior is undefined if the recv_fds does not match a send_fd* on + the other side, or if the number of received file descriptors is more than + num_file_descriptors. + The buffer argument must point to a memory area large enough to hold the + system data structures, see ANCIL_FD_BUFFER. + + + ANCIL_MAX_N_FDS + + Maximum number of file descriptors that can be sent with the sent_fds and + recv_fds functions. If you have to send more at once, use the + *_with_buffer versions. The value is enough to send "quite a few" file + descriptors. + + + ANCIL_FD_BUFFER(n) + int n: number of file descriptors + + Expands to a structure data type large enough to hold the system data + structures for n file descriptors. So the address of a variable declared + of type ANCIL_FD_BUFFER(n) is suitable as the buffer argument for + *_with_buffer on n file descriptors. + To use this macro, you need and . Bevare: with + Solaris, the _XPG4_2 macro must be defined before sys/socket is included. + + +Tuning the compilation + + This library is designed to be included in projects, not installed in + /usr/lib. If your project does not use some of the functions, the + TUNE_OPTS variable in the Makefile allows not to build them. It is a list + of proprocessor options: + + -DNDEBUG: turn assertions off (see assert(3)) + -DSPARE_SEND_FDS: do not build ancil_send_fds + -DSPARE_SEND_FD: do not build ancil_send_fd + -DSPARE_RECV_FDS: do not build ancil_recv_fds + -DSPARE_RECV_FD: do not build ancil_recv_fd diff --git a/src/main/jni/libancillary/COPYING b/src/main/jni/libancillary/COPYING new file mode 100644 index 0000000000..5bcd9c2bd0 --- /dev/null +++ b/src/main/jni/libancillary/COPYING @@ -0,0 +1,21 @@ +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. diff --git a/src/main/jni/libancillary/Makefile b/src/main/jni/libancillary/Makefile new file mode 100644 index 0000000000..3d32533f67 --- /dev/null +++ b/src/main/jni/libancillary/Makefile @@ -0,0 +1,73 @@ +########################################################################### +# libancillary - black magic on Unix domain sockets +# (C) Nicolas George +# Makefile - guess what +########################################################################### + +# 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. + +CC=gcc +CFLAGS=-Wall -g -O2 +LDFLAGS= +LIBS= +AR=ar +RANLIB=ranlib +RM=rm +CP=cp +MKDIR=mkdir +TAR=tar +GZIP=gzip -9 + +NAME=libancillary +DISTRIBUTION=API COPYING Makefile ancillary.h fd_send.c fd_recv.c test.c +VERSION=0.9.1 + +OBJECTS=fd_send.o fd_recv.o + +TUNE_OPTS=-DNDEBUG +#TUNE_OPTS=-DNDEBUG \ + -DSPARE_SEND_FDS -DSPARE_SEND_FD -DSPARE_RECV_FDS -DSPARE_RECV_FD + +.c.o: + $(CC) -c $(CFLAGS) $(TUNE_OPTS) $< + +all: libancillary.a + +libancillary.a: $(OBJECTS) + $(AR) cr $@ $(OBJECTS) + $(RANLIB) $@ + +fd_send.o: ancillary.h +fd_recv.o: ancillary.h + +test: test.c libancillary.a + $(CC) -o $@ $(CFLAGS) $(LDFLAGS) -L. test.c -lancillary $(LIBS) + +clean: + -$(RM) -f *.o *.a test + +dist: + $(MKDIR) $(NAME)-$(VERSION) + $(CP) $(DISTRIBUTION) $(NAME)-$(VERSION) + $(TAR) -cf - $(NAME)-$(VERSION) | $(GZIP) > $(NAME)-$(VERSION).tar.gz + $(RM) -rf $(NAME)-$(VERSION) diff --git a/src/main/jni/libancillary/ancillary.h b/src/main/jni/libancillary/ancillary.h new file mode 100644 index 0000000000..636d86777e --- /dev/null +++ b/src/main/jni/libancillary/ancillary.h @@ -0,0 +1,131 @@ +/*************************************************************************** + * libancillary - black magic on Unix domain sockets + * (C) Nicolas George + * ancillary.c - public header + ***************************************************************************/ + +/* + * 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. + */ + +#ifndef ANCILLARY_H__ +#define ANCILLARY_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/*************************************************************************** + * Start of the readable part. + ***************************************************************************/ + +#define ANCIL_MAX_N_FDS 960 +/* + * Maximum number of fds that can be sent or received using the "esay" + * functions; this is so that all can fit in one page. + */ + +extern int +ancil_send_fds_with_buffer(int, const int *, unsigned, void *); +/* + * ancil_send_fds_with_buffer(sock, n_fds, fds, buffer) + * + * Sends the file descriptors in the array pointed by fds, of length n_fds + * on the socket sock. + * buffer is a writeable memory area large enough to hold the required data + * structures. + * Returns: -1 and errno in case of error, 0 in case of success. + */ + +extern int +ancil_recv_fds_with_buffer(int, int *, unsigned, void *); +/* + * ancil_recv_fds_with_buffer(sock, n_fds, fds, buffer) + * + * Receives *n_fds file descriptors into the array pointed by fds + * from the socket sock. + * buffer is a writeable memory area large enough to hold the required data + * structures. + * Returns: -1 and errno in case of error, the actual number of received fd + * in case of success + */ + +#define ANCIL_FD_BUFFER(n) \ + struct { \ + struct cmsghdr h; \ + int fd[n]; \ + } +/* ANCIL_FD_BUFFER(n) + * + * A structure type suitable to be used as buffer for n file descriptors. + * Requires . + * Example: + * ANCIL_FD_BUFFER(42) buffer; + * ancil_recv_fds_with_buffer(sock, 42, my_fds, &buffer); + */ + +extern int +ancil_send_fds(int, const int *, unsigned); +/* + * ancil_send_fds(sock, n_fds, fds) + * + * Sends the file descriptors in the array pointed by fds, of length n_fds + * on the socket sock. + * n_fds must not be greater than ANCIL_MAX_N_FDS. + * Returns: -1 and errno in case of error, 0 in case of success. + */ + +extern int +ancil_recv_fds(int, int *, unsigned); +/* + * ancil_recv_fds(sock, n_fds, fds) + * + * Receives *n_fds file descriptors into the array pointed by fds + * from the socket sock. + * *n_fds must not be greater than ANCIL_MAX_N_FDS. + * Returns: -1 and errno in case of error, the actual number of received fd + * in case of success. + */ + + +extern int +ancil_send_fd(int, int); +/* ancil_recv_fd(sock, fd); + * + * Sends the file descriptor fd on the socket sock. + * Returns : -1 and errno in case of error, 0 in case of success. + */ + +extern int +ancil_recv_fd(int, int *); +/* ancil_send_fd(sock, &fd); + * + * Receives the file descriptor fd from the socket sock. + * Returns : -1 and errno in case of error, 0 in case of success. + */ + +#ifdef __cplusplus +} +#endif + +#endif /* ANCILLARY_H__ */ diff --git a/src/main/jni/libancillary/fd_recv.c b/src/main/jni/libancillary/fd_recv.c new file mode 100644 index 0000000000..46c2e69441 --- /dev/null +++ b/src/main/jni/libancillary/fd_recv.c @@ -0,0 +1,98 @@ +/*************************************************************************** + * libancillary - black magic on Unix domain sockets + * (C) Nicolas George + * fd_send.c - receiving file descriptors + ***************************************************************************/ + +/* + * 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. + */ + +#ifndef _XPG4_2 /* Solaris sucks */ +# define _XPG4_2 +#endif + +#include +#include +#include +#include +#include +#if defined(__FreeBSD__) +# include /* FreeBSD sucks */ +#endif + +#include "ancillary.h" + +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 = (msghdr.msg_controllen - sizeof(struct cmsghdr)) / sizeof(int); + return(n_fds); +} + +#ifndef SPARE_RECV_FDS +int +ancil_recv_fds(int sock, int *fd, unsigned n_fds) +{ + ANCIL_FD_BUFFER(ANCIL_MAX_N_FDS) buffer; + + assert(n_fds <= ANCIL_MAX_N_FDS); + return(ancil_recv_fds_with_buffer(sock, fd, n_fds, &buffer)); +} +#endif /* SPARE_RECV_FDS */ + +#ifndef SPARE_RECV_FD +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); +} +#endif /* SPARE_RECV_FD */ diff --git a/src/main/jni/libancillary/fd_send.c b/src/main/jni/libancillary/fd_send.c new file mode 100644 index 0000000000..01de87fd97 --- /dev/null +++ b/src/main/jni/libancillary/fd_send.c @@ -0,0 +1,92 @@ +/*************************************************************************** + * libancillary - black magic on Unix domain sockets + * (C) Nicolas George + * fd_send.c - sending file descriptors + ***************************************************************************/ + +/* + * 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. + */ + +#ifndef _XPG4_2 /* Solaris sucks */ +# define _XPG4_2 +#endif + +#include +#include +#include +#include +#include +#if defined(__FreeBSD__) +# include /* FreeBSD sucks */ +#endif + +#include "ancillary.h" + +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); +} + +#ifndef SPARE_SEND_FDS +int +ancil_send_fds(int sock, const int *fds, unsigned n_fds) +{ + ANCIL_FD_BUFFER(ANCIL_MAX_N_FDS) buffer; + + assert(n_fds <= ANCIL_MAX_N_FDS); + return(ancil_send_fds_with_buffer(sock, fds, n_fds, &buffer)); +} +#endif /* SPARE_SEND_FDS */ + +#ifndef SPARE_SEND_FD +int +ancil_send_fd(int sock, int fd) +{ + ANCIL_FD_BUFFER(1) buffer; + + return(ancil_send_fds_with_buffer(sock, &fd, 1, &buffer)); +} +#endif /* SPARE_SEND_FD */ diff --git a/src/main/jni/libancillary/test.c b/src/main/jni/libancillary/test.c new file mode 100644 index 0000000000..d3c1fdacd2 --- /dev/null +++ b/src/main/jni/libancillary/test.c @@ -0,0 +1,112 @@ +/*************************************************************************** + * libancillary - black magic on Unix domain sockets + * (C) Nicolas George + * test.c - testing and example program + ***************************************************************************/ + +/* + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include "ancillary.h" + +void child_process(int sock) +{ + int fd; + int fds[3], nfds; + char b[] = "This is on the received fd!\n"; + + if(ancil_recv_fd(sock, &fd)) { + perror("ancil_recv_fd"); + exit(1); + } else { + printf("Received fd: %d\n", fd); + } + write(fd, b, sizeof(b)); + close(fd); + sleep(2); + + nfds = ancil_recv_fds(sock, fds, 3); + if(nfds < 0) { + perror("ancil_recv_fds"); + exit(1); + } else { + printf("Received %d/3 fds : %d %d %d.\n", nfds, + fds[0], fds[1], fds[2]); + } +} + +void parent_process(int sock) +{ + int fds[2] = { 1, 2 }; + + if(ancil_send_fd(sock, 1)) { + perror("ancil_send_fd"); + exit(1); + } else { + printf("Sent fd.\n"); + } + sleep(1); + + if(ancil_send_fds(sock, fds, 2)) { + perror("ancil_send_fds"); + exit(1); + } else { + printf("Sent two fds.\n"); + } +} + +int main(void) +{ + int sock[2]; + + if(socketpair(PF_UNIX, SOCK_STREAM, 0, sock)) { + perror("socketpair"); + exit(1); + } else { + printf("Established socket pair: (%d, %d)\n", sock[0], sock[1]); + } + + switch(fork()) { + case 0: + close(sock[0]); + child_process(sock[1]); + break; + case -1: + perror("fork"); + exit(1); + default: + close(sock[1]); + parent_process(sock[0]); + wait(NULL); + break; + } + return(0); +} diff --git a/src/main/jni/system.cpp b/src/main/jni/system.cpp index e12a2bd021..8a44882d46 100644 --- a/src/main/jni/system.cpp +++ b/src/main/jni/system.cpp @@ -5,8 +5,15 @@ #include #include #include +#include #include +#include +#include +#include +#include +#include + #define LOGI(...) do { __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__); } while(0) #define LOGW(...) do { __android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__); } while(0) #define LOGE(...) do { __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__); } while(0) @@ -36,9 +43,40 @@ void Java_com_github_shadowsocks_system_exec(JNIEnv *env, jobject thiz, jstring env->ReleaseStringUTFChars(cmd, str); } +jint Java_com_github_shadowsocks_system_sendfd(JNIEnv *env, jobject thiz, jint tun_fd) { + int fd; + struct sockaddr_un addr; + + if ( (fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { + LOGE("socket() failed: %s (socket fd = %d)\n", strerror(errno), fd); + return (jint)-1; + } + + memset(&addr, 0, sizeof(addr)); + addr.sun_family = AF_UNIX; + strncpy(addr.sun_path, "/data/data/com.github.shadowsocks/sock_path", sizeof(addr.sun_path)-1); + + if (connect(fd, (struct sockaddr*)&addr, sizeof(addr)) == -1) { + LOGE("connect() failed: %s (fd = %d)\n", strerror(errno), fd); + close(fd); + return (jint)-1; + } + + if (ancil_send_fd(fd, tun_fd)) { + LOGE("ancil_send_fd: %s", strerror(errno)); + close(fd); + return (jint)-1; + } + + close(fd); + return 0; +} + static const char *classPathName = "com/github/shadowsocks/System"; static JNINativeMethod method_table[] = { + { "sendfd", "(I)I", + (void*) Java_com_github_shadowsocks_system_sendfd }, { "exec", "(Ljava/lang/String;)V", (void*) Java_com_github_shadowsocks_system_exec }, { "getABI", "()Ljava/lang/String;", diff --git a/src/main/scala/com/github/shadowsocks/ShadowsocksVpnService.scala b/src/main/scala/com/github/shadowsocks/ShadowsocksVpnService.scala index 776d378a40..53d8f0c62a 100644 --- a/src/main/scala/com/github/shadowsocks/ShadowsocksVpnService.scala +++ b/src/main/scala/com/github/shadowsocks/ShadowsocksVpnService.scala @@ -184,7 +184,7 @@ class ShadowsocksVpnService extends VpnService with BaseService { version } - def startVpn() { + def startVpn(): Int = { val builder = new Builder() builder @@ -310,7 +310,7 @@ class ShadowsocksVpnService extends VpnService with BaseService { if (conn == null) { stopRunner() - return + return -1 } val fd = conn.getFd @@ -336,7 +336,9 @@ class ShadowsocksVpnService extends VpnService with BaseService { if (BuildConfig.DEBUG) Log.d(TAG, cmd) - System.exec(cmd) + Console.runCommand(cmd.mkString(" ")) + + return fd; } /** Called when the activity is first created. */ @@ -346,8 +348,19 @@ class ShadowsocksVpnService extends VpnService with BaseService { startDnsDaemon() startDnsTunnel() } - startVpn() - true + + val fd = startVpn() + + if (fd == -1) { + false + } else { + Thread.sleep(1000) + if (System.sendfd(fd) == -1) { + false + } else { + true + } + } } override def onBind(intent: Intent): IBinder = { From 2f7424d07b96cf53ccd5190123176ac6b947f589 Mon Sep 17 00:00:00 2001 From: Max Lv Date: Wed, 22 Jul 2015 18:34:18 +0800 Subject: [PATCH 2/2] fix an issue --- src/main/jni/badvpn/tun2socks/tun2socks.c | 4 +++- .../scala/com/github/shadowsocks/ShadowsocksVpnService.scala | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/jni/badvpn/tun2socks/tun2socks.c b/src/main/jni/badvpn/tun2socks/tun2socks.c index 34d6cf2fc8..7396cc491b 100644 --- a/src/main/jni/badvpn/tun2socks/tun2socks.c +++ b/src/main/jni/badvpn/tun2socks/tun2socks.c @@ -502,9 +502,11 @@ int main (int argc, char **argv) goto fail2; } + char *path = "/data/data/com.github.shadowsocks/sock_path"; + unlink(path); memset(&addr, 0, sizeof(addr)); addr.sun_family = AF_UNIX; - strncpy(addr.sun_path, "/data/data/com.github.shadowsocks/sock_path", sizeof(addr.sun_path)-1); + strncpy(addr.sun_path, path, sizeof(addr.sun_path)-1); if (bind(sock, (struct sockaddr*)&addr, sizeof(addr)) == -1) { BLog(BLOG_ERROR, "bind() failed: %s (sock = %d)\n", strerror(errno), sock); diff --git a/src/main/scala/com/github/shadowsocks/ShadowsocksVpnService.scala b/src/main/scala/com/github/shadowsocks/ShadowsocksVpnService.scala index 53d8f0c62a..8eed974766 100644 --- a/src/main/scala/com/github/shadowsocks/ShadowsocksVpnService.scala +++ b/src/main/scala/com/github/shadowsocks/ShadowsocksVpnService.scala @@ -336,7 +336,7 @@ class ShadowsocksVpnService extends VpnService with BaseService { if (BuildConfig.DEBUG) Log.d(TAG, cmd) - Console.runCommand(cmd.mkString(" ")) + Console.runCommand(cmd) return fd; }