DataMuseum.dk

Presents historical artifacts from the history of:

DKUUG/EUUG Conference tapes

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about DKUUG/EUUG Conference tapes

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - metrics - download
Index: T s

⟦381e5070c⟧ TextFile

    Length: 8806 (0x2266)
    Types: TextFile
    Names: »sm_ns.c«

Derivation

└─⟦2d1937cfd⟧ Bits:30007241 EUUGD22: P.P 5.0
    └─⟦dc59850a2⟧ »EurOpenD22/pp5.0/pp-5.tar.Z« 
        └─⟦e5a54fb17⟧ 
            └─⟦this⟧ »pp-5.0/Chans/smtp/sm_ns.c« 

TextFile

/* sm_ns.c */

# ifndef lint
static char Rcsid[] = "@(#)$Header: /cs/research/pp/hubris/pp-beta/Chans/smtp/RCS/sm_ns.c,v 5.0 90/09/20 15:54:17 pp Exp Locker: pp $";
# endif

/*
 * $Header: /cs/research/pp/hubris/pp-beta/Chans/smtp/RCS/sm_ns.c,v 5.0 90/09/20 15:54:17 pp Exp Locker: pp $
 *
 * $Log:	sm_ns.c,v $
 * Revision 5.0  90/09/20  15:54:17  pp
 * rcsforce : 5.0 public release
 * 
 */



/* Steve Kille, based on code from Phil Cockcroft and Craig Partridge
	September 1989 */



#include "util.h"
#include "retcode.h"
#include "chan.h"
#include <signal.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>

#include <arpa/nameser.h>
#include <resolv.h>

#ifdef NAMESERVER

/* T_UNSPEC was defined only in more recent versions of BIND */

#ifdef T_UNSPEC
#define BSD4_3
#define	getshort _getshort
#endif T_UNSPEC


#ifndef MAXADDR
#define MAXADDR		10
#endif

#ifndef MAXADDR_PER
#define MAXADDR_PER	2
#endif

#ifndef MAXDATA
#define MAXDATA (4 * PACKETSZ)		/* tcp tried after udp */
#endif

#ifndef MAXMX
#define MAXMX	(MAXADDR)		/* shouldn't be < MAXADDR */
#endif


union ansbuf {			/* potentially huge */
    HEADER ab1;
    char ab2[MAXDATA];
}; 

union querybuf {		/* just for outbound stuff */
    HEADER qb1;			/* didn't want to clobber stack */
    char qb2[2 * MAXDNAME];
}; 

extern char *loc_dom_mta;

static  char dn_name[MAXDNAME];

static struct hostent hval;
static struct in_addr addrbuf[MAXADDR+1];
static char *addrptrs [MAXADDR+1];
static char addrarray[sizeof(struct in_addr) + 1][MAXADDR + 1];
extern int h_errno;

ns_gethost (key, hptr)
char *key;
struct hostent **hptr;
{
    register char *cp;
    register int i, j, n;
    HEADER *hp;
    struct hostent *he;
    union querybuf qbuf;
    union ansbuf abuf;
    u_short type, dsize;
    int pref, localpref;
    int count, mxcount;
    int sawmx;			/* are we actually processing mx's? */
    char *eom;
    char buf[MAXDNAME];		/* for expanding in dn_expand */
    char newkey[MAXDNAME]; 	/* in case we get a CNAME RR back... */
    struct {			/* intermediate table */
	char *mxname;
	u_short mxpref;
    } mx_list[MAXMX];

    int acount;

    extern char *ns_skiphdr();


    PP_TRACE (("DNS resolve host %s", key));

    for (i = 0; i <= MAXADDR; i++)
	addrptrs[i] = (char *) addrarray[i];
    *hptr = &hval;   
    hval.h_addr_list = addrptrs;
    hval.h_name = key;
    hval.h_aliases = 0;


restart:

    mxcount = 0;
    acount = 0;
    localpref = -1;
    sawmx = 0;

    n = res_mkquery(QUERY, key, C_IN, T_MX, (char *)0, 0, (char *)0,
	(char *)&qbuf, sizeof(qbuf));

