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