From 36d9993bbff189b93188f300d7589defba09b9fd Mon Sep 17 00:00:00 2001 From: Not Sure Date: Tue, 22 Dec 2020 10:21:24 +0200 Subject: [PATCH] Add --tcp-incoming-rcvbuf and --tcp-outgoing-rcvbuf which allow precise control over TCP receive buffers. --- src/common.h | 4 +++- src/jconf.c | 8 ++++++++ src/jconf.h | 2 ++ src/local.c | 40 ++++++++++++++++++++++++++++++++++++++++ src/redir.c | 40 ++++++++++++++++++++++++++++++++++++++++ src/server.c | 40 ++++++++++++++++++++++++++++++++++++++++ src/tunnel.c | 40 ++++++++++++++++++++++++++++++++++++++++ src/utils.c | 4 ++++ 8 files changed, 177 insertions(+), 1 deletion(-) diff --git a/src/common.h b/src/common.h index e101f499..6b8aeba3 100644 --- a/src/common.h +++ b/src/common.h @@ -72,7 +72,9 @@ enum { GETOPT_VAL_EXECUTABLE, GETOPT_VAL_WORKDIR, GETOPT_VAL_TCP_INCOMING_SNDBUF, - GETOPT_VAL_TCP_OUTGOING_SNDBUF + GETOPT_VAL_TCP_INCOMING_RCVBUF, + GETOPT_VAL_TCP_OUTGOING_SNDBUF, + GETOPT_VAL_TCP_OUTGOING_RCVBUF }; #endif // _COMMON_H diff --git a/src/jconf.c b/src/jconf.c index 765a3e27..5657c88f 100644 --- a/src/jconf.c +++ b/src/jconf.c @@ -278,10 +278,18 @@ read_jconf(const char *file) check_json_value_type(value, json_integer, "invalid config file: option 'tcp_incoming_sndbuf' must be an integer"); conf.tcp_incoming_sndbuf = value->u.integer; + } else if (strcmp(name, "tcp_incoming_rcvbuf") == 0) { + check_json_value_type(value, json_integer, + "invalid config file: option 'tcp_incoming_rcvbuf' must be an integer"); + conf.tcp_incoming_rcvbuf = value->u.integer; } else if (strcmp(name, "tcp_outgoing_sndbuf") == 0) { check_json_value_type(value, json_integer, "invalid config file: option 'tcp_outgoing_sndbuf' must be an integer"); conf.tcp_outgoing_sndbuf = value->u.integer; + } else if (strcmp(name, "tcp_outgoing_rcvbuf") == 0) { + check_json_value_type(value, json_integer, + "invalid config file: option 'tcp_outgoing_rcvbuf' must be an integer"); + conf.tcp_outgoing_rcvbuf = value->u.integer; } else if (strcmp(name, "auth") == 0) { FATAL("One time auth has been deprecated. Try AEAD ciphers instead."); } else if (strcmp(name, "nofile") == 0) { diff --git a/src/jconf.h b/src/jconf.h index e48bfe86..544011d3 100644 --- a/src/jconf.h +++ b/src/jconf.h @@ -73,7 +73,9 @@ typedef struct { int fast_open; int reuse_port; int tcp_incoming_sndbuf; + int tcp_incoming_rcvbuf; int tcp_outgoing_sndbuf; + int tcp_outgoing_rcvbuf; int nofile; char *nameserver; int dscp_num; diff --git a/src/local.c b/src/local.c index 7f027da8..84bcc126 100644 --- a/src/local.c +++ b/src/local.c @@ -80,7 +80,9 @@ int verbose = 0; int reuse_port = 0; int tcp_incoming_sndbuf = 0; +int tcp_incoming_rcvbuf = 0; int tcp_outgoing_sndbuf = 0; +int tcp_outgoing_rcvbuf = 0; #ifdef __ANDROID__ int vpn = 0; @@ -1306,6 +1308,10 @@ create_remote(listen_ctx_t *listener, setsockopt(remotefd, SOL_SOCKET, SO_SNDBUF, &tcp_outgoing_sndbuf, sizeof(int)); } + if (tcp_outgoing_rcvbuf > 0) { + setsockopt(remotefd, SOL_SOCKET, SO_RCVBUF, &tcp_outgoing_rcvbuf, sizeof(int)); + } + // Setup setnonblocking(remotefd); #ifdef SET_INTERFACE @@ -1400,6 +1406,10 @@ accept_cb(EV_P_ ev_io *w, int revents) setsockopt(serverfd, SOL_SOCKET, SO_SNDBUF, &tcp_incoming_sndbuf, sizeof(int)); } + if (tcp_incoming_rcvbuf > 0) { + setsockopt(serverfd, SOL_SOCKET, SO_RCVBUF, &tcp_incoming_rcvbuf, sizeof(int)); + } + server_t *server = new_server(serverfd); server->listener = listener; @@ -1441,7 +1451,9 @@ main(int argc, char **argv) static struct option long_options[] = { { "reuse-port", no_argument, NULL, GETOPT_VAL_REUSE_PORT }, { "tcp-incoming-sndbuf", required_argument, NULL, GETOPT_VAL_TCP_INCOMING_SNDBUF }, + { "tcp-incoming-rcvbuf", required_argument, NULL, GETOPT_VAL_TCP_INCOMING_RCVBUF }, { "tcp-outgoing-sndbuf", required_argument, NULL, GETOPT_VAL_TCP_OUTGOING_SNDBUF }, + { "tcp-outgoing-rcvbuf", required_argument, NULL, GETOPT_VAL_TCP_OUTGOING_RCVBUF }, { "fast-open", no_argument, NULL, GETOPT_VAL_FAST_OPEN }, { "no-delay", no_argument, NULL, GETOPT_VAL_NODELAY }, { "acl", required_argument, NULL, GETOPT_VAL_ACL }, @@ -1501,9 +1513,15 @@ main(int argc, char **argv) case GETOPT_VAL_TCP_INCOMING_SNDBUF: tcp_incoming_sndbuf = atoi(optarg); break; + case GETOPT_VAL_TCP_INCOMING_RCVBUF: + tcp_incoming_rcvbuf = atoi(optarg); + break; case GETOPT_VAL_TCP_OUTGOING_SNDBUF: tcp_outgoing_sndbuf = atoi(optarg); break; + case GETOPT_VAL_TCP_OUTGOING_RCVBUF: + tcp_outgoing_rcvbuf = atoi(optarg); + break; case 's': if (remote_num < MAX_REMOTE_NUM) { parse_addr(optarg, &remote_addr[remote_num++]); @@ -1634,9 +1652,15 @@ main(int argc, char **argv) if (tcp_incoming_sndbuf == 0) { tcp_incoming_sndbuf = conf->tcp_incoming_sndbuf; } + if (tcp_incoming_rcvbuf == 0) { + tcp_incoming_rcvbuf = conf->tcp_incoming_rcvbuf; + } if (tcp_outgoing_sndbuf == 0) { tcp_outgoing_sndbuf = conf->tcp_outgoing_sndbuf; } + if (tcp_outgoing_rcvbuf == 0) { + tcp_outgoing_rcvbuf = conf->tcp_outgoing_rcvbuf; + } if (fast_open == 0) { fast_open = conf->fast_open; } @@ -1697,6 +1721,14 @@ main(int argc, char **argv) LOGI("set TCP incoming connection send buffer size to %d", tcp_incoming_sndbuf); } + if (tcp_incoming_rcvbuf != 0 && tcp_incoming_rcvbuf < SOCKET_BUF_SIZE) { + tcp_incoming_rcvbuf = 0; + } + + if (tcp_incoming_rcvbuf != 0) { + LOGI("set TCP incoming connection receive buffer size to %d", tcp_incoming_rcvbuf); + } + if (tcp_outgoing_sndbuf != 0 && tcp_outgoing_sndbuf < SOCKET_BUF_SIZE) { tcp_outgoing_sndbuf = 0; } @@ -1705,6 +1737,14 @@ main(int argc, char **argv) LOGI("set TCP outgoing connection send buffer size to %d", tcp_outgoing_sndbuf); } + if (tcp_outgoing_rcvbuf != 0 && tcp_outgoing_rcvbuf < SOCKET_BUF_SIZE) { + tcp_outgoing_rcvbuf = 0; + } + + if (tcp_outgoing_rcvbuf != 0) { + LOGI("set TCP outgoing connection receive buffer size to %d", tcp_outgoing_recvbuf); + } + if (plugin != NULL) { uint16_t port = get_local_port(); if (port == 0) { diff --git a/src/redir.c b/src/redir.c index 522d2007..9c4c1899 100644 --- a/src/redir.c +++ b/src/redir.c @@ -90,7 +90,9 @@ static void close_and_free_server(EV_P_ server_t *server); int verbose = 0; int reuse_port = 0; int tcp_incoming_sndbuf = 0; +int tcp_incoming_rcvbuf = 0; int tcp_outgoing_sndbuf = 0; +int tcp_outgoing_rcvbuf = 0; static crypto_t *crypto; @@ -761,6 +763,10 @@ accept_cb(EV_P_ ev_io *w, int revents) setsockopt(serverfd, SOL_SOCKET, SO_SNDBUF, &tcp_incoming_sndbuf, sizeof(int)); } + if (tcp_incoming_rcvbuf > 0) { + setsockopt(serverfd, SOL_SOCKET, SO_RCVBUF, &tcp_incoming_rcvbuf, sizeof(int)); + } + int index = rand() % listener->remote_num; struct sockaddr *remote_addr = listener->remote_addr[index]; @@ -824,6 +830,10 @@ accept_cb(EV_P_ ev_io *w, int revents) setsockopt(remotefd, SOL_SOCKET, SO_SNDBUF, &tcp_outgoing_sndbuf, sizeof(int)); } + if (tcp_outgoing_rcvbuf > 0) { + setsockopt(remotefd, SOL_SOCKET, SO_RCVBUF, &tcp_outgoing_rcvbuf, sizeof(int)); + } + server_t *server = new_server(serverfd); remote_t *remote = new_remote(remotefd, listener->timeout); server->remote = remote; @@ -914,7 +924,9 @@ main(int argc, char **argv) { "plugin-opts", required_argument, NULL, GETOPT_VAL_PLUGIN_OPTS }, { "reuse-port", no_argument, NULL, GETOPT_VAL_REUSE_PORT }, { "tcp-incoming-sndbuf", required_argument, NULL, GETOPT_VAL_TCP_INCOMING_SNDBUF }, + { "tcp-incoming-rcvbuf", required_argument, NULL, GETOPT_VAL_TCP_INCOMING_RCVBUF }, { "tcp-outgoing-sndbuf", required_argument, NULL, GETOPT_VAL_TCP_OUTGOING_SNDBUF }, + { "tcp-outgoing-rcvbuf", required_argument, NULL, GETOPT_VAL_TCP_OUTGOING_RCVBUF }, { "no-delay", no_argument, NULL, GETOPT_VAL_NODELAY }, { "password", required_argument, NULL, GETOPT_VAL_PASSWORD }, { "key", required_argument, NULL, GETOPT_VAL_KEY }, @@ -959,9 +971,15 @@ main(int argc, char **argv) case GETOPT_VAL_TCP_INCOMING_SNDBUF: tcp_incoming_sndbuf = atoi(optarg); break; + case GETOPT_VAL_TCP_INCOMING_RCVBUF: + tcp_incoming_rcvbuf = atoi(optarg); + break; case GETOPT_VAL_TCP_OUTGOING_SNDBUF: tcp_outgoing_sndbuf = atoi(optarg); break; + case GETOPT_VAL_TCP_OUTGOING_RCVBUF: + tcp_outgoing_rcvbuf = atoi(optarg); + break; case 's': if (remote_num < MAX_REMOTE_NUM) { parse_addr(optarg, &remote_addr[remote_num++]); @@ -1100,9 +1118,15 @@ main(int argc, char **argv) if (tcp_incoming_sndbuf == 0) { tcp_incoming_sndbuf = conf->tcp_incoming_sndbuf; } + if (tcp_incoming_rcvbuf == 0) { + tcp_incoming_rcvbuf = conf->tcp_incoming_rcvbuf; + } if (tcp_outgoing_sndbuf == 0) { tcp_outgoing_sndbuf = conf->tcp_outgoing_sndbuf; } + if (tcp_outgoing_rcvbuf == 0) { + tcp_outgoing_rcvbuf = conf->tcp_outgoing_rcvbuf; + } if (fast_open == 0) { fast_open = conf->fast_open; } @@ -1199,6 +1223,14 @@ main(int argc, char **argv) LOGI("set TCP incoming connection send buffer size to %d", tcp_incoming_sndbuf); } + if (tcp_incoming_rcvbuf != 0 && tcp_incoming_rcvbuf < SOCKET_BUF_SIZE) { + tcp_incoming_rcvbuf = 0; + } + + if (tcp_incoming_rcvbuf != 0) { + LOGI("set TCP incoming connection receive buffer size to %d", tcp_incoming_rcvbuf); + } + if (tcp_outgoing_sndbuf != 0 && tcp_outgoing_sndbuf < SOCKET_BUF_SIZE) { tcp_outgoing_sndbuf = 0; } @@ -1207,6 +1239,14 @@ main(int argc, char **argv) LOGI("set TCP outgoing connection send buffer size to %d", tcp_outgoing_sndbuf); } + if (tcp_outgoing_rcvbuf != 0 && tcp_outgoing_rcvbuf < SOCKET_BUF_SIZE) { + tcp_outgoing_rcvbuf = 0; + } + + if (tcp_outgoing_rcvbuf != 0) { + LOGI("set TCP outgoing connection receive buffer size to %d", tcp_outgoing_recvbuf); + } + if (plugin != NULL) { int len = 0; size_t buf_size = 256 * remote_num; diff --git a/src/server.c b/src/server.c index 346829df..a0d4b557 100644 --- a/src/server.c +++ b/src/server.c @@ -110,7 +110,9 @@ static void resolv_free_cb(void *data); int verbose = 0; int reuse_port = 0; int tcp_incoming_sndbuf = 0; +int tcp_incoming_rcvbuf = 0; int tcp_outgoing_sndbuf = 0; +int tcp_outgoing_rcvbuf = 0; int is_bind_local_addr = 0; struct sockaddr_storage local_addr_v4; @@ -477,6 +479,10 @@ connect_to_remote(EV_P_ struct addrinfo *res, setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, &tcp_outgoing_sndbuf, sizeof(int)); } + if (tcp_outgoing_rcvbuf > 0) { + setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, &tcp_outgoing_rcvbuf, sizeof(int)); + } + // setup remote socks if (setnonblocking(sockfd) == -1) @@ -1549,6 +1555,10 @@ accept_cb(EV_P_ ev_io *w, int revents) setsockopt(serverfd, SOL_SOCKET, SO_SNDBUF, &tcp_incoming_sndbuf, sizeof(int)); } + if (tcp_incoming_rcvbuf > 0) { + setsockopt(serverfd, SOL_SOCKET, SO_RCVBUF, &tcp_incoming_rcvbuf, sizeof(int)); + } + setnonblocking(serverfd); server_t *server = new_server(serverfd, listener); @@ -1589,7 +1599,9 @@ main(int argc, char **argv) { "fast-open", no_argument, NULL, GETOPT_VAL_FAST_OPEN }, { "reuse-port", no_argument, NULL, GETOPT_VAL_REUSE_PORT }, { "tcp-incoming-sndbuf", required_argument, NULL, GETOPT_VAL_TCP_INCOMING_SNDBUF }, + { "tcp-incoming-rcvbuf", required_argument, NULL, GETOPT_VAL_TCP_INCOMING_RCVBUF }, { "tcp-outgoing-sndbuf", required_argument, NULL, GETOPT_VAL_TCP_OUTGOING_SNDBUF }, + { "tcp-outgoing-rcvbuf", required_argument, NULL, GETOPT_VAL_TCP_OUTGOING_RCVBUF }, { "no-delay", no_argument, NULL, GETOPT_VAL_NODELAY }, { "acl", required_argument, NULL, GETOPT_VAL_ACL }, { "manager-address", required_argument, NULL, @@ -1650,9 +1662,15 @@ main(int argc, char **argv) case GETOPT_VAL_TCP_INCOMING_SNDBUF: tcp_incoming_sndbuf = atoi(optarg); break; + case GETOPT_VAL_TCP_INCOMING_RCVBUF: + tcp_incoming_rcvbuf = atoi(optarg); + break; case GETOPT_VAL_TCP_OUTGOING_SNDBUF: tcp_outgoing_sndbuf = atoi(optarg); break; + case GETOPT_VAL_TCP_OUTGOING_RCVBUF: + tcp_outgoing_rcvbuf = atoi(optarg); + break; case 's': if (server_num < MAX_REMOTE_NUM) { parse_addr(optarg, &server_addr[server_num++]); @@ -1782,9 +1800,15 @@ main(int argc, char **argv) if (tcp_incoming_sndbuf == 0) { tcp_incoming_sndbuf = conf->tcp_incoming_sndbuf; } + if (tcp_incoming_rcvbuf == 0) { + tcp_incoming_rcvbuf = conf->tcp_incoming_rcvbuf; + } if (tcp_outgoing_sndbuf == 0) { tcp_outgoing_sndbuf = conf->tcp_outgoing_sndbuf; } + if (tcp_outgoing_rcvbuf == 0) { + tcp_outgoing_rcvbuf = conf->tcp_outgoing_rcvbuf; + } if (fast_open == 0) { fast_open = conf->fast_open; } @@ -1820,6 +1844,14 @@ main(int argc, char **argv) LOGI("set TCP incoming connection send buffer size to %d", tcp_incoming_sndbuf); } + if (tcp_incoming_rcvbuf != 0 && tcp_incoming_rcvbuf < SOCKET_BUF_SIZE) { + tcp_incoming_rcvbuf = 0; + } + + if (tcp_incoming_rcvbuf != 0) { + LOGI("set TCP incoming connection receive buffer size to %d", tcp_incoming_rcvbuf); + } + if (tcp_outgoing_sndbuf != 0 && tcp_outgoing_sndbuf < SOCKET_BUF_SIZE) { tcp_outgoing_sndbuf = 0; } @@ -1828,6 +1860,14 @@ main(int argc, char **argv) LOGI("set TCP outgoing connection send buffer size to %d", tcp_outgoing_sndbuf); } + if (tcp_outgoing_rcvbuf != 0 && tcp_outgoing_rcvbuf < SOCKET_BUF_SIZE) { + tcp_outgoing_rcvbuf = 0; + } + + if (tcp_outgoing_rcvbuf != 0) { + LOGI("set TCP outgoing connection receive buffer size to %d", tcp_outgoing_recvbuf); + } + if (server_num == 0) { server_addr[server_num++].host = "0.0.0.0"; } diff --git a/src/tunnel.c b/src/tunnel.c index dfb2bf69..faf8cf81 100644 --- a/src/tunnel.c +++ b/src/tunnel.c @@ -83,7 +83,9 @@ int vpn = 0; int verbose = 0; int reuse_port = 0; int tcp_incoming_sndbuf = 0; +int tcp_incoming_rcvbuf = 0; int tcp_outgoing_sndbuf = 0; +int tcp_outgoing_rcvbuf = 0; static crypto_t *crypto; @@ -727,6 +729,10 @@ accept_cb(EV_P_ ev_io *w, int revents) setsockopt(serverfd, SOL_SOCKET, SO_SNDBUF, &tcp_incoming_sndbuf, sizeof(int)); } + if (tcp_incoming_rcvbuf > 0) { + setsockopt(serverfd, SOL_SOCKET, SO_RCVBUF, &tcp_incoming_rcvbuf, sizeof(int)); + } + int index = rand() % listener->remote_num; struct sockaddr *remote_addr = listener->remote_addr[index]; @@ -784,6 +790,10 @@ accept_cb(EV_P_ ev_io *w, int revents) setsockopt(remotefd, SOL_SOCKET, SO_SNDBUF, &tcp_outgoing_sndbuf, sizeof(int)); } + if (tcp_outgoing_rcvbuf > 0) { + setsockopt(remotefd, SOL_SOCKET, SO_RCVBUF, &tcp_outgoing_rcvbuf, sizeof(int)); + } + // Setup setnonblocking(remotefd); #ifdef SET_INTERFACE @@ -909,7 +919,9 @@ main(int argc, char **argv) { "plugin-opts", required_argument, NULL, GETOPT_VAL_PLUGIN_OPTS }, { "reuse-port", no_argument, NULL, GETOPT_VAL_REUSE_PORT }, { "tcp-incoming-sndbuf", required_argument, NULL, GETOPT_VAL_TCP_INCOMING_SNDBUF }, + { "tcp-incoming-rcvbuf", required_argument, NULL, GETOPT_VAL_TCP_INCOMING_RCVBUF }, { "tcp-outgoing-sndbuf", required_argument, NULL, GETOPT_VAL_TCP_OUTGOING_SNDBUF }, + { "tcp-outgoing-rcvbuf", required_argument, NULL, GETOPT_VAL_TCP_OUTGOING_RCVBUF }, { "password", required_argument, NULL, GETOPT_VAL_PASSWORD }, { "key", required_argument, NULL, GETOPT_VAL_KEY }, { "help", no_argument, NULL, GETOPT_VAL_HELP }, @@ -958,9 +970,15 @@ main(int argc, char **argv) case GETOPT_VAL_TCP_INCOMING_SNDBUF: tcp_incoming_sndbuf = atoi(optarg); break; + case GETOPT_VAL_TCP_INCOMING_RCVBUF: + tcp_incoming_rcvbuf = atoi(optarg); + break; case GETOPT_VAL_TCP_OUTGOING_SNDBUF: tcp_outgoing_sndbuf = atoi(optarg); break; + case GETOPT_VAL_TCP_OUTGOING_RCVBUF: + tcp_outgoing_rcvbuf = atoi(optarg); + break; case 's': if (remote_num < MAX_REMOTE_NUM) { parse_addr(optarg, &remote_addr[remote_num++]); @@ -1107,9 +1125,15 @@ main(int argc, char **argv) if (tcp_incoming_sndbuf == 0) { tcp_incoming_sndbuf = conf->tcp_incoming_sndbuf; } + if (tcp_incoming_rcvbuf == 0) { + tcp_incoming_rcvbuf = conf->tcp_incoming_rcvbuf; + } if (tcp_outgoing_sndbuf == 0) { tcp_outgoing_sndbuf = conf->tcp_outgoing_sndbuf; } + if (tcp_outgoing_rcvbuf == 0) { + tcp_outgoing_rcvbuf = conf->tcp_outgoing_rcvbuf; + } if (fast_open == 0) { fast_open = conf->fast_open; } @@ -1138,6 +1162,14 @@ main(int argc, char **argv) LOGI("set TCP incoming connection send buffer size to %d", tcp_incoming_sndbuf); } + if (tcp_incoming_rcvbuf != 0 && tcp_incoming_rcvbuf < SOCKET_BUF_SIZE) { + tcp_incoming_rcvbuf = 0; + } + + if (tcp_incoming_rcvbuf != 0) { + LOGI("set TCP incoming connection receive buffer size to %d", tcp_incoming_rcvbuf); + } + if (tcp_outgoing_sndbuf != 0 && tcp_outgoing_sndbuf < SOCKET_BUF_SIZE) { tcp_outgoing_sndbuf = 0; } @@ -1146,6 +1178,14 @@ main(int argc, char **argv) LOGI("set TCP outgoing connection send buffer size to %d", tcp_outgoing_sndbuf); } + if (tcp_outgoing_rcvbuf != 0 && tcp_outgoing_rcvbuf < SOCKET_BUF_SIZE) { + tcp_outgoing_rcvbuf = 0; + } + + if (tcp_outgoing_rcvbuf != 0) { + LOGI("set TCP outgoing connection receive buffer size to %d", tcp_outgoing_recvbuf); + } + if (plugin != NULL) { uint16_t port = get_local_port(); if (port == 0) { diff --git a/src/utils.c b/src/utils.c index b1adec30..16defb28 100644 --- a/src/utils.c +++ b/src/utils.c @@ -389,8 +389,12 @@ usage() #endif printf( " [--tcp-incoming-sndbuf] Size of the incoming connection TCP send buffer.\n"); + printf( + " [--tcp-incoming-rcvbuf] Size of the incoming connection TCP receive buffer.\n"); printf( " [--tcp-outgoing-sndbuf] Size of the outgoing connection TCP send buffer.\n"); + printf( + " [--tcp-outgoing-rcvbuf] Size of the outgoing connection TCP receive buffer.\n"); #if defined(MODULE_REMOTE) || defined(MODULE_LOCAL) printf( " [--acl ] Path to ACL (Access Control List).\n");