From 4f0d919bd4951d2f22f2334f694a39d5d940aa10 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Tue, 11 Jun 2013 20:40:55 +0200 Subject: [PATCH] MEDIUM: tcp: add "tcp-request connection expect-proxy layer4" This configures the client-facing connection to receive a PROXY protocol header before any byte is read from the socket. This is equivalent to having the "accept-proxy" keyword on the "bind" line, except that using the TCP rule allows the PROXY protocol to be accepted only for certain IP address ranges using an ACL. This is convenient when multiple layers of load balancers are passed through by traffic coming from public hosts. --- doc/configuration.txt | 18 ++++++++++++++++-- include/types/proto_tcp.h | 7 ++++--- src/proto_tcp.c | 22 ++++++++++++++++++++++ 3 files changed, 42 insertions(+), 5 deletions(-) diff --git a/doc/configuration.txt b/doc/configuration.txt index a04c6f763..13e136d57 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -6418,7 +6418,7 @@ tcp-request connection [{if | unless} ] Arguments : defines the action to perform if the condition applies. Valid actions include : "accept", "reject", "track-sc1", "track-sc2", - and "track-sc3". See below for more details. + "track-sc3", and "expect-proxy". See below for more details. is a standard layer4-only ACL-based condition (see section 7). @@ -6456,6 +6456,15 @@ tcp-request connection [{if | unless} ] logging is absolutely desired, then "tcp-request content" rules should be used instead. + - expect-proxy layer4 : + configures the client-facing connection to receive a PROXY protocol + header before any byte is read from the socket. This is equivalent to + having the "accept-proxy" keyword on the "bind" line, except that using + the TCP rule allows the PROXY protocol to be accepted only for certain + IP address ranges using an ACL. This is convenient when multiple layers + of load balancers are passed through by traffic coming from public + hosts. + - { track-sc1 | track-sc2 | track-sc3 } [table ] : enables tracking of sticky counters from current connection. These rules do not stop evaluation and do not change default action. Two sets @@ -6516,6 +6525,10 @@ tcp-request connection [{if | unless} ] tcp-request connection track-sc1 src tcp-request connection reject if { sc1_conn_rate gt 10 } + Example: enable the PROXY protocol for traffic coming from all known proxies. + + tcp-request connection expect-proxy layer4 if { src -f proxies.lst } + See section 7 about ACL usage. See also : "tcp-request content", "stick-table" @@ -7267,7 +7280,8 @@ accept-proxy address will still be used. This keyword combined with support from external components can be used as an efficient and reliable alternative to the X-Forwarded-For mechanism which is not always reliable and not even always - usable. + usable. See also "tcp-request connection expect-proxy" for a finer-grained + setting of which client is allowed to use the protocol. alpn This enables the TLS ALPN extension and advertises the specified protocol diff --git a/include/types/proto_tcp.h b/include/types/proto_tcp.h index ac9d328b5..c9fd1e4a6 100644 --- a/include/types/proto_tcp.h +++ b/include/types/proto_tcp.h @@ -32,9 +32,10 @@ enum { TCP_ACT_ACCEPT = 1, TCP_ACT_REJECT = 2, - TCP_ACT_TRK_SC1 = 3, /* TCP request tracking : must be contiguous */ - TCP_ACT_TRK_SC2 = 4, - TCP_ACT_TRK_SC3 = 5, + TCP_ACT_EXPECT_PX = 3, + TCP_ACT_TRK_SC1 = 4, /* TCP request tracking : must be contiguous */ + TCP_ACT_TRK_SC2 = 5, + TCP_ACT_TRK_SC3 = 6, }; struct tcp_rule { diff --git a/src/proto_tcp.c b/src/proto_tcp.c index 049988c4e..956f803b5 100644 --- a/src/proto_tcp.c +++ b/src/proto_tcp.c @@ -1105,6 +1105,10 @@ int tcp_exec_req_rules(struct session *s) if (key && (ts = stktable_get_entry(t, key))) session_track_stkctr(&s->stkctr[tcp_trk_idx(rule->action)], t, ts); } + else if (rule->action == TCP_ACT_EXPECT_PX) { + s->si[0].conn->flags |= CO_FL_ACCEPT_PROXY; + conn_sock_want_recv(s->si[0].conn); + } else { /* otherwise it's an accept */ break; @@ -1222,6 +1226,24 @@ static int tcp_parse_request_rule(char **args, int arg, int section_type, rule->act_prm.trk_ctr.expr = expr; rule->action = TCP_ACT_TRK_SC1 + args[kw][8] - '1'; } + else if (strcmp(args[arg], "expect-proxy") == 0) { + if (strcmp(args[arg+1], "layer4") != 0) { + memprintf(err, + "'%s %s %s' only supports 'layer4' in %s '%s' (got '%s')", + args[0], args[1], args[arg], proxy_type_str(curpx), curpx->id, args[arg+1]); + return -1; + } + + if (!(where & SMP_VAL_FE_CON_ACC)) { + 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 += 2; + rule->action = TCP_ACT_EXPECT_PX; + } else { memprintf(err, "'%s %s' expects 'accept', 'reject', 'track-sc1', 'track-sc2' "