1: /*
   2:  *******************************************************************************
   3:  *
   4:  *  getinfo.c --
   5:  *
   6:  *	Routines to create requests to name servers
   7:  *	and interpret the answers.
   8:  *
   9:  *	Adapted from 4.3BSD BIND gethostnamadr.c
  10:  *
  11:  *	Copyright (c) 1985 Regents of the University of California.
  12:  *	All rights reserved.  The Berkeley software License Agreement
  13:  *	specifies the terms and conditions for redistribution.
  14:  *
  15:  *******************************************************************************
  16:  */
  17: 
  18: #ifndef lint
  19: static char sccsid[] = "@(#)getinfo.c	5.3 (Berkeley) 3/31/86";
  20: #endif not lint
  21: 
  22: #include <sys/types.h>
  23: #include <sys/socket.h>
  24: #include <netinet/in.h>
  25: #include <stdio.h>
  26: #include <ctype.h>
  27: #include <arpa/nameser.h>
  28: #include <resolv.h>
  29: #include "res.h"
  30: 
  31: extern char *rcodes[];
  32: extern char *res_skip();
  33: 
  34: #define MAXALIASES  35
  35: #define MAXADDRS    35
  36: #define MAXDOMAINS  35
  37: #define MAXSERVERS  10
  38: 
  39: static char *addr_list[MAXADDRS + 1];
  40: 
  41: static char *host_aliases[MAXALIASES];
  42: static int   host_aliases_len[MAXALIASES];
  43: static char  hostbuf[BUFSIZ+1];
  44: 
  45: typedef struct {
  46:     char *name;
  47:     char *domain[MAXDOMAINS];
  48:     int   numDomains;
  49:     char *address[MAXADDRS];
  50:     int   numAddresses;
  51: } ServerTable;
  52: 
  53: ServerTable server[MAXSERVERS];
  54: 
  55: typedef union {
  56:     HEADER qb1;
  57:     char qb2[PACKETSZ];
  58: } querybuf;
  59: 
  60: static union {
  61:     long al;
  62:     char ac;
  63: } align;
  64: 
  65: 
  66: /*
  67:  *******************************************************************************
  68:  *
  69:  *  GetAnswer --
  70:  *
  71:  *	Interprets an answer packet and retrieves the following
  72:  *	information:
  73:  *
  74:  *  Results:
  75:  *      SUCCESS         the info was retrieved.
  76:  *      NO_INFO         the packet did not contain an answer.
  77:  *	NONAUTH		non-authoritative information was found.
  78:  *      ERROR           the answer was malformed.
  79:  *      Other errors    returned in the packet header.
  80:  *
  81:  *******************************************************************************
  82:  */
  83: 
  84: static int
  85: GetAnswer(nsAddrPtr, queryType, msg, msglen, iquery, hostPtr)
  86:     struct in_addr      *nsAddrPtr;
  87:     char            *msg;
  88:     int             queryType;
  89:     int             msglen;
  90:     int             iquery;
  91:     register HostInfo   *hostPtr;
  92: {
  93:     register HEADER     *headerPtr;
  94:     register char       *cp;
  95:     querybuf        answer;
  96:     char            *eom, *bp, **aliasPtr;
  97:     char            **addrPtr;
  98:     char            *namePtr;
  99:     char            *dnamePtr;
 100:     int             type, class;
 101:     int             qdcount, ancount, arcount, nscount, buflen;
 102:     int             haveanswer, getclass;
 103:     int             numAliases = 0;
 104:     int             numAddresses = 0;
 105:     int             n, i, j;
 106:     int             len;
 107:     int             dlen;
 108:     int             status;
 109:     int         numServers;
 110:     int         found;
 111: 
 112: 
 113:     /*
 114: 	 *  If the hostPtr was used before, free up
 115: 	 *  the calloc'd areas.
 116: 	 */
 117:     FreeHostInfoPtr(hostPtr);
 118: 
 119:     status = SendRequest(nsAddrPtr, msg, msglen, (char *) &answer,
 120:                 sizeof(answer), &n);
 121: 
 122:     if (status != SUCCESS) {
 123:         if (_res.options & RES_DEBUG2)
 124:             printf("SendRequest failed\n");
 125:         return (status);
 126:     }
 127:     eom = (char *) &answer + n;
 128: 
 129:     headerPtr = (HEADER *) &answer;
 130:     qdcount = ntohs(headerPtr->qdcount);
 131:     ancount = ntohs(headerPtr->ancount);
 132:     arcount = ntohs(headerPtr->arcount);
 133:     nscount = ntohs(headerPtr->nscount);
 134: 
 135:     if (headerPtr->rcode != NOERROR) {
 136:         if (_res.options & RES_DEBUG) {
 137:         printf(
 138:         "Failed: %s, num. answers = %d, ns = %d, additional = %d\n",
 139:             rcodes[headerPtr->rcode], ancount, nscount, arcount);
 140:         }
 141:         return (headerPtr->rcode);
 142:     }
 143: 
 144:     /*
 145: 	 * If there are no answer, n.s. or additional records
 146: 	 * then return with an error.
 147: 	 */
 148:     if (ancount == 0 && nscount == 0 && arcount == 0) {
 149:         return (NO_INFO);
 150:     }
 151: 
 152: 
 153:     bp  = hostbuf;
 154:     buflen  = sizeof(hostbuf);
 155:     cp  = (char *) &answer + sizeof(HEADER);
 156: 
 157:     /*
 158: 	 * For inverse queries, the desired information is returned
 159: 	 * in the question section. If there are no question records,
 160: 	 * return with an error.
 161: 	 *
 162: 	 */
 163:     if (qdcount) {
 164:         if (iquery) {
 165:         if ((n = dn_expand((char *)&answer, eom, cp, bp, buflen)) < 0) {
 166:             return (ERROR);
 167:         }
 168:         cp += n + QFIXEDSZ;
 169:         len = strlen(bp) + 1;
 170:         hostPtr->name = Calloc((unsigned)1, (unsigned)len);
 171:         bcopy(bp, hostPtr->name, len);
 172:         } else {
 173:         cp += dn_skip(cp) + QFIXEDSZ;
 174:         }
 175:         while (--qdcount > 0) {
 176:         cp += dn_skip(cp) + QFIXEDSZ;
 177:         }
 178:     } else if (iquery) {
 179:         return (NO_INFO);
 180:     }
 181: 
 182:     aliasPtr    = host_aliases;
 183:     addrPtr     = addr_list;
 184:     haveanswer  = 0;
 185: 
 186:     /*
 187: 	 * Scan through the answer resource records.
 188: 	 * Answers for address query types are saved.
 189: 	 * Other query type answers are just printed.
 190: 	 */
 191:     while (--ancount >= 0 && cp < eom) {
 192:         if (queryType != T_A) {
 193:         if ((cp = Print_rr(cp, (char *) &answer, eom, stdout)) == NULL) {
 194:             return(ERROR);
 195:         }
 196:         continue;
 197:         } else {
 198:         if ((n = dn_expand((char *) &answer, eom, cp, bp, buflen)) < 0) {
 199:             return(ERROR);
 200:         }
 201:         cp += n;
 202:         type = getshort(cp);
 203:         cp += sizeof(u_short);
 204:         class = getshort(cp);
 205:         cp += sizeof(u_short) + sizeof(u_long);
 206:         dlen = getshort(cp);
 207:         cp += sizeof(u_short);
 208:         if (type == T_CNAME) {
 209:             /*
 210: 		     * Found an alias.
 211: 		     */
 212:             cp += dlen;
 213:             if (aliasPtr >= &host_aliases[MAXALIASES-1])
 214:                 continue;
 215:             *aliasPtr++ = bp;
 216:             n = strlen(bp) + 1;
 217:             host_aliases_len[numAliases] = n;
 218:             numAliases++;
 219:             bp += n;
 220:             buflen -= n;
 221:             continue;
 222:         } else if (type == T_PTR) {
 223:             /*
 224: 		     *  Found a "pointer" to the real name.
 225: 		     */
 226:             if((n= dn_expand((char *)&answer, eom, cp, bp, buflen)) < 0){
 227:             cp += n;
 228:             continue;
 229:             }
 230:             cp += n;
 231:             len = strlen(bp) + 1;
 232:             hostPtr->name = Calloc((unsigned)1, (unsigned)len);
 233:             bcopy(bp, hostPtr->name, len);
 234:             haveanswer = 1;
 235:             break;
 236:         } else if (type != T_A) {
 237:             cp += dlen;
 238:             continue;
 239:         }
 240:         if (haveanswer) {
 241:             if (n != hostPtr->addrLen) {
 242:             cp += dlen;
 243:             continue;
 244:             }
 245:             if (class != getclass) {
 246:             cp += dlen;
 247:             continue;
 248:             }
 249:         } else {
 250:             hostPtr->addrLen = dlen;
 251:             getclass = class;
 252:             hostPtr->addrType = (class == C_IN) ? AF_INET : AF_UNSPEC;
 253:             if (!iquery) {
 254:             len = strlen(bp) + 1;
 255:             hostPtr->name = Calloc((unsigned)1, (unsigned)len);
 256:             bcopy(bp, hostPtr->name, len);
 257:             }
 258:         }
 259:         bp += (((u_long)bp) % sizeof(align));
 260: 
 261:         if (bp + dlen >= &hostbuf[sizeof(hostbuf)]) {
 262:             if (_res.options & RES_DEBUG)
 263:                 printf("Size (%d) too big\n", dlen);
 264:             break;
 265:         }
 266:         bcopy(cp, *addrPtr++ = bp, dlen);
 267:         bp +=dlen;
 268:         cp += dlen;
 269:         numAddresses++;
 270:         haveanswer = 1;
 271:         }
 272:     }
 273: 
 274:     if (queryType == T_A && haveanswer) {
 275: 
 276:         /*
 277: 	     *  Go through the alias and address lists and return them
 278: 	     *  in the hostPtr variable.
 279: 	     */
 280: 
 281:         if (numAliases > 0) {
 282:         hostPtr->aliases = (char **) Calloc((unsigned)1+numAliases,
 283:                             sizeof(char *));
 284:         for (i = 0; i < numAliases; i++) {
 285:             hostPtr->aliases[i] = Calloc((unsigned)1, (unsigned)host_aliases_len[i]);
 286:             bcopy(host_aliases[i], hostPtr->aliases[i],
 287:                 host_aliases_len[i]);
 288:         }
 289:         hostPtr->aliases[i] = NULL;
 290:         }
 291:         if (numAddresses > 0) {
 292:         hostPtr->addrList = (char **) Calloc((unsigned)1+numAddresses,
 293:                             sizeof(char *));
 294:         for (i = 0; i < numAddresses; i++) {
 295:             hostPtr->addrList[i] = Calloc((unsigned)1, (unsigned)hostPtr->addrLen);
 296:             bcopy(addr_list[i], hostPtr->addrList[i],
 297:                 hostPtr->addrLen);
 298:         }
 299:         hostPtr->addrList[i] = NULL;
 300:         }
 301:         hostPtr->servers= NULL;
 302:         return (SUCCESS);
 303:     }
 304: 
 305:     /*
 306: 	 * At this point, only non-authoritative answers for
 307: 	 * the T_A query type remain. For other query types,
 308: 	 * additional information might be found in the additional
 309: 	 * resource records part.
 310: 	 */
 311: 
 312:     cp = res_skip((char *) &answer, 2);
 313: 
 314:     numServers = 0;
 315:     while (--nscount >= 0 && cp < eom) {
 316:         /*
 317: 	     *  Go through the NS records and retrieve the
 318: 	     *  names of hosts that server the requested domain,
 319: 	     *  their addresses and other domains they might serve.
 320: 	     */
 321: 
 322:       if ((n = dn_expand((char *) &answer, eom, cp, bp, buflen)) < 0) {
 323:           return(ERROR);
 324:       }
 325:       cp += n;
 326:       len = strlen(bp) + 1;
 327:       dnamePtr = Calloc((unsigned)1, (unsigned)len);   /* domain name */
 328:       bcopy(bp, dnamePtr, len);
 329: 
 330:       type = getshort(cp);
 331:       cp += sizeof(u_short);
 332:       class = getshort(cp);
 333:       cp += sizeof(u_short) + sizeof(u_long);
 334:       dlen = getshort(cp);
 335:       cp += sizeof(u_short);
 336: 
 337:       if (type != T_NS) {
 338:           cp += dlen;
 339:       } else {
 340:         if ((n = dn_expand((char *) &answer, eom, cp, bp, buflen)) < 0) {
 341:             return(ERROR);
 342:         }
 343:         cp += n;
 344:         len = strlen(bp) + 1;
 345:         namePtr = Calloc((unsigned)1, (unsigned)len); /* server host name */
 346:         bcopy(bp, namePtr, len);
 347: 
 348:         /*
 349: 	     * Store the information keyed by the server host name.
 350: 	     */
 351:         found = FALSE;
 352:         for (j = 0; j < numServers; j++) {
 353:         if (strcmp(namePtr, server[j].name) == 0) {
 354:             found = TRUE;
 355:             free(namePtr);
 356:             break;
 357:         }
 358:         }
 359:         if (found) {
 360:         server[j].numDomains++;
 361:         if (server[j].numDomains <= MAXDOMAINS) {
 362:             server[j].domain[server[j].numDomains-1] = dnamePtr;
 363:         }
 364:         } else {
 365:         if (numServers > MAXSERVERS) {
 366:             break;
 367:         }
 368:         numServers++;
 369:         server[numServers -1].name = namePtr;
 370:         server[numServers -1].domain[0] = dnamePtr;
 371:         server[numServers -1].numDomains = 1;
 372:         server[numServers -1].numAddresses = 0;
 373:         }
 374:       }
 375:     }
 376: 
 377:     if (!headerPtr->aa && (queryType != T_A) && arcount > 0) {
 378:         printf("Authoritative answers can be found from:\n");
 379:     }
 380: 
 381:     /*
 382: 	 * Additional resource records contain addresses of
 383: 	 * servers.
 384: 	 */
 385:     cp = res_skip((char *) &answer, 3);
 386:     while (--arcount >= 0 && cp < eom) {
 387:         /*
 388: 	     * If we don't need to save the record, just print it.
 389: 	     */
 390:         if (queryType != T_A) {
 391:         if ((cp = Print_rr(cp, (char *) &answer, eom, stdout)) == NULL) {
 392:             return(ERROR);
 393:         }
 394:         continue;
 395: 
 396:         } else {
 397:           if ((n = dn_expand((char *) &answer, eom, cp, bp, buflen)) < 0)
 398:               break;
 399:           cp += n;
 400:           type = getshort(cp);
 401:           cp += sizeof(u_short);
 402:           class = getshort(cp);
 403:           cp += sizeof(u_short) + sizeof(u_long);
 404:           dlen = getshort(cp);
 405:           cp += sizeof(u_short);
 406: 
 407:           if (type != T_A)  {
 408:           cp += dlen;
 409:           continue;
 410:           } else {
 411:         for (j = 0; j < numServers; j++) {
 412:           if (strcmp(bp, server[j].name) == 0) {
 413:             server[j].numAddresses++;
 414:             if (server[j].numAddresses <= MAXADDRS) {
 415:              server[j].address[server[j].numAddresses-1]=Calloc((unsigned)1,(unsigned)dlen);
 416:              bcopy(cp,server[j].address[server[j].numAddresses-1],dlen);
 417:              break;
 418:             }
 419:           }
 420:         }
 421:         cp += dlen;
 422:           }
 423:         }
 424:     }
 425: 
 426:     /*
 427: 	 * If we are returning name server info, transfer it to
 428: 	 * the hostPtr.
 429: 	 *
 430: 	 */
 431:     if (numServers > 0) {
 432:       hostPtr->servers = (ServerInfo **) Calloc((unsigned)numServers+1,
 433:                     sizeof(ServerInfo *));
 434:       for (i = 0; i < numServers; i++) {
 435:         hostPtr->servers[i] = (ServerInfo *) Calloc((unsigned)1, sizeof(ServerInfo));
 436:         hostPtr->servers[i]->name = server[i].name;
 437: 
 438: 
 439:         hostPtr->servers[i]->domains = (char **)
 440:                 Calloc((unsigned)server[i].numDomains+1,sizeof(char *));
 441:         for (j = 0; j < server[i].numDomains; j++) {
 442:           hostPtr->servers[i]->domains[j] = server[i].domain[j];
 443:         }
 444:         hostPtr->servers[i]->domains[j] = NULL;
 445: 
 446: 
 447:         hostPtr->servers[i]->addrList = (char **)
 448:                 Calloc((unsigned)server[i].numAddresses+1,sizeof(char *));
 449:         for (j = 0; j < server[i].numAddresses; j++) {
 450:           hostPtr->servers[i]->addrList[j] = server[i].address[j];
 451:         }
 452:         hostPtr->servers[i]->addrList[j] = NULL;
 453: 
 454:       }
 455:       hostPtr->servers[i] = NULL;
 456:     }
 457: 
 458: 
 459:     if (queryType != T_A) {
 460:         return(SUCCESS);
 461:     } else {
 462:         return(NONAUTH);
 463:     }
 464: }
 465: 
 466: /*
 467:  *******************************************************************************
 468:  *
 469:  *  GetHostInfo --
 470:  *
 471:  *	Retrieves host name, address and alias information
 472:  *	for a domain.
 473:  *
 474:  *  Results:
 475:  *	ERROR		- res_mkquery failed.
 476:  *	+ return values from GetAnswer()
 477:  *
 478:  *******************************************************************************
 479:  */
 480: 
 481: int
 482: GetHostInfo(nsAddrPtr, queryType, name, hostPtr)
 483:     struct in_addr *nsAddrPtr;
 484:     int         queryType;
 485:     char        *name;
 486:     HostInfo    *hostPtr;
 487: {
 488:     int      n;
 489:     int      result;
 490:     querybuf buf;
 491:     extern char *Calloc();
 492: 
 493:     /* catch explicit addresses */
 494:     if (isdigit(*name)) {
 495:         long ina;
 496: 
 497:         ina = inet_addr(name);
 498: 
 499:         if (ina == -1)
 500:         return(ERROR);
 501: 
 502:         hostPtr->name = Calloc((unsigned)strlen(name)+3,1);
 503:         sprintf(hostPtr->name,"[%s]",name);
 504:         hostPtr->aliases = 0;
 505:         hostPtr->servers = 0;
 506:         hostPtr->addrType = AF_INET;
 507:         hostPtr->addrLen = 4;
 508:         hostPtr->addrList = (char **)Calloc((unsigned)2,sizeof(char *));
 509:         hostPtr->addrList[0] = Calloc(sizeof(long),sizeof(char));
 510:         bcopy((char *)&ina,hostPtr->addrList[0],sizeof(ina));
 511:         hostPtr->addrList[1] = 0;
 512: 
 513:         return(SUCCESS);
 514:     }
 515: 
 516:     n = res_mkquery(QUERY, name, C_ANY, queryType,
 517:             (char *)0, 0, (char *)0, (char *) &buf, sizeof(buf));
 518:     if (n < 0) {
 519:         if (_res.options & RES_DEBUG) {
 520:         printf("Res_mkquery failed\n");
 521:         }
 522:         return (ERROR);
 523:     }
 524: 
 525:     result = GetAnswer(nsAddrPtr, queryType, (char *) &buf, n, 0, hostPtr);
 526: 
 527:     /*
 528: 	 * GetAnswer didn't find a name, so set it to the specified one.
 529: 	 */
 530:     if (result == NONAUTH) {
 531:         if (hostPtr->name == NULL) {
 532:         int len = strlen(name) + 1;
 533:         hostPtr->name = Calloc((unsigned)len, sizeof(char));
 534:         bcopy(name, hostPtr->name, len);
 535:         }
 536:     }
 537:     return(result);
 538: }
 539: 
 540: 
 541: /*
 542:  *******************************************************************************
 543:  *
 544:  *  FindHostInfo --
 545:  *
 546:  *	Performs an inverse query to find the host name
 547:  *	that corresponds to the given address.
 548:  *
 549:  *  Results:
 550:  *	ERROR		- res_mkquery failed.
 551:  *	+ return values from GetAnswer()
 552:  *
 553:  *******************************************************************************
 554:  */
 555: 
 556: int
 557: FindHostInfo(nsAddrPtr, address, len, hostPtr)
 558:     struct in_addr  *nsAddrPtr;
 559:     struct in_addr  *address;
 560:     int         len;
 561:     HostInfo    *hostPtr;
 562: {
 563:     int      n;
 564:     querybuf buf;
 565: 
 566:     n = res_mkquery(IQUERY, (char *)0, C_IN, T_A,
 567:         (char *)address, len, (char *)0, (char *) &buf, sizeof(buf));
 568:     if (n < 0) {
 569:         if (_res.options & RES_DEBUG) {
 570:         printf("Res_mkquery failed\n");
 571:         }
 572:         return (ERROR);
 573:     }
 574:     return(GetAnswer(nsAddrPtr, T_A, (char *) &buf, n, 1, hostPtr));
 575: }
 576: 
 577: /*
 578:  *******************************************************************************
 579:  *
 580:  *  FreeHostInfoPtr --
 581:  *
 582:  *	Deallocates all the calloc'd areas for a HostInfo
 583:  *	variable.
 584:  *
 585:  *******************************************************************************
 586:  */
 587: 
 588: void
 589: FreeHostInfoPtr(hostPtr)
 590:     HostInfo *hostPtr;
 591: {
 592:     int i, j;
 593: 
 594:     if (hostPtr->name != NULL) {
 595:         free(hostPtr->name);
 596:         hostPtr->name = NULL;
 597:     }
 598: 
 599:     if (hostPtr->aliases != NULL) {
 600:         i = 0;
 601:         while (hostPtr->aliases[i] != NULL) {
 602:         free(hostPtr->aliases[i]);
 603:         i++;
 604:         }
 605:         free((char *)hostPtr->aliases);
 606:         hostPtr->aliases = NULL;
 607:     }
 608: 
 609:     if (hostPtr->addrList != NULL) {
 610:         i = 0;
 611:         while (hostPtr->addrList[i] != NULL) {
 612:         free(hostPtr->addrList[i]);
 613:         i++;
 614:         }
 615:         free((char *)hostPtr->addrList);
 616:         hostPtr->addrList = NULL;
 617:     }
 618: 
 619:     if (hostPtr->servers != NULL) {
 620:         i = 0;
 621:         while (hostPtr->servers[i] != NULL) {
 622: 
 623:         if (hostPtr->servers[i]->name != NULL) {
 624:             free(hostPtr->servers[i]->name);
 625:         }
 626: 
 627:         if (hostPtr->servers[i]->domains != NULL) {
 628:             j = 0;
 629:             while (hostPtr->servers[i]->domains[j] != NULL) {
 630:             free(hostPtr->servers[i]->domains[j]);
 631:             j++;
 632:             }
 633:             free((char *)hostPtr->servers[i]->domains);
 634:         }
 635: 
 636:         if (hostPtr->servers[i]->addrList != NULL) {
 637:             j = 0;
 638:             while (hostPtr->servers[i]->addrList[j] != NULL) {
 639:             free(hostPtr->servers[i]->addrList[j]);
 640:             j++;
 641:             }
 642:             free((char *)hostPtr->servers[i]->addrList);
 643:         }
 644:         free((char *)hostPtr->servers[i]);
 645:         i++;
 646:         }
 647:         free((char *)hostPtr->servers);
 648:         hostPtr->servers = NULL;
 649:     }
 650: }
 651: 
 652: /*
 653:  *******************************************************************************
 654:  *
 655:  *  GetHostList --
 656:  *
 657:  *	Performs a completion query when given an incomplete
 658:  *	name.
 659:  *
 660:  *	Still under development.
 661:  *
 662:  *******************************************************************************
 663:  */
 664: 
 665: #if  notdef
 666: 
 667: int
 668: GetHostList(nsAddrPtr, queryType, name, defaultName, hostPtr)
 669:     struct in_addr  *nsAddrPtr;
 670:     int         queryType;
 671:     char        *name, *defaultName;
 672:     HostInfo    *hostPtr;
 673: {
 674:     int      n;
 675:     querybuf buf;
 676: 
 677:     n = res_mkquery(CQUERYM, name, C_IN, T_A, defaultName, 0, (char *)0,
 678:         (char *) &buf, sizeof(buf));
 679:     if (n < 0) {
 680:         if (_res.options & RES_DEBUG)
 681:             printf("Res_mkquery failed\n");
 682:         return (ERROR);
 683:     }
 684:     return(GetAnswer( nsAddrPtr, queryType, (char *) &buf, n, 0, hostPtr));
 685: }
 686: #endif  notdef

Defined functions

FindHostInfo defined in line 556; used 1 times
GetAnswer defined in line 84; used 3 times
GetHostInfo defined in line 481; used 10 times
GetHostList defined in line 667; never used

Defined variables

addr_list defined in line 39; used 2 times
host_aliases defined in line 41; used 3 times
host_aliases_len defined in line 42; used 3 times
hostbuf defined in line 43; used 4 times
sccsid defined in line 19; never used

Defined macros

MAXADDRS defined in line 35; used 3 times
MAXALIASES defined in line 34; used 3 times
MAXDOMAINS defined in line 36; used 2 times
MAXSERVERS defined in line 37; used 2 times
Last modified: 1986-05-01
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 3059
Valid CSS Valid XHTML 1.0 Strict