    /* what else can we do? */
    if (n < 0)
    {
	PP_NOTICE (("No answers from res_mkquery"));
	return(RP_NO);
    }

    PP_TRACE (("ns_gethost: sending ns query (%d bytes)",n));

    n = res_send((char *)&qbuf,n,(char *)&abuf, sizeof(abuf));

    if (n < 0)
    {
	PP_SLOG (LLOG_EXCEPTIONS, "res_send", ("DNS resolver error: "));
	return(RP_TIME);
    }

    hp = (HEADER *)&abuf;

    if (hp->rcode != NOERROR) 
	return(ns_error(hp));


    if (ntohs(hp->ancount) == 0)
    {
	mxcount = 1;
	mx_list[0].mxname = strdup(key);
	mx_list[0].mxpref = 0;
	goto doaddr;
    }

    /* read MX list */
    sawmx = 1;
    count = ntohs(hp->ancount);


    /* skip header */
    eom = ((char *)&abuf) + n;
    if ((cp = ns_skiphdr((char *)&abuf, hp, eom))==0)
    {
	PP_NOTICE (("ns_gethost: no useful answers to query"));
	return(RP_TIME);
    }

    PP_TRACE (("ns_gethost: %d answers to query",count));

    while ((cp < eom) && (count--))
    {
	n = dn_expand((char *)&abuf,eom, cp, buf, sizeof(buf));
	if (n < 0)
	    goto quit;

	cp += n;
	type = getshort(cp);
	/* get to datasize */
	cp += (2 * sizeof(u_short)) + sizeof(u_long);
	dsize = getshort(cp);
	cp += sizeof(u_short);

	/*
	 * is it an MX ? 
	 * it could be a CNAME
	 */

	if (type == T_CNAME)
	{
	    PP_TRACE (("ns_gethost: CNAME answer to MX query"));
	    n = dn_expand((char *)&abuf,eom, cp, newkey, sizeof(newkey));
	    cp += dsize;
	    if (n < 0)
		continue;	/* pray? */
	    PP_TRACE (("ns_gethost: `%s` -> `%s` (new query)",key,newkey));
	    key = newkey;
	    goto restart;
	}

	if (type != T_MX)
	{
	    PP_NOTICE (("ns_gethost: RR of type %d in response",type));
	    cp += dsize;
	    continue;       /* keep trying */
	}

	pref = getshort(cp);
	cp += sizeof(u_short);

	n = dn_expand((char *)&abuf,eom, cp, buf, sizeof(buf));
	if (n < 0)
	    goto quit;

	cp += n;

	/* is it local? */
	if ((lexequ(loc_dom_mta, buf) == 0) &&
	    ((localpref < 0) || (pref < localpref)))
	{
	    localpref = pref;
	    for(i=(mxcount-1); i >= 0; i--)
	    {
		if (mx_list[i].mxpref < localpref)
		    break;

		(void) free(mx_list[i].mxname);
		mxcount--;
	    }
	    continue;
	}

	/* now, see if we keep it */
	if ((localpref >= 0) && (pref >= localpref))
	    continue;

	/*  find where it belongs */
	for(i=0; i < mxcount; i++)
	    if (mx_list[i].mxpref > pref)
		break;

	/* not of interest */
	if (i == MAXMX)
	    continue;

	/* shift stuff to make space */
	for(j=mxcount-1; j > i; j--)
	{
	    if (j==(MAXMX-1))
		(void) free(mx_list[j].mxname);

	    mx_list[j].mxname = mx_list[j-1].mxname;
	    mx_list[j].mxpref = mx_list[j-1].mxpref;
	}

	mx_list[i].mxname = strdup(buf);
	mx_list[i].mxpref = pref;

	if (mxcount <= i)
	    mxcount = i + 1;
    }

    /*
     * should read additional RR section for addresses and cache them
     * but let's hold on that.
     */

doaddr:
    /* now build the address list */
    

    PP_TRACE (("ns_gethost: using %d mx hosts",mxcount));

