MEDIUM: server: change server ip address from stats socket

New command available on the stats socket to change a server addr using
the command "set server <backend>/<server> addr <ip4|ip6>"
diff --git a/doc/configuration.txt b/doc/configuration.txt
index 897e285..9fbffba 100644
--- a/doc/configuration.txt
+++ b/doc/configuration.txt
@@ -14930,6 +14930,9 @@
   is passed in number of sessions per second sent to the SSL stack. It applies
   before the handshake in order to protect the stack against handshake abuses.
 
+set server <backend>/<server> addr <ip4 or ip6 address>
+  Replace the current IP address of a server by the one provided.
+
 set server <backend>/<server> agent [ up | down ]
   Force a server's agent to a new state. This can be useful to immediately
   switch a server's state regardless of some slow agent checks for example.
diff --git a/include/proto/server.h b/include/proto/server.h
index 7e32995..64f2327 100644
--- a/include/proto/server.h
+++ b/include/proto/server.h
@@ -95,6 +95,13 @@
 					       const char *weight_str);
 
 /*
+ * Parses addr_str and configures sv accordingly.
+ * Returns NULL on success, error message string otherwise.
+ */
+const char *server_parse_addr_change_request(struct server *sv,
+                                             const char *addr_str);
+
+/*
  * Return true if the server has a zero user-weight, meaning it's in draining
  * mode (ie: not taking new non-persistent connections).
  */
diff --git a/src/dumpstats.c b/src/dumpstats.c
index 31bc0ba..cd19279 100644
--- a/src/dumpstats.c
+++ b/src/dumpstats.c
@@ -186,7 +186,7 @@
 	"  show table [id]: report table usage stats or dump this table's contents\n"
 	"  get weight     : report a server's current weight\n"
 	"  set weight     : change a server's weight\n"
-	"  set server     : change a server's state or weight\n"
+	"  set server     : change a server's state, weight or address\n"
 	"  set table [id] : update or create a table entry's data\n"
 	"  set timeout    : change a timeout setting\n"
 	"  set maxconn    : change a maxconn setting\n"
@@ -1510,8 +1510,15 @@
 					appctx->st0 = STAT_CLI_PRINT;
 				}
 			}
+			else if (strcmp(args[3], "addr") == 0) {
+				warning = server_parse_addr_change_request(sv, args[4]);
+				if (warning) {
+					appctx->ctx.cli.msg = warning;
+					appctx->st0 = STAT_CLI_PRINT;
+				}
+			}
 			else {
-				appctx->ctx.cli.msg = "'set server <srv>' only supports 'agent', 'health', 'state' and 'weight'.\n";
+				appctx->ctx.cli.msg = "'set server <srv>' only supports 'agent', 'health', 'state', 'weight' and 'addr'.\n";
 				appctx->st0 = STAT_CLI_PRINT;
 			}
 			return 1;
diff --git a/src/server.c b/src/server.c
index 369dd79..2bde246 100644
--- a/src/server.c
+++ b/src/server.c
@@ -802,6 +802,29 @@
 	return NULL;
 }
 
+/*
+ * Parses <addr_str> and configures <sv> accordingly.
+ * Returns:
+ *  - error string on error
+ *  - NULL on success
+ */
+const char *server_parse_addr_change_request(struct server *sv,
+                                             const char *addr_str)
+{
+	unsigned char ip[INET6_ADDRSTRLEN];
+
+	if (inet_pton(AF_INET6, addr_str, ip)) {
+		update_server_addr(sv, ip, AF_INET6, "stats command\n");
+		return NULL;
+	}
+	if (inet_pton(AF_INET, addr_str, ip)) {
+		update_server_addr(sv, ip, AF_INET, "stats command\n");
+		return NULL;
+	}
+
+	return "Could not understand IP address format.\n";
+}
+
 int parse_server(const char *file, int linenum, char **args, struct proxy *curproxy, struct proxy *defproxy)
 {
 	struct server *newsrv = NULL;