From 3e0d8fb3ea83b2b65a6425c65beda887140f9349 Mon Sep 17 00:00:00 2001 From: rsc Date: Tue, 27 Dec 2005 04:30:05 +0000 Subject: add dns --- src/cmd/ndb/dnudpserver.c | 228 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 228 insertions(+) create mode 100755 src/cmd/ndb/dnudpserver.c (limited to 'src/cmd/ndb/dnudpserver.c') diff --git a/src/cmd/ndb/dnudpserver.c b/src/cmd/ndb/dnudpserver.c new file mode 100755 index 00000000..f0ed37cd --- /dev/null +++ b/src/cmd/ndb/dnudpserver.c @@ -0,0 +1,228 @@ +#include +#include +#include +#include +#include +#include "dns.h" + +static int udpannounce(char*); +static void reply(int, uchar*, DNSmsg*, Request*); + +extern char *logfile; + +static void +ding(void *x, char *msg) +{ + USED(x); + if(strcmp(msg, "alarm") == 0) + noted(NCONT); + else + noted(NDFLT); +} + +typedef struct Inprogress Inprogress; +struct Inprogress +{ + int inuse; + OUdphdr uh; + DN *owner; + int type; + int id; +}; +Inprogress inprog[Maxactive+2]; + +/* + * record client id and ignore retransmissions. + * we're still single thread at this point. + */ +static Inprogress* +clientrxmit(DNSmsg *req, uchar *buf) +{ + Inprogress *p, *empty; + OUdphdr *uh; + + uh = (OUdphdr *)buf; + empty = 0; + for(p = inprog; p < &inprog[Maxactive]; p++){ + if(p->inuse == 0){ + if(empty == 0) + empty = p; + continue; + } + if(req->id == p->id) + if(req->qd->owner == p->owner) + if(req->qd->type == p->type) + if(memcmp(uh, &p->uh, OUdphdrsize) == 0) + return 0; + } + if(empty == 0) + return 0; /* shouldn't happen - see slave() and definition of Maxactive */ + + empty->id = req->id; + empty->owner = req->qd->owner; + empty->type = req->qd->type; + memmove(&empty->uh, uh, OUdphdrsize); + empty->inuse = 1; + return empty; +} + +/* + * a process to act as a dns server for outside reqeusts + */ +void +dnudpserver(char *mntpt) +{ + int fd, len, op; + Request req; + DNSmsg reqmsg, repmsg; + uchar buf[OUdphdrsize + Maxudp + 1024]; + char *err; + Inprogress *p; + char tname[32]; + OUdphdr *uh; + + /* fork sharing text, data, and bss with parent */ + switch(rfork(RFPROC|RFNOTEG|RFMEM|RFNOWAIT)){ + case -1: + break; + case 0: + break; + default: + return; + } + + fd = -1; + notify(ding); +restart: + if(fd >= 0) + close(fd); + while((fd = udpannounce(mntpt)) < 0) + sleep(5000); + if(setjmp(req.mret)) + putactivity(); + req.isslave = 0; + + /* loop on requests */ + for(;; putactivity()){ + memset(&repmsg, 0, sizeof(repmsg)); + memset(&reqmsg, 0, sizeof(reqmsg)); + alarm(60*1000); + len = udpread(fd, (OUdphdr*)buf, buf+OUdphdrsize, sizeof(buf)-OUdphdrsize); + alarm(0); + if(len <= 0) + goto restart; + uh = (OUdphdr*)buf; + getactivity(&req); + req.aborttime = now + 30; /* don't spend more than 30 seconds */ + err = convM2DNS(&buf[OUdphdrsize], 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); + goto freereq; + } + if(reqmsg.flags & Fresp){ + syslog(0, logfile, "server: reply not request from %I", buf); + goto freereq; + } + op = reqmsg.flags & Omask; + if(op != Oquery && op != Onotify){ + syslog(0, logfile, "server: op %d from %I", reqmsg.flags & Omask, buf); + goto freereq; + } + + if(debug || (trace && subsume(trace, reqmsg.qd->owner->name))){ + syslog(0, logfile, "%d: serve (%I/%d) %d %s %s", + req.id, buf, ((uh->rport[0])<<8)+uh->rport[1], + reqmsg.id, + reqmsg.qd->owner->name, + rrname(reqmsg.qd->type, tname, sizeof tname)); + } + + p = clientrxmit(&reqmsg, buf); + if(p == 0){ + if(debug) + syslog(0, logfile, "%d: duplicate", req.id); + goto freereq; + } + + /* loop through each question */ + while(reqmsg.qd){ + memset(&repmsg, 0, sizeof(repmsg)); + switch(op){ + case Oquery: + dnserver(&reqmsg, &repmsg, &req); + break; + case Onotify: + dnnotify(&reqmsg, &repmsg, &req); + break; + } + reply(fd, buf, &repmsg, &req); + rrfreelist(repmsg.qd); + rrfreelist(repmsg.an); + rrfreelist(repmsg.ns); + rrfreelist(repmsg.ar); + } + + p->inuse = 0; + +freereq: + rrfreelist(reqmsg.qd); + rrfreelist(reqmsg.an); + rrfreelist(reqmsg.ns); + rrfreelist(reqmsg.ar); + + if(req.isslave){ + putactivity(); + _exits(0); + } + + } +} + +/* + * announce on udp port + */ +static int +udpannounce(char *mntpt) +{ + int fd; + char buf[40]; + + USED(mntpt); + + if((fd=announce("udp!*!nameserver", buf)) < 0) + warning("can't announce on dns udp port"); + return fd; +} + +static void +reply(int fd, uchar *buf, DNSmsg *rep, Request *reqp) +{ + int len; + char tname[32]; + RR *rp; + + if(debug || (trace && subsume(trace, rep->qd->owner->name))) + syslog(0, logfile, "%d: reply (%I/%d) %d %s %s an %R ns %R ar %R", + reqp->id, buf, ((buf[4])<<8)+buf[5], + rep->id, rep->qd->owner->name, + rrname(rep->qd->type, tname, sizeof tname), rep->an, rep->ns, rep->ar); + + len = convDNS2M(rep, &buf[OUdphdrsize], Maxudp); + if(len <= 0){ + syslog(0, logfile, "error converting reply: %s %d", rep->qd->owner->name, + rep->qd->type); + for(rp = rep->an; rp; rp = rp->next) + syslog(0, logfile, "an %R", rp); + for(rp = rep->ns; rp; rp = rp->next) + syslog(0, logfile, "ns %R", rp); + for(rp = rep->ar; rp; rp = rp->next) + syslog(0, logfile, "ar %R", rp); + return; + } + if(udpwrite(fd, (OUdphdr*)buf, buf+OUdphdrsize, len) != len) + syslog(0, logfile, "error sending reply: %r"); +} -- cgit v1.2.3