]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
[MINOR] checks: add support for LDAPv3 health checks
authorGabor Lekeny <gabor.lekeny@gmail.com>
Wed, 29 Sep 2010 16:17:05 +0000 (18:17 +0200)
committerWilly Tarreau <w@1wt.eu>
Sat, 30 Oct 2010 17:04:31 +0000 (19:04 +0200)
This patch provides a new "option ldap-check" statement to enable
server health checks based on LDAPv3 bind requests.
(cherry picked from commit b76b44c6fed8a7ba6f0f565dd72a9cb77aaeca7c)

doc/configuration.txt
include/common/defaults.h
include/types/proxy.h
src/cfgparse.c
src/checks.c

index 9eedf798724392dfd1d68d7ae0523f959d49a111..12ce86ec2b0d30148de7aa351fc09cf4dd22d072 100644 (file)
@@ -898,6 +898,7 @@ option httpclose                     (*)  X          X         X         X
 option httplog                            X          X         X         X
 option http_proxy                    (*)  X          X         X         X
 option independant-streams           (*)  X          X         X         X
+option ldap-check                         X          -         X         X
 option log-health-checks             (*)  X          -         X         X
 option log-separate-errors           (*)  X          X         X         -
 option logasap                       (*)  X          X         X         -
@@ -3120,6 +3121,29 @@ no option independant-streams
   See also : "timeout client" and "timeout server"
 
 
