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>
Points to an existing "resolvers" section to resolve current server's
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:
@ -11712,21 +11708,20 @@ different steps of the process life:
host name. It uses libc functions to get the host name resolved. This
resolution relies on /etc/resolv.conf file.
2. at run time, when HAProxy gets prepared to run a health check on a server,
it verifies if the current name resolution is still considered as valid.
If not, it processes a new resolution, in parallel of the health check.
2. at run time, HAProxy performs periodically name resolutions for servers
requiring DNS resolutions.
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
because the server has a new IP address. So we need to trigger a name
resolution to know this new IP.
When using resolvers, the server name can either be a hostname, or s SRV label.
HAProxy considers anything that starts with an underscore a SRV label.
If a SRV label is specified, then the corresponding SRV records will be
retrieved from the DNS server, and the provided hostnames will be used. The
SRV label will be checked periodically, and if any server are added or removed,
haproxy will automatically do the same.
When using resolvers, the server name can either be a hostname, or a SRV label.
HAProxy considers anything that starts with an underscore as a SRV label. If a
SRV label is specified, then the corresponding SRV records will be retrieved
from the DNS server, and the provided hostnames will be used. The SRV label
will be checked periodically, and if any server are added or removed, haproxy
will automatically do the same.
A few things important to notice:
- 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
HAProxy.
There can be as many as resolvers section as needed. Each section can contain
many name servers.
HAProxy. There can be as many as resolvers section as needed. Each section can
contain many name servers.
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
@ -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.
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. stop DNS resolution
2. replay the DNS query with a new query type
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
1. HAProxy retries the same DNS query with a new query type. The A queries are
switch to AAAA or the opposite. SRV queries are not concerned here. Timeout
errors are also excluded.
HAProxy stops DNS resolution when the following errors occur:
- invalid DNS response packet
- wrong name in the query section of the response
- NX domain
- Query refused by server
- CNAME not pointing to an IP address
2. When the fallback on the query type was done (or not applicable), HAProxy
retries the original DNS query, with the preferred query type.
HAProxy tries a new query type when the following errors occur:
- no Answer records in the response
- DNS response truncated
- Error in DNS response
- No expected DNS records found in the response
- name server timeout
3. HAProxy retries previous steps <resolve_retires> times. If no valid
response is received after that, it stops the DNS resolution and reports
the error.
For example, with 2 name servers configured in a resolvers section:
- first response is valid and is applied directly, second response is ignored
- first response is invalid and second one is valid, then second response is
applied;
- first response is a NX domain and second one a truncated response, then
HAProxy replays the query with a new type;
- first response is truncated and second one is a NX Domain, then HAProxy
stops resolution.
For example, with 2 name servers configured in a resolvers section, the
following scenarios are possible:
- First response is valid and is applied directly, second response is
ignored
- First response is invalid and second one is valid, then second response is
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
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>
@ -11796,7 +11787,7 @@ A resolvers section accept the following parameters:
accepted_payload_size <nb>
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
by RFC 6891)
@ -11822,11 +11813,7 @@ hold <status> <period>
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 is triggered after <period> modulo the <inter> parameter of
the healch check.
resolution_pool_size <nb>
resolution_pool_size <nb> (deprecated)
Defines the number of resolutions available in the pool for this resolvers.
If not defines, it defaults to 64. If your configuration requires more than
<nb>, then HAProxy will return an error when parsing the configuration.
@ -11844,9 +11831,12 @@ timeout <event> <time>
Defines timeouts related to name resolution
<event> : the event on which the <time> timeout period applies to.
events available are:
- retry: time between two DNS queries, when no response have
been received.
Default value: 1s
- resolve : default time to trigger name resolutions when no
other time applied.
Default value: 1s
- retry : time between two DNS queries, when no valid response
have been received.
Default value: 1s
<time> : time related to the event. It follows the HAProxy time format.
<time> is expressed in milliseconds.
@ -11856,6 +11846,7 @@ timeout <event> <time>
nameserver dns1 10.0.0.1:53
nameserver dns2 10.0.0.2:53
resolve_retries 3
timeout resolve 1s
timeout retry 1s
hold other 30s
hold refused 30s

View File

@ -23,46 +23,26 @@
#define _PROTO_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);
int dns_str_to_dn_label_len(const char *string);
void dns_dn_label_to_str(char *dn, char *str, int dn_len);
extern struct list dns_resolvers;
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_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,
struct dns_options *dns_opts, void *currentip,
short currentip_sin_family,
void **newip, short *newip_sin_family,
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

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_error_cb(struct dns_requester *requester, int error_code);
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 */
static void inline srv_inc_sess_ctr(struct server *s)

View File

