root/src/udns/udns_resolver.c

Revision dfec9683c6674557f3639bb6485d369ebd6a347b, 40.3 kB (checked in by Theo Schlossnagle <jesus@omniti.com>, 6 years ago)

Make sure we compile with clang (trunk) on Ubuntu 11.10

This is a good milestone, so let's do an intermediate commit:
At this point we are able to compile with Clang (trunk, no less;)
on Ubuntu 11.10. I was careful with the introduced changes not to
introduce any regressions:

* bsd/libutil.h is prefered, otherwise we fallback to libutil.h
* replaced isinteger()'s guts with a call to strtod()

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