diff --git a/src/android.c b/src/android.c new file mode 100644 index 00000000..33a76eea --- /dev/null +++ b/src/android.c @@ -0,0 +1,93 @@ +/* + * 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 + +#include +#include +#include +#include +#include + +#include +#include + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "netutils.h" +#include "utils.h" + +int protect_socket(int fd) { + int sock; + struct sockaddr_un addr; + + if ( (sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { + LOGE("[android] socket() failed: %s (socket fd = %d)\n", strerror(errno), sock); + return -1; + } + + // Set timeout to 100us + struct timeval tv; + 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)); + + const char path[] = "/data/data/com.github.shadowsocks/protect_path"; + + memset(&addr, 0, sizeof(addr)); + addr.sun_family = AF_UNIX; + strncpy(addr.sun_path, path, sizeof(addr.sun_path)-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; + } + + if (ancil_send_fd(sock, fd)) { + ERROR("[android] ancil_send_fd"); + close(sock); + return -1; + } + + char ret = 0; + + if (recv(sock, &ret, 1, 0) == -1) { + ERROR("[android] recv"); + close(sock); + return -1; + } + + close(sock); + return ret; +} + diff --git a/src/common.h b/src/common.h index a63a8fdc..43a3183d 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(int fd); +#endif + +#endif // _COMMON_H diff --git a/src/local.c b/src/local.c index d67fd1d5..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; @@ -208,7 +211,9 @@ 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; + + r = recv(server->fd, buf, BUF_SIZE, 0); if (r == 0) { // connection closed @@ -251,6 +256,18 @@ static void server_recv_cb(EV_P_ ev_io *w, int revents) } if (!remote->send_ctx->connected) { + +#ifdef ANDROID + 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 + remote->buf_idx = 0; remote->buf_len = r; @@ -903,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) { @@ -957,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 cd5246d9..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__ @@ -602,6 +606,17 @@ static void accept_cb(EV_P_ ev_io *w, int revents) return; } +#ifdef ANDROID + if (vpn) { + 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 +635,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); @@ -652,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) { @@ -703,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 3ad70d5a..a3e7443c 100644 --- a/src/udprelay.c +++ b/src/udprelay.c @@ -86,6 +86,7 @@ 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 char *hash_key(const int af, const struct sockaddr_storage *addr); #ifdef UDPRELAY_REMOTE static void query_resolve_cb(struct sockaddr *addr, void *data); @@ -94,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 }; @@ -1058,6 +1060,15 @@ 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 + 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); if (s == -1) { diff --git a/src/udprelay.h b/src/udprelay.h index 4745162e..ec235906 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