xref: /freebsd/contrib/ntp/ntpd/ntp_restrict.c (revision f5f40dd63bc7acbb5312b26ac1ea1103c12352a6)
1c0b746e5SOllivier Robert /*
29c2daa00SOllivier Robert  * ntp_restrict.c - determine host restrictions
3c0b746e5SOllivier Robert  */
4c0b746e5SOllivier Robert #ifdef HAVE_CONFIG_H
5c0b746e5SOllivier Robert #include <config.h>
6c0b746e5SOllivier Robert #endif
7c0b746e5SOllivier Robert 
8c0b746e5SOllivier Robert #include <stdio.h>
9c0b746e5SOllivier Robert #include <sys/types.h>
10c0b746e5SOllivier Robert 
11c0b746e5SOllivier Robert #include "ntpd.h"
12c0b746e5SOllivier Robert #include "ntp_if.h"
132b15cb3dSCy Schubert #include "ntp_lists.h"
14c0b746e5SOllivier Robert #include "ntp_stdlib.h"
152b15cb3dSCy Schubert #include "ntp_assert.h"
16c0b746e5SOllivier Robert 
17c0b746e5SOllivier Robert /*
18*f5f40dd6SCy Schubert  * This code keeps a simple address-and-mask list of addressses we want
19*f5f40dd6SCy Schubert  * to place restrictions on (or remove them from). The restrictions are
20*f5f40dd6SCy Schubert  * implemented as a set of flags which tell you what matching addresses
21*f5f40dd6SCy Schubert  * can't do.  The list is sorted retrieve the restrictions most specific
22*f5f40dd6SCy Schubert *  to the address.
23c0b746e5SOllivier Robert  *
24c0b746e5SOllivier Robert  * This was originally intended to restrict you from sync'ing to your
259c2daa00SOllivier Robert  * own broadcasts when you are doing that, by restricting yourself from
269c2daa00SOllivier Robert  * your own interfaces. It was also thought it would sometimes be useful
279c2daa00SOllivier Robert  * to keep a misbehaving host or two from abusing your primary clock. It
289c2daa00SOllivier Robert  * has been expanded, however, to suit the needs of those with more
299c2daa00SOllivier Robert  * restrictive access policies.
30c0b746e5SOllivier Robert  */
312b15cb3dSCy Schubert #define MASK_IPV6_ADDR(dst, src, msk)					\
329c2daa00SOllivier Robert 	do {								\
33*f5f40dd6SCy Schubert 		int x;							\
34*f5f40dd6SCy Schubert 									\
35*f5f40dd6SCy Schubert 		for (x = 0; x < (int)COUNTOF((dst)->s6_addr); x++) {	\
36*f5f40dd6SCy Schubert 			(dst)->s6_addr[x] =   (src)->s6_addr[x]		\
37*f5f40dd6SCy Schubert 					    & (msk)->s6_addr[x];	\
389c2daa00SOllivier Robert 		}							\
39*f5f40dd6SCy Schubert 	} while (FALSE)
40c0b746e5SOllivier Robert 
41c0b746e5SOllivier Robert /*
422b15cb3dSCy Schubert  * We allocate INC_RESLIST{4|6} entries to the free list whenever empty.
43*f5f40dd6SCy Schubert  * Auto-tune these to be just less than 1KB (leaving at least 32 bytes
442b15cb3dSCy Schubert  * for allocator overhead).
45c0b746e5SOllivier Robert  */
46*f5f40dd6SCy Schubert #define	INC_RESLIST4	((1024 - 32) / V4_SIZEOF_RESTRICT_U)
47*f5f40dd6SCy Schubert #define	INC_RESLIST6	((1024 - 32) / V6_SIZEOF_RESTRICT_U)
489c2daa00SOllivier Robert 
49c0b746e5SOllivier Robert /*
50c0b746e5SOllivier Robert  * The restriction list
51c0b746e5SOllivier Robert  */
522b15cb3dSCy Schubert restrict_u *restrictlist4;
532b15cb3dSCy Schubert restrict_u *restrictlist6;
542b15cb3dSCy Schubert static int restrictcount;	/* count in the restrict lists */
55c0b746e5SOllivier Robert 
56c0b746e5SOllivier Robert /*
57c0b746e5SOllivier Robert  * The free list and associated counters.  Also some uninteresting
58c0b746e5SOllivier Robert  * stat counters.
59c0b746e5SOllivier Robert  */
602b15cb3dSCy Schubert static restrict_u *resfree4;	/* available entries (free list) */
612b15cb3dSCy Schubert static restrict_u *resfree6;
62c0b746e5SOllivier Robert 
63c0b746e5SOllivier Robert static u_long res_calls;
64c0b746e5SOllivier Robert static u_long res_found;
65c0b746e5SOllivier Robert static u_long res_not_found;
66c0b746e5SOllivier Robert 
67c0b746e5SOllivier Robert /*
682b15cb3dSCy Schubert  * Count number of restriction entries referring to RES_LIMITED, to
692b15cb3dSCy Schubert  * control implicit activation/deactivation of the MRU monlist.
709c2daa00SOllivier Robert  */
719c2daa00SOllivier Robert static	u_long res_limited_refcnt;
729c2daa00SOllivier Robert 
739c2daa00SOllivier Robert /*
742b15cb3dSCy Schubert  * Our default entries.
7509100258SXin LI  *
7609100258SXin LI  * We can make this cleaner with c99 support: see init_restrict().
77c0b746e5SOllivier Robert  */
782b15cb3dSCy Schubert static	restrict_u	restrict_def4;
792b15cb3dSCy Schubert static	restrict_u	restrict_def6;
802b15cb3dSCy Schubert 
812b15cb3dSCy Schubert /*
822b15cb3dSCy Schubert  * "restrict source ..." enabled knob and restriction bits.
832b15cb3dSCy Schubert  */
842b15cb3dSCy Schubert static	int		restrict_source_enabled;
852d4e511cSCy Schubert static	u_int32		restrict_source_rflags;
862b15cb3dSCy Schubert static	u_short		restrict_source_mflags;
8709100258SXin LI static	short		restrict_source_ippeerlimit;
882b15cb3dSCy Schubert 
892b15cb3dSCy Schubert /*
902b15cb3dSCy Schubert  * private functions
912b15cb3dSCy Schubert  */
922b15cb3dSCy Schubert static	restrict_u *	alloc_res4(void);
932b15cb3dSCy Schubert static	restrict_u *	alloc_res6(void);
942b15cb3dSCy Schubert static	void		free_res(restrict_u *, int);
95*f5f40dd6SCy Schubert static	inline void	inc_res_limited(void);
96*f5f40dd6SCy Schubert static	inline void	dec_res_limited(void);
972b15cb3dSCy Schubert static	restrict_u *	match_restrict4_addr(u_int32, u_short);
982b15cb3dSCy Schubert static	restrict_u *	match_restrict6_addr(const struct in6_addr *,
992b15cb3dSCy Schubert 					     u_short);
1002b15cb3dSCy Schubert static	restrict_u *	match_restrict_entry(const restrict_u *, int);
101*f5f40dd6SCy Schubert static inline int/*BOOL*/	mflags_sorts_before(u_short, u_short);
102*f5f40dd6SCy Schubert static	int/*BOOL*/	res_sorts_before4(restrict_u *, restrict_u *);
103*f5f40dd6SCy Schubert static	int/*BOOL*/	res_sorts_before6(restrict_u *, restrict_u *);
104*f5f40dd6SCy Schubert 
105*f5f40dd6SCy Schubert typedef int (*res_sort_fn)(restrict_u *, restrict_u *);
1062b15cb3dSCy Schubert 
107c0b746e5SOllivier Robert 
108*f5f40dd6SCy Schubert /* dump_restrict() & dump_restricts() are DEBUG-only */
109*f5f40dd6SCy Schubert #ifdef DEBUG
110*f5f40dd6SCy Schubert static void		dump_restrict(restrict_u *, int);
111*f5f40dd6SCy Schubert 
11209100258SXin LI 
11309100258SXin LI /*
114*f5f40dd6SCy Schubert  * dump_restrict - spit out a single restriction entry
11509100258SXin LI  */
11609100258SXin LI static void
11709100258SXin LI dump_restrict(
11809100258SXin LI 	restrict_u *	res,
11909100258SXin LI 	int		is_ipv6
12009100258SXin LI )
12109100258SXin LI {
12209100258SXin LI 	char as[INET6_ADDRSTRLEN];
12309100258SXin LI 	char ms[INET6_ADDRSTRLEN];
12409100258SXin LI 
12509100258SXin LI 	if (is_ipv6) {
12609100258SXin LI 		inet_ntop(AF_INET6, &res->u.v6.addr, as, sizeof as);
12709100258SXin LI 		inet_ntop(AF_INET6, &res->u.v6.mask, ms, sizeof ms);
12809100258SXin LI 	} else {
129*f5f40dd6SCy Schubert 		struct in_addr	sia, sim;
13009100258SXin LI 
131*f5f40dd6SCy Schubert 		sia.s_addr = htonl(res->u.v4.addr);
132*f5f40dd6SCy Schubert 		sim.s_addr = htonl(res->u.v4.addr);
13309100258SXin LI 		inet_ntop(AF_INET, &sia, as, sizeof as);
13409100258SXin LI 		inet_ntop(AF_INET, &sim, ms, sizeof ms);
13509100258SXin LI 	}
136*f5f40dd6SCy Schubert 	printf("%s/%s: hits %u ippeerlimit %hd mflags %s rflags %s",
137*f5f40dd6SCy Schubert 		as, ms, res->count, res->ippeerlimit,
138*f5f40dd6SCy Schubert 		mflags_str(res->mflags),
139*f5f40dd6SCy Schubert 		rflags_str(res->rflags));
140*f5f40dd6SCy Schubert 	if (res->expire > 0) {
141*f5f40dd6SCy Schubert 		printf(" expire %u\n", res->expire);
142*f5f40dd6SCy Schubert 	} else {
143*f5f40dd6SCy Schubert 		printf("\n");
144*f5f40dd6SCy Schubert 	}
14509100258SXin LI }
14609100258SXin LI 
14709100258SXin LI 
14809100258SXin LI /*
149*f5f40dd6SCy Schubert  * dump_restricts - spit out the 'restrict' entries
15009100258SXin LI  */
15109100258SXin LI void
15209100258SXin LI dump_restricts(void)
15309100258SXin LI {
15409100258SXin LI 	restrict_u *	res;
15509100258SXin LI 
15609100258SXin LI 	/* Spit out the IPv4 list */
157*f5f40dd6SCy Schubert 	printf("dump_restricts: restrictlist4: %p\n", restrictlist4);
158*f5f40dd6SCy Schubert 	for (res = restrictlist4; res != NULL; res = res->link) {
15909100258SXin LI 		dump_restrict(res, 0);
16009100258SXin LI 	}
16109100258SXin LI 
16209100258SXin LI 	/* Spit out the IPv6 list */
163*f5f40dd6SCy Schubert 	printf("dump_restricts: restrictlist6: %p\n", restrictlist6);
164*f5f40dd6SCy Schubert 	for (res = restrictlist6; res != NULL; res = res->link) {
16509100258SXin LI 		dump_restrict(res, 1);
16609100258SXin LI 	}
167*f5f40dd6SCy Schubert }
168*f5f40dd6SCy Schubert #endif /* DEBUG - dump_restrict() / dump_restricts() */
16909100258SXin LI 
17009100258SXin LI 
171c0b746e5SOllivier Robert /*
172c0b746e5SOllivier Robert  * init_restrict - initialize the restriction data structures
173c0b746e5SOllivier Robert  */
174c0b746e5SOllivier Robert void
175c0b746e5SOllivier Robert init_restrict(void)
176c0b746e5SOllivier Robert {
177c0b746e5SOllivier Robert 	/*
178*f5f40dd6SCy Schubert 	 * The restriction lists end with a default entry with address
1792b15cb3dSCy Schubert 	 * and mask 0, which will match any entry.  The lists are kept
1802b15cb3dSCy Schubert 	 * sorted by descending address followed by descending mask:
1812b15cb3dSCy Schubert 	 *
1822b15cb3dSCy Schubert 	 *   address	  mask
1832b15cb3dSCy Schubert 	 * 192.168.0.0	255.255.255.0	kod limited noquery nopeer
1842b15cb3dSCy Schubert 	 * 192.168.0.0	255.255.0.0	kod limited
1852b15cb3dSCy Schubert 	 * 0.0.0.0	0.0.0.0		kod limited noquery
1862b15cb3dSCy Schubert 	 *
1872b15cb3dSCy Schubert 	 * The first entry which matches an address is used.  With the
1882b15cb3dSCy Schubert 	 * example restrictions above, 192.168.0.0/24 matches the first
1892b15cb3dSCy Schubert 	 * entry, the rest of 192.168.0.0/16 matches the second, and
1902b15cb3dSCy Schubert 	 * everything else matches the third (default).
1912b15cb3dSCy Schubert 	 *
1922b15cb3dSCy Schubert 	 * Note this achieves the same result a little more efficiently
1932b15cb3dSCy Schubert 	 * than the documented behavior, which is to keep the lists
1942b15cb3dSCy Schubert 	 * sorted by ascending address followed by ascending mask, with
1952b15cb3dSCy Schubert 	 * the _last_ matching entry used.
1962b15cb3dSCy Schubert 	 *
1972b15cb3dSCy Schubert 	 * An additional wrinkle is we may have multiple entries with
1982b15cb3dSCy Schubert 	 * the same address and mask but differing match flags (mflags).
199*f5f40dd6SCy Schubert 	 * We want to never talk to ourself, so RES_IGNORE entries for
200*f5f40dd6SCy Schubert 	 * each local address are added by ntp_io.c with a host mask and
201*f5f40dd6SCy Schubert 	 * both RESM_INTERFACE and RESM_NTPONLY set.  We sort those
202*f5f40dd6SCy Schubert 	 * entries before entries without those flags to achieve this.
203*f5f40dd6SCy Schubert 	 * The remaining match flag is RESM_SOURCE, used to dynamically
204*f5f40dd6SCy Schubert 	 * set restrictions for each peer based on the prototype set by
205*f5f40dd6SCy Schubert 	 * "restrict source" in the configuration.  We want those entries
206*f5f40dd6SCy Schubert 	 * to be considered only when there is not a static host
207*f5f40dd6SCy Schubert 	 * restriction for the address in the configuration, to allow
208*f5f40dd6SCy Schubert 	 * operators to blacklist pool and manycast servers at runtime as
209*f5f40dd6SCy Schubert 	 * desired using ntpq runtime configuration.  Such static entries
210*f5f40dd6SCy Schubert 	 * have no RESM_ bits set, so the sort order for mflags is first
211*f5f40dd6SCy Schubert 	 * RESM_INTERFACE, then entries without RESM_SOURCE, finally the
212*f5f40dd6SCy Schubert 	 * remaining.
213c0b746e5SOllivier Robert 	 */
21409100258SXin LI 
21509100258SXin LI 	restrict_def4.ippeerlimit = -1;		/* Cleaner if we have C99 */
21609100258SXin LI 	restrict_def6.ippeerlimit = -1;		/* Cleaner if we have C99 */
21709100258SXin LI 
2182b15cb3dSCy Schubert 	LINK_SLIST(restrictlist4, &restrict_def4, link);
2192b15cb3dSCy Schubert 	LINK_SLIST(restrictlist6, &restrict_def6, link);
2209c2daa00SOllivier Robert 	restrictcount = 2;
2212b15cb3dSCy Schubert }
2222b15cb3dSCy Schubert 
2232b15cb3dSCy Schubert 
2242b15cb3dSCy Schubert static restrict_u *
2252b15cb3dSCy Schubert alloc_res4(void)
2262b15cb3dSCy Schubert {
2272b15cb3dSCy Schubert 	const size_t	cb = V4_SIZEOF_RESTRICT_U;
2282b15cb3dSCy Schubert 	const size_t	count = INC_RESLIST4;
2292b15cb3dSCy Schubert 	restrict_u*	rl;
2302b15cb3dSCy Schubert 	restrict_u*	res;
2313311ff84SXin LI 	size_t		i;
2322b15cb3dSCy Schubert 
2332b15cb3dSCy Schubert 	UNLINK_HEAD_SLIST(res, resfree4, link);
234*f5f40dd6SCy Schubert 	if (res != NULL) {
2352b15cb3dSCy Schubert 		return res;
236*f5f40dd6SCy Schubert 	}
237f0574f5cSXin LI 	rl = eallocarray(count, cb);
2382b15cb3dSCy Schubert 	/* link all but the first onto free list */
2392b15cb3dSCy Schubert 	res = (void *)((char *)rl + (count - 1) * cb);
2402b15cb3dSCy Schubert 	for (i = count - 1; i > 0; i--) {
2412b15cb3dSCy Schubert 		LINK_SLIST(resfree4, res, link);
2422b15cb3dSCy Schubert 		res = (void *)((char *)res - cb);
2432b15cb3dSCy Schubert 	}
244*f5f40dd6SCy Schubert 	DEBUG_INSIST(rl == res);
2452b15cb3dSCy Schubert 	/* allocate the first */
2462b15cb3dSCy Schubert 	return res;
2472b15cb3dSCy Schubert }
2482b15cb3dSCy Schubert 
2492b15cb3dSCy Schubert 
2502b15cb3dSCy Schubert static restrict_u *
2512b15cb3dSCy Schubert alloc_res6(void)
2522b15cb3dSCy Schubert {
2532b15cb3dSCy Schubert 	const size_t	cb = V6_SIZEOF_RESTRICT_U;
2542b15cb3dSCy Schubert 	const size_t	count = INC_RESLIST6;
2552b15cb3dSCy Schubert 	restrict_u *	rl;
2562b15cb3dSCy Schubert 	restrict_u *	res;
2573311ff84SXin LI 	size_t		i;
2582b15cb3dSCy Schubert 
2592b15cb3dSCy Schubert 	UNLINK_HEAD_SLIST(res, resfree6, link);
260*f5f40dd6SCy Schubert 	if (res != NULL) {
2612b15cb3dSCy Schubert 		return res;
262*f5f40dd6SCy Schubert 	}
263f0574f5cSXin LI 	rl = eallocarray(count, cb);
2642b15cb3dSCy Schubert 	/* link all but the first onto free list */
2652b15cb3dSCy Schubert 	res = (void *)((char *)rl + (count - 1) * cb);
2662b15cb3dSCy Schubert 	for (i = count - 1; i > 0; i--) {
2672b15cb3dSCy Schubert 		LINK_SLIST(resfree6, res, link);
2682b15cb3dSCy Schubert 		res = (void *)((char *)res - cb);
2692b15cb3dSCy Schubert 	}
270*f5f40dd6SCy Schubert 	DEBUG_INSIST(rl == res);
2712b15cb3dSCy Schubert 	/* allocate the first */
2722b15cb3dSCy Schubert 	return res;
2732b15cb3dSCy Schubert }
2742b15cb3dSCy Schubert 
2752b15cb3dSCy Schubert 
2762b15cb3dSCy Schubert static void
2772b15cb3dSCy Schubert free_res(
2782b15cb3dSCy Schubert 	restrict_u *	res,
2792b15cb3dSCy Schubert 	int		v6
2802b15cb3dSCy Schubert 	)
2812b15cb3dSCy Schubert {
282*f5f40dd6SCy Schubert 	restrict_u **	rlisthead_ptr;
283*f5f40dd6SCy Schubert 	restrict_u **	flisthead_ptr;
2842b15cb3dSCy Schubert 	restrict_u *	unlinked;
285*f5f40dd6SCy Schubert 	size_t		sz;
2862b15cb3dSCy Schubert 
2872b15cb3dSCy Schubert 	restrictcount--;
288*f5f40dd6SCy Schubert 	if (RES_LIMITED & res->rflags) {
2892b15cb3dSCy Schubert 		dec_res_limited();
290*f5f40dd6SCy Schubert 	}
2912b15cb3dSCy Schubert 	if (v6) {
292*f5f40dd6SCy Schubert 		rlisthead_ptr = &restrictlist6;
293*f5f40dd6SCy Schubert 		flisthead_ptr = &resfree6;
294*f5f40dd6SCy Schubert 		sz = V6_SIZEOF_RESTRICT_U;
2952b15cb3dSCy Schubert 	} else {
296*f5f40dd6SCy Schubert 		rlisthead_ptr = &restrictlist4;
297*f5f40dd6SCy Schubert 		flisthead_ptr = &resfree4;
298*f5f40dd6SCy Schubert 		sz = V4_SIZEOF_RESTRICT_U;
2992b15cb3dSCy Schubert 	}
300*f5f40dd6SCy Schubert 	UNLINK_SLIST(unlinked, *rlisthead_ptr, res, link, restrict_u);
301*f5f40dd6SCy Schubert 	INSIST(unlinked == res);
302*f5f40dd6SCy Schubert 	zero_mem(res, sz);
303*f5f40dd6SCy Schubert 	LINK_SLIST(*flisthead_ptr, res, link);
3042b15cb3dSCy Schubert }
3052b15cb3dSCy Schubert 
3062b15cb3dSCy Schubert 
307*f5f40dd6SCy Schubert static inline void
3082b15cb3dSCy Schubert inc_res_limited(void)
3092b15cb3dSCy Schubert {
310*f5f40dd6SCy Schubert 	if (0 == res_limited_refcnt) {
3112b15cb3dSCy Schubert 		mon_start(MON_RES);
312*f5f40dd6SCy Schubert 	}
3132b15cb3dSCy Schubert 	res_limited_refcnt++;
3142b15cb3dSCy Schubert }
3152b15cb3dSCy Schubert 
3162b15cb3dSCy Schubert 
317*f5f40dd6SCy Schubert static inline void
3182b15cb3dSCy Schubert dec_res_limited(void)
3192b15cb3dSCy Schubert {
3202b15cb3dSCy Schubert 	res_limited_refcnt--;
321*f5f40dd6SCy Schubert 	if (0 == res_limited_refcnt) {
3222b15cb3dSCy Schubert 		mon_stop(MON_RES);
3232b15cb3dSCy Schubert 	}
324*f5f40dd6SCy Schubert }
3252b15cb3dSCy Schubert 
3262b15cb3dSCy Schubert 
3272b15cb3dSCy Schubert static restrict_u *
3282b15cb3dSCy Schubert match_restrict4_addr(
3292b15cb3dSCy Schubert 	u_int32	addr,
3302b15cb3dSCy Schubert 	u_short	port
3312b15cb3dSCy Schubert 	)
3322b15cb3dSCy Schubert {
333*f5f40dd6SCy Schubert 	const int	v6 = FALSE;
3342b15cb3dSCy Schubert 	restrict_u *	res;
3352b15cb3dSCy Schubert 	restrict_u *	next;
3362b15cb3dSCy Schubert 
3372b15cb3dSCy Schubert 	for (res = restrictlist4; res != NULL; res = next) {
3382b15cb3dSCy Schubert 		next = res->link;
339*f5f40dd6SCy Schubert 		if (res->expire && res->expire <= current_time) {
34009100258SXin LI 			free_res(res, v6);	/* zeroes the contents */
341*f5f40dd6SCy Schubert 		}
3422b15cb3dSCy Schubert 		if (   res->u.v4.addr == (addr & res->u.v4.mask)
3432b15cb3dSCy Schubert 		    && (   !(RESM_NTPONLY & res->mflags)
34409100258SXin LI 			|| NTP_PORT == port)) {
345*f5f40dd6SCy Schubert 
3462b15cb3dSCy Schubert 			break;
3472b15cb3dSCy Schubert 		}
34809100258SXin LI 	}
3492b15cb3dSCy Schubert 	return res;
3502b15cb3dSCy Schubert }
3512b15cb3dSCy Schubert 
3522b15cb3dSCy Schubert 
3532b15cb3dSCy Schubert static restrict_u *
3542b15cb3dSCy Schubert match_restrict6_addr(
3552b15cb3dSCy Schubert 	const struct in6_addr *	addr,
3562b15cb3dSCy Schubert 	u_short			port
3572b15cb3dSCy Schubert 	)
3582b15cb3dSCy Schubert {
359*f5f40dd6SCy Schubert 	const int	v6 = TRUE;
3602b15cb3dSCy Schubert 	restrict_u *	res;
3612b15cb3dSCy Schubert 	restrict_u *	next;
3622b15cb3dSCy Schubert 	struct in6_addr	masked;
3632b15cb3dSCy Schubert 
3642b15cb3dSCy Schubert 	for (res = restrictlist6; res != NULL; res = next) {
3652b15cb3dSCy Schubert 		next = res->link;
366*f5f40dd6SCy Schubert 		if (res->expire && res->expire <= current_time) {
3672b15cb3dSCy Schubert 			free_res(res, v6);
368*f5f40dd6SCy Schubert 		}
3692b15cb3dSCy Schubert 		MASK_IPV6_ADDR(&masked, addr, &res->u.v6.mask);
3702b15cb3dSCy Schubert 		if (ADDR6_EQ(&masked, &res->u.v6.addr)
3712b15cb3dSCy Schubert 		    && (   !(RESM_NTPONLY & res->mflags)
372*f5f40dd6SCy Schubert 			|| NTP_PORT == (int)port)) {
373*f5f40dd6SCy Schubert 
3742b15cb3dSCy Schubert 			break;
3752b15cb3dSCy Schubert 		}
376*f5f40dd6SCy Schubert 	}
3772b15cb3dSCy Schubert 	return res;
3782b15cb3dSCy Schubert }
3792b15cb3dSCy Schubert 
380c0b746e5SOllivier Robert 
381c0b746e5SOllivier Robert /*
3822b15cb3dSCy Schubert  * match_restrict_entry - find an exact match on a restrict list.
3832b15cb3dSCy Schubert  *
3842b15cb3dSCy Schubert  * Exact match is addr, mask, and mflags all equal.
3852b15cb3dSCy Schubert  * In order to use more common code for IPv4 and IPv6, this routine
3862b15cb3dSCy Schubert  * requires the caller to populate a restrict_u with mflags and either
3872b15cb3dSCy Schubert  * the v4 or v6 address and mask as appropriate.  Other fields in the
3882b15cb3dSCy Schubert  * input restrict_u are ignored.
389c0b746e5SOllivier Robert  */
3902b15cb3dSCy Schubert static restrict_u *
3912b15cb3dSCy Schubert match_restrict_entry(
3922b15cb3dSCy Schubert 	const restrict_u *	pmatch,
3932b15cb3dSCy Schubert 	int			v6
3942b15cb3dSCy Schubert 	)
3952b15cb3dSCy Schubert {
3962b15cb3dSCy Schubert 	restrict_u *res;
3972b15cb3dSCy Schubert 	restrict_u *rlist;
3982b15cb3dSCy Schubert 	size_t cb;
3992b15cb3dSCy Schubert 
4002b15cb3dSCy Schubert 	if (v6) {
4012b15cb3dSCy Schubert 		rlist = restrictlist6;
4022b15cb3dSCy Schubert 		cb = sizeof(pmatch->u.v6);
4032b15cb3dSCy Schubert 	} else {
4042b15cb3dSCy Schubert 		rlist = restrictlist4;
4052b15cb3dSCy Schubert 		cb = sizeof(pmatch->u.v4);
4062b15cb3dSCy Schubert 	}
4072b15cb3dSCy Schubert 
408*f5f40dd6SCy Schubert 	for (res = rlist; res != NULL; res = res->link) {
4092b15cb3dSCy Schubert 		if (res->mflags == pmatch->mflags &&
410*f5f40dd6SCy Schubert 		    !memcmp(&res->u, &pmatch->u, cb)) {
4112b15cb3dSCy Schubert 			break;
412*f5f40dd6SCy Schubert 		}
413*f5f40dd6SCy Schubert 	}
4142b15cb3dSCy Schubert 	return res;
4152b15cb3dSCy Schubert }
4162b15cb3dSCy Schubert 
417c0b746e5SOllivier Robert 
418c0b746e5SOllivier Robert /*
419*f5f40dd6SCy Schubert  * mflags_sorts_before - common mflags sorting code
420*f5f40dd6SCy Schubert  *
421*f5f40dd6SCy Schubert  * See block comment in init_restrict() above for rationale.
422*f5f40dd6SCy Schubert  */
423*f5f40dd6SCy Schubert static inline int/*BOOL*/
424*f5f40dd6SCy Schubert mflags_sorts_before(
425*f5f40dd6SCy Schubert 	u_short	m1,
426*f5f40dd6SCy Schubert 	u_short	m2
427*f5f40dd6SCy Schubert 	)
428*f5f40dd6SCy Schubert {
429*f5f40dd6SCy Schubert 	if (    (RESM_INTERFACE & m1)
430*f5f40dd6SCy Schubert 	    && !(RESM_INTERFACE & m2)) {
431*f5f40dd6SCy Schubert 		return TRUE;
432*f5f40dd6SCy Schubert 	} else if (   !(RESM_SOURCE & m1)
433*f5f40dd6SCy Schubert 		   &&  (RESM_SOURCE & m2)) {
434*f5f40dd6SCy Schubert 		return TRUE;
435*f5f40dd6SCy Schubert 	} else {
436*f5f40dd6SCy Schubert 		return FALSE;
437*f5f40dd6SCy Schubert 	}
438*f5f40dd6SCy Schubert }
439*f5f40dd6SCy Schubert 
440*f5f40dd6SCy Schubert 
441*f5f40dd6SCy Schubert /*
442*f5f40dd6SCy Schubert  * res_sorts_before4 - compare IPv4 restriction entries
4432b15cb3dSCy Schubert  *
4442b15cb3dSCy Schubert  * Returns nonzero if r1 sorts before r2.  We sort by descending
445*f5f40dd6SCy Schubert  * address, then descending mask, then an intricate mflags sort
446*f5f40dd6SCy Schubert  * order explained in a block comment near the top of this file.
447c0b746e5SOllivier Robert  */
448*f5f40dd6SCy Schubert static int/*BOOL*/
4492b15cb3dSCy Schubert res_sorts_before4(
4502b15cb3dSCy Schubert 	restrict_u *r1,
4512b15cb3dSCy Schubert 	restrict_u *r2
4522b15cb3dSCy Schubert 	)
4532b15cb3dSCy Schubert {
4542b15cb3dSCy Schubert 	int r1_before_r2;
4552b15cb3dSCy Schubert 
456*f5f40dd6SCy Schubert 	if (r1->u.v4.addr > r2->u.v4.addr) {
457*f5f40dd6SCy Schubert 		r1_before_r2 = TRUE;
458*f5f40dd6SCy Schubert 	} else if (r1->u.v4.addr < r2->u.v4.addr) {
459*f5f40dd6SCy Schubert 		r1_before_r2 = FALSE;
460*f5f40dd6SCy Schubert 	} else if (r1->u.v4.mask > r2->u.v4.mask) {
461*f5f40dd6SCy Schubert 		r1_before_r2 = TRUE;
462*f5f40dd6SCy Schubert 	} else if (r1->u.v4.mask < r2->u.v4.mask) {
463*f5f40dd6SCy Schubert 		r1_before_r2 = FALSE;
464*f5f40dd6SCy Schubert 	} else {
465*f5f40dd6SCy Schubert 		r1_before_r2 = mflags_sorts_before(r1->mflags, r2->mflags);
466*f5f40dd6SCy Schubert 	}
4672b15cb3dSCy Schubert 
4682b15cb3dSCy Schubert 	return r1_before_r2;
4692b15cb3dSCy Schubert }
4702b15cb3dSCy Schubert 
4712b15cb3dSCy Schubert 
4722b15cb3dSCy Schubert /*
473*f5f40dd6SCy Schubert  * res_sorts_before6 - compare IPv6 restriction entries
4742b15cb3dSCy Schubert  *
4752b15cb3dSCy Schubert  * Returns nonzero if r1 sorts before r2.  We sort by descending
476*f5f40dd6SCy Schubert  * address, then descending mask, then an intricate mflags sort
477*f5f40dd6SCy Schubert  * order explained in a block comment near the top of this file.
4782b15cb3dSCy Schubert  */
479*f5f40dd6SCy Schubert static int/*BOOL*/
4802b15cb3dSCy Schubert res_sorts_before6(
4812b15cb3dSCy Schubert 	restrict_u* r1,
4822b15cb3dSCy Schubert 	restrict_u* r2
4832b15cb3dSCy Schubert )
4842b15cb3dSCy Schubert {
4852b15cb3dSCy Schubert 	int r1_before_r2;
4862b15cb3dSCy Schubert 	int cmp;
4872b15cb3dSCy Schubert 
4882b15cb3dSCy Schubert 	cmp = ADDR6_CMP(&r1->u.v6.addr, &r2->u.v6.addr);
489*f5f40dd6SCy Schubert 	if (cmp > 0) {		/* r1->addr > r2->addr */
490*f5f40dd6SCy Schubert 		r1_before_r2 = TRUE;
491*f5f40dd6SCy Schubert 	} else if (cmp < 0) {	/* r2->addr > r1->addr */
492*f5f40dd6SCy Schubert 		r1_before_r2 = FALSE;
493*f5f40dd6SCy Schubert 	} else {
4942b15cb3dSCy Schubert 		cmp = ADDR6_CMP(&r1->u.v6.mask, &r2->u.v6.mask);
495*f5f40dd6SCy Schubert 		if (cmp > 0) {		/* r1->mask > r2->mask*/
496*f5f40dd6SCy Schubert 			r1_before_r2 = TRUE;
497*f5f40dd6SCy Schubert 		} else if (cmp < 0) {	/* r2->mask > r1->mask */
498*f5f40dd6SCy Schubert 			r1_before_r2 = FALSE;
499*f5f40dd6SCy Schubert 		} else {
500*f5f40dd6SCy Schubert 			r1_before_r2 = mflags_sorts_before(r1->mflags,
501*f5f40dd6SCy Schubert 							   r2->mflags);
502*f5f40dd6SCy Schubert 		}
5032b15cb3dSCy Schubert 	}
5042b15cb3dSCy Schubert 
5052b15cb3dSCy Schubert 	return r1_before_r2;
506c0b746e5SOllivier Robert }
507c0b746e5SOllivier Robert 
508c0b746e5SOllivier Robert 
509c0b746e5SOllivier Robert /*
51009100258SXin LI  * restrictions - return restrictions for this host in *r4a
511c0b746e5SOllivier Robert  */
51209100258SXin LI void
513c0b746e5SOllivier Robert restrictions(
51409100258SXin LI 	sockaddr_u *srcadr,
51509100258SXin LI 	r4addr *r4a
516c0b746e5SOllivier Robert 	)
517c0b746e5SOllivier Robert {
5182b15cb3dSCy Schubert 	restrict_u *match;
5192b15cb3dSCy Schubert 	struct in6_addr *pin6;
52009100258SXin LI 
521*f5f40dd6SCy Schubert 	DEBUG_REQUIRE(NULL != r4a);
522c0b746e5SOllivier Robert 
523c0b746e5SOllivier Robert 	res_calls++;
52409100258SXin LI 
5252b15cb3dSCy Schubert 	if (IS_IPV4(srcadr)) {
526c0b746e5SOllivier Robert 		/*
527c0b746e5SOllivier Robert 		 * Ignore any packets with a multicast source address
5289c2daa00SOllivier Robert 		 * (this should be done early in the receive process,
5292b15cb3dSCy Schubert 		 * not later!)
530c0b746e5SOllivier Robert 		 */
53109100258SXin LI 		if (IN_CLASSD(SRCADR(srcadr))) {
532*f5f40dd6SCy Schubert 			goto multicast;
53309100258SXin LI 		}
534c0b746e5SOllivier Robert 
5352b15cb3dSCy Schubert 		match = match_restrict4_addr(SRCADR(srcadr),
5362b15cb3dSCy Schubert 					     SRCPORT(srcadr));
537*f5f40dd6SCy Schubert 		DEBUG_INSIST(match != NULL);
538c0b746e5SOllivier Robert 		match->count++;
5392b15cb3dSCy Schubert 		/*
5402b15cb3dSCy Schubert 		 * res_not_found counts only use of the final default
5412b15cb3dSCy Schubert 		 * entry, not any "restrict default ntpport ...", which
5422b15cb3dSCy Schubert 		 * would be just before the final default.
5432b15cb3dSCy Schubert 		 */
5442b15cb3dSCy Schubert 		if (&restrict_def4 == match)
545c0b746e5SOllivier Robert 			res_not_found++;
546c0b746e5SOllivier Robert 		else
547c0b746e5SOllivier Robert 			res_found++;
54809100258SXin LI 		r4a->rflags = match->rflags;
54909100258SXin LI 		r4a->ippeerlimit = match->ippeerlimit;
550*f5f40dd6SCy Schubert 	} else {
551*f5f40dd6SCy Schubert 		DEBUG_REQUIRE(IS_IPV6(srcadr));
5529c2daa00SOllivier Robert 
5532b15cb3dSCy Schubert 		pin6 = PSOCK_ADDR6(srcadr);
554c0b746e5SOllivier Robert 
555c0b746e5SOllivier Robert 		/*
5569c2daa00SOllivier Robert 		 * Ignore any packets with a multicast source address
5579c2daa00SOllivier Robert 		 * (this should be done early in the receive process,
5582b15cb3dSCy Schubert 		 * not later!)
559c0b746e5SOllivier Robert 		 */
560*f5f40dd6SCy Schubert 		if (IN6_IS_ADDR_MULTICAST(pin6)) {
561*f5f40dd6SCy Schubert 			goto multicast;
562*f5f40dd6SCy Schubert 		}
5632b15cb3dSCy Schubert 		match = match_restrict6_addr(pin6, SRCPORT(srcadr));
564*f5f40dd6SCy Schubert 		DEBUG_INSIST(match != NULL);
5652b15cb3dSCy Schubert 		match->count++;
5662b15cb3dSCy Schubert 		if (&restrict_def6 == match)
5679c2daa00SOllivier Robert 			res_not_found++;
5689c2daa00SOllivier Robert 		else
5699c2daa00SOllivier Robert 			res_found++;
57009100258SXin LI 		r4a->rflags = match->rflags;
57109100258SXin LI 		r4a->ippeerlimit = match->ippeerlimit;
572c0b746e5SOllivier Robert 	}
5732d4e511cSCy Schubert 
57409100258SXin LI 	return;
575*f5f40dd6SCy Schubert 
576*f5f40dd6SCy Schubert     multicast:
577*f5f40dd6SCy Schubert 	r4a->rflags = RES_IGNORE;
578*f5f40dd6SCy Schubert 	r4a->ippeerlimit = 0;
57909100258SXin LI }
58009100258SXin LI 
58109100258SXin LI 
582*f5f40dd6SCy Schubert #ifdef DEBUG
583*f5f40dd6SCy Schubert /* display string for restrict_op */
584*f5f40dd6SCy Schubert const char *
585*f5f40dd6SCy Schubert resop_str(restrict_op op)
586*f5f40dd6SCy Schubert {
58709100258SXin LI 	switch (op) {
58809100258SXin LI 	    case RESTRICT_FLAGS:	return "RESTRICT_FLAGS";
589*f5f40dd6SCy Schubert 	    case RESTRICT_UNFLAG:	return "RESTRICT_UNFLAG";
59009100258SXin LI 	    case RESTRICT_REMOVE:	return "RESTRICT_REMOVE";
59109100258SXin LI 	    case RESTRICT_REMOVEIF:	return "RESTRICT_REMOVEIF";
59209100258SXin LI 	}
593*f5f40dd6SCy Schubert 	DEBUG_INVARIANT(!"bad restrict_op in resop_str");
594*f5f40dd6SCy Schubert 	return "";	/* silence not all paths return value warning */
595c0b746e5SOllivier Robert }
596*f5f40dd6SCy Schubert #endif	/* DEBUG */
597c0b746e5SOllivier Robert 
598c0b746e5SOllivier Robert 
599c0b746e5SOllivier Robert /*
600c0b746e5SOllivier Robert  * hack_restrict - add/subtract/manipulate entries on the restrict list
601c0b746e5SOllivier Robert  */
602*f5f40dd6SCy Schubert int/*BOOL*/
603c0b746e5SOllivier Robert hack_restrict(
60409100258SXin LI 	restrict_op	op,
6052b15cb3dSCy Schubert 	sockaddr_u *	resaddr,
6062b15cb3dSCy Schubert 	sockaddr_u *	resmask,
60709100258SXin LI 	short		ippeerlimit,
6082b15cb3dSCy Schubert 	u_short		mflags,
60909100258SXin LI 	u_short		rflags,
610*f5f40dd6SCy Schubert 	u_int32		expire
611c0b746e5SOllivier Robert 	)
612c0b746e5SOllivier Robert {
6132b15cb3dSCy Schubert 	int		v6;
614*f5f40dd6SCy Schubert 	int		bump_res_limited = FALSE;
6152b15cb3dSCy Schubert 	restrict_u	match;
6162b15cb3dSCy Schubert 	restrict_u *	res;
6172b15cb3dSCy Schubert 	restrict_u **	plisthead;
618*f5f40dd6SCy Schubert 	res_sort_fn	pfn_sort;
619c0b746e5SOllivier Robert 
620*f5f40dd6SCy Schubert #ifdef DEBUG
621*f5f40dd6SCy Schubert 	if (debug > 0) {
622*f5f40dd6SCy Schubert 		printf("hack_restrict: op %s addr %s mask %s",
623*f5f40dd6SCy Schubert 			resop_str(op), stoa(resaddr), stoa(resmask));
624*f5f40dd6SCy Schubert 		if (ippeerlimit >= 0) {
625*f5f40dd6SCy Schubert 			printf(" ippeerlimit %d", ippeerlimit);
626*f5f40dd6SCy Schubert 		}
627*f5f40dd6SCy Schubert 		printf(" mflags %s rflags %s", mflags_str(mflags),
628*f5f40dd6SCy Schubert 		       rflags_str(rflags));
629*f5f40dd6SCy Schubert 		if (expire) {
630*f5f40dd6SCy Schubert 			printf("lifetime %u\n",
631*f5f40dd6SCy Schubert 			       expire - (u_int32)current_time);
632*f5f40dd6SCy Schubert 		} else {
633*f5f40dd6SCy Schubert 			printf("\n");
634*f5f40dd6SCy Schubert 		}
635*f5f40dd6SCy Schubert 	}
636*f5f40dd6SCy Schubert #endif
6372b15cb3dSCy Schubert 
6382b15cb3dSCy Schubert 	if (NULL == resaddr) {
639*f5f40dd6SCy Schubert 		DEBUG_REQUIRE(NULL == resmask);
640*f5f40dd6SCy Schubert 		DEBUG_REQUIRE(RESTRICT_FLAGS == op);
641*f5f40dd6SCy Schubert 		DEBUG_REQUIRE(RESM_SOURCE & mflags);
64209100258SXin LI 		restrict_source_rflags = rflags;
6432b15cb3dSCy Schubert 		restrict_source_mflags = mflags;
64409100258SXin LI 		restrict_source_ippeerlimit = ippeerlimit;
645*f5f40dd6SCy Schubert 		restrict_source_enabled = TRUE;
646*f5f40dd6SCy Schubert 		DPRINTF(1, ("restrict source template saved\n"));
647*f5f40dd6SCy Schubert 		return TRUE;
6482b15cb3dSCy Schubert 	}
6492b15cb3dSCy Schubert 
6502b15cb3dSCy Schubert 	ZERO(match);
6519034852cSGleb Smirnoff 
6522b15cb3dSCy Schubert 	if (IS_IPV4(resaddr)) {
653*f5f40dd6SCy Schubert 		DEBUG_INVARIANT(IS_IPV4(resmask));
654*f5f40dd6SCy Schubert 		v6 = FALSE;
655c0b746e5SOllivier Robert 		/*
6562b15cb3dSCy Schubert 		 * Get address and mask in host byte order for easy
6572b15cb3dSCy Schubert 		 * comparison as u_int32
658c0b746e5SOllivier Robert 		 */
6592b15cb3dSCy Schubert 		match.u.v4.addr = SRCADR(resaddr);
6602b15cb3dSCy Schubert 		match.u.v4.mask = SRCADR(resmask);
6612b15cb3dSCy Schubert 		match.u.v4.addr &= match.u.v4.mask;
662*f5f40dd6SCy Schubert 	} else {
663*f5f40dd6SCy Schubert 		DEBUG_INVARIANT(IS_IPV6(resaddr));
664*f5f40dd6SCy Schubert 		DEBUG_INVARIANT(IS_IPV6(resmask));
665*f5f40dd6SCy Schubert 		v6 = TRUE;
666c0b746e5SOllivier Robert 		/*
6672b15cb3dSCy Schubert 		 * Get address and mask in network byte order for easy
6682b15cb3dSCy Schubert 		 * comparison as byte sequences (e.g. memcmp())
669c0b746e5SOllivier Robert 		 */
6702b15cb3dSCy Schubert 		match.u.v6.mask = SOCK_ADDR6(resmask);
6712b15cb3dSCy Schubert 		MASK_IPV6_ADDR(&match.u.v6.addr, PSOCK_ADDR6(resaddr),
6722b15cb3dSCy Schubert 			       &match.u.v6.mask);
673*f5f40dd6SCy Schubert 	}
6749c2daa00SOllivier Robert 
6752b15cb3dSCy Schubert 	match.mflags = mflags;
6762b15cb3dSCy Schubert 	res = match_restrict_entry(&match, v6);
6779c2daa00SOllivier Robert 
678c0b746e5SOllivier Robert 	switch (op) {
6792b15cb3dSCy Schubert 
680c0b746e5SOllivier Robert 	case RESTRICT_FLAGS:
681c0b746e5SOllivier Robert 		/*
682*f5f40dd6SCy Schubert 		 * Here we add bits to the rflags. If we already have
683*f5f40dd6SCy Schubert 		 * this restriction modify it.
684c0b746e5SOllivier Robert 		 */
685*f5f40dd6SCy Schubert 		if (NULL != res) {
686*f5f40dd6SCy Schubert 			if (    (RES_LIMITED & rflags)
687*f5f40dd6SCy Schubert 			    && !(RES_LIMITED & res->rflags)) {
688*f5f40dd6SCy Schubert 
689*f5f40dd6SCy Schubert 				bump_res_limited = TRUE;
690*f5f40dd6SCy Schubert 			}
691*f5f40dd6SCy Schubert 			res->rflags |= rflags;
692*f5f40dd6SCy Schubert 			res->expire = expire;
693*f5f40dd6SCy Schubert 		} else {
694*f5f40dd6SCy Schubert 			match.rflags = rflags;
695*f5f40dd6SCy Schubert 			match.expire = expire;
696*f5f40dd6SCy Schubert 			match.ippeerlimit = ippeerlimit;
6972b15cb3dSCy Schubert 			if (v6) {
6982b15cb3dSCy Schubert 				res = alloc_res6();
699*f5f40dd6SCy Schubert 				memcpy(res, &match, V6_SIZEOF_RESTRICT_U);
7002b15cb3dSCy Schubert 				plisthead = &restrictlist6;
701*f5f40dd6SCy Schubert 				pfn_sort = &res_sorts_before6;
702ea906c41SOllivier Robert 			} else {
7032b15cb3dSCy Schubert 				res = alloc_res4();
704*f5f40dd6SCy Schubert 				memcpy(res, &match, V4_SIZEOF_RESTRICT_U);
7052b15cb3dSCy Schubert 				plisthead = &restrictlist4;
706*f5f40dd6SCy Schubert 				pfn_sort = &res_sorts_before4;
707ea906c41SOllivier Robert 			}
7082b15cb3dSCy Schubert 			LINK_SORT_SLIST(
7092b15cb3dSCy Schubert 				*plisthead, res,
710*f5f40dd6SCy Schubert 				(*pfn_sort)(res, L_S_S_CUR()),
7112b15cb3dSCy Schubert 				link, restrict_u);
712c0b746e5SOllivier Robert 			restrictcount++;
713*f5f40dd6SCy Schubert 			if (RES_LIMITED & rflags) {
714*f5f40dd6SCy Schubert 				bump_res_limited = TRUE;
715c0b746e5SOllivier Robert 			}
716*f5f40dd6SCy Schubert 		}
717*f5f40dd6SCy Schubert 		if (bump_res_limited) {
718*f5f40dd6SCy Schubert 			inc_res_limited();
719*f5f40dd6SCy Schubert 		}
720*f5f40dd6SCy Schubert 		return TRUE;
721c0b746e5SOllivier Robert 
722c0b746e5SOllivier Robert 	case RESTRICT_UNFLAG:
723c0b746e5SOllivier Robert 		/*
72409100258SXin LI 		 * Remove some bits from the rflags. If we didn't
725c0b746e5SOllivier Robert 		 * find this one, just return.
726c0b746e5SOllivier Robert 		 */
727*f5f40dd6SCy Schubert 		if (NULL == res) {
728*f5f40dd6SCy Schubert 			DPRINTF(1, ("No match for %s %s removing rflags %s\n",
729*f5f40dd6SCy Schubert 				    stoa(resaddr), stoa(resmask),
730*f5f40dd6SCy Schubert 				    rflags_str(rflags)));
731*f5f40dd6SCy Schubert 			return FALSE;
732c0b746e5SOllivier Robert 		}
733*f5f40dd6SCy Schubert 		if (   (RES_LIMITED & res->rflags)
734*f5f40dd6SCy Schubert 		    && (RES_LIMITED & rflags)) {
735*f5f40dd6SCy Schubert 			dec_res_limited();
736*f5f40dd6SCy Schubert 		}
737*f5f40dd6SCy Schubert 		res->rflags &= ~rflags;
738*f5f40dd6SCy Schubert 		return TRUE;
739c0b746e5SOllivier Robert 
740c0b746e5SOllivier Robert 	case RESTRICT_REMOVE:
741ea906c41SOllivier Robert 	case RESTRICT_REMOVEIF:
742c0b746e5SOllivier Robert 		/*
7439c2daa00SOllivier Robert 		 * Remove an entry from the table entirely if we
7449c2daa00SOllivier Robert 		 * found one. Don't remove the default entry and
745*f5f40dd6SCy Schubert 		 * don't remove an interface entry unless asked.
746c0b746e5SOllivier Robert 		 */
7472b15cb3dSCy Schubert 		if (   res != NULL
7482b15cb3dSCy Schubert 		    && (   RESTRICT_REMOVEIF == op
7492b15cb3dSCy Schubert 			|| !(RESM_INTERFACE & res->mflags))
7502b15cb3dSCy Schubert 		    && res != &restrict_def4
751*f5f40dd6SCy Schubert 		    && res != &restrict_def6) {
752*f5f40dd6SCy Schubert 
7532b15cb3dSCy Schubert 			free_res(res, v6);
754*f5f40dd6SCy Schubert 			return TRUE;
755c0b746e5SOllivier Robert 		}
756*f5f40dd6SCy Schubert 		DPRINTF(1, ("No match removing %s %s restriction\n",
757*f5f40dd6SCy Schubert 			    stoa(resaddr), stoa(resmask)));
758*f5f40dd6SCy Schubert 		return FALSE;
759*f5f40dd6SCy Schubert 	}
760*f5f40dd6SCy Schubert 	/* notreached */
761*f5f40dd6SCy Schubert 	return FALSE;
7622b15cb3dSCy Schubert }
7632b15cb3dSCy Schubert 
7642b15cb3dSCy Schubert 
7659c2daa00SOllivier Robert /*
7662b15cb3dSCy Schubert  * restrict_source - maintains dynamic "restrict source ..." entries as
7672b15cb3dSCy Schubert  *		     peers come and go.
7689c2daa00SOllivier Robert  */
7692b15cb3dSCy Schubert void
7702b15cb3dSCy Schubert restrict_source(
7712b15cb3dSCy Schubert 	sockaddr_u *	addr,
772*f5f40dd6SCy Schubert 	int		farewell,	/* TRUE to remove */
773*f5f40dd6SCy Schubert 	u_int32		lifetime	/* seconds, 0 forever */
7742b15cb3dSCy Schubert 	)
7752b15cb3dSCy Schubert {
7762b15cb3dSCy Schubert 	sockaddr_u	onesmask;
777*f5f40dd6SCy Schubert 	int/*BOOL*/	success;
778c0b746e5SOllivier Robert 
779*f5f40dd6SCy Schubert 	if (   !restrict_source_enabled || SOCK_UNSPEC(addr)
780*f5f40dd6SCy Schubert 	    || IS_MCAST(addr) || ISREFCLOCKADR(addr)) {
7812b15cb3dSCy Schubert 		return;
782*f5f40dd6SCy Schubert 	}
7839c2daa00SOllivier Robert 
7849034852cSGleb Smirnoff 	REQUIRE(AF_INET == AF(addr) || AF_INET6 == AF(addr));
7852b15cb3dSCy Schubert 
7862b15cb3dSCy Schubert 	SET_HOSTMASK(&onesmask, AF(addr));
7872b15cb3dSCy Schubert 	if (farewell) {
788*f5f40dd6SCy Schubert 		success = hack_restrict(RESTRICT_REMOVE, addr, &onesmask,
789*f5f40dd6SCy Schubert 					0, RESM_SOURCE, 0, 0);
790*f5f40dd6SCy Schubert 		if (success) {
791*f5f40dd6SCy Schubert 			DPRINTF(1, ("%s %s removed", __func__,
7922b15cb3dSCy Schubert 				    stoa(addr)));
793*f5f40dd6SCy Schubert 		} else {
794*f5f40dd6SCy Schubert 			msyslog(LOG_ERR, "%s remove %s failed",
795*f5f40dd6SCy Schubert 					 __func__, stoa(addr));
796c0b746e5SOllivier Robert 		}
797*f5f40dd6SCy Schubert 		return;
798*f5f40dd6SCy Schubert 	}
799*f5f40dd6SCy Schubert 
800*f5f40dd6SCy Schubert 	success = hack_restrict(RESTRICT_FLAGS, addr, &onesmask,
801*f5f40dd6SCy Schubert 				restrict_source_ippeerlimit,
802*f5f40dd6SCy Schubert 				restrict_source_mflags,
803*f5f40dd6SCy Schubert 				restrict_source_rflags,
804*f5f40dd6SCy Schubert 				lifetime > 0
805*f5f40dd6SCy Schubert 				    ? lifetime + current_time
806*f5f40dd6SCy Schubert 				    : 0);
807*f5f40dd6SCy Schubert 	if (success) {
808*f5f40dd6SCy Schubert 		DPRINTF(1, ("%s %s add/upd\n", __func__,
809*f5f40dd6SCy Schubert 			    stoa(addr)));
810*f5f40dd6SCy Schubert 	} else {
811*f5f40dd6SCy Schubert 		msyslog(LOG_ERR, "%s %s failed", __func__, stoa(addr));
812*f5f40dd6SCy Schubert 	}
813*f5f40dd6SCy Schubert }
814*f5f40dd6SCy Schubert 
815*f5f40dd6SCy Schubert 
816*f5f40dd6SCy Schubert #ifdef DEBUG
817*f5f40dd6SCy Schubert /* Convert restriction RES_ flag bits into a display string */
818*f5f40dd6SCy Schubert const char *
819*f5f40dd6SCy Schubert rflags_str(
820*f5f40dd6SCy Schubert 	u_short rflags
821*f5f40dd6SCy Schubert 	)
822*f5f40dd6SCy Schubert {
823*f5f40dd6SCy Schubert 	const size_t	sz = LIB_BUFLENGTH;
824*f5f40dd6SCy Schubert 	char *		rfs;
825*f5f40dd6SCy Schubert 
826*f5f40dd6SCy Schubert 	LIB_GETBUF(rfs);
827*f5f40dd6SCy Schubert 	rfs[0] = '\0';
828*f5f40dd6SCy Schubert 
829*f5f40dd6SCy Schubert 	if (rflags & RES_FLAKE) {
830*f5f40dd6SCy Schubert 		CLEAR_BIT_IF_DEBUG(RES_FLAKE, rflags);
831*f5f40dd6SCy Schubert 		append_flagstr(rfs, sz, "flake");
832*f5f40dd6SCy Schubert 	}
833*f5f40dd6SCy Schubert 
834*f5f40dd6SCy Schubert 	if (rflags & RES_IGNORE) {
835*f5f40dd6SCy Schubert 		CLEAR_BIT_IF_DEBUG(RES_IGNORE, rflags);
836*f5f40dd6SCy Schubert 		append_flagstr(rfs, sz, "ignore");
837*f5f40dd6SCy Schubert 	}
838*f5f40dd6SCy Schubert 
839*f5f40dd6SCy Schubert 	if (rflags & RES_KOD) {
840*f5f40dd6SCy Schubert 		CLEAR_BIT_IF_DEBUG(RES_KOD, rflags);
841*f5f40dd6SCy Schubert 		append_flagstr(rfs, sz, "kod");
842*f5f40dd6SCy Schubert 	}
843*f5f40dd6SCy Schubert 
844*f5f40dd6SCy Schubert 	if (rflags & RES_MSSNTP) {
845*f5f40dd6SCy Schubert 		CLEAR_BIT_IF_DEBUG(RES_MSSNTP, rflags);
846*f5f40dd6SCy Schubert 		append_flagstr(rfs, sz, "mssntp");
847*f5f40dd6SCy Schubert 	}
848*f5f40dd6SCy Schubert 
849*f5f40dd6SCy Schubert 	if (rflags & RES_LIMITED) {
850*f5f40dd6SCy Schubert 		CLEAR_BIT_IF_DEBUG(RES_LIMITED, rflags);
851*f5f40dd6SCy Schubert 		append_flagstr(rfs, sz, "limited");
852*f5f40dd6SCy Schubert 	}
853*f5f40dd6SCy Schubert 
854*f5f40dd6SCy Schubert 	if (rflags & RES_LPTRAP) {
855*f5f40dd6SCy Schubert 		CLEAR_BIT_IF_DEBUG(RES_LPTRAP, rflags);
856*f5f40dd6SCy Schubert 		append_flagstr(rfs, sz, "lptrap");
857*f5f40dd6SCy Schubert 	}
858*f5f40dd6SCy Schubert 
859*f5f40dd6SCy Schubert 	if (rflags & RES_NOMODIFY) {
860*f5f40dd6SCy Schubert 		CLEAR_BIT_IF_DEBUG(RES_NOMODIFY, rflags);
861*f5f40dd6SCy Schubert 		append_flagstr(rfs, sz, "nomodify");
862*f5f40dd6SCy Schubert 	}
863*f5f40dd6SCy Schubert 
864*f5f40dd6SCy Schubert 	if (rflags & RES_NOMRULIST) {
865*f5f40dd6SCy Schubert 		CLEAR_BIT_IF_DEBUG(RES_NOMRULIST, rflags);
866*f5f40dd6SCy Schubert 		append_flagstr(rfs, sz, "nomrulist");
867*f5f40dd6SCy Schubert 	}
868*f5f40dd6SCy Schubert 
869*f5f40dd6SCy Schubert 	if (rflags & RES_NOEPEER) {
870*f5f40dd6SCy Schubert 		CLEAR_BIT_IF_DEBUG(RES_NOEPEER, rflags);
871*f5f40dd6SCy Schubert 		append_flagstr(rfs, sz, "noepeer");
872*f5f40dd6SCy Schubert 	}
873*f5f40dd6SCy Schubert 
874*f5f40dd6SCy Schubert 	if (rflags & RES_NOPEER) {
875*f5f40dd6SCy Schubert 		CLEAR_BIT_IF_DEBUG(RES_NOPEER, rflags);
876*f5f40dd6SCy Schubert 		append_flagstr(rfs, sz, "nopeer");
877*f5f40dd6SCy Schubert 	}
878*f5f40dd6SCy Schubert 
879*f5f40dd6SCy Schubert 	if (rflags & RES_NOQUERY) {
880*f5f40dd6SCy Schubert 		CLEAR_BIT_IF_DEBUG(RES_NOQUERY, rflags);
881*f5f40dd6SCy Schubert 		append_flagstr(rfs, sz, "noquery");
882*f5f40dd6SCy Schubert 	}
883*f5f40dd6SCy Schubert 
884*f5f40dd6SCy Schubert 	if (rflags & RES_DONTSERVE) {
885*f5f40dd6SCy Schubert 		CLEAR_BIT_IF_DEBUG(RES_DONTSERVE, rflags);
886*f5f40dd6SCy Schubert 		append_flagstr(rfs, sz, "dontserve");
887*f5f40dd6SCy Schubert 	}
888*f5f40dd6SCy Schubert 
889*f5f40dd6SCy Schubert 	if (rflags & RES_NOTRAP) {
890*f5f40dd6SCy Schubert 		CLEAR_BIT_IF_DEBUG(RES_NOTRAP, rflags);
891*f5f40dd6SCy Schubert 		append_flagstr(rfs, sz, "notrap");
892*f5f40dd6SCy Schubert 	}
893*f5f40dd6SCy Schubert 
894*f5f40dd6SCy Schubert 	if (rflags & RES_DONTTRUST) {
895*f5f40dd6SCy Schubert 		CLEAR_BIT_IF_DEBUG(RES_DONTTRUST, rflags);
896*f5f40dd6SCy Schubert 		append_flagstr(rfs, sz, "notrust");
897*f5f40dd6SCy Schubert 	}
898*f5f40dd6SCy Schubert 
899*f5f40dd6SCy Schubert 	if (rflags & RES_SRVRSPFUZ) {
900*f5f40dd6SCy Schubert 		CLEAR_BIT_IF_DEBUG(RES_SRVRSPFUZ, rflags);
901*f5f40dd6SCy Schubert 		append_flagstr(rfs, sz, "srvrspfuz");
902*f5f40dd6SCy Schubert 	}
903*f5f40dd6SCy Schubert 
904*f5f40dd6SCy Schubert 	if (rflags & RES_VERSION) {
905*f5f40dd6SCy Schubert 		CLEAR_BIT_IF_DEBUG(RES_VERSION, rflags);
906*f5f40dd6SCy Schubert 		append_flagstr(rfs, sz, "version");
907*f5f40dd6SCy Schubert 	}
908*f5f40dd6SCy Schubert 
909*f5f40dd6SCy Schubert 	DEBUG_INVARIANT(!rflags);
910*f5f40dd6SCy Schubert 
911*f5f40dd6SCy Schubert 	if ('\0' == rfs[0]) {
912*f5f40dd6SCy Schubert 		append_flagstr(rfs, sz, "(none)");
913*f5f40dd6SCy Schubert 	}
914*f5f40dd6SCy Schubert 
915*f5f40dd6SCy Schubert 	return rfs;
916*f5f40dd6SCy Schubert }
917*f5f40dd6SCy Schubert 
918*f5f40dd6SCy Schubert 
919*f5f40dd6SCy Schubert /* Convert restriction match RESM_ flag bits into a display string */
920*f5f40dd6SCy Schubert const char *
921*f5f40dd6SCy Schubert mflags_str(
922*f5f40dd6SCy Schubert 	u_short mflags
923*f5f40dd6SCy Schubert 	)
924*f5f40dd6SCy Schubert {
925*f5f40dd6SCy Schubert 	const size_t	sz = LIB_BUFLENGTH;
926*f5f40dd6SCy Schubert 	char *		mfs;
927*f5f40dd6SCy Schubert 
928*f5f40dd6SCy Schubert 	LIB_GETBUF(mfs);
929*f5f40dd6SCy Schubert 	mfs[0] = '\0';
930*f5f40dd6SCy Schubert 
931*f5f40dd6SCy Schubert 	if (mflags & RESM_NTPONLY) {
932*f5f40dd6SCy Schubert 		CLEAR_BIT_IF_DEBUG(RESM_NTPONLY, mflags);
933*f5f40dd6SCy Schubert 		append_flagstr(mfs, sz, "ntponly");
934*f5f40dd6SCy Schubert 	}
935*f5f40dd6SCy Schubert 
936*f5f40dd6SCy Schubert 	if (mflags & RESM_SOURCE) {
937*f5f40dd6SCy Schubert 		CLEAR_BIT_IF_DEBUG(RESM_SOURCE, mflags);
938*f5f40dd6SCy Schubert 		append_flagstr(mfs, sz, "source");
939*f5f40dd6SCy Schubert 	}
940*f5f40dd6SCy Schubert 
941*f5f40dd6SCy Schubert 	if (mflags & RESM_INTERFACE) {
942*f5f40dd6SCy Schubert 		CLEAR_BIT_IF_DEBUG(RESM_INTERFACE, mflags);
943*f5f40dd6SCy Schubert 		append_flagstr(mfs, sz, "interface");
944*f5f40dd6SCy Schubert 	}
945*f5f40dd6SCy Schubert 
946*f5f40dd6SCy Schubert 	DEBUG_INVARIANT(!mflags);
947*f5f40dd6SCy Schubert 
948*f5f40dd6SCy Schubert 	return mfs;
949*f5f40dd6SCy Schubert }
950*f5f40dd6SCy Schubert #endif	/* DEBUG */
951