aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/ndb/dnudpserver.c
diff options
context:
space:
mode:
authorrsc <devnull@localhost>2005-12-27 04:30:05 +0000
committerrsc <devnull@localhost>2005-12-27 04:30:05 +0000
commit3e0d8fb3ea83b2b65a6425c65beda887140f9349 (patch)
treece1579f6999c0e4adad35b75c498ddc714b40c1e /src/cmd/ndb/dnudpserver.c
parentcff43a06f21a674b2b16e72f8853aac5fd24f48d (diff)
downloadplan9port-3e0d8fb3ea83b2b65a6425c65beda887140f9349.tar.gz
plan9port-3e0d8fb3ea83b2b65a6425c65beda887140f9349.tar.bz2
plan9port-3e0d8fb3ea83b2b65a6425c65beda887140f9349.zip
add dns
Diffstat (limited to 'src/cmd/ndb/dnudpserver.c')
-rwxr-xr-xsrc/cmd/ndb/dnudpserver.c228
1 files changed, 228 insertions, 0 deletions
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 <u.h>
+#include <libc.h>
+#include <ip.h>
+#include <bio.h>
+#include <ndb.h>
+#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");
+}