BUG/MEDIUM: dns: Consider the fact that dns answers are case-insensitive

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.
This commit is contained in:
Olivier Houchard 2020-04-01 18:30:27 +02:00
parent 5e8017d53c
commit b17b884870
1 changed files with 21 additions and 8 deletions

View File

@ -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;