[alt.sources] resolv+ -- improved resolver library -- part02/02

wisner@ims.alaska.edu (Bill Wisner) (04/23/91)

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 2 (of 2)."
# Contents:  include/arpa/nameser.h named/gethostnamadr.c res_debug.c
#   res_query.c res_send.c
# Wrapped by wisner@hayes on Mon Apr 22 18:43:58 1991
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'include/arpa/nameser.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'include/arpa/nameser.h'\"
else
echo shar: Extracting \"'include/arpa/nameser.h'\" \(7620 characters\)
sed "s/^X//" >'include/arpa/nameser.h' <<'END_OF_FILE'
X/*
X * Copyright (c) 1983, 1989 Regents of the University of California.
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms are permitted
X * provided that: (1) source distributions retain this entire copyright
X * notice and comment, and (2) distributions including binaries display
X * the following acknowledgement:  ``This product includes software
X * developed by the University of California, Berkeley and its contributors''
X * in the documentation or other materials provided with the distribution
X * and in all advertising materials mentioning features or use of this
X * software. Neither the name of the University nor the names of its
X * contributors may be used to endorse or promote products derived
X * from this software without specific prior written permission.
X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
X * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
X *
X *	@(#)nameser.h	5.24 (Berkeley) 6/1/90
X */
X
X/*
X * Define constants based on rfc883
X */
X#define PACKETSZ	512		/* maximum packet size */
X#define MAXDNAME	256		/* maximum domain name */
X#define MAXCDNAME	255		/* maximum compressed domain name */
X#define MAXLABEL	63		/* maximum length of domain label */
X	/* Number of bytes of fixed size data in query structure */
X#define QFIXEDSZ	4
X	/* number of bytes of fixed size data in resource record */
X#define RRFIXEDSZ	10
X
X/*
X * Internet nameserver port number
X */
X#define NAMESERVER_PORT	53
X
X/*
X * Currently defined opcodes
X */
X#define QUERY		0x0		/* standard query */
X#define IQUERY		0x1		/* inverse query */
X#define STATUS		0x2		/* nameserver status query */
X/*#define xxx		0x3		/* 0x3 reserved */
X	/* non standard */
X#define UPDATEA		0x9		/* add resource record */
X#define UPDATED		0xa		/* delete a specific resource record */
X#define UPDATEDA	0xb		/* delete all nemed resource record */
X#define UPDATEM		0xc		/* modify a specific resource record */
X#define UPDATEMA	0xd		/* modify all named resource record */
X
X#define ZONEINIT	0xe		/* initial zone transfer */
X#define ZONEREF		0xf		/* incremental zone referesh */
X
X/*
X * Currently defined response codes
X */
X#define NOERROR		0		/* no error */
X#define FORMERR		1		/* format error */
X#define SERVFAIL	2		/* server failure */
X#define NXDOMAIN	3		/* non existent domain */
X#define NOTIMP		4		/* not implemented */
X#define REFUSED		5		/* query refused */
X	/* non standard */
X#define NOCHANGE	0xf		/* update failed to change db */
X
X/*
X * Type values for resources and queries
X */
X#define T_A		1		/* host address */
X#define T_NS		2		/* authoritative server */
X#define T_MD		3		/* mail destination */
X#define T_MF		4		/* mail forwarder */
X#define T_CNAME		5		/* connonical name */
X#define T_SOA		6		/* start of authority zone */
X#define T_MB		7		/* mailbox domain name */
X#define T_MG		8		/* mail group member */
X#define T_MR		9		/* mail rename name */
X#define T_NULL		10		/* null resource record */
X#define T_WKS		11		/* well known service */
X#define T_PTR		12		/* domain name pointer */
X#define T_HINFO		13		/* host information */
X#define T_MINFO		14		/* mailbox information */
X#define T_MX		15		/* mail routing information */
X#define T_TXT		16		/* text strings */
X	/* non standard */
X#define T_UINFO		100		/* user (finger) information */
X#define T_UID		101		/* user ID */
X#define T_GID		102		/* group ID */
X#define T_UNSPEC	103		/* Unspecified format (binary data) */
X	/* Query type values which do not appear in resource records */
X#define T_AXFR		252		/* transfer zone of authority */
X#define T_MAILB		253		/* transfer mailbox records */
X#define T_MAILA		254		/* transfer mail agent records */
X#define T_ANY		255		/* wildcard match */
X
X/*
X * Values for class field
X */
X
X#define C_IN		1		/* the arpa internet */
X#define C_CHAOS		3		/* for chaos net at MIT */
X#define C_HS		4		/* for Hesiod name server at MIT */
X	/* Query class values which do not appear in resource records */
X#define C_ANY		255		/* wildcard match */
X
X/*
X * Status return codes for T_UNSPEC conversion routines
X */
X#define CONV_SUCCESS 0
X#define CONV_OVERFLOW -1
X#define CONV_BADFMT -2
X#define CONV_BADCKSUM -3
X#define CONV_BADBUFLEN -4
X
X#ifndef BYTE_ORDER
X#define	LITTLE_ENDIAN	1234	/* least-significant byte first (vax) */
X#define	BIG_ENDIAN	4321	/* most-significant byte first (IBM, net) */
X#define	PDP_ENDIAN	3412	/* LSB first in word, MSW first in long (pdp) */
X
X#if defined(vax) || defined(ns32000) || defined(sun386) || defined(MIPSEL) || \
X    defined(BIT_ZERO_ON_RIGHT)
X#define BYTE_ORDER	LITTLE_ENDIAN
X
X#endif
X#if defined(sel) || defined(pyr) || defined(mc68000) || defined(sparc) || \
X    defined(is68k) || defined(tahoe) || defined(ibm032) || defined(ibm370) || \
X    defined(MIPSEB) || defined (BIT_ZERO_ON_LEFT)
X#define BYTE_ORDER	BIG_ENDIAN
X#endif
X#endif /* BYTE_ORDER */
X
X#ifndef BYTE_ORDER
X	/* you must determine what the correct bit order is for your compiler */
X	UNDEFINED_BIT_ORDER;
X#endif
X/*
X * Structure for query header, the order of the fields is machine and
X * compiler dependent, in our case, the bits within a byte are assignd 
X * least significant first, while the order of transmition is most 
X * significant first.  This requires a somewhat confusing rearrangement.
X */
X
Xtypedef struct {
X	u_short	id;		/* query identification number */
X#if BYTE_ORDER == BIG_ENDIAN
X			/* fields in third byte */
X	u_char	qr:1;		/* response flag */
X	u_char	opcode:4;	/* purpose of message */
X	u_char	aa:1;		/* authoritive answer */
X	u_char	tc:1;		/* truncated message */
X	u_char	rd:1;		/* recursion desired */
X			/* fields in fourth byte */
X	u_char	ra:1;		/* recursion available */
X	u_char	pr:1;		/* primary server required (non standard) */
X	u_char	unused:2;	/* unused bits */
X	u_char	rcode:4;	/* response code */
X#endif
X#if BYTE_ORDER == LITTLE_ENDIAN || BYTE_ORDER == PDP_ENDIAN
X			/* fields in third byte */
X	u_char	rd:1;		/* recursion desired */
X	u_char	tc:1;		/* truncated message */
X	u_char	aa:1;		/* authoritive answer */
X	u_char	opcode:4;	/* purpose of message */
X	u_char	qr:1;		/* response flag */
X			/* fields in fourth byte */
X	u_char	rcode:4;	/* response code */
X	u_char	unused:2;	/* unused bits */
X	u_char	pr:1;		/* primary server required (non standard) */
X	u_char	ra:1;		/* recursion available */
X#endif
X			/* remaining bytes */
X	u_short	qdcount;	/* number of question entries */
X	u_short	ancount;	/* number of answer entries */
X	u_short	nscount;	/* number of authority entries */
X	u_short	arcount;	/* number of resource entries */
X} HEADER;
X
X/*
X * Defines for handling compressed domain names
X */
X#define INDIR_MASK	0xc0
X
X/*
X * Structure for passing resource records around.
X */
Xstruct rrec {
X	short	r_zone;			/* zone number */
X	short	r_class;		/* class number */
X	short	r_type;			/* type number */
X	u_long	r_ttl;			/* time to live */
X	int	r_size;			/* size of data area */
X	char	*r_data;		/* pointer to data */
X};
X
Xextern	u_short	_getshort();
Xextern	u_long	_getlong();
X
X/*
X * Inline versions of get/put short/long.
X * Pointer is advanced; we assume that both arguments
X * are lvalues and will already be in registers.
X * cp MUST be u_char *.
X */
X#define GETSHORT(s, cp) { \
X	(s) = *(cp)++ << 8; \
X	(s) |= *(cp)++; \
X}
X
X#define GETLONG(l, cp) { \
X	(l) = *(cp)++ << 8; \
X	(l) |= *(cp)++; (l) <<= 8; \
X	(l) |= *(cp)++; (l) <<= 8; \
X	(l) |= *(cp)++; \
X}
X
X
X#define PUTSHORT(s, cp) { \
X	*(cp)++ = (s) >> 8; \
X	*(cp)++ = (s); \
X}
X
X/*
X * Warning: PUTLONG destroys its first argument.
X */
X#define PUTLONG(l, cp) { \
X	(cp)[3] = l; \
X	(cp)[2] = (l >>= 8); \
X	(cp)[1] = (l >>= 8); \
X	(cp)[0] = l >> 8; \
X	(cp) += sizeof(u_long); \
X}
END_OF_FILE
if test 7620 -ne `wc -c <'include/arpa/nameser.h'`; then
    echo shar: \"'include/arpa/nameser.h'\" unpacked with wrong size!
