(res_queriesmatch): Fix typo in comment.
[kopensolaris-gnu/glibc.git] / resolv / gethnamaddr.c
index f2def79..7be2315 100644 (file)
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *     This product includes software developed by the University of
- *     California, Berkeley and its contributors.
  * 4. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
@@ -55,7 +51,6 @@
 
 #if defined(LIBC_SCCS) && !defined(lint)
 static char sccsid[] = "@(#)gethostnamadr.c    8.1 (Berkeley) 6/4/93";
-static char rcsid[] = "$Id$";
 #endif /* LIBC_SCCS and not lint */
 
 #include <sys/types.h>
@@ -72,6 +67,8 @@ static char rcsid[] = "$Id$";
 #include <errno.h>
 #include <syslog.h>
 
+#define RESOLVSORT
+
 #ifndef LOG_AUTH
 # define LOG_AUTH 0
 #endif
@@ -110,18 +107,24 @@ 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));
+static void map_v4v6_address (const char *src, char *dst) __THROW;
+static void map_v4v6_hostent (struct hostent *hp, char **bp, int *len) __THROW;
 
 #ifdef RESOLVSORT
-static void addrsort __P((char **, int));
+extern void addrsort (char **, int) __THROW;
 #endif
 
-#if PACKETSZ > 1024
+#if PACKETSZ > 65536
 #define        MAXPACKET       PACKETSZ
 #else
-#define        MAXPACKET       1024
+#define        MAXPACKET       65536
+#endif
+
+/* As per RFC 1034 and 1035 a host name cannot exceed 255 octets in length.  */
+#ifdef MAXHOSTNAMELEN
+# undef MAXHOSTNAMELEN
 #endif
+#define MAXHOSTNAMELEN 256
 
 typedef union {
     HEADER hdr;
@@ -139,7 +142,7 @@ extern int h_errno;
 
 #ifdef DEBUG
 static void
-dprintf(msg, num)
+Dprintf(msg, num)
        char *msg;
        int num;
 {
@@ -151,27 +154,41 @@ dprintf(msg, num)
        }
 }
 #else
-# define dprintf(msg, num) /*nada*/
+# define Dprintf(msg, num) /*nada*/
 #endif
 
+#define BOUNDED_INCR(x) \
+       do { \
+               cp += x; \
+               if (cp > eom) { \
+                       __set_h_errno (NO_RECOVERY); \
+                       return (NULL); \
+               } \
+       } while (0)
+
+#define BOUNDS_CHECK(ptr, count) \
+       do { \
+               if ((ptr) + (count) > eom) { \
+                       __set_h_errno (NO_RECOVERY); \
+                       return (NULL); \
+               } \
+       } while (0)
+
+
 static struct hostent *
-getanswer(answer, anslen, qname, qtype)
-       const querybuf *answer;
-       int anslen;
-       const char *qname;
-       int qtype;
+getanswer (const querybuf *answer, int anslen, const char *qname, int qtype)
 {
        register const HEADER *hp;
        register const u_char *cp;
        register int n;
-       const u_char *eom;
+       const u_char *eom, *erdata;
        char *bp, **ap, **hap;
        int type, class, buflen, ancount, qdcount;
        int haveanswer, had_error;
        int toobig = 0;
        char tbuf[MAXDNAME];
        const char *tname;
-       int (*name_ok) __P((const char *));
+       int (*name_ok) (const char *);
 
        tname = qname;
        host.h_name = NULL;
@@ -195,7 +212,8 @@ getanswer(answer, anslen, qname, qtype)
        qdcount = ntohs(hp->qdcount);
        bp = hostbuf;
        buflen = sizeof hostbuf;
-       cp = answer->buf + HFIXEDSZ;
+       cp = answer->buf;
+       BOUNDED_INCR(HFIXEDSZ);
        if (qdcount != 1) {
                __set_h_errno (NO_RECOVERY);
                return (NULL);
@@ -205,7 +223,7 @@ getanswer(answer, anslen, qname, qtype)
                __set_h_errno (NO_RECOVERY);
                return (NULL);
        }
-       cp += n + QFIXEDSZ;
+       BOUNDED_INCR(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
@@ -237,12 +255,15 @@ getanswer(answer, anslen, qname, qtype)
                        continue;
                }
                cp += n;                        /* name */
-               type = _getshort(cp);
-               cp += INT16SZ;                  /* type */
-               class = _getshort(cp);
-               cp += INT16SZ + INT32SZ;        /* class, TTL */
-               n = _getshort(cp);
+               BOUNDS_CHECK(cp, 3 * INT16SZ + INT32SZ);
+               type = ns_get16(cp);
+               cp += INT16SZ;                  /* type */
+               class = ns_get16(cp);
+               cp += INT16SZ + INT32SZ;        /* class, TTL */
+               n = ns_get16(cp);
                cp += INT16SZ;                  /* len */
+               BOUNDS_CHECK(cp, n);
+               erdata = cp + n;
                if (class != C_IN) {
                        /* XXX - debug? syslog? */
                        cp += n;
@@ -257,6 +278,10 @@ getanswer(answer, anslen, qname, qtype)
                                continue;
                        }
                        cp += n;
+                       if (cp != erdata) {
+                               __set_h_errno (NO_RECOVERY);
+                               return (NULL);
+                       }
                        /* Store alias. */
                        *ap++ = bp;
                        n = strlen(bp) + 1;     /* for the \0 */
@@ -280,11 +305,15 @@ getanswer(answer, anslen, qname, qtype)
                }
                if (qtype == T_PTR && type == T_CNAME) {
                        n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf);
