xref: /openbsd/usr.sbin/nsd/xfrd-notify.c (revision eab1363e)
1 /*
2  * xfrd-notify.c - notify sending routines
3  *
4  * Copyright (c) 2006, NLnet Labs. All rights reserved.
5  *
6  * See LICENSE for the license.
7  *
8  */
9 
10 #include "config.h"
11 #include <assert.h>
12 #include <string.h>
13 #include <unistd.h>
14 #include <errno.h>
15 #include "xfrd-notify.h"
16 #include "xfrd.h"
17 #include "xfrd-tcp.h"
18 #include "packet.h"
19 
20 #define XFRD_NOTIFY_RETRY_TIMOUT 3 /* seconds between retries sending NOTIFY */
21 
22 /* start sending notifies */
23 static void notify_enable(struct notify_zone* zone,
24 	struct xfrd_soa* new_soa);
25 /* setup the notify active state */
26 static void setup_notify_active(struct notify_zone* zone);
27 
28 /* handle zone notify send */
29 static void xfrd_handle_notify_send(int fd, short event, void* arg);
30 
31 static int xfrd_notify_send_udp(struct notify_zone* zone, int index);
32 
33 static void
notify_send_disable(struct notify_zone * zone)34 notify_send_disable(struct notify_zone* zone)
35 {
36 	zone->notify_send_enable = 0;
37 	event_del(&zone->notify_send_handler);
38 	if(zone->notify_send_handler.ev_fd != -1) {
39 		close(zone->notify_send_handler.ev_fd);
40 		zone->notify_send_handler.ev_fd = -1;
41 	}
42 }
43 
44 static void
notify_send6_disable(struct notify_zone * zone)45 notify_send6_disable(struct notify_zone* zone)
46 {
47 	zone->notify_send6_enable = 0;
48 	event_del(&zone->notify_send6_handler);
49 	if(zone->notify_send6_handler.ev_fd != -1) {
50 		close(zone->notify_send6_handler.ev_fd);
51 		zone->notify_send6_handler.ev_fd = -1;
52 	}
53 }
54 
55 void
notify_disable(struct notify_zone * zone)56 notify_disable(struct notify_zone* zone)
57 {
58 	zone->notify_current = 0;
59 	/* if added, then remove */
60 	if(zone->notify_send_enable) {
61 		notify_send_disable(zone);
62 	}
63 	if(zone->notify_send6_enable) {
64 		notify_send6_disable(zone);
65 	}
66 
67 	if(xfrd->notify_udp_num == XFRD_MAX_UDP_NOTIFY) {
68 		/* find next waiting and needy zone */
69 		while(xfrd->notify_waiting_first) {
70 			/* snip off */
71 			struct notify_zone* wz = xfrd->notify_waiting_first;
72 			assert(wz->is_waiting);
73 			wz->is_waiting = 0;
74 			xfrd->notify_waiting_first = wz->waiting_next;
75 			if(wz->waiting_next)
76 				wz->waiting_next->waiting_prev = NULL;
77 			if(xfrd->notify_waiting_last == wz)
78 				xfrd->notify_waiting_last = NULL;
79 			/* see if this zone needs notify sending */
80 			if(wz->notify_current) {
81 				DEBUG(DEBUG_XFRD,1, (LOG_INFO,
82 					"xfrd: zone %s: notify off waiting list.",
83 					zone->apex_str)	);
84 				setup_notify_active(wz);
85 				return;
86 			}
87 		}
88 	}
89 	xfrd->notify_udp_num--;
90 }
91 
92 void
init_notify_send(rbtree_type * tree,region_type * region,struct zone_options * options)93 init_notify_send(rbtree_type* tree, region_type* region,
94 	struct zone_options* options)
95 {
96 	struct notify_zone* not = (struct notify_zone*)
97 		region_alloc(region, sizeof(struct notify_zone));
98 	memset(not, 0, sizeof(struct notify_zone));
99 	not->apex = options->node.key;
100 	not->apex_str = options->name;
101 	not->node.key = not->apex;
102 	not->options = options;
103 
104 	/* if master zone and have a SOA */
105 	not->current_soa = (struct xfrd_soa*)region_alloc(region,
106 		sizeof(struct xfrd_soa));
107 	memset(not->current_soa, 0, sizeof(struct xfrd_soa));
108 
109 	not->notify_send_handler.ev_fd = -1;
110 	not->notify_send6_handler.ev_fd = -1;
111 	not->is_waiting = 0;
112 
113 	not->notify_send_enable = 0;
114 	not->notify_send6_enable = 0;
115 	tsig_create_record_custom(&not->notify_tsig, NULL, 0, 0, 4);
116 	not->notify_current = 0;
117 	rbtree_insert(tree, (rbnode_type*)not);
118 }
119 
120 void
xfrd_del_notify(xfrd_state_type * xfrd,const dname_type * dname)121 xfrd_del_notify(xfrd_state_type* xfrd, const dname_type* dname)
122 {
123 	/* find it */
124 	struct notify_zone* not = (struct notify_zone*)rbtree_delete(
125 		xfrd->notify_zones, dname);
126 	if(!not)
127 		return;
128 
129 	/* waiting list */
130 	if(not->is_waiting) {
131 		if(not->waiting_prev)
132 			not->waiting_prev->waiting_next = not->waiting_next;
133 		else	xfrd->notify_waiting_first = not->waiting_next;
134 		if(not->waiting_next)
135 			not->waiting_next->waiting_prev = not->waiting_prev;
136 		else	xfrd->notify_waiting_last = not->waiting_prev;
137 		not->is_waiting = 0;
138 	}
139 
140 	/* event */
141 	if(not->notify_send_enable || not->notify_send6_enable) {
142 		notify_disable(not);
143 	}
144 
145 	/* del tsig */
146 	tsig_delete_record(&not->notify_tsig, NULL);
147 
148 	/* free it */
149 	region_recycle(xfrd->region, not->current_soa, sizeof(xfrd_soa_type));
150 	/* the apex is recycled when the zone_options.node.key is removed */
151 	region_recycle(xfrd->region, not, sizeof(*not));
152 }
153 
154 static int
reply_pkt_is_ack(struct notify_zone * zone,buffer_type * packet,int index)155 reply_pkt_is_ack(struct notify_zone* zone, buffer_type* packet, int index)
156 {
157 	if((OPCODE(packet) != OPCODE_NOTIFY) ||
158 		(QR(packet) == 0)) {
159 		log_msg(LOG_ERR, "xfrd: zone %s: received bad notify reply opcode/flags from %s",
160 			zone->apex_str, zone->pkts[index].dest->ip_address_spec);
161 
162 		return 0;
163 	}
164 	/* we know it is OPCODE NOTIFY, QUERY_REPLY and for this zone */
165 	if(ID(packet) != zone->pkts[index].notify_query_id) {
166 		log_msg(LOG_ERR, "xfrd: zone %s: received notify-ack with bad ID from %s",
167 			zone->apex_str, zone->pkts[index].dest->ip_address_spec);
168 		return 0;
169 	}
170 	/* could check tsig, but why. The reply does not cause processing. */
171 	if(RCODE(packet) != RCODE_OK) {
172 		log_msg(LOG_ERR, "xfrd: zone %s: received notify response error %s from %s",
173 			zone->apex_str, rcode2str(RCODE(packet)),
174 			zone->pkts[index].dest->ip_address_spec);
175 		if(RCODE(packet) == RCODE_IMPL)
176 			return 1; /* rfc1996: notimpl notify reply: consider retries done */
177 		return 0;
178 	}
179 	DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: zone %s: host %s acknowledges notify",
180 		zone->apex_str, zone->pkts[index].dest->ip_address_spec));
181 	return 1;
182 }
183 
184 /* compare sockaddr and acl_option addr and port numbers */
185 static int
cmp_addr_equal(struct sockaddr * a,socklen_t a_len,struct acl_options * dest)186 cmp_addr_equal(struct sockaddr* a, socklen_t a_len, struct acl_options* dest)
187 {
188 	if(dest) {
189 		unsigned int destport = ((dest->port == 0)?
190 			(unsigned)atoi(TCP_PORT):dest->port);
191 #ifdef INET6
192 		struct sockaddr_storage* a1 = (struct sockaddr_storage*)a;
193 		if(a1->ss_family == AF_INET6 && dest->is_ipv6) {
194 			struct sockaddr_in6* a2 = (struct sockaddr_in6*)a;
195 			if(a_len < sizeof(struct sockaddr_in6))
196 				return 0; /* too small */
197 			if(ntohs(a2->sin6_port) != destport)
198 				return 0; /* different port number */
199 			if(memcmp(&a2->sin6_addr, &dest->addr.addr6,
200 				sizeof(struct in6_addr)) != 0)
201 				return 0; /* different address */
202 			return 1;
203 		}
204 		if(a1->ss_family == AF_INET6 || dest->is_ipv6)
205 			return 0; /* different address family */
206 		else {
207 #endif /* INET6 */
208 			struct sockaddr_in* a3 = (struct sockaddr_in*)a;
209 			if(a_len < sizeof(struct sockaddr_in))
210 				return 0; /* too small */
211 			if(ntohs(a3->sin_port) != destport)
212 				return 0; /* different port number */
213 			if(memcmp(&a3->sin_addr, &dest->addr.addr,
214 				sizeof(struct in_addr)) != 0)
215 				return 0; /* different address */
216 			return 1;
217 #ifdef INET6
218 		}
219 #endif
220 	}
221 	return 0;
222 }
223 
224 static void
notify_pkt_done(struct notify_zone * zone,int index)225 notify_pkt_done(struct notify_zone* zone, int index)
226 {
227 	zone->pkts[index].dest = NULL;
228 	zone->pkts[index].notify_retry = 0;
229 	zone->pkts[index].send_time = 0;
230 	zone->pkts[index].notify_query_id = 0;
231 	zone->notify_pkt_count--;
232 }
233 
234 static void
notify_pkt_retry(struct notify_zone * zone,int index)235 notify_pkt_retry(struct notify_zone* zone, int index)
236 {
237 	if(++zone->pkts[index].notify_retry >=
238 		zone->options->pattern->notify_retry) {
239 		log_msg(LOG_ERR, "xfrd: zone %s: max notify send count reached, %s unreachable",
240 			zone->apex_str,
241 			zone->pkts[index].dest->ip_address_spec);
242 		notify_pkt_done(zone, index);
243 		return;
244 	}
245 	if(!xfrd_notify_send_udp(zone, index)) {
246 		notify_pkt_retry(zone, index);
247 	}
248 }
249 
250 static void
xfrd_handle_notify_reply(struct notify_zone * zone,buffer_type * packet,struct sockaddr * src,socklen_t srclen)251 xfrd_handle_notify_reply(struct notify_zone* zone, buffer_type* packet,
252 	struct sockaddr* src, socklen_t srclen)
253 {
254 	int i;
255 	for(i=0; i<NOTIFY_CONCURRENT_MAX; i++) {
256 		/* is this entry in use */
257 		if(!zone->pkts[i].dest)
258 			continue;
259 		/* based on destination */
260 		if(!cmp_addr_equal(src, srclen, zone->pkts[i].dest))
261 			continue;
262 		if(reply_pkt_is_ack(zone, packet, i)) {
263 			/* is done */
264 			notify_pkt_done(zone, i);
265 			return;
266 		} else {
267 			/* retry */
268 			notify_pkt_retry(zone, i);
269 			return;
270 		}
271 	}
272 }
273 
274 static int
xfrd_notify_send_udp(struct notify_zone * zone,int index)275 xfrd_notify_send_udp(struct notify_zone* zone, int index)
276 {
277 	buffer_type* packet = xfrd_get_temp_buffer();
278 	if(!zone->pkts[index].dest) return 0;
279 	/* send NOTIFY to secondary. */
280 	xfrd_setup_packet(packet, TYPE_SOA, CLASS_IN, zone->apex,
281 		qid_generate());
282 	zone->pkts[index].notify_query_id = ID(packet);
283 	OPCODE_SET(packet, OPCODE_NOTIFY);
284 	AA_SET(packet);
285 	if(zone->current_soa->serial != 0) {
286 		/* add current SOA to answer section */
287 		ANCOUNT_SET(packet, 1);
288 		xfrd_write_soa_buffer(packet, zone->apex, zone->current_soa);
289 	}
290 	if(zone->pkts[index].dest->key_options) {
291 		xfrd_tsig_sign_request(packet, &zone->notify_tsig, zone->pkts[index].dest);
292 	}
293 	buffer_flip(packet);
294 
295 	if((zone->pkts[index].dest->is_ipv6
296 		&& zone->notify_send6_handler.ev_fd == -1) ||
297 		(!zone->pkts[index].dest->is_ipv6
298 		&& zone->notify_send_handler.ev_fd == -1)) {
299 		/* open fd */
300 		int fd = xfrd_send_udp(zone->pkts[index].dest, packet,
301 			zone->options->pattern->outgoing_interface);
302 		if(fd == -1) {
303 			log_msg(LOG_ERR, "xfrd: zone %s: could not send notify #%d to %s",
304 				zone->apex_str, zone->pkts[index].notify_retry,
305 				zone->pkts[index].dest->ip_address_spec);
306 			return 0;
307 		}
308 		if(zone->pkts[index].dest->is_ipv6)
309 			zone->notify_send6_handler.ev_fd = fd;
310 		else	zone->notify_send_handler.ev_fd = fd;
311 	} else {
312 		/* send on existing fd */
313 #ifdef INET6
314         	struct sockaddr_storage to;
315 #else
316         	struct sockaddr_in to;
317 #endif /* INET6 */
318 		int fd;
319 		socklen_t to_len = xfrd_acl_sockaddr_to(
320 			zone->pkts[index].dest, &to);
321 		if(zone->pkts[index].dest->is_ipv6)
322 			fd = zone->notify_send6_handler.ev_fd;
323 		else	fd = zone->notify_send_handler.ev_fd;
324 		if(sendto(fd,
325 			buffer_current(packet), buffer_remaining(packet), 0,
326 			(struct sockaddr*)&to, to_len) == -1) {
327 			log_msg(LOG_ERR, "xfrd notify: sendto %s failed %s",
328 				zone->pkts[index].dest->ip_address_spec,
329 				strerror(errno));
330 			return 0;
331 		}
332 	}
333 	zone->pkts[index].send_time = time(NULL);
334 	DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: zone %s: sent notify #%d to %s",
335 		zone->apex_str, zone->pkts[index].notify_retry,
336 		zone->pkts[index].dest->ip_address_spec));
337 	return 1;
338 }
339 
340 static void
notify_timeout_check(struct notify_zone * zone)341 notify_timeout_check(struct notify_zone* zone)
342 {
343 	time_t now = time(NULL);
344 	int i;
345 	for(i=0; i<NOTIFY_CONCURRENT_MAX; i++) {
346 		if(!zone->pkts[i].dest)
347 			continue;
348 		if(now >= zone->pkts[i].send_time + XFRD_NOTIFY_RETRY_TIMOUT) {
349 			notify_pkt_retry(zone, i);
350 		}
351 	}
352 }
353 
354 static void
notify_start_pkts(struct notify_zone * zone)355 notify_start_pkts(struct notify_zone* zone)
356 {
357 	int i;
358 	if(!zone->notify_current) return; /* no more acl to send to */
359 	for(i=0; i<NOTIFY_CONCURRENT_MAX; i++) {
360 		/* while loop, in case the retries all fail, and we can
361 		 * start another on this slot, or run out of notify acls */
362 		while(zone->pkts[i].dest==NULL && zone->notify_current) {
363 			zone->pkts[i].dest = zone->notify_current;
364 			zone->notify_current = zone->notify_current->next;
365 			zone->pkts[i].notify_retry = 0;
366 			zone->pkts[i].notify_query_id = 0;
367 			zone->pkts[i].send_time = 0;
368 			zone->notify_pkt_count++;
369 			if(!xfrd_notify_send_udp(zone, i)) {
370 				notify_pkt_retry(zone, i);
371 			}
372 		}
373 	}
374 }
375 
376 static void
notify_setup_event(struct notify_zone * zone)377 notify_setup_event(struct notify_zone* zone)
378 {
379 	if(zone->notify_send_handler.ev_fd != -1) {
380 		int fd = zone->notify_send_handler.ev_fd;
381 		if(zone->notify_send_enable) {
382 			event_del(&zone->notify_send_handler);
383 		}
384 		zone->notify_timeout.tv_sec = XFRD_NOTIFY_RETRY_TIMOUT;
385 		memset(&zone->notify_send_handler, 0,
386 			sizeof(zone->notify_send_handler));
387 		event_set(&zone->notify_send_handler, fd, EV_READ | EV_TIMEOUT,
388 			xfrd_handle_notify_send, zone);
389 		if(event_base_set(xfrd->event_base, &zone->notify_send_handler) != 0)
390 			log_msg(LOG_ERR, "notify_send: event_base_set failed");
391 		if(event_add(&zone->notify_send_handler, &zone->notify_timeout) != 0)
392 			log_msg(LOG_ERR, "notify_send: event_add failed");
393 		zone->notify_send_enable = 1;
394 	}
395 	if(zone->notify_send6_handler.ev_fd != -1) {
396 		int fd = zone->notify_send6_handler.ev_fd;
397 		if(zone->notify_send6_enable) {
398 			event_del(&zone->notify_send6_handler);
399 		}
400 		zone->notify_timeout.tv_sec = XFRD_NOTIFY_RETRY_TIMOUT;
401 		memset(&zone->notify_send6_handler, 0,
402 			sizeof(zone->notify_send6_handler));
403 		event_set(&zone->notify_send6_handler, fd, EV_READ | EV_TIMEOUT,
404 			xfrd_handle_notify_send, zone);
405 		if(event_base_set(xfrd->event_base, &zone->notify_send6_handler) != 0)
406 			log_msg(LOG_ERR, "notify_send: event_base_set failed");
407 		if(event_add(&zone->notify_send6_handler, &zone->notify_timeout) != 0)
408 			log_msg(LOG_ERR, "notify_send: event_add failed");
409 		zone->notify_send6_enable = 1;
410 	}
411 }
412 
413 static void
xfrd_handle_notify_send(int fd,short event,void * arg)414 xfrd_handle_notify_send(int fd, short event, void* arg)
415 {
416 	struct notify_zone* zone = (struct notify_zone*)arg;
417 	buffer_type* packet = xfrd_get_temp_buffer();
418 	if(zone->is_waiting) {
419 		DEBUG(DEBUG_XFRD,1, (LOG_INFO,
420 			"xfrd: notify waiting, skipped, %s", zone->apex_str));
421 		return;
422 	}
423 	if((event & EV_READ)) {
424 		struct sockaddr_storage src;
425 		socklen_t srclen = (socklen_t)sizeof(src);
426 		DEBUG(DEBUG_XFRD,1, (LOG_INFO,
427 			"xfrd: zone %s: read notify ACK", zone->apex_str));
428 		assert(fd != -1);
429 		if(xfrd_udp_read_packet(packet, fd, (struct sockaddr*)&src,
430 			&srclen)) {
431 			/* find entry, send retry or make entry NULL */
432 			xfrd_handle_notify_reply(zone, packet,
433 				(struct sockaddr*)&src, srclen);
434 		}
435 	}
436 	if((event & EV_TIMEOUT)) {
437 		DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: zone %s: notify timeout",
438 			zone->apex_str));
439 		/* timeout, try again */
440 	}
441 
442 	/* see which pkts have timeouted, retry or NULL them */
443 	notify_timeout_check(zone);
444 
445 	/* start new packets if we have empty space */
446 	notify_start_pkts(zone);
447 
448 	/* see if we are done */
449 	if(!zone->notify_current && !zone->notify_pkt_count) {
450 		/* we are done */
451 		DEBUG(DEBUG_XFRD,1, (LOG_INFO,
452 			"xfrd: zone %s: no more notify-send acls. stop notify.",
453 			zone->apex_str));
454 		notify_disable(zone);
455 		return;
456 	}
457 
458 	notify_setup_event(zone);
459 }
460 
461 static void
setup_notify_active(struct notify_zone * zone)462 setup_notify_active(struct notify_zone* zone)
463 {
464 	zone->notify_pkt_count = 0;
465 	memset(zone->pkts, 0, sizeof(zone->pkts));
466 	zone->notify_current = zone->options->pattern->notify;
467 	zone->notify_timeout.tv_sec = 0;
468 	zone->notify_timeout.tv_usec = 0;
469 
470 	if(zone->notify_send_enable)
471 		notify_send_disable(zone);
472 	memset(&zone->notify_send_handler, 0,
473 		sizeof(zone->notify_send_handler));
474 	event_set(&zone->notify_send_handler, -1, EV_TIMEOUT,
475 		xfrd_handle_notify_send, zone);
476 	if(event_base_set(xfrd->event_base, &zone->notify_send_handler) != 0)
477 		log_msg(LOG_ERR, "notifysend: event_base_set failed");
478 	if(evtimer_add(&zone->notify_send_handler, &zone->notify_timeout) != 0)
479 		log_msg(LOG_ERR, "notifysend: evtimer_add failed");
480 	zone->notify_send_enable = 1;
481 }
482 
483 static void
notify_enable(struct notify_zone * zone,struct xfrd_soa * new_soa)484 notify_enable(struct notify_zone* zone, struct xfrd_soa* new_soa)
485 {
486 	if(!zone->options->pattern->notify) {
487 		return; /* no notify acl, nothing to do */
488 	}
489 
490 	if(new_soa == NULL)
491 		memset(zone->current_soa, 0, sizeof(xfrd_soa_type));
492 	else
493 		memcpy(zone->current_soa, new_soa, sizeof(xfrd_soa_type));
494 	if(zone->is_waiting)
495 		return;
496 
497 	if(xfrd->notify_udp_num < XFRD_MAX_UDP_NOTIFY) {
498 		setup_notify_active(zone);
499 		xfrd->notify_udp_num++;
500 		return;
501 	}
502 	/* put it in waiting list */
503 	zone->notify_current = zone->options->pattern->notify;
504 	zone->is_waiting = 1;
505 	zone->waiting_next = NULL;
506 	zone->waiting_prev = xfrd->notify_waiting_last;
507 	if(xfrd->notify_waiting_last) {
508 		xfrd->notify_waiting_last->waiting_next = zone;
509 	} else {
510 		xfrd->notify_waiting_first = zone;
511 	}
512 	xfrd->notify_waiting_last = zone;
513 	DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: zone %s: notify on waiting list.",
514 		zone->apex_str));
515 }
516 
517 void
xfrd_notify_start(struct notify_zone * zone,struct xfrd_state * xfrd)518 xfrd_notify_start(struct notify_zone* zone, struct xfrd_state* xfrd)
519 {
520 	xfrd_zone_type* xz;
521 	if(zone->is_waiting || zone->notify_send_enable ||
522 		zone->notify_send6_enable)
523 		return;
524 	xz = (xfrd_zone_type*)rbtree_search(xfrd->zones, zone->apex);
525 	if(xz && xz->soa_nsd_acquired)
526 		notify_enable(zone, &xz->soa_nsd);
527 	else	notify_enable(zone, NULL);
528 }
529 
530 void
xfrd_send_notify(rbtree_type * tree,const dname_type * apex,struct xfrd_soa * new_soa)531 xfrd_send_notify(rbtree_type* tree, const dname_type* apex, struct xfrd_soa* new_soa)
532 {
533 	/* lookup the zone */
534 	struct notify_zone* zone = (struct notify_zone*)
535 		rbtree_search(tree, apex);
536 	assert(zone);
537 	if(zone->notify_send_enable || zone->notify_send6_enable)
538 		notify_disable(zone);
539 
540 	notify_enable(zone, new_soa);
541 }
542 
543 void
notify_handle_master_zone_soainfo(rbtree_type * tree,const dname_type * apex,struct xfrd_soa * new_soa)544 notify_handle_master_zone_soainfo(rbtree_type* tree,
545 	const dname_type* apex, struct xfrd_soa* new_soa)
546 {
547 	/* lookup the zone */
548 	struct notify_zone* zone = (struct notify_zone*)
549 		rbtree_search(tree, apex);
550 	if(!zone) return; /* got SOAINFO but zone was deleted meanwhile */
551 
552 	/* check if SOA changed */
553 	if( (new_soa == NULL && zone->current_soa->serial == 0) ||
554 		(new_soa && new_soa->serial == zone->current_soa->serial))
555 		return;
556 	if(zone->notify_send_enable || zone->notify_send6_enable)
557 		notify_disable(zone);
558 	notify_enable(zone, new_soa);
559 }
560 
561 void
close_notify_fds(rbtree_type * tree)562 close_notify_fds(rbtree_type* tree)
563 {
564 	struct notify_zone* zone;
565 	RBTREE_FOR(zone, struct notify_zone*, tree)
566 	{
567 		if(zone->notify_send_enable || zone->notify_send6_enable)
568 			notify_send_disable(zone);
569 	}
570 }
571