]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
[MEDIUM] add support for TCP MSS adjustment for listeners
authorWilly Tarreau <w@1wt.eu>
Sun, 14 Jun 2009 16:48:19 +0000 (18:48 +0200)
committerWilly Tarreau <w@1wt.eu>
Sun, 14 Jun 2009 16:48:19 +0000 (18:48 +0200)
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.

doc/configuration.txt
include/types/protocols.h
src/cfgparse.c
src/proto_tcp.c

index ce2a02b52aefd011dac50ef613cf046a2bd7fe3b..cf30c15e387a86cdafa5f3eb09bd1157fb8dcada 100644 (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
index 8d0ac9f1ff78ac31fd9dcc67babf80af8a45a176..0b4b7123a620414240c27efb0e018066191ab710 100644 (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.
index 9ec869e11c067730c2c836c6213a463dd8b11382..413aeaef3eccfa8f928bf2c8c581d07f765dea76 100644 (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
index e9b3ae37b992eee5c5754bb19eadd9e75afcd2cd..adf4e230c0158f4cb870a8921396b5a1cfe6c5c2 100644 (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;