plan9port

fork of plan9port with libvec, libstr and libsdb
Log | Files | Refs | README | LICENSE

dnudpserver.c (4507B)


      1 #include <u.h>
      2 #include <libc.h>
      3 #include <ip.h>
      4 #include <bio.h>
      5 #include <ndb.h>
      6 #include <thread.h>
      7 #include "dns.h"
      8 
      9 static int	udpannounce(char*);
     10 static void	reply(int, uchar*, DNSmsg*, Request*);
     11 
     12 extern char *logfile;
     13 
     14 typedef struct Inprogress Inprogress;
     15 struct Inprogress
     16 {
     17 	int	inuse;
     18 	Udphdr	uh;
     19 	DN	*owner;
     20 	int	type;
     21 	int	id;
     22 };
     23 Inprogress inprog[Maxactive+2];
     24 QLock inproglk;
     25 
     26 /*
     27  *  record client id and ignore retransmissions.
     28  */
     29 static Inprogress*
     30 clientrxmit(DNSmsg *req, uchar *buf)
     31 {
     32 	Inprogress *p, *empty;
     33 	Udphdr *uh;
     34 
     35 	qlock(&inproglk);
     36 	uh = (Udphdr *)buf;
     37 	empty = 0;
     38 	for(p = inprog; p < &inprog[Maxactive]; p++){
     39 		if(p->inuse == 0){
     40 			if(empty == 0)
     41 				empty = p;
     42 			continue;
     43 		}
     44 		if(req->id == p->id)
     45 		if(req->qd->owner == p->owner)
     46 		if(req->qd->type == p->type)
     47 		if(memcmp(uh, &p->uh, Udphdrsize) == 0){
     48 			qunlock(&inproglk);
     49 			return 0;
     50 		}
     51 	}
     52 	if(empty == 0){
     53 		qunlock(&inproglk);
     54 		return 0;	/* shouldn't happen - see slave() and definition of Maxactive */
     55 	}
     56 
     57 	empty->id = req->id;
     58 	empty->owner = req->qd->owner;
     59 	empty->type = req->qd->type;
     60 	memmove(&empty->uh, uh, Udphdrsize);
     61 	empty->inuse = 1;
     62 	qunlock(&inproglk);
     63 	return empty;
     64 }
     65 
     66 /*
     67  *  a process to act as a dns server for outside reqeusts
     68  */
     69 static void
     70 udpproc(void *v)
     71 {
     72 	int fd, len, op;
     73 	Request req;
     74 	DNSmsg reqmsg, repmsg;
     75 	uchar buf[Udphdrsize + Maxudp + 1024];
     76 	char *err;
     77 	Inprogress *p;
     78 	char tname[32];
     79 	Udphdr *uh;
     80 
     81 	fd = (uintptr)v;
     82 
     83 	/* loop on requests */
     84 	for(;; putactivity()){
     85 		memset(&repmsg, 0, sizeof(repmsg));
     86 		memset(&reqmsg, 0, sizeof(reqmsg));
     87 		len = udpread(fd, (Udphdr*)buf, buf+Udphdrsize, sizeof(buf)-Udphdrsize);
     88 		if(len <= 0)
     89 			continue;
     90 		uh = (Udphdr*)buf;
     91 		getactivity(&req);
     92 		req.aborttime = now + 30;	/* don't spend more than 30 seconds */
     93 		err = convM2DNS(&buf[Udphdrsize], len, &reqmsg);
     94 		if(err){
     95 			syslog(0, logfile, "server: input error: %s from %I", err, buf);
     96 			continue;
     97 		}
     98 		if(reqmsg.qdcount < 1){
     99 			syslog(0, logfile, "server: no questions from %I", buf);
    100 			goto freereq;
    101 		}
    102 		if(reqmsg.flags & Fresp){
    103 			syslog(0, logfile, "server: reply not request from %I", buf);
    104 			goto freereq;
    105 		}
    106 		op = reqmsg.flags & Omask;
    107 		if(op != Oquery && op != Onotify){
    108 			syslog(0, logfile, "server: op %d from %I", reqmsg.flags & Omask, buf);
    109 			goto freereq;
    110 		}
    111 
    112 		if(debug || (trace && subsume(trace, reqmsg.qd->owner->name))){
    113 			syslog(0, logfile, "%d: serve (%I/%d) %d %s %s",
    114 				req.id, buf, ((uh->rport[0])<<8)+uh->rport[1],
    115 				reqmsg.id,
    116 				reqmsg.qd->owner->name,
    117 				rrname(reqmsg.qd->type, tname, sizeof tname));
    118 		}
    119 
    120 		p = clientrxmit(&reqmsg, buf);
    121 		if(p == 0){
    122 			if(debug)
    123 				syslog(0, logfile, "%d: duplicate", req.id);
    124 			goto freereq;
    125 		}
    126 
    127 		/* loop through each question */
    128 		while(reqmsg.qd){
    129 			memset(&repmsg, 0, sizeof(repmsg));
    130 			switch(op){
    131 			case Oquery:
    132 				dnserver(&reqmsg, &repmsg, &req);
    133 				break;
    134 			case Onotify:
    135 				dnnotify(&reqmsg, &repmsg, &req);
    136 				break;
    137 			}
    138 			reply(fd, buf, &repmsg, &req);
    139 			rrfreelist(repmsg.qd);
    140 			rrfreelist(repmsg.an);
    141 			rrfreelist(repmsg.ns);
    142 			rrfreelist(repmsg.ar);
    143 		}
    144 
    145 		p->inuse = 0;
    146 
    147 freereq:
    148 		rrfreelist(reqmsg.qd);
    149 		rrfreelist(reqmsg.an);
    150 		rrfreelist(reqmsg.ns);
    151 		rrfreelist(reqmsg.ar);
    152 	}
    153 }
    154 
    155 /*
    156  *  announce on udp port
    157  */
    158 static int
    159 udpannounce(char *mntpt)
    160 {
    161 	int fd;
    162 	char buf[40];
    163 	USED(mntpt);
    164 
    165 	if((fd=announce(udpaddr, buf)) < 0)
    166 		warning("announce %s: %r", buf);
    167 	return fd;
    168 }
    169 
    170 static void
    171 reply(int fd, uchar *buf, DNSmsg *rep, Request *reqp)
    172 {
    173 	int len;
    174 	char tname[32];
    175 	RR *rp;
    176 
    177 	if(debug || (trace && subsume(trace, rep->qd->owner->name)))
    178 		syslog(0, logfile, "%d: reply (%I/%d) %d %s %s an %R ns %R ar %R",
    179 			reqp->id, buf, ((buf[4])<<8)+buf[5],
    180 			rep->id, rep->qd->owner->name,
    181 			rrname(rep->qd->type, tname, sizeof tname), rep->an, rep->ns, rep->ar);
    182 
    183 	len = convDNS2M(rep, &buf[Udphdrsize], Maxudp);
    184 	if(len <= 0){
    185 		syslog(0, logfile, "error converting reply: %s %d", rep->qd->owner->name,
    186 			rep->qd->type);
    187 		for(rp = rep->an; rp; rp = rp->next)
    188 			syslog(0, logfile, "an %R", rp);
    189 		for(rp = rep->ns; rp; rp = rp->next)
    190 			syslog(0, logfile, "ns %R", rp);
    191 		for(rp = rep->ar; rp; rp = rp->next)
    192 			syslog(0, logfile, "ar %R", rp);
    193 		return;
    194 	}
    195 	if(udpwrite(fd, (Udphdr*)buf, buf+Udphdrsize, len) != len)
    196 		syslog(0, logfile, "error sending reply: %r");
    197 }
    198 
    199 void
    200 dnudpserver(void *v)
    201 {
    202 	int i, fd;
    203 
    204 	while((fd = udpannounce(v)) < 0)
    205 		sleep(5*1000);
    206 	for(i=0; i<Maxactive; i++)
    207 		proccreate(udpproc, (void*)(uintptr)fd, STACK);
    208 }