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