fi
# end of 'include/arpa/nameser.h'
fi
if test -f 'named/gethostnamadr.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'named/gethostnamadr.c'\"
else
echo shar: Extracting \"'named/gethostnamadr.c'\" \(9872 characters\)
sed "s/^X//" >'named/gethostnamadr.c' <<'END_OF_FILE'
X/*
X * Copyright (c) 1985, 1988 Regents of the University of California.
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms are permitted
X * provided that the above copyright notice and this paragraph are
X * duplicated in all such forms and that any documentation,
X * advertising materials, and other materials related to such
X * distribution and use acknowledge that the software was developed
X * by the University of California, Berkeley.  The name of the
X * University may not be used to endorse or promote products derived
X * from this software without specific prior written permission.
X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
X * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
X */
X
X#if defined(LIBC_SCCS) && !defined(lint)
Xstatic char sccsid[] = "@(#)gethostnamadr.c	6.39.1 (Berkeley) 1/4/90";
X#endif /* LIBC_SCCS and not lint */
X
X#include <sys/param.h>
X#include <sys/socket.h>
X#include <netinet/in.h>
X#include <ctype.h>
X#include <netdb.h>
X#include <stdio.h>
X#include <errno.h>
X#include <arpa/inet.h>
X#include <arpa/nameser.h>
X#include <resolv.h>
X
X#define	MAXALIASES	35
X#define	MAXADDRS	35
X
Xstatic char *h_addr_ptrs[MAXADDRS + 1];
X
Xstatic struct hostent host;
Xstatic char *host_aliases[MAXALIASES];
Xstatic char hostbuf[BUFSIZ+1];
Xstatic struct in_addr host_addr;
Xstatic char HOSTDB[] = "/etc/hosts";
Xstatic FILE *hostf = NULL;
Xstatic char hostaddr[MAXADDRS];
Xstatic char *host_addrs[2];
Xstatic int stayopen = 0;
Xchar *strpbrk();
X
X#if PACKETSZ > 1024
X#define	MAXPACKET	PACKETSZ
X#else
X#define	MAXPACKET	1024
X#endif
X
Xtypedef union {
X    HEADER hdr;
X    u_char buf[MAXPACKET];
X} querybuf;
X
Xtypedef union {
X    long al;
X    char ac;
X} align;
X
X
Xint h_errno;
Xextern errno;
X
Xstatic struct hostent *
Xgetanswer(answer, anslen, iquery)
X	querybuf *answer;
X	int anslen;
X	int iquery;
X{
X	register HEADER *hp;
X	register u_char *cp;
X	register int n;
X	u_char *eom;
X	char *bp, **ap;
X	int type, class, buflen, ancount, qdcount;
X	int haveanswer, getclass = C_ANY;
X	char **hap;
X
X	eom = answer->buf + anslen;
X	/*
X	 * find first satisfactory answer
X	 */
X	hp = &answer->hdr;
X	ancount = ntohs(hp->ancount);
X	qdcount = ntohs(hp->qdcount);
X	bp = hostbuf;
X	buflen = sizeof(hostbuf);
X	cp = answer->buf + sizeof(HEADER);
X	if (qdcount) {
X		if (iquery) {
X			if ((n = dn_expand((char *)answer->buf, eom,
X			     cp, bp, buflen)) < 0) {
X				h_errno = NO_RECOVERY;
X				return ((struct hostent *) NULL);
X			}
X			cp += n + QFIXEDSZ;
X			host.h_name = bp;
X			n = strlen(bp) + 1;
X			bp += n;
X			buflen -= n;
X		} else
X			cp += dn_skipname(cp, eom) + QFIXEDSZ;
X		while (--qdcount > 0)
X			cp += dn_skipname(cp, eom) + QFIXEDSZ;
X	} else if (iquery) {
X		if (hp->aa)
X			h_errno = HOST_NOT_FOUND;
X		else
X			h_errno = TRY_AGAIN;
X		return ((struct hostent *) NULL);
X	}
X	ap = host_aliases;
X	*ap = NULL;
X	host.h_aliases = host_aliases;
X	hap = h_addr_ptrs;
X	*hap = NULL;
X#if BSD >= 43 || defined(h_addr)	/* new-style hostent structure */
X	host.h_addr_list = h_addr_ptrs;
X#endif
X	haveanswer = 0;
X	while (--ancount >= 0 && cp < eom) {
X		if ((n = dn_expand((char *)answer->buf, eom, cp, bp, buflen)) < 0)
X			break;
X		cp += n;
X		type = _getshort(cp);
X 		cp += sizeof(u_short);
X		class = _getshort(cp);
X 		cp += sizeof(u_short) + sizeof(u_long);
X		n = _getshort(cp);
X		cp += sizeof(u_short);
X		if (type == T_CNAME) {
X			cp += n;
X			if (ap >= &host_aliases[MAXALIASES-1])
X				continue;
X			*ap++ = bp;
X			n = strlen(bp) + 1;
X			bp += n;
X			buflen -= n;
X			continue;
X		}
X		if (iquery && type == T_PTR) {
X			if ((n = dn_expand((char *)answer->buf, eom,
X			    cp, bp, buflen)) < 0) {
X				cp += n;
X				continue;
X			}
X			cp += n;
X			host.h_name = bp;
X			return(&host);
X		}
X		if (iquery || type != T_A)  {
X#ifdef DEBUG
X			if (_res.options & RES_DEBUG)
X				printf("unexpected answer type %d, size %d\n",
X					type, n);
X#endif
X			cp += n;
X			continue;
X		}
X		if (haveanswer) {
X			if (n != host.h_length) {
X				cp += n;
X				continue;
X			}
X			if (class != getclass) {
X				cp += n;
X				continue;
X			}
X		} else {
X			host.h_length = n;
X			getclass = class;
X			host.h_addrtype = (class == C_IN) ? AF_INET : AF_UNSPEC;
X			if (!iquery) {
X				host.h_name = bp;
X				bp += strlen(bp) + 1;
X			}
X		}
X
X		bp += sizeof(align) - ((u_long)bp % sizeof(align));
X
X		if (bp + n >= &hostbuf[sizeof(hostbuf)]) {
X#ifdef DEBUG
X			if (_res.options & RES_DEBUG)
X				printf("size (%d) too big\n", n);
X#endif
X			break;
X		}
X		bcopy(cp, *hap++ = bp, n);
X		bp +=n;
X		cp += n;
X		haveanswer++;
X	}
X	if (haveanswer) {
X		*ap = NULL;
X#if BSD >= 43 || defined(h_addr)	/* new-style hostent structure */
X		*hap = NULL;
X#else
X		host.h_addr = h_addr_ptrs[0];
X#endif
X		return (&host);
X	} else {
X		h_errno = TRY_AGAIN;
X		return ((struct hostent *) NULL);
X	}
X}
X
Xstruct hostent *
Xgethostbyname(name)
X	char *name;
X{
X	querybuf buf;
X	register char *cp;
X	register int cc;
X	int n;
X	struct hostent *hp;
X	extern struct hostent *_gethtbyname();
X
X	/*
X	 * disallow names consisting only of digits/dots, unless
X	 * they end in a dot.
X	 */
X	if (isdigit(name[0]))
X		for (cp = name;; ++cp) {
X			if (!*cp) {
X				if (*--cp == '.')
X					break;
X				/*
X				 * All-numeric, no dot at the end.
X				 * Fake up a hostent as if we'd actually
X				 * done a lookup.  What if someone types
X				 * 255.255.255.255?  The test below will
X				 * succeed spuriously... ???
X				 */
X				if ((host_addr.s_addr = inet_addr(name)) == -1) {
X					h_errno = HOST_NOT_FOUND;
X					return((struct hostent *) NULL);
X				}
X				host.h_name = name;
X				host.h_aliases = host_aliases;
X				host_aliases[0] = NULL;
X				host.h_addrtype = AF_INET;
X				host.h_length = sizeof(u_long);
X				h_addr_ptrs[0] = (char *)&host_addr;
X				h_addr_ptrs[1] = (char *)0;
X#if BSD >= 43 || defined(h_addr)	/* new-style hostent structure */
X				host.h_addr_list = h_addr_ptrs;
X#else
X				host.h_addr = h_addr_ptrs[0];
X#endif
X				return (&host);
X			}
X			if (!isdigit(*cp) && *cp != '.') 
X				break;
X		}
X
X	if ((_res.options & RES_INIT) == 0 && res_init() == -1)
X		return((struct hostent *) NULL);
X
X	cc = 0;
X	while (_res.order[cc] != RES_SERVICE_NONE) {
X	    switch (_res.order[cc]) {
X	    case RES_SERVICE_BIND:
X		if ((n = res_search(name, C_IN, T_A, buf.buf, sizeof(buf))) < 0) {
X#ifdef DEBUG
X		    if (_res.options & RES_DEBUG)
X			printf("res_search failed\n");
X#endif
X		    if (errno == ECONNREFUSED)
X		 	return (_gethtbyname(name));
X		} else
X			return (getanswer(&buf, n, 0));
X		break;
X	    case RES_SERVICE_LOCAL:
X		hp = _gethtbyname(name);
X		if (hp)
X		    return(hp);
X	    }
X	    cc++;
X	}
X	return((struct hostent *) NULL);
X}
X
Xstruct hostent *
Xgethostbyaddr(addr, len, type)
X	char *addr;
X	int len, type;
X{
X	int n;
X	querybuf buf;
X	register int cc;
X	register struct hostent *hp;
X	char qbuf[MAXDNAME];
X	extern struct hostent *_gethtbyaddr();
X	
X	if (type != AF_INET)
X		return ((struct hostent *) NULL);
X
X	if ((_res.options & RES_INIT) == 0 && res_init() == -1)
X		return((struct hostent *) NULL);
X
X	cc = 0;
X	while (_res.order[cc] != RES_SERVICE_NONE) {
X	    switch (_res.order[cc]) {
X	    case RES_SERVICE_BIND:
X		(void)sprintf(qbuf, "%u.%u.%u.%u.in-addr.arpa",
X		    ((unsigned)addr[3] & 0xff),
X		    ((unsigned)addr[2] & 0xff),
X		    ((unsigned)addr[1] & 0xff),
X		    ((unsigned)addr[0] & 0xff));
X		n = res_query(qbuf, C_IN, T_PTR, (char *)&buf, sizeof(buf));
X		if (n < 0) {
X#ifdef DEBUG
X		    if (_res.options & RES_DEBUG)
X			printf("res_query failed\n");
X#endif
X		    if (errno == ECONNREFUSED)
X			return (_gethtbyaddr(addr, len, type));
X		    break;
X		}
X		hp = getanswer(&buf, n, 1);
X		if (hp == NULL)
X		    return ((struct hostent *) NULL);
X		hp->h_addrtype = type;
X		hp->h_length = len;
X		h_addr_ptrs[0] = (char *)&host_addr;
X		h_addr_ptrs[1] = (char *)0;
X		host_addr = *(struct in_addr *)addr;
X#if BSD < 43 && !defined(h_addr)	/* new-style hostent structure */
X		hp->h_addr = h_addr_ptrs[0];
X#endif
X		return(hp);
X		break;
X	    case RES_SERVICE_LOCAL:
X		hp = _gethtbyaddr(addr, len, type);
X		if (hp)
X		    return hp;
X	    }
X	    cc++;
X	}
X	return((struct hostent *)NULL);
X}
X
X_sethtent(f)
X	int f;
X{
X	if (hostf == NULL)
X		hostf = fopen(HOSTDB, "r" );
X	else
X		rewind(hostf);
X	stayopen |= f;
X}
X
X_endhtent()
X{
X	if (hostf && !stayopen) {
X		(void) fclose(hostf);
X		hostf = NULL;
X	}
X}
X
Xstruct hostent *
X_gethtent()
X{
X	char *p;
X	register char *cp, **q;
X
X	if (hostf == NULL && (hostf = fopen(HOSTDB, "r" )) == NULL)
X		return (NULL);
Xagain:
X	if ((p = fgets(hostbuf, BUFSIZ, hostf)) == NULL)
X		return (NULL);
X	if (*p == '#')
X		goto again;
X	cp = strpbrk(p, "#\n");
X	if (cp == NULL)
X		goto again;
X	*cp = '\0';
X	cp = strpbrk(p, " \t");
X	if (cp == NULL)
X		goto again;
X	*cp++ = '\0';
X	/* THIS STUFF IS INTERNET SPECIFIC */
X#if BSD >= 43 || defined(h_addr)	/* new-style hostent structure */
X	host.h_addr_list = host_addrs;
X#endif
X	host.h_addr = hostaddr;
X	*((u_long *)host.h_addr) = inet_addr(p);
X	host.h_length = sizeof (u_long);
X	host.h_addrtype = AF_INET;
X	while (*cp == ' ' || *cp == '\t')
X		cp++;
X	host.h_name = cp;
X	q = host.h_aliases = host_aliases;
X	cp = strpbrk(cp, " \t");
X	if (cp != NULL) 
X		*cp++ = '\0';
X	while (cp && *cp) {
X		if (*cp == ' ' || *cp == '\t') {
X			cp++;
X			continue;
X		}
X		if (q < &host_aliases[MAXALIASES - 1])
X			*q++ = cp;
X		cp = strpbrk(cp, " \t");
X		if (cp != NULL)
X			*cp++ = '\0';
X	}
X	*q = NULL;
X	return (&host);
X}
X
Xstruct hostent *
X_gethtbyname(name)
X	char *name;
X{
X	register struct hostent *p;
X	register char **cp;
X	
X	_sethtent(0);
X	while (p = _gethtent()) {
X		if (strcasecmp(p->h_name, name) == 0)
X			break;
X		for (cp = p->h_aliases; *cp != 0; cp++)
X			if (strcasecmp(*cp, name) == 0)
X				goto found;
X	}
Xfound:
X	_endhtent();
X	return (p);
X}
X
Xstruct hostent *
X_gethtbyaddr(addr, len, type)
X	char *addr;
X	int len, type;
X{
X	register struct hostent *p;
X
X	_sethtent(0);
X	while (p = _gethtent())
X		if (p->h_addrtype == type && !bcmp(p->h_addr, addr, len))
X			break;
X	_endhtent();
X	return (p);
X}
END_OF_FILE
if test 9872 -ne `wc -c <'named/gethostnamadr.c'`; then
    echo shar: \"'named/gethostnamadr.c'\" unpacked with wrong size!