+option ldap-check
+  Use LDAPv3 health checks for server testing
+  May be used in sections :   defaults | frontend | listen | backend
+                                 yes   |    no    |   yes  |   yes
+  Arguments : none
+
+  It is possible to test that the server correctly talks LDAPv3 instead of just
+  testing that it accepts the TCP connection. When this option is set, an
+  LDAPv3 anonymous simple bind message is sent to the server, and the response
+  is analyzed to find an LDAPv3 bind response message.
+
+  The server is considered valid only when the LDAP response contains success
+  resultCode (http://tools.ietf.org/html/rfc4511#section-4.1.9).
+
+  Logging of bind requests is server dependent see your documentation how to
+  configure it.
+
+  Example :
+        option ldap-check
+
+  See also : "option httpchk"
+
+
 option log-health-checks
 no option log-health-checks
   Enable or disable logging of health checks
index 845319dff3c2d781dbaee0742eccd8f223e4cee4..84ab3d48ae27fd8fa31406660f266f9bafba7c77 100644 (file)
 #define DEF_RISETIME    2
 #define DEF_CHECK_REQ   "OPTIONS / HTTP/1.0\r\n"
 #define DEF_SMTP_CHECK_REQ   "HELO localhost\r\n"
+#define DEF_LDAP_CHECK_REQ   "\x30\x0c\x02\x01\x01\x60\x07\x02\x01\x03\x04\x00\x80\x00"
 
 #define DEF_HANA_ONERR         HANA_ONERR_FAILCHK
 #define DEF_HANA_ERRLIMIT      10
index 076a381d8f7e8b68347b29766ea3b2e4064e2ac3..f28bc40cf6a8d0f22788811fc57af49c78c189b2 100644 (file)
 #define PR_O2_CHK_SNDST 0x00080000      /* send the state of each server along with HTTP health checks */
 #define PR_O2_SSL3_CHK  0x00100000      /* use SSLv3 CLIENT_HELLO packets for server health */
 #define PR_O2_FAKE_KA   0x00200000      /* pretend we do keep-alive with server eventhough we close */
+#define PR_O2_LDAP_CHK  0x00400000      /* use LDAP check for server health */
 /* end of proxy->options2 */
 
 /* bits for sticking rules */
index 14171ce9fd43f42e1c2b3d2fd0906e65d0195357..0c14648811a76c10f7f75cee8f15b81544208bae 100644 (file)
@@ -2748,6 +2748,7 @@ stats_error_parsing:
                        curproxy->options &= ~PR_O_SMTP_CHK;
                        curproxy->options2 &= ~PR_O2_SSL3_CHK;
                        curproxy->options2 &= ~PR_O2_MYSQL_CHK;
+                       curproxy->options2 &= ~PR_O2_LDAP_CHK;
                        curproxy->options |= PR_O_HTTP_CHK;
                        if (!*args[2]) { /* no argument */
                                curproxy->check_req = strdup(DEF_CHECK_REQ); /* default request */
@@ -2779,6 +2780,7 @@ stats_error_parsing:
                        curproxy->options &= ~PR_O_HTTP_CHK;
                        curproxy->options &= ~PR_O_SMTP_CHK;
                        curproxy->options2 &= ~PR_O2_MYSQL_CHK;
+                       curproxy->options2 &= ~PR_O2_LDAP_CHK;
                        curproxy->options2 |= PR_O2_SSL3_CHK;
                }
                else if (!strcmp(args[1], "smtpchk")) {
@@ -2788,6 +2790,7 @@ stats_error_parsing:
                        curproxy->options &= ~PR_O_HTTP_CHK;
                        curproxy->options2 &= ~PR_O2_SSL3_CHK;
                        curproxy->options2 &= ~PR_O2_MYSQL_CHK;
+                       curproxy->options2 &= ~PR_O2_LDAP_CHK;
                        curproxy->options |= PR_O_SMTP_CHK;
 
                        if (!*args[2] || !*args[3]) { /* no argument or incomplete EHLO host */
@@ -2814,8 +2817,23 @@ stats_error_parsing:
                        curproxy->options &= ~PR_O_HTTP_CHK;
                        curproxy->options &= ~PR_O_SMTP_CHK;
                        curproxy->options2 &= ~PR_O2_SSL3_CHK;
+                       curproxy->options2 &= ~PR_O2_LDAP_CHK;
                        curproxy->options2 |= PR_O2_MYSQL_CHK;
                }
+               else if (!strcmp(args[1], "ldap-check")) {
+                       /* use LDAP request to check servers' health */
+                       free(curproxy->check_req);
+                       curproxy->check_req = NULL;
+                       curproxy->options &= ~PR_O_HTTP_CHK;
+                       curproxy->options &= ~PR_O_SMTP_CHK;
+                       curproxy->options2 &= ~PR_O2_SSL3_CHK;
+                       curproxy->options2 &= ~PR_O2_MYSQL_CHK;
+                       curproxy->options2 |= PR_O2_LDAP_CHK;
+
+                       curproxy->check_req = (char *) malloc(sizeof(DEF_LDAP_CHECK_REQ) - 1);
+                       memcpy(curproxy->check_req, DEF_LDAP_CHECK_REQ, sizeof(DEF_LDAP_CHECK_REQ) - 1);
+                       curproxy->check_len = sizeof(DEF_LDAP_CHECK_REQ) - 1;
+               }
                else if (!strcmp(args[1], "forwardfor")) {
                        int cur_arg;
 
index ef7839b148d70cb222df950b65fa8bc6cf43ea8e..3059d5714a99b59420015dd5f63eadbb5164d670 100644 (file)
@@ -743,7 +743,8 @@ static int event_srv_chk_w(int fd)
                if ((s->proxy->options & PR_O_HTTP_CHK) ||
                    (s->proxy->options & PR_O_SMTP_CHK) ||
                    (s->proxy->options2 & PR_O2_SSL3_CHK) ||
-                   (s->proxy->options2 & PR_O2_MYSQL_CHK)) {
+                   (s->proxy->options2 & PR_O2_MYSQL_CHK) ||
+                   (s->proxy->options2 & PR_O2_LDAP_CHK)) {
                        int ret;
                        const char *check_req = s->proxy->check_req;
                        int check_len = s->proxy->check_len;
@@ -866,6 +867,7 @@ static int event_srv_chk_r(int fd)
        struct server *s = t->context;
        char *desc;
        int done;
+       unsigned short msglen;
 
        if (unlikely((s->result & SRV_CHK_ERROR) || (fdtab[fd].state == FD_STERROR))) {
                /* in case of TCP only, this tells us if the connection failed */
@@ -1024,6 +1026,60 @@ static int event_srv_chk_r(int fd)
                        set_server_check_status(s, HCHK_STATUS_L7STS, desc);
                }
        }
+       else if (s->proxy->options2 & PR_O2_LDAP_CHK) {
+               if (!done && s->check_data_len < 14)
+                       goto wait_more_data;
+
+               /* Check if the server speaks LDAP (ASN.1/BER)
+                * http://en.wikipedia.org/wiki/Basic_Encoding_Rules
+                * http://tools.ietf.org/html/rfc4511
+                */
+
+               /* http://tools.ietf.org/html/rfc4511#section-4.1.1
+                *   LDAPMessage: 0x30: SEQUENCE
+                */
+               if ((s->check_data_len < 14) || (*(s->check_data) != '\x30')) {
+                       set_server_check_status(s, HCHK_STATUS_L7RSP, "Not LDAPv3 protocol");
+               }
+               else {
+                        /* size of LDAPMessage */
+                       msglen = (*(s->check_data + 1) & 0x80) ? (*(s->check_data + 1) & 0x7f) : 0;
+
+                       /* http://tools.ietf.org/html/rfc4511#section-4.2.2
+                        *   messageID: 0x02 0x01 0x01: INTEGER 1
+                        *   protocolOp: 0x61: bindResponse
+                        */
+                       if ((msglen > 2) ||
+                           (memcmp(s->check_data + 2 + msglen, "\x02\x01\x01\x61", 4) != 0)) {
+                               set_server_check_status(s, HCHK_STATUS_L7RSP, "Not LDAPv3 protocol");
+
+                               goto out_wakeup;
+                       }
+
+                       /* size of bindResponse */
+                       msglen += (*(s->check_data + msglen + 6) & 0x80) ? (*(s->check_data + msglen + 6) & 0x7f) : 0;
+
+                       /* http://tools.ietf.org/html/rfc4511#section-4.1.9
+                        *   ldapResult: 0x0a 0x01: ENUMERATION
+                        */
+                       if ((msglen > 4) ||
+                           (memcmp(s->check_data + 7 + msglen, "\x0a\x01", 2) != 0)) {
+                               set_server_check_status(s, HCHK_STATUS_L7RSP, "Not LDAPv3 protocol");
+
+                               goto out_wakeup;
+                       }
+
+                       /* http://tools.ietf.org/html/rfc4511#section-4.1.9
+                        *   resultCode
+                        */
+                       s->check_code = *(s->check_data + msglen + 9);
+                       if (s->check_code) {
+                               set_server_check_status(s, HCHK_STATUS_L7STS, "See RFC: http://tools.ietf.org/html/rfc4511#section-4.1.9");
+                       } else {
+                               set_server_check_status(s, HCHK_STATUS_L7OKD, "Success");
+                       }
+               }
+       }
        else {
                /* other checks are valid if the connection succeeded anyway */
                set_server_check_status(s, HCHK_STATUS_L4OK, NULL);