]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: checks: add rbinary expect match type
authorGaetan Rivet <grive@u256.net>
Fri, 7 Feb 2020 14:37:17 +0000 (15:37 +0100)
committerChristopher Faulet <cfaulet@haproxy.com>
Mon, 27 Apr 2020 07:39:37 +0000 (09:39 +0200)
The rbinary match works similarly to the rstring match type, however the
received data is rewritten as hex-string before the match operation is
done.

This allows using regexes on binary content even with the POSIX regex
engine.

[Cf: I slightly updated the patch. mem2hex function was removed and dump_binary
is used instead.]

doc/configuration.txt
include/types/checks.h
src/cfgparse-listen.c
src/checks.c

index df0928003d9e7ace33cefaf845a3b2d40ea58546..09f4b669eb1817a668831b5c12d4995f046e90cc 100644 (file)
@@ -9865,8 +9865,8 @@ tcp-check expect [min-recv <int>] [!] <match> <pattern>
               the evaluation result is always conclusive.
 
     <match>   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 <int>] [!] <match> <pattern>
                          this exact hexadecimal string.
                          Purpose is to match data on binary protocols.
 
+    rbinary <regex> : 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
index 36b22fede1fb6ee850c3a88089a676499c24af8f..d798ae21f636732574c664e7d3dab8b80fa6a417 100644 (file)
@@ -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. */
 };
 
index 6c1d986355c6339fd5a6a7523eca49d87611e8d6..13ce19c2b5e233f463ae5bf826cc2cf494b6d865 100644 (file)
@@ -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 <regex> 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;
index 54055cbd337a1f58ff9eb0aaaa578fc5910e69c6..5e77ca6b062395747dfe99705879757f6bad090b 100644 (file)
@@ -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: