MEDIUM: acl: use temp_pattern to store any string-type information

Now strings and data blocks are stored in the temp_pattern's chunk
and matched against this one.

The rdp_cookie currently makes extensive use of acl_fetch_rdp_cookie()
and will be a good candidate for the initial rework so that ACLs use
the patterns framework and not the other way around.
This commit is contained in:
Willy Tarreau 2011-12-16 19:11:42 +01:00
parent 31d1b01211
commit 664092ccc1
4 changed files with 60 additions and 59 deletions

View File

@ -423,8 +423,8 @@ acl_fetch_ssl_hello_sni(struct proxy *px, struct session *l4, void *l7, int dir,
name_len = (data[7] << 8) + data[8]; name_len = (data[7] << 8) + data[8];
if (name_type == 0) { /* hostname */ if (name_type == 0) { /* hostname */
test->ptr = data + 9; temp_pattern.data.str.str = data + 9;
test->len = name_len; temp_pattern.data.str.len = name_len;
test->flags = ACL_TEST_F_VOLATILE; test->flags = ACL_TEST_F_VOLATILE;
//fprintf(stderr, "found SNI : <"); //fprintf(stderr, "found SNI : <");
//write(2, test->ptr, test->len); //write(2, test->ptr, test->len);
@ -513,8 +513,8 @@ acl_fetch_rdp_cookie(struct proxy *px, struct session *l4, void *l7, int dir,
} }
/* data points to cookie value */ /* data points to cookie value */
test->ptr = (char *)data; temp_pattern.data.str.str = (char *)data;
test->len = 0; temp_pattern.data.str.len = 0;
while (bleft > 0 && *data != '\r') { while (bleft > 0 && *data != '\r') {
data++; data++;
@ -527,7 +527,7 @@ acl_fetch_rdp_cookie(struct proxy *px, struct session *l4, void *l7, int dir,
if (data[0] != '\r' || data[1] != '\n') if (data[0] != '\r' || data[1] != '\n')
goto not_cookie; goto not_cookie;
test->len = (char *)data - test->ptr; temp_pattern.data.str.len = (char *)data - temp_pattern.data.str.str;
test->flags = ACL_TEST_F_VOLATILE; test->flags = ACL_TEST_F_VOLATILE;
return 1; return 1;
@ -545,8 +545,8 @@ acl_fetch_rdp_cookie_cnt(struct proxy *px, struct session *l4, void *l7, int dir
ret = acl_fetch_rdp_cookie(px, l4, l7, dir, expr, test); ret = acl_fetch_rdp_cookie(px, l4, l7, dir, expr, test);
test->ptr = NULL; temp_pattern.data.str.str = NULL;
test->len = 0; temp_pattern.data.str.len = 0;
if (test->flags & ACL_TEST_F_MAY_CHANGE) if (test->flags & ACL_TEST_F_MAY_CHANGE)
return 0; return 0;
@ -587,12 +587,12 @@ int acl_match_str(struct acl_test *test, struct acl_pattern *pattern)
{ {
int icase; int icase;
if (pattern->len != test->len) if (pattern->len != temp_pattern.data.str.len)
return ACL_PAT_FAIL; return ACL_PAT_FAIL;
icase = pattern->flags & ACL_PAT_F_IGNORE_CASE; icase = pattern->flags & ACL_PAT_F_IGNORE_CASE;
if ((icase && strncasecmp(pattern->ptr.str, test->ptr, test->len) == 0) || if ((icase && strncasecmp(pattern->ptr.str, temp_pattern.data.str.str, temp_pattern.data.str.len) == 0) ||
(!icase && strncmp(pattern->ptr.str, test->ptr, test->len) == 0)) (!icase && strncmp(pattern->ptr.str, temp_pattern.data.str.str, temp_pattern.data.str.len) == 0))
return ACL_PAT_PASS; return ACL_PAT_PASS;
return ACL_PAT_FAIL; return ACL_PAT_FAIL;
} }
@ -607,12 +607,12 @@ void *acl_lookup_str(struct acl_test *test, struct acl_expr *expr)
char prev; char prev;
/* we may have to force a trailing zero on the test pattern */ /* we may have to force a trailing zero on the test pattern */
prev = test->ptr[test->len]; prev = temp_pattern.data.str.str[temp_pattern.data.str.len];
if (prev) if (prev)
test->ptr[test->len] = '\0'; temp_pattern.data.str.str[temp_pattern.data.str.len] = '\0';
node = ebst_lookup(&expr->pattern_tree, test->ptr); node = ebst_lookup(&expr->pattern_tree, temp_pattern.data.str.str);
if (prev) if (prev)
test->ptr[test->len] = prev; temp_pattern.data.str.str[temp_pattern.data.str.len] = prev;
return node; return node;
} }
@ -629,28 +629,28 @@ int acl_match_reg(struct acl_test *test, struct acl_pattern *pattern)
if (unlikely(test->flags & ACL_TEST_F_READ_ONLY)) { if (unlikely(test->flags & ACL_TEST_F_READ_ONLY)) {
char *new_str; char *new_str;
new_str = calloc(1, test->len + 1); new_str = calloc(1, temp_pattern.data.str.len + 1);
if (!new_str) if (!new_str)
return ACL_PAT_FAIL; return ACL_PAT_FAIL;
memcpy(new_str, test->ptr, test->len); memcpy(new_str, temp_pattern.data.str.str, temp_pattern.data.str.len);
new_str[test->len] = 0; new_str[temp_pattern.data.str.len] = 0;
if (test->flags & ACL_TEST_F_MUST_FREE) if (test->flags & ACL_TEST_F_MUST_FREE)
free(test->ptr); free(temp_pattern.data.str.str);
test->ptr = new_str; temp_pattern.data.str.str = new_str;
test->flags |= ACL_TEST_F_MUST_FREE; test->flags |= ACL_TEST_F_MUST_FREE;
test->flags &= ~ACL_TEST_F_READ_ONLY; test->flags &= ~ACL_TEST_F_READ_ONLY;
} }
old_char = test->ptr[test->len]; old_char = temp_pattern.data.str.str[temp_pattern.data.str.len];
test->ptr[test->len] = 0; temp_pattern.data.str.str[temp_pattern.data.str.len] = 0;
if (regexec(pattern->ptr.reg, test->ptr, 0, NULL, 0) == 0) if (regexec(pattern->ptr.reg, temp_pattern.data.str.str, 0, NULL, 0) == 0)
ret = ACL_PAT_PASS; ret = ACL_PAT_PASS;
else else
ret = ACL_PAT_FAIL; ret = ACL_PAT_FAIL;
test->ptr[test->len] = old_char; temp_pattern.data.str.str[temp_pattern.data.str.len] = old_char;
return ret; return ret;
} }
@ -659,12 +659,12 @@ int acl_match_beg(struct acl_test *test, struct acl_pattern *pattern)
{ {
int icase; int icase;
if (pattern->len > test->len) if (pattern->len > temp_pattern.data.str.len)
return ACL_PAT_FAIL; return ACL_PAT_FAIL;
icase = pattern->flags & ACL_PAT_F_IGNORE_CASE; icase = pattern->flags & ACL_PAT_F_IGNORE_CASE;
if ((icase && strncasecmp(pattern->ptr.str, test->ptr, pattern->len) != 0) || if ((icase && strncasecmp(pattern->ptr.str, temp_pattern.data.str.str, pattern->len) != 0) ||
(!icase && strncmp(pattern->ptr.str, test->ptr, pattern->len) != 0)) (!icase && strncmp(pattern->ptr.str, temp_pattern.data.str.str, pattern->len) != 0))
return ACL_PAT_FAIL; return ACL_PAT_FAIL;
return ACL_PAT_PASS; return ACL_PAT_PASS;
} }
@ -674,11 +674,11 @@ int acl_match_end(struct acl_test *test, struct acl_pattern *pattern)
{ {
int icase; int icase;
if (pattern->len > test->len) if (pattern->len > temp_pattern.data.str.len)
return ACL_PAT_FAIL; return ACL_PAT_FAIL;
icase = pattern->flags & ACL_PAT_F_IGNORE_CASE; icase = pattern->flags & ACL_PAT_F_IGNORE_CASE;
if ((icase && strncasecmp(pattern->ptr.str, test->ptr + test->len - pattern->len, pattern->len) != 0) || if ((icase && strncasecmp(pattern->ptr.str, temp_pattern.data.str.str + temp_pattern.data.str.len - pattern->len, pattern->len) != 0) ||
(!icase && strncmp(pattern->ptr.str, test->ptr + test->len - pattern->len, pattern->len) != 0)) (!icase && strncmp(pattern->ptr.str, temp_pattern.data.str.str + temp_pattern.data.str.len - pattern->len, pattern->len) != 0))
return ACL_PAT_FAIL; return ACL_PAT_FAIL;
return ACL_PAT_PASS; return ACL_PAT_PASS;
} }
@ -692,20 +692,20 @@ int acl_match_sub(struct acl_test *test, struct acl_pattern *pattern)
char *end; char *end;
char *c; char *c;
if (pattern->len > test->len) if (pattern->len > temp_pattern.data.str.len)
return ACL_PAT_FAIL; return ACL_PAT_FAIL;
end = test->ptr + test->len - pattern->len; end = temp_pattern.data.str.str + temp_pattern.data.str.len - pattern->len;
icase = pattern->flags & ACL_PAT_F_IGNORE_CASE; icase = pattern->flags & ACL_PAT_F_IGNORE_CASE;
if (icase) { if (icase) {
for (c = test->ptr; c <= end; c++) { for (c = temp_pattern.data.str.str; c <= end; c++) {
if (tolower(*c) != tolower(*pattern->ptr.str)) if (tolower(*c) != tolower(*pattern->ptr.str))
continue; continue;
if (strncasecmp(pattern->ptr.str, c, pattern->len) == 0) if (strncasecmp(pattern->ptr.str, c, pattern->len) == 0)
return ACL_PAT_PASS; return ACL_PAT_PASS;
} }
} else { } else {
for (c = test->ptr; c <= end; c++) { for (c = temp_pattern.data.str.str; c <= end; c++) {
if (*c != *pattern->ptr.str) if (*c != *pattern->ptr.str)
continue; continue;
if (strncmp(pattern->ptr.str, c, pattern->len) == 0) if (strncmp(pattern->ptr.str, c, pattern->len) == 0)
@ -761,13 +761,13 @@ static int match_word(struct acl_test *test, struct acl_pattern *pattern, unsign
while (pl > 0 && is_delimiter(ps[pl - 1], delimiters)) while (pl > 0 && is_delimiter(ps[pl - 1], delimiters))
pl--; pl--;
if (pl > test->len) if (pl > temp_pattern.data.str.len)
return ACL_PAT_FAIL; return ACL_PAT_FAIL;
may_match = 1; may_match = 1;
icase = pattern->flags & ACL_PAT_F_IGNORE_CASE; icase = pattern->flags & ACL_PAT_F_IGNORE_CASE;
end = test->ptr + test->len - pl; end = temp_pattern.data.str.str + temp_pattern.data.str.len - pl;
for (c = test->ptr; c <= end; c++) { for (c = temp_pattern.data.str.str; c <= end; c++) {
if (is_delimiter(*c, delimiters)) { if (is_delimiter(*c, delimiters)) {
may_match = 1; may_match = 1;
continue; continue;
@ -822,8 +822,8 @@ int acl_match_int(struct acl_test *test, struct acl_pattern *pattern)
/* Checks that the length of the pattern in <test> is included between min and max */ /* Checks that the length of the pattern in <test> is included between min and max */
int acl_match_len(struct acl_test *test, struct acl_pattern *pattern) int acl_match_len(struct acl_test *test, struct acl_pattern *pattern)
{ {
if ((!pattern->val.range.min_set || pattern->val.range.min <= test->len) && if ((!pattern->val.range.min_set || pattern->val.range.min <= temp_pattern.data.str.len) &&
(!pattern->val.range.max_set || test->len <= pattern->val.range.max)) (!pattern->val.range.max_set || temp_pattern.data.str.len <= pattern->val.range.max))
return ACL_PAT_PASS; return ACL_PAT_PASS;
return ACL_PAT_FAIL; return ACL_PAT_FAIL;
} }
@ -1851,8 +1851,8 @@ int acl_exec_cond(struct acl_cond *cond, struct proxy *px, struct session *l4, v
/* now we may have some cleanup to do */ /* now we may have some cleanup to do */
if (test.flags & ACL_TEST_F_MUST_FREE) { if (test.flags & ACL_TEST_F_MUST_FREE) {
free(test.ptr); free(temp_pattern.data.str.str);
test.len = 0; temp_pattern.data.str.len = 0;
} }
/* we're ORing these terms, so a single PASS is enough */ /* we're ORing these terms, so a single PASS is enough */

View File

@ -413,7 +413,9 @@ struct server *get_server_rch(struct session *s)
expr.arg_len = px->hh_len; expr.arg_len = px->hh_len;
ret = acl_fetch_rdp_cookie(px, s, NULL, ACL_DIR_REQ, &expr, &test); ret = acl_fetch_rdp_cookie(px, s, NULL, ACL_DIR_REQ, &expr, &test);
if (ret == 0 || (test.flags & ACL_TEST_F_MAY_CHANGE) || test.len == 0) len = temp_pattern.data.str.len;
if (ret == 0 || (test.flags & ACL_TEST_F_MAY_CHANGE) || len == 0)
return NULL; return NULL;
/* note: we won't hash if there's only one server left */ /* note: we won't hash if there's only one server left */
@ -423,8 +425,7 @@ struct server *get_server_rch(struct session *s)
/* Found a the hh_name in the headers. /* Found a the hh_name in the headers.
* we will compute the hash based on this value ctx.val. * we will compute the hash based on this value ctx.val.
*/ */
len = test.len; p = temp_pattern.data.str.str;
p = (char *)test.ptr;
while (len) { while (len) {
hash = *p + (hash << 6) + (hash << 16) - hash; hash = *p + (hash << 6) + (hash << 16) - hash;
len--; len--;
@ -1112,14 +1113,14 @@ int tcp_persist_rdp_cookie(struct session *s, struct buffer *req, int an_bit)
expr.arg_len = s->be->rdp_cookie_len; expr.arg_len = s->be->rdp_cookie_len;
ret = acl_fetch_rdp_cookie(px, s, NULL, ACL_DIR_REQ, &expr, &test); ret = acl_fetch_rdp_cookie(px, s, NULL, ACL_DIR_REQ, &expr, &test);
if (ret == 0 || (test.flags & ACL_TEST_F_MAY_CHANGE) || test.len == 0) if (ret == 0 || (test.flags & ACL_TEST_F_MAY_CHANGE) || temp_pattern.data.str.len == 0)
goto no_cookie; goto no_cookie;
memset(&addr, 0, sizeof(addr)); memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET; addr.sin_family = AF_INET;
/* Considering an rdp cookie detected using acl, test.ptr ended with <cr><lf> and should return */ /* Considering an rdp cookie detected using acl, str ended with <cr><lf> and should return */
addr.sin_addr.s_addr = strtoul(test.ptr, &p, 10); addr.sin_addr.s_addr = strtoul(temp_pattern.data.str.str, &p, 10);
if (*p != '.') if (*p != '.')
goto no_cookie; goto no_cookie;
p++; p++;

View File

@ -7866,8 +7866,8 @@ acl_fetch_rqver(struct proxy *px, struct session *l4, void *l7, int dir,
if (len <= 0) if (len <= 0)
return 0; return 0;
test->ptr = ptr; temp_pattern.data.str.str = ptr;
test->len = len; temp_pattern.data.str.len = len;
test->flags = ACL_TEST_F_READ_ONLY | ACL_TEST_F_VOL_1ST; test->flags = ACL_TEST_F_READ_ONLY | ACL_TEST_F_VOL_1ST;
return 1; return 1;
@ -7894,8 +7894,8 @@ acl_fetch_stver(struct proxy *px, struct session *l4, void *l7, int dir,
if (len <= 0) if (len <= 0)
return 0; return 0;
test->ptr = ptr; temp_pattern.data.str.str = ptr;
test->len = len; temp_pattern.data.str.len = len;
test->flags = ACL_TEST_F_READ_ONLY | ACL_TEST_F_VOL_1ST; test->flags = ACL_TEST_F_READ_ONLY | ACL_TEST_F_VOL_1ST;
return 1; return 1;
@ -7941,8 +7941,8 @@ acl_fetch_url(struct proxy *px, struct session *l4, void *l7, int dir,
/* ensure the indexes are not affected */ /* ensure the indexes are not affected */
return 0; return 0;
test->len = txn->req.sl.rq.u_l; temp_pattern.data.str.len = txn->req.sl.rq.u_l;
test->ptr = txn->req.sol + txn->req.sl.rq.u; temp_pattern.data.str.str = txn->req.sol + txn->req.sl.rq.u;
/* we do not need to set READ_ONLY because the data is in a buffer */ /* we do not need to set READ_ONLY because the data is in a buffer */
test->flags = ACL_TEST_F_VOL_1ST; test->flags = ACL_TEST_F_VOL_1ST;
@ -8031,8 +8031,9 @@ acl_fetch_hdr(struct proxy *px, struct session *l4, void *l7, char *sol,
if (http_find_header2(expr->arg.str, expr->arg_len, sol, idx, ctx)) { if (http_find_header2(expr->arg.str, expr->arg_len, sol, idx, ctx)) {
test->flags |= ACL_TEST_F_FETCH_MORE; test->flags |= ACL_TEST_F_FETCH_MORE;
test->flags |= ACL_TEST_F_VOL_HDR; test->flags |= ACL_TEST_F_VOL_HDR;
test->len = ctx->vlen; temp_pattern.data.str.str = (char *)ctx->line + ctx->val;
test->ptr = (char *)ctx->line + ctx->val; temp_pattern.data.str.len = ctx->vlen;
return 1; return 1;
} }
@ -8292,12 +8293,12 @@ acl_fetch_path(struct proxy *px, struct session *l4, void *l7, int dir,
return 0; return 0;
/* OK, we got the '/' ! */ /* OK, we got the '/' ! */
test->ptr = ptr; temp_pattern.data.str.str = ptr;
while (ptr < end && *ptr != '?') while (ptr < end && *ptr != '?')
ptr++; ptr++;
test->len = ptr - test->ptr; temp_pattern.data.str.len = ptr - temp_pattern.data.str.str;
/* we do not need to set READ_ONLY because the data is in a buffer */ /* we do not need to set READ_ONLY because the data is in a buffer */
test->flags = ACL_TEST_F_VOL_1ST; test->flags = ACL_TEST_F_VOL_1ST;

View File

@ -1580,11 +1580,10 @@ pattern_fetch_rdp_cookie(struct proxy *px, struct session *l4, void *l7, int dir
expr.arg_len = arg_p[0].data.str.len; expr.arg_len = arg_p[0].data.str.len;
ret = acl_fetch_rdp_cookie(px, l4, NULL, ACL_DIR_REQ, &expr, &test); ret = acl_fetch_rdp_cookie(px, l4, NULL, ACL_DIR_REQ, &expr, &test);
if (ret == 0 || (test.flags & ACL_TEST_F_MAY_CHANGE) || test.len == 0) if (ret == 0 || (test.flags & ACL_TEST_F_MAY_CHANGE) || temp_pattern.data.str.len == 0)
return 0; return 0;
/* init chunk as read only */ data->str = temp_pattern.data.str;
chunk_initlen(&data->str, test.ptr, 0, test.len);
return 1; return 1;
} }