fi
# end of 'named/gethostnamadr.c'
fi
if test -f 'res_debug.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'res_debug.c'\"
else
echo shar: Extracting \"'res_debug.c'\" \(10432 characters\)
sed "s/^X//" >'res_debug.c' <<'END_OF_FILE'
X/*-
X * Copyright (c) 1985, 1990 Regents of the University of California.
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms are permitted provided
X * that: (1) source distributions retain this entire copyright notice and
X * comment, and (2) distributions including binaries display the following
X * acknowledgement:  ``This product includes software developed by the
X * University of California, Berkeley and its contributors'' in the
X * documentation or other materials provided with the distribution and in
X * all advertising materials mentioning features or use of this software.
X * Neither the name of the University nor the names of its contributors may
X * be used to endorse or promote products derived from this software without
X * specific prior written permission.
X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
X * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
X * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
X *
X *	@(#)res_debug.c	5.30 (Berkeley) 6/27/90
X */
X
X#if defined(LIBC_SCCS) && !defined(lint)
Xstatic char sccsid[] = "@(#)res_debug.c	5.30 (Berkeley) 6/27/90";
X#endif /* LIBC_SCCS and not lint */
X
X#include <sys/types.h>
X#include <netinet/in.h>
X#include <stdio.h>
X#include <arpa/nameser.h>
X
Xextern char *p_cdname(), *p_rr(), *p_type(), *p_class(), *p_time();
Xextern char *inet_ntoa();
X
Xchar *_res_opcodes[] = {
X	"QUERY",
X	"IQUERY",
X	"CQUERYM",
X	"CQUERYU",
X	"4",
X	"5",
X	"6",
X	"7",
X	"8",
X	"UPDATEA",
X	"UPDATED",
X	"UPDATEDA",
X	"UPDATEM",
X	"UPDATEMA",
X	"ZONEINIT",
X	"ZONEREF",
X};
X
Xchar *_res_resultcodes[] = {
X	"NOERROR",
X	"FORMERR",
X	"SERVFAIL",
X	"NXDOMAIN",
X	"NOTIMP",
X	"REFUSED",
X	"6",
X	"7",
X	"8",
X	"9",
X	"10",
X	"11",
X	"12",
X	"13",
X	"14",
X	"NOCHANGE",
X};
X
Xp_query(msg)
X	char *msg;
X{
X	fp_query(msg,stdout);
X}
X
X/*
X * Print the contents of a query.
X * This is intended to be primarily a debugging routine.
X */
Xfp_query(msg,file)
X	char *msg;
X	FILE *file;
X{
X	register char *cp;
X	register HEADER *hp;
X	register int n;
X
X	/*
X	 * Print header fields.
X	 */
X	hp = (HEADER *)msg;
X	cp = msg + sizeof(HEADER);
X	fprintf(file,"HEADER:\n");
X	fprintf(file,"\topcode = %s", _res_opcodes[hp->opcode]);
X	fprintf(file,", id = %d", ntohs(hp->id));
X	fprintf(file,", rcode = %s\n", _res_resultcodes[hp->rcode]);
X	fprintf(file,"\theader flags: ");
X	if (hp->qr)
X		fprintf(file," qr");
X	if (hp->aa)
X		fprintf(file," aa");
X	if (hp->tc)
X		fprintf(file," tc");
X	if (hp->rd)
X		fprintf(file," rd");
X	if (hp->ra)
X		fprintf(file," ra");
X	if (hp->pr)
X		fprintf(file," pr");
X	fprintf(file,"\n\tqdcount = %d", ntohs(hp->qdcount));
X	fprintf(file,", ancount = %d", ntohs(hp->ancount));
X	fprintf(file,", nscount = %d", ntohs(hp->nscount));
X	fprintf(file,", arcount = %d\n\n", ntohs(hp->arcount));
X	/*
X	 * Print question records.
X	 */
X	if (n = ntohs(hp->qdcount)) {
X		fprintf(file,"QUESTIONS:\n");
X		while (--n >= 0) {
X			fprintf(file,"\t");
X			cp = p_cdname(cp, msg, file);
X			if (cp == NULL)
X				return;
X			fprintf(file,", type = %s", p_type(_getshort(cp)));
X			cp += sizeof(u_short);
X			fprintf(file,", class = %s\n\n", p_class(_getshort(cp)));
X			cp += sizeof(u_short);
X		}
X	}
X	/*
X	 * Print authoritative answer records
X	 */
X	if (n = ntohs(hp->ancount)) {
X		fprintf(file,"ANSWERS:\n");
X		while (--n >= 0) {
X			fprintf(file,"\t");
X			cp = p_rr(cp, msg, file);
X			if (cp == NULL)
X				return;
X		}
X	}
X	/*
X	 * print name server records
X	 */
X	if (n = ntohs(hp->nscount)) {
X		fprintf(file,"NAME SERVERS:\n");
X		while (--n >= 0) {
X			fprintf(file,"\t");
X			cp = p_rr(cp, msg, file);
X			if (cp == NULL)
X				return;
X		}
X	}
X	/*
X	 * print additional records
X	 */
X	if (n = ntohs(hp->arcount)) {
X		fprintf(file,"ADDITIONAL RECORDS:\n");
X		while (--n >= 0) {
X			fprintf(file,"\t");
X			cp = p_rr(cp, msg, file);
X			if (cp == NULL)
X				return;
X		}
X	}
X}
X
Xchar *
Xp_cdname(cp, msg, file)
X	char *cp, *msg;
X	FILE *file;
X{
X	char name[MAXDNAME];
X	int n;
X
X	if ((n = dn_expand(msg, msg + 512, cp, name, sizeof(name))) < 0)
X		return (NULL);
X	if (name[0] == '\0') {
X		name[0] = '.';
X		name[1] = '\0';
X	}
X	fputs(name, file);
X	return (cp + n);
X}
X
X/*
X * Print resource record fields in human readable form.
X */
Xchar *
Xp_rr(cp, msg, file)
X	char *cp, *msg;
X	FILE *file;
X{
X	int type, class, dlen, n, c;
X	struct in_addr inaddr;
X	char *cp1, *cp2;
X
X	if ((cp = p_cdname(cp, msg, file)) == NULL)
X		return (NULL);			/* compression error */
X	fprintf(file,"\n\ttype = %s", p_type(type = _getshort(cp)));
X	cp += sizeof(u_short);
X	fprintf(file,", class = %s", p_class(class = _getshort(cp)));
X	cp += sizeof(u_short);
X	fprintf(file,", ttl = %s", p_time(_getlong(cp)));
X	cp += sizeof(u_long);
X	fprintf(file,", dlen = %d\n", dlen = _getshort(cp));
X	cp += sizeof(u_short);
X	cp1 = cp;
X	/*
X	 * Print type specific data, if appropriate
X	 */
X	switch (type) {
X	case T_A:
X		switch (class) {
X		case C_IN:
X		case C_HS:
X			bcopy(cp, (char *)&inaddr, sizeof(inaddr));
X			if (dlen == 4) {
X				fprintf(file,"\tinternet address = %s\n",
X					inet_ntoa(inaddr));
X				cp += dlen;
X			} else if (dlen == 7) {
X				fprintf(file,"\tinternet address = %s",
X					inet_ntoa(inaddr));
X				fprintf(file,", protocol = %d", cp[4]);
X				fprintf(file,", port = %d\n",
X					(cp[5] << 8) + cp[6]);
X				cp += dlen;
X			}
X			break;
X		default:
X			cp += dlen;
X		}
X		break;
X	case T_CNAME:
X	case T_MB:
X	case T_MG:
X	case T_MR:
X	case T_NS:
X	case T_PTR:
X		fprintf(file,"\tdomain name = ");
X		cp = p_cdname(cp, msg, file);
X		fprintf(file,"\n");
X		break;
X
X	case T_HINFO:
X		if (n = *cp++) {
X			fprintf(file,"\tCPU=%.*s\n", n, cp);
X			cp += n;
X		}
X		if (n = *cp++) {
X			fprintf(file,"\tOS=%.*s\n", n, cp);
X			cp += n;
X		}
X		break;
X
X	case T_SOA:
X		fprintf(file,"\torigin = ");
X		cp = p_cdname(cp, msg, file);
X		fprintf(file,"\n\tmail addr = ");
X		cp = p_cdname(cp, msg, file);
X		fprintf(file,"\n\tserial = %ld", _getlong(cp));
X		cp += sizeof(u_long);
X		fprintf(file,"\n\trefresh = %s", p_time(_getlong(cp)));
X		cp += sizeof(u_long);
X		fprintf(file,"\n\tretry = %s", p_time(_getlong(cp)));
X		cp += sizeof(u_long);
X		fprintf(file,"\n\texpire = %s", p_time(_getlong(cp)));
X		cp += sizeof(u_long);
X		fprintf(file,"\n\tmin = %s\n", p_time(_getlong(cp)));
X		cp += sizeof(u_long);
X		break;
X
X	case T_MX:
X		fprintf(file,"\tpreference = %ld,",_getshort(cp));
X		cp += sizeof(u_short);
X		fprintf(file," name = ");
X		cp = p_cdname(cp, msg, file);
X		break;
X
X  	case T_TXT:
X		(void) fputs("\t\"", file);
X		cp2 = cp1 + dlen;
X		while (cp < cp2) {
X			if (n = (unsigned char) *cp++) {
X				for (c = n; c > 0 && cp < cp2; c--)
X					if (*cp == '\n') {
X					    (void) putc('\\', file);
X					    (void) putc(*cp++, file);
X					} else
X					    (void) putc(*cp++, file);
X			}
X		}
X		(void) fputs("\"\n", file);
X  		break;
X
X	case T_MINFO:
X		fprintf(file,"\trequests = ");
X		cp = p_cdname(cp, msg, file);
X		fprintf(file,"\n\terrors = ");
X		cp = p_cdname(cp, msg, file);
X		break;
X
X	case T_UINFO:
X		fprintf(file,"\t%s\n", cp);
X		cp += dlen;
X		break;
X
X	case T_UID:
X	case T_GID:
X		if (dlen == 4) {
X			fprintf(file,"\t%ld\n", _getlong(cp));
X			cp += sizeof(int);
X		}
X		break;
X
X	case T_WKS:
X		if (dlen < sizeof(u_long) + 1)
X			break;
X		bcopy(cp, (char *)&inaddr, sizeof(inaddr));
X		cp += sizeof(u_long);
X		fprintf(file,"\tinternet address = %s, protocol = %d\n\t",
X			inet_ntoa(inaddr), *cp++);
X		n = 0;
X		while (cp < cp1 + dlen) {
X			c = *cp++;
X			do {
X 				if (c & 0200)
X					fprintf(file," %d", n);
X 				c <<= 1;
X			} while (++n & 07);
X		}
X		putc('\n',file);
X		break;
X
X#ifdef ALLOW_T_UNSPEC
X	case T_UNSPEC:
X		{
X			int NumBytes = 8;
X			char *DataPtr;
X			int i;
X
X			if (dlen < NumBytes) NumBytes = dlen;
X			fprintf(file, "\tFirst %d bytes of hex data:",
X				NumBytes);
X			for (i = 0, DataPtr = cp; i < NumBytes; i++, DataPtr++)
X				fprintf(file, " %x", *DataPtr);
X			fputs("\n", file);
X			cp += dlen;
X		}
X		break;
X#endif /* ALLOW_T_UNSPEC */
X
X	default:
X		fprintf(file,"\t???\n");
X		cp += dlen;
X	}
X	if (cp != cp1 + dlen) {
X		fprintf(file,"packet size error (%#x != %#x)\n", cp, cp1+dlen);
X		cp = NULL;
X	}
X	fprintf(file,"\n");
X	return (cp);
X}
X
Xstatic	char nbuf[40];
X
X/*
X * Return a string for the type
X */
Xchar *
Xp_type(type)
X	int type;
X{
X	switch (type) {
X	case T_A:
X		return("A");
X	case T_NS:		/* authoritative server */
X		return("NS");
X	case T_CNAME:		/* canonical name */
X		return("CNAME");
X	case T_SOA:		/* start of authority zone */
X		return("SOA");
X	case T_MB:		/* mailbox domain name */
X		return("MB");
X	case T_MG:		/* mail group member */
X		return("MG");
X	case T_MR:		/* mail rename name */
X		return("MR");
X	case T_NULL:		/* null resource record */
X		return("NULL");
X	case T_WKS:		/* well known service */
X		return("WKS");
X	case T_PTR:		/* domain name pointer */
X		return("PTR");
X	case T_HINFO:		/* host information */
X		return("HINFO");
X	case T_MINFO:		/* mailbox information */
X		return("MINFO");
X	case T_MX:		/* mail routing info */
X		return("MX");
X	case T_TXT:		/* text */
X		return("TXT");
X	case T_AXFR:		/* zone transfer */
X		return("AXFR");
X	case T_MAILB:		/* mail box */
X		return("MAILB");
X	case T_MAILA:		/* mail address */
X		return("MAILA");
X	case T_ANY:		/* matches any type */
X		return("ANY");
X	case T_UINFO:
X		return("UINFO");
X	case T_UID:
X		return("UID");
X	case T_GID:
X		return("GID");
X#ifdef ALLOW_T_UNSPEC
X	case T_UNSPEC:
X		return("UNSPEC");
X#endif /* ALLOW_T_UNSPEC */
X	default:
X		(void)sprintf(nbuf, "%d", type);
X		return(nbuf);
X	}
X}
X
X/*
X * Return a mnemonic for class
X */
Xchar *
Xp_class(class)
X	int class;
X{
X
X	switch (class) {
X	case C_IN:		/* internet class */
X		return("IN");
X	case C_HS:		/* hesiod class */
X		return("HS");
X	case C_ANY:		/* matches any class */
X		return("ANY");
X	default:
X		(void)sprintf(nbuf, "%d", class);
X		return(nbuf);
X	}
X}
X
X/*
X * Return a mnemonic for a time to live
X */
Xchar *
Xp_time(value)
X	u_long value;
X{
X	int secs, mins, hours;
X	register char *p;
X
X	if (value == 0) {
X		strcpy(nbuf, "0 secs");
X		return(nbuf);
X	}
X
X	secs = value % 60;
X	value /= 60;
X	mins = value % 60;
X	value /= 60;
X	hours = value % 24;
X	value /= 24;
X
X#define	PLURALIZE(x)	x, (x == 1) ? "" : "s"
X	p = nbuf;
X	if (value) {
X		(void)sprintf(p, "%d day%s", PLURALIZE(value));
X		while (*++p);
X	}
X	if (hours) {
X		if (value)
X			*p++ = ' ';
X		(void)sprintf(p, "%d hour%s", PLURALIZE(hours));
X		while (*++p);
X	}
X	if (mins) {
X		if (value || hours)
X			*p++ = ' ';
X		(void)sprintf(p, "%d min%s", PLURALIZE(mins));
X		while (*++p);
X	}
X	if (secs || ! (value || hours || mins)) {
X		if (value || hours || mins)
X			*p++ = ' ';
X		(void)sprintf(p, "%d sec%s", PLURALIZE(secs));
X	}
X	return(nbuf);
X}
END_OF_FILE
if test 10432 -ne `wc -c <'res_debug.c'`; then
    echo shar: \"'res_debug.c'\" unpacked with wrong size!
