mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-11-28 14:21:00 +01:00
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:
parent
d30e9a1709
commit
8a55193d4e
386
src/cfgparse.c
386
src/cfgparse.c
@ -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
386
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);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user