1/* $NetBSD$ */ 2 3/* 4 * Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC") 5 * 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. 9 * 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. 17 */ 18 19#ifndef lint 20static const char rcsid[] = "Id: dig8.c,v 1.4 2009/03/03 23:49:07 tbox Exp "; 21#endif 22 23/* 24 * Copyright (c) 1989 25 * The Regents of the University of California. All rights reserved. 26 * 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. 42 * 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. 54 */ 55 56/* 57 * Portions Copyright (c) 1993 by Digital Equipment Corporation. 58 * 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. 65 * 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. 74 */ 75 76/* 77 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") 78 * Portions Copyright (c) 1996-1999 by Internet Software Consortium 79 * 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. 83 * 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. 91 */ 92 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. 100 * 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. 109 * 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. 114 * 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). 121 * 122 * Paul Vixie, Palo Alto, CA, April 1993 123 **************************************************************************** 124 125 ****************************************************************** 126 * DiG -- Domain Information Groper * 127 * * 128 * dig.c - Version 2.1 (7/12/94) ("BIND takeover") * 129 * * 130 * Developed by: Steve Hotz & Paul Mockapetris * 131 * USC Information Sciences Institute (USC-ISI) * 132 * Marina del Rey, California * 133 * 1989 * 134 * * 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 * 143 * * 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 * 148 * * 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 * 153 * * 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 * 162 * * 163 * Version 1.0 (3/27/89) * 164 * o original release * 165 * * 166 * DiG is Public Domain, and may be used for any purpose as * 167 * long as this notice is not removed. * 168 ******************************************************************/ 169 170/* Import. */ 171 172#include "port_before.h" 173 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> 181 182#include <netinet/in.h> 183#include <arpa/inet.h> 184#include <arpa/nameser.h> 185 186#include <isc/dst.h> 187 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) */ 199 200#include "port_after.h" 201 202#include <resolv.h> 203 204#include "res.h" 205 206/* Global. */ 207 208#define VERSION 84 209#define VSTRING "8.4" 210 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) 220 221#ifndef MAXHOSTNAMELEN 222#define MAXHOSTNAMELEN 256 223#endif 224 225#define SAVEENV "DiG.env" 226#define DIG_MAXARGS 30 227 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 237 238static int eecode = 0; 239static FILE * qfp; 240static char myhostname[MAXHOSTNAMELEN]; 241static struct sockaddr_in myaddress; 242static struct sockaddr_in6 myaddress6; 243static u_int32_t ixfr_serial; 244static char ubuf[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:123.123.123.123")]; 245 246/* stuff for nslookup modules */ 247struct __res_state res; 248FILE *filePtr; 249jmp_buf env; 250HostInfo *defaultPtr = NULL; 251HostInfo curHostInfo, defaultRec; 252int curHostValid = FALSE; 253int queryType, queryClass; 254extern int StringToClass(), StringToType(); /* subr.c */ 255#if defined(BSD) && BSD >= 199006 && !defined(RISCOS_BSD) 256FILE *yyin = NULL; 257void yyrestart(FILE *f); 258void yyrestart(FILE *f) { UNUSED(f); } 259#endif 260char *pager = NULL; 261/* end of nslookup stuff */ 262 263/* Forward. */ 264 265static void Usage(void); 266static int setopt(const char *); 267static void res_re_init(void); 268static int xstrtonum(char *); 269static int printZone(ns_type, const char *, 270 const struct sockaddr_in *, ns_tsig_key *); 271static int print_axfr(FILE *output, const u_char *msg, 272 size_t msglen); 273static struct timeval difftv(struct timeval, struct timeval); 274static void prnttime(struct timeval); 275static void stackarg(char *, char **); 276static void reverse6(char *, struct in6_addr *); 277 278/* Public. */ 279 280int 281main(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; 300 301 time_t exectime; 302 struct timeval tv1, tv2, start_time, end_time, query_time; 303 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; 311 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; 325 326 ns_tsig_key key; 327 char *keyfile = NULL, *keyname = NULL; 328 const char *pingfmt = NULL; 329 330 UNUSED(argc); 331 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*/; 343 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*/; 350 351 res_x = res; 352 353/* 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. 357 */ 358 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; 365 } 366/* 367 * Check for batch-mode DiG; also pre-scan for 'help'. 368 */ 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); 378 } 379 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); 387 } 388 } else { 389 if (ax - args == DIG_MAXARGS) { 390 fprintf(stderr, "dig: too many arguments\n"); 391 exit(10); 392 } 393 *ax++ = *vtmp; 394 } 395 vtmp++; 396 } 397 398 gettimeofday(&tv1, NULL); 399 400/* 401 * Main section: once if cmd-line query 402 * while !EOF if batch mode 403 */ 404 *fileq = '\0'; 405 while ((dofile && fgets(fileq, sizeof fileq, qfp) != NULL) || 406 (!dofile && once--)) 407 { 408 if (*fileq == '\n' || *fileq == '#' || *fileq==';') { 409 printf("%s", fileq); /* echo but otherwise ignore */ 410 continue; /* blank lines and comments */ 411 } 412 413/* 414 * "Sticky" requests that before current parsing args 415 * return to current "working" environment (X******). 416 */ 417 if (sticky) { 418 printf(";; (using sticky settings)\n"); 419 res = res_x; 420 } 421 422/* 423 * Concat cmd-line and file args. 424 */ 425 stackarg(fileq, ax); 426 427 /* defaults */ 428 queryType = ns_t_ns; 429 queryClass = ns_c_in; 430 xfr = ns_t_invalid; 431 *pingstr = 0; 432 srv = NULL; 433 434 sprintf(cmd, "\n; <<>> DiG %s (libbind %d) <<>> ", 435 VSTRING, __RES); 436 argv = args; 437 /* argc = ax - args; */ 438/* 439 * More cmd-line options than anyone should ever have to 440 * deal with .... 441 */ 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); 447 } 448 strcat(cmd, *argv); 449 strcat(cmd, " "); 450 if (**argv == '@') { 451 srv = (*argv+1); 452 continue; 453 } 454 if (**argv == '%') 455 continue; 456 if (**argv == '+') { 457 setopt(*argv+1); 458 continue; 459 } 460 if (**argv == '=') { 461 ixfr_serial = strtoul(*argv+1, NULL, 0); 462 continue; 463 } 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; 476 } 477 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" 499 ); 500 } 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++; 512 } 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++; 521 } 522 } else { 523 printf( 524 "; invalid type specified\n" 525 ); 526 } 527 break; 528 case 'x': 529 if (!qtypeSet) { 530 queryType = T_ANY; 531 qtypeSet++; 532 } 533 if ((addrc = *++argv) == NULL) { 534 printf("; no arg for -x?\n"); 535 break; 536 } 537 r = inet_pton(AF_INET6, addrc, &in6); 538 if (r > 0) { 539 reverse6(domain, &in6); 540 break; 541 } 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'; 550 } 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; 570 } 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; 582 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; 605 } 606 break; 607 case 'k': 608 /* -k keydir:keyname */ 609 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; 617 618 keyname = strchr(keyfile, ':'); 619 if (keyname == NULL) { 620 fprintf(stderr, 621 "key option argument should be keydir:keyname\n"); 622 exit(1); 623 } 624 *keyname++='\0'; 625 break; 626 } /* switch - */ 627 continue; 628 } /* if '-' */ 629 630 if ((tmp = StringToType(*argv, -1, NULL)) != -1) { 631 if ((T_ANY == tmp) && anyflag++) { 632 queryClass = C_ANY; 633 continue; 634 } 635 if (ns_t_xfr_p(tmp) && 636 (tmp == ns_t_axfr || 637 (res.options & RES_USEVC) != 0) 638 ) { 639 res.pfcode = PRF_ZONE; 640 xfr = (ns_type)tmp; 641 } else { 642 queryType = tmp; 643 qtypeSet++; 644 } 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); 651 } 652 } /* while argv remains */ 653 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; 661 662 fp = fopen(keyfile, "r"); 663 if (fp == NULL) { 664 perror(keyfile); 665 exit(1); 666 } 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); 672 } 673 fclose(fp); 674 675 p = buf; 676 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 */ 683 } 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 */ 688 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 */ 694 } 695 p+=n1; /* advance pointer */ 696 if (sscanf((char *)p, "%d", &alg)!=1) { 697 fprintf(stderr, "Invalid key file format\n"); 698 exit(1); 699 } 700 while (*p++!='\n'); /* skip to end of line */ 701 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 */ 707 } 708 p+=n1; /* advance pointer */ 709 pp=p; 710 while (*pp++!='\n'); /* skip to end of line, 711 * terminate it */ 712 *--pp='\0'; 713 714 key.data=malloc(1024*sizeof(char)); 715 key.len=b64_pton(p, key.data, 1024); 716 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 721 * 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. 726 */ 727 DST_KEY *dst_key; 728 char cwd[PATH_MAX+1]; 729 730 if (getcwd(cwd, PATH_MAX)==NULL) { 731 perror("unable to get current directory"); 732 exit(1); 733 } 734 if (chdir(keyfile)<0) { 735 fprintf(stderr, 736 "unable to chdir to %s: %s\n", keyfile, 737 strerror(errno)); 738 exit(1); 739 } 740 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); 749 } 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; 753 754 strcpy(key.name, keyname); 755 strcpy(key.alg, "HMAC-MD5.SIG-ALG.REG.INT"); 756 757 if (chdir(cwd)<0) { 758 fprintf(stderr, "unable to chdir to %s: %s\n", 759 cwd, strerror(errno)); 760 exit(1); 761 } 762#endif 763 } 764 765 if (res.pfcode & 0x80000) 766 printf("; pfcode: %08lx, options: %08lx\n", 767 (unsigned long)res.pfcode, 768 (unsigned long)res.options); 769 770/* 771 * Current env. (after this parse) is to become the 772 * new "working" environmnet. Used in conj. with sticky. 773 */ 774 if (envset) { 775 res_x = res; 776 envset = 0; 777 } 778 779/* 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"). 783 */ 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)) 790 || 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); 796 } 797 envsave = 0; 798 } 799 800 if (res.pfcode & RES_PRF_CMD) 801 printf("%s\n", cmd); 802 803 anyflag = 0; 804 805/* 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". 812 */ 813 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; 820 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; 849 } 850 } 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; 862 } 863 printf("; (%d server%s found)\n", 864 res.nscount, (res.nscount==1)?"":"s"); 865 res.id += res.retry; 866 } 867 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; 875 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)); 891 } 892 if (!x) 893 break; /* success */ 894 } 895 fflush(stdout); 896 continue; 897 } 898 899 if (*domain && !qtypeSet) { 900 queryType = T_A; 901 qtypeSet++; 902 } 903 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; 913 } 914 if (queryType == T_IXFR) { 915 HEADER *hp = (HEADER *) packet; 916 u_char *cpp = packet + bytes_out; 917 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; 935 }; 936 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 943 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); 963 964 if (!dofile) { 965 if (eecode) 966 exit(eecode); 967 else 968 exit(9); 969 } 970 } 971 (void) gettimeofday(&end_time, NULL); 972 973 if (res.pfcode & RES_PRF_STATS) { 974 union res_sockaddr_union u[MAXNS]; 975 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); 988 } 989 990 fflush(stdout); 991/* 992 * Argh ... not particularly elegant. Should put in *real* ping code. 993 * Would necessitate root priviledges for icmp port though! 994 */ 995 if (*pingstr && srv != NULL) { 996 sprintf(doping, pingfmt, pingstr, srv, DIG_TAIL); 997 system(doping); 998 } 999 putchar('\n'); 1000 1001/* 1002 * Fairly crude method and low overhead method of keeping two 1003 * batches started at different sites somewhat synchronized. 1004 */ 1005 gettimeofday(&tv2, NULL); 1006 delay = (int)(tv2.tv_sec - tv1.tv_sec); 1007 if (delay < wait) { 1008 sleep(wait - delay); 1009 } 1010 tv1 = tv2; 1011 } 1012 return (eecode); 1013} 1014 1015/* Private. */ 1016 1017static void 1018Usage() { 1019 fputs("\ 1020usage: dig [@server] [domain] [q-type] [q-class] {q-opt} {d-opt} [%comment]\n\ 1021where: 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, "\ 1050notes: 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); 1053} 1054 1055static int 1056setopt(const char *string) { 1057 char option[NAME_LEN], *ptr; 1058 int i; 1059 1060 i = pickString(string, option, sizeof option); 1061 if (i == 0) { 1062 fprintf(stderr, ";*** Invalid option: %s\n", string); 1063 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); 1068 } 1069 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()*/ 1107 } 1108 } 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); 1204 } 1205 res_re_init(); 1206 return (SUCCESS); 1207} 1208 1209/* 1210 * Force a reinitialization when the domain is changed. 1211 */ 1212static void 1213res_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; 1219 1220 /* 1221 * This is ugly but putenv() is more portable than setenv(). 1222 */ 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; 1232} 1233 1234/* 1235 * convert char string (decimal, octal, or hex) to integer 1236 */ 1237static int 1238xstrtonum(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; 1248 } 1249 if (isupper((unsigned char)*p)) 1250 *p = tolower(*p); 1251 if (*p == 'x') { 1252 b = 16; p++; 1253 continue; 1254 } 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; 1263 } 1264 if (i >= b) { 1265 fprintf(stderr, 1266 "; *** Bad char in numeric string..ignored\n"); 1267 i = -1; 1268 } 1269 if (i >= 0) 1270 v = v * b + i; 1271 p++; 1272 } 1273 return (v); 1274} 1275 1276typedef union { 1277 HEADER qb1; 1278 u_char qb2[PACKETSZ]; 1279} querybuf; 1280 1281static int 1282printZone(ns_type xfr, const char *zone, const struct sockaddr_in *sin, 1283 ns_tsig_key *key) 1284{ 1285 static u_char *answer = NULL; 1286 static int answerLen = 0; 1287 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; 1301 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); 1310 } 1311 1312 /* 1313 * Create a query packet for the requested zone name. 1314 */ 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); 1322 } 1323 1324 /* 1325 * Sign the message if a key was sent 1326 */ 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; 1335 1336 /* ns_sign() also calls dst_init(), but there is no harm 1337 * doing it twice 1338 */ 1339 dst_init(); 1340 1341 bufsize = msglen + 1024; 1342 newmsg = (u_char *) malloc(bufsize); 1343 if (newmsg == NULL) { 1344 errno = ENOMEM; 1345 return (-1); 1346 } 1347 memcpy(newmsg, (u_char *)&buf, msglen); 1348 newmsglen = msglen; 1349 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); 1362 } 1363 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); 1376 } 1377 ns_verify_tcp_init(dstkey, sig, siglen, &tsig_state); 1378 } 1379 1380 /* 1381 * Set up a virtual circuit to the server. 1382 */ 1383 if ((sockFD = socket(sin->sin_family, SOCK_STREAM, 0)) < 0) { 1384 int e = errno; 1385 1386 perror(";; socket"); 1387 return (e); 1388 } 1389 1390 switch (sin->sin_family) { 1391 case AF_INET: 1392 if (bind(sockFD, (struct sockaddr *)&myaddress, 1393 sizeof myaddress) < 0){ 1394 int e = errno; 1395 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); 1403 } 1404 if (connect(sockFD, (const struct sockaddr *)sin, 1405 sizeof *sin) < 0) { 1406 int e = errno; 1407 1408 perror(";; connect"); 1409 (void) close(sockFD); 1410 sockFD = -1; 1411 return (e); 1412 } 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]; 1419 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); 1428 } 1429 if (connect(sockFD, (const struct sockaddr *)sin, 1430 sizeof(struct sockaddr_in6)) < 0) { 1431 int e = errno; 1432 1433 perror(";; connect"); 1434 (void) close(sockFD); 1435 sockFD = -1; 1436 return (e); 1437 } 1438 break; 1439 } 1440 1441 /* 1442 * Send length & message for zone transfer 1443 */ 1444 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); 1457 1458 /* 1459 * If we're compressing, push a gzip into the pipeline. 1460 */ 1461 if (xfr == ns_t_zxfr) { 1462 enum { rd = 0, wr = 1 }; 1463 int z[2]; 1464 1465 if (pipe(z) < 0) { 1466 int e = errno; 1467 1468 perror(";; pipe"); 1469 (void) close(sockFD); 1470 sockFD = -1; 1471 return (e); 1472 } 1473 zpid = vfork(); 1474 if (zpid < 0) { 1475 int e = errno; 1476 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); 1491 } 1492 /* Parent. */ 1493 (void) close(z[wr]); 1494 (void) dup2(z[rd], sockFD); 1495 (void) close(z[rd]); 1496 } 1497 result = 0; 1498 numAnswers = 0; 1499 numRecords = 0; 1500 soacnt = 0; 1501 error = NO_ERRORS; 1502 numRead = 0; 1503 1504 dname[0][0] = '\0'; 1505 for (done = 0; !done; (void)NULL) { 1506 /* 1507 * Read the length of the response. 1508 */ 1509 1510 cp = tmp; 1511 amtToRead = INT16SZ; 1512 while (amtToRead > 0 && 1513 (numRead = read(sockFD, cp, amtToRead)) > 0) { 1514 cp += numRead; 1515 amtToRead -= numRead; 1516 } 1517 if (numRead <= 0) { 1518 error = ERR_READING_LEN; 1519 break; 1520 } 1521 1522 len = ns_get16(tmp); 1523 if (len == 0) 1524 break; /* nothing left to read */ 1525 1526 /* 1527 * The server sent too much data to fit the existing buffer -- 1528 * allocate a new one. 1529 */ 1530 if (len > answerLen) { 1531 if (answerLen != 0) 1532 free(answer); 1533 answerLen = len; 1534 answer = (u_char *)malloc(answerLen); 1535 } 1536 1537 /* 1538 * Read the response. 1539 */ 1540 1541 amtToRead = len; 1542 cp = answer; 1543 while (amtToRead > 0 && 1544 (numRead = read(sockFD, cp, amtToRead)) > 0) { 1545 cp += numRead; 1546 amtToRead -= numRead; 1547 } 1548 if (numRead <= 0) { 1549 error = ERR_READING_MSG; 1550 break; 1551 } 1552 1553 result = print_axfr(stdout, answer, len); 1554 if (result != 0) { 1555 error = ERR_PRINTING; 1556 break; 1557 } 1558 numRecords += htons(((HEADER *)answer)->ancount); 1559 numAnswers++; 1560 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; 1572 } 1573 cp += n + QFIXEDSZ; 1574 if (cp > answer + len) { 1575 error = ERR_PRINTING; 1576 done++; 1577 break; 1578 } 1579 } 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; 1590 } 1591 cp += n; 1592 if (cp + 3 * INT16SZ + INT32SZ > answer + len) { 1593 error = ERR_PRINTING; 1594 done++; 1595 break; 1596 } 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; 1606 } 1607 if (type == T_SOA && soacnt++ && 1608 ns_samename(dname[0], dname[1]) == 1) { 1609 done++; 1610 break; 1611 } 1612 } 1613 1614 /* 1615 * Verify the TSIG 1616 */ 1617 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"); 1632 } 1633 else 1634 printf("; TSIG invalid\n"); 1635 } 1636 1637 } 1638 1639 printf(";; Received %d answer%s (%d record%s).\n", 1640 numAnswers, (numAnswers != 1) ? "s" : "", 1641 numRecords, (numRecords != 1) ? "s" : ""); 1642 1643 (void) close(sockFD); 1644 sockFD = -1; 1645 1646 /* 1647 * If we were uncompressing, reap the uncompressor. 1648 */ 1649 if (xfr == ns_t_zxfr) { 1650 pid_t pid; 1651 int status = 0; 1652 1653 pid = wait(&status); 1654 if (pid < 0) { 1655 int e = errno; 1656 1657 perror(";; wait"); 1658 return (e); 1659 } 1660 if (pid != zpid) { 1661 fprintf(stderr, ";; wrong pid (%lu != %lu)\n", 1662 (u_long)pid, (u_long)zpid); 1663 return (ERROR); 1664 } 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'); 1669 } 1670 1671 switch (error) { 1672 case NO_ERRORS: 1673 return (0); 1674 1675 case ERR_READING_LEN: 1676 return (EMSGSIZE); 1677 1678 case ERR_PRINTING: 1679 return (result); 1680 1681 case ERR_READING_MSG: 1682 return (EMSGSIZE); 1683 1684 default: 1685 return (EFAULT); 1686 } 1687} 1688 1689static int 1690print_axfr(FILE *file, const u_char *msg, size_t msglen) { 1691 ns_msg handle; 1692 1693 if (ns_initparse(msg, msglen, &handle) < 0) { 1694 fprintf(file, ";; ns_initparse: %s\n", strerror(errno)); 1695 return (ns_r_formerr); 1696 } 1697 if (ns_msg_getflag(handle, ns_f_rcode) != ns_r_noerror) 1698 return (ns_msg_getflag(handle, ns_f_rcode)); 1699 1700 /* 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. 1704 */ 1705 if (ns_msg_count(handle, ns_s_an) == 0) 1706 return (NO_INFO); 1707 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; 1717 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); 1723 } 1724 break; 1725 } 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, "@"); 1735 } 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); 1742 } 1743 strcpy(name_ctx, name); 1744 fputs(buf, file); 1745 fputc('\n', file); 1746 } 1747 return (SUCCESS); 1748} 1749 1750static struct timeval 1751difftv(struct timeval a, struct timeval b) { 1752 static struct timeval diff; 1753 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; 1758 } 1759 return (diff); 1760} 1761 1762static void 1763prnttime(struct timeval t) { 1764 printf("%lu msec", (u_long)(t.tv_sec * 1000 + (t.tv_usec / 1000))); 1765} 1766 1767/* 1768 * Take arguments appearing in simple string (from file or command line) 1769 * place in char**. 1770 */ 1771static void 1772stackarg(char *l, char **y) { 1773 int done = 0; 1774 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; 1794 } 1795 } 1796} 1797 1798static void 1799reverse6(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); 1817} 1818