From: Willy Tarreau Date: Sun, 6 May 2007 22:55:35 +0000 (+0200) Subject: [MEDIUM] added several ACL criteria and matches X-Git-Tag: v1.3.10~8 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=8797c06327f4e9fb123adc2b9eb5a01a93c28756;p=thirdparty%2Fhaproxy.git [MEDIUM] added several ACL criteria and matches Many ACL criteria have been added. Some others are still commented out because some functions are still missing. --- diff --git a/src/client.c b/src/client.c index 2754b91f72..113708efd0 100644 --- a/src/client.c +++ b/src/client.c @@ -24,6 +24,7 @@ #include #include +#include #include #include #include @@ -33,6 +34,7 @@ #include #include +#include #include #include #include @@ -448,6 +450,65 @@ int event_accept(int fd) { +/************************************************************************/ +/* All supported keywords must be declared here. */ +/************************************************************************/ + +/* set test->ptr to point to the source IPv4/IPv6 address and test->i to the family */ +static int acl_fetch_src(struct proxy *px, struct session *l4, void *l7, void *arg, struct acl_test *test) +{ + test->i = l4->cli_addr.ss_family; + if (test->i == AF_INET) + test->ptr = (void *)&((struct sockaddr_in *)&l4->cli_addr)->sin_addr; + else + test->ptr = (void *)&((struct sockaddr_in6 *)(&l4->cli_addr))->sin6_addr; + test->flags = ACL_TEST_F_READ_ONLY; + return 1; +} + + +/* set test->i to the connexion's source port */ +static int acl_fetch_sport(struct proxy *px, struct session *l4, void *l7, void *arg, struct acl_test *test) +{ + if (l4->cli_addr.ss_family == AF_INET) + test->i = ntohs(((struct sockaddr_in *)&l4->cli_addr)->sin_port); + else + test->i = ntohs(((struct sockaddr_in6 *)(&l4->cli_addr))->sin6_port); + test->flags = 0; + return 1; +} + +/* set test->i to the number of connexions to the proxy */ +static int acl_fetch_dconn(struct proxy *px, struct session *l4, void *l7, void *arg, struct acl_test *test) +{ + test->i = px->feconn; + return 1; +} + + +/* Note: must not be declared as its list will be overwritten */ +static struct acl_kw_list acl_kws = {{ },{ + { "src_port", acl_parse_range, acl_fetch_sport, acl_match_range }, +#if 0 + { "src", acl_parse_ip, acl_fetch_src, acl_match_ip }, + { "dst", acl_parse_ip, acl_fetch_dst, acl_match_ip }, + + { "dst_port", acl_parse_range, acl_fetch_dport, acl_match_range }, + + { "src_limit", acl_parse_int, acl_fetch_sconn, acl_match_max }, +#endif + { "dst_limit", acl_parse_int, acl_fetch_dconn, acl_match_max }, + { NULL, NULL, NULL, NULL }, +}}; + + +__attribute__((constructor)) +static void __client_init(void) +{ + acl_register_keywords(&acl_kws); +} + + /* * Local variables: * c-indent-level: 8 diff --git a/src/proto_http.c b/src/proto_http.c index 4540fd4d84..706ef46407 100644 --- a/src/proto_http.c +++ b/src/proto_http.c @@ -34,6 +34,7 @@ #include #include +#include #include #include #include @@ -42,6 +43,7 @@ #include #include +#include #include #include #include @@ -5124,6 +5126,217 @@ void debug_hdr(const char *dir, struct session *t, const char *start, const char } +/************************************************************************/ +/* The code below is dedicated to ACL parsing and matching */ +/************************************************************************/ + + + + +/* 1. Check on METHOD + * We use the pre-parsed method if it is known, and store its number as an + * integer. If it is unknown, we use the pointer and the length. + */ +static int acl_parse_meth(const char *text, struct acl_pattern *pattern) +{ + int len, meth; + + len = strlen(text); + meth = find_http_meth(text, len); + + pattern->val.i = meth; + if (meth == HTTP_METH_OTHER) { + pattern->ptr.str = strdup(text); + if (!pattern->ptr.str) + return 0; + pattern->len = len; + } + return 1; +} + +static int acl_fetch_meth(struct proxy *px, struct session *l4, void *l7, void *arg, struct acl_test *test) +{ + int meth; + struct http_txn *txn = l7; + + meth = txn->meth; + test->i = meth; + if (meth == HTTP_METH_OTHER) { + test->len = txn->req.sl.rq.m_l; + test->ptr = txn->req.sol; + } + test->flags = ACL_TEST_F_READ_ONLY | ACL_TEST_F_VOL_1ST; + return 1; +} + +static int acl_match_meth(struct acl_test *test, struct acl_pattern *pattern) +{ + if (test->i != pattern->val.i) + return 0; + + if (test->i != HTTP_METH_OTHER) + return 1; + + /* Other method, we must compare the strings */ + if (pattern->len != test->len) + return 0; + if (strncmp(pattern->ptr.str, test->ptr, test->len) != 0) + return 0; + return 1; +} + +/* 2. Check on Request/Status Version + * We simply compare strings here. + */ +static int acl_parse_ver(const char *text, struct acl_pattern *pattern) +{ + pattern->ptr.str = strdup(text); + if (!pattern->ptr.str) + return 0; + pattern->len = strlen(text); + return 1; +} + +static int acl_fetch_rqver(struct proxy *px, struct session *l4, void *l7, void *arg, struct acl_test *test) +{ + struct http_txn *txn = l7; + char *ptr; + int len; + + len = txn->req.sl.rq.v_l; + ptr = txn->req.sol + txn->req.sl.rq.v - txn->req.som; + + while ((len-- > 0) && (*ptr++ != '/')); + if (len <= 0) + return 0; + + test->ptr = ptr; + test->len = len; + + test->flags = ACL_TEST_F_READ_ONLY | ACL_TEST_F_VOL_1ST; + return 1; +} + +static int acl_fetch_stver(struct proxy *px, struct session *l4, void *l7, void *arg, struct acl_test *test) +{ + struct http_txn *txn = l7; + char *ptr; + int len; + + len = txn->rsp.sl.st.v_l; + ptr = txn->rsp.sol; + + while ((len-- > 0) && (*ptr++ != '/')); + if (len <= 0) + return 0; + + test->ptr = ptr; + test->len = len; + + test->flags = ACL_TEST_F_READ_ONLY | ACL_TEST_F_VOL_1ST; + return 1; +} + +/* 3. Check on Status Code. We manipulate integers here. */ +static int acl_fetch_stcode(struct proxy *px, struct session *l4, void *l7, void *arg, struct acl_test *test) +{ + struct http_txn *txn = l7; + char *ptr; + int len; + + len = txn->rsp.sl.st.c_l; + ptr = txn->rsp.sol + txn->rsp.sl.st.c - txn->rsp.som; + + test->i = __strl2ui(ptr, len); + test->flags = ACL_TEST_F_VOL_1ST; + return 1; +} + +/* 4. Check on URL/URI. A pointer to the URI is stored. */ +static int acl_fetch_url(struct proxy *px, struct session *l4, void *l7, void *arg, struct acl_test *test) +{ + struct http_txn *txn = l7; + + test->len = txn->req.sl.rq.u_l; + test->ptr = txn->req.sol + txn->req.sl.rq.u; + + test->flags = ACL_TEST_F_READ_ONLY | ACL_TEST_F_VOL_1ST; + return 1; +} + + + +/************************************************************************/ +/* All supported keywords must be declared here. */ +/************************************************************************/ + +/* Note: must not be declared as its list will be overwritten */ +static struct acl_kw_list acl_kws = {{ },{ + { "method", acl_parse_meth, acl_fetch_meth, acl_match_meth }, + { "req_ver", acl_parse_ver, acl_fetch_rqver, acl_match_str }, + { "resp_ver", acl_parse_ver, acl_fetch_stver, acl_match_str }, + { "status", acl_parse_range, acl_fetch_stcode, acl_match_range }, + + { "url", acl_parse_str, acl_fetch_url, acl_match_str }, + { "url_beg", acl_parse_str, acl_fetch_url, acl_match_beg }, + { "url_end", acl_parse_str, acl_fetch_url, acl_match_end }, + { "url_sub", acl_parse_str, acl_fetch_url, acl_match_sub }, + { "url_dir", acl_parse_str, acl_fetch_url, acl_match_dir }, + { "url_dom", acl_parse_str, acl_fetch_url, acl_match_dom }, + { NULL, NULL, NULL, NULL }, +#if 0 + { "url_reg", acl_parse_reg, acl_fetch_url, acl_match_reg }, + + { "line", acl_parse_str, acl_fetch_line, acl_match_str }, + { "line_reg", acl_parse_reg, acl_fetch_line, acl_match_reg }, + { "line_beg", acl_parse_str, acl_fetch_line, acl_match_beg }, + { "line_end", acl_parse_str, acl_fetch_line, acl_match_end }, + { "line_sub", acl_parse_str, acl_fetch_line, acl_match_sub }, + { "line_dir", acl_parse_str, acl_fetch_line, acl_match_dir }, + { "line_dom", acl_parse_str, acl_fetch_line, acl_match_dom }, + + { "path", acl_parse_str, acl_fetch_path, acl_match_str }, + { "path_reg", acl_parse_reg, acl_fetch_path, acl_match_reg }, + { "path_beg", acl_parse_str, acl_fetch_path, acl_match_beg }, + { "path_end", acl_parse_str, acl_fetch_path, acl_match_end }, + { "path_sub", acl_parse_str, acl_fetch_path, acl_match_sub }, + { "path_dir", acl_parse_str, acl_fetch_path, acl_match_dir }, + { "path_dom", acl_parse_str, acl_fetch_path, acl_match_dom }, + + { "hdr", acl_parse_str, acl_fetch_hdr, acl_match_str }, + { "hdr_reg", acl_parse_reg, acl_fetch_hdr, acl_match_reg }, + { "hdr_beg", acl_parse_str, acl_fetch_hdr, acl_match_beg }, + { "hdr_end", acl_parse_str, acl_fetch_hdr, acl_match_end }, + { "hdr_sub", acl_parse_str, acl_fetch_hdr, acl_match_sub }, + { "hdr_dir", acl_parse_str, acl_fetch_hdr, acl_match_dir }, + { "hdr_dom", acl_parse_str, acl_fetch_hdr, acl_match_dom }, + { "hdr_pst", acl_parse_none, acl_fetch_hdr, acl_match_pst }, + + { "cook", acl_parse_str, acl_fetch_cook, acl_match_str }, + { "cook_reg", acl_parse_reg, acl_fetch_cook, acl_match_reg }, + { "cook_beg", acl_parse_str, acl_fetch_cook, acl_match_beg }, + { "cook_end", acl_parse_str, acl_fetch_cook, acl_match_end }, + { "cook_sub", acl_parse_str, acl_fetch_cook, acl_match_sub }, + { "cook_dir", acl_parse_str, acl_fetch_cook, acl_match_dir }, + { "cook_dom", acl_parse_str, acl_fetch_cook, acl_match_dom }, + { "cook_pst", acl_parse_none, acl_fetch_cook, acl_match_pst }, + + { "auth_user", acl_parse_str, acl_fetch_user, acl_match_str }, + { "auth_regex", acl_parse_reg, acl_fetch_user, acl_match_reg }, + { "auth_clear", acl_parse_str, acl_fetch_auth, acl_match_str }, + { "auth_md5", acl_parse_str, acl_fetch_auth, acl_match_md5 }, + { NULL, NULL, NULL, NULL }, +#endif +}}; + + +__attribute__((constructor)) +static void __http_protocol_init(void) +{ + acl_register_keywords(&acl_kws); +} + + /* * Local variables: * c-indent-level: 8