dns_ioevent() not called when DNS server is not recursive

Michael Tokarev mjt at tls.msk.ru
Fri Feb 4 11:47:54 MSK 2011


04.02.2011 04:08, Iñaki Baz Castillo wrote:
> Hi, I'm testing udns in async mode with poll(). I know that udns is a
> stub resolver, so I'm not reporting a bug, but just want to be
> clarified.
> 
> In my test I set a non recursive DNS server in /etc/resolv.conf, then
> I do an async DNS query. poll() returns true so something has arrived
> via UDP, but dns_ioevent() doesnt' call the callback routine. In fact,
> if I test the same using "getdns" I get an error "temporary failure in
> name resolution".

It's dnsget, not getdns.  Dnsget has verbose mode (-vv) that will show
you actual (decoded) requests and replies.

> So I assume that, indeed, an UDP DNS response has been replied by the
> server, but it contains a DNS error (maybe it says that the server is
> non recursive so cannot perform the query as the client has
> requested). Then when I call dns_ioevent() the callback is not
> executed.
> 
> But after dns_ioevent() I check dns_status() and it returns 0, so no
> error. I don't understand why. Is it the expected behaviour? if so,
> how can I realize of the error?

"REFUSED" is not a valid return code for a recursive resolver listed
in /etc/resolv.conf.  That to say: if the server listed there returns
"REFUSED" we're screwed, we can't resolve any query.  What to do in
this very case is not clear.  udns tries to pretend it didn't receive
that "REFUSED" reply and will retry after a timeout, in a hope the
next time the query will be answered.

> Basically this is the important part of my testing code:
> 
> -------------------------------------------
>   dns_submit_srv(NULL, domain, service, protocol, 0, dns_cb, NULL)
> 
>   now = time(NULL);
> 
>   while (! NULL) {
>     t = dns_timeouts(0, -1, now);
>     t = poll(&pfd, 1, 100);

this is not optimal.  dns_timeouts() returned number of seconds
before next timer will expire (or -1 if no timers are pending).
So you really want to use this information when calling poll(),
like this:

      t = poll(&pfd, 1, t < 0 ? -1 : t * 1000);

(the value returned by dns_timeouts() is in seconds, poll()
expects the timeout to be in milliseconds, hence the multiplier).

>     now = time(NULL);
>     if (t) {
>       dns_ioevent(NULL, now);
>       printf("--- dns_status = %i\n", dns_status(NULL));
>       break;
>     }
>   }
> ------------------------------------------

And there's an error too.  dns_status() is valid only when some
query is complete - that's either inside the callback routine
or - in case of syncronous interface like dns_resolve() - right
after it returned.  I re-read the manpage - indeed, the description
of this function isn't entirely correct, it tells "return status
code from last operation" - I mean to say "last completed query"
not "last operation".

But it all boils down to one thing, I think.  You misunderstand
the interface a bit.

DNS isn't like this: submit (send) query, wait for the reply, and
you'll get answer.  No.  Instead, it's a try and retry and retry
sort of thing - that is, even when you know you received "something"
it may be something else, not a reply you're waiting.  The same
applies to timeouts too.

udns will complete the query when it is ready, not when there's
"something" received by the UDP socket.

Also think about multiple pending queries - even if your recursive
resolver replies to every query and does that promptly, there's
nothing to guarantee that replies will come at the same order
as you submitted your queries.  The resolver is asyncronous, and
first queries may require a bit more time than others.

> Also I would like to confirm other point, now using a recursive DNS server:
> 
> If I query for a non existing domain, the callback routine is
> executed, but rr argument is passed as NULL (and of course
> dns_status() returns -3 = DNS_R_NXDOMAIN).
> 
> So why in this case (the domain doesn't exist) the callback routine is
> executed will null rr? why in the first case the routine is not called
> neither dns_status() returns an error?.

Um, that's the same thing: receiving "something" isn't an indicator
that the query is completed.  You should wait a bit longer - wait
till udns actually executes the callback.

/mjt


More information about the udns mailing list