]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: resolvers: move resolvers section parsing from cfgparse.c to dns.c
authorEmeric Brun <ebrun@haproxy.com>
Tue, 24 Nov 2020 16:24:34 +0000 (17:24 +0100)
committerWilly Tarreau <w@1wt.eu>
Sat, 13 Feb 2021 08:43:18 +0000 (09:43 +0100)
The resolver section parsing is moved from cfgparse.c to dns.c

src/cfgparse.c
src/dns.c

index 4840008950604a2069e68d06336c28a5684839e1..0c0638e70bb59dfc5a5b9220c2f3941affadf134 100644 (file)
@@ -908,391 +908,6 @@ out:
        return err_code;
 }
 
-/*
- * Parse a <resolvers> section.
- * Returns the error code, 0 if OK, or any combination of :
- *  - ERR_ABORT: must abort ASAP
- *  - ERR_FATAL: we can continue parsing but not start the service
- *  - ERR_WARN: a warning has been emitted
- *  - ERR_ALERT: an alert has been emitted
- * Only the two first ones can stop processing, the two others are just
- * indicators.
- */
-int cfg_parse_resolvers(const char *file, int linenum, char **args, int kwm)
-{
-       static struct resolvers *curr_resolvers = NULL;
-       const char *err;
-       int err_code = 0;
-       char *errmsg = NULL;
-
-       if (strcmp(args[0], "resolvers") == 0) { /* new resolvers section */
-               if (!*args[1]) {
-                       ha_alert("parsing [%s:%d] : missing name for resolvers section.\n", file, linenum);
-                       err_code |= ERR_ALERT | ERR_ABORT;
-                       goto out;
-               }
-
-               err = invalid_char(args[1]);
-               if (err) {
-                       ha_alert("parsing [%s:%d] : character '%c' is not permitted in '%s' name '%s'.\n",
-                                file, linenum, *err, args[0], args[1]);
-                       err_code |= ERR_ALERT | ERR_ABORT;
-                       goto out;
-               }
-
-               list_for_each_entry(curr_resolvers, &sec_resolvers, list) {
-                       /* Error if two resolvers owns the same name */
-                       if (strcmp(curr_resolvers->id, args[1]) == 0) {
-                               ha_alert("Parsing [%s:%d]: resolvers '%s' has same name as another resolvers (declared at %s:%d).\n",
-                                        file, linenum, args[1], curr_resolvers->conf.file, curr_resolvers->conf.line);
-                               err_code |= ERR_ALERT | ERR_ABORT;
-                       }
-               }
-
-               if ((curr_resolvers = calloc(1, sizeof(*curr_resolvers))) == NULL) {
-                       ha_alert("parsing [%s:%d] : out of memory.\n", file, linenum);
-                       err_code |= ERR_ALERT | ERR_ABORT;
-                       goto out;
-               }
-
-               /* default values */
-               LIST_ADDQ(&sec_resolvers, &curr_resolvers->list);
-               curr_resolvers->conf.file = strdup(file);
-               curr_resolvers->conf.line = linenum;
-               curr_resolvers->id = strdup(args[1]);
-               curr_resolvers->query_ids = EB_ROOT;
-               /* default maximum response size */
-               curr_resolvers->accepted_payload_size = 512;
-               /* default hold period for nx, other, refuse and timeout is 30s */
-               curr_resolvers->hold.nx = 30000;
-               curr_resolvers->hold.other = 30000;
-               curr_resolvers->hold.refused = 30000;
-               curr_resolvers->hold.timeout = 30000;
-               curr_resolvers->hold.obsolete = 0;
-               /* default hold period for valid is 10s */
-               curr_resolvers->hold.valid = 10000;
-               curr_resolvers->timeout.resolve = 1000;
-               curr_resolvers->timeout.retry   = 1000;
-               curr_resolvers->resolve_retries = 3;
-               curr_resolvers->nb_nameservers  = 0;
-               LIST_INIT(&curr_resolvers->nameservers);
-               LIST_INIT(&curr_resolvers->resolutions.curr);
-               LIST_INIT(&curr_resolvers->resolutions.wait);
-               HA_SPIN_INIT(&curr_resolvers->lock);
-       }
-       else if (strcmp(args[0], "nameserver") == 0) { /* nameserver definition */
-               struct dns_nameserver *newnameserver = NULL;
-               struct sockaddr_storage *sk;
-               int port1, port2;
-
-               if (!*args[2]) {
-                       ha_alert("parsing [%s:%d] : '%s' expects <name> and <addr>[:<port>] as arguments.\n",
-                                file, linenum, args[0]);
-                       err_code |= ERR_ALERT | ERR_FATAL;
-                       goto out;
-               }
-
-               err = invalid_char(args[1]);
-               if (err) {
-                       ha_alert("parsing [%s:%d] : character '%c' is not permitted in server name '%s'.\n",
-                                file, linenum, *err, args[1]);
-                       err_code |= ERR_ALERT | ERR_FATAL;
-                       goto out;
-               }
-
-               list_for_each_entry(newnameserver, &curr_resolvers->nameservers, list) {
-                       /* Error if two resolvers owns the same name */
-                       if (strcmp(newnameserver->id, args[1]) == 0) {
-                               ha_alert("Parsing [%s:%d]: nameserver '%s' has same name as another nameserver (declared at %s:%d).\n",
-                                        file, linenum, args[1], newnameserver->conf.file, newnameserver->conf.line);
-                               err_code |= ERR_ALERT | ERR_FATAL;
-                       }
-               }
-
-               if ((newnameserver = calloc(1, sizeof(*newnameserver))) == NULL) {
-                       ha_alert("parsing [%s:%d] : out of memory.\n", file, linenum);
-                       err_code |= ERR_ALERT | ERR_ABORT;
-                       goto out;
-               }
-
-               /* the nameservers are linked backward first */
-               LIST_ADDQ(&curr_resolvers->nameservers, &newnameserver->list);
-               newnameserver->resolvers = curr_resolvers;
-               newnameserver->conf.file = strdup(file);
-               newnameserver->conf.line = linenum;
-               newnameserver->id = strdup(args[1]);
-
-               sk = str2sa_range(args[2], NULL, &port1, &port2, NULL, NULL,
-                                 &errmsg, NULL, NULL, PA_O_RESOLVE | PA_O_PORT_OK | PA_O_PORT_MAND | PA_O_DGRAM);
-               if (!sk) {
-                       ha_alert("parsing [%s:%d] : '%s %s' : %s\n", file, linenum, args[0], args[1], errmsg);
-                       err_code |= ERR_ALERT | ERR_FATAL;
-                       goto out;
-               }
-
-               newnameserver->addr = *sk;
-       }
-       else if (strcmp(args[0], "parse-resolv-conf") == 0) {
-               struct dns_nameserver *newnameserver = NULL;
-               const char *whitespace = "\r\n\t ";
-               char *resolv_line = NULL;
-               int resolv_linenum = 0;
-               FILE *f = NULL;
-               char *address = NULL;
-               struct sockaddr_storage *sk = NULL;
-               struct protocol *proto;
-               int duplicate_name = 0;
-
-               if ((resolv_line = malloc(sizeof(*resolv_line) * LINESIZE)) == NULL) {
-                       ha_alert("parsing [%s:%d] : out of memory.\n",
-                                file, linenum);
-                       err_code |= ERR_ALERT | ERR_FATAL;
-                       goto resolv_out;
-               }
-
-               if ((f = fopen("/etc/resolv.conf", "r")) == NULL) {
-                       ha_alert("parsing [%s:%d] : failed to open /etc/resolv.conf.\n",
-                                file, linenum);
-                       err_code |= ERR_ALERT | ERR_FATAL;
-                       goto resolv_out;
-               }
-
-               sk = calloc(1, sizeof(*sk));
-               if (sk == NULL) {
-                       ha_alert("parsing [/etc/resolv.conf:%d] : out of memory.\n",
-                                resolv_linenum);
-                       err_code |= ERR_ALERT | ERR_FATAL;
-                       goto resolv_out;
-               }
-
-               while (fgets(resolv_line, LINESIZE, f) != NULL) {
-                       resolv_linenum++;
-                       if (strncmp(resolv_line, "nameserver", 10) != 0)
-                               continue;
-
-                       address = strtok(resolv_line + 10, whitespace);
-                       if (address == resolv_line + 10)
-                               continue;
-
-                       if (address == NULL) {
-                               ha_warning("parsing [/etc/resolv.conf:%d] : nameserver line is missing address.\n",
-                                          resolv_linenum);
-                               err_code |= ERR_WARN;
-                               continue;
-                       }
-
-                       duplicate_name = 0;
-                       list_for_each_entry(newnameserver, &curr_resolvers->nameservers, list) {
-                               if (strcmp(newnameserver->id, address) == 0) {
-                                       ha_warning("Parsing [/etc/resolv.conf:%d] : generated name for /etc/resolv.conf nameserver '%s' conflicts with another nameserver (declared at %s:%d), it appears to be a duplicate and will be excluded.\n",
-                                                resolv_linenum, address, newnameserver->conf.file, newnameserver->conf.line);
-                                       err_code |= ERR_WARN;
-                                       duplicate_name = 1;
-                               }
-                       }
-
-                       if (duplicate_name)
-                               continue;
-
-                       memset(sk, 0, sizeof(*sk));
-                       if (!str2ip2(address, sk, 1)) {
-                               ha_warning("parsing [/etc/resolv.conf:%d] : address '%s' could not be recognized, nameserver will be excluded.\n",
-                                          resolv_linenum, address);
-                               err_code |= ERR_WARN;
-                               continue;
-                       }
-
-                       set_host_port(sk, 53);
-
-                       proto = protocol_by_family(sk->ss_family);
-                       if (!proto || !proto->connect) {
-                               ha_warning("parsing [/etc/resolv.conf:%d] : '%s' : connect() not supported for this address family.\n",
-                                          resolv_linenum, address);
-                               err_code |= ERR_WARN;
-                               continue;
-                       }
-
-                       if ((newnameserver = calloc(1, sizeof(*newnameserver))) == NULL) {
-                               ha_alert("parsing [/etc/resolv.conf:%d] : out of memory.\n", resolv_linenum);
-                               err_code |= ERR_ALERT | ERR_FATAL;
-                               goto resolv_out;
-                       }
-
-                       newnameserver->conf.file = strdup("/etc/resolv.conf");
-                       if (newnameserver->conf.file == NULL) {
-                               ha_alert("parsing [/etc/resolv.conf:%d] : out of memory.\n", resolv_linenum);
-                               err_code |= ERR_ALERT | ERR_FATAL;
-                               free(newnameserver);
-                               goto resolv_out;
-                       }
-
-                       newnameserver->id = strdup(address);
-                       if (newnameserver->id == NULL) {
-                               ha_alert("parsing [/etc/resolv.conf:%d] : out of memory.\n", resolv_linenum);
-                               err_code |= ERR_ALERT | ERR_FATAL;
-                               free((char *)newnameserver->conf.file);
-                               free(newnameserver);
-                               goto resolv_out;
-                       }
-
-                       newnameserver->resolvers = curr_resolvers;
-                       newnameserver->conf.line = resolv_linenum;
-                       newnameserver->addr = *sk;
-
-                       LIST_ADDQ(&curr_resolvers->nameservers, &newnameserver->list);
-               }
-
-resolv_out:
-               free(sk);
-               free(resolv_line);
-               if (f != NULL)
-                       fclose(f);
-       }
-       else if (strcmp(args[0], "hold") == 0) { /* hold periods */
-               const char *res;
-               unsigned int time;
-
-               if (!*args[2]) {
-                       ha_alert("parsing [%s:%d] : '%s' expects an <event> and a <time> as arguments.\n",
-                                file, linenum, args[0]);
-                       ha_alert("<event> can be either 'valid', 'nx', 'refused', 'timeout', or 'other'\n");
-                       err_code |= ERR_ALERT | ERR_FATAL;
-                       goto out;
-               }
-               res = parse_time_err(args[2], &time, TIME_UNIT_MS);
-               if (res == PARSE_TIME_OVER) {
-                       ha_alert("parsing [%s:%d]: timer overflow in argument <%s> to <%s>, maximum value is 2147483647 ms (~24.8 days).\n",
-                                file, linenum, args[1], args[0]);
-                       err_code |= ERR_ALERT | ERR_FATAL;
-                       goto out;
-               }
-               else if (res == PARSE_TIME_UNDER) {
-                       ha_alert("parsing [%s:%d]: timer underflow in argument <%s> to <%s>, minimum non-null value is 1 ms.\n",
-                                file, linenum, args[1], args[0]);
-                       err_code |= ERR_ALERT | ERR_FATAL;
-                       goto out;
-               }
-               else if (res) {
-                       ha_alert("parsing [%s:%d]: unexpected character '%c' in argument to <%s>.\n",
-                                file, linenum, *res, args[0]);
-                       err_code |= ERR_ALERT | ERR_FATAL;
-                       goto out;
-               }
-               if (strcmp(args[1], "nx") == 0)
-                       curr_resolvers->hold.nx = time;
-               else if (strcmp(args[1], "other") == 0)
-                       curr_resolvers->hold.other = time;
-               else if (strcmp(args[1], "refused") == 0)
-                       curr_resolvers->hold.refused = time;
-               else if (strcmp(args[1], "timeout") == 0)
-                       curr_resolvers->hold.timeout = time;
-               else if (strcmp(args[1], "valid") == 0)
-                       curr_resolvers->hold.valid = time;
-               else if (strcmp(args[1], "obsolete") == 0)
-                       curr_resolvers->hold.obsolete = time;
-               else {
-                       ha_alert("parsing [%s:%d] : '%s' unknown <event>: '%s', expects either 'nx', 'timeout', 'valid', 'obsolete' or 'other'.\n",
-                                file, linenum, args[0], args[1]);
-                       err_code |= ERR_ALERT | ERR_FATAL;
-                       goto out;
-               }
-
-       }
-       else if (strcmp(args[0], "accepted_payload_size") == 0) {
-               int i = 0;
-
-               if (!*args[1]) {
-                       ha_alert("parsing [%s:%d] : '%s' expects <nb> as argument.\n",
-                                file, linenum, args[0]);
-                       err_code |= ERR_ALERT | ERR_FATAL;
-                       goto out;
-               }
-
-               i = atoi(args[1]);
-               if (i < DNS_HEADER_SIZE || i > DNS_MAX_UDP_MESSAGE) {
-                       ha_alert("parsing [%s:%d] : '%s' must be between %d and %d inclusive (was %s).\n",
-                                file, linenum, args[0], DNS_HEADER_SIZE, DNS_MAX_UDP_MESSAGE, args[1]);
-                       err_code |= ERR_ALERT | ERR_FATAL;
-                       goto out;
-               }
-
-               curr_resolvers->accepted_payload_size = i;
-       }
-       else if (strcmp(args[0], "resolution_pool_size") == 0) {
-               ha_alert("parsing [%s:%d] : '%s' directive is not supported anymore (it never appeared in a stable release).\n",
-                          file, linenum, args[0]);
-               err_code |= ERR_ALERT | ERR_FATAL;
-               goto out;
-       }
-       else if (strcmp(args[0], "resolve_retries") == 0) {
-               if (!*args[1]) {
-                       ha_alert("parsing [%s:%d] : '%s' expects <nb> as argument.\n",
-                                file, linenum, args[0]);
-                       err_code |= ERR_ALERT | ERR_FATAL;
-                       goto out;
-               }
-               curr_resolvers->resolve_retries = atoi(args[1]);
-       }
-       else if (strcmp(args[0], "timeout") == 0) {
-               if (!*args[1]) {
-                       ha_alert("parsing [%s:%d] : '%s' expects 'retry' or 'resolve' and <time> as arguments.\n",
-                                file, linenum, args[0]);
-                       err_code |= ERR_ALERT | ERR_FATAL;
-                       goto out;
-               }
-               else if (strcmp(args[1], "retry") == 0 ||
-                        strcmp(args[1], "resolve") == 0) {
-                       const char *res;
-                       unsigned int tout;
-
-                       if (!*args[2]) {
-                               ha_alert("parsing [%s:%d] : '%s %s' expects <time> as argument.\n",
-                                        file, linenum, args[0], args[1]);
-                               err_code |= ERR_ALERT | ERR_FATAL;
-                               goto out;
-                       }
-                       res = parse_time_err(args[2], &tout, TIME_UNIT_MS);
-                       if (res == PARSE_TIME_OVER) {
-                               ha_alert("parsing [%s:%d]: timer overflow in argument <%s> to <%s %s>, maximum value is 2147483647 ms (~24.8 days).\n",
-                                        file, linenum, args[2], args[0], args[1]);
-                               err_code |= ERR_ALERT | ERR_FATAL;
-                               goto out;
-                       }
-                       else if (res == PARSE_TIME_UNDER) {
-                               ha_alert("parsing [%s:%d]: timer underflow in argument <%s> to <%s %s>, minimum non-null value is 1 ms.\n",
-                                        file, linenum, args[2], args[0], args[1]);
-                               err_code |= ERR_ALERT | ERR_FATAL;
-                               goto out;
-                       }
-                       else if (res) {
-                               ha_alert("parsing [%s:%d]: unexpected character '%c' in argument to <%s %s>.\n",
-                                        file, linenum, *res, args[0], args[1]);
-                               err_code |= ERR_ALERT | ERR_FATAL;
-                               goto out;
-                       }
-                       if (args[1][2] == 't')
-                               curr_resolvers->timeout.retry = tout;
-                       else
-                               curr_resolvers->timeout.resolve = tout;
-               }
-               else {
-                       ha_alert("parsing [%s:%d] : '%s' expects 'retry' or 'resolve' and <time> as arguments got '%s'.\n",
-                                file, linenum, args[0], args[1]);
-                       err_code |= ERR_ALERT | ERR_FATAL;
-                       goto out;
-               }
-       }
-       else if (*args[0] != 0) {
-               ha_alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], cursection);
-               err_code |= ERR_ALERT | ERR_FATAL;
-               goto out;
-       }
-
- out:
-       free(errmsg);
-       return err_code;
-}
-
 /*
  * Parse a line in a <listen>, <frontend> or <backend> section.
  * Returns the error code, 0 if OK, or any combination of :
@@ -4236,7 +3851,6 @@ REGISTER_CONFIG_SECTION("userlist",       cfg_parse_users,     NULL);
 REGISTER_CONFIG_SECTION("peers",          cfg_parse_peers,     NULL);
 REGISTER_CONFIG_SECTION("mailers",        cfg_parse_mailers,   NULL);
 REGISTER_CONFIG_SECTION("namespace_list", cfg_parse_netns,     NULL);
-REGISTER_CONFIG_SECTION("resolvers",      cfg_parse_resolvers, NULL);
 
 /*
  * Local variables:
index 9e128ca97a98c4b6e38c22dd190f86c10298877b..34546ac7a0454c12aabd3001ef2407b058bde9e8 100644 (file)
--- a/src/dns.c
+++ b/src/dns.c
@@ -33,6 +33,7 @@
 #include <haproxy/http_rules.h>
 #include <haproxy/log.h>
 #include <haproxy/net_helper.h>
+#include <haproxy/protocol.h>
 #include <haproxy/proxy.h>
 #include <haproxy/sample.h>
 #include <haproxy/server.h>
@@ -49,6 +50,7 @@ struct list sec_resolvers  = LIST_HEAD_INIT(sec_resolvers);
 struct list resolv_srvrq_list = LIST_HEAD_INIT(resolv_srvrq_list);
 
 static THREAD_LOCAL uint64_t resolv_query_id_seed = 0; /* random seed */
