2015-04-13 21:40:55 +00:00
|
|
|
/*
|
|
|
|
* Name server resolution
|
|
|
|
*
|
|
|
|
* Copyright 2014 Baptiste Assmann <bedis9@gmail.com>
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
* as published by the Free Software Foundation; either version
|
|
|
|
* 2 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <errno.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
|
|
|
|
#include <common/time.h>
|
|
|
|
#include <common/ticks.h>
|
2017-08-04 16:35:36 +00:00
|
|
|
#include <common/net_helper.h>
|
2015-04-13 21:40:55 +00:00
|
|
|
|
2017-05-04 07:05:00 +00:00
|
|
|
#include <import/lru.h>
|
|
|
|
#include <import/xxhash.h>
|
|
|
|
|
2016-11-18 23:58:54 +00:00
|
|
|
#include <types/applet.h>
|
|
|
|
#include <types/cli.h>
|
2015-04-13 21:40:55 +00:00
|
|
|
#include <types/global.h>
|
|
|
|
#include <types/dns.h>
|
|
|
|
#include <types/proto_udp.h>
|
2016-11-18 23:58:54 +00:00
|
|
|
#include <types/stats.h>
|
2015-04-13 21:40:55 +00:00
|
|
|
|
2016-11-18 23:58:54 +00:00
|
|
|
#include <proto/channel.h>
|
|
|
|
#include <proto/cli.h>
|
2015-04-13 21:40:55 +00:00
|
|
|
#include <proto/checks.h>
|
|
|
|
#include <proto/dns.h>
|
|
|
|
#include <proto/fd.h>
|
|
|
|
#include <proto/log.h>
|
|
|
|
#include <proto/server.h>
|
|
|
|
#include <proto/task.h>
|
|
|
|
#include <proto/proto_udp.h>
|
2016-11-18 23:58:54 +00:00
|
|
|
#include <proto/stream_interface.h>
|
2015-04-13 21:40:55 +00:00
|
|
|
|
|
|
|
struct list dns_resolvers = LIST_HEAD_INIT(dns_resolvers);
|
|
|
|
struct dns_resolution *resolution = NULL;
|
|
|
|
|
|
|
|
static int64_t dns_query_id_seed; /* random seed */
|
|
|
|
|
2017-05-04 07:05:00 +00:00
|
|
|
static struct lru64_head *dns_lru_tree;
|
|
|
|
static int dns_cache_size = 1024; /* arbitrary DNS cache size */
|
|
|
|
|
2017-07-06 16:46:47 +00:00
|
|
|
static struct pool_head *dns_answer_item_pool;
|
|
|
|
|
2015-04-13 21:40:55 +00:00
|
|
|
/* proto_udp callback functions for a DNS resolution */
|
|
|
|
struct dgram_data_cb resolve_dgram_cb = {
|
|
|
|
.recv = dns_resolve_recv,
|
|
|
|
.send = dns_resolve_send,
|
|
|
|
};
|
|
|
|
|
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.
2017-05-22 13:17:15 +00:00
|
|
|
/* local function prototypes */
|
|
|
|
static int dns_run_resolution(struct dns_requester *requester);
|
|
|
|
|
2015-04-13 21:40:55 +00:00
|
|
|
#if DEBUG
|
|
|
|
/*
|
|
|
|
* go through the resolutions associated to a resolvers section and print the ID and hostname in
|
|
|
|
* domain name format
|
|
|
|
* should be used for debug purpose only
|
|
|
|
*/
|
|
|
|
void dns_print_current_resolutions(struct dns_resolvers *resolvers)
|
|
|
|
{
|
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.
2017-05-22 13:17:15 +00:00
|
|
|
list_for_each_entry(resolution, &resolvers->resolution.curr, list) {
|
2015-04-13 21:40:55 +00:00
|
|
|
printf(" resolution %d for %s\n", resolution->query_id, resolution->hostname_dn);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
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.
2017-05-22 13:17:15 +00:00
|
|
|
void dump_dns_config()
|
|
|
|
{
|
|
|
|
struct dns_resolvers *curr_resolvers = NULL;
|
|
|
|
struct dns_nameserver *curr_nameserver = NULL;
|
|
|
|
struct dns_resolution *curr_resolution = NULL;
|
|
|
|
struct dns_requester *curr_requester = NULL;
|
|
|
|
|
|
|
|
printf("===============\n");
|
|
|
|
list_for_each_entry(curr_resolvers, &dns_resolvers, list) {
|
|
|
|
printf("Resolvers: %s\n", curr_resolvers->id);
|
|
|
|
|
|
|
|
printf(" nameservers:\n");
|
|
|
|
list_for_each_entry(curr_nameserver, &curr_resolvers->nameserver_list, list) {
|
|
|
|
printf(" %s\n", curr_nameserver->id);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
printf(" resolution.pool list:\n");
|
|
|
|
list_for_each_entry(curr_resolution, &curr_resolvers->resolution.pool, list) {
|
|
|
|
printf(" %p\n", curr_resolution);
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
|
|
|
|
printf(" resolution.wait list:\n");
|
|
|
|
list_for_each_entry(curr_resolution, &curr_resolvers->resolution.wait, list) {
|
|
|
|
printf(" %p %s\n", curr_resolution, curr_resolution->hostname_dn);
|
|
|
|
printf(" requester.wait list:\n");
|
|
|
|
list_for_each_entry(curr_requester, &curr_resolution->requester.wait, list) {
|
2017-08-12 09:16:55 +00:00
|
|
|
switch (obj_type(curr_requester->requester)) {
|
|
|
|
case OBJ_TYPE_SERVER:
|
|
|
|
printf(" %p SRV %s %d\n", curr_requester, objt_server(curr_requester->requester)->id, curr_requester->prefered_query_type);
|
|
|
|
break;
|
|
|
|
case OBJ_TYPE_SRVRQ:
|
|
|
|
printf(" %p SRVRQ %s %d\n", curr_requester, objt_dns_srvrq(curr_requester->requester)->name, curr_requester->prefered_query_type);
|
|
|
|
break;
|
|
|
|
case OBJ_TYPE_NONE:
|
|
|
|
default:
|
|
|
|
;;
|
|
|
|
}
|
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.
2017-05-22 13:17:15 +00:00
|
|
|
}
|
|
|
|
printf(" requester.curr list:\n");
|
|
|
|
list_for_each_entry(curr_requester, &curr_resolution->requester.curr, list) {
|
2017-08-12 09:16:55 +00:00
|
|
|
switch (obj_type(curr_requester->requester)) {
|
|
|
|
case OBJ_TYPE_SERVER:
|
|
|
|
printf(" %p SRV %s %d\n", curr_requester, objt_server(curr_requester->requester)->id, curr_requester->prefered_query_type);
|
|
|
|
break;
|
|
|
|
case OBJ_TYPE_SRVRQ:
|
|
|
|
printf(" %p SRVRQ %s %d\n", curr_requester, objt_dns_srvrq(curr_requester->requester)->name, curr_requester->prefered_query_type);
|
|
|
|
break;
|
|
|
|
case OBJ_TYPE_NONE:
|
|
|
|
default:
|
|
|
|
;;
|
|
|
|
}
|
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.
2017-05-22 13:17:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
printf(" resolution.curr list:\n");
|
|
|
|
list_for_each_entry(curr_resolution, &curr_resolvers->resolution.curr, list) {
|
|
|
|
printf(" %p %s\n", curr_resolution, curr_resolution->hostname_dn);
|
|
|
|
printf(" requester.wait list:\n");
|
|
|
|
list_for_each_entry(curr_requester, &curr_resolution->requester.wait, list) {
|
2017-08-12 09:16:55 +00:00
|
|
|
switch (obj_type(curr_requester->requester)) {
|
|
|
|
case OBJ_TYPE_SERVER:
|
|
|
|
printf(" %p SRV %s %d\n", curr_requester, objt_server(curr_requester->requester)->id, curr_requester->prefered_query_type);
|
|
|
|
break;
|
|
|
|
case OBJ_TYPE_SRVRQ:
|
|
|
|
printf(" %p SRVRQ %s %d\n", curr_requester, objt_dns_srvrq(curr_requester->requester)->name, curr_requester->prefered_query_type);
|
|
|
|
break;
|
|
|
|
case OBJ_TYPE_NONE:
|
|
|
|
default:
|
|
|
|
;;
|
|
|
|
}
|
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.
2017-05-22 13:17:15 +00:00
|
|
|
}
|
|
|
|
printf(" requester.curr list:\n");
|
|
|
|
list_for_each_entry(curr_requester, &curr_resolution->requester.curr, list) {
|
2017-08-12 09:16:55 +00:00
|
|
|
switch (obj_type(curr_requester->requester)) {
|
|
|
|
case OBJ_TYPE_SERVER:
|
|
|
|
printf(" %p SRV %s %d\n", curr_requester, objt_server(curr_requester->requester)->id, curr_requester->prefered_query_type);
|
|
|
|
break;
|
|
|
|
case OBJ_TYPE_SRVRQ:
|
|
|
|
printf(" %p SRVRQ %s %d\n", curr_requester, objt_dns_srvrq(curr_requester->requester)->name, curr_requester->prefered_query_type);
|
|
|
|
break;
|
|
|
|
case OBJ_TYPE_NONE:
|
|
|
|
default:
|
|
|
|
;;
|
|
|
|
}
|
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.
2017-05-22 13:17:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
printf("===============\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Initiates a new name resolution:
|
|
|
|
* - generates a query id
|
|
|
|
* - configure the resolution structure
|
|
|
|
* - startup the resolvers task if required
|
|
|
|
*
|
|
|
|
* returns:
|
|
|
|
* - 0 if everything started properly
|
|
|
|
* - -1 in case of error or if resolution already running
|
|
|
|
*/
|
|
|
|
int dns_trigger_resolution(struct dns_resolution *resolution)
|
|
|
|
{
|
|
|
|
struct dns_requester *requester = NULL, *tmprequester;
|
|
|
|
struct dns_resolvers *resolvers = NULL;
|
2017-08-21 11:21:48 +00:00
|
|
|
int inter, valid_period;
|
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.
2017-05-22 13:17:15 +00:00
|
|
|
|
|
|
|
/* process the element of the wait queue */
|
|
|
|
list_for_each_entry_safe(requester, tmprequester, &resolution->requester.wait, list) {
|
|
|
|
inter = 0;
|
|
|
|
|
|
|
|
switch (obj_type(requester->requester)) {
|
|
|
|
case OBJ_TYPE_SERVER:
|
2017-08-21 11:21:48 +00:00
|
|
|
valid_period = objt_server(requester->requester)->check.inter;
|
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.
2017-05-22 13:17:15 +00:00
|
|
|
resolvers = objt_server(requester->requester)->resolvers;
|
|
|
|
break;
|
2017-08-04 16:35:36 +00:00
|
|
|
case OBJ_TYPE_SRVRQ:
|
2017-08-21 11:21:48 +00:00
|
|
|
valid_period = objt_dns_srvrq(requester->requester)->inter;
|
2017-08-04 16:35:36 +00:00
|
|
|
resolvers = objt_dns_srvrq(requester->requester)->resolvers;
|
|
|
|
break;
|
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.
2017-05-22 13:17:15 +00:00
|
|
|
case OBJ_TYPE_NONE:
|
|
|
|
default:
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2017-08-21 11:21:48 +00:00
|
|
|
if (resolvers->hold.valid < valid_period)
|
|
|
|
inter = resolvers->hold.valid;
|
|
|
|
else
|
|
|
|
inter = valid_period;
|
|
|
|
|
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.
2017-05-22 13:17:15 +00:00
|
|
|
/* if data is fresh enough, let's use it */
|
|
|
|
if (!tick_is_expired(tick_add(resolution->last_resolution, inter), now_ms)) {
|
|
|
|
/* we only use cache if the response there is valid.
|
|
|
|
* If not valid, we run the resolution and move the requester to
|
|
|
|
* the run queue. */
|
|
|
|
if (resolution->status != RSLV_STATUS_VALID) {
|
|
|
|
LIST_DEL(&requester->list);
|
|
|
|
LIST_ADDQ(&resolution->requester.curr, &requester->list);
|
|
|
|
dns_run_resolution(requester);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
requester->requester_cb(requester, NULL);
|
2017-07-06 16:46:47 +00:00
|
|
|
resolvers = NULL;
|
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.
2017-05-22 13:17:15 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
LIST_DEL(&requester->list);
|
|
|
|
LIST_ADDQ(&resolution->requester.curr, &requester->list);
|
|
|
|
dns_run_resolution(requester);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (resolvers)
|
|
|
|
dns_update_resolvers_timeout(resolvers);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Prepare and send a DNS resolution.
|
|
|
|
*
|
|
|
|
* Return code:
|
|
|
|
* - 0 if no error occured
|
|
|
|
* - -1 in case of error
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
dns_run_resolution(struct dns_requester *requester)
|
|
|
|
{
|
|
|
|
struct dns_resolution *resolution;
|
|
|
|
struct dns_resolvers *resolvers;
|
|
|
|
int query_id, query_type, i;
|
|
|
|
struct proxy *proxy;
|
|
|
|
|
|
|
|
resolution = NULL;
|
|
|
|
resolvers = NULL;
|
|
|
|
proxy = NULL;
|
|
|
|
query_type = -1;
|
|
|
|
switch (obj_type(requester->requester)) {
|
|
|
|
case OBJ_TYPE_SERVER:
|
|
|
|
resolution = objt_server(requester->requester)->resolution;
|
|
|
|
resolvers = objt_server(requester->requester)->resolvers;
|
|
|
|
proxy = objt_server(requester->requester)->proxy;
|
|
|
|
query_type = requester->prefered_query_type;
|
|
|
|
break;
|
2017-08-04 16:35:36 +00:00
|
|
|
case OBJ_TYPE_SRVRQ:
|
|
|
|
resolution = objt_dns_srvrq(requester->requester)->resolution;
|
|
|
|
resolvers = objt_dns_srvrq(requester->requester)->resolvers;
|
|
|
|
proxy = objt_dns_srvrq(requester->requester)->proxy;
|
|
|
|
query_type = DNS_RTYPE_SRV;
|
|
|
|
break;
|
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.
2017-05-22 13:17:15 +00:00
|
|
|
case OBJ_TYPE_NONE:
|
|
|
|
default:
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2017-08-04 16:35:36 +00:00
|
|
|
/*
|
|
|
|
* Avoid sending requests for resolutions that don't yet have
|
|
|
|
* an hostname, ie resolutions linked to servers that do not yet
|
|
|
|
* have an fqdn
|
|
|
|
*/
|
|
|
|
if (!resolution->hostname_dn)
|
|
|
|
return 0;
|
|
|
|
|
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.
2017-05-22 13:17:15 +00:00
|
|
|
/*
|
|
|
|
* 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, in resolvers %s",
|
|
|
|
resolution->hostname_dn, resolvers->id);
|
|
|
|
|
|
|
|
if (proxy)
|
|
|
|
send_log(proxy, LOG_NOTICE, "%s.\n", trash.str);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
} while (eb32_lookup(&resolvers->query_ids, query_id));
|
|
|
|
|
|
|
|
/* move the resolution into the run queue */
|
|
|
|
LIST_DEL(&resolution->list);
|
|
|
|
LIST_ADDQ(&resolvers->resolution.curr, &resolution->list);
|
|
|
|
|
|
|
|
/* now update resolution parameters */
|
|
|
|
resolution->query_id = query_id;
|
|
|
|
resolution->qid.key = query_id;
|
|
|
|
resolution->step = RSLV_STEP_RUNNING;
|
|
|
|
resolution->query_type = query_type;
|
|
|
|
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 0;
|
|
|
|
}
|
|
|
|
|
2015-04-13 21:40:55 +00:00
|
|
|
/*
|
|
|
|
* check if there is more than 1 resolution in the resolver's resolution list
|
|
|
|
* return value:
|
|
|
|
* 0: empty list
|
|
|
|
* 1: exactly one entry in the list
|
|
|
|
* 2: more than one entry in the list
|
|
|
|
*/
|
|
|
|
int dns_check_resolution_queue(struct dns_resolvers *resolvers)
|
|
|
|
{
|
|
|
|
|
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.
2017-05-22 13:17:15 +00:00
|
|
|
if (LIST_ISEMPTY(&resolvers->resolution.curr))
|
2015-04-13 21:40:55 +00:00
|
|
|
return 0;
|
|
|
|
|
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.
2017-05-22 13:17:15 +00:00
|
|
|
if ((resolvers->resolution.curr.n) && (resolvers->resolution.curr.n == resolvers->resolution.curr.p))
|
2015-04-13 21:40:55 +00:00
|
|
|
return 1;
|
|
|
|
|
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.
2017-05-22 13:17:15 +00:00
|
|
|
if (! ((resolvers->resolution.curr.n == resolvers->resolution.curr.p)
|
|
|
|
&& (&resolvers->resolution.curr != resolvers->resolution.curr.n)))
|
2015-04-13 21:40:55 +00:00
|
|
|
return 2;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
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.
2017-05-22 13:17:15 +00:00
|
|
|
* reset some resolution parameters to initial values and also delete the
|
|
|
|
* query ID from the resolver's tree.
|
2015-04-13 21:40:55 +00:00
|
|
|
*/
|
|
|
|
void dns_reset_resolution(struct dns_resolution *resolution)
|
|
|
|
{
|
|
|
|
/* update resolution status */
|
|
|
|
resolution->step = RSLV_STEP_NONE;
|
|
|
|
|
|
|
|
resolution->try = 0;
|
|
|
|
resolution->try_cname = 0;
|
|
|
|
resolution->last_resolution = now_ms;
|
|
|
|
resolution->nb_responses = 0;
|
|
|
|
|
|
|
|
/* clean up query id */
|
|
|
|
eb32_delete(&resolution->qid);
|
|
|
|
resolution->query_id = 0;
|
|
|
|
resolution->qid.key = 0;
|
|
|
|
}
|
|
|
|
|
2017-07-06 16:46:47 +00:00
|
|
|
static inline void free_dns_answer_item(struct dns_answer_item *item)
|
|
|
|
{
|
|
|
|
pool_free2(dns_answer_item_pool, item);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-04-13 21:40:55 +00:00
|
|
|
/*
|
|
|
|
* function called when a network IO is generated on a name server socket for an incoming packet
|
|
|
|
* It performs the following actions:
|
|
|
|
* - check if the packet requires processing (not outdated resolution)
|
|
|
|
* - ensure the DNS packet received is valid and call requester's callback
|
|
|
|
* - call requester's error callback if invalid response
|
2016-04-17 20:43:26 +00:00
|
|
|
* - check the dn_name in the packet against the one sent
|
2015-04-13 21:40:55 +00:00
|
|
|
*/
|
|
|
|
void dns_resolve_recv(struct dgram_conn *dgram)
|
|
|
|
{
|
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.
2017-05-22 13:17:15 +00:00
|
|
|
struct dns_nameserver *nameserver, *tmpnameserver;
|
2015-04-13 21:40:55 +00:00
|
|
|
struct dns_resolvers *resolvers;
|
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.
2017-05-22 13:17:15 +00:00
|
|
|
struct dns_resolution *resolution = NULL;
|
2016-05-14 09:26:22 +00:00
|
|
|
struct dns_query_item *query;
|
2015-04-13 21:40:55 +00:00
|
|
|
unsigned char buf[DNS_MAX_UDP_MESSAGE + 1];
|
|
|
|
unsigned char *bufend;
|
2017-06-08 17:30:39 +00:00
|
|
|
int fd, buflen, dns_resp, need_resend = 0;
|
2017-08-18 21:35:08 +00:00
|
|
|
int max_answer_records = 0;
|
2015-04-13 21:40:55 +00:00
|
|
|
unsigned short query_id;
|
|
|
|
struct eb32_node *eb;
|
2017-05-04 07:05:00 +00:00
|
|
|
struct lru64 *lru = NULL;
|
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.
2017-05-22 13:17:15 +00:00
|
|
|
struct dns_requester *requester = NULL, *tmprequester = NULL;
|
2017-07-06 16:46:47 +00:00
|
|
|
struct dns_answer_item *item1, *item2 = NULL;
|
2015-04-13 21:40:55 +00:00
|
|
|
|
|
|
|
fd = dgram->t.sock.fd;
|
|
|
|
|
|
|
|
/* check if ready for reading */
|
|
|
|
if (!fd_recv_ready(fd))
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* no need to go further if we can't retrieve the nameserver */
|
2016-04-03 11:48:42 +00:00
|
|
|
if ((nameserver = dgram->owner) == NULL)
|
2015-04-13 21:40:55 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
resolvers = nameserver->resolvers;
|
|
|
|
|
|
|
|
/* process all pending input messages */
|
|
|
|
while (1) {
|
2017-08-04 16:35:36 +00:00
|
|
|
int removed_reso = 0;
|
2015-04-13 21:40:55 +00:00
|
|
|
/* read message received */
|
2017-08-18 21:35:08 +00:00
|
|
|
memset(buf, '\0', resolvers->accepted_payload_size + 1);
|
|
|
|
if ((buflen = recv(fd, (char*)buf , resolvers->accepted_payload_size + 1, 0)) < 0) {
|
2015-04-13 21:40:55 +00:00
|
|
|
/* FIXME : for now we consider EAGAIN only */
|
|
|
|
fd_cant_recv(fd);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* message too big */
|
2017-08-18 21:35:08 +00:00
|
|
|
if (buflen > resolvers->accepted_payload_size) {
|
2015-04-13 21:40:55 +00:00
|
|
|
nameserver->counters.too_big += 1;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* initializing variables */
|
|
|
|
bufend = buf + buflen; /* pointer to mark the end of the buffer */
|
|
|
|
|
|
|
|
/* read the query id from the packet (16 bits) */
|
|
|
|
if (buf + 2 > bufend) {
|
|
|
|
nameserver->counters.invalid += 1;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
query_id = dns_response_get_query_id(buf);
|
|
|
|
|
|
|
|
/* search the query_id in the pending resolution tree */
|
2015-09-02 20:05:24 +00:00
|
|
|
eb = eb32_lookup(&resolvers->query_ids, query_id);
|
|
|
|
if (eb == NULL) {
|
2015-04-13 21:40:55 +00:00
|
|
|
/* unknown query id means an outdated response and can be safely ignored */
|
|
|
|
nameserver->counters.outdated += 1;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* known query id means a resolution in prgress */
|
|
|
|
resolution = eb32_entry(eb, struct dns_resolution, qid);
|
|
|
|
|
|
|
|
if (!resolution) {
|
|
|
|
nameserver->counters.outdated += 1;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* number of responses received */
|
|
|
|
resolution->nb_responses += 1;
|
|
|
|
|
2017-08-18 21:35:08 +00:00
|
|
|
|
|
|
|
max_answer_records = (resolvers->accepted_payload_size - DNS_HEADER_SIZE) / DNS_MIN_RECORD_SIZE;
|
|
|
|
dns_resp = dns_validate_dns_response(buf, bufend, resolution, max_answer_records);
|
2015-04-13 21:40:55 +00:00
|
|
|
|
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.
2017-05-22 13:17:15 +00:00
|
|
|
switch (dns_resp) {
|
|
|
|
case DNS_RESP_VALID:
|
|
|
|
need_resend = 0;
|
|
|
|
break;
|
2015-04-13 21:40:55 +00:00
|
|
|
|
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.
2017-05-22 13:17:15 +00:00
|
|
|
case DNS_RESP_INVALID:
|
|
|
|
case DNS_RESP_QUERY_COUNT_ERROR:
|
|
|
|
case DNS_RESP_WRONG_NAME:
|
|
|
|
if (resolution->status != RSLV_STATUS_INVALID) {
|
|
|
|
resolution->status = RSLV_STATUS_INVALID;
|
|
|
|
resolution->last_status_change = now_ms;
|
|
|
|
}
|
|
|
|
nameserver->counters.invalid += 1;
|
|
|
|
need_resend = 0;
|
|
|
|
break;
|
2015-04-13 21:40:55 +00:00
|
|
|
|
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.
2017-05-22 13:17:15 +00:00
|
|
|
case DNS_RESP_ANCOUNT_ZERO:
|
|
|
|
if (resolution->status != RSLV_STATUS_OTHER) {
|
|
|
|
resolution->status = RSLV_STATUS_OTHER;
|
|
|
|
resolution->last_status_change = now_ms;
|
|
|
|
}
|
|
|
|
nameserver->counters.any_err += 1;
|
|
|
|
need_resend = 1;
|
|
|
|
break;
|
2015-04-13 21:40:55 +00:00
|
|
|
|
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.
2017-05-22 13:17:15 +00:00
|
|
|
case DNS_RESP_NX_DOMAIN:
|
|
|
|
if (resolution->status != RSLV_STATUS_NX) {
|
|
|
|
resolution->status = RSLV_STATUS_NX;
|
|
|
|
resolution->last_status_change = now_ms;
|
|
|
|
}
|
|
|
|
nameserver->counters.nx += 1;
|
|
|
|
need_resend = 0;
|
|
|
|
break;
|
2015-04-13 21:40:55 +00:00
|
|
|
|
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.
2017-05-22 13:17:15 +00:00
|
|
|
case DNS_RESP_REFUSED:
|
|
|
|
if (resolution->status != RSLV_STATUS_REFUSED) {
|
|
|
|
resolution->status = RSLV_STATUS_REFUSED;
|
|
|
|
resolution->last_status_change = now_ms;
|
|
|
|
}
|
|
|
|
nameserver->counters.refused += 1;
|
|
|
|
need_resend = 0;
|
|
|
|
break;
|
2015-04-13 21:40:55 +00:00
|
|
|
|
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.
2017-05-22 13:17:15 +00:00
|
|
|
case DNS_RESP_CNAME_ERROR:
|
|
|
|
if (resolution->status != RSLV_STATUS_OTHER) {
|
|
|
|
resolution->status = RSLV_STATUS_OTHER;
|
|
|
|
resolution->last_status_change = now_ms;
|
|
|
|
}
|
|
|
|
nameserver->counters.cname_error += 1;
|
|
|
|
need_resend = 1;
|
|
|
|
break;
|
2015-04-13 21:40:55 +00:00
|
|
|
|
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.
2017-05-22 13:17:15 +00:00
|
|
|
case DNS_RESP_TRUNCATED:
|
|
|
|
if (resolution->status != RSLV_STATUS_OTHER) {
|
|
|
|
resolution->status = RSLV_STATUS_OTHER;
|
|
|
|
resolution->last_status_change = now_ms;
|
|
|
|
}
|
|
|
|
nameserver->counters.truncated += 1;
|
|
|
|
need_resend = 1;
|
|
|
|
break;
|
2015-09-08 22:46:58 +00:00
|
|
|
|
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.
2017-05-22 13:17:15 +00:00
|
|
|
case DNS_RESP_NO_EXPECTED_RECORD:
|
|
|
|
if (resolution->status != RSLV_STATUS_OTHER) {
|
|
|
|
resolution->status = RSLV_STATUS_OTHER;
|
|
|
|
resolution->last_status_change = now_ms;
|
|
|
|
}
|
|
|
|
nameserver->counters.other += 1;
|
|
|
|
need_resend = 1;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DNS_RESP_ERROR:
|
|
|
|
case DNS_RESP_INTERNAL:
|
|
|
|
if (resolution->status != RSLV_STATUS_OTHER) {
|
|
|
|
resolution->status = RSLV_STATUS_OTHER;
|
|
|
|
resolution->last_status_change = now_ms;
|
|
|
|
}
|
|
|
|
nameserver->counters.other += 1;
|
|
|
|
need_resend = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2017-08-04 16:35:36 +00:00
|
|
|
/* Check for any obsolete record, also identify any SRV request, and try to find a corresponding server */
|
2017-07-06 16:46:47 +00:00
|
|
|
list_for_each_entry_safe(item1, item2, &resolution->response.answer_list,
|
|
|
|
list) {
|
|
|
|
if (item1->last_seen + nameserver->resolvers->hold.obsolete / 1000 < now.tv_sec) {
|
|
|
|
LIST_DEL(&item1->list);
|
2017-08-04 16:35:36 +00:00
|
|
|
if (item1->type == DNS_RTYPE_SRV && !LIST_ISEMPTY(&resolution->requester.curr)) {
|
|
|
|
struct dns_srvrq *srvrq;
|
|
|
|
|
2017-08-14 14:38:29 +00:00
|
|
|
list_for_each_entry_safe(requester, tmprequester, &resolution->requester.curr, list) {
|
|
|
|
srvrq = objt_dns_srvrq(requester->requester);
|
|
|
|
/* We're removing an obsolete entry, remove any associated server */
|
|
|
|
if (srvrq) {
|
|
|
|
struct server *srv;
|
|
|
|
|
|
|
|
for (srv = srvrq->proxy->srv; srv != NULL; srv = srv->next) {
|
|
|
|
if (srv->srvrq == srvrq &&
|
|
|
|
item1->data_len ==
|
|
|
|
srv->hostname_dn_len &&
|
|
|
|
!memcmp(srv->hostname_dn, item1->target, item1->data_len) &&
|
|
|
|
srv->svc_port == item1->port) {
|
|
|
|
snr_update_srv_status(srv, 1);
|
|
|
|
free(srv->hostname);
|
|
|
|
srv->hostname = NULL;
|
|
|
|
srv->hostname_dn_len = 0;
|
|
|
|
free(srv->hostname_dn);
|
|
|
|
srv->hostname_dn = NULL;
|
2017-08-14 08:37:46 +00:00
|
|
|
srv_free_from_resolution(srv);
|
2017-08-14 14:38:29 +00:00
|
|
|
}
|
2017-08-04 16:35:36 +00:00
|
|
|
}
|
|
|
|
}
|
2017-08-14 14:38:29 +00:00
|
|
|
} /* end of list_for_each(requester) */
|
2017-08-04 16:35:36 +00:00
|
|
|
}
|
2017-07-06 16:46:47 +00:00
|
|
|
free_dns_answer_item(item1);
|
2017-08-04 16:35:36 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (item1->type == DNS_RTYPE_SRV) {
|
2017-08-14 14:38:29 +00:00
|
|
|
struct server *srv = NULL;
|
|
|
|
struct dns_srvrq *srvrq = NULL;
|
2017-08-04 16:35:36 +00:00
|
|
|
|
|
|
|
if (LIST_ISEMPTY(&resolution->requester.curr))
|
|
|
|
continue;
|
|
|
|
|
2017-08-14 14:38:29 +00:00
|
|
|
list_for_each_entry_safe(requester, tmprequester, &resolution->requester.curr, list) {
|
|
|
|
srvrq = objt_dns_srvrq(requester->requester);
|
|
|
|
if (!srvrq)
|
|
|
|
continue;
|
|
|
|
/* Check if a server already uses that hostname */
|
|
|
|
for (srv = srvrq->proxy->srv; srv != NULL; srv = srv->next) {
|
|
|
|
if (srv->srvrq == srvrq &&
|
|
|
|
item1->data_len == srv->hostname_dn_len &&
|
|
|
|
!memcmp(srv->hostname_dn, item1->target, item1->data_len) &&
|
|
|
|
srv->svc_port == item1->port) {
|
|
|
|
if (srv->uweight != item1->weight) {
|
|
|
|
char weight[9];
|
|
|
|
|
|
|
|
snprintf(weight, sizeof(weight),
|
|
|
|
"%d", item1->weight);
|
|
|
|
server_parse_weight_change_request(srv, weight);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* If not, try to find a server that is down */
|
|
|
|
if (!srv) {
|
|
|
|
for (srv = srvrq->proxy->srv; srv != NULL; srv = srv->next) {
|
|
|
|
|
|
|
|
if (srv->srvrq == srvrq &&
|
|
|
|
!srv->hostname_dn)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (srv) {
|
2017-08-04 16:35:36 +00:00
|
|
|
char weight[9];
|
2017-08-18 21:36:07 +00:00
|
|
|
const char *msg = NULL;
|
2017-08-14 14:38:29 +00:00
|
|
|
char hostname[DNS_MAX_NAME_SIZE];
|
|
|
|
|
|
|
|
if (item1->data_len > DNS_MAX_NAME_SIZE)
|
|
|
|
continue;
|
|
|
|
dns_dn_label_to_str(item1->target, hostname, item1->data_len);
|
2017-08-18 21:36:07 +00:00
|
|
|
msg = update_server_fqdn(srv, hostname, "SRV record");
|
|
|
|
if (msg)
|
|
|
|
send_log(srv->proxy, LOG_NOTICE, "%s", msg);
|
|
|
|
|
2017-08-14 14:38:29 +00:00
|
|
|
srv->svc_port = item1->port;
|
|
|
|
srv->flags &= ~SRV_F_MAPPORTS;
|
|
|
|
if ((srv->check.state & CHK_ST_CONFIGURED) && !(srv->flags & SRV_F_CHECKPORT))
|
|
|
|
srv->check.port = item1->port;
|
2017-08-04 16:35:36 +00:00
|
|
|
snprintf(weight, sizeof(weight),
|
|
|
|
"%d", item1->weight);
|
|
|
|
server_parse_weight_change_request(srv, weight);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-07-06 16:46:47 +00:00
|
|
|
}
|
|
|
|
}
|
2017-08-04 16:35:36 +00:00
|
|
|
if (removed_reso)
|
|
|
|
goto next_packet;
|
2017-07-06 16:46:47 +00:00
|
|
|
|
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.
2017-05-22 13:17:15 +00:00
|
|
|
/* some error codes trigger a re-send of the query, but switching the
|
|
|
|
* query type.
|
|
|
|
* This is the case for the following error codes:
|
|
|
|
* DNS_RESP_ANCOUNT_ZERO
|
|
|
|
* DNS_RESP_TRUNCATED
|
|
|
|
* DNS_RESP_ERROR
|
|
|
|
* DNS_RESP_INTERNAL
|
|
|
|
* DNS_RESP_NO_EXPECTED_RECORD
|
|
|
|
* DNS_RESP_CNAME_ERROR
|
|
|
|
*/
|
|
|
|
if (need_resend) {
|
|
|
|
int family_prio;
|
|
|
|
int res_preferred_afinet, res_preferred_afinet6;
|
|
|
|
|
|
|
|
requester = LIST_NEXT(&resolution->requester.curr, struct dns_requester *, list);
|
|
|
|
switch (obj_type(requester->requester)) {
|
|
|
|
case OBJ_TYPE_SERVER:
|
|
|
|
family_prio = objt_server(requester->requester)->dns_opts.family_prio;
|
|
|
|
break;
|
|
|
|
case OBJ_TYPE_NONE:
|
|
|
|
default:
|
|
|
|
family_prio = AF_INET6;
|
|
|
|
}
|
|
|
|
res_preferred_afinet = family_prio == AF_INET && resolution->query_type == DNS_RTYPE_A;
|
|
|
|
res_preferred_afinet6 = 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 (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->resolution.curr, &resolution->list);
|
|
|
|
}
|
|
|
|
|
|
|
|
dns_update_resolvers_timeout(resolvers);
|
|
|
|
goto next_packet;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* if we're there, this means that we already ran out of chances to re-send
|
|
|
|
* the query */
|
|
|
|
list_for_each_entry_safe(requester, tmprequester, &resolution->requester.curr, list) {
|
|
|
|
requester->requester_error_cb(requester, dns_resp);
|
|
|
|
}
|
|
|
|
goto next_packet;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* now processing those error codes only:
|
|
|
|
* DNS_RESP_NX_DOMAIN
|
|
|
|
* DNS_RESP_REFUSED
|
|
|
|
*/
|
|
|
|
if (dns_resp != DNS_RESP_VALID) {
|
|
|
|
/* now parse list of requesters currently waiting for this resolution */
|
|
|
|
list_for_each_entry_safe(requester, tmprequester, &resolution->requester.curr, list) {
|
|
|
|
requester->requester_error_cb(requester, dns_resp);
|
|
|
|
|
|
|
|
/* we can move the requester the wait queue */
|
|
|
|
LIST_DEL(&requester->list);
|
|
|
|
LIST_ADDQ(&resolution->requester.wait, &requester->list);
|
|
|
|
}
|
|
|
|
goto next_packet;
|
2015-04-13 21:40:55 +00:00
|
|
|
}
|
|
|
|
|
2016-05-14 09:26:22 +00:00
|
|
|
/* Now let's check the query's dname corresponds to the one we sent.
|
|
|
|
* We can check only the first query of the list. We send one query at a time
|
|
|
|
* so we get one query in the response */
|
2017-05-22 13:13:10 +00:00
|
|
|
query = LIST_NEXT(&resolution->response.query_list, struct dns_query_item *, list);
|
2017-08-04 16:35:36 +00:00
|
|
|
if (!resolution->hostname_dn)
|
|
|
|
abort();
|
2016-05-14 09:26:22 +00:00
|
|
|
if (query && memcmp(query->name, resolution->hostname_dn, resolution->hostname_dn_len) != 0) {
|
|
|
|
nameserver->counters.other += 1;
|
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.
2017-05-22 13:17:15 +00:00
|
|
|
/* now parse list of requesters currently waiting for this resolution */
|
|
|
|
list_for_each_entry_safe(requester, tmprequester, &resolution->requester.curr, list) {
|
|
|
|
requester->requester_error_cb(requester, DNS_RESP_WRONG_NAME);
|
|
|
|
/* we can move the requester the wait queue */
|
|
|
|
LIST_DEL(&requester->list);
|
|
|
|
LIST_ADDQ(&resolution->requester.wait, &requester->list);
|
|
|
|
}
|
|
|
|
goto next_packet;
|
2016-05-14 09:26:22 +00:00
|
|
|
}
|
|
|
|
|
2017-05-04 07:05:00 +00:00
|
|
|
/* no errors, we can save the response in the cache */
|
|
|
|
if (dns_lru_tree) {
|
|
|
|
unsigned long long seed = 1;
|
|
|
|
struct chunk *buf = get_trash_chunk();
|
|
|
|
struct chunk *tmp = NULL;
|
|
|
|
|
|
|
|
chunk_reset(buf);
|
|
|
|
tmp = dns_cache_key(resolution->query_type, resolution->hostname_dn,
|
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.
2017-05-22 13:17:15 +00:00
|
|
|
resolution->hostname_dn_len, buf);
|
2017-05-04 07:05:00 +00:00
|
|
|
if (!tmp) {
|
|
|
|
nameserver->counters.other += 1;
|
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.
2017-05-22 13:17:15 +00:00
|
|
|
/* now parse list of requesters currently waiting for this resolution */
|
|
|
|
list_for_each_entry_safe(requester, tmprequester, &resolution->requester.curr, list) {
|
|
|
|
requester->requester_error_cb(requester, DNS_RESP_ERROR);
|
|
|
|
/* we can move the requester the wait queue */
|
|
|
|
LIST_DEL(&requester->list);
|
|
|
|
LIST_ADDQ(&resolution->requester.wait, &requester->list);
|
|
|
|
}
|
|
|
|
goto next_packet;
|
2017-05-04 07:05:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
lru = lru64_get(XXH64(buf->str, buf->len, seed),
|
|
|
|
dns_lru_tree, nameserver->resolvers, 1);
|
|
|
|
|
|
|
|
lru64_commit(lru, resolution, nameserver->resolvers, 1, NULL);
|
|
|
|
}
|
|
|
|
|
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.
2017-05-22 13:17:15 +00:00
|
|
|
if (resolution->status != RSLV_STATUS_VALID) {
|
|
|
|
resolution->status = RSLV_STATUS_VALID;
|
|
|
|
resolution->last_status_change = now_ms;
|
|
|
|
}
|
|
|
|
|
2015-08-07 08:18:32 +00:00
|
|
|
nameserver->counters.valid += 1;
|
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.
2017-05-22 13:17:15 +00:00
|
|
|
/* now parse list of requesters currently waiting for this resolution */
|
|
|
|
tmpnameserver = nameserver;
|
|
|
|
list_for_each_entry_safe(requester, tmprequester, &resolution->requester.curr, list) {
|
|
|
|
requester->requester_cb(requester, tmpnameserver);
|
|
|
|
/* we can move the requester the wait queue */
|
|
|
|
LIST_DEL(&requester->list);
|
|
|
|
LIST_ADDQ(&resolution->requester.wait, &requester->list);
|
|
|
|
/* first response is managed by the server, others are from the cache */
|
|
|
|
tmpnameserver = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
next_packet:
|
|
|
|
/* resolution may be NULL when we receive an ICMP unreachable packet */
|
|
|
|
if (resolution && LIST_ISEMPTY(&resolution->requester.curr)) {
|
|
|
|
/* move the resolution into the wait queue */
|
|
|
|
LIST_DEL(&resolution->list);
|
|
|
|
LIST_ADDQ(&resolvers->resolution.wait, &resolution->list);
|
|
|
|
/* 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);
|
|
|
|
}
|
|
|
|
|
|
|
|
} // end of while "packets" loop
|
|
|
|
|
|
|
|
dns_update_resolvers_timeout(nameserver->resolvers);
|
2015-04-13 21:40:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* function called when a resolvers network socket is ready to send data
|
|
|
|
* It performs the following actions:
|
|
|
|
*/
|
|
|
|
void dns_resolve_send(struct dgram_conn *dgram)
|
|
|
|
{
|
|
|
|
int fd;
|
|
|
|
struct dns_nameserver *nameserver;
|
|
|
|
struct dns_resolvers *resolvers;
|
|
|
|
struct dns_resolution *resolution;
|
|
|
|
|
|
|
|
fd = dgram->t.sock.fd;
|
|
|
|
|
|
|
|
/* check if ready for sending */
|
|
|
|
if (!fd_send_ready(fd))
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* we don't want/need to be waked up any more for sending */
|
|
|
|
fd_stop_send(fd);
|
|
|
|
|
|
|
|
/* no need to go further if we can't retrieve the nameserver */
|
2016-04-03 11:48:42 +00:00
|
|
|
if ((nameserver = dgram->owner) == NULL)
|
2015-04-13 21:40:55 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
resolvers = nameserver->resolvers;
|
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.
2017-05-22 13:17:15 +00:00
|
|
|
resolution = LIST_NEXT(&resolvers->resolution.curr, struct dns_resolution *, list);
|
2015-04-13 21:40:55 +00:00
|
|
|
|
|
|
|
dns_send_query(resolution);
|
|
|
|
dns_update_resolvers_timeout(resolvers);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* forge and send a DNS query to resolvers associated to a resolution
|
|
|
|
* It performs the following actions:
|
|
|
|
* returns:
|
|
|
|
* 0 in case of error or safe ignorance
|
|
|
|
* 1 if no error
|
|
|
|
*/
|
|
|
|
int dns_send_query(struct dns_resolution *resolution)
|
|
|
|
{
|
2017-05-03 10:12:02 +00:00
|
|
|
struct dns_resolvers *resolvers = NULL;
|
2015-04-13 21:40:55 +00:00
|
|
|
struct dns_nameserver *nameserver;
|
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.
2017-05-22 13:17:15 +00:00
|
|
|
struct dns_requester *requester = NULL;
|
2015-10-15 13:07:26 +00:00
|
|
|
int ret, bufsize, fd;
|
2015-04-13 21:40:55 +00:00
|
|
|
|
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.
2017-05-22 13:17:15 +00:00
|
|
|
/* nothing to do */
|
|
|
|
if (LIST_ISEMPTY(&resolution->requester.curr))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
requester = LIST_NEXT(&resolution->requester.curr, struct dns_requester *, list);
|
|
|
|
|
|
|
|
switch (obj_type(requester->requester)) {
|
|
|
|
case OBJ_TYPE_SERVER:
|
|
|
|
resolvers = objt_server(requester->requester)->resolvers;
|
|
|
|
break;
|
2017-08-04 16:35:36 +00:00
|
|
|
case OBJ_TYPE_SRVRQ:
|
|
|
|
resolvers = objt_dns_srvrq(requester->requester)->resolvers;
|
|
|
|
break;
|
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.
2017-05-22 13:17:15 +00:00
|
|
|
case OBJ_TYPE_NONE:
|
|
|
|
default:
|
|
|
|
return 0;
|
|
|
|
}
|
2017-05-03 10:12:02 +00:00
|
|
|
|
|
|
|
if (!resolvers)
|
|
|
|
return 0;
|
2015-04-13 21:40:55 +00:00
|
|
|
|
2017-08-13 22:13:01 +00:00
|
|
|
bufsize = dns_build_query(resolution->query_id, resolution->query_type, resolvers->accepted_payload_size,
|
|
|
|
resolution->hostname_dn, resolution->hostname_dn_len, trash.str, trash.size);
|
2015-04-13 21:40:55 +00:00
|
|
|
|
|
|
|
if (bufsize == -1)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
list_for_each_entry(nameserver, &resolvers->nameserver_list, list) {
|
|
|
|
fd = nameserver->dgram->t.sock.fd;
|
|
|
|
errno = 0;
|
|
|
|
|
|
|
|
ret = send(fd, trash.str, bufsize, 0);
|
|
|
|
|
|
|
|
if (ret > 0)
|
|
|
|
nameserver->counters.sent += 1;
|
|
|
|
|
|
|
|
if (ret == 0 || errno == EAGAIN) {
|
|
|
|
/* nothing written, let's update the poller that we wanted to send
|
|
|
|
* but we were not able to */
|
|
|
|
fd_want_send(fd);
|
|
|
|
fd_cant_send(fd);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* update resolution */
|
|
|
|
resolution->nb_responses = 0;
|
|
|
|
resolution->last_sent_packet = now_ms;
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* update a resolvers' task timeout for next wake up
|
|
|
|
*/
|
|
|
|
void dns_update_resolvers_timeout(struct dns_resolvers *resolvers)
|
|
|
|
{
|
|
|
|
struct dns_resolution *resolution;
|
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.
2017-05-22 13:17:15 +00:00
|
|
|
struct dns_requester *requester;
|
2015-04-13 21:40:55 +00:00
|
|
|
|
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.
2017-05-22 13:17:15 +00:00
|
|
|
if ((LIST_ISEMPTY(&resolvers->resolution.curr)) && (LIST_ISEMPTY(&resolvers->resolution.wait))) {
|
2015-04-13 21:40:55 +00:00
|
|
|
resolvers->t->expire = TICK_ETERNITY;
|
|
|
|
}
|
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.
2017-05-22 13:17:15 +00:00
|
|
|
else if (!LIST_ISEMPTY(&resolvers->resolution.curr)) {
|
|
|
|
resolution = LIST_NEXT(&resolvers->resolution.curr, struct dns_resolution *, list);
|
|
|
|
if (!resolvers->t->expire || tick_is_le(resolvers->t->expire, tick_add(resolution->last_sent_packet, resolvers->timeout.retry))) {
|
|
|
|
resolvers->t->expire = tick_add(resolution->last_sent_packet, resolvers->timeout.retry);
|
|
|
|
}
|
2015-04-13 21:40:55 +00:00
|
|
|
}
|
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.
2017-05-22 13:17:15 +00:00
|
|
|
else if (!LIST_ISEMPTY(&resolvers->resolution.wait)) {
|
|
|
|
int valid_period, inter, need_wakeup;
|
|
|
|
struct dns_resolution *res_back;
|
|
|
|
need_wakeup = 0;
|
|
|
|
list_for_each_entry_safe(resolution, res_back, &resolvers->resolution.wait, list) {
|
|
|
|
valid_period = 0;
|
|
|
|
inter = 0;
|
|
|
|
|
|
|
|
requester = LIST_NEXT(&resolution->requester.wait, struct dns_requester *, list);
|
|
|
|
|
|
|
|
switch (obj_type(requester->requester)) {
|
|
|
|
case OBJ_TYPE_SERVER:
|
|
|
|
valid_period = objt_server(requester->requester)->check.inter;
|
|
|
|
break;
|
2017-08-04 16:35:36 +00:00
|
|
|
case OBJ_TYPE_SRVRQ:
|
|
|
|
valid_period = objt_dns_srvrq(requester->requester)->inter;
|
|
|
|
break;
|
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.
2017-05-22 13:17:15 +00:00
|
|
|
case OBJ_TYPE_NONE:
|
|
|
|
default:
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (resolvers->hold.valid < valid_period)
|
|
|
|
inter = resolvers->hold.valid;
|
|
|
|
else
|
|
|
|
inter = valid_period;
|
|
|
|
|
|
|
|
if (tick_is_expired(tick_add(resolution->last_resolution, inter), now_ms)) {
|
|
|
|
switch (obj_type(requester->requester)) {
|
|
|
|
case OBJ_TYPE_SERVER:
|
|
|
|
dns_trigger_resolution(objt_server(requester->requester)->resolution);
|
|
|
|
break;
|
2017-08-04 16:35:36 +00:00
|
|
|
case OBJ_TYPE_SRVRQ:
|
|
|
|
dns_trigger_resolution(objt_dns_srvrq(requester->requester)->resolution);
|
|
|
|
break;
|
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.
2017-05-22 13:17:15 +00:00
|
|
|
case OBJ_TYPE_NONE:
|
|
|
|
default:
|
|
|
|
;;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
need_wakeup = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* in such case, we wake up in 1s */
|
|
|
|
if (need_wakeup) {
|
|
|
|
int r = 1000;
|
|
|
|
|
|
|
|
resolution = LIST_NEXT(&resolvers->resolution.wait, struct dns_resolution *, list);
|
|
|
|
if (tick_is_le(resolvers->t->expire, tick_add(now_ms, r)))
|
|
|
|
resolvers->t->expire = tick_add(now_ms, r);
|
|
|
|
resolvers->t->expire = tick_add(now_ms, 1000);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
task_queue(resolvers->t);
|
2015-04-13 21:40:55 +00:00
|
|
|
}
|
|
|
|
|
2016-05-14 09:26:22 +00:00
|
|
|
/*
|
|
|
|
* Analyse, re-build and copy the name <name> from the DNS response packet <buffer>.
|
|
|
|
* <name> must point to the 'data_len' information or pointer 'c0' for compressed data.
|
|
|
|
* The result is copied into <dest>, ensuring we don't overflow using <dest_len>
|
|
|
|
* Returns the number of bytes the caller can move forward. If 0 it means an error occured
|
|
|
|
* while parsing the name.
|
|
|
|
* <offset> is the number of bytes the caller could move forward.
|
|
|
|
*/
|
|
|
|
int dns_read_name(unsigned char *buffer, unsigned char *bufend, unsigned char *name, char *destination, int dest_len, int *offset)
|
|
|
|
{
|
|
|
|
int nb_bytes = 0, n = 0;
|
|
|
|
int label_len;
|
|
|
|
unsigned char *reader = name;
|
|
|
|
char *dest = destination;
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
/* name compression is in use */
|
|
|
|
if ((*reader & 0xc0) == 0xc0) {
|
|
|
|
/* a pointer must point BEFORE current position */
|
|
|
|
if ((buffer + reader[1]) > reader) {
|
|
|
|
goto out_error;
|
|
|
|
}
|
|
|
|
|
|
|
|
n = dns_read_name(buffer, bufend, buffer + reader[1], dest, dest_len - nb_bytes, offset);
|
|
|
|
if (n == 0)
|
|
|
|
goto out_error;
|
|
|
|
|
|
|
|
dest += n;
|
|
|
|
nb_bytes += n;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
label_len = *reader;
|
|
|
|
if (label_len == 0)
|
|
|
|
goto out;
|
|
|
|
/* Check if:
|
|
|
|
* - we won't read outside the buffer
|
|
|
|
* - there is enough place in the destination
|
|
|
|
*/
|
|
|
|
if ((reader + label_len >= bufend) || (nb_bytes + label_len >= dest_len))
|
|
|
|
goto out_error;
|
|
|
|
|
|
|
|
/* +1 to take label len + label string */
|
|
|
|
label_len += 1;
|
|
|
|
|
|
|
|
memcpy(dest, reader, label_len);
|
|
|
|
|
|
|
|
dest += label_len;
|
|
|
|
nb_bytes += label_len;
|
|
|
|
reader += label_len;
|
|
|
|
}
|
|
|
|
|
|
|
|
out:
|
|
|
|
/* offset computation:
|
|
|
|
* parse from <name> until finding either NULL or a pointer "c0xx"
|
|
|
|
*/
|
|
|
|
reader = name;
|
|
|
|
*offset = 0;
|
|
|
|
while (reader < bufend) {
|
|
|
|
if ((reader[0] & 0xc0) == 0xc0) {
|
|
|
|
*offset += 2;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else if (*reader == 0) {
|
|
|
|
*offset += 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
*offset += 1;
|
|
|
|
++reader;
|
|
|
|
}
|
|
|
|
|
|
|
|
return nb_bytes;
|
|
|
|
|
|
|
|
out_error:
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-04-13 21:40:55 +00:00
|
|
|
/*
|
|
|
|
* Function to validate that the buffer DNS response provided in <resp> and
|
|
|
|
* finishing before <bufend> is valid from a DNS protocol point of view.
|
2016-05-14 09:26:22 +00:00
|
|
|
*
|
2017-05-22 13:13:10 +00:00
|
|
|
* The result is stored in <resolution>' response, buf_response, response_query_records
|
|
|
|
* and response_answer_records members.
|
2016-05-14 09:26:22 +00:00
|
|
|
*
|
|
|
|
* This function returns one of the DNS_RESP_* code to indicate the type of
|
|
|
|
* error found.
|
2015-04-13 21:40:55 +00:00
|
|
|
*/
|
2017-08-18 21:35:08 +00:00
|
|
|
int dns_validate_dns_response(unsigned char *resp, unsigned char *bufend, struct dns_resolution *resolution, int max_answer_records)
|
2015-04-13 21:40:55 +00:00
|
|
|
{
|
2016-05-14 09:26:22 +00:00
|
|
|
unsigned char *reader;
|
|
|
|
char *previous_dname, tmpname[DNS_MAX_NAME_SIZE];
|
2017-07-06 16:46:47 +00:00
|
|
|
int len, flags, offset;
|
|
|
|
int dns_query_record_id;
|
2017-05-04 06:37:45 +00:00
|
|
|
int nb_saved_records;
|
2016-05-14 09:26:22 +00:00
|
|
|
struct dns_query_item *dns_query;
|
2017-07-06 16:46:47 +00:00
|
|
|
struct dns_answer_item *dns_answer_record, *tmp_record;
|
2017-05-22 13:13:10 +00:00
|
|
|
struct dns_response_packet *dns_p;
|
2017-07-06 16:46:47 +00:00
|
|
|
int found = 0;
|
2017-08-04 16:35:36 +00:00
|
|
|
int i;
|
2015-04-13 21:40:55 +00:00
|
|
|
|
|
|
|
reader = resp;
|
|
|
|
len = 0;
|
2016-05-14 09:26:22 +00:00
|
|
|
previous_dname = NULL;
|
2017-08-11 07:58:27 +00:00
|
|
|
dns_query = NULL;
|
2016-05-14 09:26:22 +00:00
|
|
|
|
2017-05-22 13:13:10 +00:00
|
|
|
/* initialization of response buffer and structure */
|
|
|
|
dns_p = &resolution->response;
|
2016-05-14 09:26:22 +00:00
|
|
|
|
|
|
|
/* query id */
|
|
|
|
if (reader + 2 >= bufend)
|
2015-04-13 21:40:55 +00:00
|
|
|
return DNS_RESP_INVALID;
|
2016-05-14 09:26:22 +00:00
|
|
|
dns_p->header.id = reader[0] * 256 + reader[1];
|
|
|
|
reader += 2;
|
2015-04-13 21:40:55 +00:00
|
|
|
|
|
|
|
/*
|
2016-05-14 09:26:22 +00:00
|
|
|
* flags and rcode are stored over 2 bytes
|
2015-09-02 20:08:38 +00:00
|
|
|
* First byte contains:
|
|
|
|
* - response flag (1 bit)
|
|
|
|
* - opcode (4 bits)
|
|
|
|
* - authoritative (1 bit)
|
|
|
|
* - truncated (1 bit)
|
|
|
|
* - recursion desired (1 bit)
|
2015-04-13 21:40:55 +00:00
|
|
|
*/
|
2015-09-02 20:08:38 +00:00
|
|
|
if (reader + 2 >= bufend)
|
2015-04-13 21:40:55 +00:00
|
|
|
return DNS_RESP_INVALID;
|
|
|
|
|
2015-09-02 20:08:38 +00:00
|
|
|
flags = reader[0] * 256 + reader[1];
|
|
|
|
|
|
|
|
if ((flags & DNS_FLAG_REPLYCODE) != DNS_RCODE_NO_ERROR) {
|
|
|
|
if ((flags & DNS_FLAG_REPLYCODE) == DNS_RCODE_NX_DOMAIN)
|
2015-04-13 21:40:55 +00:00
|
|
|
return DNS_RESP_NX_DOMAIN;
|
2015-09-02 20:08:38 +00:00
|
|
|
else if ((flags & DNS_FLAG_REPLYCODE) == DNS_RCODE_REFUSED)
|
2015-04-13 21:40:55 +00:00
|
|
|
return DNS_RESP_REFUSED;
|
|
|
|
|
|
|
|
return DNS_RESP_ERROR;
|
|
|
|
}
|
|
|
|
|
2015-09-02 20:08:38 +00:00
|
|
|
/* move forward 2 bytes for flags */
|
|
|
|
reader += 2;
|
2015-04-13 21:40:55 +00:00
|
|
|
|
2016-05-14 09:26:22 +00:00
|
|
|
/* 2 bytes for question count */
|
|
|
|
if (reader + 2 >= bufend)
|
2015-04-13 21:40:55 +00:00
|
|
|
return DNS_RESP_INVALID;
|
2016-05-14 09:26:22 +00:00
|
|
|
dns_p->header.qdcount = reader[0] * 256 + reader[1];
|
|
|
|
/* (for now) we send one query only, so we expect only one in the response too */
|
|
|
|
if (dns_p->header.qdcount != 1)
|
|
|
|
return DNS_RESP_QUERY_COUNT_ERROR;
|
|
|
|
if (dns_p->header.qdcount > DNS_MAX_QUERY_RECORDS)
|
2015-04-13 21:40:55 +00:00
|
|
|
return DNS_RESP_INVALID;
|
2016-05-14 09:26:22 +00:00
|
|
|
reader += 2;
|
2015-04-13 21:40:55 +00:00
|
|
|
|
2016-05-14 09:26:22 +00:00
|
|
|
/* 2 bytes for answer count */
|
|
|
|
if (reader + 2 >= bufend)
|
|
|
|
return DNS_RESP_INVALID;
|
|
|
|
dns_p->header.ancount = reader[0] * 256 + reader[1];
|
|
|
|
if (dns_p->header.ancount == 0)
|
2015-04-13 21:40:55 +00:00
|
|
|
return DNS_RESP_ANCOUNT_ZERO;
|
2016-05-14 09:26:22 +00:00
|
|
|
/* check if too many records are announced */
|
2017-08-18 21:35:08 +00:00
|
|
|
if (dns_p->header.ancount > max_answer_records)
|
2015-04-13 21:40:55 +00:00
|
|
|
return DNS_RESP_INVALID;
|
2016-05-14 09:26:22 +00:00
|
|
|
reader += 2;
|
2015-04-13 21:40:55 +00:00
|
|
|
|
2016-05-14 09:26:22 +00:00
|
|
|
/* 2 bytes authority count */
|
|
|
|
if (reader + 2 >= bufend)
|
2015-04-13 21:40:55 +00:00
|
|
|
return DNS_RESP_INVALID;
|
2016-05-14 09:26:22 +00:00
|
|
|
dns_p->header.nscount = reader[0] * 256 + reader[1];
|
|
|
|
reader += 2;
|
2015-04-13 21:40:55 +00:00
|
|
|
|
2016-05-14 09:26:22 +00:00
|
|
|
/* 2 bytes additional count */
|
|
|
|
if (reader + 2 >= bufend)
|
2015-04-13 21:40:55 +00:00
|
|
|
return DNS_RESP_INVALID;
|
2016-05-14 09:26:22 +00:00
|
|
|
dns_p->header.arcount = reader[0] * 256 + reader[1];
|
|
|
|
reader += 2;
|
2015-04-13 21:40:55 +00:00
|
|
|
|
2016-05-14 09:26:22 +00:00
|
|
|
/* parsing dns queries */
|
|
|
|
LIST_INIT(&dns_p->query_list);
|
|
|
|
for (dns_query_record_id = 0; dns_query_record_id < dns_p->header.qdcount; dns_query_record_id++) {
|
|
|
|
/* use next pre-allocated dns_query_item after ensuring there is
|
|
|
|
* still one available.
|
|
|
|
* It's then added to our packet query list.
|
|
|
|
*/
|
|
|
|
if (dns_query_record_id > DNS_MAX_QUERY_RECORDS)
|
|
|
|
return DNS_RESP_INVALID;
|
2017-05-22 13:13:10 +00:00
|
|
|
dns_query = &resolution->response_query_records[dns_query_record_id];
|
2016-05-14 09:26:22 +00:00
|
|
|
LIST_ADDQ(&dns_p->query_list, &dns_query->list);
|
2015-04-13 21:40:55 +00:00
|
|
|
|
2016-05-14 09:26:22 +00:00
|
|
|
/* name is a NULL terminated string in our case, since we have
|
|
|
|
* one query per response and the first one can't be compressed
|
|
|
|
* (using the 0x0c format)
|
|
|
|
*/
|
|
|
|
offset = 0;
|
|
|
|
len = dns_read_name(resp, bufend, reader, dns_query->name, DNS_MAX_NAME_SIZE, &offset);
|
2015-04-13 21:40:55 +00:00
|
|
|
|
2016-05-14 09:26:22 +00:00
|
|
|
if (len == 0)
|
|
|
|
return DNS_RESP_INVALID;
|
|
|
|
|
|
|
|
reader += offset;
|
|
|
|
previous_dname = dns_query->name;
|
|
|
|
|
|
|
|
/* move forward 2 bytes for question type */
|
|
|
|
if (reader + 2 >= bufend)
|
|
|
|
return DNS_RESP_INVALID;
|
|
|
|
dns_query->type = reader[0] * 256 + reader[1];
|
|
|
|
reader += 2;
|
|
|
|
|
|
|
|
/* move forward 2 bytes for question class */
|
|
|
|
if (reader + 2 >= bufend)
|
|
|
|
return DNS_RESP_INVALID;
|
|
|
|
dns_query->class = reader[0] * 256 + reader[1];
|
|
|
|
reader += 2;
|
|
|
|
}
|
2015-04-13 21:40:55 +00:00
|
|
|
|
2017-08-11 07:58:27 +00:00
|
|
|
/* TRUNCATED flag must be checked after we could read the query type
|
|
|
|
* because a TRUNCATED SRV query type response can still be exploited
|
|
|
|
*/
|
|
|
|
if (dns_query->type != DNS_RTYPE_SRV && flags & DNS_FLAG_TRUNCATED)
|
|
|
|
return DNS_RESP_TRUNCATED;
|
|
|
|
|
2015-04-13 21:40:55 +00:00
|
|
|
/* now parsing response records */
|
2017-05-04 06:37:45 +00:00
|
|
|
nb_saved_records = 0;
|
2017-08-04 16:35:36 +00:00
|
|
|
for (i = 0; i < dns_p->header.ancount; i++) {
|
2015-04-13 21:40:55 +00:00
|
|
|
if (reader >= bufend)
|
|
|
|
return DNS_RESP_INVALID;
|
|
|
|
|
2017-07-06 16:46:47 +00:00
|
|
|
dns_answer_record = pool_alloc2(dns_answer_item_pool);
|
|
|
|
if (dns_answer_record == NULL)
|
|
|
|
return (DNS_RESP_INVALID);
|
2015-04-13 21:40:55 +00:00
|
|
|
|
2016-05-14 09:26:22 +00:00
|
|
|
offset = 0;
|
|
|
|
len = dns_read_name(resp, bufend, reader, tmpname, DNS_MAX_NAME_SIZE, &offset);
|
|
|
|
|
2017-07-06 16:46:47 +00:00
|
|
|
if (len == 0) {
|
|
|
|
free_dns_answer_item(dns_answer_record);
|
2016-05-14 09:26:22 +00:00
|
|
|
return DNS_RESP_INVALID;
|
2017-07-06 16:46:47 +00:00
|
|
|
}
|
2015-04-13 21:40:55 +00:00
|
|
|
|
2016-05-14 09:26:22 +00:00
|
|
|
/* check if the current record dname is valid.
|
|
|
|
* previous_dname points either to queried dname or last CNAME target
|
|
|
|
*/
|
2017-08-11 08:31:22 +00:00
|
|
|
if (dns_query->type != DNS_RTYPE_SRV && memcmp(previous_dname, tmpname, len) != 0) {
|
2017-07-06 16:46:47 +00:00
|
|
|
free_dns_answer_item(dns_answer_record);
|
|
|
|
if (i == 0) {
|
2016-05-14 09:26:22 +00:00
|
|
|
/* first record, means a mismatch issue between queried dname
|
|
|
|
* and dname found in the first record */
|
2015-04-13 21:40:55 +00:00
|
|
|
return DNS_RESP_INVALID;
|
2016-05-14 09:26:22 +00:00
|
|
|
} else {
|
|
|
|
/* if not the first record, this means we have a CNAME resolution
|
|
|
|
* error */
|
|
|
|
return DNS_RESP_CNAME_ERROR;
|
2015-04-13 21:40:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2017-07-06 16:46:47 +00:00
|
|
|
memcpy(dns_answer_record->name, tmpname, len);
|
|
|
|
dns_answer_record->name[len] = 0;
|
2015-08-07 09:24:05 +00:00
|
|
|
|
2016-05-14 09:26:22 +00:00
|
|
|
reader += offset;
|
2017-07-06 16:46:47 +00:00
|
|
|
if (reader >= bufend) {
|
|
|
|
free_dns_answer_item(dns_answer_record);
|
2015-04-13 21:40:55 +00:00
|
|
|
return DNS_RESP_INVALID;
|
2017-07-06 16:46:47 +00:00
|
|
|
}
|
2015-04-13 21:40:55 +00:00
|
|
|
|
2016-05-14 09:26:22 +00:00
|
|
|
/* 2 bytes for record type (A, AAAA, CNAME, etc...) */
|
2017-07-06 16:46:47 +00:00
|
|
|
if (reader + 2 > bufend) {
|
|
|
|
free_dns_answer_item(dns_answer_record);
|
2015-04-13 21:40:55 +00:00
|
|
|
return DNS_RESP_INVALID;
|
2017-07-06 16:46:47 +00:00
|
|
|
}
|
2016-05-14 09:26:22 +00:00
|
|
|
dns_answer_record->type = reader[0] * 256 + reader[1];
|
|
|
|
reader += 2;
|
2015-04-13 21:40:55 +00:00
|
|
|
|
2016-05-14 09:26:22 +00:00
|
|
|
/* 2 bytes for class (2) */
|
2017-07-06 16:46:47 +00:00
|
|
|
if (reader + 2 > bufend) {
|
|
|
|
free_dns_answer_item(dns_answer_record);
|
2016-05-14 09:26:22 +00:00
|
|
|
return DNS_RESP_INVALID;
|
2017-07-06 16:46:47 +00:00
|
|
|
}
|
2016-05-14 09:26:22 +00:00
|
|
|
dns_answer_record->class = reader[0] * 256 + reader[1];
|
2015-04-13 21:40:55 +00:00
|
|
|
reader += 2;
|
|
|
|
|
2016-05-14 09:26:22 +00:00
|
|
|
/* 4 bytes for ttl (4) */
|
2017-07-06 16:46:47 +00:00
|
|
|
if (reader + 4 > bufend) {
|
|
|
|
free_dns_answer_item(dns_answer_record);
|
2015-04-13 21:40:55 +00:00
|
|
|
return DNS_RESP_INVALID;
|
2017-07-06 16:46:47 +00:00
|
|
|
}
|
2016-05-14 09:26:22 +00:00
|
|
|
dns_answer_record->ttl = reader[0] * 16777216 + reader[1] * 65536
|
|
|
|
+ reader[2] * 256 + reader[3];
|
|
|
|
reader += 4;
|
2015-04-13 21:40:55 +00:00
|
|
|
|
|
|
|
/* now reading data len */
|
2017-07-06 16:46:47 +00:00
|
|
|
if (reader + 2 > bufend) {
|
|
|
|
free_dns_answer_item(dns_answer_record);
|
2015-04-13 21:40:55 +00:00
|
|
|
return DNS_RESP_INVALID;
|
2017-07-06 16:46:47 +00:00
|
|
|
}
|
2016-05-14 09:26:22 +00:00
|
|
|
dns_answer_record->data_len = reader[0] * 256 + reader[1];
|
2015-04-13 21:40:55 +00:00
|
|
|
|
|
|
|
/* move forward 2 bytes for data len */
|
|
|
|
reader += 2;
|
|
|
|
|
|
|
|
/* analyzing record content */
|
2016-05-14 09:26:22 +00:00
|
|
|
switch (dns_answer_record->type) {
|
2015-04-13 21:40:55 +00:00
|
|
|
case DNS_RTYPE_A:
|
|
|
|
/* ipv4 is stored on 4 bytes */
|
2017-07-06 16:46:47 +00:00
|
|
|
if (dns_answer_record->data_len != 4) {
|
|
|
|
free_dns_answer_item(dns_answer_record);
|
2015-04-13 21:40:55 +00:00
|
|
|
return DNS_RESP_INVALID;
|
2017-07-06 16:46:47 +00:00
|
|
|
}
|
2016-05-14 09:26:22 +00:00
|
|
|
dns_answer_record->address.sa_family = AF_INET;
|
|
|
|
memcpy(&(((struct sockaddr_in *)&dns_answer_record->address)->sin_addr),
|
|
|
|
reader, dns_answer_record->data_len);
|
2015-04-13 21:40:55 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case DNS_RTYPE_CNAME:
|
2016-05-14 09:26:22 +00:00
|
|
|
/* check if this is the last record and update the caller about the status:
|
|
|
|
* no IP could be found and last record was a CNAME. Could be triggered
|
|
|
|
* by a wrong query type
|
|
|
|
*
|
|
|
|
* + 1 because dns_answer_record_id starts at 0 while number of answers
|
|
|
|
* is an integer and starts at 1.
|
|
|
|
*/
|
2017-07-06 16:46:47 +00:00
|
|
|
if (i + 1 == dns_p->header.ancount) {
|
|
|
|
free_dns_answer_item(dns_answer_record);
|
2016-05-14 09:26:22 +00:00
|
|
|
return DNS_RESP_CNAME_ERROR;
|
2017-07-06 16:46:47 +00:00
|
|
|
}
|
2016-05-14 09:26:22 +00:00
|
|
|
|
|
|
|
offset = 0;
|
|
|
|
len = dns_read_name(resp, bufend, reader, tmpname, DNS_MAX_NAME_SIZE, &offset);
|
|
|
|
|
2017-07-06 16:46:47 +00:00
|
|
|
if (len == 0) {
|
|
|
|
free_dns_answer_item(dns_answer_record);
|
2016-05-14 09:26:22 +00:00
|
|
|
return DNS_RESP_INVALID;
|
2017-07-06 16:46:47 +00:00
|
|
|
}
|
2016-05-14 09:26:22 +00:00
|
|
|
|
2017-07-06 16:46:47 +00:00
|
|
|
memcpy(dns_answer_record->target, tmpname, len);
|
|
|
|
dns_answer_record->target[len] = 0;
|
2016-05-14 09:26:22 +00:00
|
|
|
|
|
|
|
previous_dname = dns_answer_record->target;
|
|
|
|
|
2015-04-13 21:40:55 +00:00
|
|
|
break;
|
|
|
|
|
2017-08-04 16:35:36 +00:00
|
|
|
|
|
|
|
case DNS_RTYPE_SRV:
|
|
|
|
/*
|
|
|
|
* Answer must contain :
|
|
|
|
* - 2 bytes for the priority
|
|
|
|
* - 2 bytes for the weight
|
|
|
|
* - 2 bytes for the port
|
|
|
|
* - the target hostname
|
|
|
|
*/
|
|
|
|
if (dns_answer_record->data_len <= 6) {
|
|
|
|
free_dns_answer_item(dns_answer_record);
|
|
|
|
return DNS_RESP_INVALID;
|
|
|
|
}
|
2017-09-19 12:59:52 +00:00
|
|
|
dns_answer_record->priority = read_n16(reader);
|
2017-08-04 16:35:36 +00:00
|
|
|
reader += sizeof(uint16_t);
|
2017-09-19 12:59:52 +00:00
|
|
|
dns_answer_record->weight = read_n16(reader);
|
2017-08-04 16:35:36 +00:00
|
|
|
reader += sizeof(uint16_t);
|
2017-09-19 12:59:52 +00:00
|
|
|
dns_answer_record->port = read_n16(reader);
|
2017-08-04 16:35:36 +00:00
|
|
|
reader += sizeof(uint16_t);
|
|
|
|
offset = 0;
|
|
|
|
len = dns_read_name(resp, bufend, reader, tmpname, DNS_MAX_NAME_SIZE, &offset);
|
|
|
|
if (len == 0) {
|
|
|
|
free_dns_answer_item(dns_answer_record);
|
|
|
|
return DNS_RESP_INVALID;
|
|
|
|
}
|
|
|
|
dns_answer_record->data_len = len;
|
|
|
|
memcpy(dns_answer_record->target, tmpname, len);
|
|
|
|
dns_answer_record->target[len] = 0;
|
|
|
|
break;
|
2015-04-13 21:40:55 +00:00
|
|
|
case DNS_RTYPE_AAAA:
|
|
|
|
/* ipv6 is stored on 16 bytes */
|
2017-07-06 16:46:47 +00:00
|
|
|
if (dns_answer_record->data_len != 16) {
|
|
|
|
free_dns_answer_item(dns_answer_record);
|
2015-04-13 21:40:55 +00:00
|
|
|
return DNS_RESP_INVALID;
|
2017-07-06 16:46:47 +00:00
|
|
|
}
|
2016-05-14 09:26:22 +00:00
|
|
|
dns_answer_record->address.sa_family = AF_INET6;
|
|
|
|
memcpy(&(((struct sockaddr_in6 *)&dns_answer_record->address)->sin6_addr),
|
|
|
|
reader, dns_answer_record->data_len);
|
2015-04-13 21:40:55 +00:00
|
|
|
break;
|
2016-05-14 09:26:22 +00:00
|
|
|
|
2015-04-13 21:40:55 +00:00
|
|
|
} /* switch (record type) */
|
|
|
|
|
2017-05-04 06:37:45 +00:00
|
|
|
/* increment the counter for number of records saved into our local response */
|
|
|
|
nb_saved_records += 1;
|
|
|
|
|
2016-05-14 09:26:22 +00:00
|
|
|
/* move forward dns_answer_record->data_len for analyzing next record in the response */
|
2017-08-11 08:37:20 +00:00
|
|
|
if (dns_answer_record->type == DNS_RTYPE_SRV)
|
|
|
|
reader += offset;
|
|
|
|
else
|
|
|
|
reader += dns_answer_record->data_len;
|
2017-07-06 16:46:47 +00:00
|
|
|
|
|
|
|
/* Lookup to see if we already had this entry */
|
|
|
|
|
2017-08-04 16:35:36 +00:00
|
|
|
found = 0;
|
2017-07-06 16:46:47 +00:00
|
|
|
list_for_each_entry(tmp_record, &dns_p->answer_list, list) {
|
|
|
|
if (tmp_record->type != dns_answer_record->type)
|
|
|
|
continue;
|
|
|
|
switch (tmp_record->type) {
|
|
|
|
case DNS_RTYPE_A:
|
|
|
|
if (!memcmp(&((struct sockaddr_in *)&dns_answer_record->address)->sin_addr,
|
|
|
|
&((struct sockaddr_in *)&tmp_record->address)->sin_addr, sizeof(in_addr_t)))
|
|
|
|
found = 1;
|
|
|
|
break;
|
|
|
|
case DNS_RTYPE_AAAA:
|
|
|
|
if (!memcmp(&((struct sockaddr_in6 *)&dns_answer_record->address)->sin6_addr,
|
|
|
|
&((struct sockaddr_in6 *)&tmp_record->address)->sin6_addr, sizeof(struct in6_addr)))
|
|
|
|
found = 1;
|
|
|
|
break;
|
2017-08-04 16:35:36 +00:00
|
|
|
case DNS_RTYPE_SRV:
|
|
|
|
if (dns_answer_record->data_len == tmp_record->data_len &&
|
|
|
|
!memcmp(dns_answer_record->target,
|
|
|
|
tmp_record->target, dns_answer_record->data_len) &&
|
|
|
|
dns_answer_record->port == tmp_record->port) {
|
|
|
|
tmp_record->weight = dns_answer_record->weight;
|
|
|
|
found = 1;
|
|
|
|
}
|
|
|
|
break;
|
2017-07-06 16:46:47 +00:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (found == 1)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (found == 1) {
|
|
|
|
tmp_record->last_seen = now.tv_sec;
|
|
|
|
free_dns_answer_item(dns_answer_record);
|
|
|
|
} else {
|
|
|
|
dns_answer_record->last_seen = now.tv_sec;
|
|
|
|
LIST_ADDQ(&dns_p->answer_list, &dns_answer_record->list);
|
|
|
|
}
|
|
|
|
|
2015-04-13 21:40:55 +00:00
|
|
|
} /* for i 0 to ancount */
|
|
|
|
|
2015-09-08 22:46:58 +00:00
|
|
|
|
2017-05-04 06:37:45 +00:00
|
|
|
/* save the number of records we really own */
|
|
|
|
dns_p->header.ancount = nb_saved_records;
|
|
|
|
|
2015-04-13 21:40:55 +00:00
|
|
|
return DNS_RESP_VALID;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* search dn_name resolution in resp.
|
|
|
|
* If existing IP not found, return the first IP matching family_priority,
|
|
|
|
* otherwise, first ip found
|
|
|
|
* The following tasks are the responsibility of the caller:
|
2016-04-17 20:43:26 +00:00
|
|
|
* - <dns_p> contains an error free DNS response
|
2015-04-13 21:40:55 +00:00
|
|
|
* For both cases above, dns_validate_dns_response is required
|
|
|
|
* returns one of the DNS_UPD_* code
|
|
|
|
*/
|
2016-02-17 21:05:30 +00:00
|
|
|
#define DNS_MAX_IP_REC 20
|
2017-05-03 13:43:12 +00:00
|
|
|
int dns_get_ip_from_response(struct dns_response_packet *dns_p,
|
2017-05-03 10:12:02 +00:00
|
|
|
struct dns_options *dns_opts, void *currentip,
|
2016-02-17 20:25:09 +00:00
|
|
|
short currentip_sin_family,
|
2017-05-03 13:43:12 +00:00
|
|
|
void **newip, short *newip_sin_family,
|
|
|
|
void *owner)
|
2015-04-13 21:40:55 +00:00
|
|
|
{
|
2016-05-14 09:26:22 +00:00
|
|
|
struct dns_answer_item *record;
|
2016-02-17 20:25:09 +00:00
|
|
|
int family_priority;
|
2017-07-06 16:46:47 +00:00
|
|
|
int currentip_found;
|
2016-04-17 20:43:26 +00:00
|
|
|
unsigned char *newip4, *newip6;
|
2016-02-17 21:05:30 +00:00
|
|
|
int currentip_sel;
|
|
|
|
int j;
|
|
|
|
int score, max_score;
|
2015-04-13 21:40:55 +00:00
|
|
|
|
2017-05-03 10:12:02 +00:00
|
|
|
family_priority = dns_opts->family_prio;
|
2016-04-17 20:43:26 +00:00
|
|
|
*newip = newip4 = newip6 = NULL;
|
|
|
|
currentip_found = 0;
|
2015-04-13 21:40:55 +00:00
|
|
|
*newip_sin_family = AF_UNSPEC;
|
2017-07-06 16:46:47 +00:00
|
|
|
max_score = -1;
|
2015-04-13 21:40:55 +00:00
|
|
|
|
2016-02-17 21:05:30 +00:00
|
|
|
/* Select an IP regarding configuration preference.
|
|
|
|
* Top priority is the prefered network ip version,
|
|
|
|
* second priority is the prefered network.
|
|
|
|
* the last priority is the currently used IP,
|
|
|
|
*
|
|
|
|
* For these three priorities, a score is calculated. The
|
|
|
|
* weight are:
|
MINOR: dns: improve DNS response parsing to use as many available records as possible
A "weakness" exist in the first implementation of the parsing of the DNS
responses: HAProxy always choses the first IP available matching family
preference, or as a failover, the first IP.
It should be good enough, since most DNS servers do round robin on the
records they send back to clients.
That said, some servers does not do proper round robin, or we may be
unlucky too and deliver the same IP to all the servers sharing the same
hostname.
Let's take the simple configuration below:
backend bk
srv s1 www:80 check resolvers R
srv s2 www:80 check resolvers R
The DNS server configured with 2 IPs for 'www'.
If you're unlucky, then HAProxy may apply the same IP to both servers.
Current patch improves this situation by weighting the decision
algorithm to ensure we'll prefer use first an IP found in the response
which is not already affected to any server.
The new algorithm does not guarantee that the chosen IP is healthy,
neither a fair distribution of IPs amongst the servers in the farm,
etc...
It only guarantees that if the DNS server returns many records for a
hostname and that this hostname is being resolved by multiple servers in
the same backend, then we'll use as many records as possible.
If a server fails, HAProxy won't pick up an other record from the
response.
2016-12-26 22:21:08 +00:00
|
|
|
* 8 - prefered netwok ip version.
|
|
|
|
* 4 - prefered network.
|
|
|
|
* 2 - if the ip in the record is not affected to any other server in the same backend (duplication)
|
2016-02-17 21:05:30 +00:00
|
|
|
* 1 - current ip.
|
|
|
|
* The result with the biggest score is returned.
|
|
|
|
*/
|
|
|
|
|
2017-07-06 16:46:47 +00:00
|
|
|
list_for_each_entry(record, &dns_p->answer_list, list) {
|
|
|
|
void *ip;
|
|
|
|
unsigned char ip_type;
|
|
|
|
|
|
|
|
if (record->type == DNS_RTYPE_A) {
|
|
|
|
ip = &(((struct sockaddr_in *)&record->address)->sin_addr);
|
|
|
|
ip_type = AF_INET;
|
|
|
|
} else if (record->type == DNS_RTYPE_AAAA) {
|
|
|
|
ip_type = AF_INET6;
|
|
|
|
ip = &(((struct sockaddr_in6 *)&record->address)->sin6_addr);
|
|
|
|
} else
|
|
|
|
continue;
|
2016-02-17 21:05:30 +00:00
|
|
|
score = 0;
|
|
|
|
|
|
|
|
/* Check for prefered ip protocol. */
|
2017-07-06 16:46:47 +00:00
|
|
|
if (ip_type == family_priority)
|
MINOR: dns: improve DNS response parsing to use as many available records as possible
A "weakness" exist in the first implementation of the parsing of the DNS
responses: HAProxy always choses the first IP available matching family
preference, or as a failover, the first IP.
It should be good enough, since most DNS servers do round robin on the
records they send back to clients.
That said, some servers does not do proper round robin, or we may be
unlucky too and deliver the same IP to all the servers sharing the same
hostname.
Let's take the simple configuration below:
backend bk
srv s1 www:80 check resolvers R
srv s2 www:80 check resolvers R
The DNS server configured with 2 IPs for 'www'.
If you're unlucky, then HAProxy may apply the same IP to both servers.
Current patch improves this situation by weighting the decision
algorithm to ensure we'll prefer use first an IP found in the response
which is not already affected to any server.
The new algorithm does not guarantee that the chosen IP is healthy,
neither a fair distribution of IPs amongst the servers in the farm,
etc...
It only guarantees that if the DNS server returns many records for a
hostname and that this hostname is being resolved by multiple servers in
the same backend, then we'll use as many records as possible.
If a server fails, HAProxy won't pick up an other record from the
response.
2016-12-26 22:21:08 +00:00
|
|
|
score += 8;
|
2016-02-17 21:05:30 +00:00
|
|
|
|
|
|
|
/* Check for prefered network. */
|
2017-05-03 10:12:02 +00:00
|
|
|
for (j = 0; j < dns_opts->pref_net_nb; j++) {
|
2016-02-17 21:05:30 +00:00
|
|
|
|
|
|
|
/* Compare only the same adresses class. */
|
2017-07-06 16:46:47 +00:00
|
|
|
if (dns_opts->pref_net[j].family != ip_type)
|
2016-02-17 21:05:30 +00:00
|
|
|
continue;
|
|
|
|
|
2017-07-06 16:46:47 +00:00
|
|
|
if ((ip_type == AF_INET &&
|
|
|
|
in_net_ipv4(ip,
|
2017-05-03 10:12:02 +00:00
|
|
|
&dns_opts->pref_net[j].mask.in4,
|
|
|
|
&dns_opts->pref_net[j].addr.in4)) ||
|
2017-07-06 16:46:47 +00:00
|
|
|
(ip_type == AF_INET6 &&
|
|
|
|
in_net_ipv6(ip,
|
2017-05-03 10:12:02 +00:00
|
|
|
&dns_opts->pref_net[j].mask.in6,
|
|
|
|
&dns_opts->pref_net[j].addr.in6))) {
|
MINOR: dns: improve DNS response parsing to use as many available records as possible
A "weakness" exist in the first implementation of the parsing of the DNS
responses: HAProxy always choses the first IP available matching family
preference, or as a failover, the first IP.
It should be good enough, since most DNS servers do round robin on the
records they send back to clients.
That said, some servers does not do proper round robin, or we may be
unlucky too and deliver the same IP to all the servers sharing the same
hostname.
Let's take the simple configuration below:
backend bk
srv s1 www:80 check resolvers R
srv s2 www:80 check resolvers R
The DNS server configured with 2 IPs for 'www'.
If you're unlucky, then HAProxy may apply the same IP to both servers.
Current patch improves this situation by weighting the decision
algorithm to ensure we'll prefer use first an IP found in the response
which is not already affected to any server.
The new algorithm does not guarantee that the chosen IP is healthy,
neither a fair distribution of IPs amongst the servers in the farm,
etc...
It only guarantees that if the DNS server returns many records for a
hostname and that this hostname is being resolved by multiple servers in
the same backend, then we'll use as many records as possible.
If a server fails, HAProxy won't pick up an other record from the
response.
2016-12-26 22:21:08 +00:00
|
|
|
score += 4;
|
2016-02-17 21:05:30 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-05-03 13:43:12 +00:00
|
|
|
/* Check if the IP found in the record is already affected to a member of a group.
|
|
|
|
* If yes, the score should be incremented by 2.
|
|
|
|
*/
|
|
|
|
if (owner) {
|
2017-07-06 16:46:47 +00:00
|
|
|
if (snr_check_ip_callback(owner, ip, &ip_type))
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
MINOR: dns: improve DNS response parsing to use as many available records as possible
A "weakness" exist in the first implementation of the parsing of the DNS
responses: HAProxy always choses the first IP available matching family
preference, or as a failover, the first IP.
It should be good enough, since most DNS servers do round robin on the
records they send back to clients.
That said, some servers does not do proper round robin, or we may be
unlucky too and deliver the same IP to all the servers sharing the same
hostname.
Let's take the simple configuration below:
backend bk
srv s1 www:80 check resolvers R
srv s2 www:80 check resolvers R
The DNS server configured with 2 IPs for 'www'.
If you're unlucky, then HAProxy may apply the same IP to both servers.
Current patch improves this situation by weighting the decision
algorithm to ensure we'll prefer use first an IP found in the response
which is not already affected to any server.
The new algorithm does not guarantee that the chosen IP is healthy,
neither a fair distribution of IPs amongst the servers in the farm,
etc...
It only guarantees that if the DNS server returns many records for a
hostname and that this hostname is being resolved by multiple servers in
the same backend, then we'll use as many records as possible.
If a server fails, HAProxy won't pick up an other record from the
response.
2016-12-26 22:21:08 +00:00
|
|
|
}
|
2016-02-17 21:05:30 +00:00
|
|
|
/* Check for current ip matching. */
|
2017-07-06 16:46:47 +00:00
|
|
|
if (ip_type == currentip_sin_family &&
|
2016-02-17 21:05:30 +00:00
|
|
|
((currentip_sin_family == AF_INET &&
|
2017-07-06 16:46:47 +00:00
|
|
|
memcmp(ip, currentip, 4) == 0) ||
|
2016-02-17 21:05:30 +00:00
|
|
|
(currentip_sin_family == AF_INET6 &&
|
2017-07-06 16:46:47 +00:00
|
|
|
memcmp(ip, currentip, 16) == 0))) {
|
2016-02-17 21:05:30 +00:00
|
|
|
score += 1;
|
|
|
|
currentip_sel = 1;
|
|
|
|
} else
|
|
|
|
currentip_sel = 0;
|
|
|
|
|
MINOR: dns: improve DNS response parsing to use as many available records as possible
A "weakness" exist in the first implementation of the parsing of the DNS
responses: HAProxy always choses the first IP available matching family
preference, or as a failover, the first IP.
It should be good enough, since most DNS servers do round robin on the
records they send back to clients.
That said, some servers does not do proper round robin, or we may be
unlucky too and deliver the same IP to all the servers sharing the same
hostname.
Let's take the simple configuration below:
backend bk
srv s1 www:80 check resolvers R
srv s2 www:80 check resolvers R
The DNS server configured with 2 IPs for 'www'.
If you're unlucky, then HAProxy may apply the same IP to both servers.
Current patch improves this situation by weighting the decision
algorithm to ensure we'll prefer use first an IP found in the response
which is not already affected to any server.
The new algorithm does not guarantee that the chosen IP is healthy,
neither a fair distribution of IPs amongst the servers in the farm,
etc...
It only guarantees that if the DNS server returns many records for a
hostname and that this hostname is being resolved by multiple servers in
the same backend, then we'll use as many records as possible.
If a server fails, HAProxy won't pick up an other record from the
response.
2016-12-26 22:21:08 +00:00
|
|
|
|
2016-02-17 21:05:30 +00:00
|
|
|
/* Keep the address if the score is better than the previous
|
MINOR: dns: improve DNS response parsing to use as many available records as possible
A "weakness" exist in the first implementation of the parsing of the DNS
responses: HAProxy always choses the first IP available matching family
preference, or as a failover, the first IP.
It should be good enough, since most DNS servers do round robin on the
records they send back to clients.
That said, some servers does not do proper round robin, or we may be
unlucky too and deliver the same IP to all the servers sharing the same
hostname.
Let's take the simple configuration below:
backend bk
srv s1 www:80 check resolvers R
srv s2 www:80 check resolvers R
The DNS server configured with 2 IPs for 'www'.
If you're unlucky, then HAProxy may apply the same IP to both servers.
Current patch improves this situation by weighting the decision
algorithm to ensure we'll prefer use first an IP found in the response
which is not already affected to any server.
The new algorithm does not guarantee that the chosen IP is healthy,
neither a fair distribution of IPs amongst the servers in the farm,
etc...
It only guarantees that if the DNS server returns many records for a
hostname and that this hostname is being resolved by multiple servers in
the same backend, then we'll use as many records as possible.
If a server fails, HAProxy won't pick up an other record from the
response.
2016-12-26 22:21:08 +00:00
|
|
|
* score. The maximum score is 15, if this value is reached,
|
2016-02-17 21:05:30 +00:00
|
|
|
* we break the parsing. Implicitly, this score is reached
|
|
|
|
* the ip selected is the current ip.
|
|
|
|
*/
|
|
|
|
if (score > max_score) {
|
2017-07-06 16:46:47 +00:00
|
|
|
if (ip_type == AF_INET)
|
|
|
|
newip4 = ip;
|
2016-02-17 21:05:30 +00:00
|
|
|
else
|
2017-07-06 16:46:47 +00:00
|
|
|
newip6 = ip;
|
2016-02-17 21:05:30 +00:00
|
|
|
currentip_found = currentip_sel;
|
MINOR: dns: improve DNS response parsing to use as many available records as possible
A "weakness" exist in the first implementation of the parsing of the DNS
responses: HAProxy always choses the first IP available matching family
preference, or as a failover, the first IP.
It should be good enough, since most DNS servers do round robin on the
records they send back to clients.
That said, some servers does not do proper round robin, or we may be
unlucky too and deliver the same IP to all the servers sharing the same
hostname.
Let's take the simple configuration below:
backend bk
srv s1 www:80 check resolvers R
srv s2 www:80 check resolvers R
The DNS server configured with 2 IPs for 'www'.
If you're unlucky, then HAProxy may apply the same IP to both servers.
Current patch improves this situation by weighting the decision
algorithm to ensure we'll prefer use first an IP found in the response
which is not already affected to any server.
The new algorithm does not guarantee that the chosen IP is healthy,
neither a fair distribution of IPs amongst the servers in the farm,
etc...
It only guarantees that if the DNS server returns many records for a
hostname and that this hostname is being resolved by multiple servers in
the same backend, then we'll use as many records as possible.
If a server fails, HAProxy won't pick up an other record from the
response.
2016-12-26 22:21:08 +00:00
|
|
|
if (score == 15)
|
2016-02-17 21:05:30 +00:00
|
|
|
return DNS_UPD_NO;
|
|
|
|
max_score = score;
|
|
|
|
}
|
2017-07-06 16:46:47 +00:00
|
|
|
|
|
|
|
|
|
|
|
} /* list for each record entries */
|
2016-02-17 21:05:30 +00:00
|
|
|
|
2015-09-08 22:51:08 +00:00
|
|
|
/* no IP found in the response */
|
2017-07-06 16:46:47 +00:00
|
|
|
if (!newip4 && !newip6)
|
2015-09-08 22:51:08 +00:00
|
|
|
return DNS_UPD_NO_IP_FOUND;
|
|
|
|
|
2015-04-13 21:40:55 +00:00
|
|
|
/* case when the caller looks first for an IPv4 address */
|
|
|
|
if (family_priority == AF_INET) {
|
|
|
|
if (newip4) {
|
|
|
|
*newip = newip4;
|
|
|
|
*newip_sin_family = AF_INET;
|
|
|
|
if (currentip_found == 1)
|
|
|
|
return DNS_UPD_NO;
|
2017-05-04 06:24:11 +00:00
|
|
|
goto return_DNS_UPD_SRVIP_NOT_FOUND;
|
2015-04-13 21:40:55 +00:00
|
|
|
}
|
|
|
|
else if (newip6) {
|
|
|
|
*newip = newip6;
|
|
|
|
*newip_sin_family = AF_INET6;
|
|
|
|
if (currentip_found == 1)
|
|
|
|
return DNS_UPD_NO;
|
2017-05-04 06:24:11 +00:00
|
|
|
goto return_DNS_UPD_SRVIP_NOT_FOUND;
|
2015-04-13 21:40:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
/* case when the caller looks first for an IPv6 address */
|
|
|
|
else if (family_priority == AF_INET6) {
|
|
|
|
if (newip6) {
|
|
|
|
*newip = newip6;
|
|
|
|
*newip_sin_family = AF_INET6;
|
|
|
|
if (currentip_found == 1)
|
|
|
|
return DNS_UPD_NO;
|
2017-05-04 06:24:11 +00:00
|
|
|
goto return_DNS_UPD_SRVIP_NOT_FOUND;
|
2015-04-13 21:40:55 +00:00
|
|
|
}
|
|
|
|
else if (newip4) {
|
|
|
|
*newip = newip4;
|
|
|
|
*newip_sin_family = AF_INET;
|
|
|
|
if (currentip_found == 1)
|
|
|
|
return DNS_UPD_NO;
|
2017-05-04 06:24:11 +00:00
|
|
|
goto return_DNS_UPD_SRVIP_NOT_FOUND;
|
2015-04-13 21:40:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
/* case when the caller have no preference (we prefer IPv6) */
|
|
|
|
else if (family_priority == AF_UNSPEC) {
|
|
|
|
if (newip6) {
|
|
|
|
*newip = newip6;
|
|
|
|
*newip_sin_family = AF_INET6;
|
|
|
|
if (currentip_found == 1)
|
|
|
|
return DNS_UPD_NO;
|
2017-05-04 06:24:11 +00:00
|
|
|
goto return_DNS_UPD_SRVIP_NOT_FOUND;
|
2015-04-13 21:40:55 +00:00
|
|
|
}
|
|
|
|
else if (newip4) {
|
|
|
|
*newip = newip4;
|
|
|
|
*newip_sin_family = AF_INET;
|
|
|
|
if (currentip_found == 1)
|
|
|
|
return DNS_UPD_NO;
|
2017-05-04 06:24:11 +00:00
|
|
|
goto return_DNS_UPD_SRVIP_NOT_FOUND;
|
2015-04-13 21:40:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* no reason why we should change the server's IP address */
|
|
|
|
return DNS_UPD_NO;
|
2017-05-04 06:24:11 +00:00
|
|
|
|
|
|
|
return_DNS_UPD_SRVIP_NOT_FOUND:
|
|
|
|
list_for_each_entry(record, &dns_p->answer_list, list) {
|
|
|
|
/* move the first record to the end of the list, for internal round robin */
|
|
|
|
if (record) {
|
|
|
|
LIST_DEL(&record->list);
|
|
|
|
LIST_ADDQ(&dns_p->answer_list, &record->list);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return DNS_UPD_SRVIP_NOT_FOUND;
|
2015-04-13 21:40:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* returns the query id contained in a DNS response
|
|
|
|
*/
|
2016-01-20 22:46:34 +00:00
|
|
|
unsigned short dns_response_get_query_id(unsigned char *resp)
|
2015-04-13 21:40:55 +00:00
|
|
|
{
|
|
|
|
/* read the query id from the response */
|
|
|
|
return resp[0] * 256 + resp[1];
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* used during haproxy's init phase
|
|
|
|
* parses resolvers sections and initializes:
|
|
|
|
* - task (time events) for each resolvers section
|
|
|
|
* - the datagram layer (network IO events) for each nameserver
|
2017-02-02 21:44:15 +00:00
|
|
|
* It takes one argument:
|
|
|
|
* - close_first takes 2 values: 0 or 1. If 1, the connection is closed first.
|
2015-04-13 21:40:55 +00:00
|
|
|
* returns:
|
|
|
|
* 0 in case of error
|
|
|
|
* 1 when no error
|
|
|
|
*/
|
2017-02-02 21:44:15 +00:00
|
|
|
int dns_init_resolvers(int close_socket)
|
2015-04-13 21:40:55 +00:00
|
|
|
{
|
|
|
|
struct dns_resolvers *curr_resolvers;
|
|
|
|
struct dns_nameserver *curnameserver;
|
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.
2017-05-22 13:17:15 +00:00
|
|
|
struct dns_resolution *resolution, *res_back;
|
2015-04-13 21:40:55 +00:00
|
|
|
struct dgram_conn *dgram;
|
|
|
|
struct task *t;
|
|
|
|
int fd;
|
|
|
|
|
2017-05-04 07:05:00 +00:00
|
|
|
/* initialize our DNS resolution cache */
|
|
|
|
dns_lru_tree = lru64_new(dns_cache_size);
|
|
|
|
|
2015-04-13 21:40:55 +00:00
|
|
|
/* give a first random value to our dns query_id seed */
|
|
|
|
dns_query_id_seed = random();
|
|
|
|
|
2017-07-06 16:46:47 +00:00
|
|
|
/* Initialize the answer items pool */
|
|
|
|
dns_answer_item_pool = create_pool("dns_answer_item",
|
|
|
|
sizeof(struct dns_answer_item), MEM_F_SHARED);
|
|
|
|
if (dns_answer_item_pool == NULL) {
|
|
|
|
Alert("Failed to create the dns answer items pool");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-04-13 21:40:55 +00:00
|
|
|
/* run through the resolvers section list */
|
|
|
|
list_for_each_entry(curr_resolvers, &dns_resolvers, list) {
|
|
|
|
/* create the task associated to the resolvers section */
|
|
|
|
if ((t = task_new()) == NULL) {
|
|
|
|
Alert("Starting [%s] resolvers: out of memory.\n", curr_resolvers->id);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* update task's parameters */
|
|
|
|
t->process = dns_process_resolve;
|
|
|
|
t->context = curr_resolvers;
|
|
|
|
|
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.
2017-05-22 13:17:15 +00:00
|
|
|
/* no need to keep the new task if one is already affected to our resolvers
|
|
|
|
* section */
|
|
|
|
if (!curr_resolvers->t)
|
|
|
|
curr_resolvers->t = t;
|
|
|
|
else
|
|
|
|
task_free(t);
|
2015-04-13 21:40:55 +00:00
|
|
|
|
|
|
|
list_for_each_entry(curnameserver, &curr_resolvers->nameserver_list, list) {
|
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.
2017-05-22 13:17:15 +00:00
|
|
|
dgram = NULL;
|
2017-02-02 21:44:15 +00:00
|
|
|
|
|
|
|
if (close_socket == 1) {
|
|
|
|
if (curnameserver->dgram) {
|
2017-05-12 07:57:15 +00:00
|
|
|
fd_delete(curnameserver->dgram->t.sock.fd);
|
2017-02-02 21:44:15 +00:00
|
|
|
memset(curnameserver->dgram, '\0', sizeof(*dgram));
|
|
|
|
dgram = curnameserver->dgram;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* allocate memory only if it has not already been allocated
|
|
|
|
* by a previous call to this function */
|
2017-07-06 16:46:47 +00:00
|
|
|
|
2017-02-02 21:44:15 +00:00
|
|
|
if (!dgram && (dgram = calloc(1, sizeof(*dgram))) == NULL) {
|
2015-04-13 21:40:55 +00:00
|
|
|
Alert("Starting [%s/%s] nameserver: out of memory.\n", curr_resolvers->id,
|
|
|
|
curnameserver->id);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
/* update datagram's parameters */
|
|
|
|
dgram->owner = (void *)curnameserver;
|
|
|
|
dgram->data = &resolve_dgram_cb;
|
|
|
|
|
|
|
|
/* create network UDP socket for this nameserver */
|
2017-04-11 06:46:37 +00:00
|
|
|
if ((fd = socket(curnameserver->addr.ss_family, SOCK_DGRAM, IPPROTO_UDP)) == -1) {
|
2015-04-13 21:40:55 +00:00
|
|
|
Alert("Starting [%s/%s] nameserver: can't create socket.\n", curr_resolvers->id,
|
|
|
|
curnameserver->id);
|
|
|
|
free(dgram);
|
|
|
|
dgram = NULL;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* "connect" the UDP socket to the name server IP */
|
2015-09-21 18:55:08 +00:00
|
|
|
if (connect(fd, (struct sockaddr*)&curnameserver->addr, get_addr_len(&curnameserver->addr)) == -1) {
|
2015-04-13 21:40:55 +00:00
|
|
|
Alert("Starting [%s/%s] nameserver: can't connect socket.\n", curr_resolvers->id,
|
|
|
|
curnameserver->id);
|
|
|
|
close(fd);
|
|
|
|
free(dgram);
|
|
|
|
dgram = NULL;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* make the socket non blocking */
|
|
|
|
fcntl(fd, F_SETFL, O_NONBLOCK);
|
|
|
|
|
|
|
|
/* add the fd in the fd list and update its parameters */
|
|
|
|
fdtab[fd].owner = dgram;
|
|
|
|
fdtab[fd].iocb = dgram_fd_handler;
|
2017-09-05 07:51:57 +00:00
|
|
|
fd_insert(fd);
|
2015-04-13 21:40:55 +00:00
|
|
|
fd_want_recv(fd);
|
|
|
|
dgram->t.sock.fd = fd;
|
|
|
|
|
|
|
|
/* update nameserver's datagram property */
|
|
|
|
curnameserver->dgram = dgram;
|
|
|
|
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
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.
2017-05-22 13:17:15 +00:00
|
|
|
if (close_socket == 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* now, we can trigger DNS resolution */
|
|
|
|
list_for_each_entry_safe(resolution, res_back, &curr_resolvers->resolution.wait, list) {
|
|
|
|
/* if there is no requester in the wait queue, no need to trigger the resolution */
|
|
|
|
if (LIST_ISEMPTY(&resolution->requester.wait))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
dns_trigger_resolution(resolution);
|
|
|
|
}
|
|
|
|
|
2015-04-13 21:40:55 +00:00
|
|
|
/* task can be queued */
|
|
|
|
task_queue(t);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
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.
2017-05-22 13:17:15 +00:00
|
|
|
/*
|
|
|
|
* Allocate a pool of resolution to a resolvers section.
|
|
|
|
* Each resolution is associated with a UUID.
|
|
|
|
*
|
|
|
|
* Return code:
|
|
|
|
* - 0 if everything went smoothly
|
|
|
|
* - -1 if an error occured
|
|
|
|
*/
|
|
|
|
int dns_alloc_resolution_pool(struct dns_resolvers *resolvers)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
struct dns_resolution *resolution;
|
|
|
|
|
|
|
|
/* return if a pool has already been set for this resolvers */
|
|
|
|
if (!LIST_ISEMPTY(&resolvers->resolution.pool)) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < resolvers->resolution_pool_size; i++) {
|
|
|
|
resolution = dns_alloc_resolution();
|
|
|
|
if (!resolution) {
|
|
|
|
Alert("Starting [%s] resolvers: can't allocate memory for DNS resolution pool.\n", resolvers->id);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
resolution->uuid = i;
|
|
|
|
LIST_ADDQ(&resolvers->resolution.pool, &resolution->list);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-04-13 21:40:55 +00:00
|
|
|
/*
|
|
|
|
* Forge a DNS query. It needs the following information from the caller:
|
|
|
|
* - <query_id>: the DNS query id corresponding to this query
|
|
|
|
* - <query_type>: DNS_RTYPE_* request DNS record type (A, AAAA, ANY, etc...)
|
|
|
|
* - <hostname_dn>: hostname in domain name format
|
|
|
|
* - <hostname_dn_len>: length of <hostname_dn>
|
|
|
|
* To store the query, the caller must pass a buffer <buf> and its size <bufsize>
|
|
|
|
*
|
|
|
|
* the DNS query is stored in <buf>
|
|
|
|
* returns:
|
|
|
|
* -1 if <buf> is too short
|
|
|
|
*/
|
2017-08-13 22:13:01 +00:00
|
|
|
int dns_build_query(int query_id, int query_type, unsigned int accepted_payload_size, char *hostname_dn, int hostname_dn_len, char *buf, int bufsize)
|
2015-04-13 21:40:55 +00:00
|
|
|
{
|
|
|
|
struct dns_header *dns;
|
2016-04-08 20:17:45 +00:00
|
|
|
struct dns_question qinfo;
|
2017-08-13 22:13:01 +00:00
|
|
|
struct dns_additional_record edns;
|
2015-04-13 21:40:55 +00:00
|
|
|
char *ptr, *bufend;
|
|
|
|
|
|
|
|
memset(buf, '\0', bufsize);
|
|
|
|
ptr = buf;
|
|
|
|
bufend = buf + bufsize;
|
|
|
|
|
|
|
|
/* check if there is enough room for DNS headers */
|
|
|
|
if (ptr + sizeof(struct dns_header) >= bufend)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
/* set dns query headers */
|
|
|
|
dns = (struct dns_header *)ptr;
|
|
|
|
dns->id = (unsigned short) htons(query_id);
|
2016-07-13 12:03:43 +00:00
|
|
|
dns->flags = htons(0x0100); /* qr=0, opcode=0, aa=0, tc=0, rd=1, ra=0, z=0, rcode=0 */
|
2015-04-13 21:40:55 +00:00
|
|
|
dns->qdcount = htons(1); /* 1 question */
|
|
|
|
dns->ancount = 0;
|
|
|
|
dns->nscount = 0;
|
2017-08-13 22:13:01 +00:00
|
|
|
dns->arcount = htons(1);
|
2015-04-13 21:40:55 +00:00
|
|
|
|
|
|
|
/* move forward ptr */
|
|
|
|
ptr += sizeof(struct dns_header);
|
|
|
|
|
|
|
|
/* check if there is enough room for query hostname */
|
|
|
|
if ((ptr + hostname_dn_len) >= bufend)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
/* set up query hostname */
|
|
|
|
memcpy(ptr, hostname_dn, hostname_dn_len);
|
|
|
|
ptr[hostname_dn_len + 1] = '\0';
|
|
|
|
|
|
|
|
/* move forward ptr */
|
|
|
|
ptr += (hostname_dn_len + 1);
|
|
|
|
|
|
|
|
/* check if there is enough room for query hostname*/
|
|
|
|
if (ptr + sizeof(struct dns_question) >= bufend)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
/* set up query info (type and class) */
|
2016-04-08 20:17:45 +00:00
|
|
|
qinfo.qtype = htons(query_type);
|
|
|
|
qinfo.qclass = htons(DNS_RCLASS_IN);
|
|
|
|
memcpy(ptr, &qinfo, sizeof(qinfo));
|
2015-04-13 21:40:55 +00:00
|
|
|
|
|
|
|
ptr += sizeof(struct dns_question);
|
|
|
|
|
2017-08-13 22:13:01 +00:00
|
|
|
/* check if there is enough room for additional records */
|
|
|
|
if (ptr + sizeof(edns) >= bufend)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
/* set the DNS extension */
|
|
|
|
edns.name = 0;
|
|
|
|
edns.type = htons(DNS_RTYPE_OPT);
|
|
|
|
edns.udp_payload_size = htons(accepted_payload_size);
|
|
|
|
edns.extension = 0;
|
|
|
|
edns.data_length = 0;
|
|
|
|
memcpy(ptr, &edns, sizeof(edns));
|
|
|
|
ptr += sizeof(edns);
|
|
|
|
|
2015-04-13 21:40:55 +00:00
|
|
|
return ptr - buf;
|
|
|
|
}
|
|
|
|
|
2017-08-04 16:35:36 +00:00
|
|
|
/* Turn a domain name label into a string */
|
|
|
|
void dns_dn_label_to_str(char *dn, char *str, int dn_len)
|
|
|
|
{
|
|
|
|
int remain_size = 0;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < dn_len; i++) {
|
|
|
|
if (remain_size == 0) {
|
|
|
|
remain_size = dn[i];
|
|
|
|
if (i != 0) {
|
|
|
|
str[i - 1] = '.';
|
|
|
|
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
str[i - 1] = dn[i];
|
|
|
|
remain_size--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
str[dn_len - 1] = 0;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2015-04-13 21:40:55 +00:00
|
|
|
/*
|
|
|
|
* turn a string into domain name label:
|
|
|
|
* www.haproxy.org into 3www7haproxy3org
|
|
|
|
* if dn memory is pre-allocated, you must provide its size in dn_len
|
|
|
|
* if dn memory isn't allocated, dn_len must be set to 0.
|
|
|
|
* In the second case, memory will be allocated.
|
|
|
|
* in case of error, -1 is returned, otherwise, number of bytes copied in dn
|
|
|
|
*/
|
2015-07-22 14:42:43 +00:00
|
|
|
char *dns_str_to_dn_label(const char *string, char *dn, int dn_len)
|
2015-04-13 21:40:55 +00:00
|
|
|
{
|
|
|
|
char *c, *d;
|
|
|
|
int i, offset;
|
|
|
|
|
|
|
|
/* offset between string size and theorical dn size */
|
|
|
|
offset = 1;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* first, get the size of the string turned into its domain name version
|
|
|
|
* This function also validates the string respect the RFC
|
|
|
|
*/
|
|
|
|
if ((i = dns_str_to_dn_label_len(string)) == -1)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
/* yes, so let's check there is enough memory */
|
|
|
|
if (dn_len < i + offset)
|
|
|
|
return NULL;
|
|
|
|
|
2015-07-22 14:45:36 +00:00
|
|
|
i = strlen(string);
|
2015-04-13 21:40:55 +00:00
|
|
|
memcpy(dn + offset, string, i);
|
|
|
|
dn[i + offset] = '\0';
|
|
|
|
/* avoid a '\0' at the beginning of dn string which may prevent the for loop
|
|
|
|
* below from working.
|
|
|
|
* Actually, this is the reason of the offset. */
|
|
|
|
dn[0] = '0';
|
|
|
|
|
|
|
|
for (c = dn; *c ; ++c) {
|
|
|
|
/* c points to the first '0' char or a dot, which we don't want to read */
|
|
|
|
d = c + offset;
|
|
|
|
i = 0;
|
|
|
|
while (*d != '.' && *d) {
|
|
|
|
i++;
|
|
|
|
d++;
|
|
|
|
}
|
|
|
|
*c = i;
|
|
|
|
|
|
|
|
c = d - 1; /* because of c++ of the for loop */
|
|
|
|
}
|
|
|
|
|
|
|
|
return dn;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* compute and return the length of <string> it it were translated into domain name
|
|
|
|
* label:
|
|
|
|
* www.haproxy.org into 3www7haproxy3org would return 16
|
|
|
|
* NOTE: add +1 for '\0' when allocating memory ;)
|
|
|
|
*/
|
|
|
|
int dns_str_to_dn_label_len(const char *string)
|
|
|
|
{
|
|
|
|
return strlen(string) + 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* validates host name:
|
|
|
|
* - total size
|
|
|
|
* - each label size individually
|
|
|
|
* returns:
|
|
|
|
* 0 in case of error. If <err> is not NULL, an error message is stored there.
|
|
|
|
* 1 when no error. <err> is left unaffected.
|
|
|
|
*/
|
|
|
|
int dns_hostname_validation(const char *string, char **err)
|
|
|
|
{
|
|
|
|
const char *c, *d;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (strlen(string) > DNS_MAX_NAME_SIZE) {
|
|
|
|
if (err)
|
|
|
|
*err = DNS_TOO_LONG_FQDN;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
c = string;
|
|
|
|
while (*c) {
|
|
|
|
d = c;
|
|
|
|
|
|
|
|
i = 0;
|
|
|
|
while (*d != '.' && *d && i <= DNS_MAX_LABEL_SIZE) {
|
|
|
|
i++;
|
|
|
|
if (!((*d == '-') || (*d == '_') ||
|
|
|
|
((*d >= 'a') && (*d <= 'z')) ||
|
|
|
|
((*d >= 'A') && (*d <= 'Z')) ||
|
|
|
|
((*d >= '0') && (*d <= '9')))) {
|
|
|
|
if (err)
|
|
|
|
*err = DNS_INVALID_CHARACTER;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
d++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((i >= DNS_MAX_LABEL_SIZE) && (d[i] != '.')) {
|
|
|
|
if (err)
|
|
|
|
*err = DNS_LABEL_TOO_LONG;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (*d == '\0')
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
c = ++d;
|
|
|
|
}
|
|
|
|
out:
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 2 bytes random generator to generate DNS query ID
|
|
|
|
*/
|
|
|
|
uint16_t dns_rnd16(void)
|
|
|
|
{
|
|
|
|
dns_query_id_seed ^= dns_query_id_seed << 13;
|
|
|
|
dns_query_id_seed ^= dns_query_id_seed >> 7;
|
|
|
|
dns_query_id_seed ^= dns_query_id_seed << 17;
|
|
|
|
return dns_query_id_seed;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* function called when a timeout occurs during name resolution process
|
|
|
|
* if max number of tries is reached, then stop, otherwise, retry.
|
|
|
|
*/
|
|
|
|
struct task *dns_process_resolve(struct task *t)
|
|
|
|
{
|
|
|
|
struct dns_resolvers *resolvers = t->context;
|
|
|
|
struct dns_resolution *resolution, *res_back;
|
2016-01-06 01:01:59 +00:00
|
|
|
int res_preferred_afinet, res_preferred_afinet6;
|
2017-05-03 10:12:02 +00:00
|
|
|
struct dns_options *dns_opts = NULL;
|
2015-04-13 21:40:55 +00:00
|
|
|
|
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.
2017-05-22 13:17:15 +00:00
|
|
|
/* if both there is no resolution in the run queue, we can re-schedule a wake up */
|
|
|
|
if (LIST_ISEMPTY(&resolvers->resolution.curr)) {
|
2015-04-13 21:40:55 +00:00
|
|
|
/* no first entry, so wake up was useless */
|
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.
2017-05-22 13:17:15 +00:00
|
|
|
dns_update_resolvers_timeout(resolvers);
|
2015-04-13 21:40:55 +00:00
|
|
|
return t;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* look for the first resolution which is not expired */
|
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.
2017-05-22 13:17:15 +00:00
|
|
|
list_for_each_entry_safe(resolution, res_back, &resolvers->resolution.curr, list) {
|
|
|
|
struct dns_requester *requester = NULL;
|
|
|
|
|
2015-04-13 21:40:55 +00:00
|
|
|
/* when we find the first resolution in the future, then we can stop here */
|
|
|
|
if (tick_is_le(now_ms, resolution->last_sent_packet))
|
|
|
|
goto out;
|
|
|
|
|
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.
2017-05-22 13:17:15 +00:00
|
|
|
if (LIST_ISEMPTY(&resolution->requester.curr))
|
|
|
|
goto out;
|
|
|
|
|
2015-04-13 21:40:55 +00:00
|
|
|
/*
|
|
|
|
* if current resolution has been tried too many times and finishes in timeout
|
|
|
|
* we update its status and remove it from the list
|
|
|
|
*/
|
2015-09-08 22:54:38 +00:00
|
|
|
if (resolution->try <= 0) {
|
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.
2017-05-22 13:17:15 +00:00
|
|
|
struct dns_requester *tmprequester;
|
2015-04-13 21:40:55 +00:00
|
|
|
/* clean up resolution information and remove from the list */
|
|
|
|
dns_reset_resolution(resolution);
|
|
|
|
|
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.
2017-05-22 13:17:15 +00:00
|
|
|
LIST_DEL(&resolution->list);
|
|
|
|
LIST_ADDQ(&resolvers->resolution.wait, &resolution->list);
|
|
|
|
|
|
|
|
if (resolution->status != RSLV_STATUS_TIMEOUT) {
|
|
|
|
resolution->status = RSLV_STATUS_TIMEOUT;
|
|
|
|
resolution->last_status_change = now_ms;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* notify the result to the requesters */
|
|
|
|
list_for_each_entry_safe(requester, tmprequester, &resolution->requester.curr, list) {
|
|
|
|
requester->requester_error_cb(requester, DNS_RESP_TIMEOUT);
|
|
|
|
LIST_DEL(&requester->list);
|
|
|
|
LIST_ADDQ(&resolution->requester.wait, &requester->list);
|
|
|
|
}
|
2017-08-21 14:51:09 +00:00
|
|
|
|
|
|
|
/* this might be triggered by too big UDP packets dropped
|
|
|
|
* somewhere on the network, so lowering the accepted_payload_size
|
|
|
|
* announced */
|
|
|
|
if (resolvers->accepted_payload_size > 1280)
|
|
|
|
resolvers->accepted_payload_size = 1280;
|
2016-01-06 00:53:46 +00:00
|
|
|
goto out;
|
2015-04-13 21:40:55 +00:00
|
|
|
}
|
|
|
|
|
2015-09-08 22:54:38 +00:00
|
|
|
resolution->try -= 1;
|
|
|
|
|
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.
2017-05-22 13:17:15 +00:00
|
|
|
/* running queue is empty, nothing to do but wait */
|
|
|
|
if (LIST_ISEMPTY(&resolution->requester.curr))
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
requester = LIST_NEXT(&resolution->requester.curr, struct dns_requester *, list);
|
|
|
|
|
|
|
|
switch (obj_type(requester->requester)) {
|
|
|
|
case OBJ_TYPE_SERVER:
|
|
|
|
dns_opts = &(objt_server(requester->requester)->dns_opts);
|
2017-08-04 16:35:36 +00:00
|
|
|
res_preferred_afinet = dns_opts->family_prio == AF_INET && resolution->query_type == DNS_RTYPE_A;
|
|
|
|
res_preferred_afinet6 = dns_opts->family_prio == AF_INET6 && resolution->query_type == DNS_RTYPE_AAAA;
|
|
|
|
|
|
|
|
/* let's change the query type if needed */
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
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.
2017-05-22 13:17:15 +00:00
|
|
|
break;
|
|
|
|
|
2017-08-04 16:35:36 +00:00
|
|
|
case OBJ_TYPE_SRVRQ:
|
|
|
|
break;
|
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.
2017-05-22 13:17:15 +00:00
|
|
|
case OBJ_TYPE_NONE:
|
|
|
|
default:
|
|
|
|
/* clean up resolution information and remove from the list */
|
|
|
|
dns_reset_resolution(resolution);
|
|
|
|
|
|
|
|
LIST_DEL(&resolution->list);
|
|
|
|
LIST_ADDQ(&resolvers->resolution.wait, &resolution->list);
|
|
|
|
|
|
|
|
/* notify the result to the requester */
|
|
|
|
requester->requester_error_cb(requester, DNS_RESP_INTERNAL);
|
|
|
|
goto out;
|
|
|
|
}
|
2017-05-03 10:12:02 +00:00
|
|
|
|
2016-01-06 00:53:46 +00:00
|
|
|
/* resend the DNS query */
|
|
|
|
dns_send_query(resolution);
|
2015-04-13 21:40:55 +00:00
|
|
|
|
2016-01-06 00:53:46 +00:00
|
|
|
/* check if we have more than one resolution in the list */
|
|
|
|
if (dns_check_resolution_queue(resolvers) > 1) {
|
|
|
|
/* move the rsolution to the end of the list */
|
|
|
|
LIST_DEL(&resolution->list);
|
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.
2017-05-22 13:17:15 +00:00
|
|
|
LIST_ADDQ(&resolvers->resolution.curr, &resolution->list);
|
2015-04-13 21:40:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
out:
|
|
|
|
dns_update_resolvers_timeout(resolvers);
|
|
|
|
return t;
|
|
|
|
}
|
2016-11-18 23:58:54 +00:00
|
|
|
|
2017-05-04 07:05:00 +00:00
|
|
|
/*
|
|
|
|
* build a dns cache key composed as follow:
|
|
|
|
* <query type>#<hostname in domain name format>
|
|
|
|
* and store it into <str>.
|
|
|
|
* It's up to the caller to allocate <buf> and to reset it.
|
|
|
|
* The function returns NULL in case of error (IE <buf> too small) or a pointer
|
|
|
|
* to buf if successful
|
|
|
|
*/
|
|
|
|
struct chunk *
|
|
|
|
dns_cache_key(int query_type, char *hostname_dn, int hostname_dn_len, struct chunk *buf)
|
|
|
|
{
|
|
|
|
int len, size;
|
|
|
|
char *str;
|
|
|
|
|
|
|
|
str = buf->str;
|
|
|
|
len = buf->len;
|
|
|
|
size = buf->size;
|
|
|
|
|
|
|
|
switch (query_type) {
|
|
|
|
case DNS_RTYPE_A:
|
|
|
|
if (len + 1 > size)
|
|
|
|
return NULL;
|
|
|
|
memcpy(&str[len], "A", 1);
|
|
|
|
len += 1;
|
|
|
|
break;
|
|
|
|
case DNS_RTYPE_AAAA:
|
|
|
|
if (len + 4 > size)
|
|
|
|
return NULL;
|
|
|
|
memcpy(&str[len], "AAAA", 4);
|
|
|
|
len += 4;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (len + 1 > size)
|
|
|
|
return NULL;
|
|
|
|
memcpy(&str[len], "#", 1);
|
|
|
|
len += 1;
|
|
|
|
|
|
|
|
if (len + hostname_dn_len + 1 > size) // +1 for trailing zero
|
|
|
|
return NULL;
|
|
|
|
memcpy(&str[len], hostname_dn, hostname_dn_len);
|
|
|
|
len += hostname_dn_len;
|
|
|
|
str[len] = '\0';
|
|
|
|
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* returns a pointer to a cache entry which may still be considered as up to date
|
|
|
|
* by the caller.
|
|
|
|
* returns NULL if no entry can be found or if the data found is outdated.
|
|
|
|
*/
|
|
|
|
struct lru64 *
|
|
|
|
dns_cache_lookup(int query_type, char *hostname_dn, int hostname_dn_len, int valid_period, void *cache_domain) {
|
|
|
|
struct lru64 *elem = NULL;
|
|
|
|
struct dns_resolution *resolution = NULL;
|
|
|
|
struct dns_resolvers *resolvers = NULL;
|
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.
2017-05-22 13:17:15 +00:00
|
|
|
struct dns_requester *requester = NULL;
|
2017-05-04 07:05:00 +00:00
|
|
|
int inter = 0;
|
|
|
|
struct chunk *buf = get_trash_chunk();
|
|
|
|
struct chunk *tmp = NULL;
|
|
|
|
|
|
|
|
if (!dns_lru_tree)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
chunk_reset(buf);
|
|
|
|
tmp = dns_cache_key(query_type, hostname_dn, hostname_dn_len, buf);
|
|
|
|
if (tmp == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
elem = lru64_lookup(XXH64(buf->str, buf->len, 1), dns_lru_tree, cache_domain, 1);
|
|
|
|
|
|
|
|
if (!elem || !elem->data)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
resolution = elem->data;
|
|
|
|
|
|
|
|
/* since we can change the fqdn of a server at run time, it may happen that
|
|
|
|
* we got an innacurate elem.
|
|
|
|
* This is because resolution->hostname_dn points to (owner)->hostname_dn (which
|
|
|
|
* may be changed at run time)
|
|
|
|
*/
|
|
|
|
if ((hostname_dn_len == resolution->hostname_dn_len) &&
|
|
|
|
(memcmp(hostname_dn, resolution->hostname_dn, hostname_dn_len) != 0)) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
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.
2017-05-22 13:17:15 +00:00
|
|
|
requester = LIST_NEXT(&resolution->requester.wait, struct dns_requester *, list);
|
|
|
|
|
|
|
|
switch (obj_type(requester->requester)) {
|
|
|
|
case OBJ_TYPE_SERVER:
|
|
|
|
resolvers = objt_server(requester->requester)->resolvers;
|
|
|
|
break;
|
2017-08-04 16:35:36 +00:00
|
|
|
case OBJ_TYPE_SRVRQ:
|
|
|
|
resolvers = objt_dns_srvrq(requester->requester)->resolvers;
|
|
|
|
break;
|
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.
2017-05-22 13:17:15 +00:00
|
|
|
case OBJ_TYPE_NONE:
|
|
|
|
default:
|
|
|
|
return NULL;
|
|
|
|
}
|
2017-05-04 07:05:00 +00:00
|
|
|
|
|
|
|
if (!resolvers)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if (resolvers->hold.valid < valid_period)
|
|
|
|
inter = resolvers->hold.valid;
|
|
|
|
else
|
|
|
|
inter = valid_period;
|
|
|
|
|
|
|
|
if (!tick_is_expired(tick_add(resolution->last_resolution, inter), now_ms))
|
|
|
|
return elem;
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2016-12-16 17:06:26 +00:00
|
|
|
/* if an arg is found, it sets the resolvers section pointer into cli.p0 */
|
2016-11-18 23:58:54 +00:00
|
|
|
static int cli_parse_stat_resolvers(char **args, struct appctx *appctx, void *private)
|
|
|
|
{
|
|
|
|
struct dns_resolvers *presolvers;
|
|
|
|
|
|
|
|
if (*args[3]) {
|
|
|
|
list_for_each_entry(presolvers, &dns_resolvers, list) {
|
|
|
|
if (strcmp(presolvers->id, args[3]) == 0) {
|
2016-12-16 17:06:26 +00:00
|
|
|
appctx->ctx.cli.p0 = presolvers;
|
2016-11-18 23:58:54 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2016-12-16 17:06:26 +00:00
|
|
|
if (appctx->ctx.cli.p0 == NULL) {
|
2017-07-20 14:49:14 +00:00
|
|
|
appctx->ctx.cli.severity = LOG_ERR;
|
2016-11-18 23:58:54 +00:00
|
|
|
appctx->ctx.cli.msg = "Can't find that resolvers section\n";
|
2016-11-24 14:53:53 +00:00
|
|
|
appctx->st0 = CLI_ST_PRINT;
|
2016-11-18 23:58:54 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
2016-12-05 13:50:15 +00:00
|
|
|
return 0;
|
2016-11-18 23:58:54 +00:00
|
|
|
}
|
|
|
|
|
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.
2017-05-22 13:17:15 +00:00
|
|
|
/*
|
|
|
|
* if <resolution> is provided, then the function skips the memory allocation part.
|
|
|
|
* It does the linking only.
|
|
|
|
*
|
|
|
|
* if <resolution> is NULL, the function links a dns resolution to a requester:
|
|
|
|
* - it allocates memory for the struct requester used to link
|
|
|
|
* the resolution to the requester
|
|
|
|
* - it configures the resolution if this is the first requester to be linked to it
|
|
|
|
* - it updates the requester with a pointer to the resolution
|
|
|
|
*
|
|
|
|
* Return code:
|
|
|
|
* - 0 if everything happened smoothly
|
|
|
|
* - -1 if an error occured. Of course, no resolution is linked to the requester
|
|
|
|
*/
|
|
|
|
int dns_link_resolution(void *requester, int requester_type, struct dns_resolution *resolution)
|
|
|
|
{
|
|
|
|
struct dns_resolution *tmpresolution = NULL;
|
|
|
|
struct dns_requester *tmprequester = NULL;
|
|
|
|
struct dns_resolvers *resolvers = NULL;
|
|
|
|
char *hostname_dn = NULL;
|
|
|
|
int new_resolution;
|
|
|
|
|
2017-08-04 16:35:36 +00:00
|
|
|
|
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.
2017-05-22 13:17:15 +00:00
|
|
|
if (!resolution) {
|
|
|
|
tmprequester = calloc(1, sizeof(*tmprequester));
|
|
|
|
if (!tmprequester)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
switch (requester_type) {
|
|
|
|
case OBJ_TYPE_SERVER:
|
|
|
|
tmprequester->requester = &((struct server *)requester)->obj_type;
|
|
|
|
hostname_dn = objt_server(tmprequester->requester)->hostname_dn;
|
|
|
|
resolvers = objt_server(tmprequester->requester)->resolvers;
|
|
|
|
switch (objt_server(tmprequester->requester)->dns_opts.family_prio) {
|
|
|
|
case AF_INET:
|
|
|
|
tmprequester->prefered_query_type = DNS_RTYPE_A;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
tmprequester->prefered_query_type = DNS_RTYPE_AAAA;
|
|
|
|
}
|
|
|
|
|
2017-08-04 16:35:36 +00:00
|
|
|
break;
|
|
|
|
case OBJ_TYPE_SRVRQ:
|
|
|
|
tmprequester->requester = &((struct dns_srvrq *)requester)->obj_type;
|
|
|
|
hostname_dn = objt_dns_srvrq(requester)->hostname_dn;
|
|
|
|
resolvers = objt_dns_srvrq(requester)->resolvers;
|
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.
2017-05-22 13:17:15 +00:00
|
|
|
break;
|
|
|
|
case OBJ_TYPE_NONE:
|
|
|
|
default:
|
|
|
|
free(tmprequester);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* get a resolution from the resolvers' wait queue or pool */
|
|
|
|
tmpresolution = dns_resolution_list_get(resolvers, hostname_dn, tmprequester->prefered_query_type);
|
|
|
|
if (!tmpresolution) {
|
|
|
|
free(tmprequester);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
tmpresolution = resolution;
|
|
|
|
|
|
|
|
switch (requester_type) {
|
|
|
|
case OBJ_TYPE_SERVER:
|
|
|
|
tmprequester = ((struct server *)requester)->dns_requester;
|
|
|
|
resolvers = ((struct server *)requester)->resolvers;
|
|
|
|
break;
|
2017-08-04 16:35:36 +00:00
|
|
|
case OBJ_TYPE_SRVRQ:
|
|
|
|
tmprequester = objt_dns_srvrq(requester)->dns_requester;
|
|
|
|
resolvers = objt_dns_srvrq(requester)->resolvers;
|
|
|
|
break;
|
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.
2017-05-22 13:17:15 +00:00
|
|
|
case OBJ_TYPE_NONE:
|
|
|
|
default:
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* flag this resolution as NEW if applicable (not already linked to any requester).
|
|
|
|
* this is required to decide which parameters we have to update on the resolution.
|
|
|
|
* If new, it means we pulled up the resolution from the resolvers' pool.
|
|
|
|
*/
|
|
|
|
if (LIST_ISEMPTY(&tmpresolution->requester.wait)) {
|
|
|
|
new_resolution = 1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
new_resolution = 0;
|
|
|
|
|
|
|
|
/* those parameters are related to the requester type */
|
|
|
|
switch (obj_type(tmprequester->requester)) {
|
|
|
|
case OBJ_TYPE_SERVER:
|
|
|
|
/* some parameters should be set only if the resolution is brand new */
|
|
|
|
if (new_resolution) {
|
|
|
|
tmpresolution->query_type = tmprequester->prefered_query_type;
|
|
|
|
tmpresolution->hostname_dn = objt_server(tmprequester->requester)->hostname_dn;
|
|
|
|
tmpresolution->hostname_dn_len = objt_server(tmprequester->requester)->hostname_dn_len;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* update requester as well, only if we just allocated it */
|
|
|
|
objt_server(tmprequester->requester)->resolution = tmpresolution;
|
|
|
|
if (!resolution) {
|
|
|
|
tmprequester->requester_cb = snr_resolution_cb;
|
|
|
|
tmprequester->requester_error_cb = snr_resolution_error_cb;
|
|
|
|
objt_server(tmprequester->requester)->dns_requester = tmprequester;
|
|
|
|
}
|
|
|
|
break;
|
2017-08-04 16:35:36 +00:00
|
|
|
case OBJ_TYPE_SRVRQ:
|
|
|
|
/* some parameters should be set only if the resolution is brand new */
|
|
|
|
if (new_resolution) {
|
|
|
|
tmpresolution->query_type = DNS_RTYPE_SRV;
|
|
|
|
tmpresolution->hostname_dn = objt_dns_srvrq(tmprequester->requester)->hostname_dn;
|
|
|
|
tmpresolution->hostname_dn_len = objt_dns_srvrq(tmprequester->requester)->hostname_dn_len;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* update requester as well, only if we just allocated it */
|
|
|
|
objt_dns_srvrq(tmprequester->requester)->resolution = tmpresolution;
|
|
|
|
if (!resolution) {
|
|
|
|
tmprequester->requester_cb = snr_resolution_cb;
|
|
|
|
tmprequester->requester_error_cb = snr_resolution_error_cb;
|
|
|
|
objt_dns_srvrq(tmprequester->requester)->dns_requester = tmprequester;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
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.
2017-05-22 13:17:15 +00:00
|
|
|
case OBJ_TYPE_NONE:
|
|
|
|
default:
|
|
|
|
free(tmprequester);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* update some parameters only if this is a brand new resolution */
|
|
|
|
if (new_resolution) {
|
|
|
|
/* move the resolution to the requesters' wait queue */
|
|
|
|
LIST_DEL(&tmpresolution->list);
|
|
|
|
LIST_ADDQ(&resolvers->resolution.wait, &tmpresolution->list);
|
|
|
|
|
|
|
|
tmpresolution->status = RSLV_STATUS_NONE;
|
|
|
|
tmpresolution->step = RSLV_STEP_NONE;
|
|
|
|
tmpresolution->revision = 1;
|
2017-07-06 16:46:47 +00:00
|
|
|
LIST_INIT(&tmpresolution->response.answer_list);
|
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.
2017-05-22 13:17:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* add the requester to the resolution's wait queue */
|
|
|
|
if (resolution)
|
|
|
|
LIST_DEL(&tmprequester->list);
|
|
|
|
LIST_ADDQ(&tmpresolution->requester.wait, &tmprequester->list);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* pick up an available resolution from the different resolution list associated to a resolvers section,
|
|
|
|
* in this order:
|
|
|
|
* 1. check in resolution.curr for the same hostname and query_type
|
|
|
|
* 2. check in resolution.wait for the same hostname and query_type
|
|
|
|
* 3. take an available resolution from resolution.pool
|
|
|
|
*
|
|
|
|
* return an available resolution, NULL if none found.
|
|
|
|
*/
|
|
|
|
struct dns_resolution *dns_resolution_list_get(struct dns_resolvers *resolvers, char *hostname_dn, int query_type)
|
|
|
|
{
|
|
|
|
struct dns_resolution *resolution, *tmpresolution;
|
|
|
|
struct dns_requester *requester;
|
|
|
|
|
2017-08-04 16:35:36 +00:00
|
|
|
if (hostname_dn) {
|
|
|
|
/* search for same hostname and query type in resolution.curr */
|
|
|
|
list_for_each_entry_safe(resolution, tmpresolution, &resolvers->resolution.curr, list) {
|
|
|
|
requester = NULL;
|
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.
2017-05-22 13:17:15 +00:00
|
|
|
|
2017-08-04 16:35:36 +00:00
|
|
|
if (!LIST_ISEMPTY(&resolution->requester.wait))
|
|
|
|
requester = LIST_NEXT(&resolution->requester.wait, struct dns_requester *, list);
|
|
|
|
else if (!LIST_ISEMPTY(&resolution->requester.curr))
|
|
|
|
requester = LIST_NEXT(&resolution->requester.curr, struct dns_requester *, list);
|
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.
2017-05-22 13:17:15 +00:00
|
|
|
|
2017-08-04 16:35:36 +00:00
|
|
|
if (!requester)
|
|
|
|
continue;
|
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.
2017-05-22 13:17:15 +00:00
|
|
|
|
2017-08-04 16:35:36 +00:00
|
|
|
if ((query_type == requester->prefered_query_type) &&
|
|
|
|
(resolution->hostname_dn &&
|
|
|
|
strcmp(hostname_dn, resolution->hostname_dn) == 0)) {
|
|
|
|
return resolution;
|
|
|
|
}
|
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.
2017-05-22 13:17:15 +00:00
|
|
|
}
|
|
|
|
|
2017-08-04 16:35:36 +00:00
|
|
|
/* search for same hostname and query type in resolution.wait */
|
|
|
|
list_for_each_entry_safe(resolution, tmpresolution, &resolvers->resolution.wait, list) {
|
|
|
|
requester = NULL;
|
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.
2017-05-22 13:17:15 +00:00
|
|
|
|
2017-08-04 16:35:36 +00:00
|
|
|
if (!LIST_ISEMPTY(&resolution->requester.wait))
|
|
|
|
requester = LIST_NEXT(&resolution->requester.wait, struct dns_requester *, list);
|
|
|
|
else if (!LIST_ISEMPTY(&resolution->requester.curr))
|
|
|
|
requester = LIST_NEXT(&resolution->requester.curr, struct dns_requester *, list);
|
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.
2017-05-22 13:17:15 +00:00
|
|
|
|
2017-08-04 16:35:36 +00:00
|
|
|
if (!requester)
|
|
|
|
continue;
|
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.
2017-05-22 13:17:15 +00:00
|
|
|
|
2017-08-04 16:35:36 +00:00
|
|
|
if ((query_type == requester->prefered_query_type) &&
|
|
|
|
(resolution->hostname_dn &&
|
|
|
|
strcmp(hostname_dn, resolution->hostname_dn) == 0)) {
|
|
|
|
return resolution;
|
|
|
|
}
|
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.
2017-05-22 13:17:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
/* take the first one (hopefully) from the pool */
|
|
|
|
list_for_each_entry_safe(resolution, tmpresolution, &resolvers->resolution.pool, list) {
|
|
|
|
if (LIST_ISEMPTY(&resolution->requester.wait)) {
|
|
|
|
return resolution;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2017-05-03 08:11:44 +00:00
|
|
|
/* This function allocates memory for a DNS resolution structure.
|
|
|
|
* It's up to the caller to set the parameters
|
|
|
|
* Returns a pointer to the structure resolution or NULL if memory could
|
|
|
|
* not be allocated.
|
|
|
|
*/
|
|
|
|
struct dns_resolution *dns_alloc_resolution(void)
|
|
|
|
{
|
|
|
|
struct dns_resolution *resolution = NULL;
|
2017-05-22 13:13:10 +00:00
|
|
|
char *buffer = NULL;
|
2017-05-03 08:11:44 +00:00
|
|
|
|
|
|
|
resolution = calloc(1, sizeof(*resolution));
|
2017-05-22 13:13:10 +00:00
|
|
|
buffer = calloc(1, global.tune.bufsize);
|
2017-05-03 08:11:44 +00:00
|
|
|
|
2017-05-22 13:13:10 +00:00
|
|
|
if (!resolution || !buffer) {
|
|
|
|
free(buffer);
|
2017-05-03 08:11:44 +00:00
|
|
|
free(resolution);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
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.
2017-05-22 13:17:15 +00:00
|
|
|
LIST_INIT(&resolution->requester.wait);
|
|
|
|
LIST_INIT(&resolution->requester.curr);
|
2017-05-22 13:13:10 +00:00
|
|
|
|
2017-05-03 08:11:44 +00:00
|
|
|
return resolution;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* This function free the memory allocated to a DNS resolution */
|
|
|
|
void dns_free_resolution(struct dns_resolution *resolution)
|
|
|
|
{
|
|
|
|
free(resolution);
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
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.
2017-05-22 13:17:15 +00:00
|
|
|
/* this function free a resolution from its requester(s) and move it back to the pool */
|
|
|
|
void dns_resolution_free(struct dns_resolvers *resolvers, struct dns_resolution *resolution)
|
|
|
|
{
|
|
|
|
struct dns_requester *requester, *tmprequester;
|
|
|
|
|
|
|
|
/* clean up configuration */
|
|
|
|
dns_reset_resolution(resolution);
|
|
|
|
resolution->hostname_dn = NULL;
|
|
|
|
resolution->hostname_dn_len = 0;
|
|
|
|
|
|
|
|
list_for_each_entry_safe(requester, tmprequester, &resolution->requester.wait, list) {
|
|
|
|
LIST_DEL(&requester->list);
|
|
|
|
}
|
|
|
|
list_for_each_entry_safe(requester, tmprequester, &resolution->requester.curr, list) {
|
|
|
|
LIST_DEL(&requester->list);
|
|
|
|
}
|
|
|
|
|
|
|
|
LIST_DEL(&resolution->list);
|
|
|
|
LIST_ADDQ(&resolvers->resolution.pool, &resolution->list);
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* this function remove a requester from a resolution
|
|
|
|
* and takes care of all the consequences.
|
|
|
|
* It also cleans up some parameters from the requester
|
|
|
|
*/
|
|
|
|
void dns_rm_requester_from_resolution(struct dns_requester *requester, struct dns_resolution *resolution)
|
|
|
|
{
|
|
|
|
char *hostname_dn;
|
|
|
|
struct dns_requester *tmprequester;
|
|
|
|
|
|
|
|
/* resolution is still used by other requesters, we need to move
|
|
|
|
* some pointers to an other requester if needed
|
|
|
|
*/
|
|
|
|
switch (obj_type(requester->requester)) {
|
|
|
|
case OBJ_TYPE_SERVER:
|
|
|
|
hostname_dn = objt_server(requester->requester)->hostname_dn;
|
|
|
|
break;
|
2017-08-04 16:35:36 +00:00
|
|
|
case OBJ_TYPE_SRVRQ:
|
|
|
|
hostname_dn = objt_dns_srvrq(requester->requester)->hostname_dn;
|
|
|
|
break;
|
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.
2017-05-22 13:17:15 +00:00
|
|
|
case OBJ_TYPE_NONE:
|
|
|
|
default:
|
|
|
|
hostname_dn = NULL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (resolution->hostname_dn != hostname_dn)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* First, we need to find this other requester */
|
|
|
|
tmprequester = NULL;
|
|
|
|
list_for_each_entry(tmprequester, &resolution->requester.wait, list) {
|
|
|
|
if (tmprequester != requester)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (!tmprequester) {
|
|
|
|
/* if we can't find it in wait queue, let's get one in run queue */
|
|
|
|
list_for_each_entry(tmprequester, &resolution->requester.curr, list) {
|
|
|
|
if (tmprequester != requester)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* move hostname_dn related pointers to the next requester */
|
|
|
|
switch (obj_type(tmprequester->requester)) {
|
|
|
|
case OBJ_TYPE_SERVER:
|
|
|
|
resolution->hostname_dn = objt_server(tmprequester->requester)->hostname_dn;
|
|
|
|
resolution->hostname_dn_len = objt_server(tmprequester->requester)->hostname_dn_len;
|
|
|
|
break;
|
2017-08-04 16:35:36 +00:00
|
|
|
case OBJ_TYPE_SRVRQ:
|
|
|
|
resolution->hostname_dn = objt_dns_srvrq(tmprequester->requester)->hostname_dn;
|
|
|
|
resolution->hostname_dn_len = objt_dns_srvrq(tmprequester->requester)->hostname_dn_len;
|
|
|
|
break;
|
|
|
|
|
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.
2017-05-22 13:17:15 +00:00
|
|
|
case OBJ_TYPE_NONE:
|
|
|
|
default:
|
|
|
|
;;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* clean up the requester */
|
|
|
|
LIST_DEL(&requester->list);
|
|
|
|
switch (obj_type(requester->requester)) {
|
|
|
|
case OBJ_TYPE_SERVER:
|
|
|
|
objt_server(requester->requester)->resolution = NULL;
|
|
|
|
break;
|
2017-08-04 16:35:36 +00:00
|
|
|
case OBJ_TYPE_SRVRQ:
|
|
|
|
objt_dns_srvrq(requester->requester)->resolution = NULL;
|
|
|
|
break;
|
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.
2017-05-22 13:17:15 +00:00
|
|
|
case OBJ_TYPE_NONE:
|
|
|
|
default:
|
|
|
|
;;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-16 17:06:26 +00:00
|
|
|
/* This function dumps counters from all resolvers section and associated name
|
|
|
|
* servers. It returns 0 if the output buffer is full and it needs to be called
|
|
|
|
* again, otherwise non-zero. It may limit itself to the resolver pointed to by
|
|
|
|
* <cli.p0> if it's not null.
|
2016-11-18 23:58:54 +00:00
|
|
|
*/
|
|
|
|
static int cli_io_handler_dump_resolvers_to_buffer(struct appctx *appctx)
|
|
|
|
{
|
|
|
|
struct stream_interface *si = appctx->owner;
|
|
|
|
struct dns_resolvers *presolvers;
|
|
|
|
struct dns_nameserver *pnameserver;
|
|
|
|
|
|
|
|
chunk_reset(&trash);
|
|
|
|
|
|
|
|
switch (appctx->st2) {
|
|
|
|
case STAT_ST_INIT:
|
|
|
|
appctx->st2 = STAT_ST_LIST; /* let's start producing data */
|
|
|
|
/* fall through */
|
|
|
|
|
|
|
|
case STAT_ST_LIST:
|
|
|
|
if (LIST_ISEMPTY(&dns_resolvers)) {
|
|
|
|
chunk_appendf(&trash, "No resolvers found\n");
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
list_for_each_entry(presolvers, &dns_resolvers, list) {
|
2016-12-16 17:06:26 +00:00
|
|
|
if (appctx->ctx.cli.p0 != NULL && appctx->ctx.cli.p0 != presolvers)
|
2016-11-18 23:58:54 +00:00
|
|
|
continue;
|
|
|
|
|
|
|
|
chunk_appendf(&trash, "Resolvers section %s\n", presolvers->id);
|
|
|
|
list_for_each_entry(pnameserver, &presolvers->nameserver_list, list) {
|
|
|
|
chunk_appendf(&trash, " nameserver %s:\n", pnameserver->id);
|
|
|
|
chunk_appendf(&trash, " sent: %ld\n", pnameserver->counters.sent);
|
|
|
|
chunk_appendf(&trash, " valid: %ld\n", pnameserver->counters.valid);
|
|
|
|
chunk_appendf(&trash, " update: %ld\n", pnameserver->counters.update);
|
|
|
|
chunk_appendf(&trash, " cname: %ld\n", pnameserver->counters.cname);
|
|
|
|
chunk_appendf(&trash, " cname_error: %ld\n", pnameserver->counters.cname_error);
|
|
|
|
chunk_appendf(&trash, " any_err: %ld\n", pnameserver->counters.any_err);
|
|
|
|
chunk_appendf(&trash, " nx: %ld\n", pnameserver->counters.nx);
|
|
|
|
chunk_appendf(&trash, " timeout: %ld\n", pnameserver->counters.timeout);
|
|
|
|
chunk_appendf(&trash, " refused: %ld\n", pnameserver->counters.refused);
|
|
|
|
chunk_appendf(&trash, " other: %ld\n", pnameserver->counters.other);
|
|
|
|
chunk_appendf(&trash, " invalid: %ld\n", pnameserver->counters.invalid);
|
|
|
|
chunk_appendf(&trash, " too_big: %ld\n", pnameserver->counters.too_big);
|
|
|
|
chunk_appendf(&trash, " truncated: %ld\n", pnameserver->counters.truncated);
|
|
|
|
chunk_appendf(&trash, " outdated: %ld\n", pnameserver->counters.outdated);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* display response */
|
REORG: channel: finally rename the last bi_* / bo_* functions
For HTTP/2 we'll need some buffer-only equivalent functions to some of
the ones applying to channels and still squatting the bi_* / bo_*
namespace. Since these names have kept being misleading for quite some
time now and are really getting annoying, it's time to rename them. This
commit will use "ci/co" as the prefix (for "channel in", "channel out")
instead of "bi/bo". The following ones were renamed :
bi_getblk_nc, bi_getline_nc, bi_putblk, bi_putchr,
bo_getblk, bo_getblk_nc, bo_getline, bo_getline_nc, bo_inject,
bi_putchk, bi_putstr, bo_getchr, bo_skip, bi_swpbuf
2017-10-19 12:32:15 +00:00
|
|
|
if (ci_putchk(si_ic(si), &trash) == -1) {
|
2016-11-18 23:58:54 +00:00
|
|
|
/* let's try again later from this session. We add ourselves into
|
|
|
|
* this session's users so that it can remove us upon termination.
|
|
|
|
*/
|
|
|
|
si->flags |= SI_FL_WAIT_ROOM;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
appctx->st2 = STAT_ST_FIN;
|
|
|
|
/* fall through */
|
|
|
|
|
|
|
|
default:
|
|
|
|
appctx->st2 = STAT_ST_FIN;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* register cli keywords */
|
|
|
|
static struct cli_kw_list cli_kws = {{ },{
|
|
|
|
{ { "show", "stat", "resolvers", NULL }, "show stat resolvers [id]: dumps counters from all resolvers section and\n"
|
|
|
|
" associated name servers",
|
|
|
|
cli_parse_stat_resolvers, cli_io_handler_dump_resolvers_to_buffer },
|
|
|
|
{{},}
|
|
|
|
}};
|
|
|
|
|
|
|
|
|
|
|
|
__attribute__((constructor))
|
|
|
|
static void __dns_init(void)
|
|
|
|
{
|
|
|
|
cli_register_kw(&cli_kws);
|
|
|
|
}
|
|
|
|
|