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/dnnotify.c | 160 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 160 insertions(+) create mode 100755 src/cmd/ndb/dnnotify.c (limited to 'src/cmd/ndb/dnnotify.c') diff --git a/src/cmd/ndb/dnnotify.c b/src/cmd/ndb/dnnotify.c new file mode 100755 index 00000000..a5d91005 --- /dev/null +++ b/src/cmd/ndb/dnnotify.c @@ -0,0 +1,160 @@ +#include +#include +#include +#include +#include +#include "dns.h" + +/* get a notification from another system of a changed zone */ +void +dnnotify(DNSmsg *reqp, DNSmsg *repp, Request *r) +{ + RR *tp; + Area *a; + + USED(r); + /* move one question from reqp to repp */ + memset(repp, 0, sizeof(*repp)); + tp = reqp->qd; + reqp->qd = tp->next; + tp->next = 0; + repp->qd = tp; + repp->id = reqp->id; + repp->flags = Fresp | Onotify | Fauth; + + /* anything to do? */ + if(zonerefreshprogram == nil) + return; + + /* make sure its the right type */ + if(repp->qd->type != Tsoa) + return; + +syslog(0, logfile, "notification for %s", repp->qd->owner->name); + + /* is it something we care about? */ + a = inmyarea(repp->qd->owner->name); + if(a == nil) + return; + +syslog(0, logfile, "serial old %lud new %lud", a->soarr->soa->serial, repp->qd->soa->serial); + + /* do nothing if it didn't change */ + if(a->soarr->soa->serial== repp->qd->soa->serial) + return; + + a->needrefresh = 1; +} + +static void +ding(void *u, char *msg) +{ + USED(u); + + if(strstr(msg, "alarm")) + noted(NCONT); + else + noted(NDFLT); +} + +/* notify a slave that an area has changed. */ +static void +send_notify(char *slave, RR *soa, Request *req) +{ + int i, len, n, reqno, status, fd; + uchar obuf[Maxudp+OUdphdrsize]; + uchar ibuf[Maxudp+OUdphdrsize]; + RR *rp; + OUdphdr *up = (OUdphdr*)obuf; + char *err; + DNSmsg repmsg; + + /* create the request */ + reqno = rand(); + n = mkreq(soa->owner, Cin, obuf, Fauth | Onotify, reqno); + + /* get an address */ + if(strcmp(ipattr(slave), "ip") == 0) { + parseip(up->raddr, slave); + } else { + rp = dnresolve(slave, Cin, Ta, req, nil, 0, 1, 1, &status); + if(rp == nil) + return; + parseip(up->raddr, rp->ip->name); + rrfree(rp); + } + + fd = udpport(); + if(fd < 0) + return; + + notify(ding); + + /* send 3 times or until we get anything back */ + for(i = 0; i < 3; i++){ +syslog(0, logfile, "sending %d byte notify to %s/%I.%d about %s", n, slave, up->raddr, nhgets(up->rport), soa->owner->name); + if(udpwrite(fd, (OUdphdr*)obuf, obuf+OUdphdrsize, n) != n) + break; + alarm(2*1000); + len = udpread(fd, (Udphdr*)ibuf, ibuf+OUdphdrsize, Maxudp); + alarm(0); + if(len <= OUdphdrsize) + continue; + err = convM2DNS(&ibuf[OUdphdrsize], len, &repmsg); + if(err != nil) + continue; + if(repmsg.id == reqno && (repmsg.flags & Omask) == Onotify) + break; + } + + close(fd); +} + +/* send notifies for any updated areas */ +static void +notify_areas(Area *a, Request *req) +{ + Server *s; + + for(; a != nil; a = a->next){ + if(!a->neednotify) + continue; + + /* send notifies to all slaves */ + for(s = a->soarr->soa->slaves; s != nil; s = s->next) + send_notify(s->name, a->soarr, req); + a->neednotify = 0; + } +} + +/* + * process to notify other servers of changes + * (also reads in new databases) + */ +void +notifyproc(void) +{ + Request req; + static int already; + + if(already) + return; + + switch(rfork(RFPROC|RFNOTEG|RFMEM|RFNOWAIT)){ + case -1: + return; + case 0: + break; + default: + return; + } + + req.isslave = 1; /* son't fork off subprocesses */ + + for(;;){ + getactivity(&req); + notify_areas(owned, &req); + putactivity(); + sleep(60*1000); + } +} -- cgit v1.2.3