diff --git a/doc/haproxy-en.txt b/doc/haproxy-en.txt index 76d54c463..1341aea53 100644 --- a/doc/haproxy-en.txt +++ b/doc/haproxy-en.txt @@ -1034,6 +1034,13 @@ the response is considered as valid. Note that Apache does not generate a log when it receives only an HELLO message, which makes this type of message perfectly suit this need. +Version 1.3.10 introduced the SMTP health check. By default, it sends +"HELO localhost" to the servers, and waits for the 250 message. Note that it +can also send a specific request : + + - option smtpchk -> sends "HELO localhost" + - option smtpchk EHLO mail.mydomain.com -> sends this ESMTP greeting + See examples below. Since version 1.1.17, it is possible to specify backup servers. These servers diff --git a/doc/haproxy-fr.txt b/doc/haproxy-fr.txt index 8e83eab09..795b67b3c 100644 --- a/doc/haproxy-fr.txt +++ b/doc/haproxy-fr.txt @@ -1044,6 +1044,14 @@ r lorsqu'il reçoit des messages HELLO, ce qui en fait un type de message parfaitement adapté à ce besoin. +La version 1.3.10 est accompagnée d'un nouveau test d'état pour le SMTP. Par +défaut, il consiste à envoyer "HELO localhost" aux serveurs, et à attendre le +message "250" en retour. Notez qu'il peut aussi envoyer une requête plus +spécifique : + + - option smtpchk -> envoie "HELO localhost" + - option smtpchk EHLO mail.mydomain.com -> envoie ce message ESMTP + Voir les exemples ci-après. Depuis la version 1.1.17, il est possible de définir des serveurs de secours, diff --git a/include/common/defaults.h b/include/common/defaults.h index c99aafe4f..cfe60e8f9 100644 --- a/include/common/defaults.h +++ b/include/common/defaults.h @@ -92,6 +92,7 @@ #define DEF_FALLTIME 3 #define DEF_RISETIME 2 #define DEF_CHECK_REQ "OPTIONS / HTTP/1.0\r\n\r\n" +#define DEF_SMTP_CHECK_REQ "HELO localhost\r\n" /* Default connections limit. * diff --git a/include/types/backend.h b/include/types/backend.h index e2d4efc6f..57a8cb053 100644 --- a/include/types/backend.h +++ b/include/types/backend.h @@ -59,6 +59,7 @@ #define PR_O_TCPSPLICE 0x08000000 /* delegate data transfer to linux kernel's tcp_splice */ #define PR_O_BALANCE_UH 0x10000000 /* balance on URI hash */ #define PR_O_BALANCE (PR_O_BALANCE_RR | PR_O_BALANCE_SH | PR_O_BALANCE_UH) +#define PR_O_SMTP_CHK 0x20000000 /* use SMTP EHLO check for server health - pvandijk@vision6.com.au */ #endif /* _TYPES_BACKEND_H */ diff --git a/src/cfgparse.c b/src/cfgparse.c index 41d706611..b2e76b310 100644 --- a/src/cfgparse.c +++ b/src/cfgparse.c @@ -1029,13 +1029,14 @@ int cfg_parse_listen(const char *file, int linenum, char **args) if (curproxy->check_req != NULL) { free(curproxy->check_req); } - curproxy->options |= PR_O_HTTP_CHK; curproxy->options &= ~PR_O_SSL3_CHK; + curproxy->options &= ~PR_O_SMTP_CHK; + curproxy->options |= PR_O_HTTP_CHK; if (!*args[2]) { /* no argument */ curproxy->check_req = strdup(DEF_CHECK_REQ); /* default request */ curproxy->check_len = strlen(DEF_CHECK_REQ); } else if (!*args[3]) { /* one argument : URI */ - int reqlen = strlen(args[2]) + strlen("OPTIONS / HTTP/1.0\r\n\r\n"); + int reqlen = strlen(args[2]) + strlen("OPTIONS HTTP/1.0\r\n\r\n") + 1; curproxy->check_req = (char *)malloc(reqlen); curproxy->check_len = snprintf(curproxy->check_req, reqlen, "OPTIONS %s HTTP/1.0\r\n\r\n", args[2]); /* URI to use */ @@ -1060,8 +1061,35 @@ int cfg_parse_listen(const char *file, int linenum, char **args) free(curproxy->check_req); } curproxy->options &= ~PR_O_HTTP_CHK; + curproxy->options &= ~PR_O_SMTP_CHK; curproxy->options |= PR_O_SSL3_CHK; } + else if (!strcmp(args[1], "smtpchk")) { + /* use SMTP request to check servers' health */ + if (curproxy->check_req != NULL) { + free(curproxy->check_req); + } + curproxy->options &= ~PR_O_HTTP_CHK; + curproxy->options &= ~PR_O_SSL3_CHK; + curproxy->options |= PR_O_SMTP_CHK; + + if (!*args[2] || !*args[3]) { /* no argument or incomplete EHLO host */ + curproxy->check_req = strdup(DEF_SMTP_CHECK_REQ); /* default request */ + curproxy->check_len = strlen(DEF_SMTP_CHECK_REQ); + } else { /* ESMTP EHLO, or SMTP HELO, and a hostname */ + if (!strcmp(args[2], "EHLO") || !strcmp(args[2], "HELO")) { + int reqlen = strlen(args[2]) + strlen(args[3]) + strlen(" \r\n") + 1; + curproxy->check_req = (char *)malloc(reqlen); + curproxy->check_len = snprintf(curproxy->check_req, reqlen, + "%s %s\r\n", args[2], args[3]); /* HELO hostname */ + } else { + /* this just hits the default for now, but you could potentially expand it to allow for other stuff + though, it's unlikely you'd want to send anything other than an EHLO or HELO */ + curproxy->check_req = strdup(DEF_SMTP_CHECK_REQ); /* default request */ + curproxy->check_len = strlen(DEF_SMTP_CHECK_REQ); + } + } + } else if (!strcmp(args[1], "forwardfor")) { /* insert x-forwarded-for field, but not for the * IP address listed as an except. diff --git a/src/checks.c b/src/checks.c index 14f0c8cc8..ec56453a5 100644 --- a/src/checks.c +++ b/src/checks.c @@ -122,7 +122,8 @@ static int event_srv_chk_w(int fd) if (s->result != -1) { /* we don't want to mark 'UP' a server on which we detected an error earlier */ if ((s->proxy->options & PR_O_HTTP_CHK) || - (s->proxy->options & PR_O_SSL3_CHK)) { + (s->proxy->options & PR_O_SSL3_CHK) || + (s->proxy->options & PR_O_SMTP_CHK)) { int ret; /* we want to check if this host replies to HTTP or SSLv3 requests * so we'll send the request, and won't wake the checker up now. @@ -252,6 +253,10 @@ static int event_srv_chk_r(int fd) /* SSLv3 alert or handshake */ result = 1; } + else if ((s->proxy->options & PR_O_SMTP_CHK) && (len >= 3) && + (reply[0] == '2')) /* 2xx (should be 250) */ { + result = 1; + } if (result == -1) fdtab[fd].state = FD_STERROR;