]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
BUG/MEDIUM: dns: Be sure to renew IP address for already known servers
authorChristopher Faulet <cfaulet@haproxy.com>
Tue, 8 Sep 2020 08:27:24 +0000 (10:27 +0200)
committerChristopher Faulet <cfaulet@haproxy.com>
Tue, 8 Sep 2020 08:44:57 +0000 (10:44 +0200)
When a SRV record for an already known server is processed, only the weight is
updated, if not configured to be ignored. It is a problem if the IP address
carried by the associated additional record changes. Because the server IP
address is never renewed.

To fix this bug, If there is an addition record attached to a SRV record, we
always try to set the IP address. If it is the same, no change is
performed. This way, IP changes are always handled.

This patch should fix the issue #841. It must be backported to 2.2.

src/dns.c
src/server.c

index 8b0e659ae273c0037f27c4b7ef5273280cd0973a..c38152d7f6c3096c9b5ca2744db568b4ba0a320a 100644 (file)
--- a/src/dns.c
+++ b/src/dns.c
@@ -582,50 +582,24 @@ static void dns_check_dns_response(struct dns_resolution *res)
                                HA_SPIN_LOCK(SERVER_LOCK, &srv->lock);
                                if (srv->srvrq == srvrq && srv->svc_port == item->port &&
                                    item->data_len == srv->hostname_dn_len &&
-                                   !dns_hostname_cmp(srv->hostname_dn, item->target, item->data_len) &&
-                                   !srv->dns_opts.ignore_weight) {
-                                       int ha_weight;
-
-                                       /* DNS weight range if from 0 to 65535
-                                        * HAProxy weight is from 0 to 256
-                                        * The rule below ensures that weight 0 is well respected
-                                        * while allowing a "mapping" from DNS weight into HAProxy's one.
-                                        */
-                                       ha_weight = (item->weight + 255) / 256;
-                                       if (srv->uweight != ha_weight) {
-                                               char weight[9];
-
-                                               snprintf(weight, sizeof(weight), "%d", ha_weight);
-                                               server_parse_weight_change_request(srv, weight);
-                                       }
-                                       HA_SPIN_UNLOCK(SERVER_LOCK, &srv->lock);
+                                   !dns_hostname_cmp(srv->hostname_dn, item->target, item->data_len)) {
                                        break;
                                }
                                HA_SPIN_UNLOCK(SERVER_LOCK, &srv->lock);
                        }
-                       if (srv)
-                               continue;
 
                        /* If not, try to find a server with undefined hostname */
-                       for (srv = srvrq->proxy->srv; srv != NULL; srv = srv->next) {
-                               HA_SPIN_LOCK(SERVER_LOCK, &srv->lock);
-                               if (srv->srvrq == srvrq && !srv->hostname_dn)
-                                       break;
-                               HA_SPIN_UNLOCK(SERVER_LOCK, &srv->lock);
-                       }
-                       /* And update this server, if found */
-                       if (srv) {
-                               const char *msg = NULL;
-                               char weight[9];
-                               int ha_weight;
-                               char hostname[DNS_MAX_NAME_SIZE];
-
-                               if (dns_dn_label_to_str(item->target, item->data_len+1,
-                                                       hostname, DNS_MAX_NAME_SIZE) == -1) {
+                       if (!srv) {
+                               for (srv = srvrq->proxy->srv; srv != NULL; srv = srv->next) {
+                                       HA_SPIN_LOCK(SERVER_LOCK, &srv->lock);
+                                       if (srv->srvrq == srvrq && !srv->hostname_dn)
+                                               break;
                                        HA_SPIN_UNLOCK(SERVER_LOCK, &srv->lock);
-                                       continue;
                                }
+                       }
 
+                       /* And update this server, if found (srv is locked here) */
+                       if (srv) {
                                /* Check if an Additional Record is associated to this SRV record.
                                 * Perform some sanity checks too to ensure the record can be used.
                                 * If all fine, we simply pick up the IP address found and associate
@@ -647,9 +621,19 @@ static void dns_check_dns_response(struct dns_resolution *res)
                                        srv->flags |= SRV_F_NO_RESOLUTION;
                                }
 
-                               msg = update_server_fqdn(srv, hostname, "SRV record", 1);
-                               if (msg)
-                                       send_log(srv->proxy, LOG_NOTICE, "%s", msg);
+                               if (!srv->hostname_dn) {
+                                       const char *msg = NULL;
+                                       char hostname[DNS_MAX_NAME_SIZE];
+
+                                       if (dns_dn_label_to_str(item->target, item->data_len+1,
+                                                               hostname, DNS_MAX_NAME_SIZE) == -1) {
+                                               HA_SPIN_UNLOCK(SERVER_LOCK, &srv->lock);
+                                               continue;
+                                       }
+                                       msg = update_server_fqdn(srv, hostname, "SRV record", 1);
+                                       if (msg)
+                                               send_log(srv->proxy, LOG_NOTICE, "%s", msg);
+                               }
 
                                /* now we have an IP address associated to this server, we can update its status */
                                snr_update_srv_status(srv, 0);
@@ -661,6 +645,9 @@ static void dns_check_dns_response(struct dns_resolution *res)
                                        srv->check.port = item->port;
 
                                if (!srv->dns_opts.ignore_weight) {
+                                       char weight[9];
+                                       int ha_weight;
+
                                        /* DNS weight range if from 0 to 65535
                                         * HAProxy weight is from 0 to 256
                                         * The rule below ensures that weight 0 is well respected
index 3f26104ccf61a27737501926b9191e57f901c328..56ee6a19fb2aa417471177805f4d9a69bf2a720f 100644 (file)
@@ -3485,6 +3485,20 @@ void apply_server_state(void)
  */
 int update_server_addr(struct server *s, void *ip, int ip_sin_family, const char *updater)
 {
+       /* save the new IP family & address if necessary */
+       switch (ip_sin_family) {
+       case AF_INET:
+               if (s->addr.ss_family == ip_sin_family &&
+                   !memcmp(ip, &((struct sockaddr_in *)&s->addr)->sin_addr.s_addr, 4))
+                       return 0;
+               break;
+       case AF_INET6:
+               if (s->addr.ss_family == ip_sin_family &&
+                   !memcmp(ip, &((struct sockaddr_in6 *)&s->addr)->sin6_addr.s6_addr, 16))
+                       return 0;
+               break;
+       };
+
        /* generates a log line and a warning on stderr */
        if (1) {
                /* book enough space for both IPv4 and IPv6 */