"Fossies" - the Fresh Open Source Software Archive 
Member "udns-0.4/dnsget.c" (29 Dec 2011, 21546 Bytes) of package /linux/misc/dns/udns-0.4.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "dnsget.c" see the
Fossies "Dox" file reference documentation.
1 /* dnsget.c
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_CONFIG_H
25 # include "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("\\%03u", *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(";EDNS%d OPT record (UDPsize: %d, ERcode: %d, Flags: 0x%02x): %d bytes\n",
191 (rr->dnsrr_ttl>>16) & 0xff, /* version */
192 rr->dnsrr_cls, /* udp size */
193 (rr->dnsrr_ttl>>24) & 0xff, /* extended rcode */
194 rr->dnsrr_ttl & 0xffff, /* flags */
195 rr->dnsrr_dsz);
196 return;
197 }
198 n = printf("%s.", dns_dntosp(rr->dnsrr_dn));
199 printf("%s%u\t%s\t%s\t",
200 n > 15 ? "\t" : n > 7 ? "\t\t" : "\t\t\t",
201 rr->dnsrr_ttl,
202 dns_classname(rr->dnsrr_cls),
203 dns_typename(rr->dnsrr_typ));
204 }
205 else
206 printf("%s. %s ", dns_dntosp(rr->dnsrr_dn), dns_typename(rr->dnsrr_typ));
207 }
208
209 switch(rr->dnsrr_typ) {
210
211 case DNS_T_CNAME:
212 case DNS_T_PTR:
213 case DNS_T_NS:
214 case DNS_T_MB:
215 case DNS_T_MD:
216 case DNS_T_MF:
217 case DNS_T_MG:
218 case DNS_T_MR:
219 if (dns_getdn(pkt, &dptr, end, dn, DNS_MAXDN) <= 0) goto xperr;
220 printf("%s.", dns_dntosp(dn));
221 break;
222
223 case DNS_T_A:
224 if (rr->dnsrr_dsz != 4) goto xperr;
225 printf("%d.%d.%d.%d", dptr[0], dptr[1], dptr[2], dptr[3]);
226 break;
227
228 case DNS_T_AAAA:
229 if (rr->dnsrr_dsz != 16) goto xperr;
230 printf("%s", dns_xntop(AF_INET6, dptr));
231 break;
232
233 case DNS_T_MX:
234 c = dptr + 2;
235 if (dns_getdn(pkt, &c, end, dn, DNS_MAXDN) <= 0 || c != dend) goto xperr;
236 printf("%d %s.", dns_get16(dptr), dns_dntosp(dn));
237 break;
238
239 case DNS_T_TXT:
240 /* first verify it */
241 for(c = dptr; c < dend; c += n) {
242 n = *c++;
243 if (c + n > dend) goto xperr;
244 }
245 c = dptr; n = 0;
246 while (c < dend) {
247 if (verbose > 0) printf(n++ ? "\" \"":"\"");
248 c = printtxt(c);
249 }
250 if (verbose > 0) putchar('"');
251 break;
252
253 case DNS_T_HINFO: /* CPU, OS */
254 c = dptr;
255 n = *c++; if ((c += n) >= dend) goto xperr;
256 n = *c++; if ((c += n) != dend) goto xperr;
257 c = dptr;
258 if (verbose > 0) putchar('"');
259 c = printtxt(c);
260 if (verbose > 0) printf("\" \""); else putchar(' ');
261 printtxt(c);
262 if (verbose > 0) putchar('"');
263 break;
264
265 case DNS_T_WKS:
266 c = dptr;
267 if (dptr + 4 + 2 >= end) goto xperr;
268 printf("%s %d", dns_xntop(AF_INET, dptr), dptr[4]);
269 c = dptr + 5;
270 for (n = 0; c < dend; ++c, n += 8) {
271 if (*c) {
272 unsigned b;
273 for (b = 0; b < 8; ++b)
274 if (*c & (1 << (7-b))) printf(" %d", n + b);
275 }
276 }
277 break;
278
279 case DNS_T_SRV: /* prio weight port targetDN */
280 c = dptr;
281 c += 2 + 2 + 2;
282 if (dns_getdn(pkt, &c, end, dn, DNS_MAXDN) <= 0 || c != dend) goto xperr;
283 c = dptr;
284 printf("%d %d %d %s.",
285 dns_get16(c+0), dns_get16(c+2), dns_get16(c+4),
286 dns_dntosp(dn));
287 break;
288
289 case DNS_T_NAPTR: /* order pref flags serv regexp repl */
290 c = dptr;
291 c += 4; /* order, pref */
292 for (n = 0; n < 3; ++n)
293 if (c >= dend) goto xperr;
294 else c += *c + 1;
295 if (dns_getdn(pkt, &c, end, dn, DNS_MAXDN) <= 0 || c != dend) goto xperr;
296 c = dptr;
297 printf("%u %u", dns_get16(c+0), dns_get16(c+2));
298 c += 4;
299 for(n = 0; n < 3; ++n) {
300 putchar(' ');
301 if (verbose > 0) putchar('"');
302 c = printtxt(c);
303 if (verbose > 0) putchar('"');
304 }
305 printf(" %s.", dns_dntosp(dn));
306 break;
307
308 case DNS_T_KEY:
309 case DNS_T_DNSKEY:
310 /* flags(2) proto(1) algo(1) pubkey */
311 case DNS_T_DS:
312 case DNS_T_DLV:
313 /* ktag(2) proto(1) algo(1) pubkey */
314 c = dptr;
315 if (c + 2 + 1 + 1 > dend) goto xperr;
316 printf("%d %d %d", dns_get16(c), c[2], c[3]);
317 c += 2 + 1 + 1;
318 if (c < dend) {
319 putchar(' ');
320 printb64(c, dend);
321 }
322 break;
323
324 case DNS_T_SIG:
325 case DNS_T_RRSIG:
326 /* type(2) algo(1) labels(1) ottl(4) sexp(4) sinc(4) tag(2) sdn sig */
327 c = dptr;
328 c += 2 + 1 + 1 + 4 + 4 + 4 + 2;
329 if (dns_getdn(pkt, &c, end, dn, DNS_MAXDN) <= 0) goto xperr;
330 printf("%s %u %u %u ",
331 dns_typename(dns_get16(dptr)), dptr[2], dptr[3], dns_get32(dptr+4));
332 printdate(dns_get32(dptr+8));
333 putchar(' ');
334 printdate(dns_get32(dptr+12));
335 printf(" %d %s. ", dns_get16(dptr+10), dns_dntosp(dn));
336 printb64(c, dend);
337 break;
338
339 case DNS_T_SSHFP: /* algo(1), fp type(1), fp... */
340 if (dend < dptr + 3) goto xperr;
341 printf("%u %u ", dptr[0], dptr[1]); /* algo, fp type */
342 printhex(dptr + 2, dend);
343 break;
344
345 #if 0 /* unused RR types? */
346 case DNS_T_NSEC: /* nextDN bitmaps */
347 c = dptr;
348 if (dns_getdn(pkt, &c, end, dn, DNS_MAXDN) <= 0) goto xperr;
349 printf("%s.", dns_dntosp(dn));
350 unfinished.
351 break;
352 #endif
353
354
355 case DNS_T_SOA:
356 c = dptr;
357 if (dns_getdn(pkt, &c, end, dn, DNS_MAXDN) <= 0 ||
358 dns_getdn(pkt, &c, end, dn, DNS_MAXDN) <= 0 ||
359 c + 4*5 != dend)
360 goto xperr;
361 dns_getdn(pkt, &dptr, end, dn, DNS_MAXDN);
362 printf("%s. ", dns_dntosp(dn));
363 dns_getdn(pkt, &dptr, end, dn, DNS_MAXDN);
364 printf("%s. ", dns_dntosp(dn));
365 printf("%u %u %u %u %u",
366 dns_get32(dptr), dns_get32(dptr+4), dns_get32(dptr+8),
367 dns_get32(dptr+12), dns_get32(dptr+16));
368 break;
369
370 case DNS_T_MINFO:
371 c = dptr;
372 if (dns_getdn(pkt, &c, end, dn, DNS_MAXDN) <= 0 ||
373 dns_getdn(pkt, &c, end, dn, DNS_MAXDN) <= 0 ||
374 c != dend)
375 goto xperr;
376 dns_getdn(pkt, &dptr, end, dn, DNS_MAXDN);
377 printf("%s. ", dns_dntosp(dn));
378 dns_getdn(pkt, &dptr, end, dn, DNS_MAXDN);
379 printf("%s.", dns_dntosp(dn));
380 break;
381
382 case DNS_T_NULL:
383 default:
384 printhex(dptr, dend);
385 break;
386 }
387 putchar('\n');
388 return;
389
390 xperr:
391 printf("<parse error>\n");
392 ++errors;
393 }
394
395 static int
396 printsection(struct dns_parse *p, int nrr, const char *sname) {
397 struct dns_rr rr;
398 int r;
399 if (!nrr) return 0;
400 if (verbose > 1) printf("\n;; %s section (%d):\n", sname, nrr);
401
402 p->dnsp_rrl = nrr;
403 while((r = dns_nextrr(p, &rr)) > 0)
404 printrr(p, &rr);
405 if (r < 0) printf("<<ERROR>>\n");
406 return r;
407 }
408
409 /* dbgcb will only be called if verbose > 1 */
410 static void
411 dbgcb(int code, const struct sockaddr *sa, unsigned slen,
412 const unsigned char *pkt, int r,
413 const struct dns_query *unused_q, void *unused_data) {
414 struct dns_parse p;
415 const unsigned char *cur, *end;
416 int numqd;
417
418 if (code > 0) {
419 printf(";; trying %s.\n", dns_dntosp(dns_payload(pkt)));
420 printf(";; sending %d bytes query to ", r);
421 }
422 else
423 printf(";; received %d bytes response from ", r);
424 if (sa->sa_family == AF_INET && slen >= sizeof(struct sockaddr_in))
425 printf("%s port %d\n",
426 dns_xntop(AF_INET, &((struct sockaddr_in*)sa)->sin_addr),
427 htons(((struct sockaddr_in*)sa)->sin_port));
428 #ifdef HAVE_IPv6
429 else if (sa->sa_family == AF_INET6 && slen >= sizeof(struct sockaddr_in6))
430 printf("%s port %d\n",
431 dns_xntop(AF_INET6, &((struct sockaddr_in6*)sa)->sin6_addr),
432 htons(((struct sockaddr_in6*)sa)->sin6_port));
433 #endif
434 else
435 printf("<<unknown socket type %d>>\n", sa->sa_family);
436 if (code > 0 && verbose < 3) {
437 putchar('\n');
438 return;
439 }
440
441 if (code == -2) printf(";; reply from unexpected source\n");
442 if (code == -5) printf(";; reply to a query we didn't sent (or old)\n");
443 if (r < DNS_HSIZE) {
444 printf(";; short packet (%d bytes)\n", r);
445 return;
446 }
447 if (dns_opcode(pkt) != 0)
448 printf(";; unexpected opcode %d\n", dns_opcode(pkt));
449 if (dns_tc(pkt) != 0)
450 printf(";; warning: TC bit set, probably incomplete reply\n");
451
452 printf(";; ->>HEADER<<- opcode: ");
453 switch(dns_opcode(pkt)) {
454 case 0: printf("QUERY"); break;
455 case 1: printf("IQUERY"); break;
456 case 2: printf("STATUS"); break;
457 default: printf("UNKNOWN(%u)", dns_opcode(pkt)); break;
458 }
459 printf(", status: %s, id: %d, size: %d\n;; flags:",
460 dns_rcodename(dns_rcode(pkt)), dns_qid(pkt), r);
461 if (dns_qr(pkt)) printf(" qr");
462 if (dns_aa(pkt)) printf(" aa");
463 if (dns_tc(pkt)) printf(" tc");
464 if (dns_rd(pkt)) printf(" rd");
465 if (dns_ra(pkt)) printf(" ra");
466 /* if (dns_z(pkt)) printf(" z"); only one reserved bit left */
467 if (dns_ad(pkt)) printf(" ad");
468 if (dns_cd(pkt)) printf(" cd");
469 numqd = dns_numqd(pkt);
470 printf("; QUERY: %d, ANSWER: %d, AUTHORITY: %d, ADDITIONAL: %d\n",
471 numqd, dns_numan(pkt), dns_numns(pkt), dns_numar(pkt));
472 if (numqd != 1)
473 printf(";; unexpected number of entries in QUERY section: %d\n",
474 numqd);
475 printf("\n;; QUERY SECTION (%d):\n", numqd);
476 cur = dns_payload(pkt);
477 end = pkt + r;
478 while(numqd--) {
479 if (dns_getdn(pkt, &cur, end, p.dnsp_dnbuf, DNS_MAXDN) <= 0 ||
480 cur + 4 > end) {
481 printf("; invalid query section\n");
482 return;
483 }
484 r = printf(";%s.", dns_dntosp(p.dnsp_dnbuf));
485 printf("%s%s\t%s\n",
486 r > 23 ? "\t" : r > 15 ? "\t\t" : r > 7 ? "\t\t\t" : "\t\t\t\t",
487 dns_classname(dns_get16(cur+2)), dns_typename(dns_get16(cur)));
488 cur += 4;
489 }
490
491 p.dnsp_pkt = pkt;
492 p.dnsp_cur = p.dnsp_ans = cur;
493 p.dnsp_end = end;
494 p.dnsp_qdn = NULL;
495 p.dnsp_qcls = p.dnsp_qtyp = 0;
496 p.dnsp_ttl = 0xffffffffu;
497 p.dnsp_nrr = 0;
498
499 r = printsection(&p, dns_numan(pkt), "ANSWER");
500 if (r == 0)
501 r = printsection(&p, dns_numns(pkt), "AUTHORITY");
502 if (r == 0)
503 r = printsection(&p, dns_numar(pkt), "ADDITIONAL");
504 putchar('\n');
505 }
506
507 static void dnscb(struct dns_ctx *ctx, void *result, void *data) {
508 int r = dns_status(ctx);
509 struct query *q = data;
510 struct dns_parse p;
511 struct dns_rr rr;
512 unsigned nrr;
513 unsigned char dn[DNS_MAXDN];
514 const unsigned char *pkt, *cur, *end;
515 if (!result) {
516 dnserror(q, r);
517 return;
518 }
519 pkt = result; end = pkt + r; cur = dns_payload(pkt);
520 dns_getdn(pkt, &cur, end, dn, sizeof(dn));
521 dns_initparse(&p, NULL, pkt, cur, end);
522 p.dnsp_qcls = p.dnsp_qtyp = 0;
523 nrr = 0;
524 while((r = dns_nextrr(&p, &rr)) > 0) {
525 if (!dns_dnequal(dn, rr.dnsrr_dn)) continue;
526 if ((qcls == DNS_C_ANY || qcls == rr.dnsrr_cls) &&
527 (q->qtyp == DNS_T_ANY || q->qtyp == rr.dnsrr_typ))
528 ++nrr;
529 else if (rr.dnsrr_typ == DNS_T_CNAME && !nrr) {
530 if (dns_getdn(pkt, &rr.dnsrr_dptr, end,
531 p.dnsp_dnbuf, sizeof(p.dnsp_dnbuf)) <= 0 ||
532 rr.dnsrr_dptr != rr.dnsrr_dend) {
533 r = DNS_E_PROTOCOL;
534 break;
535 }
536 else {
537 if (verbose == 1) {
538 printf("%s.", dns_dntosp(dn));
539 printf(" CNAME %s.\n", dns_dntosp(p.dnsp_dnbuf));
540 }
541 dns_dntodn(p.dnsp_dnbuf, dn, sizeof(dn));
542 }
543 }
544 }
545 if (!r && !nrr)
546 r = DNS_E_NODATA;
547 if (r < 0) {
548 dnserror(q, r);
549 free(result);
550 return;
551 }
552 if (verbose < 2) { /* else it is already printed by dbgfn */
553 dns_rewind(&p, NULL);
554 p.dnsp_qtyp = q->qtyp == DNS_T_ANY ? 0 : q->qtyp;
555 p.dnsp_qcls = qcls == DNS_C_ANY ? 0 : qcls;
556 while(dns_nextrr(&p, &rr))
557 printrr(&p, &rr);
558 }
559 free(result);
560 query_free(q);
561 }
562
563 int main(int argc, char **argv) {
564 int i;
565 int fd;
566 fd_set fds;
567 struct timeval tv;
568 time_t now;
569 char *ns[DNS_MAXSERV];
570 int nns = 0;
571 struct query *q;
572 enum dns_type qtyp = 0;
573 struct dns_ctx *nctx = NULL;
574 int flags = 0;
575
576 if (!(progname = strrchr(argv[0], '/'))) progname = argv[0];
577 else argv[0] = ++progname;
578
579 if (argc <= 1)
580 die(0, "try `%s -h' for help", progname);
581
582 if (dns_init(NULL, 0) < 0 || !(nctx = dns_new(NULL)))
583 die(errno, "unable to initialize dns library");
584 /* we keep two dns contexts: one may be needed to resolve
585 * nameservers if given as names, using default options.
586 */
587
588 while((i = getopt(argc, argv, "vqt:c:an:o:f:h")) != EOF) switch(i) {
589 case 'v': ++verbose; break;
590 case 'q': --verbose; break;
591 case 't':
592 if (optarg[0] == '*' && !optarg[1])
593 i = DNS_T_ANY;
594 else if ((i = dns_findtypename(optarg)) <= 0)
595 die(0, "unrecognized query type `%s'", optarg);
596 qtyp = i;
597 break;
598 case 'c':
599 if (optarg[0] == '*' && !optarg[1])
600 i = DNS_C_ANY;
601 else if ((i = dns_findclassname(optarg)) < 0)
602 die(0, "unrecognized query class `%s'", optarg);
603 qcls = i;
604 break;
605 case 'a':
606 qtyp = DNS_T_ANY;
607 ++verbose;
608 break;
609 case 'n':
610 if (nns >= DNS_MAXSERV)
611 die(0, "too many nameservers, %d max", DNS_MAXSERV);
612 ns[nns++] = optarg;
613 break;
614 case 'o':
615 case 'f': {
616 char *opt;
617 const char *const delim = " \t,;";
618 for(opt = strtok(optarg, delim); opt != NULL; opt = strtok(NULL, delim)) {
619 if (dns_set_opts(NULL, optarg) == 0)
620 ;
621 else if (strcmp(opt, "aa") == 0) flags |= DNS_AAONLY;
622 else if (strcmp(optarg, "nord") == 0) flags |= DNS_NORD;
623 else if (strcmp(optarg, "dnssec") == 0) flags |= DNS_SET_DO;
624 else if (strcmp(optarg, "do") == 0) flags |= DNS_SET_DO;
625 else if (strcmp(optarg, "cd") == 0) flags |= DNS_SET_CD;
626 else
627 die(0, "invalid option: `%s'", opt);
628 }
629 break;
630 }
631 case 'h':
632 printf(
633 "%s: simple DNS query tool (using udns version %s)\n"
634 "Usage: %s [options] domain-name...\n"
635 "where options are:\n"
636 " -h - print this help and exit\n"
637 " -v - be more verbose\n"
638 " -q - be less verbose\n"
639 " -t type - set query type (A, AAA, PTR etc)\n"
640 " -c class - set query class (IN (default), CH, HS, *)\n"
641 " -a - equivalent to -t ANY -v\n"
642 " -n ns - use given nameserver(s) instead of default\n"
643 " (may be specified multiple times)\n"
644 " -o opt,opt,... (comma- or space-separated list,\n"
645 " may be specified more than once):\n"
646 " set resovler options (the same as setting $RES_OPTIONS):\n"
647 " timeout:sec - initial query timeout\n"
648 " attempts:num - number of attempt to resovle a query\n"
649 " ndots:num - if name has more than num dots, lookup it before search\n"
650 " port:num - port number for queries instead of default 53\n"
651 " udpbuf:num - size of UDP buffer (use EDNS0 if >512)\n"
652 " or query flags:\n"
653 " aa,nord,dnssec,do,cd - set query flag (auth-only, no recursion,\n"
654 " enable DNSSEC (DNSSEC Ok), check disabled)\n"
655 , progname, dns_version(), progname);
656 return 0;
657 default:
658 die(0, "try `%s -h' for help", progname);
659 }
660
661 argc -= optind; argv += optind;
662 if (!argc)
663 die(0, "no name(s) to query specified");
664
665 if (nns) {
666 /* if nameservers given as names, resolve them.
667 * We only allow IPv4 nameservers as names for now.
668 * Ok, it is easy enouth to try both AAAA and A,
669 * but the question is what to do by default.
670 */
671 struct sockaddr_in sin;
672 int j, r = 0, opened = 0;
673 memset(&sin, 0, sizeof(sin));
674 sin.sin_family = AF_INET;
675 sin.sin_port = htons(dns_set_opt(NULL, DNS_OPT_PORT, -1));
676 dns_add_serv(NULL, NULL);
677 for(i = 0; i < nns; ++i) {
678 if (dns_pton(AF_INET, ns[i], &sin.sin_addr) <= 0) {
679 struct dns_rr_a4 *rr;
680 if (!opened) {
681 if (dns_open(nctx) < 0)
682 die(errno, "unable to initialize dns context");
683 opened = 1;
684 }
685 rr = dns_resolve_a4(nctx, ns[i], 0);
686 if (!rr)
687 die(0, "unable to resolve nameserver %s: %s",
688 ns[i], dns_strerror(dns_status(nctx)));
689 for(j = 0; j < rr->dnsa4_nrr; ++j) {
690 sin.sin_addr = rr->dnsa4_addr[j];
691 if ((r = dns_add_serv_s(NULL, (struct sockaddr *)&sin)) < 0)
692 break;
693 }
694 free(rr);
695 }
696 else
697 r = dns_add_serv_s(NULL, (struct sockaddr *)&sin);
698 if (r < 0)
699 die(errno, "unable to add nameserver %s",
700 dns_xntop(AF_INET, &sin.sin_addr));
701 }
702 }
703 dns_free(nctx);
704
705 fd = dns_open(NULL);
706 if (fd < 0)
707 die(errno, "unable to initialize dns context");
708
709 if (verbose > 1)
710 dns_set_dbgfn(NULL, dbgcb);
711
712 if (flags)
713 dns_set_opt(NULL, DNS_OPT_FLAGS, flags);
714
715 for (i = 0; i < argc; ++i) {
716 char *name = argv[i];
717 union {
718 struct in_addr addr;
719 struct in6_addr addr6;
720 } a;
721 unsigned char dn[DNS_MAXDN];
722 enum dns_type l_qtyp = 0;
723 int abs;
724 if (dns_pton(AF_INET, name, &a.addr) > 0) {
725 dns_a4todn(&a.addr, 0, dn, sizeof(dn));
726 l_qtyp = DNS_T_PTR;
727 abs = 1;
728 }
729 #ifdef HAVE_IPv6
730 else if (dns_pton(AF_INET6, name, &a.addr6) > 0) {
731 dns_a6todn(&a.addr6, 0, dn, sizeof(dn));
732 l_qtyp = DNS_T_PTR;
733 abs = 1;
734 }
735 #endif
736 else if (!dns_ptodn(name, strlen(name), dn, sizeof(dn), &abs))
737 die(0, "invalid name `%s'\n", name);
738 else
739 l_qtyp = DNS_T_A;
740 if (qtyp) l_qtyp = qtyp;
741 q = query_new(name, dn, l_qtyp);
742 if (abs) abs = DNS_NOSRCH;
743 if (!dns_submit_dn(NULL, dn, qcls, l_qtyp, abs, 0, dnscb, q))
744 dnserror(q, dns_status(NULL));
745 }
746
747 FD_ZERO(&fds);
748 now = 0;
749 while((i = dns_timeouts(NULL, -1, now)) > 0) {
750 FD_SET(fd, &fds);
751 tv.tv_sec = i;
752 tv.tv_usec = 0;
753 i = select(fd+1, &fds, 0, 0, &tv);
754 now = time(NULL);
755 if (i > 0) dns_ioevent(NULL, now);
756 }
757
758 return errors ? 1 : notfound ? 100 : 0;
759 }