Hi,

Purpose of this flag is to allow IP address duplication in a backend (on a
per server basis) when the runtime resolver is in operation.
By default, the runtime resolver prevent an IP address being affected to 2
servers when they are resolved by the same hostname.

>From the 4 patches in attachment, 3 of them can be backported. They are
more cosmetic than anything, but it took me some time to figure out who,
from the code or the comment was wrong...

This feature was requested by Ryuzaki on discource. I just provide him the
patches, so waiting for his feedback.

Baptiste
From 0490a231d457236db92b73e98df57b4f6bad2b01 Mon Sep 17 00:00:00 2001
From: Baptiste Assmann <bed...@gmail.com>
Date: Fri, 22 Jun 2018 15:04:43 +0200
Subject: [PATCH 4/4] MINOR: dns: new flag to allow IP address duplication

By default, HAProxy's DNS resolution at runtime ensure that there is no
IP address duplication in a backend (for servers being resolved by the
same hostname).
There are a few cases where people want, on purpose, to disable this
feature.

This patch introduces a new server side flag for this purpose:
"resolve-accept-dup-ip".
---
 doc/configuration.txt | 21 +++++++++++++++++++++
 include/types/dns.h   |  2 ++
 src/dns.c             |  6 +++++-
 src/server.c          |  6 ++++++
 4 files changed, 34 insertions(+), 1 deletion(-)

diff --git a/doc/configuration.txt b/doc/configuration.txt
index e901d7e..85e1c9d 100644
--- a/doc/configuration.txt
+++ b/doc/configuration.txt
@@ -11682,6 +11682,27 @@ rise <count>
   after <count> consecutive successful health checks. This value defaults to 2
   if unspecified. See also the "check", "inter" and "fall" parameters.
 
+resolve-accept-dup-ip
+  By default, HAProxy prevents IP address duplication in a backend when DNS
+  resolution at runtime is in operation.
+  That said, for some cases, it makes sense that two servers (in the same
+  backend, being resolved by the same FQDN) have the same IP address.
+  For such case, simply enable this flag.
+
+  Example:
+    backend b_myapp
+      default-server init-addr none resolvers dns
+      server s1 myapp.example.com:80 check resolve-accept-dup-ip
+      server s2 myapp.example.com:81 check resolve-accept-dup-ip
+
+  With the flag resolve-accept-dup-ip set:
+  * if the nameserver returns a single IP address, then both servers will use
+    it
+  * If the nameserver returns 2 IP addresses, then each server will pick up a
+    different address
+
+  Default value: not set
+
 resolve-prefer <family>
   When DNS resolution is enabled for a server and multiple IP addresses from
   different families are returned, HAProxy will prefer using an IP address
diff --git a/include/types/dns.h b/include/types/dns.h
index 9b1d08d..488d399 100644
--- a/include/types/dns.h
+++ b/include/types/dns.h
@@ -245,6 +245,8 @@ struct dns_options {
 		} mask;
 	} pref_net[SRV_MAX_PREF_NET];
 	int pref_net_nb; /* The number of registered prefered networks. */
+	int accept_duplicate_ip; /* flag to indicate whether the associated object can use an IP address
+				    already set to an other object of the same group */
 };
 
 /* Resolution structure associated to single server and used to manage name
diff --git a/src/dns.c b/src/dns.c
index 018c86a..77bf5c0 100644
--- a/src/dns.c
+++ b/src/dns.c
@@ -962,8 +962,10 @@ int dns_get_ip_from_response(struct dns_response_packet *dns_p,
 	int currentip_sel;
 	int j;
 	int score, max_score;
+	int allowed_duplicated_ip;
 
 	family_priority   = dns_opts->family_prio;
+	allowed_duplicated_ip = dns_opts->accept_duplicate_ip;
 	*newip = newip4   = newip6 = NULL;
 	currentip_found   = 0;
 	*newip_sin_family = AF_UNSPEC;
@@ -1027,7 +1029,9 @@ int dns_get_ip_from_response(struct dns_response_packet *dns_p,
 		 * member of a group.  If not, the score should be incremented
 		 * by 2. */
 		if (owner && snr_check_ip_callback(owner, ip, &ip_type)) {
-			continue;
+			if (!allowed_duplicated_ip) {
+				continue;
+			}
 		} else {
 			score += 2;
 		}
