|
|
1.1 root 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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.