read_write(daemon->pipe_to_parent, (unsigned char *)name, m, 0);
read_write(daemon->pipe_to_parent, (unsigned char *)&new_chain->ttd, sizeof(new_chain->ttd), 0);
read_write(daemon->pipe_to_parent, (unsigned char *)&flags, sizeof(flags), 0);
-
- if (flags & (F_IPV4 | F_IPV6 | F_DNSKEY | F_DS | F_RR))
+ read_write(daemon->pipe_to_parent, (unsigned char *)&new_chain->addr, sizeof(new_chain->addr), 0);
+
+ if (flags & F_RR)
{
- read_write(daemon->pipe_to_parent, (unsigned char *)&new_chain->addr, sizeof(new_chain->addr), 0);
-
- if (flags & F_RR)
- {
- /* A negative RR entry is possible and has no data, obviously. */
- if (!(flags & F_NEG) && (flags & F_KEYTAG))
- blockdata_write(new_chain->addr.rrblock.rrdata, new_chain->addr.rrblock.datalen, daemon->pipe_to_parent);
- }
+ /* A negative RR entry is possible and has no data, obviously. */
+ if (!(flags & F_NEG) && (flags & F_KEYTAG))
+ blockdata_write(new_chain->addr.rrblock.rrdata, new_chain->addr.rrblock.datalen, daemon->pipe_to_parent);
+ }
#ifdef HAVE_DNSSEC
- if (flags & F_DNSKEY)
- {
- read_write(daemon->pipe_to_parent, (unsigned char *)&class, sizeof(class), 0);
- blockdata_write(new_chain->addr.key.keydata, new_chain->addr.key.keylen, daemon->pipe_to_parent);
- }
- else if (flags & F_DS)
- {
- read_write(daemon->pipe_to_parent, (unsigned char *)&class, sizeof(class), 0);
- /* A negative DS entry is possible and has no data, obviously. */
- if (!(flags & F_NEG))
- blockdata_write(new_chain->addr.ds.keydata, new_chain->addr.ds.keylen, daemon->pipe_to_parent);
- }
-#endif
+ if (flags & F_DNSKEY)
+ {
+ read_write(daemon->pipe_to_parent, (unsigned char *)&class, sizeof(class), 0);
+ blockdata_write(new_chain->addr.key.keydata, new_chain->addr.key.keylen, daemon->pipe_to_parent);
}
+ else if (flags & F_DS)
+ {
+ read_write(daemon->pipe_to_parent, (unsigned char *)&class, sizeof(class), 0);
+ /* A negative DS entry is possible and has no data, obviously. */
+ if (!(flags & F_NEG))
+ blockdata_write(new_chain->addr.ds.keydata, new_chain->addr.ds.keylen, daemon->pipe_to_parent);
+ }
+#endif
}
}
if (!read_write(fd, (unsigned char *)daemon->namebuff, m, 1) ||
!read_write(fd, (unsigned char *)&ttd, sizeof(ttd), 1) ||
- !read_write(fd, (unsigned char *)&flags, sizeof(flags), 1))
+ !read_write(fd, (unsigned char *)&flags, sizeof(flags), 1) ||
+ !read_write(fd, (unsigned char *)&addr, sizeof(addr), 1))
return 0;
daemon->namebuff[m] = 0;
{
unsigned short class = C_IN;
- if (flags & (F_IPV4 | F_IPV6 | F_DNSKEY | F_DS | F_RR))
+ if ((flags & F_RR) && !(flags & F_NEG) && (flags & F_KEYTAG)
+ && !(addr.rrblock.rrdata = blockdata_read(fd, addr.rrblock.datalen)))
+ return 0;
+#ifdef HAVE_DNSSEC
+ if (flags & F_DNSKEY)
{
- if (!read_write(fd, (unsigned char *)&addr, sizeof(addr), 1))
+ if (!read_write(fd, (unsigned char *)&class, sizeof(class), 1) ||
+ !(addr.key.keydata = blockdata_read(fd, addr.key.keylen)))
return 0;
-
- if ((flags & F_RR) && !(flags & F_NEG) && (flags & F_KEYTAG)
- && !(addr.rrblock.rrdata = blockdata_read(fd, addr.rrblock.datalen)))
+ }
+ else if (flags & F_DS)
+ {
+ if (!read_write(fd, (unsigned char *)&class, sizeof(class), 1) ||
+ (!(flags & F_NEG) && !(addr.key.keydata = blockdata_read(fd, addr.key.keylen))))
return 0;
-#ifdef HAVE_DNSSEC
- if (flags & F_DNSKEY)
- {
- if (!read_write(fd, (unsigned char *)&class, sizeof(class), 1) ||
- !(addr.key.keydata = blockdata_read(fd, addr.key.keylen)))
- return 0;
- }
- else if (flags & F_DS)
- {
- if (!read_write(fd, (unsigned char *)&class, sizeof(class), 1) ||
- (!(flags & F_NEG) && !(addr.key.keydata = blockdata_read(fd, addr.key.keylen))))
- return 0;
- }
-#endif
}
-
+#endif
crecp = really_insert(daemon->namebuff, &addr, class, now, ttl, flags);
}
}
p = buff;
*a = 0;
- if (strlen(n) == 0 && !(cache->flags & F_REVERSE))
- n = "<Root>";
+
+ if (cache->flags & F_REVERSE)
+ {
+ if ((cache->flags & F_NEG))
+ n = "";
+ }
+ else
+ {
+ if (strlen(n) == 0)
+ n = "<Root>";
+ }
+
p += sprintf(p, "%-30.30s ", sanitise(n));
if ((cache->flags & F_CNAME) && !is_outdated_cname_pointer(cache))
a = sanitise(cache_get_cname_target(cache));
Cache said SOA and return the difference in length between name and the name of the
SOA RR so we can look it up again.
*/
-static int find_soa(struct dns_header *header, size_t qlen, char *name, int *substring, int no_cache, time_t now)
+static int find_soa(struct dns_header *header, size_t qlen, char *name, int *substring, unsigned long *ttlp, int no_cache, time_t now)
{
unsigned char *p, *psave;
int qtype, qclass, rdlen;
if (substring)
*substring = name_len;
+
+ if (ttlp)
+ *ttlp = daemon->neg_ttl;
for (i = 0; i < ntohs(header->nscount); i++)
{
if (substring)
*substring = prefix;
- return minttl;
+ if (ttlp)
+ *ttlp = minttl;
+
+ return 1;
}
}
return 0; /* bad packet */
}
- return daemon->neg_ttl;
+ return 0;
}
/* Print TXT reply to log */
if (!found && !option_bool(OPT_NO_NEG))
{
- /* don't cache SOAs for negative PTR records */
- ttl = find_soa(header, qlen, name, NULL, 1, now);
+ /* For reverse records, we use the name field to store the SOA name. */
+ int substring, have_soa = find_soa(header, qlen, name, &substring, &ttl, no_cache_dnssec, now);
flags |= F_NEG | (secure ? F_DNSSECOK : 0);
if (name_encoding && ttl)
{
flags |= F_REVERSE | name_encoding;
- cache_insert(NULL, &addr, C_IN, now, ttl, flags);
+ if (!have_soa)
+ flags |= F_NO_RR; /* Marks no SOA found. */
+ cache_insert(name + substring, &addr, C_IN, now, ttl, flags);
}
log_query(flags | F_UPSTREAM, name, &addr, NULL, 0);
if (!found && (qtype != T_ANY || (flags & F_NXDOMAIN)))
{
- int substring;
+ int substring, have_soa;
if (flags & F_NXDOMAIN)
{
log_query(F_UPSTREAM | F_FORWARD | F_NEG | flags | (secure ? F_DNSSECOK : 0), name, NULL, NULL, 0);
- /* If there's no SOA to get the TTL from, but there is a CNAME
- pointing at this, inherit its TTL */
- if (insert && !option_bool(OPT_NO_NEG) && ((ttl = find_soa(header, qlen, name, &substring, no_cache_dnssec, now)) || cpp))
+ if (insert && !option_bool(OPT_NO_NEG))
{
- addr.rrdata.datalen = substring;
- addr.rrdata.rrtype = qtype;
+ int have_soa = find_soa(header, qlen, name, &substring, &ttl, no_cache_dnssec, now);
- if (ttl == 0)
- ttl = cttl;
+ /* If there's no SOA to get the TTL from, but there is a CNAME
+ pointing at this, inherit its TTL */
+ if (ttl || cpp)
+ {
+ if (!ttl)
+ ttl = cttl;
+
+ addr.rrdata.datalen = substring;
+ addr.rrdata.rrtype = qtype;
+
+ if (!have_soa)
+ flags |= F_NO_RR; /* Marks no SOA found. */
+ }
newc = cache_insert(name, &addr, C_IN, now, ttl, F_FORWARD | F_NEG | flags | (secure ? F_DNSSECOK : 0));
if (newc && cpp)
stale_flag = F_STALE;
}
+ if (crecp->flags & F_NEG)
+ soa_lookup = crecp;
+
if (crecp->flags & F_NXDOMAIN)
{
if (qtype == T_CNAME)
if (crecp->flags & F_NXDOMAIN)
nxdomain = 1;
log_query(stale_flag | (crecp->flags & ~F_FORWARD), name, &addr, NULL, 0);
+ soa_lookup = crecp;
}
else
{
if (!ans)
return 0; /* failed to answer a question */
- if (soa_lookup)
+ /* We found a negative record. See if we have an SOA record to
+ return in the AUTH section.
+
+ For FORWARD NEG records, the addr.rrdata.datalen field of the othewise
+ empty addr is used to held an offset in to the name which yields the SOA
+ name. For REVERSE NEG records, the otherwise empty name field holds the
+ SOA name. If soa_name has zero length, then no SOA is known. soa_lookup
+ MUST be a neg record here.
+
+ If the F_NO_RR flag is set, there was no SOA record supplied with the RR. */
+ if (soa_lookup && !(soa_lookup->flags & F_NO_RR))
{
- /* We found a negative record. See if we have an SOA record to
- return in the AUTH section. */
- char *rrdata;
- int substring = soa_lookup->addr.rrdata.datalen;
+ char *soa_name = soa_lookup->flags & F_REVERSE ? cache_get_name(soa_lookup) : name + soa_lookup->addr.rrdata.datalen;
+
crecp = NULL;
- while ((crecp = cache_find_by_name(crecp, name + substring, now, F_RR)))
+ while ((crecp = cache_find_by_name(crecp, soa_name, now, F_RR)))
if (crecp->addr.rrblock.rrtype == T_SOA)
{
+ char *rrdata;
+
if (!(crecp->flags & F_NEG) &&
(rrdata = blockdata_retrieve(crecp->addr.rrblock.rrdata, crecp->addr.rrblock.datalen, NULL)) &&
add_resource_record(header, limit, &trunc, 0, &ansp,
crec_ttl(crecp, now), NULL, T_SOA, C_IN, "t",
- name + substring, crecp->addr.rrblock.datalen, rrdata))
+ soa_name, crecp->addr.rrblock.datalen, rrdata))
{
nscount++;