MEDIUM: resolvers: move resolvers section parsing from cfgparse.c to dns.c
The resolver section parsing is moved from cfgparse.c to dns.c
diff --git a/src/cfgparse.c b/src/cfgparse.c
index 4840008..0c0638e 100644
--- a/src/cfgparse.c
+++ b/src/cfgparse.c
@@ -909,391 +909,6 @@
}
/*
- * 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 :
* - ERR_ABORT: must abort ASAP
@@ -4236,7 +3851,6 @@
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:
diff --git a/src/dns.c b/src/dns.c
index 9e128ca..34546ac 100644
--- 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 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 @@
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);