@ -22,21 +22,32 @@
#ifndef _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 */
/*
* Maximum issued from RFC:
* RFC 1035: https://www.ietf.org/rfc/rfc1035.txt chapter 2.3.4
* RFC 2671: http://tools.ietf.org/html/rfc2671
*/
#define DNS_MAX_LABEL_SIZE 63
#define DNS_MAX_NAME_SIZE 255
#define DNS_MAX_UDP_MESSAGE 8192
#define DNS_MAX_LABEL_SIZE 63
#define DNS_MAX_NAME_SIZE 255
#define DNS_MAX_UDP_MESSAGE 8192
/* 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 */
# define DNS_SMALLEST_FQDN_SIZE 4
# define DNS_SMALLEST_FQDN_SIZE 4
/* maximum number of query records in a DNS response
* For now, we allow only one */
@ -52,29 +63,29 @@
#define DNS_ANALYZE_BUFFER_SIZE DNS_MAX_UDP_MESSAGE + DNS_MAX_NAME_SIZE
/* DNS error messages */
#define DNS_TOO_LONG_FQDN "hostname too long"
#define DNS_LABEL_TOO_LONG "one label too long"
#define DNS_INVALID_CHARACTER "found an invalid character"
#define DNS_TOO_LONG_FQDN "hostname too long"
#define DNS_LABEL_TOO_LONG "one label too long"
#define DNS_INVALID_CHARACTER "found an invalid character"
/* dns query class */
#define DNS_RCLASS_IN 1 /* internet class */
#define DNS_RCLASS_IN 1 /* internet class */
/* dns record types (non exhaustive list) */
#define DNS_RTYPE_A 1 /* IPv4 address */
#define DNS_RTYPE_CNAME 5 /* canonical name */
#define DNS_RTYPE_AAAA 28 /* IPv6 address */
#define DNS_RTYPE_SRV 33 /* SRV record */
#define DNS_RTYPE_OPT 41 /* OPT */
#define DNS_RTYPE_ANY 255 /* all records */
#define DNS_RTYPE_A 1 /* IPv4 address */
#define DNS_RTYPE_CNAME 5 /* canonical name */
#define DNS_RTYPE_AAAA 28 /* IPv6 address */
#define DNS_RTYPE_SRV 33 /* SRV record */
#define DNS_RTYPE_OPT 41 /* OPT */
#define DNS_RTYPE_ANY 255 /* all records */
/* dns rcode values */
#define DNS_RCODE_NO_ERROR 0 /* no error */
#define DNS_RCODE_NX_DOMAIN 3 /* non existent domain */
#define DNS_RCODE_REFUSED 5 /* query refused */
#define DNS_RCODE_NO_ERROR 0 /* no error */
#define DNS_RCODE_NX_DOMAIN 3 /* non existent domain */
#define DNS_RCODE_REFUSED 5 /* query refused */
/* dns flags masks */
#define DNS_FLAG_TRUNCATED 0x0200 /* mask for truncated flag */
#define DNS_FLAG_REPLYCODE 0x000F /* mask for reply code */
#define DNS_FLAG_TRUNCATED 0x0200 /* mask for truncated flag */
#define DNS_FLAG_REPLYCODE 0x000F /* mask for reply code */
/* max number of network preference entries are avalaible from the
* configuration file.
@ -82,10 +93,7 @@
#define SRV_MAX_PREF_NET 5
/* DNS header size */
#define DNS_HEADER_SIZE ((int)sizeof(struct dns_header))
/* DNS resolution pool size, per resolvers section */
#define DNS_DEFAULT_RESOLUTION_POOL_SIZE 64
#define DNS_HEADER_SIZE ((int)sizeof(struct dns_header))
/* DNS request or response header structure */
struct dns_header {
@ -100,254 +108,244 @@ struct dns_header {
/* short structure to describe a DNS question */
/* NOTE: big endian structure */
struct dns_question {
unsigned short qtype; /* question type */
unsigned short qclass; /* query class */
unsigned short qtype; /* question type */
unsigned short qclass; /* query class */
};
/* NOTE: big endian structure */
struct dns_query_item {
struct list list;
char name[DNS_MAX_NAME_SIZE]; /* query name */
unsigned short type; /* question type */
unsigned short class; /* query class */
char name[DNS_MAX_NAME_SIZE]; /* query name */
unsigned short type; /* question type */
unsigned short class; /* query class */
struct list list;
};
/* NOTE: big endian structure */
struct dns_additional_record {
uint8_t name; /* domain name, must be 0 (RFC 6891) */
uint16_t type; /* record type DNS_RTYPE_OPT (41) */
uint16_t udp_payload_size; /* maximum size accepted for the response */
uint32_t extension; /* extended rcode and flags, not used for now */
uint16_t data_length; /* data length */
/* as of today, we don't support yet edns options, that said I already put a placeholder here
* for this purpose. We may need to define a dns_option_record structure which itself should
* point to different type of data, based on the extension set (client subnet, tcp keepalive,
* etc...)*/
// struct list options; /* list of option records */
uint8_t name; /* domain name, must be 0 (RFC 6891) */
uint16_t type; /* record type DNS_RTYPE_OPT (41) */
uint16_t udp_payload_size; /* maximum size accepted for the response */
uint32_t extension; /* extended rcode and flags, not used for now */
uint16_t data_length; /* data length */
/* as of today, we don't support yet edns options, that said I already put a
* placeholder here for this purpose. We may need to define a dns_option_record
* structure which itself should point to different type of data, based on the
* extension set (client subnet, tcp keepalive, etc...)*/
// struct list options; /* list of option records */
} __attribute__ ((packed));
/* NOTE: big endian structure */
struct dns_answer_item {
struct list list;
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 class; /* query class */
int32_t ttl; /* response TTL */
int16_t priority; /* SRV type priority */
int16_t weight; /* SRV type weight */
int16_t port; /* SRV type port */
int16_t data_len; /* number of bytes in target below */
struct sockaddr address; /* IPv4 or IPv6, network format */
char target[DNS_MAX_NAME_SIZE]; /* Response data: SRV or CNAME type target */
time_t last_seen; /* When was the answer was last seen */
/*For SRV type, name also includes service and protocol value */
char name[DNS_MAX_NAME_SIZE]; /* answer name */
int16_t type; /* question type */
int16_t class; /* query class */
int32_t ttl; /* response TTL */
int16_t priority; /* SRV type priority */
int16_t weight; /* SRV type weight */
int16_t port; /* SRV type port */
int16_t data_len; /* number of bytes in target below */
struct sockaddr address; /* IPv4 or IPv6, network format */
char target[DNS_MAX_NAME_SIZE]; /* Response data: SRV or CNAME type target */
time_t last_seen; /* When was the answer was last seen */
struct list list;
};
struct dns_response_packet {
struct dns_header header;
struct list query_list;
struct list answer_list;
struct list query_list;
struct list answer_list;
/* 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.
* current resolution are stored in a FIFO list.
*/
struct dns_resolvers {
struct list list; /* resolvers list */
char *id; /* resolvers unique identifier */
char *id; /* resolvers unique identifier */
struct {
const char *file; /* file where the section appears */
int line; /* line where the section appears */
} conf; /* config information */
struct list nameserver_list; /* dns server list */
unsigned int accepted_payload_size; /* maximum payload size we accept for responses */
int count_nameservers; /* total number of nameservers in a resolvers section */
int resolve_retries; /* number of retries before giving up */
struct { /* time to: */
int retry; /* wait for a response before retrying */
const char *file; /* file where the section appears */
int line; /* line where the section appears */
} conf; /* config information */
struct list nameservers; /* dns server list */
unsigned int accepted_payload_size; /* maximum payload size we accept for responses */
int nb_nameservers; /* total number of active nameservers in a resolvers section */
int resolve_retries; /* number of retries before giving up */
struct { /* time to: */
int resolve; /* wait between 2 queries for the same resolution */
int retry; /* wait for a response before retrying */
} timeout;
struct { /* time to hold current data when */
int valid; /* a response is valid */
int nx; /* a response doesn't exist */
int timeout; /* no answer was delivered */
int refused; /* dns server refused to answer */
int other; /* other dns response errors */
int obsolete; /* an answer hasn't been seen */
struct { /* time to hold current data when */
int valid; /* a response is valid */
int nx; /* a response doesn't exist */
int timeout; /* no answer was delivered */
int refused; /* dns server refused to answer */
int other; /* other dns response errors */
int obsolete; /* an answer hasn't been seen */
} hold;
struct task *t; /* timeout management */
int resolution_pool_size; /* size of the resolution pool associated to this resolvers section */
struct task *t; /* timeout management */
struct {
struct list pool; /* resolution pool dedicated to this resolvers section */
struct list wait; /* resolutions managed to this resolvers section */
struct list curr; /* current running resolutions */
} resolution;
struct eb_root query_ids; /* tree to quickly lookup/retrieve query ids currently in use */
/* used by each nameserver, but stored in resolvers since there must */
/* be a unique relation between an eb_root and an eb_node (resolution) */
struct list wait; /* resolutions managed to this resolvers section */
struct list curr; /* current running resolutions */
} resolutions;
struct eb_root query_ids; /* tree to quickly lookup/retrieve query ids currently in use
* used by each nameserver, but stored in resolvers since there must
* be a unique relation between an eb_root and an eb_node (resolution) */
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.
*/
struct dns_nameserver {
struct list list; /* nameserver chained list */
char *id; /* nameserver unique identifier */
char *id; /* nameserver unique identifier */
struct {
const char *file; /* file where the section appears */
int line; /* line where the section appears */
} conf; /* config information */
struct dns_resolvers *resolvers;
struct dgram_conn *dgram; /* transport layer */
struct sockaddr_storage addr; /* IP address */
struct { /* numbers relted to this name server: */
long int sent; /* - queries sent */
long int valid; /* - valid response */
long int update; /* - valid response used to update server's IP */
long int cname; /* - CNAME response requiring new resolution */
long int cname_error; /* - error when resolving CNAMEs */
long int any_err; /* - void response (usually because ANY qtype) */
long int nx; /* - NX response */
long int timeout; /* - queries which reached timeout */
long int refused; /* - queries refused */
long int other; /* - other type of response */
long int invalid; /* - malformed DNS response */
long int too_big; /* - too big response */
long int outdated; /* - outdated response (server slower than the other ones) */
long int truncated; /* - truncated response */
const char *file; /* file where the section appears */
int line; /* line where the section appears */
} conf; /* config information */
struct dns_resolvers *resolvers;
struct dgram_conn *dgram; /* transport layer */
struct sockaddr_storage addr; /* IP address */
struct { /* numbers relted to this name server: */
long long sent; /* - queries sent */
long long snd_error; /* - sending errors */
long long valid; /* - valid response */
long long update; /* - valid response used to update server's IP */
long long cname; /* - CNAME response requiring new resolution */
long long cname_error; /* - error when resolving CNAMEs */
long long any_err; /* - void response (usually because ANY qtype) */
long long nx; /* - NX response */
long long timeout; /* - queries which reached timeout */
long long refused; /* - queries refused */
long long other; /* - other type of response */
long long invalid; /* - malformed DNS response */
long long too_big; /* - too big response */
long long outdated; /* - outdated response (server slower than the other ones) */
long long truncated; /* - truncated response */
} counters;
struct list list; /* nameserver chained list */
};
struct dns_options {
int family_prio; /* which IP family should the resolver use when both are returned */
int family_prio; /* which IP family should the resolver use when both are returned */
struct {
int family;
union {
struct in_addr in4;
struct in_addr in4;
struct in6_addr in6;
} addr;
union {
struct in_addr in4;
struct in_addr in4;
struct in6_addr in6;
} mask;
} pref_net[SRV_MAX_PREF_NET];
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 for
* this server.
* The only link between the resolution and a nameserver is through the query_id.
/* Resolution structure associated to single server and used to manage name
* resolution for this server.
* The only link between the resolution and a nameserver is through the
* query_id.
*/
struct dns_resolution {
struct list list; /* resolution list */
struct {
struct list wait; /* list of standby requesters for this resolution */
struct list curr; /* list of requesters currently active on this resolution */
} requester;
int (*requester_cb)(struct dns_resolution *, struct dns_nameserver *);
/* requester callback for valid response */
int (*requester_error_cb)(struct dns_resolution *, int);
/* requester callback, for error management */
int uuid; /* unique id (used for debugging purpose) */
char *hostname_dn; /* server hostname in domain name label format */
int hostname_dn_len; /* server domain name label len */
unsigned int last_resolution; /* time of the lastest valid resolution */
unsigned int last_sent_packet; /* time of the latest DNS packet sent */
unsigned int last_status_change; /* time of the latest DNS resolution status change */
int query_id; /* DNS query ID dedicated for this resolution */
struct eb32_node qid; /* ebtree query id */
int query_type;
/* query type to send. By default DNS_RTYPE_A or DNS_RTYPE_AAAA depending on resolver_family_priority */
int status; /* status of the resolution being processed RSLV_STATUS_* */
int step; /* */
int try; /* current resolution try */
int try_cname; /* number of CNAME requests sent */
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_query_item response_query_records[DNS_MAX_QUERY_RECORDS]; /* <response> query records */
struct dns_resolvers *resolvers; /* pointer to the resolvers structure owning the resolution */
struct list requesters; /* list of requesters using this resolution */
int uuid; /* unique id (used for debugging purpose) */
char *hostname_dn; /* server hostname in domain name label format */
int hostname_dn_len; /* server domain name label len */
unsigned int last_resolution; /* time of the last resolution */
unsigned int last_query; /* time of the last query sent */
unsigned int last_valid; /* time of the last valid response */
int query_id; /* DNS query ID dedicated for this resolution */
struct eb32_node qid; /* ebtree query id */
int prefered_query_type; /* prefered query type */
int query_type; /* current query type */
int status; /* status of the resolution being processed RSLV_STATUS_* */
int step; /* RSLV_STEP_* */
int try; /* current resolution try */
int nb_queries; /* count number of queries sent */
int nb_responses; /* count number of responses received */
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 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 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 */
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 */
};
/* last resolution status code */
/* Last resolution status code */
enum {
RSLV_STATUS_NONE = 0, /* no resolution occured yet */
RSLV_STATUS_VALID, /* no error */
RSLV_STATUS_INVALID, /* invalid responses */
RSLV_STATUS_ERROR, /* error */
RSLV_STATUS_NX, /* NXDOMAIN */
RSLV_STATUS_REFUSED, /* server refused our query */
RSLV_STATUS_TIMEOUT, /* no response from DNS servers */
RSLV_STATUS_OTHER, /* other errors */
RSLV_STATUS_NONE = 0, /* no resolution occured yet */
RSLV_STATUS_VALID, /* no error */
RSLV_STATUS_INVALID, /* invalid responses */
RSLV_STATUS_ERROR, /* error */
RSLV_STATUS_NX, /* NXDOMAIN */
RSLV_STATUS_REFUSED, /* server refused our query */
RSLV_STATUS_TIMEOUT, /* no response from DNS servers */
RSLV_STATUS_OTHER, /* other errors */
};
/* current resolution step */
/* Current resolution step */
enum {
RSLV_STEP_NONE = 0, /* nothing happening currently */
RSLV_STEP_RUNNING, /* resolution is running */
RSLV_STEP_NONE = 0, /* nothing happening currently */
RSLV_STEP_RUNNING, /* resolution is running */
};
/* return codes after analyzing a DNS response */
/* Return codes after analyzing a DNS response */
enum {
DNS_RESP_VALID = 0, /* valid response */
DNS_RESP_INVALID, /* invalid response (various type of errors can trigger it) */
DNS_RESP_ERROR, /* DNS error code */
DNS_RESP_NX_DOMAIN, /* resolution unsuccessful */
DNS_RESP_REFUSED, /* DNS server refused to answer */
DNS_RESP_ANCOUNT_ZERO, /* no answers in the response */
DNS_RESP_WRONG_NAME, /* response does not match query name */
DNS_RESP_CNAME_ERROR, /* error when resolving a CNAME in an atomic response */
DNS_RESP_TIMEOUT, /* DNS server has not answered in time */
DNS_RESP_TRUNCATED, /* DNS response is truncated */
DNS_RESP_NO_EXPECTED_RECORD, /* No expected records were found in the response */
DNS_RESP_QUERY_COUNT_ERROR, /* we did not get the expected number of queries in the response */
DNS_RESP_INTERNAL, /* internal resolver error */
DNS_RESP_VALID = 0, /* valid response */
DNS_RESP_INVALID, /* invalid response (various type of errors can trigger it) */
DNS_RESP_ERROR, /* DNS error code */
DNS_RESP_NX_DOMAIN, /* resolution unsuccessful */
DNS_RESP_REFUSED, /* DNS server refused to answer */
DNS_RESP_ANCOUNT_ZERO, /* no answers in the response */
DNS_RESP_WRONG_NAME, /* response does not match query name */
DNS_RESP_CNAME_ERROR, /* error when resolving a CNAME in an atomic response */
DNS_RESP_TIMEOUT, /* DNS server has not answered in time */
DNS_RESP_TRUNCATED, /* DNS response is truncated */
DNS_RESP_NO_EXPECTED_RECORD, /* No expected records were found in the response */
DNS_RESP_QUERY_COUNT_ERROR, /* we did not get the expected number of queries in the response */
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 {
DNS_UPD_NO = 1, /* provided IP was found and preference is matched
* OR provided IP found and preference is not matched, but no IP
* matching preference was found */
DNS_UPD_SRVIP_NOT_FOUND, /* provided IP not found
* OR provided IP found and preference is not match and an IP
* matching preference was found */
DNS_UPD_CNAME, /* CNAME without any IP provided in the response */
DNS_UPD_NAME_ERROR, /* name in the response did not match the query */
DNS_UPD_NO_IP_FOUND, /* no IP could be found in the response */
DNS_UPD_OBSOLETE_IP, /* The server IP was obsolete, and no other IP was found */
DNS_UPD_NO = 1, /* provided IP was found and preference is matched
* OR provided IP found and preference is not matched, but no IP
* matching preference was found */
DNS_UPD_SRVIP_NOT_FOUND, /* provided IP not found
* OR provided IP found and preference is not match and an IP
* matching preference was found */
DNS_UPD_CNAME, /* CNAME without any IP provided in the response */
DNS_UPD_NAME_ERROR, /* name in the response did not match the query */
DNS_UPD_NO_IP_FOUND, /* no IP could be found in the response */
DNS_UPD_OBSOLETE_IP, /* The server IP was obsolete, and no other IP was found */
};
struct dns_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_resolution *resolution; /* server name resolution */
struct proxy *proxy; /* associated proxy */
char *name;
char *hostname_dn; /* 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 */
int inter; /* time in ms */
struct list list; /* Next SRV RQ for the same proxy */
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 proxy *proxy; /* associated proxy */
char *name;
char *hostname_dn; /* 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 list list; /* Next SRV RQ for the same proxy */
};
#endif /* _TYPES_DNS_H */

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 task *global_listener_queue_task;
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 */
#define WARN_BLOCK_DEPRECATED 0x00000001

View File

@ -438,7 +438,6 @@ struct proxy {
* name is used
*/
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 {

View File

@ -262,7 +262,6 @@ struct server {
char *hostname_dn; /* 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 */
struct dns_resolution *resolution; /* server name resolution */
struct dns_options dns_opts;
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 */

View File

@ -2149,14 +2149,13 @@ int cfg_parse_resolvers(const char *file, int linenum, char **args, int kwm)
curr_resolvers->hold.obsolete = 0;
/* default hold period for valid is 10s */
curr_resolvers->hold.valid = 10000;
curr_resolvers->timeout.retry = 1000;
curr_resolvers->timeout.resolve = 1000;
curr_resolvers->timeout.retry = 1000;
curr_resolvers->resolve_retries = 3;
/* default resolution pool size */
curr_resolvers->resolution_pool_size = DNS_DEFAULT_RESOLUTION_POOL_SIZE;
LIST_INIT(&curr_resolvers->nameserver_list);
LIST_INIT(&curr_resolvers->resolution.curr);
LIST_INIT(&curr_resolvers->resolution.wait);
LIST_INIT(&curr_resolvers->resolution.pool);
curr_resolvers->nb_nameservers = 0;
LIST_INIT(&curr_resolvers->nameservers);
LIST_INIT(&curr_resolvers->resolutions.curr);
LIST_INIT(&curr_resolvers->resolutions.wait);
}
else if (strcmp(args[0], "nameserver") == 0) { /* nameserver definition */
struct sockaddr_storage *sk;
@ -2178,7 +2177,7 @@ int cfg_parse_resolvers(const char *file, int linenum, char **args, int kwm)
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 */
if (strcmp(newnameserver->id, args[1]) == 0) {
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 */
LIST_ADDQ(&curr_resolvers->nameserver_list, &newnameserver->list);
curr_resolvers->count_nameservers++;
LIST_ADDQ(&curr_resolvers->nameservers, &newnameserver->list);
newnameserver->resolvers = curr_resolvers;
newnameserver->conf.file = strdup(file);
newnameserver->conf.line = linenum;
@ -2291,13 +2289,10 @@ int cfg_parse_resolvers(const char *file, int linenum, char **args, int kwm)
curr_resolvers->accepted_payload_size = i;
}
else if (strcmp(args[0], "resolution_pool_size") == 0) {
if (!*args[1]) {
Alert("parsing [%s:%d] : '%s' expects <nb> as argument.\n",
file, linenum, args[0]);
err_code |= ERR_ALERT | ERR_FATAL;
goto out;
}
curr_resolvers->resolution_pool_size = atoi(args[1]);
Warning("parsing [%s:%d] : '%s' directive is now deprecated and ignored.\n",
file, linenum, args[0]);
err_code |= ERR_WARN;
goto out;
}
else if (strcmp(args[0], "resolve_retries") == 0) {
if (!*args[1]) {
@ -2310,14 +2305,15 @@ int cfg_parse_resolvers(const char *file, int linenum, char **args, int kwm)
}
else if (strcmp(args[0], "timeout") == 0) {
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]);
err_code |= ERR_ALERT | ERR_FATAL;
goto out;
}
else if (strcmp(args[1], "retry") == 0) {
else if (strcmp(args[1], "retry") == 0 ||
strcmp(args[1], "resolve") == 0) {
const char *res;
unsigned int timeout_retry;
unsigned int tout;
if (!*args[2]) {
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;
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) {
Alert("parsing [%s:%d]: unexpected character '%c' in argument to <%s %s>.\n",
file, linenum, *res, args[0], args[1]);
err_code |= ERR_ALERT | ERR_FATAL;
goto out;
}
curr_resolvers->timeout.retry = timeout_retry;
if (args[1][2] == 't')
curr_resolvers->timeout.retry = tout;
else
curr_resolvers->timeout.resolve = tout;
}
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]);
err_code |= ERR_ALERT | ERR_FATAL;
goto out;
@ -7394,7 +7393,6 @@ int check_config_validity()
unsigned int next_pxid = 1;
struct bind_conf *bind_conf;
char *err;
struct dns_resolvers *curr_resolvers;
struct cfg_postparser *postparser;
bind_conf = NULL;
@ -7418,15 +7416,6 @@ int check_config_validity()
pool2_capture = create_pool("capture", global.tune.cookie_len, MEM_F_SHARED);
/* allocate pool of resolution per resolvers */
list_for_each_entry(curr_resolvers, &dns_resolvers, list) {
if (dns_alloc_resolution_pool(curr_resolvers) != 0) {
/* error message is already displayed by dns_alloc_resolution_pool() */
err_code |= ERR_ALERT | ERR_ABORT;
goto out;
}
}
/* Post initialisation of the users and groups lists. */
err_code = userlist_postinit();
if (err_code != ERR_NONE)
@ -8362,64 +8351,6 @@ out_uri_auth_compat:
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:
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.
* 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->resolution);
dns_trigger_resolution(check->server->dns_requester);
}
else if ((conn->flags & (CO_FL_CONNECTED|CO_FL_WAIT_L6_CONN)) == CO_FL_WAIT_L6_CONN) {

3201
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())
exit(1);
/* initialize structures for name resolution */
if (!dns_init_resolvers(0))
exit(1);
free(err_msg);
}
@ -2025,6 +2021,7 @@ void deinit(void)
free(s->agent.bi);
free(s->agent.bo);
free(s->agent.send_string);
free(s->hostname_dn);
free((char*)s->conf.file);
if (s->use_ssl || s->check.use_ssl) {
@ -2698,10 +2695,6 @@ int main(int argc, char **argv)
fork_poller();
}
/* initialize structures for name resolution */
if (!dns_init_resolvers(1))
exit(1);
if (global.mode & MODE_MWORKER)
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->tcpcheck_rules);
LIST_INIT(&p->filter_configs);
LIST_INIT(&p->srvrq_list);
/* Timeouts are defined as -1 */
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)
{
char *hostname_dn;
int hostname_len, hostname_dn_len;
if (!hostname)
return 0;
free(srv->hostname);
srv->hostname = strdup(hostname);
srv->hostname_dn_len = dns_str_to_dn_label_len(hostname);
srv->hostname_dn = calloc(srv->hostname_dn_len + 1, sizeof(char));
if (!srv->hostname || !srv->hostname_dn)
hostname_len = strlen(hostname);
hostname_dn = trash.str;
hostname_dn_len = dns_str_to_dn_label(hostname, hostname_len + 1,
hostname_dn, trash.size);
if (hostname_dn_len == -1)
goto err;
if (!dns_str_to_dn_label(srv->hostname,
srv->hostname_dn,
srv->hostname_dn_len + 1))
free(srv->hostname);
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;
return 0;
err:
free(srv->hostname);
srv->hostname = NULL;
free(srv->hostname_dn);
srv->hostname_dn = NULL;
free(srv->hostname); srv->hostname = NULL;
free(srv->hostname_dn); srv->hostname_dn = NULL;
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
* everything needed.
@ -2006,61 +1972,20 @@ int parse_server(const char *file, int linenum, char **args, struct proxy *curpr
/* save hostname and create associated name resolution */
if (fqdn) {
if (fqdn[0] == '_') {
struct dns_srvrq *srvrq = NULL;
int found = 0;
/* SRV record */
if (fqdn[0] == '_') { /* SRV record */
/* Check if a SRV request already exists, and if not, create it */
list_for_each_entry(srvrq, &curproxy->srvrq_list, list) {
if (!strcmp(srvrq->name, fqdn)) {
found = 1;
break;
}
}
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;
}
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);
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",
file, linenum, newsrv->id);
if ((newsrv->srvrq = find_srvrq_by_name(fqdn, curproxy)) == NULL)
newsrv->srvrq = new_dns_srvrq(newsrv, fqdn);
if (newsrv->srvrq == NULL) {
err_code |= ERR_ALERT | ERR_FATAL;
goto out;
}
}
else if (srv_prepare_for_resolution(newsrv, fqdn) == -1) {
Alert("parsing [%s:%d] : Can't create DNS resolution for server '%s'\n",
file, linenum, newsrv->id);
err_code |= ERR_ALERT | ERR_FATAL;
goto out;
}
}
@ -2299,8 +2224,6 @@ int parse_server(const char *file, int linenum, char **args, struct proxy *curpr
goto out;
}
newsrv->check.inter = val;
if (newsrv->srvrq)
newsrv->srvrq->inter = val;
cur_arg += 2;
}
else if (!strcmp(args[cur_arg], "fastinter")) {
@ -3531,8 +3454,9 @@ out:
*/
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) {
case RSLV_STATUS_NONE:
@ -3550,8 +3474,9 @@ int snr_update_srv_status(struct server *s, int has_no_ip)
return 1;
srv_set_admin_flag(s, SRV_ADMF_RMAINT,
"No IP for server ");
return (0);
return 0;
}
if (!(s->next_admin & SRV_ADMF_RMAINT))
return 1;
srv_clr_admin_flag(s, SRV_ADMF_RMAINT);
@ -3564,43 +3489,47 @@ int snr_update_srv_status(struct server *s, int has_no_ip)
case RSLV_STATUS_NX:
/* 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)) {
if (s->next_admin & SRV_ADMF_RMAINT)
return 1;
srv_set_admin_flag(s, SRV_ADMF_RMAINT, "DNS NX status");
return 0;
}
break;
exp = tick_add(resolution->last_valid, resolvers->hold.nx);
if (!tick_is_expired(exp, now_ms))
break;
if (s->next_admin & SRV_ADMF_RMAINT)
return 1;
srv_set_admin_flag(s, SRV_ADMF_RMAINT, "DNS NX status");
return 0;
case RSLV_STATUS_TIMEOUT:
/* 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)) {
if (s->next_admin & SRV_ADMF_RMAINT)
return 1;
srv_set_admin_flag(s, SRV_ADMF_RMAINT, "DNS timeout status");
return 0;
}
break;
exp = tick_add(resolution->last_valid, resolvers->hold.timeout);
if (!tick_is_expired(exp, now_ms))
break;
if (s->next_admin & SRV_ADMF_RMAINT)
return 1;
srv_set_admin_flag(s, SRV_ADMF_RMAINT, "DNS timeout status");
return 0;
case RSLV_STATUS_REFUSED:
/* 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)) {
if (s->next_admin & SRV_ADMF_RMAINT)
return 1;
srv_set_admin_flag(s, SRV_ADMF_RMAINT, "DNS refused status");
return 0;
}
break;
exp = tick_add(resolution->last_valid, resolvers->hold.refused);
if (!tick_is_expired(exp, now_ms))
break;
if (s->next_admin & SRV_ADMF_RMAINT)
return 1;
srv_set_admin_flag(s, SRV_ADMF_RMAINT, "DNS refused status");
return 0;
default:
/* stop server if resolution is in unmatched error for a long enough period */
if (tick_is_expired(tick_add(resolution->last_status_change, resolvers->hold.other), now_ms)) {
if (s->next_admin & SRV_ADMF_RMAINT)
return 1;
srv_set_admin_flag(s, SRV_ADMF_RMAINT, "unspecified DNS error");
return 0;
}
break;
/* stop server if resolution failed for a long enough period */
exp = tick_add(resolution->last_valid, resolvers->hold.other);
if (!tick_is_expired(exp, now_ms))
break;
if (s->next_admin & SRV_ADMF_RMAINT)
return 1;
srv_set_admin_flag(s, SRV_ADMF_RMAINT, "unspecified DNS error");
return 0;
}
return 1;
@ -3629,11 +3558,11 @@ int snr_resolution_cb(struct dns_requester *requester, struct dns_nameserver *na
struct chunk *chk = get_trash_chunk();
int has_no_ip = 0;
s = objt_server(requester->requester);
s = objt_server(requester->owner);
if (!s)
return 1;
resolution = s->resolution;
resolution = s->dns_requester->resolution;
/* initializing variables */
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;
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 */
if (resolution->status != RSLV_STATUS_OTHER) {
resolution->status = RSLV_STATUS_OTHER;
resolution->last_status_change = now_ms;
}
resolution->status = RSLV_STATUS_OTHER;
goto update_status;
default:
@ -3694,12 +3617,11 @@ int snr_resolution_cb(struct dns_requester *requester, struct dns_nameserver *na
}
save_ip:
if (nameserver)
nameserver->counters.update += 1;
/* save the first ip we found */
if (nameserver)
if (nameserver) {
nameserver->counters.update++;
/* save the first ip we found */
chunk_printf(chk, "%s/%s", nameserver->resolvers->id, nameserver->id);
}
else
chunk_printf(chk, "DNS cache");
update_server_addr(s, firstip, firstip_sin_family, (char *)chk->str);
@ -3710,11 +3632,9 @@ int snr_resolution_cb(struct dns_requester *requester, struct dns_nameserver *na
invalid:
if (nameserver) {
nameserver->counters.invalid += 1;
if (resolution->nb_responses >= nameserver->resolvers->count_nameservers)
goto update_status;
nameserver->counters.invalid++;
goto update_status;
}
snr_update_srv_status(s, has_no_ip);
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)
{
struct server *s = NULL;
struct dns_resolution *resolution = NULL;
struct dns_resolvers *resolvers = NULL;
struct server *s;
s = objt_server(requester->requester);
s = objt_server(requester->owner);
if (!s)
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);
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)
{
struct dns_resolution *resolution;
int hostname_dn_len;
int did_set_reso = 0;
char *hostname_dn;
int hostname_len, hostname_dn_len;
/* run time DNS resolution was not active for this server
* 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;
chunk_reset(&trash);
/* check if hostname is really a hostname and if we have enough
* room to save it in its domain name format
*/
hostname_dn_len = dns_str_to_dn_label_len(hostname);
if (hostname_dn_len == -1 || hostname_dn_len + 1 > trash.size)
hostname_len = strlen(hostname);
hostname_dn = trash.str;
hostname_dn_len = dns_str_to_dn_label(hostname, hostname_len + 1,
hostname_dn, trash.size);
if (hostname_dn_len == -1)
return -1;
if (!dns_str_to_dn_label(hostname,
trash.str,
hostname_dn_len + 1))
return -1;
resolution = srv->dns_requester->resolution;
if (resolution &&
resolution->hostname_dn &&
!strcmp(resolution->hostname_dn, hostname_dn))
return 0;
dns_unlink_resolution(srv->dns_requester);
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;
/* first, we need to unlink our server from its current resolution */
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_dn);
srv->hostname = strdup(hostname);
srv->hostname_dn = strdup(trash.str);
srv->hostname = strdup(hostname);
srv->hostname_dn = strdup(hostname_dn);
srv->hostname_dn_len = hostname_dn_len;
if (!srv->hostname || !srv->hostname_dn)
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;
}