From c73ce2b111130bd32c0ee6874ddcf3a3bb16f795 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Sun, 6 Jan 2008 10:55:10 +0100 Subject: [PATCH] [MINOR] add support for the "backlog" parameter Add the "backlog" parameter to frontends, to give hints to the system about the approximate listen backlog desired size. In order to protect against SYN flood attacks, one solution is to increase the system's SYN backlog size. Depending on the system, sometimes it is just tunable via a system parameter, sometimes it is not adjustable at all, and sometimes the system relies on hints given by the application at the time of the listen() syscall. By default, HAProxy passes the frontend's maxconn value to the listen() syscall. On systems which can make use of this value, it can sometimes be useful to be able to specify a different value, hence this backlog parameter. --- doc/configuration.txt | 28 +++++++++++++++++++++++++++- include/types/protocols.h | 1 + include/types/proxy.h | 1 + src/cfgparse.c | 12 ++++++++++++ src/proto_tcp.c | 2 +- src/proxy.c | 4 ++-- tests/test-backlog.cfg | 22 ++++++++++++++++++++++ 7 files changed, 66 insertions(+), 4 deletions(-) create mode 100644 tests/test-backlog.cfg diff --git a/doc/configuration.txt b/doc/configuration.txt index 3f0be93a22..1c7a058d24 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -4,7 +4,7 @@ ---------------------- version 1.3.14.2 willy tarreau - 2007/12/27 + 2008/01/05 This document covers the configuration language as implemented in the version @@ -502,6 +502,7 @@ keyword defaults frontend listen backend ----------------------+----------+----------+---------+--------- acl - X X X appsession - - X X +backlog X X X - balance X - X X bind - X X - block - X X X @@ -653,6 +654,31 @@ appsession len timeout See also : "cookie", "capture cookie" and "balance". +backlog + Give hints to the system about the approximate listen backlog desired size + May be used in sections : defaults | frontend | listen | backend + yes | yes | yes | no + Arguments : + is the number of pending connections. Depending on the operating + system, it may represent the number of already acknowledged + connections, of non-acknowledged ones, or both. + + In order to protect against SYN flood attacks, one solution is to increase + the system's SYN backlog size. Depending on the system, sometimes it is just + tunable via a system parameter, sometimes it is not adjustable at all, and + sometimes the system relies on hints given by the application at the time of + the listen() syscall. By default, HAProxy passes the frontend's maxconn value + to the listen() syscall. On systems which can make use of this value, it can + sometimes be useful to be able to specify a different value, hence this + backlog parameter. + + On Linux 2.4, the parameter is ignored by the system. On Linux 2.6, it is + used as a hint and the system accepts up to the smallest greater power of + two, and never more than some limits (usually 32768). + + See also : "maxconn" and the target operating system's tuning guide. + + balance [ ] Define the load balancing algorithm to be used in a backend. May be used in sections : defaults | frontend | listen | backend diff --git a/include/types/protocols.h b/include/types/protocols.h index 6c59ce10af..f360746591 100644 --- a/include/types/protocols.h +++ b/include/types/protocols.h @@ -78,6 +78,7 @@ struct listener { struct protocol *proto; /* protocol this listener belongs to */ int nbconn; /* current number of connections on this listener */ int maxconn; /* maximum connections allowed on this listener */ + unsigned int backlog; /* if set, listen backlog */ struct listener *next; /* next address for the same proxy, or NULL */ struct list proto_list; /* list in the protocol header */ int (*accept)(int fd); /* accept() function passed to fdtab[] */ diff --git a/include/types/proxy.h b/include/types/proxy.h index ef748936de..8a72d82d56 100644 --- a/include/types/proxy.h +++ b/include/types/proxy.h @@ -228,6 +228,7 @@ struct proxy { struct chunk errmsg[HTTP_ERR_SIZE]; /* default or customized error messages for known errors */ int uuid; /* universally unique proxy ID, used for SNMP */ int next_svid; /* next server-id, used for SNMP */ + unsigned int backlog; /* force the frontend's listen backlog */ }; struct switching_rule { diff --git a/src/cfgparse.c b/src/cfgparse.c index ae05da0aa4..7b43b7e68d 100644 --- a/src/cfgparse.c +++ b/src/cfgparse.c @@ -614,6 +614,7 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int inv) if (curproxy->cap & PR_CAP_FE) { curproxy->maxconn = defproxy.maxconn; + curproxy->backlog = defproxy.backlog; /* initialize error relocations */ for (rc = 0; rc < HTTP_ERR_SIZE; rc++) { @@ -1365,6 +1366,16 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int inv) } curproxy->maxconn = atol(args[1]); } + else if (!strcmp(args[0], "backlog")) { /* backlog */ + if (warnifnotcap(curproxy, PR_CAP_FE, file, linenum, args[0], NULL)) + return 0; + + if (*(args[1]) == 0) { + Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]); + return -1; + } + curproxy->backlog = atol(args[1]); + } else if (!strcmp(args[0], "fullconn")) { /* fullconn */ if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], " Maybe you want 'maxconn' instead ?")) return 0; @@ -2865,6 +2876,7 @@ int readcfgfile(const char *file) if (curproxy->options & PR_O_TCP_NOLING) listener->options |= LI_O_NOLINGER; listener->maxconn = curproxy->maxconn; + listener->backlog = curproxy->backlog; listener->timeout = &curproxy->timeout.client; listener->accept = event_accept; listener->private = curproxy; diff --git a/src/proto_tcp.c b/src/proto_tcp.c index 593096d7f3..2da34db38f 100644 --- a/src/proto_tcp.c +++ b/src/proto_tcp.c @@ -160,7 +160,7 @@ int tcp_bind_listener(struct listener *listener, char *errmsg, int errlen) goto tcp_close_return; } - if (listen(fd, listener->maxconn) == -1) { + if (listen(fd, listener->backlog ? listener->backlog : listener->maxconn) == -1) { err |= ERR_RETRYABLE | ERR_ALERT; msg = "cannot listen to socket"; goto tcp_close_return; diff --git a/src/proxy.c b/src/proxy.c index 1b12844ea2..82bb2ae14e 100644 --- a/src/proxy.c +++ b/src/proxy.c @@ -369,7 +369,7 @@ void pause_proxy(struct proxy *p) struct listener *l; for (l = p->listen; l != NULL; l = l->next) { if (shutdown(l->fd, SHUT_WR) == 0 && - listen(l->fd, p->maxconn) == 0 && + listen(l->fd, p->backlog ? p->backlog : p->maxconn) == 0 && shutdown(l->fd, SHUT_RD) == 0) { EV_FD_CLR(l->fd, DIR_RD); if (p->state != PR_STERROR) @@ -435,7 +435,7 @@ void listen_proxies(void) send_log(p, LOG_WARNING, "Enabling proxy %s.\n", p->id); for (l = p->listen; l != NULL; l = l->next) { - if (listen(l->fd, p->maxconn) == 0) { + if (listen(l->fd, p->backlog ? p->backlog : p->maxconn) == 0) { if (actconn < global.maxconn && p->feconn < p->maxconn) { EV_FD_SET(l->fd, DIR_RD); p->state = PR_STRUN; diff --git a/tests/test-backlog.cfg b/tests/test-backlog.cfg new file mode 100644 index 0000000000..bc4a71e321 --- /dev/null +++ b/tests/test-backlog.cfg @@ -0,0 +1,22 @@ +# This is a test configuration. +# It is used to check that the backlog queue works as expected. + +global + maxconn 200 + stats timeout 3s + +frontend backlog_def + mode http + timeout client 15s + maxconn 100 + bind :8000 + option httpclose + +frontend backlog_max + mode http + timeout client 15s + maxconn 100 + backlog 100000 + bind :8001 + option httpclose +