Blob


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