Hello,

Here a set of patches implementing http/tcp set-{dst,src}[-port].

The feature can be useful to connect to a IP/port which is defined in a map.

Regards,

-- 
William Lallemand
>From 4f44c85bd02830d690539b269a4669b6bd251e44 Mon Sep 17 00:00:00 2001
From: William Lallemand <wlallem...@irq6.net>
Date: Wed, 25 May 2016 01:48:42 +0200
Subject: [PATCH 1/4] 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
---
 doc/configuration.txt  | 15 +++++++++++
 include/types/action.h |  1 -
 src/proto_http.c       | 61 +++--------------------------------------
 src/proto_tcp.c        | 73 ++++++++++++++++++++++++++++++++++++++++++++++++--
 4 files changed, 90 insertions(+), 60 deletions(-)

diff --git a/doc/configuration.txt b/doc/configuration.txt
index c4df56e..f94885f 100644
--- a/doc/configuration.txt
+++ b/doc/configuration.txt
@@ -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
diff --git a/include/types/action.h b/include/types/action.h
index b97f9bf..742252e 100644
--- a/include/types/action.h
+++ b/include/types/action.h
@@ -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,
diff --git a/src/proto_http.c b/src/proto_http.c
index d79a782..6686631 100644
--- a/src/proto_http.c
+++ b/src/proto_http.c
@@ -3554,26 +3554,6 @@ resume_execution:
 			}
 			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;
 	}
diff --git a/src/proto_tcp.c b/src/proto_tcp.c
index bbe12e2..b283db4 100644
--- a/src/proto_tcp.c
+++ b/src/proto_tcp.c
@@ -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 */ }
 }};
 
-- 
2.7.3

>From fb81bec67994740bdfe26137e9d7f08e6ba14e38 Mon Sep 17 00:00:00 2001
From: William Lallemand <wlallem...@irq6.net>
Date: Wed, 25 May 2016 02:33:16 +0200
Subject: [PATCH 2/4] MINOR: set the CO_FL_ADDR_FROM_SET flags with 'set-src'

When the 'set-src' action is used, the CO_FL_ADDR_FROM_SET wasn't set,
it can lead to address being rewritten.
---
 src/proto_tcp.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/proto_tcp.c b/src/proto_tcp.c
index b283db4..806eb3e 100644
--- a/src/proto_tcp.c
+++ b/src/proto_tcp.c
@@ -1448,6 +1448,7 @@ enum act_return tcp_action_req_set_src(struct act_rule *rule, struct proxy *px,
 				((struct sockaddr_in6 *)&cli_conn->addr.from)->sin6_port = 0;
 			}
 		}
+		cli_conn->flags |= CO_FL_ADDR_FROM_SET;
 	}
 	return ACT_RET_CONT;
 }
-- 
2.7.3

>From 69c1a599574312de719333d94a0c0291c322cafe Mon Sep 17 00:00:00 2001
From: William Lallemand <wlallem...@irq6.net>
Date: Wed, 25 May 2016 01:51:35 +0200
Subject: [PATCH 3/4] MEDIUM: tcp/http: add 'set-src-port' action

set-src-port works the same way as 'set-src' but for the source port.
It's available in 'tcp-request connection' and 'http-request' actions.
---
 doc/configuration.txt | 29 +++++++++++++++++++++++++++++
 src/proto_tcp.c       | 32 +++++++++++++++++++++++++++++++-
 2 files changed, 60 insertions(+), 1 deletion(-)

