]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
BUG/MEDIUM: dns: Consider the fact that dns answers are case-insensitive
authorOlivier Houchard <cognet@ci0.org>
Wed, 1 Apr 2020 16:30:27 +0000 (18:30 +0200)
committerOlivier Houchard <cognet@ci0.org>
Wed, 1 Apr 2020 16:35:05 +0000 (18:35 +0200)
We can't expect the DNS answer to always match the case we used for the
request, so we can't just use memcmp() to compare the DNS answer with what
we are expected.
Instead, introduce dns_hostname_cmp(), which compares each string in a
case-insensitive way.
This should fix github issue #566.

This should be backported to 2.1, 2.0, 1.9 and 1.8.

src/dns.c

index 953f9414c41d83a2a17a0f8ead592658d45df64d..38f73c1577646ee0ef12b850b0eea478d72c310e 100644 (file)
--- a/src/dns.c
+++ b/src/dns.c
@@ -77,6 +77,19 @@ struct dns_resolvers *find_resolvers_by_id(const char *id)
        return NULL;
 }
 
+/* Compare hostnames in a case-insensitive way .
+ * Returns 0 if they are the same, non-zero otherwise
+ */
+static __inline int dns_hostname_cmp(const char *name1, const char *name2, int len)
+{
+       int i;
+
+       for (i = 0; i < len; i++)
+               if (tolower(name1[i]) != tolower(name2[i]))
+                       return -1;
+       return 0;
+}
+
 /* Returns a pointer on the SRV request matching the name <name> for the proxy
  * <px>. NULL is returned if no match is found.
  */
@@ -540,7 +553,7 @@ 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 &&
-                                           !memcmp(srv->hostname_dn, item->target, item->data_len)) {
+                                           !dns_hostname_cmp(srv->hostname_dn, item->target, item->data_len)) {
                                                snr_update_srv_status(srv, 1);
                                                free(srv->hostname);
                                                free(srv->hostname_dn);
@@ -572,7 +585,7 @@ 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 &&
-                                   !memcmp(srv->hostname_dn, item->target, item->data_len) &&
+                                   !dns_hostname_cmp(srv->hostname_dn, item->target, item->data_len) &&
                                    !srv->dns_opts.ignore_weight) {
                                        int ha_weight;
 
@@ -820,7 +833,7 @@ static int dns_validate_dns_response(unsigned char *resp, unsigned char *bufend,
 
                /* Check if the current record dname is valid.  previous_dname
                 * points either to queried dname or last CNAME target */
-               if (dns_query->type != DNS_RTYPE_SRV && memcmp(previous_dname, tmpname, len) != 0) {
+               if (dns_query->type != DNS_RTYPE_SRV && dns_hostname_cmp(previous_dname, tmpname, len) != 0) {
                        pool_free(dns_answer_item_pool, dns_answer_record);
                        if (i == 0) {
                                /* First record, means a mismatch issue between
@@ -999,7 +1012,7 @@ static int dns_validate_dns_response(unsigned char *resp, unsigned char *bufend,
 
                        case DNS_RTYPE_SRV:
                                 if (dns_answer_record->data_len == tmp_record->data_len &&
-                                   !memcmp(dns_answer_record->target, tmp_record->target, dns_answer_record->data_len) &&
+                                   !dns_hostname_cmp(dns_answer_record->target, tmp_record->target, dns_answer_record->data_len) &&
                                    dns_answer_record->port == tmp_record->port) {
                                        tmp_record->weight = dns_answer_record->weight;
                                         found = 1;
@@ -1179,7 +1192,7 @@ static int dns_validate_dns_response(unsigned char *resp, unsigned char *bufend,
                                if ( !(
                                        (tmp_record->type == DNS_RTYPE_SRV) &&
                                        (tmp_record->ar_item == NULL) &&
-                                       (memcmp(tmp_record->target, dns_answer_record->name, tmp_record->data_len) == 0)
+                                       (dns_hostname_cmp(tmp_record->target, dns_answer_record->name, tmp_record->data_len) == 0)
                                      )
                                   )
                                        continue;
@@ -1520,7 +1533,7 @@ static struct dns_resolution *dns_pick_resolution(struct dns_resolvers *resolver
                        continue;
                if ((query_type == res->prefered_query_type) &&
                    hostname_dn_len == res->hostname_dn_len  &&
-                   !memcmp(*hostname_dn, res->hostname_dn, hostname_dn_len))
+                   !dns_hostname_cmp(*hostname_dn, res->hostname_dn, hostname_dn_len))
                        return res;
        }
 
@@ -1530,7 +1543,7 @@ static struct dns_resolution *dns_pick_resolution(struct dns_resolvers *resolver
                        continue;
                if ((query_type == res->prefered_query_type) &&
                    hostname_dn_len == res->hostname_dn_len  &&
-                   !memcmp(*hostname_dn, res->hostname_dn, hostname_dn_len))
+                   !dns_hostname_cmp(*hostname_dn, res->hostname_dn, hostname_dn_len))
                        return res;
        }
 
@@ -1897,7 +1910,7 @@ static void dns_resolve_recv(struct dgram_conn *dgram)
                 * sent. We can check only the first query of the list. We send
                 * one query at a time so we get one query in the response */
                query = LIST_NEXT(&res->response.query_list, struct dns_query_item *, list);
-               if (query && memcmp(query->name, res->hostname_dn, res->hostname_dn_len) != 0) {
+               if (query && dns_hostname_cmp(query->name, res->hostname_dn, res->hostname_dn_len) != 0) {
                        dns_resp = DNS_RESP_WRONG_NAME;
                        ns->counters.other++;
                        goto report_res_error;