Fix a6004d7f17 to cope with >256 RRs in answer section.

This commit is contained in:
Simon Kelley
2017-12-01 22:40:56 +00:00
parent 74f0f9a042
commit 373e917389
5 changed files with 36 additions and 28 deletions

View File

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

View File

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

View File

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

View File

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

View File

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