|
|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T s
Length: 8806 (0x2266)
Types: TextFile
Names: »sm_ns.c«
└─⟦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«
/* 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