"Fossies" - the Fresh Open Source Software Archive

Member "udns-0.4/udns_resolver.c" (23 Jan 2014, 42029 Bytes) of package /linux/misc/dns/udns-0.4.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "udns_resolver.c" see the Fossies "Dox" file reference documentation.

    1 /* udns_resolver.c
    2    resolver stuff (main module)
    3 
    4    Copyright (C) 2005  Michael Tokarev <mjt@corpit.ru>
    5    This file is part of UDNS library, an async DNS stub resolver.
    6 
    7    This library is free software; you can redistribute it and/or
    8    modify it under the terms of the GNU Lesser General Public
    9    License as published by the Free Software Foundation; either
   10    version 2.1 of the License, or (at your option) any later version.
   11 
   12    This library is distributed in the hope that it will be useful,
   13    but WITHOUT ANY WARRANTY; without even the implied warranty of
   14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   15    Lesser General Public License for more details.
   16 
   17    You should have received a copy of the GNU Lesser General Public
   18    License along with this library, in file named COPYING.LGPL; if not,
   19    write to the Free Software Foundation, Inc., 59 Temple Place,
   20    Suite 330, Boston, MA  02111-1307  USA
   21 
   22  */
   23 
   24 #ifdef HAVE_CONFIG_H
   25 # include "config.h"
   26 #endif
   27 #ifdef WINDOWS
   28 # include <winsock2.h>          /* includes <windows.h> */
   29 # include <ws2tcpip.h>          /* needed for struct in6_addr */
   30 #else
   31 # include <sys/types.h>
   32 # include <sys/socket.h>
   33 # include <netinet/in.h>
   34 # include <unistd.h>
   35 # include <fcntl.h>
   36 # include <sys/time.h>
   37 # ifdef HAVE_POLL
   38 #  include <sys/poll.h>
   39 # else
   40 #  ifdef HAVE_SYS_SELECT_H
   41 #   include <sys/select.h>
   42 #  endif
   43 # endif
   44 # ifdef HAVE_TIMES
   45 #  include <sys/times.h>
   46 # endif
   47 # define closesocket(sock) close(sock)
   48 #endif  /* !WINDOWS */
   49 
   50 #include <stdlib.h>
   51 #include <string.h>
   52 #include <time.h>
   53 #include <errno.h>
   54 #include <assert.h>
   55 #include <stddef.h>
   56 #include "udns.h"
   57 
   58 #ifndef EAFNOSUPPORT
   59 # define EAFNOSUPPORT EINVAL
   60 #endif
   61 #ifndef MSG_DONTWAIT
   62 # define MSG_DONTWAIT 0
   63 #endif
   64 
   65 struct dns_qlist {
   66   struct dns_query *head, *tail;
   67 };
   68 
   69 struct dns_query {
   70   struct dns_query *dnsq_next;          /* double-linked list */
   71   struct dns_query *dnsq_prev;
   72   unsigned dnsq_origdnl0;       /* original query DN len w/o last 0 */
   73   unsigned dnsq_flags;          /* control flags for this query */
   74   unsigned dnsq_servi;          /* index of next server to try */
   75   unsigned dnsq_servwait;       /* bitmask: servers left to wait */
   76   unsigned dnsq_servskip;       /* bitmask: servers to skip */
   77   unsigned dnsq_servnEDNS0;     /* bitmask: servers refusing EDNS0 */
   78   unsigned dnsq_try;            /* number of tries made so far */
   79   dnscc_t *dnsq_nxtsrch;        /* next search pointer @dnsc_srchbuf */
   80   time_t dnsq_deadline;         /* when current try will expire */
   81   dns_parse_fn *dnsq_parse;     /* parse: raw => application */
   82   dns_query_fn *dnsq_cbck;      /* the callback to call when done */
   83   void *dnsq_cbdata;            /* user data for the callback */
   84 #ifndef NDEBUG
   85   struct dns_ctx *dnsq_ctx;     /* the resolver context */
   86 #endif
   87   /* char fields at the end to avoid padding */
   88   dnsc_t dnsq_id[2];            /* query ID */
   89   dnsc_t dnsq_typcls[4];        /* requested RR type+class */
   90   dnsc_t dnsq_dn[DNS_MAXDN+DNS_DNPAD];  /* the query DN +alignment */
   91 };
   92 
   93 /* working with dns_query lists */
   94 
   95 static __inline void qlist_init(struct dns_qlist *list) {
   96   list->head = list->tail = NULL;
   97 }
   98 
   99 static __inline void qlist_remove(struct dns_qlist *list, struct dns_query *q) {
  100    if (q->dnsq_prev) q->dnsq_prev->dnsq_next = q->dnsq_next;
  101    else list->head = q->dnsq_next;
  102    if (q->dnsq_next) q->dnsq_next->dnsq_prev = q->dnsq_prev;
  103    else list->tail = q->dnsq_prev;
  104 }
  105 
  106 static __inline void
  107 qlist_add_head(struct dns_qlist *list, struct dns_query *q) {
  108   q->dnsq_next = list->head;
  109   if (list->head) list->head->dnsq_prev = q;
  110   else list->tail = q;
  111   list->head = q;
  112   q->dnsq_prev = NULL;
  113 }
  114 
  115 static __inline void
  116 qlist_insert_after(struct dns_qlist *list,
  117                    struct dns_query *q, struct dns_query *prev) {
  118   if ((q->dnsq_prev = prev) != NULL) {
  119     if ((q->dnsq_next = prev->dnsq_next) != NULL)
  120       q->dnsq_next->dnsq_prev = q;
  121     else
  122       list->tail = q;
  123     prev->dnsq_next = q;
  124   }
  125   else
  126     qlist_add_head(list, q);
  127 }
  128 
  129 union sockaddr_ns {
  130   struct sockaddr sa;
  131   struct sockaddr_in sin;
  132 #ifdef HAVE_IPv6
  133   struct sockaddr_in6 sin6;
  134 #endif
  135 };
  136 
  137 #define sin_eq(a,b) \
  138     ((a).sin_port == (b).sin_port && \
  139      (a).sin_addr.s_addr == (b).sin_addr.s_addr)
  140 #define sin6_eq(a,b) \
  141     ((a).sin6_port == (b).sin6_port && \
  142      memcmp(&(a).sin6_addr, &(b).sin6_addr, sizeof(struct in6_addr)) == 0)
  143 
  144 struct dns_ctx {        /* resolver context */
  145   /* settings */
  146   unsigned dnsc_flags;          /* various flags */
  147   unsigned dnsc_timeout;        /* timeout (base value) for queries */
  148   unsigned dnsc_ntries;         /* number of retries */
  149   unsigned dnsc_ndots;          /* ndots to assume absolute name */
  150   unsigned dnsc_port;           /* default port (DNS_PORT) */
  151   unsigned dnsc_udpbuf;         /* size of UDP buffer */
  152   /* array of nameserver addresses */
  153   union sockaddr_ns dnsc_serv[DNS_MAXSERV];
  154   unsigned dnsc_nserv;          /* number of nameservers */
  155   unsigned dnsc_salen;          /* length of socket addresses */
  156   dnsc_t dnsc_srchbuf[1024];        /* buffer for searchlist */
  157   dnsc_t *dnsc_srchend;         /* current end of srchbuf */
  158 
  159   dns_utm_fn *dnsc_utmfn;       /* register/cancel timer events */
  160   void *dnsc_utmctx;            /* user timer context for utmfn() */
  161   time_t dnsc_utmexp;           /* when user timer expires */
  162 
  163   dns_dbgfn *dnsc_udbgfn;       /* debugging function */
  164 
  165   /* dynamic data */
  166   struct udns_jranctx dnsc_jran;    /* random number generator state */
  167   unsigned dnsc_nextid;         /* next queue ID to use if !0 */
  168   int dnsc_udpsock;         /* UDP socket */
  169   struct dns_qlist dnsc_qactive;    /* active list sorted by deadline */
  170   int dnsc_nactive;         /* number entries in dnsc_qactive */
  171   dnsc_t *dnsc_pbuf;            /* packet buffer (udpbuf size) */
  172   int dnsc_qstatus;         /* last query status value */
  173 };
  174 
  175 static const struct {
  176   const char *name;
  177   enum dns_opt opt;
  178   unsigned offset;
  179   unsigned min, max;
  180 } dns_opts[] = {
  181 #define opt(name,opt,field,min,max) \
  182     {name,opt,offsetof(struct dns_ctx,field),min,max}
  183   opt("retrans", DNS_OPT_TIMEOUT, dnsc_timeout, 1,300),
  184   opt("timeout", DNS_OPT_TIMEOUT, dnsc_timeout, 1,300),
  185   opt("retry",    DNS_OPT_NTRIES, dnsc_ntries, 1,50),
  186   opt("attempts", DNS_OPT_NTRIES, dnsc_ntries, 1,50),
  187   opt("ndots", DNS_OPT_NDOTS, dnsc_ndots, 0,1000),
  188   opt("port", DNS_OPT_PORT, dnsc_port, 1,0xffff),
  189   opt("udpbuf", DNS_OPT_UDPSIZE, dnsc_udpbuf, DNS_MAXPACKET,65536),
  190 #undef opt
  191 };
  192 #define dns_ctxopt(ctx,idx) (*((unsigned*)(((char*)ctx)+dns_opts[idx].offset)))
  193 
  194 #define ISSPACE(x) (x == ' ' || x == '\t' || x == '\r' || x == '\n')
  195 
  196 struct dns_ctx dns_defctx;
  197 
  198 #define SETCTX(ctx) if (!ctx) ctx = &dns_defctx
  199 #define SETCTXINITED(ctx) SETCTX(ctx); assert(CTXINITED(ctx))
  200 #define CTXINITED(ctx) (ctx->dnsc_flags & DNS_INITED)
  201 #define SETCTXFRESH(ctx) SETCTXINITED(ctx); assert(!CTXOPEN(ctx))
  202 #define SETCTXINACTIVE(ctx) \
  203         SETCTXINITED(ctx); assert(!ctx->dnsc_nactive)
  204 #define SETCTXOPEN(ctx) SETCTXINITED(ctx); assert(CTXOPEN(ctx))
  205 #define CTXOPEN(ctx) (ctx->dnsc_udpsock >= 0)
  206 
  207 #if defined(NDEBUG) || !defined(DEBUG)
  208 #define dns_assert_ctx(ctx)
  209 #else
  210 static void dns_assert_ctx(const struct dns_ctx *ctx) {
  211   int nactive = 0;
  212   const struct dns_query *q;
  213   for(q = ctx->dnsc_qactive.head; q; q = q->dnsq_next) {
  214     assert(q->dnsq_ctx == ctx);
  215     assert(q == (q->dnsq_next ?
  216                  q->dnsq_next->dnsq_prev : ctx->dnsc_qactive.tail));
  217     assert(q == (q->dnsq_prev ?
  218                  q->dnsq_prev->dnsq_next : ctx->dnsc_qactive.head));
  219     ++nactive;
  220   }
  221   assert(nactive == ctx->dnsc_nactive);
  222 }
  223 #endif
  224 
  225 enum {
  226   DNS_INTERNAL      = 0xffff, /* internal flags mask */
  227   DNS_INITED        = 0x0001, /* the context is initialized */
  228   DNS_ASIS_DONE     = 0x0002, /* search: skip the last as-is query */
  229   DNS_SEEN_NODATA   = 0x0004, /* search: NODATA has been received */
  230 };
  231 
  232 int dns_add_serv(struct dns_ctx *ctx, const char *serv) {
  233   union sockaddr_ns *sns;
  234   SETCTXFRESH(ctx);
  235   if (!serv)
  236     return (ctx->dnsc_nserv = 0);
  237   if (ctx->dnsc_nserv >= DNS_MAXSERV)
  238     return errno = ENFILE, -1;
  239   sns = &ctx->dnsc_serv[ctx->dnsc_nserv];
  240   memset(sns, 0, sizeof(*sns));
  241   if (dns_pton(AF_INET, serv, &sns->sin.sin_addr) > 0) {
  242     sns->sin.sin_family = AF_INET;
  243     return ++ctx->dnsc_nserv;
  244   }
  245 #ifdef HAVE_IPv6
  246   if (dns_pton(AF_INET6, serv, &sns->sin6.sin6_addr) > 0) {
  247     sns->sin6.sin6_family = AF_INET6;
  248     return ++ctx->dnsc_nserv;
  249   }
  250 #endif
  251   errno = EINVAL;
  252   return -1;
  253 }
  254 
  255 int dns_add_serv_s(struct dns_ctx *ctx, const struct sockaddr *sa) {
  256   SETCTXFRESH(ctx);
  257   if (!sa)
  258     return (ctx->dnsc_nserv = 0);
  259   if (ctx->dnsc_nserv >= DNS_MAXSERV)
  260     return errno = ENFILE, -1;
  261 #ifdef HAVE_IPv6
  262   else if (sa->sa_family == AF_INET6)
  263     ctx->dnsc_serv[ctx->dnsc_nserv].sin6 = *(struct sockaddr_in6*)sa;
  264 #endif
  265   else if (sa->sa_family == AF_INET)
  266     ctx->dnsc_serv[ctx->dnsc_nserv].sin = *(struct sockaddr_in*)sa;
  267   else
  268     return errno = EAFNOSUPPORT, -1;
  269   return ++ctx->dnsc_nserv;
  270 }
  271 
  272 int dns_set_opts(struct dns_ctx *ctx, const char *opts) {
  273   unsigned i, v;
  274   int err = 0;
  275   SETCTXINACTIVE(ctx);
  276   for(;;) {
  277     while(ISSPACE(*opts)) ++opts;
  278     if (!*opts) break;
  279     for(i = 0; ; ++i) {
  280       if (i >= sizeof(dns_opts)/sizeof(dns_opts[0])) { ++err; break; }
  281       v = strlen(dns_opts[i].name);
  282       if (strncmp(dns_opts[i].name, opts, v) != 0 ||
  283           (opts[v] != ':' && opts[v] != '='))
  284         continue;
  285       opts += v + 1;
  286       v = 0;
  287       if (*opts < '0' || *opts > '9') { ++err; break; }
  288       do v = v * 10 + (*opts++ - '0');
  289       while (*opts >= '0' && *opts <= '9');
  290       if (v < dns_opts[i].min) v = dns_opts[i].min;
  291       if (v > dns_opts[i].max) v = dns_opts[i].max;
  292       dns_ctxopt(ctx, i) = v;
  293       break;
  294     }
  295     while(*opts && !ISSPACE(*opts)) ++opts;
  296   }
  297   return err;
  298 }
  299 
  300 int dns_set_opt(struct dns_ctx *ctx, enum dns_opt opt, int val) {
  301   int prev;
  302   unsigned i;
  303   SETCTXINACTIVE(ctx);
  304   for(i = 0; i < sizeof(dns_opts)/sizeof(dns_opts[0]); ++i) {
  305     if (dns_opts[i].opt != opt) continue;
  306     prev = dns_ctxopt(ctx, i);
  307     if (val >= 0) {
  308       unsigned v = val;
  309       if (v < dns_opts[i].min || v > dns_opts[i].max) {
  310         errno = EINVAL;
  311         return -1;
  312       }
  313       dns_ctxopt(ctx, i) = v;
  314     }
  315     return prev;
  316   }
  317   if (opt == DNS_OPT_FLAGS) {
  318     prev = ctx->dnsc_flags & ~DNS_INTERNAL;
  319     if (val >= 0)
  320       ctx->dnsc_flags =
  321         (ctx->dnsc_flags & DNS_INTERNAL) | (val & ~DNS_INTERNAL);
  322     return prev;
  323   }
  324   errno = ENOSYS;
  325   return -1;
  326 }
  327 
  328 int dns_add_srch(struct dns_ctx *ctx, const char *srch) {
  329   int dnl;
  330   SETCTXINACTIVE(ctx);
  331   if (!srch) {
  332     memset(ctx->dnsc_srchbuf, 0, sizeof(ctx->dnsc_srchbuf));
  333     ctx->dnsc_srchend = ctx->dnsc_srchbuf;
  334     return 0;
  335   }
  336   dnl =
  337     sizeof(ctx->dnsc_srchbuf) - (ctx->dnsc_srchend - ctx->dnsc_srchbuf) - 1;
  338   dnl = dns_sptodn(srch, ctx->dnsc_srchend, dnl);
  339   if (dnl > 0)
  340     ctx->dnsc_srchend += dnl;
  341   ctx->dnsc_srchend[0] = '\0';  /* we ensure the list is always ends at . */
  342   if (dnl > 0)
  343     return 0;
  344   errno = EINVAL;
  345   return -1;
  346 }
  347 
  348 static void dns_drop_utm(struct dns_ctx *ctx) {
  349   if (ctx->dnsc_utmfn)
  350     ctx->dnsc_utmfn(NULL, -1, ctx->dnsc_utmctx);
  351   ctx->dnsc_utmctx = NULL;
  352   ctx->dnsc_utmexp = -1;
  353 }
  354 
  355 static void
  356 _dns_request_utm(struct dns_ctx *ctx, time_t now) {
  357   struct dns_query *q;
  358   time_t deadline;
  359   int timeout;
  360   q = ctx->dnsc_qactive.head;
  361   if (!q)
  362     deadline = -1, timeout = -1;
  363   else if (!now || q->dnsq_deadline <= now)
  364     deadline = 0, timeout = 0;
  365   else
  366     deadline = q->dnsq_deadline, timeout = (int)(deadline - now);
  367   if (ctx->dnsc_utmexp == deadline)
  368     return;
  369   ctx->dnsc_utmfn(ctx, timeout, ctx->dnsc_utmctx);
  370   ctx->dnsc_utmexp = deadline;
  371 }
  372 
  373 static __inline void
  374 dns_request_utm(struct dns_ctx *ctx, time_t now) {
  375   if (ctx->dnsc_utmfn)
  376     _dns_request_utm(ctx, now);
  377 }
  378 
  379 void dns_set_dbgfn(struct dns_ctx *ctx, dns_dbgfn *dbgfn) {
  380   SETCTXINITED(ctx);
  381   ctx->dnsc_udbgfn = dbgfn;
  382 }
  383 
  384 void
  385 dns_set_tmcbck(struct dns_ctx *ctx, dns_utm_fn *fn, void *data) {
  386   SETCTXINITED(ctx);
  387   dns_drop_utm(ctx);
  388   ctx->dnsc_utmfn = fn;
  389   ctx->dnsc_utmctx = data;
  390   if (CTXOPEN(ctx))
  391     dns_request_utm(ctx, 0);
  392 }
  393 
  394 static unsigned dns_nonrandom_32(void) {
  395 #ifdef WINDOWS
  396   FILETIME ft;
  397   GetSystemTimeAsFileTime(&ft);
  398   return ft.dwLowDateTime;
  399 #else
  400   struct timeval tv;
  401   gettimeofday(&tv, NULL);
  402   return tv.tv_usec;
  403 #endif
  404 }
  405 
  406 /* This is historic deprecated API */
  407 UDNS_API unsigned dns_random16(void);
  408 unsigned dns_random16(void) {
  409   unsigned x = dns_nonrandom_32();
  410   return (x ^ (x >> 16)) & 0xffff;
  411 }
  412 
  413 static void dns_init_rng(struct dns_ctx *ctx) {
  414   udns_jraninit(&ctx->dnsc_jran, dns_nonrandom_32());
  415   ctx->dnsc_nextid = 0;
  416 }
  417 
  418 void dns_close(struct dns_ctx *ctx) {
  419   struct dns_query *q, *p;
  420   SETCTX(ctx);
  421   if (CTXINITED(ctx)) {
  422     if (ctx->dnsc_udpsock >= 0)
  423       closesocket(ctx->dnsc_udpsock);
  424     ctx->dnsc_udpsock = -1;
  425     if (ctx->dnsc_pbuf)
  426       free(ctx->dnsc_pbuf);
  427     ctx->dnsc_pbuf = NULL;
  428     q = ctx->dnsc_qactive.head;
  429     while((p = q) != NULL) {
  430       q = q->dnsq_next;
  431       free(p);
  432     }
  433     qlist_init(&ctx->dnsc_qactive);
  434     ctx->dnsc_nactive = 0;
  435     dns_drop_utm(ctx);
  436   }
  437 }
  438 
  439 void dns_reset(struct dns_ctx *ctx) {
  440   SETCTX(ctx);
  441   dns_close(ctx);
  442   memset(ctx, 0, sizeof(*ctx));
  443   ctx->dnsc_timeout = 4;
  444   ctx->dnsc_ntries = 3;
  445   ctx->dnsc_ndots = 1;
  446   ctx->dnsc_udpbuf = DNS_EDNS0PACKET;
  447   ctx->dnsc_port = DNS_PORT;
  448   ctx->dnsc_udpsock = -1;
  449   ctx->dnsc_srchend = ctx->dnsc_srchbuf;
  450   qlist_init(&ctx->dnsc_qactive);
  451   dns_init_rng(ctx);
  452   ctx->dnsc_flags = DNS_INITED;
  453 }
  454 
  455 struct dns_ctx *dns_new(const struct dns_ctx *copy) {
  456   struct dns_ctx *ctx;
  457   SETCTXINITED(copy);
  458   dns_assert_ctx(copy);
  459   ctx = malloc(sizeof(*ctx));
  460   if (!ctx)
  461     return NULL;
  462   *ctx = *copy;
  463   ctx->dnsc_udpsock = -1;
  464   qlist_init(&ctx->dnsc_qactive);
  465   ctx->dnsc_nactive = 0;
  466   ctx->dnsc_pbuf = NULL;
  467   ctx->dnsc_qstatus = 0;
  468   ctx->dnsc_srchend = ctx->dnsc_srchbuf +
  469     (copy->dnsc_srchend - copy->dnsc_srchbuf);
  470   ctx->dnsc_utmfn = NULL;
  471   ctx->dnsc_utmctx = NULL;
  472   dns_init_rng(ctx);
  473   return ctx;
  474 }
  475 
  476 void dns_free(struct dns_ctx *ctx) {
  477   assert(ctx != NULL && ctx != &dns_defctx);
  478   dns_reset(ctx);
  479   free(ctx);
  480 }
  481 
  482 int dns_open(struct dns_ctx *ctx) {
  483   int sock;
  484   unsigned i;
  485   int port;
  486   union sockaddr_ns *sns;
  487 #ifdef HAVE_IPv6
  488   unsigned have_inet6 = 0;
  489 #endif
  490 
  491   SETCTXINITED(ctx);
  492   assert(!CTXOPEN(ctx));
  493 
  494   port = htons((unsigned short)ctx->dnsc_port);
  495   /* ensure we have at least one server */
  496   if (!ctx->dnsc_nserv) {
  497     sns = ctx->dnsc_serv;
  498     sns->sin.sin_family = AF_INET;
  499     sns->sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
  500     ctx->dnsc_nserv = 1;
  501   }
  502 
  503   for (i = 0; i < ctx->dnsc_nserv; ++i) {
  504     sns = &ctx->dnsc_serv[i];
  505     /* set port for each sockaddr */
  506 #ifdef HAVE_IPv6
  507     if (sns->sa.sa_family == AF_INET6) {
  508       if (!sns->sin6.sin6_port) sns->sin6.sin6_port = (unsigned short)port;
  509       ++have_inet6;
  510     }
  511     else
  512 #endif
  513     {
  514       assert(sns->sa.sa_family == AF_INET);
  515       if (!sns->sin.sin_port) sns->sin.sin_port = (unsigned short)port;
  516     }
  517   }
  518 
  519 #ifdef HAVE_IPv6
  520   if (have_inet6 && have_inet6 < ctx->dnsc_nserv) {
  521     /* convert all IPv4 addresses to IPv6 V4MAPPED */
  522     struct sockaddr_in6 sin6;
  523     memset(&sin6, 0, sizeof(sin6));
  524     sin6.sin6_family = AF_INET6;
  525     /* V4MAPPED: ::ffff:1.2.3.4 */
  526     sin6.sin6_addr.s6_addr[10] = 0xff;
  527     sin6.sin6_addr.s6_addr[11] = 0xff;
  528     for(i = 0; i < ctx->dnsc_nserv; ++i) {
  529       sns = &ctx->dnsc_serv[i];
  530       if (sns->sa.sa_family == AF_INET) {
  531         sin6.sin6_port = sns->sin.sin_port;
  532         memcpy(sin6.sin6_addr.s6_addr + 4*3, &sns->sin.sin_addr, 4);
  533         sns->sin6 = sin6;
  534       }
  535     }
  536   }
  537 
  538   ctx->dnsc_salen = have_inet6 ?
  539     sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in);
  540 
  541   if (have_inet6)
  542     sock = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
  543   else
  544     sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
  545 #else /* !HAVE_IPv6 */
  546   sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
  547   ctx->dnsc_salen = sizeof(struct sockaddr_in);
  548 #endif /* HAVE_IPv6 */
  549 
  550   if (sock < 0) {
  551     ctx->dnsc_qstatus = DNS_E_TEMPFAIL;
  552     return -1;
  553   }
  554 #ifdef WINDOWS
  555   { unsigned long on = 1;
  556     if (ioctlsocket(sock, FIONBIO, &on) == SOCKET_ERROR) {
  557       closesocket(sock);
  558       ctx->dnsc_qstatus = DNS_E_TEMPFAIL;
  559       return -1;
  560     }
  561   }
  562 #else   /* !WINDOWS */
  563   if (fcntl(sock, F_SETFL, fcntl(sock, F_GETFL) | O_NONBLOCK) < 0 ||
  564       fcntl(sock, F_SETFD, FD_CLOEXEC) < 0) {
  565     closesocket(sock);
  566     ctx->dnsc_qstatus = DNS_E_TEMPFAIL;
  567     return -1;
  568   }
  569 #endif  /* WINDOWS */
  570   /* allocate the packet buffer */
  571   if ((ctx->dnsc_pbuf = malloc(ctx->dnsc_udpbuf)) == NULL) {
  572     closesocket(sock);
  573     ctx->dnsc_qstatus = DNS_E_NOMEM;
  574     errno = ENOMEM;
  575     return -1;
  576   }
  577 
  578   ctx->dnsc_udpsock = sock;
  579   dns_request_utm(ctx, 0);
  580   return sock;
  581 }
  582 
  583 int dns_sock(const struct dns_ctx *ctx) {
  584   SETCTXINITED(ctx);
  585   return ctx->dnsc_udpsock;
  586 }
  587 
  588 int dns_active(const struct dns_ctx *ctx) {
  589   SETCTXINITED(ctx);
  590   dns_assert_ctx(ctx);
  591   return ctx->dnsc_nactive;
  592 }
  593 
  594 int dns_status(const struct dns_ctx *ctx) {
  595   SETCTX(ctx);
  596   return ctx->dnsc_qstatus;
  597 }
  598 void dns_setstatus(struct dns_ctx *ctx, int status) {
  599   SETCTX(ctx);
  600   ctx->dnsc_qstatus = status;
  601 }
  602 
  603 /* End the query: disconnect it from the active list, free it,
  604  * and return the result to the caller.
  605  */
  606 static void
  607 dns_end_query(struct dns_ctx *ctx, struct dns_query *q,
  608               int status, void *result) {
  609   dns_query_fn *cbck = q->dnsq_cbck;
  610   void *cbdata = q->dnsq_cbdata;
  611   ctx->dnsc_qstatus = status;
  612   assert((status < 0 && result == 0) || (status >= 0 && result != 0));
  613   assert(cbck != 0);    /*XXX callback may be NULL */
  614   assert(ctx->dnsc_nactive > 0);
  615   --ctx->dnsc_nactive;
  616   qlist_remove(&ctx->dnsc_qactive, q);
  617   /* force the query to be unconnected */
  618   /*memset(q, 0, sizeof(*q));*/
  619 #ifndef NDEBUG
  620   q->dnsq_ctx = NULL;
  621 #endif
  622   free(q);
  623   cbck(ctx, result, cbdata);
  624 }
  625 
  626 #define DNS_DBG(ctx, code, sa, slen, pkt, plen) \
  627   do { \
  628     if (ctx->dnsc_udbgfn) \
  629       ctx->dnsc_udbgfn(code, (sa), slen, pkt, plen, 0, 0); \
  630   } while(0)
  631 #define DNS_DBGQ(ctx, q, code, sa, slen, pkt, plen) \
  632   do { \
  633     if (ctx->dnsc_udbgfn) \
  634       ctx->dnsc_udbgfn(code, (sa), slen, pkt, plen, q, q->dnsq_cbdata); \
  635   } while(0)
  636 
  637 static void dns_newid(struct dns_ctx *ctx, struct dns_query *q) {
  638   /* this is how we choose an identifier for a new query (qID).
  639    * For now, it's just sequential number, incremented for every query, and
  640    * thus obviously trivial to guess.
  641    * There are two choices:
  642    *  a) use sequential numbers.  It is plain insecure. In DNS, there are two
  643    *   places where random numbers are (or can) be used to increase security:
  644    *   random qID and random source port number.  Without this randomness
  645    *   (udns uses fixed port for all queries), or when the randomness is weak,
  646    *   it's trivial to spoof query replies.  With randomness however, it
  647    *   becomes a bit more difficult task.  Too bad we only have 16 bits for
  648    *   our security, as qID is only two bytes.  It isn't a security per se,
  649    *   to rely on those 16 bits - an attacker can just flood us with fake
  650    *   replies with all possible qIDs (only 65536 of them), and in this case,
  651    *   even if we'll use true random qIDs, we'll be in trouble (not protected
  652    *   against spoofing).  Yes, this is only possible on a high-speed network
  653    *   (probably on the LAN only, since usually a border router for a LAN
  654    *   protects internal machines from packets with spoofed local addresses
  655    *   from outside, and usually a nameserver resides on LAN), but it's
  656    *   still very well possible to send us fake replies.
  657    *   In other words: there's nothing a DNS (stub) resolver can do against
  658    *   spoofing attacks, unless DNSSEC is in use, which helps here alot.
  659    *   Too bad that DNSSEC isn't widespread, so relying on it isn't an
  660    *   option in almost all cases...
  661    *  b) use random qID, based on some random-number generation mechanism.
  662    *   This way, we increase our protection a bit (see above - it's very weak
  663    *   still), but we also increase risk of qID reuse and matching late replies
  664    *   that comes to queries we've sent before against new queries.  There are
  665    *   some more corner cases around that, as well - for example, normally,
  666    *   udns tries to find the query for a given reply by qID, *and* by
  667    *   verifying that the query DN and other parameters are also the same
  668    *   (so if the new query is against another domain name, old reply will
  669    *   be ignored automatically).  But certain types of replies which we now
  670    *   handle - for example, FORMERR reply from servers which refuses to
  671    *   process EDNS0-enabled packets - comes without all the query parameters
  672    *   but the qID - so we're forced to use qID only when determining which
  673    *   query the given reply corresponds to.  This makes us even more
  674    *   vulnerable to spoofing attacks, because an attacker don't even need to
  675    *   know which queries we perform to spoof the replies - he only needs to
  676    *   flood us with fake FORMERR "replies".
  677    *
  678    * That all to say: using sequential (or any other trivially guessable)
  679    * numbers for qIDs is insecure, but the whole thing is inherently insecure
  680    * as well, and this "extra weakness" that comes from weak qID choosing
  681    * algorithm adds almost nothing to the underlying problem.
  682    *
  683    * It CAN NOT be made secure.  Period.  That's it.
  684    * Unless we choose to implement DNSSEC, which is a whole different story.
  685    * Forcing TCP mode makes it better, but who uses TCP for DNS anyway?
  686    * (and it's hardly possible because of huge impact on the recursive
  687    * nameservers).
  688    *
  689    * Note that ALL stub resolvers (again, unless they implement and enforce
  690    * DNSSEC) suffers from this same problem.
  691    *
  692    * Here, I use a pseudo-random number generator for qIDs, instead of a
  693    * simpler sequential IDs.  This is _not_ more secure than sequential
  694    * ID, but some found random IDs more enjoyeable for some reason.  So
  695    * here it goes.
  696    */
  697 
  698   /* Use random number and check if it's unique.
  699    * If it's not, try again up to 5 times.
  700    */
  701   unsigned loop;
  702   dnsc_t c0, c1;
  703   for(loop = 0; loop < 5; ++loop) {
  704     const struct dns_query *c;
  705     if (!ctx->dnsc_nextid)
  706       ctx->dnsc_nextid = udns_jranval(&ctx->dnsc_jran);
  707     c0 = ctx->dnsc_nextid & 0xff;
  708     c1 = (ctx->dnsc_nextid >> 8) & 0xff;
  709     ctx->dnsc_nextid >>= 16;
  710     for(c = ctx->dnsc_qactive.head; c; c = c->dnsq_next)
  711       if (c->dnsq_id[0] == c0 && c->dnsq_id[1] == c1)
  712         break; /* found such entry, try again */
  713     if (!c)
  714       break;
  715   }
  716   q->dnsq_id[0] = c0; q->dnsq_id[1] = c1;
  717 
  718   /* reset all parameters relevant for previous query lifetime */
  719   q->dnsq_try = 0;
  720   q->dnsq_servi = 0;
  721   /*XXX probably should keep dnsq_servnEDNS0 bits?
  722    * See also comments in dns_ioevent() about FORMERR case */
  723   q->dnsq_servwait = q->dnsq_servskip = q->dnsq_servnEDNS0 = 0;
  724 }
  725 
  726 /* Find next search suffix and fills in q->dnsq_dn.
  727  * Return 0 if no more to try. */
  728 static int dns_next_srch(struct dns_ctx *ctx, struct dns_query *q) {
  729   unsigned dnl;
  730 
  731   for(;;) {
  732     if (q->dnsq_nxtsrch > ctx->dnsc_srchend)
  733       return 0;
  734     dnl = dns_dnlen(q->dnsq_nxtsrch);
  735     if (dnl + q->dnsq_origdnl0 <= DNS_MAXDN &&
  736         (*q->dnsq_nxtsrch || !(q->dnsq_flags & DNS_ASIS_DONE)))
  737       break;
  738     q->dnsq_nxtsrch += dnl;
  739   }
  740   memcpy(q->dnsq_dn + q->dnsq_origdnl0, q->dnsq_nxtsrch, dnl);
  741   if (!*q->dnsq_nxtsrch)
  742     q->dnsq_flags |= DNS_ASIS_DONE;
  743   q->dnsq_nxtsrch += dnl;
  744   dns_newid(ctx, q); /* new ID for new qDN */
  745   return 1;
  746 }
  747 
  748 /* find the server to try for current iteration.
  749  * Note that current dnsq_servi may point to a server we should skip --
  750  * in that case advance to the next server.
  751  * Return true if found, false if all tried.
  752  */
  753 static int dns_find_serv(const struct dns_ctx *ctx, struct dns_query *q) {
  754   while(q->dnsq_servi < ctx->dnsc_nserv) {
  755     if (!(q->dnsq_servskip & (1 << q->dnsq_servi)))
  756       return 1;
  757     ++q->dnsq_servi;
  758   }
  759   return 0;
  760 }
  761 
  762 /* format and send the query to a given server.
  763  * In case of network problem (sendto() fails), return -1,
  764  * else return 0.
  765  */
  766 static int
  767 dns_send_this(struct dns_ctx *ctx, struct dns_query *q,
  768               unsigned servi, time_t now) {
  769   unsigned qlen;
  770   unsigned tries;
  771 
  772   { /* format the query buffer */
  773     dnsc_t *p = ctx->dnsc_pbuf;
  774     memset(p, 0, DNS_HSIZE);
  775     if (!(q->dnsq_flags & DNS_NORD)) p[DNS_H_F1] |= DNS_HF1_RD;
  776     if (q->dnsq_flags & DNS_AAONLY) p[DNS_H_F1] |= DNS_HF1_AA;
  777     if (q->dnsq_flags & DNS_SET_CD) p[DNS_H_F2] |= DNS_HF2_CD;
  778     p[DNS_H_QDCNT2] = 1;
  779     memcpy(p + DNS_H_QID, q->dnsq_id, 2);
  780     p = dns_payload(p);
  781     /* copy query dn */
  782     p += dns_dntodn(q->dnsq_dn, p, DNS_MAXDN);
  783     /* query type and class */
  784     memcpy(p, q->dnsq_typcls, 4); p += 4;
  785     /* add EDNS0 record. DO flag requires it */
  786     if (q->dnsq_flags & DNS_SET_DO ||
  787         (ctx->dnsc_udpbuf > DNS_MAXPACKET &&
  788          !(q->dnsq_servnEDNS0 & (1 << servi)))) {
  789       *p++ = 0;         /* empty (root) DN */
  790       p = dns_put16(p, DNS_T_OPT);
  791       p = dns_put16(p, ctx->dnsc_udpbuf);
  792       /* EDNS0 RCODE & VERSION; rest of the TTL field; RDLEN */
  793       memset(p, 0, 2+2+2);
  794       if (q->dnsq_flags & DNS_SET_DO) p[2] |= DNS_EF1_DO;
  795       p += 2+2+2;
  796       ctx->dnsc_pbuf[DNS_H_ARCNT2] = 1;
  797     }
  798     qlen = p - ctx->dnsc_pbuf;
  799     assert(qlen <= ctx->dnsc_udpbuf);
  800   }
  801 
  802   /* send the query */
  803   tries = 10;
  804   while (sendto(ctx->dnsc_udpsock, (void*)ctx->dnsc_pbuf, qlen, 0,
  805                 &ctx->dnsc_serv[servi].sa, ctx->dnsc_salen) < 0) {
  806     /*XXX just ignore the sendto() error for now and try again.
  807      * In the future, it may be possible to retrieve the error code
  808      * and find which operation/query failed.
  809      *XXX try the next server too? (if ENETUNREACH is returned immediately)
  810      */
  811     if (--tries) continue;
  812     /* if we can't send the query, fail it. */
  813     dns_end_query(ctx, q, DNS_E_TEMPFAIL, 0);
  814     return -1;
  815   }
  816   DNS_DBGQ(ctx, q, 1,
  817            &ctx->dnsc_serv[servi].sa, sizeof(union sockaddr_ns),
  818            ctx->dnsc_pbuf, qlen);
  819   q->dnsq_servwait |= 1 << servi;   /* expect reply from this ns */
  820 
  821   q->dnsq_deadline = now +
  822     (dns_find_serv(ctx, q) ? 1 : ctx->dnsc_timeout << q->dnsq_try);
  823 
  824   /* move the query to the proper place, according to the new deadline */
  825   qlist_remove(&ctx->dnsc_qactive, q);
  826   { /* insert from the tail */
  827     struct dns_query *p;
  828     for(p = ctx->dnsc_qactive.tail; p; p = p->dnsq_prev)
  829       if (p->dnsq_deadline <= q->dnsq_deadline)
  830     break;
  831     qlist_insert_after(&ctx->dnsc_qactive, q, p);
  832   }
  833 
  834   return 0;
  835 }
  836 
  837 /* send the query out using next available server
  838  * and add it to the active list, or, if no servers available,
  839  * end it.
  840  */
  841 static void
  842 dns_send(struct dns_ctx *ctx, struct dns_query *q, time_t now) {
  843 
  844   /* if we can't send the query, return TEMPFAIL even when searching:
  845    * we can't be sure whenever the name we tried to search exists or not,
  846    * so don't continue searching, or we may find the wrong name. */
  847 
  848   if (!dns_find_serv(ctx, q)) {
  849     /* no more servers in this iteration.  Try the next cycle */
  850     q->dnsq_servi = 0;  /* reset */
  851     q->dnsq_try++;  /* next try */
  852     if (q->dnsq_try >= ctx->dnsc_ntries ||
  853         !dns_find_serv(ctx, q)) {
  854       /* no more servers and tries, fail the query */
  855       /* return TEMPFAIL even when searching: no more tries for this
  856        * searchlist, and no single definitive reply (handled in dns_ioevent()
  857        * in NOERROR or NXDOMAIN cases) => all nameservers failed to process
  858        * current search list element, so we don't know whenever the name exists.
  859        */
  860       dns_end_query(ctx, q, DNS_E_TEMPFAIL, 0);
  861       return;
  862     }
  863   }
  864 
  865   dns_send_this(ctx, q, q->dnsq_servi++, now);
  866 }
  867 
  868 static void dns_dummy_cb(struct dns_ctx *ctx, void *result, void *data) {
  869   if (result) free(result);
  870   data = ctx = 0;   /* used */
  871 }
  872 
  873 /* The (only, main, real) query submission routine.
  874  * Allocate new query structure, initialize it, check validity of
  875  * parameters, and add it to the head of the active list, without
  876  * trying to send it (to be picked up on next event).
  877  * Error return (without calling the callback routine) -
  878  *  no memory or wrong parameters.
  879  *XXX The `no memory' case probably should go to the callback anyway...
  880  */
  881 struct dns_query *
  882 dns_submit_dn(struct dns_ctx *ctx,
  883               dnscc_t *dn, int qcls, int qtyp, int flags,
  884               dns_parse_fn *parse, dns_query_fn *cbck, void *data) {
  885   struct dns_query *q;
  886   SETCTXOPEN(ctx);
  887   dns_assert_ctx(ctx);
  888 
  889   q = calloc(sizeof(*q), 1);
  890   if (!q) {
  891     ctx->dnsc_qstatus = DNS_E_NOMEM;
  892     return NULL;
  893   }
  894 
  895 #ifndef NDEBUG
  896   q->dnsq_ctx = ctx;
  897 #endif
  898   q->dnsq_parse = parse;
  899   q->dnsq_cbck = cbck ? cbck : dns_dummy_cb;
  900   q->dnsq_cbdata = data;
  901 
  902   q->dnsq_origdnl0 = dns_dntodn(dn, q->dnsq_dn, sizeof(q->dnsq_dn));
  903   assert(q->dnsq_origdnl0 > 0);
  904   --q->dnsq_origdnl0;       /* w/o the trailing 0 */
  905   dns_put16(q->dnsq_typcls+0, qtyp);
  906   dns_put16(q->dnsq_typcls+2, qcls);
  907   q->dnsq_flags = (flags | ctx->dnsc_flags) & ~DNS_INTERNAL;
  908 
  909   if (flags & DNS_NOSRCH ||
  910       dns_dnlabels(q->dnsq_dn) > ctx->dnsc_ndots) {
  911     q->dnsq_nxtsrch = flags & DNS_NOSRCH ?
  912       ctx->dnsc_srchend /* end of the search list if no search requested */ :
  913       ctx->dnsc_srchbuf /* beginning of the list, but try as-is first */;
  914     q->dnsq_flags |= DNS_ASIS_DONE;
  915     dns_newid(ctx, q);
  916   }
  917   else {
  918     q->dnsq_nxtsrch = ctx->dnsc_srchbuf;
  919     dns_next_srch(ctx, q);
  920   }
  921 
  922   /* q->dnsq_deadline is set to 0 (calloc above): the new query is
  923    * "already expired" when first inserted into queue, so it's safe
  924    * to insert it into the head of the list.  Next call to dns_timeouts()
  925    * will actually send it.
  926    */
  927   qlist_add_head(&ctx->dnsc_qactive, q);
  928   ++ctx->dnsc_nactive;
  929   dns_request_utm(ctx, 0);
  930 
  931   return q;
  932 }
  933 
  934 struct dns_query *
  935 dns_submit_p(struct dns_ctx *ctx,
  936              const char *name, int qcls, int qtyp, int flags,
  937              dns_parse_fn *parse, dns_query_fn *cbck, void *data) {
  938   int isabs;
  939   SETCTXOPEN(ctx);
  940   if (dns_ptodn(name, 0, ctx->dnsc_pbuf, DNS_MAXDN, &isabs) <= 0) {
  941     ctx->dnsc_qstatus = DNS_E_BADQUERY;
  942     return NULL;
  943   }
  944   if (isabs)
  945     flags |= DNS_NOSRCH;
  946   return
  947     dns_submit_dn(ctx, ctx->dnsc_pbuf, qcls, qtyp, flags, parse, cbck, data);
  948 }
  949 
  950 /* process readable fd condition.
  951  * To be usable in edge-triggered environment, the routine
  952  * should consume all input so it should loop over.
  953  * Note it isn't really necessary to loop here, because
  954  * an application may perform the loop just fine by it's own,
  955  * but in this case we should return some sensitive result,
  956  * to indicate when to stop calling and error conditions.
  957  * Note also we may encounter all sorts of recvfrom()
  958  * errors which aren't fatal, and at the same time we may
  959  * loop forever if an error IS fatal.
  960  */
  961 void dns_ioevent(struct dns_ctx *ctx, time_t now) {
  962   int r;
  963   unsigned servi;
  964   struct dns_query *q;
  965   dnsc_t *pbuf;
  966   dnscc_t *pend, *pcur;
  967   void *result;
  968   union sockaddr_ns sns;
  969   socklen_t slen;
  970 
  971   SETCTX(ctx);
  972   if (!CTXOPEN(ctx))
  973     return;
  974   dns_assert_ctx(ctx);
  975   pbuf = ctx->dnsc_pbuf;
  976 
  977   if (!now) now = time(NULL);
  978 
  979 again: /* receive the reply */
  980 
  981   slen = sizeof(sns);
  982   r = recvfrom(ctx->dnsc_udpsock, (void*)pbuf, ctx->dnsc_udpbuf,
  983                MSG_DONTWAIT, &sns.sa, &slen);
  984   if (r < 0) {
  985     /*XXX just ignore recvfrom() errors for now.
  986      * in the future it may be possible to determine which
  987      * query failed and requeue it.
  988      * Note there may be various error conditions, triggered
  989      * by both local problems and remote problems.  It isn't
  990      * quite trivial to determine whenever an error is local
  991      * or remote.  On local errors, we should stop, while
  992      * remote errors should be ignored (for now anyway).
  993      */
  994 #ifdef WINDOWS
  995     if (WSAGetLastError() == WSAEWOULDBLOCK)
  996 #else
  997     if (errno == EAGAIN)
  998 #endif
  999     {
 1000       dns_request_utm(ctx, now);
 1001       return;
 1002     }
 1003     goto again;
 1004   }
 1005 
 1006   pend = pbuf + r;
 1007   pcur = dns_payload(pbuf);
 1008 
 1009   /* check reply header */
 1010   if (pcur > pend || dns_numqd(pbuf) > 1 || dns_opcode(pbuf) != 0) {
 1011     DNS_DBG(ctx, -1/*bad reply*/, &sns.sa, slen, pbuf, r);
 1012     goto again;
 1013   }
 1014 
 1015   /* find the matching query, by qID */
 1016   for (q = ctx->dnsc_qactive.head; ; q = q->dnsq_next) {
 1017     if (!q) {
 1018       /* no more requests: old reply? */
 1019       DNS_DBG(ctx, -5/*no matching query*/, &sns.sa, slen, pbuf, r);
 1020       goto again;
 1021     }
 1022     if (pbuf[DNS_H_QID1] == q->dnsq_id[0] &&
 1023         pbuf[DNS_H_QID2] == q->dnsq_id[1])
 1024       break;
 1025   }
 1026 
 1027   /* if we have numqd, compare with our query qDN */
 1028   if (dns_numqd(pbuf)) {
 1029     /* decode the qDN */
 1030     dnsc_t dn[DNS_MAXDN];
 1031     if (dns_getdn(pbuf, &pcur, pend, dn, sizeof(dn)) < 0 ||
 1032         pcur + 4 > pend) {
 1033       DNS_DBG(ctx, -1/*bad reply*/, &sns.sa, slen, pbuf, r);
 1034       goto again;
 1035     }
 1036     if (!dns_dnequal(dn, q->dnsq_dn) ||
 1037         memcmp(pcur, q->dnsq_typcls, 4) != 0) {
 1038       /* not this query */
 1039       DNS_DBG(ctx, -5/*no matching query*/, &sns.sa, slen, pbuf, r);
 1040       goto again;
 1041     }
 1042     /* here, query match, and pcur points past qDN in query section in pbuf */
 1043   }
 1044   /* if no numqd, we only allow FORMERR rcode */
 1045   else if (dns_rcode(pbuf) != DNS_R_FORMERR) {
 1046     /* treat it as bad reply if !FORMERR */
 1047     DNS_DBG(ctx, -1/*bad reply*/, &sns.sa, slen, pbuf, r);
 1048     goto again;
 1049   }
 1050   else {
 1051     /* else it's FORMERR, handled below */
 1052   }
 1053 
 1054   /* find server */
 1055 #ifdef HAVE_IPv6
 1056   if (sns.sa.sa_family == AF_INET6 && slen >= sizeof(sns.sin6)) {
 1057     for(servi = 0; servi < ctx->dnsc_nserv; ++servi)
 1058       if (sin6_eq(ctx->dnsc_serv[servi].sin6, sns.sin6))
 1059         break;
 1060   }
 1061   else
 1062 #endif
 1063   if (sns.sa.sa_family == AF_INET && slen >= sizeof(sns.sin)) {
 1064     for(servi = 0; servi < ctx->dnsc_nserv; ++servi)
 1065       if (sin_eq(ctx->dnsc_serv[servi].sin, sns.sin))
 1066         break;
 1067   }
 1068   else
 1069     servi = ctx->dnsc_nserv;
 1070 
 1071   /* check if we expect reply from this server.
 1072    * Note we can receive reply from first try if we're already at next */
 1073   if (!(q->dnsq_servwait & (1 << servi))) { /* if ever asked this NS */
 1074     DNS_DBG(ctx, -2/*wrong server*/, &sns.sa, slen, pbuf, r);
 1075     goto again;
 1076   }
 1077 
 1078   /* we got (some) reply for our query */
 1079 
 1080   DNS_DBGQ(ctx, q, 0, &sns.sa, slen, pbuf, r);
 1081   q->dnsq_servwait &= ~(1 << servi);    /* don't expect reply from this serv */
 1082 
 1083   /* process the RCODE */
 1084   switch(dns_rcode(pbuf)) {
 1085 
 1086   case DNS_R_NOERROR:
 1087     if (dns_tc(pbuf)) {
 1088       /* possible truncation.  We can't deal with it. */
 1089       /*XXX for now, treat TC bit the same as SERVFAIL.
 1090        * It is possible to:
 1091        *  a) try to decode the reply - may be ANSWER section is ok;
 1092        *  b) check if server understands EDNS0, and if it is, and
 1093        *   answer still don't fit, end query.
 1094        */
 1095       break;
 1096     }
 1097     if (!dns_numan(pbuf)) { /* no data of requested type */
 1098       if (dns_next_srch(ctx, q)) {
 1099         /* if we're searching, try next searchlist element,
 1100          * but remember NODATA reply. */
 1101         q->dnsq_flags |= DNS_SEEN_NODATA;
 1102         dns_send(ctx, q, now);
 1103       }
 1104       else
 1105         /* else - nothing to search any more - finish the query.
 1106          * It will be NODATA since we've seen a NODATA reply. */
 1107         dns_end_query(ctx, q, DNS_E_NODATA, 0);
 1108     }
 1109     /* we've got a positive reply here */
 1110     else if (q->dnsq_parse) {
 1111       /* if we have parsing routine, call it and return whatever it returned */
 1112       /* don't try to re-search if NODATA here.  For example,
 1113        * if we asked for A but only received CNAME.  Unless we'll
 1114        * someday do recursive queries.  And that's problematic too, since
 1115        * we may be dealing with specific AA-only nameservers for a given
 1116        * domain, but CNAME points elsewhere...
 1117        */
 1118       r = q->dnsq_parse(q->dnsq_dn, pbuf, pcur, pend, &result);
 1119       dns_end_query(ctx, q, r, r < 0 ? NULL : result);
 1120     }
 1121     /* else just malloc+copy the raw DNS reply */
 1122     else if ((result = malloc(r)) == NULL)
 1123       dns_end_query(ctx, q, DNS_E_NOMEM, NULL);
 1124     else {
 1125       memcpy(result, pbuf, r);
 1126       dns_end_query(ctx, q, r, result);
 1127     }
 1128     goto again;
 1129 
 1130   case DNS_R_NXDOMAIN:  /* Non-existing domain. */
 1131     if (dns_next_srch(ctx, q))
 1132       /* more search entries exists, try them. */
 1133       dns_send(ctx, q, now);
 1134     else
 1135       /* nothing to search anymore. End the query, returning either NODATA
 1136        * if we've seen it before, or NXDOMAIN if not. */
 1137       dns_end_query(ctx, q,
 1138            q->dnsq_flags & DNS_SEEN_NODATA ? DNS_E_NODATA : DNS_E_NXDOMAIN, 0);
 1139     goto again;
 1140 
 1141   case DNS_R_FORMERR:
 1142   case DNS_R_NOTIMPL:
 1143     /* for FORMERR and NOTIMPL rcodes, if we tried EDNS0-enabled query,
 1144      * try w/o EDNS0. */
 1145     if (ctx->dnsc_udpbuf > DNS_MAXPACKET &&
 1146         !(q->dnsq_servnEDNS0 & (1 << servi))) {
 1147       /* we always trying EDNS0 first if enabled, and retry a given query
 1148        * if not available. Maybe it's better to remember inavailability of
 1149        * EDNS0 in ctx as a per-NS flag, and never try again for this NS.
 1150        * For long-running applications.. maybe they will change the nameserver
 1151        * while we're running? :)  Also, since FORMERR is the only rcode we
 1152        * allow to be header-only, and in this case the only check we do to
 1153        * find a query it belongs to is qID (not qDN+qCLS+qTYP), it's much
 1154        * easier to spoof and to force us to perform non-EDNS0 queries only...
 1155        */
 1156       q->dnsq_servnEDNS0 |= 1 << servi;
 1157       dns_send_this(ctx, q, servi, now);
 1158       goto again;
 1159     }
 1160     /* else we handle it the same as SERVFAIL etc */
 1161 
 1162   case DNS_R_SERVFAIL:
 1163   case DNS_R_REFUSED:
 1164     /* for these rcodes, advance this request
 1165      * to the next server and reschedule */
 1166   default: /* unknown rcode? hmmm... */
 1167     break;
 1168   }
 1169 
 1170   /* here, we received unexpected reply */
 1171   q->dnsq_servskip |= (1 << servi); /* don't retry this server */
 1172 
 1173   /* we don't expect replies from this server anymore.
 1174    * But there may be other servers.  Some may be still processing our
 1175    * query, and some may be left to try.
 1176    * We just ignore this reply and wait a bit more if some NSes haven't
 1177    * replied yet (dnsq_servwait != 0), and let the situation to be handled
 1178    * on next event processing.  Timeout for this query is set correctly,
 1179    * if not taking into account the one-second difference - we can try
 1180    * next server in the same iteration sooner.
 1181    */
 1182 
 1183   /* try next server */
 1184   if (!q->dnsq_servwait) {
 1185     /* next retry: maybe some other servers will reply next time.
 1186      * dns_send() will end the query for us if no more servers to try.
 1187      * Note we can't continue with the next searchlist element here:
 1188      * we don't know if the current qdn exists or not, there's no definitive
 1189      * answer yet (which is seen in cases above).
 1190      *XXX standard resolver also tries as-is query in case all nameservers
 1191      * failed to process our query and if not tried before.  We don't do it.
 1192      */
 1193     dns_send(ctx, q, now);
 1194   }
 1195   else {
 1196     /* else don't do anything - not all servers replied yet */
 1197   }
 1198   goto again;
 1199 
 1200 }
 1201 
 1202 /* handle all timeouts */
 1203 int dns_timeouts(struct dns_ctx *ctx, int maxwait, time_t now) {
 1204   /* this is a hot routine */
 1205   struct dns_query *q;
 1206 
 1207   SETCTX(ctx);
 1208   dns_assert_ctx(ctx);
 1209 
 1210   /* Pick up first entry from query list.
 1211    * If its deadline has passed, (re)send it
 1212    * (dns_send() will move it next in the list).
 1213    * If not, this is the query which determines the closest deadline.
 1214    */
 1215 
 1216   q = ctx->dnsc_qactive.head;
 1217   if (!q)
 1218     return maxwait;
 1219   if (!now)
 1220     now = time(NULL);
 1221   do {
 1222     if (q->dnsq_deadline > now) { /* first non-expired query */
 1223       int w = (int)(q->dnsq_deadline - now);
 1224       if (maxwait < 0 || maxwait > w)
 1225         maxwait = w;
 1226       break;
 1227     }
 1228     else {
 1229       /* process expired deadline */
 1230       dns_send(ctx, q, now);
 1231     }
 1232   } while((q = ctx->dnsc_qactive.head) != NULL);
 1233 
 1234   dns_request_utm(ctx, now); /* update timer with new deadline */
 1235   return maxwait;
 1236 }
 1237 
 1238 struct dns_resolve_data {
 1239   int   dnsrd_done;
 1240   void *dnsrd_result;
 1241 };
 1242 
 1243 static void dns_resolve_cb(struct dns_ctx *ctx, void *result, void *data) {
 1244   struct dns_resolve_data *d = data;
 1245   d->dnsrd_result = result;
 1246   d->dnsrd_done = 1;
 1247   ctx = ctx;
 1248 }
 1249 
 1250 void *dns_resolve(struct dns_ctx *ctx, struct dns_query *q) {
 1251   time_t now;
 1252   struct dns_resolve_data d;
 1253   int n;
 1254   SETCTXOPEN(ctx);
 1255 
 1256   if (!q)
 1257     return NULL;
 1258 
 1259   assert(ctx == q->dnsq_ctx);
 1260   dns_assert_ctx(ctx);
 1261   /* do not allow re-resolving syncronous queries */
 1262   assert(q->dnsq_cbck != dns_resolve_cb && "can't resolve syncronous query");
 1263   if (q->dnsq_cbck == dns_resolve_cb) {
 1264     ctx->dnsc_qstatus = DNS_E_BADQUERY;
 1265     return NULL;
 1266   }
 1267   q->dnsq_cbck = dns_resolve_cb;
 1268   q->dnsq_cbdata = &d;
 1269   d.dnsrd_done = 0;
 1270 
 1271   now = time(NULL);
 1272   while(!d.dnsrd_done && (n = dns_timeouts(ctx, -1, now)) >= 0) {
 1273 #ifdef HAVE_POLL
 1274     struct pollfd pfd;
 1275     pfd.fd = ctx->dnsc_udpsock;
 1276     pfd.events = POLLIN;
 1277     n = poll(&pfd, 1, n * 1000);
 1278 #else
 1279     fd_set rfd;
 1280     struct timeval tv;
 1281     FD_ZERO(&rfd);
 1282     FD_SET(ctx->dnsc_udpsock, &rfd);
 1283     tv.tv_sec = n; tv.tv_usec = 0;
 1284     n = select(ctx->dnsc_udpsock + 1, &rfd, NULL, NULL, &tv);
 1285 #endif
 1286     now = time(NULL);
 1287     if (n > 0)
 1288       dns_ioevent(ctx, now);
 1289   }
 1290 
 1291   return d.dnsrd_result;
 1292 }
 1293 
 1294 void *dns_resolve_dn(struct dns_ctx *ctx,
 1295                      dnscc_t *dn, int qcls, int qtyp, int flags,
 1296                      dns_parse_fn *parse) {
 1297   return
 1298     dns_resolve(ctx,
 1299       dns_submit_dn(ctx, dn, qcls, qtyp, flags, parse, NULL, NULL));
 1300 }
 1301 
 1302 void *dns_resolve_p(struct dns_ctx *ctx,
 1303                     const char *name, int qcls, int qtyp, int flags,
 1304                     dns_parse_fn *parse) {
 1305   return
 1306     dns_resolve(ctx,
 1307       dns_submit_p(ctx, name, qcls, qtyp, flags, parse, NULL, NULL));
 1308 }
 1309 
 1310 int dns_cancel(struct dns_ctx *ctx, struct dns_query *q) {
 1311   SETCTX(ctx);
 1312   dns_assert_ctx(ctx);
 1313   assert(q->dnsq_ctx == ctx);
 1314   /* do not allow cancelling syncronous queries */
 1315   assert(q->dnsq_cbck != dns_resolve_cb && "can't cancel syncronous query");
 1316   if (q->dnsq_cbck == dns_resolve_cb)
 1317     return (ctx->dnsc_qstatus = DNS_E_BADQUERY);
 1318   qlist_remove(&ctx->dnsc_qactive, q);
 1319   --ctx->dnsc_nactive;
 1320   dns_request_utm(ctx, 0);
 1321   return 0;
 1322 }
 1323