Here you go.

Instead of freeing memory and let the function to allocate an other chunk,
I do a memset and do allocate memory only if the dgram pointer is not yet
set.
I wrote 2 patches: one to modify the function dns_init_resolvers and one to
enable the closing of the socket after the fork().

Baptiste
From 2252a644c8a82846f9cf9e26e460491c0df930f5 Mon Sep 17 00:00:00 2001
From: Baptiste Assmann <bed...@gmail.com>
Date: Thu, 2 Feb 2017 22:44:15 +0100
Subject: [PATCH 1/2] MINOR: dns: give ability to dns_init_resolvers() to close
 a socket when requested

The function dns_init_resolvers() is used to initialize socket used to
send DNS queries.
This patch gives the function the ability to close a socket before
re-opening it.
---
 include/proto/dns.h |  2 +-
 src/dns.c           | 18 ++++++++++++++++--
 src/haproxy.c       |  2 +-
 3 files changed, 18 insertions(+), 4 deletions(-)

diff --git a/include/proto/dns.h b/include/proto/dns.h
index c62834f..c7cd356 100644
--- a/include/proto/dns.h
+++ b/include/proto/dns.h
@@ -30,7 +30,7 @@ int dns_str_to_dn_label_len(const char *string);
 int dns_hostname_validation(const char *string, char **err);
 int dns_build_query(int query_id, int query_type, char *hostname_dn, int hostname_dn_len, char *buf, int bufsize);
 struct task *dns_process_resolve(struct task *t);
-int dns_init_resolvers(void);
+int dns_init_resolvers(int close_socket);
 uint16_t dns_rnd16(void);
 int dns_validate_dns_response(unsigned char *resp, unsigned char *bufend, struct dns_response_packet *dns_p);
 int dns_get_ip_from_response(struct dns_response_packet *dns_p,
diff --git a/src/dns.c b/src/dns.c
index 2a333f1..5542b17 100644
--- a/src/dns.c
+++ b/src/dns.c
@@ -919,11 +919,13 @@ unsigned short dns_response_get_query_id(unsigned char *resp)
  * parses resolvers sections and initializes:
  *  - task (time events) for each resolvers section
  *  - the datagram layer (network IO events) for each nameserver
+ * It takes one argument:
+ *  - close_first takes 2 values: 0 or 1. If 1, the connection is closed first.
  * returns:
  *  0 in case of error
  *  1 when no error
  */
-int dns_init_resolvers(void)
+int dns_init_resolvers(int close_socket)
 {
 	struct dns_resolvers *curr_resolvers;
 	struct dns_nameserver *curnameserver;
@@ -961,7 +963,19 @@ int dns_init_resolvers(void)
 		curr_resolvers->t = t;
 
 		list_for_each_entry(curnameserver, &curr_resolvers->nameserver_list, list) {
-			if ((dgram = calloc(1, sizeof(*dgram))) == NULL) {
+		        dgram = NULL;
+
+			if (close_socket == 1) {
+				if (curnameserver->dgram) {
+					close(curnameserver->dgram->t.sock.fd);
+					memset(curnameserver->dgram, '\0', sizeof(*dgram));
+					dgram = curnameserver->dgram;
+				}
+			}
+
+			/* allocate memory only if it has not already been allocated
+			 * by a previous call to this function */
+			if (!dgram && (dgram = calloc(1, sizeof(*dgram))) == NULL) {
 				Alert("Starting [%s/%s] nameserver: out of memory.\n", curr_resolvers->id,
 						curnameserver->id);
 				return 0;
diff --git a/src/haproxy.c b/src/haproxy.c
index 4ad370d..6a8b5c2 100644
--- a/src/haproxy.c
+++ b/src/haproxy.c
@@ -1176,7 +1176,7 @@ static void init(int argc, char **argv)
 		exit(1);
 
 	/* initialize structures for name resolution */
-	if (!dns_init_resolvers())
+	if (!dns_init_resolvers(0))
 		exit(1);
 
 	free(err_msg);
-- 
2.7.4

From e1891e1e7de86db046f1946e7518dbf0a55b284f Mon Sep 17 00:00:00 2001
From: Baptiste Assmann <bed...@gmail.com>
Date: Thu, 2 Feb 2017 23:14:51 +0100
Subject: [PATCH 2/2] BUG/MAJOR: dns: restart sockets after fork()

UDP sockets used to send DNS queries are created before fork happens and
this is a big problem because all the processes (in case of a
configuration starting multiple processes) share the same socket. Some
processes may consume responses dedicated to an other one, some servers
may be disabled, some IPs changed, etc...

As a workaround, this patch close the existing socket and create a new
one after the fork() has happened.
---
 src/haproxy.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/src/haproxy.c b/src/haproxy.c
index 6a8b5c2..41be9cd 100644
--- a/src/haproxy.c
+++ b/src/haproxy.c
@@ -1950,6 +1950,10 @@ int main(int argc, char **argv)
 		fork_poller();
 	}
 
+	/* initialize structures for name resolution */
+	if (!dns_init_resolvers(1))
+		exit(1);
+
 	protocol_enable_all();
 	/*
 	 * That's it : the central polling loop. Run until we stop.
-- 
2.7.4

Reply via email to