mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-11-29 14:50:59 +01:00
MAJOR: server: add DNS-based server name resolution
Relies on the DNS protocol freshly implemented in HAProxy. It performs a server IP addr resolution based on a server hostname.
This commit is contained in:
parent
325137d603
commit
a68ca96375
@ -29,6 +29,7 @@ const char *get_check_status_description(short check_status);
|
|||||||
const char *get_check_status_info(short check_status);
|
const char *get_check_status_info(short check_status);
|
||||||
int start_checks();
|
int start_checks();
|
||||||
void __health_adjust(struct server *s, short status);
|
void __health_adjust(struct server *s, short status);
|
||||||
|
int trigger_resolution(struct server *s);
|
||||||
|
|
||||||
extern struct data_cb check_conn_cb;
|
extern struct data_cb check_conn_cb;
|
||||||
|
|
||||||
|
|||||||
@ -26,6 +26,7 @@
|
|||||||
|
|
||||||
#include <common/config.h>
|
#include <common/config.h>
|
||||||
#include <common/time.h>
|
#include <common/time.h>
|
||||||
|
#include <types/dns.h>
|
||||||
#include <types/proxy.h>
|
#include <types/proxy.h>
|
||||||
#include <types/queue.h>
|
#include <types/queue.h>
|
||||||
#include <types/server.h>
|
#include <types/server.h>
|
||||||
@ -40,6 +41,11 @@ int srv_getinter(const struct check *check);
|
|||||||
int parse_server(const char *file, int linenum, char **args, struct proxy *curproxy, struct proxy *defproxy);
|
int parse_server(const char *file, int linenum, char **args, struct proxy *curproxy, struct proxy *defproxy);
|
||||||
int update_server_addr(struct server *s, void *ip, int ip_sin_family, char *updater);
|
int update_server_addr(struct server *s, void *ip, int ip_sin_family, char *updater);
|
||||||
|
|
||||||
|
/* functions related to server name resolution */
|
||||||
|
int snr_update_srv_status(struct server *s);
|
||||||
|
int snr_resolution_cb(struct dns_resolution *resolution, struct dns_nameserver *nameserver, unsigned char *response, int response_len);
|
||||||
|
int snr_resolution_error_cb(struct dns_resolution *resolution, int error_code);
|
||||||
|
|
||||||
/* 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)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -205,6 +205,11 @@ struct server {
|
|||||||
struct check check; /* health-check specific configuration */
|
struct check check; /* health-check specific configuration */
|
||||||
struct check agent; /* agent specific configuration */
|
struct check agent; /* agent specific configuration */
|
||||||
|
|
||||||
|
char *resolvers_id; /* resolvers section used by this server */
|
||||||
|
char *hostname; /* server hostname */
|
||||||
|
struct dns_resolution *resolution; /* server name resolution */
|
||||||
|
int resolver_family_priority; /* which IP family should the resolver use when both are returned */
|
||||||
|
|
||||||
#ifdef USE_OPENSSL
|
#ifdef USE_OPENSSL
|
||||||
int use_ssl; /* ssl enabled */
|
int use_ssl; /* ssl enabled */
|
||||||
struct {
|
struct {
|
||||||
|
|||||||
@ -8103,6 +8103,47 @@ out_uri_auth_compat:
|
|||||||
free(newsrv->trackit);
|
free(newsrv->trackit);
|
||||||
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 {
|
||||||
|
free(newsrv->resolvers_id);
|
||||||
|
newsrv->resolvers_id = NULL;
|
||||||
|
if (newsrv->resolution)
|
||||||
|
newsrv->resolution->resolvers = curr_resolvers;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|||||||
95
src/checks.c
95
src/checks.c
@ -38,6 +38,7 @@
|
|||||||
|
|
||||||
#include <types/global.h>
|
#include <types/global.h>
|
||||||
#include <types/mailers.h>
|
#include <types/mailers.h>
|
||||||
|
#include <types/dns.h>
|
||||||
|
|
||||||
#ifdef USE_OPENSSL
|
#ifdef USE_OPENSSL
|
||||||
#include <types/ssl_sock.h>
|
#include <types/ssl_sock.h>
|
||||||
@ -59,6 +60,9 @@
|
|||||||
#include <proto/server.h>
|
#include <proto/server.h>
|
||||||
#include <proto/stream_interface.h>
|
#include <proto/stream_interface.h>
|
||||||
#include <proto/task.h>
|
#include <proto/task.h>
|
||||||
|
#include <proto/log.h>
|
||||||
|
#include <proto/dns.h>
|
||||||
|
#include <proto/proto_udp.h>
|
||||||
|
|
||||||
static int httpchk_expect(struct server *s, int done);
|
static int httpchk_expect(struct server *s, int done);
|
||||||
static int tcpcheck_get_step_id(struct check *);
|
static int tcpcheck_get_step_id(struct check *);
|
||||||
@ -680,6 +684,14 @@ static void chk_report_conn_err(struct connection *conn, int errno_bck, int expi
|
|||||||
set_server_check_status(check, HCHK_STATUS_L4CON, err_msg);
|
set_server_check_status(check, HCHK_STATUS_L4CON, err_msg);
|
||||||
else if (expired)
|
else if (expired)
|
||||||
set_server_check_status(check, HCHK_STATUS_L4TOUT, err_msg);
|
set_server_check_status(check, HCHK_STATUS_L4TOUT, err_msg);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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))
|
||||||
|
trigger_resolution(check->server);
|
||||||
|
|
||||||
}
|
}
|
||||||
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) {
|
||||||
/* L6 not established (yet) */
|
/* L6 not established (yet) */
|
||||||
@ -2132,10 +2144,93 @@ static struct task *process_chk_conn(struct task *t)
|
|||||||
static struct task *process_chk(struct task *t)
|
static struct task *process_chk(struct task *t)
|
||||||
{
|
{
|
||||||
struct check *check = t->context;
|
struct check *check = t->context;
|
||||||
|
struct server *s = check->server;
|
||||||
|
struct dns_resolution *resolution = s->resolution;
|
||||||
|
|
||||||
|
/* trigger name resolution */
|
||||||
|
if ((s->check.state & CHK_ST_ENABLED) && (resolution)) {
|
||||||
|
/* check if a no resolution is running for this server */
|
||||||
|
if (resolution->step == RSLV_STEP_NONE) {
|
||||||
|
/*
|
||||||
|
* if there has not been any name resolution for a longer period than
|
||||||
|
* hold.valid, let's trigger a new one.
|
||||||
|
*/
|
||||||
|
if (tick_is_expired(tick_add(resolution->last_resolution, resolution->resolvers->hold.valid), now_ms)) {
|
||||||
|
trigger_resolution(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (check->type == PR_O2_EXT_CHK)
|
if (check->type == PR_O2_EXT_CHK)
|
||||||
return process_chk_proc(t);
|
return process_chk_proc(t);
|
||||||
return process_chk_conn(t);
|
return process_chk_conn(t);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initiates a new name resolution:
|
||||||
|
* - generates a query id
|
||||||
|
* - configure the resolution structure
|
||||||
|
* - startup the resolvers task if required
|
||||||
|
*
|
||||||
|
* returns:
|
||||||
|
* - 0 in case of error or if resolution already running
|
||||||
|
* - 1 if everything started properly
|
||||||
|
*/
|
||||||
|
int trigger_resolution(struct server *s)
|
||||||
|
{
|
||||||
|
struct dns_resolution *resolution;
|
||||||
|
struct dns_resolvers *resolvers;
|
||||||
|
int query_id;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
resolution = s->resolution;
|
||||||
|
resolvers = resolution->resolvers;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* check if a resolution has already been started for this server
|
||||||
|
* return directly to avoid resolution pill up
|
||||||
|
*/
|
||||||
|
if (resolution->step != RSLV_STEP_NONE)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* generates a query id */
|
||||||
|
i = 0;
|
||||||
|
do {
|
||||||
|
query_id = dns_rnd16();
|
||||||
|
/* we do try only 100 times to find a free query id */
|
||||||
|
if (i++ > 100) {
|
||||||
|
chunk_printf(&trash, "could not generate a query id for %s/%s, in resolvers %s",
|
||||||
|
s->proxy->id, s->id, resolvers->id);
|
||||||
|
|
||||||
|
send_log(s->proxy, LOG_NOTICE, "%s.\n", trash.str);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} while (eb32_lookup(&resolvers->query_ids, query_id));
|
||||||
|
|
||||||
|
LIST_ADDQ(&resolvers->curr_resolution, &resolution->list);
|
||||||
|
|
||||||
|
/* now update resolution parameters */
|
||||||
|
resolution->query_id = query_id;
|
||||||
|
resolution->qid.key = query_id;
|
||||||
|
resolution->step = RSLV_STEP_RUNNING;
|
||||||
|
resolution->query_type = DNS_RTYPE_ANY;
|
||||||
|
resolution->try = 0;
|
||||||
|
resolution->try_cname = 0;
|
||||||
|
resolution->nb_responses = 0;
|
||||||
|
resolution->resolver_family_priority = s->resolver_family_priority;
|
||||||
|
eb32_insert(&resolvers->query_ids, &resolution->qid);
|
||||||
|
|
||||||
|
dns_send_query(resolution);
|
||||||
|
|
||||||
|
/* update wakeup date if this resolution is the only one in the FIFO list */
|
||||||
|
if (dns_check_resolution_queue(resolvers) == 1) {
|
||||||
|
/* update task timeout */
|
||||||
|
dns_update_resolvers_timeout(resolvers);
|
||||||
|
task_queue(resolvers->t);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int start_check_task(struct check *check, int mininter,
|
static int start_check_task(struct check *check, int mininter,
|
||||||
|
|||||||
306
src/server.c
306
src/server.c
@ -20,6 +20,7 @@
|
|||||||
#include <common/time.h>
|
#include <common/time.h>
|
||||||
|
|
||||||
#include <types/global.h>
|
#include <types/global.h>
|
||||||
|
#include <types/dns.h>
|
||||||
|
|
||||||
#include <proto/checks.h>
|
#include <proto/checks.h>
|
||||||
#include <proto/port_range.h>
|
#include <proto/port_range.h>
|
||||||
@ -29,6 +30,7 @@
|
|||||||
#include <proto/server.h>
|
#include <proto/server.h>
|
||||||
#include <proto/stream.h>
|
#include <proto/stream.h>
|
||||||
#include <proto/task.h>
|
#include <proto/task.h>
|
||||||
|
#include <proto/dns.h>
|
||||||
|
|
||||||
|
|
||||||
/* List head of all known server keywords */
|
/* List head of all known server keywords */
|
||||||
@ -865,6 +867,7 @@ int parse_server(const char *file, int linenum, char **args, struct proxy *curpr
|
|||||||
struct sockaddr_storage *sk;
|
struct sockaddr_storage *sk;
|
||||||
int port1, port2;
|
int port1, port2;
|
||||||
struct protocol *proto;
|
struct protocol *proto;
|
||||||
|
struct dns_resolution *curr_resolution;
|
||||||
|
|
||||||
if ((newsrv = (struct server *)calloc(1, sizeof(struct server))) == NULL) {
|
if ((newsrv = (struct server *)calloc(1, sizeof(struct server))) == NULL) {
|
||||||
Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
|
Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
|
||||||
@ -928,6 +931,53 @@ int parse_server(const char *file, int linenum, char **args, struct proxy *curpr
|
|||||||
realport = port1;
|
realport = port1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* save hostname and create associated name resolution */
|
||||||
|
switch (sk->ss_family) {
|
||||||
|
case AF_INET: {
|
||||||
|
/* remove the port if any */
|
||||||
|
char *c;
|
||||||
|
if ((c = rindex(args[2], ':')) != NULL) {
|
||||||
|
newsrv->hostname = my_strndup(args[2], c - args[2]);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
newsrv->hostname = strdup(args[2]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case AF_INET6:
|
||||||
|
newsrv->hostname = strdup(args[2]);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
goto skip_name_resolution;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* no name resolution if an IP has been provided */
|
||||||
|
if (inet_pton(sk->ss_family, newsrv->hostname, trash.str) == 1)
|
||||||
|
goto skip_name_resolution;
|
||||||
|
|
||||||
|
if ((curr_resolution = calloc(1, sizeof(struct dns_resolution))) == NULL)
|
||||||
|
goto skip_name_resolution;
|
||||||
|
|
||||||
|
curr_resolution->hostname_dn_len = dns_str_to_dn_label_len(newsrv->hostname);
|
||||||
|
if ((curr_resolution->hostname_dn = calloc(curr_resolution->hostname_dn_len + 1, sizeof(char))) == NULL)
|
||||||
|
goto skip_name_resolution;
|
||||||
|
if ((dns_str_to_dn_label(newsrv->hostname, curr_resolution->hostname_dn, curr_resolution->hostname_dn_len + 1)) == NULL) {
|
||||||
|
Alert("parsing [%s:%d] : Invalid hostname '%s'\n",
|
||||||
|
file, linenum, args[2]);
|
||||||
|
err_code |= ERR_ALERT | ERR_FATAL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
curr_resolution->requester = newsrv;
|
||||||
|
curr_resolution->requester_cb = snr_resolution_cb;
|
||||||
|
curr_resolution->requester_error_cb = snr_resolution_error_cb;
|
||||||
|
curr_resolution->status = RSLV_STATUS_NONE;
|
||||||
|
curr_resolution->step = RSLV_STEP_NONE;
|
||||||
|
/* a first resolution has been done by the configuration parser */
|
||||||
|
curr_resolution->last_resolution = now_ms;
|
||||||
|
newsrv->resolution = curr_resolution;
|
||||||
|
|
||||||
|
skip_name_resolution:
|
||||||
newsrv->addr = *sk;
|
newsrv->addr = *sk;
|
||||||
newsrv->xprt = newsrv->check.xprt = newsrv->agent.xprt = &raw_sock;
|
newsrv->xprt = newsrv->check.xprt = newsrv->agent.xprt = &raw_sock;
|
||||||
|
|
||||||
@ -975,11 +1025,15 @@ int parse_server(const char *file, int linenum, char **args, struct proxy *curpr
|
|||||||
newsrv->agent.fall = curproxy->defsrv.agent.fall;
|
newsrv->agent.fall = curproxy->defsrv.agent.fall;
|
||||||
newsrv->agent.health = newsrv->agent.rise; /* up, but will fall down at first failure */
|
newsrv->agent.health = newsrv->agent.rise; /* up, but will fall down at first failure */
|
||||||
newsrv->agent.server = newsrv;
|
newsrv->agent.server = newsrv;
|
||||||
|
newsrv->resolver_family_priority = curproxy->defsrv.resolver_family_priority;
|
||||||
|
if (newsrv->resolver_family_priority == AF_UNSPEC)
|
||||||
|
newsrv->resolver_family_priority = AF_INET6;
|
||||||
|
|
||||||
cur_arg = 3;
|
cur_arg = 3;
|
||||||
} else {
|
} else {
|
||||||
newsrv = &curproxy->defsrv;
|
newsrv = &curproxy->defsrv;
|
||||||
cur_arg = 1;
|
cur_arg = 1;
|
||||||
|
newsrv->resolver_family_priority = AF_INET6;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (*args[cur_arg]) {
|
while (*args[cur_arg]) {
|
||||||
@ -1019,6 +1073,23 @@ int parse_server(const char *file, int linenum, char **args, struct proxy *curpr
|
|||||||
newsrv->rdr_len = strlen(args[cur_arg + 1]);
|
newsrv->rdr_len = strlen(args[cur_arg + 1]);
|
||||||
cur_arg += 2;
|
cur_arg += 2;
|
||||||
}
|
}
|
||||||
|
else if (!strcmp(args[cur_arg], "resolvers")) {
|
||||||
|
newsrv->resolvers_id = strdup(args[cur_arg + 1]);
|
||||||
|
cur_arg += 2;
|
||||||
|
}
|
||||||
|
else if (!strcmp(args[cur_arg], "resolve-prefer")) {
|
||||||
|
if (!strcmp(args[cur_arg + 1], "ipv4"))
|
||||||
|
newsrv->resolver_family_priority = AF_INET;
|
||||||
|
else if (!strcmp(args[cur_arg + 1], "ipv6"))
|
||||||
|
newsrv->resolver_family_priority = AF_INET6;
|
||||||
|
else {
|
||||||
|
Alert("parsing [%s:%d]: '%s' expects either ipv4 or ipv6 as argument.\n",
|
||||||
|
file, linenum, args[cur_arg]);
|
||||||
|
err_code |= ERR_ALERT | ERR_FATAL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
cur_arg += 2;
|
||||||
|
}
|
||||||
else if (!strcmp(args[cur_arg], "rise")) {
|
else if (!strcmp(args[cur_arg], "rise")) {
|
||||||
if (!*args[cur_arg + 1]) {
|
if (!*args[cur_arg + 1]) {
|
||||||
Alert("parsing [%s:%d]: '%s' expects an integer argument.\n",
|
Alert("parsing [%s:%d]: '%s' expects an integer argument.\n",
|
||||||
@ -1677,6 +1748,9 @@ int parse_server(const char *file, int linenum, char **args, struct proxy *curpr
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (newsrv->resolution)
|
||||||
|
newsrv->resolution->resolver_family_priority = newsrv->resolver_family_priority;
|
||||||
|
|
||||||
newsrv->check.state |= CHK_ST_CONFIGURED | CHK_ST_ENABLED;
|
newsrv->check.state |= CHK_ST_CONFIGURED | CHK_ST_ENABLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1785,6 +1859,238 @@ int update_server_addr(struct server *s, void *ip, int ip_sin_family, char *upda
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* update server status based on result of name resolution
|
||||||
|
* returns:
|
||||||
|
* 0 if server status is updated
|
||||||
|
* 1 if server status has not changed
|
||||||
|
*/
|
||||||
|
int snr_update_srv_status(struct server *s)
|
||||||
|
{
|
||||||
|
struct dns_resolution *resolution = s->resolution;
|
||||||
|
|
||||||
|
switch (resolution->status) {
|
||||||
|
case RSLV_STATUS_NONE:
|
||||||
|
/* status when HAProxy has just (re)started */
|
||||||
|
trigger_resolution(s);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Server Name Resolution valid response callback
|
||||||
|
* It expects:
|
||||||
|
* - <nameserver>: the name server which answered the valid response
|
||||||
|
* - <response>: buffer containing a valid DNS response
|
||||||
|
* - <response_len>: size of <response>
|
||||||
|
* It performs the following actions:
|
||||||
|
* - ignore response if current ip found and server family not met
|
||||||
|
* - update with first new ip found if family is met and current IP is not found
|
||||||
|
* returns:
|
||||||
|
* 0 on error
|
||||||
|
* 1 when no error or safe ignore
|
||||||
|
*/
|
||||||
|
int snr_resolution_cb(struct dns_resolution *resolution, struct dns_nameserver *nameserver, unsigned char *response, int response_len)
|
||||||
|
{
|
||||||
|
struct server *s;
|
||||||
|
void *serverip, *firstip;
|
||||||
|
short server_sin_family, firstip_sin_family;
|
||||||
|
unsigned char *response_end;
|
||||||
|
int ret;
|
||||||
|
struct chunk *chk = get_trash_chunk();
|
||||||
|
|
||||||
|
/* initializing variables */
|
||||||
|
response_end = response + response_len; /* pointer to mark the end of the response */
|
||||||
|
firstip = NULL; /* pointer to the first valid response found */
|
||||||
|
/* it will be used as the new IP if a change is required */
|
||||||
|
firstip_sin_family = AF_UNSPEC;
|
||||||
|
serverip = NULL; /* current server IP address */
|
||||||
|
|
||||||
|
/* shortcut to the server whose name is being resolved */
|
||||||
|
s = (struct server *)resolution->requester;
|
||||||
|
|
||||||
|
/* initializing server IP pointer */
|
||||||
|
server_sin_family = s->addr.ss_family;
|
||||||
|
switch (server_sin_family) {
|
||||||
|
case AF_INET:
|
||||||
|
serverip = &((struct sockaddr_in *)&s->addr)->sin_addr.s_addr;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AF_INET6:
|
||||||
|
serverip = &((struct sockaddr_in6 *)&s->addr)->sin6_addr.s6_addr;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
goto invalid;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = dns_get_ip_from_response(response, response_end, resolution->hostname_dn, resolution->hostname_dn_len,
|
||||||
|
serverip, server_sin_family, resolution->resolver_family_priority, &firstip,
|
||||||
|
&firstip_sin_family);
|
||||||
|
|
||||||
|
switch (ret) {
|
||||||
|
case DNS_UPD_NO:
|
||||||
|
if (resolution->status != RSLV_STATUS_VALID) {
|
||||||
|
resolution->status = RSLV_STATUS_VALID;
|
||||||
|
resolution->last_status_change = now_ms;
|
||||||
|
}
|
||||||
|
goto stop_resolution;
|
||||||
|
|
||||||
|
case DNS_UPD_SRVIP_NOT_FOUND:
|
||||||
|
goto save_ip;
|
||||||
|
|
||||||
|
case DNS_UPD_CNAME:
|
||||||
|
if (resolution->status != RSLV_STATUS_VALID) {
|
||||||
|
resolution->status = RSLV_STATUS_VALID;
|
||||||
|
resolution->last_status_change = now_ms;
|
||||||
|
}
|
||||||
|
goto invalid;
|
||||||
|
|
||||||
|
default:
|
||||||
|
goto invalid;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
save_ip:
|
||||||
|
nameserver->counters.update += 1;
|
||||||
|
if (resolution->status != RSLV_STATUS_VALID) {
|
||||||
|
resolution->status = RSLV_STATUS_VALID;
|
||||||
|
resolution->last_status_change = now_ms;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* save the first ip we found */
|
||||||
|
chunk_printf(chk, "%s/%s", nameserver->resolvers->id, nameserver->id);
|
||||||
|
update_server_addr(s, firstip, firstip_sin_family, (char *)chk->str);
|
||||||
|
|
||||||
|
stop_resolution:
|
||||||
|
/* update last resolution date and time */
|
||||||
|
resolution->last_resolution = now_ms;
|
||||||
|
/* reset current status flag */
|
||||||
|
resolution->step = RSLV_STEP_NONE;
|
||||||
|
/* reset values */
|
||||||
|
dns_reset_resolution(resolution);
|
||||||
|
|
||||||
|
LIST_DEL(&resolution->list);
|
||||||
|
dns_update_resolvers_timeout(nameserver->resolvers);
|
||||||
|
|
||||||
|
snr_update_srv_status(s);
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
invalid:
|
||||||
|
nameserver->counters.invalid += 1;
|
||||||
|
if (resolution->nb_responses >= nameserver->resolvers->count_nameservers)
|
||||||
|
goto stop_resolution;
|
||||||
|
|
||||||
|
snr_update_srv_status(s);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Server Name Resolution error management callback
|
||||||
|
* returns:
|
||||||
|
* 0 on error
|
||||||
|
* 1 when no error or safe ignore
|
||||||
|
*/
|
||||||
|
int snr_resolution_error_cb(struct dns_resolution *resolution, int error_code)
|
||||||
|
{
|
||||||
|
struct server *s;
|
||||||
|
struct dns_resolvers *resolvers;
|
||||||
|
|
||||||
|
/* shortcut to the server whose name is being resolved */
|
||||||
|
s = (struct server *)resolution->requester;
|
||||||
|
resolvers = resolution->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;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (error_code) {
|
||||||
|
case DNS_RESP_INVALID:
|
||||||
|
case DNS_RESP_WRONG_NAME:
|
||||||
|
if (resolution->status != RSLV_STATUS_INVALID) {
|
||||||
|
resolution->status = RSLV_STATUS_INVALID;
|
||||||
|
resolution->last_status_change = now_ms;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DNS_RESP_ANCOUNT_ZERO:
|
||||||
|
case DNS_RESP_ERROR:
|
||||||
|
if (resolution->query_type == DNS_RTYPE_ANY) {
|
||||||
|
/* let's change the query type */
|
||||||
|
if (resolution->resolver_family_priority == AF_INET6)
|
||||||
|
resolution->query_type = DNS_RTYPE_AAAA;
|
||||||
|
else
|
||||||
|
resolution->query_type = DNS_RTYPE_A;
|
||||||
|
|
||||||
|
dns_send_query(resolution);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* move the resolution to the last element of the FIFO queue
|
||||||
|
* and update timeout wakeup based on the new first entry
|
||||||
|
*/
|
||||||
|
if (dns_check_resolution_queue(resolvers) > 1) {
|
||||||
|
/* second resolution becomes first one */
|
||||||
|
LIST_DEL(&resolvers->curr_resolution);
|
||||||
|
/* ex first resolution goes to the end of the queue */
|
||||||
|
LIST_ADDQ(&resolvers->curr_resolution, &resolution->list);
|
||||||
|
}
|
||||||
|
dns_update_resolvers_timeout(resolvers);
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (resolution->status != RSLV_STATUS_OTHER) {
|
||||||
|
resolution->status = RSLV_STATUS_OTHER;
|
||||||
|
resolution->last_status_change = now_ms;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DNS_RESP_NX_DOMAIN:
|
||||||
|
if (resolution->status != RSLV_STATUS_NX) {
|
||||||
|
resolution->status = RSLV_STATUS_NX;
|
||||||
|
resolution->last_status_change = now_ms;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DNS_RESP_REFUSED:
|
||||||
|
if (resolution->status != RSLV_STATUS_REFUSED) {
|
||||||
|
resolution->status = RSLV_STATUS_REFUSED;
|
||||||
|
resolution->last_status_change = now_ms;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DNS_RESP_CNAME_ERROR:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DNS_RESP_TIMEOUT:
|
||||||
|
if (resolution->status != RSLV_STATUS_TIMEOUT) {
|
||||||
|
resolution->status = RSLV_STATUS_TIMEOUT;
|
||||||
|
resolution->last_status_change = now_ms;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* update last resolution date and time */
|
||||||
|
resolution->last_resolution = now_ms;
|
||||||
|
/* reset current status flag */
|
||||||
|
resolution->step = RSLV_STEP_NONE;
|
||||||
|
/* reset values */
|
||||||
|
dns_reset_resolution(resolution);
|
||||||
|
|
||||||
|
LIST_DEL(&resolution->list);
|
||||||
|
dns_update_resolvers_timeout(resolvers);
|
||||||
|
|
||||||
|
leave:
|
||||||
|
snr_update_srv_status(s);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Local variables:
|
* Local variables:
|
||||||
* c-indent-level: 8
|
* c-indent-level: 8
|
||||||
|
|||||||
@ -25,6 +25,7 @@
|
|||||||
#include <common/config.h>
|
#include <common/config.h>
|
||||||
#include <common/standard.h>
|
#include <common/standard.h>
|
||||||
#include <types/global.h>
|
#include <types/global.h>
|
||||||
|
#include <proto/dns.h>
|
||||||
#include <eb32tree.h>
|
#include <eb32tree.h>
|
||||||
|
|
||||||
/* enough to store NB_ITOA_STR integers of :
|
/* enough to store NB_ITOA_STR integers of :
|
||||||
@ -608,6 +609,9 @@ struct sockaddr_storage *str2ip2(const char *str, struct sockaddr_storage *sa, i
|
|||||||
if (!resolve)
|
if (!resolve)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
if (!dns_hostname_validation(str, NULL))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
#ifdef USE_GETADDRINFO
|
#ifdef USE_GETADDRINFO
|
||||||
if (global.tune.options & GTUNE_USE_GAI) {
|
if (global.tune.options & GTUNE_USE_GAI) {
|
||||||
struct addrinfo hints, *result;
|
struct addrinfo hints, *result;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user