Browse Source

add UDP relay only mode

pull/338/head
Max Lv 9 years ago
parent
commit
ea9d293abe
7 changed files with 192 additions and 130 deletions
  1. 4
      src/common.h
  2. 139
      src/local.c
  3. 47
      src/redir.c
  4. 75
      src/server.c
  5. 4
      src/shadowsocks.h
  6. 46
      src/tunnel.c
  7. 7
      src/utils.c

4
src/common.h

@ -43,6 +43,10 @@
#define SOL_TCP IPPROTO_TCP
#endif
#define TCP_ONLY 0
#define TCP_AND_UDP 1
#define UDP_ONLY 3
int init_udprelay(const char *server_host, const char *server_port,
#ifdef UDPRELAY_LOCAL
const struct sockaddr *remote_addr, const int remote_addr_len,

139
src/local.c

@ -79,9 +79,11 @@
#define BUF_SIZE 2048
#endif
int acl = 0;
int verbose = 0;
int udprelay = 0;
static int acl = 0;
static int mode = TCP_ONLY;
static int fast_open = 0;
#ifdef HAVE_SETRLIMIT
#ifndef LIB_ONLY
@ -342,7 +344,7 @@ static void server_recv_cb(EV_P_ ev_io *w, int revents)
int udp_assc = 0;
if (udprelay && request->cmd == 3) {
if (mode != TCP_ONLY && request->cmd == 3) {
udp_assc = 1;
socklen_t addr_len = sizeof(sock_addr);
getsockname(server->fd, (struct sockaddr *)&sock_addr,
@ -429,7 +431,7 @@ static void server_recv_cb(EV_P_ ev_io *w, int revents)
LOGI("connect to %s:%s", host, port);
}
if ((acl && (request->atyp == 1 || request->atyp == 3) && acl_contains_ip(host))) {
if ((acl && (request->atyp == 1 || request->atyp == 4) && acl_contains_ip(host))) {
if (verbose) {
LOGI("bypass %s:%s", host, port);
}
@ -901,7 +903,7 @@ int main(int argc, char **argv)
USE_TTY();
while ((c = getopt_long(argc, argv, "f:s:p:l:k:t:m:i:c:b:a:uv",
while ((c = getopt_long(argc, argv, "f:s:p:l:k:t:m:i:c:b:a:uUv",
long_options, &option_index)) != -1) {
switch (c) {
case 0:
@ -950,7 +952,10 @@ int main(int argc, char **argv)
user = optarg;
break;
case 'u':
udprelay = 1;
mode = TCP_AND_UDP;
break;
case 'U':
mode = UDP_ONLY;
break;
case 'v':
verbose = 1;
@ -1060,18 +1065,6 @@ int main(int argc, char **argv)
LOGI("initialize ciphers... %s", method);
int m = enc_init(password, method);
// Setup socket
int listenfd;
listenfd = create_and_bind(local_addr, local_port);
if (listenfd < 0) {
FATAL("bind() error");
}
if (listen(listenfd, SOMAXCONN) == -1) {
FATAL("listen() error");
}
setnonblocking(listenfd);
LOGI("listening at %s:%s", local_addr, local_port);
// Setup proxy context
struct listen_ctx listen_ctx;
listen_ctx.remote_num = remote_num;
@ -1079,7 +1072,7 @@ int main(int argc, char **argv)
for (i = 0; i < remote_num; i++) {
char *host = remote_addr[i].host;
char *port = remote_addr[i].port == NULL ? remote_port :
remote_addr[i].port;
remote_addr[i].port;
struct sockaddr_storage *storage = malloc(sizeof(struct sockaddr_storage));
memset(storage, 0, sizeof(struct sockaddr_storage));
if (get_sockaddr(host, port, storage, 1) == -1) {
@ -1088,21 +1081,38 @@ int main(int argc, char **argv)
listen_ctx.remote_addr[i] = (struct sockaddr *)storage;
}
listen_ctx.timeout = atoi(timeout);
listen_ctx.fd = listenfd;
listen_ctx.iface = iface;
listen_ctx.method = m;
struct ev_loop *loop = EV_DEFAULT;
ev_io_init(&listen_ctx.io, accept_cb, listenfd, EV_READ);
ev_io_start(loop, &listen_ctx.io);
if (mode != UDP_ONLY) {
// Setup socket
int listenfd;
listenfd = create_and_bind(local_addr, local_port);
if (listenfd < 0) {
FATAL("bind() error");
}
if (listen(listenfd, SOMAXCONN) == -1) {
FATAL("listen() error");
}
setnonblocking(listenfd);
listen_ctx.fd = listenfd;
ev_io_init(&listen_ctx.io, accept_cb, listenfd, EV_READ);
ev_io_start(loop, &listen_ctx.io);
}
// Setup UDP
if (udprelay) {
if (mode != TCP_ONLY) {
LOGI("udprelay enabled");
init_udprelay(local_addr, local_port, listen_ctx.remote_addr[0],
get_sockaddr_len(listen_ctx.remote_addr[0]), m, listen_ctx.timeout, iface);
}
LOGI("listening at %s:%s", local_addr, local_port);
// setuid
if (user != NULL) {
run_as(user);
@ -1119,10 +1129,15 @@ int main(int argc, char **argv)
}
// Clean up
free_connections(loop);
free_udprelay();
if (mode != UDP_ONLY) {
ev_io_stop(loop, &listen_ctx.io);
free_connections(loop);
}
if (mode != TCP_ONLY) {
free_udprelay();
}
ev_io_stop(loop, &listen_ctx.io);
for (i = 0; i < remote_num; i++) {
free(listen_ctx.remote_addr[i]);
}
@ -1153,7 +1168,7 @@ int start_ss_local_server(profile_t profile)
int local_port = profile.local_port;
int timeout = profile.timeout;
udprelay = profile.udp_relay;
mode = profile.mode;
fast_open = profile.fast_open;
verbose = profile.verbose;
@ -1191,50 +1206,57 @@ int start_ss_local_server(profile_t profile)
LOGI("initialize ciphers... %s", method);
int m = enc_init(password, method);
// Setup socket
int listenfd;
listenfd = create_and_bind(local_addr, local_port_str);
if (listenfd < 0) {
ERROR("bind()");
return -1;
}
if (listen(listenfd, SOMAXCONN) == -1) {
ERROR("listen()");
struct sockaddr_storage *storage = malloc(sizeof(struct sockaddr_storage));
memset(storage, 0, sizeof(struct sockaddr_storage));
if (get_sockaddr(remote_host, remote_port_str, storage, 1) == -1) {
return -1;
}
setnonblocking(listenfd);
LOGI("listening at %s:%s", local_addr, local_port_str);
// Setup proxy context
struct ev_loop *loop = EV_DEFAULT;
struct listen_ctx listen_ctx;
listen_ctx.remote_num = 1;
listen_ctx.remote_addr = malloc(sizeof(struct sockaddr *));
struct sockaddr_storage *storage = malloc(sizeof(struct sockaddr_storage));
memset(storage, 0, sizeof(struct sockaddr_storage));
if (get_sockaddr(remote_host, remote_port_str, storage, 1) == -1) {
return -1;
}
listen_ctx.remote_addr[0] = (struct sockaddr *)storage;
listen_ctx.timeout = timeout;
listen_ctx.fd = listenfd;
listen_ctx.method = m;
listen_ctx.iface = NULL;
struct ev_loop *loop = EV_DEFAULT;
ev_io_init(&listen_ctx.io, accept_cb, listenfd, EV_READ);
ev_io_start(loop, &listen_ctx.io);
if (mode != UDP_ONLY) {
// Setup socket
int listenfd;
listenfd = create_and_bind(local_addr, local_port_str);
if (listenfd < 0) {
ERROR("bind()");
return -1;
}
if (listen(listenfd, SOMAXCONN) == -1) {
ERROR("listen()");
return -1;
}
setnonblocking(listenfd);
listen_ctx.fd = listenfd;
ev_io_init(&listen_ctx.io, accept_cb, listenfd, EV_READ);
ev_io_start(loop, &listen_ctx.io);
}
// Setup UDP
if (udprelay) {
if (mode != TCP_ONLY) {
LOGI("udprelay enabled");
init_udprelay(local_addr, local_port_str, listen_ctx.remote_addr[0],
get_sockaddr_len(listen_ctx.remote_addr[0]), m,
listen_ctx.timeout, NULL);
struct sockaddr *addr = (struct sockaddr *)storage;
init_udprelay(local_addr, local_port_str, addr,
get_sockaddr_len(addr), m, timeout, NULL);
}
// Init connections
cork_dllist_init(&connections);
LOGI("listening at %s:%s", local_addr, local_port_str);
if (mode != UDP_ONLY) {
// Init connections
cork_dllist_init(&connections);
}
// Enter the loop
ev_run(loop, 0);
@ -1244,14 +1266,17 @@ int start_ss_local_server(profile_t profile)
}
// Clean up
free_connections(loop);
if (udprelay) {
if (mode != TCP_ONLY) {
free_udprelay();
}
ev_io_stop(loop, &listen_ctx.io);
if (mode != UDP_ONLY) {
ev_io_stop(loop, &listen_ctx.io);
free_connections(loop);
close(listen_ctx.fd);
}
free(listen_ctx.remote_addr);
close(listen_ctx.fd);
#ifdef __MINGW32__
winsock_cleanup();

47
src/redir.c

@ -81,7 +81,8 @@ static void free_server(struct server *server);
static void close_and_free_server(EV_P_ struct server *server);
int verbose = 0;
int udprelay = 0;
static int mode = TCP_ONLY;
int getdestaddr(int fd, struct sockaddr_storage *destaddr)
{
@ -613,7 +614,7 @@ int main(int argc, char **argv)
opterr = 0;
while ((c = getopt(argc, argv, "f:s:p:l:k:t:m:c:b:a:vu")) != -1) {
while ((c = getopt(argc, argv, "f:s:p:l:k:t:m:c:b:a:uUv")) != -1) {
switch (c) {
case 's':
if (remote_num < MAX_REMOTE_NUM) {
@ -650,7 +651,10 @@ int main(int argc, char **argv)
user = optarg;
break;
case 'u':
udprelay = 1;
mode = TCP_AND_UDP;
break;
case 'U':
mode = UDP_ONLY;
break;
case 'v':
verbose = 1;
@ -724,18 +728,6 @@ int main(int argc, char **argv)
LOGI("initialize ciphers... %s", method);
int m = enc_init(password, method);
// Setup socket
int listenfd;
listenfd = create_and_bind(local_addr, local_port);
if (listenfd < 0) {
FATAL("bind() error");
}
if (listen(listenfd, SOMAXCONN) == -1) {
FATAL("listen() error");
}
setnonblocking(listenfd);
LOGI("listening at %s:%s", local_addr, local_port);
// Setup proxy context
struct listen_ctx listen_ctx;
listen_ctx.remote_num = remote_num;
@ -752,20 +744,37 @@ int main(int argc, char **argv)
listen_ctx.remote_addr[i] = (struct sockaddr *)storage;
}
listen_ctx.timeout = atoi(timeout);
listen_ctx.fd = listenfd;
listen_ctx.method = m;
struct ev_loop *loop = EV_DEFAULT;
ev_io_init(&listen_ctx.io, accept_cb, listenfd, EV_READ);
ev_io_start(loop, &listen_ctx.io);
if (mode != UDP_ONLY) {
// Setup socket
int listenfd;
listenfd = create_and_bind(local_addr, local_port);
if (listenfd < 0) {
FATAL("bind() error");
}
if (listen(listenfd, SOMAXCONN) == -1) {
FATAL("listen() error");
}
setnonblocking(listenfd);
listen_ctx.fd = listenfd;
ev_io_init(&listen_ctx.io, accept_cb, listenfd, EV_READ);
ev_io_start(loop, &listen_ctx.io);
}
// Setup UDP
if (udprelay) {
if (mode != TCP_ONLY) {
LOGI("udprelay enabled");
init_udprelay(local_addr, local_port, listen_ctx.remote_addr[0],
get_sockaddr_len(listen_ctx.remote_addr[0]), m, listen_ctx.timeout, NULL);
}
LOGI("listening at %s:%s", local_addr, local_port);
// setuid
if (user != NULL) {
run_as(user);

75
src/server.c

@ -99,9 +99,11 @@ static void close_and_free_server(EV_P_ struct server *server);
static void server_resolve_cb(struct sockaddr *addr, void *data);
int acl = 0;
int verbose = 0;
int udprelay = 0;
static int acl = 0;
static int mode = TCP_ONLY;
static int fast_open = 0;
#ifdef HAVE_SETRLIMIT
static int nofile = 0;
@ -1100,7 +1102,7 @@ int main(int argc, char **argv)
USE_TTY();
while ((c = getopt_long(argc, argv, "f:s:p:l:k:t:m:c:i:d:a:uv",
while ((c = getopt_long(argc, argv, "f:s:p:l:k:t:m:c:i:d:a:uUv",
long_options, &option_index)) != -1) {
switch (c) {
case 0:
@ -1147,7 +1149,10 @@ int main(int argc, char **argv)
user = optarg;
break;
case 'u':
udprelay = 1;
mode = TCP_AND_UDP;
break;
case 'U':
mode = UDP_ONLY;
break;
case 'v':
verbose = 1;
@ -1288,39 +1293,41 @@ int main(int argc, char **argv)
int index = --server_num;
const char * host = server_host[index];
// Bind to port
int listenfd;
listenfd = create_and_bind(host, server_port);
if (listenfd < 0) {
FATAL("bind() error");
}
if (listen(listenfd, SSMAXCONN) == -1) {
FATAL("listen() error");
if (mode != UDP_ONLY) {
// Bind to port
int listenfd;
listenfd = create_and_bind(host, server_port);
if (listenfd < 0) {
FATAL("bind() error");
}
if (listen(listenfd, SSMAXCONN) == -1) {
FATAL("listen() error");
}
setnonblocking(listenfd);
struct listen_ctx *listen_ctx = &listen_ctx_list[index];
// Setup proxy context
listen_ctx->timeout = atoi(timeout);
listen_ctx->fd = listenfd;
listen_ctx->method = m;
listen_ctx->iface = iface;
listen_ctx->loop = loop;
ev_io_init(&listen_ctx->io, accept_cb, listenfd, EV_READ);
ev_io_start(loop, &listen_ctx->io);
}
setnonblocking(listenfd);
LOGI("listening at %s:%s", host ? host : "*", server_port);
struct listen_ctx *listen_ctx = &listen_ctx_list[index];
// Setup proxy context
listen_ctx->timeout = atoi(timeout);
listen_ctx->fd = listenfd;
listen_ctx->method = m;
listen_ctx->iface = iface;
listen_ctx->loop = loop;
ev_io_init(&listen_ctx->io, accept_cb, listenfd, EV_READ);
ev_io_start(loop, &listen_ctx->io);
// Setup UDP
if (udprelay) {
if (mode != TCP_ONLY) {
init_udprelay(server_host[index], server_port, m, atoi(timeout),
iface);
}
LOGI("listening at %s:%s", host ? host : "*", server_port);
}
if (udprelay) {
if (mode != TCP_ONLY) {
LOGI("udprelay enabled");
}
@ -1342,13 +1349,17 @@ int main(int argc, char **argv)
// Clean up
for (int i = 0; i <= server_num; i++) {
struct listen_ctx *listen_ctx = &listen_ctx_list[i];
ev_io_stop(loop, &listen_ctx->io);
close(listen_ctx->fd);
if (mode != UDP_ONLY) {
ev_io_stop(loop, &listen_ctx->io);
close(listen_ctx->fd);
}
}
free_connections(loop);
if (mode != UDP_ONLY) {
free_connections(loop);
}
if (udprelay) {
if (mode != TCP_ONLY) {
free_udprelay();
}

4
src/shadowsocks.h

@ -36,7 +36,7 @@ typedef struct {
char *acl; // file path to acl
char *log; // file path to log
int fast_open; // enable tcp fast open
int udp_relay; // enable udp relay
int mode; // enable udp relay
int verbose; // verbose mode
} profile_t;
@ -53,7 +53,7 @@ typedef struct {
.acl = NULL,
.log = NULL,
.fast_open = 0,
.udp_relay = 0,
.mode = 0,
.verbose = 0
};
*/

46
src/tunnel.c

@ -86,7 +86,7 @@ static void free_server(struct server *server);
static void close_and_free_server(EV_P_ struct server *server);
int verbose = 0;
int udprelay = 0;
static int mode = TCP_ONLY;
#ifndef __MINGW32__
static int setnonblocking(int fd)
@ -654,7 +654,7 @@ int main(int argc, char **argv)
USE_TTY();
while ((c = getopt(argc, argv, "f:s:p:l:k:t:m:i:c:b:L:a:uv")) != -1) {
while ((c = getopt(argc, argv, "f:s:p:l:k:t:m:i:c:b:L:a:uUv")) != -1) {
switch (c) {
case 's':
if (remote_num < MAX_REMOTE_NUM) {
@ -691,7 +691,10 @@ int main(int argc, char **argv)
local_addr = optarg;
break;
case 'u':
udprelay = 1;
mode = TCP_AND_UDP;
break;
case 'U':
mode = UDP_ONLY;
break;
case 'L':
tunnel_addr_str = optarg;
@ -782,18 +785,6 @@ int main(int argc, char **argv)
LOGI("initialize ciphers... %s", method);
int m = enc_init(password, method);
// Setup socket
int listenfd;
listenfd = create_and_bind(local_addr, local_port);
if (listenfd < 0) {
FATAL("bind() error:");
}
if (listen(listenfd, SOMAXCONN) == -1) {
FATAL("listen() error:");
}
setnonblocking(listenfd);
LOGI("listening at %s:%s", local_addr, local_port);
// Setup proxy context
struct listen_ctx listen_ctx;
listen_ctx.tunnel_addr = tunnel_addr;
@ -811,22 +802,39 @@ int main(int argc, char **argv)
listen_ctx.remote_addr[i] = (struct sockaddr *)storage;
}
listen_ctx.timeout = atoi(timeout);
listen_ctx.fd = listenfd;
listen_ctx.iface = iface;
listen_ctx.method = m;
struct ev_loop *loop = EV_DEFAULT;
ev_io_init(&listen_ctx.io, accept_cb, listenfd, EV_READ);
ev_io_start(loop, &listen_ctx.io);
if (mode != UDP_ONLY) {
// Setup socket
int listenfd;
listenfd = create_and_bind(local_addr, local_port);
if (listenfd < 0) {
FATAL("bind() error:");
}
if (listen(listenfd, SOMAXCONN) == -1) {
FATAL("listen() error:");
}
setnonblocking(listenfd);
listen_ctx.fd = listenfd;
ev_io_init(&listen_ctx.io, accept_cb, listenfd, EV_READ);
ev_io_start(loop, &listen_ctx.io);
}
// Setup UDP
if (udprelay) {
if (mode != TCP_ONLY) {
LOGI("udprelay enabled");
init_udprelay(local_addr, local_port, listen_ctx.remote_addr[0],
get_sockaddr_len(listen_ctx.remote_addr[0]),
tunnel_addr, m, listen_ctx.timeout, iface);
}
LOGI("listening at %s:%s", local_addr, local_port);
// setuid
if (user != NULL) {
run_as(user);

7
src/utils.c

@ -238,7 +238,12 @@ void usage()
" not available in server mode\n");
printf("\n");
printf(
" [-u] enable udprelay mode,\n");
" [-u] enable UDP relay,\n");
printf(
" TPROXY is required in redir mode\n");
printf("\n");
printf(
" [-U] enable UDP relay and disable TCP relay,\n");
printf(
" TPROXY is required in redir mode\n");
printf("\n");

Loading…
Cancel
Save