1: /* 2: ******************************************************************************* 3: * 4: * main.c -- 5: * 6: * Main routine and some action routines for the name server 7: * lookup program. 8: * 9: * Copyright (c) 1985 Regents of the University of California. 10: * All rights reserved. The Berkeley software License Agreement 11: * specifies the terms and conditions for redistribution. 12: * 13: * Andrew Cherenson CS298-26 Fall 1985 14: * 15: ******************************************************************************* 16: */ 17: 18: #ifndef lint 19: char copyright[] = 20: "@(#) Copyright (c) 1985 Regents of the University of California.\n\ 21: All rights reserved.\n"; 22: #endif not lint 23: 24: #ifndef lint 25: static char sccsid[] = "@(#)main.c 5.7 (Berkeley) 5/6/86"; 26: #endif not lint 27: 28: #include <stdio.h> 29: #include <strings.h> 30: #include <sys/types.h> 31: #include <netdb.h> 32: #include <sys/socket.h> 33: #include <netinet/in.h> 34: #include <arpa/nameser.h> 35: #include <resolv.h> 36: #include <signal.h> 37: #include <setjmp.h> 38: #include "res.h" 39: 40: /* 41: * Location of the help file. 42: */ 43: 44: #define HELPFILE "/usr/local/nslookup.help" 45: 46: 47: /* 48: * Internet address of the current host. 49: */ 50: 51: #define LOCALHOST "127.0.0.1" 52: 53: 54: /* 55: * Name of a top-level name server. Can be changed with 56: * the "set root" command. 57: */ 58: 59: #define ROOT_SERVER "sri-nic.arpa" 60: char rootServerName[NAME_LEN]; 61: 62: 63: /* 64: * Import the state information from the resolver library. 65: */ 66: 67: extern struct state _res; 68: 69: 70: /* 71: * Info about the most recently queried host. 72: */ 73: 74: HostInfo curHostInfo; 75: int curHostValid = FALSE; 76: 77: 78: /* 79: * Info about the default name server. 80: */ 81: 82: HostInfo *defaultPtr = NULL; 83: char defaultServer[NAME_LEN]; 84: struct in_addr defaultAddr; 85: 86: 87: /* 88: * Initial name server query type is Address. 89: */ 90: 91: int queryType = T_A; 92: 93: /* 94: * Stuff for Interrupt (control-C) signal handler. 95: * SockFD is the file descriptor for sockets used to 96: * connect with the name servers. It has to be global to 97: * allow the interrupt handler can close open sockets. 98: */ 99: 100: extern int IntrHandler(); 101: int sockFD = -1; 102: FILE *filePtr; 103: jmp_buf env; 104: 105: 106: /* 107: ******************************************************************************* 108: * 109: * main -- 110: * 111: * Initializes the resolver library and determines the address 112: * of the initial name server. The yylex routine is used to 113: * read and perform commands. 114: * 115: ******************************************************************************* 116: */ 117: 118: main(argc, argv) 119: int argc; 120: char **argv; 121: { 122: int result; 123: char hostName[NAME_LEN]; 124: char *cp; 125: char *find; 126: int useLocalServer; 127: int i; 128: struct hostent *hp; 129: 130: /* 131: * Initialize the resolver library routines. 132: */ 133: 134: if (res_init() == -1) { 135: fprintf(stderr,"*** Can't find initialize resolver.\n"); 136: exit(1); 137: } 138: 139: /* 140: * Allocate space for the default server's host info and 141: * find the server's address and name. If the resolver library 142: * already has some addresses for a potential name server, 143: * then use them. Otherwise, see if the current host has a server. 144: * Command line arguments may override the choice of initial server. 145: */ 146: 147: defaultPtr = (HostInfo *) Calloc(1, sizeof(HostInfo)); 148: 149: useLocalServer = FALSE; 150: if (argc != 0) { 151: find = *++argv; 152: if (argc == 3) { 153: /* 154: * Set explicit name server address. 155: * 156: */ 157: _res.nscount = 1; 158: _res.nsaddr.sin_addr.s_addr = inet_addr(*++argv); 159: if (_res.nsaddr.sin_addr.s_addr == (unsigned)-1) { 160: hp = gethostbyname(*argv); 161: if (hp == NULL){ 162: hperror(hp); 163: _res.nscount = 0; 164: useLocalServer = TRUE; 165: } else { 166: bcopy(hp->h_addr_list[0], &_res.nsaddr.sin_addr, 167: hp->h_length); 168: useLocalServer = FALSE; 169: } 170: } 171: } 172: if (argc > 3) { 173: fprintf(stderr, 174: "Usage: nslookup findhost { servername | address }\n"); 175: exit(1); 176: } 177: } 178: 179: 180: if (_res.nscount > 0 && !useLocalServer) { 181: for (i = 0; i < _res.nscount; i++) { 182: if (_res.nsaddr_list[i].sin_addr.s_addr == INADDR_ANY) { 183: useLocalServer = TRUE; 184: break; 185: } else { 186: result = FindHostInfo(&(_res.nsaddr_list[i].sin_addr), 187: &(_res.nsaddr_list[i].sin_addr), 188: sizeof(struct in_addr), 189: defaultPtr); 190: if (result != SUCCESS) { 191: fprintf(stderr, 192: "*** Can't find server name for address %s: %s\n", 193: inet_ntoa(_res.nsaddr_list[i].sin_addr), 194: DecodeError(result)); 195: } else { 196: defaultAddr = _res.nsaddr_list[i].sin_addr; 197: break; 198: } 199: } 200: } 201: 202: /* 203: * If we have exhausted the list, tell the user about the 204: * command line argument to specify an address. 205: */ 206: 207: if (i == _res.nscount) { 208: fprintf(stderr, 209: "*** Default servers are not available\n"); 210: exit(1); 211: } 212: 213: } 214: if (useLocalServer) { 215: 216: defaultAddr.s_addr = inet_addr(LOCALHOST); 217: gethostname(hostName, sizeof(hostName)); 218: 219: result = GetHostInfo(&defaultAddr, T_A, hostName, defaultPtr); 220: if (result != SUCCESS) { 221: fprintf(stderr, 222: "*** Can't find initialize address for server %s: %s\n", 223: defaultServer, DecodeError(result)); 224: exit(1); 225: } 226: } 227: strcpy(defaultServer, defaultPtr->name); 228: PrintHostInfo(stdout, "Default Server:", defaultPtr); 229: 230: strcpy(rootServerName, ROOT_SERVER); 231: 232: /* 233: _res.options |= (RES_DEBUG | RES_DEBUG2); 234: _res.options |= RES_DEBUG; 235: _res.retry = 2; 236: */ 237: _res.options &= ~RES_DEFNAMES; 238: 239: if (find) { 240: hp = gethostbyname(find); 241: if (hp == NULL) { 242: hperror(h_errno); 243: exit(1); 244: } 245: printanswer(hp); 246: exit(0); 247: } 248: 249: /* 250: * Setup the environment to allow the interrupt handler to return here. 251: */ 252: 253: (void) setjmp(env); 254: 255: /* 256: * Return here after a longjmp. 257: */ 258: 259: signal(SIGINT, IntrHandler); 260: 261: /* 262: * Read and evaluate commands. Yylex returns 0 when ^D or 'exit' 263: * is typed. 264: */ 265: printf("> "); 266: while(yylex()) { 267: printf("> "); 268: } 269: } 270: 271: /* 272: ******************************************************************************* 273: * 274: * SetDefaultServer -- 275: * 276: * Changes the default name server to the one specified by 277: * the first argument. The command "server name" uses the current 278: * default server to lookup the info for "name". The command 279: * "lserver name" uses the original server to lookup "name". 280: * 281: * Side effects: 282: * This routine will cause a core dump if the allocation requests fail. 283: * 284: * Results: 285: * SUCCESS The default server was changed successfully. 286: * NONAUTH The server was changed but addresses of 287: * other servers who know about the requested server 288: * were returned. 289: * Errors No info about the new server was found or 290: * requests to the current server timed-out. 291: * 292: ******************************************************************************* 293: */ 294: 295: int 296: SetDefaultServer(string, local) 297: char *string; 298: int local; 299: { 300: register HostInfo *newDefPtr; 301: char newServer[NAME_LEN]; 302: int result; 303: int i; 304: 305: /* 306: * Parse the command line. It maybe of the form "server name", 307: * "lserver name" or just "name". 308: */ 309: 310: if (local) { 311: i = sscanf(string, " lserver %s", newServer); 312: } else { 313: i = sscanf(string, " server %s", newServer); 314: } 315: if (i != 1) { 316: i = sscanf(string, " %s", newServer); 317: if (i != 1) { 318: fprintf(stderr,"SetDefaultServer: invalid name: %s\n", string); 319: return(ERROR); 320: } 321: } 322: 323: /* 324: * Allocate space for a HostInfo variable for the new server. Don't 325: * overwrite the old HostInfo struct because info about the new server 326: * might not be found and we need to have valid default server info. 327: */ 328: 329: newDefPtr = (HostInfo *) Calloc(1, sizeof(HostInfo)); 330: 331: 332: /* 333: * A 'local' lookup uses the original server that the program was 334: * initialized with. 335: */ 336: 337: if (local) { 338: result = GetHostInfo(&defaultAddr, T_A, newServer, newDefPtr); 339: } else { 340: 341: /* 342: * Check to see if we have the address of the server or the 343: * address of a server who knows about this domain. 344: * 345: * For now, just use the first address in the list. 346: */ 347: if (defaultPtr->addrList == NULL) { 348: result = GetHostInfo( 349: (struct in_addr *) defaultPtr->servers[0]->addrList[0], 350: T_A, newServer, newDefPtr); 351: } else { 352: result = GetHostInfo((struct in_addr *) defaultPtr->addrList[0], 353: T_A, newServer, newDefPtr); 354: } 355: } 356: 357: if (result == SUCCESS || result == NONAUTH) { 358: /* 359: * Found info about the new server. Free the resources for 360: * the old server. 361: */ 362: 363: FreeHostInfoPtr(defaultPtr); 364: free((char *)defaultPtr); 365: defaultPtr = newDefPtr; 366: strcpy(defaultServer, defaultPtr->name); 367: PrintHostInfo(stdout, "Default Server:", defaultPtr); 368: return(SUCCESS); 369: } else { 370: fprintf(stderr, "*** Can't find address for server %s: %s\n", 371: newServer, DecodeError(result)); 372: free((char *)newDefPtr); 373: 374: return(result); 375: } 376: } 377: 378: /* 379: ******************************************************************************* 380: * 381: * LookupHost -- 382: * 383: * Asks the default name server for information about the 384: * specified host or domain. The information is printed 385: * if the lookup was successful. 386: * 387: * Results: 388: * SUCCESS - the lookup was successful. 389: * ERROR - the output file could not be opened. 390: * Misc. Errors - an error message is printed if the lookup failed. 391: * 392: ******************************************************************************* 393: */ 394: 395: int 396: LookupHost(string, putToFile) 397: char *string; 398: int putToFile; 399: { 400: char host[NAME_LEN]; 401: char file[NAME_LEN]; 402: int result; 403: 404: /* 405: * Invalidate the current host information to prevent Finger 406: * from using bogus info. 407: */ 408: 409: curHostValid = FALSE; 410: 411: /* 412: * Parse the command string into the host and 413: * optional output file name. 414: * 415: */ 416: 417: sscanf(string, " %s", host); /* removes white space */ 418: if (!putToFile) { 419: filePtr = stdout; 420: } else { 421: filePtr = OpenFile(string, file); 422: if (filePtr == NULL) { 423: fprintf(stderr, "*** Can't open %s for writing\n", file); 424: return(ERROR); 425: } 426: fprintf(filePtr,"> %s\n", string); 427: } 428: 429: PrintHostInfo(filePtr, "Server:", defaultPtr); 430: 431: /* 432: * Check to see if we have the address of the server or the 433: * address of a server who knows about this domain. 434: * 435: * For now, just use the first address in the list. 436: */ 437: 438: if (defaultPtr->addrList == NULL) { 439: result = GetHostInfo( 440: (struct in_addr *) defaultPtr->servers[0]->addrList[0], 441: queryType, host, &curHostInfo); 442: } else { 443: result = GetHostInfo((struct in_addr *) defaultPtr->addrList[0], 444: queryType, host, &curHostInfo); 445: } 446: 447: switch(result) { 448: case SUCCESS: 449: /* 450: * If the query was for an address, then the curHostInfo 451: * variable can be used by Finger. 452: * There's no need to print anything for other query types 453: * because the info has already been printed. 454: */ 455: if (queryType == T_A) { 456: curHostValid = TRUE; 457: PrintHostInfo(filePtr, "Name:", &curHostInfo); 458: } 459: break; 460: 461: /* 462: * No Authoritative answer was available but we got names 463: * of servers who know about the host. 464: */ 465: case NONAUTH: 466: PrintHostInfo(filePtr, "Name:", &curHostInfo); 467: break; 468: 469: case NO_INFO: 470: fprintf(stderr, "*** No %s information is available for %s\n", 471: DecodeType(queryType), host); 472: break; 473: 474: case TIME_OUT: 475: fprintf(stderr, "*** Request to %s timed-out\n", defaultServer); 476: break; 477: 478: default: 479: fprintf(stderr, "*** %s can't find %s: %s\n", defaultServer, host, 480: DecodeError(result)); 481: } 482: if (putToFile) { 483: fclose(filePtr); 484: filePtr = NULL; 485: } 486: return(result); 487: } 488: 489: /* 490: ******************************************************************************* 491: * 492: * LookupHostWithServer -- 493: * 494: * Asks the name server specified in the second argument for 495: * information about the host or domain specified in the first 496: * argument. The information is printed if the lookup was successful. 497: * 498: * Address info about the requested name server is obtained 499: * from the default name server. This routine will return an 500: * error if the default server doesn't have info about the 501: * requested server. Thus an error return status might not 502: * mean the requested name server doesn't have info about the 503: * requested host. 504: * 505: * Comments from LookupHost apply here, too. 506: * 507: * Results: 508: * SUCCESS - the lookup was successful. 509: * ERROR - the output file could not be opened. 510: * Misc. Errors - an error message is printed if the lookup failed. 511: * 512: ******************************************************************************* 513: */ 514: 515: int 516: LookupHostWithServer(string, putToFile) 517: char *string; 518: int putToFile; 519: { 520: char file[NAME_LEN]; 521: char host[NAME_LEN]; 522: char server[NAME_LEN]; 523: int result; 524: static HostInfo serverInfo; 525: 526: curHostValid = FALSE; 527: 528: sscanf(string, " %s %s", host, server); 529: if (!putToFile) { 530: filePtr = stdout; 531: } else { 532: filePtr = OpenFile(string, file); 533: if (filePtr == NULL) { 534: fprintf(stderr, "*** Can't open %s for writing\n", file); 535: return(ERROR); 536: } 537: fprintf(filePtr,"> %s\n", string); 538: } 539: 540: 541: if (defaultPtr->addrList == NULL) { 542: result = GetHostInfo( 543: (struct in_addr *) defaultPtr->servers[0]->addrList[0], 544: T_A, server, &serverInfo); 545: } else { 546: result = GetHostInfo((struct in_addr *) defaultPtr->addrList[0], 547: T_A, server, &serverInfo); 548: } 549: 550: if (result != SUCCESS) { 551: fprintf(stderr,"*** Can't find address for server %s: %s\n", server, 552: DecodeError(result)); 553: } else { 554: PrintHostInfo(filePtr, "Server:", &serverInfo); 555: 556: if (serverInfo.addrList == NULL) { 557: result = GetHostInfo( 558: (struct in_addr *) serverInfo.servers[0]->addrList[0], 559: queryType, host, &curHostInfo); 560: } else { 561: result = GetHostInfo((struct in_addr *) serverInfo.addrList[0], 562: queryType, host, &curHostInfo); 563: } 564: 565: 566: switch(result) { 567: 568: case SUCCESS: 569: if (queryType == T_A) { 570: curHostValid = TRUE; 571: PrintHostInfo(filePtr, "Name:", &curHostInfo); 572: } 573: break; 574: 575: case NONAUTH: 576: PrintHostInfo(filePtr, "Name:", &curHostInfo); 577: break; 578: 579: case NO_INFO: 580: fprintf(stderr, "*** No %s information is available for %s\n", 581: DecodeType(queryType), host); 582: break; 583: 584: case TIME_OUT: 585: fprintf(stderr, "*** Request to %s timed-out\n", server); 586: break; 587: 588: default: 589: fprintf(stderr, "*** %s can't find %s: %s\n", server, host, 590: DecodeError(result)); 591: } 592: } 593: if (putToFile) { 594: fclose(filePtr); 595: filePtr = NULL; 596: } 597: return(result); 598: } 599: 600: /* 601: ******************************************************************************* 602: * 603: * SetOption -- 604: * 605: * This routine is used to change the state information 606: * that affect the lookups. The command format is 607: * set keyword[=value] 608: * Most keywords can be abbreviated. Parsing is very simplistic-- 609: * A value must not be separated from its keyword by white space. 610: * 611: * Valid keywords: Meaning: 612: * [no]aaonly authoritative query only or not (hidden). 613: * all lists current values of options. 614: * ALL lists current values of options, including 615: * hidden options. 616: * [no]d2 turn on/off extra debugging mode (hidden). 617: * [no]debug turn on/off debugging mode. 618: * [no]defname use/don't use default domain name. 619: * domain=NAME set default domain name to NAME. 620: * [no]ignore ignore/don't ignore trunc. errors (hidden). 621: * [no]primary use/don't use primary server (hidden). 622: * query=value set default query type to value, 623: * value is one of the query types in RFC883 624: * without the leading T_. (e.g. A, HINFO) 625: * [no]recurse use/don't use recursive lookup. 626: * retry=# set number of retries to #. 627: * root=NAME change root server to NAME. 628: * time=# set timeout length to #. 629: * [no]vc use/don't use virtual circuit. 630: * 631: * Results: 632: * SUCCESS the command was parsed correctly. 633: * ERROR the command was not parsed correctly. 634: * 635: ******************************************************************************* 636: */ 637: 638: int 639: SetOption(string) 640: char *string; 641: { 642: char option[NAME_LEN]; 643: char type[NAME_LEN]; 644: char *ptr; 645: int i; 646: 647: i = sscanf(string, " set %s", option); 648: if (i != 1) { 649: fprintf(stderr, "*** Invalid option: %s\n", option); 650: return(ERROR); 651: } else { 652: if (strncmp(option, "all", 3) == 0) { 653: ShowOptions(FALSE); 654: } else if (strncmp(option, "ALL", 3) == 0) { 655: ShowOptions(TRUE); 656: } else if (strncmp(option, "aa", 2) == 0) { /* aaonly */ 657: _res.options |= RES_AAONLY; 658: } else if (strncmp(option, "noaa", 4) == 0) { 659: _res.options &= ~RES_AAONLY; 660: } else if (strncmp(option, "deb", 3) == 0) { /* debug */ 661: _res.options |= RES_DEBUG; 662: } else if (strncmp(option, "nodeb", 5) == 0) { 663: _res.options &= ~(RES_DEBUG | RES_DEBUG2); 664: } else if (strncmp(option, "d2", 2) == 0) { /* d2 (more debug) */ 665: _res.options |= (RES_DEBUG | RES_DEBUG2); 666: } else if (strncmp(option, "nod2", 4) == 0) { 667: _res.options &= ~RES_DEBUG2; 668: } else if (strncmp(option, "def", 3) == 0) { /* defname */ 669: _res.options |= RES_DEFNAMES; 670: } else if (strncmp(option, "nodef", 5) == 0) { 671: _res.options &= ~RES_DEFNAMES; 672: } else if (strncmp(option, "do", 2) == 0) { /* domain */ 673: ptr = index(option, '='); 674: if (ptr != NULL) { 675: sscanf(++ptr, "%s", _res.defdname); 676: } 677: } else if (strncmp(option, "i", 1) == 0) { /* ignore */ 678: _res.options |= RES_IGNTC; 679: } else if (strncmp(option, "noi", 3) == 0) { 680: _res.options &= ~RES_IGNTC; 681: } else if (strncmp(option, "p", 1) == 0) { /* primary */ 682: _res.options |= RES_PRIMARY; 683: } else if (strncmp(option, "nop", 3) == 0) { 684: _res.options &= ~RES_PRIMARY; 685: } else if (strncmp(option, "q", 1) == 0) { /* querytype */ 686: ptr = index(option, '='); 687: if (ptr != NULL) { 688: sscanf(++ptr, "%s", type); 689: queryType = StringToType(type); 690: } 691: } else if (strncmp(option, "rec", 3) == 0) { /* recurse */ 692: _res.options |= RES_RECURSE; 693: } else if (strncmp(option, "norec", 5) == 0) { 694: _res.options &= ~RES_RECURSE; 695: } else if (strncmp(option, "ret", 3) == 0) { /* retry */ 696: ptr = index(option, '='); 697: if (ptr != NULL) { 698: sscanf(++ptr, "%d", &_res.retry); 699: } 700: } else if (strncmp(option, "ro", 2) == 0) { /* root */ 701: ptr = index(option, '='); 702: if (ptr != NULL) { 703: sscanf(++ptr, "%s", rootServerName); 704: } 705: } else if (strncmp(option, "t", 1) == 0) { /* timeout */ 706: ptr = index(option, '='); 707: if (ptr != NULL) { 708: sscanf(++ptr, "%d", &_res.retrans); 709: } 710: } else if (strncmp(option, "v", 1) == 0) { /* vc */ 711: _res.options |= RES_USEVC; 712: } else if (strncmp(option, "nov", 3) == 0) { 713: _res.options &= ~RES_USEVC; 714: } else { 715: fprintf(stderr, "*** Invalid option: %s\n", option); 716: return(ERROR); 717: } 718: } 719: return(SUCCESS); 720: } 721: 722: /* 723: ******************************************************************************* 724: * 725: * ShowOptions -- 726: * 727: * Prints out the state information used by the resolver 728: * library and other options set by the user. 729: * 730: ******************************************************************************* 731: */ 732: 733: void 734: ShowOptions(special) 735: int special; 736: { 737: int i; 738: 739: PrintHostInfo(stdout, "Default Server:", defaultPtr); 740: if (curHostValid) { 741: PrintHostInfo(stdout, "Host:", &curHostInfo); 742: } 743: 744: printf("Set options:\n"); 745: printf(" %sdebug\t", (_res.options & RES_DEBUG) ? "" : "no"); 746: printf(" %sdefname\t", (_res.options & RES_DEFNAMES) ? "" : "no"); 747: printf(" %srecurse\t", (_res.options & RES_RECURSE) ? "" : "no"); 748: printf(" %svc\n", (_res.options & RES_USEVC) ? "" : "no"); 749: 750: if (special) { 751: printf(" %saa\t", (_res.options & RES_AAONLY) ? "" : "no"); 752: printf(" %sd2\t", (_res.options & RES_DEBUG2) ? "" : "no"); 753: printf(" %signoretc\t", (_res.options & RES_IGNTC) ? "" : "no"); 754: printf(" %sprimary\n", (_res.options & RES_PRIMARY) ? "" : "no"); 755: } 756: 757: printf(" querytype=%s\t", p_type(queryType)); 758: printf(" timeout=%d\t", _res.retrans); 759: printf(" retry=%d\n", _res.retry); 760: printf(" domain=%s\n", _res.defdname); 761: printf(" root=%s\n", rootServerName); 762: 763: if (special) { 764: printf("\n"); 765: printf("State info:\n"); 766: printf(" current packet id: %d\n", _res.id); 767: printf(" number of name servers: %d\n", _res.nscount); 768: printf(" name server addresses: %s\n", 769: inet_ntoa(_res.nsaddr_list[0].sin_addr)); 770: for (i = 1; i < _res.nscount; i++) { 771: printf(" %s\n", 772: inet_ntoa(_res.nsaddr_list[i].sin_addr)); 773: } 774: } 775: } 776: 777: /* 778: ******************************************************************************* 779: * 780: * PrintHelp -- 781: * 782: * Prints out the help file. 783: * (Code taken from Mail.) 784: * 785: ******************************************************************************* 786: */ 787: 788: void 789: PrintHelp() 790: { 791: register char c; 792: register FILE *filePtr; 793: 794: if ((filePtr = fopen(HELPFILE, "r")) == NULL) { 795: perror(HELPFILE); 796: return; 797: } 798: while ((c = getc(filePtr)) != EOF) { 799: putchar(c); 800: } 801: fclose(filePtr); 802: }