-                       if (n < 0 || !res_hnok(tbuf)) {
+                       if (n < 0 || !res_dnok(tbuf)) {
                                had_error++;
                                continue;
                        }
                        cp += n;
+                       if (cp != erdata) {
+                               __set_h_errno (NO_RECOVERY);
+                               return (NULL);
+                       }
                        /* Get canonical name. */
                        n = strlen(tbuf) + 1;   /* for the \0 */
                        if (n > buflen || n >= MAXHOSTNAMELEN) {
@@ -297,6 +326,18 @@ getanswer(answer, anslen, qname, qtype)
                        buflen -= n;
                        continue;
                }
+               if ((type == T_SIG) || (type == T_KEY) || (type == T_NXT)) {
+                       /* We don't support DNSSEC yet.  For now, ignore
+                        * the record and send a low priority message
+                        * to syslog.
+                        */
+                       syslog(LOG_DEBUG|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;
+               }
                if (type != qtype) {
                        syslog(LOG_NOTICE|LOG_AUTH,
               "gethostby*.getanswer: asked for \"%s %s %s\", got type \"%s\"",
@@ -320,6 +361,10 @@ getanswer(answer, anslen, qname, qtype)
                        }
 #if MULTI_PTRS_ARE_ALIASES
                        cp += n;
+                       if (cp != erdata) {
+                               __set_h_errno (NO_RECOVERY);
+                               return (NULL);
+                       }
                        if (!haveanswer)
                                host.h_name = bp;
                        else if (ap < &host_aliases[MAXALIASES-1])
@@ -372,24 +417,33 @@ getanswer(answer, anslen, qname, qtype)
                                buflen -= nn;
                        }
 
+                       /* XXX: when incrementing bp, we have to decrement
+                        * buflen by the same amount --okir */
+                       buflen -= sizeof(align) - ((u_long)bp % sizeof(align));
+
                        bp += sizeof(align) - ((u_long)bp % sizeof(align));
 
                        if (bp + n >= &hostbuf[sizeof hostbuf]) {
-                               dprintf("size (%d) too big\n", n);
+                               Dprintf("size (%d) too big\n", n);
                                had_error++;
                                continue;
                        }
                        if (hap >= &h_addr_ptrs[MAXADDRS-1]) {
-                               if (!toobig++)
-                                       dprintf("Too many addresses (%d)\n",
+                               if (!toobig++) {
+                                       Dprintf("Too many addresses (%d)\n",
                                                MAXADDRS);
+                               }
                                cp += n;
                                continue;
                        }
-                       bcopy(cp, *hap++ = bp, n);
+                       memmove(*hap++ = bp, cp, n);
                        bp += n;
                        buflen -= n;
                        cp += n;
+                       if (cp != erdata) {
+                               __set_h_errno (NO_RECOVERY);
+                               return (NULL);
+                       }
                        break;
                default:
                        abort();
@@ -428,16 +482,19 @@ getanswer(answer, anslen, qname, qtype)
        return (NULL);
 }
 
+extern struct hostent *gethostbyname2(const char *name, int af);
+libresolv_hidden_proto (gethostbyname2)
+
 struct hostent *
 gethostbyname(name)
        const char *name;
 {
        struct hostent *hp;
 
-       if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
+       if (__res_maybe_init (&_res, 0) == -1) {
                __set_h_errno (NETDB_INTERNAL);
                return (NULL);
-       }
+       }
        if (_res.options & RES_USE_INET6) {
                hp = gethostbyname2(name, AF_INET6);
                if (hp)
@@ -451,13 +508,18 @@ gethostbyname2(name, af)
        const char *name;
        int af;
 {
-       querybuf buf;
+       union
+       {
+         querybuf *buf;
+         u_char *ptr;
+       } buf;
+       querybuf *origbuf;
        register const char *cp;
        char *bp;
        int n, size, type, len;
-       extern struct hostent *_gethtbyname2();
+       struct hostent *ret;
 
-       if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
+       if (__res_maybe_init (&_res, 0) == -1) {
                __set_h_errno (NETDB_INTERNAL);
                return (NULL);
        }
@@ -556,36 +618,51 @@ gethostbyname2(name, af)
                                break;
                }
 
-       if ((n = res_search(name, C_IN, type, buf.buf, sizeof(buf.buf))) < 0) {
-               dprintf("res_search failed (%d)\n", n);
+       buf.buf = origbuf = (querybuf *) alloca (1024);
+
+       if ((n = __libc_res_nsearch(&_res, name, C_IN, type, buf.buf->buf, 1024,
+                                   &buf.ptr)) < 0) {
+               if (buf.buf != origbuf)
+                       free (buf.buf);
+               Dprintf("res_nsearch failed (%d)\n", n);
                if (errno == ECONNREFUSED)
                        return (_gethtbyname2(name, af));
                return (NULL);
        }
-       return (getanswer(&buf, n, name, type));
+       ret = getanswer(buf.buf, n, name, type);
+       if (buf.buf != origbuf)
+               free (buf.buf);
+       return ret;
 }
+libresolv_hidden_def (gethostbyname2)
 
 struct hostent *
 gethostbyaddr(addr, len, af)
-       const char *addr;       /* XXX should have been def'd as u_char! */
-       int len, af;
+       const void *addr;
+       socklen_t len;
+       int af;
 {
        const u_char *uaddr = (const u_char *)addr;
        static const u_char mapped[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0xff,0xff };
        static const u_char tunnelled[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0,0 };
-       int n, size;
-       querybuf buf;
+       int n;
+       socklen_t size;
+       union
+       {
+         querybuf *buf;
+         u_char *ptr;
+       } buf;
+       querybuf *orig_buf;
        register struct hostent *hp;
-       char qbuf[MAXDNAME+1], *qp;
+       char qbuf[MAXDNAME+1], *qp = NULL;
 #ifdef SUNSECURITY
        register struct hostent *rhp;
        char **haddr;
        u_long old_options;
        char hname2[MAXDNAME+1];
 #endif /*SUNSECURITY*/
-       extern struct hostent *_gethtbyaddr();
 
-       if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
+       if (__res_maybe_init (&_res, 0) == -1) {
                __set_h_errno (NETDB_INTERNAL);
                return (NULL);
        }
@@ -630,19 +707,34 @@ gethostbyaddr(addr, len, af)
                                       uaddr[n] & 0xf,
                                       (uaddr[n] >> 4) & 0xf));
                }
-               strcpy(qp, "ip6.int");
+               strcpy(qp, "ip6.arpa");
                break;
        default:
                abort();
        }
