154359Sroberto/*
2132451Sroberto * ntp_restrict.c - determine host restrictions
354359Sroberto */
454359Sroberto#ifdef HAVE_CONFIG_H
554359Sroberto#include <config.h>
654359Sroberto#endif
754359Sroberto
854359Sroberto#include <stdio.h>
954359Sroberto#include <sys/types.h>
1054359Sroberto
1154359Sroberto#include "ntpd.h"
1254359Sroberto#include "ntp_if.h"
13285612Sdelphij#include "ntp_lists.h"
1454359Sroberto#include "ntp_stdlib.h"
15285612Sdelphij#include "ntp_assert.h"
1654359Sroberto
1754359Sroberto/*
1854359Sroberto * This code keeps a simple address-and-mask list of hosts we want
19132451Sroberto * to place restrictions on (or remove them from). The restrictions
2054359Sroberto * are implemented as a set of flags which tell you what the host
21132451Sroberto * can't do. There is a subroutine entry to return the flags. The
2254359Sroberto * list is kept sorted to reduce the average number of comparisons
2354359Sroberto * and make sure you get the set of restrictions most specific to
2454359Sroberto * the address.
2554359Sroberto *
2654359Sroberto * The algorithm is that, when looking up a host, it is first assumed
27132451Sroberto * that the default set of restrictions will apply. It then searches
28132451Sroberto * down through the list. Whenever it finds a match it adopts the
29132451Sroberto * match's flags instead. When you hit the point where the sorted
30132451Sroberto * address is greater than the target, you return with the last set of
31132451Sroberto * flags you found. Because of the ordering of the list, the most
32132451Sroberto * specific match will provide the final set of flags.
3354359Sroberto *
3454359Sroberto * This was originally intended to restrict you from sync'ing to your
35132451Sroberto * own broadcasts when you are doing that, by restricting yourself from
36132451Sroberto * your own interfaces. It was also thought it would sometimes be useful
37132451Sroberto * to keep a misbehaving host or two from abusing your primary clock. It
38132451Sroberto * has been expanded, however, to suit the needs of those with more
39132451Sroberto * restrictive access policies.
4054359Sroberto */
41132451Sroberto/*
42132451Sroberto * We will use two lists, one for IPv4 addresses and one for IPv6
43132451Sroberto * addresses. This is not protocol-independant but for now I can't
44132451Sroberto * find a way to respect this. We'll check this later... JFB 07/2001
45132451Sroberto */
46285612Sdelphij#define MASK_IPV6_ADDR(dst, src, msk)					\
47285612Sdelphij	do {								\
48285612Sdelphij		int idx;						\
49285612Sdelphij		for (idx = 0; idx < (int)COUNTOF((dst)->s6_addr); idx++) { \
50285612Sdelphij			(dst)->s6_addr[idx] = (src)->s6_addr[idx]	\
51285612Sdelphij					      & (msk)->s6_addr[idx];	\
52285612Sdelphij		}							\
53132451Sroberto	} while (0)
5454359Sroberto
5554359Sroberto/*
56285612Sdelphij * We allocate INC_RESLIST{4|6} entries to the free list whenever empty.
57285612Sdelphij * Auto-tune these to be just less than 1KB (leaving at least 16 bytes
58285612Sdelphij * for allocator overhead).
5954359Sroberto */
60285612Sdelphij#define	INC_RESLIST4	((1024 - 16) / V4_SIZEOF_RESTRICT_U)
61285612Sdelphij#define	INC_RESLIST6	((1024 - 16) / V6_SIZEOF_RESTRICT_U)
6254359Sroberto
6354359Sroberto/*
6454359Sroberto * The restriction list
6554359Sroberto */
66285612Sdelphijrestrict_u *restrictlist4;
67285612Sdelphijrestrict_u *restrictlist6;
68285612Sdelphijstatic int restrictcount;	/* count in the restrict lists */
6954359Sroberto
7054359Sroberto/*
7154359Sroberto * The free list and associated counters.  Also some uninteresting
7254359Sroberto * stat counters.
7354359Sroberto */
74285612Sdelphijstatic restrict_u *resfree4;	/* available entries (free list) */
75285612Sdelphijstatic restrict_u *resfree6;
7654359Sroberto
77285612Sdelphijstatic u_long res_calls;
78285612Sdelphijstatic u_long res_found;
79285612Sdelphijstatic u_long res_not_found;
8054359Sroberto
8154359Sroberto/*
82285612Sdelphij * Count number of restriction entries referring to RES_LIMITED, to
83285612Sdelphij * control implicit activation/deactivation of the MRU monlist.
8454359Sroberto */
85285612Sdelphijstatic	u_long res_limited_refcnt;
86132451Sroberto
8754359Sroberto/*
88285612Sdelphij * Our default entries.
89330141Sdelphij *
90330141Sdelphij * We can make this cleaner with c99 support: see init_restrict().
9154359Sroberto */
92285612Sdelphijstatic	restrict_u	restrict_def4;
93285612Sdelphijstatic	restrict_u	restrict_def6;
9454359Sroberto
9554359Sroberto/*
96285612Sdelphij * "restrict source ..." enabled knob and restriction bits.
9754359Sroberto */
98285612Sdelphijstatic	int		restrict_source_enabled;
99330141Sdelphijstatic	u_short		restrict_source_rflags;
100285612Sdelphijstatic	u_short		restrict_source_mflags;
101330141Sdelphijstatic	short		restrict_source_ippeerlimit;
10254359Sroberto
10354359Sroberto/*
104285612Sdelphij * private functions
105285612Sdelphij */
106285612Sdelphijstatic restrict_u *	alloc_res4(void);
107285612Sdelphijstatic restrict_u *	alloc_res6(void);
108285612Sdelphijstatic void		free_res(restrict_u *, int);
109285612Sdelphijstatic void		inc_res_limited(void);
110285612Sdelphijstatic void		dec_res_limited(void);
111285612Sdelphijstatic restrict_u *	match_restrict4_addr(u_int32, u_short);
112285612Sdelphijstatic restrict_u *	match_restrict6_addr(const struct in6_addr *,
113285612Sdelphij					     u_short);
114285612Sdelphijstatic restrict_u *	match_restrict_entry(const restrict_u *, int);
115285612Sdelphijstatic int		res_sorts_before4(restrict_u *, restrict_u *);
116285612Sdelphijstatic int		res_sorts_before6(restrict_u *, restrict_u *);
117330141Sdelphijstatic char *		roptoa(restrict_op op);
118285612Sdelphij
119285612Sdelphij
120330141Sdelphijvoid	dump_restricts(void);
121330141Sdelphij
122285612Sdelphij/*
123330141Sdelphij * dump_restrict - spit out a restrict_u
124330141Sdelphij */
125330141Sdelphijstatic void
126330141Sdelphijdump_restrict(
127330141Sdelphij	restrict_u *	res,
128330141Sdelphij	int		is_ipv6
129330141Sdelphij	)
130330141Sdelphij{
131330141Sdelphij	char as[INET6_ADDRSTRLEN];
132330141Sdelphij	char ms[INET6_ADDRSTRLEN];
133330141Sdelphij
134330141Sdelphij	if (is_ipv6) {
135330141Sdelphij		inet_ntop(AF_INET6, &res->u.v6.addr, as, sizeof as);
136330141Sdelphij		inet_ntop(AF_INET6, &res->u.v6.mask, ms, sizeof ms);
137330141Sdelphij	} else {
138330141Sdelphij		struct in_addr	sia = { htonl(res->u.v4.addr) };
139330141Sdelphij		struct in_addr	sim = { htonl(res->u.v4.mask) };
140330141Sdelphij
141330141Sdelphij		inet_ntop(AF_INET, &sia, as, sizeof as);
142330141Sdelphij		inet_ntop(AF_INET, &sim, ms, sizeof ms);
143330141Sdelphij	}
144330141Sdelphij	mprintf("restrict node at %p: %s/%s count %d, rflags %05x, mflags %05x, ippeerlimit %d, expire %lu, next %p\n",
145330141Sdelphij		res, as, ms, res->count, res->rflags, res->mflags,
146330141Sdelphij		res->ippeerlimit, res->expire, res->link);
147330141Sdelphij	return;
148330141Sdelphij}
149330141Sdelphij
150330141Sdelphij
151330141Sdelphij/*
152330141Sdelphij * dump_restricts - spit out the 'restrict' lines
153330141Sdelphij */
154330141Sdelphijvoid
155330141Sdelphijdump_restricts(void)
156330141Sdelphij{
157330141Sdelphij	int		defaultv4_done = 0;
158330141Sdelphij	int		defaultv6_done = 0;
159330141Sdelphij	restrict_u *	res;
160330141Sdelphij	restrict_u *	next;
161330141Sdelphij
162330141Sdelphij	mprintf("dump_restrict: restrict_def4: %p\n", &restrict_def4);
163330141Sdelphij	/* Spit out 'restrict {,-4,-6} default ...' lines, if needed */
164330141Sdelphij	for (res = &restrict_def4; res != NULL; res = next) {
165330141Sdelphij		dump_restrict(res, 0);
166330141Sdelphij		next = res->link;
167330141Sdelphij	}
168330141Sdelphij
169330141Sdelphij	mprintf("dump_restrict: restrict_def6: %p\n", &restrict_def6);
170330141Sdelphij	for (res = &restrict_def6; res != NULL; res = next) {
171330141Sdelphij		dump_restrict(res, 1);
172330141Sdelphij		next = res->link;
173330141Sdelphij	}
174330141Sdelphij
175330141Sdelphij	/* Spit out the IPv4 list */
176330141Sdelphij	mprintf("dump_restrict: restrictlist4: %p\n", &restrictlist4);
177330141Sdelphij	for (res = restrictlist4; res != NULL; res = next) {
178330141Sdelphij		dump_restrict(res, 0);
179330141Sdelphij		next = res->link;
180330141Sdelphij	}
181330141Sdelphij
182330141Sdelphij	/* Spit out the IPv6 list */
183330141Sdelphij	mprintf("dump_restrict: restrictlist6: %p\n", &restrictlist6);
184330141Sdelphij	for (res = restrictlist6; res != NULL; res = next) {
185330141Sdelphij		dump_restrict(res, 1);
186330141Sdelphij		next = res->link;
187330141Sdelphij	}
188330141Sdelphij
189330141Sdelphij	return;
190330141Sdelphij}
191330141Sdelphij
192330141Sdelphij/*
19354359Sroberto * init_restrict - initialize the restriction data structures
19454359Sroberto */
19554359Srobertovoid
19654359Srobertoinit_restrict(void)
19754359Sroberto{
19854359Sroberto	/*
199285612Sdelphij	 * The restriction lists begin with a default entry with address
200285612Sdelphij	 * and mask 0, which will match any entry.  The lists are kept
201285612Sdelphij	 * sorted by descending address followed by descending mask:
202285612Sdelphij	 *
203285612Sdelphij	 *   address	  mask
204285612Sdelphij	 * 192.168.0.0	255.255.255.0	kod limited noquery nopeer
205285612Sdelphij	 * 192.168.0.0	255.255.0.0	kod limited
206285612Sdelphij	 * 0.0.0.0	0.0.0.0		kod limited noquery
207285612Sdelphij	 *
208285612Sdelphij	 * The first entry which matches an address is used.  With the
209285612Sdelphij	 * example restrictions above, 192.168.0.0/24 matches the first
210285612Sdelphij	 * entry, the rest of 192.168.0.0/16 matches the second, and
211285612Sdelphij	 * everything else matches the third (default).
212285612Sdelphij	 *
213285612Sdelphij	 * Note this achieves the same result a little more efficiently
214285612Sdelphij	 * than the documented behavior, which is to keep the lists
215285612Sdelphij	 * sorted by ascending address followed by ascending mask, with
216285612Sdelphij	 * the _last_ matching entry used.
217285612Sdelphij	 *
218285612Sdelphij	 * An additional wrinkle is we may have multiple entries with
219285612Sdelphij	 * the same address and mask but differing match flags (mflags).
220285612Sdelphij	 * At present there is only one, RESM_NTPONLY.  Entries with
221285612Sdelphij	 * RESM_NTPONLY are sorted earlier so they take precedence over
222285612Sdelphij	 * any otherwise similar entry without.  Again, this is the same
223285612Sdelphij	 * behavior as but reversed implementation compared to the docs.
224285612Sdelphij	 *
22554359Sroberto	 */
226330141Sdelphij
227330141Sdelphij	restrict_def4.ippeerlimit = -1;		/* Cleaner if we have C99 */
228330141Sdelphij	restrict_def6.ippeerlimit = -1;		/* Cleaner if we have C99 */
229330141Sdelphij
230285612Sdelphij	LINK_SLIST(restrictlist4, &restrict_def4, link);
231285612Sdelphij	LINK_SLIST(restrictlist6, &restrict_def6, link);
232285612Sdelphij	restrictcount = 2;
233285612Sdelphij}
234285612Sdelphij
235285612Sdelphij
236285612Sdelphijstatic restrict_u *
237285612Sdelphijalloc_res4(void)
238285612Sdelphij{
239285612Sdelphij	const size_t	cb = V4_SIZEOF_RESTRICT_U;
240285612Sdelphij	const size_t	count = INC_RESLIST4;
241285612Sdelphij	restrict_u *	rl;
242285612Sdelphij	restrict_u *	res;
243293650Sglebius	size_t		i;
244285612Sdelphij
245285612Sdelphij	UNLINK_HEAD_SLIST(res, resfree4, link);
246285612Sdelphij	if (res != NULL)
247285612Sdelphij		return res;
248285612Sdelphij
249316069Sdelphij	rl = eallocarray(count, cb);
250285612Sdelphij	/* link all but the first onto free list */
251285612Sdelphij	res = (void *)((char *)rl + (count - 1) * cb);
252285612Sdelphij	for (i = count - 1; i > 0; i--) {
253285612Sdelphij		LINK_SLIST(resfree4, res, link);
254285612Sdelphij		res = (void *)((char *)res - cb);
25554359Sroberto	}
256289997Sglebius	INSIST(rl == res);
257285612Sdelphij	/* allocate the first */
258285612Sdelphij	return res;
259285612Sdelphij}
26054359Sroberto
26154359Sroberto
262285612Sdelphijstatic restrict_u *
263285612Sdelphijalloc_res6(void)
264285612Sdelphij{
265285612Sdelphij	const size_t	cb = V6_SIZEOF_RESTRICT_U;
266285612Sdelphij	const size_t	count = INC_RESLIST6;
267285612Sdelphij	restrict_u *	rl;
268285612Sdelphij	restrict_u *	res;
269293650Sglebius	size_t		i;
27054359Sroberto
271285612Sdelphij	UNLINK_HEAD_SLIST(res, resfree6, link);
272285612Sdelphij	if (res != NULL)
273285612Sdelphij		return res;
274285612Sdelphij
275316069Sdelphij	rl = eallocarray(count, cb);
276285612Sdelphij	/* link all but the first onto free list */
277285612Sdelphij	res = (void *)((char *)rl + (count - 1) * cb);
278285612Sdelphij	for (i = count - 1; i > 0; i--) {
279285612Sdelphij		LINK_SLIST(resfree6, res, link);
280285612Sdelphij		res = (void *)((char *)res - cb);
281285612Sdelphij	}
282289997Sglebius	INSIST(rl == res);
283285612Sdelphij	/* allocate the first */
284285612Sdelphij	return res;
28554359Sroberto}
28654359Sroberto
28754359Sroberto
288285612Sdelphijstatic void
289285612Sdelphijfree_res(
290285612Sdelphij	restrict_u *	res,
291285612Sdelphij	int		v6
292285612Sdelphij	)
293285612Sdelphij{
294285612Sdelphij	restrict_u **	plisthead;
295285612Sdelphij	restrict_u *	unlinked;
296285612Sdelphij
297285612Sdelphij	restrictcount--;
298330141Sdelphij	if (RES_LIMITED & res->rflags)
299285612Sdelphij		dec_res_limited();
300285612Sdelphij
301285612Sdelphij	if (v6)
302285612Sdelphij		plisthead = &restrictlist6;
303285612Sdelphij	else
304285612Sdelphij		plisthead = &restrictlist4;
305285612Sdelphij	UNLINK_SLIST(unlinked, *plisthead, res, link, restrict_u);
306289997Sglebius	INSIST(unlinked == res);
307285612Sdelphij
308285612Sdelphij	if (v6) {
309285612Sdelphij		zero_mem(res, V6_SIZEOF_RESTRICT_U);
310285612Sdelphij		plisthead = &resfree6;
311285612Sdelphij	} else {
312285612Sdelphij		zero_mem(res, V4_SIZEOF_RESTRICT_U);
313285612Sdelphij		plisthead = &resfree4;
314285612Sdelphij	}
315285612Sdelphij	LINK_SLIST(*plisthead, res, link);
316285612Sdelphij}
317285612Sdelphij
318285612Sdelphij
319285612Sdelphijstatic void
320285612Sdelphijinc_res_limited(void)
321285612Sdelphij{
322285612Sdelphij	if (!res_limited_refcnt)
323285612Sdelphij		mon_start(MON_RES);
324285612Sdelphij	res_limited_refcnt++;
325285612Sdelphij}
326285612Sdelphij
327285612Sdelphij
328285612Sdelphijstatic void
329285612Sdelphijdec_res_limited(void)
330285612Sdelphij{
331285612Sdelphij	res_limited_refcnt--;
332285612Sdelphij	if (!res_limited_refcnt)
333285612Sdelphij		mon_stop(MON_RES);
334285612Sdelphij}
335285612Sdelphij
336285612Sdelphij
337285612Sdelphijstatic restrict_u *
338285612Sdelphijmatch_restrict4_addr(
339285612Sdelphij	u_int32	addr,
340285612Sdelphij	u_short	port
341285612Sdelphij	)
342285612Sdelphij{
343285612Sdelphij	const int	v6 = 0;
344285612Sdelphij	restrict_u *	res;
345285612Sdelphij	restrict_u *	next;
346285612Sdelphij
347285612Sdelphij	for (res = restrictlist4; res != NULL; res = next) {
348330141Sdelphij		struct in_addr	sia = { htonl(res->u.v4.addr) };
349330141Sdelphij
350285612Sdelphij		next = res->link;
351330141Sdelphij		DPRINTF(2, ("match_restrict4_addr: Checking %s, port %d ... ",
352330141Sdelphij			    inet_ntoa(sia), port));
353330141Sdelphij		if (   res->expire
354330141Sdelphij		    && res->expire <= current_time)
355330141Sdelphij			free_res(res, v6);	/* zeroes the contents */
356330141Sdelphij		if (   res->u.v4.addr == (addr & res->u.v4.mask)
357330141Sdelphij		    && (   !(RESM_NTPONLY & res->mflags)
358330141Sdelphij			|| NTP_PORT == port)) {
359330141Sdelphij			DPRINTF(2, ("MATCH: ippeerlimit %d\n", res->ippeerlimit));
360285612Sdelphij			break;
361330141Sdelphij		}
362330141Sdelphij		DPRINTF(2, ("doesn't match: ippeerlimit %d\n", res->ippeerlimit));
363285612Sdelphij	}
364285612Sdelphij	return res;
365285612Sdelphij}
366285612Sdelphij
367285612Sdelphij
368285612Sdelphijstatic restrict_u *
369285612Sdelphijmatch_restrict6_addr(
370285612Sdelphij	const struct in6_addr *	addr,
371285612Sdelphij	u_short			port
372285612Sdelphij	)
373285612Sdelphij{
374285612Sdelphij	const int	v6 = 1;
375285612Sdelphij	restrict_u *	res;
376285612Sdelphij	restrict_u *	next;
377285612Sdelphij	struct in6_addr	masked;
378285612Sdelphij
379285612Sdelphij	for (res = restrictlist6; res != NULL; res = next) {
380285612Sdelphij		next = res->link;
381289997Sglebius		INSIST(next != res);
382285612Sdelphij		if (res->expire &&
383285612Sdelphij		    res->expire <= current_time)
384285612Sdelphij			free_res(res, v6);
385285612Sdelphij		MASK_IPV6_ADDR(&masked, addr, &res->u.v6.mask);
386285612Sdelphij		if (ADDR6_EQ(&masked, &res->u.v6.addr)
387285612Sdelphij		    && (!(RESM_NTPONLY & res->mflags)
388285612Sdelphij			|| NTP_PORT == (int)port))
389285612Sdelphij			break;
390285612Sdelphij	}
391285612Sdelphij	return res;
392285612Sdelphij}
393285612Sdelphij
394285612Sdelphij
39554359Sroberto/*
396285612Sdelphij * match_restrict_entry - find an exact match on a restrict list.
397285612Sdelphij *
398285612Sdelphij * Exact match is addr, mask, and mflags all equal.
399285612Sdelphij * In order to use more common code for IPv4 and IPv6, this routine
400285612Sdelphij * requires the caller to populate a restrict_u with mflags and either
401285612Sdelphij * the v4 or v6 address and mask as appropriate.  Other fields in the
402285612Sdelphij * input restrict_u are ignored.
403285612Sdelphij */
404285612Sdelphijstatic restrict_u *
405285612Sdelphijmatch_restrict_entry(
406285612Sdelphij	const restrict_u *	pmatch,
407285612Sdelphij	int			v6
408285612Sdelphij	)
409285612Sdelphij{
410285612Sdelphij	restrict_u *res;
411285612Sdelphij	restrict_u *rlist;
412285612Sdelphij	size_t cb;
413285612Sdelphij
414285612Sdelphij	if (v6) {
415285612Sdelphij		rlist = restrictlist6;
416285612Sdelphij		cb = sizeof(pmatch->u.v6);
417285612Sdelphij	} else {
418285612Sdelphij		rlist = restrictlist4;
419285612Sdelphij		cb = sizeof(pmatch->u.v4);
420285612Sdelphij	}
421285612Sdelphij
422285612Sdelphij	for (res = rlist; res != NULL; res = res->link)
423285612Sdelphij		if (res->mflags == pmatch->mflags &&
424285612Sdelphij		    !memcmp(&res->u, &pmatch->u, cb))
425285612Sdelphij			break;
426285612Sdelphij	return res;
427285612Sdelphij}
428285612Sdelphij
429285612Sdelphij
430285612Sdelphij/*
431285612Sdelphij * res_sorts_before4 - compare two restrict4 entries
432285612Sdelphij *
433285612Sdelphij * Returns nonzero if r1 sorts before r2.  We sort by descending
434285612Sdelphij * address, then descending mask, then descending mflags, so sorting
435285612Sdelphij * before means having a higher value.
436285612Sdelphij */
437285612Sdelphijstatic int
438285612Sdelphijres_sorts_before4(
439285612Sdelphij	restrict_u *r1,
440285612Sdelphij	restrict_u *r2
441285612Sdelphij	)
442285612Sdelphij{
443285612Sdelphij	int r1_before_r2;
444285612Sdelphij
445285612Sdelphij	if (r1->u.v4.addr > r2->u.v4.addr)
446285612Sdelphij		r1_before_r2 = 1;
447285612Sdelphij	else if (r1->u.v4.addr < r2->u.v4.addr)
448285612Sdelphij		r1_before_r2 = 0;
449285612Sdelphij	else if (r1->u.v4.mask > r2->u.v4.mask)
450285612Sdelphij		r1_before_r2 = 1;
451285612Sdelphij	else if (r1->u.v4.mask < r2->u.v4.mask)
452285612Sdelphij		r1_before_r2 = 0;
453285612Sdelphij	else if (r1->mflags > r2->mflags)
454285612Sdelphij		r1_before_r2 = 1;
455285612Sdelphij	else
456285612Sdelphij		r1_before_r2 = 0;
457285612Sdelphij
458285612Sdelphij	return r1_before_r2;
459285612Sdelphij}
460285612Sdelphij
461285612Sdelphij
462285612Sdelphij/*
463285612Sdelphij * res_sorts_before6 - compare two restrict6 entries
464285612Sdelphij *
465285612Sdelphij * Returns nonzero if r1 sorts before r2.  We sort by descending
466285612Sdelphij * address, then descending mask, then descending mflags, so sorting
467285612Sdelphij * before means having a higher value.
468285612Sdelphij */
469285612Sdelphijstatic int
470285612Sdelphijres_sorts_before6(
471285612Sdelphij	restrict_u *r1,
472285612Sdelphij	restrict_u *r2
473285612Sdelphij	)
474285612Sdelphij{
475285612Sdelphij	int r1_before_r2;
476285612Sdelphij	int cmp;
477285612Sdelphij
478285612Sdelphij	cmp = ADDR6_CMP(&r1->u.v6.addr, &r2->u.v6.addr);
479285612Sdelphij	if (cmp > 0)		/* r1->addr > r2->addr */
480285612Sdelphij		r1_before_r2 = 1;
481285612Sdelphij	else if (cmp < 0)	/* r2->addr > r1->addr */
482285612Sdelphij		r1_before_r2 = 0;
483285612Sdelphij	else {
484285612Sdelphij		cmp = ADDR6_CMP(&r1->u.v6.mask, &r2->u.v6.mask);
485285612Sdelphij		if (cmp > 0)		/* r1->mask > r2->mask*/
486285612Sdelphij			r1_before_r2 = 1;
487285612Sdelphij		else if (cmp < 0)	/* r2->mask > r1->mask */
488285612Sdelphij			r1_before_r2 = 0;
489285612Sdelphij		else if (r1->mflags > r2->mflags)
490285612Sdelphij			r1_before_r2 = 1;
491285612Sdelphij		else
492285612Sdelphij			r1_before_r2 = 0;
493285612Sdelphij	}
494285612Sdelphij
495285612Sdelphij	return r1_before_r2;
496285612Sdelphij}
497285612Sdelphij
498285612Sdelphij
499285612Sdelphij/*
500330141Sdelphij * restrictions - return restrictions for this host in *r4a
50154359Sroberto */
502330141Sdelphijvoid
50354359Srobertorestrictions(
504330141Sdelphij	sockaddr_u *srcadr,
505330141Sdelphij	r4addr *r4a
50654359Sroberto	)
50754359Sroberto{
508285612Sdelphij	restrict_u *match;
509285612Sdelphij	struct in6_addr *pin6;
51054359Sroberto
511330141Sdelphij	REQUIRE(NULL != r4a);
512330141Sdelphij
51354359Sroberto	res_calls++;
514330141Sdelphij	r4a->rflags = RES_IGNORE;
515330141Sdelphij	r4a->ippeerlimit = 0;
516330141Sdelphij
517330141Sdelphij	DPRINTF(1, ("restrictions: looking up %s\n", stoa(srcadr)));
518330141Sdelphij
519285612Sdelphij	/* IPv4 source address */
520285612Sdelphij	if (IS_IPV4(srcadr)) {
521132451Sroberto		/*
522132451Sroberto		 * Ignore any packets with a multicast source address
523132451Sroberto		 * (this should be done early in the receive process,
524285612Sdelphij		 * not later!)
525132451Sroberto		 */
526330141Sdelphij		if (IN_CLASSD(SRCADR(srcadr))) {
527330141Sdelphij			DPRINTF(1, ("restrictions: srcadr %s is multicast\n", stoa(srcadr)));
528330141Sdelphij			r4a->ippeerlimit = 2;	/* XXX: we should use a better value */
529330141Sdelphij			return;
530330141Sdelphij		}
53154359Sroberto
532285612Sdelphij		match = match_restrict4_addr(SRCADR(srcadr),
533285612Sdelphij					     SRCPORT(srcadr));
534289997Sglebius
535289997Sglebius		INSIST(match != NULL);
536289997Sglebius
537285612Sdelphij		match->count++;
538132451Sroberto		/*
539285612Sdelphij		 * res_not_found counts only use of the final default
540285612Sdelphij		 * entry, not any "restrict default ntpport ...", which
541285612Sdelphij		 * would be just before the final default.
542132451Sroberto		 */
543285612Sdelphij		if (&restrict_def4 == match)
544132451Sroberto			res_not_found++;
545132451Sroberto		else
546132451Sroberto			res_found++;
547330141Sdelphij		r4a->rflags = match->rflags;
548330141Sdelphij		r4a->ippeerlimit = match->ippeerlimit;
549132451Sroberto	}
55054359Sroberto
551132451Sroberto	/* IPv6 source address */
552285612Sdelphij	if (IS_IPV6(srcadr)) {
553285612Sdelphij		pin6 = PSOCK_ADDR6(srcadr);
55454359Sroberto
555132451Sroberto		/*
556132451Sroberto		 * Ignore any packets with a multicast source address
557132451Sroberto		 * (this should be done early in the receive process,
558285612Sdelphij		 * not later!)
559132451Sroberto		 */
560285612Sdelphij		if (IN6_IS_ADDR_MULTICAST(pin6))
561330141Sdelphij			return;
56254359Sroberto
563285612Sdelphij		match = match_restrict6_addr(pin6, SRCPORT(srcadr));
564289997Sglebius		INSIST(match != NULL);
565285612Sdelphij		match->count++;
566285612Sdelphij		if (&restrict_def6 == match)
567132451Sroberto			res_not_found++;
568132451Sroberto		else
569132451Sroberto			res_found++;
570330141Sdelphij		r4a->rflags = match->rflags;
571330141Sdelphij		r4a->ippeerlimit = match->ippeerlimit;
57254359Sroberto	}
573330141Sdelphij	return;
57454359Sroberto}
57554359Sroberto
57654359Sroberto
57754359Sroberto/*
578330141Sdelphij * roptoa - convert a restrict_op to a string
579330141Sdelphij */
580330141Sdelphijchar *
581330141Sdelphijroptoa(restrict_op op) {
582330141Sdelphij	static char sb[30];
583330141Sdelphij
584330141Sdelphij	switch(op) {
585330141Sdelphij	    case RESTRICT_FLAGS:	return "RESTRICT_FLAGS";
586330141Sdelphij	    case RESTRICT_UNFLAG:	return "RESTRICT_UNFLAGS";
587330141Sdelphij	    case RESTRICT_REMOVE:	return "RESTRICT_REMOVE";
588330141Sdelphij	    case RESTRICT_REMOVEIF:	return "RESTRICT_REMOVEIF";
589330141Sdelphij	    default:
590330141Sdelphij		snprintf(sb, sizeof sb, "**RESTRICT_#%d**", op);
591330141Sdelphij		return sb;
592330141Sdelphij	}
593330141Sdelphij}
594330141Sdelphij
595330141Sdelphij
596330141Sdelphij/*
59754359Sroberto * hack_restrict - add/subtract/manipulate entries on the restrict list
59854359Sroberto */
59954359Srobertovoid
60054359Srobertohack_restrict(
601330141Sdelphij	restrict_op	op,
602285612Sdelphij	sockaddr_u *	resaddr,
603285612Sdelphij	sockaddr_u *	resmask,
604330141Sdelphij	short		ippeerlimit,
605285612Sdelphij	u_short		mflags,
606330141Sdelphij	u_short		rflags,
607285612Sdelphij	u_long		expire
60854359Sroberto	)
60954359Sroberto{
610285612Sdelphij	int		v6;
611285612Sdelphij	restrict_u	match;
612285612Sdelphij	restrict_u *	res;
613285612Sdelphij	restrict_u **	plisthead;
61454359Sroberto
615330141Sdelphij	DPRINTF(1, ("hack_restrict: op %s addr %s mask %s ippeerlimit %d mflags %08x rflags %08x\n",
616330141Sdelphij		    roptoa(op), stoa(resaddr), stoa(resmask), ippeerlimit, mflags, rflags));
617285612Sdelphij
618285612Sdelphij	if (NULL == resaddr) {
619289997Sglebius		REQUIRE(NULL == resmask);
620289997Sglebius		REQUIRE(RESTRICT_FLAGS == op);
621330141Sdelphij		restrict_source_rflags = rflags;
622285612Sdelphij		restrict_source_mflags = mflags;
623330141Sdelphij		restrict_source_ippeerlimit = ippeerlimit;
624285612Sdelphij		restrict_source_enabled = 1;
625285612Sdelphij		return;
626285612Sdelphij	}
627285612Sdelphij
628285612Sdelphij	ZERO(match);
629289997Sglebius
630289997Sglebius#if 0
631285612Sdelphij	/* silence VC9 potentially uninit warnings */
632289997Sglebius	// HMS: let's use a compiler-specific "enable" for this.
633285612Sdelphij	res = NULL;
634285612Sdelphij	v6 = 0;
635289997Sglebius#endif
636285612Sdelphij
637285612Sdelphij	if (IS_IPV4(resaddr)) {
638285612Sdelphij		v6 = 0;
639132451Sroberto		/*
640285612Sdelphij		 * Get address and mask in host byte order for easy
641285612Sdelphij		 * comparison as u_int32
642132451Sroberto		 */
643285612Sdelphij		match.u.v4.addr = SRCADR(resaddr);
644285612Sdelphij		match.u.v4.mask = SRCADR(resmask);
645285612Sdelphij		match.u.v4.addr &= match.u.v4.mask;
64654359Sroberto
647285612Sdelphij	} else if (IS_IPV6(resaddr)) {
648285612Sdelphij		v6 = 1;
649132451Sroberto		/*
650285612Sdelphij		 * Get address and mask in network byte order for easy
651285612Sdelphij		 * comparison as byte sequences (e.g. memcmp())
652132451Sroberto		 */
653285612Sdelphij		match.u.v6.mask = SOCK_ADDR6(resmask);
654285612Sdelphij		MASK_IPV6_ADDR(&match.u.v6.addr, PSOCK_ADDR6(resaddr),
655285612Sdelphij			       &match.u.v6.mask);
656132451Sroberto
657285612Sdelphij	} else	/* not IPv4 nor IPv6 */
658289997Sglebius		REQUIRE(0);
659132451Sroberto
660330141Sdelphij	match.rflags = rflags;
661285612Sdelphij	match.mflags = mflags;
662330141Sdelphij	match.ippeerlimit = ippeerlimit;
663285612Sdelphij	match.expire = expire;
664285612Sdelphij	res = match_restrict_entry(&match, v6);
665132451Sroberto
666285612Sdelphij	switch (op) {
667285612Sdelphij
668285612Sdelphij	case RESTRICT_FLAGS:
669285612Sdelphij		/*
670330141Sdelphij		 * Here we add bits to the rflags. If this is a
671285612Sdelphij		 * new restriction add it.
672285612Sdelphij		 */
673285612Sdelphij		if (NULL == res) {
674285612Sdelphij			if (v6) {
675285612Sdelphij				res = alloc_res6();
676285612Sdelphij				memcpy(res, &match,
677285612Sdelphij				       V6_SIZEOF_RESTRICT_U);
678285612Sdelphij				plisthead = &restrictlist6;
679285612Sdelphij			} else {
680285612Sdelphij				res = alloc_res4();
681285612Sdelphij				memcpy(res, &match,
682285612Sdelphij				       V4_SIZEOF_RESTRICT_U);
683285612Sdelphij				plisthead = &restrictlist4;
68454359Sroberto			}
685285612Sdelphij			LINK_SORT_SLIST(
686285612Sdelphij				*plisthead, res,
687285612Sdelphij				(v6)
688285612Sdelphij				  ? res_sorts_before6(res, L_S_S_CUR())
689285612Sdelphij				  : res_sorts_before4(res, L_S_S_CUR()),
690285612Sdelphij				link, restrict_u);
691285612Sdelphij			restrictcount++;
692330141Sdelphij			if (RES_LIMITED & rflags)
693285612Sdelphij				inc_res_limited();
694285612Sdelphij		} else {
695330141Sdelphij			if (   (RES_LIMITED & rflags)
696330141Sdelphij			    && !(RES_LIMITED & res->rflags))
697285612Sdelphij				inc_res_limited();
698330141Sdelphij			res->rflags |= rflags;
69954359Sroberto		}
700330141Sdelphij
701330141Sdelphij		res->ippeerlimit = match.ippeerlimit;
702330141Sdelphij
703285612Sdelphij		break;
704132451Sroberto
705285612Sdelphij	case RESTRICT_UNFLAG:
706285612Sdelphij		/*
707330141Sdelphij		 * Remove some bits from the rflags. If we didn't
708285612Sdelphij		 * find this one, just return.
709285612Sdelphij		 */
710285612Sdelphij		if (res != NULL) {
711330141Sdelphij			if (   (RES_LIMITED & res->rflags)
712330141Sdelphij			    && (RES_LIMITED & rflags))
713285612Sdelphij				dec_res_limited();
714330141Sdelphij			res->rflags &= ~rflags;
715285612Sdelphij		}
716285612Sdelphij		break;
71754359Sroberto
718285612Sdelphij	case RESTRICT_REMOVE:
719285612Sdelphij	case RESTRICT_REMOVEIF:
720285612Sdelphij		/*
721285612Sdelphij		 * Remove an entry from the table entirely if we
722285612Sdelphij		 * found one. Don't remove the default entry and
723285612Sdelphij		 * don't remove an interface entry.
724285612Sdelphij		 */
725285612Sdelphij		if (res != NULL
726285612Sdelphij		    && (RESTRICT_REMOVEIF == op
727285612Sdelphij			|| !(RESM_INTERFACE & res->mflags))
728285612Sdelphij		    && res != &restrict_def4
729285612Sdelphij		    && res != &restrict_def6)
730285612Sdelphij			free_res(res, v6);
731285612Sdelphij		break;
73254359Sroberto
733285612Sdelphij	default:	/* unknown op */
734289997Sglebius		INSIST(0);
735285612Sdelphij		break;
736285612Sdelphij	}
73754359Sroberto
738285612Sdelphij}
73954359Sroberto
740132451Sroberto
741285612Sdelphij/*
742285612Sdelphij * restrict_source - maintains dynamic "restrict source ..." entries as
743285612Sdelphij *		     peers come and go.
744285612Sdelphij */
745285612Sdelphijvoid
746285612Sdelphijrestrict_source(
747285612Sdelphij	sockaddr_u *	addr,
748285612Sdelphij	int		farewell,	/* 0 to add, 1 to remove */
749285612Sdelphij	u_long		expire		/* 0 is infinite, valid until */
750285612Sdelphij	)
751285612Sdelphij{
752285612Sdelphij	sockaddr_u	onesmask;
753285612Sdelphij	restrict_u *	res;
754285612Sdelphij	int		found_specific;
755132451Sroberto
756285612Sdelphij	if (!restrict_source_enabled || SOCK_UNSPEC(addr) ||
757285612Sdelphij	    IS_MCAST(addr) || ISREFCLOCKADR(addr))
758285612Sdelphij		return;
759132451Sroberto
760289997Sglebius	REQUIRE(AF_INET == AF(addr) || AF_INET6 == AF(addr));
761132451Sroberto
762285612Sdelphij	SET_HOSTMASK(&onesmask, AF(addr));
763285612Sdelphij	if (farewell) {
764285612Sdelphij		hack_restrict(RESTRICT_REMOVE, addr, &onesmask,
765330141Sdelphij			      -2, 0, 0, 0);
766285612Sdelphij		DPRINTF(1, ("restrict_source: %s removed", stoa(addr)));
767285612Sdelphij		return;
768285612Sdelphij	}
76954359Sroberto
770285612Sdelphij	/*
771285612Sdelphij	 * If there is a specific entry for this address, hands
772285612Sdelphij	 * off, as it is condidered more specific than "restrict
773285612Sdelphij	 * server ...".
774285612Sdelphij	 * However, if the specific entry found is a fleeting one
775285612Sdelphij	 * added by pool_xmit() before soliciting, replace it
776285612Sdelphij	 * immediately regardless of the expire value to make way
777285612Sdelphij	 * for the more persistent entry.
778285612Sdelphij	 */
779285612Sdelphij	if (IS_IPV4(addr)) {
780285612Sdelphij		res = match_restrict4_addr(SRCADR(addr), SRCPORT(addr));
781289997Sglebius		INSIST(res != NULL);
782285612Sdelphij		found_specific = (SRCADR(&onesmask) == res->u.v4.mask);
783285612Sdelphij	} else {
784285612Sdelphij		res = match_restrict6_addr(&SOCK_ADDR6(addr),
785285612Sdelphij					   SRCPORT(addr));
786289997Sglebius		INSIST(res != NULL);
787285612Sdelphij		found_specific = ADDR6_EQ(&res->u.v6.mask,
788285612Sdelphij					  &SOCK_ADDR6(&onesmask));
789285612Sdelphij	}
790285612Sdelphij	if (!expire && found_specific && res->expire) {
791285612Sdelphij		found_specific = 0;
792285612Sdelphij		free_res(res, IS_IPV6(addr));
793285612Sdelphij	}
794285612Sdelphij	if (found_specific)
795285612Sdelphij		return;
796132451Sroberto
797285612Sdelphij	hack_restrict(RESTRICT_FLAGS, addr, &onesmask,
798330141Sdelphij		      restrict_source_ippeerlimit, restrict_source_mflags,
799330141Sdelphij		      restrict_source_rflags, expire);
800285612Sdelphij	DPRINTF(1, ("restrict_source: %s host restriction added\n",
801285612Sdelphij		    stoa(addr)));
80254359Sroberto}
803