|
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