MAJOR: dns: Refactor the DNS code

This is a huge patch with many changes, all about the DNS. Initially, the idea
was to update the DNS part to ease the threads support integration. But quickly,
I started to refactor some parts. And after several iterations, it was
impossible for me to commit the different parts atomically. So, instead of
adding tens of patches, often reworking the same parts, it was easier to merge
all my changes in a uniq patch. Here are all changes made on the DNS.

First, the DNS initialization has been refactored. The DNS configuration parsing
remains untouched, in cfgparse.c. But all checks have been moved in a post-check
callback. In the function dns_finalize_config, for each resolvers, the
nameservers configuration is tested and the task used to manage DNS resolutions
is created. The links between the backend's servers and the resolvers are also
created at this step. Here no connection are kept alive. So there is no needs
anymore to reopen them after HAProxy fork. Connections used to send DNS queries
will be opened on demand.

Then, the way DNS requesters are linked to a DNS resolution has been
reworked. The resolution used by a requester is now referenced into the
dns_requester structure and the resolution pointers in server and dns_srvrq
structures have been removed. wait and curr list of requesters, for a DNS
resolution, have been replaced by a uniq list. And Finally, the way a requester
is removed from a DNS resolution has been simplified. Now everything is done in
dns_unlink_resolution.

srv_set_fqdn function has been simplified. Now, there is only 1 way to set the
server's FQDN, independently it is done by the CLI or when a SRV record is
resolved.

The static DNS resolutions pool has been replaced by a dynamoc pool. The part
has been modified by Baptiste Assmann.

The way the DNS resolutions are triggered by the task or by a health-check has
been totally refactored. Now, all timeouts are respected. Especially
hold.valid. The default frequency to wake up a resolvers is now configurable
using "timeout resolve" parameter.

Now, as documented, as long as invalid repsonses are received, we really wait
all name servers responses before retrying.

As far as possible, resources allocated during DNS configuration parsing are
releases when HAProxy is shutdown.

Beside all these changes, the code has been cleaned to ease code review and the
doc has been updated.
This commit is contained in:
Christopher Faulet 2017-09-27 11:00:59 +02:00 committed by Willy Tarreau
parent ff88efbd7a
commit 67957bd59e
13 changed files with 1645 additions and 2545 deletions

View File

@ -11475,10 +11475,6 @@ resolve-net <network>[,<network[,...]]
resolvers <id> resolvers <id>
Points to an existing "resolvers" section to resolve current server's Points to an existing "resolvers" section to resolve current server's
hostname. hostname.
In order to be operational, DNS resolution requires that health check is
enabled on the server. Actually, health checks triggers the DNS resolution.
You must precise one 'resolvers' parameter on each server line where DNS
resolution is required.
Example: Example:
@ -11712,21 +11708,20 @@ different steps of the process life:
host name. It uses libc functions to get the host name resolved. This host name. It uses libc functions to get the host name resolved. This
resolution relies on /etc/resolv.conf file. resolution relies on /etc/resolv.conf file.
2. at run time, when HAProxy gets prepared to run a health check on a server, 2. at run time, HAProxy performs periodically name resolutions for servers
it verifies if the current name resolution is still considered as valid. requiring DNS resolutions.
If not, it processes a new resolution, in parallel of the health check.
A few other events can trigger a name resolution at run time: A few other events can trigger a name resolution at run time:
- when a server's health check ends up in a connection timeout: this may be - when a server's health check ends up in a connection timeout: this may be
because the server has a new IP address. So we need to trigger a name because the server has a new IP address. So we need to trigger a name
resolution to know this new IP. resolution to know this new IP.
When using resolvers, the server name can either be a hostname, or s SRV label. When using resolvers, the server name can either be a hostname, or a SRV label.
HAProxy considers anything that starts with an underscore a SRV label. HAProxy considers anything that starts with an underscore as a SRV label. If a
If a SRV label is specified, then the corresponding SRV records will be SRV label is specified, then the corresponding SRV records will be retrieved
retrieved from the DNS server, and the provided hostnames will be used. The from the DNS server, and the provided hostnames will be used. The SRV label
SRV label will be checked periodically, and if any server are added or removed, will be checked periodically, and if any server are added or removed, haproxy
haproxy will automatically do the same. will automatically do the same.
A few things important to notice: A few things important to notice:
- all the name servers are queried in the mean time. HAProxy will process the - all the name servers are queried in the mean time. HAProxy will process the
@ -11740,9 +11735,8 @@ A few things important to notice:
---------------------------- ----------------------------
This section is dedicated to host information related to name resolution in This section is dedicated to host information related to name resolution in
HAProxy. HAProxy. There can be as many as resolvers section as needed. Each section can
There can be as many as resolvers section as needed. Each section can contain contain many name servers.
many name servers.
When multiple name servers are configured in a resolvers section, then HAProxy When multiple name servers are configured in a resolvers section, then HAProxy
uses the first valid response. In case of invalid responses, only the last one uses the first valid response. In case of invalid responses, only the last one
@ -11750,43 +11744,40 @@ is treated. Purpose is to give the chance to a slow server to deliver a valid
answer after a fast faulty or outdated server. answer after a fast faulty or outdated server.
When each server returns a different error type, then only the last error is When each server returns a different error type, then only the last error is
used by HAProxy to decide what type of behavior to apply. used by HAProxy. The following processing is applied on this error:
Two types of behavior can be applied: 1. HAProxy retries the same DNS query with a new query type. The A queries are
1. stop DNS resolution switch to AAAA or the opposite. SRV queries are not concerned here. Timeout
2. replay the DNS query with a new query type errors are also excluded.
In such case, the following types are applied in this exact order:
1. ANY query type
2. query type corresponding to family pointed by resolve-prefer
server's parameter
3. remaining family type
HAProxy stops DNS resolution when the following errors occur: 2. When the fallback on the query type was done (or not applicable), HAProxy
- invalid DNS response packet retries the original DNS query, with the preferred query type.
- wrong name in the query section of the response
- NX domain
- Query refused by server
- CNAME not pointing to an IP address
HAProxy tries a new query type when the following errors occur: 3. HAProxy retries previous steps <resolve_retires> times. If no valid
- no Answer records in the response response is received after that, it stops the DNS resolution and reports
- DNS response truncated the error.
- Error in DNS response
- No expected DNS records found in the response
- name server timeout
For example, with 2 name servers configured in a resolvers section: For example, with 2 name servers configured in a resolvers section, the
- first response is valid and is applied directly, second response is ignored following scenarios are possible:
- first response is invalid and second one is valid, then second response is
applied; - First response is valid and is applied directly, second response is
- first response is a NX domain and second one a truncated response, then ignored
HAProxy replays the query with a new type;
- first response is truncated and second one is a NX Domain, then HAProxy - First response is invalid and second one is valid, then second response is
stops resolution. applied
- First response is a NX domain and second one a truncated response, then
HAProxy retries the query with a new type
- First response is a NX domain and second one is a timeout, then HAProxy
retries the query with a new type
- Query timed out for both name servers, then HAProxy retries it with the
same query type
As a DNS server may not answer all the IPs in one DNS request, haproxy keeps As a DNS server may not answer all the IPs in one DNS request, haproxy keeps
a cache of previous answers, an answer will be considered obsolete after a cache of previous answers, an answer will be considered obsolete after
"hold obsolete" seconds without the IP returned. <hold obsolete> seconds without the IP returned.
resolvers <resolvers id> resolvers <resolvers id>
@ -11796,7 +11787,7 @@ A resolvers section accept the following parameters:
accepted_payload_size <nb> accepted_payload_size <nb>
Defines the maxium payload size accepted by HAProxy and announced to all the Defines the maxium payload size accepted by HAProxy and announced to all the
naeservers configured in this resolvers section. name servers configured in this resolvers section.
<nb> is in bytes. If not set, HAProxy announces 512. (minimal value defined <nb> is in bytes. If not set, HAProxy announces 512. (minimal value defined
by RFC 6891) by RFC 6891)
@ -11822,11 +11813,7 @@ hold <status> <period>
Default value is 10s for "valid", 0s for "obsolete" and 30s for others. Default value is 10s for "valid", 0s for "obsolete" and 30s for others.
Note: since the name resolution is triggered by the health checks, a new resolution_pool_size <nb> (deprecated)
resolution is triggered after <period> modulo the <inter> parameter of
the healch check.
resolution_pool_size <nb>
Defines the number of resolutions available in the pool for this resolvers. Defines the number of resolutions available in the pool for this resolvers.
If not defines, it defaults to 64. If your configuration requires more than If not defines, it defaults to 64. If your configuration requires more than
<nb>, then HAProxy will return an error when parsing the configuration. <nb>, then HAProxy will return an error when parsing the configuration.
@ -11844,8 +11831,11 @@ timeout <event> <time>
Defines timeouts related to name resolution Defines timeouts related to name resolution
<event> : the event on which the <time> timeout period applies to. <event> : the event on which the <time> timeout period applies to.
events available are: events available are:
- retry: time between two DNS queries, when no response have - resolve : default time to trigger name resolutions when no
been received. other time applied.
Default value: 1s
- retry : time between two DNS queries, when no valid response
have been received.
Default value: 1s Default value: 1s
<time> : time related to the event. It follows the HAProxy time format. <time> : time related to the event. It follows the HAProxy time format.
<time> is expressed in milliseconds. <time> is expressed in milliseconds.
@ -11856,6 +11846,7 @@ timeout <event> <time>
nameserver dns1 10.0.0.1:53 nameserver dns1 10.0.0.1:53
nameserver dns2 10.0.0.2:53 nameserver dns2 10.0.0.2:53
resolve_retries 3 resolve_retries 3
timeout resolve 1s
timeout retry 1s timeout retry 1s
hold other 30s hold other 30s
hold refused 30s hold refused 30s

