MINOR: pattern: move functions for grouping pat_match_* and pat_parse_* and add documentation.
diff --git a/include/proto/pattern.h b/include/proto/pattern.h
index 080b062..e5c1b42 100644
--- a/include/proto/pattern.h
+++ b/include/proto/pattern.h
@@ -70,18 +70,6 @@
/* ignore the current line */
int pat_parse_nothing(const char **text, struct pattern *pattern, enum pat_usage usage, int *opaque, char **err);
-/* NB: For two strings to be identical, it is required that their lengths match */
-enum pat_match_res pat_match_str(struct sample *smp, struct pattern *pattern);
-
-/* NB: For two binary buffers to be identical, it is required that their lengths match */
-enum pat_match_res pat_match_bin(struct sample *smp, struct pattern *pattern);
-
-/* Checks that the length of the pattern in <test> is included between min and max */
-enum pat_match_res pat_match_len(struct sample *smp, struct pattern *pattern);
-
-/* Checks that the integer in <test> is included between min and max */
-enum pat_match_res pat_match_int(struct sample *smp, struct pattern *pattern);
-
/* Parse an integer. It is put both in min and max. */
int pat_parse_int(const char **text, struct pattern *pattern, enum pat_usage usage, int *opaque, char **err);
@@ -115,6 +103,18 @@
*/
int pat_parse_ip(const char **text, struct pattern *pattern, enum pat_usage usage, int *opaque, char **err);
+/* NB: For two strings to be identical, it is required that their lengths match */
+enum pat_match_res pat_match_str(struct sample *smp, struct pattern *pattern);
+
+/* NB: For two binary buffers to be identical, it is required that their lengths match */
+enum pat_match_res pat_match_bin(struct sample *smp, struct pattern *pattern);
+
+/* Checks that the length of the pattern in <test> is included between min and max */
+enum pat_match_res pat_match_len(struct sample *smp, struct pattern *pattern);
+
+/* Checks that the integer in <test> is included between min and max */
+enum pat_match_res pat_match_int(struct sample *smp, struct pattern *pattern);
+
/* always return false */
enum pat_match_res pat_match_nothing(struct sample *smp, struct pattern *pattern);
diff --git a/src/pattern.c b/src/pattern.c
index b053201..ce12a0e 100644
--- a/src/pattern.c
+++ b/src/pattern.c
@@ -90,46 +90,30 @@
};
/*
- * These functions are exported and may be used by any other component.
+ *
+ * The following functions are not exported and are used by internals process
+ * of pattern matching
+ *
*/
-/* ignore the current line */
-int pat_parse_nothing(const char **text, struct pattern *pattern, enum pat_usage usage, int *opaque, char **err)
-{
- return 1;
-}
-
-/* always return false */
-enum pat_match_res pat_match_nothing(struct sample *smp, struct pattern *pattern)
-{
- return PAT_NOMATCH;
-}
-
-
-/* NB: For two strings to be identical, it is required that their lengths match */
-enum pat_match_res pat_match_str(struct sample *smp, struct pattern *pattern)
+/* Lookup an IPv4 address in the expression's pattern tree using the longest
+ * match method. The node is returned if it exists, otherwise NULL.
+ */
+static void *pat_lookup_ip(struct sample *smp, struct pattern_expr *expr)
{
- int icase;
+ struct in_addr *s;
- if (pattern->len != smp->data.str.len)
+ if (smp->type != SMP_T_IPV4)
return PAT_NOMATCH;
- icase = pattern->flags & PAT_F_IGNORE_CASE;
- if ((icase && strncasecmp(pattern->ptr.str, smp->data.str.str, smp->data.str.len) == 0) ||
- (!icase && strncmp(pattern->ptr.str, smp->data.str.str, smp->data.str.len) == 0))
- return PAT_MATCH;
- return PAT_NOMATCH;
+ s = &smp->data.ipv4;
+ return ebmb_lookup_longest(&expr->pattern_tree, &s->s_addr);
}
-/* NB: For two binaries buf to be identical, it is required that their lengths match */
-enum pat_match_res pat_match_bin(struct sample *smp, struct pattern *pattern)
+/* Free data allocated by pat_parse_reg */
+static void pat_free_reg(void *ptr)
{
- if (pattern->len != smp->data.str.len)
- return PAT_NOMATCH;
-
- if (memcmp(pattern->ptr.str, smp->data.str.str, smp->data.str.len) == 0)
- return PAT_MATCH;
- return PAT_NOMATCH;
+ regex_free(ptr);
}
/* Lookup a string in the expression's pattern tree. The node is returned if it
@@ -151,77 +135,6 @@
return node;
}
-/* Executes a regex. It temporarily changes the data to add a trailing zero,
- * and restores the previous character when leaving.
- */
-enum pat_match_res pat_match_reg(struct sample *smp, struct pattern *pattern)
-{
- if (regex_exec(pattern->ptr.reg, smp->data.str.str, smp->data.str.len) == 0)
- return PAT_MATCH;
- return PAT_NOMATCH;
-}
-
-/* Checks that the pattern matches the beginning of the tested string. */
-enum pat_match_res pat_match_beg(struct sample *smp, struct pattern *pattern)
-{
- int icase;
-
- if (pattern->len > smp->data.str.len)
- return PAT_NOMATCH;
-
- icase = pattern->flags & PAT_F_IGNORE_CASE;
- if ((icase && strncasecmp(pattern->ptr.str, smp->data.str.str, pattern->len) != 0) ||
- (!icase && strncmp(pattern->ptr.str, smp->data.str.str, pattern->len) != 0))
- return PAT_NOMATCH;
- return PAT_MATCH;
-}
-
-/* Checks that the pattern matches the end of the tested string. */
-enum pat_match_res pat_match_end(struct sample *smp, struct pattern *pattern)
-{
- int icase;
-
- if (pattern->len > smp->data.str.len)
- return PAT_NOMATCH;
- icase = pattern->flags & PAT_F_IGNORE_CASE;
- if ((icase && strncasecmp(pattern->ptr.str, smp->data.str.str + smp->data.str.len - pattern->len, pattern->len) != 0) ||
- (!icase && strncmp(pattern->ptr.str, smp->data.str.str + smp->data.str.len - pattern->len, pattern->len) != 0))
- return PAT_NOMATCH;
- return PAT_MATCH;
-}
-
-/* Checks that the pattern is included inside the tested string.
- * NB: Suboptimal, should be rewritten using a Boyer-Moore method.
- */
-enum pat_match_res pat_match_sub(struct sample *smp, struct pattern *pattern)
-{
- int icase;
- char *end;
- char *c;
-
- if (pattern->len > smp->data.str.len)
- return PAT_NOMATCH;
-
- end = smp->data.str.str + smp->data.str.len - pattern->len;
- icase = pattern->flags & PAT_F_IGNORE_CASE;
- if (icase) {
- for (c = smp->data.str.str; c <= end; c++) {
- if (tolower(*c) != tolower(*pattern->ptr.str))
- continue;
- if (strncasecmp(pattern->ptr.str, c, pattern->len) == 0)
- return PAT_MATCH;
- }
- } else {
- for (c = smp->data.str.str; c <= end; c++) {
- if (*c != *pattern->ptr.str)
- continue;
- if (strncmp(pattern->ptr.str, c, pattern->len) == 0)
- return PAT_MATCH;
- }
- }
- return PAT_NOMATCH;
-}
-
/* Background: Fast way to find a zero byte in a word
* http://graphics.stanford.edu/~seander/bithacks.html#ZeroInWord
* hasZeroByte = (v - 0x01010101UL) & ~v & 0x80808080UL;
@@ -244,228 +157,98 @@
return d1 << 24 | d2 << 16 | d3 << 8 | d4;
}
-/* This one is used by other real functions. It checks that the pattern is
- * included inside the tested string, but enclosed between the specified
- * delimiters or at the beginning or end of the string. The delimiters are
- * provided as an unsigned int made by make_4delim() and match up to 4 different
- * delimiters. Delimiters are stripped at the beginning and end of the pattern.
- */
-static int match_word(struct sample *smp, struct pattern *pattern, unsigned int delimiters)
-{
- int may_match, icase;
- char *c, *end;
- char *ps;
- int pl;
-
- pl = pattern->len;
- ps = pattern->ptr.str;
-
- while (pl > 0 && is_delimiter(*ps, delimiters)) {
- pl--;
- ps++;
- }
-
- while (pl > 0 && is_delimiter(ps[pl - 1], delimiters))
- pl--;
-
- if (pl > smp->data.str.len)
- return PAT_NOMATCH;
- may_match = 1;
- icase = pattern->flags & PAT_F_IGNORE_CASE;
- end = smp->data.str.str + smp->data.str.len - pl;
- for (c = smp->data.str.str; c <= end; c++) {
- if (is_delimiter(*c, delimiters)) {
- may_match = 1;
- continue;
- }
+/*
+ *
+ * These functions are exported and may be used by any other component.
+ *
+ * The following functions are used for parsing pattern matching
+ * input value. The <text> contain a list of word. The last entry
+ * must be one NULL character. the <text> contain the string to be
+ * parsed. <pattern> must be a preallocated pattern. The pat_parse_*
+ * functions fill this structure with the parsed value. <usage> can
+ * be PAT_U_COMPILE or PAT_U_LOOKUP. If the value PAT_U_COMPILE is
+ * used memory is allocated for filling the pattern. If the value
+ * PAT_U_LOOKUP is set, the parser use "trash" or return pointers
+ * to the input strings. In both cases, the caller must use the
+ * value PAT_U_LOOKUP with caution. <opaque> is used to pass value
+ * between two calls to the parser. the interger must ben initilized
+ * to 0 (see note below). <err> is filled with an error message built
+ * with memprintf() function.
+ *
+ * In succes case, the pat_parse_* function return the number of
+ * <text> eated. If the function fail, it returns 0 and <err> is
+ * filled.
+ *
+ * NOTE: <opaque>iIt is used with integer range parser. The following
+ * configuration line is processed with this method:
+ *
+ * acl ... -m int eq 10 20
+ *
+ * The first call to the parser eat 2 elements: "eq" and "10". The
+ * pattern is filled with "eq 10" content. The <opaque> contain
+ * coded value value that represent "eq".
+ *
+ * The second call to the parser just eat 1 element: "20". The opaque
+ * contain the value of the operator. The parser returns pattern filled
+ * with "eq 20".
+ *
+ */
- if (!may_match)
- continue;
+/* ignore the current line */
+int pat_parse_nothing(const char **text, struct pattern *pattern, enum pat_usage usage, int *opaque, char **err)
+{
+ return 1;
+}
- if (icase) {
- if ((tolower(*c) == tolower(*ps)) &&
- (strncasecmp(ps, c, pl) == 0) &&
- (c == end || is_delimiter(c[pl], delimiters)))
- return PAT_MATCH;
- } else {
- if ((*c == *ps) &&
- (strncmp(ps, c, pl) == 0) &&
- (c == end || is_delimiter(c[pl], delimiters)))
- return PAT_MATCH;
+/* Parse a string. It is allocated and duplicated. */
+int pat_parse_str(const char **text, struct pattern *pattern, enum pat_usage usage, int *opaque, char **err)
+{
+ pattern->type = SMP_T_CSTR;
+ pattern->expect_type = SMP_T_CSTR;
+ if (usage == PAT_U_COMPILE) {
+ pattern->ptr.str = strdup(*text);
+ if (!pattern->ptr.str) {
+ memprintf(err, "out of memory while loading string pattern");
+ return 0;
}
- may_match = 0;
}
- return PAT_NOMATCH;
+ else
+ pattern->ptr.str = (char *)*text;
+ pattern->len = strlen(*text);
+ return 1;
}
-/* Checks that the pattern is included inside the tested string, but enclosed
- * between the delimiters '?' or '/' or at the beginning or end of the string.
- * Delimiters at the beginning or end of the pattern are ignored.
- */
-enum pat_match_res pat_match_dir(struct sample *smp, struct pattern *pattern)
+/* Parse a binary written in hexa. It is allocated. */
+int pat_parse_bin(const char **text, struct pattern *pattern, enum pat_usage usage, int *opaque, char **err)
{
- return match_word(smp, pattern, make_4delim('/', '?', '?', '?'));
-}
+ struct chunk *trash;
-/* Checks that the pattern is included inside the tested string, but enclosed
- * between the delmiters '/', '?', '.' or ":" or at the beginning or end of
- * the string. Delimiters at the beginning or end of the pattern are ignored.
- */
-enum pat_match_res pat_match_dom(struct sample *smp, struct pattern *pattern)
-{
- return match_word(smp, pattern, make_4delim('/', '?', '.', ':'));
-}
+ pattern->type = SMP_T_CBIN;
+ pattern->expect_type = SMP_T_CBIN;
-/* Checks that the integer in <test> is included between min and max */
-enum pat_match_res pat_match_int(struct sample *smp, struct pattern *pattern)
-{
- if ((!pattern->val.range.min_set || pattern->val.range.min <= smp->data.uint) &&
- (!pattern->val.range.max_set || smp->data.uint <= pattern->val.range.max))
- return PAT_MATCH;
- return PAT_NOMATCH;
-}
+ if (usage == PAT_U_COMPILE)
+ /* If the parse_binary fails, it returns 0. In succes case, it returns
+ * the length of the arsed binary content. The functions pat_parse_*
+ * must return 0 if fail and the number of elements eated from **text
+ * if not fail. In succes case, this function eat always 1 elements.
+ * The double operator "!" converts the range "1-n" to "1".
+ */
+ return !!parse_binary(*text, &pattern->ptr.str, &pattern->len, err);
-/* Checks that the length of the pattern in <test> is included between min and max */
-enum pat_match_res pat_match_len(struct sample *smp, struct pattern *pattern)
-{
- if ((!pattern->val.range.min_set || pattern->val.range.min <= smp->data.str.len) &&
- (!pattern->val.range.max_set || smp->data.str.len <= pattern->val.range.max))
- return PAT_MATCH;
- return PAT_NOMATCH;
+ trash = get_trash_chunk();
+ pattern->len = trash->size;
+ pattern->ptr.str = trash->str;
+ return !!parse_binary(*text, &pattern->ptr.str, &pattern->len, err);
}
-enum pat_match_res pat_match_ip(struct sample *smp, struct pattern *pattern)
+/* Parse and concatenate all further strings into one. */
+int
+pat_parse_strcat(const char **text, struct pattern *pattern, enum pat_usage usage, int *opaque, char **err)
{
- unsigned int v4; /* in network byte order */
- struct in6_addr *v6;
- int bits, pos;
- struct in6_addr tmp6;
-
- if (pattern->type == SMP_T_IPV4) {
- if (smp->type == SMP_T_IPV4) {
- v4 = smp->data.ipv4.s_addr;
- }
- else if (smp->type == SMP_T_IPV6) {
- /* v4 match on a V6 sample. We want to check at least for
- * the following forms :
- * - ::ffff:ip:v4 (ipv4 mapped)
- * - ::0000:ip:v4 (old ipv4 mapped)
- * - 2002:ip:v4:: (6to4)
- */
- if (*(uint32_t*)&smp->data.ipv6.s6_addr[0] == 0 &&
- *(uint32_t*)&smp->data.ipv6.s6_addr[4] == 0 &&
- (*(uint32_t*)&smp->data.ipv6.s6_addr[8] == 0 ||
- *(uint32_t*)&smp->data.ipv6.s6_addr[8] == htonl(0xFFFF))) {
- v4 = *(uint32_t*)&smp->data.ipv6.s6_addr[12];
- }
- else if (*(uint16_t*)&smp->data.ipv6.s6_addr[0] == htons(0x2002)) {
- v4 = htonl((ntohs(*(uint16_t*)&smp->data.ipv6.s6_addr[2]) << 16) +
- ntohs(*(uint16_t*)&smp->data.ipv6.s6_addr[4]));
- }
- else
- return PAT_NOMATCH;
- }
- else
- return PAT_NOMATCH;
-
- if (((v4 ^ pattern->val.ipv4.addr.s_addr) & pattern->val.ipv4.mask.s_addr) == 0)
- return PAT_MATCH;
- else
- return PAT_NOMATCH;
- }
- else if (pattern->type == SMP_T_IPV6) {
- if (smp->type == SMP_T_IPV4) {
- /* Convert the IPv4 sample address to IPv4 with the
- * mapping method using the ::ffff: prefix.
- */
- memset(&tmp6, 0, 10);
- *(uint16_t*)&tmp6.s6_addr[10] = htons(0xffff);
- *(uint32_t*)&tmp6.s6_addr[12] = smp->data.ipv4.s_addr;
- v6 = &tmp6;
- }
- else if (smp->type == SMP_T_IPV6) {
- v6 = &smp->data.ipv6;
- }
- else {
- return PAT_NOMATCH;
- }
-
- bits = pattern->val.ipv6.mask;
- for (pos = 0; bits > 0; pos += 4, bits -= 32) {
- v4 = *(uint32_t*)&v6->s6_addr[pos] ^ *(uint32_t*)&pattern->val.ipv6.addr.s6_addr[pos];
- if (bits < 32)
- v4 &= htonl((~0U) << (32-bits));
- if (v4)
- return PAT_NOMATCH;
- }
- return PAT_MATCH;
- }
- return PAT_NOMATCH;
-}
-
-/* Lookup an IPv4 address in the expression's pattern tree using the longest
- * match method. The node is returned if it exists, otherwise NULL.
- */
-static void *pat_lookup_ip(struct sample *smp, struct pattern_expr *expr)
-{
- struct in_addr *s;
-
- if (smp->type != SMP_T_IPV4)
- return PAT_NOMATCH;
-
- s = &smp->data.ipv4;
- return ebmb_lookup_longest(&expr->pattern_tree, &s->s_addr);
-}
-
-/* Parse a string. It is allocated and duplicated. */
-int pat_parse_str(const char **text, struct pattern *pattern, enum pat_usage usage, int *opaque, char **err)
-{
- pattern->type = SMP_T_CSTR;
- pattern->expect_type = SMP_T_CSTR;
- if (usage == PAT_U_COMPILE) {
- pattern->ptr.str = strdup(*text);
- if (!pattern->ptr.str) {
- memprintf(err, "out of memory while loading string pattern");
- return 0;
- }
- }
- else
- pattern->ptr.str = (char *)*text;
- pattern->len = strlen(*text);
- return 1;
-}
-
-/* Parse a binary written in hexa. It is allocated. */
-int pat_parse_bin(const char **text, struct pattern *pattern, enum pat_usage usage, int *opaque, char **err)
-{
- struct chunk *trash;
-
- pattern->type = SMP_T_CBIN;
- pattern->expect_type = SMP_T_CBIN;
-
- if (usage == PAT_U_COMPILE)
- /* If the parse_binary fails, it returns 0. In succes case, it returns
- * the length of the arsed binary content. The function pat_parse_*
- * must return 0 if fail and the number of elements eated from **text
- * if not fail. In succes case, this function eat always 1 elements.
- * The double operator "!" converts the range "1-n" to "1".
- */
- return !!parse_binary(*text, &pattern->ptr.str, &pattern->len, err);
-
- trash = get_trash_chunk();
- pattern->len = trash->size;
- pattern->ptr.str = trash->str;
- return !!parse_binary(*text, &pattern->ptr.str, &pattern->len, err);
-}
-
-/* Parse and concatenate all further strings into one. */
-int
-pat_parse_strcat(const char **text, struct pattern *pattern, enum pat_usage usage, int *opaque, char **err)
-{
- int len = 0, i;
- char *s;
- struct chunk *trash;
+ int len = 0, i;
+ char *s;
+ struct chunk *trash;
for (i = 0; *text[i]; i++)
len += strlen(text[i])+1;
@@ -498,12 +281,6 @@
return i;
}
-/* Free data allocated by pat_parse_reg */
-static void pat_free_reg(void *ptr)
-{
- regex_free(ptr);
-}
-
/* Parse a regex. It is allocated. */
int pat_parse_reg(const char **text, struct pattern *pattern, enum pat_usage usage, int *opaque, char **err)
{
@@ -768,6 +545,280 @@
}
}
+/*
+ *
+ * These functions are exported and may be used by any other component.
+ *
+ * This fucntion just take a sample <smp> and check if this sample match
+ * with the pattern <pattern>. This fucntion return just PAT_MATCH or
+ * PAT_NOMATCH.
+ *
+ */
+
+/* always return false */
+enum pat_match_res pat_match_nothing(struct sample *smp, struct pattern *pattern)
+{
+ return PAT_NOMATCH;
+}
+
+
+/* NB: For two strings to be identical, it is required that their lengths match */
+enum pat_match_res pat_match_str(struct sample *smp, struct pattern *pattern)
+{
+ int icase;
+
+ if (pattern->len != smp->data.str.len)
+ return PAT_NOMATCH;
+
+ icase = pattern->flags & PAT_F_IGNORE_CASE;
+ if ((icase && strncasecmp(pattern->ptr.str, smp->data.str.str, smp->data.str.len) == 0) ||
+ (!icase && strncmp(pattern->ptr.str, smp->data.str.str, smp->data.str.len) == 0))
+ return PAT_MATCH;
+ return PAT_NOMATCH;
+}
+
+/* NB: For two binaries buf to be identical, it is required that their lengths match */
+enum pat_match_res pat_match_bin(struct sample *smp, struct pattern *pattern)
+{
+ if (pattern->len != smp->data.str.len)
+ return PAT_NOMATCH;
+
+ if (memcmp(pattern->ptr.str, smp->data.str.str, smp->data.str.len) == 0)
+ return PAT_MATCH;
+ return PAT_NOMATCH;
+}
+
+/* Executes a regex. It temporarily changes the data to add a trailing zero,
+ * and restores the previous character when leaving.
+ */
+enum pat_match_res pat_match_reg(struct sample *smp, struct pattern *pattern)
+{
+ if (regex_exec(pattern->ptr.reg, smp->data.str.str, smp->data.str.len) == 0)
+ return PAT_MATCH;
+ return PAT_NOMATCH;
+}
+
+/* Checks that the pattern matches the beginning of the tested string. */
+enum pat_match_res pat_match_beg(struct sample *smp, struct pattern *pattern)
+{
+ int icase;
+
+ if (pattern->len > smp->data.str.len)
+ return PAT_NOMATCH;
+
+ icase = pattern->flags & PAT_F_IGNORE_CASE;
+ if ((icase && strncasecmp(pattern->ptr.str, smp->data.str.str, pattern->len) != 0) ||
+ (!icase && strncmp(pattern->ptr.str, smp->data.str.str, pattern->len) != 0))
+ return PAT_NOMATCH;
+ return PAT_MATCH;
+}
+
+/* Checks that the pattern matches the end of the tested string. */
+enum pat_match_res pat_match_end(struct sample *smp, struct pattern *pattern)
+{
+ int icase;
+
+ if (pattern->len > smp->data.str.len)
+ return PAT_NOMATCH;
+ icase = pattern->flags & PAT_F_IGNORE_CASE;
+ if ((icase && strncasecmp(pattern->ptr.str, smp->data.str.str + smp->data.str.len - pattern->len, pattern->len) != 0) ||
+ (!icase && strncmp(pattern->ptr.str, smp->data.str.str + smp->data.str.len - pattern->len, pattern->len) != 0))
+ return PAT_NOMATCH;
+ return PAT_MATCH;
+}
+
+/* Checks that the pattern is included inside the tested string.
+ * NB: Suboptimal, should be rewritten using a Boyer-Moore method.
+ */
+enum pat_match_res pat_match_sub(struct sample *smp, struct pattern *pattern)
+{
+ int icase;
+ char *end;
+ char *c;
+
+ if (pattern->len > smp->data.str.len)
+ return PAT_NOMATCH;
+
+ end = smp->data.str.str + smp->data.str.len - pattern->len;
+ icase = pattern->flags & PAT_F_IGNORE_CASE;
+ if (icase) {
+ for (c = smp->data.str.str; c <= end; c++) {
+ if (tolower(*c) != tolower(*pattern->ptr.str))
+ continue;
+ if (strncasecmp(pattern->ptr.str, c, pattern->len) == 0)
+ return PAT_MATCH;
+ }
+ } else {
+ for (c = smp->data.str.str; c <= end; c++) {
+ if (*c != *pattern->ptr.str)
+ continue;
+ if (strncmp(pattern->ptr.str, c, pattern->len) == 0)
+ return PAT_MATCH;
+ }
+ }
+ return PAT_NOMATCH;
+}
+
+/* This one is used by other real functions. It checks that the pattern is
+ * included inside the tested string, but enclosed between the specified
+ * delimiters or at the beginning or end of the string. The delimiters are
+ * provided as an unsigned int made by make_4delim() and match up to 4 different
+ * delimiters. Delimiters are stripped at the beginning and end of the pattern.
+ */
+static int match_word(struct sample *smp, struct pattern *pattern, unsigned int delimiters)
+{
+ int may_match, icase;
+ char *c, *end;
+ char *ps;
+ int pl;
+
+ pl = pattern->len;
+ ps = pattern->ptr.str;
+
+ while (pl > 0 && is_delimiter(*ps, delimiters)) {
+ pl--;
+ ps++;
+ }
+
+ while (pl > 0 && is_delimiter(ps[pl - 1], delimiters))
+ pl--;
+
+ if (pl > smp->data.str.len)
+ return PAT_NOMATCH;
+
+ may_match = 1;
+ icase = pattern->flags & PAT_F_IGNORE_CASE;
+ end = smp->data.str.str + smp->data.str.len - pl;
+ for (c = smp->data.str.str; c <= end; c++) {
+ if (is_delimiter(*c, delimiters)) {
+ may_match = 1;
+ continue;
+ }
+
+ if (!may_match)
+ continue;
+
+ if (icase) {
+ if ((tolower(*c) == tolower(*ps)) &&
+ (strncasecmp(ps, c, pl) == 0) &&
+ (c == end || is_delimiter(c[pl], delimiters)))
+ return PAT_MATCH;
+ } else {
+ if ((*c == *ps) &&
+ (strncmp(ps, c, pl) == 0) &&
+ (c == end || is_delimiter(c[pl], delimiters)))
+ return PAT_MATCH;
+ }
+ may_match = 0;
+ }
+ return PAT_NOMATCH;
+}
+
+/* Checks that the pattern is included inside the tested string, but enclosed
+ * between the delimiters '?' or '/' or at the beginning or end of the string.
+ * Delimiters at the beginning or end of the pattern are ignored.
+ */
+enum pat_match_res pat_match_dir(struct sample *smp, struct pattern *pattern)
+{
+ return match_word(smp, pattern, make_4delim('/', '?', '?', '?'));
+}
+
+/* Checks that the pattern is included inside the tested string, but enclosed
+ * between the delmiters '/', '?', '.' or ":" or at the beginning or end of
+ * the string. Delimiters at the beginning or end of the pattern are ignored.
+ */
+enum pat_match_res pat_match_dom(struct sample *smp, struct pattern *pattern)
+{
+ return match_word(smp, pattern, make_4delim('/', '?', '.', ':'));
+}
+
+/* Checks that the integer in <test> is included between min and max */
+enum pat_match_res pat_match_int(struct sample *smp, struct pattern *pattern)
+{
+ if ((!pattern->val.range.min_set || pattern->val.range.min <= smp->data.uint) &&
+ (!pattern->val.range.max_set || smp->data.uint <= pattern->val.range.max))
+ return PAT_MATCH;
+ return PAT_NOMATCH;
+}
+
+/* Checks that the length of the pattern in <test> is included between min and max */
+enum pat_match_res pat_match_len(struct sample *smp, struct pattern *pattern)
+{
+ if ((!pattern->val.range.min_set || pattern->val.range.min <= smp->data.str.len) &&
+ (!pattern->val.range.max_set || smp->data.str.len <= pattern->val.range.max))
+ return PAT_MATCH;
+ return PAT_NOMATCH;
+}
+
+enum pat_match_res pat_match_ip(struct sample *smp, struct pattern *pattern)
+{
+ unsigned int v4; /* in network byte order */
+ struct in6_addr *v6;
+ int bits, pos;
+ struct in6_addr tmp6;
+
+ if (pattern->type == SMP_T_IPV4) {
+ if (smp->type == SMP_T_IPV4) {
+ v4 = smp->data.ipv4.s_addr;
+ }
+ else if (smp->type == SMP_T_IPV6) {
+ /* v4 match on a V6 sample. We want to check at least for
+ * the following forms :
+ * - ::ffff:ip:v4 (ipv4 mapped)
+ * - ::0000:ip:v4 (old ipv4 mapped)
+ * - 2002:ip:v4:: (6to4)
+ */
+ if (*(uint32_t*)&smp->data.ipv6.s6_addr[0] == 0 &&
+ *(uint32_t*)&smp->data.ipv6.s6_addr[4] == 0 &&
+ (*(uint32_t*)&smp->data.ipv6.s6_addr[8] == 0 ||
+ *(uint32_t*)&smp->data.ipv6.s6_addr[8] == htonl(0xFFFF))) {
+ v4 = *(uint32_t*)&smp->data.ipv6.s6_addr[12];
+ }
+ else if (*(uint16_t*)&smp->data.ipv6.s6_addr[0] == htons(0x2002)) {
+ v4 = htonl((ntohs(*(uint16_t*)&smp->data.ipv6.s6_addr[2]) << 16) +
+ ntohs(*(uint16_t*)&smp->data.ipv6.s6_addr[4]));
+ }
+ else
+ return PAT_NOMATCH;
+ }
+ else
+ return PAT_NOMATCH;
+
+ if (((v4 ^ pattern->val.ipv4.addr.s_addr) & pattern->val.ipv4.mask.s_addr) == 0)
+ return PAT_MATCH;
+ else
+ return PAT_NOMATCH;
+ }
+ else if (pattern->type == SMP_T_IPV6) {
+ if (smp->type == SMP_T_IPV4) {
+ /* Convert the IPv4 sample address to IPv4 with the
+ * mapping method using the ::ffff: prefix.
+ */
+ memset(&tmp6, 0, 10);
+ *(uint16_t*)&tmp6.s6_addr[10] = htons(0xffff);
+ *(uint32_t*)&tmp6.s6_addr[12] = smp->data.ipv4.s_addr;
+ v6 = &tmp6;
+ }
+ else if (smp->type == SMP_T_IPV6) {
+ v6 = &smp->data.ipv6;
+ }
+ else {
+ return PAT_NOMATCH;
+ }
+
+ bits = pattern->val.ipv6.mask;
+ for (pos = 0; bits > 0; pos += 4, bits -= 32) {
+ v4 = *(uint32_t*)&v6->s6_addr[pos] ^ *(uint32_t*)&pattern->val.ipv6.addr.s6_addr[pos];
+ if (bits < 32)
+ v4 &= htonl((~0U) << (32-bits));
+ if (v4)
+ return PAT_NOMATCH;
+ }
+ return PAT_MATCH;
+ }
+ return PAT_NOMATCH;
+}
+
/* NB: does nothing if <pat> is NULL */
void pattern_free(struct pattern *pat)
{