fi
# end of 'res_debug.c'
fi
if test -f 'res_query.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'res_query.c'\"
else
echo shar: Extracting \"'res_query.c'\" \(7583 characters\)
sed "s/^X//" >'res_query.c' <<'END_OF_FILE'
X/*
X * Copyright (c) 1988 Regents of the University of California.
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms are permitted
X * provided that: (1) source distributions retain this entire copyright
X * notice and comment, and (2) distributions including binaries display
X * the following acknowledgement:  ``This product includes software
X * developed by the University of California, Berkeley and its contributors''
X * in the documentation or other materials provided with the distribution
X * and in all advertising materials mentioning features or use of this
X * software. Neither the name of the University nor the names of its
X * contributors may be used to endorse or promote products derived
X * from this software without specific prior written permission.
X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
X * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
X */
X
X#if defined(LIBC_SCCS) && !defined(lint)
Xstatic char sccsid[] = "@(#)res_query.c	5.7 (Berkeley) 6/1/90";
X#endif /* LIBC_SCCS and not lint */
X
X#include <sys/param.h>
X#include <sys/socket.h>
X#include <netinet/in.h>
X#include <ctype.h>
X#include <netdb.h>
X#include <stdio.h>
X#include <errno.h>
X#include <string.h>
X#include <arpa/inet.h>
X#include <arpa/nameser.h>
X#include <resolv.h>
X
X#if PACKETSZ > 1024
X#define MAXPACKET	PACKETSZ
X#else
X#define MAXPACKET	1024
X#endif
X
Xextern int errno;
Xint h_errno;
X
X/*
X * Formulate a normal query, send, and await answer.
X * Returned answer is placed in supplied buffer "answer".
X * Perform preliminary check of answer, returning success only
X * if no error is indicated and the answer count is nonzero.
X * Return the size of the response on success, -1 on error.
X * Error number is left in h_errno.
X * Caller must parse answer and determine whether it answers the question.
X */
Xres_query(name, class, type, answer, anslen)
X	char *name;		/* domain name */
X	int class, type;	/* class and type of query */
X	u_char *answer;		/* buffer to put answer */
X	int anslen;		/* size of answer buffer */
X{
X	char buf[MAXPACKET];
X	HEADER *hp;
X	int n;
X
X	if ((_res.options & RES_INIT) == 0 && res_init() == -1)
X		return (-1);
X#ifdef DEBUG
X	if (_res.options & RES_DEBUG)
X		printf("res_query(%s, %d, %d)\n", name, class, type);
X#endif
X	n = res_mkquery(QUERY, name, class, type, (char *)NULL, 0, NULL,
X	    buf, sizeof(buf));
X
X	if (n <= 0) {
X#ifdef DEBUG
X		if (_res.options & RES_DEBUG)
X			printf("res_query: mkquery failed\n");
X#endif
X		h_errno = NO_RECOVERY;
X		return (n);
X	}
X	n = res_send(buf, n, answer, anslen);
X	if (n < 0) {
X#ifdef DEBUG
X		if (_res.options & RES_DEBUG)
X			printf("res_query: send error\n");
X#endif
X		h_errno = TRY_AGAIN;
X		return(n);
X	}
X
X	hp = (HEADER *) answer;
X	if (hp->rcode != NOERROR || ntohs(hp->ancount) == 0) {
X#ifdef DEBUG
X		if (_res.options & RES_DEBUG)
X			printf("rcode = %d, ancount=%d\n", hp->rcode,
X			    ntohs(hp->ancount));
X#endif
X		switch (hp->rcode) {
X			case NXDOMAIN:
X				h_errno = HOST_NOT_FOUND;
X				break;
X			case SERVFAIL:
X				h_errno = TRY_AGAIN;
X				break;
X			case NOERROR:
X				h_errno = NO_DATA;
X				break;
X			case FORMERR:
X			case NOTIMP:
X			case REFUSED:
X			default:
X				h_errno = NO_RECOVERY;
X				break;
X		}
X		return (-1);
X	}
X	return(n);
X}
X
X/*
X * Formulate a normal query, send, and retrieve answer in supplied buffer.
X * Return the size of the response on success, -1 on error.
X * If enabled, implement search rules until answer or unrecoverable failure
X * is detected.  Error number is left in h_errno.
X * Only useful for queries in the same name hierarchy as the local host
X * (not, for example, for host address-to-name lookups in domain in-addr.arpa).
X */
Xres_search(name, class, type, answer, anslen)
X	char *name;		/* domain name */
X	int class, type;	/* class and type of query */
X	u_char *answer;		/* buffer to put answer */
X	int anslen;		/* size of answer */
X{
X	register char *cp, **domain;
X	int n, ret, got_nodata = 0;
X	char *hostalias();
X
X	if ((_res.options & RES_INIT) == 0 && res_init() == -1)
X		return (-1);
X
X	errno = 0;
X	h_errno = HOST_NOT_FOUND;		/* default, if we never query */
X	for (cp = name, n = 0; *cp; cp++)
X		if (*cp == '.')
X			n++;
X	if (n == 0 && (cp = hostalias(name)))
X		return (res_query(cp, class, type, answer, anslen));
X
X	/*
X	 * We do at least one level of search if
X	 *	- there is no dot and RES_DEFNAME is set, or
X	 *	- there is at least one dot, there is no trailing dot,
X	 *	  and RES_DNSRCH is set.
X	 */
X	if ((n == 0 && _res.options & RES_DEFNAMES) ||
X	   (n != 0 && *--cp != '.' && _res.options & RES_DNSRCH))
X	     for (domain = _res.dnsrch; *domain; domain++) {
X		ret = res_querydomain(name, *domain, class, type,
X		    answer, anslen);
X		if (ret > 0)
X			return (ret);
X		/*
X		 * If no server present, give up.
X		 * If name isn't found in this domain,
X		 * keep trying higher domains in the search list
X		 * (if that's enabled).
X		 * On a NO_DATA error, keep trying, otherwise
X		 * a wildcard entry of another type could keep us
X		 * from finding this entry higher in the domain.
X		 * If we get some other error (negative answer or
X		 * server failure), then stop searching up,
X		 * but try the input name below in case it's fully-qualified.
X		 */
X		if (errno == ECONNREFUSED) {
X			h_errno = TRY_AGAIN;
X			return (-1);
X		}
X		if (h_errno == NO_DATA)
X			got_nodata++;
X		if ((h_errno != HOST_NOT_FOUND && h_errno != NO_DATA) ||
X		    (_res.options & RES_DNSRCH) == 0)
X			break;
X	}
X	/*
X	 * If the search/default failed, try the name as fully-qualified,
X	 * but only if it contained at least one dot (even trailing).
X	 * This is purely a heuristic; we assume that any reasonable query
X	 * about a top-level domain (for servers, SOA, etc) will not use
X	 * res_search.
X	 */
X	if (n && (ret = res_querydomain(name, (char *)NULL, class, type,
X	    answer, anslen)) > 0)
X		return (ret);
X	if (got_nodata)
X		h_errno = NO_DATA;
X	return (-1);
X}
X
X/*
X * Perform a call on res_query on the concatenation of name and domain,
X * removing a trailing dot from name if domain is NULL.
X */
Xres_querydomain(name, domain, class, type, answer, anslen)
X	char *name, *domain;
X	int class, type;	/* class and type of query */
X	u_char *answer;		/* buffer to put answer */
X	int anslen;		/* size of answer */
X{
X	char nbuf[2*MAXDNAME+2];
X	char *longname = nbuf;
X	int n;
X
X#ifdef DEBUG
X	if (_res.options & RES_DEBUG)
X		printf("res_querydomain(%s, %s, %d, %d)\n",
X		    name, domain, class, type);
X#endif
X	if (domain == NULL) {
X		/*
X		 * Check for trailing '.';
X		 * copy without '.' if present.
X		 */
X		n = strlen(name) - 1;
X		if (name[n] == '.' && n < sizeof(nbuf) - 1) {
X			bcopy(name, nbuf, n);
X			nbuf[n] = '\0';
X		} else
X			longname = name;
X	} else
X		(void)sprintf(nbuf, "%.*s.%.*s",
X		    MAXDNAME, name, MAXDNAME, domain);
X
X	return (res_query(longname, class, type, answer, anslen));
X}
X
Xchar *
Xhostalias(name)
X	register char *name;
X{
X	register char *C1, *C2;
X	FILE *fp;
X	char *file, *getenv(), *strcpy(), *strncpy();
X	char buf[BUFSIZ];
X	static char abuf[MAXDNAME];
X
X	file = getenv("HOSTALIASES");
X	if (file == NULL || (fp = fopen(file, "r")) == NULL)
X		return (NULL);
X	buf[sizeof(buf) - 1] = '\0';
X	while (fgets(buf, sizeof(buf), fp)) {
X		for (C1 = buf; *C1 && !isspace(*C1); ++C1);
X		if (!*C1)
X			break;
X		*C1 = '\0';
X		if (!strcasecmp(buf, name)) {
X			while (isspace(*++C1));
X			if (!*C1)
X				break;
X			for (C2 = C1 + 1; *C2 && !isspace(*C2); ++C2);
X			abuf[sizeof(abuf) - 1] = *C2 = '\0';
X			(void)strncpy(abuf, C1, sizeof(abuf) - 1);
X			fclose(fp);
X			return (abuf);
X		}
X	}
X	fclose(fp);
X	return (NULL);
X}
END_OF_FILE
if test 7583 -ne `wc -c <'res_query.c'`; then
    echo shar: \"'res_query.c'\" unpacked with wrong size!