-       n = res_query(qbuf, C_IN, T_PTR, (u_char *)buf.buf, sizeof buf.buf);
+
+       buf.buf = orig_buf = (querybuf *) alloca (1024);
+
+       n = __libc_res_nquery(&_res, qbuf, C_IN, T_PTR, buf.buf->buf, 1024,
+                             &buf.ptr);
+       if (n < 0 && af == AF_INET6 && (_res.options & RES_NOIP6DOTINT) == 0) {
+               strcpy(qp, "ip6.int");
+               n = __libc_res_nquery(&_res, qbuf, C_IN, T_PTR, buf.buf->buf,
+                                     buf.buf != orig_buf ? MAXPACKET : 1024,
+                                     &buf.ptr);
+       }
        if (n < 0) {
-               dprintf("res_query failed (%d)\n", n);
+               if (buf.buf != orig_buf)
+                       free (buf.buf);
+               Dprintf("res_nquery failed (%d)\n", n);
                if (errno == ECONNREFUSED)
                        return (_gethtbyaddr(addr, len, af));
                return (NULL);
        }
-       if (!(hp = getanswer(&buf, n, qbuf, T_PTR)))
+       hp = getanswer(buf.buf, n, qbuf, T_PTR);
+       if (buf.buf != orig_buf)
+               free (buf.buf);
+       if (!hp)
                return (NULL);  /* h_errno was set by getanswer() */
 #ifdef SUNSECURITY
        if (af == AF_INET) {
@@ -678,7 +770,7 @@ gethostbyaddr(addr, len, af)
 #endif /*SUNSECURITY*/
        hp->h_addrtype = af;
        hp->h_length = len;
-       bcopy(addr, host_addr, len);
+       memmove(host_addr, addr, len);
        h_addr_ptrs[0] = (char *)host_addr;
        h_addr_ptrs[1] = NULL;
        if (af == AF_INET && (_res.options & RES_USE_INET6)) {
@@ -700,6 +792,7 @@ _sethtent(f)
                rewind(hostf);
        stayopen = f;
 }
+libresolv_hidden_def (_sethtent)
 
 void
 _endhtent()
@@ -758,7 +851,7 @@ _gethtent()
                cp++;
        host.h_name = cp;
        q = host.h_aliases = host_aliases;
-       if (cp = strpbrk(cp, " \t"))
+       if ((cp = strpbrk(cp, " \t")))
                *cp++ = '\0';
        while (cp && *cp) {
                if (*cp == ' ' || *cp == '\t') {
@@ -767,19 +860,19 @@ _gethtent()
                }
                if (q < &host_aliases[MAXALIASES - 1])
                        *q++ = cp;
-               if (cp = strpbrk(cp, " \t"))
+               if ((cp = strpbrk(cp, " \t")))
                        *cp++ = '\0';
        }
        *q = NULL;
        __set_h_errno (NETDB_SUCCESS);
        return (&host);
 }
