]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/ndb/dnnotify.c
ndb/dns: various changes
[plan9front.git] / sys / src / cmd / ndb / dnnotify.c
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 }