Hi. Your diff looks correct. I can't see a reason for the "ar_datalen == -1" special case here.
According to my tests, gethostbyname() with a bogus nameserver (not responding, not reachable, ...) now fails with TRY_AGAIN, but still fails with HOST_NOT_FOUND if "bind" is not set on the lookup directive, which feels consistent. I have to review the resolver logic to see if a fix is needed at deeper level. But still, this diff makes sense on its own, so ok eric@. Eric. On Wed, Jun 26, 2019 at 11:57:10AM +0200, Martijn van Duren wrote: > Found this yesterday while playing with a dnsbl filter for smtpd during > network outage and found that gethostbyname returns HOST_NOT_FOUND. > Glibc, musl, and FreeBSD return TRY_AGAIN. > > This is annoying because for a DNSBL I need to be able to differentiate > between a resolver not being available and an entry not existing in the > upstream database. > > The reason is that in gethostnamadr_async.c for case ASR_STATE_NOT_FOUND > the ar_h_errno is set to HOST_NOT_FOUND if we don't have a subq_h_errno. > > Looking at case ASR_STATE_SUBQUERY we don't copy subq_h_errno from > ar->ar_h_errno, while res_send_async.c (which is used by gethostnamaddr > as a backend) always sets ar_h_errno and ar_count in case > ASR_STATE_HALT. > > I've looked at the code but I can't find any reason why not getting a > reply gets this special treatment. > > Assuming I haven't missed anything the diff below uses the fact that > no packet also has ar_count set to 0 (res_send_async.c:268) and always > copy the ar_h_errno from the subquery. > > This both reduces the LoC and fixes the issue for me. > > OK? > > martijn@ > > Index: gethostnamadr_async.c > =================================================================== > RCS file: /cvs/src/lib/libc/asr/gethostnamadr_async.c,v > retrieving revision 1.44 > diff -u -p -r1.44 gethostnamadr_async.c > --- gethostnamadr_async.c 28 Apr 2018 15:16:49 -0000 1.44 > +++ gethostnamadr_async.c 26 Jun 2019 09:55:02 -0000 > @@ -289,12 +289,10 @@ gethostnamadr_async_run(struct asr_query > /* Done. */ > as->as_subq = NULL; > > - if (ar->ar_datalen == -1) { > - async_set_state(as, ASR_STATE_NEXT_DB); > - break; > - } > - > - /* If we got a packet but no anwser, use the next DB. */ > + /* > + * We either got no packet or a packet without an answer. > + * Saveguard the h_errno and use the next DB. > + */ > if (ar->ar_count == 0) { > free(ar->ar_data); > as->as.hostnamadr.subq_h_errno = ar->ar_h_errno; > >