diff --git a/doc/configuration.txt b/doc/configuration.txt
index f94885f..d3ff223 100644
--- a/doc/configuration.txt
+++ b/doc/configuration.txt
@@ -3845,6 +3845,21 @@ http-request { allow | deny | tarpit | auth [realm <realm>] | redirect <rule> |
 
       When set-src is successful, the source port is set to 0.
 
+    - set-src-port <expr> :
+      Is used to set the source port address to the value of specified
+      expression.
+
+         <expr>    Is a standard HAProxy expression formed by a sample-fetch
+                   followed by some converters.
+
+      Example:
+
+         http-request set-src-port hdr(x-port)
+         http-request set-src-port int(4000)
+
+      Be careful to use "set-src-port" after "set-src", because "set-src" sets
+      the source port 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 to prevent the client from being notified. The effect it then
@@ -8689,6 +8704,20 @@ tcp-request connection <action> [{if | unless} <condition>]
 
       When set-src is successful, the source port is set to 0.
 
+    - set-src-port <expr> :
+      Is used to set the source port address to the value of specified
+      expression.
+
+         <expr>    Is a standard HAProxy expression formed by a sample-fetch
+                   followed by some converters.
+
+      Example:
+
+         tcp-request connection set-src-port int(4000)
+
+      Be careful to use "set-src-port" after "set-src", because "set-src" sets
+      the source port 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
diff --git a/src/proto_tcp.c b/src/proto_tcp.c
index 806eb3e..99438d8 100644
--- a/src/proto_tcp.c
+++ b/src/proto_tcp.c
@@ -1453,6 +1453,32 @@ enum act_return tcp_action_req_set_src(struct act_rule *rule, struct proxy *px,
 	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
+ */
+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_ctrl_ready(cli_conn)) {
+		struct sample *smp;
+
+		conn_get_from_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.from)->ss_family == AF_INET) {
+				((struct sockaddr_in *)&cli_conn->addr.from)->sin_port = htons(smp->data.u.sint);
+			} else if (((struct sockaddr_storage *)&cli_conn->addr.from)->ss_family == AF_INET6) {
+				((struct sockaddr_in6 *)&cli_conn->addr.from)->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)
 {
@@ -2061,7 +2087,7 @@ static int tcp_parse_tcp_req(char **args, int section_type, struct proxy *curpx,
 	return -1;
 }
 
-/* parse "set-src" action */
+/* 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)
 {
 	int cur_arg;
@@ -2091,6 +2117,8 @@ enum act_parse_ret tcp_parse_set_src(const char **args, int *orig_arg, struct pr
 
 	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 {
 		return ACT_RET_PRS_ERR;
 	}
@@ -2493,6 +2521,7 @@ 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 },
 	{ /* END */ }
 }};
 
@@ -2509,6 +2538,7 @@ 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 },
 	{ /* END */ }
 }};
 
-- 
2.7.3

>From 3daea1db5a18aeda04f7c8205a32a44d5a0d83a3 Mon Sep 17 00:00:00 2001
From: William Lallemand <wlallem...@irq6.net>
Date: Wed, 25 May 2016 02:34:07 +0200
Subject: [PATCH 4/4] 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.
---
 doc/configuration.txt | 56 +++++++++++++++++++++++++++++++++++++++
 src/proto_tcp.c       | 73 ++++++++++++++++++++++++++++++++++++++++++++++-----
 2 files changed, 123 insertions(+), 6 deletions(-)

diff --git a/doc/configuration.txt b/doc/configuration.txt
index d3ff223..678be44 100644
--- a/doc/configuration.txt
+++ b/doc/configuration.txt
@@ -3860,6 +3860,34 @@ http-request { allow | deny | tarpit | auth [realm <realm>] | redirect <rule> |
       Be careful to use "set-src-port" after "set-src", because "set-src" sets
       the source port to 0.
 
+    - set-dst <expr> :
+      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.
+
+         <expr>    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 <expr> :
+      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.
+
+         <expr>    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 <action> [{if | unless} <condition>]
       Be careful to use "set-src-port" after "set-src", because "set-src" sets
       the source port to 0.
 
+    - set-dst <expr> :
+      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.
+
+         <expr>    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 <expr> :
+      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.
+
+
+         <expr>    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 99438d8..5344703 100644
--- a/src/proto_tcp.c
+++ b/src/proto_tcp.c
@@ -1454,6 +1454,33 @@ enum act_return tcp_action_req_set_src(struct act_rule *rule, struct proxy *px,
 }
 
 /*
+ * 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 */ }
 }};
 
-- 
2.7.3

Reply via email to