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);
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)
* 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;
*/
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;
}
}
- /* 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. */
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:
return 1;
}
+/*
+ * Function to check if <ip> is already affected to a server in the backend
+ * which owns <srv>.
+ * It returns a pointer to the first server found or NULL if <ip> is not yet
+ * assigned.
+ * NOTE: <ip> and <ip_family> 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