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