diff --git a/doc/configuration.txt b/doc/configuration.txt index 0d1476333..6ce658c6a 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -17512,6 +17512,18 @@ tcp-md5sig introduction of spoofed TCP segments into the connection stream. But it can be useful for any very long-lived TCP connections. +tcp-ss + Sets the TCP Save SYN option for all incoming connections instantiated from + this listening socket. This option is available on Linux since version 4.3. + It instructs the kernel to try to keep a copy of the incoming IP packet + containing the TCP SYN flag, for later inspection. The option knows 3 modes: + - 0 SYN packet saving is disabled, this is the default + - 1 SYN packet saving is enabled, and contains IP and TCP headers + - 2 SYN packet saving is enabled, and contains ETH, IP and TCP headers + + This only works for regular TCP connections, and is ignored for other + protocols (e.g. UNIX sockets). See also "fc.saved_syn". + tcp-ut Sets the TCP User Timeout for all incoming connections instantiated from this listening socket. This option is available on Linux since version 2.6.37. It diff --git a/include/haproxy/listener-t.h b/include/haproxy/listener-t.h index 5f17b34b8..50deb5476 100644 --- a/include/haproxy/listener-t.h +++ b/include/haproxy/listener-t.h @@ -204,6 +204,7 @@ struct bind_conf { unsigned int backlog; /* if set, listen backlog */ int maxconn; /* maximum connections allowed on this listener */ int (*accept)(struct connection *conn); /* upper layer's accept() */ + int tcp_ss; /* for TCP, Save SYN */ int level; /* stats access level (ACCESS_LVL_*) */ int severity_output; /* default severity output format in cli feedback messages */ short int nice; /* nice value to assign to the instantiated tasks */ diff --git a/src/cfgparse-tcp.c b/src/cfgparse-tcp.c index cf6b50c02..ba713f9a9 100644 --- a/src/cfgparse-tcp.c +++ b/src/cfgparse-tcp.c @@ -146,6 +146,25 @@ static int bind_parse_tcp_md5sig(char **args, int cur_arg, struct proxy *px, str } #endif +#ifdef TCP_SAVE_SYN +/* parse the "tcp-ss" bind keyword */ +static int bind_parse_tcp_ss(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err) +{ + int tcp_ss = -1; + + if (isdigit((unsigned char)*args[cur_arg + 1])) + tcp_ss = atoi(args[cur_arg + 1]); + + if (tcp_ss < 0 || tcp_ss > 2) { + memprintf(err, "'%s' : TCP Save SYN option expects an integer argument from 0 to 2", args[cur_arg]); + return ERR_ALERT | ERR_FATAL; + } + + conf->tcp_ss = tcp_ss; + return 0; +} +#endif + #ifdef TCP_USER_TIMEOUT /* parse the "tcp-ut" bind keyword */ static int bind_parse_tcp_ut(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err) @@ -332,6 +351,9 @@ static struct bind_kw_list bind_kws = { "TCP", { }, { #if defined(__linux__) && defined(TCP_MD5SIG) { "tcp-md5sig", bind_parse_tcp_md5sig, 1 }, /* set TCP MD5 signature password */ #endif +#ifdef TCP_SAVE_SYN + { "tcp-ss", bind_parse_tcp_ss, 1 }, /* set TCP Save SYN option (0=no, 1=yes, 2=with MAC hdr) */ +#endif #ifdef TCP_USER_TIMEOUT { "tcp-ut", bind_parse_tcp_ut, 1 }, /* set User Timeout on listening socket */ #endif diff --git a/src/proto_tcp.c b/src/proto_tcp.c index 1f8c8f293..b90445868 100644 --- a/src/proto_tcp.c +++ b/src/proto_tcp.c @@ -778,6 +778,17 @@ int tcp_bind_listener(struct listener *listener, char *errmsg, int errlen) } } #endif +#if defined(TCP_SAVE_SYN) + if (listener->bind_conf->tcp_ss) { + if (setsockopt(fd, IPPROTO_TCP, TCP_SAVE_SYN, + &listener->bind_conf->tcp_ss, sizeof(listener->bind_conf->tcp_ss)) == -1) { + chunk_appendf(msg, "%scannot set TCP Save SYN, (%s)", msg->data ? ", " : "", + strerror(errno)); + err |= ERR_WARN; + } + } else + setsockopt(fd, IPPROTO_TCP, TCP_SAVE_SYN, &zero, sizeof(zero)); +#endif #if defined(TCP_USER_TIMEOUT) if (listener->bind_conf->tcp_ut) { if (setsockopt(fd, IPPROTO_TCP, TCP_USER_TIMEOUT,