root/src/udns/udns_resolver.c

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

fixes #70

  • 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   data = ctx = 0;       /* used */
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   slen = sizeof(sns);
953   r = recvfrom(ctx->dnsc_udpsock, (void*)pbuf, ctx->dnsc_udpbuf,
954                MSG_DONTWAIT, &sns.sa, &slen);
955   if (r < 0) {
956     /*XXX just ignore recvfrom() errors for now.
957      * in the future it may be possible to determine which
958      * query failed and requeue it.
959      * Note there may be various error conditions, triggered
960      * by both local problems and remote problems.  It isn't
961      * quite trivial to determine whenever an error is local
962      * or remote.  On local errors, we should stop, while
963      * remote errors should be ignored (for now anyway).
964      */
965 #ifdef WINDOWS
966     if (WSAGetLastError() == WSAEWOULDBLOCK)
967 #else
968     if (errno == EAGAIN)
969 #endif
970     {
971       dns_request_utm(ctx, now);
972       return;
973     }
974     goto again;
975   }
976
977   pend = pbuf + r;
978   pcur = dns_payload(pbuf);
979
980   /* check reply header */
981   if (pcur > pend || dns_numqd(pbuf) > 1 || dns_opcode(pbuf) != 0) {
982     DNS_DBG(ctx, -1/*bad reply*/, &sns.sa, slen, pbuf, r);
983     goto again;
984   }
985
986   /* find the matching query, by qID */
987   for (q = QLIST_FIRST(&ctx->dnsc_qactive, next);; q = QLIST_NEXT(q, next)) {
988     if (QLIST_ISLAST(&ctx->dnsc_qactive, q)) {
989       /* no more requests: old reply? */
990       DNS_DBG(ctx, -5/*no matching query*/, &sns.sa, slen, pbuf, r);
991       goto again;
992     }
993     if (pbuf[DNS_H_QID1] == q->dnsq_id[0] &&
994         pbuf[DNS_H_QID2] == q->dnsq_id[1])
995       break;
996   }
997
998   /* if we have numqd, compare with our query qDN */
999   if (dns_numqd(pbuf)) {
1000     /* decode the qDN */
1001     dnsc_t dn[DNS_MAXDN];
1002     if (dns_getdn(pbuf, &pcur, pend, dn, sizeof(dn)) < 0 ||
1003         pcur + 4 > pend) {
1004       DNS_DBG(ctx, -1/*bad reply*/, &sns.sa, slen, pbuf, r);
1005       goto again;
1006     }
1007     if (!dns_dnequal(dn, q->dnsq_dn) ||
1008         memcmp(pcur, q->dnsq_typcls, 4) != 0) {
1009       /* not this query */
1010       DNS_DBG(ctx, -5/*no matching query*/, &sns.sa, slen, pbuf, r);
1011       goto again;
1012     }
1013     /* here, query match, and pcur points past qDN in query section in pbuf */
1014   }
1015   /* if no numqd, we only allow FORMERR rcode */
1016   else if (dns_rcode(pbuf) != DNS_R_FORMERR) {
1017     /* treat it as bad reply if !FORMERR */
1018     DNS_DBG(ctx, -1/*bad reply*/, &sns.sa, slen, pbuf, r);
1019     goto again;
1020   }
1021   else {
1022     /* else it's FORMERR, handled below */
1023   }
1024
1025   /* find server */
1026 #ifdef HAVE_IPv6
1027   if (sns.sa.sa_family == AF_INET6 && slen >= sizeof(sns.sin6)) {
1028     for(servi = 0; servi < ctx->dnsc_nserv; ++servi)
1029       if (sin6_eq(ctx->dnsc_serv[servi].sin6, sns.sin6))
1030         break;
1031   }
1032   else
1033 #endif
1034   if (sns.sa.sa_family == AF_INET && slen >= sizeof(sns.sin)) {
1035     for(servi = 0; servi < ctx->dnsc_nserv; ++servi)
1036       if (sin_eq(ctx->dnsc_serv[servi].sin, sns.sin))
1037         break;
1038   }
1039   else
1040     servi = ctx->dnsc_nserv;
1041
1042   /* check if we expect reply from this server.
1043    * Note we can receive reply from first try if we're already at next */
1044   if (!(q->dnsq_servwait & (1 << servi))) { /* if ever asked this NS */
1045     DNS_DBG(ctx, -2/*wrong server*/, &sns.sa, slen, pbuf, r);
1046     goto again;
1047   }
1048
1049   /* we got (some) reply for our query */
1050
1051   DNS_DBGQ(ctx, q, 0, &sns.sa, slen, pbuf, r);
1052   q->dnsq_servwait &= ~(1 << servi);    /* don't expect reply from this serv */
1053
1054   /* process the RCODE */
1055   switch(dns_rcode(pbuf)) {
1056
1057   case DNS_R_NOERROR:
1058     if (dns_tc(pbuf)) {
1059       /* possible truncation.  We can't deal with it. */
1060       /*XXX for now, treat TC bit the same as SERVFAIL.
1061        * It is possible to:
1062        *  a) try to decode the reply - may be ANSWER section is ok;
1063        *  b) check if server understands EDNS0, and if it is, and
1064        *   answer still don't fit, end query.
1065        */
1066       break;
1067     }
1068     if (!dns_numan(pbuf)) {     /* no data of requested type */
1069       if (dns_next_srch(ctx, q)) {
1070         /* if we're searching, try next searchlist element,
1071          * but remember NODATA reply. */
1072         q->dnsq_flags |= DNS_SEEN_NODATA;
1073         dns_send(ctx, q, now);
1074       }
1075       else
1076         /* else - nothing to search any more - finish the query.
1077          * It will be NODATA since we've seen a NODATA reply. */
1078         dns_end_query(ctx, q, DNS_E_NODATA, 0);
1079     }
1080     /* we've got a positive reply here */
1081     else if (q->dnsq_parse) {
1082       /* if we have parsing routine, call it and return whatever it returned */
1083       /* don't try to re-search if NODATA here.  For example,
1084        * if we asked for A but only received CNAME.  Unless we'll
1085        * someday do recursive queries.  And that's problematic too, since
1086        * we may be dealing with specific AA-only nameservers for a given
1087        * domain, but CNAME points elsewhere...
1088        */
1089       r = q->dnsq_parse(q->dnsq_dn, pbuf, pcur, pend, &result);
1090       dns_end_query(ctx, q, r, r < 0 ? NULL : result);
1091     }
1092     /* else just malloc+copy the raw DNS reply */
1093     else if ((result = malloc(r)) == NULL)
1094       dns_end_query(ctx, q, DNS_E_NOMEM, NULL);
1095     else {
1096       memcpy(result, pbuf, r);
1097       dns_end_query(ctx, q, r, result);
1098     }
1099     goto again;
1100
1101   case DNS_R_NXDOMAIN:  /* Non-existing domain. */
1102     if (dns_next_srch(ctx, q))
1103       /* more search entries exists, try them. */
1104       dns_send(ctx, q, now);
1105     else
1106       /* nothing to search anymore. End the query, returning either NODATA
1107        * if we've seen it before, or NXDOMAIN if not. */
1108       dns_end_query(ctx, q,
1109            q->dnsq_flags & DNS_SEEN_NODATA ? DNS_E_NODATA : DNS_E_NXDOMAIN, 0);
1110     goto again;
1111
1112   case DNS_R_FORMERR:
1113   case DNS_R_NOTIMPL:
1114     /* for FORMERR and NOTIMPL rcodes, if we tried EDNS0-enabled query,
1115      * try w/o EDNS0. */
1116     if (ctx->dnsc_udpbuf > DNS_MAXPACKET &&
1117         !(q->dnsq_servnEDNS0 & (1 << servi))) {
1118       /* we always trying EDNS0 first if enabled, and retry a given query
1119        * if not available. Maybe it's better to remember inavailability of
1120        * EDNS0 in ctx as a per-NS flag, and never try again for this NS.
1121        * For long-running applications.. maybe they will change the nameserver
1122        * while we're running? :)  Also, since FORMERR is the only rcode we
1123        * allow to be header-only, and in this case the only check we do to
1124        * find a query it belongs to is qID (not qDN+qCLS+qTYP), it's much
1125        * easier to spoof and to force us to perform non-EDNS0 queries only...
1126        */
1127       q->dnsq_servnEDNS0 |= 1 << servi;
1128       dns_send_this(ctx, q, servi, now);
1129       goto again;
1130     }
1131     /* else we handle it the same as SERVFAIL etc */
1132
1133   case DNS_R_SERVFAIL:
1134   case DNS_R_REFUSED:
1135     /* for these rcodes, advance this request
1136      * to the next server and reschedule */
1137   default: /* unknown rcode? hmmm... */
1138     break;
1139   }
1140
1141   /* here, we received unexpected reply */
1142   q->dnsq_servskip |= (1 << servi);     /* don't retry this server */
1143
1144   /* we don't expect replies from this server anymore.
1145    * But there may be other servers.  Some may be still processing our
1146    * query, and some may be left to try.
1147    * We just ignore this reply and wait a bit more if some NSes haven't
1148    * replied yet (dnsq_servwait != 0), and let the situation to be handled
1149    * on next event processing.  Timeout for this query is set correctly,
1150    * if not taking into account the one-second difference - we can try
1151    * next server in the same iteration sooner.
1152    */
1153
1154   /* try next server */
1155   if (!q->dnsq_servwait) {
1156     /* next retry: maybe some other servers will reply next time.
1157      * dns_send() will end the query for us if no more servers to try.
1158      * Note we can't continue with the next searchlist element here:
1159      * we don't know if the current qdn exists or not, there's no definitive
1160      * answer yet (which is seen in cases above).
1161      *XXX standard resolver also tries as-is query in case all nameservers
1162      * failed to process our query and if not tried before.  We don't do it.
1163      */
1164     dns_send(ctx, q, now);
1165   }
1166   else {
1167     /* else don't do anything - not all servers replied yet */
1168   }
1169   goto again;
1170
1171 }
1172
1173 /* handle all timeouts */
1174 int dns_timeouts(struct dns_ctx *ctx, int maxwait, time_t now) {
1175   /* this is a hot routine */
1176   struct dns_query *q;
1177
1178   SETCTX(ctx);
1179   dns_assert_ctx(ctx);
1180
1181   /* Pick up first entry from query list.
1182    * If its deadline has passed, (re)send it
1183    * (dns_send() will move it next in the list).
1184    * If not, this is the query which determines the closest deadline.
1185    */
1186
1187   q = qlist_first(&ctx->dnsc_qactive);
1188   if (!q)
1189     return maxwait;
1190   if (!now)
1191     now = time(NULL);
1192   do {
1193     if (q->dnsq_deadline > now) { /* first non-expired query */
1194       int w = (int)(q->dnsq_deadline - now);
1195       if (maxwait < 0 || maxwait > w)
1196         maxwait = w;
1197       break;
1198     }
1199     else {
1200       /* process expired deadline */
1201       dns_send(ctx, q, now);
1202     }
1203   } while((q = qlist_first(&ctx->dnsc_qactive)) != NULL);
1204
1205   dns_request_utm(ctx, now); /* update timer with new deadline */
1206   return maxwait;
1207 }
1208
1209 struct dns_resolve_data {
1210   int   dnsrd_done;
1211   void *dnsrd_result;
1212 };
1213
1214 static void dns_resolve_cb(struct dns_ctx *ctx, void *result, void *data) {
1215   struct dns_resolve_data *d = data;
1216   d->dnsrd_result = result;
1217   d->dnsrd_done = 1;
1218   ctx = ctx;
1219 }
1220
1221 void *dns_resolve(struct dns_ctx *ctx, struct dns_query *q) {
1222   time_t now;
1223   struct dns_resolve_data d;
1224   int n;
1225   SETCTXOPEN(ctx);
1226
1227   if (!q)
1228     return NULL;
1229
1230   assert(ctx == q->dnsq_ctx);
1231   dns_assert_ctx(ctx);
1232   /* do not allow re-resolving syncronous queries */
1233   assert(q->dnsq_cbck != dns_resolve_cb && "can't resolve syncronous query");
1234   if (q->dnsq_cbck == dns_resolve_cb) {
1235     ctx->dnsc_qstatus = DNS_E_BADQUERY;
1236     return NULL;
1237   }
1238   q->dnsq_cbck = dns_resolve_cb;
1239   q->dnsq_cbdata = &d;
1240   d.dnsrd_done = 0;
1241
1242   now = time(NULL);
1243   while(!d.dnsrd_done && (n = dns_timeouts(ctx, -1, now)) >= 0) {
1244 #ifdef HAVE_POLL
1245     struct pollfd pfd;
1246     pfd.fd = ctx->dnsc_udpsock;
1247     pfd.events = POLLIN;
1248     n = poll(&pfd, 1, n * 1000);
1249 #else
1250     fd_set rfd;
1251     struct timeval tv;
1252     FD_ZERO(&rfd);
1253     FD_SET(ctx->dnsc_udpsock, &rfd);
1254     tv.tv_sec = n; tv.tv_usec = 0;
1255     n = select(ctx->dnsc_udpsock + 1, &rfd, NULL, NULL, &tv);
1256 #endif
1257     now = time(NULL);
1258     if (n > 0)
1259       dns_ioevent(ctx, now);
1260   }
1261
1262   return d.dnsrd_result;
1263 }
1264
1265 void *dns_resolve_dn(struct dns_ctx *ctx,
1266                      dnscc_t *dn, int qcls, int qtyp, int flags,
1267                      dns_parse_fn *parse) {
1268   return
1269     dns_resolve(ctx,
1270       dns_submit_dn(ctx, dn, qcls, qtyp, flags, parse, NULL, NULL));
1271 }
1272
1273 void *dns_resolve_p(struct dns_ctx *ctx,
1274                     const char *name, int qcls, int qtyp, int flags,
1275                     dns_parse_fn *parse) {
1276   return
1277     dns_resolve(ctx,
1278       dns_submit_p(ctx, name, qcls, qtyp, flags, parse, NULL, NULL));
1279 }
1280
1281 int dns_cancel(struct dns_ctx *ctx, struct dns_query *q) {
1282   SETCTX(ctx);
1283   dns_assert_ctx(ctx);
1284   assert(q->dnsq_ctx == ctx);
1285   /* do not allow cancelling syncronous queries */
1286   assert(q->dnsq_cbck != dns_resolve_cb && "can't cancel syncronous query");
1287   if (q->dnsq_cbck == dns_resolve_cb)
1288     return (ctx->dnsc_qstatus = DNS_E_BADQUERY);
1289   qlist_remove(q);
1290   --ctx->dnsc_nactive;
1291   dns_request_utm(ctx, 0);
1292   return 0;
1293 }
1294
Note: See TracBrowser for help on using the browser.