|  | #include <u.h> | 
|  | #include <libc.h> | 
|  | #include <ip.h> | 
|  | #include <bio.h> | 
|  | #include <ndb.h> | 
|  | #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; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * this isn't going to work as a thread! | 
|  | */ | 
|  |  | 
|  | 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+Udphdrsize]; | 
|  | uchar ibuf[Maxudp+Udphdrsize]; | 
|  | RR *rp; | 
|  | Udphdr *up = (Udphdr*)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, (Udphdr*)obuf, obuf+Udphdrsize, n) != n) | 
|  | break; | 
|  | alarm(2*1000); | 
|  | len = udpread(fd, (Udphdr*)ibuf, ibuf+Udphdrsize, Maxudp); | 
|  | alarm(0); | 
|  | if(len <= Udphdrsize) | 
|  | continue; | 
|  | err = convM2DNS(&ibuf[Udphdrsize], 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 *v) | 
|  | { | 
|  | Request req; | 
|  |  | 
|  | USED(v); | 
|  |  | 
|  | for(;;){ | 
|  | getactivity(&req); | 
|  | notify_areas(owned, &req); | 
|  | putactivity(); | 
|  | sleep(60*1000); | 
|  | } | 
|  | } |