No empty .Rs/.Re
[netbsd-mini2440.git] / external / bsd / libbind / dist / tests / dig8.c
blobd8f2e2b8bf039c972cc4e1df6f357965b90cd1ee
1 /* $NetBSD$ */
3 /*
4 * Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC")
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
10 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
11 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
12 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
13 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
14 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
15 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16 * PERFORMANCE OF THIS SOFTWARE.
19 #ifndef lint
20 static const char rcsid[] = "Id: dig8.c,v 1.4 2009/03/03 23:49:07 tbox Exp";
21 #endif
24 * Copyright (c) 1989
25 * The Regents of the University of California. All rights reserved.
27 * Redistribution and use in source and binary forms, with or without
28 * modification, are permitted provided that the following conditions
29 * are met:
30 * 1. Redistributions of source code must retain the above copyright
31 * notice, this list of conditions and the following disclaimer.
32 * 2. Redistributions in binary form must reproduce the above copyright
33 * notice, this list of conditions and the following disclaimer in the
34 * documentation and/or other materials provided with the distribution.
35 * 3. All advertising materials mentioning features or use of this software
36 * must display the following acknowledgement:
37 * This product includes software developed by the University of
38 * California, Berkeley and its contributors.
39 * 4. Neither the name of the University nor the names of its contributors
40 * may be used to endorse or promote products derived from this software
41 * without specific prior written permission.
43 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
44 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
45 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
46 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
47 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
48 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
49 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
50 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
51 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
52 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
53 * SUCH DAMAGE.
57 * Portions Copyright (c) 1993 by Digital Equipment Corporation.
59 * Permission to use, copy, modify, and distribute this software for any
60 * purpose with or without fee is hereby granted, provided that the above
61 * copyright notice and this permission notice appear in all copies, and that
62 * the name of Digital Equipment Corporation not be used in advertising or
63 * publicity pertaining to distribution of the document or software without
64 * specific, written prior permission.
66 * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
67 * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
68 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
69 * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
70 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
71 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
72 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
73 * SOFTWARE.
77 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
78 * Portions Copyright (c) 1996-1999 by Internet Software Consortium
80 * Permission to use, copy, modify, and distribute this software for any
81 * purpose with or without fee is hereby granted, provided that the above
82 * copyright notice and this permission notice appear in all copies.
84 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
85 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
86 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
87 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
88 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
89 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
90 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
93 /*********************** Notes for the BIND 4.9 release (Paul Vixie, DEC)
94 * dig 2.0 was written by copying sections of libresolv.a and nslookup
95 * and modifying them to be more useful for a general lookup utility.
96 * as of BIND 4.9, the changes needed to support dig have mostly been
97 * incorporated into libresolv.a and nslookup; dig now links against
98 * some of nslookup's .o files rather than #including them or maintaining
99 * local copies of them.
101 * while merging dig back into the BIND release, i made a number of
102 * structural changes. for one thing, i put all of dig's private
103 * library routines into this file rather than maintaining them in
104 * separate, #included, files. i don't like to #include ".c" files.
105 * i removed all calls to "bcopy", replacing them with structure
106 * assignments. i removed all "extern"'s of standard functions,
107 * replacing them with #include's of standard header files. this
108 * version of dig is probably as portable as the rest of BIND.
110 * i had to remove the query-time and packet-count statistics since
111 * the current libresolv.a is a lot harder to modify to maintain these
112 * than the 4.8 one (used in the original dig) was. for consolation,
113 * i added a "usage" message with extensive help text.
115 * to save my (limited, albeit) sanity, i ran "indent" over the source.
116 * i also added the standard berkeley/DEC copyrights, since this file now
117 * contains a fair amount of non-USC code. note that the berkeley and
118 * DEC copyrights do not prohibit redistribution, with or without fee;
119 * we add them only to protect ourselves (you have to claim copyright
120 * in order to disclaim liability and warranty).
122 * Paul Vixie, Palo Alto, CA, April 1993
123 ****************************************************************************
125 ******************************************************************
126 * DiG -- Domain Information Groper *
128 * dig.c - Version 2.1 (7/12/94) ("BIND takeover") *
130 * Developed by: Steve Hotz & Paul Mockapetris *
131 * USC Information Sciences Institute (USC-ISI) *
132 * Marina del Rey, California *
133 * 1989 *
135 * dig.c - *
136 * Version 2.0 (9/1/90) *
137 * o renamed difftime() difftv() to avoid *
138 * clash with ANSI C *
139 * o fixed incorrect # args to strcmp,gettimeofday *
140 * o incorrect length specified to strncmp *
141 * o fixed broken -sticky -envsa -envset functions *
142 * o print options/flags redefined & modified *
144 * Version 2.0.beta (5/9/90) *
145 * o output format - helpful to `doc` *
146 * o minor cleanup *
147 * o release to beta testers *
149 * Version 1.1.beta (10/26/89) *
150 * o hanging zone transer (when REFUSED) fixed *
151 * o trailing dot added to domain names in RDATA *
152 * o ISI internal *
154 * Version 1.0.tmp (8/27/89) *
155 * o Error in prnttime() fixed *
156 * o no longer dumps core on large pkts *
157 * o zone transfer (axfr) added *
158 * o -x added for inverse queries *
159 * (i.e. "dig -x 128.9.0.32") *
160 * o give address of default server *
161 * o accept broadcast to server @255.255.255.255 *
163 * Version 1.0 (3/27/89) *
164 * o original release *
166 * DiG is Public Domain, and may be used for any purpose as *
167 * long as this notice is not removed. *
168 ******************************************************************/
170 /* Import. */
172 #include "port_before.h"
174 #include <sys/types.h>
175 #include <sys/param.h>
176 #include <sys/file.h>
177 #include <sys/stat.h>
178 #include <sys/socket.h>
179 #include <sys/time.h>
180 #include <sys/wait.h>
182 #include <netinet/in.h>
183 #include <arpa/inet.h>
184 #include <arpa/nameser.h>
186 #include <isc/dst.h>
188 #include <assert.h>
189 #include <ctype.h>
190 #include <errno.h>
191 #include <fcntl.h>
192 #include <netdb.h>
193 #include <setjmp.h>
194 #include <stdio.h>
195 #include <stdlib.h>
196 #include <string.h>
197 #include <unistd.h>
198 #include <time.h> /* time(2), ctime(3) */
200 #include "port_after.h"
202 #include <resolv.h>
204 #include "res.h"
206 /* Global. */
208 #define VERSION 84
209 #define VSTRING "8.4"
211 #define PRF_DEF (RES_PRF_STATS | RES_PRF_CMD | RES_PRF_QUES | \
212 RES_PRF_ANS | RES_PRF_AUTH | RES_PRF_ADD | \
213 RES_PRF_HEAD1 | RES_PRF_HEAD2 | RES_PRF_TTLID | \
214 RES_PRF_HEADX | RES_PRF_REPLY | RES_PRF_TRUNC)
215 #define PRF_MIN (RES_PRF_QUES | RES_PRF_ANS | RES_PRF_HEAD1 | \
216 RES_PRF_HEADX | RES_PRF_REPLY | RES_PRF_TRUNC)
217 #define PRF_ZONE (RES_PRF_STATS | RES_PRF_CMD | RES_PRF_QUES | \
218 RES_PRF_ANS | RES_PRF_AUTH | RES_PRF_ADD | \
219 RES_PRF_TTLID | RES_PRF_REPLY | RES_PRF_TRUNC)
221 #ifndef MAXHOSTNAMELEN
222 #define MAXHOSTNAMELEN 256
223 #endif
225 #define SAVEENV "DiG.env"
226 #define DIG_MAXARGS 30
228 #ifndef DIG_PING
229 #define DIG_PING "ping"
230 #endif
231 #ifndef DIG_TAIL
232 #define DIG_TAIL "tail"
233 #endif
234 #ifndef DIG_PINGFMT
235 #define DIG_PINGFMT "%s -s %s 56 3 | %s -3"
236 #endif
238 static int eecode = 0;
239 static FILE * qfp;
240 static char myhostname[MAXHOSTNAMELEN];
241 static struct sockaddr_in myaddress;
242 static struct sockaddr_in6 myaddress6;
243 static u_int32_t ixfr_serial;
244 static char ubuf[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:123.123.123.123")];
246 /* stuff for nslookup modules */
247 struct __res_state res;
248 FILE *filePtr;
249 jmp_buf env;
250 HostInfo *defaultPtr = NULL;
251 HostInfo curHostInfo, defaultRec;
252 int curHostValid = FALSE;
253 int queryType, queryClass;
254 extern int StringToClass(), StringToType(); /* subr.c */
255 #if defined(BSD) && BSD >= 199006 && !defined(RISCOS_BSD)
256 FILE *yyin = NULL;
257 void yyrestart(FILE *f);
258 void yyrestart(FILE *f) { UNUSED(f); }
259 #endif
260 char *pager = NULL;
261 /* end of nslookup stuff */
263 /* Forward. */
265 static void Usage(void);
266 static int setopt(const char *);
267 static void res_re_init(void);
268 static int xstrtonum(char *);
269 static int printZone(ns_type, const char *,
270 const struct sockaddr_in *, ns_tsig_key *);
271 static int print_axfr(FILE *output, const u_char *msg,
272 size_t msglen);
273 static struct timeval difftv(struct timeval, struct timeval);
274 static void prnttime(struct timeval);
275 static void stackarg(char *, char **);
276 static void reverse6(char *, struct in6_addr *);
278 /* Public. */
281 main(int argc, char **argv) {
282 short port = htons(NAMESERVER_PORT);
283 short lport;
284 /* Wierd stuff for SPARC alignment, hurts nothing else. */
285 union {
286 HEADER header_;
287 u_char packet_[PACKETSZ];
288 } packet_;
289 #define header (packet_.header_)
290 #define packet (packet_.packet_)
291 union {
292 HEADER u;
293 u_char b[NS_MAXMSG];
294 } answer;
295 int n;
296 char doping[90];
297 char pingstr[50];
298 char *afile;
299 char *addrc, *addrend, *addrbegin;
301 time_t exectime;
302 struct timeval tv1, tv2, start_time, end_time, query_time;
304 char *srv;
305 int anyflag = 0;
306 int sticky = 0;
307 int tmp;
308 int qtypeSet;
309 ns_type xfr = ns_t_invalid;
310 int bytes_out, bytes_in;
312 char cmd[512];
313 char domain[MAXDNAME];
314 char msg[120], **vtmp;
315 char *args[DIG_MAXARGS];
316 char **ax;
317 int once = 1, dofile = 0; /* batch -vs- interactive control */
318 char fileq[384];
319 int fp;
320 int wait=0, delay;
321 int envset=0, envsave=0;
322 struct __res_state res_x, res_t;
323 int r;
324 struct in6_addr in6;
326 ns_tsig_key key;
327 char *keyfile = NULL, *keyname = NULL;
328 const char *pingfmt = NULL;
330 UNUSED(argc);
332 res_ninit(&res);
333 res.pfcode = PRF_DEF;
334 qtypeSet = 0;
335 memset(domain, 0, sizeof domain);
336 gethostname(myhostname, (sizeof myhostname));
337 #ifdef HAVE_SA_LEN
338 myaddress.sin_len = sizeof(struct sockaddr_in);
339 #endif
340 myaddress.sin_family = AF_INET;
341 myaddress.sin_addr.s_addr = INADDR_ANY;
342 myaddress.sin_port = 0; /*INPORT_ANY*/;
344 #ifdef HAVE_SA_LEN
345 myaddress6.sin6_len = sizeof(struct sockaddr_in6);
346 #endif
347 myaddress6.sin6_family = AF_INET6;
348 myaddress6.sin6_addr = in6addr_any;
349 myaddress6.sin6_port = 0; /*INPORT_ANY*/;
351 res_x = res;
354 * If LOCALDEF in environment, should point to file
355 * containing local favourite defaults. Also look for file
356 * DiG.env (i.e. SAVEENV) in local directory.
359 if ((((afile = (char *) getenv("LOCALDEF")) != (char *) NULL) &&
360 ((fp = open(afile, O_RDONLY)) > 0)) ||
361 ((fp = open(SAVEENV, O_RDONLY)) > 0)) {
362 read(fp, (char *)&res_x, (sizeof res_x));
363 close(fp);
364 res = res_x;
367 * Check for batch-mode DiG; also pre-scan for 'help'.
369 vtmp = argv;
370 ax = args;
371 while (*vtmp != NULL) {
372 if (strcmp(*vtmp, "-h") == 0 ||
373 strcmp(*vtmp, "-help") == 0 ||
374 strcmp(*vtmp, "-usage") == 0 ||
375 strcmp(*vtmp, "help") == 0) {
376 Usage();
377 exit(0);
380 if (strcmp(*vtmp, "-f") == 0) {
381 dofile++; once=0;
382 if ((qfp = fopen(*++vtmp, "r")) == NULL) {
383 fflush(stdout);
384 perror("file open");
385 fflush(stderr);
386 exit(10);
388 } else {
389 if (ax - args == DIG_MAXARGS) {
390 fprintf(stderr, "dig: too many arguments\n");
391 exit(10);
393 *ax++ = *vtmp;
395 vtmp++;
398 gettimeofday(&tv1, NULL);
401 * Main section: once if cmd-line query
402 * while !EOF if batch mode
404 *fileq = '\0';
405 while ((dofile && fgets(fileq, sizeof fileq, qfp) != NULL) ||
406 (!dofile && once--))
408 if (*fileq == '\n' || *fileq == '#' || *fileq==';') {
409 printf("%s", fileq); /* echo but otherwise ignore */
410 continue; /* blank lines and comments */
414 * "Sticky" requests that before current parsing args
415 * return to current "working" environment (X******).
417 if (sticky) {
418 printf(";; (using sticky settings)\n");
419 res = res_x;
423 * Concat cmd-line and file args.
425 stackarg(fileq, ax);
427 /* defaults */
428 queryType = ns_t_ns;
429 queryClass = ns_c_in;
430 xfr = ns_t_invalid;
431 *pingstr = 0;
432 srv = NULL;
434 sprintf(cmd, "\n; <<>> DiG %s (libbind %d) <<>> ",
435 VSTRING, __RES);
436 argv = args;
437 /* argc = ax - args; */
439 * More cmd-line options than anyone should ever have to
440 * deal with ....
442 while (*(++argv) != NULL && **argv != '\0') {
443 if (strlen(cmd) + strlen(*argv) + 2 > sizeof (cmd)) {
444 fprintf(stderr,
445 "Argument too large for input buffer\n");
446 exit(1);
448 strcat(cmd, *argv);
449 strcat(cmd, " ");
450 if (**argv == '@') {
451 srv = (*argv+1);
452 continue;
454 if (**argv == '%')
455 continue;
456 if (**argv == '+') {
457 setopt(*argv+1);
458 continue;
460 if (**argv == '=') {
461 ixfr_serial = strtoul(*argv+1, NULL, 0);
462 continue;
464 if (strncmp(*argv, "-nost", 5) == 0) {
465 sticky = 0;
466 continue;
467 } else if (strncmp(*argv, "-st", 3) == 0) {
468 sticky++;
469 continue;
470 } else if (strncmp(*argv, "-envsa", 6) == 0) {
471 envsave++;
472 continue;
473 } else if (strncmp(*argv, "-envse", 6) == 0) {
474 envset++;
475 continue;
478 if (**argv == '-') {
479 switch (argv[0][1]) {
480 case 'T':
481 if (*++argv == NULL)
482 printf("; no arg for -T?\n");
483 else
484 wait = atoi(*argv);
485 break;
486 case 'c':
487 if(*++argv == NULL)
488 printf("; no arg for -c?\n");
489 else if ((tmp = atoi(*argv))
490 || *argv[0] == '0') {
491 queryClass = tmp;
492 } else if ((tmp = StringToClass(*argv,
493 0, NULL)
494 ) != 0) {
495 queryClass = tmp;
496 } else {
497 printf(
498 "; invalid class specified\n"
501 break;
502 case 't':
503 if (*++argv == NULL)
504 printf("; no arg for -t?\n");
505 else if ((tmp = atoi(*argv))
506 || *argv[0]=='0') {
507 if (ns_t_xfr_p(tmp)) {
508 xfr = tmp;
509 } else {
510 queryType = tmp;
511 qtypeSet++;
513 } else if ((tmp = StringToType(*argv,
514 0, NULL)
515 ) != 0) {
516 if (ns_t_xfr_p(tmp)) {
517 xfr = tmp;
518 } else {
519 queryType = tmp;
520 qtypeSet++;
522 } else {
523 printf(
524 "; invalid type specified\n"
527 break;
528 case 'x':
529 if (!qtypeSet) {
530 queryType = T_ANY;
531 qtypeSet++;
533 if ((addrc = *++argv) == NULL) {
534 printf("; no arg for -x?\n");
535 break;
537 r = inet_pton(AF_INET6, addrc, &in6);
538 if (r > 0) {
539 reverse6(domain, &in6);
540 break;
542 addrend = addrc + strlen(addrc);
543 if (*addrend == '.')
544 *addrend = '\0';
545 *domain = '\0';
546 while ((addrbegin = strrchr(addrc,'.'))) {
547 strcat(domain, addrbegin+1);
548 strcat(domain, ".");
549 *addrbegin = '\0';
551 strcat(domain, addrc);
552 strcat(domain, ".in-addr.arpa.");
553 break;
554 case 'p':
555 if (argv[0][2] != '\0')
556 port = htons(atoi(argv[0]+2));
557 else if (*++argv == NULL)
558 printf("; no arg for -p?\n");
559 else
560 port = htons(atoi(*argv));
561 break;
562 case 'P':
563 if (argv[0][2] != '\0') {
564 strcpy(pingstr, argv[0]+2);
565 pingfmt =
566 "%s %s 56 3 | %s -3";
567 } else {
568 strcpy(pingstr, DIG_PING);
569 pingfmt = DIG_PINGFMT;
571 break;
572 case 'n':
573 if (argv[0][2] != '\0')
574 res.ndots = atoi(argv[0]+2);
575 else if (*++argv == NULL)
576 printf("; no arg for -n?\n");
577 else
578 res.ndots = atoi(*argv);
579 break;
580 case 'b': {
581 char *a, *p;
583 if (argv[0][2] != '\0')
584 a = argv[0]+2;
585 else if (*++argv == NULL) {
586 printf("; no arg for -b?\n");
587 break;
588 } else
589 a = *argv;
590 if ((p = strchr(a, ':')) != NULL) {
591 *p++ = '\0';
592 lport = htons(atoi(p));
593 } else
594 lport = htons(0);
595 if (inet_pton(AF_INET6, a,
596 &myaddress6.sin6_addr) == 1) {
597 myaddress6.sin6_port = lport;
598 } else if (!inet_aton(a,
599 &myaddress.sin_addr)) {
600 fprintf(stderr,
601 ";; bad -b addr\n");
602 exit(1);
603 } else
604 myaddress.sin_port = lport;
606 break;
607 case 'k':
608 /* -k keydir:keyname */
610 if (argv[0][2] != '\0')
611 keyfile = argv[0]+2;
612 else if (*++argv == NULL) {
613 printf("; no arg for -k?\n");
614 break;
615 } else
616 keyfile = *argv;
618 keyname = strchr(keyfile, ':');
619 if (keyname == NULL) {
620 fprintf(stderr,
621 "key option argument should be keydir:keyname\n");
622 exit(1);
624 *keyname++='\0';
625 break;
626 } /* switch - */
627 continue;
628 } /* if '-' */
630 if ((tmp = StringToType(*argv, -1, NULL)) != -1) {
631 if ((T_ANY == tmp) && anyflag++) {
632 queryClass = C_ANY;
633 continue;
635 if (ns_t_xfr_p(tmp) &&
636 (tmp == ns_t_axfr ||
637 (res.options & RES_USEVC) != 0)
639 res.pfcode = PRF_ZONE;
640 xfr = (ns_type)tmp;
641 } else {
642 queryType = tmp;
643 qtypeSet++;
645 } else if ((tmp = StringToClass(*argv, -1, NULL))
646 != -1) {
647 queryClass = tmp;
648 } else {
649 memset(domain, 0, sizeof domain);
650 sprintf(domain,"%s",*argv);
652 } /* while argv remains */
654 /* process key options */
655 if (keyfile) {
656 #ifdef PARSE_KEYFILE
657 int i, n1;
658 char buf[BUFSIZ], *p;
659 FILE *fp = NULL;
660 int file_major, file_minor, alg;
662 fp = fopen(keyfile, "r");
663 if (fp == NULL) {
664 perror(keyfile);
665 exit(1);
667 /* Now read the header info from the file. */
668 i = fread(buf, 1, BUFSIZ, fp);
669 if (i < 5) {
670 fclose(fp);
671 exit(1);
673 fclose(fp);
675 p = buf;
677 n=strlen(p); /* get length of strings */
678 n1=strlen("Private-key-format: v");
679 if (n1 > n ||
680 strncmp(buf, "Private-key-format: v", n1)) {
681 fprintf(stderr, "Invalid key file format\n");
682 exit(1); /* not a match */
684 p+=n1; /* advance pointer */
685 sscanf((char *)p, "%d.%d", &file_major, &file_minor);
686 /* should do some error checking with these someday */
687 while (*p++!='\n'); /* skip to end of line */
689 n=strlen(p); /* get length of strings */
690 n1=strlen("Algorithm: ");
691 if (n1 > n || strncmp(p, "Algorithm: ", n1)) {
692 fprintf(stderr, "Invalid key file format\n");
693 exit(1); /* not a match */
695 p+=n1; /* advance pointer */
696 if (sscanf((char *)p, "%d", &alg)!=1) {
697 fprintf(stderr, "Invalid key file format\n");
698 exit(1);
700 while (*p++!='\n'); /* skip to end of line */
702 n=strlen(p); /* get length of strings */
703 n1=strlen("Key: ");
704 if (n1 > n || strncmp(p, "Key: ", n1)) {
705 fprintf(stderr, "Invalid key file format\n");
706 exit(1); /* not a match */
708 p+=n1; /* advance pointer */
709 pp=p;
710 while (*pp++!='\n'); /* skip to end of line,
711 * terminate it */
712 *--pp='\0';
714 key.data=malloc(1024*sizeof(char));
715 key.len=b64_pton(p, key.data, 1024);
717 strcpy(key.name, keyname);
718 strcpy(key.alg, "HMAC-MD5.SIG-ALG.REG.INT");
719 #else
720 /* use the dst* routines to parse the key files
722 * This requires that both the .key and the .private
723 * files exist in your cwd, so the keyfile parmeter
724 * here is assumed to be a path in which the
725 * K*.{key,private} files exist.
727 DST_KEY *dst_key;
728 char cwd[PATH_MAX+1];
730 if (getcwd(cwd, PATH_MAX)==NULL) {
731 perror("unable to get current directory");
732 exit(1);
734 if (chdir(keyfile)<0) {
735 fprintf(stderr,
736 "unable to chdir to %s: %s\n", keyfile,
737 strerror(errno));
738 exit(1);
741 dst_init();
742 dst_key = dst_read_key(keyname,
743 0 /* not used for priv keys */,
744 KEY_HMAC_MD5, DST_PRIVATE);
745 if (!dst_key) {
746 fprintf(stderr,
747 "dst_read_key: error reading key\n");
748 exit(1);
750 key.data=malloc(1024*sizeof(char));
751 dst_key_to_buffer(dst_key, key.data, 1024);
752 key.len=dst_key->dk_key_size;
754 strcpy(key.name, keyname);
755 strcpy(key.alg, "HMAC-MD5.SIG-ALG.REG.INT");
757 if (chdir(cwd)<0) {
758 fprintf(stderr, "unable to chdir to %s: %s\n",
759 cwd, strerror(errno));
760 exit(1);
762 #endif
765 if (res.pfcode & 0x80000)
766 printf("; pfcode: %08lx, options: %08lx\n",
767 (unsigned long)res.pfcode,
768 (unsigned long)res.options);
771 * Current env. (after this parse) is to become the
772 * new "working" environmnet. Used in conj. with sticky.
774 if (envset) {
775 res_x = res;
776 envset = 0;
780 * Current env. (after this parse) is to become the
781 * new default saved environmnet. Save in user specified
782 * file if exists else is SAVEENV (== "DiG.env").
784 if (envsave) {
785 afile = (char *) getenv("LOCALDEF");
786 if ((afile &&
787 ((fp = open(afile,
788 O_WRONLY|O_CREAT|O_TRUNC,
789 S_IREAD|S_IWRITE)) > 0))
791 ((fp = open(SAVEENV,
792 O_WRONLY|O_CREAT|O_TRUNC,
793 S_IREAD|S_IWRITE)) > 0)) {
794 write(fp, (char *)&res, (sizeof res));
795 close(fp);
797 envsave = 0;
800 if (res.pfcode & RES_PRF_CMD)
801 printf("%s\n", cmd);
803 anyflag = 0;
806 * Find address of server to query. If not dot-notation, then
807 * try to resolve domain-name (if so, save and turn off print
808 * options, this domain-query is not the one we want. Restore
809 * user options when done.
810 * Things get a bit wierd since we need to use resolver to be
811 * able to "put the resolver to work".
814 if (srv != NULL) {
815 int nscount = 0;
816 union res_sockaddr_union u[MAXNS];
817 struct addrinfo *answer = NULL;
818 struct addrinfo *cur = NULL;
819 struct addrinfo hint;
821 memset(u, 0, sizeof(u));
822 res_t = res;
823 res_ninit(&res);
824 res.pfcode = 0;
825 res.options = RES_DEFAULT;
826 memset(&hint, 0, sizeof(hint));
827 hint.ai_socktype = SOCK_DGRAM;
828 if (!getaddrinfo(srv, NULL, &hint, &answer)) {
829 res = res_t;
830 cur = answer;
831 for (cur = answer;
832 cur != NULL;
833 cur = cur->ai_next) {
834 if (nscount == MAXNS)
835 break;
836 switch (cur->ai_addr->sa_family) {
837 case AF_INET6:
838 u[nscount].sin6 =
839 *(struct sockaddr_in6*)cur->ai_addr;
840 u[nscount++].sin6.sin6_port =
841 port;
842 break;
843 case AF_INET:
844 u[nscount].sin =
845 *(struct sockaddr_in*)cur->ai_addr;
846 u[nscount++].sin.sin_port =
847 port;
848 break;
851 if (nscount != 0)
852 res_setservers(&res, u, nscount);
853 freeaddrinfo(answer);
854 } else {
855 res = res_t;
856 fflush(stdout);
857 fprintf(stderr,
858 "; Bad server: %s -- using default server and timer opts\n",
859 srv);
860 fflush(stderr);
861 srv = NULL;
863 printf("; (%d server%s found)\n",
864 res.nscount, (res.nscount==1)?"":"s");
865 res.id += res.retry;
868 if (ns_t_xfr_p(xfr)) {
869 int i;
870 int nscount;
871 union res_sockaddr_union u[MAXNS];
872 nscount = res_getservers(&res, u, MAXNS);
873 for (i = 0; i < nscount; i++) {
874 int x;
876 if (keyfile)
877 x = printZone(xfr, domain,
878 &u[i].sin,
879 &key);
880 else
881 x = printZone(xfr, domain,
882 &u[i].sin,
883 NULL);
884 if (res.pfcode & RES_PRF_STATS) {
885 exectime = time(NULL);
886 printf(";; FROM: %s to SERVER: %s\n",
887 myhostname,
888 p_sockun(u[i], ubuf,
889 sizeof(ubuf)));
890 printf(";; WHEN: %s", ctime(&exectime));
892 if (!x)
893 break; /* success */
895 fflush(stdout);
896 continue;
899 if (*domain && !qtypeSet) {
900 queryType = T_A;
901 qtypeSet++;
904 bytes_out = n = res_nmkquery(&res, QUERY, domain,
905 queryClass, queryType,
906 NULL, 0, NULL,
907 packet, sizeof packet);
908 if (n < 0) {
909 fflush(stderr);
910 printf(";; res_nmkquery: buffer too small\n\n");
911 fflush(stdout);
912 continue;
914 if (queryType == T_IXFR) {
915 HEADER *hp = (HEADER *) packet;
916 u_char *cpp = packet + bytes_out;
918 hp->nscount = htons(1+ntohs(hp->nscount));
919 n = dn_comp(domain, cpp,
920 (sizeof packet) - (cpp - packet),
921 NULL, NULL);
922 cpp += n;
923 PUTSHORT(T_SOA, cpp); /* type */
924 PUTSHORT(C_IN, cpp); /* class */
925 PUTLONG(0, cpp); /* ttl */
926 PUTSHORT(22, cpp); /* dlen */
927 *cpp++ = 0; /* mname */
928 *cpp++ = 0; /* rname */
929 PUTLONG(ixfr_serial, cpp);
930 PUTLONG(0xDEAD, cpp); /* Refresh */
931 PUTLONG(0xBEEF, cpp); /* Retry */
932 PUTLONG(0xABCD, cpp); /* Expire */
933 PUTLONG(0x1776, cpp); /* Min TTL */
934 bytes_out = n = cpp - packet;
937 #if defined(RES_USE_EDNS0) && defined(RES_USE_DNSSEC)
938 if (n > 0 &&
939 (res.options & (RES_USE_EDNS0|RES_USE_DNSSEC)) != 0)
940 bytes_out = n = res_nopt(&res, n, packet,
941 sizeof(packet), 4096);
942 #endif
944 eecode = 0;
945 if (res.pfcode & RES_PRF_HEAD1)
946 fp_resstat(&res, stdout);
947 (void) gettimeofday(&start_time, NULL);
948 if (keyfile)
949 n = res_nsendsigned(&res, packet, n, &key,
950 answer.b, sizeof(answer.b));
951 else
952 n = res_nsend(&res, packet, n,
953 answer.b, sizeof(answer.b));
954 if ((bytes_in = n) < 0) {
955 fflush(stdout);
956 n = 0 - n;
957 if (keyfile)
958 strcpy(msg, ";; res_nsendsigned");
959 else
960 strcpy(msg, ";; res_nsend");
961 perror(msg);
962 fflush(stderr);
964 if (!dofile) {
965 if (eecode)
966 exit(eecode);
967 else
968 exit(9);
971 (void) gettimeofday(&end_time, NULL);
973 if (res.pfcode & RES_PRF_STATS) {
974 union res_sockaddr_union u[MAXNS];
976 (void) res_getservers(&res, u, MAXNS);
977 query_time = difftv(start_time, end_time);
978 printf(";; Total query time: ");
979 prnttime(query_time);
980 putchar('\n');
981 exectime = time(NULL);
982 printf(";; FROM: %s to SERVER: %s\n", myhostname,
983 p_sockun(u[RES_GETLAST(res)],
984 ubuf, sizeof(ubuf)));
985 printf(";; WHEN: %s", ctime(&exectime));
986 printf(";; MSG SIZE sent: %d rcvd: %d\n",
987 bytes_out, bytes_in);
990 fflush(stdout);
992 * Argh ... not particularly elegant. Should put in *real* ping code.
993 * Would necessitate root priviledges for icmp port though!
995 if (*pingstr && srv != NULL) {
996 sprintf(doping, pingfmt, pingstr, srv, DIG_TAIL);
997 system(doping);
999 putchar('\n');
1002 * Fairly crude method and low overhead method of keeping two
1003 * batches started at different sites somewhat synchronized.
1005 gettimeofday(&tv2, NULL);
1006 delay = (int)(tv2.tv_sec - tv1.tv_sec);
1007 if (delay < wait) {
1008 sleep(wait - delay);
1010 tv1 = tv2;
1012 return (eecode);
1015 /* Private. */
1017 static void
1018 Usage() {
1019 fputs("\
1020 usage: dig [@server] [domain] [q-type] [q-class] {q-opt} {d-opt} [%comment]\n\
1021 where: server,\n\
1022 domain are names in the Domain Name System\n\
1023 q-class is one of (in,any,...) [default: in]\n\
1024 q-type is one of (a,any,mx,ns,soa,hinfo,axfr,txt,...) [default: a]\n\
1025 ", stderr);
1026 fputs("\
1027 q-opt is one of:\n\
1028 -x dot-notation-address (shortcut to in-addr.arpa lookups)\n\
1029 -f file (batch mode input file name)\n\
1030 -T time (batch mode time delay, per query)\n\
1031 -p port (nameserver is on this port) [53]\n\
1032 -b addr[:port] (bind AXFR to this tcp address) [*]\n\
1033 -P[ping-string] (see man page)\n\
1034 -t query-type (synonym for q-type)\n\
1035 -c query-class (synonym for q-class)\n\
1036 -k keydir:keyname (sign the query with this TSIG key)\n\
1037 -envsav,-envset (see man page)\n\
1038 -[no]stick (see man page)\n\
1039 ", stderr);
1040 fputs("\
1041 d-opt is of the form ``+keyword=value'' where keyword is one of:\n\
1042 [no]debug [no]d2 [no]recurse retry=# time=# [no]ko [no]vc\n\
1043 [no]defname [no]search domain=NAME [no]ignore [no]primary\n\
1044 [no]aaonly [no]cmd [no]stats [no]Header [no]header [no]trunc\n\
1045 [no]ttlid [no]cl [no]qr [no]reply [no]ques [no]answer\n\
1046 [no]author [no]addit [no]dnssec pfdef pfmin\n\
1047 pfset=# pfand=# pfor=#\n\
1048 ", stderr);
1049 fprintf(stderr, "\
1050 notes: defname and search don't work; use fully-qualified names.\n\
1051 this is DiG version %s (libbind %d)\n\
1052 Id: dig8.c,v 1.4 2009/03/03 23:49:07 tbox Exp\n", VSTRING, __RES);
1055 static int
1056 setopt(const char *string) {
1057 char option[NAME_LEN], *ptr;
1058 int i;
1060 i = pickString(string, option, sizeof option);
1061 if (i == 0) {
1062 fprintf(stderr, ";*** Invalid option: %s\n", string);
1064 /* this is ugly, but fixing the caller to behave
1065 properly with an error return value would require a major
1066 cleanup. */
1067 exit(9);
1070 if (strncmp(option, "aa", 2) == 0) { /* aaonly */
1071 res.options |= RES_AAONLY;
1072 } else if (strncmp(option, "noaa", 4) == 0) {
1073 res.options &= ~RES_AAONLY;
1074 } else if (strncmp(option, "deb", 3) == 0) { /* debug */
1075 res.options |= RES_DEBUG;
1076 } else if (strncmp(option, "nodeb", 5) == 0) {
1077 res.options &= ~(RES_DEBUG | RES_DEBUG2);
1078 } else if (strncmp(option, "ko", 2) == 0) { /* keepopen */
1079 res.options |= (RES_STAYOPEN | RES_USEVC);
1080 } else if (strncmp(option, "noko", 4) == 0) {
1081 res.options &= ~RES_STAYOPEN;
1082 } else if (strncmp(option, "d2", 2) == 0) { /* d2 (more debug) */
1083 res.options |= (RES_DEBUG | RES_DEBUG2);
1084 } else if (strncmp(option, "nod2", 4) == 0) {
1085 res.options &= ~RES_DEBUG2;
1086 } else if (strncmp(option, "def", 3) == 0) { /* defname */
1087 res.options |= RES_DEFNAMES;
1088 } else if (strncmp(option, "nodef", 5) == 0) {
1089 res.options &= ~RES_DEFNAMES;
1090 } else if (strncmp(option, "dn", 2) == 0) { /* dnssec */
1091 res.options |= RES_USE_DNSSEC;
1092 } else if (strncmp(option, "nodn", 4) == 0) {
1093 res.options &= ~RES_USE_DNSSEC;
1094 } else if (strncmp(option, "sea", 3) == 0) { /* search list */
1095 res.options |= RES_DNSRCH;
1096 } else if (strncmp(option, "nosea", 5) == 0) {
1097 res.options &= ~RES_DNSRCH;
1098 } else if (strncmp(option, "do", 2) == 0) { /* domain */
1099 ptr = strchr(option, '=');
1100 if (ptr != NULL) {
1101 i = pickString(++ptr, res.defdname, sizeof res.defdname);
1102 if (i == 0) { /* value's too long or non-existant. This actually
1103 shouldn't happen due to pickString()
1104 above */
1105 fprintf(stderr, "*** Invalid domain: %s\n", ptr) ;
1106 exit(9); /* see comment at previous call to exit()*/
1109 } else if (strncmp(option, "ti", 2) == 0) { /* timeout */
1110 ptr = strchr(option, '=');
1111 if (ptr != NULL)
1112 sscanf(++ptr, "%d", &res.retrans);
1113 } else if (strncmp(option, "ret", 3) == 0) { /* retry */
1114 ptr = strchr(option, '=');
1115 if (ptr != NULL)
1116 sscanf(++ptr, "%d", &res.retry);
1117 } else if (strncmp(option, "i", 1) == 0) { /* ignore */
1118 res.options |= RES_IGNTC;
1119 } else if (strncmp(option, "noi", 3) == 0) {
1120 res.options &= ~RES_IGNTC;
1121 } else if (strncmp(option, "pr", 2) == 0) { /* primary */
1122 res.options |= RES_PRIMARY;
1123 } else if (strncmp(option, "nop", 3) == 0) {
1124 res.options &= ~RES_PRIMARY;
1125 } else if (strncmp(option, "rec", 3) == 0) { /* recurse */
1126 res.options |= RES_RECURSE;
1127 } else if (strncmp(option, "norec", 5) == 0) {
1128 res.options &= ~RES_RECURSE;
1129 } else if (strncmp(option, "v", 1) == 0) { /* vc */
1130 res.options |= RES_USEVC;
1131 } else if (strncmp(option, "nov", 3) == 0) {
1132 res.options &= ~RES_USEVC;
1133 } else if (strncmp(option, "pfset", 5) == 0) {
1134 ptr = strchr(option, '=');
1135 if (ptr != NULL)
1136 res.pfcode = xstrtonum(++ptr);
1137 } else if (strncmp(option, "pfand", 5) == 0) {
1138 ptr = strchr(option, '=');
1139 if (ptr != NULL)
1140 res.pfcode = res.pfcode & xstrtonum(++ptr);
1141 } else if (strncmp(option, "pfor", 4) == 0) {
1142 ptr = strchr(option, '=');
1143 if (ptr != NULL)
1144 res.pfcode |= xstrtonum(++ptr);
1145 } else if (strncmp(option, "pfmin", 5) == 0) {
1146 res.pfcode = PRF_MIN;
1147 } else if (strncmp(option, "pfdef", 5) == 0) {
1148 res.pfcode = PRF_DEF;
1149 } else if (strncmp(option, "an", 2) == 0) { /* answer section */
1150 res.pfcode |= RES_PRF_ANS;
1151 } else if (strncmp(option, "noan", 4) == 0) {
1152 res.pfcode &= ~RES_PRF_ANS;
1153 } else if (strncmp(option, "qu", 2) == 0) { /* question section */
1154 res.pfcode |= RES_PRF_QUES;
1155 } else if (strncmp(option, "noqu", 4) == 0) {
1156 res.pfcode &= ~RES_PRF_QUES;
1157 } else if (strncmp(option, "au", 2) == 0) { /* authority section */
1158 res.pfcode |= RES_PRF_AUTH;
1159 } else if (strncmp(option, "noau", 4) == 0) {
1160 res.pfcode &= ~RES_PRF_AUTH;
1161 } else if (strncmp(option, "ad", 2) == 0) { /* addition section */
1162 res.pfcode |= RES_PRF_ADD;
1163 } else if (strncmp(option, "noad", 4) == 0) {
1164 res.pfcode &= ~RES_PRF_ADD;
1165 } else if (strncmp(option, "tt", 2) == 0) { /* TTL & ID */
1166 res.pfcode |= RES_PRF_TTLID;
1167 } else if (strncmp(option, "nott", 4) == 0) {
1168 res.pfcode &= ~RES_PRF_TTLID;
1169 } else if (strncmp(option, "tr", 2) == 0) { /* TTL & ID */
1170 res.pfcode |= RES_PRF_TRUNC;
1171 } else if (strncmp(option, "notr", 4) == 0) {
1172 res.pfcode &= ~RES_PRF_TRUNC;
1173 } else if (strncmp(option, "he", 2) == 0) { /* head flags stats */
1174 res.pfcode |= RES_PRF_HEAD2;
1175 } else if (strncmp(option, "nohe", 4) == 0) {
1176 res.pfcode &= ~RES_PRF_HEAD2;
1177 } else if (strncmp(option, "H", 1) == 0) { /* header all */
1178 res.pfcode |= RES_PRF_HEADX;
1179 } else if (strncmp(option, "noH", 3) == 0) {
1180 res.pfcode &= ~(RES_PRF_HEADX);
1181 } else if (strncmp(option, "qr", 2) == 0) { /* query */
1182 res.pfcode |= RES_PRF_QUERY;
1183 } else if (strncmp(option, "noqr", 4) == 0) {
1184 res.pfcode &= ~RES_PRF_QUERY;
1185 } else if (strncmp(option, "rep", 3) == 0) { /* reply */
1186 res.pfcode |= RES_PRF_REPLY;
1187 } else if (strncmp(option, "norep", 5) == 0) {
1188 res.pfcode &= ~RES_PRF_REPLY;
1189 } else if (strncmp(option, "cm", 2) == 0) { /* command line */
1190 res.pfcode |= RES_PRF_CMD;
1191 } else if (strncmp(option, "nocm", 4) == 0) {
1192 res.pfcode &= ~RES_PRF_CMD;
1193 } else if (strncmp(option, "cl", 2) == 0) { /* class mnemonic */
1194 res.pfcode |= RES_PRF_CLASS;
1195 } else if (strncmp(option, "nocl", 4) == 0) {
1196 res.pfcode &= ~RES_PRF_CLASS;
1197 } else if (strncmp(option, "st", 2) == 0) { /* stats*/
1198 res.pfcode |= RES_PRF_STATS;
1199 } else if (strncmp(option, "nost", 4) == 0) {
1200 res.pfcode &= ~RES_PRF_STATS;
1201 } else {
1202 fprintf(stderr, "; *** Invalid option: %s\n", option);
1203 return (ERROR);
1205 res_re_init();
1206 return (SUCCESS);
1210 * Force a reinitialization when the domain is changed.
1212 static void
1213 res_re_init() {
1214 static char localdomain[] = "LOCALDOMAIN";
1215 u_long pfcode = res.pfcode, options = res.options;
1216 unsigned ndots = res.ndots;
1217 int retrans = res.retrans, retry = res.retry;
1218 char *buf;
1221 * This is ugly but putenv() is more portable than setenv().
1223 buf = malloc((sizeof localdomain) + strlen(res.defdname) +10/*fuzz*/);
1224 sprintf(buf, "%s=%s", localdomain, res.defdname);
1225 putenv(buf); /* keeps the argument, so we won't free it */
1226 res_ninit(&res);
1227 res.pfcode = pfcode;
1228 res.options = options;
1229 res.ndots = ndots;
1230 res.retrans = retrans;
1231 res.retry = retry;
1235 * convert char string (decimal, octal, or hex) to integer
1237 static int
1238 xstrtonum(char *p) {
1239 int v = 0;
1240 int i;
1241 int b = 10;
1242 int flag = 0;
1243 while (*p != 0) {
1244 if (!flag++)
1245 if (*p == '0') {
1246 b = 8; p++;
1247 continue;
1249 if (isupper((unsigned char)*p))
1250 *p = tolower(*p);
1251 if (*p == 'x') {
1252 b = 16; p++;
1253 continue;
1255 if (isdigit((unsigned char)*p)) {
1256 i = *p - '0';
1257 } else if (isxdigit((unsigned char)*p)) {
1258 i = *p - 'a' + 10;
1259 } else {
1260 fprintf(stderr,
1261 "; *** Bad char in numeric string..ignored\n");
1262 i = -1;
1264 if (i >= b) {
1265 fprintf(stderr,
1266 "; *** Bad char in numeric string..ignored\n");
1267 i = -1;
1269 if (i >= 0)
1270 v = v * b + i;
1271 p++;
1273 return (v);
1276 typedef union {
1277 HEADER qb1;
1278 u_char qb2[PACKETSZ];
1279 } querybuf;
1281 static int
1282 printZone(ns_type xfr, const char *zone, const struct sockaddr_in *sin,
1283 ns_tsig_key *key)
1285 static u_char *answer = NULL;
1286 static int answerLen = 0;
1288 querybuf buf;
1289 int msglen, amtToRead, numRead, result, sockFD, len;
1290 int count, type, rlen, done, n;
1291 int numAnswers, numRecords, soacnt;
1292 u_char *cp, tmp[NS_INT16SZ];
1293 char dname[2][NS_MAXDNAME];
1294 enum { NO_ERRORS, ERR_READING_LEN, ERR_READING_MSG, ERR_PRINTING }
1295 error;
1296 pid_t zpid = -1;
1297 u_char *newmsg;
1298 int newmsglen;
1299 ns_tcp_tsig_state tsig_state;
1300 int tsig_ret, tsig_required, tsig_present;
1302 switch (xfr) {
1303 case ns_t_axfr:
1304 case ns_t_zxfr:
1305 break;
1306 default:
1307 fprintf(stderr, ";; %s - transfer type not supported\n",
1308 p_type(xfr));
1309 return (ERROR);
1313 * Create a query packet for the requested zone name.
1315 msglen = res_nmkquery(&res, ns_o_query, zone,
1316 queryClass, ns_t_axfr, NULL,
1317 0, 0, buf.qb2, sizeof buf);
1318 if (msglen < 0) {
1319 if (res.options & RES_DEBUG)
1320 fprintf(stderr, ";; res_nmkquery failed\n");
1321 return (ERROR);
1325 * Sign the message if a key was sent
1327 if (key == NULL) {
1328 newmsg = (u_char *)&buf;
1329 newmsglen = msglen;
1330 } else {
1331 DST_KEY *dstkey;
1332 int bufsize, siglen;
1333 u_char sig[64];
1334 int ret;
1336 /* ns_sign() also calls dst_init(), but there is no harm
1337 * doing it twice
1339 dst_init();
1341 bufsize = msglen + 1024;
1342 newmsg = (u_char *) malloc(bufsize);
1343 if (newmsg == NULL) {
1344 errno = ENOMEM;
1345 return (-1);
1347 memcpy(newmsg, (u_char *)&buf, msglen);
1348 newmsglen = msglen;
1350 if (strcmp(key->alg, NS_TSIG_ALG_HMAC_MD5) != 0)
1351 dstkey = NULL;
1352 else
1353 dstkey = dst_buffer_to_key(key->name, KEY_HMAC_MD5,
1354 NS_KEY_TYPE_AUTH_ONLY,
1355 NS_KEY_PROT_ANY,
1356 key->data, key->len);
1357 if (dstkey == NULL) {
1358 errno = EINVAL;
1359 if (key)
1360 free(newmsg);
1361 return (-1);
1364 siglen = sizeof(sig);
1365 /* newmsglen++; */
1366 ret = ns_sign(newmsg, &newmsglen, bufsize, NOERROR, dstkey, NULL, 0,
1367 sig, &siglen, 0);
1368 if (ret < 0) {
1369 if (key)
1370 free (newmsg);
1371 if (ret == NS_TSIG_ERROR_NO_SPACE)
1372 errno = EMSGSIZE;
1373 else if (ret == -1)
1374 errno = EINVAL;
1375 return (ret);
1377 ns_verify_tcp_init(dstkey, sig, siglen, &tsig_state);
1381 * Set up a virtual circuit to the server.
1383 if ((sockFD = socket(sin->sin_family, SOCK_STREAM, 0)) < 0) {
1384 int e = errno;
1386 perror(";; socket");
1387 return (e);
1390 switch (sin->sin_family) {
1391 case AF_INET:
1392 if (bind(sockFD, (struct sockaddr *)&myaddress,
1393 sizeof myaddress) < 0){
1394 int e = errno;
1396 fprintf(stderr, ";; bind(%s port %u): %s\n",
1397 inet_ntoa(myaddress.sin_addr),
1398 ntohs(myaddress.sin_port),
1399 strerror(e));
1400 (void) close(sockFD);
1401 sockFD = -1;
1402 return (e);
1404 if (connect(sockFD, (const struct sockaddr *)sin,
1405 sizeof *sin) < 0) {
1406 int e = errno;
1408 perror(";; connect");
1409 (void) close(sockFD);
1410 sockFD = -1;
1411 return (e);
1413 break;
1414 case AF_INET6:
1415 if (bind(sockFD, (struct sockaddr *)&myaddress6,
1416 sizeof myaddress6) < 0){
1417 int e = errno;
1418 char buf[80];
1420 fprintf(stderr, ";; bind(%s port %u): %s\n",
1421 inet_ntop(AF_INET6, &myaddress6.sin6_addr,
1422 buf, sizeof(buf)),
1423 ntohs(myaddress6.sin6_port),
1424 strerror(e));
1425 (void) close(sockFD);
1426 sockFD = -1;
1427 return (e);
1429 if (connect(sockFD, (const struct sockaddr *)sin,
1430 sizeof(struct sockaddr_in6)) < 0) {
1431 int e = errno;
1433 perror(";; connect");
1434 (void) close(sockFD);
1435 sockFD = -1;
1436 return (e);
1438 break;
1442 * Send length & message for zone transfer
1445 ns_put16(newmsglen, tmp);
1446 if (write(sockFD, (char *)tmp, NS_INT16SZ) != NS_INT16SZ ||
1447 write(sockFD, (char *)newmsg, newmsglen) != newmsglen) {
1448 int e = errno;
1449 if (key)
1450 free (newmsg);
1451 perror(";; write");
1452 (void) close(sockFD);
1453 sockFD = -1;
1454 return (e);
1455 } else if (key)
1456 free (newmsg);
1459 * If we're compressing, push a gzip into the pipeline.
1461 if (xfr == ns_t_zxfr) {
1462 enum { rd = 0, wr = 1 };
1463 int z[2];
1465 if (pipe(z) < 0) {
1466 int e = errno;
1468 perror(";; pipe");
1469 (void) close(sockFD);
1470 sockFD = -1;
1471 return (e);
1473 zpid = vfork();
1474 if (zpid < 0) {
1475 int e = errno;
1477 perror(";; fork");
1478 (void) close(sockFD);
1479 sockFD = -1;
1480 return (e);
1481 } else if (zpid == 0) {
1482 /* Child. */
1483 (void) close(z[rd]);
1484 (void) dup2(sockFD, STDIN_FILENO);
1485 (void) close(sockFD);
1486 (void) dup2(z[wr], STDOUT_FILENO);
1487 (void) close(z[wr]);
1488 execlp("gzip", "gzip", "-d", "-v", NULL);
1489 perror(";; child: execlp(gunzip)");
1490 _exit(1);
1492 /* Parent. */
1493 (void) close(z[wr]);
1494 (void) dup2(z[rd], sockFD);
1495 (void) close(z[rd]);
1497 result = 0;
1498 numAnswers = 0;
1499 numRecords = 0;
1500 soacnt = 0;
1501 error = NO_ERRORS;
1502 numRead = 0;
1504 dname[0][0] = '\0';
1505 for (done = 0; !done; (void)NULL) {
1507 * Read the length of the response.
1510 cp = tmp;
1511 amtToRead = INT16SZ;
1512 while (amtToRead > 0 &&
1513 (numRead = read(sockFD, cp, amtToRead)) > 0) {
1514 cp += numRead;
1515 amtToRead -= numRead;
1517 if (numRead <= 0) {
1518 error = ERR_READING_LEN;
1519 break;
1522 len = ns_get16(tmp);
1523 if (len == 0)
1524 break; /* nothing left to read */
1527 * The server sent too much data to fit the existing buffer --
1528 * allocate a new one.
1530 if (len > answerLen) {
1531 if (answerLen != 0)
1532 free(answer);
1533 answerLen = len;
1534 answer = (u_char *)malloc(answerLen);
1538 * Read the response.
1541 amtToRead = len;
1542 cp = answer;
1543 while (amtToRead > 0 &&
1544 (numRead = read(sockFD, cp, amtToRead)) > 0) {
1545 cp += numRead;
1546 amtToRead -= numRead;
1548 if (numRead <= 0) {
1549 error = ERR_READING_MSG;
1550 break;
1553 result = print_axfr(stdout, answer, len);
1554 if (result != 0) {
1555 error = ERR_PRINTING;
1556 break;
1558 numRecords += htons(((HEADER *)answer)->ancount);
1559 numAnswers++;
1561 /* Header. */
1562 cp = answer + HFIXEDSZ;
1563 /* Question. */
1564 for (count = ntohs(((HEADER *)answer)->qdcount);
1565 count > 0;
1566 count--) {
1567 n = dn_skipname(cp, answer + len);
1568 if (n < 0) {
1569 error = ERR_PRINTING;
1570 done++;
1571 break;
1573 cp += n + QFIXEDSZ;
1574 if (cp > answer + len) {
1575 error = ERR_PRINTING;
1576 done++;
1577 break;
1580 /* Answer. */
1581 for (count = ntohs(((HEADER *)answer)->ancount);
1582 count > 0 && !done;
1583 count--) {
1584 n = dn_expand(answer, answer + len, cp,
1585 dname[soacnt], sizeof dname[0]);
1586 if (n < 0) {
1587 error = ERR_PRINTING;
1588 done++;
1589 break;
1591 cp += n;
1592 if (cp + 3 * INT16SZ + INT32SZ > answer + len) {
1593 error = ERR_PRINTING;
1594 done++;
1595 break;
1597 GETSHORT(type, cp);
1598 cp += INT16SZ;
1599 cp += INT32SZ; /* ttl */
1600 GETSHORT(rlen, cp);
1601 cp += rlen;
1602 if (cp > answer + len) {
1603 error = ERR_PRINTING;
1604 done++;
1605 break;
1607 if (type == T_SOA && soacnt++ &&
1608 ns_samename(dname[0], dname[1]) == 1) {
1609 done++;
1610 break;
1615 * Verify the TSIG
1618 if (key) {
1619 if (ns_find_tsig(answer, answer + len) != NULL)
1620 tsig_present = 1;
1621 else
1622 tsig_present = 0;
1623 if (numAnswers == 1 || soacnt > 1)
1624 tsig_required = 1;
1625 else
1626 tsig_required = 0;
1627 tsig_ret = ns_verify_tcp(answer, &len, &tsig_state,
1628 tsig_required);
1629 if (tsig_ret == 0) {
1630 if (tsig_present)
1631 printf("; TSIG ok\n");
1633 else
1634 printf("; TSIG invalid\n");
1639 printf(";; Received %d answer%s (%d record%s).\n",
1640 numAnswers, (numAnswers != 1) ? "s" : "",
1641 numRecords, (numRecords != 1) ? "s" : "");
1643 (void) close(sockFD);
1644 sockFD = -1;
1647 * If we were uncompressing, reap the uncompressor.
1649 if (xfr == ns_t_zxfr) {
1650 pid_t pid;
1651 int status = 0;
1653 pid = wait(&status);
1654 if (pid < 0) {
1655 int e = errno;
1657 perror(";; wait");
1658 return (e);
1660 if (pid != zpid) {
1661 fprintf(stderr, ";; wrong pid (%lu != %lu)\n",
1662 (u_long)pid, (u_long)zpid);
1663 return (ERROR);
1665 printf(";; pid %lu: exit %d, signal %d, core %c\n",
1666 (u_long)pid, WEXITSTATUS(status),
1667 WIFSIGNALED(status) ? WTERMSIG(status) : 0,
1668 WCOREDUMP(status) ? 't' : 'f');
1671 switch (error) {
1672 case NO_ERRORS:
1673 return (0);
1675 case ERR_READING_LEN:
1676 return (EMSGSIZE);
1678 case ERR_PRINTING:
1679 return (result);
1681 case ERR_READING_MSG:
1682 return (EMSGSIZE);
1684 default:
1685 return (EFAULT);
1689 static int
1690 print_axfr(FILE *file, const u_char *msg, size_t msglen) {
1691 ns_msg handle;
1693 if (ns_initparse(msg, msglen, &handle) < 0) {
1694 fprintf(file, ";; ns_initparse: %s\n", strerror(errno));
1695 return (ns_r_formerr);
1697 if (ns_msg_getflag(handle, ns_f_rcode) != ns_r_noerror)
1698 return (ns_msg_getflag(handle, ns_f_rcode));
1701 * We are looking for info from answer resource records.
1702 * If there aren't any, return with an error. We assume
1703 * there aren't any question records.
1705 if (ns_msg_count(handle, ns_s_an) == 0)
1706 return (NO_INFO);
1708 #ifdef PROTOCOLDEBUG
1709 printf(";;; (message of %d octets has %d answers)\n",
1710 msglen, ns_msg_count(handle, ns_s_an));
1711 #endif
1712 for (;;) {
1713 static char origin[NS_MAXDNAME], name_ctx[NS_MAXDNAME];
1714 const char *name;
1715 char buf[2048]; /* XXX need to malloc/realloc. */
1716 ns_rr rr;
1718 if (ns_parserr(&handle, ns_s_an, -1, &rr)) {
1719 if (errno != ENODEV) {
1720 fprintf(file, ";; ns_parserr: %s\n",
1721 strerror(errno));
1722 return (FORMERR);
1724 break;
1726 name = ns_rr_name(rr);
1727 if (origin[0] == '\0' && name[0] != '\0') {
1728 if (strcmp(name, ".") != 0)
1729 strcpy(origin, name);
1730 fprintf(file, "$ORIGIN %s.\n", origin);
1731 if (strcmp(name, ".") == 0)
1732 strcpy(origin, name);
1733 if (res.pfcode & RES_PRF_TRUNC)
1734 strcpy(name_ctx, "@");
1736 if (ns_sprintrr(&handle, &rr,
1737 (res.pfcode & RES_PRF_TRUNC) ? name_ctx : NULL,
1738 (res.pfcode & RES_PRF_TRUNC) ? origin : NULL,
1739 buf, sizeof buf) < 0) {
1740 fprintf(file, ";; ns_sprintrr: %s\n", strerror(errno));
1741 return (FORMERR);
1743 strcpy(name_ctx, name);
1744 fputs(buf, file);
1745 fputc('\n', file);
1747 return (SUCCESS);
1750 static struct timeval
1751 difftv(struct timeval a, struct timeval b) {
1752 static struct timeval diff;
1754 diff.tv_sec = b.tv_sec - a.tv_sec;
1755 if ((diff.tv_usec = b.tv_usec - a.tv_usec) < 0) {
1756 diff.tv_sec--;
1757 diff.tv_usec += 1000000;
1759 return (diff);
1762 static void
1763 prnttime(struct timeval t) {
1764 printf("%lu msec", (u_long)(t.tv_sec * 1000 + (t.tv_usec / 1000)));
1768 * Take arguments appearing in simple string (from file or command line)
1769 * place in char**.
1771 static void
1772 stackarg(char *l, char **y) {
1773 int done = 0;
1775 while (!done) {
1776 switch (*l) {
1777 case '\t':
1778 case ' ':
1779 l++;
1780 break;
1781 case '\0':
1782 case '\n':
1783 done++;
1784 *y = NULL;
1785 break;
1786 default:
1787 *y++ = l;
1788 while (!isspace((unsigned char)*l))
1789 l++;
1790 if (*l == '\n')
1791 done++;
1792 *l++ = '\0';
1793 *y = NULL;
1798 static void
1799 reverse6(char *domain, struct in6_addr *in6) {
1800 sprintf(domain, "%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.ip6.arpa",
1801 in6->s6_addr[15] & 0x0f, (in6->s6_addr[15] >> 4) & 0x0f,
1802 in6->s6_addr[14] & 0x0f, (in6->s6_addr[14] >> 4) & 0x0f,
1803 in6->s6_addr[13] & 0x0f, (in6->s6_addr[13] >> 4) & 0x0f,
1804 in6->s6_addr[12] & 0x0f, (in6->s6_addr[12] >> 4) & 0x0f,
1805 in6->s6_addr[11] & 0x0f, (in6->s6_addr[11] >> 4) & 0x0f,
1806 in6->s6_addr[10] & 0x0f, (in6->s6_addr[10] >> 4) & 0x0f,
1807 in6->s6_addr[9] & 0x0f, (in6->s6_addr[9] >> 4) & 0x0f,
1808 in6->s6_addr[8] & 0x0f, (in6->s6_addr[8] >> 4) & 0x0f,
1809 in6->s6_addr[7] & 0x0f, (in6->s6_addr[7] >> 4) & 0x0f,
1810 in6->s6_addr[6] & 0x0f, (in6->s6_addr[6] >> 4) & 0x0f,
1811 in6->s6_addr[5] & 0x0f, (in6->s6_addr[5] >> 4) & 0x0f,
1812 in6->s6_addr[4] & 0x0f, (in6->s6_addr[4] >> 4) & 0x0f,
1813 in6->s6_addr[3] & 0x0f, (in6->s6_addr[3] >> 4) & 0x0f,
1814 in6->s6_addr[2] & 0x0f, (in6->s6_addr[2] >> 4) & 0x0f,
1815 in6->s6_addr[1] & 0x0f, (in6->s6_addr[1] >> 4) & 0x0f,
1816 in6->s6_addr[0] & 0x0f, (in6->s6_addr[0] >> 4) & 0x0f);