diff options
author | Jason Downs <downsj@cvs.openbsd.org> | 1997-03-13 19:07:42 +0000 |
---|---|---|
committer | Jason Downs <downsj@cvs.openbsd.org> | 1997-03-13 19:07:42 +0000 |
commit | 6f186362d0923eb9f92a696a1132378f6854f243 (patch) | |
tree | c516aca93e6026f753f6dcf2f004073ee9cd8ca3 /lib/libc/net/gethostnamadr.c | |
parent | 6e0f740fe402f51cdf52c350f93fbda7a6328142 (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.c | 775 |
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 |