diff --git a/doc/configuration.txt b/doc/configuration.txt index df0928003..09f4b669e 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -9865,8 +9865,8 @@ tcp-check expect [min-recv ] [!] the evaluation result is always conclusive. is a keyword indicating how to look for a specific pattern in the - response. The keyword may be one of "string", "rstring" or - binary. + response. The keyword may be one of "string", "rstring", "binary" or + "rbinary". The keyword may be preceded by an exclamation mark ("!") to negate the match. Spaces are allowed between the exclamation mark and the keyword. See below for more details on the supported keywords. @@ -9904,6 +9904,15 @@ tcp-check expect [min-recv ] [!] this exact hexadecimal string. Purpose is to match data on binary protocols. + rbinary : test a regular expression on the response buffer, like + "rstring". However, the response buffer is transformed + into its hexadecimal form, including NUL-bytes. This + allows using all regex engines to match any binary + content. The hexadecimal transformation takes twice the + size of the original response. As such, the expected + pattern should work on at-most half the response buffer + size. + It is important to note that the responses will be limited to a certain size defined by the global "tune.chksize" option, which defaults to 16384 bytes. Thus, too large responses may not contain the mandatory pattern when using diff --git a/include/types/checks.h b/include/types/checks.h index 36b22fede..d798ae21f 100644 --- a/include/types/checks.h +++ b/include/types/checks.h @@ -215,6 +215,7 @@ enum tcpcheck_expect_type { TCPCHK_EXPECT_UNDEF = 0, /* Match is not used. */ TCPCHK_EXPECT_STRING, /* Matches a string. */ TCPCHK_EXPECT_REGEX, /* Matches a regular pattern. */ + TCPCHK_EXPECT_REGEX_BINARY, /* Matches a regular pattern on a hex-encoded text. */ TCPCHK_EXPECT_BINARY, /* Matches a binary sequence. */ }; diff --git a/src/cfgparse-listen.c b/src/cfgparse-listen.c index 6c1d98635..13ce19c2b 100644 --- a/src/cfgparse-listen.c +++ b/src/cfgparse-listen.c @@ -3282,7 +3282,8 @@ stats_error_parsing: expect->string = strdup(args[cur_arg + 1]); expect->length = strlen(expect->string); } - else if (strcmp(ptr_arg, "rstring") == 0) { + else if (strcmp(ptr_arg, "rstring") == 0 || + strcmp(ptr_arg, "rbinary") == 0) { if (!*(args[cur_arg + 1])) { ha_alert("parsing [%s:%d] : '%s %s %s' expects as an argument.\n", file, linenum, args[0], args[1], ptr_arg); @@ -3290,8 +3291,7 @@ stats_error_parsing: goto out; } - expect->type = TCPCHK_EXPECT_REGEX; - + expect->type = ((strcmp(ptr_arg, "rbinary") == 0) ? TCPCHK_EXPECT_REGEX_BINARY : TCPCHK_EXPECT_REGEX); error = NULL; if (!(expect->regex = regex_comp(args[cur_arg + 1], 1, 1, &error))) { ha_alert("parsing [%s:%d] : '%s %s %s' : regular expression '%s': %s.\n", @@ -3302,7 +3302,7 @@ stats_error_parsing: } } else { - ha_alert("parsing [%s:%d] : '%s %s' only supports [!] 'binary', 'string', 'rstring', found '%s'.\n", + ha_alert("parsing [%s:%d] : '%s %s' only supports [!] 'binary', 'string', 'rstring', 'rbinary', found '%s'.\n", file, linenum, args[0], args[1], ptr_arg); err_code |= ERR_ALERT | ERR_FATAL; goto out; diff --git a/src/checks.c b/src/checks.c index 54055cbd3..5e77ca6b0 100644 --- a/src/checks.c +++ b/src/checks.c @@ -652,6 +652,9 @@ static void chk_report_conn_err(struct check *check, int errno_bck, int expired) case TCPCHK_EXPECT_REGEX: chunk_appendf(chk, " (expect regex)"); break; + case TCPCHK_EXPECT_REGEX_BINARY: + chunk_appendf(chk, " (expect binary regex)"); + break; case TCPCHK_EXPECT_UNDEF: chunk_appendf(chk, " (undefined expect!)"); break; @@ -2775,7 +2778,6 @@ static char * tcpcheck_get_step_comment(struct check *check, int stepid) */ static int tcpcheck_main(struct check *check) { - char *comment; struct tcpcheck_rule *next; int done = 0, ret = 0, step = 0; struct conn_stream *cs = check->cs; @@ -2784,6 +2786,7 @@ static int tcpcheck_main(struct check *check) struct proxy *proxy = check->proxy; struct task *t = check->task; struct list *head = check->tcpcheck_rules; + char *comment; int retcode = 0; /* here, we know that the check is complete or that it failed */ @@ -3064,8 +3067,7 @@ static int tcpcheck_main(struct check *check) check->current_step = LIST_NEXT(&check->current_step->list, struct tcpcheck_rule *, list); /* bypass all comment rules */ - while (&check->current_step->list != head && - check->current_step->action == TCPCHK_ACT_COMMENT) + while (&check->current_step->list != head && check->current_step->action == TCPCHK_ACT_COMMENT) check->current_step = LIST_NEXT(&check->current_step->list, struct tcpcheck_rule *, list); if (&check->current_step->list == head) @@ -3189,6 +3191,12 @@ static int tcpcheck_main(struct check *check) case TCPCHK_EXPECT_REGEX: match = regex_exec2(expect->regex, b_head(&check->bi), MIN(b_data(&check->bi), b_size(&check->bi)-1)); break; + + case TCPCHK_EXPECT_REGEX_BINARY: + chunk_reset(&trash); + dump_binary(&trash, b_head(&check->bi), b_data(&check->bi)); + match = regex_exec2(expect->regex, b_head(&trash), MIN(b_data(&trash), b_size(&trash)-1)); + break; case TCPCHK_EXPECT_UNDEF: /* Should never happen. */ retcode = -1; @@ -3239,6 +3247,10 @@ static int tcpcheck_main(struct check *check) chunk_printf(&trash, "TCPCHK %s (regex) at step %d", diag, step); break; + case TCPCHK_EXPECT_REGEX_BINARY: + chunk_printf(&trash, "TCPCHK %s (binary regex) at step %d", + diag, step); + break; case TCPCHK_EXPECT_UNDEF: /* Should never happen. */ retcode = -1; @@ -3356,6 +3368,7 @@ void email_alert_free(struct email_alert *alert) free(rule->expect.string); break; case TCPCHK_EXPECT_REGEX: + case TCPCHK_EXPECT_REGEX_BINARY: regex_free(rule->expect.regex); break; case TCPCHK_EXPECT_UNDEF: