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 * r)10 dnnotify(DNSmsg *reqp, DNSmsg *repp, Request *r)
11 {
12 	RR *tp;
13 	Area *a;
14 
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;
24 
25 	/* anything to do? */
26 	if(zonerefreshprogram == nil)
27 		return;
28 
29 	/* make sure its the right type */
30 	if(repp->qd->type != Tsoa)
31 		return;
32 
33 syslog(0, logfile, "notification for %s", repp->qd->owner->name);
34 
35 	/* is it something we care about? */
36 	a = inmyarea(repp->qd->owner->name);
37 	if(a == nil)
38 		return;
39 
40 syslog(0, logfile, "serial old %lud new %lud", a->soarr->soa->serial, repp->qd->soa->serial);
41 
42 	/* do nothing if it didn't change */
43 	if(a->soarr->soa->serial== repp->qd->soa->serial)
44 		return;
45 
46 	a->needrefresh = 1;
47 }
48 
49 /*
50  * this isn't going to work as a thread!
51  */
52 
53 static void
ding(void * u,char * msg)54 ding(void *u, char *msg)
55 {
56 	USED(u);
57 
58 	if(strstr(msg, "alarm"))
59 		noted(NCONT);
60 	else
61 		noted(NDFLT);
62 }
63 
64 /* notify a slave that an area has changed. */
65 static void
send_notify(char * slave,RR * soa,Request * req)66 send_notify(char *slave, RR *soa, Request *req)
67 {
68 	int i, len, n, reqno, status, fd;
69 	uchar obuf[Maxudp+Udphdrsize];
70 	uchar ibuf[Maxudp+Udphdrsize];
71 	RR *rp;
72 	Udphdr *up = (Udphdr*)obuf;
73 	char *err;
74 	DNSmsg repmsg;
75 
76 	/* create the request */
77 	reqno = rand();
78 	n = mkreq(soa->owner, Cin, obuf, Fauth | Onotify, reqno);
79 
80 	/* get an address */
81 	if(strcmp(ipattr(slave), "ip") == 0) {
82 		parseip(up->raddr, slave);
83 	} else {
84 		rp = dnresolve(slave, Cin, Ta, req, nil, 0, 1, 1, &status);
85 		if(rp == nil)
86 			return;
87 		parseip(up->raddr, rp->ip->name);
88 		rrfree(rp);
89 	}
90 
91 	fd = udpport();
92 	if(fd < 0)
93 		return;
94 
95 	notify(ding);
96 
97 	/* send 3 times or until we get anything back */
98 	for(i = 0; i < 3; i++){
99 syslog(0, logfile, "sending %d byte notify to %s/%I.%d about %s", n, slave, up->raddr, nhgets(up->rport), soa->owner->name);
100 		if(udpwrite(fd, (Udphdr*)obuf, obuf+Udphdrsize, n) != n)
101 			break;
102 		alarm(2*1000);
103 		len = udpread(fd, (Udphdr*)ibuf, ibuf+Udphdrsize, Maxudp);
104 		alarm(0);
105 		if(len <= Udphdrsize)
106 			continue;
107 		err = convM2DNS(&ibuf[Udphdrsize], len, &repmsg);
108 		if(err != nil)
109 			continue;
110 		if(repmsg.id == reqno && (repmsg.flags & Omask) == Onotify)
111 			break;
112 	}
113 
114 	close(fd);
115 }
116 
117 /* send notifies for any updated areas */
118 static void
notify_areas(Area * a,Request * req)119 notify_areas(Area *a, Request *req)
120 {
121 	Server *s;
122 
123 	for(; a != nil; a = a->next){
124 		if(!a->neednotify)
125 			continue;
126 
127 		/* send notifies to all slaves */
128 		for(s = a->soarr->soa->slaves; s != nil; s = s->next)
129 			send_notify(s->name, a->soarr, req);
130 		a->neednotify = 0;
131 	}
132 }
133 
134 /*
135  *  process to notify other servers of changes
136  *  (also reads in new databases)
137  */
138 void
notifyproc(void * v)139 notifyproc(void *v)
140 {
141 	Request req;
142 
143 	USED(v);
144 
145 	for(;;){
146 		getactivity(&req);
147 		notify_areas(owned, &req);
148 		putactivity();
149 		sleep(60*1000);
150 	}
151 }
152