From: Christopher Faulet Date: Mon, 25 Oct 2021 06:26:34 +0000 (+0200) Subject: MEDIUM: tcp-act: Set addresses at the apprioriate level in set-(src/dst) actions X-Git-Tag: v2.5-dev12~43 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=d69377eb02a15e801eaa66f81f5ad3c563e2b3b8;p=thirdparty%2Fhaproxy.git MEDIUM: tcp-act: Set addresses at the apprioriate level in set-(src/dst) actions When client source or destination addresses are changed via a tcp/http action, we update addresses at the appropriate level. When "tcp-request connection" rules are evaluated, we update addresses at the connection level. When "tcp-request session" rules is evaluated, we update those at the session level. And finally, when "tcp-request content" or "http-request" rules are evaluated, we update the addresses at the stream level. The same is performed when source or destination ports are changed. Of course, for now, not all level are supported. But thanks to this patch, it will be possible. --- diff --git a/src/tcp_act.c b/src/tcp_act.c index 8223aaa818..25ff446772 100644 --- a/src/tcp_act.c +++ b/src/tcp_act.c @@ -35,7 +35,8 @@ #include #include #include -#include +#include +#include #include #include @@ -48,26 +49,50 @@ static enum act_return tcp_action_req_set_src(struct act_rule *rule, struct prox struct session *sess, struct stream *s, int flags) { struct connection *cli_conn; + struct sockaddr_storage *src; + struct sample *smp; + + switch (rule->from) { + case ACT_F_TCP_REQ_CON: + cli_conn = objt_conn(sess->origin); + if (!cli_conn || !conn_get_src(cli_conn)) + goto end; + src = cli_conn->src; + break; + + case ACT_F_TCP_REQ_SES: + if (!sess_get_src(sess)) + goto end; + src = sess->src; + break; + + case ACT_F_TCP_REQ_CNT: + case ACT_F_HTTP_REQ: + if (!si_get_src(&s->si[0])) + goto end; + src = s->si[0].src; + break; + + default: + goto end; + } - 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; - } + 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(src); + + if (smp->data.type == SMP_T_IPV4) { + ((struct sockaddr_in *)src)->sin_family = AF_INET; + ((struct sockaddr_in *)src)->sin_addr.s_addr = smp->data.u.ipv4.s_addr; + ((struct sockaddr_in *)src)->sin_port = port; + } else if (smp->data.type == SMP_T_IPV6) { + ((struct sockaddr_in6 *)src)->sin6_family = AF_INET6; + memcpy(&((struct sockaddr_in6 *)src)->sin6_addr, &smp->data.u.ipv6, sizeof(struct in6_addr)); + ((struct sockaddr_in6 *)src)->sin6_port = port; } - cli_conn->flags |= CO_FL_ADDR_FROM_SET; } + + end: return ACT_RET_CONT; } @@ -80,26 +105,50 @@ static enum act_return tcp_action_req_set_dst(struct act_rule *rule, struct prox struct session *sess, struct stream *s, int flags) { struct connection *cli_conn; + struct sockaddr_storage *dst; + struct sample *smp; + + switch (rule->from) { + case ACT_F_TCP_REQ_CON: + cli_conn = objt_conn(sess->origin); + if (!cli_conn || !conn_get_dst(cli_conn)) + goto end; + dst = cli_conn->dst; + break; + + case ACT_F_TCP_REQ_SES: + if (!sess_get_dst(sess)) + goto end; + dst = sess->dst; + break; + + case ACT_F_TCP_REQ_CNT: + case ACT_F_HTTP_REQ: + if (!si_get_dst(&s->si[0])) + goto end; + dst = s->si[0].dst; + break; + + default: + goto end; + } - 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; - ((struct sockaddr_in *)cli_conn->dst)->sin_port = port; - } 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; + 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(dst); + + if (smp->data.type == SMP_T_IPV4) { + ((struct sockaddr_in *)dst)->sin_family = AF_INET; + ((struct sockaddr_in *)dst)->sin_addr.s_addr = smp->data.u.ipv4.s_addr; + ((struct sockaddr_in *)dst)->sin_port = port; + } else if (smp->data.type == SMP_T_IPV6) { + ((struct sockaddr_in6 *)dst)->sin6_family = AF_INET6; + memcpy(&((struct sockaddr_in6 *)dst)->sin6_addr, &smp->data.u.ipv6, sizeof(struct in6_addr)); + ((struct sockaddr_in6 *)dst)->sin6_port = port; } } + + end: return ACT_RET_CONT; } @@ -113,23 +162,48 @@ static enum act_return tcp_action_req_set_src_port(struct act_rule *rule, struct struct session *sess, struct stream *s, int flags) { struct connection *cli_conn; + struct sockaddr_storage *src; + struct sample *smp; + + switch (rule->from) { + case ACT_F_TCP_REQ_CON: + cli_conn = objt_conn(sess->origin); + if (!cli_conn || !conn_get_src(cli_conn)) + goto end; + src = cli_conn->src; + break; + + case ACT_F_TCP_REQ_SES: + if (!sess_get_src(sess)) + goto end; + src = sess->src; + break; + + case ACT_F_TCP_REQ_CNT: + case ACT_F_HTTP_REQ: + if (!si_get_src(&s->si[0])) + goto end; + src = s->si[0].src; + break; + + default: + goto end; + } - 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); + smp = sample_fetch_as_type(px, sess, s, SMP_OPT_DIR_REQ|SMP_OPT_FINAL, rule->arg.expr, SMP_T_SINT); + if (smp) { + if (src->ss_family == AF_INET6) { + ((struct sockaddr_in6 *)src)->sin6_port = htons(smp->data.u.sint); + } else { + if (src->ss_family != AF_INET) { + src->ss_family = AF_INET; + ((struct sockaddr_in *)src)->sin_addr.s_addr = 0; } + ((struct sockaddr_in *)src)->sin_port = htons(smp->data.u.sint); } } + + end: return ACT_RET_CONT; } @@ -143,23 +217,48 @@ static enum act_return tcp_action_req_set_dst_port(struct act_rule *rule, struct struct session *sess, struct stream *s, int flags) { struct connection *cli_conn; + struct sockaddr_storage *dst; + struct sample *smp; + + switch (rule->from) { + case ACT_F_TCP_REQ_CON: + cli_conn = objt_conn(sess->origin); + if (!cli_conn || !conn_get_dst(cli_conn)) + goto end; + dst = cli_conn->dst; + break; + + case ACT_F_TCP_REQ_SES: + if (!sess_get_dst(sess)) + goto end; + dst = sess->dst; + break; + + case ACT_F_TCP_REQ_CNT: + case ACT_F_HTTP_REQ: + if (!si_get_dst(&s->si[0])) + goto end; + dst = s->si[0].dst; + break; + + default: + goto end; + } - 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); + smp = sample_fetch_as_type(px, sess, s, SMP_OPT_DIR_REQ|SMP_OPT_FINAL, rule->arg.expr, SMP_T_SINT); + if (smp) { + if (dst->ss_family == AF_INET6) { + ((struct sockaddr_in6 *)dst)->sin6_port = htons(smp->data.u.sint); + } else { + if (dst->ss_family != AF_INET) { + dst->ss_family = AF_INET; + ((struct sockaddr_in *)dst)->sin_addr.s_addr = 0; } + ((struct sockaddr_in *)dst)->sin_port = htons(smp->data.u.sint); } } + + end: return ACT_RET_CONT; }