[MEDIUM] add support for TCP MSS adjustment for listeners

Sometimes it can be useful to limit the advertised TCP MSS on
incoming connections, for instance when requests come through
a VPN or when the system is running with jumbo frames enabled.

Passing the "mss <value>" arguments to a "bind" line will set
the value. This works under Linux >= 2.6.28, and maybe a few
earlier ones, though due to an old kernel bug most of earlier
versions will probably ignore it. It is also possible that some
other OSes will support this.
This commit is contained in:
Willy Tarreau 2009-06-14 18:48:19 +02:00
parent 32087312e3
commit be1b91842a
4 changed files with 51 additions and 0 deletions

View File

@ -1012,6 +1012,7 @@ balance url_param <param> [check_post [<max_wait>]]
bind [<address>]:<port> [, ...]
bind [<address>]:<port> [, ...] interface <interface>
bind [<address>]:<port> [, ...] mss <maxseg>
bind [<address>]:<port> [, ...] 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 [<address>]:<port> [, ...] transparent
Note that binding to a physical interface requires root
privileges.
<maxseg> 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

View File

@ -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.

View File

@ -23,6 +23,8 @@
#include <fcntl.h>
#include <unistd.h>
#include <netinet/tcp.h>
#include <common/cfgparse.h>
#include <common/config.h>
#include <common/memory.h>
@ -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

View File

@ -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;