From 78784507f12e956fbb2fb611b510fb7da66b179d Mon Sep 17 00:00:00 2001 From: zfl9 Date: Sat, 18 Jul 2020 16:23:21 +0800 Subject: [PATCH] add `tcp_tproxy` option, use tproxy instead of redirect (tcp) --- src/jconf.c | 5 +++++ src/jconf.h | 1 + src/redir.c | 50 ++++++++++++++++++++++++++++++++++++++++++++------ src/utils.c | 4 ++++ 4 files changed, 54 insertions(+), 6 deletions(-) diff --git a/src/jconf.c b/src/jconf.c index dd38ee96..5ad6110a 100644 --- a/src/jconf.c +++ b/src/jconf.c @@ -338,6 +338,11 @@ read_jconf(const char *file) value, json_boolean, "invalid config file: option 'no_delay' must be a boolean"); conf.no_delay = value->u.boolean; + } else if (strcmp(name, "tcp_tproxy") == 0) { + check_json_value_type( + value, json_boolean, + "invalid config file: option 'tcp_tproxy' must be a boolean"); + conf.tcp_tproxy = value->u.boolean; } else if (strcmp(name, "workdir") == 0) { conf.workdir = to_string(value); } else if (strcmp(name, "acl") == 0) { diff --git a/src/jconf.h b/src/jconf.h index ed0ecafc..4bf7f5e2 100644 --- a/src/jconf.h +++ b/src/jconf.h @@ -82,6 +82,7 @@ typedef struct { int mptcp; int ipv6_first; int no_delay; + int tcp_tproxy; char *workdir; char *acl; char *manager_address; diff --git a/src/redir.c b/src/redir.c index 4ba1c3f8..0c33d767 100644 --- a/src/redir.c +++ b/src/redir.c @@ -65,6 +65,14 @@ #define IP6T_SO_ORIGINAL_DST 80 #endif +#ifndef IP_TRANSPARENT +#define IP_TRANSPARENT 19 +#endif + +#ifndef IPV6_TRANSPARENT +#define IPV6_TRANSPARENT 75 +#endif + static void accept_cb(EV_P_ ev_io *w, int revents); static void server_recv_cb(EV_P_ ev_io *w, int revents); static void server_send_cb(EV_P_ ev_io *w, int revents); @@ -97,19 +105,26 @@ static struct ev_signal sigint_watcher; static struct ev_signal sigterm_watcher; static struct ev_signal sigchld_watcher; +static int tcp_tproxy = 0; /* use tproxy instead of redirect (for tcp) */ + static int getdestaddr(int fd, struct sockaddr_storage *destaddr) { socklen_t socklen = sizeof(*destaddr); int error = 0; - error = getsockopt(fd, SOL_IPV6, IP6T_SO_ORIGINAL_DST, destaddr, &socklen); - if (error) { // Didn't find a proper way to detect IP version. - error = getsockopt(fd, SOL_IP, SO_ORIGINAL_DST, destaddr, &socklen); - if (error) { - return -1; + if (tcp_tproxy) { + error = getsockname(fd, (void *)destaddr, &socklen); + } else { + error = getsockopt(fd, SOL_IPV6, IP6T_SO_ORIGINAL_DST, destaddr, &socklen); + if (error) { // Didn't find a proper way to detect IP version. + error = getsockopt(fd, SOL_IP, SO_ORIGINAL_DST, destaddr, &socklen); } } + + if (error) { + return -1; + } return 0; } @@ -165,6 +180,23 @@ create_and_bind(const char *addr, const char *port) } } + if (tcp_tproxy) { + int level = 0, optname = 0; + if (rp->ai_family == AF_INET) { + level = IPPROTO_IP; + optname = IP_TRANSPARENT; + } else { + level = IPPROTO_IPV6; + optname = IPV6_TRANSPARENT; + } + + if (setsockopt(listen_sock, level, optname, &opt, sizeof(opt)) != 0) { + ERROR("setsockopt IP_TRANSPARENT"); + exit(EXIT_FAILURE); + } + LOGI("tcp tproxy mode enabled"); + } + s = bind(listen_sock, rp->ai_addr, rp->ai_addrlen); if (s == 0) { /* We managed to bind successfully! */ @@ -882,7 +914,7 @@ main(int argc, char **argv) USE_TTY(); - while ((c = getopt_long(argc, argv, "f:s:p:l:k:t:m:c:b:a:n:huUv6A", + while ((c = getopt_long(argc, argv, "f:s:p:l:k:t:m:c:b:a:n:huUTv6A", long_options, NULL)) != -1) { switch (c) { case GETOPT_VAL_FAST_OPEN: @@ -957,6 +989,9 @@ main(int argc, char **argv) case 'U': mode = UDP_ONLY; break; + case 'T': + tcp_tproxy = 1; + break; case 'v': verbose = 1; break; @@ -1029,6 +1064,9 @@ main(int argc, char **argv) if (mode == TCP_ONLY) { mode = conf->mode; } + if (tcp_tproxy == 0) { + tcp_tproxy = conf->tcp_tproxy; + } if (mtu == 0) { mtu = conf->mtu; } diff --git a/src/utils.c b/src/utils.c index 87107aa3..0e94e5d9 100644 --- a/src/utils.c +++ b/src/utils.c @@ -360,6 +360,10 @@ usage() #endif printf( " [-U] Enable UDP relay and disable TCP relay.\n"); +#ifdef MODULE_REDIR + printf( + " [-T] Use tproxy instead of redirect (for tcp).\n"); +#endif #ifdef MODULE_REMOTE printf( " [-6] Resovle hostname to IPv6 address first.\n");