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 +