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: }