mirror of
https://github.com/pi-hole/dnsmasq.git
synced 2025-12-19 18:28:25 +00:00
Fix a6004d7f17 to cope with >256 RRs in answer section.
This commit is contained in:
@@ -118,8 +118,9 @@ int main (int argc, char **argv)
|
||||
daemon->namebuff = safe_malloc(MAXDNAME * 2);
|
||||
daemon->keyname = safe_malloc(MAXDNAME * 2);
|
||||
daemon->workspacename = safe_malloc(MAXDNAME * 2);
|
||||
/* one char flag per possible RR in answer section. */
|
||||
daemon->rr_status = safe_malloc(256);
|
||||
/* one char flag per possible RR in answer section (may get extended). */
|
||||
daemon->rr_status_sz = 64;
|
||||
daemon->rr_status = safe_malloc(daemon->rr_status_sz);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -1030,7 +1030,8 @@ extern struct daemon {
|
||||
#ifdef HAVE_DNSSEC
|
||||
char *keyname; /* MAXDNAME size buffer */
|
||||
char *workspacename; /* ditto */
|
||||
char *rr_status; /* 256 bytes as flags for individual RRs */
|
||||
char *rr_status; /* flags for individual RRs */
|
||||
int rr_status_sz;
|
||||
#endif
|
||||
unsigned int local_answer, queries_forwarded, auth_answer;
|
||||
struct frec *frec_list;
|
||||
@@ -1145,7 +1146,7 @@ size_t setup_reply(struct dns_header *header, size_t qlen,
|
||||
unsigned long ttl);
|
||||
int extract_addresses(struct dns_header *header, size_t qlen, char *name,
|
||||
time_t now, char **ipsets, int is_sign, int check_rebind,
|
||||
int no_cache_dnssec, int secure, int *doctored, char *rr_status);
|
||||
int no_cache_dnssec, int secure, int *doctored);
|
||||
size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
struct in_addr local_addr, struct in_addr local_netmask,
|
||||
time_t now, int ad_reqd, int do_bit, int have_pseudoheader);
|
||||
@@ -1178,7 +1179,7 @@ size_t dnssec_generate_query(struct dns_header *header, unsigned char *end, char
|
||||
int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname, int class);
|
||||
int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname, int class);
|
||||
int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname, int *class,
|
||||
int check_unsigned, int *neganswer, int *nons, char *rr_status);
|
||||
int check_unsigned, int *neganswer, int *nons);
|
||||
int dnskey_keytag(int alg, int flags, unsigned char *key, int keylen);
|
||||
size_t filter_rrsigs(struct dns_header *header, size_t plen);
|
||||
unsigned char* hash_questions(struct dns_header *header, size_t plen, char *name);
|
||||
|
||||
30
src/dnssec.c
30
src/dnssec.c
@@ -859,7 +859,7 @@ int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char
|
||||
if (qtype != T_DS || qclass != class)
|
||||
rc = STAT_BOGUS;
|
||||
else
|
||||
rc = dnssec_validate_reply(now, header, plen, name, keyname, NULL, 0, &neganswer, &nons, NULL);
|
||||
rc = dnssec_validate_reply(now, header, plen, name, keyname, NULL, 0, &neganswer, &nons);
|
||||
|
||||
if (rc == STAT_INSECURE)
|
||||
rc = STAT_BOGUS;
|
||||
@@ -1645,11 +1645,11 @@ static int zone_status(char *name, int class, char *keyname, time_t now)
|
||||
STAT_NEED_KEY need DNSKEY to complete validation (name is returned in keyname, class in *class)
|
||||
STAT_NEED_DS need DS to complete validation (name is returned in keyname)
|
||||
|
||||
If non-NULL, rr_status points to a char array which corressponds to the RRs in the
|
||||
daemon->rr_status points to a char array which corressponds to the RRs in the
|
||||
answer section (only). This is set to 1 for each RR which is validated, and 0 for any which aren't.
|
||||
*/
|
||||
int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname,
|
||||
int *class, int check_unsigned, int *neganswer, int *nons, char *rr_status)
|
||||
int *class, int check_unsigned, int *neganswer, int *nons)
|
||||
{
|
||||
static unsigned char **targets = NULL;
|
||||
static int target_sz = 0;
|
||||
@@ -1659,8 +1659,20 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
|
||||
int i, j, rc;
|
||||
int secure = STAT_SECURE;
|
||||
|
||||
if (rr_status)
|
||||
memset(rr_status, 0, ntohs(header->ancount));
|
||||
/* extend rr_status if necessary */
|
||||
if (daemon->rr_status_sz < ntohs(header->ancount))
|
||||
{
|
||||
char *new = whine_malloc(ntohs(header->ancount) + 64);
|
||||
|
||||
if (!new)
|
||||
return STAT_BOGUS;
|
||||
|
||||
free(daemon->rr_status);
|
||||
daemon->rr_status = new;
|
||||
daemon->rr_status_sz = ntohs(header->ancount) + 64;
|
||||
}
|
||||
|
||||
memset(daemon->rr_status, 0, ntohs(header->ancount));
|
||||
|
||||
if (neganswer)
|
||||
*neganswer = 0;
|
||||
@@ -1754,8 +1766,8 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
|
||||
if (j != i)
|
||||
{
|
||||
/* Done already: copy the validation status */
|
||||
if (rr_status && (i < ntohs(header->ancount)))
|
||||
rr_status[i] = rr_status[j];
|
||||
if (i < ntohs(header->ancount))
|
||||
daemon->rr_status[i] = daemon->rr_status[j];
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1814,8 +1826,8 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
|
||||
/* rc is now STAT_SECURE or STAT_SECURE_WILDCARD */
|
||||
|
||||
/* Note that RR is validated */
|
||||
if (rr_status && (i < ntohs(header->ancount)))
|
||||
rr_status[i] = 1;
|
||||
if (i < ntohs(header->ancount))
|
||||
daemon->rr_status[i] = 1;
|
||||
|
||||
/* Note if we've validated either the answer to the question
|
||||
or the target of a CNAME. Any not noted will need NSEC or
|
||||
|
||||
@@ -560,7 +560,6 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
|
||||
char **sets = 0;
|
||||
int munged = 0, is_sign;
|
||||
size_t plen;
|
||||
char *rr_status = NULL;
|
||||
|
||||
(void)ad_reqd;
|
||||
(void)do_bit;
|
||||
@@ -651,11 +650,6 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
|
||||
server->flags |= SERV_WARNED_RECURSIVE;
|
||||
}
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
if (option_bool(OPT_DNSSEC_VALID))
|
||||
rr_status = daemon->rr_status;
|
||||
#endif
|
||||
|
||||
if (daemon->bogus_addr && RCODE(header) != NXDOMAIN &&
|
||||
check_for_bogus_wildcard(header, n, daemon->namebuff, daemon->bogus_addr, now))
|
||||
{
|
||||
@@ -681,7 +675,7 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
|
||||
cache_secure = 0;
|
||||
}
|
||||
|
||||
if (extract_addresses(header, n, daemon->namebuff, now, sets, is_sign, check_rebind, no_cache, cache_secure, &doctored, rr_status))
|
||||
if (extract_addresses(header, n, daemon->namebuff, now, sets, is_sign, check_rebind, no_cache, cache_secure, &doctored))
|
||||
{
|
||||
my_syslog(LOG_WARNING, _("possible DNS-rebind attack detected: %s"), daemon->namebuff);
|
||||
munged = 1;
|
||||
@@ -906,7 +900,7 @@ void reply_query(int fd, int family, time_t now)
|
||||
else
|
||||
status = dnssec_validate_reply(now, header, n, daemon->namebuff, daemon->keyname, &forward->class,
|
||||
option_bool(OPT_DNSSEC_NO_SIGN) && (server->flags & SERV_DO_DNSSEC),
|
||||
NULL, NULL, daemon->rr_status);
|
||||
NULL, NULL);
|
||||
}
|
||||
|
||||
/* Can't validate, as we're missing key data. Put this
|
||||
@@ -1491,7 +1485,7 @@ static int tcp_key_recurse(time_t now, int status, struct dns_header *header, si
|
||||
else
|
||||
new_status = dnssec_validate_reply(now, header, n, name, keyname, &class,
|
||||
option_bool(OPT_DNSSEC_NO_SIGN) && (server->flags & SERV_DO_DNSSEC),
|
||||
NULL, NULL, daemon->rr_status);
|
||||
NULL, NULL);
|
||||
|
||||
if (new_status != STAT_NEED_DS && new_status != STAT_NEED_KEY)
|
||||
break;
|
||||
|
||||
@@ -585,7 +585,7 @@ static int find_soa(struct dns_header *header, size_t qlen, char *name, int *doc
|
||||
Return 1 if we reject an address because it look like part of dns-rebinding attack. */
|
||||
int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t now,
|
||||
char **ipsets, int is_sign, int check_rebind, int no_cache_dnssec,
|
||||
int secure, int *doctored, char *rr_status)
|
||||
int secure, int *doctored)
|
||||
{
|
||||
unsigned char *p, *p1, *endrr, *namep;
|
||||
int i, j, qtype, qclass, aqtype, aqclass, ardlen, res, searched_soa = 0;
|
||||
@@ -610,9 +610,9 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t
|
||||
{
|
||||
if (secure)
|
||||
return 0;
|
||||
if (rr_status)
|
||||
if (option_bool(OPT_DNSSEC_VALID))
|
||||
for (i = 0; i < ntohs(header->ancount); i++)
|
||||
if (rr_status[i])
|
||||
if (daemon->rr_status[i])
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -682,7 +682,7 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t
|
||||
if (!extract_name(header, qlen, &p1, name, 1, 0))
|
||||
return 0;
|
||||
|
||||
if (rr_status && rr_status[j])
|
||||
if (option_bool(OPT_DNSSEC_VALID) && daemon->rr_status[j])
|
||||
{
|
||||
/* validated RR anywhere in CNAME chain, don't cache. */
|
||||
if (cname_short || aqtype == T_CNAME)
|
||||
@@ -766,7 +766,7 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t
|
||||
if (aqclass == C_IN && res != 2 && (aqtype == T_CNAME || aqtype == qtype))
|
||||
{
|
||||
#ifdef HAVE_DNSSEC
|
||||
if (rr_status && rr_status[j])
|
||||
if (option_bool(OPT_DNSSEC_VALID) && daemon->rr_status[j])
|
||||
secflag = F_DNSSECOK;
|
||||
#endif
|
||||
if (aqtype == T_CNAME)
|
||||
|
||||
Reference in New Issue
Block a user