View File

@ -23,46 +23,26 @@
#define _PROTO_DNS_H #define _PROTO_DNS_H
#include <types/dns.h> #include <types/dns.h>
#include <types/proto_udp.h>
char *dns_str_to_dn_label(const char *string, char *dn, int dn_len); extern struct list dns_resolvers;
int dns_str_to_dn_label_len(const char *string);
void dns_dn_label_to_str(char *dn, char *str, int dn_len); struct dns_resolvers *find_resolvers_by_id(const char *id);
struct dns_srvrq *find_srvrq_by_name(const char *name, struct proxy *px);
struct dns_srvrq *new_dns_srvrq(struct server *srv, char *fqdn);
int dns_str_to_dn_label(const char *str, int str_len, char *dn, int dn_len);
int dns_dn_label_to_str(const char *dn, int dn_len, char *str, int str_len);
int dns_hostname_validation(const char *string, char **err); int dns_hostname_validation(const char *string, char **err);
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 task *dns_process_resolve(struct task *t);
int dns_init_resolvers(int close_socket);
uint16_t dns_rnd16(void);
int dns_validate_dns_response(unsigned char *resp, unsigned char *bufend, struct dns_resolution *resolution, int max_answer_records);
int dns_get_ip_from_response(struct dns_response_packet *dns_p, int dns_get_ip_from_response(struct dns_response_packet *dns_p,
struct dns_options *dns_opts, void *currentip, struct dns_options *dns_opts, void *currentip,
short currentip_sin_family, short currentip_sin_family,
void **newip, short *newip_sin_family, void **newip, short *newip_sin_family,
void *owner); void *owner);
void dns_resolve_send(struct dgram_conn *dgram);
void dns_resolve_recv(struct dgram_conn *dgram);
int dns_send_query(struct dns_resolution *resolution);
void dns_print_current_resolutions(struct dns_resolvers *resolvers);
void dns_update_resolvers_timeout(struct dns_resolvers *resolvers);
void dns_reset_resolution(struct dns_resolution *resolution);
void dns_resolution_free(struct dns_resolvers *resolvers, struct dns_resolution *resolution);
void dns_rm_requester_from_resolution(struct dns_requester *requester, struct dns_resolution *resolution);
int dns_check_resolution_queue(struct dns_resolvers *resolvers);
unsigned short dns_response_get_query_id(unsigned char *resp);
struct dns_resolution *dns_alloc_resolution(void);
void dns_free_resolution(struct dns_resolution *resolution);
struct chunk *dns_cache_key(int query_type, char *hostname_dn, int hostname_dn_len, struct chunk *buf);
struct lru64 *dns_cache_lookup(int query_type, char *hostname_dn, int hostname_dn_len, int valid_period, void *cache_domain);
int dns_link_resolution(void *requester, int requester_type, struct dns_resolution *resolution);
struct dns_resolution *dns_resolution_list_get(struct dns_resolvers *resolvers, char *hostname_dn, int query_type);
int dns_trigger_resolution(struct dns_resolution *resolution);
int dns_alloc_resolution_pool(struct dns_resolvers *resolvers);
void dump_dns_config(void); int dns_link_resolution(void *requester, int requester_type);
void dns_unlink_resolution(struct dns_requester *requester);
void dns_trigger_resolution(struct dns_requester *requester);
/*
* erases all information of a dns_requester structure
*/
#define dns_clear_requester(requester) memset(requester, '\0', sizeof(*requester));
#endif // _PROTO_DNS_H #endif // _PROTO_DNS_H

View File

