aboutsummaryrefslogtreecommitdiff
path: root/resolv
diff options
context:
space:
mode:
Diffstat (limited to 'resolv')
-rw-r--r--resolv/Makefile5
-rw-r--r--resolv/arpa/nameser.h13
-rw-r--r--resolv/gethnamaddr.c736
-rw-r--r--resolv/getnetnamadr.c4
-rw-r--r--resolv/inet_addr.c14
-rw-r--r--resolv/inet_ntop.c189
-rw-r--r--resolv/inet_pton.c223
-rw-r--r--resolv/res_comp.c95
-rw-r--r--resolv/res_debug.c21
-rw-r--r--resolv/res_hconf.c566
-rw-r--r--resolv/res_hconf.h50
-rw-r--r--resolv/res_init.c24
-rw-r--r--resolv/resolv.h17
13 files changed, 1735 insertions, 222 deletions
diff --git a/resolv/Makefile b/resolv/Makefile
index ebb8967..58f3282 100644
--- a/resolv/Makefile
+++ b/resolv/Makefile
@@ -22,11 +22,12 @@
subdir := resolv
headers := resolv.h netdb.h arpa/nameser.h sys/bitypes.h
-distribute := ../conf/portability.h
+distribute := ../conf/portability.h res_hconf.h
routines := gethnamaddr getnetbyaddr getnetbyname getnetent getnetnamadr \
herror nsap_addr res_comp res_debug res_data res_init res_mkquery \
- res_query res_send sethostent inet_addr
+ res_query res_send sethostent inet_addr inet_ntop inet_pton \
+ res_hconf
include ../Rules
diff --git a/resolv/arpa/nameser.h b/resolv/arpa/nameser.h
index 3792b79..0fb04a1 100644
--- a/resolv/arpa/nameser.h
+++ b/resolv/arpa/nameser.h
@@ -3,7 +3,7 @@
* -
* Copyright (c) 1983, 1989, 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:
@@ -19,7 +19,7 @@
* 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
@@ -33,14 +33,14 @@
* 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
@@ -97,7 +97,8 @@
#define RRFIXEDSZ 10 /* #/bytes of fixed data in r record */
#define INT32SZ 4 /* for systems without 32-bit ints */
#define INT16SZ 2 /* for systems without 16-bit ints */
-#define INADDRSZ 4 /* for sizeof(struct inaddr) != 4 */
+#define INADDRSZ 4 /* IPv4 T_A */
+#define IN6ADDRSZ 16 /* IPv6 T_AAAA */
/*
* Internet nameserver port number
@@ -110,7 +111,7 @@
#define QUERY 0x0 /* standard query */
#define IQUERY 0x1 /* inverse query */
#define STATUS 0x2 /* nameserver status query */
-/*#define xxx 0x3 /* 0x3 reserved */
+/*#define xxx 0x3*/ /* 0x3 reserved */
#define NS_NOTIFY_OP 0x4 /* notify secondary of SOA change */
#ifdef ALLOW_UPDATES
/* non standard - supports ALLOW_UPDATES stuff from Mike Schwartz */
diff --git a/resolv/gethnamaddr.c b/resolv/gethnamaddr.c
index f108f27..b80595b 100644
--- a/resolv/gethnamaddr.c
+++ b/resolv/gethnamaddr.c
@@ -3,7 +3,7 @@
* -
* 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:
@@ -19,7 +19,7 @@
* 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
@@ -33,14 +33,14 @@
* 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
@@ -71,13 +71,15 @@ static char rcsid[] = "$Id$";
#include <errno.h>
#include <syslog.h>
+#include "res_hconf.h"
+
#ifndef LOG_AUTH
# define LOG_AUTH 0
#endif
#define MULTI_PTRS_ARE_ALIASES 1 /* XXX - experimental */
-#if defined(BSD) && (BSD >= 199103)
+#if defined(BSD) && (BSD >= 199103) && defined(AF_INET6)
# include <string.h>
#else
# include "../conf/portability.h"
@@ -88,6 +90,7 @@ static char rcsid[] = "$Id$";
#define MAXALIASES 35
#define MAXADDRS 35
+#define MAXADDRBUFSIZE 8192
static const char AskedForGot[] =
"gethostby*.getanswer: asked for \"%s\", got \"%s\"";
@@ -97,11 +100,14 @@ static struct hostent *gethostbyname_ipv4 __P((const char *));
static struct hostent host;
static char *host_aliases[MAXALIASES];
-static char hostbuf[8*1024];
-static struct in_addr host_addr;
+static char hostbuf[MAXADDRBUFSIZE];
+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
@@ -142,11 +148,11 @@ dprintf(msg, num)
#endif
static struct hostent *
-getanswer(answer, anslen, qname, qclass, qtype)
+getanswer(answer, anslen, qname, qtype)
const querybuf *answer;
int anslen;
const char *qname;
- int qclass, qtype;
+ int qtype;
{
register const HEADER *hp;
register const u_char *cp;
@@ -165,13 +171,14 @@ getanswer(answer, anslen, qname, qclass, qtype)
eom = answer->buf + anslen;
switch (qtype) {
case T_A:
+ case T_AAAA:
name_ok = res_hnok;
break;
case T_PTR:
- name_ok = dn_isvalid;
+ name_ok = res_dnok;
break;
default:
- abort();
+ return (NULL); /* XXX should be abort(); */
}
/*
* find first satisfactory answer
@@ -192,7 +199,7 @@ getanswer(answer, anslen, qname, qclass, qtype)
return (NULL);
}
cp += n + QFIXEDSZ;
- if (qtype == T_A) {
+ 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).
@@ -209,9 +216,7 @@ getanswer(answer, anslen, qname, qclass, qtype)
host.h_aliases = host_aliases;
hap = h_addr_ptrs;
*hap = NULL;
-#if BSD >= 43 || defined(h_addr) /* new-style hostent structure */
host.h_addr_list = h_addr_ptrs;
-#endif
haveanswer = 0;
had_error = 0;
while (ancount-- > 0 && cp < eom && !had_error) {
@@ -227,12 +232,12 @@ getanswer(answer, anslen, qname, qclass, qtype)
cp += INT16SZ + INT32SZ; /* class, TTL */
n = _getshort(cp);
cp += INT16SZ; /* len */
- if (class != qclass) {
+ if (class != C_IN) {
/* XXX - debug? syslog? */
cp += n;
continue; /* XXX - had_error++ ? */
}
- if (qtype == T_A && type == T_CNAME) {
+ 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);
@@ -241,12 +246,6 @@ getanswer(answer, anslen, qname, qclass, qtype)
continue;
}
cp += n;
- if (host.h_name && strcasecmp(host.h_name, bp) != 0) {
- syslog(LOG_NOTICE|LOG_AUTH,
- "gethostby*.getanswer: asked for \"%s\", got CNAME for \"%s\"",
- host.h_name, bp);
- continue; /* XXX - had_error++ ? */
- }
/* Store alias. */
*ap++ = bp;
n = strlen(bp) + 1; /* for the \0 */
@@ -286,7 +285,7 @@ getanswer(answer, anslen, qname, qclass, qtype)
if (type != qtype) {
syslog(LOG_NOTICE|LOG_AUTH,
"gethostby*.getanswer: asked for \"%s %s %s\", got type \"%s\"",
- qname, p_class(qclass), p_type(qtype),
+ qname, p_class(C_IN), p_type(qtype),
p_type(type));
cp += n;
continue; /* XXX - had_error++ ? */
@@ -320,10 +319,17 @@ getanswer(answer, anslen, qname, qclass, qtype)
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);
@@ -338,10 +344,6 @@ getanswer(answer, anslen, qname, qclass, qtype)
} else {
register int nn;
- host.h_length = n;
- host.h_addrtype = (class == C_IN)
- ? AF_INET
- : AF_UNSPEC;
host.h_name = bp;
nn = strlen(bp) + 1; /* for the \0 */
bp += nn;
@@ -367,13 +369,11 @@ getanswer(answer, anslen, qname, qclass, qtype)
cp += n;
break;
default:
- dprintf("Impossible condition (type=%d)\n", type);
- h_errno = NO_RECOVERY;
- return (NULL);
- } /*switch*/
+ abort();
+ }
if (!had_error)
haveanswer++;
- } /*while*/
+ }
if (haveanswer) {
*ap = NULL;
*hap = NULL;
@@ -383,44 +383,39 @@ getanswer(answer, anslen, qname, qclass, qtype)
* in its return structures - should give it the "best"
* address in that case, not some random one
*/
- if (_res.nsort && haveanswer > 1 &&
- qclass == C_IN && qtype == T_A)
+ if (_res.nsort && haveanswer > 1 && qtype == T_A)
addrsort(h_addr_ptrs, haveanswer);
# endif /*RESOLVSORT*/
-#if BSD >= 43 || defined(h_addr) /* new-style hostent structure */
- /* nothing */
-#else
- host.h_addr = h_addr_ptrs[0];
-#endif /*BSD*/
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);
- } else {
- h_errno = TRY_AGAIN;
- return (NULL);
}
+ try_again:
+ h_errno = TRY_AGAIN;
+ return (NULL);
}
struct hostent *
gethostbyname(name)
const char *name;
{
- /* Moved #if line to here because declaring HP would lead to a
- warning. --drepper@gnu */
-#if defined(AF_INET6) && defined(RES_TRY_INET6)
struct hostent *hp;
-/* #if defined(AF_INET6) && defined(RES_TRY_INET6) */
- if (_res.options & RES_TRY_INET6) {
+ if (_res.options & RES_USE_INET6) {
hp = gethostbyname2(name, AF_INET6);
if (hp)
return (hp);
}
-#endif
return (gethostbyname2(name, AF_INET));
}
@@ -429,29 +424,35 @@ gethostbyname2(name, af)
const char *name;
int af;
{
- switch (af) {
- case AF_INET:
- return (gethostbyname_ipv4(name));
- }
- errno = EAFNOSUPPORT;
- h_errno = NETDB_INTERNAL;
- return (NULL);
-}
-
-static struct hostent *
-gethostbyname_ipv4(name)
- const char *name;
-{
querybuf buf;
register const char *cp;
- int n;
- extern struct hostent *_gethtbyname();
+ char *bp;
+ int i, n, size, type, len;
+ extern struct hostent *_gethtbyname2();
if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
h_errno = NETDB_INTERNAL;
return (NULL);
}
+ 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
@@ -474,117 +475,254 @@ gethostbyname_ipv4(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,
+ sizeof 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;
- host.h_addrtype = AF_INET;
- host.h_length = INT32SZ;
h_addr_ptrs[0] = (char *)&host_addr;
h_addr_ptrs[1] = NULL;
-#if BSD >= 43 || defined(h_addr) /* new-style hostent structure */
host.h_addr_list = h_addr_ptrs;
-#else
- host.h_addr = h_addr_ptrs[0];
-#endif
+ if (_res.options & RES_USE_INET6)
+ map_v4v6_hostent(&host, &bp, &len);
h_errno = NETDB_SUCCESS;
return (&host);
}
- if (!isdigit(*cp) && *cp != '.')
+ if (!isdigit(*cp) && *cp != '.')
break;
}
- if ((n = res_search(name, C_IN, T_A, buf.buf, sizeof(buf))) < 0) {
- dprintf("res_search failed (%d)\n", n);
- if (errno == ECONNREFUSED)
- return (_gethtbyname(name));
- return (NULL);
+ h_errno = HOST_NOT_FOUND;
+ for (i = 0; i < _res_hconf.num_services; ++i) {
+ struct hostent * hp;
+ char * cp = (char *) name;
+
+ if (_res_hconf.num_trimdomains > 0) {
+ size_t name_len = strlen(name);
+
+ cp = malloc(name_len + 1);
+ memcpy(cp, name, name_len + 1);
+ _res_hconf_trim_domain(cp);
+ }
+
+ hp = NULL;
+ switch (_res_hconf.service[i]) {
+ case SERVICE_BIND:
+ if ((n = res_search(cp, C_IN, type,
+ buf.buf, sizeof(buf))) < 0)
+ {
+ dprintf("res_search failed (%d)\n", n);
+ break;
+ }
+ hp = getanswer(&buf, n, cp, type);
+ break;
+
+ case SERVICE_HOSTS:
+ hp = _gethtbyname2(cp, af);
+ break;
+#ifdef HAVE_NYS
+ case SERVICE_NIS:
+ hp = _getnishost(cp, "hosts.byname");
+ break;
+#endif
+ default:
+ break;
+ }
+ if (cp != name)
+ free(cp);
+ if (hp) {
+ if ((_res_hconf.flags & HCONF_FLAG_REORDER)
+ && hp->h_addr_list[0] && hp->h_addr_list[1])
+ _res_hconf_reorder_addrs(hp);
+ _res_hconf_trim_domains(hp);
+ return hp;
+ }
}
- return (getanswer(&buf, n, name, C_IN, T_A));
+ if (h_errno == NETDB_SUCCESS)
+ h_errno = HOST_NOT_FOUND;
+ return NULL;
}
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;
+ 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;
querybuf buf;
register struct hostent *hp;
- char qbuf[MAXDNAME+1];
-#ifdef SUNSECURITY
+ char qbuf[MAXDNAME+1], *qp;
register struct hostent *rhp;
char **haddr;
u_long old_options;
char hname2[MAXDNAME+1];
-#endif /*SUNSECURITY*/
+ int i, old_num_trimdomains;
extern struct hostent *_gethtbyaddr();
-
+
if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
h_errno = NETDB_INTERNAL;
return (NULL);
}
- if (type != AF_INET || len != INADDRSZ) {
+ 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);
}
- (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));
- n = res_query(qbuf, C_IN, T_PTR, (u_char *)buf.buf, sizeof buf.buf);
- if (n < 0) {
- dprintf("res_query failed (%d)\n", n);
- if (errno == ECONNREFUSED)
- return (_gethtbyaddr(addr, len, type));
- return (NULL);
- }
- if (!(hp = getanswer(&buf, n, qbuf, C_IN, T_PTR)))
- return (NULL); /* h_errno was set by getanswer() */
-#ifdef SUNSECURITY
- /*
- * turn off search as the name should be absolute,
- * 'localhost' should be matched by defnames
- */
- strncpy(hname2, hp->h_name, MAXDNAME);
- hname2[MAXDNAME] = '\0';
- old_options = _res.options;
- _res.options &= ~RES_DNSRCH;
- _res.options |= RES_DEFNAMES;
- if (!(rhp = gethostbyname(hname2))) {
- syslog(LOG_NOTICE|LOG_AUTH,
- "gethostbyaddr: No A record for %s (verifying [%s])",
- hname2, inet_ntoa(*((struct in_addr *)addr)));
- _res.options = old_options;
- h_errno = HOST_NOT_FOUND;
+ if (size != len) {
+ errno = EINVAL;
+ h_errno = NETDB_INTERNAL;
return (NULL);
}
- _res.options = old_options;
- for (haddr = rhp->h_addr_list; *haddr; haddr++)
- if (!memcmp(*haddr, addr, INADDRSZ))
+
+ h_errno = NETDB_SUCCESS;
+ for (i = 0; i < _res_hconf.num_services; ++i) {
+ hp = NULL;
+ switch (_res_hconf.service[i]) {
+ case SERVICE_BIND:
+ 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();
+ }
+ n = res_query(qbuf, C_IN, T_PTR,
+ (u_char *)buf.buf, sizeof buf.buf);
+ if (n < 0) {
+ dprintf("res_query failed (%d)\n", n);
+ break;
+ }
+ hp = getanswer(&buf, n, qbuf, T_PTR);
+ if (!hp)
+ break; /* h_errno was set by getanswer() */
+ if (af == AF_INET
+ && (_res_hconf.flags & HCONF_FLAG_SPOOF)) {
+ /*
+ * Turn off search as the name should
+ * be absolute, 'localhost' should be
+ * matched by defnames
+ */
+ strncpy(hname2, hp->h_name, MAXDNAME);
+ hname2[MAXDNAME] = '\0';
+ old_options = _res.options;
+ /*
+ * Also turn off domain trimming to prevent it
+ * from causing the name comparison to fail.
+ */
+ old_num_trimdomains =
+ _res_hconf.num_trimdomains;
+ _res.options &= ~RES_DNSRCH;
+ _res.options |= RES_DEFNAMES;
+ rhp = gethostbyname(hname2);
+ _res.options = old_options;
+ /* There must be an A record and
+ the names must match. */
+ if (!rhp || strcmp(hname2, rhp->h_name)) {
+ syslog(LOG_NOTICE|LOG_AUTH,
+ "gethostbyaddr: No A record for"
+ " %s (verifying [%s])",
+ hname2,
+ inet_ntoa(*((struct in_addr *)
+ addr)));
+ h_errno = HOST_NOT_FOUND;
+ break;
+ }
+ for (haddr = rhp->h_addr_list; *haddr; haddr++)
+ if (!memcmp(*haddr, addr, INADDRSZ))
+ break;
+ if (!*haddr) {
+ syslog(LOG_NOTICE|LOG_AUTH,
+ "gethostbyaddr: A record of %s"
+ " != PTR record [%s]",
+ hname2,
+ inet_ntoa(*((struct in_addr *)
+ addr)));
+ h_errno = HOST_NOT_FOUND;
+ 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] = 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;
- if (!*haddr) {
- syslog(LOG_NOTICE|LOG_AUTH,
- "gethostbyaddr: A record of %s != PTR record [%s]",
- hname2, inet_ntoa(*((struct in_addr *)addr)));
- h_errno = HOST_NOT_FOUND;
- return (NULL);
+
+ case SERVICE_HOSTS:
+ hp = _gethtbyaddr(addr, len, af);
+ break;
+
+#ifdef HAVE_NYS
+ case SERVICE_NIS:
+ if (af == AF_INET) {
+ sprintf(qbuf, "%u.%u.%u.%u",
+ (unsigned)addr[0] & 0xff,
+ (unsigned)addr[1] & 0xff,
+ (unsigned)addr[2] & 0xff,
+ (unsigned)addr[3] & 0xff);
+ hp = _getnishost(qbuf, "hosts.byaddr");
+ }
+ break;
+#endif
+
+ default:
+ break;
+ }
+ if (hp) {
+ _res_hconf_trim_domains(hp);
+ return hp;
+ }
}
-#endif /*SUNSECURITY*/
- hp->h_addrtype = type;
- hp->h_length = len;
- h_addr_ptrs[0] = (char *)&host_addr;
- h_addr_ptrs[1] = NULL;
- host_addr = *(struct in_addr *)addr;
- h_errno = NETDB_SUCCESS;
- return (hp);
+ if (h_errno == NETDB_SUCCESS)
+ h_errno = HOST_NOT_FOUND;
+ return NULL;
}
void
@@ -612,12 +750,13 @@ _gethtent()
{
char *p;
register char *cp, **q;
+ int af, len;
if (!hostf && !(hostf = fopen(_PATH_HOSTS, "r" ))) {
h_errno = NETDB_INTERNAL;
return (NULL);
}
-again:
+ again:
if (!(p = fgets(hostbuf, sizeof hostbuf, hostf))) {
h_errno = HOST_NOT_FOUND;
return (NULL);
@@ -630,18 +769,27 @@ again:
if (!(cp = strpbrk(p, " \t")))
goto again;
*cp++ = '\0';
- /* THIS STUFF IS INTERNET SPECIFIC */
- if (!inet_aton(p, &host_addr))
+ if ((_res.options & RES_USE_INET6) &&
+ inet_pton(AF_INET6, p, host_addr, sizeof host_addr) > 0) {
+ af = AF_INET6;
+ len = IN6ADDRSZ;
+ } else if (inet_pton(AF_INET, p, host_addr, sizeof 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;
-#if BSD >= 43 || defined(h_addr) /* new-style hostent structure */
host.h_addr_list = h_addr_ptrs;
-#else
- host.h_addr = h_addr_ptrs[0];
-#endif
- host.h_length = INT32SZ;
- host.h_addrtype = AF_INET;
+ host.h_length = len;
+ host.h_addrtype = af;
while (*cp == ' ' || *cp == '\t')
cp++;
host.h_name = cp;
@@ -659,45 +807,275 @@ again:
*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 hstorage {
+ char name[MAXHOSTNAMELEN + 1]; /* canonical name */
+ char ** alp; /* address list pointer */
+ char * abp; /* address buffer pointer */
+ char * addr_list[MAXADDRS + 1]; /* address list storage */
+ char addr_buf[MAXADDRBUFSIZE]; /* addresses storage */
+};
+
+static void
+append_addr (struct hstorage * hs, struct hostent *p)
+{
+ if (hs->alp < hs->addr_list + MAXADDRS
+ && hs->abp + p->h_length < hs->addr_buf + MAXADDRBUFSIZE)
+ {
+ hs->alp[0] = hs->abp;
+ hs->alp[1] = 0;
+ memcpy(hs->abp, p->h_addr_list[0], p->h_length);
+ hs->abp += p->h_length;
+ ++hs->alp;
+ }
+}
+
+/*
+ * Lookup IP address and aliases for host NAME. If multiaddress mode
+ * is enabled, the entire /etc/hosts file is searched and the union of
+ * all addresses found for NAME is returned (this may be slow with
+ * large /etc/hosts files, but is convenient for smallish sites that
+ * don't want to go through the complexity of running named locally).
+ * If multiaddress mode is enabled, the address returned in
+ * h_addr_list[0] is one that is on the same net as one of the host's
+ * local addresses (if such an address exists). For compatibility
+ * with the BIND version of gethostbyname(), the alias field is empty
+ * unless the name being looked up is an alias itself. In the latter
+ * case, the name field contains the canonical name and the alias
+ * field the name that is being looked up. A difference from the BIND
+ * version is that this is true even if the alias applies only to one
+ * of the interfaces on the target host.o
+ */
struct hostent *
_gethtbyname(name)
- char *name;
+ const char *name;
+{
+ extern struct hostent *_gethtbyname2 __P((const char *, int));
+ 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 (strcasecmp(p->h_name, name) == 0)
- break;
- for (cp = p->h_aliases; *cp != 0; cp++)
- if (strcasecmp(*cp, name) == 0)
- goto found;
+
+ if (_res_hconf.flags & HCONF_FLAG_MULTI) {
+ /*
+ * More statics; not pretty, but it would require
+ * interface changes to make these functions
+ * reentrant.
+ */
+ static char * aliases[2];
+ static char alias[MAXHOSTNAMELEN + 1];
+ static struct hstorage self, target;
+ static struct hostent ht;
+ int found;
+
+ aliases[0] = aliases[1] = 0;
+
+ gethostname(self.name, sizeof(self.name));
+ self.alp = self.addr_list;
+ self.abp = self.addr_buf;
+
+ strncpy(target.name, name, MAXHOSTNAMELEN);
+ target.name[MAXHOSTNAMELEN] = '\0';
+ target.alp = target.addr_list;
+ target.abp = target.addr_buf;
+
+ _sethtent(0);
+ while ((p = _gethtent()) != 0) {
+ found = 1;
+
+ if (p->h_addrtype != af)
+ continue;
+ if (strcasecmp(p->h_name, name) != 0) {
+ found = 0;
+ for (cp = p->h_aliases; *cp; ++cp)
+ if (strcasecmp(*cp, name) == 0) {
+ found = 1;
+ if (!aliases[0]) {
+ strcpy(target.name,
+ p->h_name);
+ strncpy(alias, name,
+ MAXHOSTNAMELEN);
+ alias[MAXHOSTNAMELEN]
+ = '\0';
+ aliases[0] = alias;
+ }
+ break;
+ }
+ }
+ if (found) {
+ /* they better be all the same type and length! */
+ ht.h_addrtype = p->h_addrtype;
+ ht.h_length = p->h_length;
+ append_addr(&target, p);
+ /*
+ * If the current hostentry is for the target host, we don't
+ * check for the local host name. This nicely optimizes the
+ * case where NAME is a local name since address ordering
+ * doesn't matter in that case.
+ */
+ continue;
+ }
+ found = 1;
+ if (strcasecmp(p->h_name, self.name) != 0) {
+ found = 0;
+ for (cp = p->h_aliases; *cp; ++cp)
+ if (strcasecmp(*cp, self.name) == 0) {
+ found = 1;
+ break;
+ }
+ }
+ if (found) {
+ append_addr(&self, p);
+ }
+ }
+ _endhtent();
+
+ if (target.alp == target.addr_list)
+ return NULL; /* found nothing */
+
+ ht.h_aliases = aliases;
+ ht.h_name = target.name;
+ ht.h_addr_list = target.addr_list;
+ /*
+ * XXX (davidm) Isn't this subsumed by REORDER???
+ *
+ * Finding the `best' address is necessarily address
+ * specific. For now, we do IPv4 addresses only.
+ */
+ if (af == AF_INET) {
+ u_int32_t a1, a2, diff, mindiff = ~0;
+ int i, j, bestaddr = 0;
+
+ for (i = 0; self.addr_list[i]; ++i) {
+ for (j = 0; target.addr_list[j]; ++j) {
+ memcpy(&a1, self.addr_list[i], 4);
+ memcpy(&a2, target.addr_list[j], 4);
+ a1 = ntohl(a1);
+ a2 = ntohl(a2);
+ diff = a1 ^ a2;
+ if (diff < mindiff) {
+ bestaddr = j;
+ mindiff = diff;
+ }
+ }
+ }
+ if (bestaddr > 0) {
+ char * tmp;
+
+ tmp = target.addr_list[0];
+ target.addr_list[0] = target.addr_list[bestaddr];
+ target.addr_list[bestaddr] = tmp;
+ }
+ } else if (af == AF_INET6) {
+ /* XXX To do!!! */
+ }
+ ht.h_addr_list = target.addr_list;
+ return &ht;
+ } else {
+ _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();
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();
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)
@@ -712,7 +1090,7 @@ addrsort(ap, num)
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 ==
+ if (_res.sort_list[j].addr.s_addr ==
(((struct in_addr *)(*p))->s_addr & _res.sort_list[j].mask))
break;
aval[i] = j;
@@ -766,17 +1144,57 @@ ht_gethostbyname(name)
}
struct hostent *
-ht_gethostbyaddr(addr, len, type)
+ht_gethostbyaddr(addr, len, af)
const char *addr;
- int len, type;
+ int len, af;
{
- return (_gethtbyaddr(addr, len, type));
+ return (_gethtbyaddr(addr, len, af));
}
struct hostent *
gethostent()
{
- return (_gethtent());
+ struct hostent * hp;
+ int i;
+
+ if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
+ h_errno = NETDB_INTERNAL;
+ return (NULL);
+ }
+
+ /*
+ * This doesn't look quite right. Shouldn't we read one
+ * service until it returns 0, then move on to the next
+ * service? If so, it requires adding some state and
+ * initializing that state in sethostent().
+ * (davidm@azstarnet.com)
+ */
+ for (i = 0; i < _res_hconf.num_services; ++i) {
+ hp = NULL;
+ switch (_res_hconf.service[i]) {
+ case SERVICE_HOSTS:
+ hp = _gethtent ();
+ break;
+
+#ifdef HAVE_NYS
+ case SERVICE_NIS:
+ hp = _getnishost (NULL, "hosts.byname");
+ break;
+#endif
+
+ case SERVICE_BIND:
+ default:
+ break;
+ }
+ if (hp) {
+ if ((_res_hconf.flags & HCONF_FLAG_REORDER)
+ && hp->h_addr_list[0] && hp->h_addr_list[1])
+ _res_hconf_reorder_addrs (hp);
+ return hp;
+ }
+ }
+ h_errno = HOST_NOT_FOUND;
+ return NULL;
}
void
diff --git a/resolv/getnetnamadr.c b/resolv/getnetnamadr.c
index fad2b8c..9739995 100644
--- a/resolv/getnetnamadr.c
+++ b/resolv/getnetnamadr.c
@@ -139,7 +139,7 @@ static char *net_aliases[MAXALIASES], netbuf[BUFSIZ+1];
haveanswer = 0;
while (--ancount >= 0 && cp < eom) {
n = dn_expand(answer->buf, eom, cp, bp, buflen);
- if ((n < 0) || !dn_isvalid(bp))
+ if ((n < 0) || !res_dnok(bp))
break;
cp += n;
ans[0] = '\0';
@@ -209,7 +209,7 @@ getnetbyaddr(net, net_type)
int nn, anslen;
querybuf buf;
char qbuf[MAXDNAME];
- u_int32_t net2;
+ u_int32_t net2; /* Changed from unsigned long --roland */
struct netent *net_entry;
if (net_type != AF_INET)
diff --git a/resolv/inet_addr.c b/resolv/inet_addr.c
index bcf7f0d..2caf747 100644
--- a/resolv/inet_addr.c
+++ b/resolv/inet_addr.c
@@ -3,7 +3,7 @@
* -
* Copyright (c) 1983, 1990, 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:
@@ -19,7 +19,7 @@
* 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
@@ -33,14 +33,14 @@
* 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
@@ -70,7 +70,7 @@ static char rcsid[] = "$Id$";
* Ascii internet address interpretation routine.
* The value returned is in network order.
*/
-u_int32_t
+u_long
inet_addr(cp)
register const char *cp;
{
@@ -81,7 +81,7 @@ inet_addr(cp)
return (INADDR_NONE);
}
-/*
+/*
* Check whether "cp" is a valid ascii representation
* of an Internet address and convert to a binary address.
* Returns 1 if the address is valid, 0 if not.
@@ -93,7 +93,7 @@ inet_aton(cp, addr)
register const char *cp;
struct in_addr *addr;
{
- register u_int32_t val;
+ register u_int32_t val; /* changed from u_long --david */
register int base, n;
register char c;
u_int parts[4];
diff --git a/resolv/inet_ntop.c b/resolv/inet_ntop.c
new file mode 100644
index 0000000..71db06d
--- /dev/null
+++ b/resolv/inet_ntop.c
@@ -0,0 +1,189 @@
+/* Copyright (c) 1996 by Internet Software Consortium.
+ *
+ * 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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM 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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char rcsid[] = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+#include <string.h>
+#include <errno.h>
+#include <stdio.h>
+#include "../conf/portability.h"
+
+/*
+ * WARNING: Don't even consider trying to compile this on a system where
+ * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX.
+ */
+
+static const char *inet_ntop4 __P((const u_char *src, char *dst, size_t size));
+static const char *inet_ntop6 __P((const u_char *src, char *dst, size_t size));
+
+/* char *
+ * inet_ntop(af, src, dst, size)
+ * convert a network format address to presentation format.
+ * return:
+ * pointer to presentation format address (`dst'), or NULL (see errno).
+ * author:
+ * Paul Vixie, 1996.
+ */
+const char *
+inet_ntop(af, src, dst, size)
+ int af;
+ const void *src;
+ char *dst;
+ size_t size;
+{
+ switch (af) {
+ case AF_INET:
+ return (inet_ntop4(src, dst, size));
+ case AF_INET6:
+ return (inet_ntop6(src, dst, size));
+ default:
+ errno = EAFNOSUPPORT;
+ return (NULL);
+ }
+ /* NOTREACHED */
+}
+
+/* const char *
+ * inet_ntop4(src, dst, size)
+ * format an IPv4 address, more or less like inet_ntoa()
+ * return:
+ * `dst' (as a const)
+ * notes:
+ * (1) uses no statics
+ * (2) takes a u_char* not an in_addr as input
+ * author:
+ * Paul Vixie, 1996.
+ */
+static const char *
+inet_ntop4(src, dst, size)
+ const u_char *src;
+ char *dst;
+ size_t size;
+{
+ static const char fmt[] = "%u.%u.%u.%u";
+ char tmp[sizeof "255.255.255.255"];
+
+ if (sprintf(tmp, fmt, src[0], src[1], src[2], src[3]) > size) {
+ errno = ENOSPC;
+ return (NULL);
+ }
+ strcpy(dst, tmp);
+ return (dst);
+}
+
+/* const char *
+ * inet_ntop6(src, dst, size)
+ * convert IPv6 binary address into presentation (printable) format
+ * author:
+ * Paul Vixie, 1996.
+ */
+static const char *
+inet_ntop6(src, dst, size)
+ const u_char *src;
+ char *dst;
+ size_t size;
+{
+ /*
+ * Note that int32_t and int16_t need only be "at least" large enough
+ * to contain a value of the specified size. On some systems, like
+ * Crays, there is no such thing as an integer variable with 16 bits.
+ * Keep this in mind if you think this function should have been coded
+ * to use pointer overlays. All the world's not a VAX.
+ */
+ char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"], *tp;
+ struct { int base, len; } best, cur;
+ u_int words[IN6ADDRSZ / INT16SZ];
+ int i;
+
+ /*
+ * Preprocess:
+ * Copy the input (bytewise) array into a wordwise array.
+ * Find the longest run of 0x00's in src[] for :: shorthanding.
+ */
+ bzero(words, sizeof words);
+ for (i = 0; i < IN6ADDRSZ; i++)
+ words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3));
+ best.base = -1;
+ cur.base = -1;
+ for (i = 0; i < (IN6ADDRSZ / INT16SZ); i++) {
+ if (words[i] == 0) {
+ if (cur.base == -1)
+ cur.base = i, cur.len = 1;
+ else
+ cur.len++;
+ } else {
+ if (cur.base != -1) {
+ if (best.base == -1 || cur.len > best.len)
+ best = cur;
+ cur.base = -1;
+ }
+ }
+ }
+ if (cur.base != -1) {
+ if (best.base == -1 || cur.len > best.len)
+ best = cur;
+ }
+ if (best.base != -1 && best.len < 2)
+ best.base = -1;
+
+ /*
+ * Format the result.
+ */
+ tp = tmp;
+ for (i = 0; i < (IN6ADDRSZ / INT16SZ); i++) {
+ /* Are we inside the best run of 0x00's? */
+ if (best.base != -1 && i >= best.base &&
+ i < (best.base + best.len)) {
+ if (i == best.base)
+ *tp++ = ':';
+ continue;
+ }
+ /* Are we following an initial run of 0x00s or any real hex? */
+ if (i != 0)
+ *tp++ = ':';
+ /* Is this address an encapsulated IPv4? */
+ if (i == 6 && best.base == 0 &&
+ (best.len == 6 || (best.len == 5 && words[5] == 0xffff))) {
+ if (!inet_ntop4(src+12, tp, sizeof tmp - (tp - tmp)))
+ return (NULL);
+ tp += strlen(tp);
+ break;
+ }
+ tp += sprintf(tp, "%x", words[i]);
+ }
+ /* Was it a trailing run of 0x00's? */
+ if (best.base != -1 && (best.base + best.len) == (IN6ADDRSZ / INT16SZ))
+ *tp++ = ':';
+ *tp++ = '\0';
+
+ /*
+ * Check for overflow, copy, and we're done.
+ */
+ if ((tp - tmp) > size) {
+ errno = ENOSPC;
+ return (NULL);
+ }
+ strcpy(dst, tmp);
+ return (dst);
+}
diff --git a/resolv/inet_pton.c b/resolv/inet_pton.c
new file mode 100644
index 0000000..385dc25
--- /dev/null
+++ b/resolv/inet_pton.c
@@ -0,0 +1,223 @@
+/* Copyright (c) 1996 by Internet Software Consortium.
+ *
+ * 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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM 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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char rcsid[] = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+#include <string.h>
+#include <errno.h>
+#include "../conf/portability.h"
+
+/*
+ * WARNING: Don't even consider trying to compile this on a system where
+ * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX.
+ */
+
+static int inet_pton4 __P((const char *src, u_char *dst));
+static int inet_pton6 __P((const char *src, u_char *dst));
+
+/* int
+ * inet_pton(af, src, dst, size)
+ * convert from presentation format (which usually means ASCII printable)
+ * to network format (which is usually some kind of binary format).
+ * return:
+ * 1 if the address was valid for the specified address family
+ * 0 if the address wasn't valid (`dst' is untouched in this case)
+ * -1 if some other error occurred (`dst' is untouched in this case, too)
+ * author:
+ * Paul Vixie, 1996.
+ */
+int
+inet_pton(af, src, dst, size)
+ int af;
+ const char *src;
+ void *dst;
+ size_t size;
+{
+ switch (af) {
+ case AF_INET:
+ if (size < INADDRSZ) {
+ errno = ENOSPC;
+ return (-1);
+ }
+ return (inet_pton4(src, dst));
+ case AF_INET6:
+ if (size < IN6ADDRSZ) {
+ errno = ENOSPC;
+ return (-1);
+ }
+ return (inet_pton6(src, dst));
+ default:
+ errno = EINVAL;
+ return (-1);
+ }
+ /* NOTREACHED */
+}
+
+/* int
+ * inet_pton4(src, dst)
+ * like inet_pton() but without all the hexadecimal and shorthand.
+ * return:
+ * 1 if `src' is a valid dotted quad, else 0.
+ * notice:
+ * does not touch `dst' unless it's returning 1.
+ * author:
+ * Paul Vixie, 1996.
+ */
+static int
+inet_pton4(src, dst)
+ const char *src;
+ u_char *dst;
+{
+ static const char digits[] = "0123456789";
+ int saw_digit, octets, ch;
+ u_char tmp[INADDRSZ], *tp;
+
+ saw_digit = 0;
+ octets = 0;
+ *(tp = tmp) = 0;
+ while ((ch = *src++) != '\0') {
+ const char *pch;
+
+ if ((pch = strchr(digits, ch)) != NULL) {
+ u_int new = *tp * 10 + (pch - digits);
+
+ if (new > 255)
+ return (0);
+ *tp = new;
+ if (! saw_digit) {
+ if (++octets > 4)
+ return (0);
+ saw_digit = 1;
+ }
+ } else if (ch == '.' && saw_digit) {
+ if (octets == 4)
+ return (0);
+ *++tp = 0;
+ saw_digit = 0;
+ } else
+ return (0);
+ }
+ if (octets < 4)
+ return (0);
+ bcopy(tmp, dst, INADDRSZ);
+ return (1);
+}
+
+/* int
+ * inet_pton6(src, dst)
+ * convert presentation level address to network order binary form.
+ * return:
+ * 1 if `src' is a valid [RFC1884 2.2] address, else 0.
+ * notice:
+ * (1) does not touch `dst' unless it's returning 1.
+ * (2) :: in a full address is silently ignored.
+ * credit:
+ * inspired by Mark Andrews.
+ * author:
+ * Paul Vixie, 1996.
+ */
+static int
+inet_pton6(src, dst)
+ const char *src;
+ u_char *dst;
+{
+ static const char xdigits_l[] = "0123456789abcdef",
+ xdigits_u[] = "0123456789ABCDEF";
+ u_char tmp[IN6ADDRSZ], *tp, *endp, *colonp;
+ const char *xdigits, *curtok;
+ int ch, saw_xdigit;
+ u_int val;
+
+ bzero((tp = tmp), IN6ADDRSZ);
+ endp = tp + IN6ADDRSZ;
+ colonp = NULL;
+ /* Leading :: requires some special handling. */
+ if (*src == ':')
+ if (*++src != ':')
+ return (0);
+ curtok = src;
+ saw_xdigit = 0;
+ val = 0;
+ while ((ch = *src++) != '\0') {
+ const char *pch;
+
+ if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
+ pch = strchr((xdigits = xdigits_u), ch);
+ if (pch != NULL) {
+ val <<= 4;
+ val |= (pch - xdigits);
+ if (val > 0xffff)
+ return (0);
+ saw_xdigit = 1;
+ continue;
+ }
+ if (ch == ':') {
+ curtok = src;
+ if (!saw_xdigit) {
+ if (colonp)
+ return (0);
+ colonp = tp;
+ continue;
+ }
+ if (tp + INT16SZ > endp)
+ return (0);
+ *tp++ = (u_char) (val >> 8) & 0xff;
+ *tp++ = (u_char) val & 0xff;
+ saw_xdigit = 0;
+ val = 0;
+ continue;
+ }
+ if (ch == '.' && ((tp + INADDRSZ) <= endp) &&
+ inet_pton4(curtok, tp) > 0) {
+ tp += INADDRSZ;
+ saw_xdigit = 0;
+ break; /* '\0' was seen by inet_pton4(). */
+ }
+ return (0);
+ }
+ if (saw_xdigit) {
+ if (tp + INT16SZ > endp)
+ return (0);
+ *tp++ = (u_char) (val >> 8) & 0xff;
+ *tp++ = (u_char) val & 0xff;
+ }
+ if (colonp != NULL) {
+ /*
+ * Since some memmove()'s erroneously fail to handle
+ * overlapping regions, we'll do the shift by hand.
+ */
+ const howmany = tp - colonp;
+ int i;
+
+ for (i = 1; i <= howmany; i++) {
+ endp[- i] = colonp[howmany - i];
+ colonp[howmany - i] = 0;
+ }
+ tp = endp;
+ }
+ if (tp != endp)
+ return (0);
+ bcopy(tmp, dst, IN6ADDRSZ);
+ return (1);
+}
diff --git a/resolv/res_comp.c b/resolv/res_comp.c
index f234772..e105dbb 100644
--- a/resolv/res_comp.c
+++ b/resolv/res_comp.c
@@ -3,7 +3,7 @@
* -
* Copyright (c) 1985, 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:
@@ -19,7 +19,7 @@
* 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
@@ -33,14 +33,14 @@
* 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
@@ -343,7 +343,7 @@ dn_find(exp_dn, msg, dnptrs, lastdnptr)
/****
To: "Lawrence R. Rogers" <lrr@cert.org>
cc: cert@cert.org, pvm@home.net
-Subject: Re: VU#14542
+Subject: Re: VU#14542
In-reply-to: Your message of "Mon, 19 Feb 1996 17:16:27 PST."
Date: Tue, 20 Feb 1996 22:37:21 -0800
From: Paul A Vixie <vixie@wisdom.home.vix.com>
@@ -359,7 +359,7 @@ in retrospect,
should have been
hostname = label ( "." label )+
- firstchar = [a-zA-Z0-9_]
+ firstchar = [a-zA-Z0-9]
otherchar = [a-zA-Z0-9_-]
label = firstchar otherchar*
@@ -368,53 +368,98 @@ earlier. since i'm only trying to bend the spec to fit actual known uses,
i should not have widened the rules as far as i did earlier.
****/
-#define firstchar(c) ((isascii(c) && isalnum(c)) || (c) == '_')
-#define otherchar(c) (firstchar(c) || (c) == '-')
-#define wildlabel(firstlabel, ch, nch) \
- ((firstlabel) && (ch) == '*' && ((nch) == '.' || (nch) == '\0'))
+/*
+ * Note the conspicuous absence of ctype macros in these definitions. On
+ * non-ASCII hosts, we can't depend on string literals or ctype macros to
+ * tell us anything about network-format data. The rest of the BIND system
+ * is not careful about this, but for some reason, we're doing it right here.
+ */
+#define PERIOD 0x2e
+#define hyphenchar(c) ((c) == 0x2d)
+#define bslashchar(c) ((c) == 0x5c)
+#define periodchar(c) ((c) == PERIOD)
+#define asterchar(c) ((c) == 0x2a)
+#define alphachar(c) (((c) >= 0x41 && (c) <= 0x5a) \
+ || ((c) >= 0x61 && (c) <= 0x7a))
+#define digitchar(c) ((c) >= 0x30 && (c) <= 0x39)
+
+#define borderchar(c) (alphachar(c) || digitchar(c))
+#define middlechar(c) (borderchar(c) || hyphenchar(c))
+#define domainchar(c) ((c) > 0x20 && (c) < 0x7f)
int
res_hnok(dn)
const char *dn;
{
- int ppch = '\0', pch = '.', ch = *dn++, firstlabel = 1;
+ int ppch = '\0', pch = PERIOD, ch = *dn++;
while (ch != '\0') {
int nch = *dn++;
- if (ch == '.' || (ch == '\\' && nch == '.')) {
+ if (periodchar(ch)) {
NULL;
- } else if (pch == '.' && ppch != '\\') {
- if (!firstchar(ch) && !wildlabel(firstlabel, ch, nch))
+ } else if (periodchar(pch)) {
+ if (!borderchar(ch))
+ return (0);
+ } else if (periodchar(nch) || nch == '\0') {
+ if (!borderchar(ch))
return (0);
} else {
- if (!otherchar(ch))
+ if (!middlechar(ch))
return (0);
}
ppch = pch, pch = ch, ch = nch;
- firstlabel = 0;
}
return (1);
}
/*
+ * hostname-like (A, MX, WKS) owners can have "*" as their first label
+ * but must otherwise be as a host name.
+ */
+int
+res_ownok(dn)
+ const char *dn;
+{
+ if (asterchar(dn[0]) && periodchar(dn[1]))
+ dn += 2;
+ return (res_hnok(dn));
+}
+
+/*
+ * SOA RNAMEs and RP RNAMEs can have any printable character in their first
+ * label, but the rest of the name has to look like a host name.
+ */
+int
+res_mailok(dn)
+ const char *dn;
+{
+ int ch, pch;
+
+ pch = '\0';
+ while ((ch = *dn++) != '\0') {
+ if (!domainchar(ch))
+ return (0);
+ if (periodchar(ch) && !bslashchar(pch))
+ break;
+ pch = ch;
+ }
+ return (res_hnok(dn));
+}
+
+/*
* This function is quite liberal, since RFC 1034's character sets are only
* recommendations.
- *
- * Note that some char's are signed, so we have to cast to unsigned.
*/
int
-dn_isvalid(dn)
+res_dnok(dn)
const char *dn;
{
- unsigned char *t = (unsigned char *)dn;
int ch;
- while ((ch = *t++) != '\0')
- if (ch <= 0x1f || ch >= 0x7f) {
- /* Unprintable in ASCII. */
+ while ((ch = *dn++) != '\0')
+ if (!domainchar(ch))
return (0);
- }
return (1);
}
@@ -498,7 +543,7 @@ putlong(l, msgp)
{
__putlong(l, msgp);
}
-
+
#undef dn_skipname
dn_skipname(comp_dn, eom)
const u_char *comp_dn, *eom;
diff --git a/resolv/res_debug.c b/resolv/res_debug.c
index 85ec628..4f55804 100644
--- a/resolv/res_debug.c
+++ b/resolv/res_debug.c
@@ -3,7 +3,7 @@
* -
* Copyright (c) 1985, 1990, 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:
@@ -19,7 +19,7 @@
* 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
@@ -33,14 +33,14 @@
* 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
@@ -59,6 +59,8 @@ static char rcsid[] = "$Id$";
#endif /* LIBC_SCCS and not lint */
#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <arpa/nameser.h>
@@ -66,7 +68,7 @@ static char rcsid[] = "$Id$";
#include <stdio.h>
#include <netdb.h>
#include <resolv.h>
-#if defined(BSD) && (BSD >= 199103)
+#if defined(BSD) && (BSD >= 199103) && defined(AF_INET6)
# include <string.h>
#else
# include "../conf/portability.h"
@@ -295,7 +297,7 @@ __fp_nquery(msg, len, file)
fprintf(file, ", Auth: %d", ntohs(hp->nscount));
fprintf(file, ", Addit: %d", ntohs(hp->arcount));
}
- if ((!_res.pfcode) || (_res.pfcode &
+ if ((!_res.pfcode) || (_res.pfcode &
(RES_PRF_HEADX | RES_PRF_HEAD2 | RES_PRF_HEAD1))) {
putc('\n',file);
}
@@ -590,6 +592,13 @@ __p_rr(cp, msg, file)
cp += dlen;
break;
+ case T_AAAA: {
+ char t[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"];
+
+ fprintf(file, "\t%s\n", inet_ntop(AF_INET6, cp, t, sizeof t));
+ break;
+ }
+
case T_MINFO:
case T_RP:
putc('\t', file);
diff --git a/resolv/res_hconf.c b/resolv/res_hconf.c
new file mode 100644
index 0000000..b08dd3c
--- /dev/null
+++ b/resolv/res_hconf.c
@@ -0,0 +1,566 @@
+/* Copyright (C) 1993, 1995, 1996 Free Software Foundation, Inc.
+ Contributed by David Mosberger (davidm@azstarnet.com).
+
+The GNU C Library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+The GNU C Library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA. */
+
+/* This file provides a Linux /etc/host.conf compatible front end to
+the various name resolvers (/etc/hosts, named, NIS server, etc.).
+Though mostly compatibly, the following differences exist compared
+to the original implementation:
+
+ - new command "spoof" takes an arguments like RESOLV_SPOOF_CHECK
+ environment variable (i.e., `off', `nowarn', or `warn').
+
+ - line comments can appear anywhere (not just at the beginning of
+ a line)
+*/
+#include <ctype.h>
+#include <memory.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "res_hconf.h"
+
+#define _PATH_HOSTCONF "/etc/host.conf"
+
+/* Environment vars that all user to override default behavior: */
+#define ENV_HOSTCONF "RESOLV_HOST_CONF"
+#define ENV_SERVORDER "RESOLV_SERV_ORDER"
+#define ENV_SPOOF "RESOLV_SPOOF_CHECK"
+#define ENV_TRIM_OVERR "RESOLV_OVERRIDE_TRIM_DOMAINS"
+#define ENV_TRIM_ADD "RESOLV_ADD_TRIM_DOMAINS"
+#define ENV_MULTI "RESOLV_MULTI"
+#define ENV_REORDER "RESOLV_REORDER"
+
+static const char * arg_service_list (const char *, int, const char *,
+ unsigned);
+static const char * arg_trimdomain_list (const char *, int, const char *,
+ unsigned);
+static const char * arg_spoof (const char *, int, const char *, unsigned);
+static const char * arg_bool (const char *, int, const char *, unsigned);
+
+static struct cmd {
+ const char * name;
+ const char * (*parse_args)(const char * filename, int line_num,
+ const char * args, unsigned arg);
+ unsigned arg;;
+} cmd[] = {
+ {"order", arg_service_list, 0},
+ {"trim", arg_trimdomain_list, 0},
+ {"spoof", arg_spoof, 0},
+ {"multi", arg_bool, HCONF_FLAG_MULTI},
+ {"nospoof", arg_bool, HCONF_FLAG_SPOOF},
+ {"spoofalert", arg_bool, HCONF_FLAG_SPOOFALERT},
+ {"reorder", arg_bool, HCONF_FLAG_REORDER}
+};
+
+
+/*
+ * Why isn't this in stdlib?
+ */
+char *
+strndup (const char * s, size_t n)
+{
+ char * retval;
+
+ retval = malloc (n + 1);
+ if (!retval)
+ return retval;
+
+ memcpy (retval, s, n);
+ retval[n] = '\0'; /* ensure return value is terminated */
+ return retval;
+}
+
+
+/* Skip white space. */
+static const char *
+skip_ws (const char * str)
+{
+ while (isspace (*str)) ++str;
+ return str;
+}
+
+
+/* Skip until whitespace, comma, end of line, or comment character. */
+static const char *
+skip_string (const char * str)
+{
+ while (*str && !isspace (*str) && *str != '#' && *str != ',') ++str;
+ return str;
+}
+
+
+static const char *
+arg_service_list (const char * fname, int line_num, const char * args,
+ unsigned arg)
+{
+ enum Name_Service service;
+ const char * start;
+ size_t len;
+ int i;
+ static struct {
+ const char * name;
+ enum Name_Service service;
+ } svcs[] = {
+ {"bind", SERVICE_BIND},
+ {"hosts", SERVICE_HOSTS},
+ {"nis", SERVICE_NIS},
+ };
+
+ do
+ {
+ start = args;
+ args = skip_string (args);
+ len = args - start;
+
+ service = SERVICE_NONE;
+ for (i = 0; i < sizeof (svcs) / sizeof (svcs[0]); ++i)
+ {
+ if (strncasecmp (start, svcs[i].name, len) == 0
+ && len == strlen (svcs[i].name))
+ {
+ service = svcs[i].service;
+ break;
+ }
+ }
+ if (service == SERVICE_NONE)
+ {
+ fprintf (stderr, "%s: line %d: expected service, found `%s'\n",
+ fname, line_num, start);
+ return 0;
+ }
+ if (_res_hconf.num_services >= SERVICE_MAX)
+ {
+ fprintf (stderr, "%s: line %d: cannot specify more than %d services",
+ fname, line_num, SERVICE_MAX);
+ return 0;
+ }
+ _res_hconf.service[_res_hconf.num_services++] = service;
+
+ args = skip_ws (args);
+ switch (*args)
+ {
+ case ',': case ';': case ':':
+ args = skip_ws (++args);
+ if (!*args || *args == '#')
+ {
+ fprintf (stderr,
+ "%s: line %d: list delimiter not followed by keyword",
+ fname, line_num);
+ return 0;
+ }
+ default:
+ break;
+ }
+ }
+ while (*args && *args != '#');
+ return args;
+}
+
+
+static const char *
+arg_trimdomain_list (const char * fname, int line_num, const char * args,
+ unsigned flag)
+{
+ const char * start;
+ size_t len;
+
+ do
+ {
+ start = args;
+ args = skip_string (args);
+ len = args - start;
+
+ if (_res_hconf.num_trimdomains >= TRIMDOMAINS_MAX)
+ {
+ fprintf (stderr,
+ "%s: line %d: cannot specify more than %d trim domains",
+ fname, line_num, TRIMDOMAINS_MAX);
+ return 0;
+ }
+ _res_hconf.trimdomain[_res_hconf.num_trimdomains++] =
+ strndup (start, len);
+ args = skip_ws (args);
+ switch (*args)
+ {
+ case ',': case ';': case ':':
+ args = skip_ws (++args);
+ if (!*args || *args == '#')
+ {
+ fprintf (stderr,
+ "%s: line %d: list delimiter not followed by domain",
+ fname, line_num);
+ return 0;
+ }
+ default:
+ break;
+ }
+ }
+ while (*args && *args != '#');
+ return args;
+}
+
+
+static const char *
+arg_spoof (const char * fname, int line_num, const char * args, unsigned flag)
+{
+ const char * start = args;
+ size_t len;
+
+ args = skip_string (args);
+ len = args - start;
+
+ if (len == 3 && strncasecmp (start, "off", len) == 0)
+ _res_hconf.flags &= ~(HCONF_FLAG_SPOOF | HCONF_FLAG_SPOOFALERT);
+ else
+ {
+ _res_hconf.flags |= (HCONF_FLAG_SPOOF | HCONF_FLAG_SPOOFALERT);
+ if ((len == 6 && strncasecmp (start, "nowarn", len) == 0)
+ || !(len == 4 && strncasecmp (start, "warn", len) == 0))
+ _res_hconf.flags &= ~HCONF_FLAG_SPOOFALERT;
+ }
+ return args;
+}
+
+
+static const char *
+arg_bool (const char * fname, int line_num, const char * args, unsigned flag)
+{
+ if (strncasecmp (args, "on", 2) == 0)
+ {
+ args += 2;
+ _res_hconf.flags |= flag;
+ }
+ else if (strncasecmp (args, "off", 3) == 0)
+ {
+ args += 3;
+ _res_hconf.flags &= ~flag;
+ }
+ else
+ {
+ fprintf (stderr, "%s: line %d: expected `on' or `off', found `%s'\n",
+ fname, line_num, args);
+ return 0;
+ }
+ return args;
+}
+
+
+static void
+parse_line (const char * fname, int line_num, const char * str)
+{
+ const char * start;
+ struct cmd * c = 0;
+ size_t len;
+ int i;
+
+ str = skip_ws (str);
+
+ if (*str == '#') return; /* skip line comment */
+
+ start = str;
+ str = skip_string (str);
+ len = str - start;
+
+ for (i = 0; i < sizeof (cmd) / sizeof (cmd[0]); ++i)
+ {
+ if (strncasecmp (start, cmd[i].name, len) == 0
+ && strlen (cmd[i].name) == len)
+ {
+ c = &cmd[i];
+ break;
+ }
+ }
+ if (!c)
+ {
+ fprintf (stderr, "%s: line %d: bad command `%s'\n",
+ fname, line_num, start);
+ return;
+ }
+
+ /* process args: */
+ str = skip_ws (str);
+ str = (*c->parse_args) (fname, line_num, str, c->arg);
+ if (!str)
+ return;
+
+ /* rest of line must contain white space or comment only: */
+ while (*str)
+ {
+ if (!isspace (*str)) {
+ if (*str != '#')
+ fprintf (stderr, "%s: line %d: ignoring trailing garbage `%s'\n",
+ fname, line_num, str);
+ break;
+ }
+ ++str;
+ }
+}
+
+
+/* Initialize hconf datastructure by reading host.conf file and
+ environment variables. */
+void
+_res_hconf_init (void)
+{
+ const char * hconf_name;
+ int line_num = 0;
+ char buf[256], * end, * envval;
+ FILE * fp;
+
+ memset (&_res_hconf, 0, sizeof (_res_hconf));
+
+ hconf_name = getenv (ENV_HOSTCONF);
+ if (!hconf_name)
+ hconf_name = _PATH_HOSTCONF;
+
+ fp = fopen (hconf_name, "r");
+ if (!fp)
+ /* make up something reasonable: */
+ _res_hconf.service[_res_hconf.num_services++] = SERVICE_BIND;
+ else
+ {
+ while (fgets (buf, sizeof (buf), fp))
+ {
+ ++line_num;
+ end = strchr (buf, '\n');
+ if (end)
+ *end = '\0';
+ parse_line (hconf_name, line_num, buf);
+ }
+ fclose (fp);
+ }
+
+ envval = getenv (ENV_SERVORDER);
+ if (envval)
+ {
+ _res_hconf.num_services = 0;
+ arg_service_list (ENV_SERVORDER, 1, envval, 0);
+ }
+
+ envval = getenv (ENV_SPOOF);
+ if (envval)
+ arg_spoof (ENV_SPOOF, 1, envval, 0);
+
+ envval = getenv (ENV_MULTI);
+ if (envval)
+ arg_bool (ENV_MULTI, 1, envval, HCONF_FLAG_MULTI);
+
+ envval = getenv (ENV_REORDER);
+ if (envval)
+ arg_bool (ENV_REORDER, 1, envval, HCONF_FLAG_REORDER);
+
+ envval = getenv (ENV_TRIM_ADD);
+ if (envval)
+ arg_trimdomain_list (ENV_TRIM_ADD, 1, envval, 0);
+
+ envval = getenv (ENV_TRIM_OVERR);
+ if (envval)
+ {
+ _res_hconf.num_trimdomains = 0;
+ arg_trimdomain_list (ENV_TRIM_OVERR, 1, envval, 0);
+ }
+}
+
+
+/* Reorder addresses returned in a hostent such that the first address
+ is an address on the local subnet, if there is such an address.
+ Otherwise, nothing is changed. */
+
+void
+_res_hconf_reorder_addrs (struct hostent * hp)
+{
+#if defined (SIOCGIFCONF) && defined (SIOCGIFNETMASK)
+ static int num_ifs = -1; /* number of interfaces */
+ static struct netaddr {
+ int addrtype;
+ union {
+ struct {
+ u_int32_t addr;
+ u_int32_t mask;
+ } ipv4
+ } u;
+ } * ifaddrs;
+
+ if (hp->h_addrtype != AF_INET)
+ return; /* can't deal with anything but IPv4 for now... */
+
+ if (num_ifs <= 0)
+ {
+ struct ifconf ifs;
+ struct ifreq * ifr;
+ size_t size, num;
+ int sd;
+
+ /* initialize interface table: */
+
+ num_ifs = 0;
+
+ sd = socket (AF_INET, SOCK_DGRAM, 0);
+ if (sd < 0)
+ return;
+
+ /* Now get list of interfaces. Since we don't know how many
+ interfaces there are, we keep increasing the buffer size
+ until we have at least sizeof(struct ifreq) too many bytes.
+ That implies that the ioctl() return because it ran out of
+ interfaces, not memory */
+ size = 0;
+ ifs.ifc_buf = 0;
+ do {
+ size += 4 * sizeof (struct ifreq);
+ ifs.ifc_buf = realloc (ifs.ifs_buf, size);
+ if (!ifs.ifc_buf)
+ {
+ close (sd);
+ return;
+ }
+ ifs.ifc_len = size;
+ if (ioctl (sd, SIOCGIFCONF, &ifs) < 0)
+ goto cleanup;
+ } while (size - ifs.ifc_len < sizeof (struct ifreq));
+
+ num = ifs.ifc_len / sizeof (struct ifreq);
+
+ ifaddrs = malloc (num * sizeof (ifaddrs[0]));
+ if (!ifaddrs)
+ goto cleanup;
+
+ ifr = ifs.ifc_req;
+ for (i = 0; i < num; ++i) {
+ if (ifr->ifr_addr.sa_family != AF_INET)
+ continue;
+ ifaddrs[num_ifs].addrtype = AF_INET;
+
+ memcpy (&ifaddrs[num_ifs].u.ipv4.addr,
+ &((struct sockaddr_in *)ifr->ifr_addr)->sin_addr, 4);
+
+ if (ioctl (sd, SIOCGIFNETMASK, if) < 0)
+ continue;
+ memcpy (&ifaddrs[num_ifs].u.ipv4.mask,
+ ((struct sockaddr_in *)ifr->ifr_mask)->sin_addr, 4);
+
+ ++num_ifs; /* now we're committed to this entry */
+ }
+ /* just keep enough memory to hold all the interfaces we want: */
+ ifaddrs = realloc (ifaddrs, num_ifs * sizeof (ifaddrs[0]));
+
+ cleanup:
+ close (sd);
+ free (ifs.ifc_buf);
+ }
+
+ if (num_ifs == 0)
+ return;
+
+ /* find an address for which we have a direct connection: */
+ for (i = 0; hp->h_addr_list[i]; ++i)
+ {
+ h_addr = (struct in_addr *) hp->h_addr_list[i];
+
+ for (j = 0; j < num_ifs; ++j)
+ {
+ if_addr = ifaddrs[j].u.ipv4.addr;
+ if_netmask = ifaddrs[j].u.ipv4.mask;
+
+ if (((h_addr->s_addr ^ if_addr) & if_netmask) == 0)
+ {
+ void * tmp;
+
+ tmp = hp->h_addr_list[i];
+ hp->h_addr_list[i] = hp->h_addr_list[0];
+ hp->h_addr_list[0] = tmp;
+ return;
+ }
+ }
+ }
+#endif /* defined(SIOCGIFCONF) && ... */
+}
+
+
+/* If HOSTNAME has a postfix matching any of the trimdomains, trim away
+ that postfix. Notice that HOSTNAME is modified inplace. Also, the
+ original code applied all trimdomains in order, meaning that the
+ same domainname could be trimmed multiple times. I believe this
+ was unintentional. */
+void
+_res_hconf_trim_domain (char * hostname)
+{
+ size_t hostname_len, trim_len;
+ int i;
+
+ hostname_len = strlen(hostname);
+
+ for (i = 0; i < _res_hconf.num_trimdomains; ++i)
+ {
+ const char * trim = _res_hconf.trimdomain[i];
+
+ trim_len = strlen(trim);
+ if (hostname_len > trim_len
+ && strcasecmp(&hostname[hostname_len - trim_len], trim) == 0)
+ {
+ hostname[hostname_len - trim_len] = '\0';
+ break;
+ }
+ }
+}
+
+
+/* Trim all hostnames/aliases in HP according to the trimdomain list.
+ Notice that HP is modified inplace! */
+void
+_res_hconf_trim_domains (struct hostent * hp)
+{
+ int i;
+
+ if (_res_hconf.num_trimdomains == 0)
+ return;
+
+ _res_hconf_trim_domain (hp->h_name);
+ for (i = 0; hp->h_aliases[i]; ++i)
+ _res_hconf_trim_domain (hp->h_aliases[i]);
+}
+
+
+#if 0
+
+struct hostent *
+_hconf_gethostent (void)
+{
+}
+
+
+struct hostent *
+_hconf_gethostbyname (const char * name)
+{
+
+}
+
+
+struct hostent *
+_hconf_gethostbyaddr (const char * addr, int len, int type)
+{
+}
+
+
+struct hostent *
+_hconf_gethtbyname (const char * name)
+{
+}
+
+#endif
diff --git a/resolv/res_hconf.h b/resolv/res_hconf.h
new file mode 100644
index 0000000..2165e40
--- /dev/null
+++ b/resolv/res_hconf.h
@@ -0,0 +1,50 @@
+/* Copyright (C) 1993, 1995, 1996 Free Software Foundation, Inc.
+ Contributed by David Mosberger (davidm@azstarnet.com).
+
+The GNU C Library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+The GNU C Library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA. */
+
+#ifndef _RES_HCONF_H_
+#define _RES_HCONF_H_
+
+#include <netdb.h>
+
+#define TRIMDOMAINS_MAX 4
+
+enum Name_Service {
+ SERVICE_NONE = 0,
+ SERVICE_BIND, SERVICE_HOSTS, SERVICE_NIS,
+ SERVICE_MAX
+};
+
+struct hconf {
+ int num_services;
+ enum Name_Service service[SERVICE_MAX];
+ int num_trimdomains;
+ const char * trimdomain[TRIMDOMAINS_MAX];
+ unsigned flags;
+# define HCONF_FLAG_INITED (1 << 0) /* initialized? */
+# define HCONF_FLAG_SPOOF (1 << 1) /* refuse spoofed addresses */
+# define HCONF_FLAG_SPOOFALERT (1 << 2) /* syslog warning of spoofed */
+# define HCONF_FLAG_REORDER (1 << 3) /* list best address first */
+# define HCONF_FLAG_MULTI (1 << 4) /* see comments for gethtbyname() */
+} _res_hconf;
+
+extern void _res_hconf_init (void);
+extern void _res_hconf_trim_domain (char * domain);
+extern void _res_hconf_trim_domains (struct hostent * hp);
+extern void _res_hconf_reorder_addrs (struct hostent * hp);
+
+#endif /* _RES_HCONF_H_ */
diff --git a/resolv/res_init.c b/resolv/res_init.c
index 42c7c2e..4e8af68 100644
--- a/resolv/res_init.c
+++ b/resolv/res_init.c
@@ -3,7 +3,7 @@
* -
* Copyright (c) 1985, 1989, 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:
@@ -19,7 +19,7 @@
* 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
@@ -33,14 +33,14 @@
* 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
@@ -76,6 +76,8 @@ static char rcsid[] = "$Id$";
# include "../conf/portability.h"
#endif
+#include "res_hconf.h"
+
/*-------------------------------------- info about "sortlist" --------------
* Marc Majka 1994/04/16
* Allan Nathanson 1994/10/29 (BIND 4.9.3.x)
@@ -137,7 +139,7 @@ struct __res_state _res;
* since it was noted that INADDR_ANY actually meant ``the first interface
* you "ifconfig"'d at boot time'' and if this was a SLIP or PPP interface,
* it had to be "up" in order for you to reach your own name server. It
- * was later decided that since the recommended practice is to always
+ * was later decided that since the recommended practice is to always
* install local static routes through 127.0.0.1 for all your network
* interfaces, that we could solve this problem without a code change.
*
@@ -354,11 +356,11 @@ res_init()
if (inet_aton(net, &a)) {
_res.sort_list[nsort].mask = a.s_addr;
} else {
- _res.sort_list[nsort].mask =
+ _res.sort_list[nsort].mask =
net_mask(_res.sort_list[nsort].addr);
}
} else {
- _res.sort_list[nsort].mask =
+ _res.sort_list[nsort].mask =
net_mask(_res.sort_list[nsort].addr);
}
nsort++;
@@ -373,7 +375,7 @@ res_init()
continue;
}
}
- if (nserv > 1)
+ if (nserv > 1)
_res.nscount = nserv;
#ifdef RESOLVSORT
_res.nsort = nsort;
@@ -419,6 +421,8 @@ res_init()
if ((cp = getenv("RES_OPTIONS")) != NULL)
res_setoptions(cp, "env");
_res.options |= RES_INIT;
+
+ _res_hconf_init ();
return (0);
}
@@ -458,6 +462,8 @@ res_setoptions(options, source)
}
printf(";;\tdebug\n");
#endif
+ } else if (!strncmp(cp, "inet6", sizeof("inet6") - 1)) {
+ _res.options |= RES_USE_INET6;
} else {
/* XXX - print a warning here? */
}
@@ -562,7 +568,7 @@ netinfo_res_init(haveenv, havesearch)
}
ni_namelist_free(&nl);
}
-
+
if (nserv > 1)
_res.nscount = nserv;
diff --git a/resolv/resolv.h b/resolv/resolv.h
index 1a4a0de..0f5d5b8 100644
--- a/resolv/resolv.h
+++ b/resolv/resolv.h
@@ -3,7 +3,7 @@
* -
* Copyright (c) 1983, 1987, 1989, 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:
@@ -19,7 +19,7 @@
* 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
@@ -33,14 +33,14 @@
* 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
@@ -140,6 +140,7 @@ struct __res_state {
#define RES_INSECURE1 0x00000400 /* type 1 security disabled */
#define RES_INSECURE2 0x00000800 /* type 2 security disabled */
#define RES_NOALIASES 0x00001000 /* shuts off HOSTALIASES feature */
+#define RES_USE_INET6 0x00002000 /* use/map IPv6 in gethostbyname() */
#define RES_DEFAULT (RES_RECURSE | RES_DEFNAMES | RES_DNSRCH)
@@ -185,7 +186,9 @@ extern struct __res_state _res;
/* Private routines shared between libc/net, named, nslookup and others. */
#define res_hnok __res_hnok
-#define dn_isvalid __dn_isvalid
+#define res_ownok __res_ownok
+#define res_mailok __res_mailok
+#define res_dnok __res_dnok
#define dn_skipname __dn_skipname
#define fp_query __fp_query
#define fp_nquery __fp_nquery
@@ -206,7 +209,9 @@ extern struct __res_state _res;
#define res_queriesmatch __res_queriesmatch
__BEGIN_DECLS
int __res_hnok __P((const char *));
-int __dn_isvalid __P((const char *));
+int __res_ownok __P((const char *));
+int __res_mailok __P((const char *));
+int __res_dnok __P((const char *));
int __dn_skipname __P((const u_char *, const u_char *));
void __fp_resstat __P((struct __res_state *, FILE *));
void __fp_query __P((const u_char *, FILE *));