1 #include <u.h> 2 #include <libc.h> 3 #include <ip.h> 4 #include <bio.h> 5 #include <ndb.h> 6 #include "dns.h" 7 8 /* get a notification from another system of a changed zone */ 9 void 10 dnnotify(DNSmsg *reqp, DNSmsg *repp, Request *) 11 { 12 RR *tp; 13 Area *a; 14 15 /* move one question from reqp to repp */ 16 memset(repp, 0, sizeof(*repp)); 17 tp = reqp->qd; 18 reqp->qd = tp->next; 19 tp->next = 0; 20 repp->qd = tp; 21 repp->id = reqp->id; 22 repp->flags = Fresp | Onotify | Fauth; 23 24 /* anything to do? */ 25 if(zonerefreshprogram == nil) 26 return; 27 28 /* make sure its the right type */ 29 if(repp->qd->type != Tsoa) 30 return; 31 32 dnslog("notification for %s", repp->qd->owner->name); 33 34 /* is it something we care about? */ 35 a = inmyarea(repp->qd->owner->name); 36 if(a == nil) 37 return; 38 39 dnslog("serial old %lud new %lud", a->soarr->soa->serial, 40 repp->qd->soa->serial); 41 42 /* do nothing if it didn't change */ 43 if(a->soarr->soa->serial != repp->qd->soa->serial) 44 a->needrefresh = 1; 45 } 46 47 /* notify a slave that an area has changed. */ 48 static void 49 send_notify(char *slave, RR *soa, Request *req) 50 { 51 int i, len, n, reqno, status, fd; 52 char *err; 53 uchar ibuf[Maxudp+Udphdrsize], obuf[Maxudp+Udphdrsize]; 54 RR *rp; 55 Udphdr *up = (Udphdr*)obuf; 56 DNSmsg repmsg; 57 58 /* create the request */ 59 reqno = rand(); 60 n = mkreq(soa->owner, Cin, obuf, Fauth | Onotify, reqno); 61 62 /* get an address */ 63 if(strcmp(ipattr(slave), "ip") == 0) { 64 if (parseip(up->raddr, slave) == -1) 65 dnslog("bad address %s to notify", slave); 66 } else { 67 rp = dnresolve(slave, Cin, Ta, req, nil, 0, 1, 1, &status); 68 if(rp == nil) 69 rp = dnresolve(slave, Cin, Taaaa, req, nil, 0, 1, 1, &status); 70 if(rp == nil) 71 return; 72 parseip(up->raddr, rp->ip->name); 73 rrfreelist(rp); /* was rrfree */ 74 } 75 76 fd = udpport(nil); 77 if(fd < 0) 78 return; 79 80 /* send 3 times or until we get anything back */ 81 n += Udphdrsize; 82 for(i = 0; i < 3; i++, freeanswers(&repmsg)){ 83 dnslog("sending %d byte notify to %s/%I.%d about %s", n, slave, 84 up->raddr, nhgets(up->rport), soa->owner->name); 85 memset(&repmsg, 0, sizeof repmsg); 86 if(write(fd, obuf, n) != n) 87 break; 88 alarm(2*1000); 89 len = read(fd, ibuf, sizeof ibuf); 90 alarm(0); 91 if(len <= Udphdrsize) 92 continue; 93 err = convM2DNS(&ibuf[Udphdrsize], len, &repmsg, nil); 94 if(err != nil) { 95 free(err); 96 continue; 97 } 98 if(repmsg.id == reqno && (repmsg.flags & Omask) == Onotify) 99 break; 100 } 101 if (i < 3) 102 freeanswers(&repmsg); 103 close(fd); 104 } 105 106 /* send notifies for any updated areas */ 107 static void 108 notify_areas(Area *a, Request *req) 109 { 110 Server *s; 111 112 for(; a != nil; a = a->next){ 113 if(!a->neednotify) 114 continue; 115 116 /* send notifies to all slaves */ 117 for(s = a->soarr->soa->slaves; s != nil; s = s->next) 118 send_notify(s->name, a->soarr, req); 119 a->neednotify = 0; 120 } 121 } 122 123 /* 124 * process to notify other servers of changes 125 * (also reads in new databases) 126 */ 127 void 128 notifyproc(void) 129 { 130 Request req; 131 132 switch(rfork(RFPROC|RFNOTEG|RFMEM|RFNOWAIT)){ 133 case -1: 134 return; 135 case 0: 136 break; 137 default: 138 return; 139 } 140 141 procsetname("notify slaves"); 142 memset(&req, 0, sizeof req); 143 req.isslave = 1; /* don't fork off subprocesses */ 144 145 for(;;){ 146 getactivity(&req, 0); 147 notify_areas(owned, &req); 148 putactivity(0); 149 sleep(60*1000); 150 } 151 } 152