fi
# end of 'res_query.c'
fi
if test -f 'res_send.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'res_send.c'\"
else
echo shar: Extracting \"'res_send.c'\" \(10025 characters\)
sed "s/^X//" >'res_send.c' <<'END_OF_FILE'
X/*
X * Copyright (c) 1985, 1989 Regents of the University of California.
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms are permitted
X * provided that: (1) source distributions retain this entire copyright
X * notice and comment, and (2) distributions including binaries display
X * the following acknowledgement:  ``This product includes software
X * developed by the University of California, Berkeley and its contributors''
X * in the documentation or other materials provided with the distribution
X * and in all advertising materials mentioning features or use of this
X * software. Neither the name of the University nor the names of its
X * contributors may be used to endorse or promote products derived
X * from this software without specific prior written permission.
X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
X * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
X */
X
X#if defined(LIBC_SCCS) && !defined(lint)
Xstatic char sccsid[] = "@(#)res_send.c	6.25 (Berkeley) 6/1/90";
X#endif /* LIBC_SCCS and not lint */
X
X/*
X * Send query to name server and wait for reply.
X */
X
X#include <sys/param.h>
X#include <sys/time.h>
X#include <sys/socket.h>
X#include <sys/uio.h>
X#include <netinet/in.h>
X#include <stdio.h>
X#include <errno.h>
X#include <arpa/nameser.h>
X#include <resolv.h>
X
Xextern int errno;
X
Xstatic int s = -1;	/* socket used for communications */
Xstatic struct sockaddr no_addr;
X  
X
X#ifndef FD_SET
X#define	NFDBITS		32
X#define	FD_SETSIZE	32
X#define	FD_SET(n, p)	((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
X#define	FD_CLR(n, p)	((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS)))
X#define	FD_ISSET(n, p)	((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))
X#define FD_ZERO(p)	bzero((char *)(p), sizeof(*(p)))
X#endif
X
Xres_send(buf, buflen, answer, anslen)
X	char *buf;
X	int buflen;
X	char *answer;
X	int anslen;
X{
X	register int n;
X	int try, v_circuit, resplen, ns;
X	int gotsomewhere = 0, connected = 0;
X	int connreset = 0;
X	u_short id, len;
X	char *cp;
X	fd_set dsmask;
X	struct timeval timeout;
X	HEADER *hp = (HEADER *) buf;
X	HEADER *anhp = (HEADER *) answer;
X	struct iovec iov[2];
X	int terrno = ETIMEDOUT;
X	char junk[512];
X
X#ifdef DEBUG
X	if (_res.options & RES_DEBUG) {
X		printf("res_send()\n");
X		p_query(buf);
X	}
X#endif DEBUG
X	if (!(_res.options & RES_INIT))
X		if (res_init() == -1) {
X			return(-1);
X		}
X	v_circuit = (_res.options & RES_USEVC) || buflen > PACKETSZ;
X	id = hp->id;
X	/*
X	 * Send request, RETRY times, or until successful
X	 */
X	for (try = 0; try < _res.retry; try++) {
X	   for (ns = 0; ns < _res.nscount; ns++) {
X#ifdef DEBUG
X		if (_res.options & RES_DEBUG)
X			printf("Querying server (# %d) address = %s\n", ns+1,
X			      inet_ntoa(_res.nsaddr_list[ns].sin_addr));
X#endif DEBUG
X	usevc:
X		if (v_circuit) {
X			int truncated = 0;
X
X			/*
X			 * Use virtual circuit;
X			 * at most one attempt per server.
X			 */
X			try = _res.retry;
X			if (s < 0) {
X				s = socket(AF_INET, SOCK_STREAM, 0);
X				if (s < 0) {
X					terrno = errno;
X#ifdef DEBUG
X					if (_res.options & RES_DEBUG)
X					    perror("socket (vc) failed");
X#endif DEBUG
X					continue;
X				}
X				if (connect(s, &(_res.nsaddr_list[ns]),
X				   sizeof(struct sockaddr)) < 0) {
X					terrno = errno;
X#ifdef DEBUG
X					if (_res.options & RES_DEBUG)
X					    perror("connect failed");
X#endif DEBUG
X					(void) close(s);
X					s = -1;
X					continue;
X				}
X			}
X			/*
X			 * Send length & message
X			 */
X			len = htons((u_short)buflen);
X			iov[0].iov_base = (caddr_t)&len;
X			iov[0].iov_len = sizeof(len);
X			iov[1].iov_base = buf;
X			iov[1].iov_len = buflen;
X			if (writev(s, iov, 2) != sizeof(len) + buflen) {
X				terrno = errno;
X#ifdef DEBUG
X				if (_res.options & RES_DEBUG)
X					perror("write failed");
X#endif DEBUG
X				(void) close(s);
X				s = -1;
X				continue;
X			}
X			/*
X			 * Receive length & response
X			 */
X			cp = answer;
X			len = sizeof(short);
X			while (len != 0 &&
X			    (n = read(s, (char *)cp, (int)len)) > 0) {
X				cp += n;
X				len -= n;
X			}
X			if (n <= 0) {
X				terrno = errno;
X#ifdef DEBUG
X				if (_res.options & RES_DEBUG)
X					perror("read failed");
X#endif DEBUG
X				(void) close(s);
X				s = -1;
X				/*
X				 * A long running process might get its TCP
X				 * connection reset if the remote server was
X				 * restarted.  Requery the server instead of
X				 * trying a new one.  When there is only one
X				 * server, this means that a query might work
X				 * instead of failing.  We only allow one reset
X				 * per query to prevent looping.
X				 */
X				if (terrno == ECONNRESET && !connreset) {
X					connreset = 1;
X					ns--;
X				}
X				continue;
X			}
X			cp = answer;
X			if ((resplen = ntohs(*(u_short *)cp)) > anslen) {
X#ifdef DEBUG
X				if (_res.options & RES_DEBUG)
X					fprintf(stderr, "response truncated\n");
X#endif DEBUG
X				len = anslen;
X				truncated = 1;
X			} else
X				len = resplen;
X			while (len != 0 &&
X			   (n = read(s, (char *)cp, (int)len)) > 0) {
X				cp += n;
X				len -= n;
X			}
X			if (n <= 0) {
X				terrno = errno;
X#ifdef DEBUG
X				if (_res.options & RES_DEBUG)
X					perror("read failed");
X#endif DEBUG
X				(void) close(s);
X				s = -1;
X				continue;
X			}
X			if (truncated) {
X				/*
X				 * Flush rest of answer
X				 * so connection stays in synch.
X				 */
X				anhp->tc = 1;
X				len = resplen - anslen;
X				while (len != 0) {
X					n = (len > sizeof(junk) ?
X					    sizeof(junk) : len);
X					if ((n = read(s, junk, n)) > 0)
X						len -= n;
X					else
X						break;
X				}
X			}
X		} else {
X			/*
X			 * Use datagrams.
X			 */
X			if (s < 0) {
X				s = socket(AF_INET, SOCK_DGRAM, 0);
X				if (s < 0) {
X					terrno = errno;
X#ifdef DEBUG
X					if (_res.options & RES_DEBUG)
X					    perror("socket (dg) failed");
X#endif DEBUG
X					continue;
X				}
X			}
X#if	BSD >= 43
X			/*
X			 * I'm tired of answering this question, so:
X			 * On a 4.3BSD+ machine (client and server,
X			 * actually), sending to a nameserver datagram
X			 * port with no nameserver will cause an
X			 * ICMP port unreachable message to be returned.
X			 * If our datagram socket is "connected" to the
X			 * server, we get an ECONNREFUSED error on the next
X			 * socket operation, and select returns if the
X			 * error message is received.  We can thus detect
X			 * the absence of a nameserver without timing out.
X			 * If we have sent queries to at least two servers,
X			 * however, we don't want to remain connected,
X			 * as we wish to receive answers from the first
X			 * server to respond.
X			 */
X			if (_res.nscount == 1 || (try == 0 && ns == 0)) {
X				/*
X				 * Don't use connect if we might
X				 * still receive a response
X				 * from another server.
X				 */
X				if (connected == 0) {
X					if (connect(s, &_res.nsaddr_list[ns],
X					    sizeof(struct sockaddr)) < 0) {
X#ifdef DEBUG
X						if (_res.options & RES_DEBUG)
X							perror("connect");
X#endif DEBUG
X						continue;
X					}
X					connected = 1;
X				}
X				if (send(s, buf, buflen, 0) != buflen) {
X#ifdef DEBUG
X					if (_res.options & RES_DEBUG)
X						perror("send");
X#endif DEBUG
X					continue;
X				}
X			} else {
X				/*
X				 * Disconnect if we want to listen
X				 * for responses from more than one server.
X				 */
X				if (connected) {
X					(void) connect(s, &no_addr,
X					    sizeof(no_addr));
X					connected = 0;
X				}
X#endif BSD
X				if (sendto(s, buf, buflen, 0,
X				    &_res.nsaddr_list[ns],
X				    sizeof(struct sockaddr)) != buflen) {
X#ifdef DEBUG
X					if (_res.options & RES_DEBUG)
X						perror("sendto");
X#endif DEBUG
X					continue;
X				}
X#if	BSD >= 43
X			}
X#endif
X
X			/*
X			 * Wait for reply
X			 */
X			timeout.tv_sec = (_res.retrans << try);
X			if (try > 0)
X				timeout.tv_sec /= _res.nscount;
X			if (timeout.tv_sec <= 0)
X				timeout.tv_sec = 1;
X			timeout.tv_usec = 0;
Xwait:
X			FD_ZERO(&dsmask);
X			FD_SET(s, &dsmask);
X			n = select(s+1, &dsmask, (fd_set *)NULL,
X				(fd_set *)NULL, &timeout);
X			if (n < 0) {
X#ifdef DEBUG
X				if (_res.options & RES_DEBUG)
X					perror("select");
X#endif DEBUG
X				continue;
X			}
X			if (n == 0) {
X				/*
X				 * timeout
X				 */
X#ifdef DEBUG
X				if (_res.options & RES_DEBUG)
X					printf("timeout\n");
X#endif DEBUG
X#if BSD >= 43
X				gotsomewhere = 1;
X#endif
X				continue;
X			}
X			if ((resplen = recv(s, answer, anslen, 0)) <= 0) {
X#ifdef DEBUG
X				if (_res.options & RES_DEBUG)
X					perror("recvfrom");
X#endif DEBUG
X				continue;
X			}
X			gotsomewhere = 1;
X			if (id != anhp->id) {
X				/*
X				 * response from old query, ignore it
X				 */
X#ifdef DEBUG
X				if (_res.options & RES_DEBUG) {
X					printf("old answer:\n");
X					p_query(answer);
X				}
X#endif DEBUG
X				goto wait;
X			}
X			if (!(_res.options & RES_IGNTC) && anhp->tc) {
X				/*
X				 * get rest of answer;
X				 * use TCP with same server.
X				 */
X#ifdef DEBUG
X				if (_res.options & RES_DEBUG)
X					printf("truncated answer\n");
X#endif DEBUG
X				(void) close(s);
X				s = -1;
X				v_circuit = 1;
X				goto usevc;
X			}
X		}
X#ifdef DEBUG
X		if (_res.options & RES_DEBUG) {
X			printf("got answer:\n");
X			p_query(answer);
X		}
X#endif DEBUG
X		/*
X		 * If using virtual circuits, we assume that the first server
X		 * is preferred * over the rest (i.e. it is on the local
X		 * machine) and only keep that one open.
X		 * If we have temporarily opened a virtual circuit,
X		 * or if we haven't been asked to keep a socket open,
X		 * close the socket.
X		 */
X		if ((v_circuit &&
X		    ((_res.options & RES_USEVC) == 0 || ns != 0)) ||
X		    (_res.options & RES_STAYOPEN) == 0) {
X			(void) close(s);
X			s = -1;
X		}
X		return (resplen);
X	   }
X	}
X	if (s >= 0) {
X		(void) close(s);
X		s = -1;
X	}
X	if (v_circuit == 0)
X		if (gotsomewhere == 0)
X			errno = ECONNREFUSED;	/* no nameservers found */
X		else
X			errno = ETIMEDOUT;	/* no answer obtained */
X	else
X		errno = terrno;
X	return (-1);
X}
X
X/*
X * This routine is for closing the socket if a virtual circuit is used and
X * the program wants to close it.  This provides support for endhostent()
X * which expects to close the socket.
X *
X * This routine is not expected to be user visible.
X */
X_res_close()
X{
X	if (s != -1) {
X		(void) close(s);
X		s = -1;
X	}
X}
END_OF_FILE
if test 10025 -ne `wc -c <'res_send.c'`; then
    echo shar: \"'res_send.c'\" unpacked with wrong size!
fi
# end of 'res_send.c'
fi
echo shar: End of archive 2 \(of 2\).
cp /dev/null ark2isdone
MISSING=""
for I in 1 2 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked both archives.
    rm -f ark[1-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0