mirror of
https://github.com/pi-hole/dnsmasq.git
synced 2025-12-19 18:28:25 +00:00
Add --cache-rr to enable caching of arbitrary RR types.
This commit is contained in:
160
src/rfc1035.c
160
src/rfc1035.c
@@ -89,23 +89,14 @@ int extract_name(struct dns_header *header, size_t plen, unsigned char **pp,
|
||||
if (isExtract)
|
||||
{
|
||||
unsigned char c = *p;
|
||||
#ifdef HAVE_DNSSEC
|
||||
if (option_bool(OPT_DNSSEC_VALID))
|
||||
|
||||
if (c == 0 || c == '.' || c == NAME_ESCAPE)
|
||||
{
|
||||
if (c == 0 || c == '.' || c == NAME_ESCAPE)
|
||||
{
|
||||
*cp++ = NAME_ESCAPE;
|
||||
*cp++ = c+1;
|
||||
}
|
||||
else
|
||||
*cp++ = c;
|
||||
*cp++ = NAME_ESCAPE;
|
||||
*cp++ = c+1;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if (c != 0 && c != '.')
|
||||
*cp++ = c;
|
||||
else
|
||||
return 0;
|
||||
*cp++ = c;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -118,10 +109,9 @@ int extract_name(struct dns_header *header, size_t plen, unsigned char **pp,
|
||||
cp++;
|
||||
if (c1 >= 'A' && c1 <= 'Z')
|
||||
c1 += 'a' - 'A';
|
||||
#ifdef HAVE_DNSSEC
|
||||
if (option_bool(OPT_DNSSEC_VALID) && c1 == NAME_ESCAPE)
|
||||
|
||||
if (c1 == NAME_ESCAPE)
|
||||
c1 = (*cp++)-1;
|
||||
#endif
|
||||
|
||||
if (c2 >= 'A' && c2 <= 'Z')
|
||||
c2 += 'a' - 'A';
|
||||
@@ -502,12 +492,10 @@ static int find_soa(struct dns_header *header, size_t qlen, int *doctored)
|
||||
}
|
||||
|
||||
/* Print TXT reply to log */
|
||||
static int print_txt(struct dns_header *header, const size_t qlen, char *name,
|
||||
unsigned char *p, const int ardlen, int secflag)
|
||||
static int log_txt(char *name, unsigned char *p, const int ardlen, int secflag)
|
||||
{
|
||||
unsigned char *p1 = p;
|
||||
if (!CHECK_LEN(header, p1, qlen, ardlen))
|
||||
return 0;
|
||||
|
||||
/* Loop over TXT payload */
|
||||
while ((p1 - p) < ardlen)
|
||||
{
|
||||
@@ -526,7 +514,7 @@ static int print_txt(struct dns_header *header, const size_t qlen, char *name,
|
||||
}
|
||||
|
||||
*p3 = 0;
|
||||
log_query(secflag | F_FORWARD | F_UPSTREAM, name, NULL, (char*)p1, 0);
|
||||
log_query(secflag | F_FORWARD, name, NULL, (char*)p1, 0);
|
||||
/* restore */
|
||||
memmove(p1 + 1, p1, i);
|
||||
*p1 = len;
|
||||
@@ -719,6 +707,8 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t
|
||||
}
|
||||
else if (qtype == T_SRV)
|
||||
flags |= F_SRV;
|
||||
else if (qtype != T_CNAME && rr_on_list(daemon->cache_rr, qtype))
|
||||
flags |= F_RR;
|
||||
else
|
||||
insert = 0; /* NOTE: do not cache data from CNAME queries. */
|
||||
|
||||
@@ -804,7 +794,7 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t
|
||||
#ifdef HAVE_DNSSEC
|
||||
if (!option_bool(OPT_DNSSEC_VALID) || aqtype != T_RRSIG)
|
||||
#endif
|
||||
log_query(secflag | F_FORWARD | F_UPSTREAM, name, NULL, NULL, aqtype);
|
||||
log_query(secflag | F_FORWARD | F_UPSTREAM | F_RRNAME, name, NULL, NULL, aqtype);
|
||||
}
|
||||
else if (!(flags & F_NXDOMAIN))
|
||||
{
|
||||
@@ -829,6 +819,64 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t
|
||||
if (!extract_name(header, qlen, &tmp, name, 1, 0))
|
||||
return 2;
|
||||
}
|
||||
else if (flags & F_RR)
|
||||
{
|
||||
short desc, *rrdesc = rrfilter_desc(aqtype);
|
||||
unsigned char *tmp = namep;
|
||||
|
||||
if (!CHECK_LEN(header, p1, qlen, ardlen))
|
||||
return 2; /* bad packet */
|
||||
addr.rr.rrtype = aqtype;
|
||||
addr.rr.datalen = 0;
|
||||
|
||||
/* The RR data may include names, and those names may include
|
||||
compression, which will be rendered meaningless when
|
||||
copied into another packet.
|
||||
Here we go through a description of the packet type to
|
||||
find the names, and extract them to a c-string and then
|
||||
re-encode them to standalone DNS format without compression. */
|
||||
if (!(addr.rr.rrdata = blockdata_alloc(NULL, 0)))
|
||||
return 0;
|
||||
do
|
||||
{
|
||||
desc = *rrdesc++;
|
||||
|
||||
if (desc == -1)
|
||||
{
|
||||
/* Copy the rest of the RR and end. */
|
||||
if (!blockdata_expand(addr.rr.rrdata, addr.rr.datalen, (char *)p1, endrr - p1))
|
||||
return 0;
|
||||
addr.rr.datalen += endrr - p1;
|
||||
}
|
||||
else if (desc == 0)
|
||||
{
|
||||
/* Name, extract it then re-encode. */
|
||||
int len;
|
||||
|
||||
if (!extract_name(header, qlen, &p1, name, 1, 0))
|
||||
return 2;
|
||||
|
||||
len = to_wire(name);
|
||||
if (!blockdata_expand(addr.rr.rrdata, addr.rr.datalen, name, len))
|
||||
return 0;
|
||||
addr.rr.datalen += len;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* desc is length of a block of data to be used as-is */
|
||||
if (desc > endrr - p1)
|
||||
desc = endrr - p1;
|
||||
if (!blockdata_expand(addr.rr.rrdata, addr.rr.datalen, (char *)p1, desc))
|
||||
return 0;
|
||||
addr.rr.datalen += desc;
|
||||
p1 += desc;
|
||||
}
|
||||
} while (desc != -1);
|
||||
|
||||
/* we overwrote the original name, so get it back here. */
|
||||
if (!extract_name(header, qlen, &tmp, name, 1, 0))
|
||||
return 2;
|
||||
}
|
||||
else if (flags & (F_IPV4 | F_IPV6))
|
||||
{
|
||||
/* copy address into aligned storage */
|
||||
@@ -876,8 +924,10 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t
|
||||
|
||||
if (aqtype == T_TXT)
|
||||
{
|
||||
if (!print_txt(header, qlen, name, p1, ardlen, secflag))
|
||||
return 2;
|
||||
if (!CHECK_LEN(header, p1, qlen, ardlen))
|
||||
return 2;
|
||||
|
||||
log_txt(name, p1, ardlen, secflag | F_UPSTREAM);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -903,7 +953,7 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t
|
||||
{
|
||||
if (flags & F_NXDOMAIN)
|
||||
{
|
||||
flags &= ~(F_IPV4 | F_IPV6 | F_SRV);
|
||||
flags &= ~(F_IPV4 | F_IPV6 | F_SRV | F_RR);
|
||||
|
||||
/* Can store NXDOMAIN reply for any qtype. */
|
||||
insert = 1;
|
||||
@@ -924,7 +974,10 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t
|
||||
if (ttl == 0)
|
||||
ttl = cttl;
|
||||
|
||||
newc = cache_insert(name, NULL, C_IN, now, ttl, F_FORWARD | F_NEG | flags | (secure ? F_DNSSECOK : 0));
|
||||
if (flags & F_RR)
|
||||
addr.rr.rrtype = qtype;
|
||||
|
||||
newc = cache_insert(name, &addr, C_IN, now, ttl, F_FORWARD | F_NEG | flags | (secure ? F_DNSSECOK : 0));
|
||||
if (newc && cpp)
|
||||
{
|
||||
next_uid(newc);
|
||||
@@ -2044,7 +2097,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
if (!found)
|
||||
{
|
||||
if ((crecp = cache_find_by_name(NULL, name, now, F_SRV | F_NXDOMAIN | (dryrun ? F_NO_RR : 0))) &&
|
||||
rd_bit && (!do_bit || (option_bool(OPT_DNSSEC_VALID) && !(crecp->flags & F_DNSSECOK))))
|
||||
rd_bit && (!do_bit || cache_validated(crecp)))
|
||||
do
|
||||
{
|
||||
int stale_flag = 0;
|
||||
@@ -2125,8 +2178,57 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
if (!dryrun)
|
||||
log_query(F_CONFIG | F_NEG, name, &addr, NULL, 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (!ans && qtype != T_ANY)
|
||||
{
|
||||
if ((crecp = cache_find_by_name(NULL, name, now, F_RR | F_NXDOMAIN | (dryrun ? F_NO_RR : 0))) &&
|
||||
rd_bit && (!do_bit || cache_validated(crecp)))
|
||||
do
|
||||
{
|
||||
int stale_flag = 0;
|
||||
|
||||
if (crecp->addr.rr.rrtype == qtype)
|
||||
{
|
||||
if (crec_isstale(crecp, now))
|
||||
{
|
||||
if (stale)
|
||||
*stale = 1;
|
||||
|
||||
stale_flag = F_STALE;
|
||||
}
|
||||
|
||||
if (!(crecp->flags & F_DNSSECOK))
|
||||
sec_data = 0;
|
||||
|
||||
auth = 0;
|
||||
ans = 1;
|
||||
|
||||
if (!dryrun)
|
||||
{
|
||||
char *rrdata = NULL;
|
||||
|
||||
if (!(crecp->flags & F_NEG))
|
||||
{
|
||||
rrdata = blockdata_retrieve(crecp->addr.rr.rrdata, crecp->addr.rr.datalen, NULL);
|
||||
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
crec_ttl(crecp, now), NULL, qtype, C_IN, "t",
|
||||
crecp->addr.rr.datalen, rrdata))
|
||||
anscount++;
|
||||
}
|
||||
|
||||
/* log after cache insertion as log_txt mangles rrdata */
|
||||
if (qtype == T_TXT && !(crecp->flags & F_NEG))
|
||||
log_txt(name, (unsigned char *)rrdata, crecp->addr.rr.datalen, crecp->flags & F_DNSSECOK);
|
||||
else
|
||||
log_query(stale_flag | crecp->flags, name, &crecp->addr, NULL, 0);
|
||||
}
|
||||
}
|
||||
} while ((crecp = cache_find_by_name(crecp, name, now, F_RR)));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!ans)
|
||||
{
|
||||
/* We may know that the domain doesn't exist for any RRtype. */
|
||||
|
||||
Reference in New Issue
Block a user