From: Willy Tarreau Date: Fri, 28 Aug 2020 09:03:28 +0000 (+0200) Subject: REORG: tcp: move TCP actions from proto_tcp.c to tcp_act.c X-Git-Tag: v2.3-dev4~66 X-Git-Url: http://git.haproxy.org/?a=commitdiff_plain;h=aeae66cf22527299c7187e0d498361073cf2a854;p=haproxy-2.5.git REORG: tcp: move TCP actions from proto_tcp.c to tcp_act.c The file proto_tcp.c has become a real mess because it still contains tons of definitions that have nothing to do with the TCP protocol setup. This commit moves the ruleset actions "set-src-port", "set-dst-port", "set-src", "set-dst", and "silent-drop" to a new file "tcp_act.c". Nothing has changed beyond this. --- diff --git a/Makefile b/Makefile index d4c96a2..be916a9 100644 --- a/Makefile +++ b/Makefile @@ -809,7 +809,7 @@ OBJS = src/mux_fcgi.o src/mux_h1.o src/mux_h2.o src/backend.o \ src/task.o src/ring.o src/vars.o src/trace.o src/mux_pt.o \ src/xxhash.o src/mworker-prog.o src/h1_htx.o src/frontend.o \ src/extcheck.o src/channel.o src/action.o src/mailers.o \ - src/proto_sockpair.o src/ebmbtree.o src/thread.o \ + src/tcp_act.o src/proto_sockpair.o src/ebmbtree.o src/thread.o \ src/lb_fwrr.o src/time.o src/regex.o src/lb_fwlc.o \ src/htx.o src/h2.o src/hpack-tbl.o src/lru.o src/wdt.o \ src/lb_map.o src/eb32sctree.o src/ebistree.o src/h1.o \ diff --git a/src/proto_tcp.c b/src/proto_tcp.c index 98a6310..b2733d6 100644 --- a/src/proto_tcp.c +++ b/src/proto_tcp.c @@ -30,7 +30,6 @@ #include #include -#include #include #include #include @@ -1207,254 +1206,6 @@ int tcp_pause_listener(struct listener *l) return 1; } -/* - * Execute the "set-src" action. May be called from {tcp,http}request. - * It only changes the address and tries to preserve the original port. If the - * previous family was neither AF_INET nor AF_INET6, the port is set to zero. - */ -enum act_return tcp_action_req_set_src(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_get_src(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) { - int port = get_net_port(cli_conn->src); - - if (smp->data.type == SMP_T_IPV4) { - ((struct sockaddr_in *)cli_conn->src)->sin_family = AF_INET; - ((struct sockaddr_in *)cli_conn->src)->sin_addr.s_addr = smp->data.u.ipv4.s_addr; - ((struct sockaddr_in *)cli_conn->src)->sin_port = port; - } else if (smp->data.type == SMP_T_IPV6) { - ((struct sockaddr_in6 *)cli_conn->src)->sin6_family = AF_INET6; - memcpy(&((struct sockaddr_in6 *)cli_conn->src)->sin6_addr, &smp->data.u.ipv6, sizeof(struct in6_addr)); - ((struct sockaddr_in6 *)cli_conn->src)->sin6_port = port; - } - } - cli_conn->flags |= CO_FL_ADDR_FROM_SET; - } - return ACT_RET_CONT; -} - -/* - * Execute the "set-dst" action. May be called from {tcp,http}request. - * It only changes the address and tries to preserve the original port. If the - * previous family was neither AF_INET nor AF_INET6, the port is set to zero. - */ -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_get_dst(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) { - int port = get_net_port(cli_conn->dst); - - if (smp->data.type == SMP_T_IPV4) { - ((struct sockaddr_in *)cli_conn->dst)->sin_family = AF_INET; - ((struct sockaddr_in *)cli_conn->dst)->sin_addr.s_addr = smp->data.u.ipv4.s_addr; - } else if (smp->data.type == SMP_T_IPV6) { - ((struct sockaddr_in6 *)cli_conn->dst)->sin6_family = AF_INET6; - memcpy(&((struct sockaddr_in6 *)cli_conn->dst)->sin6_addr, &smp->data.u.ipv6, sizeof(struct in6_addr)); - ((struct sockaddr_in6 *)cli_conn->dst)->sin6_port = port; - } - 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. If the address family - * is neither AF_INET nor AF_INET6, the address is forced to AF_INET "0.0.0.0" - * and the port is assigned. - */ -enum act_return tcp_action_req_set_src_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_get_src(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_SINT); - if (smp) { - if (cli_conn->src->ss_family == AF_INET6) { - ((struct sockaddr_in6 *)cli_conn->src)->sin6_port = htons(smp->data.u.sint); - } else { - if (cli_conn->src->ss_family != AF_INET) { - cli_conn->src->ss_family = AF_INET; - ((struct sockaddr_in *)cli_conn->src)->sin_addr.s_addr = 0; - } - ((struct sockaddr_in *)cli_conn->src)->sin_port = htons(smp->data.u.sint); - } - } - } - 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. If the address family - * is neither AF_INET nor AF_INET6, the address is forced to AF_INET "0.0.0.0" - * and the port is assigned. - */ -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_get_dst(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_SINT); - if (smp) { - if (cli_conn->dst->ss_family == AF_INET6) { - ((struct sockaddr_in6 *)cli_conn->dst)->sin6_port = htons(smp->data.u.sint); - } else { - if (cli_conn->dst->ss_family != AF_INET) { - cli_conn->dst->ss_family = AF_INET; - ((struct sockaddr_in *)cli_conn->dst)->sin_addr.s_addr = 0; - } - ((struct sockaddr_in *)cli_conn->dst)->sin_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) -{ - struct connection *conn = objt_conn(sess->origin); - - if (!conn) - goto out; - - if (!conn_ctrl_ready(conn)) - goto out; - -#ifdef TCP_QUICKACK - /* drain is needed only to send the quick ACK */ - conn_sock_drain(conn); - - /* re-enable quickack if it was disabled to ack all data and avoid - * retransmits from the client that might trigger a real reset. - */ - setsockopt(conn->handle.fd, SOL_TCP, TCP_QUICKACK, &one, sizeof(one)); -#endif - /* lingering must absolutely be disabled so that we don't send a - * shutdown(), this is critical to the TCP_REPAIR trick. When no stream - * is present, returning with ERR will cause lingering to be disabled. - */ - if (strm) - strm->si[0].flags |= SI_FL_NOLINGER; - - /* We're on the client-facing side, we must force to disable lingering to - * ensure we will use an RST exclusively and kill any pending data. - */ - fdtab[conn->handle.fd].linger_risk = 1; - -#ifdef TCP_REPAIR - if (setsockopt(conn->handle.fd, SOL_TCP, TCP_REPAIR, &one, sizeof(one)) == 0) { - /* socket will be quiet now */ - goto out; - } -#endif - /* either TCP_REPAIR is not defined or it failed (eg: permissions). - * Let's fall back on the TTL trick, though it only works for routed - * network and has no effect on local net. - */ -#ifdef IP_TTL - setsockopt(conn->handle.fd, SOL_IP, IP_TTL, &one, sizeof(one)); -#endif - out: - /* kill the stream if any */ - if (strm) { - channel_abort(&strm->req); - channel_abort(&strm->res); - strm->req.analysers &= AN_REQ_FLT_END; - strm->res.analysers &= AN_RES_FLT_END; - if (strm->flags & SF_BE_ASSIGNED) - _HA_ATOMIC_ADD(&strm->be->be_counters.denied_req, 1); - if (!(strm->flags & SF_ERR_MASK)) - strm->flags |= SF_ERR_PRXCOND; - if (!(strm->flags & SF_FINST_MASK)) - strm->flags |= SF_FINST_R; - } - - _HA_ATOMIC_ADD(&sess->fe->fe_counters.denied_req, 1); - if (sess->listener->counters) - _HA_ATOMIC_ADD(&sess->listener->counters->denied_req, 1); - - return ACT_RET_ABRT; -} - -/* 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; - unsigned int where; - - cur_arg = *orig_arg; - expr = sample_parse_expr((char **)args, &cur_arg, px->conf.args.file, px->conf.args.line, err, &px->conf.args, NULL); - if (!expr) - return ACT_RET_PRS_ERR; - - where = 0; - if (px->cap & PR_CAP_FE) - where |= SMP_VAL_FE_HRQ_HDR; - if (px->cap & PR_CAP_BE) - where |= SMP_VAL_BE_HRQ_HDR; - - if (!(expr->fetch->val & where)) { - memprintf(err, - "fetch method '%s' extracts information from '%s', none of which is available here", - args[cur_arg-1], sample_src_names(expr->fetch->use)); - free(expr); - return ACT_RET_PRS_ERR; - } - rule->arg.expr = expr; - rule->action = ACT_CUSTOM; - - if (!strcmp(args[*orig_arg-1], "set-src")) { - 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; - } - - (*orig_arg)++; - - return ACT_RET_PRS_OK; -} - - -/* Parse a "silent-drop" action. It takes no argument. It returns ACT_RET_PRS_OK on - * success, ACT_RET_PRS_ERR on error. - */ -static enum act_parse_ret tcp_parse_silent_drop(const char **args, int *orig_arg, struct proxy *px, - struct act_rule *rule, char **err) -{ - rule->action = ACT_CUSTOM; - rule->action_ptr = tcp_exec_action_silent_drop; - return ACT_RET_PRS_OK; -} - - /************************************************************************/ /* All supported sample fetch functions must be declared here */ /************************************************************************/ @@ -2101,61 +1852,6 @@ static struct srv_kw_list srv_kws = { "TCP", { }, { INITCALL1(STG_REGISTER, srv_register_keywords, &srv_kws); -static struct action_kw_list tcp_req_conn_actions = {ILH, { - { "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 }, - { "silent-drop", tcp_parse_silent_drop }, - { /* END */ } -}}; - -INITCALL1(STG_REGISTER, tcp_req_conn_keywords_register, &tcp_req_conn_actions); - -static struct action_kw_list tcp_req_sess_actions = {ILH, { - { "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 }, - { "silent-drop", tcp_parse_silent_drop }, - { /* END */ } -}}; - -INITCALL1(STG_REGISTER, tcp_req_sess_keywords_register, &tcp_req_sess_actions); - -static struct action_kw_list tcp_req_cont_actions = {ILH, { - { "set-dst" , tcp_parse_set_src_dst }, - { "set-dst-port", tcp_parse_set_src_dst }, - { "silent-drop", tcp_parse_silent_drop }, - { /* END */ } -}}; - -INITCALL1(STG_REGISTER, tcp_req_cont_keywords_register, &tcp_req_cont_actions); - -static struct action_kw_list tcp_res_cont_actions = {ILH, { - { "silent-drop", tcp_parse_silent_drop }, - { /* END */ } -}}; - -INITCALL1(STG_REGISTER, tcp_res_cont_keywords_register, &tcp_res_cont_actions); - -static struct action_kw_list http_req_actions = {ILH, { - { "silent-drop", tcp_parse_silent_drop }, - { "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 */ } -}}; - -INITCALL1(STG_REGISTER, http_req_keywords_register, &http_req_actions); - -static struct action_kw_list http_res_actions = {ILH, { - { "silent-drop", tcp_parse_silent_drop }, - { /* END */ } -}}; - -INITCALL1(STG_REGISTER, http_res_keywords_register, &http_res_actions); REGISTER_BUILD_OPTS("Built with transparent proxy support using:" #if defined(IP_TRANSPARENT) diff --git a/src/tcp_act.c b/src/tcp_act.c new file mode 100644 index 0000000..182234f --- /dev/null +++ b/src/tcp_act.c @@ -0,0 +1,354 @@ +/* + * AF_INET/AF_INET6 SOCK_STREAM protocol layer (tcp) + * + * Copyright 2000-2013 Willy Tarreau + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Execute the "set-src" action. May be called from {tcp,http}request. + * It only changes the address and tries to preserve the original port. If the + * previous family was neither AF_INET nor AF_INET6, the port is set to zero. + */ +static enum act_return tcp_action_req_set_src(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_get_src(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) { + int port = get_net_port(cli_conn->src); + + if (smp->data.type == SMP_T_IPV4) { + ((struct sockaddr_in *)cli_conn->src)->sin_family = AF_INET; + ((struct sockaddr_in *)cli_conn->src)->sin_addr.s_addr = smp->data.u.ipv4.s_addr; + ((struct sockaddr_in *)cli_conn->src)->sin_port = port; + } else if (smp->data.type == SMP_T_IPV6) { + ((struct sockaddr_in6 *)cli_conn->src)->sin6_family = AF_INET6; + memcpy(&((struct sockaddr_in6 *)cli_conn->src)->sin6_addr, &smp->data.u.ipv6, sizeof(struct in6_addr)); + ((struct sockaddr_in6 *)cli_conn->src)->sin6_port = port; + } + } + cli_conn->flags |= CO_FL_ADDR_FROM_SET; + } + return ACT_RET_CONT; +} + +/* + * Execute the "set-dst" action. May be called from {tcp,http}request. + * It only changes the address and tries to preserve the original port. If the + * previous family was neither AF_INET nor AF_INET6, the port is set to zero. + */ +static 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_get_dst(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) { + int port = get_net_port(cli_conn->dst); + + if (smp->data.type == SMP_T_IPV4) { + ((struct sockaddr_in *)cli_conn->dst)->sin_family = AF_INET; + ((struct sockaddr_in *)cli_conn->dst)->sin_addr.s_addr = smp->data.u.ipv4.s_addr; + } else if (smp->data.type == SMP_T_IPV6) { + ((struct sockaddr_in6 *)cli_conn->dst)->sin6_family = AF_INET6; + memcpy(&((struct sockaddr_in6 *)cli_conn->dst)->sin6_addr, &smp->data.u.ipv6, sizeof(struct in6_addr)); + ((struct sockaddr_in6 *)cli_conn->dst)->sin6_port = port; + } + 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. If the address family + * is neither AF_INET nor AF_INET6, the address is forced to AF_INET "0.0.0.0" + * and the port is assigned. + */ +static enum act_return tcp_action_req_set_src_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_get_src(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_SINT); + if (smp) { + if (cli_conn->src->ss_family == AF_INET6) { + ((struct sockaddr_in6 *)cli_conn->src)->sin6_port = htons(smp->data.u.sint); + } else { + if (cli_conn->src->ss_family != AF_INET) { + cli_conn->src->ss_family = AF_INET; + ((struct sockaddr_in *)cli_conn->src)->sin_addr.s_addr = 0; + } + ((struct sockaddr_in *)cli_conn->src)->sin_port = htons(smp->data.u.sint); + } + } + } + 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. If the address family + * is neither AF_INET nor AF_INET6, the address is forced to AF_INET "0.0.0.0" + * and the port is assigned. + */ +static 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_get_dst(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_SINT); + if (smp) { + if (cli_conn->dst->ss_family == AF_INET6) { + ((struct sockaddr_in6 *)cli_conn->dst)->sin6_port = htons(smp->data.u.sint); + } else { + if (cli_conn->dst->ss_family != AF_INET) { + cli_conn->dst->ss_family = AF_INET; + ((struct sockaddr_in *)cli_conn->dst)->sin_addr.s_addr = 0; + } + ((struct sockaddr_in *)cli_conn->dst)->sin_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) +{ + struct connection *conn = objt_conn(sess->origin); + + if (!conn) + goto out; + + if (!conn_ctrl_ready(conn)) + goto out; + +#ifdef TCP_QUICKACK + /* drain is needed only to send the quick ACK */ + conn_sock_drain(conn); + + /* re-enable quickack if it was disabled to ack all data and avoid + * retransmits from the client that might trigger a real reset. + */ + setsockopt(conn->handle.fd, SOL_TCP, TCP_QUICKACK, &one, sizeof(one)); +#endif + /* lingering must absolutely be disabled so that we don't send a + * shutdown(), this is critical to the TCP_REPAIR trick. When no stream + * is present, returning with ERR will cause lingering to be disabled. + */ + if (strm) + strm->si[0].flags |= SI_FL_NOLINGER; + + /* We're on the client-facing side, we must force to disable lingering to + * ensure we will use an RST exclusively and kill any pending data. + */ + fdtab[conn->handle.fd].linger_risk = 1; + +#ifdef TCP_REPAIR + if (setsockopt(conn->handle.fd, SOL_TCP, TCP_REPAIR, &one, sizeof(one)) == 0) { + /* socket will be quiet now */ + goto out; + } +#endif + /* either TCP_REPAIR is not defined or it failed (eg: permissions). + * Let's fall back on the TTL trick, though it only works for routed + * network and has no effect on local net. + */ +#ifdef IP_TTL + setsockopt(conn->handle.fd, SOL_IP, IP_TTL, &one, sizeof(one)); +#endif + out: + /* kill the stream if any */ + if (strm) { + channel_abort(&strm->req); + channel_abort(&strm->res); + strm->req.analysers &= AN_REQ_FLT_END; + strm->res.analysers &= AN_RES_FLT_END; + if (strm->flags & SF_BE_ASSIGNED) + _HA_ATOMIC_ADD(&strm->be->be_counters.denied_req, 1); + if (!(strm->flags & SF_ERR_MASK)) + strm->flags |= SF_ERR_PRXCOND; + if (!(strm->flags & SF_FINST_MASK)) + strm->flags |= SF_FINST_R; + } + + _HA_ATOMIC_ADD(&sess->fe->fe_counters.denied_req, 1); + if (sess->listener->counters) + _HA_ATOMIC_ADD(&sess->listener->counters->denied_req, 1); + + return ACT_RET_ABRT; +} + +/* parse "set-{src,dst}[-port]" action */ +static 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; + unsigned int where; + + cur_arg = *orig_arg; + expr = sample_parse_expr((char **)args, &cur_arg, px->conf.args.file, px->conf.args.line, err, &px->conf.args, NULL); + if (!expr) + return ACT_RET_PRS_ERR; + + where = 0; + if (px->cap & PR_CAP_FE) + where |= SMP_VAL_FE_HRQ_HDR; + if (px->cap & PR_CAP_BE) + where |= SMP_VAL_BE_HRQ_HDR; + + if (!(expr->fetch->val & where)) { + memprintf(err, + "fetch method '%s' extracts information from '%s', none of which is available here", + args[cur_arg-1], sample_src_names(expr->fetch->use)); + free(expr); + return ACT_RET_PRS_ERR; + } + rule->arg.expr = expr; + rule->action = ACT_CUSTOM; + + if (!strcmp(args[*orig_arg-1], "set-src")) { + 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; + } + + (*orig_arg)++; + + return ACT_RET_PRS_OK; +} + + +/* Parse a "silent-drop" action. It takes no argument. It returns ACT_RET_PRS_OK on + * success, ACT_RET_PRS_ERR on error. + */ +static enum act_parse_ret tcp_parse_silent_drop(const char **args, int *orig_arg, struct proxy *px, + struct act_rule *rule, char **err) +{ + rule->action = ACT_CUSTOM; + rule->action_ptr = tcp_exec_action_silent_drop; + return ACT_RET_PRS_OK; +} + + +static struct action_kw_list tcp_req_conn_actions = {ILH, { + { "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 }, + { "silent-drop", tcp_parse_silent_drop }, + { /* END */ } +}}; + +INITCALL1(STG_REGISTER, tcp_req_conn_keywords_register, &tcp_req_conn_actions); + +static struct action_kw_list tcp_req_sess_actions = {ILH, { + { "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 }, + { "silent-drop", tcp_parse_silent_drop }, + { /* END */ } +}}; + +INITCALL1(STG_REGISTER, tcp_req_sess_keywords_register, &tcp_req_sess_actions); + +static struct action_kw_list tcp_req_cont_actions = {ILH, { + { "set-dst" , tcp_parse_set_src_dst }, + { "set-dst-port", tcp_parse_set_src_dst }, + { "silent-drop", tcp_parse_silent_drop }, + { /* END */ } +}}; + +INITCALL1(STG_REGISTER, tcp_req_cont_keywords_register, &tcp_req_cont_actions); + +static struct action_kw_list tcp_res_cont_actions = {ILH, { + { "silent-drop", tcp_parse_silent_drop }, + { /* END */ } +}}; + +INITCALL1(STG_REGISTER, tcp_res_cont_keywords_register, &tcp_res_cont_actions); + +static struct action_kw_list http_req_actions = {ILH, { + { "silent-drop", tcp_parse_silent_drop }, + { "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 */ } +}}; + +INITCALL1(STG_REGISTER, http_req_keywords_register, &http_req_actions); + +static struct action_kw_list http_res_actions = {ILH, { + { "silent-drop", tcp_parse_silent_drop }, + { /* END */ } +}}; + +INITCALL1(STG_REGISTER, http_res_keywords_register, &http_res_actions); + + +/* + * Local variables: + * c-indent-level: 8 + * c-basic-offset: 8 + * End: + */