diff --git a/src/server.c b/src/server.c
index 277d140..b3bd9e2 100644
--- a/src/server.c
+++ b/src/server.c
@@ -1544,6 +1544,7 @@ static void srv_settings_cpy(struct server *srv, struct server *src, int srv_tmp
 	if (src->resolvers_id != NULL)
 		srv->resolvers_id = strdup(src->resolvers_id);
 	srv->dns_opts.family_prio = src->dns_opts.family_prio;
+	srv->dns_opts.accept_duplicate_ip = src->dns_opts.accept_duplicate_ip;
 	if (srv->dns_opts.family_prio == AF_UNSPEC)
 		srv->dns_opts.family_prio = AF_INET6;
 	memcpy(srv->dns_opts.pref_net,
@@ -2082,6 +2083,7 @@ int parse_server(const char *file, int linenum, char **args, struct proxy *curpr
 			newsrv = &curproxy->defsrv;
 			cur_arg = 1;
 			newsrv->dns_opts.family_prio = AF_INET6;
+			newsrv->dns_opts.accept_duplicate_ip = 0;
 		}
 
 		while (*args[cur_arg]) {
@@ -2177,6 +2179,10 @@ int parse_server(const char *file, int linenum, char **args, struct proxy *curpr
 				newsrv->resolvers_id = strdup(args[cur_arg + 1]);
 				cur_arg += 2;
 			}
+			else if (!strcmp(args[cur_arg], "resolve-accept-dup-ip")) {
+				newsrv->dns_opts.accept_duplicate_ip = 1;
+				cur_arg += 1;
+			}
 			else if (!strcmp(args[cur_arg], "resolve-prefer")) {
 				if (!strcmp(args[cur_arg + 1], "ipv4"))
 					newsrv->dns_opts.family_prio = AF_INET;
-- 
2.7.4

From d1b88d4e8f27bd38d291f931971185eb89fed238 Mon Sep 17 00:00:00 2001
From: Baptiste Assmann <bed...@gmail.com>
Date: Fri, 22 Jun 2018 13:03:50 +0200
Subject: [PATCH 3/4] MINOR: dns: fix wrong score computation in
 dns_get_ip_from_response

dns_get_ip_from_response() is used to compare the caller current IP to
the IP available in the records returned by the DNS server.
A scoring system is in place to get the best IP address available.
That said, in the current implementation, there are a couple of issues:
1. a comment does not match what the code does
2. the code does not match what the commet says (score value is not
   incremented with '2')

This patch fixes both issues.

Backport status: 1.8
---
 src/dns.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/src/dns.c b/src/dns.c
index c86e57d..018c86a 100644
--- a/src/dns.c
+++ b/src/dns.c
@@ -1024,10 +1024,13 @@ int dns_get_ip_from_response(struct dns_response_packet *dns_p,
 		}
 
 		/* Check if the IP found in the record is already affected to a
-		 * member of a group.  If yes, the score should be incremented
+		 * member of a group.  If not, the score should be incremented
 		 * by 2. */
-		if (owner && snr_check_ip_callback(owner, ip, &ip_type))
+		if (owner && snr_check_ip_callback(owner, ip, &ip_type)) {
 			continue;
+		} else {
+			score += 2;
+		}
 
 		/* Check for current ip matching. */
 		if (ip_type == currentip_sin_family &&
-- 
2.7.4

From 5ec14978cb5b1f5895c21d5a62f1a7d665ff5545 Mon Sep 17 00:00:00 2001
From: Baptiste Assmann <bed...@gmail.com>
Date: Fri, 22 Jun 2018 12:51:51 +0200
Subject: [PATCH 2/4] TYPO: dns: inacurate comment about prefered IP score

The comment was about "prefered network ip version" while it's actually
"prefered ip version" in the code.
Fixed

Backport status: 1.7 and 1.8
  Be careful, this patch may not apply on 1.7, since the score was '4'
  for this item at that time.
---
 src/dns.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/dns.c b/src/dns.c
index 8ae183f..c86e57d 100644
--- a/src/dns.c
+++ b/src/dns.c
@@ -976,7 +976,7 @@ int dns_get_ip_from_response(struct dns_response_packet *dns_p,
 	 *
 	 * For these three priorities, a score is calculated. The
 	 * weight are:
-	 *  8 - prefered netwok ip version.
+	 *  8 - prefered ip version.
 	 *  4 - prefered network.
 	 *  2 - if the ip in the record is not affected to any other server in the same backend (duplication)
 	 *  1 - current ip.
-- 
2.7.4

From 33d16583966847658ad106cbe5ab7db158820044 Mon Sep 17 00:00:00 2001
From: Baptiste Assmann <bed...@gmail.com>
Date: Thu, 21 Jun 2018 11:45:58 +0200
Subject: [PATCH 1/4] CLEANUP: dns: remove obsolete macro DNS_MAX_IP_REC

Since a8c6db8d2d97629b2734c1d2be0860b6b11e5709, this macro is not used
anymore and can be safely removed.

Backport status: 1.8
---
 src/dns.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/dns.c b/src/dns.c
index 8d6a6d6..8ae183f 100644
--- a/src/dns.c
+++ b/src/dns.c
@@ -949,7 +949,6 @@ static int dns_validate_dns_response(unsigned char *resp, unsigned char *bufend,
  * For both cases above, dns_validate_dns_response is required
  * returns one of the DNS_UPD_* code
  */
-#define DNS_MAX_IP_REC 20
 int dns_get_ip_from_response(struct dns_response_packet *dns_p,
                              struct dns_options *dns_opts, void *currentip,
                              short currentip_sin_family,
-- 
2.7.4

Reply via email to