diff options
author | stevel@tonic-gate <none@none> | 2005-06-14 00:00:00 -0700 |
---|---|---|
committer | stevel@tonic-gate <none@none> | 2005-06-14 00:00:00 -0700 |
commit | 7c478bd95313f5f23a4c958a745db2134aa03244 (patch) | |
tree | c871e58545497667cbb4b0a4f2daf204743e1fe7 /usr/src/lib/libresolv/res_gethost.c | |
download | illumos-joyent-7c478bd95313f5f23a4c958a745db2134aa03244.tar.gz |
OpenSolaris Launch
Diffstat (limited to 'usr/src/lib/libresolv/res_gethost.c')
-rw-r--r-- | usr/src/lib/libresolv/res_gethost.c | 472 |
1 files changed, 472 insertions, 0 deletions
diff --git a/usr/src/lib/libresolv/res_gethost.c b/usr/src/lib/libresolv/res_gethost.c new file mode 100644 index 0000000000..9e20672a14 --- /dev/null +++ b/usr/src/lib/libresolv/res_gethost.c @@ -0,0 +1,472 @@ +/* + * Copyright (c) 1985, 1988 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that this notice is preserved and that due credit is given + * to the University of California at Berkeley. The name of the University + * may not be used to endorse or promote products derived from this + * software without specific prior written permission. This software + * is provided ``as is'' without express or implied warranty. + * + */ + +#pragma ident "%Z%%M% %I% %E% SMI" /* SunOS 1.11; UCB 6.32 */ + +#include "synonyms.h" + +#include <sys/param.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <ctype.h> +#include <netdb.h> +#include <stdio.h> +#include <errno.h> +#include <arpa/inet.h> +#include <arpa/nameser.h> +#include <resolv.h> +#include <syslog.h> + +/* + * When the name service switch calls libresolv, it doesn't want fallback + * to /etc/hosts, so we provide a method to turn it off. + */ +static int no_hosts_fallback = 0; + +void +__res_set_no_hosts_fallback(void) { + no_hosts_fallback = 1; +} + +static int +__res_no_hosts_fallback(void) { + return(no_hosts_fallback); +} + +static char *h_addr_ptrs[MAXADDRS + 1]; + +static struct hostent host; +static char *host_aliases[MAXALIASES]; +static char hostbuf[BUFSIZ+1]; +static struct in_addr host_addr; +static char HOSTDB[] = "/etc/hosts"; +static FILE *hostf = NULL; +static char hostaddr[MAXADDRS]; +static char *host_addrs[2]; +static int stayopen = 0; +static char *any(); + +#if PACKETSZ > 1024 +#define MAXPACKET PACKETSZ +#else +#define MAXPACKET 1024 +#endif + +typedef union { + HEADER hdr; + u_char buf[MAXPACKET]; +} querybuf; + +static union { + long al; + char ac; +} align; + + +int h_errno; + +static struct hostent * +getanswer(answer, anslen, iquery) + querybuf *answer; + int anslen; + int iquery; +{ + register HEADER *hp; + register u_char *cp; + register int n; + u_char *eom; + char *bp, **ap; + int type, class, buflen, ancount, qdcount; + int haveanswer, getclass = C_ANY; + char **hap; + + eom = answer->buf + anslen; + /* + * find first satisfactory answer + */ + hp = &answer->hdr; + 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((char *)answer->buf, eom, + cp, 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); + } + ap = host_aliases; + host.h_aliases = host_aliases; + hap = h_addr_ptrs; +#if BSD >= 43 || defined(h_addr) /* new-style hostent structure */ + host.h_addr_list = h_addr_ptrs; +#endif + haveanswer = 0; + while (--ancount >= 0 && cp < eom && haveanswer < MAXADDRS) { + if ((n = dn_expand((char *)answer->buf, eom, + cp, bp, buflen)) < 0) + break; + cp += n; + type = _getshort(cp); + cp += sizeof (u_short); + class = _getshort(cp); + cp += sizeof (u_short) + sizeof (u_long); + n = _getshort(cp); + cp += sizeof (u_short); + if (type == T_CNAME) { + cp += n; + if (ap >= &host_aliases[MAXALIASES-1]) + continue; + *ap++ = bp; + n = strlen(bp) + 1; + bp += n; + buflen -= n; + continue; + } + if (iquery && type == T_PTR) { + if ((n = dn_expand((char *)answer->buf, eom, + cp, bp, buflen)) < 0) { + cp += n; + continue; + } + cp += n; + host.h_name = bp; + return (&host); + } + if (iquery || type != T_A) { +#ifdef DEBUG + if (_res.options & RES_DEBUG) + printf("unexpected answer type %d, size %d\n", + type, n); +#endif + cp += n; + continue; + } + if (haveanswer) { + if (n != host.h_length) { + cp += n; + continue; + } + if (class != getclass) { + cp += n; + continue; + } + } else { + host.h_length = n; + getclass = class; + host.h_addrtype = (class == C_IN) ? AF_INET : AF_UNSPEC; + if (!iquery) { + host.h_name = bp; + bp += strlen(bp) + 1; + } + } + + bp += sizeof (align) - ((u_long)bp % sizeof (align)); + + if (bp + n >= &hostbuf[sizeof (hostbuf)]) { +#ifdef DEBUG + if (_res.options & RES_DEBUG) + printf("size (%d) too big\n", n); +#endif + break; + } +#ifdef SYSV + memcpy((void *)(*hap++ = bp), (void *)cp, n); +#else + bcopy(cp, *hap++ = bp, n); +#endif + bp += n; + cp += n; + haveanswer++; + } + if (haveanswer) { + *ap = NULL; +#if BSD >= 43 || defined(h_addr) /* new-style hostent structure */ + *hap = NULL; +#else + host.h_addr = h_addr_ptrs[0]; +#endif + return (&host); + } else { + h_errno = TRY_AGAIN; + return ((struct hostent *) NULL); + } +} + +struct hostent * +res_gethostbyname(name) + char *name; +{ + querybuf buf; + register char *cp; + int n; + struct hostent *hp, *gethostdomain(); + static struct hostent *_gethtbyname(); + + /* + * disallow names consisting only of digits/dots, unless + * they end in a dot. + */ + if (isdigit(name[0])) + for (cp = name; /*EMPTY*/; ++cp) { + if (!*cp) { + if (*--cp == '.') + break; + h_errno = HOST_NOT_FOUND; + return ((struct hostent *) NULL); + } + if (!isdigit(*cp) && *cp != '.') + break; + } + + if ((n = res_search(name, C_IN, T_A, buf.buf, sizeof (buf))) < 0) { +#ifdef DEBUG + if (_res.options & RES_DEBUG) + printf("res_search failed\n"); +#endif + if (errno == ECONNREFUSED) + return (_gethtbyname(name)); + else + return ((struct hostent *) NULL); + } + return (getanswer(&buf, n, 0)); +} + +static struct hostent * +_getrhbyaddr(addr, len, type) + char *addr; + int len, type; +{ + int n; + querybuf buf; + register struct hostent *hp; + char qbuf[MAXDNAME]; + static struct hostent *_gethtbyaddr(); + + if (type != AF_INET) + return ((struct hostent *) NULL); + (void) sprintf(qbuf, "%d.%d.%d.%d.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)); + if (n < 0) { +#ifdef DEBUG + if (_res.options & RES_DEBUG) + printf("res_query failed\n"); +#endif + if (errno == ECONNREFUSED) + return (_gethtbyaddr(addr, len, type)); + return ((struct hostent *) NULL); + } + hp = getanswer(&buf, n, 1); + if (hp == NULL) + return ((struct hostent *) NULL); + hp->h_addrtype = type; + hp->h_length = len; + h_addr_ptrs[0] = (char *)&host_addr; + h_addr_ptrs[1] = (char *)0; + host_addr = *(struct in_addr *)addr; + return (hp); +} + +/* + * First we get what the PTR record says, but do an extra call + * to gethostbyname() to make sure that someone is not trying to + * spoof us. Hopefully this is not done that often, so good + * performance is not really an issue. + */ +struct hostent * +res_gethostbyaddr(addr, len, type) + char *addr; + int len; + int type; +{ + char **a, hbuf[MAXHOSTNAMELEN]; + struct hostent *hp, *hp2; + + if ((hp = _getrhbyaddr(addr, len, type)) == (struct hostent *)NULL) + return ((struct hostent *)NULL); + + /* hang on to what we got as an answer */ + (void) strcpy(hbuf, hp->h_name); + + /* check to make sure by doing a forward query */ + if ((hp2 = res_gethostbyname(hbuf)) != (struct hostent *)NULL) + for (a = hp2->h_addr_list; *a; a++) +#ifdef SYSV + if (memcmp(*a, addr, hp2->h_length) == 0) +#else + if (bcmp(*a, addr, hp2->h_length) == 0) +#endif + return (hp2); + + /* + * we've been spoofed, make sure to log it. + * XXX - syslog needs a security priority level. + */ + syslog(LOG_NOTICE, "gethostbyaddr: %s != %s", hbuf, + inet_ntoa(*(struct in_addr *)addr)); + return ((struct hostent *)NULL); +} + +static +_sethtent(f) + int f; +{ + if (__res_no_hosts_fallback()) return(0); + + if (hostf == NULL) + hostf = fopen(HOSTDB, "r"); + else + rewind(hostf); + stayopen |= f; +} + +static +_endhtent() +{ + if (__res_no_hosts_fallback()) return(0); + + if (hostf && !stayopen) { + (void) fclose(hostf); + hostf = NULL; + } +} + +static struct hostent * +_gethtent() +{ + char *p; + register char *cp, **q; + + if (__res_no_hosts_fallback()) return(NULL); + + if (hostf == NULL && (hostf = fopen(HOSTDB, "r")) == NULL) + return (NULL); +again: + if ((p = fgets(hostbuf, BUFSIZ, hostf)) == NULL) + return (NULL); + if (*p == '#') + goto again; + cp = any(p, "#\n"); + if (cp == NULL) + goto again; + *cp = '\0'; + cp = any(p, " \t"); + if (cp == NULL) + goto again; + *cp++ = '\0'; + /* THIS STUFF IS INTERNET SPECIFIC */ +#if BSD >= 43 || defined(h_addr) /* new-style hostent structure */ + host.h_addr_list = host_addrs; +#endif + host.h_addr = hostaddr; + *((u_long *)host.h_addr) = inet_addr(p); + host.h_length = sizeof (u_long); + host.h_addrtype = AF_INET; + while (*cp == ' ' || *cp == '\t') + cp++; + host.h_name = cp; + q = host.h_aliases = host_aliases; + cp = any(cp, " \t"); + if (cp != NULL) + *cp++ = '\0'; + while (cp && *cp) { + if (*cp == ' ' || *cp == '\t') { + cp++; + continue; + } + if (q < &host_aliases[MAXALIASES - 1]) + *q++ = cp; + cp = any(cp, " \t"); + if (cp != NULL) + *cp++ = '\0'; + } + *q = NULL; + return (&host); +} + +static char * +any(cp, match) + register char *cp; + char *match; +{ + register char *mp, c; + + while (c = *cp) { + for (mp = match; *mp; mp++) + if (*mp == c) + return (cp); + cp++; + } + return ((char *)0); +} + +static struct hostent * +_gethtbyname(name) + char *name; +{ + 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; + } +found: + _endhtent(); + return (p); +} + +static struct hostent * +_gethtbyaddr(addr, len, type) + char *addr; + int len, type; +{ + register struct hostent *p; + + _sethtent(0); + while (p = _gethtent()) +#ifdef SYSV + if (p->h_addrtype == type && !memcmp(p->h_addr, addr, len)) +#else + if (p->h_addrtype == type && !bcmp(p->h_addr, addr, len)) +#endif + break; + _endhtent(); + return (p); +} |