summaryrefslogtreecommitdiff
path: root/lib/libc/net/gethostnamadr.c
diff options
context:
space:
mode:
authorJason Downs <downsj@cvs.openbsd.org>1997-03-13 19:07:42 +0000
committerJason Downs <downsj@cvs.openbsd.org>1997-03-13 19:07:42 +0000
commit6f186362d0923eb9f92a696a1132378f6854f243 (patch)
treec516aca93e6026f753f6dcf2f004073ee9cd8ca3 /lib/libc/net/gethostnamadr.c
parent6e0f740fe402f51cdf52c350f93fbda7a6328142 (diff)
Integrate BIND 4.9.5 resolver and associated routines.
Includes the DNS aware getnetby*() routines and IPv6 support.
Diffstat (limited to 'lib/libc/net/gethostnamadr.c')
-rw-r--r--lib/libc/net/gethostnamadr.c775
1 files changed, 569 insertions, 206 deletions
diff --git a/lib/libc/net/gethostnamadr.c b/lib/libc/net/gethostnamadr.c
index 83e0225a656..9826b468050 100644
--- a/lib/libc/net/gethostnamadr.c
+++ b/lib/libc/net/gethostnamadr.c
@@ -52,7 +52,7 @@
*/
#if defined(LIBC_SCCS) && !defined(lint)
-static char rcsid[] = "$OpenBSD: gethostnamadr.c,v 1.13 1997/01/30 05:56:06 deraadt Exp $";
+static char rcsid[] = "$OpenBSD: gethostnamadr.c,v 1.14 1997/03/13 19:07:24 downsj Exp $";
#endif /* LIBC_SCCS and not lint */
#include <sys/param.h>
@@ -66,6 +66,7 @@ static char rcsid[] = "$OpenBSD: gethostnamadr.c,v 1.13 1997/01/30 05:56:06 dera
#include <ctype.h>
#include <errno.h>
#include <string.h>
+#include <syslog.h>
#ifdef YP
#include <rpc/rpc.h>
#include <rpcsvc/yp.h>
@@ -73,6 +74,8 @@ static char rcsid[] = "$OpenBSD: gethostnamadr.c,v 1.13 1997/01/30 05:56:06 dera
#include "ypinternal.h"
#endif
+#define MULTI_PTRS_ARE_ALIASES 1 /* XXX - experimental */
+
#define MAXALIASES 35
#define MAXADDRS 35
@@ -85,10 +88,22 @@ static char *__ypdomain;
static struct hostent host;
static char *host_aliases[MAXALIASES];
static char hostbuf[BUFSIZ+1];
-static struct in_addr host_addr;
+static u_char host_addr[16]; /* IPv4 or IPv6 */
static FILE *hostf = NULL;
static int stayopen = 0;
+static void map_v4v6_address __P((const char *src, char *dst));
+static void map_v4v6_hostent __P((struct hostent *hp, char **bp, int *len));
+
+#ifdef RESOLVSORT
+static void addrsort __P((char **, int));
+#endif
+
+static int hokchar __P((const char *));
+
+static const char AskedForGot[] =
+ "gethostby*.getanswer: asked for \"%s\", got \"%s\"";
+
#if PACKETSZ > 1024
#define MAXPACKET PACKETSZ
#else
@@ -105,15 +120,14 @@ typedef union {
char ac;
} align;
-static int qcomp __P((struct in_addr **, struct in_addr **));
-static struct hostent *getanswer __P((querybuf *, int, int));
-static int hbadchar __P((char *));
+static struct hostent *getanswer __P((const querybuf *, int, const char *,
+ int));
extern int h_errno;
static int
-hbadchar(p)
- char *p;
+hokchar(p)
+ const char *p;
{
char c;
@@ -121,7 +135,7 @@ hbadchar(p)
* Many people do not obey RFC 822 and 1035. The valid
* characters are a-z, A-Z, 0-9, '-' and . But the others
* tested for below can happen, and we must be more permissive
- * until those idiots clean up their act.
+ * than the resolver until those idiots clean up their act.
*/
while ((c = *p++)) {
if (('a' >= c && c <= 'z') ||
@@ -130,28 +144,50 @@ hbadchar(p)
continue;
if (strchr("-_/.[]\\", c) ||
(c == '.' && p[1] == '.'))
- return 1;
+ return 0;
}
- return 0;
+ return 1;
}
static struct hostent *
-getanswer(answer, anslen, iquery)
- querybuf *answer;
+getanswer(answer, anslen, qname, qtype)
+ const querybuf *answer;
int anslen;
- int iquery;
+ const char *qname;
+ int qtype;
{
- register HEADER *hp;
- register u_char *cp;
+ register const HEADER *hp;
+ register const u_char *cp;
register int n;
- u_char *eom;
- char *bp, **ap;
+ const u_char *eom;
+ char *bp, **ap, **hap;
int type, class, buflen, ancount, qdcount;
- int haveanswer, getclass = C_ANY;
- char **hap;
- int good = 1;
+ 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:
+#ifdef USE_RESOLV_NAME_OK
+ name_ok = res_hnok;
+ break;
+#endif
+ case T_PTR:
+#ifdef USE_RESOLV_NAME_OK
+ name_ok = res_dnok;
+#else
+ name_ok = hokchar;
+#endif
+ break;
+ default:
+ return (NULL); /* XXX should be abort(); */
+ }
/*
* find first satisfactory answer
*/
@@ -159,34 +195,29 @@ getanswer(answer, anslen, iquery)
ancount = ntohs(hp->ancount);
qdcount = ntohs(hp->qdcount);
bp = hostbuf;
- buflen = sizeof(hostbuf);
- cp = answer->buf + sizeof(HEADER);
- if (qdcount) {
- if (iquery) {
- if ((n = dn_expand((u_char *)answer->buf,
- (u_char *)eom, (u_char *)cp, bp,
- buflen)) < 0) {
- h_errno = NO_RECOVERY;
- return ((struct hostent *) NULL);
- }
- cp += n + QFIXEDSZ;
- host.h_name = bp;
- n = strlen(bp);
- if (n >= MAXHOSTNAMELEN)
- host.h_name[MAXHOSTNAMELEN-1] = '\0';
- n++;
- bp += n;
- buflen -= n;
- } else
- cp += __dn_skipname(cp, eom) + QFIXEDSZ;
- while (--qdcount > 0)
- cp += __dn_skipname(cp, eom) + QFIXEDSZ;
- } else if (iquery) {
- if (hp->aa)
- h_errno = HOST_NOT_FOUND;
- else
- h_errno = TRY_AGAIN;
- return ((struct hostent *) NULL);
+ 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;
@@ -195,124 +226,258 @@ getanswer(answer, anslen, iquery)
*hap = NULL;
host.h_addr_list = h_addr_ptrs;
haveanswer = 0;
- if (ancount > MAXADDRS)
- ancount = MAXADDRS;
- while (--ancount >= 0 && cp < eom) {
- if ((n = dn_expand((u_char *)answer->buf, (u_char *)eom,
- (u_char *)cp, bp, buflen)) < 0)
- break;
- cp += n;
+ 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 += sizeof(u_int16_t);
+ cp += INT16SZ; /* type */
class = _getshort(cp);
- cp += sizeof(u_int16_t) + sizeof(u_int32_t);
+ cp += INT16SZ + INT32SZ; /* class, TTL */
n = _getshort(cp);
- cp += sizeof(u_int16_t);
- if (type == T_CNAME) {
+ 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;
- if (n > MAXHOSTNAMELEN)
- bp[MAXHOSTNAMELEN-1] = '\0';
+ 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 (iquery && type == T_PTR) {
- if ((n = dn_expand((u_char *)answer->buf,
- (u_char *)eom, (u_char *)cp, bp,
- buflen)) < 0)
- break;
+ 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;
- host.h_name = bp;
- n = strlen(host.h_name);
- if (n >= MAXHOSTNAMELEN)
- host.h_name[MAXHOSTNAMELEN-1] = '\0';
- goto gotent;
+ /* 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 (iquery || type != T_A) {
-#ifdef DEBUG
- if (_res.options & RES_DEBUG)
- printf("unexpected answer type %d, size %d\n",
- type, n);
-#endif
+ 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;
+ continue; /* XXX - had_error++ ? */
}
-
- if (haveanswer) {
- if (n != host.h_length) {
+ switch (type) {
+ case T_PTR:
+ if (strcasecmp(tname, bp) != 0) {
+ syslog(LOG_NOTICE|LOG_AUTH,
+ AskedForGot, qname, bp);
cp += n;
- continue;
+ continue; /* XXX - had_error++ ? */
}
- if (class != getclass) {
+ 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;
}
- } else {
- host.h_length = n;
- getclass = class;
- host.h_addrtype = (class == C_IN) ? AF_INET : AF_UNSPEC;
- if (host.h_addrtype == AF_INET)
- host.h_length = INADDRSZ;
- if (!iquery) {
+ if (!haveanswer) {
+ register int nn;
+
host.h_name = bp;
- bp += strlen(bp) + 1;
- if (strlen(host.h_name) >= MAXHOSTNAMELEN)
- host.h_name[MAXHOSTNAMELEN-1] = '\0';
+ nn = strlen(bp) + 1; /* for the \0 */
+ bp += nn;
+ buflen -= nn;
}
- }
- bp += sizeof(align) - ((u_long)bp % sizeof(align));
+ bp += sizeof(align) - ((u_long)bp % sizeof(align));
- if (bp + n >= &hostbuf[sizeof(hostbuf)]) {
+ if (bp + n >= &hostbuf[sizeof hostbuf]) {
+#ifdef DEBUG
+ if (_res.options & RES_DEBUG)
+ printf("size (%d) too big\n", n);
+#endif
+ had_error++;
+ continue;
+ }
+ if (hap >= &h_addr_ptrs[MAXADDRS-1]) {
+ if (!toobig++)
#ifdef DEBUG
- if (_res.options & RES_DEBUG)
- printf("size (%d) too big\n", n);
+ if (_res.options & RES_DEBUG)
+ printf("Too many addresses (%d)\n", MAXADDRS);
#endif
+ cp += n;
+ continue;
+ }
+ bcopy(cp, *hap++ = bp, n);
+ bp += n;
+ buflen -= n;
+ cp += n;
break;
+ default:
+ abort();
}
- bcopy(cp, *hap++ = bp, n);
- bp +=n;
- cp += n;
- haveanswer++;
- }
- if (!haveanswer) {
- h_errno = TRY_AGAIN;
- return ((struct hostent *) NULL);
- }
- *ap = NULL;
- *hap = NULL;
- if (_res.nsort) {
- qsort(host.h_addr_list, haveanswer,
- sizeof(struct in_addr),
- (int (*)__P((const void *, const void *)))qcomp);
+ if (!had_error)
+ haveanswer++;
}
-gotent:
- if (hbadchar(host.h_name))
- good = 0;
- for (ap = host_aliases; good && *ap; ap++)
- if (hbadchar(*ap))
- good = 0;
- if (good)
+ 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);
- h_errno = NO_RECOVERY;
- return ((struct hostent *) NULL);
+ }
+ try_again:
+ h_errno = TRY_AGAIN;
+ return (NULL);
}
struct hostent *
gethostbyname(name)
const char *name;
{
+ struct hostent *hp;
+ extern struct hostent *_gethtbyname2();
+
+ if ((_res.options & RES_INIT) == 0 && res_init() == -1)
+ return (_gethtbyname2(name, AF_INET));
+
+ 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;
register const char *cp;
- int n, i;
- extern struct hostent *_gethtbyname(), *_yp_gethtbyname();
+ char *bp;
+ int n, size, type, len, i;
+ extern struct hostent *_gethtbyname2(), *_yp_gethtbyname();
register struct hostent *hp;
char lookups[MAXDNSLUS];
+ if ((_res.options & RES_INIT) == 0 && res_init() == -1)
+ return (_gethtbyname2(name, af));
+
+ 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.
@@ -327,26 +492,58 @@ gethostbyname(name)
* Fake up a hostent as if we'd actually
* done a lookup.
*/
- if (!inet_aton(name, &host_addr)) {
+ if (inet_pton(af, name, host_addr) <= 0) {
h_errno = HOST_NOT_FOUND;
- return((struct hostent *) NULL);
+ return (NULL);
}
- host.h_name = (char *)name;
+ 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;
- host.h_addrtype = AF_INET;
- host.h_length = sizeof(u_int32_t);
- h_addr_ptrs[0] = (char *)&host_addr;
+ 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 ((_res.options & RES_INIT) == 0 && res_init() == -1)
- return (_gethtbyname(name));
+ if (isxdigit(name[0]) || 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')
@@ -357,11 +554,13 @@ gethostbyname(name)
switch (lookups[i]) {
#ifdef YP
case 'y':
- hp = _yp_gethtbyname(name);
+ /* YP only suports AF_INET. */
+ if (af == AF_INET)
+ hp = _yp_gethtbyname(name);
break;
#endif
case 'b':
- if ((n = res_search(name, C_IN, T_A, buf.buf,
+ if ((n = res_search(name, C_IN, type, buf.buf,
sizeof(buf))) < 0) {
#ifdef DEBUG
if (_res.options & RES_DEBUG)
@@ -369,10 +568,10 @@ gethostbyname(name)
#endif
break;
}
- hp = getanswer(&buf, n, 0);
+ hp = getanswer(&buf, n, name, type);
break;
case 'f':
- hp = _gethtbyname(name);
+ hp = _gethtbyname2(name, af);
break;
}
}
@@ -380,27 +579,69 @@ gethostbyname(name)
}
struct hostent *
-gethostbyaddr(addr, len, type)
- const char *addr;
- int len, type;
+gethostbyaddr(addr, len, af)
+ const char *addr; /* XXX should have been def'd as u_char! */
+ int len, af;
{
- int n, i;
+ 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;
register struct hostent *hp;
- char qbuf[MAXDNAME];
+ char qbuf[MAXDNAME+1], *qp;
extern struct hostent *_gethtbyaddr(), *_yp_gethtbyaddr();
char lookups[MAXDNSLUS];
- if (type != AF_INET)
- return ((struct hostent *) NULL);
- (void)sprintf(qbuf, "%u.%u.%u.%u.in-addr.arpa",
- ((unsigned)addr[3] & 0xff),
- ((unsigned)addr[2] & 0xff),
- ((unsigned)addr[1] & 0xff),
- ((unsigned)addr[0] & 0xff));
-
if ((_res.options & RES_INIT) == 0 && res_init() == -1)
- return (_gethtbyaddr(addr, len, type));
+ 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')
@@ -411,29 +652,38 @@ gethostbyaddr(addr, len, type)
switch (lookups[i]) {
#ifdef YP
case 'y':
- hp = _yp_gethtbyaddr(addr);
+ /* YP only supports AF_INET. */
+ if (af == AF_INET)
+ hp = _yp_gethtbyaddr(addr);
break;
#endif
case 'b':
- n = res_query(qbuf, C_IN, T_PTR, (u_char *)&buf, sizeof(buf));
+ n = res_query(qbuf, C_IN, T_PTR, (u_char *)buf.buf,
+ sizeof buf.buf);
if (n < 0) {
#ifdef DEBUG
if (_res.options & RES_DEBUG)
printf("res_query failed\n");
#endif
- break;
+ return (NULL);
}
- hp = getanswer(&buf, n, 1);
- if (hp == NULL)
- break;
- hp->h_addrtype = type;
+ if (!(hp = getanswer(&buf, n, qbuf, T_PTR)))
+ return (NULL); /* h_errno was set by getanswer() */
+ hp->h_addrtype = af;
hp->h_length = len;
- h_addr_ptrs[0] = (char *)&host_addr;
- h_addr_ptrs[1] = (char *)0;
- host_addr = *(struct in_addr *)addr;
+ bcopy(addr, host_addr, len);
+ h_addr_ptrs[0] = (char *)host_addr;
+ h_addr_ptrs[1] = NULL;
+ 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, type);
+ hp = _gethtbyaddr(addr, len, af);
break;
}
}
@@ -465,35 +715,51 @@ _gethtent()
{
char *p;
register char *cp, **q;
+ int af, len;
- if (hostf == NULL && (hostf = fopen(_PATH_HOSTS, "r" )) == NULL)
+ if (!hostf && !(hostf = fopen(_PATH_HOSTS, "r" ))) {
+ h_errno = NETDB_INTERNAL;
return (NULL);
-again:
- if ((p = fgets(hostbuf, BUFSIZ, hostf)) == NULL)
+ }
+ again:
+ if (!(p = fgets(hostbuf, sizeof hostbuf, hostf))) {
+ h_errno = HOST_NOT_FOUND;
return (NULL);
+ }
if (*p == '#')
goto again;
- cp = strpbrk(p, "#\n");
- if (cp == NULL)
+ if (!(cp = strpbrk(p, "#\n")))
goto again;
*cp = '\0';
- cp = strpbrk(p, " \t");
- if (cp == NULL)
+ if (!(cp = strpbrk(p, " \t")))
goto again;
*cp++ = '\0';
- /* THIS STUFF IS INTERNET SPECIFIC */
- h_addr_ptrs[0] = (char *)&host_addr;
+ 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;
- (void) inet_aton(p, &host_addr);
host.h_addr_list = h_addr_ptrs;
- host.h_length = sizeof(u_int32_t);
- host.h_addrtype = AF_INET;
+ host.h_length = len;
+ host.h_addrtype = af;
while (*cp == ' ' || *cp == '\t')
cp++;
host.h_name = cp;
q = host.h_aliases = host_aliases;
- cp = strpbrk(cp, " \t");
- if (cp != NULL)
+ if (cp = strpbrk(cp, " \t"))
*cp++ = '\0';
while (cp && *cp) {
if (*cp == ' ' || *cp == '\t') {
@@ -502,11 +768,17 @@ again:
}
if (q < &host_aliases[MAXALIASES - 1])
*q++ = cp;
- cp = strpbrk(cp, " \t");
- if (cp != NULL)
+ if (cp = strpbrk(cp, " \t"))
*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);
}
@@ -514,58 +786,55 @@ struct hostent *
_gethtbyname(name)
const char *name;
{
+ extern struct hostent *_gethtbyname2();
+ 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()) {
+ 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:
+ found:
_endhtent();
- if (p==NULL)
- h_errno = HOST_NOT_FOUND;
return (p);
}
struct hostent *
-_gethtbyaddr(addr, len, type)
+_gethtbyaddr(addr, len, af)
const char *addr;
- int len, type;
+ int len, af;
{
register struct hostent *p;
_sethtent(0);
while (p = _gethtent())
- if (p->h_addrtype == type && !bcmp(p->h_addr, addr, len))
+ if (p->h_addrtype == af && !bcmp(p->h_addr, addr, len))
break;
_endhtent();
- if (p==NULL)
- h_errno = HOST_NOT_FOUND;
return (p);
}
-static int
-qcomp(a1, a2)
- struct in_addr **a1, **a2;
-{
- int pos1, pos2;
-
- for (pos1 = 0; pos1 < _res.nsort; pos1++)
- if (_res.sort_list[pos1].addr.s_addr ==
- ((*a1)->s_addr & _res.sort_list[pos1].mask))
- break;
- for (pos2 = 0; pos2 < _res.nsort; pos2++)
- if (_res.sort_list[pos2].addr.s_addr ==
- ((*a2)->s_addr & _res.sort_list[pos2].mask))
- break;
- return pos1 - pos2;
-}
-
#ifdef YP
struct hostent *
_yphostent(line)
@@ -687,10 +956,104 @@ _yp_gethtbyname(name)
__ypcurrent = NULL;
r = yp_match(__ypdomain, "hosts.byname", name,
strlen(name), &__ypcurrent, &__ypcurrentlen);
- if (r==0)
+ if (r == 0)
hp = _yphostent(__ypcurrent);
- if (hp==NULL)
+ if (hp == NULL)
h_errno = HOST_NOT_FOUND;
return (hp);
}
#endif
+
+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