@ -60,7 +60,6 @@ const char *update_server_fqdn(struct server *server, const char *fqdn, const ch
int snr_resolution_cb(struct dns_requester *requester, struct dns_nameserver *nameserver); int snr_resolution_cb(struct dns_requester *requester, struct dns_nameserver *nameserver);
int snr_resolution_error_cb(struct dns_requester *requester, int error_code); int snr_resolution_error_cb(struct dns_requester *requester, int error_code);
struct server *snr_check_ip_callback(struct server *srv, void *ip, unsigned char *ip_family); struct server *snr_check_ip_callback(struct server *srv, void *ip, unsigned char *ip_family);
void srv_free_from_resolution(struct server *srv);
/* increase the number of cumulated connections on the designated server */ /* increase the number of cumulated connections on the designated server */
static void inline srv_inc_sess_ctr(struct server *s) static void inline srv_inc_sess_ctr(struct server *s)

View File

@ -22,6 +22,17 @@
#ifndef _TYPES_DNS_H #ifndef _TYPES_DNS_H
#define _TYPES_DNS_H #define _TYPES_DNS_H
#include <eb32tree.h>
#include <common/mini-clist.h>
#include <types/connection.h>
#include <types/obj_type.h>
#include <types/proto_udp.h>
#include <types/proxy.h>
#include <types/server.h>
#include <types/task.h>
/*DNS maximum values */ /*DNS maximum values */
/* /*
* Maximum issued from RFC: * Maximum issued from RFC:
@ -33,7 +44,7 @@
#define DNS_MAX_UDP_MESSAGE 8192 #define DNS_MAX_UDP_MESSAGE 8192
/* DNS minimun record size: 1 char + 1 NULL + type + class */ /* DNS minimun record size: 1 char + 1 NULL + type + class */
#define DNS_MIN_RECORD_SIZE ( 1 + 1 + 2 + 2 ) #define DNS_MIN_RECORD_SIZE (1 + 1 + 2 + 2)
/* DNS smallest fqdn 'a.gl' size */ /* DNS smallest fqdn 'a.gl' size */
# define DNS_SMALLEST_FQDN_SIZE 4 # define DNS_SMALLEST_FQDN_SIZE 4
@ -84,9 +95,6 @@
/* DNS header size */ /* DNS header size */
#define DNS_HEADER_SIZE ((int)sizeof(struct dns_header)) #define DNS_HEADER_SIZE ((int)sizeof(struct dns_header))
/* DNS resolution pool size, per resolvers section */
#define DNS_DEFAULT_RESOLUTION_POOL_SIZE 64
/* DNS request or response header structure */ /* DNS request or response header structure */
struct dns_header { struct dns_header {
uint16_t id; uint16_t id;
@ -106,10 +114,10 @@ struct dns_question {
/* NOTE: big endian structure */ /* NOTE: big endian structure */
struct dns_query_item { struct dns_query_item {
struct list list;
char name[DNS_MAX_NAME_SIZE]; /* query name */ char name[DNS_MAX_NAME_SIZE]; /* query name */
unsigned short type; /* question type */ unsigned short type; /* question type */
unsigned short class; /* query class */ unsigned short class; /* query class */
struct list list;
}; };
/* NOTE: big endian structure */ /* NOTE: big endian structure */
@ -119,19 +127,17 @@ struct dns_additional_record {
uint16_t udp_payload_size; /* maximum size accepted for the response */ uint16_t udp_payload_size; /* maximum size accepted for the response */
uint32_t extension; /* extended rcode and flags, not used for now */ uint32_t extension; /* extended rcode and flags, not used for now */
uint16_t data_length; /* data length */ uint16_t data_length; /* data length */
/* as of today, we don't support yet edns options, that said I already put a placeholder here /* as of today, we don't support yet edns options, that said I already put a
* for this purpose. We may need to define a dns_option_record structure which itself should * placeholder here for this purpose. We may need to define a dns_option_record
* point to different type of data, based on the extension set (client subnet, tcp keepalive, * structure which itself should point to different type of data, based on the
* etc...)*/ * extension set (client subnet, tcp keepalive, etc...)*/
// struct list options; /* list of option records */ // struct list options; /* list of option records */
} __attribute__ ((packed)); } __attribute__ ((packed));
/* NOTE: big endian structure */ /* NOTE: big endian structure */
struct dns_answer_item { struct dns_answer_item {
struct list list; /*For SRV type, name also includes service and protocol value */
char name[DNS_MAX_NAME_SIZE]; /* answer name char name[DNS_MAX_NAME_SIZE]; /* answer name */
* For SRV type, name also includes service
* and protocol value */
int16_t type; /* question type */ int16_t type; /* question type */
int16_t class; /* query class */ int16_t class; /* query class */
int32_t ttl; /* response TTL */ int32_t ttl; /* response TTL */
@ -142,6 +148,7 @@ struct dns_answer_item {
struct sockaddr address; /* IPv4 or IPv6, network format */ struct sockaddr address; /* IPv4 or IPv6, network format */
char target[DNS_MAX_NAME_SIZE]; /* Response data: SRV or CNAME type target */ char target[DNS_MAX_NAME_SIZE]; /* Response data: SRV or CNAME type target */
time_t last_seen; /* When was the answer was last seen */ time_t last_seen; /* When was the answer was last seen */
struct list list;
}; };
struct dns_response_packet { struct dns_response_packet {
@ -151,23 +158,22 @@ struct dns_response_packet {
/* authority and additional_information ignored for now */ /* authority and additional_information ignored for now */
}; };
/* /* Resolvers section and parameters. It is linked to the name servers
* resolvers section and parameters. It is linked to the name servers
* servers points to it. * servers points to it.
* current resolution are stored in a FIFO list. * current resolution are stored in a FIFO list.
*/ */
struct dns_resolvers { struct dns_resolvers {
struct list list; /* resolvers list */
char *id; /* resolvers unique identifier */ char *id; /* resolvers unique identifier */
struct { struct {
const char *file; /* file where the section appears */ const char *file; /* file where the section appears */
int line; /* line where the section appears */ int line; /* line where the section appears */
} conf; /* config information */ } conf; /* config information */
struct list nameserver_list; /* dns server list */ struct list nameservers; /* dns server list */
unsigned int accepted_payload_size; /* maximum payload size we accept for responses */ unsigned int accepted_payload_size; /* maximum payload size we accept for responses */
int count_nameservers; /* total number of nameservers in a resolvers section */ int nb_nameservers; /* total number of active nameservers in a resolvers section */
int resolve_retries; /* number of retries before giving up */ int resolve_retries; /* number of retries before giving up */
struct { /* time to: */ struct { /* time to: */
int resolve; /* wait between 2 queries for the same resolution */
int retry; /* wait for a response before retrying */ int retry; /* wait for a response before retrying */
} timeout; } timeout;
struct { /* time to hold current data when */ struct { /* time to hold current data when */
@ -179,47 +185,48 @@ struct dns_resolvers {
int obsolete; /* an answer hasn't been seen */ int obsolete; /* an answer hasn't been seen */
} hold; } hold;
struct task *t; /* timeout management */ struct task *t; /* timeout management */
int resolution_pool_size; /* size of the resolution pool associated to this resolvers section */
struct { struct {
struct list pool; /* resolution pool dedicated to this resolvers section */
struct list wait; /* resolutions managed to this resolvers section */ struct list wait; /* resolutions managed to this resolvers section */
struct list curr; /* current running resolutions */ struct list curr; /* current running resolutions */
} resolution; } resolutions;
struct eb_root query_ids; /* tree to quickly lookup/retrieve query ids currently in use */ struct eb_root query_ids; /* tree to quickly lookup/retrieve query ids currently in use
/* used by each nameserver, but stored in resolvers since there must */ * used by each nameserver, but stored in resolvers since there must
/* be a unique relation between an eb_root and an eb_node (resolution) */ * be a unique relation between an eb_root and an eb_node (resolution) */
struct list list; /* resolvers list */
}; };
/* /* Structure describing a name server used during name resolution.
* structure describing a name server used during name resolution.
* A name server belongs to a resolvers section. * A name server belongs to a resolvers section.
*/ */
struct dns_nameserver { struct dns_nameserver {
struct list list; /* nameserver chained list */
char *id; /* nameserver unique identifier */ char *id; /* nameserver unique identifier */
struct { struct {
const char *file; /* file where the section appears */ const char *file; /* file where the section appears */
int line; /* line where the section appears */ int line; /* line where the section appears */
} conf; /* config information */ } conf; /* config information */
struct dns_resolvers *resolvers; struct dns_resolvers *resolvers;
struct dgram_conn *dgram; /* transport layer */ struct dgram_conn *dgram; /* transport layer */
struct sockaddr_storage addr; /* IP address */ struct sockaddr_storage addr; /* IP address */
struct { /* numbers relted to this name server: */ struct { /* numbers relted to this name server: */
long int sent; /* - queries sent */ long long sent; /* - queries sent */
long int valid; /* - valid response */ long long snd_error; /* - sending errors */
long int update; /* - valid response used to update server's IP */ long long valid; /* - valid response */
long int cname; /* - CNAME response requiring new resolution */ long long update; /* - valid response used to update server's IP */
long int cname_error; /* - error when resolving CNAMEs */ long long cname; /* - CNAME response requiring new resolution */
long int any_err; /* - void response (usually because ANY qtype) */ long long cname_error; /* - error when resolving CNAMEs */
long int nx; /* - NX response */ long long any_err; /* - void response (usually because ANY qtype) */
long int timeout; /* - queries which reached timeout */ long long nx; /* - NX response */
long int refused; /* - queries refused */ long long timeout; /* - queries which reached timeout */
long int other; /* - other type of response */ long long refused; /* - queries refused */
long int invalid; /* - malformed DNS response */ long long other; /* - other type of response */
long int too_big; /* - too big response */ long long invalid; /* - malformed DNS response */
long int outdated; /* - outdated response (server slower than the other ones) */ long long too_big; /* - too big response */
long int truncated; /* - truncated response */ long long outdated; /* - outdated response (server slower than the other ones) */
long long truncated; /* - truncated response */
} counters; } counters;
struct list list; /* nameserver chained list */
}; };
struct dns_options { struct dns_options {
@ -238,55 +245,48 @@ struct dns_options {
int pref_net_nb; /* The number of registered prefered networks. */ int pref_net_nb; /* The number of registered prefered networks. */
}; };
/* /* Resolution structure associated to single server and used to manage name
* resolution structure associated to single server and used to manage name resolution for * resolution for this server.
* this server. * The only link between the resolution and a nameserver is through the
* The only link between the resolution and a nameserver is through the query_id. * query_id.
*/ */
struct dns_resolution { struct dns_resolution {
struct list list; /* resolution list */ struct dns_resolvers *resolvers; /* pointer to the resolvers structure owning the resolution */
struct { struct list requesters; /* list of requesters using this resolution */
struct list wait; /* list of standby requesters for this resolution */
struct list curr; /* list of requesters currently active on this resolution */
} requester;
int (*requester_cb)(struct dns_resolution *, struct dns_nameserver *);
/* requester callback for valid response */
int (*requester_error_cb)(struct dns_resolution *, int);
/* requester callback, for error management */
int uuid; /* unique id (used for debugging purpose) */ int uuid; /* unique id (used for debugging purpose) */
char *hostname_dn; /* server hostname in domain name label format */ char *hostname_dn; /* server hostname in domain name label format */
int hostname_dn_len; /* server domain name label len */ int hostname_dn_len; /* server domain name label len */
unsigned int last_resolution; /* time of the lastest valid resolution */ unsigned int last_resolution; /* time of the last resolution */
unsigned int last_sent_packet; /* time of the latest DNS packet sent */ unsigned int last_query; /* time of the last query sent */
unsigned int last_status_change; /* time of the latest DNS resolution status change */ unsigned int last_valid; /* time of the last valid response */
int query_id; /* DNS query ID dedicated for this resolution */ int query_id; /* DNS query ID dedicated for this resolution */
struct eb32_node qid; /* ebtree query id */ struct eb32_node qid; /* ebtree query id */
int query_type; int prefered_query_type; /* prefered query type */
/* query type to send. By default DNS_RTYPE_A or DNS_RTYPE_AAAA depending on resolver_family_priority */ int query_type; /* current query type */
int status; /* status of the resolution being processed RSLV_STATUS_* */ int status; /* status of the resolution being processed RSLV_STATUS_* */
int step; /* */ int step; /* RSLV_STEP_* */
int try; /* current resolution try */ int try; /* current resolution try */
int try_cname; /* number of CNAME requests sent */ int nb_queries; /* count number of queries sent */
int nb_responses; /* count number of responses received */ int nb_responses; /* count number of responses received */
unsigned long long revision; /* updated for each update */
struct dns_response_packet response; /* structure hosting the DNS response */ struct dns_response_packet response; /* structure hosting the DNS response */
struct dns_query_item response_query_records[DNS_MAX_QUERY_RECORDS]; /* <response> query records */ struct dns_query_item response_query_records[DNS_MAX_QUERY_RECORDS]; /* <response> query records */
struct list list; /* resolution list */
}; };
/* /* Structure used to describe the owner of a DNS resolution. */
* structure used to describe the owner of a DNS resolution.
*/
struct dns_requester { struct dns_requester {
enum obj_type *owner; /* pointer to the owner (server or dns_srvrq) */
struct dns_resolution *resolution; /* pointer to the owned DNS resolution */
int (*requester_cb)(struct dns_requester *, struct dns_nameserver *); /* requester callback for valid response */
int (*requester_error_cb)(struct dns_requester *, int); /* requester callback, for error management */
struct list list; /* requester list */ struct list list; /* requester list */
enum obj_type *requester; /* pointer to the requester */
int prefered_query_type; /* prefered query type */
int (*requester_cb)(struct dns_requester *, struct dns_nameserver *);
/* requester callback for valid response */
int (*requester_error_cb)(struct dns_requester *, int);
/* requester callback, for error management */
}; };
/* last resolution status code */ /* Last resolution status code */
enum { enum {
RSLV_STATUS_NONE = 0, /* no resolution occured yet */ RSLV_STATUS_NONE = 0, /* no resolution occured yet */
RSLV_STATUS_VALID, /* no error */ RSLV_STATUS_VALID, /* no error */
@ -298,13 +298,13 @@ enum {
RSLV_STATUS_OTHER, /* other errors */ RSLV_STATUS_OTHER, /* other errors */
}; };
/* current resolution step */ /* Current resolution step */
enum { enum {
RSLV_STEP_NONE = 0, /* nothing happening currently */ RSLV_STEP_NONE = 0, /* nothing happening currently */
RSLV_STEP_RUNNING, /* resolution is running */ RSLV_STEP_RUNNING, /* resolution is running */
}; };
/* return codes after analyzing a DNS response */ /* Return codes after analyzing a DNS response */
enum { enum {
DNS_RESP_VALID = 0, /* valid response */ DNS_RESP_VALID = 0, /* valid response */
DNS_RESP_INVALID, /* invalid response (various type of errors can trigger it) */ DNS_RESP_INVALID, /* invalid response (various type of errors can trigger it) */
@ -321,7 +321,9 @@ enum {
DNS_RESP_INTERNAL, /* internal resolver error */ DNS_RESP_INTERNAL, /* internal resolver error */
}; };
/* return codes after searching an IP in a DNS response buffer, using a family preference */ /* Return codes after searching an IP in a DNS response buffer, using a family
* preference
*/
enum { enum {
DNS_UPD_NO = 1, /* provided IP was found and preference is matched DNS_UPD_NO = 1, /* provided IP was found and preference is matched
* OR provided IP found and preference is not matched, but no IP * OR provided IP found and preference is not matched, but no IP
@ -338,15 +340,11 @@ enum {
struct dns_srvrq { struct dns_srvrq {
enum obj_type obj_type; /* object type == OBJ_TYPE_SRVRQ */ enum obj_type obj_type; /* object type == OBJ_TYPE_SRVRQ */
struct dns_resolvers *resolvers; /* pointer to the resolvers structure used for this server template */ struct dns_resolvers *resolvers; /* pointer to the resolvers structure used for this server template */
struct dns_resolution *resolution; /* server name resolution */
struct proxy *proxy; /* associated proxy */ struct proxy *proxy; /* associated proxy */
char *name; char *name;
char *hostname_dn; /* server hostname in Domain Name format */ char *hostname_dn; /* server hostname in Domain Name format */
int hostname_dn_len; /* string length of the server hostname in Domain Name format */ int hostname_dn_len; /* string length of the server hostname in Domain Name format */
struct dns_requester *dns_requester; /* used to link to its DNS resolution */ struct dns_requester *dns_requester; /* used to link to its DNS resolution */
int inter; /* time in ms */
struct list list; /* Next SRV RQ for the same proxy */ struct list list; /* Next SRV RQ for the same proxy */
}; };

View File

@ -183,7 +183,6 @@ extern char localpeer[MAX_HOSTNAME_LEN];
extern struct list global_listener_queue; /* list of the temporarily limited listeners */ extern struct list global_listener_queue; /* list of the temporarily limited listeners */
extern struct task *global_listener_queue_task; extern struct task *global_listener_queue_task;
extern unsigned int warned; /* bitfield of a few warnings to emit just once */ extern unsigned int warned; /* bitfield of a few warnings to emit just once */
extern struct list dns_resolvers;
/* bit values to go with "warned" above */ /* bit values to go with "warned" above */
#define WARN_BLOCK_DEPRECATED 0x00000001 #define WARN_BLOCK_DEPRECATED 0x00000001

View File

@ -438,7 +438,6 @@ struct proxy {
* name is used * name is used
*/ */
struct list filter_configs; /* list of the filters that are declared on this proxy */ struct list filter_configs; /* list of the filters that are declared on this proxy */
struct list srvrq_list; /* List of SRV requests associated with this proxy */
}; };
struct switching_rule { struct switching_rule {

View File

@ -262,7 +262,6 @@ struct server {
char *hostname_dn; /* server hostname in Domain Name format */ char *hostname_dn; /* server hostname in Domain Name format */
int hostname_dn_len; /* sting lenght of the server hostname in Domain Name format */ int hostname_dn_len; /* sting lenght of the server hostname in Domain Name format */
char *lastaddr; /* the address string provided by the server-state file */ char *lastaddr; /* the address string provided by the server-state file */
struct dns_resolution *resolution; /* server name resolution */
struct dns_options dns_opts; struct dns_options dns_opts;
struct sockaddr_storage init_addr; /* plain IP address specified on the init-addr line */ struct sockaddr_storage init_addr; /* plain IP address specified on the init-addr line */
unsigned int init_addr_methods; /* initial address setting, 3-bit per method, ends at 0, enough to store 10 entries */ unsigned int init_addr_methods; /* initial address setting, 3-bit per method, ends at 0, enough to store 10 entries */

View File

@ -2149,14 +2149,13 @@ int cfg_parse_resolvers(const char *file, int linenum, char **args, int kwm)
curr_resolvers->hold.obsolete = 0; curr_resolvers->hold.obsolete = 0;
/* default hold period for valid is 10s */ /* default hold period for valid is 10s */
curr_resolvers->hold.valid = 10000; curr_resolvers->hold.valid = 10000;
curr_resolvers->timeout.resolve = 1000;
curr_resolvers->timeout.retry = 1000; curr_resolvers->timeout.retry = 1000;
curr_resolvers->resolve_retries = 3; curr_resolvers->resolve_retries = 3;
/* default resolution pool size */ curr_resolvers->nb_nameservers = 0;
curr_resolvers->resolution_pool_size = DNS_DEFAULT_RESOLUTION_POOL_SIZE; LIST_INIT(&curr_resolvers->nameservers);
LIST_INIT(&curr_resolvers->nameserver_list); LIST_INIT(&curr_resolvers->resolutions.curr);
LIST_INIT(&curr_resolvers->resolution.curr); LIST_INIT(&curr_resolvers->resolutions.wait);
LIST_INIT(&curr_resolvers->resolution.wait);
LIST_INIT(&curr_resolvers->resolution.pool);
} }
else if (strcmp(args[0], "nameserver") == 0) { /* nameserver definition */ else if (strcmp(args[0], "nameserver") == 0) { /* nameserver definition */
struct sockaddr_storage *sk; struct sockaddr_storage *sk;
@ -2178,7 +2177,7 @@ int cfg_parse_resolvers(const char *file, int linenum, char **args, int kwm)
goto out; goto out;
} }
list_for_each_entry(newnameserver, &curr_resolvers->nameserver_list, list) { list_for_each_entry(newnameserver, &curr_resolvers->nameservers, list) {
/* Error if two resolvers owns the same name */ /* Error if two resolvers owns the same name */
if (strcmp(newnameserver->id, args[1]) == 0) { if (strcmp(newnameserver->id, args[1]) == 0) {
Alert("Parsing [%s:%d]: nameserver '%s' has same name as another nameserver (declared at %s:%d).\n", Alert("Parsing [%s:%d]: nameserver '%s' has same name as another nameserver (declared at %s:%d).\n",
@ -2194,8 +2193,7 @@ int cfg_parse_resolvers(const char *file, int linenum, char **args, int kwm)
} }
/* the nameservers are linked backward first */ /* the nameservers are linked backward first */
LIST_ADDQ(&curr_resolvers->nameserver_list, &newnameserver->list); LIST_ADDQ(&curr_resolvers->nameservers, &newnameserver->list);
curr_resolvers->count_nameservers++;
newnameserver->resolvers = curr_resolvers; newnameserver->resolvers = curr_resolvers;
newnameserver->conf.file = strdup(file); newnameserver->conf.file = strdup(file);
newnameserver->conf.line = linenum; newnameserver->conf.line = linenum;
@ -2291,14 +2289,11 @@ int cfg_parse_resolvers(const char *file, int linenum, char **args, int kwm)
curr_resolvers->accepted_payload_size = i; curr_resolvers->accepted_payload_size = i;
} }
else if (strcmp(args[0], "resolution_pool_size") == 0) { else if (strcmp(args[0], "resolution_pool_size") == 0) {
if (!*args[1]) { Warning("parsing [%s:%d] : '%s' directive is now deprecated and ignored.\n",
Alert("parsing [%s:%d] : '%s' expects <nb> as argument.\n",
file, linenum, args[0]); file, linenum, args[0]);
err_code |= ERR_ALERT | ERR_FATAL; err_code |= ERR_WARN;
goto out; goto out;
} }
curr_resolvers->resolution_pool_size = atoi(args[1]);
}
else if (strcmp(args[0], "resolve_retries") == 0) { else if (strcmp(args[0], "resolve_retries") == 0) {
if (!*args[1]) { if (!*args[1]) {
Alert("parsing [%s:%d] : '%s' expects <nb> as argument.\n", Alert("parsing [%s:%d] : '%s' expects <nb> as argument.\n",
@ -2310,14 +2305,15 @@ int cfg_parse_resolvers(const char *file, int linenum, char **args, int kwm)
} }
else if (strcmp(args[0], "timeout") == 0) { else if (strcmp(args[0], "timeout") == 0) {
if (!*args[1]) { if (!*args[1]) {
Alert("parsing [%s:%d] : '%s' expects 'retry' and <time> as arguments.\n", Alert("parsing [%s:%d] : '%s' expects 'retry' or 'resolve' and <time> as arguments.\n",
file, linenum, args[0]); file, linenum, args[0]);
err_code |= ERR_ALERT | ERR_FATAL; err_code |= ERR_ALERT | ERR_FATAL;
goto out; goto out;
} }
else if (strcmp(args[1], "retry") == 0) { else if (strcmp(args[1], "retry") == 0 ||
strcmp(args[1], "resolve") == 0) {
const char *res; const char *res;
unsigned int timeout_retry; unsigned int tout;
if (!*args[2]) { if (!*args[2]) {
Alert("parsing [%s:%d] : '%s %s' expects <time> as argument.\n", Alert("parsing [%s:%d] : '%s %s' expects <time> as argument.\n",
@ -2325,17 +2321,20 @@ int cfg_parse_resolvers(const char *file, int linenum, char **args, int kwm)
err_code |= ERR_ALERT | ERR_FATAL; err_code |= ERR_ALERT | ERR_FATAL;
goto out; goto out;
} }
res = parse_time_err(args[2], &timeout_retry, TIME_UNIT_MS); res = parse_time_err(args[2], &tout, TIME_UNIT_MS);
if (res) { if (res) {
Alert("parsing [%s:%d]: unexpected character '%c' in argument to <%s %s>.\n", Alert("parsing [%s:%d]: unexpected character '%c' in argument to <%s %s>.\n",
file, linenum, *res, args[0], args[1]); file, linenum, *res, args[0], args[1]);
err_code |= ERR_ALERT | ERR_FATAL; err_code |= ERR_ALERT | ERR_FATAL;
goto out; goto out;
} }
curr_resolvers->timeout.retry = timeout_retry; if (args[1][2] == 't')
curr_resolvers->timeout.retry = tout;
else
curr_resolvers->timeout.resolve = tout;
} }
else { else {
Alert("parsing [%s:%d] : '%s' expects 'retry' and <time> as arguments got '%s'.\n", Alert("parsing [%s:%d] : '%s' expects 'retry' or 'resolve' and <time> as arguments got '%s'.\n",
file, linenum, args[0], args[1]); file, linenum, args[0], args[1]);
err_code |= ERR_ALERT | ERR_FATAL; err_code |= ERR_ALERT | ERR_FATAL;
goto out; goto out;
@ -7394,7 +7393,6 @@ int check_config_validity()
unsigned int next_pxid = 1; unsigned int next_pxid = 1;
struct bind_conf *bind_conf; struct bind_conf *bind_conf;
char *err; char *err;
struct dns_resolvers *curr_resolvers;
struct cfg_postparser *postparser; struct cfg_postparser *postparser;
bind_conf = NULL; bind_conf = NULL;
@ -7418,15 +7416,6 @@ int check_config_validity()
pool2_capture = create_pool("capture", global.tune.cookie_len, MEM_F_SHARED); pool2_capture = create_pool("capture", global.tune.cookie_len, MEM_F_SHARED);
/* allocate pool of resolution per resolvers */
list_for_each_entry(curr_resolvers, &dns_resolvers, list) {
if (dns_alloc_resolution_pool(curr_resolvers) != 0) {
/* error message is already displayed by dns_alloc_resolution_pool() */
err_code |= ERR_ALERT | ERR_ABORT;
goto out;
}
}
/* Post initialisation of the users and groups lists. */ /* Post initialisation of the users and groups lists. */
err_code = userlist_postinit(); err_code = userlist_postinit();
if (err_code != ERR_NONE) if (err_code != ERR_NONE)
@ -8362,64 +8351,6 @@ int check_config_validity()
newsrv->trackit = NULL; newsrv->trackit = NULL;
} }
/*
* resolve server's resolvers name and update the resolvers pointer
* accordingly
*/
if (newsrv->resolvers_id) {
struct dns_resolvers *curr_resolvers;
int found;
found = 0;
list_for_each_entry(curr_resolvers, &dns_resolvers, list) {
if (!strcmp(curr_resolvers->id, newsrv->resolvers_id)) {
found = 1;
break;
}
}
if (!found) {
Alert("config : %s '%s', server '%s': unable to find required resolvers '%s'\n",
proxy_type_str(curproxy), curproxy->id,
newsrv->id, newsrv->resolvers_id);
cfgerr++;
} else {
if (newsrv->srvrq) {
if (!newsrv->srvrq->resolvers) {
newsrv->srvrq->resolvers = curr_resolvers;
if (dns_link_resolution(newsrv->srvrq,
OBJ_TYPE_SRVRQ, NULL) != 0) {
Alert("config : %s '%s', server '%s': unable to set DNS resolution\n",
proxy_type_str(curproxy), curproxy->id,
newsrv->id);
cfgerr++;
}
}
}
if (newsrv->srvrq || newsrv->hostname_dn) {
newsrv->resolvers = curr_resolvers;
if (dns_link_resolution(newsrv, OBJ_TYPE_SERVER, NULL) != 0) {
Alert("config : %s '%s', server '%s': unable to set DNS resolution\n",
proxy_type_str(curproxy), curproxy->id,
newsrv->id);
cfgerr++;
}
}
}
}
else {
/* if no resolvers section associated to this server
* we can clean up the associated resolution structure
*/
if (newsrv->resolution) {
free(newsrv->resolution->hostname_dn);
newsrv->resolution->hostname_dn = NULL;
free(newsrv->resolution);
newsrv->resolution = NULL;
}
}
next_srv: next_srv:
newsrv = newsrv->next; newsrv = newsrv->next;
} }

View File

@ -667,8 +667,7 @@ static void chk_report_conn_err(struct check *check, int errno_bck, int expired)
* might be due to a server IP change. * might be due to a server IP change.
* Let's trigger a DNS resolution if none are currently running. * Let's trigger a DNS resolution if none are currently running.
*/ */
if ((check->server->resolution) && (check->server->resolution->step == RSLV_STEP_NONE)) dns_trigger_resolution(check->server->dns_requester);
dns_trigger_resolution(check->server->resolution);
} }
else if ((conn->flags & (CO_FL_CONNECTED|CO_FL_WAIT_L6_CONN)) == CO_FL_WAIT_L6_CONN) { else if ((conn->flags & (CO_FL_CONNECTED|CO_FL_WAIT_L6_CONN)) == CO_FL_WAIT_L6_CONN) {

3135
src/dns.c

File diff suppressed because it is too large Load Diff

View File

@ -1766,10 +1766,6 @@ static void init(int argc, char **argv)
if (!hlua_post_init()) if (!hlua_post_init())
exit(1); exit(1);
/* initialize structures for name resolution */
if (!dns_init_resolvers(0))
exit(1);
free(err_msg); free(err_msg);
} }
@ -2025,6 +2021,7 @@ void deinit(void)
free(s->agent.bi); free(s->agent.bi);
free(s->agent.bo); free(s->agent.bo);
free(s->agent.send_string); free(s->agent.send_string);
free(s->hostname_dn);
free((char*)s->conf.file); free((char*)s->conf.file);
if (s->use_ssl || s->check.use_ssl) { if (s->use_ssl || s->check.use_ssl) {
@ -2698,10 +2695,6 @@ int main(int argc, char **argv)
fork_poller(); fork_poller();
} }
/* initialize structures for name resolution */
if (!dns_init_resolvers(1))
exit(1);
if (global.mode & MODE_MWORKER) if (global.mode & MODE_MWORKER)
mworker_pipe_register(mworker_pipe); mworker_pipe_register(mworker_pipe);

View File

@ -754,7 +754,6 @@ void init_new_proxy(struct proxy *p)
LIST_INIT(&p->conf.args.list); LIST_INIT(&p->conf.args.list);
LIST_INIT(&p->tcpcheck_rules); LIST_INIT(&p->tcpcheck_rules);
LIST_INIT(&p->filter_configs); LIST_INIT(&p->filter_configs);
LIST_INIT(&p->srvrq_list);
/* Timeouts are defined as -1 */ /* Timeouts are defined as -1 */
proxy_reset_timeouts(p); proxy_reset_timeouts(p);

View File

@ -1375,70 +1375,36 @@ static void srv_ssl_settings_cpy(struct server *srv, struct server *src)
*/ */
static int srv_prepare_for_resolution(struct server *srv, const char *hostname) static int srv_prepare_for_resolution(struct server *srv, const char *hostname)
{ {
char *hostname_dn;
int hostname_len, hostname_dn_len;
if (!hostname) if (!hostname)
return 0; return 0;
free(srv->hostname); hostname_len = strlen(hostname);
srv->hostname = strdup(hostname); hostname_dn = trash.str;
hostname_dn_len = dns_str_to_dn_label(hostname, hostname_len + 1,
srv->hostname_dn_len = dns_str_to_dn_label_len(hostname); hostname_dn, trash.size);
srv->hostname_dn = calloc(srv->hostname_dn_len + 1, sizeof(char)); if (hostname_dn_len == -1)
if (!srv->hostname || !srv->hostname_dn)
goto err; goto err;
if (!dns_str_to_dn_label(srv->hostname,
srv->hostname_dn, free(srv->hostname);
srv->hostname_dn_len + 1)) free(srv->hostname_dn);
srv->hostname = strdup(hostname);
srv->hostname_dn = strdup(hostname_dn);
srv->hostname_dn_len = hostname_dn_len;
if (!srv->hostname || !srv->hostname_dn)
goto err; goto err;
return 0; return 0;
err: err:
free(srv->hostname); free(srv->hostname); srv->hostname = NULL;
srv->hostname = NULL; free(srv->hostname_dn); srv->hostname_dn = NULL;
free(srv->hostname_dn);
srv->hostname_dn = NULL;
return -1; return -1;
} }
/*
* Free the link between a server and its resolution.
* It also performs the following tasks:
* - check if resolution can be moved back in the resolvers' pool
* (and do it)
* - move resolution's hostname_dn and hostname_dn_len to the next requester
* available (when applied)
*/
void srv_free_from_resolution(struct server *srv)
{
struct dns_requester *requester;
int count;
/* check if we can move the resolution back to the pool.
* if <count> is greater than 1, then we can't */
count = 0;
list_for_each_entry(requester, &srv->resolution->requester.wait, list) {
++count;
if (count > 1)
break;
}
list_for_each_entry(requester, &srv->resolution->requester.curr, list) {
++count;
if (count > 1)
break;
}
if (count <= 1) {
/* move the resolution back to the pool */
dns_resolution_free(srv->resolvers, srv->resolution);
return;
}
dns_rm_requester_from_resolution(srv->dns_requester, srv->resolution);
return;
}
/* /*
* Copy <src> server settings to <srv> server allocating * Copy <src> server settings to <srv> server allocating
* everything needed. * everything needed.
@ -2006,57 +1972,16 @@ int parse_server(const char *file, int linenum, char **args, struct proxy *curpr
/* save hostname and create associated name resolution */ /* save hostname and create associated name resolution */
if (fqdn) { if (fqdn) {
if (fqdn[0] == '_') { if (fqdn[0] == '_') { /* SRV record */
struct dns_srvrq *srvrq = NULL;
int found = 0;
/* SRV record */
/* Check if a SRV request already exists, and if not, create it */ /* Check if a SRV request already exists, and if not, create it */
list_for_each_entry(srvrq, &curproxy->srvrq_list, list) { if ((newsrv->srvrq = find_srvrq_by_name(fqdn, curproxy)) == NULL)
if (!strcmp(srvrq->name, fqdn)) { newsrv->srvrq = new_dns_srvrq(newsrv, fqdn);
found = 1; if (newsrv->srvrq == NULL) {
break; err_code |= ERR_ALERT | ERR_FATAL;
}
}
if (found == 0) {
int hostname_dn_len;
srvrq = calloc(1, sizeof(*srvrq));
if (!srvrq) {
Alert("Failed to allocate memory");
err_code = ERR_ALERT | ERR_FATAL;
goto out; goto out;
} }
srvrq->obj_type = OBJ_TYPE_SRVRQ;
srvrq->proxy = proxy;
srvrq->name = strdup(fqdn);
srvrq->inter = 2000;
hostname_dn_len = dns_str_to_dn_label_len(fqdn);
if (hostname_dn_len == -1) {
Alert("Failed to parse domaine name '%s'", fqdn);
err_code = ERR_ALERT | ERR_FATAL;
goto out;
} }
srvrq->hostname_dn = malloc(hostname_dn_len + 1); else if (srv_prepare_for_resolution(newsrv, fqdn) == -1) {
srvrq->hostname_dn_len = hostname_dn_len;
if (!srvrq->hostname_dn) {
Alert("Failed to alloc memory");
err_code = ERR_ALERT | ERR_FATAL;
goto out;
}
if (!dns_str_to_dn_label(fqdn,
srvrq->hostname_dn,
hostname_dn_len + 1)) {
Alert("Failed to parse domain name '%s'", fqdn);
err_code = ERR_ALERT | ERR_FATAL;
goto out;
}
LIST_ADDQ(&proxy->srvrq_list, &srvrq->list);
}
newsrv->srvrq = srvrq;
} else if (srv_prepare_for_resolution(newsrv, fqdn) == -1) {
Alert("parsing [%s:%d] : Can't create DNS resolution for server '%s'\n", Alert("parsing [%s:%d] : Can't create DNS resolution for server '%s'\n",
file, linenum, newsrv->id); file, linenum, newsrv->id);
err_code |= ERR_ALERT | ERR_FATAL; err_code |= ERR_ALERT | ERR_FATAL;
@ -2299,8 +2224,6 @@ int parse_server(const char *file, int linenum, char **args, struct proxy *curpr
goto out; goto out;
} }
newsrv->check.inter = val; newsrv->check.inter = val;
if (newsrv->srvrq)
newsrv->srvrq->inter = val;
cur_arg += 2; cur_arg += 2;
} }
else if (!strcmp(args[cur_arg], "fastinter")) { else if (!strcmp(args[cur_arg], "fastinter")) {
@ -3531,8 +3454,9 @@ const char *update_server_addr_port(struct server *s, const char *addr, const ch
*/ */
int snr_update_srv_status(struct server *s, int has_no_ip) int snr_update_srv_status(struct server *s, int has_no_ip)
{ {
struct dns_resolution *resolution = s->resolution;
struct dns_resolvers *resolvers = s->resolvers; struct dns_resolvers *resolvers = s->resolvers;
struct dns_resolution *resolution = s->dns_requester->resolution;
int exp;
switch (resolution->status) { switch (resolution->status) {
case RSLV_STATUS_NONE: case RSLV_STATUS_NONE:
@ -3550,8 +3474,9 @@ int snr_update_srv_status(struct server *s, int has_no_ip)
return 1; return 1;
srv_set_admin_flag(s, SRV_ADMF_RMAINT, srv_set_admin_flag(s, SRV_ADMF_RMAINT,
"No IP for server "); "No IP for server ");
return (0); return 0;
} }
if (!(s->next_admin & SRV_ADMF_RMAINT)) if (!(s->next_admin & SRV_ADMF_RMAINT))
return 1; return 1;
srv_clr_admin_flag(s, SRV_ADMF_RMAINT); srv_clr_admin_flag(s, SRV_ADMF_RMAINT);
@ -3564,44 +3489,48 @@ int snr_update_srv_status(struct server *s, int has_no_ip)
case RSLV_STATUS_NX: case RSLV_STATUS_NX:
/* stop server if resolution is NX for a long enough period */ /* stop server if resolution is NX for a long enough period */
if (tick_is_expired(tick_add(resolution->last_status_change, resolvers->hold.nx), now_ms)) { exp = tick_add(resolution->last_valid, resolvers->hold.nx);
if (!tick_is_expired(exp, now_ms))
break;
if (s->next_admin & SRV_ADMF_RMAINT) if (s->next_admin & SRV_ADMF_RMAINT)
return 1; return 1;
srv_set_admin_flag(s, SRV_ADMF_RMAINT, "DNS NX status"); srv_set_admin_flag(s, SRV_ADMF_RMAINT, "DNS NX status");
return 0; return 0;
}
break;
case RSLV_STATUS_TIMEOUT: case RSLV_STATUS_TIMEOUT:
/* stop server if resolution is TIMEOUT for a long enough period */ /* stop server if resolution is TIMEOUT for a long enough period */
if (tick_is_expired(tick_add(resolution->last_status_change, resolvers->hold.timeout), now_ms)) { exp = tick_add(resolution->last_valid, resolvers->hold.timeout);
if (!tick_is_expired(exp, now_ms))
break;
if (s->next_admin & SRV_ADMF_RMAINT) if (s->next_admin & SRV_ADMF_RMAINT)
return 1; return 1;
srv_set_admin_flag(s, SRV_ADMF_RMAINT, "DNS timeout status"); srv_set_admin_flag(s, SRV_ADMF_RMAINT, "DNS timeout status");
return 0; return 0;
}
break;
case RSLV_STATUS_REFUSED: case RSLV_STATUS_REFUSED:
/* stop server if resolution is REFUSED for a long enough period */ /* stop server if resolution is REFUSED for a long enough period */
if (tick_is_expired(tick_add(resolution->last_status_change, resolvers->hold.refused), now_ms)) { exp = tick_add(resolution->last_valid, resolvers->hold.refused);
if (!tick_is_expired(exp, now_ms))
break;
if (s->next_admin & SRV_ADMF_RMAINT) if (s->next_admin & SRV_ADMF_RMAINT)
return 1; return 1;
srv_set_admin_flag(s, SRV_ADMF_RMAINT, "DNS refused status"); srv_set_admin_flag(s, SRV_ADMF_RMAINT, "DNS refused status");
return 0; return 0;
}
break;
default: default:
/* stop server if resolution is in unmatched error for a long enough period */ /* stop server if resolution failed for a long enough period */
if (tick_is_expired(tick_add(resolution->last_status_change, resolvers->hold.other), now_ms)) { exp = tick_add(resolution->last_valid, resolvers->hold.other);
if (!tick_is_expired(exp, now_ms))
break;
if (s->next_admin & SRV_ADMF_RMAINT) if (s->next_admin & SRV_ADMF_RMAINT)
return 1; return 1;
srv_set_admin_flag(s, SRV_ADMF_RMAINT, "unspecified DNS error"); srv_set_admin_flag(s, SRV_ADMF_RMAINT, "unspecified DNS error");
return 0; return 0;
} }
break;
}
return 1; return 1;
} }
@ -3629,11 +3558,11 @@ int snr_resolution_cb(struct dns_requester *requester, struct dns_nameserver *na
struct chunk *chk = get_trash_chunk(); struct chunk *chk = get_trash_chunk();
int has_no_ip = 0; int has_no_ip = 0;
s = objt_server(requester->requester); s = objt_server(requester->owner);
if (!s) if (!s)
return 1; return 1;
resolution = s->resolution; resolution = s->dns_requester->resolution;
/* initializing variables */ /* initializing variables */
firstip = NULL; /* pointer to the first valid response found */ firstip = NULL; /* pointer to the first valid response found */
@ -3678,14 +3607,8 @@ int snr_resolution_cb(struct dns_requester *requester, struct dns_nameserver *na
goto update_status; goto update_status;
case DNS_UPD_NAME_ERROR: case DNS_UPD_NAME_ERROR:
/* if this is not the last expected response, we ignore it */
if (nameserver && (resolution->nb_responses < nameserver->resolvers->count_nameservers))
return 0;
/* update resolution status to OTHER error type */ /* update resolution status to OTHER error type */
if (resolution->status != RSLV_STATUS_OTHER) {
resolution->status = RSLV_STATUS_OTHER; resolution->status = RSLV_STATUS_OTHER;
resolution->last_status_change = now_ms;
}
goto update_status; goto update_status;
default: default:
@ -3694,12 +3617,11 @@ int snr_resolution_cb(struct dns_requester *requester, struct dns_nameserver *na
} }
save_ip: save_ip:
if (nameserver) if (nameserver) {
nameserver->counters.update += 1; nameserver->counters.update++;
/* save the first ip we found */ /* save the first ip we found */
if (nameserver)
chunk_printf(chk, "%s/%s", nameserver->resolvers->id, nameserver->id); chunk_printf(chk, "%s/%s", nameserver->resolvers->id, nameserver->id);
}
else else
chunk_printf(chk, "DNS cache"); chunk_printf(chk, "DNS cache");
update_server_addr(s, firstip, firstip_sin_family, (char *)chk->str); update_server_addr(s, firstip, firstip_sin_family, (char *)chk->str);
@ -3710,11 +3632,9 @@ int snr_resolution_cb(struct dns_requester *requester, struct dns_nameserver *na
invalid: invalid:
if (nameserver) { if (nameserver) {
nameserver->counters.invalid += 1; nameserver->counters.invalid++;
if (resolution->nb_responses >= nameserver->resolvers->count_nameservers)
goto update_status; goto update_status;
} }
snr_update_srv_status(s, has_no_ip); snr_update_srv_status(s, has_no_ip);
return 0; return 0;
} }
@ -3727,22 +3647,11 @@ int snr_resolution_cb(struct dns_requester *requester, struct dns_nameserver *na
*/ */
int snr_resolution_error_cb(struct dns_requester *requester, int error_code) int snr_resolution_error_cb(struct dns_requester *requester, int error_code)
{ {
struct server *s = NULL; struct server *s;
struct dns_resolution *resolution = NULL;
struct dns_resolvers *resolvers = NULL;
s = objt_server(requester->requester); s = objt_server(requester->owner);
if (!s) if (!s)
return 1; return 1;
resolution = s->resolution;
resolvers = s->resolvers;
/* can be ignored if this is not the last response */
if ((error_code != DNS_RESP_TIMEOUT) && (resolution->nb_responses < resolvers->count_nameservers)) {
return 1;
}
snr_update_srv_status(s, 0); snr_update_srv_status(s, 0);
return 1; return 1;
} }
@ -3816,8 +3725,8 @@ int srv_set_addr_via_libc(struct server *srv, int *err_code)
int srv_set_fqdn(struct server *srv, const char *hostname) int srv_set_fqdn(struct server *srv, const char *hostname)
{ {
struct dns_resolution *resolution; struct dns_resolution *resolution;
int hostname_dn_len; char *hostname_dn;
int did_set_reso = 0; int hostname_len, hostname_dn_len;
/* run time DNS resolution was not active for this server /* run time DNS resolution was not active for this server
* and we can't enable it at run time for now. * and we can't enable it at run time for now.
@ -3826,60 +3735,31 @@ int srv_set_fqdn(struct server *srv, const char *hostname)
return -1; return -1;
chunk_reset(&trash); chunk_reset(&trash);
hostname_len = strlen(hostname);
/* check if hostname is really a hostname and if we have enough hostname_dn = trash.str;
* room to save it in its domain name format hostname_dn_len = dns_str_to_dn_label(hostname, hostname_len + 1,
*/ hostname_dn, trash.size);
hostname_dn_len = dns_str_to_dn_label_len(hostname); if (hostname_dn_len == -1)
if (hostname_dn_len == -1 || hostname_dn_len + 1 > trash.size)
return -1; return -1;
if (!dns_str_to_dn_label(hostname, resolution = srv->dns_requester->resolution;
trash.str, if (resolution &&
hostname_dn_len + 1)) resolution->hostname_dn &&
return -1; !strcmp(resolution->hostname_dn, hostname_dn))
if (srv->resolution->hostname_dn) {
/* get a resolution from the curr or wait queues, or a brand new one from the pool */
resolution = dns_resolution_list_get(srv->resolvers, trash.str, srv->dns_requester->prefered_query_type);
if (!resolution)
return -1;
/* in this case, the new hostanme is the same than the old one */
if (srv->resolution == resolution && srv->hostname)
return 0; return 0;
/* first, we need to unlink our server from its current resolution */ dns_unlink_resolution(srv->dns_requester);
srv_free_from_resolution(srv);
} else {
/* this server's fqdn has been set by a SRV record */
resolution = dns_resolution_list_get(srv->resolvers, trash.str, srv->dns_requester->prefered_query_type);
srv_free_from_resolution(srv);
srv->resolution = resolution;
if (resolution->hostname_dn == NULL) {
resolution->last_resolution = now_ms;
did_set_reso = 1;
}
}
/* now we update server's parameters */
free(srv->hostname); free(srv->hostname);
free(srv->hostname_dn); free(srv->hostname_dn);
srv->hostname = strdup(hostname); srv->hostname = strdup(hostname);
srv->hostname_dn = strdup(trash.str); srv->hostname_dn = strdup(hostname_dn);
srv->hostname_dn_len = hostname_dn_len; srv->hostname_dn_len = hostname_dn_len;
if (!srv->hostname || !srv->hostname_dn) if (!srv->hostname || !srv->hostname_dn)
return -1; return -1;
if (did_set_reso) {
resolution->query_type = srv->dns_requester->prefered_query_type;
resolution->hostname_dn = srv->hostname_dn;
resolution->hostname_dn_len = hostname_dn_len;
}
/* then we can link srv to its new resolution */
dns_link_resolution(srv, OBJ_TYPE_SERVER, resolution);
if (dns_link_resolution(srv, OBJ_TYPE_SERVER) == -1)
return -1;
return 0; return 0;
} }