haproxy/src/dns.c

2692 lines
78 KiB
C
Raw Normal View History

/*
* 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>
#include <common/net_helper.h>
#include <import/lru.h>
#include <import/xxhash.h>
#include <types/applet.h>
#include <types/cli.h>
#include <types/global.h>
#include <types/dns.h>
#include <types/proto_udp.h>
#include <types/stats.h>
#include <proto/channel.h>
#include <proto/cli.h>
#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>
#include <proto/stream_interface.h>
struct list dns_resolvers = LIST_HEAD_INIT(dns_resolvers);
struct dns_resolution *resolution = NULL;
static int64_t dns_query_id_seed; /* random seed */
static struct lru64_head *dns_lru_tree;
static int dns_cache_size = 1024; /* arbitrary DNS cache size */
static struct pool_head *dns_answer_item_pool;
/* 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);
#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) {
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) {
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) {
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) {
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) {
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;
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:
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;
case OBJ_TYPE_SRVRQ:
valid_period = objt_dns_srvrq(requester->requester)->inter;
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;
}
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);
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;
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;
}
/*
* 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;
}
/*
* 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))
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))
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)))
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.
*/
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;
}
static inline void free_dns_answer_item(struct dns_answer_item *item)
{
pool_free2(dns_answer_item_pool, item);
}
/*
* 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
* - check the dn_name in the packet against the one sent
*/
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;
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;
struct dns_query_item *query;
unsigned char buf[DNS_MAX_UDP_MESSAGE + 1];
unsigned char *bufend;
int fd, buflen, dns_resp, need_resend = 0;
int max_answer_records = 0;
unsigned short query_id;
struct eb32_node *eb;
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;
struct dns_answer_item *item1, *item2 = NULL;
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 */
if ((nameserver = dgram->owner) == NULL)
return;
resolvers = nameserver->resolvers;
/* process all pending input messages */
while (1) {
int removed_reso = 0;
/* read message received */
memset(buf, '\0', resolvers->accepted_payload_size + 1);
if ((buflen = recv(fd, (char*)buf , resolvers->accepted_payload_size + 1, 0)) < 0) {
/* FIXME : for now we consider EAGAIN only */
fd_cant_recv(fd);
break;
}
/* message too big */
if (buflen > resolvers->accepted_payload_size) {
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 */
eb = eb32_lookup(&resolvers->query_ids, query_id);
if (eb == NULL) {
/* 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;
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);
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;
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;
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;
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;
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;
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;
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;
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;
}
/* Check for any obsolete record, also identify any SRV request, and try to find a corresponding server */
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);
if (item1->type == DNS_RTYPE_SRV && !LIST_ISEMPTY(&resolution->requester.curr)) {
struct dns_srvrq *srvrq;
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;
srv_free_from_resolution(srv);
}
}
}
} /* end of list_for_each(requester) */
}
free_dns_answer_item(item1);
continue;
}
if (item1->type == DNS_RTYPE_SRV) {
struct server *srv = NULL;
struct dns_srvrq *srvrq = NULL;
if (LIST_ISEMPTY(&resolution->requester.curr))
continue;
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) {
char weight[9];
const char *msg = NULL;
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);
msg = update_server_fqdn(srv, hostname, "SRV record");
if (msg)
send_log(srv->proxy, LOG_NOTICE, "%s", msg);
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;
snprintf(weight, sizeof(weight),
"%d", item1->weight);
server_parse_weight_change_request(srv, weight);
}
}
}
}
}
if (removed_reso)
goto next_packet;
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;
}
/* 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 */
query = LIST_NEXT(&resolution->response.query_list, struct dns_query_item *, list);
if (!resolution->hostname_dn)
abort();
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;
}
/* 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);
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;
}
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;
}
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);
}
/*
* 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 */
if ((nameserver = dgram->owner) == NULL)
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);
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)
{
REORG: dns: dns_option structure, storage of hostname_dn This patch introduces a some re-organisation around the DNS code in HAProxy. 1. make the dns_* functions less dependent on 'struct server' and 'struct resolution'. With this in mind, the following changes were performed: - 'struct dns_options' has been removed from 'struct resolution' (well, we might need it back at some point later, we'll see) ==> we'll use the 'struct dns_options' from the owner of the resolution - dns_get_ip_from_response(): takes a 'struct dns_options' instead of 'struct resolution' ==> so the caller can pass its own dns options to get the most appropriate IP from the response - dns_process_resolve(): struct dns_option is deduced from new resolution->requester_type parameter 2. add hostname_dn and hostname_dn_len into struct server In order to avoid recomputing a server's hostname into its domain name format (and use a trash buffer to store the result), it is safer to compute it once at configuration parsing and to store it into the struct server. In the mean time, the struct resolution linked to the server doesn't need anymore to store the hostname in domain name format. A simple pointer to the server one will make the trick. The function srv_alloc_dns_resolution() properly manages everything for us: memory allocation, pointer updates, etc... 3. move resolvers pointer into struct server This patch makes the pointer to struct dns_resolvers from struct dns_resolution obsolete. Purpose is to make the resolution as "neutral" as possible and since the requester is already linked to the resolvers, then we don't need this information anymore in the resolution itself.
2017-05-03 10:12:02 +00:00
struct dns_resolvers *resolvers = NULL;
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;
int ret, bufsize, fd;
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;
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;
}
REORG: dns: dns_option structure, storage of hostname_dn This patch introduces a some re-organisation around the DNS code in HAProxy. 1. make the dns_* functions less dependent on 'struct server' and 'struct resolution'. With this in mind, the following changes were performed: - 'struct dns_options' has been removed from 'struct resolution' (well, we might need it back at some point later, we'll see) ==> we'll use the 'struct dns_options' from the owner of the resolution - dns_get_ip_from_response(): takes a 'struct dns_options' instead of 'struct resolution' ==> so the caller can pass its own dns options to get the most appropriate IP from the response - dns_process_resolve(): struct dns_option is deduced from new resolution->requester_type parameter 2. add hostname_dn and hostname_dn_len into struct server In order to avoid recomputing a server's hostname into its domain name format (and use a trash buffer to store the result), it is safer to compute it once at configuration parsing and to store it into the struct server. In the mean time, the struct resolution linked to the server doesn't need anymore to store the hostname in domain name format. A simple pointer to the server one will make the trick. The function srv_alloc_dns_resolution() properly manages everything for us: memory allocation, pointer updates, etc... 3. move resolvers pointer into struct server This patch makes the pointer to struct dns_resolvers from struct dns_resolution obsolete. Purpose is to make the resolution as "neutral" as possible and since the requester is already linked to the resolvers, then we don't need this information anymore in the resolution itself.
2017-05-03 10:12:02 +00:00
if (!resolvers)
return 0;
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);
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;
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))) {
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);
}
}
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;
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;
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);
}
/*
* 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;
}
/*
* Function to validate that the buffer DNS response provided in <resp> and
* finishing before <bufend> is valid from a DNS protocol point of view.
*
* The result is stored in <resolution>' response, buf_response, response_query_records
* and response_answer_records members.
*
* This function returns one of the DNS_RESP_* code to indicate the type of
* error found.
*/
int dns_validate_dns_response(unsigned char *resp, unsigned char *bufend, struct dns_resolution *resolution, int max_answer_records)
{
unsigned char *reader;
char *previous_dname, tmpname[DNS_MAX_NAME_SIZE];
int len, flags, offset;
int dns_query_record_id;
int nb_saved_records;
struct dns_query_item *dns_query;
struct dns_answer_item *dns_answer_record, *tmp_record;
struct dns_response_packet *dns_p;
int found = 0;
int i;
reader = resp;
len = 0;
previous_dname = NULL;
dns_query = NULL;
/* initialization of response buffer and structure */
dns_p = &resolution->response;
/* query id */
if (reader + 2 >= bufend)
return DNS_RESP_INVALID;
dns_p->header.id = reader[0] * 256 + reader[1];
reader += 2;
/*
* flags and rcode are stored over 2 bytes
* First byte contains:
* - response flag (1 bit)
* - opcode (4 bits)
* - authoritative (1 bit)
* - truncated (1 bit)
* - recursion desired (1 bit)
*/
if (reader + 2 >= bufend)
return DNS_RESP_INVALID;
flags = reader[0] * 256 + reader[1];
if ((flags & DNS_FLAG_REPLYCODE) != DNS_RCODE_NO_ERROR) {
if ((flags & DNS_FLAG_REPLYCODE) == DNS_RCODE_NX_DOMAIN)
return DNS_RESP_NX_DOMAIN;
else if ((flags & DNS_FLAG_REPLYCODE) == DNS_RCODE_REFUSED)
return DNS_RESP_REFUSED;
return DNS_RESP_ERROR;
}
/* move forward 2 bytes for flags */
reader += 2;
/* 2 bytes for question count */
if (reader + 2 >= bufend)
return DNS_RESP_INVALID;
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)
return DNS_RESP_INVALID;
reader += 2;
/* 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)
return DNS_RESP_ANCOUNT_ZERO;
/* check if too many records are announced */
if (dns_p->header.ancount > max_answer_records)
return DNS_RESP_INVALID;
reader += 2;
/* 2 bytes authority count */
if (reader + 2 >= bufend)
return DNS_RESP_INVALID;
dns_p->header.nscount = reader[0] * 256 + reader[1];
reader += 2;
/* 2 bytes additional count */
if (reader + 2 >= bufend)
return DNS_RESP_INVALID;
dns_p->header.arcount = reader[0] * 256 + reader[1];
reader += 2;
/* 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;
dns_query = &resolution->response_query_records[dns_query_record_id];
LIST_ADDQ(&dns_p->query_list, &dns_query->list);
/* 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);
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;
}
/* 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;
/* now parsing response records */
nb_saved_records = 0;
for (i = 0; i < dns_p->header.ancount; i++) {
if (reader >= bufend)
return DNS_RESP_INVALID;
dns_answer_record = pool_alloc2(dns_answer_item_pool);
if (dns_answer_record == NULL)
return (DNS_RESP_INVALID);
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;
}
/* check if the current record dname is valid.
* previous_dname points either to queried dname or last CNAME target
*/
if (dns_query->type != DNS_RTYPE_SRV && memcmp(previous_dname, tmpname, len) != 0) {
free_dns_answer_item(dns_answer_record);
if (i == 0) {
/* first record, means a mismatch issue between queried dname
* and dname found in the first record */
return DNS_RESP_INVALID;
} else {
/* if not the first record, this means we have a CNAME resolution
* error */
return DNS_RESP_CNAME_ERROR;
}
}
memcpy(dns_answer_record->name, tmpname, len);
dns_answer_record->name[len] = 0;
reader += offset;
if (reader >= bufend) {
free_dns_answer_item(dns_answer_record);
return DNS_RESP_INVALID;
}
/* 2 bytes for record type (A, AAAA, CNAME, etc...) */
if (reader + 2 > bufend) {
free_dns_answer_item(dns_answer_record);
return DNS_RESP_INVALID;
}
dns_answer_record->type = reader[0] * 256 + reader[1];
reader += 2;
/* 2 bytes for class (2) */
if (reader + 2 > bufend) {
free_dns_answer_item(dns_answer_record);
return DNS_RESP_INVALID;
}
dns_answer_record->class = reader[0] * 256 + reader[1];
reader += 2;
/* 4 bytes for ttl (4) */
if (reader + 4 > bufend) {
free_dns_answer_item(dns_answer_record);
return DNS_RESP_INVALID;
}
dns_answer_record->ttl = reader[0] * 16777216 + reader[1] * 65536
+ reader[2] * 256 + reader[3];
reader += 4;
/* now reading data len */
if (reader + 2 > bufend) {
free_dns_answer_item(dns_answer_record);
return DNS_RESP_INVALID;
}
dns_answer_record->data_len = reader[0] * 256 + reader[1];
/* move forward 2 bytes for data len */
reader += 2;
/* analyzing record content */
switch (dns_answer_record->type) {
case DNS_RTYPE_A:
/* ipv4 is stored on 4 bytes */
if (dns_answer_record->data_len != 4) {
free_dns_answer_item(dns_answer_record);
return DNS_RESP_INVALID;
}
dns_answer_record->address.sa_family = AF_INET;
memcpy(&(((struct sockaddr_in *)&dns_answer_record->address)->sin_addr),
reader, dns_answer_record->data_len);
break;
case DNS_RTYPE_CNAME:
/* 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.
*/
if (i + 1 == dns_p->header.ancount) {
free_dns_answer_item(dns_answer_record);
return DNS_RESP_CNAME_ERROR;
}
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;
}
memcpy(dns_answer_record->target, tmpname, len);
dns_answer_record->target[len] = 0;
previous_dname = dns_answer_record->target;
break;
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;
}
dns_answer_record->priority = read_n16(reader);
reader += sizeof(uint16_t);
dns_answer_record->weight = read_n16(reader);
reader += sizeof(uint16_t);
dns_answer_record->port = read_n16(reader);
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;
case DNS_RTYPE_AAAA:
/* ipv6 is stored on 16 bytes */
if (dns_answer_record->data_len != 16) {
free_dns_answer_item(dns_answer_record);
return DNS_RESP_INVALID;
}
dns_answer_record->address.sa_family = AF_INET6;
memcpy(&(((struct sockaddr_in6 *)&dns_answer_record->address)->sin6_addr),
reader, dns_answer_record->data_len);
break;
} /* switch (record type) */
/* increment the counter for number of records saved into our local response */
nb_saved_records += 1;
/* move forward dns_answer_record->data_len for analyzing next record in the response */
if (dns_answer_record->type == DNS_RTYPE_SRV)
reader += offset;
else
reader += dns_answer_record->data_len;
/* Lookup to see if we already had this entry */
found = 0;
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;
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;
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);
}
} /* for i 0 to ancount */
/* save the number of records we really own */
dns_p->header.ancount = nb_saved_records;
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:
* - <dns_p> contains an error free DNS response
* For both cases above, dns_validate_dns_response is required
* returns one of the DNS_UPD_* code
*/
#define DNS_MAX_IP_REC 20
int dns_get_ip_from_response(struct dns_response_packet *dns_p,
REORG: dns: dns_option structure, storage of hostname_dn This patch introduces a some re-organisation around the DNS code in HAProxy. 1. make the dns_* functions less dependent on 'struct server' and 'struct resolution'. With this in mind, the following changes were performed: - 'struct dns_options' has been removed from 'struct resolution' (well, we might need it back at some point later, we'll see) ==> we'll use the 'struct dns_options' from the owner of the resolution - dns_get_ip_from_response(): takes a 'struct dns_options' instead of 'struct resolution' ==> so the caller can pass its own dns options to get the most appropriate IP from the response - dns_process_resolve(): struct dns_option is deduced from new resolution->requester_type parameter 2. add hostname_dn and hostname_dn_len into struct server In order to avoid recomputing a server's hostname into its domain name format (and use a trash buffer to store the result), it is safer to compute it once at configuration parsing and to store it into the struct server. In the mean time, the struct resolution linked to the server doesn't need anymore to store the hostname in domain name format. A simple pointer to the server one will make the trick. The function srv_alloc_dns_resolution() properly manages everything for us: memory allocation, pointer updates, etc... 3. move resolvers pointer into struct server This patch makes the pointer to struct dns_resolvers from struct dns_resolution obsolete. Purpose is to make the resolution as "neutral" as possible and since the requester is already linked to the resolvers, then we don't need this information anymore in the resolution itself.
2017-05-03 10:12:02 +00:00
struct dns_options *dns_opts, void *currentip,
short currentip_sin_family,
void **newip, short *newip_sin_family,
void *owner)
{
struct dns_answer_item *record;
int family_priority;
int currentip_found;
unsigned char *newip4, *newip6;
int currentip_sel;
int j;
int score, max_score;
REORG: dns: dns_option structure, storage of hostname_dn This patch introduces a some re-organisation around the DNS code in HAProxy. 1. make the dns_* functions less dependent on 'struct server' and 'struct resolution'. With this in mind, the following changes were performed: - 'struct dns_options' has been removed from 'struct resolution' (well, we might need it back at some point later, we'll see) ==> we'll use the 'struct dns_options' from the owner of the resolution - dns_get_ip_from_response(): takes a 'struct dns_options' instead of 'struct resolution' ==> so the caller can pass its own dns options to get the most appropriate IP from the response - dns_process_resolve(): struct dns_option is deduced from new resolution->requester_type parameter 2. add hostname_dn and hostname_dn_len into struct server In order to avoid recomputing a server's hostname into its domain name format (and use a trash buffer to store the result), it is safer to compute it once at configuration parsing and to store it into the struct server. In the mean time, the struct resolution linked to the server doesn't need anymore to store the hostname in domain name format. A simple pointer to the server one will make the trick. The function srv_alloc_dns_resolution() properly manages everything for us: memory allocation, pointer updates, etc... 3. move resolvers pointer into struct server This patch makes the pointer to struct dns_resolvers from struct dns_resolution obsolete. Purpose is to make the resolution as "neutral" as possible and since the requester is already linked to the resolvers, then we don't need this information anymore in the resolution itself.
2017-05-03 10:12:02 +00:00
family_priority = dns_opts->family_prio;
*newip = newip4 = newip6 = NULL;
currentip_found = 0;
*newip_sin_family = AF_UNSPEC;
max_score = -1;
/* 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:
* 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)
* 1 - current ip.
* The result with the biggest score is returned.
*/
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;
score = 0;
/* Check for prefered ip protocol. */
if (ip_type == family_priority)
score += 8;
/* Check for prefered network. */
REORG: dns: dns_option structure, storage of hostname_dn This patch introduces a some re-organisation around the DNS code in HAProxy. 1. make the dns_* functions less dependent on 'struct server' and 'struct resolution'. With this in mind, the following changes were performed: - 'struct dns_options' has been removed from 'struct resolution' (well, we might need it back at some point later, we'll see) ==> we'll use the 'struct dns_options' from the owner of the resolution - dns_get_ip_from_response(): takes a 'struct dns_options' instead of 'struct resolution' ==> so the caller can pass its own dns options to get the most appropriate IP from the response - dns_process_resolve(): struct dns_option is deduced from new resolution->requester_type parameter 2. add hostname_dn and hostname_dn_len into struct server In order to avoid recomputing a server's hostname into its domain name format (and use a trash buffer to store the result), it is safer to compute it once at configuration parsing and to store it into the struct server. In the mean time, the struct resolution linked to the server doesn't need anymore to store the hostname in domain name format. A simple pointer to the server one will make the trick. The function srv_alloc_dns_resolution() properly manages everything for us: memory allocation, pointer updates, etc... 3. move resolvers pointer into struct server This patch makes the pointer to struct dns_resolvers from struct dns_resolution obsolete. Purpose is to make the resolution as "neutral" as possible and since the requester is already linked to the resolvers, then we don't need this information anymore in the resolution itself.
2017-05-03 10:12:02 +00:00
for (j = 0; j < dns_opts->pref_net_nb; j++) {
/* Compare only the same adresses class. */
if (dns_opts->pref_net[j].family != ip_type)
continue;
if ((ip_type == AF_INET &&
in_net_ipv4(ip,
REORG: dns: dns_option structure, storage of hostname_dn This patch introduces a some re-organisation around the DNS code in HAProxy. 1. make the dns_* functions less dependent on 'struct server' and 'struct resolution'. With this in mind, the following changes were performed: - 'struct dns_options' has been removed from 'struct resolution' (well, we might need it back at some point later, we'll see) ==> we'll use the 'struct dns_options' from the owner of the resolution - dns_get_ip_from_response(): takes a 'struct dns_options' instead of 'struct resolution' ==> so the caller can pass its own dns options to get the most appropriate IP from the response - dns_process_resolve(): struct dns_option is deduced from new resolution->requester_type parameter 2. add hostname_dn and hostname_dn_len into struct server In order to avoid recomputing a server's hostname into its domain name format (and use a trash buffer to store the result), it is safer to compute it once at configuration parsing and to store it into the struct server. In the mean time, the struct resolution linked to the server doesn't need anymore to store the hostname in domain name format. A simple pointer to the server one will make the trick. The function srv_alloc_dns_resolution() properly manages everything for us: memory allocation, pointer updates, etc... 3. move resolvers pointer into struct server This patch makes the pointer to struct dns_resolvers from struct dns_resolution obsolete. Purpose is to make the resolution as "neutral" as possible and since the requester is already linked to the resolvers, then we don't need this information anymore in the resolution itself.
2017-05-03 10:12:02 +00:00
&dns_opts->pref_net[j].mask.in4,
&dns_opts->pref_net[j].addr.in4)) ||
(ip_type == AF_INET6 &&
in_net_ipv6(ip,
REORG: dns: dns_option structure, storage of hostname_dn This patch introduces a some re-organisation around the DNS code in HAProxy. 1. make the dns_* functions less dependent on 'struct server' and 'struct resolution'. With this in mind, the following changes were performed: - 'struct dns_options' has been removed from 'struct resolution' (well, we might need it back at some point later, we'll see) ==> we'll use the 'struct dns_options' from the owner of the resolution - dns_get_ip_from_response(): takes a 'struct dns_options' instead of 'struct resolution' ==> so the caller can pass its own dns options to get the most appropriate IP from the response - dns_process_resolve(): struct dns_option is deduced from new resolution->requester_type parameter 2. add hostname_dn and hostname_dn_len into struct server In order to avoid recomputing a server's hostname into its domain name format (and use a trash buffer to store the result), it is safer to compute it once at configuration parsing and to store it into the struct server. In the mean time, the struct resolution linked to the server doesn't need anymore to store the hostname in domain name format. A simple pointer to the server one will make the trick. The function srv_alloc_dns_resolution() properly manages everything for us: memory allocation, pointer updates, etc... 3. move resolvers pointer into struct server This patch makes the pointer to struct dns_resolvers from struct dns_resolution obsolete. Purpose is to make the resolution as "neutral" as possible and since the requester is already linked to the resolvers, then we don't need this information anymore in the resolution itself.
2017-05-03 10:12:02 +00:00
&dns_opts->pref_net[j].mask.in6,
&dns_opts->pref_net[j].addr.in6))) {
score += 4;
break;
}
}
/* 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) {
if (snr_check_ip_callback(owner, ip, &ip_type))
{
continue;
}
}
/* Check for current ip matching. */
if (ip_type == currentip_sin_family &&
((currentip_sin_family == AF_INET &&
memcmp(ip, currentip, 4) == 0) ||
(currentip_sin_family == AF_INET6 &&
memcmp(ip, currentip, 16) == 0))) {
score += 1;
currentip_sel = 1;
} else
currentip_sel = 0;
/* Keep the address if the score is better than the previous
* score. The maximum score is 15, if this value is reached,
* we break the parsing. Implicitly, this score is reached
* the ip selected is the current ip.
*/
if (score > max_score) {
if (ip_type == AF_INET)
newip4 = ip;
else
newip6 = ip;
currentip_found = currentip_sel;
if (score == 15)
return DNS_UPD_NO;
max_score = score;
}
} /* list for each record entries */
/* no IP found in the response */
if (!newip4 && !newip6)
return DNS_UPD_NO_IP_FOUND;
/* 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;
goto return_DNS_UPD_SRVIP_NOT_FOUND;
}
else if (newip6) {
*newip = newip6;
*newip_sin_family = AF_INET6;
if (currentip_found == 1)
return DNS_UPD_NO;
goto return_DNS_UPD_SRVIP_NOT_FOUND;
}
}
/* 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;
goto return_DNS_UPD_SRVIP_NOT_FOUND;
}
else if (newip4) {
*newip = newip4;
*newip_sin_family = AF_INET;
if (currentip_found == 1)
return DNS_UPD_NO;
goto return_DNS_UPD_SRVIP_NOT_FOUND;
}
}
/* 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;
goto return_DNS_UPD_SRVIP_NOT_FOUND;
}
else if (newip4) {
*newip = newip4;
*newip_sin_family = AF_INET;
if (currentip_found == 1)
return DNS_UPD_NO;
goto return_DNS_UPD_SRVIP_NOT_FOUND;
}
}
/* no reason why we should change the server's IP address */
return DNS_UPD_NO;
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;
}
/*
* returns the query id contained in a DNS response
*/
unsigned short dns_response_get_query_id(unsigned char *resp)
{
/* 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
* It takes one argument:
* - close_first takes 2 values: 0 or 1. If 1, the connection is closed first.
* returns:
* 0 in case of error
* 1 when no error
*/
int dns_init_resolvers(int close_socket)
{
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;
struct dgram_conn *dgram;
struct task *t;
int fd;
/* initialize our DNS resolution cache */
dns_lru_tree = lru64_new(dns_cache_size);
/* give a first random value to our dns query_id seed */
dns_query_id_seed = random();
/* 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;
}
/* 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);
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;
if (close_socket == 1) {
if (curnameserver->dgram) {
fd_delete(curnameserver->dgram->t.sock.fd);
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 */
if (!dgram && (dgram = calloc(1, sizeof(*dgram))) == NULL) {
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 */
if ((fd = socket(curnameserver->addr.ss_family, SOCK_DGRAM, IPPROTO_UDP)) == -1) {
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 */
if (connect(fd, (struct sockaddr*)&curnameserver->addr, get_addr_len(&curnameserver->addr)) == -1) {
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;
fd_insert(fd);
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);
}
/* 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;
}
/*
* 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
*/
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)
{
struct dns_header *dns;
struct dns_question qinfo;
struct dns_additional_record edns;
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);
dns->flags = htons(0x0100); /* qr=0, opcode=0, aa=0, tc=0, rd=1, ra=0, z=0, rcode=0 */
dns->qdcount = htons(1); /* 1 question */
dns->ancount = 0;
dns->nscount = 0;
dns->arcount = htons(1);
/* 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) */
qinfo.qtype = htons(query_type);
qinfo.qclass = htons(DNS_RCLASS_IN);
memcpy(ptr, &qinfo, sizeof(qinfo));
ptr += sizeof(struct dns_question);
/* 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);
return ptr - buf;
}
/* 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;
}
/*
* 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
*/
char *dns_str_to_dn_label(const char *string, char *dn, int dn_len)
{
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;
i = strlen(string);
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;
int res_preferred_afinet, res_preferred_afinet6;
REORG: dns: dns_option structure, storage of hostname_dn This patch introduces a some re-organisation around the DNS code in HAProxy. 1. make the dns_* functions less dependent on 'struct server' and 'struct resolution'. With this in mind, the following changes were performed: - 'struct dns_options' has been removed from 'struct resolution' (well, we might need it back at some point later, we'll see) ==> we'll use the 'struct dns_options' from the owner of the resolution - dns_get_ip_from_response(): takes a 'struct dns_options' instead of 'struct resolution' ==> so the caller can pass its own dns options to get the most appropriate IP from the response - dns_process_resolve(): struct dns_option is deduced from new resolution->requester_type parameter 2. add hostname_dn and hostname_dn_len into struct server In order to avoid recomputing a server's hostname into its domain name format (and use a trash buffer to store the result), it is safer to compute it once at configuration parsing and to store it into the struct server. In the mean time, the struct resolution linked to the server doesn't need anymore to store the hostname in domain name format. A simple pointer to the server one will make the trick. The function srv_alloc_dns_resolution() properly manages everything for us: memory allocation, pointer updates, etc... 3. move resolvers pointer into struct server This patch makes the pointer to struct dns_resolvers from struct dns_resolution obsolete. Purpose is to make the resolution as "neutral" as possible and since the requester is already linked to the resolvers, then we don't need this information anymore in the resolution itself.
2017-05-03 10:12:02 +00:00
struct dns_options *dns_opts = 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 both there is no resolution in the run queue, we can re-schedule a wake up */
if (LIST_ISEMPTY(&resolvers->resolution.curr)) {
/* 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);
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;
/* 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;
/*
* if current resolution has been tried too many times and finishes in timeout
* we update its status and remove it from the list
*/
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;
/* 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);
}
/* 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;
goto out;
}
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);
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;
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;
}
REORG: dns: dns_option structure, storage of hostname_dn This patch introduces a some re-organisation around the DNS code in HAProxy. 1. make the dns_* functions less dependent on 'struct server' and 'struct resolution'. With this in mind, the following changes were performed: - 'struct dns_options' has been removed from 'struct resolution' (well, we might need it back at some point later, we'll see) ==> we'll use the 'struct dns_options' from the owner of the resolution - dns_get_ip_from_response(): takes a 'struct dns_options' instead of 'struct resolution' ==> so the caller can pass its own dns options to get the most appropriate IP from the response - dns_process_resolve(): struct dns_option is deduced from new resolution->requester_type parameter 2. add hostname_dn and hostname_dn_len into struct server In order to avoid recomputing a server's hostname into its domain name format (and use a trash buffer to store the result), it is safer to compute it once at configuration parsing and to store it into the struct server. In the mean time, the struct resolution linked to the server doesn't need anymore to store the hostname in domain name format. A simple pointer to the server one will make the trick. The function srv_alloc_dns_resolution() properly manages everything for us: memory allocation, pointer updates, etc... 3. move resolvers pointer into struct server This patch makes the pointer to struct dns_resolvers from struct dns_resolution obsolete. Purpose is to make the resolution as "neutral" as possible and since the requester is already linked to the resolvers, then we don't need this information anymore in the resolution itself.
2017-05-03 10:12:02 +00:00
/* resend the DNS query */
dns_send_query(resolution);
/* 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);
}
}
out:
dns_update_resolvers_timeout(resolvers);
return t;
}
/*
* 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;
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;
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;
}
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;
}
/* if an arg is found, it sets the resolvers section pointer into cli.p0 */
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) {
appctx->ctx.cli.p0 = presolvers;
break;
}
}
if (appctx->ctx.cli.p0 == NULL) {
appctx->ctx.cli.severity = LOG_ERR;
appctx->ctx.cli.msg = "Can't find that resolvers section\n";
appctx->st0 = CLI_ST_PRINT;
return 1;
}
}
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 <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;
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;
}
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;
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;
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;
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;
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
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
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
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
}
/* 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
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
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
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;
}
/* 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;
char *buffer = NULL;
resolution = calloc(1, sizeof(*resolution));
buffer = calloc(1, global.tune.bufsize);
if (!resolution || !buffer) {
free(buffer);
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);
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;
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;
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;
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:
;;
}
}
/* 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.
*/
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) {
if (appctx->ctx.cli.p0 != NULL && appctx->ctx.cli.p0 != presolvers)
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 */
if (ci_putchk(si_ic(si), &trash) == -1) {
/* 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);
}