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

Reply via email to