diff --git a/doc/configuration.txt b/doc/configuration.txt index ce2a02b52..cf30c15e3 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -1012,6 +1012,7 @@ balance url_param [check_post []] bind [
]: [, ...] bind [
]: [, ...] interface +bind [
]: [, ...] mss bind [
]: [, ...] transparent Define one or several listening addresses and/or ports in a frontend. May be used in sections : defaults | frontend | listen | backend @@ -1037,6 +1038,15 @@ bind [
]: [, ...] transparent Note that binding to a physical interface requires root privileges. + is an optional TCP Maximum Segment Size (MSS) value to be + advertised on incoming connections. This can be used to force + a lower MSS for certain specific ports, for instance for + connections passing through a VPN. Note that this relies on a + kernel feature which is theorically supported under Linux but + was buggy in all versions prior to 2.6.28. It may or may not + work on other operating systems. The commonly advertised + value on Ethernet networks is 1460 = 1500(MTU) - 40(IP+TCP). + transparent is an optional keyword which is supported only on certain Linux kernels. It indicates that the addresses will be bound even if they do not belong to the local machine. Any packet diff --git a/include/types/protocols.h b/include/types/protocols.h index 8d0ac9f1f..0b4b7123a 100644 --- a/include/types/protocols.h +++ b/include/types/protocols.h @@ -98,6 +98,7 @@ struct listener { } ux; } perm; char *interface; /* interface name or NULL */ + int maxseg; /* for TCP, advertised MSS */ }; /* This structure contains all information needed to easily handle a protocol. diff --git a/src/cfgparse.c b/src/cfgparse.c index 9ec869e11..413aeaef3 100644 --- a/src/cfgparse.c +++ b/src/cfgparse.c @@ -23,6 +23,8 @@ #include #include +#include + #include #include #include @@ -959,6 +961,35 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm) file, linenum, args[0], args[cur_arg]); return -1; #endif + } + if (!strcmp(args[cur_arg], "mss")) { /* set MSS of listening socket */ +#ifdef TCP_MAXSEG + struct listener *l; + int mss; + + if (!*args[cur_arg + 1]) { + Alert("parsing [%s:%d] : '%s' : missing MSS value.\n", + file, linenum, args[0]); + return -1; + } + + mss = str2uic(args[cur_arg + 1]); + if (mss < 1 || mss > 65535) { + Alert("parsing [%s:%d]: %s expects an MSS value between 1 and 65535.\n", + file, linenum, args[0]); + return -1; + } + + for (l = curproxy->listen; l != last_listen; l = l->next) + l->maxseg = mss; + + cur_arg += 2; + continue; +#else + Alert("parsing [%s:%d] : '%s' : '%s' option not implemented.\n", + file, linenum, args[0], args[cur_arg]); + return -1; +#endif } if (!strcmp(args[cur_arg], "transparent")) { /* transparently bind to these addresses */ #ifdef CONFIG_HAP_LINUX_TPROXY diff --git a/src/proto_tcp.c b/src/proto_tcp.c index e9b3ae37b..adf4e230c 100644 --- a/src/proto_tcp.c +++ b/src/proto_tcp.c @@ -250,6 +250,15 @@ int tcp_bind_listener(struct listener *listener, char *errmsg, int errlen) err |= ERR_WARN; } } +#endif +#ifdef TCP_MAXSEG + if (listener->maxseg) { + if (setsockopt(fd, SOL_TCP, TCP_MAXSEG, + &listener->maxseg, sizeof(listener->maxseg)) == -1) { + msg = "cannot set MSS"; + err |= ERR_WARN; + } + } #endif if (bind(fd, (struct sockaddr *)&listener->addr, listener->proto->sock_addrlen) == -1) { err |= ERR_RETRYABLE | ERR_ALERT;