root/src/udns/dnsget.c

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

svn merge -r 327:330 https://labs.omniti.com/reconnoiter/branches/dev/udns .

closes #38

  • Property mode set to 100644
Line 
1 /* $Id: dnsget.c,v 1.31 2007/01/08 01:14:44 mjt Exp $
2    simple host/dig-like application using UDNS library
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 <windows.h>
29 #include <winsock2.h>
30 #else
31 #include <sys/types.h>
32 #include <sys/socket.h>
33 #include <netinet/in.h>
34 #include <sys/time.h>
35 #include <unistd.h>
36 #endif
37 #include <time.h>
38 #include <stdarg.h>
39 #include <errno.h>
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include "udns.h"
44
45 #ifndef HAVE_GETOPT
46 # include "getopt.c"
47 #endif
48
49 #ifndef AF_INET6
50 # define AF_INET6 10
51 #endif
52
53 static char *progname;
54 static int verbose = 1;
55 static int errors;
56 static int notfound;
57
58 /* verbosity level:
59  * <0 - bare result
60  *  0 - bare result and error messages
61  *  1 - readable result
62  *  2 - received packet contents and `trying ...' stuff
63  *  3 - sent and received packet contents
64  */
65
66 static void die(int errnum, const char *fmt, ...) {
67   va_list ap;
68   fprintf(stderr, "%s: ", progname);
69   va_start(ap, fmt); vfprintf(stderr, fmt, ap); va_end(ap);
70   if (errnum) fprintf(stderr, ": %s\n", strerror(errnum));
71   else putc('\n', stderr);
72   fflush(stderr);
73   exit(1);
74 }
75
76 static const char *dns_xntop(int af, const void *src) {
77   static char buf[6*5+4*4];
78   return dns_ntop(af, src, buf, sizeof(buf));
79 }
80
81 struct query {
82   const char *name;             /* original query string */
83   unsigned char *dn;            /* the DN being looked up */
84   enum dns_type qtyp;           /* type of the query */
85 };
86
87 static void query_free(struct query *q) {
88   free(q->dn);
89   free(q);
90 }
91
92 static struct query *
93 query_new(const char *name, const unsigned char *dn, enum dns_type qtyp) {
94   struct query *q = malloc(sizeof(*q));
95   unsigned l = dns_dnlen(dn);
96   unsigned char *cdn = malloc(l);
97   if (!q || !cdn) die(0, "out of memory");
98   memcpy(cdn, dn, l);
99   q->name = name;
100   q->dn = cdn;
101   q->qtyp = qtyp;
102   return q;
103 }
104
105 static enum dns_class qcls = DNS_C_IN;
106
107 static void
108 dnserror(struct query *q, int errnum) {
109   if (verbose >= 0)
110     fprintf(stderr, "%s: unable to lookup %s record for %s: %s\n", progname,
111             dns_typename(q->qtyp), dns_dntosp(q->dn), dns_strerror(errnum));
112   if (errnum == DNS_E_NXDOMAIN || errnum == DNS_E_NODATA)
113     ++notfound;
114   else
115     ++errors;
116   query_free(q);
117 }
118
119 static const unsigned char *
120 printtxt(const unsigned char *c) {
121   unsigned n = *c++;
122   const unsigned char *e = c + n;
123   if (verbose > 0) while(c < e) {
124     if (*c < ' ' || *c >= 127) printf("\\%02x", *c);
125     else if (*c == '\\' || *c == '"') printf("\\%c", *c);
126     else putchar(*c);
127     ++c;
128   }
129   else
130    fwrite(c, n, 1, stdout);
131   return e;
132 }
133
134 static void
135 printhex(const unsigned char *c, const unsigned char *e) {
136   while(c < e)
137     printf("%02x", *c++);
138 }
139
140 static unsigned char to_b64[] =
141 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
142
143 static void
144 printb64(const unsigned char *c, const unsigned char *e) {
145   while(c < e) {
146     putchar(to_b64[c[0] >> 2]);
147     if (c+1 < e) {
148       putchar(to_b64[(c[0] & 0x3) << 4 | c[1] >> 4]);
149       if (c+2 < e) {
150         putchar(to_b64[(c[1] & 0xf) << 2 | c[2] >> 6]);
151         putchar(to_b64[c[2] & 0x3f]);
152       }
153       else {
154         putchar(to_b64[(c[1] & 0xf) << 2]);
155         putchar('=');
156         break;
157       }
158     }
159     else {
160       putchar(to_b64[(c[0] & 0x3) << 4]);
161       putchar('=');
162       putchar('=');
163       break;
164     }
165     c += 3;
166   }
167 }
168
169 static void
170 printdate(time_t time) {
171   struct tm *tm = gmtime(&time);
172   printf("%04d%02d%02d%02d%02d%02d",
173     tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
174     tm->tm_hour, tm->tm_min, tm->tm_sec);
175 }
176
177 static void
178 printrr(const struct dns_parse *p, struct dns_rr *rr) {
179   const unsigned char *pkt = p->dnsp_pkt;
180   const unsigned char *end = p->dnsp_end;
181   const unsigned char *dptr = rr->dnsrr_dptr;
182   const unsigned char *dend = rr->dnsrr_dend;
183   unsigned char *dn = rr->dnsrr_dn;
184   const unsigned char *c;
185   unsigned n;
186
187   if (verbose > 0) {
188     if (verbose > 1) {
189       if (!p->dnsp_rrl && !rr->dnsrr_dn[0] && rr->dnsrr_typ == DNS_T_OPT) {
190         printf(";EDNS0 OPT record (UDPsize: %d): %d bytes\n",
191                rr->dnsrr_cls, rr->dnsrr_dsz);
192         return;
193       }
194       n = printf("%s.", dns_dntosp(rr->dnsrr_dn));
195       printf("%s%u\t%s\t%s\t",
196              n > 15 ? "\t" : n > 7 ? "\t\t" : "\t\t\t",
197              rr->dnsrr_ttl,
198              dns_classname(rr->dnsrr_cls),
199              dns_typename(rr->dnsrr_typ));
200     }
201     else
202       printf("%s. %s ", dns_dntosp(rr->dnsrr_dn), dns_typename(rr->dnsrr_typ));
203   }
204
205   switch(rr->dnsrr_typ) {
206
207   case DNS_T_CNAME:
208   case DNS_T_PTR:
209   case DNS_T_NS:
210   case DNS_T_MB:
211   case DNS_T_MD:
212   case DNS_T_MF:
213   case DNS_T_MG:
214   case DNS_T_MR:
215     if (dns_getdn(pkt, &dptr, end, dn, DNS_MAXDN) <= 0) goto xperr;
216     printf("%s.", dns_dntosp(dn));
217     break;
218
219   case DNS_T_A:
220     if (rr->dnsrr_dsz != 4) goto xperr;
221     printf("%d.%d.%d.%d", dptr[0], dptr[1], dptr[2], dptr[3]);
222     break;
223
224   case DNS_T_AAAA:
225     if (rr->dnsrr_dsz != 16) goto xperr;
226     printf("%s", dns_xntop(AF_INET6, dptr));
227     break;
228
229   case DNS_T_MX:
230     c = dptr + 2;
231     if (dns_getdn(pkt, &c, end, dn, DNS_MAXDN) <= 0 || c != dend) goto xperr;
232     printf("%d %s.", dns_get16(dptr), dns_dntosp(dn));
233     break;
234
235   case DNS_T_TXT:
236     /* first verify it */
237     for(c = dptr; c < dend; c += n) {
238       n = *c++;
239       if (c + n > dend) goto xperr;
240     }
241     c = dptr; n = 0;
242     while (c < dend) {
243       if (verbose > 0) printf(n++ ? "\" \"":"\"");
244       c = printtxt(c);
245     }
246     if (verbose > 0) putchar('"');
247     break;
248
249   case DNS_T_HINFO:     /* CPU, OS */
250     c = dptr;
251     n = *c++; if ((c += n) >= dend) goto xperr;
252     n = *c++; if ((c += n) != dend) goto xperr;
253     c = dptr;
254     if (verbose > 0) putchar('"');
255     c = printtxt(c);
256     if (verbose > 0) printf("\" \""); else putchar(' ');
257     printtxt(c);
258     if (verbose > 0) putchar('"');
259     break;
260
261   case DNS_T_WKS:
262     c = dptr;
263     if (dptr + 4 + 2 >= end) goto xperr;
264     printf("%s %d", dns_xntop(AF_INET, dptr), dptr[4]);
265     c = dptr + 5;
266     for (n = 0; c < dend; ++c, n += 8) {
267       if (*c) {
268         unsigned b;
269         for (b = 0; b < 8; ++b)
270           if (*c & (1 << (7-b))) printf(" %d", n + b);
271       }
272     }
273     break;
274
275   case DNS_T_SRV:       /* prio weight port targetDN */
276     c = dptr;
277     c += 2 + 2 + 2;
278     if (dns_getdn(pkt, &c, end, dn, DNS_MAXDN) <= 0 || c != dend) goto xperr;
279     c = dptr;
280     printf("%d %d %d %s.",
281            dns_get16(c+0), dns_get16(c+2), dns_get16(c+4),
282            dns_dntosp(dn));
283     break;
284
285   case DNS_T_NAPTR:     /* order pref flags serv regexp repl */
286     c = dptr;
287     c += 4;     /* order, pref */
288     for (n = 0; n < 3; ++n)
289       if (c >= dend) goto xperr;
290       else c += *c + 1;
291     if (dns_getdn(pkt, &c, end, dn, DNS_MAXDN) <= 0 || c != dend) goto xperr;
292     c = dptr;
293     printf("%u %u", dns_get16(c+0), dns_get16(c+2));
294     c += 4;
295     for(n = 0; n < 3; ++n) {
296       putchar(' ');
297       if (verbose > 0) putchar('"');
298       c = printtxt(c);
299       if (verbose > 0) putchar('"');
300     }
301     printf(" %s.", dns_dntosp(dn));
302     break;
303
304   case DNS_T_KEY: /* flags(2) proto(1) algo(1) pubkey */
305     c = dptr;
306     if (c + 2 + 1 + 1 > dend) goto xperr;
307     printf("%d %d %d", dns_get16(c), c[2], c[3]);
308     c += 2 + 1 + 1;
309     if (c < dend) {
310       putchar(' ');
311       printb64(c, dend);
312     }
313     break;
314
315   case DNS_T_SIG:
316     /* type(2) algo(1) labels(1) ottl(4) sexp(4) sinc(4) tag(2) sdn sig */
317     c = dptr;
318     c += 2 + 1 + 1 + 4 + 4 + 4 + 2;
319     if (dns_getdn(pkt, &c, end, dn, DNS_MAXDN) <= 0) goto xperr;
320     printf("%d %u %u %u ",
321            dns_get16(dptr), dptr[2], dptr[3], dns_get32(dptr+4));
322     printdate(dns_get32(dptr+8));
323     putchar(' ');
324     printdate(dns_get32(dptr+12));
325     printf(" %d %s. ", dns_get16(dptr+10), dns_dntosp(dn));
326     printb64(c, dend);
327     break;
328
329 #if 0   /* unused RR types? */
330   case DNS_T_DS:
331     c = dptr;
332     if (c + 2 + 2 >= dend) goto xperr;
333     printf("%u %u %u ", dns_get16(c), c[2], c[3]);
334     printhex(c + 4, dend);
335     break;
336
337   case DNS_T_NSEC:
338     c = dptr;
339     if (dns_getdn(pkt, &c, end, dn, DNS_MAXDN) <= 0) goto xperr;
340     printf("%s.", dns_dntosp(dn));
341     unfinished.
342     break;
343 #endif
344
345
346   case DNS_T_SOA:
347     c = dptr;
348     if (dns_getdn(pkt, &c, end, dn, DNS_MAXDN) <= 0 ||
349         dns_getdn(pkt, &c, end, dn, DNS_MAXDN) <= 0 ||
350         c + 4*5 != dend)
351       goto xperr;
352     dns_getdn(pkt, &dptr, end, dn, DNS_MAXDN);
353     printf("%s. ", dns_dntosp(dn));
354     dns_getdn(pkt, &dptr, end, dn, DNS_MAXDN);
355     printf("%s. ", dns_dntosp(dn));
356     printf("%u %u %u %u %u",
357            dns_get32(dptr), dns_get32(dptr+4), dns_get32(dptr+8),
358            dns_get32(dptr+12), dns_get32(dptr+16));
359     break;
360
361   case DNS_T_MINFO:
362     c = dptr;
363     if (dns_getdn(pkt, &c, end, dn, DNS_MAXDN) <= 0 ||
364         dns_getdn(pkt, &c, end, dn, DNS_MAXDN) <= 0 ||
365         c != dend)
366       goto xperr;
367     dns_getdn(pkt, &dptr, end, dn, DNS_MAXDN);
368     printf("%s. ", dns_dntosp(dn));
369     dns_getdn(pkt, &dptr, end, dn, DNS_MAXDN);
370     printf("%s.", dns_dntosp(dn));
371     break;
372
373   case DNS_T_NULL:
374   default:
375     printhex(dptr, dend);
376     break;
377   }
378   putchar('\n');
379   return;
380
381 xperr:
382   printf("<parse error>\n");
383   ++errors;
384 }
385
386 static int
387 printsection(struct dns_parse *p, int nrr, const char *sname) {
388   struct dns_rr rr;
389   int r;
390   if (!nrr) return 0;
391   if (verbose > 1) printf("\n;; %s section (%d):\n", sname, nrr);
392
393   p->dnsp_rrl = nrr;
394   while((r = dns_nextrr(p, &rr)) > 0)
395     printrr(p, &rr);
396   if (r < 0) printf("<<ERROR>>\n");
397   return r;
398 }
399
400 /* dbgcb will only be called if verbose > 1 */
401 static void
402 dbgcb(int code, const struct sockaddr *sa, unsigned slen,
403       const unsigned char *pkt, int r,
404       const struct dns_query *unused_q, void *unused_data) {
405   struct dns_parse p;
406   const unsigned char *cur, *end;
407   int numqd;
408
409   if (code > 0) {
410     printf(";; trying %s.\n", dns_dntosp(dns_payload(pkt)));
411     printf(";; sending %d bytes query to ", r);
412   }
413   else
414     printf(";; received %d bytes response from ", r);
415   if (sa->sa_family == AF_INET && slen >= sizeof(struct sockaddr_in))
416     printf("%s port %d\n",
417            dns_xntop(AF_INET, &((struct sockaddr_in*)sa)->sin_addr),
418            htons(((struct sockaddr_in*)sa)->sin_port));
419 #ifdef HAVE_IPv6
420   else if (sa->sa_family == AF_INET6 && slen >= sizeof(struct sockaddr_in6))
421     printf("%s port %d\n",
422            dns_xntop(AF_INET6, &((struct sockaddr_in6*)sa)->sin6_addr),
423            htons(((struct sockaddr_in6*)sa)->sin6_port));
424 #endif
425   else
426     printf("<<unknown socket type %d>>\n", sa->sa_family);
427   if (code > 0 && verbose < 3) {
428     putchar('\n');
429     return;
430   }
431
432   if (code == -2) printf(";; reply from unexpected source\n");
433   if (code == -5) printf(";; reply to a query we didn't sent (or old)\n");
434   if (r < DNS_HSIZE) {
435     printf(";; short packet (%d bytes)\n", r);
436     return;
437   }
438   if (dns_opcode(pkt) != 0)
439     printf(";; unexpected opcode %d\n", dns_opcode(pkt));
440   if (dns_tc(pkt) != 0)
441     printf(";; warning: TC bit set, probably incomplete reply\n");
442
443   printf(";; ->>HEADER<<- opcode: ");
444   switch(dns_opcode(pkt)) {
445   case 0: printf("QUERY"); break;
446   case 1: printf("IQUERY"); break;
447   case 2: printf("STATUS"); break;
448   default: printf("UNKNOWN(%u)", dns_opcode(pkt)); break;
449   }
450   printf(", status: %s, id: %d, size: %d\n;; flags:",
451          dns_rcodename(dns_rcode(pkt)), dns_qid(pkt), r);
452   if (dns_qr(pkt)) printf(" qr");
453   if (dns_rd(pkt)) printf(" rd");
454   if (dns_ra(pkt)) printf(" ra");
455   if (dns_aa(pkt)) printf(" aa");
456   if (dns_tc(pkt)) printf(" tc");
457   numqd = dns_numqd(pkt);
458   printf("; QUERY: %d, ANSWER: %d, AUTHORITY: %d, ADDITIONAL: %d\n",
459          numqd, dns_numan(pkt), dns_numns(pkt), dns_numar(pkt));
460   if (numqd != 1)
461     printf(";; unexpected number of entries in QUERY section: %d\n",
462            numqd);
463   printf("\n;; QUERY SECTION (%d):\n", numqd);
464   cur = dns_payload(pkt);
465   end = pkt + r;
466   while(numqd--) {
467     if (dns_getdn(pkt, &cur, end, p.dnsp_dnbuf, DNS_MAXDN) <= 0 ||
468         cur + 4 > end) {
469       printf("; invalid query section\n");
470       return;
471     }
472     r = printf(";%s.", dns_dntosp(p.dnsp_dnbuf));
473     printf("%s%s\t%s\n",
474            r > 23 ? "\t" : r > 15 ? "\t\t" : r > 7 ? "\t\t\t" : "\t\t\t\t",
475            dns_classname(dns_get16(cur+2)), dns_typename(dns_get16(cur)));
476     cur += 4;
477   }
478
479   p.dnsp_pkt = pkt;
480   p.dnsp_cur = p.dnsp_ans = cur;
481   p.dnsp_end = end;
482   p.dnsp_qdn = NULL;
483   p.dnsp_qcls = p.dnsp_qtyp = 0;
484   p.dnsp_ttl = 0xffffffffu;
485   p.dnsp_nrr = 0;
486
487   r = printsection(&p, dns_numan(pkt), "ANSWER");
488   if (r == 0)
489     r = printsection(&p, dns_numns(pkt), "AUTHORITY");
490   if (r == 0)
491     r = printsection(&p, dns_numar(pkt), "ADDITIONAL");
492   putchar('\n');
493 }
494
495 static void dnscb(struct dns_ctx *ctx, void *result, void *data) {
496   int r = dns_status(ctx);
497   struct query *q = data;
498   struct dns_parse p;
499   struct dns_rr rr;
500   unsigned nrr;
501   unsigned char dn[DNS_MAXDN];
502   const unsigned char *pkt, *cur, *end;
503   if (!result) {
504     dnserror(q, r);
505     return;
506   }
507   pkt = result; end = pkt + r; cur = dns_payload(pkt);
508   dns_getdn(pkt, &cur, end, dn, sizeof(dn));
509   dns_initparse(&p, NULL, pkt, cur, end);
510   p.dnsp_qcls = p.dnsp_qtyp = 0;
511   nrr = 0;
512   while((r = dns_nextrr(&p, &rr)) > 0) {
513     if (!dns_dnequal(dn, rr.dnsrr_dn)) continue;
514     if ((qcls == DNS_C_ANY || qcls == rr.dnsrr_cls) &&
515         (q->qtyp == DNS_T_ANY || q->qtyp == rr.dnsrr_typ))
516       ++nrr;
517     else if (rr.dnsrr_typ == DNS_T_CNAME && !nrr) {
518       if (dns_getdn(pkt, &rr.dnsrr_dptr, end,
519                     p.dnsp_dnbuf, sizeof(p.dnsp_dnbuf)) <= 0 ||
520           rr.dnsrr_dptr != rr.dnsrr_dend) {
521         r = DNS_E_PROTOCOL;
522         break;
523       }
524       else {
525         if (verbose == 1) {
526           printf("%s.", dns_dntosp(dn));
527           printf(" CNAME %s.\n", dns_dntosp(p.dnsp_dnbuf));
528         }
529         dns_dntodn(p.dnsp_dnbuf, dn, sizeof(dn));
530       }
531     }
532   }
533   if (!r && !nrr)
534     r = DNS_E_NODATA;
535   if (r < 0) {
536     dnserror(q, r);
537     free(result);
538     return;
539   }
540   if (verbose < 2) {    /* else it is already printed by dbgfn */
541     dns_rewind(&p, NULL);
542     p.dnsp_qtyp = q->qtyp == DNS_T_ANY ? 0 : q->qtyp;
543     p.dnsp_qcls = qcls == DNS_C_ANY ? 0 : qcls;
544     while(dns_nextrr(&p, &rr))
545       printrr(&p, &rr);
546   }
547   free(result);
548   query_free(q);
549 }
550
551 int main(int argc, char **argv) {
552   int i;
553   int fd;
554   fd_set fds;
555   struct timeval tv;
556   time_t now;
557   char *ns[DNS_MAXSERV];
558   int nns = 0;
559   struct query *q;
560   enum dns_type qtyp = 0;
561   struct dns_ctx *nctx = NULL;
562
563   if (!(progname = strrchr(argv[0], '/'))) progname = argv[0];
564   else argv[0] = ++progname;
565
566   if (argc <= 1)
567     die(0, "try `%s -h' for help", progname);
568
569   if (dns_init(NULL, 0) < 0 || !(nctx = dns_new(NULL)))
570     die(errno, "unable to initialize dns library");
571   /* we keep two dns contexts: one may be needed to resolve
572    * nameservers if given as names, using default options.
573    */
574
575   while((i = getopt(argc, argv, "vqt:c:an:o:h")) != EOF) switch(i) {
576   case 'v': ++verbose; break;
577   case 'q': --verbose; break;
578   case 't':
579     if (optarg[0] == '*' && !optarg[1])
580       i = DNS_T_ANY;
581     else if ((i = dns_findtypename(optarg)) <= 0)
582       die(0, "unrecognized query type `%s'", optarg);
583     qtyp = i;
584     break;
585   case 'c':
586     if (optarg[0] == '*' && !optarg[1])
587       i = DNS_C_ANY;
588     else if ((i = dns_findclassname(optarg)) < 0)
589       die(0, "unrecognized query class `%s'", optarg);
590     qcls = i;
591     break;
592   case 'a':
593     qtyp = DNS_T_ANY;
594     ++verbose;
595     break;
596   case 'n':
597     if (nns >= DNS_MAXSERV)
598       die(0, "too many nameservers, %d max", DNS_MAXSERV);
599     ns[nns++] = optarg;
600     break;
601   case 'o':
602     if (dns_set_opts(NULL, optarg) != 0)
603       die(0, "invalid option string: `%s'", optarg);
604     break;
605   case 'h':
606     printf(
607 "%s: simple DNS query tool (using udns version %s)\n"
608 "Usage: %s [options] domain-name...\n"
609 "where options are:\n"
610 " -h - print this help and exit\n"
611 " -v - be more verbose\n"
612 " -q - be less verbose\n"
613 " -t type - set query type (A, AAA, PTR etc)\n"
614 " -c class - set query class (IN (default), CH, HS, *)\n"
615 " -a - equivalent to -t ANY -v\n"
616 " -n ns - use given nameserver(s) instead of default\n"
617 "  (may be specified multiple times)\n"
618 " -o option:value - set resovler option (the same as setting $RES_OPTIONS):\n"
619 "  timeout:sec  - initial query timeout\n"
620 "  attempts:num - number of attempt to resovle a query\n"
621 "  ndots:num    - if name has more than num dots, lookup it before search\n"
622 "  port:num     - port number for queries instead of default 53\n"
623 "  udpbuf:num   - size of UDP buffer (use EDNS0 if >512)\n"
624 "  (may be specified more than once)\n"
625       , progname, dns_version(), progname);
626     return 0;
627   default:
628     die(0, "try `%s -h' for help", progname);
629   }
630
631   argc -= optind; argv += optind;
632   if (!argc)
633     die(0, "no name(s) to query specified");
634
635   if (nns) {
636     /* if nameservers given as names, resolve them.
637      * We only allow IPv4 nameservers as names for now.
638      * Ok, it is easy enouth to try both AAAA and A,
639      * but the question is what to do by default.
640      */
641     struct sockaddr_in sin;
642     int j, r = 0, opened = 0;
643     memset(&sin, 0, sizeof(sin));
644     sin.sin_family = AF_INET;
645     sin.sin_port = htons(dns_set_opt(NULL, DNS_OPT_PORT, -1));
646     dns_add_serv(NULL, NULL);
647     for(i = 0; i < nns; ++i) {
648       if (dns_pton(AF_INET, ns[i], &sin.sin_addr) <= 0) {
649         struct dns_rr_a4 *rr;
650         if (!opened) {
651           if (dns_open(nctx) < 0)
652             die(errno, "unable to initialize dns context");
653           opened = 1;
654         }
655         rr = dns_resolve_a4(nctx, ns[i], 0);
656         if (!rr)
657           die(0, "unable to resolve nameserver %s: %s",
658               ns[i], dns_strerror(dns_status(nctx)));
659         for(j = 0; j < rr->dnsa4_nrr; ++j) {
660           sin.sin_addr = rr->dnsa4_addr[j];
661           if ((r = dns_add_serv_s(NULL, (struct sockaddr *)&sin)) < 0)
662             break;
663         }
664         free(rr);
665       }
666       else
667         r = dns_add_serv_s(NULL, (struct sockaddr *)&sin);
668       if (r < 0)
669         die(errno, "unable to add nameserver %s",
670              dns_xntop(AF_INET, &sin.sin_addr));
671     }
672   }
673   dns_free(nctx);
674
675   fd = dns_open(NULL);
676   if (fd < 0)
677     die(errno, "unable to initialize dns context");
678
679   if (verbose > 1)
680     dns_set_dbgfn(NULL, dbgcb);
681
682   for (i = 0; i < argc; ++i) {
683     char *name = argv[i];
684     union {
685       struct in_addr addr;
686       struct in6_addr addr6;
687     } a;
688     unsigned char dn[DNS_MAXDN];
689     enum dns_type l_qtyp = 0;
690     int abs;
691     if (dns_pton(AF_INET, name, &a.addr) > 0) {
692       dns_a4todn(&a.addr, 0, dn, sizeof(dn));
693       l_qtyp = DNS_T_PTR;
694       abs = 1;
695     }
696 #ifdef HAVE_IPv6
697     else if (dns_pton(AF_INET6, name, &a.addr6) > 0) {
698       dns_a6todn(&a.addr6, 0, dn, sizeof(dn));
699       l_qtyp = DNS_T_PTR;
700       abs = 1;
701     }
702 #endif
703     else if (!dns_ptodn(name, strlen(name), dn, sizeof(dn), &abs))
704       die(0, "invalid name `%s'\n", name);
705     else
706       l_qtyp = DNS_T_A;
707     if (qtyp) l_qtyp = qtyp;
708     q = query_new(name, dn, l_qtyp);
709     if (abs) abs = DNS_NOSRCH;
710     if (!dns_submit_dn(NULL, dn, qcls, l_qtyp, abs, 0, dnscb, q))
711       dnserror(q, dns_status(NULL));
712   }
713
714   FD_ZERO(&fds);
715   now = 0;
716   while((i = dns_timeouts(NULL, -1, now)) > 0) {
717     FD_SET(fd, &fds);
718     tv.tv_sec = i;
719     tv.tv_usec = 0;
720     i = select(fd+1, &fds, 0, 0, &tv);
721     now = time(NULL);
722     if (i > 0) dns_ioevent(NULL, now);
723   }
724
725   return errors ? 1 : notfound ? 100 : 0;
726 }
Note: See TracBrowser for help on using the browser.