xref: /netbsd-src/external/bsd/ntp/dist/ntpd/ntp_restrict.c (revision 9e9fa66ad400fe02341b89216c5270e23a212d33)
1*9e9fa66aSchristos /*	$NetBSD: ntp_restrict.c,v 1.13 2024/10/01 20:59:51 christos Exp $	*/
2abb0f93cSkardel 
3abb0f93cSkardel /*
4abb0f93cSkardel  * ntp_restrict.c - determine host restrictions
5abb0f93cSkardel  */
6abb0f93cSkardel #ifdef HAVE_CONFIG_H
7abb0f93cSkardel #include <config.h>
8abb0f93cSkardel #endif
9abb0f93cSkardel 
10abb0f93cSkardel #include <stdio.h>
11abb0f93cSkardel #include <sys/types.h>
12abb0f93cSkardel 
13abb0f93cSkardel #include "ntpd.h"
14abb0f93cSkardel #include "ntp_if.h"
15f003fb54Skardel #include "ntp_lists.h"
16abb0f93cSkardel #include "ntp_stdlib.h"
17f003fb54Skardel #include "ntp_assert.h"
18abb0f93cSkardel 
19abb0f93cSkardel /*
20eabc0478Schristos  * This code keeps a simple address-and-mask list of addressses we want
21eabc0478Schristos  * to place restrictions on (or remove them from). The restrictions are
22eabc0478Schristos  * implemented as a set of flags which tell you what matching addresses
23eabc0478Schristos  * can't do.  The list is sorted retrieve the restrictions most specific
24eabc0478Schristos *  to the address.
25abb0f93cSkardel  *
26abb0f93cSkardel  * This was originally intended to restrict you from sync'ing to your
27abb0f93cSkardel  * own broadcasts when you are doing that, by restricting yourself from
28abb0f93cSkardel  * your own interfaces. It was also thought it would sometimes be useful
29abb0f93cSkardel  * to keep a misbehaving host or two from abusing your primary clock. It
30abb0f93cSkardel  * has been expanded, however, to suit the needs of those with more
31abb0f93cSkardel  * restrictive access policies.
32abb0f93cSkardel  */
33f003fb54Skardel #define MASK_IPV6_ADDR(dst, src, msk)					\
34abb0f93cSkardel 	do {								\
35eabc0478Schristos 		int x;							\
36eabc0478Schristos 									\
37eabc0478Schristos 		for (x = 0; x < (int)COUNTOF((dst)->s6_addr); x++) {	\
38eabc0478Schristos 			(dst)->s6_addr[x] =   (src)->s6_addr[x]		\
39eabc0478Schristos 					    & (msk)->s6_addr[x];	\
40abb0f93cSkardel 		}							\
41eabc0478Schristos 	} while (FALSE)
42abb0f93cSkardel 
43abb0f93cSkardel /*
44f003fb54Skardel  * We allocate INC_RESLIST{4|6} entries to the free list whenever empty.
45eabc0478Schristos  * Auto-tune these to be just less than 1KB (leaving at least 32 bytes
46f003fb54Skardel  * for allocator overhead).
47abb0f93cSkardel  */
48*9e9fa66aSchristos #define	INC_RESLIST4	((1024 - 32) / sizeof(struct restrict_4))
49*9e9fa66aSchristos #define	INC_RESLIST6	((1024 - 32) / sizeof(struct restrict_6))
50abb0f93cSkardel 
51abb0f93cSkardel /*
52abb0f93cSkardel  * The restriction list
53abb0f93cSkardel  */
54*9e9fa66aSchristos struct restrict_4 *restrictlist4;
55*9e9fa66aSchristos struct restrict_6 *restrictlist6;
56*9e9fa66aSchristos static size_t restrictcount;	/* count in the restrict lists */
57abb0f93cSkardel 
58abb0f93cSkardel /*
59abb0f93cSkardel  * The free list and associated counters.  Also some uninteresting
60abb0f93cSkardel  * stat counters.
61abb0f93cSkardel  */
62*9e9fa66aSchristos static struct restrict_4 *resfree4;	/* available entries (free list) */
63*9e9fa66aSchristos static struct restrict_6 *resfree6;
64abb0f93cSkardel 
65abb0f93cSkardel static u_long res_calls;
66abb0f93cSkardel static u_long res_found;
67abb0f93cSkardel static u_long res_not_found;
68abb0f93cSkardel 
69abb0f93cSkardel /*
70f003fb54Skardel  * Count number of restriction entries referring to RES_LIMITED, to
71f003fb54Skardel  * control implicit activation/deactivation of the MRU monlist.
72abb0f93cSkardel  */
73abb0f93cSkardel static	u_long res_limited_refcnt;
74abb0f93cSkardel 
75abb0f93cSkardel /*
76f003fb54Skardel  * Our default entries.
774eea345dSchristos  *
784eea345dSchristos  * We can make this cleaner with c99 support: see init_restrict().
79abb0f93cSkardel  */
80*9e9fa66aSchristos static	struct restrict_4	restrict_def4;
81*9e9fa66aSchristos static	struct restrict_6	restrict_def6;
82f003fb54Skardel 
83f003fb54Skardel /*
84f003fb54Skardel  * "restrict source ..." enabled knob and restriction bits.
85f003fb54Skardel  */
86f003fb54Skardel static	int		restrict_source_enabled;
87cdfa2a7eSchristos static	u_int32		restrict_source_rflags;
88f003fb54Skardel static	u_short		restrict_source_mflags;
894eea345dSchristos static	short		restrict_source_ippeerlimit;
90f003fb54Skardel 
91f003fb54Skardel /*
92f003fb54Skardel  * private functions
93f003fb54Skardel  */
94*9e9fa66aSchristos static	struct restrict_4 *	alloc_res4(void);
95*9e9fa66aSchristos static	struct restrict_6 *	alloc_res6(void);
96*9e9fa66aSchristos static	void		free_res4(struct restrict_4 *);
97*9e9fa66aSchristos static	void		free_res6(struct restrict_6 *);
98eabc0478Schristos static	inline void	inc_res_limited(void);
99eabc0478Schristos static	inline void	dec_res_limited(void);
100*9e9fa66aSchristos static	struct restrict_4 *	match_restrict4_addr(u_int32, u_short);
101*9e9fa66aSchristos static	struct restrict_6 *	match_restrict6_addr(const struct in6_addr *,
102f003fb54Skardel 					     u_short);
103eabc0478Schristos static inline int/*BOOL*/	mflags_sorts_before(u_short, u_short);
104*9e9fa66aSchristos static	int/*BOOL*/	res_sorts_before4(struct restrict_4 *,
105*9e9fa66aSchristos 					struct restrict_4 *);
106*9e9fa66aSchristos static	int/*BOOL*/	res_sorts_before6(struct restrict_6 *,
107*9e9fa66aSchristos 					struct restrict_6 *);
108eabc0478Schristos 
109eabc0478Schristos #ifdef DEBUG
110*9e9fa66aSchristos /* dump_restrict() & dump_restricts() are DEBUG-only */
111eabc0478Schristos 
112*9e9fa66aSchristos static void
113*9e9fa66aSchristos dump_restrict(const struct restrict_info *ri, const char *as, const char *ms)
114*9e9fa66aSchristos {
115*9e9fa66aSchristos 	printf("%s/%s: hits %u ippeerlimit %hd mflags %s rflags %s",
116*9e9fa66aSchristos 		as, ms, ri->count, ri->ippeerlimit,
117*9e9fa66aSchristos 		mflags_str(ri->mflags),
118*9e9fa66aSchristos 		rflags_str(ri->rflags));
119*9e9fa66aSchristos 	if (ri->expire > 0) {
120*9e9fa66aSchristos 		printf(" expire %u\n", ri->expire);
121*9e9fa66aSchristos 	} else {
122*9e9fa66aSchristos 		printf("\n");
123*9e9fa66aSchristos 	}
124*9e9fa66aSchristos }
1254eea345dSchristos 
1264eea345dSchristos /*
127eabc0478Schristos  * dump_restrict - spit out a single restriction entry
1284eea345dSchristos  */
1294eea345dSchristos static void
130*9e9fa66aSchristos dump_restrict4(
131*9e9fa66aSchristos 	struct restrict_4 *	res)
1324eea345dSchristos {
1334eea345dSchristos 	char as[INET6_ADDRSTRLEN];
1344eea345dSchristos 	char ms[INET6_ADDRSTRLEN];
1354eea345dSchristos 
136eabc0478Schristos 	struct in_addr	sia, sim;
1374eea345dSchristos 
138*9e9fa66aSchristos 	sia.s_addr = htonl(res->v4.addr);
139*9e9fa66aSchristos 	sim.s_addr = htonl(res->v4.addr);
1404eea345dSchristos 	inet_ntop(AF_INET, &sia, as, sizeof as);
1414eea345dSchristos 	inet_ntop(AF_INET, &sim, ms, sizeof ms);
142*9e9fa66aSchristos 
143*9e9fa66aSchristos 	dump_restrict(&res->ri, as, ms);
1444eea345dSchristos }
145*9e9fa66aSchristos 
146*9e9fa66aSchristos static void
147*9e9fa66aSchristos dump_restrict6(
148*9e9fa66aSchristos 	struct restrict_6 *	res)
149*9e9fa66aSchristos {
150*9e9fa66aSchristos 	char as[INET6_ADDRSTRLEN];
151*9e9fa66aSchristos 	char ms[INET6_ADDRSTRLEN];
152*9e9fa66aSchristos 
153*9e9fa66aSchristos 	inet_ntop(AF_INET6, &res->v6.addr, as, sizeof as);
154*9e9fa66aSchristos 	inet_ntop(AF_INET6, &res->v6.mask, ms, sizeof ms);
155*9e9fa66aSchristos 
156*9e9fa66aSchristos 	dump_restrict(&res->ri, as, ms);
1574eea345dSchristos }
1584eea345dSchristos 
1594eea345dSchristos 
1604eea345dSchristos /*
161eabc0478Schristos  * dump_restricts - spit out the 'restrict' entries
1624eea345dSchristos  */
1634eea345dSchristos void
1644eea345dSchristos dump_restricts(void)
1654eea345dSchristos {
166*9e9fa66aSchristos 	struct restrict_4 *	res4;
167*9e9fa66aSchristos 	struct restrict_6 *	res6;
1684eea345dSchristos 
1694eea345dSchristos 	/* Spit out the IPv4 list */
170eabc0478Schristos 	printf("dump_restricts: restrictlist4: %p\n", restrictlist4);
171*9e9fa66aSchristos 	for (res4 = restrictlist4; res4 != NULL; res4 = res4->link) {
172*9e9fa66aSchristos 		dump_restrict4(res4);
1734eea345dSchristos 	}
1744eea345dSchristos 
1754eea345dSchristos 	/* Spit out the IPv6 list */
176eabc0478Schristos 	printf("dump_restricts: restrictlist6: %p\n", restrictlist6);
177*9e9fa66aSchristos 	for (res6 = restrictlist6; res6 != NULL; res6 = res6->link) {
178*9e9fa66aSchristos 		dump_restrict6(res6);
1794eea345dSchristos 	}
180eabc0478Schristos }
181eabc0478Schristos #endif /* DEBUG - dump_restrict() / dump_restricts() */
1824eea345dSchristos 
1834eea345dSchristos 
184abb0f93cSkardel /*
185abb0f93cSkardel  * init_restrict - initialize the restriction data structures
186abb0f93cSkardel  */
187abb0f93cSkardel void
188abb0f93cSkardel init_restrict(void)
189abb0f93cSkardel {
190abb0f93cSkardel 	/*
191eabc0478Schristos 	 * The restriction lists end with a default entry with address
192f003fb54Skardel 	 * and mask 0, which will match any entry.  The lists are kept
193f003fb54Skardel 	 * sorted by descending address followed by descending mask:
194f003fb54Skardel 	 *
195f003fb54Skardel 	 *   address	  mask
196f003fb54Skardel 	 * 192.168.0.0	255.255.255.0	kod limited noquery nopeer
197f003fb54Skardel 	 * 192.168.0.0	255.255.0.0	kod limited
198f003fb54Skardel 	 * 0.0.0.0	0.0.0.0		kod limited noquery
199f003fb54Skardel 	 *
200f003fb54Skardel 	 * The first entry which matches an address is used.  With the
201f003fb54Skardel 	 * example restrictions above, 192.168.0.0/24 matches the first
202f003fb54Skardel 	 * entry, the rest of 192.168.0.0/16 matches the second, and
203f003fb54Skardel 	 * everything else matches the third (default).
204f003fb54Skardel 	 *
205f003fb54Skardel 	 * Note this achieves the same result a little more efficiently
206f003fb54Skardel 	 * than the documented behavior, which is to keep the lists
207f003fb54Skardel 	 * sorted by ascending address followed by ascending mask, with
208f003fb54Skardel 	 * the _last_ matching entry used.
209f003fb54Skardel 	 *
210f003fb54Skardel 	 * An additional wrinkle is we may have multiple entries with
211f003fb54Skardel 	 * the same address and mask but differing match flags (mflags).
212eabc0478Schristos 	 * We want to never talk to ourself, so RES_IGNORE entries for
213eabc0478Schristos 	 * each local address are added by ntp_io.c with a host mask and
214eabc0478Schristos 	 * both RESM_INTERFACE and RESM_NTPONLY set.  We sort those
215eabc0478Schristos 	 * entries before entries without those flags to achieve this.
216eabc0478Schristos 	 * The remaining match flag is RESM_SOURCE, used to dynamically
217eabc0478Schristos 	 * set restrictions for each peer based on the prototype set by
218eabc0478Schristos 	 * "restrict source" in the configuration.  We want those entries
219eabc0478Schristos 	 * to be considered only when there is not a static host
220eabc0478Schristos 	 * restriction for the address in the configuration, to allow
221eabc0478Schristos 	 * operators to blacklist pool and manycast servers at runtime as
222eabc0478Schristos 	 * desired using ntpq runtime configuration.  Such static entries
223eabc0478Schristos 	 * have no RESM_ bits set, so the sort order for mflags is first
224eabc0478Schristos 	 * RESM_INTERFACE, then entries without RESM_SOURCE, finally the
225eabc0478Schristos 	 * remaining.
226abb0f93cSkardel 	 */
2274eea345dSchristos 
228*9e9fa66aSchristos 	restrict_def4.ri.ippeerlimit = -1;	/* Cleaner if we have C99 */
229*9e9fa66aSchristos 	restrict_def6.ri.ippeerlimit = -1;	/* Cleaner if we have C99 */
2304eea345dSchristos 
231f003fb54Skardel 	LINK_SLIST(restrictlist4, &restrict_def4, link);
232f003fb54Skardel 	LINK_SLIST(restrictlist6, &restrict_def6, link);
233abb0f93cSkardel 	restrictcount = 2;
234f003fb54Skardel }
235f003fb54Skardel 
236f003fb54Skardel 
237*9e9fa66aSchristos static struct restrict_4 *
238f003fb54Skardel alloc_res4(void)
239f003fb54Skardel {
240f003fb54Skardel 	const size_t	count = INC_RESLIST4;
241*9e9fa66aSchristos 	struct restrict_4*	rl;
242*9e9fa66aSchristos 	struct restrict_4*	res;
243*9e9fa66aSchristos 	const size_t	cb = sizeof(*rl);
2448b8da087Schristos 	size_t		i;
245f003fb54Skardel 
246f003fb54Skardel 	UNLINK_HEAD_SLIST(res, resfree4, link);
247eabc0478Schristos 	if (res != NULL) {
248f003fb54Skardel 		return res;
249eabc0478Schristos 	}
250ccc794f0Schristos 	rl = eallocarray(count, cb);
251f003fb54Skardel 	/* link all but the first onto free list */
252f003fb54Skardel 	res = (void *)((char *)rl + (count - 1) * cb);
253f003fb54Skardel 	for (i = count - 1; i > 0; i--) {
254f003fb54Skardel 		LINK_SLIST(resfree4, res, link);
255f003fb54Skardel 		res = (void *)((char *)res - cb);
256f003fb54Skardel 	}
257eabc0478Schristos 	DEBUG_INSIST(rl == res);
258f003fb54Skardel 	/* allocate the first */
259f003fb54Skardel 	return res;
260f003fb54Skardel }
261f003fb54Skardel 
262f003fb54Skardel 
263*9e9fa66aSchristos static struct restrict_6 *
264f003fb54Skardel alloc_res6(void)
265f003fb54Skardel {
266f003fb54Skardel 	const size_t	count = INC_RESLIST6;
267*9e9fa66aSchristos 	struct restrict_6 *	rl;
268*9e9fa66aSchristos 	struct restrict_6 *	res;
269*9e9fa66aSchristos 	const size_t	cb = sizeof(*rl);
2708b8da087Schristos 	size_t		i;
271f003fb54Skardel 
272f003fb54Skardel 	UNLINK_HEAD_SLIST(res, resfree6, link);
273eabc0478Schristos 	if (res != NULL) {
274f003fb54Skardel 		return res;
275eabc0478Schristos 	}
276ccc794f0Schristos 	rl = eallocarray(count, cb);
277f003fb54Skardel 	/* link all but the first onto free list */
278f003fb54Skardel 	res = (void *)((char *)rl + (count - 1) * cb);
279f003fb54Skardel 	for (i = count - 1; i > 0; i--) {
280f003fb54Skardel 		LINK_SLIST(resfree6, res, link);
281f003fb54Skardel 		res = (void *)((char *)res - cb);
282f003fb54Skardel 	}
283eabc0478Schristos 	DEBUG_INSIST(rl == res);
284f003fb54Skardel 	/* allocate the first */
285f003fb54Skardel 	return res;
286f003fb54Skardel }
287f003fb54Skardel 
288f003fb54Skardel 
289f003fb54Skardel static void
290*9e9fa66aSchristos free_res6(struct restrict_6 *	res)
291f003fb54Skardel {
292*9e9fa66aSchristos 	struct restrict_6 *	unlinked;
293f003fb54Skardel 
294f003fb54Skardel 	restrictcount--;
295*9e9fa66aSchristos 	if (RES_LIMITED & res->ri.rflags) {
296f003fb54Skardel 		dec_res_limited();
297eabc0478Schristos 	}
298*9e9fa66aSchristos 	UNLINK_SLIST(unlinked, restrictlist6, res, link, struct restrict_6);
299eabc0478Schristos 	INSIST(unlinked == res);
300*9e9fa66aSchristos 	zero_mem(res, sizeof(*res));
301*9e9fa66aSchristos 	LINK_SLIST(resfree6, res, link);
302f003fb54Skardel }
303f003fb54Skardel 
304*9e9fa66aSchristos static void
305*9e9fa66aSchristos free_res4(struct restrict_4 *	res)
306*9e9fa66aSchristos {
307*9e9fa66aSchristos 	struct restrict_4 *	unlinked;
308*9e9fa66aSchristos 
309*9e9fa66aSchristos 	restrictcount--;
310*9e9fa66aSchristos 	if (RES_LIMITED & res->ri.rflags) {
311*9e9fa66aSchristos 		dec_res_limited();
312*9e9fa66aSchristos 	}
313*9e9fa66aSchristos 	UNLINK_SLIST(unlinked, restrictlist4, res, link, struct restrict_4);
314*9e9fa66aSchristos 	INSIST(unlinked == res);
315*9e9fa66aSchristos 	zero_mem(res, sizeof(*res));
316*9e9fa66aSchristos 	LINK_SLIST(resfree4, res, link);
317*9e9fa66aSchristos }
318f003fb54Skardel 
319eabc0478Schristos static inline void
320f003fb54Skardel inc_res_limited(void)
321f003fb54Skardel {
322eabc0478Schristos 	if (0 == res_limited_refcnt) {
323f003fb54Skardel 		mon_start(MON_RES);
324eabc0478Schristos 	}
325f003fb54Skardel 	res_limited_refcnt++;
326f003fb54Skardel }
327f003fb54Skardel 
328f003fb54Skardel 
329eabc0478Schristos static inline void
330f003fb54Skardel dec_res_limited(void)
331f003fb54Skardel {
332f003fb54Skardel 	res_limited_refcnt--;
333eabc0478Schristos 	if (0 == res_limited_refcnt) {
334f003fb54Skardel 		mon_stop(MON_RES);
335f003fb54Skardel 	}
336eabc0478Schristos }
337f003fb54Skardel 
338f003fb54Skardel 
339*9e9fa66aSchristos static struct restrict_4 *
340f003fb54Skardel match_restrict4_addr(
341f003fb54Skardel 	u_int32	addr,
342f003fb54Skardel 	u_short	port
343f003fb54Skardel 	)
344f003fb54Skardel {
345*9e9fa66aSchristos 	struct restrict_4 *	res;
346*9e9fa66aSchristos 	struct restrict_4 *	next;
347f003fb54Skardel 
348f003fb54Skardel 	for (res = restrictlist4; res != NULL; res = next) {
349f003fb54Skardel 		next = res->link;
350*9e9fa66aSchristos 		if (res->ri.expire && res->ri.expire <= current_time) {
351*9e9fa66aSchristos 			free_res4(res);	/* zeroes the contents */
352eabc0478Schristos 		}
353*9e9fa66aSchristos 		if (   res->v4.addr == (addr & res->v4.mask)
354*9e9fa66aSchristos 		    && (   !(RESM_NTPONLY & res->ri.mflags)
3554eea345dSchristos 			|| NTP_PORT == port)) {
356eabc0478Schristos 
357f003fb54Skardel 			break;
358f003fb54Skardel 		}
3594eea345dSchristos 	}
360f003fb54Skardel 	return res;
361f003fb54Skardel }
362f003fb54Skardel 
363f003fb54Skardel 
364*9e9fa66aSchristos static struct restrict_6 *
365f003fb54Skardel match_restrict6_addr(
366f003fb54Skardel 	const struct in6_addr *	addr,
367f003fb54Skardel 	u_short			port
368f003fb54Skardel 	)
369f003fb54Skardel {
370*9e9fa66aSchristos 	struct restrict_6 *	res;
371*9e9fa66aSchristos 	struct restrict_6 *	next;
372f003fb54Skardel 	struct in6_addr	masked;
373f003fb54Skardel 
374f003fb54Skardel 	for (res = restrictlist6; res != NULL; res = next) {
375f003fb54Skardel 		next = res->link;
376*9e9fa66aSchristos 		if (res->ri.expire && res->ri.expire <= current_time) {
377*9e9fa66aSchristos 			free_res6(res);
378eabc0478Schristos 		}
379*9e9fa66aSchristos 		MASK_IPV6_ADDR(&masked, addr, &res->v6.mask);
380*9e9fa66aSchristos 		if (ADDR6_EQ(&masked, &res->v6.addr)
381*9e9fa66aSchristos 		    && (   !(RESM_NTPONLY & res->ri.mflags)
382eabc0478Schristos 			|| NTP_PORT == (int)port)) {
383eabc0478Schristos 
384f003fb54Skardel 			break;
385f003fb54Skardel 		}
386eabc0478Schristos 	}
387f003fb54Skardel 	return res;
388f003fb54Skardel }
389f003fb54Skardel 
390abb0f93cSkardel 
391abb0f93cSkardel /*
392f003fb54Skardel  * match_restrict_entry - find an exact match on a restrict list.
393f003fb54Skardel  *
394f003fb54Skardel  * Exact match is addr, mask, and mflags all equal.
395f003fb54Skardel  * In order to use more common code for IPv4 and IPv6, this routine
396*9e9fa66aSchristos  * requires the caller to populate a restrict_[46] with mflags and either
397f003fb54Skardel  * the v4 or v6 address and mask as appropriate.  Other fields in the
398f003fb54Skardel  * input restrict_u are ignored.
399abb0f93cSkardel  */
400*9e9fa66aSchristos static struct restrict_4 *
401*9e9fa66aSchristos match_restrict4_entry(
402*9e9fa66aSchristos 	const struct restrict_4 *	pmatch)
403f003fb54Skardel {
404*9e9fa66aSchristos 	struct restrict_4 *res;
405f003fb54Skardel 
406*9e9fa66aSchristos 	for (res = restrictlist4; res != NULL; res = res->link) {
407*9e9fa66aSchristos 		if (res->ri.mflags == pmatch->ri.mflags &&
408*9e9fa66aSchristos 		    !memcmp(&res->v4, &pmatch->v4, sizeof(res->v4))) {
409f003fb54Skardel 			break;
410eabc0478Schristos 		}
411eabc0478Schristos 	}
412f003fb54Skardel 	return res;
413f003fb54Skardel }
414f003fb54Skardel 
415*9e9fa66aSchristos static struct restrict_6 *
416*9e9fa66aSchristos match_restrict6_entry(
417*9e9fa66aSchristos 	const struct restrict_6 *	pmatch)
418*9e9fa66aSchristos {
419*9e9fa66aSchristos 	struct restrict_6 *res;
420*9e9fa66aSchristos 
421*9e9fa66aSchristos 	for (res = restrictlist6; res != NULL; res = res->link) {
422*9e9fa66aSchristos 		if (res->ri.mflags == pmatch->ri.mflags &&
423*9e9fa66aSchristos 		    !memcmp(&res->v6, &pmatch->v6, sizeof(res->v6))) {
424*9e9fa66aSchristos 			break;
425*9e9fa66aSchristos 		}
426*9e9fa66aSchristos 	}
427*9e9fa66aSchristos 	return res;
428*9e9fa66aSchristos }
429abb0f93cSkardel 
430abb0f93cSkardel /*
431eabc0478Schristos  * mflags_sorts_before - common mflags sorting code
432eabc0478Schristos  *
433eabc0478Schristos  * See block comment in init_restrict() above for rationale.
434eabc0478Schristos  */
435eabc0478Schristos static inline int/*BOOL*/
436eabc0478Schristos mflags_sorts_before(
437eabc0478Schristos 	u_short	m1,
438eabc0478Schristos 	u_short	m2
439eabc0478Schristos 	)
440eabc0478Schristos {
441eabc0478Schristos 	if (    (RESM_INTERFACE & m1)
442eabc0478Schristos 	    && !(RESM_INTERFACE & m2)) {
443eabc0478Schristos 		return TRUE;
444eabc0478Schristos 	} else if (   !(RESM_SOURCE & m1)
445eabc0478Schristos 		   &&  (RESM_SOURCE & m2)) {
446eabc0478Schristos 		return TRUE;
447eabc0478Schristos 	} else {
448eabc0478Schristos 		return FALSE;
449eabc0478Schristos 	}
450eabc0478Schristos }
451eabc0478Schristos 
452eabc0478Schristos 
453eabc0478Schristos /*
454eabc0478Schristos  * res_sorts_before4 - compare IPv4 restriction entries
455f003fb54Skardel  *
456f003fb54Skardel  * Returns nonzero if r1 sorts before r2.  We sort by descending
457eabc0478Schristos  * address, then descending mask, then an intricate mflags sort
458eabc0478Schristos  * order explained in a block comment near the top of this file.
459abb0f93cSkardel  */
460eabc0478Schristos static int/*BOOL*/
461f003fb54Skardel res_sorts_before4(
462*9e9fa66aSchristos 	struct restrict_4 *r1,
463*9e9fa66aSchristos 	struct restrict_4 *r2
464f003fb54Skardel 	)
465f003fb54Skardel {
466f003fb54Skardel 	int r1_before_r2;
467f003fb54Skardel 
468*9e9fa66aSchristos 	if (r1->v4.addr > r2->v4.addr) {
469eabc0478Schristos 		r1_before_r2 = TRUE;
470*9e9fa66aSchristos 	} else if (r1->v4.addr < r2->v4.addr) {
471eabc0478Schristos 		r1_before_r2 = FALSE;
472*9e9fa66aSchristos 	} else if (r1->v4.mask > r2->v4.mask) {
473eabc0478Schristos 		r1_before_r2 = TRUE;
474*9e9fa66aSchristos 	} else if (r1->v4.mask < r2->v4.mask) {
475eabc0478Schristos 		r1_before_r2 = FALSE;
476eabc0478Schristos 	} else {
477*9e9fa66aSchristos 		r1_before_r2 = mflags_sorts_before(r1->ri.mflags, r2->ri.mflags);
478eabc0478Schristos 	}
479f003fb54Skardel 
480f003fb54Skardel 	return r1_before_r2;
481f003fb54Skardel }
482f003fb54Skardel 
483f003fb54Skardel 
484f003fb54Skardel /*
485eabc0478Schristos  * res_sorts_before6 - compare IPv6 restriction entries
486f003fb54Skardel  *
487f003fb54Skardel  * Returns nonzero if r1 sorts before r2.  We sort by descending
488eabc0478Schristos  * address, then descending mask, then an intricate mflags sort
489eabc0478Schristos  * order explained in a block comment near the top of this file.
490f003fb54Skardel  */
491eabc0478Schristos static int/*BOOL*/
492f003fb54Skardel res_sorts_before6(
493*9e9fa66aSchristos 	struct restrict_6* r1,
494*9e9fa66aSchristos 	struct restrict_6* r2
495f003fb54Skardel )
496f003fb54Skardel {
497f003fb54Skardel 	int r1_before_r2;
498f003fb54Skardel 	int cmp;
499f003fb54Skardel 
500*9e9fa66aSchristos 	cmp = ADDR6_CMP(&r1->v6.addr, &r2->v6.addr);
501eabc0478Schristos 	if (cmp > 0) {		/* r1->addr > r2->addr */
502eabc0478Schristos 		r1_before_r2 = TRUE;
503eabc0478Schristos 	} else if (cmp < 0) {	/* r2->addr > r1->addr */
504eabc0478Schristos 		r1_before_r2 = FALSE;
505eabc0478Schristos 	} else {
506*9e9fa66aSchristos 		cmp = ADDR6_CMP(&r1->v6.mask, &r2->v6.mask);
507eabc0478Schristos 		if (cmp > 0) {		/* r1->mask > r2->mask*/
508eabc0478Schristos 			r1_before_r2 = TRUE;
509eabc0478Schristos 		} else if (cmp < 0) {	/* r2->mask > r1->mask */
510eabc0478Schristos 			r1_before_r2 = FALSE;
511eabc0478Schristos 		} else {
512*9e9fa66aSchristos 			r1_before_r2 = mflags_sorts_before(r1->ri.mflags,
513*9e9fa66aSchristos 							   r2->ri.mflags);
514eabc0478Schristos 		}
515f003fb54Skardel 	}
516f003fb54Skardel 
517f003fb54Skardel 	return r1_before_r2;
518abb0f93cSkardel }
519abb0f93cSkardel 
520abb0f93cSkardel 
521abb0f93cSkardel /*
5224eea345dSchristos  * restrictions - return restrictions for this host in *r4a
523abb0f93cSkardel  */
5244eea345dSchristos void
525abb0f93cSkardel restrictions(
5264eea345dSchristos 	sockaddr_u *srcadr,
5274eea345dSchristos 	r4addr *r4a
528abb0f93cSkardel 	)
529abb0f93cSkardel {
530f003fb54Skardel 	struct in6_addr *pin6;
5314eea345dSchristos 
532eabc0478Schristos 	DEBUG_REQUIRE(NULL != r4a);
533abb0f93cSkardel 
534abb0f93cSkardel 	res_calls++;
5354eea345dSchristos 
536abb0f93cSkardel 	if (IS_IPV4(srcadr)) {
537*9e9fa66aSchristos 		struct restrict_4 *match;
538abb0f93cSkardel 		/*
539abb0f93cSkardel 		 * Ignore any packets with a multicast source address
540abb0f93cSkardel 		 * (this should be done early in the receive process,
541abb0f93cSkardel 		 * not later!)
542abb0f93cSkardel 		 */
5434eea345dSchristos 		if (IN_CLASSD(SRCADR(srcadr))) {
544eabc0478Schristos 			goto multicast;
5454eea345dSchristos 		}
546abb0f93cSkardel 
547f003fb54Skardel 		match = match_restrict4_addr(SRCADR(srcadr),
548f003fb54Skardel 					     SRCPORT(srcadr));
549eabc0478Schristos 		DEBUG_INSIST(match != NULL);
550*9e9fa66aSchristos 		match->ri.count++;
551f003fb54Skardel 		/*
552f003fb54Skardel 		 * res_not_found counts only use of the final default
553f003fb54Skardel 		 * entry, not any "restrict default ntpport ...", which
554f003fb54Skardel 		 * would be just before the final default.
555f003fb54Skardel 		 */
556f003fb54Skardel 		if (&restrict_def4 == match)
557abb0f93cSkardel 			res_not_found++;
558abb0f93cSkardel 		else
559abb0f93cSkardel 			res_found++;
560*9e9fa66aSchristos 		r4a->rflags = match->ri.rflags;
561*9e9fa66aSchristos 		r4a->ippeerlimit = match->ri.ippeerlimit;
562eabc0478Schristos 	} else {
563*9e9fa66aSchristos 		struct restrict_6 *match;
564eabc0478Schristos 		DEBUG_REQUIRE(IS_IPV6(srcadr));
565abb0f93cSkardel 
566f003fb54Skardel 		pin6 = PSOCK_ADDR6(srcadr);
567abb0f93cSkardel 
568abb0f93cSkardel 		/*
569abb0f93cSkardel 		 * Ignore any packets with a multicast source address
570abb0f93cSkardel 		 * (this should be done early in the receive process,
571abb0f93cSkardel 		 * not later!)
572abb0f93cSkardel 		 */
573eabc0478Schristos 		if (IN6_IS_ADDR_MULTICAST(pin6)) {
574eabc0478Schristos 			goto multicast;
575eabc0478Schristos 		}
576f003fb54Skardel 		match = match_restrict6_addr(pin6, SRCPORT(srcadr));
577eabc0478Schristos 		DEBUG_INSIST(match != NULL);
578*9e9fa66aSchristos 		match->ri.count++;
579f003fb54Skardel 		if (&restrict_def6 == match)
580abb0f93cSkardel 			res_not_found++;
581abb0f93cSkardel 		else
582abb0f93cSkardel 			res_found++;
583*9e9fa66aSchristos 		r4a->rflags = match->ri.rflags;
584*9e9fa66aSchristos 		r4a->ippeerlimit = match->ri.ippeerlimit;
585abb0f93cSkardel 	}
586cdfa2a7eSchristos 
5874eea345dSchristos 	return;
588eabc0478Schristos 
589eabc0478Schristos     multicast:
590eabc0478Schristos 	r4a->rflags = RES_IGNORE;
591eabc0478Schristos 	r4a->ippeerlimit = 0;
5924eea345dSchristos }
5934eea345dSchristos 
5944eea345dSchristos 
595eabc0478Schristos #ifdef DEBUG
596eabc0478Schristos /* display string for restrict_op */
5974eea345dSchristos const char *
598eabc0478Schristos resop_str(restrict_op op)
599eabc0478Schristos {
6004eea345dSchristos 	switch (op) {
6014eea345dSchristos 	    case RESTRICT_FLAGS:	return "RESTRICT_FLAGS";
602eabc0478Schristos 	    case RESTRICT_UNFLAG:	return "RESTRICT_UNFLAG";
6034eea345dSchristos 	    case RESTRICT_REMOVE:	return "RESTRICT_REMOVE";
6044eea345dSchristos 	    case RESTRICT_REMOVEIF:	return "RESTRICT_REMOVEIF";
6054eea345dSchristos 	}
606eabc0478Schristos 	DEBUG_INVARIANT(!"bad restrict_op in resop_str");
607eabc0478Schristos 	return "";	/* silence not all paths return value warning */
608abb0f93cSkardel }
609eabc0478Schristos #endif	/* DEBUG */
610abb0f93cSkardel 
611abb0f93cSkardel 
612abb0f93cSkardel /*
613abb0f93cSkardel  * hack_restrict - add/subtract/manipulate entries on the restrict list
614abb0f93cSkardel  */
615eabc0478Schristos int/*BOOL*/
616abb0f93cSkardel hack_restrict(
6174eea345dSchristos 	restrict_op	op,
618abb0f93cSkardel 	sockaddr_u *	resaddr,
619abb0f93cSkardel 	sockaddr_u *	resmask,
6204eea345dSchristos 	short		ippeerlimit,
621f003fb54Skardel 	u_short		mflags,
6224eea345dSchristos 	u_short		rflags,
623eabc0478Schristos 	u_int32		expire
624abb0f93cSkardel 	)
625abb0f93cSkardel {
626eabc0478Schristos 	int		bump_res_limited = FALSE;
627*9e9fa66aSchristos 	struct restrict_4	match4, *res4 = NULL;
628*9e9fa66aSchristos 	struct restrict_6	match6, *res6 = NULL;
629*9e9fa66aSchristos 	struct restrict_info *ri;
630f003fb54Skardel 
631eabc0478Schristos #ifdef DEBUG
632eabc0478Schristos 	if (debug > 0) {
633eabc0478Schristos 		printf("hack_restrict: op %s addr %s mask %s",
634eabc0478Schristos 			resop_str(op), stoa(resaddr), stoa(resmask));
635eabc0478Schristos 		if (ippeerlimit >= 0) {
636eabc0478Schristos 			printf(" ippeerlimit %d", ippeerlimit);
637eabc0478Schristos 		}
638eabc0478Schristos 		printf(" mflags %s rflags %s", mflags_str(mflags),
639eabc0478Schristos 		       rflags_str(rflags));
640eabc0478Schristos 		if (expire) {
641eabc0478Schristos 			printf("lifetime %u\n",
642eabc0478Schristos 			       expire - (u_int32)current_time);
643eabc0478Schristos 		} else {
644eabc0478Schristos 			printf("\n");
645eabc0478Schristos 		}
646eabc0478Schristos 	}
647eabc0478Schristos #endif
648f003fb54Skardel 
649f003fb54Skardel 	if (NULL == resaddr) {
650eabc0478Schristos 		DEBUG_REQUIRE(NULL == resmask);
651eabc0478Schristos 		DEBUG_REQUIRE(RESTRICT_FLAGS == op);
652eabc0478Schristos 		DEBUG_REQUIRE(RESM_SOURCE & mflags);
6534eea345dSchristos 		restrict_source_rflags = rflags;
654f003fb54Skardel 		restrict_source_mflags = mflags;
6554eea345dSchristos 		restrict_source_ippeerlimit = ippeerlimit;
656eabc0478Schristos 		restrict_source_enabled = TRUE;
657eabc0478Schristos 		DPRINTF(1, ("restrict source template saved\n"));
658eabc0478Schristos 		return TRUE;
659f003fb54Skardel 	}
660f003fb54Skardel 
661af12ab5eSchristos 
662abb0f93cSkardel 	if (IS_IPV4(resaddr)) {
663eabc0478Schristos 		DEBUG_INVARIANT(IS_IPV4(resmask));
664abb0f93cSkardel 		/*
665f003fb54Skardel 		 * Get address and mask in host byte order for easy
666f003fb54Skardel 		 * comparison as u_int32
667abb0f93cSkardel 		 */
668*9e9fa66aSchristos 		ZERO(match4);
669*9e9fa66aSchristos 		match4.v4.addr = SRCADR(resaddr);
670*9e9fa66aSchristos 		match4.v4.mask = SRCADR(resmask);
671*9e9fa66aSchristos 		match4.v4.addr &= match4.v4.mask;
672*9e9fa66aSchristos 		match4.ri.mflags = mflags;
673*9e9fa66aSchristos 		res4 = match_restrict4_entry(&match4);
674*9e9fa66aSchristos 		ri = res4 ? &res4->ri : NULL;
675eabc0478Schristos 	} else {
676eabc0478Schristos 		DEBUG_INVARIANT(IS_IPV6(resaddr));
677eabc0478Schristos 		DEBUG_INVARIANT(IS_IPV6(resmask));
678f003fb54Skardel 		/*
679f003fb54Skardel 		 * Get address and mask in network byte order for easy
680f003fb54Skardel 		 * comparison as byte sequences (e.g. memcmp())
681f003fb54Skardel 		 */
682*9e9fa66aSchristos 		ZERO(match6);
683*9e9fa66aSchristos 		match6.v6.mask = SOCK_ADDR6(resmask);
684*9e9fa66aSchristos 		MASK_IPV6_ADDR(&match6.v6.addr, PSOCK_ADDR6(resaddr),
685*9e9fa66aSchristos 			       &match6.v6.mask);
686*9e9fa66aSchristos 		match6.ri.mflags = mflags;
687*9e9fa66aSchristos 		res6 = match_restrict6_entry(&match6);
688*9e9fa66aSchristos 		ri = res6 ? &res6->ri : NULL;
689eabc0478Schristos 	}
690abb0f93cSkardel 
691f003fb54Skardel 
692f003fb54Skardel 	switch (op) {
693f003fb54Skardel 
694f003fb54Skardel 	case RESTRICT_FLAGS:
695abb0f93cSkardel 		/*
696eabc0478Schristos 		 * Here we add bits to the rflags. If we already have
697eabc0478Schristos 		 * this restriction modify it.
698abb0f93cSkardel 		 */
699*9e9fa66aSchristos 		if (NULL != ri) {
700eabc0478Schristos 			if (    (RES_LIMITED & rflags)
701*9e9fa66aSchristos 			    && !(RES_LIMITED & ri->rflags)) {
702eabc0478Schristos 
703eabc0478Schristos 				bump_res_limited = TRUE;
704eabc0478Schristos 			}
705*9e9fa66aSchristos 			ri->rflags |= rflags;
706*9e9fa66aSchristos 			ri->expire = expire;
707eabc0478Schristos 		} else {
708*9e9fa66aSchristos 			if (IS_IPV4(resaddr)) {
709*9e9fa66aSchristos 				match4.ri.rflags = rflags;
710*9e9fa66aSchristos 				match4.ri.expire = expire;
711*9e9fa66aSchristos 				match4.ri.ippeerlimit = ippeerlimit;
712*9e9fa66aSchristos 				res4 = alloc_res4();
713*9e9fa66aSchristos 				memcpy(res4, &match4, sizeof(*res4));
714f003fb54Skardel 				LINK_SORT_SLIST(
715*9e9fa66aSchristos 				    restrictlist4, res4,
716*9e9fa66aSchristos 				    res_sorts_before4(res4, L_S_S_CUR()),
717*9e9fa66aSchristos 				    link, struct restrict_4);
718*9e9fa66aSchristos 			} else {
719*9e9fa66aSchristos 				match6.ri.rflags = rflags;
720*9e9fa66aSchristos 				match6.ri.expire = expire;
721*9e9fa66aSchristos 				match6.ri.ippeerlimit = ippeerlimit;
722*9e9fa66aSchristos 				res6 = alloc_res6();
723*9e9fa66aSchristos 				memcpy(res6, &match6, sizeof(*res6));
724*9e9fa66aSchristos 				LINK_SORT_SLIST(
725*9e9fa66aSchristos 				    restrictlist6, res6,
726*9e9fa66aSchristos 				    res_sorts_before6(res6, L_S_S_CUR()),
727*9e9fa66aSchristos 				    link, struct restrict_6);
728*9e9fa66aSchristos 			}
729f003fb54Skardel 			restrictcount++;
730eabc0478Schristos 			if (RES_LIMITED & rflags) {
731eabc0478Schristos 				bump_res_limited = TRUE;
732abb0f93cSkardel 			}
733eabc0478Schristos 		}
734eabc0478Schristos 		if (bump_res_limited) {
735eabc0478Schristos 			inc_res_limited();
736eabc0478Schristos 		}
737eabc0478Schristos 		return TRUE;
738abb0f93cSkardel 
739abb0f93cSkardel 	case RESTRICT_UNFLAG:
740abb0f93cSkardel 		/*
7414eea345dSchristos 		 * Remove some bits from the rflags. If we didn't
742abb0f93cSkardel 		 * find this one, just return.
743abb0f93cSkardel 		 */
744*9e9fa66aSchristos 		if (NULL == ri) {
745eabc0478Schristos 			DPRINTF(1, ("No match for %s %s removing rflags %s\n",
746eabc0478Schristos 				    stoa(resaddr), stoa(resmask),
747eabc0478Schristos 				    rflags_str(rflags)));
748eabc0478Schristos 			return FALSE;
749abb0f93cSkardel 		}
750*9e9fa66aSchristos 		if (   (RES_LIMITED & ri->rflags)
751eabc0478Schristos 		    && (RES_LIMITED & rflags)) {
752eabc0478Schristos 			dec_res_limited();
753eabc0478Schristos 		}
754*9e9fa66aSchristos 		ri->rflags &= ~rflags;
755eabc0478Schristos 		return TRUE;
756abb0f93cSkardel 
757abb0f93cSkardel 	case RESTRICT_REMOVE:
758abb0f93cSkardel 	case RESTRICT_REMOVEIF:
759abb0f93cSkardel 		/*
760abb0f93cSkardel 		 * Remove an entry from the table entirely if we
761abb0f93cSkardel 		 * found one. Don't remove the default entry and
762eabc0478Schristos 		 * don't remove an interface entry unless asked.
763abb0f93cSkardel 		 */
764*9e9fa66aSchristos 		if (   ri != NULL
765f003fb54Skardel 		    && (   RESTRICT_REMOVEIF == op
766*9e9fa66aSchristos 			|| !(RESM_INTERFACE & ri->mflags))) {
767*9e9fa66aSchristos 			if (res4 && res4 != &restrict_def4) {
768*9e9fa66aSchristos 				free_res4(res4);
769eabc0478Schristos 				return TRUE;
770abb0f93cSkardel 			}
771*9e9fa66aSchristos 			if (res6 && res6 != &restrict_def6) {
772*9e9fa66aSchristos 				free_res6(res6);
773*9e9fa66aSchristos 				return TRUE;
774*9e9fa66aSchristos 			}
775*9e9fa66aSchristos 		}
776eabc0478Schristos 		DPRINTF(1, ("No match removing %s %s restriction\n",
777eabc0478Schristos 			    stoa(resaddr), stoa(resmask)));
778eabc0478Schristos 		return FALSE;
779eabc0478Schristos 	}
780eabc0478Schristos 	/* notreached */
781eabc0478Schristos 	return FALSE;
782abb0f93cSkardel }
783f003fb54Skardel 
7842950cc38Schristos 
7852950cc38Schristos /*
7862950cc38Schristos  * restrict_source - maintains dynamic "restrict source ..." entries as
7872950cc38Schristos  *		     peers come and go.
7882950cc38Schristos  */
7892950cc38Schristos void
7902950cc38Schristos restrict_source(
7912950cc38Schristos 	sockaddr_u *	addr,
792eabc0478Schristos 	int		farewell,	/* TRUE to remove */
793eabc0478Schristos 	u_int32		lifetime	/* seconds, 0 forever */
7942950cc38Schristos 	)
7952950cc38Schristos {
7962950cc38Schristos 	sockaddr_u	onesmask;
797eabc0478Schristos 	int/*BOOL*/	success;
7982950cc38Schristos 
799eabc0478Schristos 	if (   !restrict_source_enabled || SOCK_UNSPEC(addr)
800eabc0478Schristos 	    || IS_MCAST(addr) || ISREFCLOCKADR(addr)) {
8012950cc38Schristos 		return;
802eabc0478Schristos 	}
8032950cc38Schristos 
804af12ab5eSchristos 	REQUIRE(AF_INET == AF(addr) || AF_INET6 == AF(addr));
8052950cc38Schristos 
8062950cc38Schristos 	SET_HOSTMASK(&onesmask, AF(addr));
8072950cc38Schristos 	if (farewell) {
808eabc0478Schristos 		success = hack_restrict(RESTRICT_REMOVE, addr, &onesmask,
809eabc0478Schristos 					0, RESM_SOURCE, 0, 0);
810eabc0478Schristos 		if (success) {
811eabc0478Schristos 			DPRINTF(1, ("%s %s removed", __func__,
8122950cc38Schristos 				    stoa(addr)));
813eabc0478Schristos 		} else {
814eabc0478Schristos 			msyslog(LOG_ERR, "%s remove %s failed",
815eabc0478Schristos 					 __func__, stoa(addr));
8162950cc38Schristos 		}
817eabc0478Schristos 		return;
818eabc0478Schristos 	}
819eabc0478Schristos 
820eabc0478Schristos 	success = hack_restrict(RESTRICT_FLAGS, addr, &onesmask,
821eabc0478Schristos 				restrict_source_ippeerlimit,
822eabc0478Schristos 				restrict_source_mflags,
823eabc0478Schristos 				restrict_source_rflags,
824eabc0478Schristos 				lifetime > 0
825eabc0478Schristos 				    ? lifetime + current_time
826eabc0478Schristos 				    : 0);
827eabc0478Schristos 	if (success) {
828eabc0478Schristos 		DPRINTF(1, ("%s %s add/upd\n", __func__,
829eabc0478Schristos 			    stoa(addr)));
830eabc0478Schristos 	} else {
831eabc0478Schristos 		msyslog(LOG_ERR, "%s %s failed", __func__, stoa(addr));
832eabc0478Schristos 	}
833eabc0478Schristos }
834eabc0478Schristos 
835eabc0478Schristos 
836eabc0478Schristos #ifdef DEBUG
837eabc0478Schristos /* Convert restriction RES_ flag bits into a display string */
838eabc0478Schristos const char *
839eabc0478Schristos rflags_str(
840eabc0478Schristos 	u_short rflags
841eabc0478Schristos 	)
842eabc0478Schristos {
843eabc0478Schristos 	const size_t	sz = LIB_BUFLENGTH;
844eabc0478Schristos 	char *		rfs;
845eabc0478Schristos 
846eabc0478Schristos 	LIB_GETBUF(rfs);
847eabc0478Schristos 	rfs[0] = '\0';
848eabc0478Schristos 
849eabc0478Schristos 	if (rflags & RES_FLAKE) {
850eabc0478Schristos 		CLEAR_BIT_IF_DEBUG(RES_FLAKE, rflags);
851eabc0478Schristos 		append_flagstr(rfs, sz, "flake");
852eabc0478Schristos 	}
853eabc0478Schristos 
854eabc0478Schristos 	if (rflags & RES_IGNORE) {
855eabc0478Schristos 		CLEAR_BIT_IF_DEBUG(RES_IGNORE, rflags);
856eabc0478Schristos 		append_flagstr(rfs, sz, "ignore");
857eabc0478Schristos 	}
858eabc0478Schristos 
859eabc0478Schristos 	if (rflags & RES_KOD) {
860eabc0478Schristos 		CLEAR_BIT_IF_DEBUG(RES_KOD, rflags);
861eabc0478Schristos 		append_flagstr(rfs, sz, "kod");
862eabc0478Schristos 	}
863eabc0478Schristos 
864eabc0478Schristos 	if (rflags & RES_MSSNTP) {
865eabc0478Schristos 		CLEAR_BIT_IF_DEBUG(RES_MSSNTP, rflags);
866eabc0478Schristos 		append_flagstr(rfs, sz, "mssntp");
867eabc0478Schristos 	}
868eabc0478Schristos 
869eabc0478Schristos 	if (rflags & RES_LIMITED) {
870eabc0478Schristos 		CLEAR_BIT_IF_DEBUG(RES_LIMITED, rflags);
871eabc0478Schristos 		append_flagstr(rfs, sz, "limited");
872eabc0478Schristos 	}
873eabc0478Schristos 
874eabc0478Schristos 	if (rflags & RES_LPTRAP) {
875eabc0478Schristos 		CLEAR_BIT_IF_DEBUG(RES_LPTRAP, rflags);
876eabc0478Schristos 		append_flagstr(rfs, sz, "lptrap");
877eabc0478Schristos 	}
878eabc0478Schristos 
879eabc0478Schristos 	if (rflags & RES_NOMODIFY) {
880eabc0478Schristos 		CLEAR_BIT_IF_DEBUG(RES_NOMODIFY, rflags);
881eabc0478Schristos 		append_flagstr(rfs, sz, "nomodify");
882eabc0478Schristos 	}
883eabc0478Schristos 
884eabc0478Schristos 	if (rflags & RES_NOMRULIST) {
885eabc0478Schristos 		CLEAR_BIT_IF_DEBUG(RES_NOMRULIST, rflags);
886eabc0478Schristos 		append_flagstr(rfs, sz, "nomrulist");
887eabc0478Schristos 	}
888eabc0478Schristos 
889eabc0478Schristos 	if (rflags & RES_NOEPEER) {
890eabc0478Schristos 		CLEAR_BIT_IF_DEBUG(RES_NOEPEER, rflags);
891eabc0478Schristos 		append_flagstr(rfs, sz, "noepeer");
892eabc0478Schristos 	}
893eabc0478Schristos 
894eabc0478Schristos 	if (rflags & RES_NOPEER) {
895eabc0478Schristos 		CLEAR_BIT_IF_DEBUG(RES_NOPEER, rflags);
896eabc0478Schristos 		append_flagstr(rfs, sz, "nopeer");
897eabc0478Schristos 	}
898eabc0478Schristos 
899eabc0478Schristos 	if (rflags & RES_NOQUERY) {
900eabc0478Schristos 		CLEAR_BIT_IF_DEBUG(RES_NOQUERY, rflags);
901eabc0478Schristos 		append_flagstr(rfs, sz, "noquery");
902eabc0478Schristos 	}
903eabc0478Schristos 
904eabc0478Schristos 	if (rflags & RES_DONTSERVE) {
905eabc0478Schristos 		CLEAR_BIT_IF_DEBUG(RES_DONTSERVE, rflags);
906eabc0478Schristos 		append_flagstr(rfs, sz, "dontserve");
907eabc0478Schristos 	}
908eabc0478Schristos 
909eabc0478Schristos 	if (rflags & RES_NOTRAP) {
910eabc0478Schristos 		CLEAR_BIT_IF_DEBUG(RES_NOTRAP, rflags);
911eabc0478Schristos 		append_flagstr(rfs, sz, "notrap");
912eabc0478Schristos 	}
913eabc0478Schristos 
914eabc0478Schristos 	if (rflags & RES_DONTTRUST) {
915eabc0478Schristos 		CLEAR_BIT_IF_DEBUG(RES_DONTTRUST, rflags);
916eabc0478Schristos 		append_flagstr(rfs, sz, "notrust");
917eabc0478Schristos 	}
918eabc0478Schristos 
919eabc0478Schristos 	if (rflags & RES_SRVRSPFUZ) {
920eabc0478Schristos 		CLEAR_BIT_IF_DEBUG(RES_SRVRSPFUZ, rflags);
921eabc0478Schristos 		append_flagstr(rfs, sz, "srvrspfuz");
922eabc0478Schristos 	}
923eabc0478Schristos 
924eabc0478Schristos 	if (rflags & RES_VERSION) {
925eabc0478Schristos 		CLEAR_BIT_IF_DEBUG(RES_VERSION, rflags);
926eabc0478Schristos 		append_flagstr(rfs, sz, "version");
927eabc0478Schristos 	}
928eabc0478Schristos 
929eabc0478Schristos 	DEBUG_INVARIANT(!rflags);
930eabc0478Schristos 
931eabc0478Schristos 	if ('\0' == rfs[0]) {
932eabc0478Schristos 		append_flagstr(rfs, sz, "(none)");
933eabc0478Schristos 	}
934eabc0478Schristos 
935eabc0478Schristos 	return rfs;
936eabc0478Schristos }
937eabc0478Schristos 
938eabc0478Schristos 
939eabc0478Schristos /* Convert restriction match RESM_ flag bits into a display string */
940eabc0478Schristos const char *
941eabc0478Schristos mflags_str(
942eabc0478Schristos 	u_short mflags
943eabc0478Schristos 	)
944eabc0478Schristos {
945eabc0478Schristos 	const size_t	sz = LIB_BUFLENGTH;
946eabc0478Schristos 	char *		mfs;
947eabc0478Schristos 
948eabc0478Schristos 	LIB_GETBUF(mfs);
949eabc0478Schristos 	mfs[0] = '\0';
950eabc0478Schristos 
951eabc0478Schristos 	if (mflags & RESM_NTPONLY) {
952eabc0478Schristos 		CLEAR_BIT_IF_DEBUG(RESM_NTPONLY, mflags);
953eabc0478Schristos 		append_flagstr(mfs, sz, "ntponly");
954eabc0478Schristos 	}
955eabc0478Schristos 
956eabc0478Schristos 	if (mflags & RESM_SOURCE) {
957eabc0478Schristos 		CLEAR_BIT_IF_DEBUG(RESM_SOURCE, mflags);
958eabc0478Schristos 		append_flagstr(mfs, sz, "source");
959eabc0478Schristos 	}
960eabc0478Schristos 
961eabc0478Schristos 	if (mflags & RESM_INTERFACE) {
962eabc0478Schristos 		CLEAR_BIT_IF_DEBUG(RESM_INTERFACE, mflags);
963eabc0478Schristos 		append_flagstr(mfs, sz, "interface");
964eabc0478Schristos 	}
965eabc0478Schristos 
966eabc0478Schristos 	DEBUG_INVARIANT(!mflags);
967eabc0478Schristos 
968eabc0478Schristos 	return mfs;
969eabc0478Schristos }
970eabc0478Schristos #endif	/* DEBUG */
971