938
944
s->check_code = str2uic(s->check_data + 9);
940
945
desc = ltrim(s->check_data + 12, ' ');
942
/* check the reply : HTTP/1.X 2xx and 3xx are OK */
943
if (*(s->check_data + 9) == '2' || *(s->check_data + 9) == '3') {
945
set_server_check_status(s, HCHK_STATUS_L7OKD, desc);
947
else if ((s->proxy->options & PR_O_DISABLE404) &&
948
(s->state & SRV_RUNNING) &&
949
(s->check_code == 404)) {
947
if ((s->proxy->options & PR_O_DISABLE404) &&
948
(s->state & SRV_RUNNING) && (s->check_code == 404)) {
950
949
/* 404 may be accepted as "stopping" only if the server was up */
952
951
set_server_check_status(s, HCHK_STATUS_L7OKCD, desc);
953
else if (s->proxy->options2 & PR_O2_EXP_TYPE) {
954
/* Run content verification check... We know we have at least 13 chars */
955
if (!httpchk_expect(s, done))
958
/* check the reply : HTTP/1.X 2xx and 3xx are OK */
959
else if (*(s->check_data + 9) == '2' || *(s->check_data + 9) == '3') {
961
set_server_check_status(s, HCHK_STATUS_L7OKD, desc);
956
965
set_server_check_status(s, HCHK_STATUS_L7STS, desc);
993
1002
set_server_check_status(s, HCHK_STATUS_L7STS, desc);
995
1004
else if (s->proxy->options2 & PR_O2_MYSQL_CHK) {
996
/* MySQL Error packet always begin with field_count = 0xff
997
* contrary to OK Packet who always begin whith 0x00 */
998
1005
if (!done && s->check_data_len < 5)
999
1006
goto wait_more_data;
1001
if (*(s->check_data + 4) != '\xff') {
1002
/* We set the MySQL Version in description for information purpose
1003
* FIXME : it can be cool to use MySQL Version for other purpose,
1004
* like mark as down old MySQL server.
1006
if (s->check_data_len > 51) {
1007
desc = ltrim(s->check_data + 5, ' ');
1008
set_server_check_status(s, HCHK_STATUS_L7OKD, desc);
1008
if (s->proxy->check_len == 0) { // old mode
1009
if (*(s->check_data + 4) != '\xff') {
1010
/* We set the MySQL Version in description for information purpose
1011
* FIXME : it can be cool to use MySQL Version for other purpose,
1012
* like mark as down old MySQL server.
1014
if (s->check_data_len > 51) {
1015
desc = ltrim(s->check_data + 5, ' ');
1016
set_server_check_status(s, HCHK_STATUS_L7OKD, desc);
1020
goto wait_more_data;
1021
/* it seems we have a OK packet but without a valid length,
1022
* it must be a protocol error
1024
set_server_check_status(s, HCHK_STATUS_L7RSP, s->check_data);
1028
/* An error message is attached in the Error packet */
1029
desc = ltrim(s->check_data + 7, ' ');
1030
set_server_check_status(s, HCHK_STATUS_L7STS, desc);
1033
unsigned int first_packet_len = ((unsigned int) *s->check_data) +
1034
(((unsigned int) *(s->check_data + 1)) << 8) +
1035
(((unsigned int) *(s->check_data + 2)) << 16);
1037
if (s->check_data_len == first_packet_len + 4) {
1038
/* MySQL Error packet always begin with field_count = 0xff */
1039
if (*(s->check_data + 4) != '\xff') {
1040
/* We have only one MySQL packet and it is a Handshake Initialization packet
1041
* but we need to have a second packet to know if it is alright
1043
if (!done && s->check_data_len < first_packet_len + 5)
1044
goto wait_more_data;
1047
/* We have only one packet and it is an Error packet,
1048
* an error message is attached, so we can display it
1050
desc = &s->check_data[7];
1051
//Warning("onlyoneERR: %s\n", desc);
1052
set_server_check_status(s, HCHK_STATUS_L7STS, desc);
1054
} else if (s->check_data_len > first_packet_len + 4) {
1055
unsigned int second_packet_len = ((unsigned int) *(s->check_data + first_packet_len + 4)) +
1056
(((unsigned int) *(s->check_data + first_packet_len + 5)) << 8) +
1057
(((unsigned int) *(s->check_data + first_packet_len + 6)) << 16);
1059
if (s->check_data_len == first_packet_len + 4 + second_packet_len + 4 ) {
1060
/* We have 2 packets and that's good */
1061
/* Check if the second packet is a MySQL Error packet or not */
1062
if (*(s->check_data + first_packet_len + 8) != '\xff') {
1063
/* No error packet */
1064
/* We set the MySQL Version in description for information purpose */
1065
desc = &s->check_data[5];
1066
//Warning("2packetOK: %s\n", desc);
1067
set_server_check_status(s, HCHK_STATUS_L7OKD, desc);
1070
/* An error message is attached in the Error packet
1071
* so we can display it ! :)
1073
desc = &s->check_data[first_packet_len+11];
1074
//Warning("2packetERR: %s\n", desc);
1075
set_server_check_status(s, HCHK_STATUS_L7STS, desc);
1012
1081
goto wait_more_data;
1013
/* it seems we have a OK packet but without a valid length,
1082
/* it seems we have a Handshake Initialization packet but without a valid length,
1014
1083
* it must be a protocol error
1016
set_server_check_status(s, HCHK_STATUS_L7RSP, s->check_data);
1085
desc = &s->check_data[5];
1086
//Warning("protoerr: %s\n", desc);
1087
set_server_check_status(s, HCHK_STATUS_L7RSP, desc);
1091
else if (s->proxy->options2 & PR_O2_LDAP_CHK) {
1092
if (!done && s->check_data_len < 14)
1093
goto wait_more_data;
1095
/* Check if the server speaks LDAP (ASN.1/BER)
1096
* http://en.wikipedia.org/wiki/Basic_Encoding_Rules
1097
* http://tools.ietf.org/html/rfc4511
1100
/* http://tools.ietf.org/html/rfc4511#section-4.1.1
1101
* LDAPMessage: 0x30: SEQUENCE
1103
if ((s->check_data_len < 14) || (*(s->check_data) != '\x30')) {
1104
set_server_check_status(s, HCHK_STATUS_L7RSP, "Not LDAPv3 protocol");
1020
/* An error message is attached in the Error packet,
1021
* so we can display it ! :)
1023
desc = ltrim(s->check_data + 7, ' ');
1024
set_server_check_status(s, HCHK_STATUS_L7STS, desc);
1107
/* size of LDAPMessage */
1108
msglen = (*(s->check_data + 1) & 0x80) ? (*(s->check_data + 1) & 0x7f) : 0;
1110
/* http://tools.ietf.org/html/rfc4511#section-4.2.2
1111
* messageID: 0x02 0x01 0x01: INTEGER 1
1112
* protocolOp: 0x61: bindResponse
1115
(memcmp(s->check_data + 2 + msglen, "\x02\x01\x01\x61", 4) != 0)) {
1116
set_server_check_status(s, HCHK_STATUS_L7RSP, "Not LDAPv3 protocol");
1121
/* size of bindResponse */
1122
msglen += (*(s->check_data + msglen + 6) & 0x80) ? (*(s->check_data + msglen + 6) & 0x7f) : 0;
1124
/* http://tools.ietf.org/html/rfc4511#section-4.1.9
1125
* ldapResult: 0x0a 0x01: ENUMERATION
1128
(memcmp(s->check_data + 7 + msglen, "\x0a\x01", 2) != 0)) {
1129
set_server_check_status(s, HCHK_STATUS_L7RSP, "Not LDAPv3 protocol");
1134
/* http://tools.ietf.org/html/rfc4511#section-4.1.9
1137
s->check_code = *(s->check_data + msglen + 9);
1138
if (s->check_code) {
1139
set_server_check_status(s, HCHK_STATUS_L7STS, "See RFC: http://tools.ietf.org/html/rfc4511#section-4.1.9");
1141
set_server_check_status(s, HCHK_STATUS_L7OKD, "Success");
1583
* Perform content verification check on data in s->check_data buffer.
1584
* The buffer MUST be terminated by a null byte before calling this function.
1585
* Sets server status appropriately. The caller is responsible for ensuring
1586
* that the buffer contains at least 13 characters. If <done> is zero, we may
1587
* return 0 to indicate that data is required to decide of a match.
1589
static int httpchk_expect(struct server *s, int done)
1591
static char status_msg[] = "HTTP status check returned code <000>";
1592
char status_code[] = "000";
1597
switch (s->proxy->options2 & PR_O2_EXP_TYPE) {
1599
case PR_O2_EXP_RSTS:
1600
memcpy(status_code, s->check_data + 9, 3);
1601
memcpy(status_msg + strlen(status_msg) - 4, s->check_data + 9, 3);
1603
if ((s->proxy->options2 & PR_O2_EXP_TYPE) == PR_O2_EXP_STS)
1604
ret = strncmp(s->proxy->expect_str, status_code, 3) == 0;
1606
ret = regexec(s->proxy->expect_regex, status_code, MAX_MATCH, pmatch, 0) == 0;
1608
/* we necessarily have the response, so there are no partial failures */
1609
if (s->proxy->options2 & PR_O2_EXP_INV)
1612
set_server_check_status(s, ret ? HCHK_STATUS_L7OKD : HCHK_STATUS_L7STS, status_msg);
1616
case PR_O2_EXP_RSTR:
1617
/* very simple response parser: ignore CR and only count consecutive LFs,
1618
* stop with contentptr pointing to first char after the double CRLF or
1619
* to '\0' if crlf < 2.
1622
for (contentptr = s->check_data; *contentptr; contentptr++) {
1625
if (*contentptr == '\r')
1627
else if (*contentptr == '\n')
1633
/* Check that response contains a body... */
1638
set_server_check_status(s, HCHK_STATUS_L7RSP,
1639
"HTTP content check could not find a response body");
1643
/* Check that response body is not empty... */
1644
if (*contentptr == '\0') {
1645
set_server_check_status(s, HCHK_STATUS_L7RSP,
1646
"HTTP content check found empty response body");
1650
/* Check the response content against the supplied string
1652
if ((s->proxy->options2 & PR_O2_EXP_TYPE) == PR_O2_EXP_STR)
1653
ret = strstr(contentptr, s->proxy->expect_str) != NULL;
1655
ret = regexec(s->proxy->expect_regex, contentptr, MAX_MATCH, pmatch, 0) == 0;
1657
/* if we don't match, we may need to wait more */
1662
/* content matched */
1663
if (s->proxy->options2 & PR_O2_EXP_INV)
1664
set_server_check_status(s, HCHK_STATUS_L7RSP,
1665
"HTTP check matched unwanted content");
1667
set_server_check_status(s, HCHK_STATUS_L7OKD,
1668
"HTTP content check matched");
1671
if (s->proxy->options2 & PR_O2_EXP_INV)
1672
set_server_check_status(s, HCHK_STATUS_L7OKD,
1673
"HTTP check did not match unwanted content");
1675
set_server_check_status(s, HCHK_STATUS_L7RSP,
1676
"HTTP content check did not match");
1465
1684
* Local variables:
1466
1685
* c-indent-level: 8
1467
1686
* c-basic-offset: 8