+libresolv_hidden_def (_gethtent)
 
 struct hostent *
 _gethtbyname(name)
        const char *name;
 {
-       extern struct hostent *_gethtbyname2();
        struct hostent *hp;
 
        if (_res.options & RES_USE_INET6) {
@@ -799,7 +892,7 @@ _gethtbyname2(name, af)
        register char **cp;
 
        _sethtent(0);
-       while (p = _gethtent()) {
+       while ((p = _gethtent())) {
                if (p->h_addrtype != af)
                        continue;
                if (strcasecmp(p->h_name, name) == 0)
@@ -812,21 +905,24 @@ _gethtbyname2(name, af)
        _endhtent();
        return (p);
 }
+libresolv_hidden_def (_gethtbyname2)
 
 struct hostent *
 _gethtbyaddr(addr, len, af)
        const char *addr;
-       int len, af;
+       size_t len;
+       int af;
 {
        register struct hostent *p;
 
        _sethtent(0);
-       while (p = _gethtent())
+       while ((p = _gethtent()))
                if (p->h_addrtype == af && !bcmp(p->h_addr, addr, len))
                        break;
        _endhtent();
        return (p);
 }
+libresolv_hidden_def (_gethtbyaddr)
 
 static void
 map_v4v6_address(src, dst)
@@ -838,14 +934,14 @@ map_v4v6_address(src, dst)
        int i;
 
        /* Stash a temporary copy so our caller can update in place. */
-       bcopy(src, tmp, INADDRSZ);
+       memcpy(tmp, src, 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);
+       memcpy((void*)p, tmp, INADDRSZ);
 }
 
 static void
@@ -878,7 +974,7 @@ map_v4v6_hostent(hp, bpp, lenp)
 }
 
 #ifdef RESOLVSORT
-static void
+extern void
 addrsort(ap, num)
        char **ap;
        int num;
@@ -947,7 +1043,8 @@ ht_gethostbyname(name)
 struct hostent *
 ht_gethostbyaddr(addr, len, af)
        const char *addr;
-       int len, af;
+       size_t len;
+       int af;
 {
        return (_gethtbyaddr(addr, len, af));
 }