mirror of
http://git.haproxy.org/git/haproxy.git/
synced 2025-04-11 03:31:36 +00:00
MEDIUM: tcp: add a new tcp-request capture directive
This new directive captures the specified fetch expression, converts it to text and puts it into the next capture slot. The capture slots are shared with header captures so that it is possible to dump all captures at once or selectively in logs and header processing. The purpose is to permit logs to contain whatever payload is found in a request, for example bytes at a fixed location or the SNI of forwarded SSL traffic.
This commit is contained in:
parent
3a4ac422ce
commit
18bf01e900
@ -7171,7 +7171,7 @@ tcp-request connection <action> [{if | unless} <condition>]
|
||||
accept the incoming connection. There is no specific limit to the number of
|
||||
rules which may be inserted.
|
||||
|
||||
Three types of actions are supported :
|
||||
Five types of actions are supported :
|
||||
- accept :
|
||||
accepts the connection if the condition is true (when used with "if")
|
||||
or false (when used with "unless"). The first such rule executed ends
|
||||
@ -7200,6 +7200,18 @@ tcp-request connection <action> [{if | unless} <condition>]
|
||||
of load balancers are passed through by traffic coming from public
|
||||
hosts.
|
||||
|
||||
- capture <sample> len <length> :
|
||||
This only applies to "tcp-request content" rules. It captures sample
|
||||
expression <sample> from the request buffer, and converts it to a
|
||||
string of at most <len> characters. The resulting string is stored into
|
||||
the next request "capture" slot, so it will possibly appear next to
|
||||
some captured HTTP headers. It will then automatically appear in the
|
||||
logs, and it will be possible to extract it using sample fetch rules to
|
||||
feed it into headers or anything. The length should be limited given
|
||||
that this size will be allocated for each capture during the whole
|
||||
session life. Since it applies to Please check section 7.3 (Fetching
|
||||
samples) and "capture request header" for more information.
|
||||
|
||||
- { track-sc0 | track-sc1 | track-sc2 } <key> [table <table>] :
|
||||
enables tracking of sticky counters from current connection. These
|
||||
rules do not stop evaluation and do not change default action. Two sets
|
||||
@ -7278,8 +7290,8 @@ tcp-request content <action> [{if | unless} <condition>]
|
||||
Arguments :
|
||||
<action> defines the action to perform if the condition applies. Valid
|
||||
actions include : "accept", "reject", "track-sc0", "track-sc1",
|
||||
and "track-sc2". See "tcp-request connection" above for their
|
||||
signification.
|
||||
"track-sc2" and "capture". See "tcp-request connection" above
|
||||
for their signification.
|
||||
|
||||
<condition> is a standard layer 4-7 ACL-based condition (see section 7).
|
||||
|
||||
@ -7307,9 +7319,10 @@ tcp-request content <action> [{if | unless} <condition>]
|
||||
contents. There is no specific limit to the number of rules which may be
|
||||
inserted.
|
||||
|
||||
Three types of actions are supported :
|
||||
- accept :
|
||||
- reject :
|
||||
Four types of actions are supported :
|
||||
- accept : the request is accepted
|
||||
- reject : the request is rejected and the connection is closed
|
||||
- capture : the specified sample expression is captured
|
||||
- { track-sc0 | track-sc1 | track-sc2 } <key> [table <table>]
|
||||
|
||||
They have the same meaning as their counter-parts in "tcp-request connection"
|
||||
|
130
src/proto_tcp.c
130
src/proto_tcp.c
@ -35,6 +35,7 @@
|
||||
#include <common/standard.h>
|
||||
|
||||
#include <types/global.h>
|
||||
#include <types/capture.h>
|
||||
#include <types/server.h>
|
||||
|
||||
#include <proto/acl.h>
|
||||
@ -990,13 +991,8 @@ int tcp_inspect_request(struct session *s, struct channel *req, int an_bit)
|
||||
|
||||
if (rule->cond) {
|
||||
ret = acl_exec_cond(rule->cond, s->be, s, &s->txn, SMP_OPT_DIR_REQ | partial);
|
||||
if (ret == ACL_TEST_MISS) {
|
||||
channel_dont_connect(req);
|
||||
/* just set the request timeout once at the beginning of the request */
|
||||
if (!tick_isset(req->analyse_exp) && s->be->tcp_req.inspect_delay)
|
||||
req->analyse_exp = tick_add(now_ms, s->be->tcp_req.inspect_delay);
|
||||
return 0;
|
||||
}
|
||||
if (ret == ACL_TEST_MISS)
|
||||
goto missing_data;
|
||||
|
||||
ret = acl_pass(ret);
|
||||
if (rule->cond->pol == ACL_COND_UNLESS)
|
||||
@ -1040,6 +1036,32 @@ int tcp_inspect_request(struct session *s, struct channel *req, int an_bit)
|
||||
stkctr_set_flags(&s->stkctr[tcp_trk_idx(rule->action)], STKCTR_TRACK_BACKEND);
|
||||
}
|
||||
}
|
||||
else if (rule->action == TCP_ACT_CAPTURE) {
|
||||
struct sample *key;
|
||||
struct cap_hdr *h = rule->act_prm.cap.hdr;
|
||||
char **cap = s->txn.req.cap;
|
||||
int len;
|
||||
|
||||
key = sample_fetch_string(s->be, s, &s->txn, SMP_OPT_DIR_REQ | partial, rule->act_prm.cap.expr);
|
||||
if (!key)
|
||||
continue;
|
||||
|
||||
if (key->flags & SMP_F_MAY_CHANGE)
|
||||
goto missing_data;
|
||||
|
||||
if (cap[h->index] == NULL)
|
||||
cap[h->index] = pool_alloc2(h->pool);
|
||||
|
||||
if (cap[h->index] == NULL) /* no more capture memory */
|
||||
continue;
|
||||
|
||||
len = key->data.str.len;
|
||||
if (len > h->len)
|
||||
len = h->len;
|
||||
|
||||
memcpy(cap[h->index], key->data.str.str, len);
|
||||
cap[h->index][len] = 0;
|
||||
}
|
||||
else {
|
||||
/* otherwise accept */
|
||||
break;
|
||||
@ -1053,6 +1075,14 @@ int tcp_inspect_request(struct session *s, struct channel *req, int an_bit)
|
||||
req->analysers &= ~an_bit;
|
||||
req->analyse_exp = TICK_ETERNITY;
|
||||
return 1;
|
||||
|
||||
missing_data:
|
||||
channel_dont_connect(req);
|
||||
/* just set the request timeout once at the beginning of the request */
|
||||
if (!tick_isset(req->analyse_exp) && s->be->tcp_req.inspect_delay)
|
||||
req->analyse_exp = tick_add(now_ms, s->be->tcp_req.inspect_delay);
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
/* This function performs the TCP response analysis on the current response. It
|
||||
@ -1287,6 +1317,92 @@ static int tcp_parse_request_rule(char **args, int arg, int section_type,
|
||||
arg++;
|
||||
rule->action = TCP_ACT_REJECT;
|
||||
}
|
||||
else if (strcmp(args[arg], "capture") == 0) {
|
||||
struct sample_expr *expr;
|
||||
struct cap_hdr *hdr;
|
||||
int kw = arg;
|
||||
int len = 0;
|
||||
|
||||
if (!(curpx->cap & PR_CAP_FE)) {
|
||||
memprintf(err,
|
||||
"'%s %s %s' : proxy '%s' has no frontend capability",
|
||||
args[0], args[1], args[kw], curpx->id);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!(where & SMP_VAL_FE_REQ_CNT)) {
|
||||
memprintf(err,
|
||||
"'%s %s' is not allowed in '%s %s' rules in %s '%s'",
|
||||
args[arg], args[arg+1], args[0], args[1], proxy_type_str(curpx), curpx->id);
|
||||
return -1;
|
||||
}
|
||||
|
||||
arg++;
|
||||
|
||||
curpx->conf.args.ctx = ARGC_CAP;
|
||||
expr = sample_parse_expr(args, &arg, file, line, err, &curpx->conf.args);
|
||||
if (!expr) {
|
||||
memprintf(err,
|
||||
"'%s %s %s' : %s",
|
||||
args[0], args[1], args[kw], *err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!(expr->fetch->val & where)) {
|
||||
memprintf(err,
|
||||
"'%s %s %s' : fetch method '%s' extracts information from '%s', none of which is available here",
|
||||
args[0], args[1], args[kw], args[arg-1], sample_src_names(expr->fetch->use));
|
||||
free(expr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (strcmp(args[arg], "len") == 0) {
|
||||
arg++;
|
||||
if (!args[arg]) {
|
||||
memprintf(err,
|
||||
"'%s %s %s' : missing length value",
|
||||
args[0], args[1], args[kw]);
|
||||
free(expr);
|
||||
return -1;
|
||||
}
|
||||
/* we copy the table name for now, it will be resolved later */
|
||||
len = atoi(args[arg]);
|
||||
if (len <= 0) {
|
||||
memprintf(err,
|
||||
"'%s %s %s' : length must be > 0",
|
||||
args[0], args[1], args[kw]);
|
||||
free(expr);
|
||||
return -1;
|
||||
}
|
||||
arg++;
|
||||
}
|
||||
|
||||
if (!len) {
|
||||
memprintf(err,
|
||||
"'%s %s %s' : a positive 'len' argument is mandatory",
|
||||
args[0], args[1], args[kw]);
|
||||
free(expr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
hdr = calloc(sizeof(struct cap_hdr), 1);
|
||||
hdr->next = curpx->req_cap;
|
||||
hdr->name = NULL; /* not a header capture */
|
||||
hdr->namelen = 0;
|
||||
hdr->len = len;
|
||||
hdr->pool = create_pool("caphdr", hdr->len + 1, MEM_F_SHARED);
|
||||
hdr->index = curpx->nb_req_cap++;
|
||||
|
||||
curpx->req_cap = hdr;
|
||||
curpx->to_log |= LW_REQHDR;
|
||||
|
||||
/* check if we need to allocate an hdr_idx struct for HTTP parsing */
|
||||
curpx->http_needed |= !!(expr->fetch->use & SMP_USE_HTTP_ANY);
|
||||
|
||||
rule->act_prm.cap.expr = expr;
|
||||
rule->act_prm.cap.hdr = hdr;
|
||||
rule->action = TCP_ACT_CAPTURE;
|
||||
}
|
||||
else if (strncmp(args[arg], "track-sc", 8) == 0 &&
|
||||
args[arg][9] == '\0' && args[arg][8] >= '0' &&
|
||||
args[arg][8] <= '0' + MAX_SESS_STKCTR) { /* track-sc 0..9 */
|
||||
|
Loading…
Reference in New Issue
Block a user