xref: /freebsd/contrib/ntp/ntpd/ntp_restrict.c (revision 02e9120893770924227138ba49df1edb3896112a)
1 /*
2  * ntp_restrict.c - determine host restrictions
3  */
4 #ifdef HAVE_CONFIG_H
5 #include <config.h>
6 #endif
7 
8 #include <stdio.h>
9 #include <sys/types.h>
10 
11 #include "ntpd.h"
12 #include "ntp_if.h"
13 #include "ntp_lists.h"
14 #include "ntp_stdlib.h"
15 #include "ntp_assert.h"
16 
17 /*
18  * This code keeps a simple address-and-mask list of hosts we want
19  * to place restrictions on (or remove them from). The restrictions
20  * are implemented as a set of flags which tell you what the host
21  * can't do. There is a subroutine entry to return the flags. The
22  * list is kept sorted to reduce the average number of comparisons
23  * and make sure you get the set of restrictions most specific to
24  * the address.
25  *
26  * The algorithm is that, when looking up a host, it is first assumed
27  * that the default set of restrictions will apply. It then searches
28  * down through the list. Whenever it finds a match it adopts the
29  * match's flags instead. When you hit the point where the sorted
30  * address is greater than the target, you return with the last set of
31  * flags you found. Because of the ordering of the list, the most
32  * specific match will provide the final set of flags.
33  *
34  * This was originally intended to restrict you from sync'ing to your
35  * own broadcasts when you are doing that, by restricting yourself from
36  * your own interfaces. It was also thought it would sometimes be useful
37  * to keep a misbehaving host or two from abusing your primary clock. It
38  * has been expanded, however, to suit the needs of those with more
39  * restrictive access policies.
40  */
41 /*
42  * We will use two lists, one for IPv4 addresses and one for IPv6
43  * addresses. This is not protocol-independant but for now I can't
44  * find a way to respect this. We'll check this later... JFB 07/2001
45  */
46 #define MASK_IPV6_ADDR(dst, src, msk)					\
47 	do {								\
48 		int idx;						\
49 		for (idx = 0; idx < (int)COUNTOF((dst)->s6_addr); idx++) { \
50 			(dst)->s6_addr[idx] = (src)->s6_addr[idx]	\
51 					      & (msk)->s6_addr[idx];	\
52 		}							\
53 	} while (0)
54 
55 /*
56  * We allocate INC_RESLIST{4|6} entries to the free list whenever empty.
57  * Auto-tune these to be just less than 1KB (leaving at least 16 bytes
58  * for allocator overhead).
59  */
60 #define	INC_RESLIST4	((1024 - 16) / V4_SIZEOF_RESTRICT_U)
61 #define	INC_RESLIST6	((1024 - 16) / V6_SIZEOF_RESTRICT_U)
62 
63 /*
64  * The restriction list
65  */
66 restrict_u *restrictlist4;
67 restrict_u *restrictlist6;
68 static int restrictcount;	/* count in the restrict lists */
69 
70 /*
71  * The free list and associated counters.  Also some uninteresting
72  * stat counters.
73  */
74 static restrict_u *resfree4;	/* available entries (free list) */
75 static restrict_u *resfree6;
76 
77 static u_long res_calls;
78 static u_long res_found;
79 static u_long res_not_found;
80 
81 /*
82  * Count number of restriction entries referring to RES_LIMITED, to
83  * control implicit activation/deactivation of the MRU monlist.
84  */
85 static	u_long res_limited_refcnt;
86 
87 /*
88  * Our default entries.
89  *
90  * We can make this cleaner with c99 support: see init_restrict().
91  */
92 static	restrict_u	restrict_def4;
93 static	restrict_u	restrict_def6;
94 
95 /*
96  * "restrict source ..." enabled knob and restriction bits.
97  */
98 static	int		restrict_source_enabled;
99 static	u_int32		restrict_source_rflags;
100 static	u_short		restrict_source_mflags;
101 static	short		restrict_source_ippeerlimit;
102 
103 /*
104  * private functions
105  */
106 static restrict_u *	alloc_res4(void);
107 static restrict_u *	alloc_res6(void);
108 static void		free_res(restrict_u *, int);
109 static void		inc_res_limited(void);
110 static void		dec_res_limited(void);
111 static restrict_u *	match_restrict4_addr(u_int32, u_short);
112 static restrict_u *	match_restrict6_addr(const struct in6_addr *,
113 					     u_short);
114 static restrict_u *	match_restrict_entry(const restrict_u *, int);
115 static int		res_sorts_before4(restrict_u *, restrict_u *);
116 static int		res_sorts_before6(restrict_u *, restrict_u *);
117 static char *		roptoa(restrict_op op);
118 
119 
120 void	dump_restricts(void);
121 
122 /*
123  * dump_restrict - spit out a restrict_u
124  */
125 static void
126 dump_restrict(
127 	restrict_u *	res,
128 	int		is_ipv6
129 	)
130 {
131 	char as[INET6_ADDRSTRLEN];
132 	char ms[INET6_ADDRSTRLEN];
133 
134 	if (is_ipv6) {
135 		inet_ntop(AF_INET6, &res->u.v6.addr, as, sizeof as);
136 		inet_ntop(AF_INET6, &res->u.v6.mask, ms, sizeof ms);
137 	} else {
138 		struct in_addr	sia = { htonl(res->u.v4.addr) };
139 		struct in_addr	sim = { htonl(res->u.v4.mask) };
140 
141 		inet_ntop(AF_INET, &sia, as, sizeof as);
142 		inet_ntop(AF_INET, &sim, ms, sizeof ms);
143 	}
144 	mprintf("restrict node at %p: %s/%s count %d, rflags %08x, mflags %04x, ippeerlimit %d, expire %lu, next %p\n",
145 		res, as, ms, res->count, res->rflags, res->mflags,
146 		res->ippeerlimit, res->expire, res->link);
147 	return;
148 }
149 
150 
151 /*
152  * dump_restricts - spit out the 'restrict' lines
153  */
154 void
155 dump_restricts(void)
156 {
157 	restrict_u *	res;
158 	restrict_u *	next;
159 
160 	mprintf("dump_restrict: restrict_def4: %p\n", &restrict_def4);
161 	/* Spit out 'restrict {,-4,-6} default ...' lines, if needed */
162 	for (res = &restrict_def4; res != NULL; res = next) {
163 		dump_restrict(res, 0);
164 		next = res->link;
165 	}
166 
167 	mprintf("dump_restrict: restrict_def6: %p\n", &restrict_def6);
168 	for (res = &restrict_def6; res != NULL; res = next) {
169 		dump_restrict(res, 1);
170 		next = res->link;
171 	}
172 
173 	/* Spit out the IPv4 list */
174 	mprintf("dump_restrict: restrictlist4: %p\n", &restrictlist4);
175 	for (res = restrictlist4; res != NULL; res = next) {
176 		dump_restrict(res, 0);
177 		next = res->link;
178 	}
179 
180 	/* Spit out the IPv6 list */
181 	mprintf("dump_restrict: restrictlist6: %p\n", &restrictlist6);
182 	for (res = restrictlist6; res != NULL; res = next) {
183 		dump_restrict(res, 1);
184 		next = res->link;
185 	}
186 
187 	return;
188 }
189 
190 /*
191  * init_restrict - initialize the restriction data structures
192  */
193 void
194 init_restrict(void)
195 {
196 	/*
197 	 * The restriction lists begin with a default entry with address
198 	 * and mask 0, which will match any entry.  The lists are kept
199 	 * sorted by descending address followed by descending mask:
200 	 *
201 	 *   address	  mask
202 	 * 192.168.0.0	255.255.255.0	kod limited noquery nopeer
203 	 * 192.168.0.0	255.255.0.0	kod limited
204 	 * 0.0.0.0	0.0.0.0		kod limited noquery
205 	 *
206 	 * The first entry which matches an address is used.  With the
207 	 * example restrictions above, 192.168.0.0/24 matches the first
208 	 * entry, the rest of 192.168.0.0/16 matches the second, and
209 	 * everything else matches the third (default).
210 	 *
211 	 * Note this achieves the same result a little more efficiently
212 	 * than the documented behavior, which is to keep the lists
213 	 * sorted by ascending address followed by ascending mask, with
214 	 * the _last_ matching entry used.
215 	 *
216 	 * An additional wrinkle is we may have multiple entries with
217 	 * the same address and mask but differing match flags (mflags).
218 	 * At present there is only one, RESM_NTPONLY.  Entries with
219 	 * RESM_NTPONLY are sorted earlier so they take precedence over
220 	 * any otherwise similar entry without.  Again, this is the same
221 	 * behavior as but reversed implementation compared to the docs.
222 	 *
223 	 */
224 
225 	restrict_def4.ippeerlimit = -1;		/* Cleaner if we have C99 */
226 	restrict_def6.ippeerlimit = -1;		/* Cleaner if we have C99 */
227 
228 	LINK_SLIST(restrictlist4, &restrict_def4, link);
229 	LINK_SLIST(restrictlist6, &restrict_def6, link);
230 	restrictcount = 2;
231 }
232 
233 
234 static restrict_u *
235 alloc_res4(void)
236 {
237 	const size_t	cb = V4_SIZEOF_RESTRICT_U;
238 	const size_t	count = INC_RESLIST4;
239 	restrict_u *	rl;
240 	restrict_u *	res;
241 	size_t		i;
242 
243 	UNLINK_HEAD_SLIST(res, resfree4, link);
244 	if (res != NULL)
245 		return res;
246 
247 	rl = eallocarray(count, cb);
248 	/* link all but the first onto free list */
249 	res = (void *)((char *)rl + (count - 1) * cb);
250 	for (i = count - 1; i > 0; i--) {
251 		LINK_SLIST(resfree4, res, link);
252 		res = (void *)((char *)res - cb);
253 	}
254 	INSIST(rl == res);
255 	/* allocate the first */
256 	return res;
257 }
258 
259 
260 static restrict_u *
261 alloc_res6(void)
262 {
263 	const size_t	cb = V6_SIZEOF_RESTRICT_U;
264 	const size_t	count = INC_RESLIST6;
265 	restrict_u *	rl;
266 	restrict_u *	res;
267 	size_t		i;
268 
269 	UNLINK_HEAD_SLIST(res, resfree6, link);
270 	if (res != NULL)
271 		return res;
272 
273 	rl = eallocarray(count, cb);
274 	/* link all but the first onto free list */
275 	res = (void *)((char *)rl + (count - 1) * cb);
276 	for (i = count - 1; i > 0; i--) {
277 		LINK_SLIST(resfree6, res, link);
278 		res = (void *)((char *)res - cb);
279 	}
280 	INSIST(rl == res);
281 	/* allocate the first */
282 	return res;
283 }
284 
285 
286 static void
287 free_res(
288 	restrict_u *	res,
289 	int		v6
290 	)
291 {
292 	restrict_u **	plisthead;
293 	restrict_u *	unlinked;
294 
295 	restrictcount--;
296 	if (RES_LIMITED & res->rflags)
297 		dec_res_limited();
298 
299 	if (v6)
300 		plisthead = &restrictlist6;
301 	else
302 		plisthead = &restrictlist4;
303 	UNLINK_SLIST(unlinked, *plisthead, res, link, restrict_u);
304 	INSIST(unlinked == res);
305 
306 	if (v6) {
307 		zero_mem(res, V6_SIZEOF_RESTRICT_U);
308 		plisthead = &resfree6;
309 	} else {
310 		zero_mem(res, V4_SIZEOF_RESTRICT_U);
311 		plisthead = &resfree4;
312 	}
313 	LINK_SLIST(*plisthead, res, link);
314 }
315 
316 
317 static void
318 inc_res_limited(void)
319 {
320 	if (!res_limited_refcnt)
321 		mon_start(MON_RES);
322 	res_limited_refcnt++;
323 }
324 
325 
326 static void
327 dec_res_limited(void)
328 {
329 	res_limited_refcnt--;
330 	if (!res_limited_refcnt)
331 		mon_stop(MON_RES);
332 }
333 
334 
335 static restrict_u *
336 match_restrict4_addr(
337 	u_int32	addr,
338 	u_short	port
339 	)
340 {
341 	const int	v6 = 0;
342 	restrict_u *	res;
343 	restrict_u *	next;
344 
345 	for (res = restrictlist4; res != NULL; res = next) {
346 		struct in_addr	sia = { htonl(res->u.v4.addr) };
347 
348 		next = res->link;
349 		DPRINTF(2, ("match_restrict4_addr: Checking %s, port %d ... ",
350 			    inet_ntoa(sia), port));
351 		if (   res->expire
352 		    && res->expire <= current_time)
353 			free_res(res, v6);	/* zeroes the contents */
354 		if (   res->u.v4.addr == (addr & res->u.v4.mask)
355 		    && (   !(RESM_NTPONLY & res->mflags)
356 			|| NTP_PORT == port)) {
357 			DPRINTF(2, ("MATCH: ippeerlimit %d\n", res->ippeerlimit));
358 			break;
359 		}
360 		DPRINTF(2, ("doesn't match: ippeerlimit %d\n", res->ippeerlimit));
361 	}
362 	return res;
363 }
364 
365 
366 static restrict_u *
367 match_restrict6_addr(
368 	const struct in6_addr *	addr,
369 	u_short			port
370 	)
371 {
372 	const int	v6 = 1;
373 	restrict_u *	res;
374 	restrict_u *	next;
375 	struct in6_addr	masked;
376 
377 	for (res = restrictlist6; res != NULL; res = next) {
378 		next = res->link;
379 		INSIST(next != res);
380 		if (res->expire &&
381 		    res->expire <= current_time)
382 			free_res(res, v6);
383 		MASK_IPV6_ADDR(&masked, addr, &res->u.v6.mask);
384 		if (ADDR6_EQ(&masked, &res->u.v6.addr)
385 		    && (!(RESM_NTPONLY & res->mflags)
386 			|| NTP_PORT == (int)port))
387 			break;
388 	}
389 	return res;
390 }
391 
392 
393 /*
394  * match_restrict_entry - find an exact match on a restrict list.
395  *
396  * Exact match is addr, mask, and mflags all equal.
397  * In order to use more common code for IPv4 and IPv6, this routine
398  * requires the caller to populate a restrict_u with mflags and either
399  * the v4 or v6 address and mask as appropriate.  Other fields in the
400  * input restrict_u are ignored.
401  */
402 static restrict_u *
403 match_restrict_entry(
404 	const restrict_u *	pmatch,
405 	int			v6
406 	)
407 {
408 	restrict_u *res;
409 	restrict_u *rlist;
410 	size_t cb;
411 
412 	if (v6) {
413 		rlist = restrictlist6;
414 		cb = sizeof(pmatch->u.v6);
415 	} else {
416 		rlist = restrictlist4;
417 		cb = sizeof(pmatch->u.v4);
418 	}
419 
420 	for (res = rlist; res != NULL; res = res->link)
421 		if (res->mflags == pmatch->mflags &&
422 		    !memcmp(&res->u, &pmatch->u, cb))
423 			break;
424 	return res;
425 }
426 
427 
428 /*
429  * res_sorts_before4 - compare two restrict4 entries
430  *
431  * Returns nonzero if r1 sorts before r2.  We sort by descending
432  * address, then descending mask, then descending mflags, so sorting
433  * before means having a higher value.
434  */
435 static int
436 res_sorts_before4(
437 	restrict_u *r1,
438 	restrict_u *r2
439 	)
440 {
441 	int r1_before_r2;
442 
443 	if (r1->u.v4.addr > r2->u.v4.addr)
444 		r1_before_r2 = 1;
445 	else if (r1->u.v4.addr < r2->u.v4.addr)
446 		r1_before_r2 = 0;
447 	else if (r1->u.v4.mask > r2->u.v4.mask)
448 		r1_before_r2 = 1;
449 	else if (r1->u.v4.mask < r2->u.v4.mask)
450 		r1_before_r2 = 0;
451 	else if (r1->mflags > r2->mflags)
452 		r1_before_r2 = 1;
453 	else
454 		r1_before_r2 = 0;
455 
456 	return r1_before_r2;
457 }
458 
459 
460 /*
461  * res_sorts_before6 - compare two restrict6 entries
462  *
463  * Returns nonzero if r1 sorts before r2.  We sort by descending
464  * address, then descending mask, then descending mflags, so sorting
465  * before means having a higher value.
466  */
467 static int
468 res_sorts_before6(
469 	restrict_u *r1,
470 	restrict_u *r2
471 	)
472 {
473 	int r1_before_r2;
474 	int cmp;
475 
476 	cmp = ADDR6_CMP(&r1->u.v6.addr, &r2->u.v6.addr);
477 	if (cmp > 0)		/* r1->addr > r2->addr */
478 		r1_before_r2 = 1;
479 	else if (cmp < 0)	/* r2->addr > r1->addr */
480 		r1_before_r2 = 0;
481 	else {
482 		cmp = ADDR6_CMP(&r1->u.v6.mask, &r2->u.v6.mask);
483 		if (cmp > 0)		/* r1->mask > r2->mask*/
484 			r1_before_r2 = 1;
485 		else if (cmp < 0)	/* r2->mask > r1->mask */
486 			r1_before_r2 = 0;
487 		else if (r1->mflags > r2->mflags)
488 			r1_before_r2 = 1;
489 		else
490 			r1_before_r2 = 0;
491 	}
492 
493 	return r1_before_r2;
494 }
495 
496 
497 /*
498  * restrictions - return restrictions for this host in *r4a
499  */
500 void
501 restrictions(
502 	sockaddr_u *srcadr,
503 	r4addr *r4a
504 	)
505 {
506 	restrict_u *match;
507 	struct in6_addr *pin6;
508 
509 	REQUIRE(NULL != r4a);
510 
511 	res_calls++;
512 	r4a->rflags = RES_IGNORE;
513 	r4a->ippeerlimit = 0;
514 
515 	DPRINTF(1, ("restrictions: looking up %s\n", stoa(srcadr)));
516 
517 	/* IPv4 source address */
518 	if (IS_IPV4(srcadr)) {
519 		/*
520 		 * Ignore any packets with a multicast source address
521 		 * (this should be done early in the receive process,
522 		 * not later!)
523 		 */
524 		if (IN_CLASSD(SRCADR(srcadr))) {
525 			DPRINTF(1, ("restrictions: srcadr %s is multicast\n", stoa(srcadr)));
526 			r4a->ippeerlimit = 2;	/* XXX: we should use a better value */
527 			return;
528 		}
529 
530 		match = match_restrict4_addr(SRCADR(srcadr),
531 					     SRCPORT(srcadr));
532 
533 		INSIST(match != NULL);
534 
535 		match->count++;
536 		/*
537 		 * res_not_found counts only use of the final default
538 		 * entry, not any "restrict default ntpport ...", which
539 		 * would be just before the final default.
540 		 */
541 		if (&restrict_def4 == match)
542 			res_not_found++;
543 		else
544 			res_found++;
545 		r4a->rflags = match->rflags;
546 		r4a->ippeerlimit = match->ippeerlimit;
547 	}
548 
549 	/* IPv6 source address */
550 	if (IS_IPV6(srcadr)) {
551 		pin6 = PSOCK_ADDR6(srcadr);
552 
553 		/*
554 		 * Ignore any packets with a multicast source address
555 		 * (this should be done early in the receive process,
556 		 * not later!)
557 		 */
558 		if (IN6_IS_ADDR_MULTICAST(pin6))
559 			return;
560 
561 		match = match_restrict6_addr(pin6, SRCPORT(srcadr));
562 		INSIST(match != NULL);
563 		match->count++;
564 		if (&restrict_def6 == match)
565 			res_not_found++;
566 		else
567 			res_found++;
568 		r4a->rflags = match->rflags;
569 		r4a->ippeerlimit = match->ippeerlimit;
570 	}
571 
572 	return;
573 }
574 
575 
576 /*
577  * roptoa - convert a restrict_op to a string
578  */
579 char *
580 roptoa(restrict_op op) {
581 	static char sb[30];
582 
583 	switch(op) {
584 	    case RESTRICT_FLAGS:	return "RESTRICT_FLAGS";
585 	    case RESTRICT_UNFLAG:	return "RESTRICT_UNFLAGS";
586 	    case RESTRICT_REMOVE:	return "RESTRICT_REMOVE";
587 	    case RESTRICT_REMOVEIF:	return "RESTRICT_REMOVEIF";
588 	    default:
589 		snprintf(sb, sizeof sb, "**RESTRICT_#%d**", op);
590 		return sb;
591 	}
592 }
593 
594 
595 /*
596  * hack_restrict - add/subtract/manipulate entries on the restrict list
597  */
598 void
599 hack_restrict(
600 	restrict_op	op,
601 	sockaddr_u *	resaddr,
602 	sockaddr_u *	resmask,
603 	short		ippeerlimit,
604 	u_short		mflags,
605 	u_short		rflags,
606 	u_long		expire
607 	)
608 {
609 	int		v6;
610 	restrict_u	match;
611 	restrict_u *	res;
612 	restrict_u **	plisthead;
613 
614 	DPRINTF(1, ("hack_restrict: op %s addr %s mask %s ippeerlimit %d mflags %08x rflags %08x\n",
615 		    roptoa(op), stoa(resaddr), stoa(resmask), ippeerlimit, mflags, rflags));
616 
617 	if (NULL == resaddr) {
618 		REQUIRE(NULL == resmask);
619 		REQUIRE(RESTRICT_FLAGS == op);
620 		restrict_source_rflags = rflags;
621 		restrict_source_mflags = mflags;
622 		restrict_source_ippeerlimit = ippeerlimit;
623 		restrict_source_enabled = 1;
624 		return;
625 	}
626 
627 	ZERO(match);
628 
629 #if 0
630 	/* silence VC9 potentially uninit warnings */
631 	// HMS: let's use a compiler-specific "enable" for this.
632 	res = NULL;
633 	v6 = 0;
634 #endif
635 
636 	if (IS_IPV4(resaddr)) {
637 		v6 = 0;
638 		/*
639 		 * Get address and mask in host byte order for easy
640 		 * comparison as u_int32
641 		 */
642 		match.u.v4.addr = SRCADR(resaddr);
643 		match.u.v4.mask = SRCADR(resmask);
644 		match.u.v4.addr &= match.u.v4.mask;
645 
646 	} else if (IS_IPV6(resaddr)) {
647 		v6 = 1;
648 		/*
649 		 * Get address and mask in network byte order for easy
650 		 * comparison as byte sequences (e.g. memcmp())
651 		 */
652 		match.u.v6.mask = SOCK_ADDR6(resmask);
653 		MASK_IPV6_ADDR(&match.u.v6.addr, PSOCK_ADDR6(resaddr),
654 			       &match.u.v6.mask);
655 
656 	} else	/* not IPv4 nor IPv6 */
657 		REQUIRE(0);
658 
659 	match.rflags = rflags;
660 	match.mflags = mflags;
661 	match.ippeerlimit = ippeerlimit;
662 	match.expire = expire;
663 	res = match_restrict_entry(&match, v6);
664 
665 	switch (op) {
666 
667 	case RESTRICT_FLAGS:
668 		/*
669 		 * Here we add bits to the rflags. If this is a
670 		 * new restriction add it.
671 		 */
672 		if (NULL == res) {
673 			if (v6) {
674 				res = alloc_res6();
675 				memcpy(res, &match,
676 				       V6_SIZEOF_RESTRICT_U);
677 				plisthead = &restrictlist6;
678 			} else {
679 				res = alloc_res4();
680 				memcpy(res, &match,
681 				       V4_SIZEOF_RESTRICT_U);
682 				plisthead = &restrictlist4;
683 			}
684 			LINK_SORT_SLIST(
685 				*plisthead, res,
686 				(v6)
687 				  ? res_sorts_before6(res, L_S_S_CUR())
688 				  : res_sorts_before4(res, L_S_S_CUR()),
689 				link, restrict_u);
690 			restrictcount++;
691 			if (RES_LIMITED & rflags)
692 				inc_res_limited();
693 		} else {
694 			if (   (RES_LIMITED & rflags)
695 			    && !(RES_LIMITED & res->rflags))
696 				inc_res_limited();
697 			res->rflags |= rflags;
698 		}
699 
700 		res->ippeerlimit = match.ippeerlimit;
701 
702 		break;
703 
704 	case RESTRICT_UNFLAG:
705 		/*
706 		 * Remove some bits from the rflags. If we didn't
707 		 * find this one, just return.
708 		 */
709 		if (res != NULL) {
710 			if (   (RES_LIMITED & res->rflags)
711 			    && (RES_LIMITED & rflags))
712 				dec_res_limited();
713 			res->rflags &= ~rflags;
714 		}
715 		break;
716 
717 	case RESTRICT_REMOVE:
718 	case RESTRICT_REMOVEIF:
719 		/*
720 		 * Remove an entry from the table entirely if we
721 		 * found one. Don't remove the default entry and
722 		 * don't remove an interface entry.
723 		 */
724 		if (res != NULL
725 		    && (RESTRICT_REMOVEIF == op
726 			|| !(RESM_INTERFACE & res->mflags))
727 		    && res != &restrict_def4
728 		    && res != &restrict_def6)
729 			free_res(res, v6);
730 		break;
731 
732 	default:	/* unknown op */
733 		INSIST(0);
734 		break;
735 	}
736 
737 }
738 
739 
740 /*
741  * restrict_source - maintains dynamic "restrict source ..." entries as
742  *		     peers come and go.
743  */
744 void
745 restrict_source(
746 	sockaddr_u *	addr,
747 	int		farewell,	/* 0 to add, 1 to remove */
748 	u_long		expire		/* 0 is infinite, valid until */
749 	)
750 {
751 	sockaddr_u	onesmask;
752 	restrict_u *	res;
753 	int		found_specific;
754 
755 	if (!restrict_source_enabled || SOCK_UNSPEC(addr) ||
756 	    IS_MCAST(addr) || ISREFCLOCKADR(addr))
757 		return;
758 
759 	REQUIRE(AF_INET == AF(addr) || AF_INET6 == AF(addr));
760 
761 	SET_HOSTMASK(&onesmask, AF(addr));
762 	if (farewell) {
763 		hack_restrict(RESTRICT_REMOVE, addr, &onesmask,
764 			      -2, 0, 0, 0);
765 		DPRINTF(1, ("restrict_source: %s removed", stoa(addr)));
766 		return;
767 	}
768 
769 	/*
770 	 * If there is a specific entry for this address, hands
771 	 * off, as it is condidered more specific than "restrict
772 	 * server ...".
773 	 * However, if the specific entry found is a fleeting one
774 	 * added by pool_xmit() before soliciting, replace it
775 	 * immediately regardless of the expire value to make way
776 	 * for the more persistent entry.
777 	 */
778 	if (IS_IPV4(addr)) {
779 		res = match_restrict4_addr(SRCADR(addr), SRCPORT(addr));
780 		INSIST(res != NULL);
781 		found_specific = (SRCADR(&onesmask) == res->u.v4.mask);
782 	} else {
783 		res = match_restrict6_addr(&SOCK_ADDR6(addr),
784 					   SRCPORT(addr));
785 		INSIST(res != NULL);
786 		found_specific = ADDR6_EQ(&res->u.v6.mask,
787 					  &SOCK_ADDR6(&onesmask));
788 	}
789 	if (!expire && found_specific && res->expire) {
790 		found_specific = 0;
791 		free_res(res, IS_IPV6(addr));
792 	}
793 	if (found_specific)
794 		return;
795 
796 	hack_restrict(RESTRICT_FLAGS, addr, &onesmask,
797 		      restrict_source_ippeerlimit,
798 		      restrict_source_mflags, restrict_source_rflags, expire);
799 	DPRINTF(1, ("restrict_source: %s host restriction added\n",
800 		    stoa(addr)));
801 }
802