--- embedaddon/dnsmasq/src/auth.c 2016/11/02 09:57:01 1.1.1.3 +++ embedaddon/dnsmasq/src/auth.c 2023/09/27 11:02:07 1.1.1.5 @@ -1,4 +1,4 @@ -/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley +/* dnsmasq is Copyright (c) 2000-2022 Simon Kelley This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -18,36 +18,51 @@ #ifdef HAVE_AUTH -static struct addrlist *find_subnet(struct auth_zone *zone, int flag, struct all_addr *addr_u) +static struct addrlist *find_addrlist(struct addrlist *list, int flag, union all_addr *addr_u) { - struct addrlist *subnet; + do { + if (!(list->flags & ADDRLIST_IPV6)) + { + struct in_addr netmask, addr = addr_u->addr4; + + if (!(flag & F_IPV4)) + continue; + + netmask.s_addr = htonl(~(in_addr_t)0 << (32 - list->prefixlen)); + + if (is_same_net(addr, list->addr.addr4, netmask)) + return list; + } + else if (is_same_net6(&(addr_u->addr6), &list->addr.addr6, list->prefixlen)) + return list; + + } while ((list = list->next)); + + return NULL; +} - for (subnet = zone->subnet; subnet; subnet = subnet->next) - { - if (!(subnet->flags & ADDRLIST_IPV6)) - { - struct in_addr netmask, addr = addr_u->addr.addr4; +static struct addrlist *find_subnet(struct auth_zone *zone, int flag, union all_addr *addr_u) +{ + if (!zone->subnet) + return NULL; + + return find_addrlist(zone->subnet, flag, addr_u); +} - if (!(flag & F_IPV4)) - continue; - - netmask.s_addr = htonl(~(in_addr_t)0 << (32 - subnet->prefixlen)); - - if (is_same_net(addr, subnet->addr.addr.addr4, netmask)) - return subnet; - } -#ifdef HAVE_IPV6 - else if (is_same_net6(&(addr_u->addr.addr6), &subnet->addr.addr.addr6, subnet->prefixlen)) - return subnet; -#endif - - } - return NULL; +static struct addrlist *find_exclude(struct auth_zone *zone, int flag, union all_addr *addr_u) +{ + if (!zone->exclude) + return NULL; + + return find_addrlist(zone->exclude, flag, addr_u); } -static int filter_zone(struct auth_zone *zone, int flag, struct all_addr *addr_u) +static int filter_zone(struct auth_zone *zone, int flag, union all_addr *addr_u) { - /* No zones specified, no filter */ + if (find_exclude(zone, flag, addr_u)) + return 0; + + /* No subnets specified, no filter */ if (!zone->subnet) return 1; @@ -86,11 +101,11 @@ size_t answer_auth(struct dns_header *header, char *li { char *name = daemon->namebuff; unsigned char *p, *ansp; - int qtype, qclass; + int qtype, qclass, rc; int nameoffset, axfroffset = 0; int q, anscount = 0, authcount = 0; struct crec *crecp; - int auth = !local_query, trunc = 0, nxdomain = 1, soa = 0, ns = 0, axfr = 0; + int auth = !local_query, trunc = 0, nxdomain = 1, soa = 0, ns = 0, axfr = 0, out_of_zone = 0; struct auth_zone *zone = NULL; struct addrlist *subnet = NULL; char *cut; @@ -98,8 +113,9 @@ size_t answer_auth(struct dns_header *header, char *li struct txt_record *txt; struct interface_name *intr; struct naptr *na; - struct all_addr addr; - struct cname *a; + union all_addr addr; + struct cname *a, *candidate; + unsigned int wclen; if (ntohs(header->qdcount) == 0 || OPCODE(header) != QUERY ) return 0; @@ -113,8 +129,9 @@ size_t answer_auth(struct dns_header *header, char *li for (q = ntohs(header->qdcount); q != 0; q--) { - unsigned short flag = 0; + unsigned int flag = 0; int found = 0; + int cname_wildcard = 0; /* save pointer to name for copying into answers */ nameoffset = p - (unsigned char *)header; @@ -129,6 +146,7 @@ size_t answer_auth(struct dns_header *header, char *li if (qclass != C_IN) { auth = 0; + out_of_zone = 1; continue; } @@ -142,6 +160,7 @@ size_t answer_auth(struct dns_header *header, char *li if (!zone) { + out_of_zone = 1; auth = 0; continue; } @@ -161,7 +180,7 @@ size_t answer_auth(struct dns_header *header, char *li struct addrlist *addrlist; for (addrlist = intr->addr; addrlist; addrlist = addrlist->next) - if (!(addrlist->flags & ADDRLIST_IPV6) && addr.addr.addr4.s_addr == addrlist->addr.addr.addr4.s_addr) + if (!(addrlist->flags & ADDRLIST_IPV6) && addr.addr4.s_addr == addrlist->addr.addr4.s_addr) break; if (addrlist) @@ -170,14 +189,13 @@ size_t answer_auth(struct dns_header *header, char *li while (intr->next && strcmp(intr->intr, intr->next->intr) == 0) intr = intr->next; } -#ifdef HAVE_IPV6 else if (flag == F_IPV6) for (intr = daemon->int_names; intr; intr = intr->next) { struct addrlist *addrlist; for (addrlist = intr->addr; addrlist; addrlist = addrlist->next) - if ((addrlist->flags & ADDRLIST_IPV6) && IN6_ARE_ADDR_EQUAL(&addr.addr.addr6, &addrlist->addr.addr.addr6)) + if ((addrlist->flags & ADDRLIST_IPV6) && IN6_ARE_ADDR_EQUAL(&addr.addr6, &addrlist->addr.addr6)) break; if (addrlist) @@ -186,14 +204,13 @@ size_t answer_auth(struct dns_header *header, char *li while (intr->next && strcmp(intr->intr, intr->next->intr) == 0) intr = intr->next; } -#endif if (intr) { if (local_query || in_zone(zone, intr->name, NULL)) { found = 1; - log_query(flag | F_REVERSE | F_CONFIG, intr->name, &addr, NULL); + log_query(flag | F_REVERSE | F_CONFIG, intr->name, &addr, NULL, 0); if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl, NULL, T_PTR, C_IN, "d", intr->name)) @@ -217,7 +234,7 @@ size_t answer_auth(struct dns_header *header, char *li strcat(name, "."); strcat(name, zone->domain); } - log_query(flag | F_DHCP | F_REVERSE, name, &addr, record_source(crecp->uid)); + log_query(flag | F_DHCP | F_REVERSE, name, &addr, record_source(crecp->uid), 0); found = 1; if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl, NULL, @@ -226,7 +243,7 @@ size_t answer_auth(struct dns_header *header, char *li } else if (crecp->flags & (F_DHCP | F_HOSTS) && (local_query || in_zone(zone, name, NULL))) { - log_query(crecp->flags & ~F_FORWARD, name, &addr, record_source(crecp->uid)); + log_query(crecp->flags & ~F_FORWARD, name, &addr, record_source(crecp->uid), 0); found = 1; if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl, NULL, @@ -238,10 +255,21 @@ size_t answer_auth(struct dns_header *header, char *li } while ((crecp = cache_find_by_addr(crecp, &addr, now, flag))); + if (!found && is_rev_synth(flag, &addr, name) && (local_query || in_zone(zone, name, NULL))) + { + log_query(F_CONFIG | F_REVERSE | flag, name, &addr, NULL, 0); + found = 1; + + if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, + daemon->auth_ttl, NULL, + T_PTR, C_IN, "d", name)) + anscount++; + } + if (found) nxdomain = 0; else - log_query(flag | F_NEG | F_NXDOMAIN | F_REVERSE | (auth ? F_AUTH : 0), NULL, &addr, NULL); + log_query(flag | F_NEG | F_NXDOMAIN | F_REVERSE | (auth ? F_AUTH : 0), NULL, &addr, NULL, 0); continue; } @@ -258,20 +286,21 @@ size_t answer_auth(struct dns_header *header, char *li if (!zone) { + out_of_zone = 1; auth = 0; continue; } } for (rec = daemon->mxnames; rec; rec = rec->next) - if (!rec->issrv && hostname_isequal(name, rec->name)) + if (!rec->issrv && (rc = hostname_issubdomain(name, rec->name))) { nxdomain = 0; - if (qtype == T_MX) + if (rc == 2 && qtype == T_MX) { found = 1; - log_query(F_CONFIG | F_RRNAME, name, NULL, ""); + log_query(F_CONFIG | F_RRNAME, name, NULL, "", 0); if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl, NULL, T_MX, C_IN, "sd", rec->weight, rec->target)) anscount++; @@ -279,14 +308,14 @@ size_t answer_auth(struct dns_header *header, char *li } for (move = NULL, up = &daemon->mxnames, rec = daemon->mxnames; rec; rec = rec->next) - if (rec->issrv && hostname_isequal(name, rec->name)) + if (rec->issrv && (rc = hostname_issubdomain(name, rec->name))) { nxdomain = 0; - if (qtype == T_SRV) + if (rc == 2 && qtype == T_SRV) { found = 1; - log_query(F_CONFIG | F_RRNAME, name, NULL, ""); + log_query(F_CONFIG | F_RRNAME, name, NULL, "", 0); if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl, NULL, T_SRV, C_IN, "sssd", rec->priority, rec->weight, rec->srvport, rec->target)) @@ -314,13 +343,13 @@ size_t answer_auth(struct dns_header *header, char *li } for (txt = daemon->rr; txt; txt = txt->next) - if (hostname_isequal(name, txt->name)) + if ((rc = hostname_issubdomain(name, txt->name))) { nxdomain = 0; - if (txt->class == qtype) + if (rc == 2 && txt->class == qtype) { found = 1; - log_query(F_CONFIG | F_RRNAME, name, NULL, ""); + log_query(F_CONFIG | F_RRNAME, name, NULL, NULL, txt->class); if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl, NULL, txt->class, C_IN, "t", txt->len, txt->txt)) anscount++; @@ -328,13 +357,13 @@ size_t answer_auth(struct dns_header *header, char *li } for (txt = daemon->txt; txt; txt = txt->next) - if (txt->class == C_IN && hostname_isequal(name, txt->name)) + if (txt->class == C_IN && (rc = hostname_issubdomain(name, txt->name))) { nxdomain = 0; - if (qtype == T_TXT) + if (rc == 2 && qtype == T_TXT) { found = 1; - log_query(F_CONFIG | F_RRNAME, name, NULL, ""); + log_query(F_CONFIG | F_RRNAME, name, NULL, "", 0); if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl, NULL, T_TXT, C_IN, "t", txt->len, txt->txt)) anscount++; @@ -342,13 +371,13 @@ size_t answer_auth(struct dns_header *header, char *li } for (na = daemon->naptr; na; na = na->next) - if (hostname_isequal(name, na->name)) + if ((rc = hostname_issubdomain(name, na->name))) { nxdomain = 0; - if (qtype == T_NAPTR) + if (rc == 2 && qtype == T_NAPTR) { found = 1; - log_query(F_CONFIG | F_RRNAME, name, NULL, ""); + log_query(F_CONFIG | F_RRNAME, name, NULL, "", 0); if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl, NULL, T_NAPTR, C_IN, "sszzzd", na->order, na->pref, na->flags, na->services, na->regexp, na->replace)) @@ -359,55 +388,43 @@ size_t answer_auth(struct dns_header *header, char *li if (qtype == T_A) flag = F_IPV4; -#ifdef HAVE_IPV6 if (qtype == T_AAAA) flag = F_IPV6; -#endif for (intr = daemon->int_names; intr; intr = intr->next) - if (hostname_isequal(name, intr->name)) + if ((rc = hostname_issubdomain(name, intr->name))) { struct addrlist *addrlist; nxdomain = 0; - if (flag) + if (rc == 2 && flag) for (addrlist = intr->addr; addrlist; addrlist = addrlist->next) if (((addrlist->flags & ADDRLIST_IPV6) ? T_AAAA : T_A) == qtype && (local_query || filter_zone(zone, flag, &addrlist->addr))) { -#ifdef HAVE_IPV6 if (addrlist->flags & ADDRLIST_REVONLY) continue; -#endif + found = 1; - log_query(F_FORWARD | F_CONFIG | flag, name, &addrlist->addr, NULL); + log_query(F_FORWARD | F_CONFIG | flag, name, &addrlist->addr, NULL, 0); if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl, NULL, qtype, C_IN, qtype == T_A ? "4" : "6", &addrlist->addr)) anscount++; } } - - for (a = daemon->cnames; a; a = a->next) - if (hostname_isequal(name, a->alias) ) - { - log_query(F_CONFIG | F_CNAME, name, NULL, NULL); - strcpy(name, a->target); - if (!strchr(name, '.')) - { - strcat(name, "."); - strcat(name, zone->domain); - } - found = 1; - if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, - daemon->auth_ttl, &nameoffset, - T_CNAME, C_IN, "d", name)) - anscount++; - - goto cname_restart; - } + if (!found && is_name_synthetic(flag, name, &addr) ) + { + nxdomain = 0; + + log_query(F_FORWARD | F_CONFIG | flag, name, &addr, NULL, 0); + if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, + daemon->auth_ttl, NULL, qtype, C_IN, qtype == T_A ? "4" : "6", &addr)) + anscount++; + } + if (!cut) { nxdomain = 0; @@ -415,8 +432,7 @@ size_t answer_auth(struct dns_header *header, char *li if (qtype == T_SOA) { auth = soa = 1; /* inhibits auth section */ - found = 1; - log_query(F_RRNAME | F_AUTH, zone->domain, NULL, ""); + log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "", 0); } else if (qtype == T_AXFR) { @@ -424,27 +440,24 @@ size_t answer_auth(struct dns_header *header, char *li if (peer_addr->sa.sa_family == AF_INET) peer_addr->in.sin_port = 0; -#ifdef HAVE_IPV6 else { peer_addr->in6.sin6_port = 0; peer_addr->in6.sin6_scope_id = 0; } -#endif for (peers = daemon->auth_peers; peers; peers = peers->next) if (sockaddr_isequal(peer_addr, &peers->addr)) break; - /* Refuse all AXFR unless --auth-sec-servers is set */ - if ((!peers && daemon->auth_peers) || !daemon->secondary_forward_server) + /* Refuse all AXFR unless --auth-sec-servers or auth-peers is set */ + if ((!daemon->secondary_forward_server && !daemon->auth_peers) || + (daemon->auth_peers && !peers)) { if (peer_addr->sa.sa_family == AF_INET) inet_ntop(AF_INET, &peer_addr->in.sin_addr, daemon->addrbuff, ADDRSTRLEN); -#ifdef HAVE_IPV6 else inet_ntop(AF_INET6, &peer_addr->in6.sin6_addr, daemon->addrbuff, ADDRSTRLEN); -#endif my_syslog(LOG_WARNING, _("ignoring zone transfer request from %s"), daemon->addrbuff); return 0; @@ -454,16 +467,14 @@ size_t answer_auth(struct dns_header *header, char *li soa = 1; /* inhibits auth section */ ns = 1; /* ensure we include NS records! */ axfr = 1; - found = 1; axfroffset = nameoffset; - log_query(F_RRNAME | F_AUTH, zone->domain, NULL, ""); + log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "", 0); } else if (qtype == T_NS) { auth = 1; ns = 1; /* inhibits auth section */ - found = 1; - log_query(F_RRNAME | F_AUTH, zone->domain, NULL, ""); + log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "", 0); } } @@ -478,12 +489,11 @@ size_t answer_auth(struct dns_header *header, char *li { nxdomain = 0; if ((crecp->flags & flag) && - (local_query || filter_zone(zone, flag, &(crecp->addr.addr)))) + (local_query || filter_zone(zone, flag, &(crecp->addr)))) { *cut = '.'; /* restore domain part */ - log_query(crecp->flags, name, &crecp->addr.addr, record_source(crecp->uid)); + log_query(crecp->flags, name, &crecp->addr, record_source(crecp->uid), 0); *cut = 0; /* remove domain part */ - found = 1; if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl, NULL, qtype, C_IN, qtype == T_A ? "4" : "6", &crecp->addr)) @@ -501,10 +511,9 @@ size_t answer_auth(struct dns_header *header, char *li do { nxdomain = 0; - if ((crecp->flags & flag) && (local_query || filter_zone(zone, flag, &(crecp->addr.addr)))) + if ((crecp->flags & flag) && (local_query || filter_zone(zone, flag, &(crecp->addr)))) { - log_query(crecp->flags, name, &crecp->addr.addr, record_source(crecp->uid)); - found = 1; + log_query(crecp->flags, name, &crecp->addr, record_source(crecp->uid), 0); if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl, NULL, qtype, C_IN, qtype == T_A ? "4" : "6", &crecp->addr)) @@ -513,8 +522,64 @@ size_t answer_auth(struct dns_header *header, char *li } while ((crecp = cache_find_by_name(crecp, name, now, F_IPV4 | F_IPV6))); } - if (!found) - log_query(flag | F_NEG | (nxdomain ? F_NXDOMAIN : 0) | F_FORWARD | F_AUTH, name, NULL, NULL); + /* Only supply CNAME if no record for any type is known. */ + if (nxdomain) + { + /* Check for possible wildcard match against *.domain + return length of match, to get longest. + Note that if return length of wildcard section, so + we match b.simon to _both_ *.simon and b.simon + but return a longer (better) match to b.simon. + */ + for (wclen = 0, candidate = NULL, a = daemon->cnames; a; a = a->next) + if (a->alias[0] == '*') + { + char *test = name; + + while ((test = strchr(test+1, '.'))) + { + if (hostname_isequal(test, &(a->alias[1]))) + { + if (strlen(test) > wclen && !cname_wildcard) + { + wclen = strlen(test); + candidate = a; + cname_wildcard = 1; + } + break; + } + } + + } + else if (hostname_isequal(a->alias, name) && strlen(a->alias) > wclen) + { + /* Simple case, no wildcard */ + wclen = strlen(a->alias); + candidate = a; + } + + if (candidate) + { + log_query(F_CONFIG | F_CNAME, name, NULL, NULL, 0); + strcpy(name, candidate->target); + if (!strchr(name, '.')) + { + strcat(name, "."); + strcat(name, zone->domain); + } + found = 1; + if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, + daemon->auth_ttl, &nameoffset, + T_CNAME, C_IN, "d", name)) + anscount++; + + goto cname_restart; + } + else if (cache_find_non_terminal(name, now)) + nxdomain = 0; + + log_query(flag | F_NEG | (nxdomain ? F_NXDOMAIN : 0) | F_FORWARD | F_AUTH, name, NULL, NULL, 0); + } } @@ -534,19 +599,18 @@ size_t answer_auth(struct dns_header *header, char *li if (!(subnet->flags & ADDRLIST_IPV6)) { - in_addr_t a = ntohl(subnet->addr.addr.addr4.s_addr) >> 8; + in_addr_t a = ntohl(subnet->addr.addr4.s_addr) >> 8; char *p = name; if (subnet->prefixlen >= 24) - p += sprintf(p, "%d.", a & 0xff); + p += sprintf(p, "%u.", a & 0xff); a = a >> 8; if (subnet->prefixlen >= 16 ) - p += sprintf(p, "%d.", a & 0xff); + p += sprintf(p, "%u.", a & 0xff); a = a >> 8; - p += sprintf(p, "%d.in-addr.arpa", a & 0xff); + sprintf(p, "%u.in-addr.arpa", a & 0xff); } -#ifdef HAVE_IPV6 else { char *p = name; @@ -554,13 +618,12 @@ size_t answer_auth(struct dns_header *header, char *li for (i = subnet->prefixlen-1; i >= 0; i -= 4) { - int dig = ((unsigned char *)&subnet->addr.addr.addr6)[i>>3]; + int dig = ((unsigned char *)&subnet->addr.addr6)[i>>3]; p += sprintf(p, "%.1x.", (i>>2) & 1 ? dig & 15 : dig >> 4); } - p += sprintf(p, "ip6.arpa"); + sprintf(p, "ip6.arpa"); } -#endif } /* handle NS and SOA in auth section or for explicit queries */ @@ -584,16 +647,20 @@ size_t answer_auth(struct dns_header *header, char *li { struct name_list *secondary; - newoffset = ansp - (unsigned char *)header; - if (add_resource_record(header, limit, &trunc, -offset, &ansp, - daemon->auth_ttl, NULL, T_NS, C_IN, "d", offset == 0 ? authname : NULL, daemon->authserver)) + /* Only include the machine running dnsmasq if it's acting as an auth server */ + if (daemon->authinterface) { - if (offset == 0) - offset = newoffset; - if (ns) - anscount++; - else - authcount++; + newoffset = ansp - (unsigned char *)header; + if (add_resource_record(header, limit, &trunc, -offset, &ansp, + daemon->auth_ttl, NULL, T_NS, C_IN, "d", offset == 0 ? authname : NULL, daemon->authserver)) + { + if (offset == 0) + offset = newoffset; + if (ns) + anscount++; + else + authcount++; + } } if (!subnet) @@ -697,14 +764,12 @@ size_t answer_auth(struct dns_header *header, char *li daemon->auth_ttl, NULL, T_A, C_IN, "4", cut ? intr->name : NULL, &addrlist->addr)) anscount++; -#ifdef HAVE_IPV6 for (addrlist = intr->addr; addrlist; addrlist = addrlist->next) if ((addrlist->flags & ADDRLIST_IPV6) && (local_query || filter_zone(zone, F_IPV6, &addrlist->addr)) && add_resource_record(header, limit, &trunc, -axfroffset, &ansp, daemon->auth_ttl, NULL, T_AAAA, C_IN, "6", cut ? intr->name : NULL, &addrlist->addr)) anscount++; -#endif /* restore config data */ if (cut) @@ -741,38 +806,26 @@ size_t answer_auth(struct dns_header *header, char *li { char *cache_name = cache_get_name(crecp); if (!strchr(cache_name, '.') && - (local_query || filter_zone(zone, (crecp->flags & (F_IPV6 | F_IPV4)), &(crecp->addr.addr)))) - { - qtype = T_A; -#ifdef HAVE_IPV6 - if (crecp->flags & F_IPV6) - qtype = T_AAAA; -#endif - if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, - daemon->auth_ttl, NULL, qtype, C_IN, - (crecp->flags & F_IPV4) ? "4" : "6", cache_name, &crecp->addr)) - anscount++; - } + (local_query || filter_zone(zone, (crecp->flags & (F_IPV6 | F_IPV4)), &(crecp->addr))) && + add_resource_record(header, limit, &trunc, -axfroffset, &ansp, + daemon->auth_ttl, NULL, (crecp->flags & F_IPV6) ? T_AAAA : T_A, C_IN, + (crecp->flags & F_IPV4) ? "4" : "6", cache_name, &crecp->addr)) + anscount++; } if ((crecp->flags & F_HOSTS) || (((crecp->flags & F_DHCP) && option_bool(OPT_DHCP_FQDN)))) { strcpy(name, cache_get_name(crecp)); if (in_zone(zone, name, &cut) && - (local_query || filter_zone(zone, (crecp->flags & (F_IPV6 | F_IPV4)), &(crecp->addr.addr)))) + (local_query || filter_zone(zone, (crecp->flags & (F_IPV6 | F_IPV4)), &(crecp->addr)))) { - qtype = T_A; -#ifdef HAVE_IPV6 - if (crecp->flags & F_IPV6) - qtype = T_AAAA; -#endif - if (cut) - *cut = 0; + if (cut) + *cut = 0; - if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, - daemon->auth_ttl, NULL, qtype, C_IN, - (crecp->flags & F_IPV4) ? "4" : "6", cut ? name : NULL, &crecp->addr)) - anscount++; + if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, + daemon->auth_ttl, NULL, (crecp->flags & F_IPV6) ? T_AAAA : T_A, C_IN, + (crecp->flags & F_IPV4) ? "4" : "6", cut ? name : NULL, &crecp->addr)) + anscount++; } } } @@ -806,7 +859,10 @@ size_t answer_auth(struct dns_header *header, char *li header->hb4 &= ~HB4_RA; } - /* authoritive */ + /* data is never DNSSEC signed. */ + header->hb4 &= ~HB4_AD; + + /* authoritative */ if (auth) header->hb3 |= HB3_AA; @@ -818,10 +874,22 @@ size_t answer_auth(struct dns_header *header, char *li SET_RCODE(header, NXDOMAIN); else SET_RCODE(header, NOERROR); /* no error */ + header->ancount = htons(anscount); header->nscount = htons(authcount); header->arcount = htons(0); + if (!local_query && out_of_zone) + { + SET_RCODE(header, REFUSED); + header->ancount = htons(0); + header->nscount = htons(0); + addr.log.rcode = REFUSED; + addr.log.ede = EDE_NOT_AUTH; + log_query(F_UPSTREAM | F_RCODE, "error", &addr, NULL, 0); + return resize_packet(header, ansp - (unsigned char *)header, NULL, 0); + } + /* Advertise our packet size limit in our reply */ if (have_pseudoheader) return add_pseudoheader(header, ansp - (unsigned char *)header, (unsigned char *)limit, daemon->edns_pktsz, 0, NULL, 0, do_bit, 0); @@ -830,6 +898,3 @@ size_t answer_auth(struct dns_header *header, char *li } #endif - - -