diff --git a/doc/configuration.txt b/doc/configuration.txt index f20b8b2ea..daec87958 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -1463,9 +1463,14 @@ bind / [, ...] [ group | gid ] 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). - This parameter is only compatible with TCP sockets. + work on other operating systems. It may also not change the + advertised value but change the effective size of outgoing + segments. The commonly advertised value on Ethernet networks + is 1460 = 1500(MTU) - 40(IP+TCP). If this value is positive, + it will be used as the advertised MSS. If it is negative, it + will indicate by how much to reduce the incoming connection's + advertised MSS for outgoing segments. This parameter is only + compatible with TCP sockets. is a persistent value for socket ID. Must be positive and unique in the proxy. An unused value will automatically be diff --git a/src/cfgparse.c b/src/cfgparse.c index ddfbe4253..a67b34838 100644 --- a/src/cfgparse.c +++ b/src/cfgparse.c @@ -1683,9 +1683,9 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm) goto out; } - 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", + mss = atoi(args[cur_arg + 1]); + if (!mss || abs(mss) > 65535) { + Alert("parsing [%s:%d]: %s expects an MSS with and absolute value between 1 and 65535.\n", file, linenum, args[0]); err_code |= ERR_ALERT | ERR_FATAL; goto out; diff --git a/src/frontend.c b/src/frontend.c index 4fc4460f0..8842e28ca 100644 --- a/src/frontend.c +++ b/src/frontend.c @@ -20,6 +20,8 @@ #include #include +#include + #include #include #include @@ -100,6 +102,17 @@ int frontend_accept(struct session *s) if (s->fe->options & PR_O_TCP_NOLING) setsockopt(cfd, SOL_SOCKET, SO_LINGER, (struct linger *) &nolinger, sizeof(struct linger)); +#if defined(TCP_MAXSEG) + if (s->listener->maxseg < 0) { + /* we just want to reduce the current MSS by that value */ + int mss; + int mss_len = sizeof(mss); + if (getsockopt(cfd, IPPROTO_TCP, TCP_MAXSEG, &mss, &mss_len) == 0) { + mss += s->listener->maxseg; /* remember, it's < 0 */ + setsockopt(cfd, IPPROTO_TCP, TCP_MAXSEG, &mss, sizeof(mss)); + } + } +#endif } if (global.tune.client_sndbuf) diff --git a/src/proto_tcp.c b/src/proto_tcp.c index 5039db8be..6328d0a5a 100644 --- a/src/proto_tcp.c +++ b/src/proto_tcp.c @@ -509,7 +509,7 @@ int tcp_bind_listener(struct listener *listener, char *errmsg, int errlen) } #endif #if defined(TCP_MAXSEG) - if (listener->maxseg) { + if (listener->maxseg > 0) { if (setsockopt(fd, IPPROTO_TCP, TCP_MAXSEG, &listener->maxseg, sizeof(listener->maxseg)) == -1) { msg = "cannot set MSS";