/* ******************************************************************************* * * getinfo.c -- * * Routines to create requests to name servers * and interpret the answers. * * Adapted from 4.3BSD BIND gethostnamadr.c * * Copyright (c) 1985 Regents of the University of California. * All rights reserved. The Berkeley software License Agreement * specifies the terms and conditions for redistribution. * ******************************************************************************* */ #ifndef lint static char sccsid[] = "@(#)getinfo.c 5.3 (Berkeley) 3/31/86"; #endif not lint #include #include #include #include #include #include #include #include "res.h" extern char *rcodes[]; extern char *res_skip(); #define MAXALIASES 35 #define MAXADDRS 35 #define MAXDOMAINS 35 #define MAXSERVERS 10 static char *addr_list[MAXADDRS + 1]; static char *host_aliases[MAXALIASES]; static int host_aliases_len[MAXALIASES]; static char hostbuf[BUFSIZ+1]; typedef struct { char *name; char *domain[MAXDOMAINS]; int numDomains; char *address[MAXADDRS]; int numAddresses; } ServerTable; ServerTable server[MAXSERVERS]; typedef union { HEADER qb1; char qb2[PACKETSZ]; } querybuf; static union { long al; char ac; } align; /* ******************************************************************************* * * GetAnswer -- * * Interprets an answer packet and retrieves the following * information: * * Results: * SUCCESS the info was retrieved. * NO_INFO the packet did not contain an answer. * NONAUTH non-authoritative information was found. * ERROR the answer was malformed. * Other errors returned in the packet header. * ******************************************************************************* */ static int GetAnswer(nsAddrPtr, queryType, msg, msglen, iquery, hostPtr) struct in_addr *nsAddrPtr; char *msg; int queryType; int msglen; int iquery; register HostInfo *hostPtr; { register HEADER *headerPtr; register char *cp; querybuf answer; char *eom, *bp, **aliasPtr; char **addrPtr; char *namePtr; char *dnamePtr; int type, class; int qdcount, ancount, arcount, nscount, buflen; int haveanswer, getclass; int numAliases = 0; int numAddresses = 0; int n, i, j; int len; int dlen; int status; int numServers; int found; /* * If the hostPtr was used before, free up * the calloc'd areas. */ FreeHostInfoPtr(hostPtr); status = SendRequest(nsAddrPtr, msg, msglen, (char *) &answer, sizeof(answer), &n); if (status != SUCCESS) { if (_res.options & RES_DEBUG2) printf("SendRequest failed\n"); return (status); } eom = (char *) &answer + n; headerPtr = (HEADER *) &answer; qdcount = ntohs(headerPtr->qdcount); ancount = ntohs(headerPtr->ancount); arcount = ntohs(headerPtr->arcount); nscount = ntohs(headerPtr->nscount); if (headerPtr->rcode != NOERROR) { if (_res.options & RES_DEBUG) { printf( "Failed: %s, num. answers = %d, ns = %d, additional = %d\n", rcodes[headerPtr->rcode], ancount, nscount, arcount); } return (headerPtr->rcode); } /* * If there are no answer, n.s. or additional records * then return with an error. */ if (ancount == 0 && nscount == 0 && arcount == 0) { return (NO_INFO); } bp = hostbuf; buflen = sizeof(hostbuf); cp = (char *) &answer + sizeof(HEADER); /* * For inverse queries, the desired information is returned * in the question section. If there are no question records, * return with an error. * */ if (qdcount) { if (iquery) { if ((n = dn_expand((char *)&answer, eom, cp, bp, buflen)) < 0) { return (ERROR); } cp += n + QFIXEDSZ; len = strlen(bp) + 1; hostPtr->name = Calloc((unsigned)1, (unsigned)len); bcopy(bp, hostPtr->name, len); } else { cp += dn_skip(cp) + QFIXEDSZ; } while (--qdcount > 0) { cp += dn_skip(cp) + QFIXEDSZ; } } else if (iquery) { return (NO_INFO); } aliasPtr = host_aliases; addrPtr = addr_list; haveanswer = 0; /* * Scan through the answer resource records. * Answers for address query types are saved. * Other query type answers are just printed. */ while (--ancount >= 0 && cp < eom) { if (queryType != T_A) { if ((cp = Print_rr(cp, (char *) &answer, eom, stdout)) == NULL) { return(ERROR); } continue; } else { if ((n = dn_expand((char *) &answer, eom, cp, bp, buflen)) < 0) { return(ERROR); } cp += n; type = getshort(cp); cp += sizeof(u_short); class = getshort(cp); cp += sizeof(u_short) + sizeof(u_long); dlen = getshort(cp); cp += sizeof(u_short); if (type == T_CNAME) { /* * Found an alias. */ cp += dlen; if (aliasPtr >= &host_aliases[MAXALIASES-1]) continue; *aliasPtr++ = bp; n = strlen(bp) + 1; host_aliases_len[numAliases] = n; numAliases++; bp += n; buflen -= n; continue; } else if (type == T_PTR) { /* * Found a "pointer" to the real name. */ if((n= dn_expand((char *)&answer, eom, cp, bp, buflen)) < 0){ cp += n; continue; } cp += n; len = strlen(bp) + 1; hostPtr->name = Calloc((unsigned)1, (unsigned)len); bcopy(bp, hostPtr->name, len); haveanswer = 1; break; } else if (type != T_A) { cp += dlen; continue; } if (haveanswer) { if (n != hostPtr->addrLen) { cp += dlen; continue; } if (class != getclass) { cp += dlen; continue; } } else { hostPtr->addrLen = dlen; getclass = class; hostPtr->addrType = (class == C_IN) ? AF_INET : AF_UNSPEC; if (!iquery) { len = strlen(bp) + 1; hostPtr->name = Calloc((unsigned)1, (unsigned)len); bcopy(bp, hostPtr->name, len); } } bp += (((u_long)bp) % sizeof(align)); if (bp + dlen >= &hostbuf[sizeof(hostbuf)]) { if (_res.options & RES_DEBUG) printf("Size (%d) too big\n", dlen); break; } bcopy(cp, *addrPtr++ = bp, dlen); bp +=dlen; cp += dlen; numAddresses++; haveanswer = 1; } } if (queryType == T_A && haveanswer) { /* * Go through the alias and address lists and return them * in the hostPtr variable. */ if (numAliases > 0) { hostPtr->aliases = (char **) Calloc((unsigned)1+numAliases, sizeof(char *)); for (i = 0; i < numAliases; i++) { hostPtr->aliases[i] = Calloc((unsigned)1, (unsigned)host_aliases_len[i]); bcopy(host_aliases[i], hostPtr->aliases[i], host_aliases_len[i]); } hostPtr->aliases[i] = NULL; } if (numAddresses > 0) { hostPtr->addrList = (char **) Calloc((unsigned)1+numAddresses, sizeof(char *)); for (i = 0; i < numAddresses; i++) { hostPtr->addrList[i] = Calloc((unsigned)1, (unsigned)hostPtr->addrLen); bcopy(addr_list[i], hostPtr->addrList[i], hostPtr->addrLen); } hostPtr->addrList[i] = NULL; } hostPtr->servers= NULL; return (SUCCESS); } /* * At this point, only non-authoritative answers for * the T_A query type remain. For other query types, * additional information might be found in the additional * resource records part. */ cp = res_skip((char *) &answer, 2); numServers = 0; while (--nscount >= 0 && cp < eom) { /* * Go through the NS records and retrieve the * names of hosts that server the requested domain, * their addresses and other domains they might serve. */ if ((n = dn_expand((char *) &answer, eom, cp, bp, buflen)) < 0) { return(ERROR); } cp += n; len = strlen(bp) + 1; dnamePtr = Calloc((unsigned)1, (unsigned)len); /* domain name */ bcopy(bp, dnamePtr, len); type = getshort(cp); cp += sizeof(u_short); class = getshort(cp); cp += sizeof(u_short) + sizeof(u_long); dlen = getshort(cp); cp += sizeof(u_short); if (type != T_NS) { cp += dlen; } else { if ((n = dn_expand((char *) &answer, eom, cp, bp, buflen)) < 0) { return(ERROR); } cp += n; len = strlen(bp) + 1; namePtr = Calloc((unsigned)1, (unsigned)len); /* server host name */ bcopy(bp, namePtr, len); /* * Store the information keyed by the server host name. */ found = FALSE; for (j = 0; j < numServers; j++) { if (strcmp(namePtr, server[j].name) == 0) { found = TRUE; free(namePtr); break; } } if (found) { server[j].numDomains++; if (server[j].numDomains <= MAXDOMAINS) { server[j].domain[server[j].numDomains-1] = dnamePtr; } } else { if (numServers > MAXSERVERS) { break; } numServers++; server[numServers -1].name = namePtr; server[numServers -1].domain[0] = dnamePtr; server[numServers -1].numDomains = 1; server[numServers -1].numAddresses = 0; } } } if (!headerPtr->aa && (queryType != T_A) && arcount > 0) { printf("Authoritative answers can be found from:\n"); } /* * Additional resource records contain addresses of * servers. */ cp = res_skip((char *) &answer, 3); while (--arcount >= 0 && cp < eom) { /* * If we don't need to save the record, just print it. */ if (queryType != T_A) { if ((cp = Print_rr(cp, (char *) &answer, eom, stdout)) == NULL) { return(ERROR); } continue; } else { if ((n = dn_expand((char *) &answer, eom, cp, bp, buflen)) < 0) break; cp += n; type = getshort(cp); cp += sizeof(u_short); class = getshort(cp); cp += sizeof(u_short) + sizeof(u_long); dlen = getshort(cp); cp += sizeof(u_short); if (type != T_A) { cp += dlen; continue; } else { for (j = 0; j < numServers; j++) { if (strcmp(bp, server[j].name) == 0) { server[j].numAddresses++; if (server[j].numAddresses <= MAXADDRS) { server[j].address[server[j].numAddresses-1]=Calloc((unsigned)1,(unsigned)dlen); bcopy(cp,server[j].address[server[j].numAddresses-1],dlen); break; } } } cp += dlen; } } } /* * If we are returning name server info, transfer it to * the hostPtr. * */ if (numServers > 0) { hostPtr->servers = (ServerInfo **) Calloc((unsigned)numServers+1, sizeof(ServerInfo *)); for (i = 0; i < numServers; i++) { hostPtr->servers[i] = (ServerInfo *) Calloc((unsigned)1, sizeof(ServerInfo)); hostPtr->servers[i]->name = server[i].name; hostPtr->servers[i]->domains = (char **) Calloc((unsigned)server[i].numDomains+1,sizeof(char *)); for (j = 0; j < server[i].numDomains; j++) { hostPtr->servers[i]->domains[j] = server[i].domain[j]; } hostPtr->servers[i]->domains[j] = NULL; hostPtr->servers[i]->addrList = (char **) Calloc((unsigned)server[i].numAddresses+1,sizeof(char *)); for (j = 0; j < server[i].numAddresses; j++) { hostPtr->servers[i]->addrList[j] = server[i].address[j]; } hostPtr->servers[i]->addrList[j] = NULL; } hostPtr->servers[i] = NULL; } if (queryType != T_A) { return(SUCCESS); } else { return(NONAUTH); } } /* ******************************************************************************* * * GetHostInfo -- * * Retrieves host name, address and alias information * for a domain. * * Results: * ERROR - res_mkquery failed. * + return values from GetAnswer() * ******************************************************************************* */ int GetHostInfo(nsAddrPtr, queryType, name, hostPtr) struct in_addr *nsAddrPtr; int queryType; char *name; HostInfo *hostPtr; { int n; int result; querybuf buf; extern char *Calloc(); /* catch explicit addresses */ if (isdigit(*name)) { long ina; ina = inet_addr(name); if (ina == -1) return(ERROR); hostPtr->name = Calloc((unsigned)strlen(name)+3,1); sprintf(hostPtr->name,"[%s]",name); hostPtr->aliases = 0; hostPtr->servers = 0; hostPtr->addrType = AF_INET; hostPtr->addrLen = 4; hostPtr->addrList = (char **)Calloc((unsigned)2,sizeof(char *)); hostPtr->addrList[0] = Calloc(sizeof(long),sizeof(char)); bcopy((char *)&ina,hostPtr->addrList[0],sizeof(ina)); hostPtr->addrList[1] = 0; return(SUCCESS); } n = res_mkquery(QUERY, name, C_ANY, queryType, (char *)0, 0, (char *)0, (char *) &buf, sizeof(buf)); if (n < 0) { if (_res.options & RES_DEBUG) { printf("Res_mkquery failed\n"); } return (ERROR); } result = GetAnswer(nsAddrPtr, queryType, (char *) &buf, n, 0, hostPtr); /* * GetAnswer didn't find a name, so set it to the specified one. */ if (result == NONAUTH) { if (hostPtr->name == NULL) { int len = strlen(name) + 1; hostPtr->name = Calloc((unsigned)len, sizeof(char)); bcopy(name, hostPtr->name, len); } } return(result); } /* ******************************************************************************* * * FindHostInfo -- * * Performs an inverse query to find the host name * that corresponds to the given address. * * Results: * ERROR - res_mkquery failed. * + return values from GetAnswer() * ******************************************************************************* */ int FindHostInfo(nsAddrPtr, address, len, hostPtr) struct in_addr *nsAddrPtr; struct in_addr *address; int len; HostInfo *hostPtr; { int n; querybuf buf; n = res_mkquery(IQUERY, (char *)0, C_IN, T_A, (char *)address, len, (char *)0, (char *) &buf, sizeof(buf)); if (n < 0) { if (_res.options & RES_DEBUG) { printf("Res_mkquery failed\n"); } return (ERROR); } return(GetAnswer(nsAddrPtr, T_A, (char *) &buf, n, 1, hostPtr)); } /* ******************************************************************************* * * FreeHostInfoPtr -- * * Deallocates all the calloc'd areas for a HostInfo * variable. * ******************************************************************************* */ void FreeHostInfoPtr(hostPtr) HostInfo *hostPtr; { int i, j; if (hostPtr->name != NULL) { free(hostPtr->name); hostPtr->name = NULL; } if (hostPtr->aliases != NULL) { i = 0; while (hostPtr->aliases[i] != NULL) { free(hostPtr->aliases[i]); i++; } free((char *)hostPtr->aliases); hostPtr->aliases = NULL; } if (hostPtr->addrList != NULL) { i = 0; while (hostPtr->addrList[i] != NULL) { free(hostPtr->addrList[i]); i++; } free((char *)hostPtr->addrList); hostPtr->addrList = NULL; } if (hostPtr->servers != NULL) { i = 0; while (hostPtr->servers[i] != NULL) { if (hostPtr->servers[i]->name != NULL) { free(hostPtr->servers[i]->name); } if (hostPtr->servers[i]->domains != NULL) { j = 0; while (hostPtr->servers[i]->domains[j] != NULL) { free(hostPtr->servers[i]->domains[j]); j++; } free((char *)hostPtr->servers[i]->domains); } if (hostPtr->servers[i]->addrList != NULL) { j = 0; while (hostPtr->servers[i]->addrList[j] != NULL) { free(hostPtr->servers[i]->addrList[j]); j++; } free((char *)hostPtr->servers[i]->addrList); } free((char *)hostPtr->servers[i]); i++; } free((char *)hostPtr->servers); hostPtr->servers = NULL; } } /* ******************************************************************************* * * GetHostList -- * * Performs a completion query when given an incomplete * name. * * Still under development. * ******************************************************************************* */ #if notdef int GetHostList(nsAddrPtr, queryType, name, defaultName, hostPtr) struct in_addr *nsAddrPtr; int queryType; char *name, *defaultName; HostInfo *hostPtr; { int n; querybuf buf; n = res_mkquery(CQUERYM, name, C_IN, T_A, defaultName, 0, (char *)0, (char *) &buf, sizeof(buf)); if (n < 0) { if (_res.options & RES_DEBUG) printf("Res_mkquery failed\n"); return (ERROR); } return(GetAnswer( nsAddrPtr, queryType, (char *) &buf, n, 0, hostPtr)); } #endif notdef