diff --git a/include/types/checks.h b/include/types/checks.h index 252928f3a..02fc74375 100644 --- a/include/types/checks.h +++ b/include/types/checks.h @@ -204,6 +204,7 @@ enum { TCPCHK_ACT_SEND = 0, /* send action, regular string format */ TCPCHK_ACT_EXPECT, /* expect action, either regular or binary string */ TCPCHK_ACT_CONNECT, /* connect action, to probe a new port */ + TCPCHK_ACT_COMMENT, /* no action, simply a comment used for logs */ }; /* flags used by tcpcheck_rule->conn_opts */ diff --git a/src/cfgparse.c b/src/cfgparse.c index 96ee79873..39ba14515 100644 --- a/src/cfgparse.c +++ b/src/cfgparse.c @@ -2106,7 +2106,7 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm) rc = PR_CAP_LISTEN; else if (!strcmp(args[0], "frontend")) rc = PR_CAP_FE | PR_CAP_RS; - else if (!strcmp(args[0], "backend")) + else if (!strcmp(args[0], "backend")) rc = PR_CAP_BE | PR_CAP_RS; else if (!strcmp(args[0], "ruleset")) rc = PR_CAP_RS; @@ -4683,7 +4683,26 @@ stats_error_parsing: if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL)) err_code |= ERR_WARN; - if (strcmp(args[1], "connect") == 0) { + if (strcmp(args[1], "comment") == 0) { + int cur_arg; + struct tcpcheck_rule *tcpcheck; + + cur_arg = 1; + tcpcheck = (struct tcpcheck_rule *)calloc(1, sizeof(*tcpcheck)); + tcpcheck->action = TCPCHK_ACT_COMMENT; + + if (!*args[cur_arg + 1]) { + Alert("parsing [%s:%d] : '%s' expects a comment string.\n", + file, linenum, args[cur_arg]); + err_code |= ERR_ALERT | ERR_FATAL; + goto out; + } + + tcpcheck->comment = strdup(args[cur_arg + 1]); + + LIST_ADDQ(&curproxy->tcpcheck_rules, &tcpcheck->list); + } + else if (strcmp(args[1], "connect") == 0) { const char *ptr_arg; int cur_arg; struct tcpcheck_rule *tcpcheck; @@ -4693,6 +4712,13 @@ stats_error_parsing: l = (struct list *)&curproxy->tcpcheck_rules; if (l->p != l->n) { tcpcheck = (struct tcpcheck_rule *)l->n; + while (tcpcheck->action == TCPCHK_ACT_COMMENT) { + tcpcheck = (struct tcpcheck_rule *)tcpcheck->list.n; + } + /* we've reached the end of the list, and the list is full of comments */ + if (tcpcheck == (struct tcpcheck_rule *)l) + tcpcheck = NULL; + if (tcpcheck && tcpcheck->action != TCPCHK_ACT_CONNECT) { Alert("parsing [%s:%d] : first step MUST also be a 'connect' when there is a 'connect' step in the tcp-check ruleset.\n", file, linenum); @@ -4731,11 +4757,22 @@ stats_error_parsing: cur_arg++; } #endif /* USE_OPENSSL */ + /* comment for this tcpcheck line */ + else if (strcmp(args[cur_arg], "comment") == 0) { + if (!*args[cur_arg + 1]) { + Alert("parsing [%s:%d] : '%s' expects a comment string.\n", + file, linenum, args[cur_arg]); + err_code |= ERR_ALERT | ERR_FATAL; + goto out; + } + tcpcheck->comment = strdup(args[cur_arg + 1]); + cur_arg += 2; + } else { #ifdef USE_OPENSSL - Alert("parsing [%s:%d] : '%s %s' expects 'port', 'send-proxy' or 'ssl' but got '%s' as argument.\n", + Alert("parsing [%s:%d] : '%s %s' expects 'comment', 'port', 'send-proxy' or 'ssl' but got '%s' as argument.\n", #else /* USE_OPENSSL */ - Alert("parsing [%s:%d] : '%s %s' expects 'port', 'send-proxy' or but got '%s' as argument.\n", + Alert("parsing [%s:%d] : '%s %s' expects 'comment', 'port', 'send-proxy' or but got '%s' as argument.\n", #endif /* USE_OPENSSL */ file, linenum, args[0], args[1], args[cur_arg]); err_code |= ERR_ALERT | ERR_FATAL; @@ -4763,6 +4800,17 @@ stats_error_parsing: tcpcheck->string = strdup(args[2]); tcpcheck->expect_regex = NULL; + /* comment for this tcpcheck line */ + if (strcmp(args[3], "comment") == 0) { + if (!*args[4]) { + Alert("parsing [%s:%d] : '%s' expects a comment string.\n", + file, linenum, args[3]); + err_code |= ERR_ALERT | ERR_FATAL; + goto out; + } + tcpcheck->comment = strdup(args[4]); + } + LIST_ADDQ(&curproxy->tcpcheck_rules, &tcpcheck->list); } } @@ -4788,6 +4836,17 @@ stats_error_parsing: } tcpcheck->expect_regex = NULL; + /* comment for this tcpcheck line */ + if (strcmp(args[3], "comment") == 0) { + if (!*args[4]) { + Alert("parsing [%s:%d] : '%s' expects a comment string.\n", + file, linenum, args[3]); + err_code |= ERR_ALERT | ERR_FATAL; + goto out; + } + tcpcheck->comment = strdup(args[4]); + } + LIST_ADDQ(&curproxy->tcpcheck_rules, &tcpcheck->list); } } @@ -4839,6 +4898,18 @@ stats_error_parsing: tcpcheck->expect_regex = NULL; tcpcheck->inverse = inverse; + /* tcpcheck comment */ + cur_arg += 2; + if (strcmp(args[cur_arg], "comment") == 0) { + if (!*args[cur_arg + 1]) { + Alert("parsing [%s:%d] : '%s' expects a comment string.\n", + file, linenum, args[cur_arg + 1]); + err_code |= ERR_ALERT | ERR_FATAL; + goto out; + } + tcpcheck->comment = strdup(args[cur_arg + 1]); + } + LIST_ADDQ(&curproxy->tcpcheck_rules, &tcpcheck->list); } else if (strcmp(ptr_arg, "string") == 0) { @@ -4859,6 +4930,18 @@ stats_error_parsing: tcpcheck->expect_regex = NULL; tcpcheck->inverse = inverse; + /* tcpcheck comment */ + cur_arg += 2; + if (strcmp(args[cur_arg], "comment") == 0) { + if (!*args[cur_arg + 1]) { + Alert("parsing [%s:%d] : '%s' expects a comment string.\n", + file, linenum, args[cur_arg + 1]); + err_code |= ERR_ALERT | ERR_FATAL; + goto out; + } + tcpcheck->comment = strdup(args[cur_arg + 1]); + } + LIST_ADDQ(&curproxy->tcpcheck_rules, &tcpcheck->list); } else if (strcmp(ptr_arg, "rstring") == 0) { @@ -4887,6 +4970,18 @@ stats_error_parsing: } tcpcheck->inverse = inverse; + /* tcpcheck comment */ + cur_arg += 2; + if (strcmp(args[cur_arg], "comment") == 0) { + if (!*args[cur_arg + 1]) { + Alert("parsing [%s:%d] : '%s' expects a comment string.\n", + file, linenum, args[cur_arg + 1]); + err_code |= ERR_ALERT | ERR_FATAL; + goto out; + } + tcpcheck->comment = strdup(args[cur_arg + 1]); + } + LIST_ADDQ(&curproxy->tcpcheck_rules, &tcpcheck->list); } else { @@ -4897,7 +4992,7 @@ stats_error_parsing: } } else { - Alert("parsing [%s:%d] : '%s' only supports 'connect', 'send' or 'expect'.\n", file, linenum, args[0]); + Alert("parsing [%s:%d] : '%s' only supports 'comment', 'connect', 'send' or 'expect'.\n", file, linenum, args[0]); err_code |= ERR_ALERT | ERR_FATAL; goto out; } diff --git a/src/checks.c b/src/checks.c index b66b9f188..26cccae76 100644 --- a/src/checks.c +++ b/src/checks.c @@ -62,6 +62,7 @@ static int httpchk_expect(struct server *s, int done); static int tcpcheck_get_step_id(struct check *); +static char * tcpcheck_get_step_comment(struct check *, int); static void tcpcheck_main(struct connection *); static const struct check_status check_statuses[HCHK_STATUS_SIZE] = { @@ -608,6 +609,7 @@ static void chk_report_conn_err(struct connection *conn, int errno_bck, int expi const char *err_msg; struct chunk *chk; int step; + char *comment; if (check->result != CHK_RES_UNKNOWN) return; @@ -648,6 +650,10 @@ static void chk_report_conn_err(struct connection *conn, int errno_bck, int expi else if (check->last_started_step && check->last_started_step->action == TCPCHK_ACT_SEND) { chunk_appendf(chk, " (send)"); } + + comment = tcpcheck_get_step_comment(check, step); + if (comment) + chunk_appendf(chk, " comment: '%s'", comment); } } @@ -2382,9 +2388,44 @@ static int tcpcheck_get_step_id(struct check *check) return i; } +/* + * return the latest known comment before (including) the given stepid + * returns NULL if no comment found + */ +static char * tcpcheck_get_step_comment(struct check *check, int stepid) +{ + struct tcpcheck_rule *cur = NULL; + char *ret = NULL; + int i = 0; + + /* not even started anything yet, return latest comment found before any action */ + if (!check->current_step) { + list_for_each_entry(cur, check->tcpcheck_rules, list) { + if (cur->action == TCPCHK_ACT_COMMENT) + ret = cur->comment; + else + goto return_comment; + } + } + + i = 1; + list_for_each_entry(cur, check->tcpcheck_rules, list) { + if (cur->comment) + ret = cur->comment; + + if (i >= stepid) + goto return_comment; + + ++i; + } + + return_comment: + return ret; +} + static void tcpcheck_main(struct connection *conn) { - char *contentptr; + char *contentptr, *comment; struct tcpcheck_rule *cur, *next; int done = 0, ret = 0, step = 0; struct check *check = conn->owner; @@ -2483,6 +2524,12 @@ static void tcpcheck_main(struct connection *conn) /* have 'next' point to the next rule or NULL if we're on the last one */ next = (struct tcpcheck_rule *)cur->list.n; + + /* bypass all comment rules */ + while (next->action == TCPCHK_ACT_COMMENT) + next = (struct tcpcheck_rule *)next->list.n; + + /* NULL if we're on the last rule */ if (&next->list == head) next = NULL; @@ -2572,6 +2619,9 @@ static void tcpcheck_main(struct connection *conn) step = tcpcheck_get_step_id(check); chunk_printf(&trash, "TCPCHK error establishing connection at step %d: %s", step, strerror(errno)); + comment = tcpcheck_get_step_comment(check, step); + if (comment) + chunk_appendf(&trash, " comment: '%s'", comment); set_server_check_status(check, HCHK_STATUS_L4CON, trash.str); goto out_end_tcpcheck; case SF_ERR_PRXCOND: @@ -2579,12 +2629,20 @@ static void tcpcheck_main(struct connection *conn) case SF_ERR_INTERNAL: step = tcpcheck_get_step_id(check); chunk_printf(&trash, "TCPCHK error establishing connection at step %d", step); + comment = tcpcheck_get_step_comment(check, step); + if (comment) + chunk_appendf(&trash, " comment: '%s'", comment); set_server_check_status(check, HCHK_STATUS_SOCKERR, trash.str); goto out_end_tcpcheck; } /* allow next rule */ cur = (struct tcpcheck_rule *)cur->list.n; + + /* bypass all comment rules */ + while (cur->action == TCPCHK_ACT_COMMENT) + cur = (struct tcpcheck_rule *)cur->list.n; + check->current_step = cur; /* don't do anything until the connection is established */ @@ -2640,6 +2698,11 @@ static void tcpcheck_main(struct connection *conn) /* go to next rule and try to send */ cur = (struct tcpcheck_rule *)cur->list.n; + + /* bypass all comment rules */ + while (cur->action == TCPCHK_ACT_COMMENT) + cur = (struct tcpcheck_rule *)cur->list.n; + check->current_step = cur; } /* end 'send' */ else if (check->current_step->action == TCPCHK_ACT_EXPECT) { @@ -2688,6 +2751,9 @@ static void tcpcheck_main(struct connection *conn) /* empty response */ step = tcpcheck_get_step_id(check); chunk_printf(&trash, "TCPCHK got an empty response at step %d", step); + comment = tcpcheck_get_step_comment(check, step); + if (comment) + chunk_appendf(&trash, " comment: '%s'", comment); set_server_check_status(check, HCHK_STATUS_L7RSP, trash.str); goto out_end_tcpcheck; @@ -2719,13 +2785,23 @@ static void tcpcheck_main(struct connection *conn) /* we were looking for a regex */ chunk_printf(&trash, "TCPCHK matched unwanted content (regex) at step %d", step); } + comment = tcpcheck_get_step_comment(check, step); + if (comment) + chunk_appendf(&trash, " comment: '%s'", comment); set_server_check_status(check, HCHK_STATUS_L7RSP, trash.str); goto out_end_tcpcheck; } /* matched and was supposed to => OK, next step */ else { - cur = (struct tcpcheck_rule*)cur->list.n; + /* allow next rule */ + cur = (struct tcpcheck_rule *)cur->list.n; + + /* bypass all comment rules */ + while (cur->action == TCPCHK_ACT_COMMENT) + cur = (struct tcpcheck_rule *)cur->list.n; + check->current_step = cur; + if (check->current_step->action == TCPCHK_ACT_EXPECT) goto tcpcheck_expect; __conn_data_stop_recv(conn); @@ -2735,6 +2811,15 @@ static void tcpcheck_main(struct connection *conn) /* not matched */ /* not matched and was not supposed to => OK, next step */ if (cur->inverse) { + /* allow next rule */ + cur = (struct tcpcheck_rule *)cur->list.n; + + /* bypass all comment rules */ + while (cur->action == TCPCHK_ACT_COMMENT) + cur = (struct tcpcheck_rule *)cur->list.n; + + check->current_step = cur; + cur = (struct tcpcheck_rule*)cur->list.n; check->current_step = cur; if (check->current_step->action == TCPCHK_ACT_EXPECT) @@ -2753,6 +2838,9 @@ static void tcpcheck_main(struct connection *conn) chunk_printf(&trash, "TCPCHK did not match content (regex) at step %d", step); } + comment = tcpcheck_get_step_comment(check, step); + if (comment) + chunk_appendf(&trash, " comment: '%s'", comment); set_server_check_status(check, HCHK_STATUS_L7RSP, trash.str); goto out_end_tcpcheck; }