|
|
1.1 root 1: /*
2: *******************************************************************************
3: *
4: * list.c --
5: *
6: * Routines to obtain info from name and finger servers.
7: *
8: * Adapted from 4.3BSD BIND ns_init.c and from /usr/src/ucb/finger.c
9: *
10: * Copyright (c) 1985 Regents of the University of California.
11: * All rights reserved. The Berkeley software License Agreement
12: * specifies the terms and conditions for redistribution.
13: *
14: *******************************************************************************
15: */
16:
17: #ifndef lint
18: static char sccsid[] = "@(#)list.c 5.4 (Berkeley) 4/10/86";
19: #endif not lint
20:
21: #include <sys/types.h>
22: #include <sys/socket.h>
23: #include <netinet/in.h>
24: #include <netdb.h>
25: #include <stdio.h>
26: #include <strings.h>
27: #include <ctype.h>
28: #include <arpa/nameser.h>
29: #include <resolv.h>
30: #include "res.h"
31:
32: /*
33: * Imported from res_debug.c
34: */
35: extern char *rcodes[];
36:
37: typedef union {
38: HEADER qb1;
39: char qb2[PACKETSZ];
40: } querybuf;
41:
42: extern u_long inet_addr();
43: extern HostInfo *defaultPtr;
44: extern HostInfo curHostInfo;
45: extern int curHostValid;
46:
47: /*
48: * During a listing to a file, hash marks are printed
49: * every HASH_SIZE records.
50: */
51:
52: #define HASH_SIZE 50
53:
54:
55: /*
56: *******************************************************************************
57: *
58: * ListHosts --
59: *
60: * Requests the name server to do a zone transfer so we
61: * find out what hosts it knows about.
62: *
63: * There are three types of output:
64: * - internet addresses (default)
65: * - cpu type and operating system (-h option)
66: * - canonical and alias names (-a option)
67: *
68: * To see all three types of information in sorted order,
69: * do the following:
70: * ls domain.edu > file
71: * ls -a domain.edu >> file
72: * ls -h domain.edu >> file
73: * view file
74: *
75: * Results:
76: * SUCCESS the listing was successful.
77: * ERROR the server could not be contacted because
78: * a socket could not be obtained or an error
79: * occured while receiving, or the output file
80: * could not be opened.
81: *
82: *******************************************************************************
83: */
84:
85: int
86: ListHosts(string, putToFile)
87: char *string;
88: int putToFile;
89: {
90: querybuf buf;
91: struct sockaddr_in sin;
92: HEADER *headerPtr;
93: int queryType;
94: int msglen;
95: int amtToRead;
96: int numRead;
97: int i;
98: int numAnswers = 0;
99: int result;
100: int soacnt = 0;
101: u_short len;
102: char *cp;
103: char name[NAME_LEN];
104: char option[NAME_LEN];
105: char file[NAME_LEN];
106: char *namePtr;
107: enum {
108: NO_ERRORS,
109: ERR_READING_LEN,
110: ERR_READING_MSG,
111: ERR_PRINTING,
112: } error = NO_ERRORS;
113:
114:
115: /*
116: *
117: /*
118: * Parse the command line. It maybe of the form "ls domain",
119: * "ls -a domain" or "ls -h domain".
120: */
121: i = sscanf(string, " ls %s %s", option, name);
122: if (putToFile && i == 2 && name[0] == '>') {
123: i--;
124: }
125: if (i == 2) {
126: if (strcmp("-a", option) == 0) {
127: queryType = T_CNAME;
128: } else if (strcmp("-h", option) == 0) {
129: queryType = T_HINFO;
130: } else if (strcmp("-m", option) == 0) {
131: queryType = T_MX;
132: } else {
133: queryType = T_A;
134: }
135: namePtr = name;
136: } else if (i == 1) {
137: namePtr = option;
138: queryType = T_A;
139: } else {
140: fprintf(stderr, "ListHosts: invalid request %s\n",string);
141: return(ERROR);
142: }
143:
144:
145: /*
146: * Create a query packet for the requested domain name.
147: *
148: */
149: msglen = res_mkquery(QUERY, namePtr, C_IN, T_AXFR,
150: (char *)0, 0, (char *)0,
151: (char *) &buf, sizeof(buf));
152: if (msglen < 0) {
153: if (_res.options & RES_DEBUG) {
154: fprintf(stderr, "ListHosts: Res_mkquery failed\n");
155: }
156: return (ERROR);
157: }
158:
159: bzero((char *)&sin, sizeof(sin));
160: sin.sin_family = AF_INET;
161: sin.sin_port = htons(NAMESERVER_PORT);
162:
163: /*
164: * Check to see if we have the address of the server or the
165: * address of a server who knows about this domain.
166: *
167: * For now, just use the first address in the list.
168: */
169:
170: if (defaultPtr->addrList != NULL) {
171: sin.sin_addr = *(struct in_addr *) defaultPtr->addrList[0];
172: } else {
173: sin.sin_addr = *(struct in_addr *)defaultPtr->servers[0]->addrList[0];
174: }
175:
176: /*
177: * Set up a virtual circuit to the server.
178: */
179: if ((sockFD = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
180: perror("ListHosts");
181: return(ERROR);
182: }
183: if (connect(sockFD, &sin, sizeof(sin)) < 0) {
184: perror("ListHosts");
185: (void) close(sockFD);
186: sockFD = -1;
187: return(ERROR);
188: }
189:
190: /*
191: * Send length & message for zone transfer
192: */
193:
194: len = htons(msglen);
195:
196: if (write(sockFD, (char *)&len, sizeof(len)) != sizeof(len) ||
197: write(sockFD, (char *) &buf, msglen) != msglen) {
198: perror("ListHosts");
199: (void) close(sockFD);
200: sockFD = -1;
201: return(ERROR);
202: }
203:
204: fprintf(stdout,"[%s]\n",
205: (defaultPtr->addrList != NULL) ? defaultPtr->name :
206: defaultPtr->servers[0]->name);
207:
208: if (!putToFile) {
209: filePtr = stdout;
210: } else {
211: filePtr = OpenFile(string, file);
212: if (filePtr == NULL) {
213: fprintf(stderr, "*** Can't open %s for writing\n", file);
214: (void) close(sockFD);
215: sockFD = -1;
216: return(ERROR);
217: }
218: fprintf(filePtr, "> %s\n", string);
219: fprintf(filePtr,"[%s]\n",
220: (defaultPtr->addrList != NULL) ? defaultPtr->name :
221: defaultPtr->servers[0]->name);
222: }
223:
224: fprintf(filePtr, "%-30s", "Host or domain name");
225: switch(queryType) {
226: case T_A:
227: fprintf(filePtr, " %-30s\n", "Internet address");
228: break;
229: case T_HINFO:
230: fprintf(filePtr, " %-20s %s\n", "CPU", "OS");
231: break;
232: case T_CNAME:
233: fprintf(filePtr, " %-30s\n", "Alias");
234: break;
235: case T_MX:
236: fprintf(filePtr, " %10s %s\n", "Metric", "Host");
237: }
238:
239:
240: while (1) {
241:
242: /*
243: * Read the length of the response.
244: */
245:
246: cp = (char *) &buf;
247: amtToRead = sizeof(u_short);
248: while(amtToRead > 0 && (numRead = read(sockFD, cp, amtToRead)) > 0){
249: cp += numRead;
250: amtToRead -= numRead;
251: }
252: if (numRead <= 0) {
253: error = ERR_READING_LEN;
254: break;
255: }
256:
257: if ((len = htons(*(u_short *)&buf)) == 0) {
258: break; /* nothing left to read */
259: }
260:
261: /*
262: * Read the response.
263: */
264:
265: amtToRead = len;
266: cp = (char *) &buf;
267: while(amtToRead > 0 && (numRead = read(sockFD, cp, amtToRead)) > 0){
268: cp += numRead;
269: amtToRead -= numRead;
270: }
271: if (numRead <= 0) {
272: error = ERR_READING_MSG;
273: break;
274: }
275:
276: result = PrintListInfo(filePtr, (char *) &buf, cp, queryType);
277: if (result != SUCCESS) {
278: error = ERR_PRINTING;
279: break;
280: }
281:
282: numAnswers++;
283: if (putToFile && ((numAnswers % HASH_SIZE) == 0)) {
284: fprintf(stdout, "#");
285: fflush(stdout);
286: }
287: cp = buf.qb2 + sizeof(HEADER);
288: cp += dn_skip(cp) + QFIXEDSZ;
289: cp += dn_skip(cp);
290: if ((getshort(cp) == T_SOA)) {
291: if (soacnt)
292: break;
293: else
294: soacnt++;
295: }
296: }
297:
298: if (putToFile) {
299: fprintf(stdout, "%sReceived %d record%s.\n",
300: (numAnswers >= HASH_SIZE) ? "\n" : "",
301: numAnswers,
302: (numAnswers > 1) ? "s" : "");
303: }
304:
305: (void) close(sockFD);
306: sockFD = -1;
307: if (putToFile) {
308: fclose(filePtr);
309: filePtr = NULL;
310: }
311:
312: switch (error) {
313: case NO_ERRORS:
314: return (SUCCESS);
315:
316: case ERR_READING_LEN:
317: return(ERROR);
318:
319: case ERR_PRINTING:
320: fprintf(stderr,"*** Error during listing of %s: %s\n",
321: namePtr, DecodeError(result));
322: return(result);
323:
324: case ERR_READING_MSG:
325: headerPtr = (HEADER *) &buf;
326: fprintf(stderr,"ListHosts: error receiving zone transfer:\n");
327: fprintf(stderr,
328: " result: %s, answers = %d, authority = %d, additional = %d\n",
329: rcodes[headerPtr->rcode],
330: ntohs(headerPtr->ancount), ntohs(headerPtr->nscount),
331: ntohs(headerPtr->arcount));
332: return(ERROR);
333: default:
334: return(ERROR);
335: }
336: }
337:
338:
339: /*
340: *******************************************************************************
341: *
342: * PrintListInfo --
343: *
344: * Used by the ListInfo routine to print the answer
345: * received from the name server. Only the desired
346: * information is printed.
347: *
348: * Results:
349: * SUCCESS the answer was printed without a problem.
350: * NO_INFO the answer packet did not contain an answer.
351: * ERROR the answer was malformed.
352: * Misc. errors returned in the packet header.
353: *
354: *******************************************************************************
355: */
356:
357: #define NAME_FORMAT " %-30s"
358: #define STRIP_DOMAIN(string) if((dot = index(string, '.')) != NULL) *dot = '\0'
359:
360:
361: PrintListInfo(file, msg, eom, queryType)
362: FILE *file;
363: char *msg, *eom;
364: int queryType;
365: {
366: register char *cp;
367: HEADER *headerPtr;
368: int type, class, dlen, nameLen;
369: int n;
370: struct in_addr inaddr;
371: char name[NAME_LEN];
372: char name2[NAME_LEN];
373: char *dot;
374:
375: /*
376: * Read the header fields.
377: */
378: headerPtr = (HEADER *)msg;
379: cp = msg + sizeof(HEADER);
380: if (headerPtr->rcode != NOERROR) {
381: return(headerPtr->rcode);
382: }
383:
384: /*
385: * We are looking for info from answer resource records.
386: * If there aren't any, return with an error. We assume
387: * there aren't any question records.
388: */
389:
390: if (ntohs(headerPtr->ancount) == 0) {
391: return(NO_INFO);
392: } else {
393: if ((nameLen = dn_expand(msg, eom, cp, name, sizeof(name))) < 0) {
394: return (ERROR);
395: }
396: cp += nameLen;
397: type = getshort(cp);
398: cp += sizeof(u_short);
399: class = getshort(cp);
400: cp += sizeof(u_short) + sizeof(u_long);
401: dlen = getshort(cp);
402: cp += sizeof(u_short);
403:
404: /*
405: * QueryType is used to specify the type of desired information.
406: * T_A - internet address
407: * T_CNAME - aliases
408: * T_HINFO - cpu, OS type
409: * T_MX - mail routing
410: *
411:
412: */
413: switch (type) {
414:
415: case T_A:
416: if (queryType != T_A)
417: break;
418:
419: if (class == C_IN) {
420: STRIP_DOMAIN(name);
421: fprintf(file, NAME_FORMAT, name);
422: bcopy(cp, (char *)&inaddr, sizeof(inaddr));
423: if (dlen == 4) {
424: fprintf(file," %s\n", inet_ntoa(inaddr));
425: } else if (dlen == 7) {
426: fprintf(file," %s", inet_ntoa(inaddr));
427: fprintf(file," (%d, %d)\n", cp[4],(cp[5] << 8) + cp[6]);
428: }
429: }
430: break;
431:
432: case T_CNAME:
433: if (queryType != T_CNAME)
434: break;
435:
436: STRIP_DOMAIN(name);
437: if ((nameLen = dn_expand(msg, eom, cp, name2, sizeof(name2))) < 0) {
438: return (ERROR);
439: }
440: /*
441: * a bug -- cnames need not be in same domain!
442: * STRIP_DOMAIN(name2);
443: */
444:
445: fprintf(file, NAME_FORMAT, name2);
446: fprintf(file, " %s\n", name);
447: break;
448:
449: case T_HINFO:
450: if (queryType != T_HINFO)
451: break;
452:
453: STRIP_DOMAIN(name);
454: fprintf(file, NAME_FORMAT, name);
455: if (n = *cp++) {
456: sprintf(name,"%.*s", n, cp);
457: fprintf(file," %-20s", name);
458: cp += n;
459: } else {
460: fprintf(file," %-20s", " ");
461: }
462: if (n = *cp++) {
463: fprintf(file," %.*s\n", n, cp);
464: cp += n;
465: }
466: break;
467:
468: case T_MX:
469: if (queryType != T_MX)
470: break;
471:
472: STRIP_DOMAIN(name);
473: fprintf(file, NAME_FORMAT, name);
474:
475: {
476: short pref;
477:
478: pref = getshort(cp);
479: cp += sizeof(u_short);
480: fprintf(file,"%10d",pref);
481: }
482: if ((nameLen = dn_expand(msg, eom, cp, name2, sizeof(name2))) < 0) {
483: return (ERROR);
484: }
485: fprintf(file, " %s\n", name2);
486:
487: break;
488:
489:
490: case T_NS:
491: case T_PTR:
492: if (queryType != T_A)
493: break;
494: /*
495: * Found a name server or pointer record.
496: */
497: fprintf(file, NAME_FORMAT, name);
498: fprintf(file," server = ");
499: cp = Print_cdname2(cp, msg, eom, file);
500: fprintf(file,"\n");
501: break;
502:
503: default:
504: /*
505: * Unwanted answer type -- ignore it.
506: */
507: break;
508: }
509: }
510: return(SUCCESS);
511: }
512:
513:
514: /*
515: *******************************************************************************
516: *
517: * ViewList --
518: *
519: * A hack to view the output of the ls command in sorted
520: * order using more.
521: *
522: *******************************************************************************
523: */
524:
525: ViewList(string)
526: char *string;
527: {
528: char file[NAME_LEN];
529: char command[NAME_LEN];
530:
531: sscanf(string, " view %s", file);
532: sprintf(command, "grep \"^ \" %s | sort | more", file);
533: system(command);
534: }
535:
536: /*
537: *******************************************************************************
538: *
539: * Finger --
540: *
541: * Connects with the finger server for the current host
542: * to request info on the specified person (long form)
543: * who is on the system (short form).
544: *
545: * Results:
546: * SUCCESS the finger server was contacted.
547: * ERROR the server could not be contacted because
548: * a socket could not be obtained or connected
549: * to or the service could not be found.
550: *
551: *******************************************************************************
552: */
553:
554: Finger(string, putToFile)
555: char *string;
556: int putToFile;
557: {
558: struct servent *sp;
559: struct sockaddr_in sin;
560: register FILE *f;
561: register int c;
562: register int lastc;
563: char name[NAME_LEN];
564: char file[NAME_LEN];
565:
566: /*
567: * We need a valid current host info to get an inet address.
568: */
569: if (!curHostValid) {
570: fprintf(stderr, "Finger: no current host defined.\n");
571: return (ERROR);
572: }
573:
574: if (sscanf(string, " finger %s", name) == 1) {
575: if (putToFile && (name[0] == '>')) {
576: name[0] = '\0';
577: }
578: } else {
579: name[0] = '\0';
580: }
581:
582: sp = getservbyname("finger", "tcp");
583: if (sp == 0) {
584: fprintf(stderr, "Finger: unknown service\n");
585: return (ERROR);
586: }
587:
588: bzero((char *)&sin, sizeof(sin));
589: sin.sin_family = curHostInfo.addrType;
590: sin.sin_port = sp->s_port;
591: bcopy(curHostInfo.addrList[0], (char *)&sin.sin_addr,
592: curHostInfo.addrLen);
593:
594: /*
595: * Set up a virtual circuit to the host.
596: */
597:
598: sockFD = socket(curHostInfo.addrType, SOCK_STREAM, 0);
599: if (sockFD < 0) {
600: fflush(stdout);
601: perror("Finger");
602: return (ERROR);
603: }
604:
605: if (connect(sockFD, (char *)&sin, sizeof (sin)) < 0) {
606: fflush(stdout);
607: perror("Finger");
608: close(sockFD);
609: sockFD = -1;
610: return (ERROR);
611: }
612:
613: if (!putToFile) {
614: filePtr = stdout;
615: } else {
616: filePtr = OpenFile(string, file);
617: if (filePtr == NULL) {
618: fprintf(stderr, "*** Can't open %s for writing\n", file);
619: close(sockFD);
620: sockFD = -1;
621: return(ERROR);
622: }
623: fprintf(filePtr,"> %s\n", string);
624: }
625: fprintf(filePtr, "[%s]\n", curHostInfo.name);
626:
627: if (name[0] != '\0') {
628: write(sockFD, "/W ", 3);
629: }
630: write(sockFD, name, strlen(name));
631: write(sockFD, "\r\n", 2);
632: f = fdopen(sockFD, "r");
633: while ((c = getc(f)) != EOF) {
634: switch(c) {
635: case 0210:
636: case 0211:
637: case 0212:
638: case 0214:
639: c -= 0200;
640: break;
641: case 0215:
642: c = '\n';
643: break;
644: }
645: putc(lastc = c, filePtr);
646: }
647: if (lastc != '\n') {
648: putc('\n', filePtr);
649: }
650: putc('\n', filePtr);
651:
652: close(sockFD);
653: sockFD = -1;
654:
655: if (putToFile) {
656: fclose(filePtr);
657: filePtr = NULL;
658: }
659: return (SUCCESS);
660: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.