]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: dns: new snr_check_ip_callback function
authorBaptiste Assmann <bedis9@gmail.com>
Wed, 3 May 2017 13:43:12 +0000 (15:43 +0200)
committerWilly Tarreau <w@1wt.eu>
Fri, 2 Jun 2017 09:28:14 +0000 (11:28 +0200)
In the process of breaking links between dns_* functions and other
structures (mainly server and a bit of resolution), the function
dns_get_ip_from_response needs to be reworked: it now can call
"callback" functions based on resolution's owner type to allow modifying
the way the response is processed.

For now, main purpose of the callback function is to check that an IP
address is not already affected to an element of the same type.

For now, only server type has a callback.

include/proto/dns.h
include/proto/server.h
src/dns.c
src/server.c

index 12f0393443195015498dd731470f31fd9df37422..ffb1cac65a1216cd01f617ea6c9d67581bff223c 100644 (file)
@@ -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);
index 6e3ccf39fe39d9799ba80ed4557a3509140691da..ec29230e8c198865491f513095a9b97eb3b79f7d 100644 (file)
@@ -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)
index ca6ff8ff3ecc3921b6701386da5deb7b8fd7b4ae..0a1c5208bd325e5f0416403077676ab338329897 100644 (file)
--- 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. */
index f67505c3a34eb6aac8c357726c2a7e0d4ff20c74..9970cde605cd51dbf6dbd4d23e1500249efd2919 100644 (file)
@@ -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 <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