From 21d761b3f99e14153bcf8af05cf3ef93a7a15313 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Sat, 19 Sep 2009 07:54:16 +0200 Subject: [PATCH] [MINOR] acl: add support for hdr_ip to match IP addresses in headers For x-forwarded-for and such headers, it's sometimes needed to match based on network addresses. Let's use hdr_ip() for that. --- doc/configuration.txt | 6 ++++ include/common/standard.h | 5 +++ src/proto_http.c | 70 +++++++++++++++++++++++++++++++++++++++ src/standard.c | 2 +- 4 files changed, 82 insertions(+), 1 deletion(-) diff --git a/doc/configuration.txt b/doc/configuration.txt index be2eac04e0..2de2591179 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -4971,6 +4971,12 @@ hdr_cnt(header) request smugling attacks by rejecting requests which contain more than one of certain headers. See "hdr" for more information on header matching. +hdr_ip +hdr_ip(header) + Returns true when one of the headers' values contains an IP address matching + . This is mainly used with headers such as X-Forwarded-For or + X-Client-IP. See "hdr" for more information on header matching. + 7.6. Pre-defined ACLs --------------------- diff --git a/include/common/standard.h b/include/common/standard.h index d9b9e096a2..c1e29ae70e 100644 --- a/include/common/standard.h +++ b/include/common/standard.h @@ -187,6 +187,11 @@ struct sockaddr_in *str2sa_range(char *str, int *low, int *high); */ int str2net(const char *str, struct in_addr *addr, struct in_addr *mask); +/* + * Parse IP address found in url. + */ +int url2ip(const char *addr, struct in_addr *dst); + /* * Resolve destination server from URL. Convert to a sockaddr_in*. */ diff --git a/src/proto_http.c b/src/proto_http.c index 77092e0240..e2dd23ff74 100644 --- a/src/proto_http.c +++ b/src/proto_http.c @@ -4903,6 +4903,74 @@ acl_fetch_shdr_val(struct proxy *px, struct session *l4, void *l7, int dir, return acl_fetch_hdr_val(px, l4, txn, txn->rsp.sol, expr, test); } +/* 7. Check on HTTP header's IPv4 address value. The IPv4 address is returned. + * This generic function is used by both acl_fetch_chdr* and acl_fetch_shdr*. + */ +static int +acl_fetch_hdr_ip(struct proxy *px, struct session *l4, void *l7, char *sol, + struct acl_expr *expr, struct acl_test *test) +{ + struct http_txn *txn = l7; + struct hdr_idx *idx = &txn->hdr_idx; + struct hdr_ctx *ctx = (struct hdr_ctx *)test->ctx.a; + + if (!txn) + return 0; + + if (!(test->flags & ACL_TEST_F_FETCH_MORE)) + /* search for header from the beginning */ + ctx->idx = 0; + + 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_VOL_HDR; + /* Same optimization as url_ip */ + memset(&l4->srv_addr.sin_addr, 0, sizeof(l4->srv_addr.sin_addr)); + url2ip((char *)ctx->line + ctx->val, &l4->srv_addr.sin_addr); + test->ptr = (void *)&l4->srv_addr.sin_addr; + test->i = AF_INET; + return 1; + } + + test->flags &= ~ACL_TEST_F_FETCH_MORE; + test->flags |= ACL_TEST_F_VOL_HDR; + return 0; +} + +static int +acl_fetch_chdr_ip(struct proxy *px, struct session *l4, void *l7, int dir, + struct acl_expr *expr, struct acl_test *test) +{ + struct http_txn *txn = l7; + + if (!txn) + return 0; + + if (txn->req.msg_state != HTTP_MSG_BODY) + return 0; + + if (txn->rsp.msg_state != HTTP_MSG_RPBEFORE) + /* ensure the indexes are not affected */ + return 0; + + return acl_fetch_hdr_ip(px, l4, txn, txn->req.sol, expr, test); +} + +static int +acl_fetch_shdr_ip(struct proxy *px, struct session *l4, void *l7, int dir, + struct acl_expr *expr, struct acl_test *test) +{ + struct http_txn *txn = l7; + + if (!txn) + return 0; + + if (txn->rsp.msg_state != HTTP_MSG_BODY) + return 0; + + return acl_fetch_hdr_ip(px, l4, txn, txn->rsp.sol, expr, test); +} + /* 8. Check on URI PATH. A pointer to the PATH is stored. The path starts at * the first '/' after the possible hostname, and ends before the possible '?'. */ @@ -4974,6 +5042,7 @@ static struct acl_kw_list acl_kws = {{ },{ { "hdr_dom", acl_parse_str, acl_fetch_chdr, acl_match_dom, ACL_USE_L7REQ_VOLATILE }, { "hdr_cnt", acl_parse_int, acl_fetch_chdr_cnt,acl_match_int, ACL_USE_L7REQ_VOLATILE }, { "hdr_val", acl_parse_int, acl_fetch_chdr_val,acl_match_int, ACL_USE_L7REQ_VOLATILE }, + { "hdr_ip", acl_parse_ip, acl_fetch_chdr_ip, acl_match_ip, ACL_USE_L7REQ_VOLATILE }, { "shdr", acl_parse_str, acl_fetch_shdr, acl_match_str, ACL_USE_L7RTR_VOLATILE }, { "shdr_reg", acl_parse_reg, acl_fetch_shdr, acl_match_reg, ACL_USE_L7RTR_VOLATILE }, @@ -4984,6 +5053,7 @@ static struct acl_kw_list acl_kws = {{ },{ { "shdr_dom", acl_parse_str, acl_fetch_shdr, acl_match_dom, ACL_USE_L7RTR_VOLATILE }, { "shdr_cnt", acl_parse_int, acl_fetch_shdr_cnt,acl_match_int, ACL_USE_L7RTR_VOLATILE }, { "shdr_val", acl_parse_int, acl_fetch_shdr_val,acl_match_int, ACL_USE_L7RTR_VOLATILE }, + { "shdr_ip", acl_parse_ip, acl_fetch_shdr_ip, acl_match_ip, ACL_USE_L7RTR_VOLATILE }, { "path", acl_parse_str, acl_fetch_path, acl_match_str, ACL_USE_L7REQ_VOLATILE }, { "path_reg", acl_parse_reg, acl_fetch_path, acl_match_reg, ACL_USE_L7REQ_VOLATILE }, diff --git a/src/standard.c b/src/standard.c index 9dc56afbf7..eecc36069b 100644 --- a/src/standard.c +++ b/src/standard.c @@ -363,7 +363,7 @@ int str2net(const char *str, struct in_addr *addr, struct in_addr *mask) /* * Parse IP address found in url. */ -static int url2ip(const char *addr, struct in_addr *dst) +int url2ip(const char *addr, struct in_addr *dst) { int saw_digit, octets, ch; u_char tmp[4], *tp; -- 2.47.3