9aee5e4673
Reference ISC BIND issue: ``1278. [bug] free() of non-malloced memory in nslookup.'' Reported by: phkmalloc, Mike Tancsa <mike@sentex.net>
1112 lines
31 KiB
C
1112 lines
31 KiB
C
/* $FreeBSD$ */
|
||
/*
|
||
* Copyright (c) 1985, 1989
|
||
* The Regents of the University of California. All rights reserved.
|
||
*
|
||
* Redistribution and use in source and binary forms, with or without
|
||
* modification, are permitted provided that the following conditions
|
||
* are met:
|
||
* 1. Redistributions of source code must retain the above copyright
|
||
* notice, this list of conditions and the following disclaimer.
|
||
* 2. Redistributions in binary form must reproduce the above copyright
|
||
* notice, this list of conditions and the following disclaimer in the
|
||
* documentation and/or other materials provided with the distribution.
|
||
* 3. All advertising materials mentioning features or use of this software
|
||
* must display the following acknowledgement:
|
||
* This product includes software developed by the University of
|
||
* California, Berkeley and its contributors.
|
||
* 4. Neither the name of the University nor the names of its contributors
|
||
* may be used to endorse or promote products derived from this software
|
||
* without specific prior written permission.
|
||
*
|
||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||
* SUCH DAMAGE.
|
||
*/
|
||
|
||
/*
|
||
* Portions Copyright (c) 1993 by Digital Equipment Corporation.
|
||
*
|
||
* Permission to use, copy, modify, and distribute this software for any
|
||
* purpose with or without fee is hereby granted, provided that the above
|
||
* copyright notice and this permission notice appear in all copies, and that
|
||
* the name of Digital Equipment Corporation not be used in advertising or
|
||
* publicity pertaining to distribution of the document or software without
|
||
* specific, written prior permission.
|
||
*
|
||
* THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
|
||
* WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
|
||
* OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
|
||
* CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
|
||
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
|
||
* ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
|
||
* SOFTWARE.
|
||
*/
|
||
|
||
#ifndef lint
|
||
static const char sccsid[] = "@(#)getinfo.c 5.26 (Berkeley) 3/21/91";
|
||
static const char rcsid[] = "$Id: getinfo.c,v 8.23 2002/04/29 01:11:52 marka Exp $";
|
||
#endif /* not lint */
|
||
|
||
/*
|
||
******************************************************************************
|
||
*
|
||
* getinfo.c --
|
||
*
|
||
* Routines to create requests to name servers
|
||
* and interpret the answers.
|
||
*
|
||
* Adapted from 4.3BSD BIND gethostnamadr.c
|
||
*
|
||
******************************************************************************
|
||
*/
|
||
|
||
#include "port_before.h"
|
||
|
||
#include <sys/param.h>
|
||
#include <sys/socket.h>
|
||
|
||
#include <netinet/in.h>
|
||
#include <arpa/nameser.h>
|
||
#include <arpa/inet.h>
|
||
|
||
#include <ctype.h>
|
||
#include <stdio.h>
|
||
#include <stdlib.h>
|
||
#include <string.h>
|
||
|
||
#include "port_after.h"
|
||
|
||
#include <resolv.h>
|
||
|
||
#include "res.h"
|
||
|
||
static char *addr_list[MAXADDRS + 1];
|
||
static int addr_len[MAXADDRS + 1];
|
||
static int addr_type[MAXADDRS + 1];
|
||
|
||
static char *host_aliases[MAXALIASES];
|
||
static int host_aliases_len[MAXALIASES];
|
||
static u_char hostbuf[MAXDNAME];
|
||
|
||
typedef struct {
|
||
char *name;
|
||
char *domain[MAXDOMAINS];
|
||
int numDomains;
|
||
char *address[MAXADDRS];
|
||
char len[MAXADDRS];
|
||
char type[MAXADDRS];
|
||
int numAddresses;
|
||
} ServerTable;
|
||
|
||
ServerTable server[MAXSERVERS];
|
||
|
||
typedef union {
|
||
HEADER qb1;
|
||
u_char qb2[64*1024];
|
||
} querybuf;
|
||
|
||
typedef union {
|
||
int32_t al;
|
||
char ac;
|
||
} align;
|
||
|
||
#define GetShort(cp) ns_get16(cp); cp += INT16SZ;
|
||
|
||
|
||
/*
|
||
******************************************************************************
|
||
*
|
||
* 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, isServer,
|
||
merge)
|
||
union res_sockaddr_union *nsAddrPtr;
|
||
char *msg;
|
||
int queryType;
|
||
int msglen;
|
||
Boolean iquery;
|
||
register HostInfo *hostPtr;
|
||
Boolean isServer;
|
||
Boolean merge;
|
||
{
|
||
register HEADER *headerPtr;
|
||
register const u_char *cp;
|
||
querybuf answer;
|
||
char **aliasPtr;
|
||
u_char *eom, *bp;
|
||
char **addrPtr;
|
||
int *lenPtr;
|
||
int *typePtr;
|
||
char *namePtr;
|
||
char *dnamePtr;
|
||
int type, class;
|
||
int qdcount, ancount, arcount, nscount, buflen;
|
||
int origClass = 0;
|
||
int numAliases = 0;
|
||
int numAddresses = 0;
|
||
int n, i, j, k, l, m;
|
||
int dlen;
|
||
int status;
|
||
int numServers;
|
||
size_t s;
|
||
Boolean haveAnswer;
|
||
Boolean printedAnswers = FALSE;
|
||
int oldAliases;
|
||
char **newAliases;
|
||
int oldServers;
|
||
ServerInfo **newServers;
|
||
int oldAddresses;
|
||
AddrInfo **newAddresses;
|
||
|
||
|
||
/*
|
||
* If the hostPtr was used before, free up the calloc'd areas.
|
||
*/
|
||
if (!merge)
|
||
FreeHostInfoPtr(hostPtr);
|
||
|
||
status = SendRequest(nsAddrPtr, (u_char *)msg, msglen, (u_char *) &answer,
|
||
sizeof(answer), &n);
|
||
|
||
if (status != SUCCESS) {
|
||
if (res.options & RES_DEBUG2)
|
||
printf("SendRequest failed\n");
|
||
return (status);
|
||
}
|
||
eom = (u_char *) &answer + n;
|
||
|
||
headerPtr = (HEADER *) &answer;
|
||
|
||
if (headerPtr->rcode != NOERROR) {
|
||
return (headerPtr->rcode);
|
||
}
|
||
|
||
qdcount = ntohs(headerPtr->qdcount);
|
||
ancount = ntohs(headerPtr->ancount);
|
||
arcount = ntohs(headerPtr->arcount);
|
||
nscount = ntohs(headerPtr->nscount);
|
||
|
||
/*
|
||
* 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 = (u_char *) &answer + HFIXEDSZ;
|
||
|
||
/* Skip over question section. */
|
||
while (qdcount-- > 0) {
|
||
n = dn_skipname(cp, eom);
|
||
if (n < 0)
|
||
return (ERROR);
|
||
cp += n + QFIXEDSZ;
|
||
if (cp > eom)
|
||
return (ERROR);
|
||
}
|
||
|
||
aliasPtr = host_aliases;
|
||
addrPtr = addr_list;
|
||
lenPtr = addr_len;
|
||
typePtr = addr_type;
|
||
haveAnswer = FALSE;
|
||
|
||
/*
|
||
* Scan through the answer resource records.
|
||
* Answers for address query types are saved.
|
||
* Other query type answers are just printed.
|
||
*/
|
||
if (ancount != 0) {
|
||
|
||
if (headerPtr->ad)
|
||
printf("Answer crypto-validated by server:\n");
|
||
|
||
if (!isServer && !headerPtr->aa) {
|
||
printf("Non-authoritative answer:\n");
|
||
}
|
||
|
||
if (queryType != T_A && queryType != T_AAAA && /* A6? */
|
||
!(iquery && queryType == T_PTR)) {
|
||
while (--ancount >= 0 && cp < eom) {
|
||
if ((cp = Print_rr(cp, (u_char *)&answer,
|
||
eom, stdout)) == NULL) {
|
||
return(ERROR);
|
||
}
|
||
}
|
||
printedAnswers = TRUE;
|
||
} else {
|
||
while (--ancount >= 0 && cp < eom) {
|
||
n = dn_expand(answer.qb2, eom, cp, (char *)bp, buflen);
|
||
if (n < 0)
|
||
return(ERROR);
|
||
cp += n;
|
||
if (cp + 3 * INT16SZ + INT32SZ > eom)
|
||
return (ERROR);
|
||
type = GetShort(cp);
|
||
class = GetShort(cp);
|
||
cp += INT32SZ; /* skip TTL */
|
||
dlen = GetShort(cp);
|
||
if (cp + dlen > eom)
|
||
return (ERROR);
|
||
if (type == T_CNAME) {
|
||
/*
|
||
* Found an alias.
|
||
*/
|
||
cp += dlen;
|
||
if (aliasPtr >= &host_aliases[MAXALIASES-1]) {
|
||
continue;
|
||
}
|
||
*aliasPtr++ = (char *)bp;
|
||
s = strlen((char *)bp) + 1;
|
||
host_aliases_len[numAliases] = s;
|
||
numAliases++;
|
||
bp += s;
|
||
buflen -= s;
|
||
continue;
|
||
} else if (type == T_PTR) {
|
||
/*
|
||
* Found a "pointer" to the real name.
|
||
*/
|
||
n = dn_expand(answer.qb2, eom, cp, (char *)bp, buflen);
|
||
if (n < 0) {
|
||
cp += n;
|
||
continue;
|
||
}
|
||
cp += n;
|
||
s = strlen((char *)bp) + 1;
|
||
hostPtr->name = Calloc(1, s);
|
||
memcpy(hostPtr->name, bp, s);
|
||
haveAnswer = TRUE;
|
||
break;
|
||
} else if (type != T_A && type != T_AAAA) {
|
||
cp += dlen;
|
||
continue;
|
||
}
|
||
if (type == T_A && dlen != INADDRSZ)
|
||
return (ERROR);
|
||
if (type == T_AAAA && dlen != 16)
|
||
return (ERROR);
|
||
if (haveAnswer) {
|
||
/*
|
||
* If we've already got 1 address, we aren't interested
|
||
* in addresses with a different class.
|
||
*/
|
||
if (class != origClass) {
|
||
cp += dlen;
|
||
continue;
|
||
}
|
||
} else {
|
||
/*
|
||
* First address: record its class so we only save
|
||
* additonal ones with the same attributes.
|
||
*/
|
||
origClass = class;
|
||
if (hostPtr->name == NULL) {
|
||
s = strlen((char *)bp) + 1;
|
||
hostPtr->name = Calloc(1, s);
|
||
memcpy(hostPtr->name, bp, s);
|
||
}
|
||
}
|
||
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;
|
||
}
|
||
if (numAddresses >= MAXADDRS) {
|
||
printf("MAXADDRS exceeded: skipping address\n");
|
||
cp += dlen;
|
||
continue;
|
||
}
|
||
memcpy(*addrPtr++ = (char *)bp, cp, dlen);
|
||
*lenPtr++ = dlen;
|
||
*typePtr++ = (class == C_IN) ?
|
||
((type == T_A) ? AF_INET : AF_INET6) :
|
||
AF_UNSPEC;
|
||
bp += dlen;
|
||
cp += dlen;
|
||
numAddresses++;
|
||
haveAnswer = TRUE;
|
||
}
|
||
}
|
||
}
|
||
|
||
if ((queryType == T_A || queryType == T_PTR) && haveAnswer) {
|
||
|
||
/*
|
||
* Go through the alias and address lists and return them
|
||
* in the hostPtr variable.
|
||
*/
|
||
|
||
oldAliases = 0;
|
||
if (merge && hostPtr->aliases != NULL) {
|
||
while (hostPtr->aliases[oldAliases] != NULL)
|
||
oldAliases++;
|
||
}
|
||
if (numAliases > 0) {
|
||
newAliases =
|
||
(char **) Calloc(1 + numAliases + oldAliases, sizeof(char *));
|
||
if (merge && hostPtr->aliases != NULL) {
|
||
memcpy(newAliases, hostPtr->aliases,
|
||
oldAliases * sizeof(char *));
|
||
free(hostPtr->aliases);
|
||
}
|
||
hostPtr->aliases = newAliases;
|
||
k = oldAliases;
|
||
for (i = 0; i < numAliases; i++) {
|
||
for (l = 0; l < k; l++)
|
||
if (!strcasecmp(hostPtr->aliases[l], host_aliases[i]))
|
||
break;
|
||
if (l < k)
|
||
continue;
|
||
hostPtr->aliases[k] = Calloc(1, host_aliases_len[i]);
|
||
memcpy(hostPtr->aliases[k], host_aliases[i],
|
||
host_aliases_len[i]);
|
||
k++;
|
||
}
|
||
hostPtr->aliases[k] = NULL;
|
||
}
|
||
oldAddresses = 0;
|
||
if (merge && hostPtr->addrList != NULL) {
|
||
while (hostPtr->addrList[oldAddresses] != NULL)
|
||
oldAddresses++;
|
||
}
|
||
if (numAddresses > 0) {
|
||
newAddresses =
|
||
(AddrInfo **)Calloc(1+numAddresses, sizeof(AddrInfo *));
|
||
if (merge && hostPtr->addrList != NULL) {
|
||
memcpy(newAddresses, hostPtr->addrList,
|
||
oldAddresses * sizeof(char *));
|
||
free(hostPtr->addrList);
|
||
}
|
||
hostPtr->addrList = newAddresses;
|
||
k = oldAddresses;
|
||
for (i = 0; i < numAddresses; i++) {
|
||
for (l = 0; l < k; l++)
|
||
if (hostPtr->addrList[l]->addrType == addr_type[i] &&
|
||
hostPtr->addrList[l]->addrLen == addr_len[i] &&
|
||
!memcmp(hostPtr->addrList[l]->addr, addr_list[i],
|
||
addr_len[i]))
|
||
break;
|
||
if (l < k)
|
||
continue;
|
||
hostPtr->addrList[k] = (AddrInfo*)Calloc(1, sizeof(AddrInfo));
|
||
hostPtr->addrList[k]->addr = Calloc(1, addr_len[i]);
|
||
hostPtr->addrList[k]->addrType = addr_type[i];
|
||
hostPtr->addrList[k]->addrLen = addr_len[i];
|
||
memcpy(hostPtr->addrList[k]->addr, addr_list[i], addr_len[i]);
|
||
k++;
|
||
}
|
||
hostPtr->addrList[k] = NULL;
|
||
}
|
||
#ifdef verbose
|
||
if (headerPtr->aa || nscount == 0) {
|
||
hostPtr->servers = NULL;
|
||
return (SUCCESS);
|
||
}
|
||
#else
|
||
hostPtr->servers = NULL;
|
||
return (SUCCESS);
|
||
#endif
|
||
}
|
||
|
||
/*
|
||
* At this point, for the T_A query type, only empty answers remain.
|
||
* For other query types, additional information might be found
|
||
* in the additional resource records part.
|
||
*/
|
||
|
||
if (!headerPtr->aa && (queryType != T_A) && (queryType != T_AAAA) &&
|
||
(nscount > 0 || arcount > 0)) {
|
||
if (printedAnswers) {
|
||
putchar('\n');
|
||
}
|
||
printf("Authoritative answers can be found from:\n");
|
||
}
|
||
|
||
cp = res_skip((u_char *)&answer, 2, eom);
|
||
|
||
numServers = 0;
|
||
if (queryType != T_A && queryType != T_AAAA) {
|
||
/*
|
||
* If we don't need to save the record, just print it.
|
||
*/
|
||
while (--nscount >= 0 && cp < eom) {
|
||
if ((cp = Print_rr(cp, (u_char *) &answer,
|
||
eom, stdout)) == NULL) {
|
||
return(ERROR);
|
||
}
|
||
}
|
||
} else {
|
||
while (--nscount >= 0 && cp < eom) {
|
||
/*
|
||
* Go through the NS records and retrieve the names of hosts
|
||
* that serve the requested domain.
|
||
*/
|
||
|
||
n = dn_expand(answer.qb2, eom, cp, (char *)bp, buflen);
|
||
if (n < 0) {
|
||
return(ERROR);
|
||
}
|
||
cp += n;
|
||
s = strlen((char *)bp) + 1;
|
||
dnamePtr = Calloc(1, s); /* domain name */
|
||
memcpy(dnamePtr, bp, s);
|
||
|
||
if (cp + 3 * INT16SZ + INT32SZ > eom)
|
||
return (ERROR);
|
||
type = GetShort(cp);
|
||
class = GetShort(cp);
|
||
cp += INT32SZ; /* skip TTL */
|
||
dlen = GetShort(cp);
|
||
if (cp + dlen > eom)
|
||
return (ERROR);
|
||
|
||
if (type != T_NS) {
|
||
cp += dlen;
|
||
} else {
|
||
Boolean found;
|
||
|
||
n = dn_expand(answer.qb2, eom, cp, (char *)bp, buflen);
|
||
if (n < 0) {
|
||
return(ERROR);
|
||
}
|
||
cp += n;
|
||
s = strlen((char *)bp) + 1;
|
||
namePtr = Calloc(1, s); /* server host name */
|
||
memcpy(namePtr, bp, s);
|
||
|
||
/*
|
||
* Store the information keyed by the server host name.
|
||
*/
|
||
found = FALSE;
|
||
for (j = 0; j < numServers; j++) {
|
||
if (strcasecmp(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;
|
||
}
|
||
server[numServers].name = namePtr;
|
||
server[numServers].domain[0] = dnamePtr;
|
||
server[numServers].numDomains = 1;
|
||
server[numServers].numAddresses = 0;
|
||
numServers++;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
/*
|
||
* Additional resource records contain addresses of servers.
|
||
*/
|
||
cp = res_skip((u_char*)&answer, 3, eom);
|
||
|
||
if (queryType != T_A) {
|
||
/*
|
||
* If we don't need to save the record, just print it.
|
||
*/
|
||
while (--arcount >= 0 && cp < eom) {
|
||
if ((cp = Print_rr(cp, (u_char *) &answer,
|
||
eom, stdout)) == NULL) {
|
||
return(ERROR);
|
||
}
|
||
}
|
||
} else {
|
||
while (--arcount >= 0 && cp < eom) {
|
||
n = dn_expand(answer.qb2, eom, cp, (char *)bp, buflen);
|
||
if (n < 0) {
|
||
break;
|
||
}
|
||
cp += n;
|
||
if (cp + 3 * INT16SZ + INT32SZ > eom)
|
||
return (ERROR);
|
||
type = GetShort(cp);
|
||
class = GetShort(cp);
|
||
cp += INT32SZ; /* skip TTL */
|
||
dlen = GetShort(cp);
|
||
if (cp + dlen > eom)
|
||
return (ERROR);
|
||
|
||
if (type != T_A && type != T_AAAA) {
|
||
cp += dlen;
|
||
continue;
|
||
} else {
|
||
if (type == T_A && dlen != INADDRSZ)
|
||
return (ERROR);
|
||
if (type == T_AAAA && dlen != 16)
|
||
return (ERROR);
|
||
for (j = 0; j < numServers; j++) {
|
||
if (strcasecmp((char *)bp, server[j].name) == 0) {
|
||
server[j].numAddresses++;
|
||
if (server[j].numAddresses <= MAXADDRS) {
|
||
server[j].address[server[j].numAddresses-1] =
|
||
Calloc(1,dlen);
|
||
memcpy(server[j].address[server[j].numAddresses-1],
|
||
cp, dlen);
|
||
server[j].len[server[j].numAddresses-1] = dlen;
|
||
server[j].type[server[j].numAddresses-1] =
|
||
(type == T_A) ? AF_INET : AF_INET6;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
cp += dlen;
|
||
}
|
||
}
|
||
}
|
||
|
||
/*
|
||
* If we are returning name server info, transfer it to the hostPtr.
|
||
*/
|
||
oldServers = 0;
|
||
if (merge && hostPtr->servers != NULL) {
|
||
while (hostPtr->servers[oldServers] != NULL)
|
||
oldServers++;
|
||
}
|
||
if (numServers > 0) {
|
||
newServers = (ServerInfo **) Calloc(numServers+oldServers+1,
|
||
sizeof(ServerInfo *));
|
||
if (merge && hostPtr->servers != NULL) {
|
||
memcpy(newServers, hostPtr->servers,
|
||
oldServers * sizeof(ServerInfo *));
|
||
free(hostPtr->servers);
|
||
}
|
||
hostPtr->servers = newServers;
|
||
k = oldServers;
|
||
for (i = 0; i < numServers; i++) {
|
||
for (l = 0; l < k; l++)
|
||
if (!strcasecmp(hostPtr->servers[l]->name, server[i].name))
|
||
break;
|
||
if (l < k) {
|
||
free(server[i].name);
|
||
for (j = 0; j < server[i].numDomains; j++)
|
||
free(server[i].domain[j]);
|
||
} else {
|
||
hostPtr->servers[l] = (ServerInfo *)
|
||
Calloc(1, sizeof(ServerInfo));
|
||
hostPtr->servers[l]->name = server[i].name;
|
||
k++;
|
||
|
||
hostPtr->servers[l]->domains = (char **)
|
||
Calloc(server[i].numDomains+1,sizeof(char *));
|
||
for (j = 0; j < server[i].numDomains; j++) {
|
||
hostPtr->servers[l]->domains[j] = server[i].domain[j];
|
||
}
|
||
hostPtr->servers[l]->domains[j] = NULL;
|
||
}
|
||
|
||
|
||
oldAddresses = 0;
|
||
if (merge && hostPtr->servers[l]->addrList != NULL)
|
||
while (hostPtr->servers[l]->addrList[oldAddresses] != NULL)
|
||
oldAddresses++;
|
||
newAddresses = (AddrInfo **)
|
||
Calloc(server[i].numAddresses+oldAddresses+1,
|
||
sizeof(AddrInfo *));
|
||
if (merge && hostPtr->servers[l]->addrList != NULL) {
|
||
memcpy(newAddresses, hostPtr->servers[l]->addrList,
|
||
sizeof(AddrInfo *) * oldAddresses);
|
||
free(hostPtr->servers[l]->addrList);
|
||
}
|
||
hostPtr->servers[l]->addrList = newAddresses;
|
||
m = oldAddresses;
|
||
for (j = 0; j < server[l].numAddresses; j++) {
|
||
for (n = 0; n < m; n++)
|
||
if (hostPtr->servers[l]->addrList[n]->addrType ==
|
||
server[i].type[j] &&
|
||
hostPtr->servers[l]->addrList[n]->addrLen ==
|
||
server[i].len[j] &&
|
||
!memcmp(hostPtr->servers[l]->addrList[n]->addr,
|
||
server[i].address[j], server[i].len[j]))
|
||
break;
|
||
if (n < m) {
|
||
free(server[i].address[j]);
|
||
continue;
|
||
}
|
||
hostPtr->servers[l]->addrList[m] =
|
||
(AddrInfo*)Calloc(1, sizeof(AddrInfo));
|
||
hostPtr->servers[l]->addrList[m]->addr =
|
||
server[i].address[j];
|
||
hostPtr->servers[l]->addrList[m]->addrType =
|
||
server[i].type[j];
|
||
hostPtr->servers[l]->addrList[m]->addrLen =
|
||
server[i].len[j];
|
||
m++;
|
||
}
|
||
hostPtr->servers[l]->addrList[m] = NULL;
|
||
}
|
||
hostPtr->servers[k] = NULL;
|
||
}
|
||
|
||
switch (queryType) {
|
||
case T_AAAA:
|
||
case T_A:
|
||
return NONAUTH;
|
||
case T_PTR:
|
||
if (iquery)
|
||
return NO_INFO;
|
||
/* fall through */
|
||
default:
|
||
return SUCCESS;
|
||
}
|
||
}
|
||
|
||
/*
|
||
*******************************************************************************
|
||
*
|
||
* GetHostInfo --
|
||
*
|
||
* Retrieves host name, address and alias information
|
||
* for a domain.
|
||
*
|
||
* Algorithm from res_nsearch().
|
||
*
|
||
* Results:
|
||
* ERROR - res_nmkquery failed.
|
||
* + return values from GetAnswer()
|
||
*
|
||
*******************************************************************************
|
||
*/
|
||
|
||
int
|
||
GetHostInfoByName(nsAddrPtr, queryClass, queryType, name, hostPtr, isServer,
|
||
merge)
|
||
union res_sockaddr_union *nsAddrPtr;
|
||
int queryClass;
|
||
int queryType;
|
||
const char *name;
|
||
HostInfo *hostPtr;
|
||
Boolean isServer;
|
||
Boolean merge;
|
||
{
|
||
int n;
|
||
register int result;
|
||
register char **domain;
|
||
const char *cp;
|
||
Boolean got_nodata = FALSE;
|
||
union res_sockaddr_union ina;
|
||
Boolean tried_as_is = FALSE;
|
||
char tmp[NS_MAXDNAME];
|
||
|
||
/* Catch explicit addresses */
|
||
if ((queryType == T_A) && IsAddr(name, &ina)) {
|
||
hostPtr->name = Calloc(strlen(name)+3, 1);
|
||
(void)sprintf(hostPtr->name,"[%s]",name);
|
||
switch (ina.sin.sin_family) {
|
||
case AF_INET:
|
||
hostPtr->aliases = NULL;
|
||
hostPtr->servers = NULL;
|
||
hostPtr->addrList = (AddrInfo **)Calloc(2, sizeof(AddrInfo *));
|
||
hostPtr->addrList[0] = (AddrInfo *)Calloc(1, sizeof(AddrInfo));
|
||
hostPtr->addrList[0]->addr = Calloc(INT32SZ, sizeof(char));
|
||
memcpy(hostPtr->addrList[0]->addr, &ina.sin.sin_addr, INADDRSZ);
|
||
hostPtr->addrList[0]->addrType = AF_INET;
|
||
hostPtr->addrList[0]->addrLen = INADDRSZ;
|
||
hostPtr->addrList[1] = NULL;
|
||
break;
|
||
case AF_INET6:
|
||
hostPtr->aliases = NULL;
|
||
hostPtr->servers = NULL;
|
||
hostPtr->addrList = (AddrInfo **)Calloc(2, sizeof(AddrInfo *));
|
||
hostPtr->addrList[0] = (AddrInfo *)Calloc(1, sizeof(AddrInfo));
|
||
hostPtr->addrList[0]->addr = Calloc(1, 16);
|
||
memcpy(hostPtr->addrList[0]->addr, &ina.sin6.sin6_addr, 16);
|
||
hostPtr->addrList[0]->addrType = AF_INET6;
|
||
hostPtr->addrList[0]->addrLen = 16;
|
||
hostPtr->addrList[1] = NULL;
|
||
break;
|
||
}
|
||
return(SUCCESS);
|
||
}
|
||
|
||
result = NXDOMAIN;
|
||
for (cp = name, n = 0; *cp; cp++)
|
||
if (*cp == '.')
|
||
n++;
|
||
if (n == 0 && (cp = res_hostalias(&res, name, tmp, sizeof tmp))) {
|
||
printf("Aliased to \"%s\"\n\n", cp);
|
||
return (GetHostDomain(nsAddrPtr, queryClass, queryType,
|
||
cp, (char *)NULL, hostPtr, isServer, merge));
|
||
}
|
||
|
||
/*
|
||
* If there are dots in the name already, let's just give it a try
|
||
* 'as is'. The threshold can be set with the "ndots" option.
|
||
*/
|
||
if (n >= (int)res.ndots) {
|
||
result = GetHostDomain(nsAddrPtr, queryClass, queryType,
|
||
name, (char *)NULL, hostPtr, isServer,
|
||
merge);
|
||
if (result == SUCCESS)
|
||
return (result);
|
||
if (result == NO_INFO)
|
||
got_nodata++;
|
||
tried_as_is++;
|
||
}
|
||
|
||
/*
|
||
* We do at least one level of search if
|
||
* - there is no dot and RES_DEFNAME is set, or
|
||
* - there is at least one dot, there is no trailing dot,
|
||
* and RES_DNSRCH is set.
|
||
*/
|
||
if ((n == 0 && (res.options & RES_DEFNAMES) != 0) ||
|
||
(n != 0 && *--cp != '.' && (res.options & RES_DNSRCH) != 0))
|
||
for (domain = res.dnsrch; *domain != NULL; domain++) {
|
||
result = GetHostDomain(nsAddrPtr, queryClass, queryType,
|
||
name, *domain, hostPtr, isServer,
|
||
merge);
|
||
/*
|
||
* If no server present, give up.
|
||
* If name isn't found in this domain,
|
||
* keep trying higher domains in the search list
|
||
* (if that's enabled).
|
||
* On a NO_INFO error, keep trying, otherwise
|
||
* a wildcard entry of another type could keep us
|
||
* from finding this entry higher in the domain.
|
||
* If we get some other error (negative answer or
|
||
* server failure), then stop searching up,
|
||
* but try the input name below in case it's fully-qualified.
|
||
*/
|
||
if (result == SUCCESS || result == NO_RESPONSE)
|
||
return result;
|
||
if (result == NO_INFO)
|
||
got_nodata++;
|
||
if ((result != NXDOMAIN && result != NO_INFO) ||
|
||
(res.options & RES_DNSRCH) == 0)
|
||
break;
|
||
}
|
||
/* if we have not already tried the name "as is", do that now.
|
||
* note that we do this regardless of how many dots were in the
|
||
* name or whether it ends with a dot.
|
||
*/
|
||
if (!tried_as_is &&
|
||
(result = GetHostDomain(nsAddrPtr, queryClass, queryType,
|
||
name, (char *)NULL, hostPtr, isServer, merge)
|
||
) == SUCCESS)
|
||
return (result);
|
||
if (got_nodata)
|
||
result = NO_INFO;
|
||
return (result);
|
||
}
|
||
|
||
/*
|
||
* Perform a query on the concatenation of name and domain,
|
||
* removing a trailing dot from name if domain is NULL.
|
||
*/
|
||
int
|
||
GetHostDomain(nsAddrPtr, queryClass, queryType, name, domain, hostPtr,
|
||
isServer, merge)
|
||
union res_sockaddr_union *nsAddrPtr;
|
||
int queryClass;
|
||
int queryType;
|
||
const char *name;
|
||
char *domain;
|
||
HostInfo *hostPtr;
|
||
Boolean isServer;
|
||
Boolean merge;
|
||
{
|
||
querybuf buf;
|
||
char nbuf[2*MAXDNAME+2];
|
||
const char *longname = nbuf;
|
||
int n;
|
||
|
||
if (domain == NULL) {
|
||
/*
|
||
* Check for trailing '.';
|
||
* copy without '.' if present.
|
||
*/
|
||
n = strlen(name) - 1;
|
||
if (name[n] == '.' && n < (int)sizeof(nbuf) - 1) {
|
||
memcpy(nbuf, name, n);
|
||
nbuf[n] = '\0';
|
||
} else
|
||
longname = name;
|
||
} else {
|
||
(void)sprintf(nbuf, "%.*s.%.*s",
|
||
MAXDNAME, name, MAXDNAME, domain);
|
||
longname = nbuf;
|
||
}
|
||
n = res_nmkquery(&res, QUERY, longname, queryClass, queryType,
|
||
NULL, 0, 0, buf.qb2, sizeof(buf));
|
||
if (n < 0) {
|
||
if (res.options & RES_DEBUG) {
|
||
printf("Res_nmkquery failed\n");
|
||
}
|
||
return (ERROR);
|
||
}
|
||
|
||
n = GetAnswer(nsAddrPtr, queryType, (char *)&buf, n, 0, hostPtr,
|
||
isServer, merge);
|
||
|
||
/*
|
||
* GetAnswer didn't find a name, so set it to the specified one.
|
||
*/
|
||
if (n == NONAUTH) {
|
||
if (hostPtr->name == NULL) {
|
||
size_t len = strlen(longname) + 1;
|
||
|
||
hostPtr->name = Calloc(len, sizeof(char));
|
||
memcpy(hostPtr->name, longname, len);
|
||
}
|
||
}
|
||
return(n);
|
||
}
|
||
|
||
|
||
/*
|
||
*******************************************************************************
|
||
*
|
||
* GetHostInfoByAddr --
|
||
*
|
||
* Performs a PTR lookup in in-addr.arpa to find the host name
|
||
* that corresponds to the given address.
|
||
*
|
||
* Results:
|
||
* ERROR - res_nmkquery failed.
|
||
* + return values from GetAnswer()
|
||
*
|
||
*******************************************************************************
|
||
*/
|
||
|
||
int
|
||
GetHostInfoByAddr(union res_sockaddr_union *nsAddrPtr,
|
||
union res_sockaddr_union *address,
|
||
HostInfo * hostPtr)
|
||
{
|
||
int n;
|
||
querybuf buf;
|
||
char qbuf[MAXDNAME];
|
||
char qbuf2[MAXDNAME];
|
||
char *p = NULL;
|
||
int ismapped = 0;
|
||
|
||
switch (address->sin.sin_family) {
|
||
case AF_INET:
|
||
p = (char *) &address->sin.sin_addr.s_addr;
|
||
mapped:
|
||
(void)sprintf(qbuf, "%u.%u.%u.%u.in-addr.arpa",
|
||
((unsigned)p[3 + (ismapped ? 12 : 0)] & 0xff),
|
||
((unsigned)p[2 + (ismapped ? 12 : 0)] & 0xff),
|
||
((unsigned)p[1 + (ismapped ? 12 : 0)] & 0xff),
|
||
((unsigned)p[0 + (ismapped ? 12 : 0)] & 0xff));
|
||
break;
|
||
case AF_INET6:
|
||
p = (char *)address->sin6.sin6_addr.s6_addr;
|
||
if (IN6_IS_ADDR_V4MAPPED(&address->sin6.sin6_addr) ||
|
||
IN6_IS_ADDR_V4COMPAT(&address->sin6.sin6_addr)) {
|
||
ismapped = 1;
|
||
goto mapped;
|
||
}
|
||
(void)sprintf(qbuf,
|
||
"%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x."
|
||
"%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x."
|
||
"ip6.arpa",
|
||
p[15] & 0xf, (p[15] >> 4) & 0xf,
|
||
p[14] & 0xf, (p[14] >> 4) & 0xf,
|
||
p[13] & 0xf, (p[13] >> 4) & 0xf,
|
||
p[12] & 0xf, (p[12] >> 4) & 0xf,
|
||
p[11] & 0xf, (p[11] >> 4) & 0xf,
|
||
p[10] & 0xf, (p[10] >> 4) & 0xf,
|
||
p[9] & 0xf, (p[9] >> 4) & 0xf,
|
||
p[8] & 0xf, (p[8] >> 4) & 0xf,
|
||
p[7] & 0xf, (p[7] >> 4) & 0xf,
|
||
p[6] & 0xf, (p[4] >> 4) & 0xf,
|
||
p[5] & 0xf, (p[5] >> 4) & 0xf,
|
||
p[4] & 0xf, (p[4] >> 4) & 0xf,
|
||
p[3] & 0xf, (p[3] >> 4) & 0xf,
|
||
p[2] & 0xf, (p[2] >> 4) & 0xf,
|
||
p[1] & 0xf, (p[1] >> 4) & 0xf,
|
||
p[0] & 0xf, (p[0] >> 4) & 0xf);
|
||
(void)sprintf(qbuf2,
|
||
"%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x."
|
||
"%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x."
|
||
"ip6.int",
|
||
p[15] & 0xf, (p[15] >> 4) & 0xf,
|
||
p[14] & 0xf, (p[14] >> 4) & 0xf,
|
||
p[13] & 0xf, (p[13] >> 4) & 0xf,
|
||
p[12] & 0xf, (p[12] >> 4) & 0xf,
|
||
p[11] & 0xf, (p[11] >> 4) & 0xf,
|
||
p[10] & 0xf, (p[10] >> 4) & 0xf,
|
||
p[9] & 0xf, (p[9] >> 4) & 0xf,
|
||
p[8] & 0xf, (p[8] >> 4) & 0xf,
|
||
p[7] & 0xf, (p[7] >> 4) & 0xf,
|
||
p[6] & 0xf, (p[4] >> 4) & 0xf,
|
||
p[5] & 0xf, (p[5] >> 4) & 0xf,
|
||
p[4] & 0xf, (p[4] >> 4) & 0xf,
|
||
p[3] & 0xf, (p[3] >> 4) & 0xf,
|
||
p[2] & 0xf, (p[2] >> 4) & 0xf,
|
||
p[1] & 0xf, (p[1] >> 4) & 0xf,
|
||
p[0] & 0xf, (p[0] >> 4) & 0xf);
|
||
break;
|
||
}
|
||
n = res_nmkquery(&res, QUERY, qbuf, C_IN, T_PTR, NULL, 0, NULL,
|
||
buf.qb2, sizeof buf);
|
||
if (n < 0) {
|
||
if (res.options & RES_DEBUG) {
|
||
printf("res_nmkquery() failed\n");
|
||
}
|
||
return (ERROR);
|
||
}
|
||
n = GetAnswer(nsAddrPtr, T_PTR, (char *) &buf, n, 1, hostPtr, 1, 0);
|
||
if (n == SUCCESS) {
|
||
switch (address->sin.sin_family) {
|
||
case AF_INET:
|
||
hostPtr->addrList = (AddrInfo **)Calloc(2, sizeof(AddrInfo *));
|
||
hostPtr->addrList[0] = (AddrInfo *)Calloc(1, sizeof(AddrInfo));
|
||
hostPtr->addrList[0]->addr = Calloc(INT32SZ, sizeof(char));
|
||
memcpy(hostPtr->addrList[0]->addr, p, INADDRSZ);
|
||
hostPtr->addrList[0]->addrType = AF_INET;
|
||
hostPtr->addrList[0]->addrLen = 4;
|
||
hostPtr->addrList[1] = NULL;
|
||
break;
|
||
case AF_INET6:
|
||
hostPtr->addrList = (AddrInfo **)Calloc(2, sizeof(AddrInfo *));
|
||
hostPtr->addrList[0] = (AddrInfo *)Calloc(1, sizeof(AddrInfo));
|
||
hostPtr->addrList[0]->addr = Calloc(16, sizeof(char));
|
||
memcpy(hostPtr->addrList[0]->addr, p, 16);
|
||
hostPtr->addrList[0]->addrType = AF_INET6;
|
||
hostPtr->addrList[0]->addrLen = 16;
|
||
hostPtr->addrList[1] = NULL;
|
||
break;
|
||
}
|
||
}
|
||
if (n == SUCCESS || ismapped || address->sin.sin_family != AF_INET6)
|
||
return n;
|
||
n = res_nmkquery(&res, QUERY, qbuf2, C_IN, T_PTR, NULL, 0, NULL,
|
||
buf.qb2, sizeof buf);
|
||
if (n < 0) {
|
||
if (res.options & RES_DEBUG) {
|
||
printf("res_nmkquery() failed\n");
|
||
}
|
||
return (ERROR);
|
||
}
|
||
n = GetAnswer(nsAddrPtr, T_PTR, (char *) &buf, n, 1, hostPtr, 1, 0);
|
||
if (n == SUCCESS) {
|
||
hostPtr->addrList = (AddrInfo **)Calloc(2, sizeof(AddrInfo *));
|
||
hostPtr->addrList[0] = (AddrInfo *)Calloc(1, sizeof(AddrInfo *));
|
||
hostPtr->addrList[0]->addr = Calloc(16, sizeof(char));
|
||
memcpy(hostPtr->addrList[0]->addr, p, 16);
|
||
hostPtr->addrList[0]->addrType = AF_INET6;
|
||
hostPtr->addrList[0]->addrLen = 16;
|
||
hostPtr->addrList[1] = NULL;
|
||
}
|
||
return n;
|
||
}
|
||
|
||
/*
|
||
*******************************************************************************
|
||
*
|
||
* FreeHostInfoPtr --
|
||
*
|
||
* Deallocates all the calloc'd areas for a HostInfo variable.
|
||
*
|
||
*******************************************************************************
|
||
*/
|
||
|
||
void
|
||
FreeHostInfoPtr(hostPtr)
|
||
register 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]->addr);
|
||
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]->addr);
|
||
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;
|
||
}
|
||
}
|