MAJOR/REORG: dns: DNS resolution task and requester queues
This patch is a major upgrade of the internal run-time DNS resolver in HAProxy and it brings the following 2 main changes: 1. DNS resolution task Up to now, DNS resolution was triggered by the health check task. From now, DNS resolution task is autonomous. It is started by HAProxy right after the scheduler is available and it is woken either when a network IO occurs for one of its nameserver or when a timeout is matched. From now, this means we can enable DNS resolution for a server without enabling health checking. 2. Introduction of a dns_requester structure Up to now, DNS resolution was purposely made for resolving server hostnames. The idea, is to ensure that any HAProxy internal object should be able to trigger a DNS resolution. For this purpose, 2 things has to be done: - clean up the DNS code from the server structure (this was already quite clean actually) and clean up the server's callbacks from manipulating too much DNS resolution - create an agnostic structure which allows linking a DNS resolution and a requester of any type (using obj_type enum) 3. Manage requesters through queues Up to now, there was an uniq relationship between a resolution and it's owner (aka the requester now). It's a shame, because in some cases, multiple objects may share the same hostname and may benefit from a resolution being performed by a third party. This patch introduces the notion of queues, which are basically lists of either currently running resolution or waiting ones. The resolutions are now available as a pool, which belongs to the resolvers. The pool has has a default size of 64 resolutions per resolvers and is allocated at configuration parsing.
This commit is contained in:
parent
8ea0bcc911
commit
201c07f681
@ -11597,9 +11597,6 @@ resolution at run time.
|
||||
Whether run time server name resolution has been enable or not, HAProxy will
|
||||
carry on doing the first resolution when parsing the configuration.
|
||||
|
||||
Bear in mind that DNS resolution is triggered by health checks. This makes
|
||||
health checks mandatory to allow DNS resolution.
|
||||
|
||||
|
||||
5.3.1. Global overview
|
||||
----------------------
|
||||
@ -11703,6 +11700,11 @@ hold <status> <period>
|
||||
resolution is triggered after <period> modulo the <inter> parameter of
|
||||
the healch check.
|
||||
|
||||
resolution_pool_size <nb>
|
||||
Defines the number of resolutions available in the pool for this resolvers.
|
||||
If not defines, it defaults to 64. If your configuration requires more than
|
||||
<nb>, then HAProxy will return an error when parsing the configuration.
|
||||
|
||||
resolve_retries <nb>
|
||||
Defines the number <nb> of queries to send to resolve a server name before
|
||||
giving up.
|
||||
|
@ -28,7 +28,6 @@
|
||||
const char *get_check_status_description(short check_status);
|
||||
const char *get_check_status_info(short check_status);
|
||||
void __health_adjust(struct server *s, short status);
|
||||
int trigger_resolution(struct server *s);
|
||||
|
||||
extern struct data_cb check_conn_cb;
|
||||
|
||||
|
@ -44,11 +44,24 @@ int dns_send_query(struct dns_resolution *resolution);
|
||||
void dns_print_current_resolutions(struct dns_resolvers *resolvers);
|
||||
void dns_update_resolvers_timeout(struct dns_resolvers *resolvers);
|
||||
void dns_reset_resolution(struct dns_resolution *resolution);
|
||||
void dns_resolution_free(struct dns_resolvers *resolvers, struct dns_resolution *resolution);
|
||||
void dns_rm_requester_from_resolution(struct dns_requester *requester, struct dns_resolution *resolution);
|
||||
int dns_check_resolution_queue(struct dns_resolvers *resolvers);
|
||||
unsigned short dns_response_get_query_id(unsigned char *resp);
|
||||
struct dns_resolution *dns_alloc_resolution(void);
|
||||
void dns_free_resolution(struct dns_resolution *resolution);
|
||||
struct chunk *dns_cache_key(int query_type, char *hostname_dn, int hostname_dn_len, struct chunk *buf);
|
||||
struct lru64 *dns_cache_lookup(int query_type, char *hostname_dn, int hostname_dn_len, int valid_period, void *cache_domain);
|
||||
int dns_link_resolution(void *requester, int requester_type, struct dns_resolution *resolution);
|
||||
struct dns_resolution *dns_resolution_list_get(struct dns_resolvers *resolvers, char *hostname_dn, int query_type);
|
||||
int dns_trigger_resolution(struct dns_resolution *resolution);
|
||||
int dns_alloc_resolution_pool(struct dns_resolvers *resolvers);
|
||||
|
||||
void dump_dns_config(void);
|
||||
|
||||
/*
|
||||
* erases all information of a dns_requester structure
|
||||
*/
|
||||
#define dns_clear_requester(requester) memset(requester, '\0', sizeof(*requester));
|
||||
|
||||
#endif // _PROTO_DNS_H
|
||||
|
@ -53,8 +53,8 @@ struct server *cli_find_server(struct appctx *appctx, char *arg);
|
||||
|
||||
/* functions related to server name resolution */
|
||||
int snr_update_srv_status(struct server *s);
|
||||
int snr_resolution_cb(struct dns_resolution *resolution, struct dns_nameserver *nameserver);
|
||||
int snr_resolution_error_cb(struct dns_resolution *resolution, int error_code);
|
||||
int snr_resolution_cb(struct dns_requester *requester, struct dns_nameserver *nameserver);
|
||||
int snr_resolution_error_cb(struct dns_requester *requester, int error_code);
|
||||
struct server *snr_check_ip_callback(struct server *srv, void *ip, unsigned char *ip_family);
|
||||
|
||||
/* increase the number of cumulated connections on the designated server */
|
||||
|
@ -82,6 +82,9 @@
|
||||
/* DNS header size */
|
||||
#define DNS_HEADER_SIZE sizeof(struct dns_header)
|
||||
|
||||
/* DNS resolution pool size, per resolvers section */
|
||||
#define DNS_DEFAULT_RESOLUTION_POOL_SIZE 64
|
||||
|
||||
/* DNS request or response header structure */
|
||||
struct dns_header {
|
||||
uint16_t id;
|
||||
@ -157,7 +160,12 @@ struct dns_resolvers {
|
||||
int other; /* other dns response errors */
|
||||
} hold;
|
||||
struct task *t; /* timeout management */
|
||||
struct list curr_resolution; /* current running resolutions */
|
||||
int resolution_pool_size; /* size of the resolution pool associated to this resolvers section */
|
||||
struct {
|
||||
struct list pool; /* resolution pool dedicated to this resolvers section */
|
||||
struct list wait; /* resolutions managed to this resolvers section */
|
||||
struct list curr; /* current running resolutions */
|
||||
} resolution;
|
||||
struct eb_root query_ids; /* tree to quickly lookup/retrieve query ids currently in use */
|
||||
/* used by each nameserver, but stored in resolvers since there must */
|
||||
/* be a unique relation between an eb_root and an eb_node (resolution) */
|
||||
@ -218,11 +226,15 @@ struct dns_options {
|
||||
*/
|
||||
struct dns_resolution {
|
||||
struct list list; /* resolution list */
|
||||
void *requester; /* owner of this name resolution */
|
||||
struct {
|
||||
struct list wait; /* list of standby requesters for this resolution */
|
||||
struct list curr; /* list of requesters currently active on this resolution */
|
||||
} requester;
|
||||
int (*requester_cb)(struct dns_resolution *, struct dns_nameserver *);
|
||||
/* requester callback for valid response */
|
||||
int (*requester_error_cb)(struct dns_resolution *, int);
|
||||
/* requester callback, for error management */
|
||||
int uuid; /* unique id (used for debugging purpose) */
|
||||
char *hostname_dn; /* server hostname in domain name label format */
|
||||
int hostname_dn_len; /* server domain name label len */
|
||||
unsigned int last_resolution; /* time of the lastest valid resolution */
|
||||
@ -244,6 +256,19 @@ struct dns_resolution {
|
||||
struct chunk response_buffer; /* buffer used as a data store for <response> above TODO: optimize the size (might be smaller) */
|
||||
};
|
||||
|
||||
/*
|
||||
* structure used to describe the owner of a DNS resolution.
|
||||
*/
|
||||
struct dns_requester {
|
||||
struct list list; /* requester list */
|
||||
enum obj_type *requester; /* pointer to the requester */
|
||||
int prefered_query_type; /* prefered query type */
|
||||
int (*requester_cb)(struct dns_requester *, struct dns_nameserver *);
|
||||
/* requester callback for valid response */
|
||||
int (*requester_error_cb)(struct dns_requester *, int);
|
||||
/* requester callback, for error management */
|
||||
};
|
||||
|
||||
/* last resolution status code */
|
||||
enum {
|
||||
RSLV_STATUS_NONE = 0, /* no resolution occured yet */
|
||||
|
@ -254,6 +254,7 @@ struct server {
|
||||
struct check check; /* health-check specific configuration */
|
||||
struct check agent; /* agent specific configuration */
|
||||
|
||||
struct dns_requester *dns_requester; /* used to link a server to its DNS resolution */
|
||||
char *resolvers_id; /* resolvers section used by this server */
|
||||
struct dns_resolvers *resolvers; /* pointer to the resolvers structure used by this server */
|
||||
char *hostname; /* server hostname */
|
||||
|
@ -59,6 +59,7 @@
|
||||
#include <proto/channel.h>
|
||||
#include <proto/checks.h>
|
||||
#include <proto/compression.h>
|
||||
#include <proto/dns.h>
|
||||
#include <proto/stats.h>
|
||||
#include <proto/filters.h>
|
||||
#include <proto/frontend.h>
|
||||
@ -2164,8 +2165,12 @@ int cfg_parse_resolvers(const char *file, int linenum, char **args, int kwm)
|
||||
curr_resolvers->hold.valid = 10000;
|
||||
curr_resolvers->timeout.retry = 1000;
|
||||
curr_resolvers->resolve_retries = 3;
|
||||
/* default resolution pool size */
|
||||
curr_resolvers->resolution_pool_size = DNS_DEFAULT_RESOLUTION_POOL_SIZE;
|
||||
LIST_INIT(&curr_resolvers->nameserver_list);
|
||||
LIST_INIT(&curr_resolvers->curr_resolution);
|
||||
LIST_INIT(&curr_resolvers->resolution.curr);
|
||||
LIST_INIT(&curr_resolvers->resolution.wait);
|
||||
LIST_INIT(&curr_resolvers->resolution.pool);
|
||||
}
|
||||
else if (strcmp(args[0], "nameserver") == 0) { /* nameserver definition */
|
||||
struct sockaddr_storage *sk;
|
||||
@ -2277,6 +2282,15 @@ int cfg_parse_resolvers(const char *file, int linenum, char **args, int kwm)
|
||||
}
|
||||
|
||||
}
|
||||
else if (strcmp(args[0], "resolution_pool_size") == 0) {
|
||||
if (!*args[1]) {
|
||||
Alert("parsing [%s:%d] : '%s' expects <nb> as argument.\n",
|
||||
file, linenum, args[0]);
|
||||
err_code |= ERR_ALERT | ERR_FATAL;
|
||||
goto out;
|
||||
}
|
||||
curr_resolvers->resolution_pool_size = atoi(args[1]);
|
||||
}
|
||||
else if (strcmp(args[0], "resolve_retries") == 0) {
|
||||
if (!*args[1]) {
|
||||
Alert("parsing [%s:%d] : '%s' expects <nb> as argument.\n",
|
||||
@ -7365,6 +7379,7 @@ int check_config_validity()
|
||||
unsigned int next_pxid = 1;
|
||||
struct bind_conf *bind_conf;
|
||||
char *err;
|
||||
struct dns_resolvers *curr_resolvers;
|
||||
|
||||
bind_conf = NULL;
|
||||
/*
|
||||
@ -7385,6 +7400,15 @@ int check_config_validity()
|
||||
|
||||
pool2_capture = create_pool("capture", global.tune.cookie_len, MEM_F_SHARED);
|
||||
|
||||
/* allocate pool of resolution per resolvers */
|
||||
list_for_each_entry(curr_resolvers, &dns_resolvers, list) {
|
||||
if (dns_alloc_resolution_pool(curr_resolvers) != 0) {
|
||||
/* error message is already displayed by dns_alloc_resolution_pool() */
|
||||
err_code |= ERR_ALERT | ERR_ABORT;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
/* Post initialisation of the users and groups lists. */
|
||||
err_code = userlist_postinit();
|
||||
if (err_code != ERR_NONE)
|
||||
@ -8514,8 +8538,15 @@ out_uri_auth_compat:
|
||||
newsrv->id, newsrv->resolvers_id);
|
||||
cfgerr++;
|
||||
} else {
|
||||
if (newsrv->resolution)
|
||||
if (newsrv->hostname_dn) {
|
||||
newsrv->resolvers = curr_resolvers;
|
||||
if (dns_link_resolution(newsrv, OBJ_TYPE_SERVER, NULL) != 0) {
|
||||
Alert("config : %s '%s', server '%s': unable to set DNS resolution\n",
|
||||
proxy_type_str(curproxy), curproxy->id,
|
||||
newsrv->id);
|
||||
cfgerr++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
89
src/checks.c
89
src/checks.c
@ -695,7 +695,7 @@ static void chk_report_conn_err(struct connection *conn, int errno_bck, int expi
|
||||
* Let's trigger a DNS resolution if none are currently running.
|
||||
*/
|
||||
if ((check->server->resolution) && (check->server->resolution->step == RSLV_STEP_NONE))
|
||||
trigger_resolution(check->server);
|
||||
dns_trigger_resolution(check->server->resolution);
|
||||
|
||||
}
|
||||
else if ((conn->flags & (CO_FL_CONNECTED|CO_FL_WAIT_L6_CONN)) == CO_FL_WAIT_L6_CONN) {
|
||||
@ -2207,23 +2207,6 @@ static struct task *process_chk_conn(struct task *t)
|
||||
static struct task *process_chk(struct task *t)
|
||||
{
|
||||
struct check *check = t->context;
|
||||
struct server *s = check->server;
|
||||
struct dns_resolution *resolution = s->resolution;
|
||||
struct dns_resolvers *resolvers = s->resolvers;
|
||||
|
||||
/* trigger name resolution */
|
||||
if ((s->check.state & CHK_ST_ENABLED) && (resolution)) {
|
||||
/* check if a no resolution is running for this server */
|
||||
if (resolution->step == RSLV_STEP_NONE) {
|
||||
/*
|
||||
* if there has not been any name resolution for a longer period than
|
||||
* hold.valid, let's trigger a new one.
|
||||
*/
|
||||
if (!resolution->last_resolution || tick_is_expired(tick_add(resolution->last_resolution, resolvers->hold.valid), now_ms)) {
|
||||
trigger_resolution(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (check->type == PR_O2_EXT_CHK)
|
||||
return process_chk_proc(t);
|
||||
@ -2231,76 +2214,6 @@ static struct task *process_chk(struct task *t)
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Initiates a new name resolution:
|
||||
* - generates a query id
|
||||
* - configure the resolution structure
|
||||
* - startup the resolvers task if required
|
||||
*
|
||||
* returns:
|
||||
* - 0 in case of error or if resolution already running
|
||||
* - 1 if everything started properly
|
||||
*/
|
||||
int trigger_resolution(struct server *s)
|
||||
{
|
||||
struct dns_resolution *resolution = NULL;
|
||||
struct dns_resolvers *resolvers = NULL;
|
||||
int query_id;
|
||||
int i;
|
||||
|
||||
resolution = s->resolution;
|
||||
resolvers = s->resolvers;
|
||||
|
||||
/*
|
||||
* check if a resolution has already been started for this server
|
||||
* return directly to avoid resolution pill up
|
||||
*/
|
||||
if (resolution->step != RSLV_STEP_NONE)
|
||||
return 0;
|
||||
|
||||
/* generates a query id */
|
||||
i = 0;
|
||||
do {
|
||||
query_id = dns_rnd16();
|
||||
/* we do try only 100 times to find a free query id */
|
||||
if (i++ > 100) {
|
||||
chunk_printf(&trash, "could not generate a query id for %s/%s, in resolvers %s",
|
||||
s->proxy->id, s->id, resolvers->id);
|
||||
|
||||
send_log(s->proxy, LOG_NOTICE, "%s.\n", trash.str);
|
||||
return 0;
|
||||
}
|
||||
} while (eb32_lookup(&resolvers->query_ids, query_id));
|
||||
|
||||
LIST_ADDQ(&resolvers->curr_resolution, &resolution->list);
|
||||
|
||||
/* now update resolution parameters */
|
||||
resolution->query_id = query_id;
|
||||
resolution->qid.key = query_id;
|
||||
resolution->step = RSLV_STEP_RUNNING;
|
||||
if (s->dns_opts.family_prio == AF_INET) {
|
||||
resolution->query_type = DNS_RTYPE_A;
|
||||
} else {
|
||||
resolution->query_type = DNS_RTYPE_AAAA;
|
||||
}
|
||||
resolution->try = resolvers->resolve_retries;
|
||||
resolution->try_cname = 0;
|
||||
resolution->nb_responses = 0;
|
||||
eb32_insert(&resolvers->query_ids, &resolution->qid);
|
||||
|
||||
dns_send_query(resolution);
|
||||
resolution->try -= 1;
|
||||
|
||||
/* update wakeup date if this resolution is the only one in the FIFO list */
|
||||
if (dns_check_resolution_queue(resolvers) == 1) {
|
||||
/* update task timeout */
|
||||
dns_update_resolvers_timeout(resolvers);
|
||||
task_queue(resolvers->t);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int start_check_task(struct check *check, int mininter,
|
||||
int nbcheck, int srvpos)
|
||||
{
|
||||
|
309
src/server.c
309
src/server.c
@ -47,7 +47,6 @@
|
||||
static void srv_update_state(struct server *srv, int version, char **params);
|
||||
static int srv_apply_lastaddr(struct server *srv, int *err_code);
|
||||
static int srv_set_fqdn(struct server *srv, const char *fqdn);
|
||||
static void srv_free_dns_resolution(struct server *srv);
|
||||
|
||||
/* List head of all known server keywords */
|
||||
static struct srv_kw_list srv_keywords = {
|
||||
@ -1652,60 +1651,29 @@ static void srv_ssl_settings_cpy(struct server *srv, struct server *src)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Allocate <srv> server dns resolution.
|
||||
* Prepare <srv> for hostname resolution.
|
||||
* May be safely called with a default server as <src> argument (without hostname).
|
||||
* Returns -1 in case of any allocation failure, 0 if not.
|
||||
*/
|
||||
static int srv_alloc_dns_resolution(struct server *srv, const char *hostname)
|
||||
static int srv_prepare_for_resolution(struct server *srv, const char *hostname)
|
||||
{
|
||||
struct dns_resolution *dst_dns_rslt;
|
||||
|
||||
if (!hostname)
|
||||
return 0;
|
||||
|
||||
free(srv->hostname);
|
||||
srv->hostname = strdup(hostname);
|
||||
dst_dns_rslt = dns_alloc_resolution();
|
||||
|
||||
srv->hostname_dn_len = dns_str_to_dn_label_len(hostname);
|
||||
srv->hostname_dn = calloc(srv->hostname_dn_len + 1, sizeof(char));
|
||||
|
||||
if (!srv->hostname || !dst_dns_rslt || !srv->hostname_dn)
|
||||
if (!srv->hostname || !srv->hostname_dn)
|
||||
goto err;
|
||||
|
||||
srv->resolution = dst_dns_rslt;
|
||||
|
||||
if (!dns_str_to_dn_label(srv->hostname,
|
||||
srv->hostname_dn,
|
||||
srv->hostname_dn_len + 1))
|
||||
goto err;
|
||||
|
||||
srv->resolution->hostname_dn = srv->hostname_dn;
|
||||
srv->resolution->hostname_dn_len = srv->hostname_dn_len;
|
||||
srv->resolution->revision = 1;
|
||||
srv->resolution->requester = srv;
|
||||
srv->resolution->requester_cb = snr_resolution_cb;
|
||||
srv->resolution->requester_error_cb = snr_resolution_error_cb;
|
||||
srv->resolution->status = RSLV_STATUS_NONE;
|
||||
srv->resolution->step = RSLV_STEP_NONE;
|
||||
/* a first resolution has been done by the configuration parser */
|
||||
srv->resolution->last_resolution = 0;
|
||||
|
||||
if (srv->resolvers_id) {
|
||||
struct dns_resolvers *curr_resolvers;
|
||||
int found = 0;
|
||||
|
||||
list_for_each_entry(curr_resolvers, &dns_resolvers, list) {
|
||||
if (!strcmp(curr_resolvers->id, srv->resolvers_id)) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
goto err;
|
||||
srv->resolvers = curr_resolvers;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
@ -1713,17 +1681,44 @@ static int srv_alloc_dns_resolution(struct server *srv, const char *hostname)
|
||||
srv->hostname = NULL;
|
||||
free(srv->hostname_dn);
|
||||
srv->hostname_dn = NULL;
|
||||
dns_free_resolution(dst_dns_rslt);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void srv_free_dns_resolution(struct server *srv)
|
||||
/*
|
||||
* Free the link between a server and its resolution.
|
||||
* It also performs the following tasks:
|
||||
* - check if resolution can be moved back in the resolvers' pool
|
||||
* (and do it)
|
||||
* - move resolution's hostname_dn and hostname_dn_len to the next requester
|
||||
* available (when applied)
|
||||
*/
|
||||
static void srv_free_from_resolution(struct server *srv)
|
||||
{
|
||||
if (!srv->resolution)
|
||||
return;
|
||||
struct dns_requester *requester;
|
||||
int count;
|
||||
|
||||
dns_free_resolution(srv->resolution);
|
||||
srv->resolution = NULL;
|
||||
/* check if we can move the resolution back to the pool.
|
||||
* if <count> is greater than 1, then we can't */
|
||||
count = 0;
|
||||
list_for_each_entry(requester, &srv->resolution->requester.wait, list) {
|
||||
++count;
|
||||
if (count > 1)
|
||||
break;
|
||||
}
|
||||
list_for_each_entry(requester, &srv->resolution->requester.curr, list) {
|
||||
++count;
|
||||
if (count > 1)
|
||||
break;
|
||||
}
|
||||
if (count <= 1) {
|
||||
/* move the resolution back to the pool */
|
||||
dns_resolution_free(srv->resolvers, srv->resolution);
|
||||
return;
|
||||
}
|
||||
|
||||
dns_rm_requester_from_resolution(srv->dns_requester, srv->resolution);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -2114,7 +2109,7 @@ static int server_template_init(struct server *srv, struct proxy *px)
|
||||
goto err;
|
||||
|
||||
srv_settings_cpy(newsrv, srv, 1);
|
||||
srv_alloc_dns_resolution(newsrv, srv->hostname);
|
||||
srv_prepare_for_resolution(newsrv, srv->hostname);
|
||||
#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
|
||||
if (newsrv->sni_expr) {
|
||||
newsrv->ssl_ctx.sni = srv_sni_sample_parse_expr(newsrv, px, NULL, 0, NULL);
|
||||
@ -2290,7 +2285,7 @@ int parse_server(const char *file, int linenum, char **args, struct proxy *curpr
|
||||
|
||||
/* save hostname and create associated name resolution */
|
||||
if (fqdn) {
|
||||
if (srv_alloc_dns_resolution(newsrv, fqdn) == -1) {
|
||||
if (srv_prepare_for_resolution(newsrv, fqdn) == -1) {
|
||||
Alert("parsing [%s:%d] : Can't create DNS resolution for server '%s'\n",
|
||||
file, linenum, newsrv->id);
|
||||
err_code |= ERR_ALERT | ERR_FATAL;
|
||||
@ -3749,8 +3744,8 @@ int snr_update_srv_status(struct server *s)
|
||||
|
||||
switch (resolution->status) {
|
||||
case RSLV_STATUS_NONE:
|
||||
/* status when HAProxy has just (re)started */
|
||||
trigger_resolution(s);
|
||||
/* status when HAProxy has just (re)started.
|
||||
* Nothing to do, since the task is already automatically started */
|
||||
break;
|
||||
|
||||
case RSLV_STATUS_VALID:
|
||||
@ -3825,23 +3820,27 @@ int snr_update_srv_status(struct server *s)
|
||||
* 0 on error
|
||||
* 1 when no error or safe ignore
|
||||
*/
|
||||
int snr_resolution_cb(struct dns_resolution *resolution, struct dns_nameserver *nameserver)
|
||||
int snr_resolution_cb(struct dns_requester *requester, struct dns_nameserver *nameserver)
|
||||
{
|
||||
struct server *s;
|
||||
struct server *s = NULL;
|
||||
struct dns_resolution *resolution = NULL;
|
||||
void *serverip, *firstip;
|
||||
short server_sin_family, firstip_sin_family;
|
||||
int ret;
|
||||
struct chunk *chk = get_trash_chunk();
|
||||
|
||||
s = objt_server(requester->requester);
|
||||
if (!s)
|
||||
return 1;
|
||||
|
||||
resolution = s->resolution;
|
||||
|
||||
/* initializing variables */
|
||||
firstip = NULL; /* pointer to the first valid response found */
|
||||
/* it will be used as the new IP if a change is required */
|
||||
firstip_sin_family = AF_UNSPEC;
|
||||
serverip = NULL; /* current server IP address */
|
||||
|
||||
/* shortcut to the server whose name is being resolved */
|
||||
s = resolution->requester;
|
||||
|
||||
/* initializing server IP pointer */
|
||||
server_sin_family = s->addr.ss_family;
|
||||
switch (server_sin_family) {
|
||||
@ -3866,20 +3865,12 @@ int snr_resolution_cb(struct dns_resolution *resolution, struct dns_nameserver *
|
||||
|
||||
switch (ret) {
|
||||
case DNS_UPD_NO:
|
||||
if (resolution->status != RSLV_STATUS_VALID) {
|
||||
resolution->status = RSLV_STATUS_VALID;
|
||||
resolution->last_status_change = now_ms;
|
||||
}
|
||||
goto stop_resolution;
|
||||
goto update_status;
|
||||
|
||||
case DNS_UPD_SRVIP_NOT_FOUND:
|
||||
goto save_ip;
|
||||
|
||||
case DNS_UPD_CNAME:
|
||||
if (resolution->status != RSLV_STATUS_VALID) {
|
||||
resolution->status = RSLV_STATUS_VALID;
|
||||
resolution->last_status_change = now_ms;
|
||||
}
|
||||
goto invalid;
|
||||
|
||||
case DNS_UPD_NO_IP_FOUND:
|
||||
@ -3887,18 +3878,18 @@ int snr_resolution_cb(struct dns_resolution *resolution, struct dns_nameserver *
|
||||
resolution->status = RSLV_STATUS_OTHER;
|
||||
resolution->last_status_change = now_ms;
|
||||
}
|
||||
goto stop_resolution;
|
||||
goto update_status;
|
||||
|
||||
case DNS_UPD_NAME_ERROR:
|
||||
/* if this is not the last expected response, we ignore it */
|
||||
if (resolution->nb_responses < nameserver->resolvers->count_nameservers)
|
||||
if (nameserver && (resolution->nb_responses < nameserver->resolvers->count_nameservers))
|
||||
return 0;
|
||||
/* update resolution status to OTHER error type */
|
||||
if (resolution->status != RSLV_STATUS_OTHER) {
|
||||
resolution->status = RSLV_STATUS_OTHER;
|
||||
resolution->last_status_change = now_ms;
|
||||
}
|
||||
goto stop_resolution;
|
||||
goto update_status;
|
||||
|
||||
default:
|
||||
goto invalid;
|
||||
@ -3906,33 +3897,25 @@ int snr_resolution_cb(struct dns_resolution *resolution, struct dns_nameserver *
|
||||
}
|
||||
|
||||
save_ip:
|
||||
nameserver->counters.update += 1;
|
||||
if (resolution->status != RSLV_STATUS_VALID) {
|
||||
resolution->status = RSLV_STATUS_VALID;
|
||||
resolution->last_status_change = now_ms;
|
||||
}
|
||||
if (nameserver)
|
||||
nameserver->counters.update += 1;
|
||||
|
||||
/* save the first ip we found */
|
||||
chunk_printf(chk, "%s/%s", nameserver->resolvers->id, nameserver->id);
|
||||
if (nameserver)
|
||||
chunk_printf(chk, "%s/%s", nameserver->resolvers->id, nameserver->id);
|
||||
else
|
||||
chunk_printf(chk, "DNS cache");
|
||||
update_server_addr(s, firstip, firstip_sin_family, (char *)chk->str);
|
||||
|
||||
stop_resolution:
|
||||
/* update last resolution date and time */
|
||||
resolution->last_resolution = now_ms;
|
||||
/* reset current status flag */
|
||||
resolution->step = RSLV_STEP_NONE;
|
||||
/* reset values */
|
||||
dns_reset_resolution(resolution);
|
||||
|
||||
dns_update_resolvers_timeout(nameserver->resolvers);
|
||||
|
||||
update_status:
|
||||
snr_update_srv_status(s);
|
||||
return 0;
|
||||
return 1;
|
||||
|
||||
invalid:
|
||||
nameserver->counters.invalid += 1;
|
||||
if (nameserver)
|
||||
nameserver->counters.invalid += 1;
|
||||
if (resolution->nb_responses >= nameserver->resolvers->count_nameservers)
|
||||
goto stop_resolution;
|
||||
goto update_status;
|
||||
|
||||
snr_update_srv_status(s);
|
||||
return 0;
|
||||
@ -3944,14 +3927,17 @@ int snr_resolution_cb(struct dns_resolution *resolution, struct dns_nameserver *
|
||||
* 0 on error
|
||||
* 1 when no error or safe ignore
|
||||
*/
|
||||
int snr_resolution_error_cb(struct dns_resolution *resolution, int error_code)
|
||||
int snr_resolution_error_cb(struct dns_requester *requester, int error_code)
|
||||
{
|
||||
struct server *s;
|
||||
struct dns_resolvers *resolvers;
|
||||
int res_preferred_afinet, res_preferred_afinet6;
|
||||
struct server *s = NULL;
|
||||
struct dns_resolution *resolution = NULL;
|
||||
struct dns_resolvers *resolvers = NULL;
|
||||
|
||||
/* shortcut to the server whose name is being resolved */
|
||||
s = resolution->requester;
|
||||
s = objt_server(requester->requester);
|
||||
if (!s)
|
||||
return 1;
|
||||
|
||||
resolution = s->resolution;
|
||||
resolvers = s->resolvers;
|
||||
|
||||
/* can be ignored if this is not the last response */
|
||||
@ -3959,99 +3945,6 @@ int snr_resolution_error_cb(struct dns_resolution *resolution, int error_code)
|
||||
return 1;
|
||||
}
|
||||
|
||||
switch (error_code) {
|
||||
case DNS_RESP_INVALID:
|
||||
case DNS_RESP_WRONG_NAME:
|
||||
if (resolution->status != RSLV_STATUS_INVALID) {
|
||||
resolution->status = RSLV_STATUS_INVALID;
|
||||
resolution->last_status_change = now_ms;
|
||||
}
|
||||
break;
|
||||
|
||||
case DNS_RESP_ANCOUNT_ZERO:
|
||||
case DNS_RESP_TRUNCATED:
|
||||
case DNS_RESP_ERROR:
|
||||
case DNS_RESP_NO_EXPECTED_RECORD:
|
||||
case DNS_RESP_CNAME_ERROR:
|
||||
res_preferred_afinet = s->dns_opts.family_prio == AF_INET && resolution->query_type == DNS_RTYPE_A;
|
||||
res_preferred_afinet6 = s->dns_opts.family_prio == AF_INET6 && resolution->query_type == DNS_RTYPE_AAAA;
|
||||
|
||||
if ((res_preferred_afinet || res_preferred_afinet6)
|
||||
|| (resolution->try > 0)) {
|
||||
/* let's change the query type */
|
||||
if (res_preferred_afinet6) {
|
||||
/* fallback from AAAA to A */
|
||||
resolution->query_type = DNS_RTYPE_A;
|
||||
}
|
||||
else if (res_preferred_afinet) {
|
||||
/* fallback from A to AAAA */
|
||||
resolution->query_type = DNS_RTYPE_AAAA;
|
||||
}
|
||||
else {
|
||||
resolution->try -= 1;
|
||||
if (s->dns_opts.family_prio == AF_INET) {
|
||||
resolution->query_type = DNS_RTYPE_A;
|
||||
} else {
|
||||
resolution->query_type = DNS_RTYPE_AAAA;
|
||||
}
|
||||
}
|
||||
|
||||
dns_send_query(resolution);
|
||||
|
||||
/*
|
||||
* move the resolution to the last element of the FIFO queue
|
||||
* and update timeout wakeup based on the new first entry
|
||||
*/
|
||||
if (dns_check_resolution_queue(resolvers) > 1) {
|
||||
/* second resolution becomes first one */
|
||||
LIST_DEL(&resolution->list);
|
||||
/* ex first resolution goes to the end of the queue */
|
||||
LIST_ADDQ(&resolvers->curr_resolution, &resolution->list);
|
||||
}
|
||||
dns_update_resolvers_timeout(resolvers);
|
||||
goto leave;
|
||||
}
|
||||
else {
|
||||
if (resolution->status != RSLV_STATUS_OTHER) {
|
||||
resolution->status = RSLV_STATUS_OTHER;
|
||||
resolution->last_status_change = now_ms;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case DNS_RESP_NX_DOMAIN:
|
||||
if (resolution->status != RSLV_STATUS_NX) {
|
||||
resolution->status = RSLV_STATUS_NX;
|
||||
resolution->last_status_change = now_ms;
|
||||
}
|
||||
break;
|
||||
|
||||
case DNS_RESP_REFUSED:
|
||||
if (resolution->status != RSLV_STATUS_REFUSED) {
|
||||
resolution->status = RSLV_STATUS_REFUSED;
|
||||
resolution->last_status_change = now_ms;
|
||||
}
|
||||
break;
|
||||
|
||||
case DNS_RESP_TIMEOUT:
|
||||
if (resolution->status != RSLV_STATUS_TIMEOUT) {
|
||||
resolution->status = RSLV_STATUS_TIMEOUT;
|
||||
resolution->last_status_change = now_ms;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* update last resolution date and time */
|
||||
resolution->last_resolution = now_ms;
|
||||
/* reset current status flag */
|
||||
resolution->step = RSLV_STEP_NONE;
|
||||
/* reset values */
|
||||
dns_reset_resolution(resolution);
|
||||
|
||||
LIST_DEL(&resolution->list);
|
||||
dns_update_resolvers_timeout(resolvers);
|
||||
|
||||
leave:
|
||||
snr_update_srv_status(s);
|
||||
return 1;
|
||||
}
|
||||
@ -4080,9 +3973,9 @@ struct server *snr_check_ip_callback(struct server *srv, void *ip, unsigned char
|
||||
* one used for the server found in the backend
|
||||
* * the server found in the backend is not our current server
|
||||
*/
|
||||
if ((tmpsrv->resolution == NULL) ||
|
||||
(srv->resolution->hostname_dn_len != tmpsrv->resolution->hostname_dn_len) ||
|
||||
(strcmp(srv->resolution->hostname_dn, tmpsrv->resolution->hostname_dn) != 0) ||
|
||||
if ((tmpsrv->hostname_dn == NULL) ||
|
||||
(srv->hostname_dn_len != tmpsrv->hostname_dn_len) ||
|
||||
(strcmp(srv->hostname_dn, tmpsrv->hostname_dn) != 0) ||
|
||||
(srv->puid == tmpsrv->puid))
|
||||
continue;
|
||||
|
||||
@ -4121,9 +4014,55 @@ int srv_set_addr_via_libc(struct server *srv, int *err_code)
|
||||
*/
|
||||
int srv_set_fqdn(struct server *srv, const char *hostname)
|
||||
{
|
||||
srv_free_dns_resolution(srv);
|
||||
struct dns_resolution *resolution;
|
||||
int hostname_dn_len;
|
||||
|
||||
return srv_alloc_dns_resolution(srv, hostname);
|
||||
/* run time DNS resolution was not active for this server
|
||||
* and we can't enable it at run time for now.
|
||||
*/
|
||||
if (!srv->dns_requester)
|
||||
return -1;
|
||||
|
||||
chunk_reset(&trash);
|
||||
|
||||
/* check if hostname is really a hostname and if we have enough
|
||||
* room to save it in its domain name format
|
||||
*/
|
||||
hostname_dn_len = dns_str_to_dn_label_len(hostname);
|
||||
if (hostname_dn_len == -1 || hostname_dn_len + 1 > trash.size)
|
||||
return -1;
|
||||
|
||||
if (!dns_str_to_dn_label(hostname,
|
||||
trash.str,
|
||||
hostname_dn_len + 1))
|
||||
return -1;
|
||||
|
||||
|
||||
/* get a resolution from the curr or wait queues, or a brand new one from the pool */
|
||||
resolution = dns_resolution_list_get(srv->resolvers, trash.str, srv->dns_requester->prefered_query_type);
|
||||
if (!resolution)
|
||||
return -1;
|
||||
|
||||
/* in this case, the new hostanme is the same than the old one */
|
||||
if (srv->resolution == resolution)
|
||||
return 0;
|
||||
|
||||
/* first, we need to unlink our server from its current resolution */
|
||||
srv_free_from_resolution(srv);
|
||||
|
||||
/* now we update server's parameters */
|
||||
free(srv->hostname);
|
||||
free(srv->hostname_dn);
|
||||
srv->hostname = strdup(hostname);
|
||||
srv->hostname_dn = strdup(trash.str);
|
||||
srv->hostname_dn_len = hostname_dn_len;
|
||||
if (!srv->hostname || !srv->hostname_dn)
|
||||
return -1;
|
||||
|
||||
/* then we can link srv to its new resolution */
|
||||
dns_link_resolution(srv, OBJ_TYPE_SERVER, resolution);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Sets the server's address (srv->addr) from srv->lastaddr which was filled
|
||||
|
Loading…
Reference in New Issue
Block a user