henesyinit from p9fce6d0435 years agoHistory
282 lines · 5.6 KB · C
RawDownload
#include <u.h>#include <libc.h>#include <ip.h>#include "dns.h" int	udpannounce(void);static RR*	getipaddr(DN*);static void	recurse(DNSmsg*, Request*);static void	local(DNSmsg*);static void	reply(int, uchar*, DNSmsg*);static void	hint(RR**, RR*); extern char *logfile; /* *  a process to act as a dns server for outside reqeusts */voiddnserver(void){	int fd, len;	char *err;	RR *tp;	Request req;	DNSmsg reqmsg;	DNSmsg repmsg;	uchar buf[Udphdrsize + Maxudp];	char tname[32]; 	/* fork sharing text, data, and bss with parent */	switch(rfork(RFPROC|RFNOTEG|RFMEM|RFNOWAIT)){	case -1:		break;	case 0:		break;	default:		return;	} 	while((fd = udpannounce()) < 0)		sleep(5000);	setjmp(req.mret);	req.isslave = 0; 	/* loop on requests */	for(;;){		memset(&repmsg, 0, sizeof(repmsg));		len = read(fd, buf, sizeof(buf));		err = convM2DNS(&buf[Udphdrsize], len, &reqmsg);		if(err){			syslog(0, logfile, "server: input error: %s from %I", err, buf);			continue;		}		if(reqmsg.qdcount < 1){			syslog(0, logfile, "server: no questions from %I", buf);		} else if(reqmsg.flags & Fresp){			syslog(0, logfile, "server: reply not request from %I", buf);		} else if(reqmsg.qd->owner->class != Cin){			syslog(0, logfile, "server: class %d from %I", reqmsg.qd->owner->class,				buf);			memset(&repmsg, 0, sizeof(repmsg));			repmsg.id = reqmsg.id;			repmsg.flags = Runimplimented | Fresp | Fcanrec | Oquery;			repmsg.qd = reqmsg.qd;			reply(fd, buf, &repmsg);		} else if((reqmsg.flags & Omask) != Oquery){			syslog(0, logfile, "server: op %d from %I", reqmsg.flags & Omask, buf);		} else {			/* loop through each question */			while(reqmsg.qd){				if(debug)					syslog(0, logfile, "serve %s %s",						reqmsg.qd->owner->name,						rrname(reqmsg.qd->type, tname));				memset(&repmsg, 0, sizeof(repmsg));				repmsg.id = reqmsg.id;				repmsg.flags = Fresp | Fcanrec | Oquery;				repmsg.qd = reqmsg.qd;				reqmsg.qd = reqmsg.qd->next;				repmsg.qd->next = 0;					/*				 *  get the answer if we can				 */				if(reqmsg.flags & Frecurse)					recurse(&repmsg, &req);				else					local(&repmsg);					/*				 *  add ip addresses as hints				 */				for(tp = repmsg.ns; tp; tp = tp->next)					hint(&repmsg.ar, tp);				for(tp = repmsg.an; tp; tp = tp->next)					hint(&repmsg.ar, tp); 				reply(fd, buf, &repmsg); 				rrfreelist(repmsg.qd);				rrfreelist(repmsg.an);				rrfreelist(repmsg.ns);				rrfreelist(repmsg.ar);			}		}		rrfreelist(reqmsg.qd);		rrfreelist(reqmsg.an);		rrfreelist(reqmsg.ns);		rrfreelist(reqmsg.ar); 		if(req.isslave)			_exits(0);	}} /* *  satisfy a recursive request.  dnlookup will handle cnames. */static voidrecurse(DNSmsg *mp, Request *req){	int type;	char *name;	RR *cname; 	name = mp->qd->owner->name;	type = mp->qd->type;	cname = 0;	rrcat(&mp->an, dnresolve(name, Cin, type, req, &cname), type);	if(cname)		rrcat(&mp->an, cname, Tcname);	if(mp->an && mp->an->auth)		mp->flags |= Fauth;}  /* *  satisfy a request with local info only */static voidlocal(DNSmsg *mp){	DN *dp, *nsdp;	RR *nsrp;	char *cp;	int type; 	dp = mp->qd->owner;	type = mp->qd->type;	mp->flags |= Fauth; 	/* in-addr.arpa queries are special */	if(type == Tptr){		rrcat(&mp->an, dbinaddr(dp), type);		if(mp->an)			return;	} 	/*	 *  Quick grab, see if it's a 'relative to my domain' request.	 *  I'm not sure this is a good idea but our x-terminals want it.	 */	if(strchr(dp->name, '.') == 0){		nsrp = dblookup(dp->name, dp->class, type, 1);		if(nsrp){			rrcat(&mp->an, nsrp, type);			return;		}	} 	/* 	 *  walk up the domain name looking for	 *  a name server for the domain.	 */	for(cp = dp->name; /* mp->an==0 && */ cp; cp = walkup(cp)){		/* look for ns in cache and database */		nsdp = dnlookup(cp, dp->class, 0);		nsrp = 0;		if(nsdp)			nsrp = rrlookup(nsdp, Tns);		if(nsrp == 0)			nsrp = dblookup(cp, dp->class, Tns, 0);		if(nsrp == 0)			continue; 		if(nsrp->local){			/* local domains resolved from this db */			if(nsrp->db)	/* free database rr's */				rrfreelist(nsrp);			rrcat(&mp->an, dblookup(dp->name, Cin, type, 1), type);		} else {			/* just return the name of a name server to use */			rrcat(&mp->ns, nsrp, Tns);		} 		break;	}} static voidreply(int fd, uchar *buf, DNSmsg *rep){	int len;	char tname[32]; 	if(debug)		syslog(0, logfile, "reply (%I/%d) %s %s an %R ns %R ar %R",			buf, ((buf[4])<<8)+buf[5], rep->qd->owner->name,			rrname(rep->qd->type, tname), rep->an, rep->ns, rep->ar); 	len = convDNS2M(rep, &buf[Udphdrsize], Maxudp);	if(len <= 0)		fatal("dnserver: converting reply");	len += Udphdrsize;	if(write(fd, buf, len) != len)		fatal("dnserver: sending reply");} static voidhint(RR **last, RR *rp){	switch(rp->type){	case Tns:	case Tmx:	case Tmb:	case Tmf:	case Tmd:		rrcat(last, dblookup(rp->host->name, Cin, Ta, 0), Ta);		break;	}} /* *  get ip addresses without looking off machine */static RR*getipaddr(DN *dp){	RR *rp; 	/* first try the cache */	rp = rrlookup(dp, Ta);	if(rp)		return rp; 	/* then try on disk db */	return dblookup(dp->name, dp->class, Ta, 0);} /* *  announce on udp port and set message style interface */static char *hmsg = "headers"; intudpannounce(void){	int data, ctl;	char dir[64];	char datafile[64+6]; 	/* get a udp port */	ctl = announce("udp!*!dns", dir);	if(ctl < 0){		warning("can't announce on udp port");		return -1;	}	snprint(datafile, sizeof(datafile), "%s/data", dir); 	/* turn on header style interface */	if(write(ctl, hmsg, strlen(hmsg)) , 0)		fatal(hmsg);	data = open(datafile, ORDWR);	if(data < 0){		close(ctl);		warning("can't announce on udp port");		return -1;	} 	close(ctl);	return data;}