1: /* 2: * Copyright (c) 1985,1989 Regents of the University of California. 3: * All rights reserved. 4: * 5: * Redistribution and use in source and binary forms are permitted provided 6: * that: (1) source distributions retain this entire copyright notice and 7: * comment, and (2) distributions including binaries display the following 8: * acknowledgement: ``This product includes software developed by the 9: * University of California, Berkeley and its contributors'' in the 10: * documentation or other materials provided with the distribution and in 11: * all advertising materials mentioning features or use of this software. 12: * Neither the name of the University nor the names of its contributors may 13: * be used to endorse or promote products derived from this software without 14: * specific prior written permission. 15: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED 16: * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 17: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 18: */ 19: 20: #if !defined(lint) && defined(DOSCCS) 21: char copyright[] = 22: "@(#) Copyright (c) 1985,1989 Regents of the University of California.\n\ 23: All rights reserved.\n"; 24: 25: static char sccsid[] = "@(#)main.c 5.39 (Berkeley) 6/24/90"; 26: #endif 27: 28: /* 29: ******************************************************************************* 30: * 31: * main.c -- 32: * 33: * Main routine and some action routines for the name server 34: * lookup program. 35: * 36: * Andrew Cherenson 37: * U.C. Berkeley Computer Science Div. 38: * CS298-26, Fall 1985 39: * 40: ******************************************************************************* 41: */ 42: 43: #include <sys/param.h> 44: #include <netdb.h> 45: #include <sys/socket.h> 46: #include <netinet/in.h> 47: #include <arpa/nameser.h> 48: #include <arpa/inet.h> 49: #include <resolv.h> 50: #include <signal.h> 51: #include <setjmp.h> 52: #include <ctype.h> 53: #include <stdio.h> 54: #include <string.h> 55: #include "res.h" 56: #include "pathnames.h" 57: 58: /* 59: * Default Internet address of the current host. 60: */ 61: 62: #if BSD < 43 63: #define LOCALHOST "127.0.0.1" 64: #endif 65: 66: 67: /* 68: * Name of a top-level name server. Can be changed with 69: * the "set root" command. 70: */ 71: 72: #ifndef ROOT_SERVER 73: #define ROOT_SERVER "ns.internic.net." 74: #endif 75: char rootServerName[NAME_LEN] = ROOT_SERVER; 76: 77: 78: /* 79: * Import the state information from the resolver library. 80: */ 81: 82: extern struct state _res; 83: 84: 85: /* 86: * Info about the most recently queried host. 87: */ 88: 89: HostInfo curHostInfo; 90: int curHostValid = FALSE; 91: 92: 93: /* 94: * Info about the default name server. 95: */ 96: 97: HostInfo *defaultPtr = NULL; 98: char defaultServer[NAME_LEN]; 99: struct in_addr defaultAddr; 100: 101: 102: /* 103: * Initial name server query type is Address. 104: */ 105: 106: int queryType = T_A; 107: int queryClass = C_IN; 108: 109: /* 110: * Stuff for Interrupt (control-C) signal handler. 111: */ 112: 113: #ifdef SVR3 114: extern void IntrHandler(); 115: #else 116: extern int IntrHandler(); 117: #endif 118: FILE *filePtr; 119: jmp_buf env; 120: 121: static void CvtAddrToPtr(); 122: static void ReadRC(); 123: 124: 125: /* 126: ******************************************************************************* 127: * 128: * main -- 129: * 130: * Initializes the resolver library and determines the address 131: * of the initial name server. The yylex routine is used to 132: * read and perform commands. 133: * 134: ******************************************************************************* 135: */ 136: 137: main(argc, argv) 138: int argc; 139: char **argv; 140: { 141: char *wantedHost = NULL; 142: Boolean useLocalServer; 143: int result; 144: int i; 145: struct hostent *hp; 146: extern int h_errno; 147: 148: /* 149: * Initialize the resolver library routines. 150: */ 151: 152: if (res_init() == -1) { 153: fprintf(stderr,"*** Can't initialize resolver.\n"); 154: exit(1); 155: } 156: 157: /* 158: * Allocate space for the default server's host info and 159: * find the server's address and name. If the resolver library 160: * already has some addresses for a potential name server, 161: * then use them. Otherwise, see if the current host has a server. 162: * Command line arguments may override the choice of initial server. 163: */ 164: 165: defaultPtr = (HostInfo *) Calloc(1, sizeof(HostInfo)); 166: 167: /* 168: * Parse the arguments: 169: * no args = go into interactive mode, use default host as server 170: * 1 arg = use as host name to be looked up, default host will be server 171: * non-interactive mode 172: * 2 args = 1st arg: 173: * if it is '-', then 174: * ignore but go into interactive mode 175: * else 176: * use as host name to be looked up, 177: * go into non-interactive mode 178: * 2nd arg: name or inet address of server 179: * 180: * "Set" options are specified with a leading - and must come before 181: * any arguments. For example, to find the well-known services for 182: * a host, type "nslookup -query=wks host" 183: */ 184: 185: ReadRC(); /* look for options file */ 186: 187: ++argv; --argc; /* skip prog name */ 188: 189: while (argc && *argv[0] == '-' && argv[0][1]) { 190: (void) SetOption (&(argv[0][1])); 191: ++argv; --argc; 192: } 193: if (argc > 2) { 194: Usage(); 195: } 196: if (argc && *argv[0] != '-') { 197: wantedHost = *argv; /* name of host to be looked up */ 198: } 199: 200: useLocalServer = FALSE; 201: if (argc == 2) { 202: struct in_addr addr; 203: 204: /* 205: * Use an explicit name server. If the hostname lookup fails, 206: * default to the server(s) in resolv.conf. 207: */ 208: 209: addr.s_addr = inet_addr(*++argv); 210: if (addr.s_addr != (u_long)-1) { 211: _res.nscount = 1; 212: _res.nsaddr.sin_addr = addr; 213: } else { 214: hp = gethostbyname(*argv); 215: if (hp == NULL) { 216: fprintf(stderr, "*** Can't find server address for '%s': ", 217: *argv); 218: herror((char *)NULL); 219: fputc('\n', stderr); 220: } else { 221: #if BSD < 43 222: bcopy(hp->h_addr, (char *)&_res.nsaddr.sin_addr, hp->h_length); 223: _res.nscount = 1; 224: #else 225: for (i = 0; i < MAXNS && hp->h_addr_list[i] != NULL; i++) { 226: bcopy(hp->h_addr_list[i], 227: (char *)&_res.nsaddr_list[i].sin_addr, 228: hp->h_length); 229: } 230: _res.nscount = i; 231: #endif 232: } 233: } 234: } 235: 236: 237: if (_res.nscount == 0 || useLocalServer) { 238: LocalServer(defaultPtr); 239: } else { 240: for (i = 0; i < _res.nscount; i++) { 241: if (_res.nsaddr_list[i].sin_addr.s_addr == INADDR_ANY) { 242: LocalServer(defaultPtr); 243: break; 244: } else { 245: result = GetHostInfoByAddr(&(_res.nsaddr_list[i].sin_addr), 246: &(_res.nsaddr_list[i].sin_addr), 247: defaultPtr); 248: if (result != SUCCESS) { 249: fprintf(stderr, 250: "*** Can't find server name for address %s: %s\n", 251: inet_ntoa(_res.nsaddr_list[i].sin_addr), 252: DecodeError(result)); 253: } else { 254: defaultAddr = _res.nsaddr_list[i].sin_addr; 255: break; 256: } 257: } 258: } 259: 260: /* 261: * If we have exhausted the list, tell the user about the 262: * command line argument to specify an address. 263: */ 264: 265: if (i == _res.nscount) { 266: fprintf(stderr, "*** Default servers are not available\n"); 267: exit(1); 268: } 269: 270: } 271: strcpy(defaultServer, defaultPtr->name); 272: 273: 274: #ifdef DEBUG 275: #ifdef DEBUG2 276: _res.options |= RES_DEBUG2; 277: #endif 278: _res.options |= RES_DEBUG; 279: _res.retry = 2; 280: #endif DEBUG 281: 282: /* 283: * If we're in non-interactive mode, look up the wanted host and quit. 284: * Otherwise, print the initial server's name and continue with 285: * the initialization. 286: */ 287: 288: if (wantedHost != (char *) NULL) { 289: LookupHost(wantedHost, 0); 290: } else { 291: PrintHostInfo(stdout, "Default Server:", defaultPtr); 292: 293: /* 294: * Setup the environment to allow the interrupt handler to return here. 295: */ 296: 297: (void) setjmp(env); 298: 299: /* 300: * Return here after a longjmp. 301: */ 302: 303: signal(SIGINT, IntrHandler); 304: signal(SIGPIPE, SIG_IGN); 305: 306: /* 307: * Read and evaluate commands. The commands are described in commands.l 308: * Yylex returns 0 when ^D or 'exit' is typed. 309: */ 310: 311: printf("> "); 312: fflush(stdout); 313: while(yylex()) { 314: printf("> "); 315: fflush(stdout); 316: } 317: } 318: exit(0); 319: } 320: 321: 322: LocalServer(defaultPtr) 323: HostInfo *defaultPtr; 324: { 325: char hostName[NAME_LEN]; 326: #if BSD < 43 327: int result; 328: #endif 329: 330: gethostname(hostName, sizeof(hostName)); 331: 332: #if BSD < 43 333: defaultAddr.s_addr = inet_addr(LOCALHOST); 334: result = GetHostInfoByName(&defaultAddr, C_IN, T_A, 335: hostName, defaultPtr, 1); 336: if (result != SUCCESS) { 337: fprintf(stderr, 338: "*** Can't find initialize address for server %s: %s\n", 339: defaultServer, DecodeError(result)); 340: exit(1); 341: } 342: #else 343: defaultAddr.s_addr = htonl(INADDR_ANY); 344: (void) GetHostInfoByName(&defaultAddr, C_IN, T_A, "0.0.0.0", defaultPtr, 1); 345: free(defaultPtr->name); 346: defaultPtr->name = Calloc(1, sizeof(hostName)+1); 347: strcpy(defaultPtr->name, hostName); 348: #endif 349: } 350: 351: 352: /* 353: ******************************************************************************* 354: * 355: * Usage -- 356: * 357: * Lists the proper methods to run the program and exits. 358: * 359: ******************************************************************************* 360: */ 361: 362: Usage() 363: { 364: fprintf(stderr, "Usage:\n"); 365: fprintf(stderr, 366: " nslookup [-opt ...] # interactive mode using default server\n"); 367: fprintf(stderr, 368: " nslookup [-opt ...] - server # interactive mode using 'server'\n"); 369: fprintf(stderr, 370: " nslookup [-opt ...] host # just look up 'host' using default server\n"); 371: fprintf(stderr, 372: " nslookup [-opt ...] host server # just look up 'host' using 'server'\n"); 373: exit(1); 374: } 375: 376: /* 377: ******************************************************************************* 378: * 379: * IsAddr -- 380: * 381: * Returns TRUE if the string looks like an Internet address. 382: * A string with a trailing dot is not an address, even if it looks 383: * like one. 384: * 385: * XXX doesn't treat 255.255.255.255 as an address. 386: * 387: ******************************************************************************* 388: */ 389: 390: Boolean 391: IsAddr(host, addrPtr) 392: char *host; 393: u_long *addrPtr; /* If return TRUE, contains IP address */ 394: { 395: register char *cp; 396: u_long addr; 397: 398: if (isdigit(host[0])) { 399: /* Make sure it has only digits and dots. */ 400: for (cp = host; *cp; ++cp) { 401: if (!isdigit(*cp) && *cp != '.') 402: return FALSE; 403: } 404: /* If it has a trailing dot, don't treat it as an address. */ 405: if (*--cp != '.') { 406: if ((addr = inet_addr(host)) != (u_long) -1) { 407: *addrPtr = addr; 408: return TRUE; 409: #if 0 410: } else { 411: /* XXX Check for 255.255.255.255 case */ 412: #endif 413: } 414: } 415: } 416: return FALSE; 417: } 418: 419: 420: /* 421: ******************************************************************************* 422: * 423: * SetDefaultServer -- 424: * 425: * Changes the default name server to the one specified by 426: * the first argument. The command "server name" uses the current 427: * default server to lookup the info for "name". The command 428: * "lserver name" uses the original server to lookup "name". 429: * 430: * Side effects: 431: * This routine will cause a core dump if the allocation requests fail. 432: * 433: * Results: 434: * SUCCESS The default server was changed successfully. 435: * NONAUTH The server was changed but addresses of 436: * other servers who know about the requested server 437: * were returned. 438: * Errors No info about the new server was found or 439: * requests to the current server timed-out. 440: * 441: ******************************************************************************* 442: */ 443: 444: int 445: SetDefaultServer(string, local) 446: char *string; 447: Boolean local; 448: { 449: register HostInfo *newDefPtr; 450: struct in_addr *servAddrPtr; 451: struct in_addr addr; 452: char newServer[NAME_LEN]; 453: int result; 454: int i; 455: 456: /* 457: * Parse the command line. It maybe of the form "server name", 458: * "lserver name" or just "name". 459: */ 460: 461: if (local) { 462: i = sscanf(string, " lserver %s", newServer); 463: } else { 464: i = sscanf(string, " server %s", newServer); 465: } 466: if (i != 1) { 467: i = sscanf(string, " %s", newServer); 468: if (i != 1) { 469: fprintf(stderr,"SetDefaultServer: invalid name: %s\n", string); 470: return(ERROR); 471: } 472: } 473: 474: /* 475: * Allocate space for a HostInfo variable for the new server. Don't 476: * overwrite the old HostInfo struct because info about the new server 477: * might not be found and we need to have valid default server info. 478: */ 479: 480: newDefPtr = (HostInfo *) Calloc(1, sizeof(HostInfo)); 481: 482: 483: /* 484: * A 'local' lookup uses the original server that the program was 485: * initialized with. 486: * 487: * Check to see if we have the address of the server or the 488: * address of a server who knows about this domain. 489: * XXX For now, just use the first address in the list. 490: */ 491: 492: if (local) { 493: servAddrPtr = &defaultAddr; 494: } else if (defaultPtr->addrList != NULL) { 495: servAddrPtr = (struct in_addr *) defaultPtr->addrList[0]; 496: } else { 497: servAddrPtr = (struct in_addr *) defaultPtr->servers[0]->addrList[0]; 498: } 499: 500: result = ERROR; 501: if (IsAddr(newServer, &addr.s_addr)) { 502: result = GetHostInfoByAddr(servAddrPtr, &addr, newDefPtr); 503: /* If we can't get the name, fall through... */ 504: } 505: if (result != SUCCESS && result != NONAUTH) { 506: result = GetHostInfoByName(servAddrPtr, C_IN, T_A, 507: newServer, newDefPtr, 1); 508: } 509: 510: if (result == SUCCESS || result == NONAUTH) { 511: /* 512: * Found info about the new server. Free the resources for 513: * the old server. 514: */ 515: 516: FreeHostInfoPtr(defaultPtr); 517: free((char *)defaultPtr); 518: defaultPtr = newDefPtr; 519: strcpy(defaultServer, defaultPtr->name); 520: PrintHostInfo(stdout, "Default Server:", defaultPtr); 521: return(SUCCESS); 522: } else { 523: fprintf(stderr, "*** Can't find address for server %s: %s\n", 524: newServer, DecodeError(result)); 525: free((char *)newDefPtr); 526: 527: return(result); 528: } 529: } 530: 531: /* 532: ******************************************************************************* 533: * 534: * DoLoookup -- 535: * 536: * Common subroutine for LookupHost and LookupHostWithServer. 537: * 538: * Results: 539: * SUCCESS - the lookup was successful. 540: * Misc. Errors - an error message is printed if the lookup failed. 541: * 542: ******************************************************************************* 543: */ 544: 545: static int 546: DoLookup(host, servPtr, serverName) 547: char *host; 548: HostInfo *servPtr; 549: char *serverName; 550: { 551: int result; 552: struct in_addr *servAddrPtr; 553: struct in_addr addr; 554: 555: /* Skip escape character */ 556: if (host[0] == '\\') 557: host++; 558: 559: /* 560: * If the user gives us an address for an address query, 561: * silently treat it as a PTR query. If the query type is already 562: * PTR, then convert the address into the in-addr.arpa format. 563: * 564: * Use the address of the server if it exists, otherwise use the 565: * address of a server who knows about this domain. 566: * XXX For now, just use the first address in the list. 567: */ 568: 569: if (servPtr->addrList != NULL) { 570: servAddrPtr = (struct in_addr *) servPtr->addrList[0]; 571: } else { 572: servAddrPtr = (struct in_addr *) servPtr->servers[0]->addrList[0]; 573: } 574: 575: /* 576: * RFC1123 says we "SHOULD check the string syntactically for a 577: * dotted-decimal number before looking it up [...]" (p. 13). 578: */ 579: if (queryType == T_A && IsAddr(host, &addr.s_addr)) { 580: result = GetHostInfoByAddr(servAddrPtr, &addr, &curHostInfo); 581: } else { 582: if (queryType == T_PTR) { 583: CvtAddrToPtr(host); 584: } 585: result = GetHostInfoByName(servAddrPtr, queryClass, queryType, host, 586: &curHostInfo, 0); 587: } 588: 589: switch (result) { 590: case SUCCESS: 591: /* 592: * If the query was for an address, then the &curHostInfo 593: * variable can be used by Finger. 594: * There's no need to print anything for other query types 595: * because the info has already been printed. 596: */ 597: if (queryType == T_A) { 598: curHostValid = TRUE; 599: PrintHostInfo(filePtr, "Name:", &curHostInfo); 600: } 601: break; 602: 603: /* 604: * No Authoritative answer was available but we got names 605: * of servers who know about the host. 606: */ 607: case NONAUTH: 608: PrintHostInfo(filePtr, "Name:", &curHostInfo); 609: break; 610: 611: case NO_INFO: 612: fprintf(stderr, "*** No %s (%s) records available for %s\n", 613: DecodeType(queryType), p_type(queryType), host); 614: break; 615: 616: case TIME_OUT: 617: fprintf(stderr, "*** Request to %s timed-out\n", serverName); 618: break; 619: 620: default: 621: fprintf(stderr, "*** %s can't find %s: %s\n", serverName, host, 622: DecodeError(result)); 623: } 624: return result; 625: } 626: 627: /* 628: ******************************************************************************* 629: * 630: * LookupHost -- 631: * 632: * Asks the default name server for information about the 633: * specified host or domain. The information is printed 634: * if the lookup was successful. 635: * 636: * Results: 637: * ERROR - the output file could not be opened. 638: * + results of DoLookup 639: * 640: ******************************************************************************* 641: */ 642: 643: int 644: LookupHost(string, putToFile) 645: char *string; 646: Boolean putToFile; 647: { 648: char host[NAME_LEN]; 649: char file[NAME_LEN]; 650: int result; 651: 652: /* 653: * Invalidate the current host information to prevent Finger 654: * from using bogus info. 655: */ 656: 657: curHostValid = FALSE; 658: 659: /* 660: * Parse the command string into the host and 661: * optional output file name. 662: * 663: */ 664: 665: sscanf(string, " %s", host); /* removes white space */ 666: if (!putToFile) { 667: filePtr = stdout; 668: } else { 669: filePtr = OpenFile(string, file); 670: if (filePtr == NULL) { 671: fprintf(stderr, "*** Can't open %s for writing\n", file); 672: return(ERROR); 673: } 674: fprintf(filePtr,"> %s\n", string); 675: } 676: 677: PrintHostInfo(filePtr, "Server:", defaultPtr); 678: 679: result = DoLookup(host, defaultPtr, defaultServer); 680: 681: if (putToFile) { 682: fclose(filePtr); 683: filePtr = NULL; 684: } 685: return(result); 686: } 687: 688: /* 689: ******************************************************************************* 690: * 691: * LookupHostWithServer -- 692: * 693: * Asks the name server specified in the second argument for 694: * information about the host or domain specified in the first 695: * argument. The information is printed if the lookup was successful. 696: * 697: * Address info about the requested name server is obtained 698: * from the default name server. This routine will return an 699: * error if the default server doesn't have info about the 700: * requested server. Thus an error return status might not 701: * mean the requested name server doesn't have info about the 702: * requested host. 703: * 704: * Comments from LookupHost apply here, too. 705: * 706: * Results: 707: * ERROR - the output file could not be opened. 708: * + results of DoLookup 709: * 710: ******************************************************************************* 711: */ 712: 713: int 714: LookupHostWithServer(string, putToFile) 715: char *string; 716: Boolean putToFile; 717: { 718: char file[NAME_LEN]; 719: char host[NAME_LEN]; 720: char server[NAME_LEN]; 721: int result; 722: static HostInfo serverInfo; 723: 724: curHostValid = FALSE; 725: 726: sscanf(string, " %s %s", host, server); 727: if (!putToFile) { 728: filePtr = stdout; 729: } else { 730: filePtr = OpenFile(string, file); 731: if (filePtr == NULL) { 732: fprintf(stderr, "*** Can't open %s for writing\n", file); 733: return(ERROR); 734: } 735: fprintf(filePtr,"> %s\n", string); 736: } 737: 738: result = GetHostInfoByName( 739: defaultPtr->addrList ? 740: (struct in_addr *) defaultPtr->addrList[0] : 741: (struct in_addr *) defaultPtr->servers[0]->addrList[0], 742: C_IN, T_A, server, &serverInfo, 1); 743: 744: if (result != SUCCESS) { 745: fprintf(stderr,"*** Can't find address for server %s: %s\n", server, 746: DecodeError(result)); 747: } else { 748: PrintHostInfo(filePtr, "Server:", &serverInfo); 749: 750: result = DoLookup(host, &serverInfo, server); 751: } 752: if (putToFile) { 753: fclose(filePtr); 754: filePtr = NULL; 755: } 756: return(result); 757: } 758: 759: /* 760: ******************************************************************************* 761: * 762: * SetOption -- 763: * 764: * This routine is used to change the state information 765: * that affect the lookups. The command format is 766: * set keyword[=value] 767: * Most keywords can be abbreviated. Parsing is very simplistic-- 768: * A value must not be separated from its keyword by white space. 769: * 770: * Valid keywords: Meaning: 771: * all lists current values of options. 772: * ALL lists current values of options, including 773: * hidden options. 774: * [no]d2 turn on/off extra debugging mode. 775: * [no]debug turn on/off debugging mode. 776: * [no]defname use/don't use default domain name. 777: * [no]search use/don't use domain search list. 778: * domain=NAME set default domain name to NAME. 779: * [no]ignore ignore/don't ignore trunc. errors. 780: * query=value set default query type to value, 781: * value is one of the query types in RFC883 782: * without the leading T_. (e.g., A, HINFO) 783: * [no]recurse use/don't use recursive lookup. 784: * retry=# set number of retries to #. 785: * root=NAME change root server to NAME. 786: * time=# set timeout length to #. 787: * [no]vc use/don't use virtual circuit. 788: * port TCP/UDP port to server. 789: * 790: * Deprecated: 791: * [no]primary use/don't use primary server. 792: * 793: * Results: 794: * SUCCESS the command was parsed correctly. 795: * ERROR the command was not parsed correctly. 796: * 797: ******************************************************************************* 798: */ 799: 800: int 801: SetOption(option) 802: register char *option; 803: { 804: char type[NAME_LEN]; 805: char *ptr; 806: int tmp; 807: 808: while (isspace(*option)) 809: ++option; 810: if (strncmp (option, "set ", 4) == 0) 811: option += 4; 812: while (isspace(*option)) 813: ++option; 814: 815: if (*option == 0) { 816: fprintf(stderr, "*** Invalid set command\n"); 817: return(ERROR); 818: } else { 819: if (strncmp(option, "all", 3) == 0) { 820: ShowOptions(); 821: } else if (strncmp(option, "ALL", 3) == 0) { 822: ShowOptions(); 823: } else if (strncmp(option, "d2", 2) == 0) { /* d2 (more debug) */ 824: _res.options |= (RES_DEBUG | RES_DEBUG2); 825: } else if (strncmp(option, "nod2", 4) == 0) { 826: _res.options &= ~RES_DEBUG2; 827: printf("d2 mode disabled; still in debug mode\n"); 828: } else if (strncmp(option, "def", 3) == 0) { /* defname */ 829: _res.options |= RES_DEFNAMES; 830: } else if (strncmp(option, "nodef", 5) == 0) { 831: _res.options &= ~RES_DEFNAMES; 832: } else if (strncmp(option, "do", 2) == 0) { /* domain */ 833: ptr = strchr(option, '='); 834: if (ptr != NULL) { 835: sscanf(++ptr, "%s", _res.defdname); 836: res_re_init(); 837: } 838: } else if (strncmp(option, "deb", 1) == 0) { /* debug */ 839: _res.options |= RES_DEBUG; 840: } else if (strncmp(option, "nodeb", 5) == 0) { 841: _res.options &= ~(RES_DEBUG | RES_DEBUG2); 842: } else if (strncmp(option, "ig", 2) == 0) { /* ignore */ 843: _res.options |= RES_IGNTC; 844: } else if (strncmp(option, "noig", 4) == 0) { 845: _res.options &= ~RES_IGNTC; 846: } else if (strncmp(option, "po", 2) == 0) { /* port */ 847: ptr = strchr(option, '='); 848: if (ptr != NULL) { 849: sscanf(++ptr, "%hu", &nsport); 850: } 851: #ifdef deprecated 852: } else if (strncmp(option, "pri", 3) == 0) { /* primary */ 853: _res.options |= RES_PRIMARY; 854: } else if (strncmp(option, "nopri", 5) == 0) { 855: _res.options &= ~RES_PRIMARY; 856: #endif 857: } else if (strncmp(option, "q", 1) == 0 || /* querytype */ 858: strncmp(option, "ty", 2) == 0) { /* type */ 859: ptr = strchr(option, '='); 860: if (ptr != NULL) { 861: sscanf(++ptr, "%s", type); 862: queryType = StringToType(type, queryType); 863: } 864: } else if (strncmp(option, "cl", 2) == 0) { /* query class */ 865: ptr = strchr(option, '='); 866: if (ptr != NULL) { 867: sscanf(++ptr, "%s", type); 868: queryClass = StringToClass(type, queryClass); 869: } 870: } else if (strncmp(option, "rec", 3) == 0) { /* recurse */ 871: _res.options |= RES_RECURSE; 872: } else if (strncmp(option, "norec", 5) == 0) { 873: _res.options &= ~RES_RECURSE; 874: } else if (strncmp(option, "ret", 3) == 0) { /* retry */ 875: ptr = strchr(option, '='); 876: if (ptr != NULL) { 877: sscanf(++ptr, "%d", &tmp); 878: if (tmp >= 0) { 879: _res.retry = tmp; 880: } 881: } 882: } else if (strncmp(option, "ro", 2) == 0) { /* root */ 883: ptr = strchr(option, '='); 884: if (ptr != NULL) { 885: sscanf(++ptr, "%s", rootServerName); 886: } 887: } else if (strncmp(option, "sea", 3) == 0) { /* search list */ 888: _res.options |= RES_DNSRCH; 889: } else if (strncmp(option, "nosea", 5) == 0) { 890: _res.options &= ~RES_DNSRCH; 891: } else if (strncmp(option, "srchl", 5) == 0) { /* domain search list */ 892: ptr = strchr(option, '='); 893: if (ptr != NULL) { 894: res_dnsrch(++ptr); 895: } 896: } else if (strncmp(option, "ti", 2) == 0) { /* timeout */ 897: ptr = strchr(option, '='); 898: if (ptr != NULL) { 899: sscanf(++ptr, "%d", &tmp); 900: if (tmp >= 0) { 901: _res.retrans = tmp; 902: } 903: } 904: } else if (strncmp(option, "v", 1) == 0) { /* vc */ 905: _res.options |= RES_USEVC; 906: } else if (strncmp(option, "nov", 3) == 0) { 907: _res.options &= ~RES_USEVC; 908: } else { 909: fprintf(stderr, "*** Invalid option: %s\n", option); 910: return(ERROR); 911: } 912: } 913: return(SUCCESS); 914: } 915: 916: /* 917: * Fake a reinitialization when the domain is changed. 918: */ 919: res_re_init() 920: { 921: register char *cp, **pp; 922: int n; 923: 924: /* find components of local domain that might be searched */ 925: pp = _res.dnsrch; 926: *pp++ = _res.defdname; 927: for (cp = _res.defdname, n = 0; *cp; cp++) 928: if (*cp == '.') 929: n++; 930: cp = _res.defdname; 931: for (; n >= LOCALDOMAINPARTS && pp < _res.dnsrch + MAXDFLSRCH; n--) { 932: cp = strchr(cp, '.'); 933: *pp++ = ++cp; 934: } 935: *pp = 0; 936: _res.options |= RES_INIT; 937: } 938: 939: #define SRCHLIST_SEP '/' 940: 941: res_dnsrch(cp) 942: register char *cp; 943: { 944: register char **pp; 945: int n; 946: 947: (void)strncpy(_res.defdname, cp, sizeof(_res.defdname) - 1); 948: if ((cp = strchr(_res.defdname, '\n')) != NULL) 949: *cp = '\0'; 950: /* 951: * Set search list to be blank-separated strings 952: * on rest of line. 953: */ 954: cp = _res.defdname; 955: pp = _res.dnsrch; 956: *pp++ = cp; 957: for (n = 0; *cp && pp < _res.dnsrch + MAXDNSRCH; cp++) { 958: if (*cp == SRCHLIST_SEP) { 959: *cp = '\0'; 960: n = 1; 961: } else if (n) { 962: *pp++ = cp; 963: n = 0; 964: } 965: } 966: if ((cp = strchr(pp[-1], SRCHLIST_SEP)) != NULL) { 967: *cp = '\0'; 968: } 969: *pp = NULL; 970: } 971: 972: 973: /* 974: ******************************************************************************* 975: * 976: * ShowOptions -- 977: * 978: * Prints out the state information used by the resolver 979: * library and other options set by the user. 980: * 981: ******************************************************************************* 982: */ 983: 984: void 985: ShowOptions() 986: { 987: register char **cp; 988: 989: PrintHostInfo(stdout, "Default Server:", defaultPtr); 990: if (curHostValid) { 991: PrintHostInfo(stdout, "Host:", &curHostInfo); 992: } 993: 994: printf("Set options:\n"); 995: printf(" %sdebug \t", (_res.options & RES_DEBUG) ? "" : "no"); 996: printf(" %sdefname\t", (_res.options & RES_DEFNAMES) ? "" : "no"); 997: printf(" %ssearch\t", (_res.options & RES_DNSRCH) ? "" : "no"); 998: printf(" %srecurse\n", (_res.options & RES_RECURSE) ? "" : "no"); 999: 1000: printf(" %sd2\t\t", (_res.options & RES_DEBUG2) ? "" : "no"); 1001: printf(" %svc\t\t", (_res.options & RES_USEVC) ? "" : "no"); 1002: printf(" %signoretc\t", (_res.options & RES_IGNTC) ? "" : "no"); 1003: printf(" port=%u\n", nsport); 1004: 1005: printf(" querytype=%s\t", p_type(queryType)); 1006: printf(" class=%s\t", p_class(queryClass)); 1007: printf(" timeout=%d\t", _res.retrans); 1008: printf(" retry=%d\n", _res.retry); 1009: printf(" root=%s\n", rootServerName); 1010: printf(" domain=%s\n", _res.defdname); 1011: 1012: if (cp = _res.dnsrch) { 1013: printf(" srchlist=%s", *cp); 1014: for (cp++; *cp; cp++) { 1015: printf("%c%s", SRCHLIST_SEP, *cp); 1016: } 1017: putchar('\n'); 1018: } 1019: putchar('\n'); 1020: } 1021: #undef SRCHLIST_SEP 1022: 1023: /* 1024: ******************************************************************************* 1025: * 1026: * PrintHelp -- 1027: * 1028: * Prints out the help file. 1029: * (Code taken from Mail.) 1030: * 1031: ******************************************************************************* 1032: */ 1033: 1034: void 1035: PrintHelp() 1036: { 1037: register int c; 1038: register FILE *helpFilePtr; 1039: 1040: if ((helpFilePtr = fopen(_PATH_HELPFILE, "r")) == NULL) { 1041: perror(_PATH_HELPFILE); 1042: return; 1043: } 1044: while ((c = getc(helpFilePtr)) != EOF) { 1045: putchar((char) c); 1046: } 1047: fclose(helpFilePtr); 1048: } 1049: 1050: /* 1051: ******************************************************************************* 1052: * 1053: * CvtAddrToPtr -- 1054: * 1055: * Convert a dotted-decimal Internet address into the standard 1056: * PTR format (reversed address with .in-arpa. suffix). 1057: * 1058: * Assumes the argument buffer is large enougth to hold the result. 1059: * 1060: ******************************************************************************* 1061: */ 1062: 1063: static void 1064: CvtAddrToPtr(name) 1065: char *name; 1066: { 1067: char *p; 1068: int ip[4]; 1069: struct in_addr addr; 1070: 1071: if (IsAddr(name, &addr.s_addr)) { 1072: p = inet_ntoa(addr); 1073: if (sscanf(p, "%d.%d.%d.%d", &ip[0], &ip[1], &ip[2], &ip[3]) == 4) { 1074: sprintf(name, "%d.%d.%d.%d.in-addr.arpa.", 1075: ip[3], ip[2], ip[1], ip[0]); 1076: } 1077: } 1078: } 1079: 1080: /* 1081: ******************************************************************************* 1082: * 1083: * ReadRC -- 1084: * 1085: * Use the contents of ~/.nslookuprc as options. 1086: * 1087: ******************************************************************************* 1088: */ 1089: 1090: static void 1091: ReadRC() 1092: { 1093: register FILE *fp; 1094: register char *cp; 1095: char buf[NAME_LEN]; 1096: 1097: if ((cp = getenv("HOME")) != NULL) { 1098: (void) strcpy(buf, cp); 1099: (void) strcat(buf, "/.nslookuprc"); 1100: 1101: if ((fp = fopen(buf, "r")) != NULL) { 1102: while (fgets(buf, sizeof(buf), fp) != NULL) { 1103: if ((cp = strchr(buf, '\n')) != NULL) { 1104: *cp = '\0'; 1105: } 1106: (void) SetOption(buf); 1107: } 1108: (void) fclose(fp); 1109: } 1110: } 1111: }