MEDIUM: resolvers: move resolvers section parsing from cfgparse.c to dns.c

The resolver section parsing is moved from cfgparse.c to dns.c
This commit is contained in:
Emeric Brun 2020-11-24 17:24:34 +01:00 committed by Willy Tarreau
parent d30e9a1709
commit 8a55193d4e
2 changed files with 386 additions and 386 deletions

View 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:

386
src/dns.c
View File

@ -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);