From b59a5c2567aafac35734d9660d9480613999e4cb Mon Sep 17 00:00:00 2001 From: Simon Kelley Date: Fri, 25 Oct 2019 16:13:38 +0100 Subject: [PATCH] Generalise CNAME handling. Cope with cached and configured CNAMES for all record types we support, including local-config but not cached types such as TXT. Also, if we have a locally configured CNAME but no target for the requested type, don't forward the query. --- src/rfc1035.c | 106 ++++++++++++++++++-------------------------------- 1 file changed, 37 insertions(+), 69 deletions(-) diff --git a/src/rfc1035.c b/src/rfc1035.c index 0344af7..d077887 100644 --- a/src/rfc1035.c +++ b/src/rfc1035.c @@ -1362,7 +1362,36 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen, GETSHORT(qclass, p); ans = 0; /* have we answered this question */ - + + while ((crecp = cache_find_by_name(NULL, name, now, F_CNAME))) + { + char *cname_target = cache_get_cname_target(crecp); + + /* If the client asked for DNSSEC don't use cached data. */ + if ((crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) || + !do_bit || + (option_bool(OPT_DNSSEC_VALID) && !(crecp->flags & F_DNSSECOK))) + + { + if (crecp->flags & F_CONFIG || qtype == T_CNAME) + ans = 1; + + if (!(crecp->flags & F_DNSSECOK)) + sec_data = 0; + + if (!dryrun) + { + log_query(crecp->flags, name, NULL, record_source(crecp->uid)); + if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, + crec_ttl(crecp, now), &nameoffset, + T_CNAME, C_IN, "d", cname_target)) + anscount++; + } + + strcpy(name, cname_target); + } + } + if (qtype == T_TXT || qtype == T_ANY) { struct txt_record *t; @@ -1604,7 +1633,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen, } } } - + for (flag = F_IPV4; flag; flag = (flag == F_IPV4) ? F_IPV6 : 0) { unsigned short type = (flag == F_IPV6) ? T_AAAA : T_A; @@ -1614,7 +1643,6 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen, continue; /* interface name stuff */ - intname_restart: for (intr = daemon->int_names; intr; intr = intr->next) if (hostname_isequal(name, intr->name)) break; @@ -1672,8 +1700,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen, continue; } - cname_restart: - if ((crecp = cache_find_by_name(NULL, name, now, flag | F_CNAME | (dryrun ? F_NO_RR : 0)))) + if ((crecp = cache_find_by_name(NULL, name, now, flag | (dryrun ? F_NO_RR : 0)))) { int localise = 0; @@ -1689,7 +1716,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen, localise = 1; break; } - } while ((crecp = cache_find_by_name(crecp, name, now, flag | F_CNAME))); + } while ((crecp = cache_find_by_name(crecp, name, now, flag))); crecp = save; } @@ -1707,27 +1734,6 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen, if (!(crecp->flags & F_DNSSECOK)) sec_data = 0; - if (crecp->flags & F_CNAME) - { - char *cname_target = cache_get_cname_target(crecp); - - if (!dryrun) - { - log_query(crecp->flags, name, NULL, record_source(crecp->uid)); - if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, - crec_ttl(crecp, now), &nameoffset, - T_CNAME, C_IN, "d", cname_target)) - anscount++; - } - - strcpy(name, cname_target); - /* check if target interface_name */ - if (crecp->addr.cname.uid == SRC_INTERFACE) - goto intname_restart; - else - goto cname_restart; - } - if (crecp->flags & F_NEG) { ans = 1; @@ -1761,7 +1767,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen, anscount++; } } - } while ((crecp = cache_find_by_name(crecp, name, now, flag | F_CNAME))); + } while ((crecp = cache_find_by_name(crecp, name, now, flag))); } else if (is_name_synthetic(flag, name, &addr)) { @@ -1776,27 +1782,6 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen, } } - if (qtype == T_CNAME || qtype == T_ANY) - { - if ((crecp = cache_find_by_name(NULL, name, now, F_CNAME | (dryrun ? F_NO_RR : 0))) && - (qtype == T_CNAME || (crecp->flags & F_CONFIG)) && - ((crecp->flags & F_CONFIG) || !do_bit || (option_bool(OPT_DNSSEC_VALID) && !(crecp->flags & F_DNSSECOK)))) - { - if (!(crecp->flags & F_DNSSECOK)) - sec_data = 0; - - ans = 1; - if (!dryrun) - { - log_query(crecp->flags, name, NULL, record_source(crecp->uid)); - if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, - crec_ttl(crecp, now), &nameoffset, - T_CNAME, C_IN, "d", cache_get_cname_target(crecp))) - anscount++; - } - } - } - if (qtype == T_MX || qtype == T_ANY) { int found = 0; @@ -1880,8 +1865,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen, if (!found) { - cname_srv_restart: - if ((crecp = cache_find_by_name(NULL, name, now, F_CNAME | F_SRV | (dryrun ? F_NO_RR : 0))) && + if ((crecp = cache_find_by_name(NULL, name, now, F_SRV | (dryrun ? F_NO_RR : 0))) && (!do_bit || (option_bool(OPT_DNSSEC_VALID) && !(crecp->flags & F_DNSSECOK)))) { if (!(crecp->flags & F_DNSSECOK)) @@ -1891,23 +1875,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen, found = ans = 1; do { - if (crecp->flags & F_CNAME) - { - char *cname_target = cache_get_cname_target(crecp); - - if (!dryrun) - { - log_query(crecp->flags, name, NULL, record_source(crecp->uid)); - if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, - crec_ttl(crecp, now), &nameoffset, - T_CNAME, C_IN, "d", cname_target)) - anscount++; - } - - strcpy(name, cname_target); - goto cname_srv_restart; - } - else if (crecp->flags & F_NEG) + if (crecp->flags & F_NEG) { if (crecp->flags & F_NXDOMAIN) nxdomain = 1; @@ -1935,7 +1903,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen, return 0; /* bad packet */ } } - } while ((crecp = cache_find_by_name(crecp, name, now, F_SRV | F_CNAME))); + } while ((crecp = cache_find_by_name(crecp, name, now, F_SRV))); } }