On 16/06/2022 05:46, John Gilmour via Dnsmasq-discuss wrote:
Hello,
So, further to my email I have added the following lines to my version
of dnsmasq:
src/cache.c/cache_reload:
/* Make non-terminal records for all locally-define RRs */
+ memset (&lrec, 0, sizeof (lrec));
lrec.flags = F_FORWARD | F_CONFIG | F_NAMEP | F_IMMORTAL;
src/cache.c/make_non_terminals:
if (crecp) {
+ memcpy(crecp, source, sizeof (source));
crecp->flags = (source->flags | F_NAMEP) & ~(F_IPV4 | F_IPV6
| F_CNAME | F_SRV | F_DNSKEY | F_DS | F_REVERSE);
- crecp->ttd = source->ttd;
crecp->name.namep = name;
Also, there seems to me to be a bug in make_non_terminals. As best as I
can tell, there is a "daemon->txt" structure that contains a number of
entries. These are added to the daemon in "src/option.c/read_opts":
#ifndef NO_ID
add_txt("version.bind", "dnsmasq-" VERSION, 0 );
add_txt("authors.bind", "Simon Kelley", 0);
.........
The call to cache_reload calls make_non_terminals:
for (txt = daemon->txt; txt; txt = txt->next)
{
lrec.name.namep = txt->name;
make_non_terminals(&lrec);
}
I believe that there should be 1 entry in the cache for each of the
read_opts. But there is not. There is only one entry with the name
"bind".
The comment for make_non_terminals says:
Creates empty cache entries for subnames (ie, for three.two.one,
for two.one and one)
What is happening is that the function splits the string up by the
delimiter ".". It does this by using:
while ((name = strchr (name, '.')))
name++;
So, when it gets to the following code the name equals "bind" and this
is all it adds to the cache. Subsequent attempts to add new read_opts
boil down to "bind" so after the reload the entire cache consists of
only one "bind" entry.
crecp->flags = (source->flags | F_NAMEP) & ~(F_IPV4 | F_IPV6 |
F_CNAME | F_SRV | F_DNSKEY | F_DS | F_REVERSE);
crecp->ttd = source->ttd;
crecp->name.namep = name;
cache_hash(crecp);
I am not sure what is supposed to be added to the cache - the full name,
each delimited name, just the last name. If you could advise me on this
function I would be eternally grateful.
Non-terminals are best described by example.
Consider a DNS name "example.com" which has no resource records
associated with it. A query for that name of any type would return a "no
such domain" reply. Now consider the case again that there are no
resource records associated with "example.com", but there is a resource
record (of any type) associated with "www.example.com" querying
www.example.com will return that resource record. In this case, querying
"example.com" MUST NOT return NDDOMAIN. a query of any type should
return a NODATA reply instead.
In other words, a domain name can exist either because there's at least
one resource record at that name, OR because there's at least one
subdomain of that name, (or both).
In the case you're looking at, a load of names of the form
"version.bind" and "author.bind" get added to the cache. The purpose of
make-non-terminals is simply to add a special cache record named "bind"
which ensures that answers to queries for "bind" return NODATA replies
and not NXDOMAIN replies, even though there are no resource records for
"bind".
These particular records are of type TXT. TXT records are not held in
the cache, they are answered directly from the daemon->txt datstructure,
which is why you don't see a cache entry for them. See src/rfc1035.c
around line 1507 for the code that does this. That's why you only see
the "bind" cache entry required to convert the answer to a query for
"bind" from NXDOMAIN to NODATA.
Simon.
_______________________________________________
Dnsmasq-discuss mailing list
Dnsmasq-discuss@lists.thekelleys.org.uk
https://lists.thekelleys.org.uk/cgi-bin/mailman/listinfo/dnsmasq-discuss