]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
[MINOR] acl: add support for hdr_ip to match IP addresses in headers
authorWilly Tarreau <w@1wt.eu>
Sat, 19 Sep 2009 05:54:16 +0000 (07:54 +0200)
committerWilly Tarreau <w@1wt.eu>
Sat, 19 Sep 2009 12:47:49 +0000 (14:47 +0200)
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
include/common/standard.h
src/proto_http.c
src/standard.c

index 84fc9c9218fb42f6cd5e3633930ad281c47b105c..4a287b42bec750792543e723faa8437a0add6361 100644 (file)
@@ -5144,6 +5144,12 @@ hdr_cnt(header) <integer>
   request smugling attacks by rejecting requests which contain more than one
   of certain headers. See "hdr" for more information on header matching.
 
+hdr_ip <ip_address>
+hdr_ip(header) <ip_address>
+  Returns true when one of the headers' values contains an IP address matching
+  <ip_address>. 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
 ---------------------
index 447061e9423a9632f08e26238e7ee00141588f2d..00144ccf5f3703e5a495e8698939186e1e3fd9ee 100644 (file)
@@ -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 <str> to a sockaddr_in*.
  */
index dd4ee9cb7ad9559f8ab7a69b10d277f1f36bbfa3..d5077e1e47011670d18365a9cbd48aef6c5ba80f 100644 (file)
@@ -5100,6 +5100,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 '?'.
  */
@@ -5224,6 +5292,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 },
@@ -5234,6 +5303,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 },
index 9dc56afbf7dafc278f19b8aa9676029061d29d57..eecc36069b764308f9fc9673f88e20f175b5fd2b 100644 (file)
@@ -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;