+struct resolvers *curr_resolvers = NULL;
 
 DECLARE_STATIC_POOL(resolv_answer_item_pool, "resolv_answer_item", sizeof(struct resolv_answer_item));
 DECLARE_STATIC_POOL(resolv_resolution_pool,  "resolv_resolution",  sizeof(struct resolv_resolution));
@@ -2932,6 +2934,390 @@ int check_action_do_resolve(struct act_rule *rule, struct proxy *px, char **err)
 
        return 1;
 }
+/*
+ * Parse a <resolvers> section.
+ * Returns the error code, 0 if OK, or any combination of :
+ *  - ERR_ABORT: must abort ASAP
+ *  - ERR_FATAL: we can continue parsing but not start the service
+ *  - ERR_WARN: a warning has been emitted
+ *  - ERR_ALERT: an alert has been emitted
+ * Only the two first ones can stop processing, the two others are just
+ * indicators.
+ */
+int cfg_parse_resolvers(const char *file, int linenum, char **args, int kwm)
+{
+       const char *err;
+       int err_code = 0;
+       char *errmsg = NULL;
+
+       if (strcmp(args[0], "resolvers") == 0) { /* new resolvers section */
+               if (!*args[1]) {
+                       ha_alert("parsing [%s:%d] : missing name for resolvers section.\n", file, linenum);
+                       err_code |= ERR_ALERT | ERR_ABORT;
+                       goto out;
+               }
+
+               err = invalid_char(args[1]);
+               if (err) {
+                       ha_alert("parsing [%s:%d] : character '%c' is not permitted in '%s' name '%s'.\n",
+                                file, linenum, *err, args[0], args[1]);
+                       err_code |= ERR_ALERT | ERR_ABORT;
+                       goto out;
+               }
+
+               list_for_each_entry(curr_resolvers, &sec_resolvers, list) {
+                       /* Error if two resolvers owns the same name */
+                       if (strcmp(curr_resolvers->id, args[1]) == 0) {
+                               ha_alert("Parsing [%s:%d]: resolvers '%s' has same name as another resolvers (declared at %s:%d).\n",
+                                        file, linenum, args[1], curr_resolvers->conf.file, curr_resolvers->conf.line);
+                               err_code |= ERR_ALERT | ERR_ABORT;
+                       }
+               }
+
+               if ((curr_resolvers = calloc(1, sizeof(*curr_resolvers))) == NULL) {
+                       ha_alert("parsing [%s:%d] : out of memory.\n", file, linenum);
+                       err_code |= ERR_ALERT | ERR_ABORT;
+                       goto out;
+               }
+
+               /* default values */
+               LIST_ADDQ(&sec_resolvers, &curr_resolvers->list);
+               curr_resolvers->conf.file = strdup(file);
+               curr_resolvers->conf.line = linenum;
+               curr_resolvers->id = strdup(args[1]);
+               curr_resolvers->query_ids = EB_ROOT;
+               /* default maximum response size */
+               curr_resolvers->accepted_payload_size = 512;
+               /* default hold period for nx, other, refuse and timeout is 30s */
+               curr_resolvers->hold.nx = 30000;
+               curr_resolvers->hold.other = 30000;
+               curr_resolvers->hold.refused = 30000;
+               curr_resolvers->hold.timeout = 30000;
+               curr_resolvers->hold.obsolete = 0;
+               /* default hold period for valid is 10s */
+               curr_resolvers->hold.valid = 10000;
+               curr_resolvers->timeout.resolve = 1000;
+               curr_resolvers->timeout.retry   = 1000;
+               curr_resolvers->resolve_retries = 3;
+               curr_resolvers->nb_nameservers  = 0;
+               LIST_INIT(&curr_resolvers->nameservers);
+               LIST_INIT(&curr_resolvers->resolutions.curr);
+               LIST_INIT(&curr_resolvers->resolutions.wait);
+               HA_SPIN_INIT(&curr_resolvers->lock);
+       }
+       else if (strcmp(args[0], "nameserver") == 0) { /* nameserver definition */
+               struct dns_nameserver *newnameserver = NULL;
+               struct sockaddr_storage *sk;
+               int port1, port2;
+
+               if (!*args[2]) {
+                       ha_alert("parsing [%s:%d] : '%s' expects <name> and <addr>[:<port>] as arguments.\n",
+                                file, linenum, args[0]);
+                       err_code |= ERR_ALERT | ERR_FATAL;
+                       goto out;
+               }
+
+               err = invalid_char(args[1]);
+               if (err) {
+                       ha_alert("parsing [%s:%d] : character '%c' is not permitted in server name '%s'.\n",
+                                file, linenum, *err, args[1]);
+                       err_code |= ERR_ALERT | ERR_FATAL;
+                       goto out;
+               }
+
+               list_for_each_entry(newnameserver, &curr_resolvers->nameservers, list) {
+                       /* Error if two resolvers owns the same name */
+                       if (strcmp(newnameserver->id, args[1]) == 0) {
+                               ha_alert("Parsing [%s:%d]: nameserver '%s' has same name as another nameserver (declared at %s:%d).\n",
+                                        file, linenum, args[1], newnameserver->conf.file, newnameserver->conf.line);
+                               err_code |= ERR_ALERT | ERR_FATAL;
+                       }
+               }
+
+               if ((newnameserver = calloc(1, sizeof(*newnameserver))) == NULL) {
+                       ha_alert("parsing [%s:%d] : out of memory.\n", file, linenum);
+                       err_code |= ERR_ALERT | ERR_ABORT;
+                       goto out;
+               }
+
+               /* the nameservers are linked backward first */
+               LIST_ADDQ(&curr_resolvers->nameservers, &newnameserver->list);
+               newnameserver->resolvers = curr_resolvers;
+               newnameserver->conf.file = strdup(file);
+               newnameserver->conf.line = linenum;
+               newnameserver->id = strdup(args[1]);
+
+               sk = str2sa_range(args[2], NULL, &port1, &port2, NULL, NULL,
+                                 &errmsg, NULL, NULL, PA_O_RESOLVE | PA_O_PORT_OK | PA_O_PORT_MAND | PA_O_DGRAM);
+               if (!sk) {
+                       ha_alert("parsing [%s:%d] : '%s %s' : %s\n", file, linenum, args[0], args[1], errmsg);
+                       err_code |= ERR_ALERT | ERR_FATAL;
+                       goto out;
+               }
+
+               newnameserver->addr = *sk;
+       }
+       else if (strcmp(args[0], "parse-resolv-conf") == 0) {
+               struct dns_nameserver *newnameserver = NULL;
+               const char *whitespace = "\r\n\t ";
+               char *resolv_line = NULL;
+               int resolv_linenum = 0;
+               FILE *f = NULL;
+               char *address = NULL;
+               struct sockaddr_storage *sk = NULL;
+               struct protocol *proto;
+               int duplicate_name = 0;
+
+               if ((resolv_line = malloc(sizeof(*resolv_line) * LINESIZE)) == NULL) {
+                       ha_alert("parsing [%s:%d] : out of memory.\n",
+                                file, linenum);
+                       err_code |= ERR_ALERT | ERR_FATAL;
+                       goto resolv_out;
+               }
+
+               if ((f = fopen("/etc/resolv.conf", "r")) == NULL) {
+                       ha_alert("parsing [%s:%d] : failed to open /etc/resolv.conf.\n",
+                                file, linenum);
+                       err_code |= ERR_ALERT | ERR_FATAL;
+                       goto resolv_out;
+               }
+
+               sk = calloc(1, sizeof(*sk));
+               if (sk == NULL) {
+                       ha_alert("parsing [/etc/resolv.conf:%d] : out of memory.\n",
+                                resolv_linenum);
+                       err_code |= ERR_ALERT | ERR_FATAL;
+                       goto resolv_out;
+               }
+
+               while (fgets(resolv_line, LINESIZE, f) != NULL) {
+                       resolv_linenum++;
+                       if (strncmp(resolv_line, "nameserver", 10) != 0)
+                               continue;
+
+                       address = strtok(resolv_line + 10, whitespace);
+                       if (address == resolv_line + 10)
+                               continue;
+
+                       if (address == NULL) {
+                               ha_warning("parsing [/etc/resolv.conf:%d] : nameserver line is missing address.\n",
+                                          resolv_linenum);
+                               err_code |= ERR_WARN;
+                               continue;
+                       }
+
+                       duplicate_name = 0;
+                       list_for_each_entry(newnameserver, &curr_resolvers->nameservers, list) {
+                               if (strcmp(newnameserver->id, address) == 0) {
+                                       ha_warning("Parsing [/etc/resolv.conf:%d] : generated name for /etc/resolv.conf nameserver '%s' conflicts with another nameserver (declared at %s:%d), it appears to be a duplicate and will be excluded.\n",
+                                                resolv_linenum, address, newnameserver->conf.file, newnameserver->conf.line);
+                                       err_code |= ERR_WARN;
+                                       duplicate_name = 1;
+                               }
+                       }
+
+                       if (duplicate_name)
+                               continue;
+
+                       memset(sk, 0, sizeof(*sk));
+                       if (!str2ip2(address, sk, 1)) {
+                               ha_warning("parsing [/etc/resolv.conf:%d] : address '%s' could not be recognized, nameserver will be excluded.\n",
+                                          resolv_linenum, address);
+                               err_code |= ERR_WARN;
+                               continue;
+                       }
+
+                       set_host_port(sk, 53);
+
+                       proto = protocol_by_family(sk->ss_family);
+                       if (!proto || !proto->connect) {
+                               ha_warning("parsing [/etc/resolv.conf:%d] : '%s' : connect() not supported for this address family.\n",
+                                          resolv_linenum, address);
+                               err_code |= ERR_WARN;
+                               continue;
+                       }
+
+                       if ((newnameserver = calloc(1, sizeof(*newnameserver))) == NULL) {
+                               ha_alert("parsing [/etc/resolv.conf:%d] : out of memory.\n", resolv_linenum);
+                               err_code |= ERR_ALERT | ERR_FATAL;
+                               goto resolv_out;
+                       }
+
+                       newnameserver->conf.file = strdup("/etc/resolv.conf");
+                       if (newnameserver->conf.file == NULL) {
+                               ha_alert("parsing [/etc/resolv.conf:%d] : out of memory.\n", resolv_linenum);
+                               err_code |= ERR_ALERT | ERR_FATAL;
+                               free(newnameserver);
+                               goto resolv_out;
+                       }
+
+                       newnameserver->id = strdup(address);
+                       if (newnameserver->id == NULL) {
+                               ha_alert("parsing [/etc/resolv.conf:%d] : out of memory.\n", resolv_linenum);
+                               err_code |= ERR_ALERT | ERR_FATAL;
+                               free((char *)newnameserver->conf.file);
+                               free(newnameserver);
+                               goto resolv_out;
+                       }
+
+                       newnameserver->resolvers = curr_resolvers;
+                       newnameserver->conf.line = resolv_linenum;
+                       newnameserver->addr = *sk;
+
+                       LIST_ADDQ(&curr_resolvers->nameservers, &newnameserver->list);
+               }
+
+resolv_out:
+               free(sk);
+               free(resolv_line);
+               if (f != NULL)
+                       fclose(f);
+       }
+       else if (strcmp(args[0], "hold") == 0) { /* hold periods */
+               const char *res;
+               unsigned int time;
+
+               if (!*args[2]) {
+                       ha_alert("parsing [%s:%d] : '%s' expects an <event> and a <time> as arguments.\n",
+                                file, linenum, args[0]);
+                       ha_alert("<event> can be either 'valid', 'nx', 'refused', 'timeout', or 'other'\n");
+                       err_code |= ERR_ALERT | ERR_FATAL;
+                       goto out;
+               }
+               res = parse_time_err(args[2], &time, TIME_UNIT_MS);
+               if (res == PARSE_TIME_OVER) {
+                       ha_alert("parsing [%s:%d]: timer overflow in argument <%s> to <%s>, maximum value is 2147483647 ms (~24.8 days).\n",
+                                file, linenum, args[1], args[0]);
+                       err_code |= ERR_ALERT | ERR_FATAL;
+                       goto out;
+               }
+               else if (res == PARSE_TIME_UNDER) {
+                       ha_alert("parsing [%s:%d]: timer underflow in argument <%s> to <%s>, minimum non-null value is 1 ms.\n",
+                                file, linenum, args[1], args[0]);
+                       err_code |= ERR_ALERT | ERR_FATAL;
+                       goto out;
+               }
+               else if (res) {
+                       ha_alert("parsing [%s:%d]: unexpected character '%c' in argument to <%s>.\n",
+                                file, linenum, *res, args[0]);
+                       err_code |= ERR_ALERT | ERR_FATAL;
+                       goto out;
+               }
+               if (strcmp(args[1], "nx") == 0)
+                       curr_resolvers->hold.nx = time;
+               else if (strcmp(args[1], "other") == 0)
+                       curr_resolvers->hold.other = time;
+               else if (strcmp(args[1], "refused") == 0)
+                       curr_resolvers->hold.refused = time;
+               else if (strcmp(args[1], "timeout") == 0)
+                       curr_resolvers->hold.timeout = time;
+               else if (strcmp(args[1], "valid") == 0)
+                       curr_resolvers->hold.valid = time;
+               else if (strcmp(args[1], "obsolete") == 0)
+                       curr_resolvers->hold.obsolete = time;
+               else {
+                       ha_alert("parsing [%s:%d] : '%s' unknown <event>: '%s', expects either 'nx', 'timeout', 'valid', 'obsolete' or 'other'.\n",
+                                file, linenum, args[0], args[1]);
+                       err_code |= ERR_ALERT | ERR_FATAL;
+                       goto out;
+               }
+
+       }
+       else if (strcmp(args[0], "accepted_payload_size") == 0) {
+               int i = 0;
+
+               if (!*args[1]) {
+                       ha_alert("parsing [%s:%d] : '%s' expects <nb> as argument.\n",
+                                file, linenum, args[0]);
+                       err_code |= ERR_ALERT | ERR_FATAL;
+                       goto out;
+               }
+
+               i = atoi(args[1]);
+               if (i < DNS_HEADER_SIZE || i > DNS_MAX_UDP_MESSAGE) {
+                       ha_alert("parsing [%s:%d] : '%s' must be between %d and %d inclusive (was %s).\n",
+                                file, linenum, args[0], DNS_HEADER_SIZE, DNS_MAX_UDP_MESSAGE, args[1]);
+                       err_code |= ERR_ALERT | ERR_FATAL;
+                       goto out;
+               }
+
+               curr_resolvers->accepted_payload_size = i;
+       }
+       else if (strcmp(args[0], "resolution_pool_size") == 0) {
+               ha_alert("parsing [%s:%d] : '%s' directive is not supported anymore (it never appeared in a stable release).\n",
+                          file, linenum, args[0]);
+               err_code |= ERR_ALERT | ERR_FATAL;
+               goto out;
+       }
+       else if (strcmp(args[0], "resolve_retries") == 0) {
+               if (!*args[1]) {
+                       ha_alert("parsing [%s:%d] : '%s' expects <nb> as argument.\n",
+                                file, linenum, args[0]);
+                       err_code |= ERR_ALERT | ERR_FATAL;
+                       goto out;
+               }
+               curr_resolvers->resolve_retries = atoi(args[1]);
+       }
+       else if (strcmp(args[0], "timeout") == 0) {
+               if (!*args[1]) {
+                       ha_alert("parsing [%s:%d] : '%s' expects 'retry' or 'resolve' and <time> as arguments.\n",
+                                file, linenum, args[0]);
+                       err_code |= ERR_ALERT | ERR_FATAL;
+                       goto out;
+               }
+               else if (strcmp(args[1], "retry") == 0 ||
+                        strcmp(args[1], "resolve") == 0) {
+                       const char *res;
+                       unsigned int tout;
+
+                       if (!*args[2]) {
+                               ha_alert("parsing [%s:%d] : '%s %s' expects <time> as argument.\n",
+                                        file, linenum, args[0], args[1]);
+                               err_code |= ERR_ALERT | ERR_FATAL;
+                               goto out;
+                       }
+                       res = parse_time_err(args[2], &tout, TIME_UNIT_MS);
+                       if (res == PARSE_TIME_OVER) {
+                               ha_alert("parsing [%s:%d]: timer overflow in argument <%s> to <%s %s>, maximum value is 2147483647 ms (~24.8 days).\n",
+                                        file, linenum, args[2], args[0], args[1]);
+                               err_code |= ERR_ALERT | ERR_FATAL;
+                               goto out;
+                       }
+                       else if (res == PARSE_TIME_UNDER) {
+                               ha_alert("parsing [%s:%d]: timer underflow in argument <%s> to <%s %s>, minimum non-null value is 1 ms.\n",
+                                        file, linenum, args[2], args[0], args[1]);
+                               err_code |= ERR_ALERT | ERR_FATAL;
+                               goto out;
+                       }
+                       else if (res) {
+                               ha_alert("parsing [%s:%d]: unexpected character '%c' in argument to <%s %s>.\n",
+                                        file, linenum, *res, args[0], args[1]);
+                               err_code |= ERR_ALERT | ERR_FATAL;
+                               goto out;
+                       }
+                       if (args[1][2] == 't')
+                               curr_resolvers->timeout.retry = tout;
+                       else
+                               curr_resolvers->timeout.resolve = tout;
+               }
+               else {
+                       ha_alert("parsing [%s:%d] : '%s' expects 'retry' or 'resolve' and <time> as arguments got '%s'.\n",
+                                file, linenum, args[0], args[1]);
+                       err_code |= ERR_ALERT | ERR_FATAL;
+                       goto out;
+               }
+       }
+       else if (*args[0] != 0) {
+               ha_alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], cursection);
+               err_code |= ERR_ALERT | ERR_FATAL;
+               goto out;
+       }
+
+ out:
+       free(errmsg);
+       return err_code;
+}
 
+REGISTER_CONFIG_SECTION("resolvers",      cfg_parse_resolvers, NULL);
 REGISTER_POST_DEINIT(resolvers_deinit);
 REGISTER_CONFIG_POSTPARSER("dns runtime resolver", resolvers_finalize_config);