|
|
BSD 4.3
/*
*******************************************************************************
*
* 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 <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
#include <ctype.h>
#include <arpa/nameser.h>
#include <resolv.h>
#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
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.