Commit 373e9173 authored by Simon Kelley's avatar Simon Kelley

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

parent 74f0f9a0
...@@ -118,8 +118,9 @@ int main (int argc, char **argv) ...@@ -118,8 +118,9 @@ int main (int argc, char **argv)
daemon->namebuff = safe_malloc(MAXDNAME * 2); daemon->namebuff = safe_malloc(MAXDNAME * 2);
daemon->keyname = safe_malloc(MAXDNAME * 2); daemon->keyname = safe_malloc(MAXDNAME * 2);
daemon->workspacename = safe_malloc(MAXDNAME * 2); daemon->workspacename = safe_malloc(MAXDNAME * 2);
/* one char flag per possible RR in answer section. */ /* one char flag per possible RR in answer section (may get extended). */
daemon->rr_status = safe_malloc(256); daemon->rr_status_sz = 64;
daemon->rr_status = safe_malloc(daemon->rr_status_sz);
} }
#endif #endif
......
...@@ -1030,7 +1030,8 @@ extern struct daemon { ...@@ -1030,7 +1030,8 @@ extern struct daemon {
#ifdef HAVE_DNSSEC #ifdef HAVE_DNSSEC
char *keyname; /* MAXDNAME size buffer */ char *keyname; /* MAXDNAME size buffer */
char *workspacename; /* ditto */ 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 #endif
unsigned int local_answer, queries_forwarded, auth_answer; unsigned int local_answer, queries_forwarded, auth_answer;
struct frec *frec_list; struct frec *frec_list;
...@@ -1145,7 +1146,7 @@ size_t setup_reply(struct dns_header *header, size_t qlen, ...@@ -1145,7 +1146,7 @@ size_t setup_reply(struct dns_header *header, size_t qlen,
unsigned long ttl); unsigned long ttl);
int extract_addresses(struct dns_header *header, size_t qlen, char *name, int extract_addresses(struct dns_header *header, size_t qlen, char *name,
time_t now, char **ipsets, int is_sign, int check_rebind, 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, size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
struct in_addr local_addr, struct in_addr local_netmask, struct in_addr local_addr, struct in_addr local_netmask,
time_t now, int ad_reqd, int do_bit, int have_pseudoheader); 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 ...@@ -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_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_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 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); int dnskey_keytag(int alg, int flags, unsigned char *key, int keylen);
size_t filter_rrsigs(struct dns_header *header, size_t plen); size_t filter_rrsigs(struct dns_header *header, size_t plen);
unsigned char* hash_questions(struct dns_header *header, size_t plen, char *name); unsigned char* hash_questions(struct dns_header *header, size_t plen, char *name);
......
...@@ -859,7 +859,7 @@ int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char ...@@ -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) if (qtype != T_DS || qclass != class)
rc = STAT_BOGUS; rc = STAT_BOGUS;
else 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) if (rc == STAT_INSECURE)
rc = STAT_BOGUS; rc = STAT_BOGUS;
...@@ -1645,11 +1645,11 @@ static int zone_status(char *name, int class, char *keyname, time_t now) ...@@ -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_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) 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. 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 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 unsigned char **targets = NULL;
static int target_sz = 0; static int target_sz = 0;
...@@ -1659,8 +1659,20 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch ...@@ -1659,8 +1659,20 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
int i, j, rc; int i, j, rc;
int secure = STAT_SECURE; int secure = STAT_SECURE;
if (rr_status) /* extend rr_status if necessary */
memset(rr_status, 0, ntohs(header->ancount)); 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) if (neganswer)
*neganswer = 0; *neganswer = 0;
...@@ -1754,8 +1766,8 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch ...@@ -1754,8 +1766,8 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
if (j != i) if (j != i)
{ {
/* Done already: copy the validation status */ /* Done already: copy the validation status */
if (rr_status && (i < ntohs(header->ancount))) if (i < ntohs(header->ancount))
rr_status[i] = rr_status[j]; daemon->rr_status[i] = daemon->rr_status[j];
} }
else else
{ {
...@@ -1814,8 +1826,8 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch ...@@ -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 */ /* rc is now STAT_SECURE or STAT_SECURE_WILDCARD */
/* Note that RR is validated */ /* Note that RR is validated */
if (rr_status && (i < ntohs(header->ancount))) if (i < ntohs(header->ancount))
rr_status[i] = 1; daemon->rr_status[i] = 1;
/* Note if we've validated either the answer to the question /* Note if we've validated either the answer to the question
or the target of a CNAME. Any not noted will need NSEC or 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 ...@@ -560,7 +560,6 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
char **sets = 0; char **sets = 0;
int munged = 0, is_sign; int munged = 0, is_sign;
size_t plen; size_t plen;
char *rr_status = NULL;
(void)ad_reqd; (void)ad_reqd;
(void)do_bit; (void)do_bit;
...@@ -651,11 +650,6 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server ...@@ -651,11 +650,6 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
server->flags |= SERV_WARNED_RECURSIVE; 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 && if (daemon->bogus_addr && RCODE(header) != NXDOMAIN &&
check_for_bogus_wildcard(header, n, daemon->namebuff, daemon->bogus_addr, now)) 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 ...@@ -681,7 +675,7 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
cache_secure = 0; 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); my_syslog(LOG_WARNING, _("possible DNS-rebind attack detected: %s"), daemon->namebuff);
munged = 1; munged = 1;
...@@ -906,7 +900,7 @@ void reply_query(int fd, int family, time_t now) ...@@ -906,7 +900,7 @@ void reply_query(int fd, int family, time_t now)
else else
status = dnssec_validate_reply(now, header, n, daemon->namebuff, daemon->keyname, &forward->class, status = dnssec_validate_reply(now, header, n, daemon->namebuff, daemon->keyname, &forward->class,
option_bool(OPT_DNSSEC_NO_SIGN) && (server->flags & SERV_DO_DNSSEC), 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 /* 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 ...@@ -1491,7 +1485,7 @@ static int tcp_key_recurse(time_t now, int status, struct dns_header *header, si
else else
new_status = dnssec_validate_reply(now, header, n, name, keyname, &class, new_status = dnssec_validate_reply(now, header, n, name, keyname, &class,
option_bool(OPT_DNSSEC_NO_SIGN) && (server->flags & SERV_DO_DNSSEC), 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) if (new_status != STAT_NEED_DS && new_status != STAT_NEED_KEY)
break; break;
......
...@@ -585,7 +585,7 @@ static int find_soa(struct dns_header *header, size_t qlen, char *name, int *doc ...@@ -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. */ 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, 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, 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; unsigned char *p, *p1, *endrr, *namep;
int i, j, qtype, qclass, aqtype, aqclass, ardlen, res, searched_soa = 0; 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 ...@@ -610,9 +610,9 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t
{ {
if (secure) if (secure)
return 0; return 0;
if (rr_status) if (option_bool(OPT_DNSSEC_VALID))
for (i = 0; i < ntohs(header->ancount); i++) for (i = 0; i < ntohs(header->ancount); i++)
if (rr_status[i]) if (daemon->rr_status[i])
return 0; return 0;
} }
} }
...@@ -682,7 +682,7 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t ...@@ -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)) if (!extract_name(header, qlen, &p1, name, 1, 0))
return 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. */ /* validated RR anywhere in CNAME chain, don't cache. */
if (cname_short || aqtype == T_CNAME) if (cname_short || aqtype == T_CNAME)
...@@ -766,7 +766,7 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t ...@@ -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)) if (aqclass == C_IN && res != 2 && (aqtype == T_CNAME || aqtype == qtype))
{ {
#ifdef HAVE_DNSSEC #ifdef HAVE_DNSSEC
if (rr_status && rr_status[j]) if (option_bool(OPT_DNSSEC_VALID) && daemon->rr_status[j])
secflag = F_DNSSECOK; secflag = F_DNSSECOK;
#endif #endif
if (aqtype == T_CNAME) if (aqtype == T_CNAME)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment