static void cache_blockdata_free(struct crec *crecp)
{
if (crecp->flags & F_DNSKEY)
- {
- if (crecp->flags & F_DS)
- blockdata_free(crecp->addr.sig.keydata);
- else
- blockdata_free(crecp->addr.key.keydata);
- }
+ blockdata_free(crecp->addr.key.keydata);
else if ((crecp->flags & F_DS) && !(crecp->flags & F_NEG))
blockdata_free(crecp->addr.ds.keydata);
}
}
#ifdef HAVE_DNSSEC
- /* Deletion has to be class-sensitive for DS, DNSKEY, RRSIG, also
- type-covered sensitive for RRSIG */
- if ((flags & (F_DNSKEY | F_DS)) &&
- (flags & (F_DNSKEY | F_DS)) == (crecp->flags & (F_DNSKEY | F_DS)) &&
- crecp->uid == addr->addr.dnssec.class &&
- (!((flags & (F_DS | F_DNSKEY)) == (F_DS | F_DNSKEY)) ||
- crecp->addr.sig.type_covered == addr->addr.dnssec.type))
+ /* Deletion has to be class-sensitive for DS and DNSKEY */
+ if ((flags & crecp->flags & (F_DNSKEY | F_DS)) && crecp->uid == addr->addr.dnssec.class)
{
if (crecp->flags & F_CONFIG)
return crecp;
struct all_addr free_addr = new->addr.addr;;
#ifdef HAVE_DNSSEC
- /* For DNSSEC records, addr holds class and type_covered for RRSIG */
+ /* For DNSSEC records, addr holds class. */
if (new->flags & (F_DS | F_DNSKEY))
- {
- free_addr.addr.dnssec.class = new->uid;
- if ((new->flags & (F_DS | F_DNSKEY)) == (F_DS | F_DNSKEY))
- free_addr.addr.dnssec.type = new->addr.sig.type_covered;
- }
+ free_addr.addr.dnssec.class = new->uid;
#endif
free_avail = 1; /* Must be free space now. */
if (!is_expired(now, crecp) && !is_outdated_cname_pointer(crecp))
{
if ((crecp->flags & F_FORWARD) &&
-#ifdef HAVE_DNSSEC
- (((crecp->flags & (F_DNSKEY | F_DS)) == (prot & (F_DNSKEY | F_DS))) || (prot & F_NSIGMATCH)) &&
-#endif
(crecp->flags & prot) &&
hostname_isequal(cache_get_name(crecp), name))
{
if (ans &&
(ans->flags & F_FORWARD) &&
-#ifdef HAVE_DNSSEC
- (((ans->flags & (F_DNSKEY | F_DS)) == (prot & (F_DNSKEY | F_DS))) || (prot & F_NSIGMATCH)) &&
-#endif
(ans->flags & prot) &&
hostname_isequal(cache_get_name(ans), name))
return ans;
#ifdef HAVE_DNSSEC
else if (cache->flags & F_DS)
{
- if (cache->flags & F_DNSKEY)
- /* RRSIG */
- sprintf(a, "%5u %3u %s", cache->addr.sig.keytag,
- cache->addr.sig.algo, querystr("", cache->addr.sig.type_covered));
- else if (!(cache->flags & F_NEG))
+ if (!(cache->flags & F_NEG))
sprintf(a, "%5u %3u %3u", cache->addr.ds.keytag,
cache->addr.ds.algo, cache->addr.ds.digest);
}
else if (cache->flags & F_CNAME)
t = "C";
#ifdef HAVE_DNSSEC
- else if ((cache->flags & (F_DS | F_DNSKEY)) == (F_DS | F_DNSKEY))
- t = "G"; /* DNSKEY and DS set -> RRISG */
else if (cache->flags & F_DS)
t = "S";
else if (cache->flags & F_DNSKEY)
unsigned char algo;
unsigned char digest;
} ds;
- struct {
- struct blockdata *keydata;
- unsigned short keylen, type_covered, keytag;
- char algo;
- } sig;
} addr;
time_t ttd; /* time to die */
- /* used as class if DNSKEY/DS/RRSIG, index to source for F_HOSTS */
+ /* used as class if DNSKEY/DS, index to source for F_HOSTS */
unsigned int uid;
unsigned short flags;
union {
#define F_SECSTAT (1u<<24)
#define F_NO_RR (1u<<25)
#define F_IPSET (1u<<26)
-#define F_NSIGMATCH (1u<<27)
-#define F_NOEXTRA (1u<<28)
+#define F_NOEXTRA (1u<<27)
/* Values of uid in crecs with F_CONFIG bit set. */
#define SRC_INTERFACE 0
{
unsigned char *psave, *p = (unsigned char *)(header+1);
struct crec *crecp, *recp1;
- int rc, j, qtype, qclass, ttl, rdlen, flags, algo, valid, keytag, type_covered;
+ int rc, j, qtype, qclass, ttl, rdlen, flags, algo, valid, keytag;
struct blockdata *key;
struct all_addr a;
if (valid)
{
- /* DNSKEY RRset determined to be OK, now cache it and the RRsigs that sign it. */
+ /* DNSKEY RRset determined to be OK, now cache it. */
cache_start_insert();
p = skip_questions(header, plen);
if ((key = blockdata_alloc((char*)p, rdlen - 4)))
{
if (!(recp1 = cache_insert(name, &a, now, ttl, F_FORWARD | F_DNSKEY | F_DNSSECOK)))
- blockdata_free(key);
+ {
+ blockdata_free(key);
+ return STAT_BOGUS;
+ }
else
{
a.addr.keytag = keytag;
}
}
}
- else if (qtype == T_RRSIG)
- {
- /* RRSIG, cache if covers DNSKEY RRset */
- if (rdlen < 18)
- return STAT_BOGUS; /* bad packet */
-
- GETSHORT(type_covered, p);
-
- if (type_covered == T_DNSKEY)
- {
- a.addr.dnssec.class = class;
- a.addr.dnssec.type = type_covered;
-
- algo = *p++;
- p += 13; /* labels, orig_ttl, expiration, inception */
- GETSHORT(keytag, p);
- if ((key = blockdata_alloc((char*)psave, rdlen)))
- {
- if (!(crecp = cache_insert(name, &a, now, ttl, F_FORWARD | F_DNSKEY | F_DS)))
- blockdata_free(key);
- else
- {
- crecp->addr.sig.keydata = key;
- crecp->addr.sig.keylen = rdlen;
- crecp->addr.sig.keytag = keytag;
- crecp->addr.sig.type_covered = type_covered;
- crecp->addr.sig.algo = algo;
- }
- }
- }
- }
-
+
p = psave;
}
cache_start_insert();
a.addr.dnssec.class = class;
- cache_insert(name, &a, now, ttl, flags);
+ if (!cache_insert(name, &a, now, ttl, flags))
+ return STAT_BOGUS;
cache_end_insert();
/* Not done, validate now */
if (j == i)
{
- int ttl, keytag, algo, digest, type_covered, sigcnt, rrcnt;
+ int ttl, keytag, algo, digest, sigcnt, rrcnt;
unsigned char *psave;
struct all_addr a;
struct blockdata *key;
struct crec *crecp;
char *wildname;
- int have_wildcard = 0;
-
+
if (!explore_rrset(header, plen, class1, type1, name, keyname, &sigcnt, &rrcnt))
return STAT_BOGUS;
if (rc == STAT_SECURE_WILDCARD)
{
- have_wildcard = 1;
-
/* An attacker replay a wildcard answer with a different
answer and overlay a genuine RR. To prove this
hasn't happened, the answer must prove that
return rc;
}
- /* Cache RRsigs in answer section, and if we just validated a DS RRset, cache it */
+ /* If we just validated a DS RRset, cache it */
/* Also note if the RRset is the answer to the question, or the target of a CNAME */
cache_start_insert();
}
}
}
- else if (type2 == T_RRSIG)
- {
- if (rdlen2 < 18)
- return STAT_BOGUS; /* bad packet */
-
- GETSHORT(type_covered, p2);
-
- if (type_covered == type1 &&
- (type_covered == T_A || type_covered == T_AAAA ||
- type_covered == T_CNAME || type_covered == T_DS ||
- type_covered == T_DNSKEY || type_covered == T_PTR))
- {
- a.addr.dnssec.type = type_covered;
- a.addr.dnssec.class = class1;
-
- algo = *p2++;
- p2 += 13; /* labels, orig_ttl, expiration, inception */
- GETSHORT(keytag, p2);
-
- /* We don't cache sigs for wildcard answers, because to reproduce the
- answer from the cache will require one or more NSEC/NSEC3 records
- which we don't cache. The lack of the RRSIG ensures that a query for
- this RRset asking for a secure answer will always be forwarded. */
- if (!have_wildcard && (key = blockdata_alloc((char*)psave, rdlen2)))
- {
- if (!(crecp = cache_insert(name, &a, now, ttl, F_FORWARD | F_DNSKEY | F_DS)))
- blockdata_free(key);
- else
- {
- crecp->addr.sig.keydata = key;
- crecp->addr.sig.keylen = rdlen2;
- crecp->addr.sig.keytag = keytag;
- crecp->addr.sig.type_covered = type_covered;
- crecp->addr.sig.algo = algo;
- }
- }
- }
- }
-
+
p2 = psave;
}
struct naptr *naptr;
/* Note: the call to cache_find_by_name is intended to find any record which matches
- ie A, AAAA, CNAME, DS. Because RRSIG records are marked by setting both F_DS and F_DNSKEY,
- cache_find_by name ordinarily only returns records with an exact match on those bits (ie
- for the call below, only DS records). The F_NSIGMATCH bit changes this behaviour */
+ ie A, AAAA, CNAME. */
- if ((crecp = cache_find_by_name(NULL, name, now, F_IPV4 | F_IPV6 | F_CNAME | F_DS | F_NO_RR | F_NSIGMATCH)) &&
+ if ((crecp = cache_find_by_name(NULL, name, now, F_IPV4 | F_IPV6 | F_CNAME |F_NO_RR)) &&
(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)))
return 1;
GETSHORT(flags, pheader);
if ((sec_reqd = flags & 0x8000))
- *do_bit = 1;/* do bit */
+ {
+ *do_bit = 1;/* do bit */
+ *ad_reqd = 1;
+ }
- *ad_reqd = 1;
dryrun = 1;
}
}
}
-#ifdef HAVE_DNSSEC
- if (option_bool(OPT_DNSSEC_VALID) && (qtype == T_DNSKEY || qtype == T_DS))
- {
- int gotone = 0;
- struct blockdata *keydata;
-
- /* Do we have RRSIG? Can't do DS or DNSKEY otherwise. */
- if (sec_reqd)
- {
- crecp = NULL;
- while ((crecp = cache_find_by_name(crecp, name, now, F_DNSKEY | F_DS)))
- if (crecp->uid == qclass && crecp->addr.sig.type_covered == qtype)
- break;
- }
-
- if (!sec_reqd || crecp)
- {
- if (qtype == T_DS)
- {
- crecp = NULL;
- while ((crecp = cache_find_by_name(crecp, name, now, F_DS)))
- if (crecp->uid == qclass)
- {
- gotone = 1;
- if (!dryrun)
- {
- if (crecp->flags & F_NEG)
- {
- if (crecp->flags & F_NXDOMAIN)
- nxdomain = 1;
- log_query(F_UPSTREAM, name, NULL, "no DS");
- }
- else if ((keydata = blockdata_retrieve(crecp->addr.ds.keydata, crecp->addr.ds.keylen, NULL)))
- {
- struct all_addr a;
- a.addr.keytag = crecp->addr.ds.keytag;
- log_query(F_KEYTAG | (crecp->flags & F_CONFIG), name, &a, "DS keytag %u");
- if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
- crec_ttl(crecp, now), &nameoffset,
- T_DS, qclass, "sbbt",
- crecp->addr.ds.keytag, crecp->addr.ds.algo,
- crecp->addr.ds.digest, crecp->addr.ds.keylen, keydata))
- anscount++;
-
- }
- }
- }
- }
- else /* DNSKEY */
- {
- crecp = NULL;
- while ((crecp = cache_find_by_name(crecp, name, now, F_DNSKEY)))
- if (crecp->uid == qclass)
- {
- gotone = 1;
- if (!dryrun && (keydata = blockdata_retrieve(crecp->addr.key.keydata, crecp->addr.key.keylen, NULL)))
- {
- struct all_addr a;
- a.addr.keytag = crecp->addr.key.keytag;
- log_query(F_KEYTAG | (crecp->flags & F_CONFIG), name, &a, "DNSKEY keytag %u");
- if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
- crec_ttl(crecp, now), &nameoffset,
- T_DNSKEY, qclass, "sbbt",
- crecp->addr.key.flags, 3, crecp->addr.key.algo, crecp->addr.key.keylen, keydata))
- anscount++;
- }
- }
- }
- }
-
- /* Now do RRSIGs */
- if (gotone)
- {
- ans = 1;
- auth = 0;
- if (!dryrun && sec_reqd)
- {
- crecp = NULL;
- while ((crecp = cache_find_by_name(crecp, name, now, F_DNSKEY | F_DS)))
- if (crecp->uid == qclass && crecp->addr.sig.type_covered == qtype &&
- (keydata = blockdata_retrieve(crecp->addr.sig.keydata, crecp->addr.sig.keylen, NULL)))
- {
- add_resource_record(header, limit, &trunc, nameoffset, &ansp,
- crec_ttl(crecp, now), &nameoffset,
- T_RRSIG, qclass, "t", crecp->addr.sig.keylen, keydata);
- anscount++;
- }
- }
- }
- }
-#endif
-
if (qclass == C_IN)
{
struct txt_record *t;
if ((t->class == qtype || qtype == T_ANY) && hostname_isequal(name, t->name))
{
ans = 1;
+ sec_data = 0;
if (!dryrun)
{
log_query(F_CONFIG | F_RRNAME, name, NULL, "<RR>");
if (intr)
{
+ sec_data = 0;
ans = 1;
if (!dryrun)
{
else if (ptr)
{
ans = 1;
+ sec_data = 0;
if (!dryrun)
{
log_query(F_CONFIG | F_RRNAME, name, NULL, "<PTR>");
}
else if ((crecp = cache_find_by_addr(NULL, &addr, now, is_arpa)))
{
- if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) && sec_reqd)
- {
- if (!option_bool(OPT_DNSSEC_VALID) || ((crecp->flags & F_NEG) && (crecp->flags & F_DNSSECOK)))
- crecp = NULL;
-#ifdef HAVE_DNSSEC
- else if (crecp->flags & F_DNSSECOK)
- {
- int gotsig = 0;
- struct crec *rr_crec = NULL;
-
- while ((rr_crec = cache_find_by_name(rr_crec, name, now, F_DS | F_DNSKEY)))
- {
- if (rr_crec->addr.sig.type_covered == T_PTR && rr_crec->uid == C_IN)
- {
- char *sigdata = blockdata_retrieve(rr_crec->addr.sig.keydata, rr_crec->addr.sig.keylen, NULL);
- gotsig = 1;
-
- if (!dryrun &&
- add_resource_record(header, limit, &trunc, nameoffset, &ansp,
- rr_crec->ttd - now, &nameoffset,
- T_RRSIG, C_IN, "t", crecp->addr.sig.keylen, sigdata))
- anscount++;
- }
- }
-
- if (!gotsig)
- crecp = NULL;
- }
-#endif
- }
-
- if (crecp)
+ /* Don't use cache when DNSSEC data required. */
+ if ((crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) || !sec_reqd || !(crecp->flags & F_DNSSECOK))
{
do
{
if (!(crecp->flags & F_DNSSECOK))
sec_data = 0;
-
+
+ ans = 1;
+
if (crecp->flags & F_NEG)
{
- ans = 1;
auth = 0;
if (crecp->flags & F_NXDOMAIN)
nxdomain = 1;
if (!dryrun)
log_query(crecp->flags & ~F_FORWARD, name, &addr, NULL);
}
- else if ((crecp->flags & (F_HOSTS | F_DHCP)) || !sec_reqd || option_bool(OPT_DNSSEC_VALID))
+ else
{
- ans = 1;
if (!(crecp->flags & (F_HOSTS | F_DHCP)))
auth = 0;
if (!dryrun)
else if (is_rev_synth(is_arpa, &addr, name))
{
ans = 1;
+ sec_data = 0;
if (!dryrun)
{
log_query(F_CONFIG | F_REVERSE | is_arpa, name, &addr, NULL);
{
/* if not in cache, enabled and private IPV4 address, return NXDOMAIN */
ans = 1;
+ sec_data = 0;
nxdomain = 1;
if (!dryrun)
log_query(F_CONFIG | F_REVERSE | F_IPV4 | F_NEG | F_NXDOMAIN,
if (i == 4)
{
ans = 1;
+ sec_data = 0;
if (!dryrun)
{
addr.addr.addr4.s_addr = htonl(a);
continue;
#endif
ans = 1;
+ sec_data = 0;
if (!dryrun)
{
gotit = 1;
crecp = save;
}
- /* If the client asked for DNSSEC and we can't provide RRSIGs, either
- because we've not doing DNSSEC or the cached answer is signed by negative,
- don't answer from the cache, forward instead. */
- if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) && sec_reqd)
- {
- if (!option_bool(OPT_DNSSEC_VALID) || ((crecp->flags & F_NEG) && (crecp->flags & F_DNSSECOK)))
- crecp = NULL;
-#ifdef HAVE_DNSSEC
- else if (crecp->flags & F_DNSSECOK)
- {
- /* We're returning validated data, need to return the RRSIG too. */
- struct crec *rr_crec = NULL;
- int sigtype = type;
- /* The signature may have expired even though the data is still in cache,
- forward instead of answering from cache if so. */
- int gotsig = 0;
-
- if (crecp->flags & F_CNAME)
- sigtype = T_CNAME;
-
- while ((rr_crec = cache_find_by_name(rr_crec, name, now, F_DS | F_DNSKEY)))
- {
- if (rr_crec->addr.sig.type_covered == sigtype && rr_crec->uid == C_IN)
- {
- char *sigdata = blockdata_retrieve(rr_crec->addr.sig.keydata, rr_crec->addr.sig.keylen, NULL);
- gotsig = 1;
-
- if (!dryrun &&
- add_resource_record(header, limit, &trunc, nameoffset, &ansp,
- rr_crec->ttd - now, &nameoffset,
- T_RRSIG, C_IN, "t", rr_crec->addr.sig.keylen, sigdata))
- anscount++;
- }
- }
-
- if (!gotsig)
- crecp = NULL;
- }
-#endif
- }
-
- if (crecp)
+ /* If the client asked for DNSSEC don't use cached data. */
+ if ((crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) || !sec_reqd || !(crecp->flags & F_DNSSECOK))
do
{
/* don't answer wildcard queries with data not from /etc/hosts