|
|
@ -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; |
|
|
|
} |
|
|
|
|