Bug in ex-rdns.c?

Michael Tokarev mjt at tls.msk.ru
Tue Feb 15 11:06:54 MSK 2011


[Cc'ng to udns mailing list, I hope you don't mind]

15.02.2011 10:41, Joseph Tam wrote:
> 
> Hi Michael,
> 
> Thanks for writing your udns library.  I am modifying the example
> ex-rdns.c modifying it slightly to make the output closer to djbdns
> dnsfilter since I have other tools that assume dnsfilter style output.
> 
> I am puzzled, though, by how you use the variable 'c' in ex-rdns.c.
> It appears to be an index to the number of arguments to this program,
> but then, it's then used as a timeout parameter to poll():
> 
>     ...
>     now = time(NULL);
>     c = optind;
>     eof = 0;
> 
>     ...
> 
>     t = dns_timeouts(0, -1, now);
>     t = poll(&pfd, 1, c * 1000);
>     now = time(NULL);
>     ...
> 
> Do you really intend to vary the poll() timeout proportional to the
> number of arguments to ex-rdns?  If this is not what you intend, what
> should I set 'c' to?  For now, I used a poll timeout of 2000ms.

Yes this is a bug, spotted by Iñaki Baz Castillo and fixed just
a few days ago.  Originally the code was a bit different, and
somehow I managed to screw up a usage example.  This is the
patch that I comitted:

--- ex-rdns.c	7 Jan 2007 22:46:47 -0000	1.8
+++ ex-rdns.c	7 Feb 2011 09:39:07 -0000	1.9
@@ -56,7 +56,7 @@ static void dnscb(struct dns_ctx *ctx, s
 }

 int main(int argc, char **argv) {
-  int c, t;
+  int c;
   time_t now;
   int maxq = 10;
   struct pollfd pfd;
@@ -103,10 +103,11 @@ int main(int argc, char **argv) {
       continue;
     }
     if (curq) {
-      t = dns_timeouts(0, -1, now);
-      t = poll(&pfd, 1, c * 1000);
+      c = dns_timeouts(0, -1, now);
+      c = poll(&pfd, 1, c < 0 ? -1 : c * 1000);
       now = time(NULL);
-      if (t) dns_ioevent(0, now);
+      if (c)
+        dns_ioevent(0, now);
     }
   }
   return 0;

> Also, can you give a clue how I could write a version that would spread
> queries over many DNS servers?  By "spread", I mean that each item
> to be resolved is sent to one (and only) one of several DNS servers,
> not the same query to many different servers (which is what I assume
> dns_add_serv() does).  The idea to is scale up the resolving rate by
> using more than one DNS server.

Currently there's no code like that exists, but yes, either separate
context or separate executable (which also means separate context)
will do.  It really depends on the task you're doing, see below.

> Would I have to create one context for each nameserver?  Maybe it's
> just easier to split the input stream and run ex-rdns on each stream
> with different $NSCACHEIP?  (The man page udns.3 refers to "DNSCACHEIP"
> but that ought to be changed to NSCACHEIP).

Oh, yet another documentation bug, thank you for spotting this!

Speaking of the queries balancing.  I didn't think of this till
now, usually one nameserver works quite well even for large load.
I'm not really sure it will help much to spread load to multiple
servers.  If you do observe that the resolvers can't cope with
the load, maybe you should take a look at improving them instead? :)
Seriously, -- take a look at unbound for example (http://unbound.net/).
If you perform large amount of queries, you may want to use dedicated
nameserver for the task (to not disturb others and don't be disturbed).
Modern nameservers scales quite well, utilizing multiple cores and
threads, using advanced techniques for network access and so on.
Besides, you usually want some info to be cached (like at least
nameserver information for all domains you're querying), and there,
using multiple nameservers does not really help.

I can imagine a situation where you really want lots of queries to
be performed.  But I'm not sure that using multiple servers is the
way to go in this case.

However it is sorta trivial to verify: split your input into
several pieces and run several independent clients (like
ex-rdns or whatever you're using), and compare results
(you'll have to flush your nameserver caches before each
run in order to have the same starting conditions for
both tests).

Two cautions however.   First, think if you really need to
hammer nameservers on the 'net like this.  Yes you are
spreading the load to all different auth nameservers out
there, but at the same time you place quite some load to
2nd-level nameservers (for TLDs like ca, ru, com, net etc).

And second, imagine one of your nameservers failed somehow
and stopped responding.  If you have more than one of them,
udns will query others too (whole thing will be just a bit
slower), but in your case (using just _one_ nameserver) it
will fail.  So in this case, consider using two each time,
but list them in different order - second one will be queried
much less often if first is quick enough.

It isn't terrible difficult to modify the code to perform
a sort of load balancing betweeen available nameservers.
And it may be a useful feature for other applications too.
I will think about this.

> Thanks for any information you can provide.

And thank you for spotting the bug!

/mjt


More information about the udns mailing list