]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: tcp-act: Set addresses at the apprioriate level in set-(src/dst) actions
authorChristopher Faulet <cfaulet@haproxy.com>
Mon, 25 Oct 2021 06:26:34 +0000 (08:26 +0200)
committerChristopher Faulet <cfaulet@haproxy.com>
Wed, 27 Oct 2021 09:35:59 +0000 (11:35 +0200)
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.

src/tcp_act.c

index 8223aaa818ed9cce9f640b5716f2c9596aec7cc1..25ff446772ac8c3b91e5ddb41a4c02ac15374433 100644 (file)
@@ -35,7 +35,8 @@
 #include <haproxy/proto_tcp.h>
 #include <haproxy/proxy-t.h>
 #include <haproxy/sample.h>
-#include <haproxy/stream-t.h>
+#include <haproxy/session.h>
+#include <haproxy/stream_interface.h>
 #include <haproxy/tcp_rules.h>
 #include <haproxy/tools.h>
 
@@ -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;
 }