43fa6fe319
identifier namespace by renaming non standard functions and variables such that they have a leading underscore. The library will use those names internally. Weak aliases are used to provide the original names to the API. This is only the first part of this change. It is most of the functions which are implemented in C for all NetBSD ports. Subsequent changes are to add the same support to the remaining C files, to assembly files, and to the automagically generated assembly source used for system calls. When all of the above is done, ports with weak alias support should add a definition for __weak_alias to <sys/cdefs.h>.
1124 lines
25 KiB
C
1124 lines
25 KiB
C
/* $NetBSD: gethostnamadr.c,v 1.26 1997/07/21 14:07:54 jtc Exp $ */
|
|
|
|
/*
|
|
* ++Copyright++ 1985, 1988, 1993
|
|
* -
|
|
* Copyright (c) 1985, 1988, 1993
|
|
* 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.
|
|
* -
|
|
* --Copyright--
|
|
*/
|
|
|
|
#include <sys/cdefs.h>
|
|
#if defined(LIBC_SCCS) && !defined(lint)
|
|
#if 0
|
|
static char sccsid[] = "@(#)gethostnamadr.c 8.1 (Berkeley) 6/4/93";
|
|
static char rcsid[] = "Id: gethnamaddr.c,v 8.20 1996/09/28 06:51:07 vixie Exp";
|
|
#else
|
|
__RCSID("$NetBSD: gethostnamadr.c,v 1.26 1997/07/21 14:07:54 jtc Exp $");
|
|
#endif
|
|
#endif /* LIBC_SCCS and not lint */
|
|
|
|
#include "namespace.h"
|
|
#include <sys/types.h>
|
|
#include <sys/param.h>
|
|
#include <sys/socket.h>
|
|
#include <netinet/in.h>
|
|
#include <arpa/inet.h>
|
|
#include <arpa/nameser.h>
|
|
|
|
#include <stdio.h>
|
|
#include <netdb.h>
|
|
#include <resolv.h>
|
|
#include <ctype.h>
|
|
#include <errno.h>
|
|
#include <syslog.h>
|
|
|
|
#ifndef LOG_AUTH
|
|
# define LOG_AUTH 0
|
|
#endif
|
|
|
|
#define MULTI_PTRS_ARE_ALIASES 1 /* XXX - experimental */
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#ifdef YP
|
|
#include <rpc/rpc.h>
|
|
#include <rpcsvc/yp_prot.h>
|
|
#include <rpcsvc/ypclnt.h>
|
|
#endif
|
|
|
|
#define MAXALIASES 35
|
|
#define MAXADDRS 35
|
|
|
|
static const char AskedForGot[] =
|
|
"gethostby*.getanswer: asked for \"%s\", got \"%s\"";
|
|
|
|
static char *h_addr_ptrs[MAXADDRS + 1];
|
|
|
|
#ifdef YP
|
|
static char *__ypdomain;
|
|
#endif
|
|
|
|
static struct hostent host;
|
|
static char *host_aliases[MAXALIASES];
|
|
static char hostbuf[8*1024];
|
|
static u_char host_addr[16]; /* IPv4 or IPv6 */
|
|
static FILE *hostf = NULL;
|
|
static int stayopen = 0;
|
|
|
|
|
|
#if PACKETSZ > 1024
|
|
#define MAXPACKET PACKETSZ
|
|
#else
|
|
#define MAXPACKET 1024
|
|
#endif
|
|
|
|
typedef union {
|
|
HEADER hdr;
|
|
u_char buf[MAXPACKET];
|
|
} querybuf;
|
|
|
|
typedef union {
|
|
int32_t al;
|
|
char ac;
|
|
} align;
|
|
|
|
extern int h_errno;
|
|
|
|
#ifdef DEBUG
|
|
static void dprintf __P((char *, int));
|
|
#endif
|
|
static struct hostent *getanswer __P((const querybuf *, int,
|
|
const char *, int));
|
|
static void map_v4v6_address __P((const char *, char *));
|
|
static void map_v4v6_hostent __P((struct hostent *, char **, int *));
|
|
#ifdef RESOLVSORT
|
|
static void addrsort __P((char **, int));
|
|
#endif
|
|
|
|
struct hostent *gethostbyname __P((const char *));
|
|
struct hostent *gethostbyname2 __P((const char *, int));
|
|
struct hostent *gethostbyaddr __P((const char *, int, int ));
|
|
void _sethtent __P((int));
|
|
void _endhtent __P((void));
|
|
struct hostent *_gethtent __P((void));
|
|
struct hostent *_gethtbyname __P((const char *));
|
|
struct hostent *_gethtbyname2 __P((const char *, int));
|
|
struct hostent *_gethtbyaddr __P((const char *, int, int ));
|
|
void ht_sethostent __P((int));
|
|
void ht_endhostent __P((void));
|
|
struct hostent *ht_gethostbyname __P((char *));
|
|
struct hostent *ht_gethostbyaddr __P((const char *, int, int ));
|
|
struct hostent *gethostent __P((void));
|
|
void dns_service __P((void));
|
|
int dn_skipname __P((const u_char *, const u_char *));
|
|
#ifdef YP
|
|
struct hostent *_yphostent __P((char *));
|
|
struct hostent *_yp_gethtbyaddr __P((const char *, int, int ));
|
|
struct hostent *_yp_gethtbyname __P((const char *));
|
|
#endif
|
|
|
|
|
|
#ifdef DEBUG
|
|
static void
|
|
dprintf(msg, num)
|
|
char *msg;
|
|
int num;
|
|
{
|
|
if (_res.options & RES_DEBUG) {
|
|
int save = errno;
|
|
|
|
printf(msg, num);
|
|
errno = save;
|
|
}
|
|
}
|
|
#else
|
|
# define dprintf(msg, num) /*nada*/
|
|
#endif
|
|
|
|
static struct hostent *
|
|
getanswer(answer, anslen, qname, qtype)
|
|
const querybuf *answer;
|
|
int anslen;
|
|
const char *qname;
|
|
int qtype;
|
|
{
|
|
register const HEADER *hp;
|
|
register const u_char *cp;
|
|
register int n;
|
|
const u_char *eom;
|
|
char *bp, **ap, **hap;
|
|
int type, class, buflen, ancount, qdcount;
|
|
int haveanswer, had_error;
|
|
int toobig = 0;
|
|
char tbuf[MAXDNAME];
|
|
const char *tname;
|
|
int (*name_ok) __P((const char *));
|
|
|
|
tname = qname;
|
|
host.h_name = NULL;
|
|
eom = answer->buf + anslen;
|
|
switch (qtype) {
|
|
case T_A:
|
|
case T_AAAA:
|
|
name_ok = res_hnok;
|
|
break;
|
|
case T_PTR:
|
|
name_ok = res_dnok;
|
|
break;
|
|
default:
|
|
return (NULL); /* XXX should be abort(); */
|
|
}
|
|
/*
|
|
* find first satisfactory answer
|
|
*/
|
|
hp = &answer->hdr;
|
|
ancount = ntohs(hp->ancount);
|
|
qdcount = ntohs(hp->qdcount);
|
|
bp = hostbuf;
|
|
buflen = sizeof hostbuf;
|
|
cp = answer->buf + HFIXEDSZ;
|
|
if (qdcount != 1) {
|
|
h_errno = NO_RECOVERY;
|
|
return (NULL);
|
|
}
|
|
n = dn_expand(answer->buf, eom, cp, bp, buflen);
|
|
if ((n < 0) || !(*name_ok)(bp)) {
|
|
h_errno = NO_RECOVERY;
|
|
return (NULL);
|
|
}
|
|
cp += n + QFIXEDSZ;
|
|
if (qtype == T_A || qtype == T_AAAA) {
|
|
/* res_send() has already verified that the query name is the
|
|
* same as the one we sent; this just gets the expanded name
|
|
* (i.e., with the succeeding search-domain tacked on).
|
|
*/
|
|
n = strlen(bp) + 1; /* for the \0 */
|
|
host.h_name = bp;
|
|
bp += n;
|
|
buflen -= n;
|
|
/* The qname can be abbreviated, but h_name is now absolute. */
|
|
qname = host.h_name;
|
|
}
|
|
ap = host_aliases;
|
|
*ap = NULL;
|
|
host.h_aliases = host_aliases;
|
|
hap = h_addr_ptrs;
|
|
*hap = NULL;
|
|
host.h_addr_list = h_addr_ptrs;
|
|
haveanswer = 0;
|
|
had_error = 0;
|
|
while (ancount-- > 0 && cp < eom && !had_error) {
|
|
n = dn_expand(answer->buf, eom, cp, bp, buflen);
|
|
if ((n < 0) || !(*name_ok)(bp)) {
|
|
had_error++;
|
|
continue;
|
|
}
|
|
cp += n; /* name */
|
|
type = _getshort(cp);
|
|
cp += INT16SZ; /* type */
|
|
class = _getshort(cp);
|
|
cp += INT16SZ + INT32SZ; /* class, TTL */
|
|
n = _getshort(cp);
|
|
cp += INT16SZ; /* len */
|
|
if (class != C_IN) {
|
|
/* XXX - debug? syslog? */
|
|
cp += n;
|
|
continue; /* XXX - had_error++ ? */
|
|
}
|
|
if ((qtype == T_A || qtype == T_AAAA) && type == T_CNAME) {
|
|
if (ap >= &host_aliases[MAXALIASES-1])
|
|
continue;
|
|
n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf);
|
|
if ((n < 0) || !(*name_ok)(tbuf)) {
|
|
had_error++;
|
|
continue;
|
|
}
|
|
cp += n;
|
|
/* Store alias. */
|
|
*ap++ = bp;
|
|
n = strlen(bp) + 1; /* for the \0 */
|
|
bp += n;
|
|
buflen -= n;
|
|
/* Get canonical name. */
|
|
n = strlen(tbuf) + 1; /* for the \0 */
|
|
if (n > buflen) {
|
|
had_error++;
|
|
continue;
|
|
}
|
|
strcpy(bp, tbuf);
|
|
host.h_name = bp;
|
|
bp += n;
|
|
buflen -= n;
|
|
continue;
|
|
}
|
|
if (qtype == T_PTR && type == T_CNAME) {
|
|
n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf);
|
|
if ((n < 0) || !res_hnok(tbuf)) {
|
|
had_error++;
|
|
continue;
|
|
}
|
|
cp += n;
|
|
/* Get canonical name. */
|
|
n = strlen(tbuf) + 1; /* for the \0 */
|
|
if (n > buflen) {
|
|
had_error++;
|
|
continue;
|
|
}
|
|
strcpy(bp, tbuf);
|
|
tname = bp;
|
|
bp += n;
|
|
buflen -= n;
|
|
continue;
|
|
}
|
|
if (type != qtype) {
|
|
syslog(LOG_NOTICE|LOG_AUTH,
|
|
"gethostby*.getanswer: asked for \"%s %s %s\", got type \"%s\"",
|
|
qname, p_class(C_IN), p_type(qtype),
|
|
p_type(type));
|
|
cp += n;
|
|
continue; /* XXX - had_error++ ? */
|
|
}
|
|
switch (type) {
|
|
case T_PTR:
|
|
if (strcasecmp(tname, bp) != 0) {
|
|
syslog(LOG_NOTICE|LOG_AUTH,
|
|
AskedForGot, qname, bp);
|
|
cp += n;
|
|
continue; /* XXX - had_error++ ? */
|
|
}
|
|
n = dn_expand(answer->buf, eom, cp, bp, buflen);
|
|
if ((n < 0) || !res_hnok(bp)) {
|
|
had_error++;
|
|
break;
|
|
}
|
|
#if MULTI_PTRS_ARE_ALIASES
|
|
cp += n;
|
|
if (!haveanswer)
|
|
host.h_name = bp;
|
|
else if (ap < &host_aliases[MAXALIASES-1])
|
|
*ap++ = bp;
|
|
else
|
|
n = -1;
|
|
if (n != -1) {
|
|
n = strlen(bp) + 1; /* for the \0 */
|
|
bp += n;
|
|
buflen -= n;
|
|
}
|
|
break;
|
|
#else
|
|
host.h_name = bp;
|
|
if (_res.options & RES_USE_INET6) {
|
|
n = strlen(bp) + 1; /* for the \0 */
|
|
bp += n;
|
|
buflen -= n;
|
|
map_v4v6_hostent(&host, &bp, &buflen);
|
|
}
|
|
h_errno = NETDB_SUCCESS;
|
|
return (&host);
|
|
#endif
|
|
case T_A:
|
|
case T_AAAA:
|
|
if (strcasecmp(host.h_name, bp) != 0) {
|
|
syslog(LOG_NOTICE|LOG_AUTH,
|
|
AskedForGot, host.h_name, bp);
|
|
cp += n;
|
|
continue; /* XXX - had_error++ ? */
|
|
}
|
|
if (n != host.h_length) {
|
|
cp += n;
|
|
continue;
|
|
}
|
|
if (!haveanswer) {
|
|
register int nn;
|
|
|
|
host.h_name = bp;
|
|
nn = strlen(bp) + 1; /* for the \0 */
|
|
bp += nn;
|
|
buflen -= nn;
|
|
}
|
|
|
|
bp += sizeof(align) - ((u_long)bp % sizeof(align));
|
|
|
|
if (bp + n >= &hostbuf[sizeof hostbuf]) {
|
|
dprintf("size (%d) too big\n", n);
|
|
had_error++;
|
|
continue;
|
|
}
|
|
if (hap >= &h_addr_ptrs[MAXADDRS-1]) {
|
|
if (!toobig++)
|
|
dprintf("Too many addresses (%d)\n",
|
|
MAXADDRS);
|
|
cp += n;
|
|
continue;
|
|
}
|
|
bcopy(cp, *hap++ = bp, n);
|
|
bp += n;
|
|
buflen -= n;
|
|
cp += n;
|
|
break;
|
|
default:
|
|
abort();
|
|
}
|
|
if (!had_error)
|
|
haveanswer++;
|
|
}
|
|
if (haveanswer) {
|
|
*ap = NULL;
|
|
*hap = NULL;
|
|
# if defined(RESOLVSORT)
|
|
/*
|
|
* Note: we sort even if host can take only one address
|
|
* in its return structures - should give it the "best"
|
|
* address in that case, not some random one
|
|
*/
|
|
if (_res.nsort && haveanswer > 1 && qtype == T_A)
|
|
addrsort(h_addr_ptrs, haveanswer);
|
|
# endif /*RESOLVSORT*/
|
|
if (!host.h_name) {
|
|
n = strlen(qname) + 1; /* for the \0 */
|
|
if (n > buflen)
|
|
goto try_again;
|
|
strcpy(bp, qname);
|
|
host.h_name = bp;
|
|
bp += n;
|
|
buflen -= n;
|
|
}
|
|
if (_res.options & RES_USE_INET6)
|
|
map_v4v6_hostent(&host, &bp, &buflen);
|
|
h_errno = NETDB_SUCCESS;
|
|
return (&host);
|
|
}
|
|
try_again:
|
|
h_errno = TRY_AGAIN;
|
|
return (NULL);
|
|
}
|
|
|
|
struct hostent *
|
|
gethostbyname(name)
|
|
const char *name;
|
|
{
|
|
struct hostent *hp;
|
|
|
|
if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
|
|
h_errno = NETDB_INTERNAL;
|
|
return (NULL);
|
|
}
|
|
if (_res.options & RES_USE_INET6) {
|
|
hp = gethostbyname2(name, AF_INET6);
|
|
if (hp)
|
|
return (hp);
|
|
}
|
|
return (gethostbyname2(name, AF_INET));
|
|
}
|
|
|
|
struct hostent *
|
|
gethostbyname2(name, af)
|
|
const char *name;
|
|
int af;
|
|
{
|
|
querybuf buf;
|
|
const char *cp;
|
|
char *bp;
|
|
int n, size, type, len, i;
|
|
char lookups[MAXDNSLUS];
|
|
struct hostent *hp;
|
|
|
|
if ((_res.options & RES_INIT) == 0 && res_init() == -1)
|
|
return (_gethtbyname(name));
|
|
|
|
switch (af) {
|
|
case AF_INET:
|
|
size = INADDRSZ;
|
|
type = T_A;
|
|
break;
|
|
case AF_INET6:
|
|
size = IN6ADDRSZ;
|
|
type = T_AAAA;
|
|
break;
|
|
default:
|
|
h_errno = NETDB_INTERNAL;
|
|
errno = EAFNOSUPPORT;
|
|
return (NULL);
|
|
}
|
|
|
|
host.h_addrtype = af;
|
|
host.h_length = size;
|
|
|
|
/*
|
|
* if there aren't any dots, it could be a user-level alias.
|
|
* this is also done in res_query() since we are not the only
|
|
* function that looks up host names.
|
|
*/
|
|
if (!strchr(name, '.') && (cp = __hostalias(name)))
|
|
name = cp;
|
|
|
|
/*
|
|
* disallow names consisting only of digits/dots, unless
|
|
* they end in a dot.
|
|
*/
|
|
if (isdigit(name[0]))
|
|
for (cp = name;; ++cp) {
|
|
if (!*cp) {
|
|
if (*--cp == '.')
|
|
break;
|
|
/*
|
|
* All-numeric, no dot at the end.
|
|
* Fake up a hostent as if we'd actually
|
|
* done a lookup.
|
|
*/
|
|
if (inet_pton(af, name, host_addr) <= 0) {
|
|
h_errno = HOST_NOT_FOUND;
|
|
return (NULL);
|
|
}
|
|
strncpy(hostbuf, name, MAXDNAME);
|
|
hostbuf[MAXDNAME] = '\0';
|
|
bp = hostbuf + MAXDNAME;
|
|
len = sizeof hostbuf - MAXDNAME;
|
|
host.h_name = hostbuf;
|
|
host.h_aliases = host_aliases;
|
|
host_aliases[0] = NULL;
|
|
h_addr_ptrs[0] = (char *)host_addr;
|
|
h_addr_ptrs[1] = NULL;
|
|
host.h_addr_list = h_addr_ptrs;
|
|
if (_res.options & RES_USE_INET6)
|
|
map_v4v6_hostent(&host, &bp, &len);
|
|
h_errno = NETDB_SUCCESS;
|
|
return (&host);
|
|
}
|
|
if (!isdigit(*cp) && *cp != '.')
|
|
break;
|
|
}
|
|
if ((isxdigit(name[0]) && strchr(name, ':') != NULL) ||
|
|
name[0] == ':')
|
|
for (cp = name;; ++cp) {
|
|
if (!*cp) {
|
|
if (*--cp == '.')
|
|
break;
|
|
/*
|
|
* All-IPv6-legal, no dot at the end.
|
|
* Fake up a hostent as if we'd actually
|
|
* done a lookup.
|
|
*/
|
|
if (inet_pton(af, name, host_addr) <= 0) {
|
|
h_errno = HOST_NOT_FOUND;
|
|
return (NULL);
|
|
}
|
|
strncpy(hostbuf, name, MAXDNAME);
|
|
hostbuf[MAXDNAME] = '\0';
|
|
bp = hostbuf + MAXDNAME;
|
|
len = sizeof hostbuf - MAXDNAME;
|
|
host.h_name = hostbuf;
|
|
host.h_aliases = host_aliases;
|
|
host_aliases[0] = NULL;
|
|
h_addr_ptrs[0] = (char *)host_addr;
|
|
h_addr_ptrs[1] = NULL;
|
|
host.h_addr_list = h_addr_ptrs;
|
|
h_errno = NETDB_SUCCESS;
|
|
return (&host);
|
|
}
|
|
if (!isxdigit(*cp) && *cp != ':' && *cp != '.')
|
|
break;
|
|
}
|
|
|
|
bcopy(_res.lookups, lookups, sizeof lookups);
|
|
if (lookups[0] == '\0')
|
|
strncpy(lookups, "bf", sizeof lookups);
|
|
|
|
hp = (struct hostent *)NULL;
|
|
for (i = 0; i < MAXDNSLUS && hp == NULL && lookups[i]; i++) {
|
|
switch (lookups[i]) {
|
|
#ifdef YP
|
|
case 'y':
|
|
hp = _yp_gethtbyname(name);
|
|
break;
|
|
#endif
|
|
case 'b':
|
|
if ((n = res_search(name, C_IN, T_A, buf.buf,
|
|
sizeof(buf))) < 0) {
|
|
dprintf("res_search failed (%d)\n", n);
|
|
break;
|
|
}
|
|
hp = getanswer(&buf, n, name, type);
|
|
break;
|
|
case 'f':
|
|
hp = _gethtbyname(name);
|
|
break;
|
|
}
|
|
}
|
|
return (hp);
|
|
}
|
|
|
|
struct hostent *
|
|
gethostbyaddr(addr, len, af)
|
|
const char *addr; /* XXX should have been def'd as u_char! */
|
|
int len, af;
|
|
{
|
|
const u_char *uaddr = (const u_char *)addr;
|
|
static const u_char mapped[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0xff,0xff };
|
|
static const u_char tunnelled[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0,0 };
|
|
int n, size, i;
|
|
querybuf buf;
|
|
struct hostent *hp;
|
|
char qbuf[MAXDNAME+1], *qp;
|
|
char lookups[MAXDNSLUS];
|
|
|
|
if ((_res.options & RES_INIT) == 0 && res_init() == -1)
|
|
return (_gethtbyaddr(addr, len, af));
|
|
|
|
if (af == AF_INET6 && len == IN6ADDRSZ &&
|
|
(!bcmp(uaddr, mapped, sizeof mapped) ||
|
|
!bcmp(uaddr, tunnelled, sizeof tunnelled))) {
|
|
/* Unmap. */
|
|
addr += sizeof mapped;
|
|
uaddr += sizeof mapped;
|
|
af = AF_INET;
|
|
len = INADDRSZ;
|
|
}
|
|
switch (af) {
|
|
case AF_INET:
|
|
size = INADDRSZ;
|
|
break;
|
|
case AF_INET6:
|
|
size = IN6ADDRSZ;
|
|
break;
|
|
default:
|
|
errno = EAFNOSUPPORT;
|
|
h_errno = NETDB_INTERNAL;
|
|
return (NULL);
|
|
}
|
|
if (size != len) {
|
|
errno = EINVAL;
|
|
h_errno = NETDB_INTERNAL;
|
|
return (NULL);
|
|
}
|
|
switch (af) {
|
|
case AF_INET:
|
|
(void) sprintf(qbuf, "%u.%u.%u.%u.in-addr.arpa",
|
|
(uaddr[3] & 0xff),
|
|
(uaddr[2] & 0xff),
|
|
(uaddr[1] & 0xff),
|
|
(uaddr[0] & 0xff));
|
|
break;
|
|
case AF_INET6:
|
|
qp = qbuf;
|
|
for (n = IN6ADDRSZ - 1; n >= 0; n--) {
|
|
qp += sprintf(qp, "%x.%x.",
|
|
uaddr[n] & 0xf,
|
|
(uaddr[n] >> 4) & 0xf);
|
|
}
|
|
strcpy(qp, "ip6.int");
|
|
break;
|
|
default:
|
|
abort();
|
|
}
|
|
|
|
bcopy(_res.lookups, lookups, sizeof lookups);
|
|
if (lookups[0] == '\0')
|
|
strncpy(lookups, "bf", sizeof lookups);
|
|
|
|
hp = (struct hostent *)NULL;
|
|
for (i = 0; i < MAXDNSLUS && hp == NULL && lookups[i]; i++) {
|
|
switch (lookups[i]) {
|
|
#ifdef YP
|
|
case 'y':
|
|
hp = _yp_gethtbyaddr(addr, len, af);
|
|
break;
|
|
#endif
|
|
case 'b':
|
|
n = res_query(qbuf, C_IN, T_PTR, (u_char *)&buf,
|
|
sizeof(buf));
|
|
if (n < 0) {
|
|
dprintf("res_query failed (%d)\n", n);
|
|
break;
|
|
}
|
|
hp = getanswer(&buf, n, qbuf, T_PTR);
|
|
if (hp == NULL)
|
|
break;
|
|
hp->h_addrtype = af;
|
|
hp->h_length = len;
|
|
bcopy(addr, host_addr, len);
|
|
h_addr_ptrs[0] = (char *)&host_addr;
|
|
h_addr_ptrs[1] = (char *)0;
|
|
if (af == AF_INET && (_res.options & RES_USE_INET6)) {
|
|
map_v4v6_address((char*)host_addr,
|
|
(char*)host_addr);
|
|
hp->h_addrtype = AF_INET6;
|
|
hp->h_length = IN6ADDRSZ;
|
|
}
|
|
h_errno = NETDB_SUCCESS;
|
|
break;
|
|
case 'f':
|
|
hp = _gethtbyaddr(addr, len, af);
|
|
break;
|
|
}
|
|
}
|
|
return (hp);
|
|
}
|
|
|
|
void
|
|
_sethtent(f)
|
|
int f;
|
|
{
|
|
if (!hostf)
|
|
hostf = fopen(_PATH_HOSTS, "r" );
|
|
else
|
|
rewind(hostf);
|
|
stayopen = f;
|
|
}
|
|
|
|
void
|
|
_endhtent()
|
|
{
|
|
if (hostf && !stayopen) {
|
|
(void) fclose(hostf);
|
|
hostf = NULL;
|
|
}
|
|
}
|
|
|
|
struct hostent *
|
|
_gethtent()
|
|
{
|
|
char *p;
|
|
register char *cp, **q;
|
|
int af, len;
|
|
|
|
if (!hostf && !(hostf = fopen(_PATH_HOSTS, "r" ))) {
|
|
h_errno = NETDB_INTERNAL;
|
|
return (NULL);
|
|
}
|
|
again:
|
|
if (!(p = fgets(hostbuf, sizeof hostbuf, hostf))) {
|
|
h_errno = HOST_NOT_FOUND;
|
|
return (NULL);
|
|
}
|
|
if (*p == '#')
|
|
goto again;
|
|
if (!(cp = strpbrk(p, "#\n")))
|
|
goto again;
|
|
*cp = '\0';
|
|
if (!(cp = strpbrk(p, " \t")))
|
|
goto again;
|
|
*cp++ = '\0';
|
|
if ((_res.options & RES_USE_INET6) &&
|
|
inet_pton(AF_INET6, p, host_addr) > 0) {
|
|
af = AF_INET6;
|
|
len = IN6ADDRSZ;
|
|
} else if (inet_pton(AF_INET, p, host_addr) > 0) {
|
|
if (_res.options & RES_USE_INET6) {
|
|
map_v4v6_address((char*)host_addr, (char*)host_addr);
|
|
af = AF_INET6;
|
|
len = IN6ADDRSZ;
|
|
} else {
|
|
af = AF_INET;
|
|
len = INADDRSZ;
|
|
}
|
|
} else {
|
|
goto again;
|
|
}
|
|
h_addr_ptrs[0] = (char *)host_addr;
|
|
h_addr_ptrs[1] = NULL;
|
|
host.h_addr_list = h_addr_ptrs;
|
|
host.h_length = len;
|
|
host.h_addrtype = af;
|
|
while (*cp == ' ' || *cp == '\t')
|
|
cp++;
|
|
host.h_name = cp;
|
|
q = host.h_aliases = host_aliases;
|
|
if ((cp = strpbrk(cp, " \t")) != NULL)
|
|
*cp++ = '\0';
|
|
while (cp && *cp) {
|
|
if (*cp == ' ' || *cp == '\t') {
|
|
cp++;
|
|
continue;
|
|
}
|
|
if (q < &host_aliases[MAXALIASES - 1])
|
|
*q++ = cp;
|
|
if ((cp = strpbrk(cp, " \t")) != NULL)
|
|
*cp++ = '\0';
|
|
}
|
|
*q = NULL;
|
|
if (_res.options & RES_USE_INET6) {
|
|
char *bp = hostbuf;
|
|
int buflen = sizeof hostbuf;
|
|
|
|
map_v4v6_hostent(&host, &bp, &buflen);
|
|
}
|
|
h_errno = NETDB_SUCCESS;
|
|
return (&host);
|
|
}
|
|
|
|
struct hostent *
|
|
_gethtbyname(name)
|
|
const char *name;
|
|
{
|
|
struct hostent *hp;
|
|
|
|
if (_res.options & RES_USE_INET6) {
|
|
hp = _gethtbyname2(name, AF_INET6);
|
|
if (hp)
|
|
return (hp);
|
|
}
|
|
return (_gethtbyname2(name, AF_INET));
|
|
}
|
|
|
|
struct hostent *
|
|
_gethtbyname2(name, af)
|
|
const char *name;
|
|
int af;
|
|
{
|
|
register struct hostent *p;
|
|
register char **cp;
|
|
|
|
_sethtent(0);
|
|
while ((p = _gethtent()) != NULL) {
|
|
if (p->h_addrtype != af)
|
|
continue;
|
|
if (strcasecmp(p->h_name, name) == 0)
|
|
break;
|
|
for (cp = p->h_aliases; *cp != 0; cp++)
|
|
if (strcasecmp(*cp, name) == 0)
|
|
goto found;
|
|
}
|
|
found:
|
|
_endhtent();
|
|
return (p);
|
|
}
|
|
|
|
struct hostent *
|
|
_gethtbyaddr(addr, len, af)
|
|
const char *addr;
|
|
int len, af;
|
|
{
|
|
register struct hostent *p;
|
|
|
|
_sethtent(0);
|
|
while ((p = _gethtent()) != NULL)
|
|
if (p->h_addrtype == af && !bcmp(p->h_addr, addr, len))
|
|
break;
|
|
_endhtent();
|
|
return (p);
|
|
}
|
|
|
|
static void
|
|
map_v4v6_address(src, dst)
|
|
const char *src;
|
|
char *dst;
|
|
{
|
|
u_char *p = (u_char *)dst;
|
|
char tmp[INADDRSZ];
|
|
int i;
|
|
|
|
/* Stash a temporary copy so our caller can update in place. */
|
|
bcopy(src, tmp, INADDRSZ);
|
|
/* Mark this ipv6 addr as a mapped ipv4. */
|
|
for (i = 0; i < 10; i++)
|
|
*p++ = 0x00;
|
|
*p++ = 0xff;
|
|
*p++ = 0xff;
|
|
/* Retrieve the saved copy and we're done. */
|
|
bcopy(tmp, (void*)p, INADDRSZ);
|
|
}
|
|
|
|
static void
|
|
map_v4v6_hostent(hp, bpp, lenp)
|
|
struct hostent *hp;
|
|
char **bpp;
|
|
int *lenp;
|
|
{
|
|
char **ap;
|
|
|
|
if (hp->h_addrtype != AF_INET || hp->h_length != INADDRSZ)
|
|
return;
|
|
hp->h_addrtype = AF_INET6;
|
|
hp->h_length = IN6ADDRSZ;
|
|
for (ap = hp->h_addr_list; *ap; ap++) {
|
|
int i = sizeof(align) - ((u_long)*bpp % sizeof(align));
|
|
|
|
if (*lenp < (i + IN6ADDRSZ)) {
|
|
/* Out of memory. Truncate address list here. XXX */
|
|
*ap = NULL;
|
|
return;
|
|
}
|
|
*bpp += i;
|
|
*lenp -= i;
|
|
map_v4v6_address(*ap, *bpp);
|
|
*ap = *bpp;
|
|
*bpp += IN6ADDRSZ;
|
|
*lenp -= IN6ADDRSZ;
|
|
}
|
|
}
|
|
|
|
#ifdef RESOLVSORT
|
|
static void
|
|
addrsort(ap, num)
|
|
char **ap;
|
|
int num;
|
|
{
|
|
int i, j;
|
|
char **p;
|
|
short aval[MAXADDRS];
|
|
int needsort = 0;
|
|
|
|
p = ap;
|
|
for (i = 0; i < num; i++, p++) {
|
|
for (j = 0 ; (unsigned)j < _res.nsort; j++)
|
|
if (_res.sort_list[j].addr.s_addr ==
|
|
(((struct in_addr *)(*p))->s_addr & _res.sort_list[j].mask))
|
|
break;
|
|
aval[i] = j;
|
|
if (needsort == 0 && i > 0 && j < aval[i-1])
|
|
needsort = i;
|
|
}
|
|
if (!needsort)
|
|
return;
|
|
|
|
while (needsort < num) {
|
|
for (j = needsort - 1; j >= 0; j--) {
|
|
if (aval[j] > aval[j+1]) {
|
|
char *hp;
|
|
|
|
i = aval[j];
|
|
aval[j] = aval[j+1];
|
|
aval[j+1] = i;
|
|
|
|
hp = ap[j];
|
|
ap[j] = ap[j+1];
|
|
ap[j+1] = hp;
|
|
|
|
} else
|
|
break;
|
|
}
|
|
needsort++;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#if defined(BSD43_BSD43_NFS) || defined(sun)
|
|
/* some libc's out there are bound internally to these names (UMIPS) */
|
|
void
|
|
ht_sethostent(stayopen)
|
|
int stayopen;
|
|
{
|
|
_sethtent(stayopen);
|
|
}
|
|
|
|
void
|
|
ht_endhostent()
|
|
{
|
|
_endhtent();
|
|
}
|
|
|
|
struct hostent *
|
|
ht_gethostbyname(name)
|
|
char *name;
|
|
{
|
|
return (_gethtbyname(name));
|
|
}
|
|
|
|
struct hostent *
|
|
ht_gethostbyaddr(addr, len, af)
|
|
const char *addr;
|
|
int len, af;
|
|
{
|
|
return (_gethtbyaddr(addr, len, af));
|
|
}
|
|
|
|
struct hostent *
|
|
gethostent()
|
|
{
|
|
return (_gethtent());
|
|
}
|
|
|
|
void
|
|
dns_service()
|
|
{
|
|
return;
|
|
}
|
|
|
|
#undef dn_skipname
|
|
dn_skipname(comp_dn, eom)
|
|
const u_char *comp_dn, *eom;
|
|
{
|
|
return (__dn_skipname(comp_dn, eom));
|
|
}
|
|
#endif /*old-style libc with yp junk in it*/
|
|
|
|
#ifdef YP
|
|
struct hostent *
|
|
_yphostent(line)
|
|
char *line;
|
|
{
|
|
static struct in_addr host_addrs[MAXADDRS];
|
|
char *p = line;
|
|
char *cp, **q;
|
|
char **hap;
|
|
struct in_addr *buf;
|
|
int more;
|
|
|
|
host.h_name = NULL;
|
|
host.h_addr_list = h_addr_ptrs;
|
|
host.h_length = sizeof(u_int32_t);
|
|
host.h_addrtype = AF_INET;
|
|
hap = h_addr_ptrs;
|
|
buf = host_addrs;
|
|
q = host.h_aliases = host_aliases;
|
|
|
|
nextline:
|
|
more = 0;
|
|
cp = strpbrk(p, " \t");
|
|
if (cp == NULL) {
|
|
if (host.h_name == NULL)
|
|
return (NULL);
|
|
else
|
|
goto done;
|
|
}
|
|
*cp++ = '\0';
|
|
|
|
*hap++ = (char *)buf;
|
|
(void) inet_aton(p, buf++);
|
|
|
|
while (*cp == ' ' || *cp == '\t')
|
|
cp++;
|
|
p = cp;
|
|
cp = strpbrk(p, " \t\n");
|
|
if (cp != NULL) {
|
|
if (*cp == '\n')
|
|
more = 1;
|
|
*cp++ = '\0';
|
|
}
|
|
if (!host.h_name)
|
|
host.h_name = p;
|
|
else if (strcmp(host.h_name, p)==0)
|
|
;
|
|
else if (q < &host_aliases[MAXALIASES - 1])
|
|
*q++ = p;
|
|
p = cp;
|
|
if (more)
|
|
goto nextline;
|
|
|
|
while (cp && *cp) {
|
|
if (*cp == ' ' || *cp == '\t') {
|
|
cp++;
|
|
continue;
|
|
}
|
|
if (*cp == '\n') {
|
|
cp++;
|
|
goto nextline;
|
|
}
|
|
if (q < &host_aliases[MAXALIASES - 1])
|
|
*q++ = cp;
|
|
cp = strpbrk(cp, " \t");
|
|
if (cp != NULL)
|
|
*cp++ = '\0';
|
|
}
|
|
done:
|
|
*q = NULL;
|
|
*hap = NULL;
|
|
return (&host);
|
|
}
|
|
|
|
struct hostent *
|
|
_yp_gethtbyaddr(addr, len, type)
|
|
const char *addr;
|
|
int len, type;
|
|
{
|
|
struct hostent *hp = (struct hostent *)NULL;
|
|
static char *__ypcurrent;
|
|
int __ypcurrentlen, r;
|
|
char name[sizeof("xxx.xxx.xxx.xxx") + 1];
|
|
|
|
if (!__ypdomain) {
|
|
if (_yp_check(&__ypdomain) == 0)
|
|
return (hp);
|
|
}
|
|
(void)snprintf(name, sizeof name, "%u.%u.%u.%u",
|
|
((unsigned)addr[0] & 0xff),
|
|
((unsigned)addr[1] & 0xff),
|
|
((unsigned)addr[2] & 0xff),
|
|
((unsigned)addr[3] & 0xff));
|
|
if (__ypcurrent)
|
|
free(__ypcurrent);
|
|
__ypcurrent = NULL;
|
|
r = yp_match(__ypdomain, "hosts.byaddr", name,
|
|
strlen(name), &__ypcurrent, &__ypcurrentlen);
|
|
if (r==0)
|
|
hp = _yphostent(__ypcurrent);
|
|
if (hp==NULL)
|
|
h_errno = HOST_NOT_FOUND;
|
|
return (hp);
|
|
}
|
|
|
|
struct hostent *
|
|
_yp_gethtbyname(name)
|
|
const char *name;
|
|
{
|
|
struct hostent *hp = (struct hostent *)NULL;
|
|
static char *__ypcurrent;
|
|
int __ypcurrentlen, r;
|
|
|
|
if (!__ypdomain) {
|
|
if (_yp_check(&__ypdomain) == 0)
|
|
return (hp);
|
|
}
|
|
if (__ypcurrent)
|
|
free(__ypcurrent);
|
|
__ypcurrent = NULL;
|
|
r = yp_match(__ypdomain, "hosts.byname", name,
|
|
strlen(name), &__ypcurrent, &__ypcurrentlen);
|
|
if (r==0)
|
|
hp = _yphostent(__ypcurrent);
|
|
if (hp==NULL)
|
|
h_errno = HOST_NOT_FOUND;
|
|
return (hp);
|
|
}
|
|
#endif
|