xref: /plan9/sys/src/cmd/ndb/dnnotify.c (revision 98813beef1db23409911a4b339e6bb9c03d0a5c0)
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
dnnotify(DNSmsg * reqp,DNSmsg * repp,Request *)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
send_notify(char * slave,RR * soa,Request * req)49 send_notify(char *slave, RR *soa, Request *req)
50 {
51 	int i, len, n, reqno, status, fd;
52 	char *err;
53 	uchar ibuf[Maxpayload+Udphdrsize], obuf[Maxpayload+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
notify_areas(Area * a,Request * req)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
notifyproc(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