mirror of
https://github.com/pi-hole/dnsmasq.git
synced 2025-12-19 10:18:25 +00:00
backup
This commit is contained in:
20
src/cache.c
20
src/cache.c
@@ -26,7 +26,7 @@ static union bigname *big_free = NULL;
|
||||
static int bignames_left, hash_size;
|
||||
static int uid = 1;
|
||||
#ifdef HAVE_DNSSEC
|
||||
static struct keydata *keyblock_free = NULL;
|
||||
static struct blockdata *keyblock_free = NULL;
|
||||
#endif
|
||||
|
||||
/* type->string mapping: this is also used by the name-hash function as a mixing table. */
|
||||
@@ -198,7 +198,7 @@ static void cache_free(struct crec *crecp)
|
||||
}
|
||||
#ifdef HAVE_DNSSEC
|
||||
else if (crecp->flags & (F_DNSKEY | F_DS))
|
||||
keydata_free(crecp->addr.key.keydata);
|
||||
blockdata_free(crecp->addr.key.keydata);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1361,10 +1361,10 @@ void log_query(unsigned int flags, char *name, struct all_addr *addr, char *arg)
|
||||
}
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
struct keydata *keydata_alloc(char *data, size_t len)
|
||||
struct blockdata *blockdata_alloc(char *data, size_t len)
|
||||
{
|
||||
struct keydata *block, *ret = NULL;
|
||||
struct keydata **prev = &ret;
|
||||
struct blockdata *block, *ret = NULL;
|
||||
struct blockdata **prev = &ret;
|
||||
size_t blen;
|
||||
|
||||
while (len > 0)
|
||||
@@ -1375,12 +1375,12 @@ struct keydata *keydata_alloc(char *data, size_t len)
|
||||
keyblock_free = block->next;
|
||||
}
|
||||
else
|
||||
block = whine_malloc(sizeof(struct keydata));
|
||||
block = whine_malloc(sizeof(struct blockdata));
|
||||
|
||||
if (!block)
|
||||
{
|
||||
/* failed to alloc, free partial chain */
|
||||
keydata_free(ret);
|
||||
blockdata_free(ret);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1396,7 +1396,7 @@ struct keydata *keydata_alloc(char *data, size_t len)
|
||||
return ret;
|
||||
}
|
||||
|
||||
size_t keydata_walk(struct keydata **key, unsigned char **p, size_t cnt)
|
||||
size_t blockdata_walk(struct blockdata **key, unsigned char **p, size_t cnt)
|
||||
{
|
||||
if (*p == NULL)
|
||||
*p = (*key)->key;
|
||||
@@ -1411,9 +1411,9 @@ size_t keydata_walk(struct keydata **key, unsigned char **p, size_t cnt)
|
||||
return MIN(cnt, (*key)->key + KEYBLOCK_LEN - (*p));
|
||||
}
|
||||
|
||||
void keydata_free(struct keydata *blocks)
|
||||
void blockdata_free(struct blockdata *blocks)
|
||||
{
|
||||
struct keydata *tmp;
|
||||
struct blockdata *tmp;
|
||||
|
||||
if (blocks)
|
||||
{
|
||||
|
||||
@@ -140,3 +140,9 @@ struct dns_header {
|
||||
GETLONG(var, ptr); \
|
||||
(len) -= 4; \
|
||||
} while (0)
|
||||
|
||||
#define CHECK_LEN(header, pp, plen, len) \
|
||||
((size_t)((pp) - (unsigned char *)(header) + (len)) <= (plen))
|
||||
|
||||
#define ADD_RDLEN(header, pp, plen, len) \
|
||||
(!CHECK_LEN(header, pp, plen, len) ? 0 : (((pp) += (len)), 1))
|
||||
|
||||
@@ -81,8 +81,14 @@ int main (int argc, char **argv)
|
||||
umask(022); /* known umask, create leases and pid files as 0644 */
|
||||
|
||||
read_opts(argc, argv, compile_opts);
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
if (option_bool(OPT_DNSSEC_VALID))
|
||||
if (daemon->doctors) exit(1); /* TODO */
|
||||
|
||||
daemon->keyname = safe_malloc(MAXDNAME);
|
||||
#endif
|
||||
|
||||
if (daemon->edns_pktsz < PACKETSZ)
|
||||
daemon->edns_pktsz = option_bool(OPT_DNSSEC_VALID) ? EDNS_PKTSZ : PACKETSZ;
|
||||
daemon->packet_buff_sz = daemon->edns_pktsz > DNSMASQ_PACKETSZ ?
|
||||
|
||||
@@ -335,8 +335,8 @@ union bigname {
|
||||
union bigname *next; /* freelist */
|
||||
};
|
||||
|
||||
struct keydata {
|
||||
struct keydata *next;
|
||||
struct blockdata {
|
||||
struct blockdata *next;
|
||||
unsigned char key[KEYBLOCK_LEN];
|
||||
};
|
||||
|
||||
@@ -528,6 +528,7 @@ struct frec {
|
||||
unsigned int crc;
|
||||
time_t time;
|
||||
#ifdef HAVE_DNSSEC
|
||||
int class;
|
||||
struct blockdata *stash; /* Saved reply, whilst we validate */
|
||||
size_t stash_len;
|
||||
struct frec *dependent; /* Query awaiting internally-generated DNSKEY or DS query */
|
||||
@@ -900,6 +901,9 @@ extern struct daemon {
|
||||
char *packet; /* packet buffer */
|
||||
int packet_buff_sz; /* size of above */
|
||||
char *namebuff; /* MAXDNAME size buffer */
|
||||
#ifdef HAVE_DNSSEC
|
||||
char *keyname; /* MAXDNAME size buffer */
|
||||
#endif
|
||||
unsigned int local_answer, queries_forwarded, auth_answer;
|
||||
struct frec *frec_list;
|
||||
struct serverfd *sfds;
|
||||
@@ -1030,7 +1034,11 @@ int in_zone(struct auth_zone *zone, char *name, char **cut);
|
||||
#endif
|
||||
|
||||
/* dnssec.c */
|
||||
int dnssec_validate(int flags, struct dns_header *header, size_t plen);
|
||||
size_t dnssec_generate_query(struct dns_header *header, char *name, int class, int type);
|
||||
int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t n, 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 validate_rrset(time_t now, struct dns_header *header, size_t plen, int class, int type, char *name, char *keyname);
|
||||
int dnssec_validate_reply(struct dns_header *header, size_t plen, char *name, char *keyname, int *class);
|
||||
|
||||
/* util.c */
|
||||
void rand_init(void);
|
||||
|
||||
359
src/dnssec.c
359
src/dnssec.c
@@ -21,11 +21,15 @@
|
||||
/* Maximum length in octects of a domain name, in wire format */
|
||||
#define MAXCDNAME 256
|
||||
|
||||
#define MAXRRSET 16
|
||||
|
||||
#define SERIAL_UNDEF -100
|
||||
#define SERIAL_EQ 0
|
||||
#define SERIAL_LT -1
|
||||
#define SERIAL_GT 1
|
||||
|
||||
static int dnskey_keytag(int alg, unsigned char *rdata, int rdlen);
|
||||
|
||||
/* Implement RFC1982 wrapped compare for 32-bit numbers */
|
||||
static int serial_compare_32(unsigned long s1, unsigned long s2)
|
||||
{
|
||||
@@ -494,7 +498,359 @@ static int digestalg_add_rdata(int sigtype, struct dns_header *header, size_t pk
|
||||
return 1;
|
||||
}
|
||||
|
||||
size_t dnssec_generate_query(struct dns_header *header, char *name, int class, int type)
|
||||
{
|
||||
unsigned char *p;
|
||||
|
||||
header->qdcount = htons(1);
|
||||
header->ancount = htons(0);
|
||||
header->nscount = htons(0);
|
||||
header->arcount = htons(0);
|
||||
|
||||
header->hb3 = HB3_RD;
|
||||
SET_OPCODE(header, QUERY);
|
||||
header->hb4 = 0;
|
||||
|
||||
/* ID filled in later */
|
||||
|
||||
p = (unsigned char *)(header+1);
|
||||
|
||||
p = do_rfc1035_name(p, name);
|
||||
PUTSHORT(type, p);
|
||||
PUTSHORT(class, p);
|
||||
|
||||
return add_do_bit(header, p - (unsigned char *)header, ((char *) header) + PACKETSZ);
|
||||
}
|
||||
|
||||
/* The DNS packet is expected to contain the answer to a DNSKEY query
|
||||
Put all DNSKEYs in the answer which are valid into the cache.
|
||||
return codes:
|
||||
STAT_INSECURE bad packet, no DNSKEYs in reply.
|
||||
STAT_SECURE At least one valid DNSKEY found and in cache.
|
||||
STAT_BOGUS At least one DNSKEY found, which fails validation.
|
||||
STAT_NEED_DS DS records to validate a key not found, name in namebuff
|
||||
*/
|
||||
int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname, int class)
|
||||
{
|
||||
unsigned char *p;
|
||||
struct crec *crecp, *recp1;
|
||||
int j, qtype, qclass, ttl, rdlen, flags, protocol, algo, gotone;
|
||||
struct blockdata *key;
|
||||
|
||||
if (ntohs(header->qdcount) != 1)
|
||||
return STAT_INSECURE;
|
||||
|
||||
if (!extract_name(header, plen, &p, name, 1, 4))
|
||||
return STAT_INSECURE;
|
||||
|
||||
GETSHORT(qtype, p);
|
||||
GETSHORT(qclass, p);
|
||||
|
||||
if (qtype != T_DNSKEY || qclass != class)
|
||||
return STAT_INSECURE;
|
||||
|
||||
cache_start_insert();
|
||||
|
||||
for (gotone = 0, j = ntohs(header->ancount); j != 0; j--)
|
||||
{
|
||||
/* Ensure we have type, class TTL and length */
|
||||
if (!extract_name(header, plen, &p, name, 1, 10))
|
||||
return STAT_INSECURE; /* bad packet */
|
||||
|
||||
GETSHORT(qtype, p);
|
||||
GETSHORT(qclass, p);
|
||||
GETLONG(ttl, p);
|
||||
GETSHORT(rdlen, p);
|
||||
|
||||
if (qclass != class || qtype != T_DNSKEY || rdlen < 4)
|
||||
{
|
||||
/* skip all records other than DNSKEY */
|
||||
p += rdlen;
|
||||
continue;
|
||||
}
|
||||
|
||||
crecp = cache_find_by_name(NULL, name, now, F_DS);
|
||||
|
||||
/* length at least covers flags, protocol and algo now. */
|
||||
GETSHORT(flags, p);
|
||||
protocol = *p++;
|
||||
algo = *p++;
|
||||
|
||||
/* See if we have cached a DS record which validates this key */
|
||||
for (recp1 = crecp; recp1; recp1 = cache_find_by_name(recp1, name, now, F_DS))
|
||||
if (recp1->addr.key.algo == algo && is_supported_digest(recp1->addr.key.digest))
|
||||
break;
|
||||
|
||||
/* DS record needed to validate key is missing, return name of DS in namebuff */
|
||||
if (!recp1)
|
||||
return STAT_NEED_DS;
|
||||
else
|
||||
{
|
||||
int valid = 1;
|
||||
/* calculate digest of canonicalised DNSKEY data using digest in (recp1->addr.key.digest)
|
||||
and see if it equals digest stored in recp1
|
||||
*/
|
||||
|
||||
if (!valid)
|
||||
return STAT_BOGUS;
|
||||
}
|
||||
|
||||
if ((key = blockdata_alloc((char*)p, rdlen)))
|
||||
{
|
||||
|
||||
/* We've proved that the KEY is OK, store it in the cache */
|
||||
if ((crecp = cache_insert(name, NULL, now, ttl, F_FORWARD | F_DNSKEY)))
|
||||
{
|
||||
crecp->uid = rdlen;
|
||||
crecp->addr.key.keydata = key;
|
||||
crecp->addr.key.algo = algo;
|
||||
crecp->addr.key.keytag = dnskey_keytag(algo, (char*)p, rdlen);
|
||||
gotone = 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
cache_end_insert();
|
||||
|
||||
|
||||
return gotone ? STAT_SECURE : STAT_INSECURE;
|
||||
}
|
||||
/* The DNS packet is expected to contain the answer to a DS query
|
||||
Put all DSs in the answer which are valid into the cache.
|
||||
return codes:
|
||||
STAT_INSECURE bad packet, no DNSKEYs in reply.
|
||||
STAT_SECURE At least one valid DS found and in cache.
|
||||
STAT_BOGUS At least one DS found, which fails validation.
|
||||
STAT_NEED_DNSKEY DNSKEY records to validate a DS not found, name in keyname
|
||||
*/
|
||||
|
||||
int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname, int class)
|
||||
{
|
||||
unsigned char *p = (unsigned char *)(header+1);
|
||||
struct crec *crecp, *recp1;
|
||||
int qtype, qclass, val, j, gotone;
|
||||
struct blockdata *key;
|
||||
|
||||
if (ntohs(header->qdcount) != 1)
|
||||
return STAT_INSECURE;
|
||||
|
||||
if (!extract_name(header, plen, &p, name, 1, 4))
|
||||
return STAT_INSECURE;
|
||||
|
||||
GETSHORT(qtype, p);
|
||||
GETSHORT(qclass, p);
|
||||
|
||||
if (qtype != T_DS || qclass != class)
|
||||
return STAT_INSECURE;
|
||||
|
||||
val = validate_rrset(header, plen, class, T_DS, name, keyname);
|
||||
|
||||
/* failed to validate or missing key. */
|
||||
if (val != STAT_SECURE)
|
||||
return val;
|
||||
|
||||
cache_start_insert();
|
||||
|
||||
for (gotone = 0, j = ntohs(header->ancount); j != 0; j--)
|
||||
{
|
||||
int ttl, rdlen, rc, algo;
|
||||
|
||||
/* Ensure we have type, class TTL and length */
|
||||
if (!(rc = extract_name(header, plen, &p, name, 0, 10)))
|
||||
return STAT_INSECURE; /* bad packet */
|
||||
|
||||
GETSHORT(qtype, p);
|
||||
GETSHORT(qclass, p);
|
||||
GETLONG(ttl, p);
|
||||
GETSHORT(rdlen, p);
|
||||
|
||||
/* check type, class and name, skip if not in DS rrset */
|
||||
if (qclass != class || qtype != T_DS || rc == 2)
|
||||
{
|
||||
p += rdlen;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((key = blockdata_alloc((char*)p, rdlen)))
|
||||
{
|
||||
|
||||
/* We've proved that the DS is OK, store it in the cache */
|
||||
if ((crecp = cache_insert(name, NULL, now, ttl, F_FORWARD | F_DS)))
|
||||
{
|
||||
crecp->uid = rdlen;
|
||||
crecp->addr.key.keydata = key;
|
||||
crecp->addr.key.algo = algo;
|
||||
crecp->addr.key.keytag = dnskey_keytag(algo, (char*)p, rdlen);
|
||||
gotone = 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
cache_end_insert();
|
||||
|
||||
|
||||
return gotone ? STAT_SECURE : STAT_INSECURE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Validate a single RRset (class, type, name) in the supplied DNS reply
|
||||
Return code:
|
||||
STAT_SECURE if it validates.
|
||||
STAT_INSECURE can't validate (no RRSIG, bad packet).
|
||||
STAT_BOGUS signature is wrong.
|
||||
STAT_NEED_KEY need DNSKEY to complete validation (name is returned in keyname)
|
||||
*/
|
||||
int validate_rrset(time_t now, struct dns_header *header, size_t plen, int class, int type, char *name, char *keyname)
|
||||
{
|
||||
unsigned char *p, *psav, *sig;
|
||||
int rrsetidx, res, sigttl, sig_data_len, j;
|
||||
struct crec *crecp;
|
||||
void *rrset[MAXRRSET]; /* TODO: max RRset size? */
|
||||
int type_covered, algo, labels, orig_ttl, sig_expiration, sig_inception, key_tag;
|
||||
|
||||
if (!(p = skip_questions(header, plen)))
|
||||
return STAT_INSECURE;
|
||||
|
||||
/* look for an RRSIG record for this RRset and get pointers to each record */
|
||||
for (rrsetidx = 0, sig = NULL, j = ntohs(header->ancount) + ntohs(header->nscount);
|
||||
j != 0; j--)
|
||||
{
|
||||
unsigned char *pstart = p;
|
||||
int stype, sclass, sttl, rdlen;
|
||||
|
||||
if (!(res = extract_name(header, plen, &p, name, 0, 10)))
|
||||
return STAT_INSECURE; /* bad packet */
|
||||
|
||||
GETSHORT(stype, p);
|
||||
GETSHORT(sclass, p);
|
||||
GETLONG(sttl, p);
|
||||
GETSHORT(rdlen, p);
|
||||
|
||||
if (!CHECK_LEN(header, p, plen, rdlen))
|
||||
return STAT_INSECURE; /* bad packet */
|
||||
|
||||
if (res == 2 || htons(stype) != T_RRSIG || htons(sclass) != class)
|
||||
continue;
|
||||
|
||||
if (htons(stype) == type)
|
||||
{
|
||||
rrset[rrsetidx++] = pstart;
|
||||
if (rrsetidx == MAXRRSET)
|
||||
return STAT_INSECURE; /* RRSET too big TODO */
|
||||
}
|
||||
|
||||
if (htons(stype) == T_RRSIG)
|
||||
{
|
||||
/* name matches, RRSIG for correct class */
|
||||
/* enough data? */
|
||||
if (rdlen < 18)
|
||||
return STAT_INSECURE;
|
||||
|
||||
GETSHORT(type_covered, p);
|
||||
algo = *p++;
|
||||
labels = *p++;
|
||||
GETLONG(orig_ttl, p);
|
||||
GETLONG(sig_expiration, p);
|
||||
GETLONG(sig_inception, p);
|
||||
GETSHORT(key_tag, p);
|
||||
|
||||
if (type_covered != type ||
|
||||
!check_date_range(sig_inception, sig_expiration))
|
||||
{
|
||||
/* covers wrong type or out of date - skip */
|
||||
p = psav;
|
||||
if (!ADD_RDLEN(header, p, plen, rdlen))
|
||||
return STAT_INSECURE;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!extract_name(header, plen, &p, keyname, 1, 0))
|
||||
return STAT_INSECURE;
|
||||
|
||||
/* OK, we have the signature record, see if the
|
||||
relevant DNSKEY is in the cache. */
|
||||
for (crecp = cache_find_by_name(NULL, keyname, now, F_DNSKEY);
|
||||
crecp;
|
||||
crecp = cache_find_by_name(crecp, keyname, now, F_DNSKEY))
|
||||
if (crecp->addr.key.algo == algo && crecp->addr.key.keytag == key_tag)
|
||||
break;
|
||||
|
||||
/* No, abort for now whilst we get it */
|
||||
if (!crecp)
|
||||
return STAT_NEED_KEY;
|
||||
|
||||
/* Save point to signature data */
|
||||
sig = p;
|
||||
sig_data_len = rdlen - (p - psav);
|
||||
sigttl = sttl;
|
||||
|
||||
/* next record */
|
||||
p = psav;
|
||||
if (!ADD_RDLEN(header, p, plen, rdlen))
|
||||
return STAT_INSECURE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Didn't find RRSIG or RRset is empty */
|
||||
if (!sig || rrsetidx == 0)
|
||||
return STAT_INSECURE;
|
||||
|
||||
/* OK, we have an RRSIG and an RRset and we have a the DNSKEY that validates them. */
|
||||
|
||||
/* Sort RRset records in canonical order. */
|
||||
rrset_canonical_order_ctx.header = header;
|
||||
rrset_canonical_order_ctx.pktlen = plen;
|
||||
qsort(rrset, rrsetidx, sizeof(void*), rrset_canonical_order);
|
||||
|
||||
/* Now initialize the signature verification algorithm and process the whole
|
||||
RRset */
|
||||
VerifyAlgCtx *alg = verifyalg_alloc(algo);
|
||||
if (!alg)
|
||||
return STAT_INSECURE;
|
||||
|
||||
alg->sig = sig;
|
||||
alg->siglen = sig_data_len;
|
||||
|
||||
u16 ntype = htons(type);
|
||||
u16 nclass = htons(class);
|
||||
u32 nsigttl = htonl(sigttl);
|
||||
|
||||
/* TODO: we shouldn't need to convert this to wire here. Best solution would be:
|
||||
- Use process_name() instead of extract_name() everywhere in dnssec code
|
||||
- Convert from wire format to representation format only for querying/storing cache
|
||||
*/
|
||||
unsigned char owner_wire[MAXCDNAME];
|
||||
int owner_wire_len = convert_domain_to_wire(name, owner_wire);
|
||||
|
||||
digestalg_begin(alg->vtbl->digest_algo);
|
||||
digestalg_add_data(sigrdata, 18+signer_name_rdlen);
|
||||
for (i = 0; i < rrsetidx; ++i)
|
||||
{
|
||||
p = (unsigned char*)(rrset[i]);
|
||||
|
||||
digestalg_add_data(owner_wire, owner_wire_len);
|
||||
digestalg_add_data(&ntype, 2);
|
||||
digestalg_add_data(&nclass, 2);
|
||||
digestalg_add_data(&nsigttl, 4);
|
||||
|
||||
p += 8;
|
||||
if (!digestalg_add_rdata(ntohs(sigtype), header, pktlen, p))
|
||||
return 0;
|
||||
}
|
||||
int digest_len = digestalg_len();
|
||||
memcpy(alg->digest, digestalg_final(), digest_len);
|
||||
|
||||
if (alg->vtbl->verify(alg, crecp->addr.key.keydata, crecp_uid))
|
||||
return STAT_SECURE;
|
||||
|
||||
return STAT_INSECURE;
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
static int begin_rrsig_validation(struct dns_header *header, size_t pktlen,
|
||||
unsigned char *reply, int count, char *owner,
|
||||
int sigclass, int sigrdlen, unsigned char *sig,
|
||||
@@ -624,6 +980,7 @@ static int end_rrsig_validation(PendingRRSIGValidation *val, struct crec *crec_d
|
||||
return val->alg->vtbl->verify(val->alg, crec_dnskey->addr.key.keydata, crec_dnskey->uid);
|
||||
}
|
||||
|
||||
|
||||
static void dnssec_parserrsig(struct dns_header *header, size_t pktlen,
|
||||
unsigned char *reply, int count, char *owner,
|
||||
int sigclass, int sigrdlen, unsigned char *sig)
|
||||
@@ -663,6 +1020,8 @@ static void dnssec_parserrsig(struct dns_header *header, size_t pktlen,
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* comment out */
|
||||
|
||||
/* Compute keytag (checksum to quickly index a key). See RFC4034 */
|
||||
static int dnskey_keytag(int alg, unsigned char *rdata, int rdlen)
|
||||
{
|
||||
|
||||
@@ -678,15 +678,14 @@ void reply_query(int fd, int family, time_t now)
|
||||
if (option_bool(OPT_DNSSEC_VALID) && !(forward->flags & FREC_CHECKING_DISABLED))
|
||||
{
|
||||
int status;
|
||||
char rrbitmap[256/8];
|
||||
int class;
|
||||
|
||||
if (forward->flags && FREC_DNSSKEY_QUERY)
|
||||
status = dnssec_validate_by_ds(header, n, daemon->namebuff, &class);
|
||||
else if (forward->flags && FREC_DS_QUERY)
|
||||
status = dnssec_validate_dnskey(header, n, daemon->namebuff, &class);
|
||||
if (forward->flags & FREC_DNSKEY_QUERY)
|
||||
status = dnssec_validate_by_ds(now, header, n, daemon->namebuff, daemon->keyname, forward->class);
|
||||
else if (forward->flags & FREC_DS_QUERY)
|
||||
status = dnssec_validate_ds(now, header, n, daemon->namebuff, daemon->keyname, forward->class);
|
||||
else
|
||||
status = dnssec_validate_reply(&rrbitmap, header, n, daemon->namebuff, &class);
|
||||
status = dnssec_validate_reply(header, n, daemon->namebuff, daemon->keyname, &forward->class);
|
||||
|
||||
/* Can't validate, as we're missing key data. Put this
|
||||
answer aside, whilst we get that. */
|
||||
@@ -717,7 +716,7 @@ void reply_query(int fd, int family, time_t now)
|
||||
}
|
||||
new->crc = questions_crc(header, nn, daemon->namebuff);
|
||||
new->new_id = get_id(new->crc);
|
||||
header->id = htons(new->id);
|
||||
header->id = htons(new->new_id);
|
||||
|
||||
/* Don't resend this. */
|
||||
daemon->srv_save = NULL;
|
||||
@@ -751,22 +750,30 @@ void reply_query(int fd, int family, time_t now)
|
||||
and validate them with the new data. Failure to find needed data here is an internal error.
|
||||
Once we get to the original answer (FREC_DNSSEC_QUERY not set) and it validates,
|
||||
return it to the original requestor. */
|
||||
while (forward->flags & FREC_DNSSEC_QUERY)
|
||||
while (forward->dependent)
|
||||
{
|
||||
if (status == STAT_SECURE)
|
||||
extract_dnssec_replies();
|
||||
struct frec *prev = forward->dependent;
|
||||
free_frec(forward);
|
||||
forward = forward->dependent;
|
||||
forward = prev;
|
||||
blockdata_retrieve_and_free(forward->stash, forward->stash_len, (void *)header);
|
||||
n = forward->stash_len;
|
||||
if (status == STAT_SECURE)
|
||||
{
|
||||
status = dnssec_validate(forward->flags, header, n);
|
||||
if (status == STAT_NEED_DS || status == STAT_NEED_KEY)
|
||||
my_syslog(LOG_ERR, _("Unexpected missing data for DNSSEC validation"));
|
||||
if (forward->flags & FREC_DNSKEY_QUERY)
|
||||
status = dnssec_validate_by_ds(now, header, n, daemon->namebuff, daemon->keyname, forward->class);
|
||||
else if (forward->flags & FREC_DS_QUERY)
|
||||
status = dnssec_validate_dnskey(now, header, n, daemon->namebuff, daemon->keyname, forward->class);
|
||||
|
||||
if (status == STAT_NEED_DS || status == STAT_NEED_KEY)
|
||||
my_syslog(LOG_ERR, _("Unexpected missing data for DNSSEC validation"));
|
||||
}
|
||||
}
|
||||
|
||||
/* All DNSKEY and DS records done and in cache, now finally validate original
|
||||
answer, provided last DNSKEY is OK. */
|
||||
if (status == STAT_SECURE)
|
||||
status = dnssec_validate_reply(header, n, daemon->namebuff, daemon->keyname, &forward->class);
|
||||
|
||||
if (status == STAT_SECURE)
|
||||
cache_secure = 1;
|
||||
/* TODO return SERVFAIL here */
|
||||
|
||||
@@ -16,13 +16,6 @@
|
||||
|
||||
#include "dnsmasq.h"
|
||||
|
||||
|
||||
#define CHECK_LEN(header, pp, plen, len) \
|
||||
((size_t)((pp) - (unsigned char *)(header) + (len)) <= (plen))
|
||||
|
||||
#define ADD_RDLEN(header, pp, plen, len) \
|
||||
(!CHECK_LEN(header, pp, plen, len) ? 0 : (((pp) += (len)), 1))
|
||||
|
||||
int extract_name(struct dns_header *header, size_t plen, unsigned char **pp,
|
||||
char *name, int isExtract, int extrabytes)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user