root/src/udns/udns_resolver.c

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

we need to check if we're still open before we do this (post again:)

  • 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         ((struct in_addr*)&sin6.sin6_addr)[3] = sns->sin.sin_addr;
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(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    * So, instead of trying to be more secure (which actually is not - false
693    * sense of security is - I think - is worse than no security), I'm trying
694    * to be more robust here (by preventing qID reuse, which helps in normal
695    * conditions).  And use sequential qID generation scheme.
696    */
697   dns_put16(q->dnsq_id, ctx->dnsc_nextid++);
698   /* reset all parameters relevant for previous query lifetime */
699   q->dnsq_try = 0;
700   q->dnsq_servi = 0;
701   /*XXX probably should keep dnsq_servnEDNS0 bits?
702    * See also comments in dns_ioevent() about FORMERR case */
703   q->dnsq_servwait = q->dnsq_servskip = q->dnsq_servnEDNS0 = 0;
704 }
705
706 /* Find next search suffix and fills in q->dnsq_dn.
707  * Return 0 if no more to try. */
708 static int dns_next_srch(struct dns_ctx *ctx, struct dns_query *q) {
709   unsigned dnl;
710
711   for(;;) {
712     if (q->dnsq_nxtsrch > ctx->dnsc_srchend)
713       return 0;
714     dnl = dns_dnlen(q->dnsq_nxtsrch);
715     if (dnl + q->dnsq_origdnl0 <= DNS_MAXDN &&
716         (*q->dnsq_nxtsrch || !(q->dnsq_flags & DNS_ASIS_DONE)))
717       break;
718     q->dnsq_nxtsrch += dnl;
719   }
720   memcpy(q->dnsq_dn + q->dnsq_origdnl0, q->dnsq_nxtsrch, dnl);
721   if (!*q->dnsq_nxtsrch)
722     q->dnsq_flags |= DNS_ASIS_DONE;
723   q->dnsq_nxtsrch += dnl;
724   dns_newid(ctx, q); /* new ID for new qDN */
725   return 1;
726 }
727
728 /* find the server to try for current iteration.
729  * Note that current dnsq_servi may point to a server we should skip --
730  * in that case advance to the next server.
731  * Return true if found, false if all tried.
732  */
733 static int dns_find_serv(const struct dns_ctx *ctx, struct dns_query *q) {
734   while(q->dnsq_servi < ctx->dnsc_nserv) {
735     if (!(q->dnsq_servskip & (1 << q->dnsq_servi)))
736       return 1;
737     ++q->dnsq_servi;
738   }
739   return 0;
740 }
741
742 /* format and send the query to a given server.
743  * In case of network problem (sendto() fails), return -1,
744  * else return 0.
745  */
746 static int
747 dns_send_this(struct dns_ctx *ctx, struct dns_query *q,
748               unsigned servi, time_t now) {
749   unsigned qlen;
750   unsigned tries;
751
752   { /* format the query buffer */
753     dnsc_t *p = ctx->dnsc_pbuf;
754     memset(p, 0, DNS_HSIZE);
755     if (!(q->dnsq_flags & DNS_NORD)) p[DNS_H_F1] |= DNS_HF1_RD;
756     if (q->dnsq_flags & DNS_AAONLY) p[DNS_H_F1] |= DNS_HF1_AA;
757     p[DNS_H_QDCNT2] = 1;
758     memcpy(p + DNS_H_QID, q->dnsq_id, 2);
759     p = dns_payload(p);
760     /* copy query dn */
761     p += dns_dntodn(q->dnsq_dn, p, DNS_MAXDN);
762     /* query type and class */
763     memcpy(p, q->dnsq_typcls, 4); p += 4;
764     /* add EDNS0 size record */
765     if (ctx->dnsc_udpbuf > DNS_MAXPACKET &&
766         !(q->dnsq_servnEDNS0 & (1 << servi))) {
767       *p++ = 0;                 /* empty (root) DN */
768       p = dns_put16(p, DNS_T_OPT);
769       p = dns_put16(p, ctx->dnsc_udpbuf);
770       /* EDNS0 RCODE & VERSION; rest of the TTL field; RDLEN */
771       memset(p, 0, 2+2+2); p += 2+2+2;
772       ctx->dnsc_pbuf[DNS_H_ARCNT2] = 1;
773     }
774     qlen = p - ctx->dnsc_pbuf;
775     assert(qlen <= ctx->dnsc_udpbuf);
776   }
777
778   /* send the query */
779   tries = 10;
780   while (sendto(ctx->dnsc_udpsock, (void*)ctx->dnsc_pbuf, qlen, 0,
781                 &ctx->dnsc_serv[servi].sa, ctx->dnsc_salen) < 0) {
782     /*XXX just ignore the sendto() error for now and try again.
783      * In the future, it may be possible to retrieve the error code
784      * and find which operation/query failed.
785      *XXX try the next server too? (if ENETUNREACH is returned immediately)
786      */
787     if (--tries) continue;
788     /* if we can't send the query, fail it. */
789     dns_end_query(ctx, q, DNS_E_TEMPFAIL, 0);
790     return -1;
791   }
792   DNS_DBGQ(ctx, q, 1,
793            &ctx->dnsc_serv[servi].sa, sizeof(union sockaddr_ns),
794            ctx->dnsc_pbuf, qlen);
795   q->dnsq_servwait |= 1 << servi;       /* expect reply from this ns */
796
797   q->dnsq_deadline = now +
798     (dns_find_serv(ctx, q) ? 1 : ctx->dnsc_timeout << q->dnsq_try);
799
800   /* move the query to the proper place, according to the new deadline */
801   qlist_remove(q);
802   { /* insert from the tail */
803     struct dns_query *p;
804     QLIST_FOR_EACH(&ctx->dnsc_qactive, p, prev)
805       if (p->dnsq_deadline <= q->dnsq_deadline)
806         break;
807     qlist_insert_after(q, p);
808   }
809
810   return 0;
811 }
812
813 /* send the query out using next available server
814  * and add it to the active list, or, if no servers available,
815  * end it.
816  */
817 static void
818 dns_send(struct dns_ctx *ctx, struct dns_query *q, time_t now) {
819
820   /* if we can't send the query, return TEMPFAIL even when searching:
821    * we can't be sure whenever the name we tried to search exists or not,
822    * so don't continue searching, or we may find the wrong name. */
823
824   if (!dns_find_serv(ctx, q)) {
825     /* no more servers in this iteration.  Try the next cycle */
826     q->dnsq_servi = 0;  /* reset */
827     q->dnsq_try++;      /* next try */
828     if (q->dnsq_try >= ctx->dnsc_ntries ||
829         !dns_find_serv(ctx, q)) {
830       /* no more servers and tries, fail the query */
831       /* return TEMPFAIL even when searching: no more tries for this
832        * searchlist, and no single definitive reply (handled in dns_ioevent()
833        * in NOERROR or NXDOMAIN cases) => all nameservers failed to process
834        * current search list element, so we don't know whenever the name exists.
835        */
836       dns_end_query(ctx, q, DNS_E_TEMPFAIL, 0);
837       return;
838     }
839   }
840
841   dns_send_this(ctx, q, q->dnsq_servi++, now);
842 }
843
844 static void dns_dummy_cb(struct dns_ctx *ctx, void *result, void *data) {
845   if (result) free(result);
846 }
847
848 /* The (only, main, real) query submission routine.
849  * Allocate new query structure, initialize it, check validity of
850  * parameters, and add it to the head of the active list, without
851  * trying to send it (to be picked up on next event).
852  * Error return (without calling the callback routine) -
853  *  no memory or wrong parameters.
854  *XXX The `no memory' case probably should go to the callback anyway...
855  */
856 struct dns_query *
857 dns_submit_dn(struct dns_ctx *ctx,
858               dnscc_t *dn, int qcls, int qtyp, int flags,
859               dns_parse_fn *parse, dns_query_fn *cbck, void *data) {
860   struct dns_query *q;
861   SETCTXOPEN(ctx);
862   dns_assert_ctx(ctx);
863
864   q = calloc(sizeof(*q), 1);
865   if (!q) {
866     ctx->dnsc_qstatus = DNS_E_NOMEM;
867     return NULL;
868   }
869
870 #ifndef NDEBUG
871   q->dnsq_ctx = ctx;
872 #endif
873   q->dnsq_parse = parse;
874   q->dnsq_cbck = cbck ? cbck : dns_dummy_cb;
875   q->dnsq_cbdata = data;
876
877   q->dnsq_origdnl0 = dns_dntodn(dn, q->dnsq_dn, sizeof(q->dnsq_dn));
878   assert(q->dnsq_origdnl0 > 0);
879   --q->dnsq_origdnl0;           /* w/o the trailing 0 */
880   dns_put16(q->dnsq_typcls+0, qtyp);
881   dns_put16(q->dnsq_typcls+2, qcls);
882   q->dnsq_flags = (flags | ctx->dnsc_flags) & ~DNS_INTERNAL;
883
884   if (flags & DNS_NOSRCH ||
885       dns_dnlabels(q->dnsq_dn) > ctx->dnsc_ndots) {
886     q->dnsq_nxtsrch = flags & DNS_NOSRCH ?
887       ctx->dnsc_srchend /* end of the search list if no search requested */ :
888       ctx->dnsc_srchbuf /* beginning of the list, but try as-is first */;
889     q->dnsq_flags |= DNS_ASIS_DONE;
890     dns_newid(ctx, q);
891   }
892   else {
893     q->dnsq_nxtsrch = ctx->dnsc_srchbuf;
894     dns_next_srch(ctx, q);
895   }
896
897   qlist_add_head(q, &ctx->dnsc_qactive);
898   ++ctx->dnsc_nactive;
899   dns_request_utm(ctx, 0);
900
901   return q;
902 }
903
904 struct dns_query *
905 dns_submit_p(struct dns_ctx *ctx,
906              const char *name, int qcls, int qtyp, int flags,
907              dns_parse_fn *parse, dns_query_fn *cbck, void *data) {
908   int isabs;
909   SETCTXOPEN(ctx);
910   if (dns_ptodn(name, 0, ctx->dnsc_pbuf, DNS_MAXDN, &isabs) <= 0) {
911     ctx->dnsc_qstatus = DNS_E_BADQUERY;
912     return NULL;
913   }
914   if (isabs)
915     flags |= DNS_NOSRCH;
916   return
917     dns_submit_dn(ctx, ctx->dnsc_pbuf, qcls, qtyp, flags, parse, cbck, data);
918 }
919
920 /* process readable fd condition.
921  * To be usable in edge-triggered environment, the routine
922  * should consume all input so it should loop over.
923  * Note it isn't really necessary to loop here, because
924  * an application may perform the loop just fine by it's own,
925  * but in this case we should return some sensitive result,
926  * to indicate when to stop calling and error conditions.
927  * Note also we may encounter all sorts of recvfrom()
928  * errors which aren't fatal, and at the same time we may
929  * loop forever if an error IS fatal.
930  */
931 void dns_ioevent(struct dns_ctx *ctx, time_t now) {
932   int r;
933   unsigned servi;
934   struct dns_query *q;
935   dnsc_t *pbuf;
936   dnscc_t *pend, *pcur;
937   void *result;
938   union sockaddr_ns sns;
939   socklen_t slen;
940
941   SETCTX(ctx);
942   if (!CTXOPEN(ctx))
943     return;
944   dns_assert_ctx(ctx);
945   pbuf = ctx->dnsc_pbuf;
946
947   if (!now) now = time(NULL);
948
949 again: /* receive the reply */
950
951   if (!CTXOPEN(ctx))
952     return;
953   slen = sizeof(sns);
954   r = recvfrom(ctx->dnsc_udpsock, (void*)pbuf, ctx->dnsc_udpbuf,
955                MSG_DONTWAIT, &sns.sa, &slen);
956   if (r < 0) {
957     /*XXX just ignore recvfrom() errors for now.
958      * in the future it may be possible to determine which
959      * query failed and requeue it.
960      * Note there may be various error conditions, triggered
961      * by both local problems and remote problems.  It isn't
962      * quite trivial to determine whenever an error is local
963      * or remote.  On local errors, we should stop, while
964      * remote errors should be ignored (for now anyway).
965      */
966 #ifdef WINDOWS
967     if (WSAGetLastError() == WSAEWOULDBLOCK)
968 #else
969     if (errno == EAGAIN)
970 #endif
971     {
972       dns_request_utm(ctx, now);
973       return;
974     }
975     goto again;
976   }
977
978   pend = pbuf + r;
979   pcur = dns_payload(pbuf);
980
981   /* check reply header */
982   if (pcur > pend || dns_numqd(pbuf) > 1 || dns_opcode(pbuf) != 0) {
983     DNS_DBG(ctx, -1/*bad reply*/, &sns.sa, slen, pbuf, r);
984     goto again;
985   }
986
987   /* find the matching query, by qID */
988   for (q = QLIST_FIRST(&ctx->dnsc_qactive, next);; q = QLIST_NEXT(q, next)) {
989     if (QLIST_ISLAST(&ctx->dnsc_qactive, q)) {
990       /* no more requests: old reply? */
991       DNS_DBG(ctx, -5/*no matching query*/, &sns.sa, slen, pbuf, r);
992       goto again;
993     }
994     if (pbuf[DNS_H_QID1] == q->dnsq_id[0] &&
995         pbuf[DNS_H_QID2] == q->dnsq_id[1])
996       break;
997   }
998
999   /* if we have numqd, compare with our query qDN */
1000   if (dns_numqd(pbuf)) {
1001     /* decode the qDN */
1002     dnsc_t dn[DNS_MAXDN];
1003     if (dns_getdn(pbuf, &pcur, pend, dn, sizeof(dn)) < 0 ||
1004         pcur + 4 > pend) {
1005       DNS_DBG(ctx, -1/*bad reply*/, &sns.sa, slen, pbuf, r);
1006       goto again;
1007     }
1008     if (!dns_dnequal(dn, q->dnsq_dn) ||
1009         memcmp(pcur, q->dnsq_typcls, 4) != 0) {
1010       /* not this query */
1011       DNS_DBG(ctx, -5/*no matching query*/, &sns.sa, slen, pbuf, r);
1012       goto again;
1013     }
1014     /* here, query match, and pcur points past qDN in query section in pbuf */
1015   }
1016   /* if no numqd, we only allow FORMERR rcode */
1017   else if (dns_rcode(pbuf) != DNS_R_FORMERR) {
1018     /* treat it as bad reply if !FORMERR */
1019     DNS_DBG(ctx, -1/*bad reply*/, &sns.sa, slen, pbuf, r);
1020     goto again;
1021   }
1022   else {
1023     /* else it's FORMERR, handled below */
1024   }
1025
1026   /* find server */
1027 #ifdef HAVE_IPv6
1028   if (sns.sa.sa_family == AF_INET6 && slen >= sizeof(sns.sin6)) {
1029     for(servi = 0; servi < ctx->dnsc_nserv; ++servi)
1030       if (sin6_eq(ctx->dnsc_serv[servi].sin6, sns.sin6))
1031         break;
1032   }
1033   else
1034 #endif
1035   if (sns.sa.sa_family == AF_INET && slen >= sizeof(sns.sin)) {
1036     for(servi = 0; servi < ctx->dnsc_nserv; ++servi)
1037       if (sin_eq(ctx->dnsc_serv[servi].sin, sns.sin))
1038         break;
1039   }
1040   else
1041     servi = ctx->dnsc_nserv;
1042
1043   /* check if we expect reply from this server.
1044    * Note we can receive reply from first try if we're already at next */
1045   if (!(q->dnsq_servwait & (1 << servi))) { /* if ever asked this NS */
1046     DNS_DBG(ctx, -2/*wrong server*/, &sns.sa, slen, pbuf, r);
1047     goto again;
1048   }
1049
1050   /* we got (some) reply for our query */
1051
1052   DNS_DBGQ(ctx, q, 0, &sns.sa, slen, pbuf, r);
1053   q->dnsq_servwait &= ~(1 << servi);    /* don't expect reply from this serv */
1054
1055   /* process the RCODE */
1056   switch(dns_rcode(pbuf)) {
1057
1058   case DNS_R_NOERROR:
1059     if (dns_tc(pbuf)) {
1060       /* possible truncation.  We can't deal with it. */
1061       /*XXX for now, treat TC bit the same as SERVFAIL.
1062        * It is possible to:
1063        *  a) try to decode the reply - may be ANSWER section is ok;
1064        *  b) check if server understands EDNS0, and if it is, and
1065        *   answer still don't fit, end query.
1066        */
1067       break;
1068     }
1069     if (!dns_numan(pbuf)) {     /* no data of requested type */
1070       if (dns_next_srch(ctx, q)) {
1071         /* if we're searching, try next searchlist element,
1072          * but remember NODATA reply. */
1073         q->dnsq_flags |= DNS_SEEN_NODATA;
1074         dns_send(ctx, q, now);
1075       }
1076       else
1077         /* else - nothing to search any more - finish the query.
1078          * It will be NODATA since we've seen a NODATA reply. */
1079         dns_end_query(ctx, q, DNS_E_NODATA, 0);
1080     }
1081     /* we've got a positive reply here */
1082     else if (q->dnsq_parse) {
1083       /* if we have parsing routine, call it and return whatever it returned */
1084       /* don't try to re-search if NODATA here.  For example,
1085        * if we asked for A but only received CNAME.  Unless we'll
1086        * someday do recursive queries.  And that's problematic too, since
1087        * we may be dealing with specific AA-only nameservers for a given
1088        * domain, but CNAME points elsewhere...
1089        */
1090       r = q->dnsq_parse(q->dnsq_dn, pbuf, pcur, pend, &result);
1091       dns_end_query(ctx, q, r, r < 0 ? NULL : result);
1092     }
1093     /* else just malloc+copy the raw DNS reply */
1094     else if ((result = malloc(r)) == NULL)
1095       dns_end_query(ctx, q, DNS_E_NOMEM, NULL);
1096     else {
1097       memcpy(result, pbuf, r);
1098       dns_end_query(ctx, q, r, result);
1099     }
1100     goto again;
1101
1102   case DNS_R_NXDOMAIN:  /* Non-existing domain. */
1103     if (dns_next_srch(ctx, q))
1104       /* more search entries exists, try them. */
1105       dns_send(ctx, q, now);
1106     else
1107       /* nothing to search anymore. End the query, returning either NODATA
1108        * if we've seen it before, or NXDOMAIN if not. */
1109       dns_end_query(ctx, q,
1110            q->dnsq_flags & DNS_SEEN_NODATA ? DNS_E_NODATA : DNS_E_NXDOMAIN, 0);
1111     goto again;
1112
1113   case DNS_R_FORMERR:
1114   case DNS_R_NOTIMPL:
1115     /* for FORMERR and NOTIMPL rcodes, if we tried EDNS0-enabled query,
1116      * try w/o EDNS0. */
1117     if (ctx->dnsc_udpbuf > DNS_MAXPACKET &&
1118         !(q->dnsq_servnEDNS0 & (1 << servi))) {
1119       /* we always trying EDNS0 first if enabled, and retry a given query
1120        * if not available. Maybe it's better to remember inavailability of
1121        * EDNS0 in ctx as a per-NS flag, and never try again for this NS.
1122        * For long-running applications.. maybe they will change the nameserver
1123        * while we're running? :)  Also, since FORMERR is the only rcode we
1124        * allow to be header-only, and in this case the only check we do to
1125        * find a query it belongs to is qID (not qDN+qCLS+qTYP), it's much
1126        * easier to spoof and to force us to perform non-EDNS0 queries only...
1127        */
1128       q->dnsq_servnEDNS0 |= 1 << servi;
1129       dns_send_this(ctx, q, servi, now);
1130       goto again;
1131     }
1132     /* else we handle it the same as SERVFAIL etc */
1133
1134   case DNS_R_SERVFAIL:
1135   case DNS_R_REFUSED:
1136     /* for these rcodes, advance this request
1137      * to the next server and reschedule */
1138   default: /* unknown rcode? hmmm... */
1139     break;
1140   }
1141
1142   /* here, we received unexpected reply */
1143   q->dnsq_servskip |= (1 << servi);     /* don't retry this server */
1144
1145   /* we don't expect replies from this server anymore.
1146    * But there may be other servers.  Some may be still processing our
1147    * query, and some may be left to try.
1148    * We just ignore this reply and wait a bit more if some NSes haven't
1149    * replied yet (dnsq_servwait != 0), and let the situation to be handled
1150    * on next event processing.  Timeout for this query is set correctly,
1151    * if not taking into account the one-second difference - we can try
1152    * next server in the same iteration sooner.
1153    */
1154
1155   /* try next server */
1156   if (!q->dnsq_servwait) {
1157     /* next retry: maybe some other servers will reply next time.
1158      * dns_send() will end the query for us if no more servers to try.
1159      * Note we can't continue with the next searchlist element here:
1160      * we don't know if the current qdn exists or not, there's no definitive
1161      * answer yet (which is seen in cases above).
1162      *XXX standard resolver also tries as-is query in case all nameservers
1163      * failed to process our query and if not tried before.  We don't do it.
1164      */
1165     dns_send(ctx, q, now);
1166   }
1167   else {
1168     /* else don't do anything - not all servers replied yet */
1169   }
1170   goto again;
1171
1172 }
1173
1174 /* handle all timeouts */
1175 int dns_timeouts(struct dns_ctx *ctx, int maxwait, time_t now) {
1176   /* this is a hot routine */
1177   struct dns_query *q;
1178
1179   SETCTX(ctx);
1180   dns_assert_ctx(ctx);
1181
1182   /* Pick up first entry from query list.
1183    * If its deadline has passed, (re)send it
1184    * (dns_send() will move it next in the list).
1185    * If not, this is the query which determines the closest deadline.
1186    */
1187
1188   q = qlist_first(&ctx->dnsc_qactive);
1189   if (!q)
1190     return maxwait;
1191   if (!now)
1192     now = time(NULL);
1193   do {
1194     if (q->dnsq_deadline > now) { /* first non-expired query */
1195       int w = (int)(q->dnsq_deadline - now);
1196       if (maxwait < 0 || maxwait > w)
1197         maxwait = w;
1198       break;
1199     }
1200     else {
1201       /* process expired deadline */
1202       dns_send(ctx, q, now);
1203     }
1204   } while((q = qlist_first(&ctx->dnsc_qactive)) != NULL);
1205
1206   dns_request_utm(ctx, now); /* update timer with new deadline */
1207   return maxwait;
1208 }
1209
1210 struct dns_resolve_data {
1211   int   dnsrd_done;
1212   void *dnsrd_result;
1213 };
1214
1215 static void dns_resolve_cb(struct dns_ctx *ctx, void *result, void *data) {
1216   struct dns_resolve_data *d = data;
1217   d->dnsrd_result = result;
1218   d->dnsrd_done = 1;
1219   ctx = ctx;
1220 }
1221
1222 void *dns_resolve(struct dns_ctx *ctx, struct dns_query *q) {
1223   time_t now;
1224   struct dns_resolve_data d;
1225   int n;
1226   SETCTXOPEN(ctx);
1227
1228   if (!q)
1229     return NULL;
1230
1231   assert(ctx == q->dnsq_ctx);
1232   dns_assert_ctx(ctx);
1233   /* do not allow re-resolving syncronous queries */
1234   assert(q->dnsq_cbck != dns_resolve_cb && "can't resolve syncronous query");
1235   if (q->dnsq_cbck == dns_resolve_cb) {
1236     ctx->dnsc_qstatus = DNS_E_BADQUERY;
1237     return NULL;
1238   }
1239   q->dnsq_cbck = dns_resolve_cb;
1240   q->dnsq_cbdata = &d;
1241   d.dnsrd_done = 0;
1242
1243   now = time(NULL);
1244   while(!d.dnsrd_done && (n = dns_timeouts(ctx, -1, now)) >= 0) {
1245 #ifdef HAVE_POLL
1246     struct pollfd pfd;
1247     pfd.fd = ctx->dnsc_udpsock;
1248     pfd.events = POLLIN;
1249     n = poll(&pfd, 1, n * 1000);
1250 #else
1251     fd_set rfd;
1252     struct timeval tv;
1253     FD_ZERO(&rfd);
1254     FD_SET(ctx->dnsc_udpsock, &rfd);
1255     tv.tv_sec = n; tv.tv_usec = 0;
1256     n = select(ctx->dnsc_udpsock + 1, &rfd, NULL, NULL, &tv);
1257 #endif
1258     now = time(NULL);
1259     if (n > 0)
1260       dns_ioevent(ctx, now);
1261   }
1262
1263   return d.dnsrd_result;
1264 }
1265
1266 void *dns_resolve_dn(struct dns_ctx *ctx,
1267                      dnscc_t *dn, int qcls, int qtyp, int flags,
1268                      dns_parse_fn *parse) {
1269   return
1270     dns_resolve(ctx,
1271       dns_submit_dn(ctx, dn, qcls, qtyp, flags, parse, NULL, NULL));
1272 }
1273
1274 void *dns_resolve_p(struct dns_ctx *ctx,
1275                     const char *name, int qcls, int qtyp, int flags,
1276                     dns_parse_fn *parse) {
1277   return
1278     dns_resolve(ctx,
1279       dns_submit_p(ctx, name, qcls, qtyp, flags, parse, NULL, NULL));
1280 }
1281
1282 int dns_cancel(struct dns_ctx *ctx, struct dns_query *q) {
1283   SETCTX(ctx);
1284   dns_assert_ctx(ctx);
1285   assert(q->dnsq_ctx == ctx);
1286   /* do not allow cancelling syncronous queries */
1287   assert(q->dnsq_cbck != dns_resolve_cb && "can't cancel syncronous query");
1288   if (q->dnsq_cbck == dns_resolve_cb)
1289     return (ctx->dnsc_qstatus = DNS_E_BADQUERY);
1290   qlist_remove(q);
1291   --ctx->dnsc_nactive;
1292   dns_request_utm(ctx, 0);
1293   return 0;
1294 }
1295
Note: See TracBrowser for help on using the browser.