    for(i=0,j=0; (i < mxcount) && (j < MAXADDR); i++)
    {
	/*
	 * note that gethostbyname() is slow -- we should cache so
	 * we don't ask for an address repeatedly
	 */

	he = gethostbyname(mx_list[i].mxname);

	if (he == 0)
	{
	    PP_NOTICE (("ns_gethost: no addresses for %s",
		mx_list[i].mxname));
	    /* nope -- were trying special case and no address */
	    if ((!sawmx) && (h_errno != TRY_AGAIN))
		return(RP_NO);

	    continue;
	}

	if (j == 0)
 	{
		hval.h_length = he -> h_length;
		hval.h_addrtype = he -> h_addrtype;
	}

	for(n=0; (j < MAXADDR) && (n < MAXADDR_PER); n++, j++)
	{
	    if (he->h_addr_list[n] == 0)
		break;

	    bcopy(he->h_addr_list[n],hval.h_addr_list[j],sizeof(struct in_addr));

	}
	PP_TRACE (("ns_gethost: %d addresses saved for %s",
		n, mx_list[i].mxname));
    }
    acount = j;
    hval.h_addr_list[j] = 0; 

quit:
    for(i=0; i < mxcount; i++)
	(void) free(mx_list[i].mxname);

    if (acount == 0)
	PP_NOTICE (("ns_gethost: No addresess derived from MX query"));
    else
	PP_NOTICE (("DNS resolves %s to %d address%s", key, acount,
		    acount > 1 ? "es" : ""));
    /* if localpref is set, then we got an answer */
    return (acount == 0 ? (localpref < 0 ? RP_TIME : RP_NO) : RP_OK);
}

static char *prcode (n)
int n;
{
	static char tbuf[40];

	switch (n) {
	    case NOERROR:
		return "No Error (NOERROR)";

	    case FORMERR:
		return "Format Error (FORMERR)";

	    case SERVFAIL:
		return "Server failure (SERVFAIL)";

	    case NXDOMAIN:
		return "Non existant domain (NXDOMAIN)";

	    case NOTIMP:
		return "Not implemented (NOTIMP)";

	    case REFUSED:
		return "Query Refused (REFUSED)";

	    default:
		(void) sprintf (tbuf, "Unknown code %d", n);
		return tbuf;
	}
}
		
/*
 * figure out proper error code to return given an error
 */

static
ns_error(hp)
register HEADER *hp;
{

    PP_NOTICE (("DNS error: %s",prcode(hp->rcode)));

    switch (hp->rcode)
    {
	case NXDOMAIN:
	    return(RP_NO); /* even if not authoritative */

	case SERVFAIL:
	    return(RP_TIME);

	default:
	    break;
    }

    return(RP_NO);
}

/*
 * skip header of query and return pointer to first answer RR.
 */

static
char *ns_skiphdr(answer, hp, eom)
char *answer;
HEADER *hp;
register char *eom;
{
    register int qdcount;
    register char *cp;
    register int n;
    char tmp[MAXDNAME];

    qdcount = ntohs(hp->qdcount);

    cp = answer + sizeof(HEADER);

    while ((qdcount-- > 0) && (cp < eom))
    {
	n = dn_expand(answer,eom,cp,tmp,sizeof(tmp));
	if (n < 0)
	    return(0);
	cp += (n + QFIXEDSZ);
    }

    return((cp < eom)? cp : 0);
}

/*
 * routine to set the resolver timeouts
 * takes maximum number of seconds you are willing to wait
 */

ns_settimeo(ns_time)
int     ns_time;
{
    static int called = 0;
    static struct state oldres;

    if ((_res.options & RES_INIT) == 0)
	    res_init ();

    /* always start afresh */
    if (called)
    {
	bcopy((char *)&oldres,(char *)&_res,sizeof(oldres));
    }
    else
    {
	called = 1;
	bcopy((char *)&_res,(char *)&oldres,sizeof(oldres));
    }

    /*
     * bind uses an exponential backoff
     */

    _res.retrans = ns_time >> _res.retry;

    PP_TRACE (("ns_timeo: servers(%d), retrans(%d), retry(%d)",
	_res.nscount, _res.retrans, _res.retry));
}
#endif