From: William Lallemand Date: Wed, 25 May 2016 00:34:07 +0000 (+0200) Subject: MEDIUM: tcp/http: new set-dst/set-dst-port actions X-Git-Tag: v1.7-dev4~84 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=13e9b0c9ed968e55612183127161ed84f4970bbb;p=thirdparty%2Fhaproxy.git MEDIUM: tcp/http: new set-dst/set-dst-port actions Like 'set-src' and 'set-src-port' but for destination address and port. It's available in 'tcp-request connection' and 'http-request' actions. --- diff --git a/doc/configuration.txt b/doc/configuration.txt index d3ff22341b..678be4419c 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -3860,6 +3860,34 @@ http-request { allow | deny | tarpit | auth [realm ] | redirect | Be careful to use "set-src-port" after "set-src", because "set-src" sets the source port to 0. + - set-dst : + Is used to set the destination IP address to the value of specified + expression. Useful when a proxy in front of HAProxy rewrites destination + IP, but provides the correct IP in a HTTP header; or you want to mask + the IP for privacy. If you want to connect to the new address/port, use + '0.0.0.0:0' as a server address in the backend. + + Is a standard HAProxy expression formed by a sample-fetch + followed by some converters. + + Example: + + http-request set-dst hdr(x-dst) + http-request set-dst dst,ipmask(24) + + - set-dst-port : + Is used to set the destination port address to the value of specified + expression. If you want to connect to the new address/port, use + '0.0.0.0:0' as a server address in the backend. + + Is a standard HAProxy expression formed by a sample-fetch + followed by some converters. + + Example: + + http-request set-dst-port hdr(x-port) + http-request set-dst-port int(4000) + - "silent-drop" : this stops the evaluation of the rules and makes the client-facing connection suddenly disappear using a system-dependant way that tries to prevent the client from being notified. The effect it then @@ -8718,6 +8746,34 @@ tcp-request connection [{if | unless} ] Be careful to use "set-src-port" after "set-src", because "set-src" sets the source port to 0. + - set-dst : + Is used to set the destination IP address to the value of specified + expression. Useful if you want to mask IP for privacy in log. + If you want to provide an IP from a HTTP header use "http-request + set-dst". If you want to connect to the new address/port, use + '0.0.0.0:0' as a server address in the backend. + + Is a standard HAProxy expression formed by a sample-fetch + followed by some converters. + + Example: + + tcp-request connection set-dst dst,ipmask(24) + tcp-request connection set-dst ipv4(10.0.0.1) + + - set-dst-port : + Is used to set the destination port address to the value of specified + expression. If you want to connect to the new address/port, use + '0.0.0.0:0' as a server address in the backend. + + + Is a standard HAProxy expression formed by a sample-fetch + followed by some converters. + + Example: + + tcp-request connection set-dst-port int(4000) + - "silent-drop" : This stops the evaluation of the rules and makes the client-facing connection suddenly disappear using a system-dependant way that tries diff --git a/src/proto_tcp.c b/src/proto_tcp.c index 99438d8e6a..53447037d9 100644 --- a/src/proto_tcp.c +++ b/src/proto_tcp.c @@ -1453,6 +1453,33 @@ enum act_return tcp_action_req_set_src(struct act_rule *rule, struct proxy *px, return ACT_RET_CONT; } +/* + * Execute the "set-dst" action. May be called from {tcp,http}request + */ +enum act_return tcp_action_req_set_dst(struct act_rule *rule, struct proxy *px, + struct session *sess, struct stream *s, int flags) +{ + struct connection *cli_conn; + + if ((cli_conn = objt_conn(sess->origin)) && conn_ctrl_ready(cli_conn)) { + struct sample *smp; + + smp = sample_fetch_as_type(px, sess, s, SMP_OPT_DIR_REQ|SMP_OPT_FINAL, rule->arg.expr, SMP_T_ADDR); + if (smp) { + if (smp->data.type == SMP_T_IPV4) { + ((struct sockaddr_in *)&cli_conn->addr.to)->sin_family = AF_INET; + ((struct sockaddr_in *)&cli_conn->addr.to)->sin_addr.s_addr = smp->data.u.ipv4.s_addr; + } else if (smp->data.type == SMP_T_IPV6) { + ((struct sockaddr_in6 *)&cli_conn->addr.to)->sin6_family = AF_INET6; + memcpy(&((struct sockaddr_in6 *)&cli_conn->addr.to)->sin6_addr, &smp->data.u.ipv6, sizeof(struct in6_addr)); + ((struct sockaddr_in6 *)&cli_conn->addr.to)->sin6_port = 0; + } + cli_conn->flags |= CO_FL_ADDR_TO_SET; + } + } + return ACT_RET_CONT; +} + /* * Execute the "set-src-port" action. May be called from {tcp,http}request * We must test the sin_family before setting the port @@ -1479,6 +1506,32 @@ enum act_return tcp_action_req_set_src_port(struct act_rule *rule, struct proxy return ACT_RET_CONT; } +/* + * Execute the "set-dst-port" action. May be called from {tcp,http}request + * We must test the sin_family before setting the port + */ +enum act_return tcp_action_req_set_dst_port(struct act_rule *rule, struct proxy *px, + struct session *sess, struct stream *s, int flags) +{ + struct connection *cli_conn; + + if ((cli_conn = objt_conn(sess->origin)) && conn_ctrl_ready(cli_conn)) { + struct sample *smp; + + conn_get_to_addr(cli_conn); + + smp = sample_fetch_as_type(px, sess, s, SMP_OPT_DIR_REQ|SMP_OPT_FINAL, rule->arg.expr, SMP_T_SINT); + if (smp) { + if (((struct sockaddr_storage *)&cli_conn->addr.to)->ss_family == AF_INET) { + ((struct sockaddr_in *)&cli_conn->addr.to)->sin_port = htons(smp->data.u.sint); + } else if (((struct sockaddr_storage *)&cli_conn->addr.to)->ss_family == AF_INET6) { + ((struct sockaddr_in6 *)&cli_conn->addr.to)->sin6_port = htons(smp->data.u.sint); + } + } + } + return ACT_RET_CONT; +} + /* Executes the "silent-drop" action. May be called from {tcp,http}{request,response} */ static enum act_return tcp_exec_action_silent_drop(struct act_rule *rule, struct proxy *px, struct session *sess, struct stream *strm, int flags) { @@ -2087,8 +2140,8 @@ static int tcp_parse_tcp_req(char **args, int section_type, struct proxy *curpx, return -1; } -/* parse "set-src" and "set-src-port" actions */ -enum act_parse_ret tcp_parse_set_src(const char **args, int *orig_arg, struct proxy *px, struct act_rule *rule, char **err) +/* parse "set-{src,dst}[-port]" action */ +enum act_parse_ret tcp_parse_set_src_dst(const char **args, int *orig_arg, struct proxy *px, struct act_rule *rule, char **err) { int cur_arg; struct sample_expr *expr; @@ -2119,6 +2172,10 @@ enum act_parse_ret tcp_parse_set_src(const char **args, int *orig_arg, struct pr rule->action_ptr = tcp_action_req_set_src; } else if (!strcmp(args[*orig_arg-1], "set-src-port")) { rule->action_ptr = tcp_action_req_set_src_port; + } else if (!strcmp(args[*orig_arg-1], "set-dst")) { + rule->action_ptr = tcp_action_req_set_dst; + } else if (!strcmp(args[*orig_arg-1], "set-dst-port")) { + rule->action_ptr = tcp_action_req_set_dst_port; } else { return ACT_RET_PRS_ERR; } @@ -2520,8 +2577,10 @@ static struct srv_kw_list srv_kws = { "TCP", { }, { static struct action_kw_list tcp_req_conn_actions = {ILH, { { "silent-drop", tcp_parse_silent_drop }, - { "set-src", tcp_parse_set_src }, - { "set-src-port", tcp_parse_set_src }, + { "set-src", tcp_parse_set_src_dst }, + { "set-src-port", tcp_parse_set_src_dst }, + { "set-dst" , tcp_parse_set_src_dst }, + { "set-dst-port", tcp_parse_set_src_dst }, { /* END */ } }}; @@ -2537,8 +2596,10 @@ static struct action_kw_list tcp_res_cont_actions = {ILH, { static struct action_kw_list http_req_actions = {ILH, { { "silent-drop", tcp_parse_silent_drop }, - { "set-src", tcp_parse_set_src }, - { "set-src-port", tcp_parse_set_src }, + { "set-src", tcp_parse_set_src_dst }, + { "set-src-port", tcp_parse_set_src_dst }, + { "set-dst", tcp_parse_set_src_dst }, + { "set-dst-port", tcp_parse_set_src_dst }, { /* END */ } }};