xref: /freebsd/contrib/ntp/ntpd/ntp_restrict.c (revision 9034852c84a13f0e3b5527e1c886ca94b2863b2b)
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 /*
18c0b746e5SOllivier Robert  * This code keeps a simple address-and-mask list of hosts we want
19c0b746e5SOllivier Robert  * to place restrictions on (or remove them from). The restrictions
20c0b746e5SOllivier Robert  * are implemented as a set of flags which tell you what the host
21c0b746e5SOllivier Robert  * can't do. There is a subroutine entry to return the flags. The
22c0b746e5SOllivier Robert  * list is kept sorted to reduce the average number of comparisons
23c0b746e5SOllivier Robert  * and make sure you get the set of restrictions most specific to
24c0b746e5SOllivier Robert  * the address.
25c0b746e5SOllivier Robert  *
26c0b746e5SOllivier Robert  * The algorithm is that, when looking up a host, it is first assumed
27c0b746e5SOllivier Robert  * that the default set of restrictions will apply. It then searches
289c2daa00SOllivier Robert  * down through the list. Whenever it finds a match it adopts the
299c2daa00SOllivier Robert  * match's flags instead. When you hit the point where the sorted
309c2daa00SOllivier Robert  * address is greater than the target, you return with the last set of
319c2daa00SOllivier Robert  * flags you found. Because of the ordering of the list, the most
329c2daa00SOllivier Robert  * specific match will provide the final set of flags.
33c0b746e5SOllivier Robert  *
34c0b746e5SOllivier Robert  * This was originally intended to restrict you from sync'ing to your
359c2daa00SOllivier Robert  * own broadcasts when you are doing that, by restricting yourself from
369c2daa00SOllivier Robert  * your own interfaces. It was also thought it would sometimes be useful
379c2daa00SOllivier Robert  * to keep a misbehaving host or two from abusing your primary clock. It
389c2daa00SOllivier Robert  * has been expanded, however, to suit the needs of those with more
399c2daa00SOllivier Robert  * restrictive access policies.
40c0b746e5SOllivier Robert  */
419c2daa00SOllivier Robert /*
429c2daa00SOllivier Robert  * We will use two lists, one for IPv4 addresses and one for IPv6
439c2daa00SOllivier Robert  * addresses. This is not protocol-independant but for now I can't
449c2daa00SOllivier Robert  * find a way to respect this. We'll check this later... JFB 07/2001
459c2daa00SOllivier Robert  */
462b15cb3dSCy Schubert #define MASK_IPV6_ADDR(dst, src, msk)					\
479c2daa00SOllivier Robert 	do {								\
489c2daa00SOllivier Robert 		int idx;						\
492b15cb3dSCy Schubert 		for (idx = 0; idx < (int)COUNTOF((dst)->s6_addr); idx++) { \
502b15cb3dSCy Schubert 			(dst)->s6_addr[idx] = (src)->s6_addr[idx]	\
512b15cb3dSCy Schubert 					      & (msk)->s6_addr[idx];	\
529c2daa00SOllivier Robert 		}							\
539c2daa00SOllivier Robert 	} while (0)
54c0b746e5SOllivier Robert 
55c0b746e5SOllivier Robert /*
562b15cb3dSCy Schubert  * We allocate INC_RESLIST{4|6} entries to the free list whenever empty.
572b15cb3dSCy Schubert  * Auto-tune these to be just less than 1KB (leaving at least 16 bytes
582b15cb3dSCy Schubert  * for allocator overhead).
59c0b746e5SOllivier Robert  */
602b15cb3dSCy Schubert #define	INC_RESLIST4	((1024 - 16) / V4_SIZEOF_RESTRICT_U)
612b15cb3dSCy Schubert #define	INC_RESLIST6	((1024 - 16) / V6_SIZEOF_RESTRICT_U)
629c2daa00SOllivier Robert 
63c0b746e5SOllivier Robert /*
64c0b746e5SOllivier Robert  * The restriction list
65c0b746e5SOllivier Robert  */
662b15cb3dSCy Schubert restrict_u *restrictlist4;
672b15cb3dSCy Schubert restrict_u *restrictlist6;
682b15cb3dSCy Schubert static int restrictcount;	/* count in the restrict lists */
69c0b746e5SOllivier Robert 
70c0b746e5SOllivier Robert /*
71c0b746e5SOllivier Robert  * The free list and associated counters.  Also some uninteresting
72c0b746e5SOllivier Robert  * stat counters.
73c0b746e5SOllivier Robert  */
742b15cb3dSCy Schubert static restrict_u *resfree4;	/* available entries (free list) */
752b15cb3dSCy Schubert static restrict_u *resfree6;
76c0b746e5SOllivier Robert 
77c0b746e5SOllivier Robert static u_long res_calls;
78c0b746e5SOllivier Robert static u_long res_found;
79c0b746e5SOllivier Robert static u_long res_not_found;
80c0b746e5SOllivier Robert 
81c0b746e5SOllivier Robert /*
822b15cb3dSCy Schubert  * Count number of restriction entries referring to RES_LIMITED, to
832b15cb3dSCy Schubert  * control implicit activation/deactivation of the MRU monlist.
849c2daa00SOllivier Robert  */
859c2daa00SOllivier Robert static	u_long res_limited_refcnt;
869c2daa00SOllivier Robert 
879c2daa00SOllivier Robert /*
882b15cb3dSCy Schubert  * Our default entries.
89c0b746e5SOllivier Robert  */
902b15cb3dSCy Schubert static	restrict_u	restrict_def4;
912b15cb3dSCy Schubert static	restrict_u	restrict_def6;
922b15cb3dSCy Schubert 
932b15cb3dSCy Schubert /*
942b15cb3dSCy Schubert  * "restrict source ..." enabled knob and restriction bits.
952b15cb3dSCy Schubert  */
962b15cb3dSCy Schubert static	int		restrict_source_enabled;
972b15cb3dSCy Schubert static	u_short		restrict_source_flags;
982b15cb3dSCy Schubert static	u_short		restrict_source_mflags;
992b15cb3dSCy Schubert 
1002b15cb3dSCy Schubert /*
1012b15cb3dSCy Schubert  * private functions
1022b15cb3dSCy Schubert  */
1032b15cb3dSCy Schubert static restrict_u *	alloc_res4(void);
1042b15cb3dSCy Schubert static restrict_u *	alloc_res6(void);
1052b15cb3dSCy Schubert static void		free_res(restrict_u *, int);
1062b15cb3dSCy Schubert static void		inc_res_limited(void);
1072b15cb3dSCy Schubert static void		dec_res_limited(void);
1082b15cb3dSCy Schubert static restrict_u *	match_restrict4_addr(u_int32, u_short);
1092b15cb3dSCy Schubert static restrict_u *	match_restrict6_addr(const struct in6_addr *,
1102b15cb3dSCy Schubert 					     u_short);
1112b15cb3dSCy Schubert static restrict_u *	match_restrict_entry(const restrict_u *, int);
1122b15cb3dSCy Schubert static int		res_sorts_before4(restrict_u *, restrict_u *);
1132b15cb3dSCy Schubert static int		res_sorts_before6(restrict_u *, restrict_u *);
1142b15cb3dSCy Schubert 
115c0b746e5SOllivier Robert 
116c0b746e5SOllivier Robert /*
117c0b746e5SOllivier Robert  * init_restrict - initialize the restriction data structures
118c0b746e5SOllivier Robert  */
119c0b746e5SOllivier Robert void
120c0b746e5SOllivier Robert init_restrict(void)
121c0b746e5SOllivier Robert {
122c0b746e5SOllivier Robert 	/*
1232b15cb3dSCy Schubert 	 * The restriction lists begin with a default entry with address
1242b15cb3dSCy Schubert 	 * and mask 0, which will match any entry.  The lists are kept
1252b15cb3dSCy Schubert 	 * sorted by descending address followed by descending mask:
1262b15cb3dSCy Schubert 	 *
1272b15cb3dSCy Schubert 	 *   address	  mask
1282b15cb3dSCy Schubert 	 * 192.168.0.0	255.255.255.0	kod limited noquery nopeer
1292b15cb3dSCy Schubert 	 * 192.168.0.0	255.255.0.0	kod limited
1302b15cb3dSCy Schubert 	 * 0.0.0.0	0.0.0.0		kod limited noquery
1312b15cb3dSCy Schubert 	 *
1322b15cb3dSCy Schubert 	 * The first entry which matches an address is used.  With the
1332b15cb3dSCy Schubert 	 * example restrictions above, 192.168.0.0/24 matches the first
1342b15cb3dSCy Schubert 	 * entry, the rest of 192.168.0.0/16 matches the second, and
1352b15cb3dSCy Schubert 	 * everything else matches the third (default).
1362b15cb3dSCy Schubert 	 *
1372b15cb3dSCy Schubert 	 * Note this achieves the same result a little more efficiently
1382b15cb3dSCy Schubert 	 * than the documented behavior, which is to keep the lists
1392b15cb3dSCy Schubert 	 * sorted by ascending address followed by ascending mask, with
1402b15cb3dSCy Schubert 	 * the _last_ matching entry used.
1412b15cb3dSCy Schubert 	 *
1422b15cb3dSCy Schubert 	 * An additional wrinkle is we may have multiple entries with
1432b15cb3dSCy Schubert 	 * the same address and mask but differing match flags (mflags).
1442b15cb3dSCy Schubert 	 * At present there is only one, RESM_NTPONLY.  Entries with
1452b15cb3dSCy Schubert 	 * RESM_NTPONLY are sorted earlier so they take precedence over
1462b15cb3dSCy Schubert 	 * any otherwise similar entry without.  Again, this is the same
1472b15cb3dSCy Schubert 	 * behavior as but reversed implementation compared to the docs.
1482b15cb3dSCy Schubert 	 *
149c0b746e5SOllivier Robert 	 */
1502b15cb3dSCy Schubert 	LINK_SLIST(restrictlist4, &restrict_def4, link);
1512b15cb3dSCy Schubert 	LINK_SLIST(restrictlist6, &restrict_def6, link);
1529c2daa00SOllivier Robert 	restrictcount = 2;
1532b15cb3dSCy Schubert }
1542b15cb3dSCy Schubert 
1552b15cb3dSCy Schubert 
1562b15cb3dSCy Schubert static restrict_u *
1572b15cb3dSCy Schubert alloc_res4(void)
1582b15cb3dSCy Schubert {
1592b15cb3dSCy Schubert 	const size_t	cb = V4_SIZEOF_RESTRICT_U;
1602b15cb3dSCy Schubert 	const size_t	count = INC_RESLIST4;
1612b15cb3dSCy Schubert 	restrict_u *	rl;
1622b15cb3dSCy Schubert 	restrict_u *	res;
1632b15cb3dSCy Schubert 	int		i;
1642b15cb3dSCy Schubert 
1652b15cb3dSCy Schubert 	UNLINK_HEAD_SLIST(res, resfree4, link);
1662b15cb3dSCy Schubert 	if (res != NULL)
1672b15cb3dSCy Schubert 		return res;
1682b15cb3dSCy Schubert 
1692b15cb3dSCy Schubert 	rl = emalloc_zero(count * cb);
1702b15cb3dSCy Schubert 	/* link all but the first onto free list */
1712b15cb3dSCy Schubert 	res = (void *)((char *)rl + (count - 1) * cb);
1722b15cb3dSCy Schubert 	for (i = count - 1; i > 0; i--) {
1732b15cb3dSCy Schubert 		LINK_SLIST(resfree4, res, link);
1742b15cb3dSCy Schubert 		res = (void *)((char *)res - cb);
1752b15cb3dSCy Schubert 	}
176*9034852cSGleb Smirnoff 	INSIST(rl == res);
1772b15cb3dSCy Schubert 	/* allocate the first */
1782b15cb3dSCy Schubert 	return res;
1792b15cb3dSCy Schubert }
1802b15cb3dSCy Schubert 
1812b15cb3dSCy Schubert 
1822b15cb3dSCy Schubert static restrict_u *
1832b15cb3dSCy Schubert alloc_res6(void)
1842b15cb3dSCy Schubert {
1852b15cb3dSCy Schubert 	const size_t	cb = V6_SIZEOF_RESTRICT_U;
1862b15cb3dSCy Schubert 	const size_t	count = INC_RESLIST6;
1872b15cb3dSCy Schubert 	restrict_u *	rl;
1882b15cb3dSCy Schubert 	restrict_u *	res;
1892b15cb3dSCy Schubert 	int		i;
1902b15cb3dSCy Schubert 
1912b15cb3dSCy Schubert 	UNLINK_HEAD_SLIST(res, resfree6, link);
1922b15cb3dSCy Schubert 	if (res != NULL)
1932b15cb3dSCy Schubert 		return res;
1942b15cb3dSCy Schubert 
1952b15cb3dSCy Schubert 	rl = emalloc_zero(count * cb);
1962b15cb3dSCy Schubert 	/* link all but the first onto free list */
1972b15cb3dSCy Schubert 	res = (void *)((char *)rl + (count - 1) * cb);
1982b15cb3dSCy Schubert 	for (i = count - 1; i > 0; i--) {
1992b15cb3dSCy Schubert 		LINK_SLIST(resfree6, res, link);
2002b15cb3dSCy Schubert 		res = (void *)((char *)res - cb);
2012b15cb3dSCy Schubert 	}
202*9034852cSGleb Smirnoff 	INSIST(rl == res);
2032b15cb3dSCy Schubert 	/* allocate the first */
2042b15cb3dSCy Schubert 	return res;
2052b15cb3dSCy Schubert }
2062b15cb3dSCy Schubert 
2072b15cb3dSCy Schubert 
2082b15cb3dSCy Schubert static void
2092b15cb3dSCy Schubert free_res(
2102b15cb3dSCy Schubert 	restrict_u *	res,
2112b15cb3dSCy Schubert 	int		v6
2122b15cb3dSCy Schubert 	)
2132b15cb3dSCy Schubert {
2142b15cb3dSCy Schubert 	restrict_u **	plisthead;
2152b15cb3dSCy Schubert 	restrict_u *	unlinked;
2162b15cb3dSCy Schubert 
2172b15cb3dSCy Schubert 	restrictcount--;
2182b15cb3dSCy Schubert 	if (RES_LIMITED & res->flags)
2192b15cb3dSCy Schubert 		dec_res_limited();
2202b15cb3dSCy Schubert 
2212b15cb3dSCy Schubert 	if (v6)
2222b15cb3dSCy Schubert 		plisthead = &restrictlist6;
2232b15cb3dSCy Schubert 	else
2242b15cb3dSCy Schubert 		plisthead = &restrictlist4;
2252b15cb3dSCy Schubert 	UNLINK_SLIST(unlinked, *plisthead, res, link, restrict_u);
226*9034852cSGleb Smirnoff 	INSIST(unlinked == res);
2272b15cb3dSCy Schubert 
2282b15cb3dSCy Schubert 	if (v6) {
2292b15cb3dSCy Schubert 		zero_mem(res, V6_SIZEOF_RESTRICT_U);
2302b15cb3dSCy Schubert 		plisthead = &resfree6;
2312b15cb3dSCy Schubert 	} else {
2322b15cb3dSCy Schubert 		zero_mem(res, V4_SIZEOF_RESTRICT_U);
2332b15cb3dSCy Schubert 		plisthead = &resfree4;
2342b15cb3dSCy Schubert 	}
2352b15cb3dSCy Schubert 	LINK_SLIST(*plisthead, res, link);
2362b15cb3dSCy Schubert }
2372b15cb3dSCy Schubert 
2382b15cb3dSCy Schubert 
2392b15cb3dSCy Schubert static void
2402b15cb3dSCy Schubert inc_res_limited(void)
2412b15cb3dSCy Schubert {
2422b15cb3dSCy Schubert 	if (!res_limited_refcnt)
2432b15cb3dSCy Schubert 		mon_start(MON_RES);
2442b15cb3dSCy Schubert 	res_limited_refcnt++;
2452b15cb3dSCy Schubert }
2462b15cb3dSCy Schubert 
2472b15cb3dSCy Schubert 
2482b15cb3dSCy Schubert static void
2492b15cb3dSCy Schubert dec_res_limited(void)
2502b15cb3dSCy Schubert {
2512b15cb3dSCy Schubert 	res_limited_refcnt--;
2522b15cb3dSCy Schubert 	if (!res_limited_refcnt)
2532b15cb3dSCy Schubert 		mon_stop(MON_RES);
2542b15cb3dSCy Schubert }
2552b15cb3dSCy Schubert 
2562b15cb3dSCy Schubert 
2572b15cb3dSCy Schubert static restrict_u *
2582b15cb3dSCy Schubert match_restrict4_addr(
2592b15cb3dSCy Schubert 	u_int32	addr,
2602b15cb3dSCy Schubert 	u_short	port
2612b15cb3dSCy Schubert 	)
2622b15cb3dSCy Schubert {
2632b15cb3dSCy Schubert 	const int	v6 = 0;
2642b15cb3dSCy Schubert 	restrict_u *	res;
2652b15cb3dSCy Schubert 	restrict_u *	next;
2662b15cb3dSCy Schubert 
2672b15cb3dSCy Schubert 	for (res = restrictlist4; res != NULL; res = next) {
2682b15cb3dSCy Schubert 		next = res->link;
2692b15cb3dSCy Schubert 		if (res->expire &&
2702b15cb3dSCy Schubert 		    res->expire <= current_time)
2712b15cb3dSCy Schubert 			free_res(res, v6);
2722b15cb3dSCy Schubert 		if (res->u.v4.addr == (addr & res->u.v4.mask)
2732b15cb3dSCy Schubert 		    && (!(RESM_NTPONLY & res->mflags)
2742b15cb3dSCy Schubert 			|| NTP_PORT == port))
2752b15cb3dSCy Schubert 			break;
2762b15cb3dSCy Schubert 	}
2772b15cb3dSCy Schubert 	return res;
2782b15cb3dSCy Schubert }
2792b15cb3dSCy Schubert 
2802b15cb3dSCy Schubert 
2812b15cb3dSCy Schubert static restrict_u *
2822b15cb3dSCy Schubert match_restrict6_addr(
2832b15cb3dSCy Schubert 	const struct in6_addr *	addr,
2842b15cb3dSCy Schubert 	u_short			port
2852b15cb3dSCy Schubert 	)
2862b15cb3dSCy Schubert {
2872b15cb3dSCy Schubert 	const int	v6 = 1;
2882b15cb3dSCy Schubert 	restrict_u *	res;
2892b15cb3dSCy Schubert 	restrict_u *	next;
2902b15cb3dSCy Schubert 	struct in6_addr	masked;
2912b15cb3dSCy Schubert 
2922b15cb3dSCy Schubert 	for (res = restrictlist6; res != NULL; res = next) {
2932b15cb3dSCy Schubert 		next = res->link;
294*9034852cSGleb Smirnoff 		INSIST(next != res);
2952b15cb3dSCy Schubert 		if (res->expire &&
2962b15cb3dSCy Schubert 		    res->expire <= current_time)
2972b15cb3dSCy Schubert 			free_res(res, v6);
2982b15cb3dSCy Schubert 		MASK_IPV6_ADDR(&masked, addr, &res->u.v6.mask);
2992b15cb3dSCy Schubert 		if (ADDR6_EQ(&masked, &res->u.v6.addr)
3002b15cb3dSCy Schubert 		    && (!(RESM_NTPONLY & res->mflags)
3012b15cb3dSCy Schubert 			|| NTP_PORT == (int)port))
3022b15cb3dSCy Schubert 			break;
3032b15cb3dSCy Schubert 	}
3042b15cb3dSCy Schubert 	return res;
3052b15cb3dSCy Schubert }
3062b15cb3dSCy Schubert 
307c0b746e5SOllivier Robert 
308c0b746e5SOllivier Robert /*
3092b15cb3dSCy Schubert  * match_restrict_entry - find an exact match on a restrict list.
3102b15cb3dSCy Schubert  *
3112b15cb3dSCy Schubert  * Exact match is addr, mask, and mflags all equal.
3122b15cb3dSCy Schubert  * In order to use more common code for IPv4 and IPv6, this routine
3132b15cb3dSCy Schubert  * requires the caller to populate a restrict_u with mflags and either
3142b15cb3dSCy Schubert  * the v4 or v6 address and mask as appropriate.  Other fields in the
3152b15cb3dSCy Schubert  * input restrict_u are ignored.
316c0b746e5SOllivier Robert  */
3172b15cb3dSCy Schubert static restrict_u *
3182b15cb3dSCy Schubert match_restrict_entry(
3192b15cb3dSCy Schubert 	const restrict_u *	pmatch,
3202b15cb3dSCy Schubert 	int			v6
3212b15cb3dSCy Schubert 	)
3222b15cb3dSCy Schubert {
3232b15cb3dSCy Schubert 	restrict_u *res;
3242b15cb3dSCy Schubert 	restrict_u *rlist;
3252b15cb3dSCy Schubert 	size_t cb;
3262b15cb3dSCy Schubert 
3272b15cb3dSCy Schubert 	if (v6) {
3282b15cb3dSCy Schubert 		rlist = restrictlist6;
3292b15cb3dSCy Schubert 		cb = sizeof(pmatch->u.v6);
3302b15cb3dSCy Schubert 	} else {
3312b15cb3dSCy Schubert 		rlist = restrictlist4;
3322b15cb3dSCy Schubert 		cb = sizeof(pmatch->u.v4);
3332b15cb3dSCy Schubert 	}
3342b15cb3dSCy Schubert 
3352b15cb3dSCy Schubert 	for (res = rlist; res != NULL; res = res->link)
3362b15cb3dSCy Schubert 		if (res->mflags == pmatch->mflags &&
3372b15cb3dSCy Schubert 		    !memcmp(&res->u, &pmatch->u, cb))
3382b15cb3dSCy Schubert 			break;
3392b15cb3dSCy Schubert 	return res;
3402b15cb3dSCy Schubert }
3412b15cb3dSCy Schubert 
342c0b746e5SOllivier Robert 
343c0b746e5SOllivier Robert /*
3442b15cb3dSCy Schubert  * res_sorts_before4 - compare two restrict4 entries
3452b15cb3dSCy Schubert  *
3462b15cb3dSCy Schubert  * Returns nonzero if r1 sorts before r2.  We sort by descending
3472b15cb3dSCy Schubert  * address, then descending mask, then descending mflags, so sorting
3482b15cb3dSCy Schubert  * before means having a higher value.
349c0b746e5SOllivier Robert  */
3502b15cb3dSCy Schubert static int
3512b15cb3dSCy Schubert res_sorts_before4(
3522b15cb3dSCy Schubert 	restrict_u *r1,
3532b15cb3dSCy Schubert 	restrict_u *r2
3542b15cb3dSCy Schubert 	)
3552b15cb3dSCy Schubert {
3562b15cb3dSCy Schubert 	int r1_before_r2;
3572b15cb3dSCy Schubert 
3582b15cb3dSCy Schubert 	if (r1->u.v4.addr > r2->u.v4.addr)
3592b15cb3dSCy Schubert 		r1_before_r2 = 1;
3602b15cb3dSCy Schubert 	else if (r1->u.v4.addr < r2->u.v4.addr)
3612b15cb3dSCy Schubert 		r1_before_r2 = 0;
3622b15cb3dSCy Schubert 	else if (r1->u.v4.mask > r2->u.v4.mask)
3632b15cb3dSCy Schubert 		r1_before_r2 = 1;
3642b15cb3dSCy Schubert 	else if (r1->u.v4.mask < r2->u.v4.mask)
3652b15cb3dSCy Schubert 		r1_before_r2 = 0;
3662b15cb3dSCy Schubert 	else if (r1->mflags > r2->mflags)
3672b15cb3dSCy Schubert 		r1_before_r2 = 1;
3682b15cb3dSCy Schubert 	else
3692b15cb3dSCy Schubert 		r1_before_r2 = 0;
3702b15cb3dSCy Schubert 
3712b15cb3dSCy Schubert 	return r1_before_r2;
3722b15cb3dSCy Schubert }
3732b15cb3dSCy Schubert 
3742b15cb3dSCy Schubert 
3752b15cb3dSCy Schubert /*
3762b15cb3dSCy Schubert  * res_sorts_before6 - compare two restrict6 entries
3772b15cb3dSCy Schubert  *
3782b15cb3dSCy Schubert  * Returns nonzero if r1 sorts before r2.  We sort by descending
3792b15cb3dSCy Schubert  * address, then descending mask, then descending mflags, so sorting
3802b15cb3dSCy Schubert  * before means having a higher value.
3812b15cb3dSCy Schubert  */
3822b15cb3dSCy Schubert static int
3832b15cb3dSCy Schubert res_sorts_before6(
3842b15cb3dSCy Schubert 	restrict_u *r1,
3852b15cb3dSCy Schubert 	restrict_u *r2
3862b15cb3dSCy Schubert 	)
3872b15cb3dSCy Schubert {
3882b15cb3dSCy Schubert 	int r1_before_r2;
3892b15cb3dSCy Schubert 	int cmp;
3902b15cb3dSCy Schubert 
3912b15cb3dSCy Schubert 	cmp = ADDR6_CMP(&r1->u.v6.addr, &r2->u.v6.addr);
3922b15cb3dSCy Schubert 	if (cmp > 0)		/* r1->addr > r2->addr */
3932b15cb3dSCy Schubert 		r1_before_r2 = 1;
3942b15cb3dSCy Schubert 	else if (cmp < 0)	/* r2->addr > r1->addr */
3952b15cb3dSCy Schubert 		r1_before_r2 = 0;
3962b15cb3dSCy Schubert 	else {
3972b15cb3dSCy Schubert 		cmp = ADDR6_CMP(&r1->u.v6.mask, &r2->u.v6.mask);
3982b15cb3dSCy Schubert 		if (cmp > 0)		/* r1->mask > r2->mask*/
3992b15cb3dSCy Schubert 			r1_before_r2 = 1;
4002b15cb3dSCy Schubert 		else if (cmp < 0)	/* r2->mask > r1->mask */
4012b15cb3dSCy Schubert 			r1_before_r2 = 0;
4022b15cb3dSCy Schubert 		else if (r1->mflags > r2->mflags)
4032b15cb3dSCy Schubert 			r1_before_r2 = 1;
4042b15cb3dSCy Schubert 		else
4052b15cb3dSCy Schubert 			r1_before_r2 = 0;
4062b15cb3dSCy Schubert 	}
4072b15cb3dSCy Schubert 
4082b15cb3dSCy Schubert 	return r1_before_r2;
409c0b746e5SOllivier Robert }
410c0b746e5SOllivier Robert 
411c0b746e5SOllivier Robert 
412c0b746e5SOllivier Robert /*
413c0b746e5SOllivier Robert  * restrictions - return restrictions for this host
414c0b746e5SOllivier Robert  */
4152b15cb3dSCy Schubert u_short
416c0b746e5SOllivier Robert restrictions(
4172b15cb3dSCy Schubert 	sockaddr_u *srcadr
418c0b746e5SOllivier Robert 	)
419c0b746e5SOllivier Robert {
4202b15cb3dSCy Schubert 	restrict_u *match;
4212b15cb3dSCy Schubert 	struct in6_addr *pin6;
4222b15cb3dSCy Schubert 	u_short flags;
423c0b746e5SOllivier Robert 
424c0b746e5SOllivier Robert 	res_calls++;
4252b15cb3dSCy Schubert 	flags = 0;
4262b15cb3dSCy Schubert 	/* IPv4 source address */
4272b15cb3dSCy Schubert 	if (IS_IPV4(srcadr)) {
428c0b746e5SOllivier Robert 		/*
429c0b746e5SOllivier Robert 		 * Ignore any packets with a multicast source address
4309c2daa00SOllivier Robert 		 * (this should be done early in the receive process,
4312b15cb3dSCy Schubert 		 * not later!)
432c0b746e5SOllivier Robert 		 */
4339c2daa00SOllivier Robert 		if (IN_CLASSD(SRCADR(srcadr)))
434c0b746e5SOllivier Robert 			return (int)RES_IGNORE;
435c0b746e5SOllivier Robert 
4362b15cb3dSCy Schubert 		match = match_restrict4_addr(SRCADR(srcadr),
4372b15cb3dSCy Schubert 					     SRCPORT(srcadr));
438*9034852cSGleb Smirnoff 
439*9034852cSGleb Smirnoff 		INSIST(match != NULL);
440*9034852cSGleb Smirnoff 
441c0b746e5SOllivier Robert 		match->count++;
4422b15cb3dSCy Schubert 		/*
4432b15cb3dSCy Schubert 		 * res_not_found counts only use of the final default
4442b15cb3dSCy Schubert 		 * entry, not any "restrict default ntpport ...", which
4452b15cb3dSCy Schubert 		 * would be just before the final default.
4462b15cb3dSCy Schubert 		 */
4472b15cb3dSCy Schubert 		if (&restrict_def4 == match)
448c0b746e5SOllivier Robert 			res_not_found++;
449c0b746e5SOllivier Robert 		else
450c0b746e5SOllivier Robert 			res_found++;
4519c2daa00SOllivier Robert 		flags = match->flags;
4529c2daa00SOllivier Robert 	}
4539c2daa00SOllivier Robert 
4549c2daa00SOllivier Robert 	/* IPv6 source address */
4552b15cb3dSCy Schubert 	if (IS_IPV6(srcadr)) {
4562b15cb3dSCy Schubert 		pin6 = PSOCK_ADDR6(srcadr);
457c0b746e5SOllivier Robert 
458c0b746e5SOllivier Robert 		/*
4599c2daa00SOllivier Robert 		 * Ignore any packets with a multicast source address
4609c2daa00SOllivier Robert 		 * (this should be done early in the receive process,
4612b15cb3dSCy Schubert 		 * not later!)
462c0b746e5SOllivier Robert 		 */
4632b15cb3dSCy Schubert 		if (IN6_IS_ADDR_MULTICAST(pin6))
4649c2daa00SOllivier Robert 			return (int)RES_IGNORE;
465c0b746e5SOllivier Robert 
4662b15cb3dSCy Schubert 		match = match_restrict6_addr(pin6, SRCPORT(srcadr));
467*9034852cSGleb Smirnoff 		INSIST(match != NULL);
4682b15cb3dSCy Schubert 		match->count++;
4692b15cb3dSCy Schubert 		if (&restrict_def6 == match)
4709c2daa00SOllivier Robert 			res_not_found++;
4719c2daa00SOllivier Robert 		else
4729c2daa00SOllivier Robert 			res_found++;
4732b15cb3dSCy Schubert 		flags = match->flags;
474c0b746e5SOllivier Robert 	}
4759c2daa00SOllivier Robert 	return (flags);
476c0b746e5SOllivier Robert }
477c0b746e5SOllivier Robert 
478c0b746e5SOllivier Robert 
479c0b746e5SOllivier Robert /*
480c0b746e5SOllivier Robert  * hack_restrict - add/subtract/manipulate entries on the restrict list
481c0b746e5SOllivier Robert  */
482c0b746e5SOllivier Robert void
483c0b746e5SOllivier Robert hack_restrict(
484c0b746e5SOllivier Robert 	int		op,
4852b15cb3dSCy Schubert 	sockaddr_u *	resaddr,
4862b15cb3dSCy Schubert 	sockaddr_u *	resmask,
4872b15cb3dSCy Schubert 	u_short		mflags,
4882b15cb3dSCy Schubert 	u_short		flags,
4892b15cb3dSCy Schubert 	u_long		expire
490c0b746e5SOllivier Robert 	)
491c0b746e5SOllivier Robert {
4922b15cb3dSCy Schubert 	int		v6;
4932b15cb3dSCy Schubert 	restrict_u	match;
4942b15cb3dSCy Schubert 	restrict_u *	res;
4952b15cb3dSCy Schubert 	restrict_u **	plisthead;
496c0b746e5SOllivier Robert 
4972b15cb3dSCy Schubert 	DPRINTF(1, ("restrict: op %d addr %s mask %s mflags %08x flags %08x\n",
4982b15cb3dSCy Schubert 		    op, stoa(resaddr), stoa(resmask), mflags, flags));
4992b15cb3dSCy Schubert 
5002b15cb3dSCy Schubert 	if (NULL == resaddr) {
501*9034852cSGleb Smirnoff 		REQUIRE(NULL == resmask);
502*9034852cSGleb Smirnoff 		REQUIRE(RESTRICT_FLAGS == op);
5032b15cb3dSCy Schubert 		restrict_source_flags = flags;
5042b15cb3dSCy Schubert 		restrict_source_mflags = mflags;
5052b15cb3dSCy Schubert 		restrict_source_enabled = 1;
5062b15cb3dSCy Schubert 		return;
5072b15cb3dSCy Schubert 	}
5082b15cb3dSCy Schubert 
5092b15cb3dSCy Schubert 	ZERO(match);
510*9034852cSGleb Smirnoff 
511*9034852cSGleb Smirnoff #if 0
5122b15cb3dSCy Schubert 	/* silence VC9 potentially uninit warnings */
513*9034852cSGleb Smirnoff 	// HMS: let's use a compiler-specific "enable" for this.
5142b15cb3dSCy Schubert 	res = NULL;
5152b15cb3dSCy Schubert 	v6 = 0;
516*9034852cSGleb Smirnoff #endif
5172b15cb3dSCy Schubert 
5182b15cb3dSCy Schubert 	if (IS_IPV4(resaddr)) {
5192b15cb3dSCy Schubert 		v6 = 0;
520c0b746e5SOllivier Robert 		/*
5212b15cb3dSCy Schubert 		 * Get address and mask in host byte order for easy
5222b15cb3dSCy Schubert 		 * comparison as u_int32
523c0b746e5SOllivier Robert 		 */
5242b15cb3dSCy Schubert 		match.u.v4.addr = SRCADR(resaddr);
5252b15cb3dSCy Schubert 		match.u.v4.mask = SRCADR(resmask);
5262b15cb3dSCy Schubert 		match.u.v4.addr &= match.u.v4.mask;
527c0b746e5SOllivier Robert 
5282b15cb3dSCy Schubert 	} else if (IS_IPV6(resaddr)) {
5292b15cb3dSCy Schubert 		v6 = 1;
530c0b746e5SOllivier Robert 		/*
5312b15cb3dSCy Schubert 		 * Get address and mask in network byte order for easy
5322b15cb3dSCy Schubert 		 * comparison as byte sequences (e.g. memcmp())
533c0b746e5SOllivier Robert 		 */
5342b15cb3dSCy Schubert 		match.u.v6.mask = SOCK_ADDR6(resmask);
5352b15cb3dSCy Schubert 		MASK_IPV6_ADDR(&match.u.v6.addr, PSOCK_ADDR6(resaddr),
5362b15cb3dSCy Schubert 			       &match.u.v6.mask);
5379c2daa00SOllivier Robert 
5382b15cb3dSCy Schubert 	} else	/* not IPv4 nor IPv6 */
539*9034852cSGleb Smirnoff 		REQUIRE(0);
5409c2daa00SOllivier Robert 
5412b15cb3dSCy Schubert 	match.flags = flags;
5422b15cb3dSCy Schubert 	match.mflags = mflags;
5432b15cb3dSCy Schubert 	match.expire = expire;
5442b15cb3dSCy Schubert 	res = match_restrict_entry(&match, v6);
5459c2daa00SOllivier Robert 
546c0b746e5SOllivier Robert 	switch (op) {
5472b15cb3dSCy Schubert 
548c0b746e5SOllivier Robert 	case RESTRICT_FLAGS:
549c0b746e5SOllivier Robert 		/*
5509c2daa00SOllivier Robert 		 * Here we add bits to the flags. If this is a
5519c2daa00SOllivier Robert 		 * new restriction add it.
552c0b746e5SOllivier Robert 		 */
5532b15cb3dSCy Schubert 		if (NULL == res) {
5542b15cb3dSCy Schubert 			if (v6) {
5552b15cb3dSCy Schubert 				res = alloc_res6();
5562b15cb3dSCy Schubert 				memcpy(res, &match,
5572b15cb3dSCy Schubert 				       V6_SIZEOF_RESTRICT_U);
5582b15cb3dSCy Schubert 				plisthead = &restrictlist6;
559ea906c41SOllivier Robert 			} else {
5602b15cb3dSCy Schubert 				res = alloc_res4();
5612b15cb3dSCy Schubert 				memcpy(res, &match,
5622b15cb3dSCy Schubert 				       V4_SIZEOF_RESTRICT_U);
5632b15cb3dSCy Schubert 				plisthead = &restrictlist4;
564ea906c41SOllivier Robert 			}
5652b15cb3dSCy Schubert 			LINK_SORT_SLIST(
5662b15cb3dSCy Schubert 				*plisthead, res,
5672b15cb3dSCy Schubert 				(v6)
5682b15cb3dSCy Schubert 				  ? res_sorts_before6(res, L_S_S_CUR())
5692b15cb3dSCy Schubert 				  : res_sorts_before4(res, L_S_S_CUR()),
5702b15cb3dSCy Schubert 				link, restrict_u);
571c0b746e5SOllivier Robert 			restrictcount++;
5722b15cb3dSCy Schubert 			if (RES_LIMITED & flags)
5732b15cb3dSCy Schubert 				inc_res_limited();
5742b15cb3dSCy Schubert 		} else {
5752b15cb3dSCy Schubert 			if ((RES_LIMITED & flags) &&
5762b15cb3dSCy Schubert 			    !(RES_LIMITED & res->flags))
5772b15cb3dSCy Schubert 				inc_res_limited();
5782b15cb3dSCy Schubert 			res->flags |= flags;
579c0b746e5SOllivier Robert 		}
580c0b746e5SOllivier Robert 		break;
581c0b746e5SOllivier Robert 
582c0b746e5SOllivier Robert 	case RESTRICT_UNFLAG:
583c0b746e5SOllivier Robert 		/*
584c0b746e5SOllivier Robert 		 * Remove some bits from the flags. If we didn't
585c0b746e5SOllivier Robert 		 * find this one, just return.
586c0b746e5SOllivier Robert 		 */
5872b15cb3dSCy Schubert 		if (res != NULL) {
5882b15cb3dSCy Schubert 			if ((RES_LIMITED & res->flags)
5892b15cb3dSCy Schubert 			    && (RES_LIMITED & flags))
5902b15cb3dSCy Schubert 				dec_res_limited();
5912b15cb3dSCy Schubert 			res->flags &= ~flags;
592c0b746e5SOllivier Robert 		}
593c0b746e5SOllivier Robert 		break;
594c0b746e5SOllivier Robert 
595c0b746e5SOllivier Robert 	case RESTRICT_REMOVE:
596ea906c41SOllivier Robert 	case RESTRICT_REMOVEIF:
597c0b746e5SOllivier Robert 		/*
5989c2daa00SOllivier Robert 		 * Remove an entry from the table entirely if we
5999c2daa00SOllivier Robert 		 * found one. Don't remove the default entry and
6009c2daa00SOllivier Robert 		 * don't remove an interface entry.
601c0b746e5SOllivier Robert 		 */
6022b15cb3dSCy Schubert 		if (res != NULL
6032b15cb3dSCy Schubert 		    && (RESTRICT_REMOVEIF == op
6042b15cb3dSCy Schubert 			|| !(RESM_INTERFACE & res->mflags))
6052b15cb3dSCy Schubert 		    && res != &restrict_def4
6062b15cb3dSCy Schubert 		    && res != &restrict_def6)
6072b15cb3dSCy Schubert 			free_res(res, v6);
608c0b746e5SOllivier Robert 		break;
609c0b746e5SOllivier Robert 
6102b15cb3dSCy Schubert 	default:	/* unknown op */
611*9034852cSGleb Smirnoff 		INSIST(0);
612c0b746e5SOllivier Robert 		break;
613c0b746e5SOllivier Robert 	}
6142b15cb3dSCy Schubert 
6152b15cb3dSCy Schubert }
6162b15cb3dSCy Schubert 
6172b15cb3dSCy Schubert 
6189c2daa00SOllivier Robert /*
6192b15cb3dSCy Schubert  * restrict_source - maintains dynamic "restrict source ..." entries as
6202b15cb3dSCy Schubert  *		     peers come and go.
6219c2daa00SOllivier Robert  */
6222b15cb3dSCy Schubert void
6232b15cb3dSCy Schubert restrict_source(
6242b15cb3dSCy Schubert 	sockaddr_u *	addr,
6252b15cb3dSCy Schubert 	int		farewell,	/* 0 to add, 1 to remove */
6262b15cb3dSCy Schubert 	u_long		expire		/* 0 is infinite, valid until */
6272b15cb3dSCy Schubert 	)
6282b15cb3dSCy Schubert {
6292b15cb3dSCy Schubert 	sockaddr_u	onesmask;
6302b15cb3dSCy Schubert 	restrict_u *	res;
6312b15cb3dSCy Schubert 	int		found_specific;
632c0b746e5SOllivier Robert 
6332b15cb3dSCy Schubert 	if (!restrict_source_enabled || SOCK_UNSPEC(addr) ||
6342b15cb3dSCy Schubert 	    IS_MCAST(addr) || ISREFCLOCKADR(addr))
6352b15cb3dSCy Schubert 		return;
6369c2daa00SOllivier Robert 
637*9034852cSGleb Smirnoff 	REQUIRE(AF_INET == AF(addr) || AF_INET6 == AF(addr));
6382b15cb3dSCy Schubert 
6392b15cb3dSCy Schubert 	SET_HOSTMASK(&onesmask, AF(addr));
6402b15cb3dSCy Schubert 	if (farewell) {
6412b15cb3dSCy Schubert 		hack_restrict(RESTRICT_REMOVE, addr, &onesmask,
6422b15cb3dSCy Schubert 			      0, 0, 0);
6432b15cb3dSCy Schubert 		DPRINTF(1, ("restrict_source: %s removed", stoa(addr)));
6442b15cb3dSCy Schubert 		return;
6452b15cb3dSCy Schubert 	}
6462b15cb3dSCy Schubert 
6479c2daa00SOllivier Robert 	/*
6482b15cb3dSCy Schubert 	 * If there is a specific entry for this address, hands
6492b15cb3dSCy Schubert 	 * off, as it is condidered more specific than "restrict
6502b15cb3dSCy Schubert 	 * server ...".
6512b15cb3dSCy Schubert 	 * However, if the specific entry found is a fleeting one
6522b15cb3dSCy Schubert 	 * added by pool_xmit() before soliciting, replace it
6532b15cb3dSCy Schubert 	 * immediately regardless of the expire value to make way
6542b15cb3dSCy Schubert 	 * for the more persistent entry.
6559c2daa00SOllivier Robert 	 */
6562b15cb3dSCy Schubert 	if (IS_IPV4(addr)) {
6572b15cb3dSCy Schubert 		res = match_restrict4_addr(SRCADR(addr), SRCPORT(addr));
658*9034852cSGleb Smirnoff 		INSIST(res != NULL);
6592b15cb3dSCy Schubert 		found_specific = (SRCADR(&onesmask) == res->u.v4.mask);
660ea906c41SOllivier Robert 	} else {
6612b15cb3dSCy Schubert 		res = match_restrict6_addr(&SOCK_ADDR6(addr),
6622b15cb3dSCy Schubert 					   SRCPORT(addr));
663*9034852cSGleb Smirnoff 		INSIST(res != NULL);
6642b15cb3dSCy Schubert 		found_specific = ADDR6_EQ(&res->u.v6.mask,
6652b15cb3dSCy Schubert 					  &SOCK_ADDR6(&onesmask));
666ea906c41SOllivier Robert 	}
6672b15cb3dSCy Schubert 	if (!expire && found_specific && res->expire) {
6682b15cb3dSCy Schubert 		found_specific = 0;
6692b15cb3dSCy Schubert 		free_res(res, IS_IPV6(addr));
6709c2daa00SOllivier Robert 	}
6712b15cb3dSCy Schubert 	if (found_specific)
6722b15cb3dSCy Schubert 		return;
6739c2daa00SOllivier Robert 
6742b15cb3dSCy Schubert 	hack_restrict(RESTRICT_FLAGS, addr, &onesmask,
6752b15cb3dSCy Schubert 		      restrict_source_mflags, restrict_source_flags,
6762b15cb3dSCy Schubert 		      expire);
6772b15cb3dSCy Schubert 	DPRINTF(1, ("restrict_source: %s host restriction added\n",
6782b15cb3dSCy Schubert 		    stoa(addr)));
679c0b746e5SOllivier Robert }
680