diff --git a/include/proto/dns.h b/include/proto/dns.h index 12f039344..ffb1cac65 100644 --- a/include/proto/dns.h +++ b/include/proto/dns.h @@ -33,10 +33,11 @@ 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_response_packet *dns_p); -int dns_get_ip_from_response(struct dns_response_packet *dns_p, struct dns_resolution *resol, +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 **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); diff --git a/include/proto/server.h b/include/proto/server.h index 6e3ccf39f..ec29230e8 100644 --- a/include/proto/server.h +++ b/include/proto/server.h @@ -55,6 +55,7 @@ struct server *cli_find_server(struct appctx *appctx, char *arg); int snr_update_srv_status(struct server *s); int snr_resolution_cb(struct dns_resolution *resolution, struct dns_nameserver *nameserver, struct dns_response_packet *dns_p); int snr_resolution_error_cb(struct dns_resolution *resolution, int error_code); +struct server *snr_check_ip_callback(struct server *srv, void *ip, unsigned char *ip_family); /* increase the number of cumulated connections on the designated server */ static void inline srv_inc_sess_ctr(struct server *s) diff --git a/src/dns.c b/src/dns.c index ca6ff8ff3..0a1c5208b 100644 --- a/src/dns.c +++ b/src/dns.c @@ -719,10 +719,11 @@ int dns_validate_dns_response(unsigned char *resp, unsigned char *bufend, struct * returns one of the DNS_UPD_* code */ #define DNS_MAX_IP_REC 20 -int dns_get_ip_from_response(struct dns_response_packet *dns_p, struct dns_resolution *resol, +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 **newip, short *newip_sin_family, + void *owner) { struct dns_answer_item *record; int family_priority; @@ -788,8 +789,6 @@ int dns_get_ip_from_response(struct dns_response_packet *dns_p, struct dns_resol */ max_score = -1; for (i = 0; i < rec_nb; i++) { - struct server *srv, *tmpsrv; - struct proxy *be; int record_ip_already_affected = 0; score = 0; @@ -818,36 +817,14 @@ int dns_get_ip_from_response(struct dns_response_packet *dns_p, struct dns_resol } } - /* Check if the IP found in the record is already affected to an other server. */ - srv = resol->requester; - be = srv->proxy; - for (tmpsrv = be->srv; tmpsrv; tmpsrv = tmpsrv->next) { - /* We want to compare the IP in the record with the IP of the servers in the - * same backend, only if: - * * DNS resolution is enabled on the server - * * the hostname used for the resolution by our server is the same than the - * one used for the server found in the backend - * * the server found in the backend is not our current server - */ - if ((tmpsrv->resolution == NULL) || - (srv->resolution->hostname_dn_len != tmpsrv->resolution->hostname_dn_len) || - (strcmp(srv->resolution->hostname_dn, tmpsrv->resolution->hostname_dn) != 0) || - (srv->puid == tmpsrv->puid)) - continue; - - /* At this point, we have 2 different servers using the same DNS hostname - * for their respective resolution. - */ - if (rec[i].type == tmpsrv->addr.ss_family && - ((tmpsrv->addr.ss_family == AF_INET && - memcmp(rec[i].ip, &((struct sockaddr_in *)&tmpsrv->addr)->sin_addr, 4) == 0) || - (tmpsrv->addr.ss_family == AF_INET6 && - memcmp(rec[i].ip, &((struct sockaddr_in6 *)&tmpsrv->addr)->sin6_addr, 16) == 0))) { + /* Check if the IP found in the record is already affected to a member of a group. + * If yes, the score should be incremented by 2. + */ + if (owner) { + if (snr_check_ip_callback(owner, rec[i].ip, &rec[i].type)) record_ip_already_affected = 1; - break; - } } - if (!record_ip_already_affected) + if (record_ip_already_affected == 0) score += 2; /* Check for current ip matching. */ diff --git a/src/server.c b/src/server.c index f67505c3a..9970cde60 100644 --- a/src/server.c +++ b/src/server.c @@ -3859,9 +3859,9 @@ int snr_resolution_cb(struct dns_resolution *resolution, struct dns_nameserver * goto invalid; } - ret = dns_get_ip_from_response(dns_p, resolution, &s->dns_opts, + ret = dns_get_ip_from_response(dns_p, &s->dns_opts, serverip, server_sin_family, &firstip, - &firstip_sin_family); + &firstip_sin_family, s); switch (ret) { case DNS_UPD_NO: @@ -4055,6 +4055,51 @@ int snr_resolution_error_cb(struct dns_resolution *resolution, int error_code) return 1; } +/* + * Function to check if is already affected to a server in the backend + * which owns . + * It returns a pointer to the first server found or NULL if is not yet + * assigned. + * NOTE: and are provided by a 'struct rec' available in dns.c. + */ +struct server *snr_check_ip_callback(struct server *srv, void *ip, unsigned char *ip_family) +{ + struct server *tmpsrv; + struct proxy *be; + + if (!srv) + return NULL; + + be = srv->proxy; + for (tmpsrv = be->srv; tmpsrv; tmpsrv = tmpsrv->next) { + /* We want to compare the IP in the record with the IP of the servers in the + * same backend, only if: + * * DNS resolution is enabled on the server + * * the hostname used for the resolution by our server is the same than the + * one used for the server found in the backend + * * the server found in the backend is not our current server + */ + if ((tmpsrv->resolution == NULL) || + (srv->resolution->hostname_dn_len != tmpsrv->resolution->hostname_dn_len) || + (strcmp(srv->resolution->hostname_dn, tmpsrv->resolution->hostname_dn) != 0) || + (srv->puid == tmpsrv->puid)) + continue; + + /* At this point, we have 2 different servers using the same DNS hostname + * for their respective resolution. + */ + if (*ip_family == tmpsrv->addr.ss_family && + ((tmpsrv->addr.ss_family == AF_INET && + memcmp(ip, &((struct sockaddr_in *)&tmpsrv->addr)->sin_addr, 4) == 0) || + (tmpsrv->addr.ss_family == AF_INET6 && + memcmp(ip, &((struct sockaddr_in6 *)&tmpsrv->addr)->sin6_addr, 16) == 0))) { + return tmpsrv; + } + } + + return NULL; +} + /* Sets the server's address (srv->addr) from srv->hostname using the libc's * resolver. This is suited for initial address configuration. Returns 0 on * success otherwise a non-zero error code. In case of error, *err_code, if