diff options
Diffstat (limited to 'resolv/gethnamaddr.c')
-rw-r--r-- | resolv/gethnamaddr.c | 457 |
1 files changed, 328 insertions, 129 deletions
diff --git a/resolv/gethnamaddr.c b/resolv/gethnamaddr.c index 96248bc0de..35e9007ca7 100644 --- a/resolv/gethnamaddr.c +++ b/resolv/gethnamaddr.c @@ -1,8 +1,8 @@ /* - * ++Copyright++ 1985, 1988 + * ++Copyright++ 1985, 1988, 1993 * - - * Copyright (c) 1985, 1988 Regents of the University of California. - * All rights reserved. + * 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 @@ -54,7 +54,7 @@ */ #if defined(LIBC_SCCS) && !defined(lint) -static char sccsid[] = "@(#)gethostnamadr.c 6.47 (Berkeley) 6/18/92"; +static char sccsid[] = "@(#)gethostnamadr.c 8.1 (Berkeley) 6/4/93"; static char rcsid[] = "$Id$"; #endif /* LIBC_SCCS and not lint */ @@ -63,27 +63,47 @@ static char rcsid[] = "$Id$"; #include <netinet/in.h> #include <arpa/inet.h> #include <arpa/nameser.h> + +#include <stdio.h> #include <netdb.h> #include <resolv.h> -#include <stdio.h> #include <ctype.h> #include <errno.h> -#include "../conf/portability.h" +#include <syslog.h> + +#ifndef LOG_AUTH +# define LOG_AUTH 0 +#endif + +#define MULTI_PTRS_ARE_ALIASES 1 /* XXX - experimental */ + +#if defined(BSD) && (BSD >= 199103) +# include <string.h> +#else +# include "../conf/portability.h" +#endif +#if defined(USE_OPTIONS_H) +# include <../conf/options.h> +#endif #define MAXALIASES 35 #define MAXADDRS 35 +static const char AskedForGot[] = + "gethostby*.getanswer: asked for \"%s\", got \"%s\""; + static char *h_addr_ptrs[MAXADDRS + 1]; static struct hostent host; static char *host_aliases[MAXALIASES]; -static char hostbuf[BUFSIZ+1]; +static char hostbuf[8*1024]; static struct in_addr host_addr; static FILE *hostf = NULL; -static char hostaddr[MAXADDRS]; -static char *host_addrs[2]; static int stayopen = 0; -char *strpbrk(); + +#ifdef RESOLVSORT +static void addrsort __P((char **, int)); +#endif #if PACKETSZ > 1024 #define MAXPACKET PACKETSZ @@ -104,20 +124,23 @@ typedef union { extern int h_errno; static struct hostent * -getanswer(answer, anslen, iquery) - querybuf *answer; +getanswer(answer, anslen, qname, qclass, qtype) + const querybuf *answer; int anslen; - int iquery; + const char *qname; + int qclass, 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 haveanswer, had_error; + int toobig = 0; + char tbuf[MAXDNAME+1]; + host.h_name = NULL; eom = answer->buf + anslen; /* * find first satisfactory answer @@ -126,31 +149,28 @@ 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, (u_char *)bp, - buflen)) < 0) { - h_errno = NO_RECOVERY; - return ((struct hostent *) NULL); - } - cp += n + QFIXEDSZ; - host.h_name = bp; - n = strlen(bp) + 1; - 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); + } + if ((n = dn_expand(answer->buf, eom, cp, bp, buflen)) < 0) { + h_errno = NO_RECOVERY; + return (NULL); + } + cp += n + QFIXEDSZ; + if (qtype == T_A) { + /* 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; @@ -161,91 +181,174 @@ getanswer(answer, anslen, iquery) host.h_addr_list = h_addr_ptrs; #endif haveanswer = 0; - while (--ancount >= 0 && cp < eom) { - if ((n = dn_expand((u_char *)answer->buf, (u_char *)eom, - (u_char *)cp, (u_char *)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) { + had_error++; + continue; + } + cp += n; /* name */ type = _getshort(cp); - cp += sizeof(u_short); + cp += INT16SZ; /* type */ class = _getshort(cp); - cp += sizeof(u_short) + sizeof(u_int32_t); + cp += INT16SZ + INT32SZ; /* class, TTL */ n = _getshort(cp); - cp += sizeof(u_short); - if (type == T_CNAME) { + cp += INT16SZ; /* len */ + if (class != qclass) { + /* XXX - debug? syslog? */ cp += n; + continue; /* XXX - had_error++ ? */ + } + if (qtype == T_A && type == T_CNAME) { if (ap >= &host_aliases[MAXALIASES-1]) continue; + n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf); + if (n < 0) { + had_error++; + 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; + n = strlen(bp) + 1; /* for the \0 */ bp += n; buflen -= n; - continue; - } - if (iquery && type == T_PTR) { - if ((n = dn_expand((u_char *)answer->buf, - (u_char *)eom, (u_char *)cp, (u_char *)bp, - buflen)) < 0) { - cp += n; + /* Get canonical name. */ + n = strlen(tbuf) + 1; /* for the \0 */ + if (n > buflen) { + had_error++; continue; } - cp += n; + strcpy(bp, tbuf); host.h_name = bp; - return(&host); + 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 type %d(%s), got %d(%s)", + qtype, qname, type, bp); cp += n; - continue; + continue; /* XXX - had_error++ ? */ } - if (haveanswer) { - if (n != host.h_length) { + switch (type) { + case T_PTR: + if (strcasecmp(qname, bp) != 0) { + syslog(LOG_NOTICE|LOG_AUTH, + AskedForGot, qname, bp); cp += n; - continue; + continue; /* XXX - had_error++ ? */ + } + n = dn_expand(answer->buf, eom, cp, bp, buflen); + if (n < 0) { + 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; } - if (class != getclass) { + break; +#else + host.h_name = bp; + return (&host); +#endif + case T_A: + if (strcasecmp(host.h_name, bp) != 0) { + syslog(LOG_NOTICE|LOG_AUTH, + AskedForGot, host.h_name, bp); cp += n; - continue; + continue; /* XXX - had_error++ ? */ } - } else { - host.h_length = n; - getclass = class; - host.h_addrtype = (class == C_IN) ? AF_INET : AF_UNSPEC; - if (!iquery) { + if (haveanswer) { + if (n != host.h_length) { + cp += n; + continue; + } + } else { + register int nn; + + host.h_length = n; + host.h_addrtype = (class == C_IN) + ? AF_INET + : AF_UNSPEC; host.h_name = bp; - bp += strlen(bp) + 1; + nn = strlen(bp) + 1; /* for the \0 */ + bp += nn; + buflen -= nn; } - } - bp += sizeof(align) - ((u_int32_t)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); + if (_res.options & RES_DEBUG) + printf("size (%d) too big\n", n); #endif + had_error++; + continue; + } + if (hap >= &h_addr_ptrs[MAXADDRS-1]) { + if (_res.options & RES_DEBUG && !toobig++) + printf("Too many addresses (%d)\n", + MAXADDRS); + cp += n; + continue; + } + bcopy(cp, *hap++ = bp, n); + bp += n; + cp += n; break; - } - bcopy(cp, *hap++ = bp, n); - bp +=n; - cp += n; - haveanswer++; - } + default: + abort(); + } /*switch*/ + if (!had_error) + haveanswer++; + } /*while*/ if (haveanswer) { *ap = NULL; -#if BSD >= 43 || defined(h_addr) /* new-style hostent structure */ *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 && + qclass == C_IN && 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 +#endif /*BSD*/ + if (!host.h_name) { + n = strlen(qname) + 1; /* for the \0 */ + strcpy(bp, qname); + host.h_name = bp; + } return (&host); } else { h_errno = TRY_AGAIN; - return ((struct hostent *) NULL); + return (NULL); } } @@ -274,15 +377,15 @@ gethostbyname(name) */ if (!inet_aton(name, &host_addr)) { h_errno = HOST_NOT_FOUND; - return((struct hostent *) NULL); + return (NULL); } host.h_name = (char *)name; host.h_aliases = host_aliases; host_aliases[0] = NULL; host.h_addrtype = AF_INET; - host.h_length = sizeof(u_int32_t); + host.h_length = INT32SZ; h_addr_ptrs[0] = (char *)&host_addr; - h_addr_ptrs[1] = (char *)0; + h_addr_ptrs[1] = NULL; #if BSD >= 43 || defined(h_addr) /* new-style hostent structure */ host.h_addr_list = h_addr_ptrs; #else @@ -302,9 +405,9 @@ gethostbyname(name) if (errno == ECONNREFUSED) return (_gethtbyname(name)); else - return ((struct hostent *) NULL); + return (NULL); } - return (getanswer(&buf, n, 0)); + return (getanswer(&buf, n, name, C_IN, T_A)); } struct hostent * @@ -315,17 +418,22 @@ gethostbyaddr(addr, len, type) int n; querybuf buf; register struct hostent *hp; - char qbuf[MAXDNAME]; + char qbuf[MAXDNAME+1]; +#ifdef SUNSECURITY + register struct hostent *rhp; + char **haddr; + u_long old_options; +#endif /*SUNSECURITY*/ extern struct hostent *_gethtbyaddr(); if (type != AF_INET) - return ((struct hostent *) NULL); + 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, (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) @@ -333,31 +441,57 @@ gethostbyaddr(addr, len, type) #endif if (errno == ECONNREFUSED) return (_gethtbyaddr(addr, len, type)); - return ((struct hostent *) NULL); + return (NULL); + } + if (!(hp = getanswer(&buf, n, qbuf, C_IN, T_PTR))) + return (NULL); +#ifdef SUNSECURITY + /* + * turn off search as the name should be absolute, + * 'localhost' should be matched by defnames + */ + old_options = _res.options; + _res.options &= ~RES_DNSRCH; + _res.options |= RES_DEFNAMES; + if (!(rhp = gethostbyname(hp->h_name))) { + syslog(LOG_NOTICE|LOG_AUTH, + "gethostbyaddr: No A record for %s (verifying [%s])", + hp->h_name, inet_ntoa(*((struct in_addr *)addr))); + _res.options = old_options; + return (NULL); } - hp = getanswer(&buf, n, 1); - if (hp == NULL) - return ((struct hostent *) NULL); + _res.options = old_options; + 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]", + hp->h_name, inet_ntoa(*((struct in_addr *)addr))); + h_errno = HOST_NOT_FOUND; + return (NULL); + } +#endif /*SUNSECURITY*/ hp->h_addrtype = type; hp->h_length = len; h_addr_ptrs[0] = (char *)&host_addr; - h_addr_ptrs[1] = (char *)0; + h_addr_ptrs[1] = NULL; host_addr = *(struct in_addr *)addr; #if BSD < 43 && !defined(h_addr) /* new-style hostent structure */ hp->h_addr = h_addr_ptrs[0]; #endif - return(hp); + return (hp); } void _sethtent(f) int f; { - if (hostf == NULL) + if (!hostf) hostf = fopen(_PATH_HOSTS, "r" ); else rewind(hostf); - stayopen |= f; + stayopen = f; } void @@ -375,35 +509,36 @@ _gethtent() char *p; register char *cp, **q; - if (hostf == NULL && (hostf = fopen(_PATH_HOSTS, "r" )) == NULL) + if (!hostf && !(hostf = fopen(_PATH_HOSTS, "r" ))) return (NULL); again: - if ((p = fgets(hostbuf, BUFSIZ, hostf)) == NULL) + if (!(p = fgets(hostbuf, sizeof hostbuf, hostf))) 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 */ + if (!inet_aton(p, &host_addr)) + 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 = host_addrs; + host.h_addr_list = h_addr_ptrs; +#else + host.h_addr = h_addr_ptrs[0]; #endif - host.h_addr = hostaddr; - *((u_int32_t *)host.h_addr) = inet_addr(p); - host.h_length = sizeof (u_int32_t); + host.h_length = INT32SZ; host.h_addrtype = AF_INET; 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') { @@ -412,8 +547,7 @@ 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; @@ -455,6 +589,51 @@ _gethtbyaddr(addr, len, type) return (p); } +#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 ; j < _res.nsort; j++) + if (_res.sort_list[j].addr.s_addr == + (((struct in_addr *)(*p))->s_addr & _res.sort_list[j].mask)) + break; + aval[i] = j; + if (needsort == 0 && i > 0 && j < aval[i-1]) + needsort = i; + } + if (!needsort) + return; + + while (needsort < num) { + for (j = needsort - 1; j >= 0; j--) { + if (aval[j] > aval[j+1]) { + char *hp; + + i = aval[j]; + aval[j] = aval[j+1]; + aval[j+1] = i; + + hp = ap[j]; + ap[j] = ap[j+1]; + ap[j+1] = hp; + + } else + break; + } + needsort++; + } +} +#endif + #if defined(BSD43_BSD43_NFS) || defined(sun) /* some libc's out there are bound internally to these names (UMIPS) */ void @@ -474,7 +653,7 @@ struct hostent * ht_gethostbyname(name) char *name; { - return _gethtbyname(name); + return (_gethtbyname(name)); } struct hostent * @@ -482,13 +661,13 @@ ht_gethostbyaddr(addr, len, type) const char *addr; int len, type; { - return _gethtbyaddr(addr, len, type); + return (_gethtbyaddr(addr, len, type)); } struct hostent * gethostent() { - return _gethtent(); + return (_gethtent()); } void @@ -501,6 +680,26 @@ dns_service() dn_skipname(comp_dn, eom) const u_char *comp_dn, *eom; { - return __dn_skipname(comp_dn, eom); + return (__dn_skipname(comp_dn, eom)); } #endif /*old-style libc with yp junk in it*/ + +#ifdef ultrix +/* more icky libc packaging in ultrix */ +int +local_hostname_length(hostname) + const char *hostname; +{ + int len_host, len_domain; + + if (!*_res.defdname) + res_init(); + len_host = strlen(hostname); + len_domain = strlen(_res.defdname); + if (len_host > len_domain && + !strcasecmp(hostname + len_host - len_domain, _res.defdname) && + hostname[len_host - len_domain - 1] == '.') + return (len_host - len_domain - 1); + return (0); +} +#endif |