From 34b9036b5b66b1e86f0205b80619528596a5951d Mon Sep 17 00:00:00 2001 From: Max Lv Date: Wed, 3 Aug 2016 11:50:07 +0800 Subject: [PATCH] Add MTU option --- .gitignore | 1 - doc/ss-local.asciidoc | 5 ++- doc/ss-redir.asciidoc | 5 ++- doc/ss-server.asciidoc | 5 ++- doc/ss-tunnel.asciidoc | 5 ++- src/common.h | 2 +- src/local.c | 10 ++++-- src/redir.c | 11 ++++-- src/server.c | 9 +++-- src/tunnel.c | 11 ++++-- src/udprelay.c | 78 ++++++++++++++++++++++++++---------------- src/udprelay.h | 2 +- src/utils.c | 2 ++ 13 files changed, 100 insertions(+), 46 deletions(-) diff --git a/.gitignore b/.gitignore index 59a8f763..23ebeea4 100644 --- a/.gitignore +++ b/.gitignore @@ -13,7 +13,6 @@ config.log config.status libtool pid -ss.* src/ss-* !src/ss-nat stamp-h1 diff --git a/doc/ss-local.asciidoc b/doc/ss-local.asciidoc index ae5b4b40..90a15318 100644 --- a/doc/ss-local.asciidoc +++ b/doc/ss-local.asciidoc @@ -12,7 +12,7 @@ SYNOPSIS [-s ] [-p ] [-l ] [-k ] [-m ] [-f ] [-t ] [-c ] [-b ] [-a ] - [-n ] [--fast-open] [--acl ] + [-n ] [--fast-open] [--acl ] [--mtu ] DESCRIPTION ----------- @@ -102,6 +102,9 @@ Only available with Linux kernel > 3.7.0. --acl :: Enable ACL (Access Control List) and specify config file. +--mtu :: +Specify the MTU of your network interface. + -v:: Enable verbose mode. diff --git a/doc/ss-redir.asciidoc b/doc/ss-redir.asciidoc index d48e8a21..c1cf2010 100644 --- a/doc/ss-redir.asciidoc +++ b/doc/ss-redir.asciidoc @@ -12,7 +12,7 @@ SYNOPSIS [-s ] [-p ] [-l ] [-k ] [-m ] [-f ] [-t ] [-c ] [-b ] - [-a ] [-n ] + [-a ] [-n ] [--mtu ] DESCRIPTION ----------- @@ -89,6 +89,9 @@ Enable UDP relay and disable TCP relay. -A:: Enable onetime authentication. +--mtu :: +Specify the MTU of your network interface. + -v:: Enable verbose mode. diff --git a/doc/ss-server.asciidoc b/doc/ss-server.asciidoc index 8fda7412..8bf7ce62 100644 --- a/doc/ss-server.asciidoc +++ b/doc/ss-server.asciidoc @@ -13,7 +13,7 @@ SYNOPSIS [-k ] [-m ] [-f ] [-t ] [-c ] [-i ] [-a ] [-d ] [-n ] - [--fast-open] [--acl ] + [--fast-open] [--acl ] [--mtu ] [--manager-address ] DESCRIPTION @@ -115,6 +115,9 @@ Specify UNIX domain socket address for the communication between ss-manager(1) a + Only available in server and manager mode. +--mtu :: +Specify the MTU of your network interface. + -v:: Enable verbose mode. diff --git a/doc/ss-tunnel.asciidoc b/doc/ss-tunnel.asciidoc index 58dbe720..ea154d6e 100644 --- a/doc/ss-tunnel.asciidoc +++ b/doc/ss-tunnel.asciidoc @@ -13,7 +13,7 @@ SYNOPSIS [-k ] [-m ] [-f ] [-t ] [-c ] [-i ] [-b ] [-a ] [-n ] - [-L addr:port] + [-L addr:port] [--mtu ] DESCRIPTION ----------- @@ -100,6 +100,9 @@ Specify destination server address and port for local port forwarding. + Only used and available in tunnel mode. +--mtu :: +Specify the MTU of your network interface. + -v:: Enable verbose mode. diff --git a/src/common.h b/src/common.h index c1155d87..f093db6f 100644 --- a/src/common.h +++ b/src/common.h @@ -60,7 +60,7 @@ int init_udprelay(const char *server_host, const char *server_port, const ss_addr_t tunnel_addr, #endif #endif - int method, int auth, int timeout, const char *iface); + int mtu, int method, int auth, int timeout, const char *iface); void free_udprelay(void); diff --git a/src/local.c b/src/local.c index 1204b734..af9681f4 100644 --- a/src/local.c +++ b/src/local.c @@ -982,6 +982,7 @@ int main(int argc, char **argv) { int i, c; int pid_flags = 0; + int mtu = 0; char *user = NULL; char *local_port = NULL; char *local_addr = NULL; @@ -1002,6 +1003,7 @@ int main(int argc, char **argv) static struct option long_options[] = { { "fast-open", no_argument , 0, 0 }, { "acl" , required_argument, 0, 0 }, + { "mtu" , required_argument, 0, 0 }, { "help" , no_argument , 0, 0 }, { 0, 0, 0, 0 } }; @@ -1025,6 +1027,9 @@ int main(int argc, char **argv) LOGI("initializing acl..."); acl = !init_acl(optarg, BLACK_LIST); } else if (option_index == 2) { + mtu = atoi(optarg); + LOGI("Set MTU to %d", mtu); + } else if (option_index == 3) { usage(); exit(EXIT_SUCCESS); } @@ -1258,7 +1263,7 @@ int main(int argc, char **argv) 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, auth, listen_ctx.timeout, iface); + get_sockaddr_len(listen_ctx.remote_addr[0]), mtu, m, auth, listen_ctx.timeout, iface); } LOGI("listening at %s:%s", local_addr, local_port); @@ -1318,6 +1323,7 @@ int start_ss_local_server(profile_t profile) int remote_port = profile.remote_port; int local_port = profile.local_port; int timeout = profile.timeout; + int mtu = 0; auth = profile.auth; mode = profile.mode; @@ -1406,7 +1412,7 @@ int start_ss_local_server(profile_t profile) LOGI("udprelay enabled"); struct sockaddr *addr = (struct sockaddr *)storage; init_udprelay(local_addr, local_port_str, addr, - get_sockaddr_len(addr), m, auth, timeout, NULL); + get_sockaddr_len(addr), mtu, m, auth, timeout, NULL); } LOGI("listening at %s:%s", local_addr, local_port_str); diff --git a/src/redir.c b/src/redir.c index 2b106c60..cb7fcefa 100644 --- a/src/redir.c +++ b/src/redir.c @@ -683,6 +683,7 @@ int main(int argc, char **argv) int i, c; int pid_flags = 0; + int mtu = 0; char *user = NULL; char *local_port = NULL; char *local_addr = NULL; @@ -698,8 +699,9 @@ int main(int argc, char **argv) int option_index = 0; static struct option long_options[] = { - { "help", no_argument, 0, 0 }, - { 0, 0, 0, 0 } + { "mtu", required_argument, 0, 0 }, + { "help", no_argument , 0, 0 }, + { 0, 0 , 0, 0 } }; opterr = 0; @@ -709,6 +711,9 @@ int main(int argc, char **argv) switch (c) { case 0: if (option_index == 0) { + mtu = atoi(optarg); + LOGI("Set MTU to %d", mtu); + } else if (option_index == 1) { usage(); exit(EXIT_SUCCESS); } @@ -905,7 +910,7 @@ int main(int argc, char **argv) if (mode != TCP_ONLY) { LOGI("UDP relay enabled"); init_udprelay(local_addr, local_port, listen_ctx.remote_addr[0], - get_sockaddr_len(listen_ctx.remote_addr[0]), m, auth, listen_ctx.timeout, NULL); + get_sockaddr_len(listen_ctx.remote_addr[0]), mtu, m, auth, listen_ctx.timeout, NULL); } if (mode == UDP_ONLY) { diff --git a/src/server.c b/src/server.c index c0c066e2..2f0b9fcc 100644 --- a/src/server.c +++ b/src/server.c @@ -1338,6 +1338,7 @@ int main(int argc, char **argv) { int i, c; int pid_flags = 0; + int mtu = 0; char *user = NULL; char *password = NULL; char *timeout = NULL; @@ -1358,6 +1359,7 @@ int main(int argc, char **argv) { "fast-open" , no_argument , 0, 0 }, { "acl" , required_argument, 0, 0 }, { "manager-address", required_argument, 0, 0 }, + { "mtu" , required_argument, 0, 0 }, { "help" , no_argument , 0, 0 }, { 0, 0, 0, 0 } }; @@ -1379,6 +1381,9 @@ int main(int argc, char **argv) } else if (option_index == 2) { manager_address = optarg; } else if (option_index == 3) { + mtu = atoi(optarg); + LOGI("Set MTU to %d", mtu); + } else if (option_index == 4) { usage(); exit(EXIT_SUCCESS); } @@ -1636,8 +1641,8 @@ int main(int argc, char **argv) // Setup UDP if (mode != TCP_ONLY) { - init_udprelay(server_host[index], server_port, m, auth, atoi(timeout), - iface); + init_udprelay(server_host[index], server_port, mtu, m, + auth, atoi(timeout), iface); } LOGI("listening at %s:%s", host ? host : "*", server_port); diff --git a/src/tunnel.c b/src/tunnel.c index 6e9107d2..3d0255d2 100644 --- a/src/tunnel.c +++ b/src/tunnel.c @@ -692,6 +692,7 @@ int main(int argc, char **argv) int i, c; int pid_flags = 0; + int mtu = 0; char *user = NULL; char *local_port = NULL; char *local_addr = NULL; @@ -711,8 +712,9 @@ int main(int argc, char **argv) int option_index = 0; static struct option long_options[] = { - { "help", no_argument, 0, 0 }, - { 0, 0, 0, 0 } + { "mtu", required_argument, 0, 0 }, + { "help", no_argument, 0, 0 }, + { 0, 0, 0, 0 } }; opterr = 0; @@ -729,6 +731,9 @@ int main(int argc, char **argv) switch (c) { case 0: if (option_index == 0) { + mtu = atoi(optarg); + LOGI("Set MTU to %d", mtu); + } else if (option_index == 1) { usage(); exit(EXIT_SUCCESS); } @@ -959,7 +964,7 @@ int main(int argc, char **argv) LOGI("UDP relay enabled"); init_udprelay(local_addr, local_port, listen_ctx.remote_addr[0], get_sockaddr_len(listen_ctx.remote_addr[0]), - tunnel_addr, m, auth, listen_ctx.timeout, iface); + tunnel_addr, mtu, m, auth, listen_ctx.timeout, iface); } if (mode == UDP_ONLY) { diff --git a/src/udprelay.c b/src/udprelay.c index 2c498e6a..60859fe0 100644 --- a/src/udprelay.c +++ b/src/udprelay.c @@ -81,8 +81,6 @@ #define EWOULDBLOCK EAGAIN #endif -#define BUF_SIZE MAX_UDP_PACKET_SIZE - 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); @@ -101,6 +99,8 @@ extern uint64_t tx; extern uint64_t rx; #endif +static int packet_size = DEFAULT_PACKET_SIZE; +static int buf_size = DEFAULT_PACKET_SIZE * 2; static int server_num = 0; static server_ctx_t *server_ctx_list[MAX_REMOTE_NUM] = { NULL }; @@ -645,27 +645,25 @@ static void remote_recv_cb(EV_P_ ev_io *w, int revents) memset(&src_addr, 0, src_addr_len); buffer_t *buf = ss_malloc(sizeof(buffer_t)); - balloc(buf, BUF_SIZE); + balloc(buf, packet_size); // recv - r = recvfrom(remote_ctx->fd, buf->array, BUF_SIZE, 0, (struct sockaddr *)&src_addr, &src_addr_len); + r = recvfrom(remote_ctx->fd, buf->array, buf_size, 0, (struct sockaddr *)&src_addr, &src_addr_len); if (r == -1) { // error on recv // simply drop that packet - ERROR("[udp] remote_recvfrom"); + ERROR("[udp] remote_recv_recvfrom"); + goto CLEAN_UP; + } else if (r > packet_size) { + LOGE("[udp] remote_recv_recvfrom fragmentation"); goto CLEAN_UP; } buf->len = r; - // packet size > default MTU - if (verbose && buf->len > MTU) { - LOGE("[udp] possible ip fragment, size: %d", (int)buf->len); - } - #ifdef MODULE_LOCAL - int err = ss_decrypt_all(buf, server_ctx->method, 0, BUF_SIZE); + int err = ss_decrypt_all(buf, server_ctx->method, 0, packet_size); if (err) { // drop the packet silently goto CLEAN_UP; @@ -699,7 +697,7 @@ static void remote_recv_cb(EV_P_ ev_io *w, int revents) memmove(buf->array, buf->array + len, buf->len); #else // Construct packet - brealloc(buf, buf->len + 3, BUF_SIZE); + brealloc(buf, buf->len + 3, packet_size); memmove(buf->array + 3, buf->array, buf->len); memset(buf->array, 0, 3); buf->len += 3; @@ -720,18 +718,23 @@ static void remote_recv_cb(EV_P_ ev_io *w, int revents) } // Construct packet - brealloc(buf, buf->len + addr_header_len, BUF_SIZE); + brealloc(buf, buf->len + addr_header_len, packet_size); memmove(buf->array + addr_header_len, buf->array, buf->len); memcpy(buf->array, addr_header, addr_header_len); buf->len += addr_header_len; - int err = ss_encrypt_all(buf, server_ctx->method, 0, BUF_SIZE); + int err = ss_encrypt_all(buf, server_ctx->method, 0, packet_size); if (err) { // drop the packet silently goto CLEAN_UP; } #endif + if (buf->len > packet_size) { + LOGE("[udp] remote_recv_sendto fragmentation"); + goto CLEAN_UP; + } + size_t remote_src_addr_len = get_sockaddr_len((struct sockaddr *)&remote_ctx->src_addr); #ifdef MODULE_REDIR @@ -794,7 +797,7 @@ static void server_recv_cb(EV_P_ ev_io *w, int revents) memset(&src_addr, 0, sizeof(struct sockaddr_storage)); buffer_t *buf = ss_malloc(sizeof(buffer_t)); - balloc(buf, BUF_SIZE); + balloc(buf, packet_size); socklen_t src_addr_len = sizeof(struct sockaddr_storage); unsigned int offset = 0; @@ -812,7 +815,7 @@ static void server_recv_cb(EV_P_ ev_io *w, int revents) msg.msg_controllen = sizeof(control_buffer); iov[0].iov_base = buf->array; - iov[0].iov_len = BUF_SIZE; + iov[0].iov_len = packet_size; msg.msg_iov = iov; msg.msg_iovlen = 1; @@ -820,6 +823,9 @@ static void server_recv_cb(EV_P_ ev_io *w, int revents) if (buf->len == -1) { ERROR("[udp] server_recvmsg"); goto CLEAN_UP; + } else if (buf->len > packet_size) { + ERROR("[udp] UDP server_recv_recvmsg fragmentation"); + goto CLEAN_UP; } if (get_dstaddr(&msg, &dst_addr)) { @@ -830,13 +836,16 @@ static void server_recv_cb(EV_P_ ev_io *w, int revents) src_addr_len = msg.msg_namelen; #else ssize_t r; - r = recvfrom(server_ctx->fd, buf->array, BUF_SIZE, + r = recvfrom(server_ctx->fd, buf->array, buf_size, 0, (struct sockaddr *)&src_addr, &src_addr_len); if (r == -1) { // error on recv // simply drop that packet - ERROR("[udp] server_recvfrom"); + ERROR("[udp] server_recv_recvfrom"); + goto CLEAN_UP; + } else if (r > packet_size) { + ERROR("[udp] server_recv_recvfrom fragmentation"); goto CLEAN_UP; } @@ -851,7 +860,7 @@ static void server_recv_cb(EV_P_ ev_io *w, int revents) tx += buf->len; - int err = ss_decrypt_all(buf, server_ctx->method, server_ctx->auth, BUF_SIZE); + int err = ss_decrypt_all(buf, server_ctx->method, server_ctx->auth, packet_size); if (err) { // drop the packet silently goto CLEAN_UP; @@ -865,11 +874,6 @@ static void server_recv_cb(EV_P_ ev_io *w, int revents) #endif #endif - // packet size > default MTU - if (verbose && buf->len > MTU) { - LOGE("[udp] possible ip fragment, size: %d", (int)buf->len); - } - /* * * SOCKS5 UDP Request @@ -924,7 +928,7 @@ static void server_recv_cb(EV_P_ ev_io *w, int revents) } // reconstruct the buffer - brealloc(buf, buf->len + addr_header_len, BUF_SIZE); + brealloc(buf, buf->len + addr_header_len, packet_size); memmove(buf->array + addr_header_len, buf->array, buf->len); memcpy(buf->array, addr_header, addr_header_len); buf->len += addr_header_len; @@ -978,7 +982,7 @@ static void server_recv_cb(EV_P_ ev_io *w, int revents) addr_header_len += 2; // reconstruct the buffer - brealloc(buf, buf->len + addr_header_len, BUF_SIZE); + brealloc(buf, buf->len + addr_header_len, packet_size); memmove(buf->array + addr_header_len, buf->array, buf->len); memcpy(buf->array, addr_header, addr_header_len); buf->len += addr_header_len; @@ -1116,17 +1120,22 @@ static void server_recv_cb(EV_P_ ev_io *w, int revents) buf->array[0] |= ONETIMEAUTH_FLAG; } - int err = ss_encrypt_all(buf, server_ctx->method, server_ctx->auth, BUF_SIZE); + int err = ss_encrypt_all(buf, server_ctx->method, server_ctx->auth, packet_size); if (err) { // drop the packet silently goto CLEAN_UP; } + if (buf->len > packet_size) { + LOGE("[udp] server_recv_sendto fragmentation"); + goto CLEAN_UP; + } + int s = sendto(remote_ctx->fd, buf->array, buf->len, 0, remote_addr, remote_addr_len); if (s == -1) { - ERROR("[udp] sendto_remote"); + ERROR("[udp] server_recv_sendto"); } #else @@ -1134,6 +1143,11 @@ static void server_recv_cb(EV_P_ ev_io *w, int revents) int cache_hit = 0; int need_query = 0; + if (buf->len - addr_header_len > packet_size) { + LOGE("[udp] server_recv_sendto fragmentation"); + goto CLEAN_UP; + } + if (remote_ctx != NULL) { cache_hit = 1; // detect destination mismatch @@ -1249,11 +1263,17 @@ int init_udprelay(const char *server_host, const char *server_port, const ss_addr_t tunnel_addr, #endif #endif - int method, int auth, int timeout, const char *iface) + int mtu, int method, int auth, int timeout, const char *iface) { // Inilitialize ev loop struct ev_loop *loop = EV_DEFAULT; + // Inilitialize MTU + if (mtu > 0) { + packet_size = mtu - 1 - 28 - 2 - 64; + buf_size = packet_size * 2; + } + // Inilitialize cache struct cache *conn_cache; cache_create(&conn_cache, MAX_UDP_CONN_NUM, free_cb); diff --git a/src/udprelay.h b/src/udprelay.h index dafb1e95..59922256 100644 --- a/src/udprelay.h +++ b/src/udprelay.h @@ -39,7 +39,7 @@ #define MAX_UDP_PACKET_SIZE (65507) -#define MTU 1397 // 1492 - 1 - 28 - 2 - 64 = 1397, the default MTU for UDP relay +#define DEFAULT_PACKET_SIZE 1397 // 1492 - 1 - 28 - 2 - 64 = 1397, the default MTU for UDP relay typedef struct server_ctx { ev_io io; diff --git a/src/utils.c b/src/utils.c index a4e41439..5e20d521 100644 --- a/src/utils.c +++ b/src/utils.c @@ -309,6 +309,8 @@ void usage() printf( " [--executable ] Path to the executable of ss-server.\n"); #endif + printf( + " [--mtu ] MTU of your network interface.\n"); printf("\n"); printf( " [-v] Verbose mode.\n");