MEDIUM: tcp: add 'set-src' to 'tcp-request connection'

The 'set-src' action was not available for tcp actions The action code
has been converted into a function in proto_tcp.c to be used for both
'http-request' and 'tcp-request connection' actions.

Both http and tcp keywords are registered in proto_tcp.c
This commit is contained in:
William Lallemand 2016-05-25 01:48:42 +02:00 committed by Willy Tarreau
parent bb933468b4
commit 2e785f23cb
4 changed files with 90 additions and 60 deletions

View File

@ -8674,6 +8674,21 @@ tcp-request connection <action> [{if | unless} <condition>]
an error occurs, this action silently fails and the actions evaluation
continues.
- set-src <expr> :
Is used to set the source IP address to the value of specified
expression. Useful if you want to mask source IP for privacy.
If you want to provide an IP from a HTTP header use "http-request
set-src"
<expr> Is a standard HAProxy expression formed by a sample-fetch
followed by some converters.
Example:
tcp-request connection set-src src,ipmask(24)
When set-src is successful, the source port is set to 0.
- "silent-drop" :
This stops the evaluation of the rules and makes the client-facing
connection suddenly disappear using a system-dependant way that tries

View File

@ -80,7 +80,6 @@ enum act_name {
/* http request actions. */
ACT_HTTP_REQ_TARPIT,
ACT_HTTP_REQ_AUTH,
ACT_HTTP_REQ_SET_SRC,
/* tcp actions */
ACT_TCP_EXPECT_PX,

View File

@ -3554,26 +3554,6 @@ http_req_get_intercept_rule(struct proxy *px, struct list *rules, struct stream
}
break;
case ACT_HTTP_REQ_SET_SRC:
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.from)->sin_family = AF_INET;
((struct sockaddr_in *)&cli_conn->addr.from)->sin_addr.s_addr = smp->data.u.ipv4.s_addr;
((struct sockaddr_in *)&cli_conn->addr.from)->sin_port = 0;
} else if (smp->data.type == SMP_T_IPV6) {
((struct sockaddr_in6 *)&cli_conn->addr.from)->sin6_family = AF_INET6;
memcpy(&((struct sockaddr_in6 *)&cli_conn->addr.from)->sin6_addr, &smp->data.u.ipv6, sizeof(struct in6_addr));
((struct sockaddr_in6 *)&cli_conn->addr.from)->sin6_port = 0;
}
}
}
break;
/* other flags exists, but normaly, they never be matched. */
default:
break;
@ -9204,39 +9184,6 @@ struct act_rule *parse_http_req_cond(const char **args, const char *file, int li
proxy->conf.lfs_line = proxy->conf.args.line;
cur_arg += 2;
} else if (strncmp(args[0], "set-src", 7) == 0) {
struct sample_expr *expr;
unsigned int where;
char *err = NULL;
cur_arg = 1;
proxy->conf.args.ctx = ARGC_HRQ;
expr = sample_parse_expr((char **)args, &cur_arg, file, linenum, &err, &proxy->conf.args);
if (!expr) {
Alert("parsing [%s:%d] : error detected in %s '%s' while parsing 'http-request %s' rule : %s.\n",
file, linenum, proxy_type_str(proxy), proxy->id, args[0], err);
free(err);
goto out_err;
}
where = 0;
if (proxy->cap & PR_CAP_FE)
where |= SMP_VAL_FE_HRQ_HDR;
if (proxy->cap & PR_CAP_BE)
where |= SMP_VAL_BE_HRQ_HDR;
if (!(expr->fetch->val & where)) {
Alert("parsing [%s:%d] : error detected in %s '%s' while parsing 'http-request %s' rule :"
" fetch method '%s' extracts information from '%s', none of which is available here.\n",
file, linenum, proxy_type_str(proxy), proxy->id, args[0],
args[cur_arg-1], sample_src_names(expr->fetch->use));
free(expr);
goto out_err;
}
rule->arg.expr = expr;
rule->action = ACT_HTTP_REQ_SET_SRC;
} else if (((custom = action_http_req_custom(args[0])) != NULL)) {
char *errmsg = NULL;
cur_arg = 1;
@ -9253,8 +9200,8 @@ struct act_rule *parse_http_req_cond(const char **args, const char *file, int li
action_build_list(&http_req_keywords.list, &trash);
Alert("parsing [%s:%d]: 'http-request' expects 'allow', 'deny', 'auth', 'redirect', "
"'tarpit', 'add-header', 'set-header', 'replace-header', 'replace-value', 'set-nice', "
"'set-tos', 'set-mark', 'set-log-level', 'add-acl', 'del-acl', 'del-map', 'set-map', "
"'set-src'%s%s, but got '%s'%s.\n",
"'set-tos', 'set-mark', 'set-log-level', 'add-acl', 'del-acl', 'del-map', 'set-map'"
"%s%s, but got '%s'%s.\n",
file, linenum, *trash.str ? ", " : "", trash.str, args[0], *args[0] ? "" : " (missing argument)");
goto out_err;
}
@ -9614,8 +9561,8 @@ struct act_rule *parse_http_res_cond(const char **args, const char *file, int li
action_build_list(&http_res_keywords.list, &trash);
Alert("parsing [%s:%d]: 'http-response' expects 'allow', 'deny', 'redirect', "
"'add-header', 'del-header', 'set-header', 'replace-header', 'replace-value', 'set-nice', "
"'set-tos', 'set-mark', 'set-log-level', 'add-acl', 'del-acl', 'del-map', 'set-map', "
"'set-src'%s%s, but got '%s'%s.\n",
"'set-tos', 'set-mark', 'set-log-level', 'add-acl', 'del-acl', 'del-map', 'set-map'"
"%s%s, but got '%s'%s.\n",
file, linenum, *trash.str ? ", " : "", trash.str, args[0], *args[0] ? "" : " (missing argument)");
goto out_err;
}

View File

@ -1425,6 +1425,33 @@ int tcp_exec_req_rules(struct session *sess)
return result;
}
/*
* Execute the "set-src" action. May be called from {tcp,http}request
*/
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_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.from)->sin_family = AF_INET;
((struct sockaddr_in *)&cli_conn->addr.from)->sin_addr.s_addr = smp->data.u.ipv4.s_addr;
((struct sockaddr_in *)&cli_conn->addr.from)->sin_port = 0;
} else if (smp->data.type == SMP_T_IPV6) {
((struct sockaddr_in6 *)&cli_conn->addr.from)->sin6_family = AF_INET6;
memcpy(&((struct sockaddr_in6 *)&cli_conn->addr.from)->sin6_addr, &smp->data.u.ipv6, sizeof(struct in6_addr));
((struct sockaddr_in6 *)&cli_conn->addr.from)->sin6_port = 0;
}
}
}
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)
{
@ -2033,6 +2060,46 @@ static int tcp_parse_tcp_req(char **args, int section_type, struct proxy *curpx,
return -1;
}
/* parse "set-src" action */
enum act_parse_ret tcp_parse_set_src(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);
if (!expr)
return ACT_RET_PRS_ERR;
where = 0;
if (proxy->cap & PR_CAP_FE)
where |= SMP_VAL_FE_HRQ_HDR;
if (proxy->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 {
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.
*/
@ -2423,7 +2490,8 @@ static struct srv_kw_list srv_kws = { "TCP", { }, {
}};
static struct action_kw_list tcp_req_conn_actions = {ILH, {
{ "silent-drop", tcp_parse_silent_drop },
{ "silent-drop", tcp_parse_silent_drop },
{ "set-src", tcp_parse_set_src },
{ /* END */ }
}};
@ -2438,7 +2506,8 @@ 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 },
{ "silent-drop", tcp_parse_silent_drop },
{ "set-src", tcp_parse_set_src },
{ /* END */ }
}};