Search
j0ke.net Open Build Service
>
Projects
>
internetx
:
projects
:
http
>
haproxy
> haproxy-1.5-geolocation.patch
Sign Up
|
Log In
Username
Password
Cancel
Overview
Repositories
Revisions
Requests
Users
Advanced
Attributes
Meta
File haproxy-1.5-geolocation.patch of Package haproxy
From b0ed0615b148d1ee261c018011e0770b684d38f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cyril=20Bont=C3=A9?= <cyril.bonte@free.fr> Date: Mon, 17 Jun 2013 22:36:19 +0200 Subject: [PATCH] Geolocation based on haproxy 1.5-dev19 --- include/common/chunk.h | 1 + include/proto/acl.h | 4 ++ include/proto/proto_http.h | 2 + include/proto/proto_tcp.h | 1 + include/types/acl.h | 1 + include/types/proto_http.h | 1 + include/types/proxy.h | 10 ++++ src/acl.c | 63 ++++++++++++++++++++- src/cfgparse.c | 88 +++++++++++++++++++++++++++++ src/chunk.c | 50 +++++++++++++++++ src/haproxy.c | 7 +++ src/proto_http.c | 136 ++++++++++++++++++++++++++++++++++++++++++--- src/proto_tcp.c | 5 +- 13 files changed, 354 insertions(+), 15 deletions(-) diff --git a/include/common/chunk.h b/include/common/chunk.h index 18f41af..4e883b5 100644 --- a/include/common/chunk.h +++ b/include/common/chunk.h @@ -47,6 +47,7 @@ int chunk_htmlencode(struct chunk *dst, struct chunk *src); int chunk_asciiencode(struct chunk *dst, struct chunk *src, char qc); int chunk_strcmp(const struct chunk *chk, const char *str); int chunk_strcasecmp(const struct chunk *chk, const char *str); +int chunk_replace(struct chunk *chk, const char *token, const char *value, const int ofs); int alloc_trash_buffers(int bufsize); struct chunk *get_trash_chunk(void); diff --git a/include/proto/acl.h b/include/proto/acl.h index 6859b3d..8c7dda5 100644 --- a/include/proto/acl.h +++ b/include/proto/acl.h @@ -224,6 +224,10 @@ int acl_match_ip(struct sample *smp, struct acl_pattern *pattern); */ int acl_match_reg(struct sample *smp, struct acl_pattern *pattern); +void *acl_lookup_ip(struct sample *smp, struct acl_expr *expr); +int init_geolocate(char *filename, struct acl_expr **geolocate, char **err); +void deinit_geolocate(struct acl_expr *expr); + #endif /* _PROTO_ACL_H */ /* diff --git a/include/proto/proto_http.h b/include/proto/proto_http.h index 24e3581..315688e 100644 --- a/include/proto/proto_http.h +++ b/include/proto/proto_http.h @@ -117,6 +117,8 @@ struct chunk *http_error_message(struct session *s, int msgnum); struct redirect_rule *http_parse_redirect_rule(const char *file, int line, struct proxy *curproxy, const char **args, char **errmsg); +int smp_fetch_hdr_ip(struct proxy *px, struct session *l4, void *l7, unsigned int opt, const struct arg *args, struct sample *smp); + /* to be used when contents change in an HTTP message */ #define http_msg_move_end(msg, bytes) do { \ unsigned int _bytes = (bytes); \ diff --git a/include/proto/proto_tcp.h b/include/proto/proto_tcp.h index 4644452..3ac5230 100644 --- a/include/proto/proto_tcp.h +++ b/include/proto/proto_tcp.h @@ -38,6 +38,7 @@ int tcp_drain(int fd); int tcp_inspect_request(struct session *s, struct channel *req, int an_bit); int tcp_inspect_response(struct session *s, struct channel *rep, int an_bit); int tcp_exec_req_rules(struct session *s); +int smp_fetch_src(struct proxy *px, struct session *l4, void *l7, unsigned int opt, const struct arg *args, struct sample *smp); /* Converts the INET/INET6 source address to a stick_table key usable for table * lookups. Returns either NULL if the source cannot be converted (eg: not diff --git a/include/types/acl.h b/include/types/acl.h index 42e2e9c..80d7805 100644 --- a/include/types/acl.h +++ b/include/types/acl.h @@ -77,6 +77,7 @@ enum { ACL_PAT_F_FROM_FILE = 1 << 1, /* pattern comes from a file */ ACL_PAT_F_TREE_OK = 1 << 2, /* the pattern parser is allowed to build a tree */ ACL_PAT_F_TREE = 1 << 3, /* some patterns are arranged in a tree */ + ACL_PAT_F_DICTIONARY = 1 << 4, /* some patterns define a dictionary (geolocation) */ }; /* ACL match methods */ diff --git a/include/types/proto_http.h b/include/types/proto_http.h index 1d7c92f..55ad5fe 100644 --- a/include/types/proto_http.h +++ b/include/types/proto_http.h @@ -416,6 +416,7 @@ struct http_txn { char *cli_cookie; /* cookie presented by the client, in capture mode */ char *srv_cookie; /* cookie presented by the server, in capture mode */ char *sessid; /* the appsession id, if found in the request or in the response */ + char *geoloc; /* geolocation detected for this transaction */ int cookie_first_date; /* if non-zero, first date the expirable cookie was set/seen */ int cookie_last_date; /* if non-zero, last date the expirable cookie was set/seen */ diff --git a/include/types/proxy.h b/include/types/proxy.h index e6bc755..c25abe0 100644 --- a/include/types/proxy.h +++ b/include/types/proxy.h @@ -173,6 +173,9 @@ enum { #define STK_IS_STORE 0x00000002 /* store on request fetch */ #define STK_ON_RSP 0x00000004 /* store on response fetch */ +#define GEOLOC_SRC 0x00000001 /* geolocation based on the client source IP */ +#define GEOLOC_HDR 0x00000002 /* geolocation based on a HTTP header */ + struct error_snapshot { struct timeval when; /* date of this event, (tv_sec == 0) means "never" */ unsigned int len; /* original length of the last invalid request/response */ @@ -333,6 +336,13 @@ struct proxy { unsigned int backlog; /* force the frontend's listen backlog */ unsigned int bind_proc; /* bitmask of processes using this proxy. 0 = all. */ + int geoloc_options; /* GEOLOC_SRC, GEOLOC_HDR */ + char *geoloc_hdr_name; /* header name used for geolocation if defined */ + int geoloc_hdr_len; /* length of the name of the header above */ + int geoloc_hdr_occ; /* occurrence number of header above: >0 = from first, <0 = from end, 0=disabled */ + struct acl_expr *geolocate; /* special acl expression reserved for the geolocation */ + struct acl_cond *geolocate_cond; /* acl condition to meet before applying geolocation */ + /* warning: these structs are huge, keep them at the bottom */ struct sockaddr_storage dispatch_addr; /* the default address to connect to */ struct error_snapshot invalid_req, invalid_rep; /* captures of last errors */ diff --git a/src/acl.c b/src/acl.c index 664ef5c..a37a26e 100644 --- a/src/acl.c +++ b/src/acl.c @@ -142,7 +142,7 @@ int acl_match_bin(struct sample *smp, struct acl_pattern *pattern) /* Lookup a string in the expression's pattern tree. The node is returned if it * exists, otherwise NULL. */ -static void *acl_lookup_str(struct sample *smp, struct acl_expr *expr) +void *acl_lookup_str(struct sample *smp, struct acl_expr *expr) { /* data are stored in a tree */ struct ebmb_node *node; @@ -424,7 +424,7 @@ int acl_match_ip(struct sample *smp, struct acl_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 *acl_lookup_ip(struct sample *smp, struct acl_expr *expr) +void *acl_lookup_ip(struct sample *smp, struct acl_expr *expr) { struct in_addr *s; @@ -797,14 +797,18 @@ int acl_parse_ip(const char **text, struct acl_pattern *pattern, int *opaque, ch */ pattern->type = SMP_T_IPV4; if (mask + (mask & -mask) == 0 && tree) { + int len = (pattern->ptr.str ? strlen(pattern->ptr.str) + 1 : 0); /* optional null terminated string length */ mask = mask ? 33 - flsnz(mask & -mask) : 0; /* equals cidr value */ /* FIXME: insert <addr>/<mask> into the tree here */ - node = calloc(1, sizeof(*node) + 4); /* reserve 4 bytes for IPv4 address */ + node = calloc(1, sizeof(*node) + 4 + len); /* reserve 4 bytes for IPv4 address + optional tring length */ if (!node) { memprintf(err, "out of memory while loading IPv4 pattern"); return 0; } memcpy(node->key, &pattern->val.ipv4.addr, 4); /* network byte order */ + if (len) + memcpy(node->key + 4, pattern->ptr.str, len); + node->node.pfx = mask; if (ebmb_insert_prefix(tree, node, 4) != node) free(node); /* was a duplicate */ @@ -965,6 +969,8 @@ static int acl_read_patterns_from_file(struct acl_expr *expr, pattern = NULL; args[1] = ""; while (fgets(trash.str, trash.size, file) != NULL) { + char *value = NULL; + line++; c = trash.str; @@ -978,6 +984,14 @@ static int acl_read_patterns_from_file(struct acl_expr *expr, args[0] = c; + if (patflags & ACL_PAT_F_DICTIONARY) { + while (*c && *c != '\n' && *c != '\r' && *c != '\t' && *c != ' ') + c++; + while (*c == ' ' || *c == '\t') + *c++ = 0; + value = c; + } + while (*c && *c != '\n' && *c != '\r') c++; *c = 0; @@ -997,6 +1011,9 @@ static int acl_read_patterns_from_file(struct acl_expr *expr, memset(pattern, 0, sizeof(*pattern)); pattern->flags = patflags; + if (value) { + pattern->ptr.str = strdup(value); + } if (!(pattern->flags & ACL_PAT_F_IGNORE_CASE) && (expr->match == acl_match_str || expr->match == acl_match_ip)) { /* we pre-set the data pointer to the tree's head so that functions @@ -1956,6 +1973,46 @@ int init_acl() return err; } +/* + * Initialize a specific acl expression used for geolocation. + */ +int init_geolocate(char *filename, struct acl_expr **geolocate, char **err) { + struct sample_fetch *smp; + struct acl_expr *expr; + + smp = find_sample_fetch("src", 3); + if (!smp) { + memprintf(err, "unable to find internal acl keyword while loading geoloc dictionary"); + return 0; + } + + expr = (struct acl_expr *)calloc(1, sizeof(*expr)); + if (!expr) { + memprintf(err, "out of memory while loading geoloc dictionary"); + return 0; + } + + expr->kw = smp->kw; + LIST_INIT(&expr->patterns); + expr->pattern_tree = EB_ROOT_UNIQUE; + expr->parse = acl_parse_fcts[ACL_MATCH_IP]; + expr->match = acl_match_fcts[ACL_MATCH_IP]; + expr->args = empty_arg_list; + expr->smp = smp; + + *geolocate = expr; + + return acl_read_patterns_from_file(expr, filename, ACL_PAT_F_FROM_FILE | ACL_PAT_F_DICTIONARY, err); +} + +/* + * Purge the gelocation expression and free memory. + */ +void deinit_geolocate(struct acl_expr *expr) { + prune_acl_expr(expr); + free(expr); +} + /************************************************************************/ /* All supported sample fetch functions must be declared here */ /************************************************************************/ diff --git a/src/cfgparse.c b/src/cfgparse.c index b3435ef..fd911dc 100644 --- a/src/cfgparse.c +++ b/src/cfgparse.c @@ -5626,6 +5626,94 @@ stats_error_parsing: goto out; } } + else if (!strcmp(args[0], "geolocate")) { + int cur_arg; + + if (warnifnotcap(curproxy, PR_CAP_FE | PR_CAP_BE, file, linenum, args[0], NULL)) + err_code |= ERR_WARN; + + cur_arg = 1; + if (strcmp(args[cur_arg], "src") == 0) { + curproxy->geoloc_options = GEOLOC_SRC; + } else if (strncmp(args[cur_arg], "hdr_ip(", 7) == 0) { + char *name, *end; + + name = args[cur_arg] + 7; + while (isspace(*name)) + name++; + + end = name; + while (*end && !isspace(*end) && *end != ',' && *end != ')') + end++; + + curproxy->geoloc_options = GEOLOC_HDR; + curproxy->geoloc_hdr_name = calloc(1, end - name + 1); + curproxy->geoloc_hdr_len = end - name; + memcpy(curproxy->geoloc_hdr_name, name, end - name); + curproxy->geoloc_hdr_name[end-name] = '\0'; + curproxy->geoloc_hdr_occ = -1; + + /* now look for an occurrence number */ + while (isspace(*end)) + end++; + if (*end == ',') { + end++; + name = end; + if (*end == '-') + end++; + while (isdigit(*end)) + end++; + curproxy->geoloc_hdr_occ = strl2ic(name, end-name); + } + + if (curproxy->geoloc_hdr_occ < -MAX_HDR_HISTORY) { + Alert("parsing [%s:%d] : hdr_ip(name,num) does not support negative" + " occurrences values smaller than %d.\n", + file, linenum, MAX_HDR_HISTORY); + err_code |= ERR_ALERT | ERR_FATAL; + goto out; + } + } + else if (!*args[cur_arg]) { + Alert("parsing [%s:%d] : '%s' expects 'src' or 'hdr_ip(<hdr>,<occ>)' as argument.\n", + file, linenum, args[0]); + err_code |= ERR_ALERT | ERR_FATAL; + goto out; + } + cur_arg++; + if (*args[cur_arg]) { + if (!init_geolocate(args[cur_arg], &curproxy->geolocate, &errmsg)) { + Alert("parsing [%s:%d] : %s: error detected while processing geolocation rule : %s\n", + file, linenum, args[0], errmsg); + err_code |= ERR_ALERT | ERR_FATAL; + goto out; + } + } + else { + Alert("parsing [%s:%d] : '%s' expects <filename> as argument.\n", + file, linenum, args[0]); + err_code |= ERR_ALERT | ERR_FATAL; + goto out; + } + cur_arg++; + if ((strcmp(args[cur_arg], "if") == 0 || strcmp(args[cur_arg], "unless") == 0)) { + if ((curproxy->geolocate_cond = build_acl_cond(file, linenum, curproxy, (const char **)args+cur_arg, &errmsg)) == NULL) { + Alert("parsing [%s:%d] : error detected while parsing a '%s' condition : %s.\n", + file, linenum, args[0], errmsg); + err_code |= ERR_ALERT | ERR_FATAL; + goto out; + } + err_code |= warnif_cond_conflicts(curproxy->geolocate_cond, + (curproxy->cap & PR_CAP_FE) ? SMP_VAL_FE_HRQ_HDR : SMP_VAL_BE_HRQ_HDR, + file, linenum); + } + else if (*args[cur_arg]) { + Alert("parsing [%s:%d] : '%s' : Expecting nothing, 'if', or 'unless', got '%s'.\n", + file, linenum, args[0], args[cur_arg]); + err_code |= ERR_ALERT | ERR_FATAL; + goto out; + } + } else { struct cfg_kw_list *kwl; int index; diff --git a/src/chunk.c b/src/chunk.c index 9463abb..551f3e4 100644 --- a/src/chunk.c +++ b/src/chunk.c @@ -241,6 +241,56 @@ int chunk_strcasecmp(const struct chunk *chk, const char *str) return diff; } + +/* + * Replace a token in chunk with a specified value, beginning at the <ofs> + * offset in the chunk, respecting the limit of at most chk->size chars. + * Returns the new chunk size. + */ +int chunk_replace(struct chunk *chk, const char *token, const char *value, const int ofs) +{ + int i; + int token_len, value_len, delta; + char *s; + int len = chk->len; + + token_len = strlen(token); + if (!token_len) + goto out; + + value_len = strlen(value); + delta = value_len - token_len; + int n = len - token_len; + + i = ofs; + s = chk->str + i; + while (i <= n) { + if ((*s == token[0]) && (memcmp(s, token, token_len) == 0)) { + if (delta) { + if (len + delta > chk->size) + return -1; + if (n - i) + memmove(s + value_len, s + token_len, n - i); + len += delta; + n += delta; + } + if (value_len) { + memcpy(s, value, value_len); + /* skip the value inserted to prevent recursion */ + i += value_len; + s += value_len; + } + } else { + i++; + s++; + } + } + chk->len = len; + out: + return len; +} + + /* * Local variables: * c-indent-level: 8 diff --git a/src/haproxy.c b/src/haproxy.c index ac9fba1..456d719 100644 --- a/src/haproxy.c +++ b/src/haproxy.c @@ -1091,6 +1091,13 @@ void deinit(void) deinit_stick_rules(&p->storersp_rules); deinit_stick_rules(&p->sticking_rules); + if (p->geolocate) + deinit_geolocate(p->geolocate); + if (p->geolocate_cond) { + prune_acl_cond(p->geolocate_cond); + free(p->geolocate_cond); + } + free(p->appsession_name); h = p->req_cap; diff --git a/src/proto_http.c b/src/proto_http.c index 9068050..89313a7 100644 --- a/src/proto_http.c +++ b/src/proto_http.c @@ -3344,10 +3344,11 @@ http_res_get_intercept_rule(struct proxy *px, struct list *rules, struct session * returns non-zero on success, or zero in case of a, irrecoverable error such * as too large a request to build a valid response. */ -static int http_apply_redirect_rule(struct redirect_rule *rule, struct session *s, struct http_txn *txn) +static int http_apply_redirect_rule(struct redirect_rule *rule, struct session *s, struct http_txn *txn, int do_geoloc) { struct http_msg *msg = &txn->req; const char *msg_fmt; + int location_ofs; /* build redirect message */ switch(rule->code) { @@ -3371,6 +3372,8 @@ static int http_apply_redirect_rule(struct redirect_rule *rule, struct session * if (unlikely(!chunk_strcpy(&trash, msg_fmt))) return 0; + + location_ofs = trash.len; switch(rule->type) { case REDIRECT_TYPE_SCHEME: { @@ -3499,6 +3502,10 @@ static int http_apply_redirect_rule(struct redirect_rule *rule, struct session * break; } + if (do_geoloc && chunk_replace(&trash, "${geoloc}", txn->geoloc ? txn->geoloc : "", location_ofs) < 0) { + return 0; + } + if (rule->cookie_len) { memcpy(trash.str + trash.len, "\r\nSet-Cookie: ", 14); trash.len += 14; @@ -3563,6 +3570,81 @@ static int http_apply_redirect_rule(struct redirect_rule *rule, struct session * return 1; } +/* + * Determine the request geolocation from the session. If both the backend and + * the frontend provide a geolocation rule, then the backend is predominant. + * Returns 1 if a geolocation rule exists or zero if none is defined. + */ +static int geolocate(struct session *s) +{ + struct http_txn *txn = &s->txn; + int do_geoloc; + struct proxy *px; + + do_geoloc = (txn->geoloc != 0); /* The transaction is geolocated, which means a previous rule exists */ + px = s->be; + while (1) { + if (px->geolocate) { + int ret = 1; + if (px->geolocate_cond) { + struct acl_cond *cond = px->geolocate_cond; + ret = acl_exec_cond(cond, px, s, txn, SMP_OPT_DIR_REQ|SMP_OPT_FINAL); + + ret = acl_pass(ret); + if (cond->pol == ACL_COND_UNLESS) + ret = !ret; + } + if (ret) { + struct sample smp; + smp.type = SMP_TYPES; /* default value used to detect non matches */ + smp.ctx.a[0] = NULL; + if (px->geoloc_options & GEOLOC_SRC) { + struct arg args[0]; + smp_fetch_src(px, s, txn, SMP_OPT_DIR_REQ, args, &smp); + } + else if (px->geoloc_options & GEOLOC_HDR) { + struct arg args[2]; + args[0].type = ARGT_STR; + args[0].data.str.str = px->geoloc_hdr_name; + args[0].data.str.len = px->geoloc_hdr_len; + + args[1].type = ARGT_SINT; + args[1].data.uint = px->geoloc_hdr_occ; + + smp_fetch_hdr_ip(px, s, txn, SMP_OPT_DIR_REQ, args, &smp); + } + + if (smp.type == SMP_T_IPV4 || smp.type == SMP_T_IPV6) { + struct ebmb_node *node = NULL; + if (!eb_is_empty(&px->geolocate->pattern_tree)) { + /* a tree is present, let's check what type it is */ + node = acl_lookup_ip(&smp, px->geolocate); + } + if (node) { + txn->geoloc = (char *) (node->key + 4); + } + else { + struct acl_pattern *pattern; + /* call the match() function for all tests on this value */ + list_for_each_entry(pattern, &px->geolocate->patterns, list) { + if (px->geolocate->match(&smp, pattern)) { + txn->geoloc = pattern->ptr.str; + break; + } + } + } + } + } + do_geoloc = 1; + } + if (txn->geoloc || (px == s->fe)) { + break; + } + px = s->fe; + } + return do_geoloc; +} + /* This stream analyser runs all HTTP request processing which is common to * frontends and backends, which means blocking ACLs, filters, connection-close, * reqadd, stats and redirects. This is performed for the designated proxy. @@ -3579,6 +3661,7 @@ int http_process_req_common(struct session *s, struct channel *req, int an_bit, struct redirect_rule *rule; struct cond_wordlist *wl; int do_stats; + int do_geoloc; if (unlikely(msg->msg_state < HTTP_MSG_BODY)) { /* we need more data */ @@ -3779,6 +3862,8 @@ int http_process_req_common(struct session *s, struct channel *req, int an_bit, goto return_prx_cond; } + do_geoloc = geolocate(s); + /* add request headers from the rule sets in the same order */ list_for_each_entry(wl, &px->req_add, list) { if (wl->cond) { @@ -3795,7 +3880,7 @@ int http_process_req_common(struct session *s, struct channel *req, int an_bit, } if (http_req_last_rule && http_req_last_rule->action == HTTP_REQ_ACT_REDIR) { - if (!http_apply_redirect_rule(http_req_last_rule->arg.redir, s, txn)) + if (!http_apply_redirect_rule(http_req_last_rule->arg.redir, s, txn, do_geoloc)) goto return_bad_req; req->analyse_exp = TICK_ETERNITY; return 1; @@ -3824,7 +3909,7 @@ int http_process_req_common(struct session *s, struct channel *req, int an_bit, if (!ret) continue; } - if (!http_apply_redirect_rule(rule, s, txn)) + if (!http_apply_redirect_rule(rule, s, txn, do_geoloc)) goto return_bad_req; req->analyse_exp = TICK_ETERNITY; @@ -8172,6 +8257,7 @@ unsigned int http_get_hdr(const struct http_msg *msg, const char *hname, int hle hist_ptr -= MAX_HDR_HISTORY; *vptr = ptr_hist[hist_ptr]; *vlen = len_hist[hist_ptr]; + return 1; } @@ -8327,7 +8413,7 @@ void http_end_txn(struct session *s) txn->uri = NULL; txn->srv_cookie = NULL; txn->cli_cookie = NULL; - + txn->geoloc = NULL; if (txn->req.cap) { struct cap_hdr *h; for (h = s->fe->req_cap; h; h = h->next) @@ -9339,8 +9425,9 @@ smp_fetch_hdr(struct proxy *px, struct session *l4, void *l7, unsigned int opt, smp->type = SMP_T_CSTR; smp->flags |= SMP_F_VOL_HDR; - if (http_get_hdr(msg, name_str, name_len, idx, occ, ctx, &smp->data.str.str, &smp->data.str.len)) + if (http_get_hdr(msg, name_str, name_len, idx, occ, ctx, &smp->data.str.str, &smp->data.str.len)) { return 1; + } smp->flags &= ~SMP_F_NOT_LAST; return 0; @@ -9398,9 +9485,8 @@ smp_fetch_hdr_val(struct proxy *px, struct session *l4, void *l7, unsigned int o * and an optional one of type int to designate a specific occurrence. * It returns an IPv4 or IPv6 address. */ -static int -smp_fetch_hdr_ip(struct proxy *px, struct session *l4, void *l7, unsigned int opt, - const struct arg *args, struct sample *smp) +int smp_fetch_hdr_ip(struct proxy *px, struct session *l4, void *l7, unsigned int opt, + const struct arg *args, struct sample *smp) { int ret; @@ -9419,7 +9505,6 @@ smp_fetch_hdr_ip(struct proxy *px, struct session *l4, void *l7, unsigned int op } } } - /* if the header doesn't match an IP address, fetch next one */ if (!(smp->flags & SMP_F_NOT_LAST)) return 0; @@ -9587,6 +9672,35 @@ smp_fetch_base32_src(struct proxy *px, struct session *l4, void *l7, unsigned in return 1; } + +static int +smp_fetch_geoloc(struct proxy *px, struct session *l4, void *l7, unsigned int opt, + const struct arg *args, struct sample *smp) +{ + struct http_txn *txn = l7; + + CHECK_HTTP_MESSAGE_FIRST(); + + if (!txn->geoloc) + return 0; + + strcpy(trash.str, txn->geoloc); + smp->type = SMP_T_STR; + smp->data.str.str = trash.str; + smp->data.str.len = strlen(trash.str); + + smp->flags = 0; + return 1; +} + +static int +acl_match_geoloc(struct sample *smp, struct acl_pattern *pattern) { + if (strcmp(pattern->ptr.str, "*") == 0) { + return ACL_PAT_PASS; + } + return acl_match_str(smp, pattern); +} + static int smp_fetch_proto_http(struct proxy *px, struct session *l4, void *l7, unsigned int opt, const struct arg *args, struct sample *smp) @@ -10125,6 +10239,8 @@ static struct acl_kw_list acl_kws = {{ },{ { "cook_reg", "req.cook", acl_parse_reg, acl_match_reg }, { "cook_sub", "req.cook", acl_parse_str, acl_match_sub }, + { "geoloc", "geoloc", acl_parse_str, acl_match_geoloc }, + { "hdr", "req.hdr", acl_parse_str, acl_match_str }, { "hdr_beg", "req.hdr", acl_parse_str, acl_match_beg }, { "hdr_dir", "req.hdr", acl_parse_str, acl_match_dir }, @@ -10207,6 +10323,8 @@ static struct sample_fetch_kw_list sample_fetch_keywords = {{ },{ { "cook_cnt", smp_fetch_cookie_cnt, ARG1(0,STR), NULL, SMP_T_UINT, SMP_USE_HRQHV }, { "cook_val", smp_fetch_cookie_val, ARG1(0,STR), NULL, SMP_T_UINT, SMP_USE_HRQHV }, + { "geoloc", smp_fetch_geoloc, 0, NULL, SMP_T_CSTR, SMP_USE_HRQHV }, + /* hdr is valid in both directions (eg: for "stick ...") but hdr_* are * only here to match the ACL's name, are request-only and are used for * ACL compatibility only. diff --git a/src/proto_tcp.c b/src/proto_tcp.c index bfce6a2..0632792 100644 --- a/src/proto_tcp.c +++ b/src/proto_tcp.c @@ -1537,9 +1537,8 @@ static int tcp_parse_tcp_req(char **args, int section_type, struct proxy *curpx, /************************************************************************/ /* fetch the connection's source IPv4/IPv6 address */ -static int -smp_fetch_src(struct proxy *px, struct session *l4, void *l7, unsigned int opt, - const struct arg *args, struct sample *smp) +int smp_fetch_src(struct proxy *px, struct session *l4, void *l7, unsigned int opt, + const struct arg *args, struct sample *smp) { switch (l4->si[0].conn->addr.from.ss_family) { case AF_INET: -- 1.8.3.1