From feed7cc1f965dba94ec8c8919bd9b5541f8464ce Mon Sep 17 00:00:00 2001 From: Max Lv Date: Fri, 24 Jul 2015 10:42:46 +0800 Subject: [PATCH 1/7] add android ipc function --- src/android.c | 203 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/android.h | 45 +++++++++++ src/local.c | 64 ++++++++++++---- 3 files changed, 299 insertions(+), 13 deletions(-) create mode 100644 src/android.c create mode 100644 src/android.h diff --git a/src/android.c b/src/android.c new file mode 100644 index 00000000..8a51ba43 --- /dev/null +++ b/src/android.c @@ -0,0 +1,203 @@ +/* + * android.c - Setup IPC for shadowsocks-android + * + * Copyright (C) 2013 - 2015, Max Lv + * + * This file is part of the shadowsocks-libev. + * + * shadowsocks-libev is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * shadowsocks-libev is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with shadowsocks-libev; see the file COPYING. If not, see + * . + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "netutils.h" +#include "utils.h" +#include "android.h" + +#ifndef EAGAIN +#define EAGAIN EWOULDBLOCK +#endif + +#ifndef EWOULDBLOCK +#define EWOULDBLOCK EAGAIN +#endif + +static void remote_recv_cb(EV_P_ ev_io *w, int revents); +static void remote_send_cb(EV_P_ ev_io *w, int revents); + +static struct remote * new_remote(int fd, int timeout); + +static void free_remote(struct remote *remote); +static void close_and_free_remote(EV_P_ struct remote *remote); + +int verbose = 0; + +static int setnonblocking(int fd) +{ + int flags; + if (-1 == (flags = fcntl(fd, F_GETFL, 0))) { + flags = 0; + } + return fcntl(fd, F_SETFL, flags | O_NONBLOCK); +} + +static void remote_timeout_cb(EV_P_ ev_timer *watcher, int revents) +{ + struct remote_ctx *remote_ctx = (struct remote_ctx *)(((void *)watcher) - sizeof(ev_io)); + struct remote *remote = remote_ctx->remote; + + if (verbose) { + LOGI("[android] IPC connection timeout"); + } + + remote->protect_cb(-1, remote->data); + close_and_free_remote(EV_A_ remote); +} + +static void remote_recv_cb(EV_P_ ev_io *w, int revents) +{ + struct remote_ctx *remote_recv_ctx = (struct remote_ctx *)w; + struct remote *remote = remote_recv_ctx->remote; + + int fd, ret = 0; + + if (ancil_recv_fd(remote->fd, &fd)) { + ERROR("[android] ancil_recv_fd"); + ret = -1; + } + + if (fd != remote->protect_fd) { + ret = -1; + } + + remote->protect_cb(ret, remote->data); + close_and_free_remote(remote); +} + +static void remote_send_cb(EV_P_ ev_io *w, int revents) +{ + struct remote_ctx *remote_send_ctx = (struct remote_ctx *)w; + struct remote *remote = remote_send_ctx->remote; + + int r = getpeername(remote->fd, (struct sockaddr *)&addr, &len); + + if (r == 0) { + ev_io_stop(EV_A_ & remote_send_ctx->io); + ev_timer_stop(EV_A_ & remote_send_ctx->watcher); + + if (ancil_send_fd(remote->fd, remote->protect_fd)) { + ERROR("[android] ancil_send_fd"); + remote->protect_cb(-1, remote->data); + close_and_free_remote(EV_A_ remote); + return; + } + + ev_io_start(EV_A_ & remote->recv_ctx->io); + ev_timer_start(EV_A_ & remote->recv_ctx->watcher); + } else { + ERROR("[android] getpeername"); + remote->protect_cb(-1, remote->data); + close_and_free_remote(EV_A_ remote); + return; + } +} + + +static struct remote * new_remote(int fd, int timeout) +{ + struct remote *remote; + remote = malloc(sizeof(struct remote)); + remote->recv_ctx = malloc(sizeof(struct remote_ctx)); + remote->send_ctx = malloc(sizeof(struct remote_ctx)); + remote->fd = fd; + ev_io_init(&remote->recv_ctx->io, remote_recv_cb, fd, EV_READ); + ev_io_init(&remote->send_ctx->io, remote_send_cb, fd, EV_WRITE); + ev_timer_init(&remote->send_ctx->watcher, remote_timeout_cb, timeout, 0); + ev_timer_init(&remote->recv_ctx->watcher, remote_timeout_cb, timeout, 0); + remote->recv_ctx->remote = remote; + remote->send_ctx->remote = remote; + return remote; +} + +static void free_remote(struct remote *remote) +{ + if (remote != NULL) { + free(remote->recv_ctx); + free(remote->send_ctx); + free(remote); + } +} + +static void close_and_free_remote(EV_P_ struct remote *remote) +{ + if (remote != NULL) { + ev_timer_stop(EV_A_ & remote->send_ctx->watcher); + ev_timer_stop(EV_A_ & remote->recv_ctx->watcher); + ev_io_stop(EV_A_ & remote->send_ctx->io); + ev_io_stop(EV_A_ & remote->recv_ctx->io); + close(remote->fd); + free_remote(remote); + } +} + +int protect_socket(void (*protect_cb)(int ret, void *data), void *data, int fd) { + // Inilitialize ev loop + struct ev_loop *loop = EV_DEFAULT; + + int remotefd; + struct sockaddr_un addr; + + // Setup + setnonblocking(remotefd); + + if ( (remotefd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { + LOGE("[android] socket() failed: %s (socket fd = %d)\n", strerror(errno), remotefd); + return -1; + } + + memset(&addr, 0, sizeof(addr)); + addr.sun_family = AF_UNIX; + strncpy(addr.sun_path, "/data/data/com.github.shadowsocks/protect_path", sizeof(addr.sun_path)-1); + + struct remote *remote = new_remote(remotefd, 100); + + remote->protect_fd = fd; + remote->protect_cb = protect_cb; + remote->data = data; + + if (connect(remotefd, (struct sockaddr*)&addr, sizeof(addr)) == -1) { + LOGE("[android] connect() failed: %s (fd = %d)\n", strerror(errno), remotefd); + close(remotefd); + return -1 + } + + // listen to remote connected event + ev_io_start(EV_A_ & remote->send_ctx->io); + ev_timer_start(EV_A_ & remote->send_ctx->watcher); + + return 0; +} + diff --git a/src/android.h b/src/android.h new file mode 100644 index 00000000..d7d430d8 --- /dev/null +++ b/src/android.h @@ -0,0 +1,45 @@ +/* + * android.h - Define Android IPC's buffers and callbacks + * + * Copyright (C) 2013 - 2015, Max Lv + * + * This file is part of the shadowsocks-libev. + * + * shadowsocks-libev is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * shadowsocks-libev is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with shadowsocks-libev; see the file COPYING. If not, see + * . + */ + +#ifndef _ANDROID_H +#define _ANDROID_H + +#include + +#include "common.h" + +struct remote_ctx { + ev_io io; + ev_timer watcher; + struct remote *remote; +}; + +struct remote { + int fd; + int protect_fd; + void *data; + void (*protect_cb)(int ret, void *data); + struct remote_ctx *recv_ctx; + struct remote_ctx *send_ctx; +}; + +#endif // _ANDROID_H diff --git a/src/local.c b/src/local.c index d67fd1d5..244a3197 100644 --- a/src/local.c +++ b/src/local.c @@ -67,6 +67,10 @@ #include "acl.h" #include "local.h" +#ifdef ANDROID +#include "android.h" +#endif + #ifndef EAGAIN #define EAGAIN EWOULDBLOCK #endif @@ -98,6 +102,8 @@ static void remote_send_cb(EV_P_ ev_io *w, int revents); static void accept_cb(EV_P_ ev_io *w, int revents); static void signal_cb(EV_P_ ev_signal *w, int revents); +static void protect_cb(int ret, void *data); + static int create_and_bind(const char *addr, const char *port); static struct remote * create_remote(struct listen_ctx *listener, struct sockaddr *addr); static void free_remote(struct remote *remote); @@ -195,6 +201,26 @@ static void free_connections(struct ev_loop *loop) } } +#ifdef ANDROID +static void protect_cb(int ret, void *data) { + struct remote_ctx *remote_ctx = (struct remote_ctx *)data; + struct remote *remote = remote_ctx->remote; + struct server *server = remote->server; + + if (verbose) { + LOGI("[android] one connection protected"); + } + + if (ret == -1) { + close_and_free_remote(EV_DEFAULT, remote); + close_and_free_remote(EV_DEFAULT, server); + return; + } + + server_recv_cb(EV_DEFAULT, server->recv_ctx, EV_CUSTOM); +} +#endif + static void server_recv_cb(EV_P_ ev_io *w, int revents) { struct server_ctx *server_recv_ctx = (struct server_ctx *)w; @@ -208,23 +234,27 @@ static void server_recv_cb(EV_P_ ev_io *w, int revents) buf = remote->buf; } - ssize_t r = recv(server->fd, buf, BUF_SIZE, 0); + ssize_t r; - if (r == 0) { - // connection closed - close_and_free_remote(EV_A_ remote); - close_and_free_server(EV_A_ server); - return; - } else if (r < 0) { - if (errno == EAGAIN || errno == EWOULDBLOCK) { - // no data - // continue to wait for recv - return; - } else { - ERROR("server_recv_cb_recv"); + if (revents != EV_CUSTOM) { + r = recv(server->fd, buf, BUF_SIZE, 0); + + if (r == 0) { + // connection closed close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; + } else if (r < 0) { + if (errno == EAGAIN || errno == EWOULDBLOCK) { + // no data + // continue to wait for recv + return; + } else { + ERROR("server_recv_cb_recv"); + close_and_free_remote(EV_A_ remote); + close_and_free_server(EV_A_ server); + return; + } } } @@ -237,6 +267,14 @@ static void server_recv_cb(EV_P_ ev_io *w, int revents) return; } +#ifdef ANDROID + if (revents != EV_CUSTOM) { + ev_io_stop(EV_A_ & server_recv_ctx->io); + protect_socket(protect_cb, (void*)remote, remote->fd); + return; + } +#endif + // insert shadowsocks header if (!remote->direct) { remote->buf = ss_encrypt(BUF_SIZE, remote->buf, &r, From 2c0dd4a33de832740239f70911a62aeb81046fdc Mon Sep 17 00:00:00 2001 From: Max Lv Date: Fri, 24 Jul 2015 10:55:29 +0800 Subject: [PATCH 2/7] fix some issues --- src/android.c | 18 +++++++++++++++--- src/common.h | 10 +++++++--- src/local.c | 4 ---- 3 files changed, 22 insertions(+), 10 deletions(-) diff --git a/src/android.c b/src/android.c index 8a51ba43..453dfcaf 100644 --- a/src/android.c +++ b/src/android.c @@ -29,6 +29,15 @@ #include #include +#include +#include +#include +#include +#include + +#include +#include + #ifdef HAVE_CONFIG_H #include "config.h" #endif @@ -53,7 +62,7 @@ static struct remote * new_remote(int fd, int timeout); static void free_remote(struct remote *remote); static void close_and_free_remote(EV_P_ struct remote *remote); -int verbose = 0; +extern int verbose; static int setnonblocking(int fd) { @@ -94,7 +103,7 @@ static void remote_recv_cb(EV_P_ ev_io *w, int revents) } remote->protect_cb(ret, remote->data); - close_and_free_remote(remote); + close_and_free_remote(EV_A_ remote); } static void remote_send_cb(EV_P_ ev_io *w, int revents) @@ -102,6 +111,9 @@ static void remote_send_cb(EV_P_ ev_io *w, int revents) struct remote_ctx *remote_send_ctx = (struct remote_ctx *)w; struct remote *remote = remote_send_ctx->remote; + struct sockaddr_storage addr; + socklen_t len = sizeof addr; + int r = getpeername(remote->fd, (struct sockaddr *)&addr, &len); if (r == 0) { @@ -191,7 +203,7 @@ int protect_socket(void (*protect_cb)(int ret, void *data), void *data, int fd) if (connect(remotefd, (struct sockaddr*)&addr, sizeof(addr)) == -1) { LOGE("[android] connect() failed: %s (fd = %d)\n", strerror(errno), remotefd); close(remotefd); - return -1 + return -1; } // listen to remote connected event diff --git a/src/common.h b/src/common.h index a63a8fdc..8e8492d3 100644 --- a/src/common.h +++ b/src/common.h @@ -19,8 +19,8 @@ * . */ -#ifndef _INCLUDE_H -#define _INCLUDE_H +#ifndef _COMMON_H +#define _COMMON_H // only enable TCP_FASTOPEN on linux #if __linux @@ -58,4 +58,8 @@ int init_udprelay(const char *server_host, const char *server_port, void free_udprelay(void); -#endif // _INCLUDE_H +#ifdef ANDROID +int protect_socket(void (*protect_cb)(int ret, void *data), void *data, int fd); +#endif + +#endif // _COMMON_H diff --git a/src/local.c b/src/local.c index 244a3197..22bf795a 100644 --- a/src/local.c +++ b/src/local.c @@ -67,10 +67,6 @@ #include "acl.h" #include "local.h" -#ifdef ANDROID -#include "android.h" -#endif - #ifndef EAGAIN #define EAGAIN EWOULDBLOCK #endif From 15010013a4d36e8fa2ceca0fe07c52778cc3e5b6 Mon Sep 17 00:00:00 2001 From: Max Lv Date: Fri, 24 Jul 2015 13:51:36 +0800 Subject: [PATCH 3/7] protect udp relay socket --- src/udprelay.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ src/udprelay.h | 10 ++++++++++ 2 files changed, 54 insertions(+) diff --git a/src/udprelay.c b/src/udprelay.c index 3ad70d5a..1341684f 100644 --- a/src/udprelay.c +++ b/src/udprelay.c @@ -86,6 +86,8 @@ static void server_recv_cb(EV_P_ ev_io *w, int revents); static void remote_recv_cb(EV_P_ ev_io *w, int revents); static void remote_timeout_cb(EV_P_ ev_timer *watcher, int revents); +static void protect_cb(int ret, void *data); + static char *hash_key(const int af, const struct sockaddr_storage *addr); #ifdef UDPRELAY_REMOTE static void query_resolve_cb(struct sockaddr *addr, void *data); @@ -98,6 +100,42 @@ extern int verbose; static int server_num = 0; static struct server_ctx *server_ctx_list[MAX_REMOTE_NUM] = { NULL }; +#ifdef ANDROID +static struct protect_ctx *new_protect_ctx(char *buf, int buf_len, + struct sockaddr *addr, int addr_len) { + struct protect_ctx *protect_ctx = (struct protect_ctx *)malloc(sizeof(struct protect_ctx)); + memset(protect_ctx, 0, sizeof(struct protect_ctx)); + + protect_ctx->buf = malloc(buf_len); + memcpy(protect_ctx->buf, buf, buf_len); + protect_ctx->buf_len = buf_len; + + memcpy(&protect_ctx->addr, (const char*)addr, addr_len); + protect_ctx->addr_len = addr_len; + + return protect_ctx; +} + +static void free_protect_ctx(struct protect_ctx *protect_ctx) { + if (protect_ctx != NULL) { + free(protect_ctx->buf); + free(protect_ctx); + } +} + +static void protect_cb(int ret, void *data) { + struct protect_ctx *protect_ctx = (struct protect_ctx*)data; + if (ret != -1) { + int s = sendto(protect_ctx->remote_ctx->fd, protect_ctx->buf, + protect_ctx->buf_len, 0, protect_ctx->addr, protect_ctx->addr_len); + if (s == -1) { + ERROR("[udp] sendto_remote"); + } + } + free_protect_ctx(protect_ctx); +} +#endif + #ifndef __MINGW32__ static int setnonblocking(int fd) { @@ -1058,11 +1096,17 @@ static void server_recv_cb(EV_P_ ev_io *w, int revents) buf = ss_encrypt_all(BUF_SIZE, buf, &buf_len, server_ctx->method); +#ifdef ANDROID + struct protect_ctx *protect_ctx = new_protect_ctx(buf, buf_len, &remote_addr, remote_addr_len); + protect_ctx->remote_ctx = remote_ctx; + protect_socket(protect_cb, (void*)protect_ctx, remote_ctx->fd); +#else int s = sendto(remote_ctx->fd, buf, buf_len, 0, remote_addr, remote_addr_len); if (s == -1) { ERROR("[udp] sendto_remote"); } +#endif #else diff --git a/src/udprelay.h b/src/udprelay.h index 4745162e..a6f89a37 100644 --- a/src/udprelay.h +++ b/src/udprelay.h @@ -82,4 +82,14 @@ struct remote_ctx { struct server_ctx *server_ctx; }; +#ifdef ANDROID +struct protect_ctx { + int buf_len; + char *buf; + struct sockaddr_storage addr; + int addr_len; + struct remote_ctx *remote_ctx; +} +#endif + #endif // _UDPRELAY_H From 87fb63654515f22943f833f3e31c4e99a95424f2 Mon Sep 17 00:00:00 2001 From: Max Lv Date: Fri, 24 Jul 2015 14:07:53 +0800 Subject: [PATCH 4/7] fix some issues --- src/android.c | 6 +++--- src/local.c | 4 ++-- src/udprelay.c | 2 +- src/udprelay.h | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/android.c b/src/android.c index 453dfcaf..639774dc 100644 --- a/src/android.c +++ b/src/android.c @@ -182,14 +182,14 @@ int protect_socket(void (*protect_cb)(int ret, void *data), void *data, int fd) int remotefd; struct sockaddr_un addr; - // Setup - setnonblocking(remotefd); - if ( (remotefd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { LOGE("[android] socket() failed: %s (socket fd = %d)\n", strerror(errno), remotefd); return -1; } + // Setup + setnonblocking(remotefd); + memset(&addr, 0, sizeof(addr)); addr.sun_family = AF_UNIX; strncpy(addr.sun_path, "/data/data/com.github.shadowsocks/protect_path", sizeof(addr.sun_path)-1); diff --git a/src/local.c b/src/local.c index 22bf795a..a784b794 100644 --- a/src/local.c +++ b/src/local.c @@ -209,11 +209,11 @@ static void protect_cb(int ret, void *data) { if (ret == -1) { close_and_free_remote(EV_DEFAULT, remote); - close_and_free_remote(EV_DEFAULT, server); + close_and_free_server(EV_DEFAULT, server); return; } - server_recv_cb(EV_DEFAULT, server->recv_ctx, EV_CUSTOM); + server_recv_cb(EV_DEFAULT, &server->recv_ctx->io, EV_CUSTOM); } #endif diff --git a/src/udprelay.c b/src/udprelay.c index 1341684f..15685d1e 100644 --- a/src/udprelay.c +++ b/src/udprelay.c @@ -127,7 +127,7 @@ static void protect_cb(int ret, void *data) { struct protect_ctx *protect_ctx = (struct protect_ctx*)data; if (ret != -1) { int s = sendto(protect_ctx->remote_ctx->fd, protect_ctx->buf, - protect_ctx->buf_len, 0, protect_ctx->addr, protect_ctx->addr_len); + protect_ctx->buf_len, 0, &protect_ctx->addr, protect_ctx->addr_len); if (s == -1) { ERROR("[udp] sendto_remote"); } diff --git a/src/udprelay.h b/src/udprelay.h index a6f89a37..ec235906 100644 --- a/src/udprelay.h +++ b/src/udprelay.h @@ -89,7 +89,7 @@ struct protect_ctx { struct sockaddr_storage addr; int addr_len; struct remote_ctx *remote_ctx; -} +}; #endif #endif // _UDPRELAY_H From 680007589c5aaafede801081e46b013b27c93939 Mon Sep 17 00:00:00 2001 From: Max Lv Date: Fri, 24 Jul 2015 18:55:19 +0800 Subject: [PATCH 5/7] fix a build issue --- src/android.c | 12 +++++------- src/udprelay.c | 13 ++++++++----- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/src/android.c b/src/android.c index 639774dc..3283711b 100644 --- a/src/android.c +++ b/src/android.c @@ -190,21 +190,19 @@ int protect_socket(void (*protect_cb)(int ret, void *data), void *data, int fd) // Setup setnonblocking(remotefd); + const char path[] = "/data/data/com.github.shadowsocks/protect_path"; + memset(&addr, 0, sizeof(addr)); addr.sun_family = AF_UNIX; - strncpy(addr.sun_path, "/data/data/com.github.shadowsocks/protect_path", sizeof(addr.sun_path)-1); + strncpy(addr.sun_path, path, sizeof(addr.sun_path)-1); - struct remote *remote = new_remote(remotefd, 100); + struct remote *remote = new_remote(remotefd, 1); remote->protect_fd = fd; remote->protect_cb = protect_cb; remote->data = data; - if (connect(remotefd, (struct sockaddr*)&addr, sizeof(addr)) == -1) { - LOGE("[android] connect() failed: %s (fd = %d)\n", strerror(errno), remotefd); - close(remotefd); - return -1; - } + connect(remotefd, (struct sockaddr*)&addr, sizeof(addr)); // listen to remote connected event ev_io_start(EV_A_ & remote->send_ctx->io); diff --git a/src/udprelay.c b/src/udprelay.c index 15685d1e..7161fd37 100644 --- a/src/udprelay.c +++ b/src/udprelay.c @@ -86,7 +86,10 @@ static void server_recv_cb(EV_P_ ev_io *w, int revents); static void remote_recv_cb(EV_P_ ev_io *w, int revents); static void remote_timeout_cb(EV_P_ ev_timer *watcher, int revents); + +#if defined(ANDROID) && !defined(UDPRELAY_TUNNEL) static void protect_cb(int ret, void *data); +#endif static char *hash_key(const int af, const struct sockaddr_storage *addr); #ifdef UDPRELAY_REMOTE @@ -100,9 +103,9 @@ extern int verbose; static int server_num = 0; static struct server_ctx *server_ctx_list[MAX_REMOTE_NUM] = { NULL }; -#ifdef ANDROID +#if defined(ANDROID) && !defined(UDPRELAY_TUNNEL) static struct protect_ctx *new_protect_ctx(char *buf, int buf_len, - struct sockaddr *addr, int addr_len) { + const struct sockaddr *addr, int addr_len) { struct protect_ctx *protect_ctx = (struct protect_ctx *)malloc(sizeof(struct protect_ctx)); memset(protect_ctx, 0, sizeof(struct protect_ctx)); @@ -127,7 +130,7 @@ static void protect_cb(int ret, void *data) { struct protect_ctx *protect_ctx = (struct protect_ctx*)data; if (ret != -1) { int s = sendto(protect_ctx->remote_ctx->fd, protect_ctx->buf, - protect_ctx->buf_len, 0, &protect_ctx->addr, protect_ctx->addr_len); + protect_ctx->buf_len, 0, (const struct sockaddr *)&protect_ctx->addr, protect_ctx->addr_len); if (s == -1) { ERROR("[udp] sendto_remote"); } @@ -1096,8 +1099,8 @@ static void server_recv_cb(EV_P_ ev_io *w, int revents) buf = ss_encrypt_all(BUF_SIZE, buf, &buf_len, server_ctx->method); -#ifdef ANDROID - struct protect_ctx *protect_ctx = new_protect_ctx(buf, buf_len, &remote_addr, remote_addr_len); +#if defined(ANDROID) && !defined(UDPRELAY_TUNNEL) + struct protect_ctx *protect_ctx = new_protect_ctx(buf, buf_len, remote_addr, remote_addr_len); protect_ctx->remote_ctx = remote_ctx; protect_socket(protect_cb, (void*)protect_ctx, remote_ctx->fd); #else From 94a1c4fa10c6af71600048e43b148f8e8b8ab8b2 Mon Sep 17 00:00:00 2001 From: Max Lv Date: Fri, 24 Jul 2015 20:42:22 +0800 Subject: [PATCH 6/7] use blocking IPC --- src/android.c | 176 ++++++++----------------------------------------- src/android.h | 45 ------------- src/common.h | 2 +- src/local.c | 68 +++++++------------ src/tunnel.c | 10 +++ src/udprelay.c | 53 ++------------- 6 files changed, 69 insertions(+), 285 deletions(-) delete mode 100644 src/android.h diff --git a/src/android.c b/src/android.c index 3283711b..793d6e6c 100644 --- a/src/android.c +++ b/src/android.c @@ -44,151 +44,22 @@ #include "netutils.h" #include "utils.h" -#include "android.h" -#ifndef EAGAIN -#define EAGAIN EWOULDBLOCK -#endif - -#ifndef EWOULDBLOCK -#define EWOULDBLOCK EAGAIN -#endif - -static void remote_recv_cb(EV_P_ ev_io *w, int revents); -static void remote_send_cb(EV_P_ ev_io *w, int revents); - -static struct remote * new_remote(int fd, int timeout); - -static void free_remote(struct remote *remote); -static void close_and_free_remote(EV_P_ struct remote *remote); - -extern int verbose; - -static int setnonblocking(int fd) -{ - int flags; - if (-1 == (flags = fcntl(fd, F_GETFL, 0))) { - flags = 0; - } - return fcntl(fd, F_SETFL, flags | O_NONBLOCK); -} - -static void remote_timeout_cb(EV_P_ ev_timer *watcher, int revents) -{ - struct remote_ctx *remote_ctx = (struct remote_ctx *)(((void *)watcher) - sizeof(ev_io)); - struct remote *remote = remote_ctx->remote; - - if (verbose) { - LOGI("[android] IPC connection timeout"); - } - - remote->protect_cb(-1, remote->data); - close_and_free_remote(EV_A_ remote); -} - -static void remote_recv_cb(EV_P_ ev_io *w, int revents) -{ - struct remote_ctx *remote_recv_ctx = (struct remote_ctx *)w; - struct remote *remote = remote_recv_ctx->remote; - - int fd, ret = 0; - - if (ancil_recv_fd(remote->fd, &fd)) { - ERROR("[android] ancil_recv_fd"); - ret = -1; - } - - if (fd != remote->protect_fd) { - ret = -1; - } - - remote->protect_cb(ret, remote->data); - close_and_free_remote(EV_A_ remote); -} - -static void remote_send_cb(EV_P_ ev_io *w, int revents) -{ - struct remote_ctx *remote_send_ctx = (struct remote_ctx *)w; - struct remote *remote = remote_send_ctx->remote; - - struct sockaddr_storage addr; - socklen_t len = sizeof addr; - - int r = getpeername(remote->fd, (struct sockaddr *)&addr, &len); - - if (r == 0) { - ev_io_stop(EV_A_ & remote_send_ctx->io); - ev_timer_stop(EV_A_ & remote_send_ctx->watcher); - - if (ancil_send_fd(remote->fd, remote->protect_fd)) { - ERROR("[android] ancil_send_fd"); - remote->protect_cb(-1, remote->data); - close_and_free_remote(EV_A_ remote); - return; - } - - ev_io_start(EV_A_ & remote->recv_ctx->io); - ev_timer_start(EV_A_ & remote->recv_ctx->watcher); - } else { - ERROR("[android] getpeername"); - remote->protect_cb(-1, remote->data); - close_and_free_remote(EV_A_ remote); - return; - } -} - - -static struct remote * new_remote(int fd, int timeout) -{ - struct remote *remote; - remote = malloc(sizeof(struct remote)); - remote->recv_ctx = malloc(sizeof(struct remote_ctx)); - remote->send_ctx = malloc(sizeof(struct remote_ctx)); - remote->fd = fd; - ev_io_init(&remote->recv_ctx->io, remote_recv_cb, fd, EV_READ); - ev_io_init(&remote->send_ctx->io, remote_send_cb, fd, EV_WRITE); - ev_timer_init(&remote->send_ctx->watcher, remote_timeout_cb, timeout, 0); - ev_timer_init(&remote->recv_ctx->watcher, remote_timeout_cb, timeout, 0); - remote->recv_ctx->remote = remote; - remote->send_ctx->remote = remote; - return remote; -} - -static void free_remote(struct remote *remote) -{ - if (remote != NULL) { - free(remote->recv_ctx); - free(remote->send_ctx); - free(remote); - } -} - -static void close_and_free_remote(EV_P_ struct remote *remote) -{ - if (remote != NULL) { - ev_timer_stop(EV_A_ & remote->send_ctx->watcher); - ev_timer_stop(EV_A_ & remote->recv_ctx->watcher); - ev_io_stop(EV_A_ & remote->send_ctx->io); - ev_io_stop(EV_A_ & remote->recv_ctx->io); - close(remote->fd); - free_remote(remote); - } -} - -int protect_socket(void (*protect_cb)(int ret, void *data), void *data, int fd) { - // Inilitialize ev loop - struct ev_loop *loop = EV_DEFAULT; - - int remotefd; +int protect_socket(int fd) { + int sock, recvfd; struct sockaddr_un addr; - if ( (remotefd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { - LOGE("[android] socket() failed: %s (socket fd = %d)\n", strerror(errno), remotefd); + if ( (sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { + LOGE("[android] socket() failed: %s (socket fd = %d)\n", strerror(errno), sock); return -1; } - // Setup - setnonblocking(remotefd); + // Set timeout to 100us + struct timeval tv; + tv.tv_sec = 0; /* 30 Secs Timeout */ + tv.tv_usec = 1000; // Not init'ing this can cause strange errors + setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(struct timeval)); + setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (char *)&tv, sizeof(struct timeval)); const char path[] = "/data/data/com.github.shadowsocks/protect_path"; @@ -196,18 +67,27 @@ int protect_socket(void (*protect_cb)(int ret, void *data), void *data, int fd) addr.sun_family = AF_UNIX; strncpy(addr.sun_path, path, sizeof(addr.sun_path)-1); - struct remote *remote = new_remote(remotefd, 1); + if (connect(sock, (struct sockaddr*)&addr, sizeof(addr)) == -1) { + LOGE("[android] connect() failed: %s (socket fd = %d)\n", strerror(errno), sock); + close(sock); + return -1; + } - remote->protect_fd = fd; - remote->protect_cb = protect_cb; - remote->data = data; + if (ancil_send_fd(sock, fd)) { + ERROR("[android] ancil_send_fd"); + close(sock); + return -1; + } - connect(remotefd, (struct sockaddr*)&addr, sizeof(addr)); + char ret = 0; - // listen to remote connected event - ev_io_start(EV_A_ & remote->send_ctx->io); - ev_timer_start(EV_A_ & remote->send_ctx->watcher); + if (recv(sock, &ret, 1, 0) == -1) { + ERROR("[android] recv"); + close(sock); + return -1; + } - return 0; + close(sock); + return ret; } diff --git a/src/android.h b/src/android.h deleted file mode 100644 index d7d430d8..00000000 --- a/src/android.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * android.h - Define Android IPC's buffers and callbacks - * - * Copyright (C) 2013 - 2015, Max Lv - * - * This file is part of the shadowsocks-libev. - * - * shadowsocks-libev is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * shadowsocks-libev is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with shadowsocks-libev; see the file COPYING. If not, see - * . - */ - -#ifndef _ANDROID_H -#define _ANDROID_H - -#include - -#include "common.h" - -struct remote_ctx { - ev_io io; - ev_timer watcher; - struct remote *remote; -}; - -struct remote { - int fd; - int protect_fd; - void *data; - void (*protect_cb)(int ret, void *data); - struct remote_ctx *recv_ctx; - struct remote_ctx *send_ctx; -}; - -#endif // _ANDROID_H diff --git a/src/common.h b/src/common.h index 8e8492d3..43a3183d 100644 --- a/src/common.h +++ b/src/common.h @@ -59,7 +59,7 @@ int init_udprelay(const char *server_host, const char *server_port, void free_udprelay(void); #ifdef ANDROID -int protect_socket(void (*protect_cb)(int ret, void *data), void *data, int fd); +int protect_socket(int fd); #endif #endif // _COMMON_H diff --git a/src/local.c b/src/local.c index a784b794..8f7c239b 100644 --- a/src/local.c +++ b/src/local.c @@ -98,8 +98,6 @@ static void remote_send_cb(EV_P_ ev_io *w, int revents); static void accept_cb(EV_P_ ev_io *w, int revents); static void signal_cb(EV_P_ ev_signal *w, int revents); -static void protect_cb(int ret, void *data); - static int create_and_bind(const char *addr, const char *port); static struct remote * create_remote(struct listen_ctx *listener, struct sockaddr *addr); static void free_remote(struct remote *remote); @@ -197,26 +195,6 @@ static void free_connections(struct ev_loop *loop) } } -#ifdef ANDROID -static void protect_cb(int ret, void *data) { - struct remote_ctx *remote_ctx = (struct remote_ctx *)data; - struct remote *remote = remote_ctx->remote; - struct server *server = remote->server; - - if (verbose) { - LOGI("[android] one connection protected"); - } - - if (ret == -1) { - close_and_free_remote(EV_DEFAULT, remote); - close_and_free_server(EV_DEFAULT, server); - return; - } - - server_recv_cb(EV_DEFAULT, &server->recv_ctx->io, EV_CUSTOM); -} -#endif - static void server_recv_cb(EV_P_ ev_io *w, int revents) { struct server_ctx *server_recv_ctx = (struct server_ctx *)w; @@ -232,25 +210,23 @@ static void server_recv_cb(EV_P_ ev_io *w, int revents) ssize_t r; - if (revents != EV_CUSTOM) { - r = recv(server->fd, buf, BUF_SIZE, 0); + r = recv(server->fd, buf, BUF_SIZE, 0); - if (r == 0) { - // connection closed + if (r == 0) { + // connection closed + close_and_free_remote(EV_A_ remote); + close_and_free_server(EV_A_ server); + return; + } else if (r < 0) { + if (errno == EAGAIN || errno == EWOULDBLOCK) { + // no data + // continue to wait for recv + return; + } else { + ERROR("server_recv_cb_recv"); close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; - } else if (r < 0) { - if (errno == EAGAIN || errno == EWOULDBLOCK) { - // no data - // continue to wait for recv - return; - } else { - ERROR("server_recv_cb_recv"); - close_and_free_remote(EV_A_ remote); - close_and_free_server(EV_A_ server); - return; - } } } @@ -263,14 +239,6 @@ static void server_recv_cb(EV_P_ ev_io *w, int revents) return; } -#ifdef ANDROID - if (revents != EV_CUSTOM) { - ev_io_stop(EV_A_ & server_recv_ctx->io); - protect_socket(protect_cb, (void*)remote, remote->fd); - return; - } -#endif - // insert shadowsocks header if (!remote->direct) { remote->buf = ss_encrypt(BUF_SIZE, remote->buf, &r, @@ -285,6 +253,16 @@ static void server_recv_cb(EV_P_ ev_io *w, int revents) } if (!remote->send_ctx->connected) { + +#ifdef ANDROID + if (protect_socket(remote->fd) == -1) { + ERROR("protect_socket"); + close_and_free_remote(EV_A_ remote); + close_and_free_server(EV_A_ server); + return; + } +#endif + remote->buf_idx = 0; remote->buf_len = r; diff --git a/src/tunnel.c b/src/tunnel.c index cd5246d9..f975339c 100644 --- a/src/tunnel.c +++ b/src/tunnel.c @@ -602,6 +602,15 @@ static void accept_cb(EV_P_ ev_io *w, int revents) return; } +#ifdef ANDROID + if (protect_socket(remotefd) == -1) { + ERROR("protect_socket"); + close(remotefd); + return; + } +#endif + + setsockopt(remotefd, SOL_TCP, TCP_NODELAY, &opt, sizeof(opt)); #ifdef SO_NOSIGPIPE setsockopt(remotefd, SOL_SOCKET, SO_NOSIGPIPE, &opt, sizeof(opt)); @@ -620,6 +629,7 @@ static void accept_cb(EV_P_ ev_io *w, int revents) server->destaddr = listener->tunnel_addr; server->remote = remote; remote->server = server; + connect(remotefd, remote_addr, get_sockaddr_len(remote_addr)); // listen to remote connected event ev_io_start(EV_A_ & remote->send_ctx->io); diff --git a/src/udprelay.c b/src/udprelay.c index 7161fd37..6c772b98 100644 --- a/src/udprelay.c +++ b/src/udprelay.c @@ -87,10 +87,6 @@ static void server_recv_cb(EV_P_ ev_io *w, int revents); static void remote_recv_cb(EV_P_ ev_io *w, int revents); static void remote_timeout_cb(EV_P_ ev_timer *watcher, int revents); -#if defined(ANDROID) && !defined(UDPRELAY_TUNNEL) -static void protect_cb(int ret, void *data); -#endif - static char *hash_key(const int af, const struct sockaddr_storage *addr); #ifdef UDPRELAY_REMOTE static void query_resolve_cb(struct sockaddr *addr, void *data); @@ -103,42 +99,6 @@ extern int verbose; static int server_num = 0; static struct server_ctx *server_ctx_list[MAX_REMOTE_NUM] = { NULL }; -#if defined(ANDROID) && !defined(UDPRELAY_TUNNEL) -static struct protect_ctx *new_protect_ctx(char *buf, int buf_len, - const struct sockaddr *addr, int addr_len) { - struct protect_ctx *protect_ctx = (struct protect_ctx *)malloc(sizeof(struct protect_ctx)); - memset(protect_ctx, 0, sizeof(struct protect_ctx)); - - protect_ctx->buf = malloc(buf_len); - memcpy(protect_ctx->buf, buf, buf_len); - protect_ctx->buf_len = buf_len; - - memcpy(&protect_ctx->addr, (const char*)addr, addr_len); - protect_ctx->addr_len = addr_len; - - return protect_ctx; -} - -static void free_protect_ctx(struct protect_ctx *protect_ctx) { - if (protect_ctx != NULL) { - free(protect_ctx->buf); - free(protect_ctx); - } -} - -static void protect_cb(int ret, void *data) { - struct protect_ctx *protect_ctx = (struct protect_ctx*)data; - if (ret != -1) { - int s = sendto(protect_ctx->remote_ctx->fd, protect_ctx->buf, - protect_ctx->buf_len, 0, (const struct sockaddr *)&protect_ctx->addr, protect_ctx->addr_len); - if (s == -1) { - ERROR("[udp] sendto_remote"); - } - } - free_protect_ctx(protect_ctx); -} -#endif - #ifndef __MINGW32__ static int setnonblocking(int fd) { @@ -1099,17 +1059,18 @@ static void server_recv_cb(EV_P_ ev_io *w, int revents) buf = ss_encrypt_all(BUF_SIZE, buf, &buf_len, server_ctx->method); -#if defined(ANDROID) && !defined(UDPRELAY_TUNNEL) - struct protect_ctx *protect_ctx = new_protect_ctx(buf, buf_len, remote_addr, remote_addr_len); - protect_ctx->remote_ctx = remote_ctx; - protect_socket(protect_cb, (void*)protect_ctx, remote_ctx->fd); -#else +#if defined(ANDROID) + if (protect_socket(remote_ctx->fd) == -1) { + ERROR("protect_socket"); + close_and_free_remote(EV_A_ remote_ctx); + goto CLEAN_UP; + } +#endif int s = sendto(remote_ctx->fd, buf, buf_len, 0, remote_addr, remote_addr_len); if (s == -1) { ERROR("[udp] sendto_remote"); } -#endif #else From 3d2b98016149ddf4c0c6912b16f56f2a56cb658b Mon Sep 17 00:00:00 2001 From: Max Lv Date: Fri, 24 Jul 2015 21:38:12 +0800 Subject: [PATCH 7/7] add android vpn mode option --- src/android.c | 6 +++--- src/local.c | 25 ++++++++++++++++++++----- src/tunnel.c | 23 +++++++++++++++++++---- src/udprelay.c | 13 ++++++++----- 4 files changed, 50 insertions(+), 17 deletions(-) diff --git a/src/android.c b/src/android.c index 793d6e6c..33a76eea 100644 --- a/src/android.c +++ b/src/android.c @@ -46,7 +46,7 @@ #include "utils.h" int protect_socket(int fd) { - int sock, recvfd; + int sock; struct sockaddr_un addr; if ( (sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { @@ -56,8 +56,8 @@ int protect_socket(int fd) { // Set timeout to 100us struct timeval tv; - tv.tv_sec = 0; /* 30 Secs Timeout */ - tv.tv_usec = 1000; // Not init'ing this can cause strange errors + tv.tv_sec = 1; /* 0 Secs Timeout */ + tv.tv_usec = 0; // Not init'ing this can cause strange errors setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(struct timeval)); setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (char *)&tv, sizeof(struct timeval)); diff --git a/src/local.c b/src/local.c index 8f7c239b..c0388949 100644 --- a/src/local.c +++ b/src/local.c @@ -80,6 +80,9 @@ #endif int verbose = 0; +#ifdef ANDROID +int vpn = 0; +#endif static int acl = 0; static int mode = TCP_ONLY; @@ -255,11 +258,13 @@ static void server_recv_cb(EV_P_ ev_io *w, int revents) if (!remote->send_ctx->connected) { #ifdef ANDROID - if (protect_socket(remote->fd) == -1) { - ERROR("protect_socket"); - close_and_free_remote(EV_A_ remote); - close_and_free_server(EV_A_ server); - return; + if (vpn) { + if (protect_socket(remote->fd) == -1) { + ERROR("protect_socket"); + close_and_free_remote(EV_A_ remote); + close_and_free_server(EV_A_ server); + return; + } } #endif @@ -915,8 +920,13 @@ int main(int argc, char **argv) USE_TTY(); +#ifdef ANDROID + while ((c = getopt_long(argc, argv, "f:s:p:l:k:t:m:i:c:b:a:uvV", + long_options, &option_index)) != -1) { +#else while ((c = getopt_long(argc, argv, "f:s:p:l:k:t:m:i:c:b:a:uv", long_options, &option_index)) != -1) { +#endif switch (c) { case 0: if (option_index == 0) { @@ -969,6 +979,11 @@ int main(int argc, char **argv) case 'v': verbose = 1; break; +#ifdef ANDROID + case 'V': + vpn = 1; + break; +#endif } } diff --git a/src/tunnel.c b/src/tunnel.c index f975339c..1407319f 100644 --- a/src/tunnel.c +++ b/src/tunnel.c @@ -85,7 +85,11 @@ static void close_and_free_remote(EV_P_ struct remote *remote); static void free_server(struct server *server); static void close_and_free_server(EV_P_ struct server *server); +#ifdef ANDROID +int vpn = 0; +#endif int verbose = 0; + static int mode = TCP_ONLY; #ifndef __MINGW32__ @@ -603,10 +607,12 @@ static void accept_cb(EV_P_ ev_io *w, int revents) } #ifdef ANDROID - if (protect_socket(remotefd) == -1) { - ERROR("protect_socket"); - close(remotefd); - return; + if (vpn) { + if (protect_socket(remotefd) == -1) { + ERROR("protect_socket"); + close(remotefd); + return; + } } #endif @@ -662,7 +668,11 @@ int main(int argc, char **argv) USE_TTY(); +#ifdef ANDROID + while ((c = getopt(argc, argv, "f:s:p:l:k:t:m:i:c:b:L:a:uUvV")) != -1) { +#else while ((c = getopt(argc, argv, "f:s:p:l:k:t:m:i:c:b:L:a:uUv")) != -1) { +#endif switch (c) { case 's': if (remote_num < MAX_REMOTE_NUM) { @@ -713,6 +723,11 @@ int main(int argc, char **argv) case 'v': verbose = 1; break; +#ifdef ANDROID + case 'V': + vpn = 1; + break; +#endif } } diff --git a/src/udprelay.c b/src/udprelay.c index 6c772b98..a3e7443c 100644 --- a/src/udprelay.c +++ b/src/udprelay.c @@ -95,6 +95,7 @@ static void close_and_free_remote(EV_P_ struct remote_ctx *ctx); static struct remote_ctx * new_remote(int fd, struct server_ctx * server_ctx); extern int verbose; +extern int vpn; static int server_num = 0; static struct server_ctx *server_ctx_list[MAX_REMOTE_NUM] = { NULL }; @@ -1059,11 +1060,13 @@ static void server_recv_cb(EV_P_ ev_io *w, int revents) buf = ss_encrypt_all(BUF_SIZE, buf, &buf_len, server_ctx->method); -#if defined(ANDROID) - if (protect_socket(remote_ctx->fd) == -1) { - ERROR("protect_socket"); - close_and_free_remote(EV_A_ remote_ctx); - goto CLEAN_UP; +#ifdef ANDROID + if (vpn) { + if (protect_socket(remote_ctx->fd) == -1) { + ERROR("protect_socket"); + close_and_free_remote(EV_A_ remote_ctx); + goto CLEAN_UP; + } } #endif int s = sendto(remote_ctx->fd, buf, buf_len, 0, remote_addr, remote_addr_len);