resolv+ -- improved resolver library -- part02/02
Bill Wisner
wisner at ims.alaska.edu
Tue Apr 23 12:48:11 AEST 1991
#! /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 at 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
More information about the Alt.sources
mailing list