1 /* $NetBSD: ntp_restrict.c,v 1.6 2007/01/06 19:45:23 kardel Exp $ */
4 * ntp_restrict.c - determine host restrictions
11 #include <sys/types.h>
15 #include "ntp_stdlib.h"
18 * This code keeps a simple address-and-mask list of hosts we want
19 * to place restrictions on (or remove them from). The restrictions
20 * are implemented as a set of flags which tell you what the host
21 * can't do. There is a subroutine entry to return the flags. The
22 * list is kept sorted to reduce the average number of comparisons
23 * and make sure you get the set of restrictions most specific to
26 * The algorithm is that, when looking up a host, it is first assumed
27 * that the default set of restrictions will apply. It then searches
28 * down through the list. Whenever it finds a match it adopts the
29 * match's flags instead. When you hit the point where the sorted
30 * address is greater than the target, you return with the last set of
31 * flags you found. Because of the ordering of the list, the most
32 * specific match will provide the final set of flags.
34 * This was originally intended to restrict you from sync'ing to your
35 * own broadcasts when you are doing that, by restricting yourself from
36 * your own interfaces. It was also thought it would sometimes be useful
37 * to keep a misbehaving host or two from abusing your primary clock. It
38 * has been expanded, however, to suit the needs of those with more
39 * restrictive access policies.
42 * We will use two lists, one for IPv4 addresses and one for IPv6
43 * addresses. This is not protocol-independant but for now I can't
44 * find a way to respect this. We'll check this later... JFB 07/2001
46 #define SET_IPV6_ADDR_MASK(dst, src, msk) \
49 for (idx = 0; idx < 16; idx++) { \
50 (dst)->s6_addr[idx] = \
51 (u_char) ((src)->s6_addr[idx] & (msk)->s6_addr[idx]); \
56 * Memory allocation parameters. We allocate INITRESLIST entries
57 * initially, and add INCRESLIST entries to the free list whenever
60 #define INITRESLIST 10
63 #define RES_AVG 8. /* interpacket averaging factor */
66 * The restriction list
68 struct restrictlist
*restrictlist
;
69 struct restrictlist6
*restrictlist6
;
70 static int restrictcount
; /* count of entries in the res list */
71 static int restrictcount6
; /* count of entries in the res list 2*/
74 * The free list and associated counters. Also some uninteresting
77 static struct restrictlist
*resfree
;
78 static struct restrictlist6
*resfree6
;
79 static int numresfree
; /* number of structures on free list */
80 static int numresfree6
; /* number of structures on free list 2 */
82 static u_long res_calls
;
83 static u_long res_found
;
84 static u_long res_not_found
;
87 * Parameters of the RES_LIMITED restriction option.
89 u_long res_avg_interval
= 5; /* min average interpacket interval */
90 u_long res_min_interval
= 1; /* min interpacket interval */
93 * Count number of restriction entries referring to RES_LIMITED controls
94 * activation/deactivation of monitoring (with respect to RES_LIMITED
97 static u_long res_limited_refcnt
;
98 static u_long res_limited_refcnt6
;
101 * Our initial allocation of lists entries.
103 static struct restrictlist resinit
[INITRESLIST
];
104 static struct restrictlist6 resinit6
[INITRESLIST
];
107 * init_restrict - initialize the restriction data structures
115 * Zero the list and put all but one on the free list
118 memset((char *)resinit
, 0, sizeof resinit
);
120 memset((char *)resinit6
, 0, sizeof resinit6
);
121 for (i
= 1; i
< INITRESLIST
; i
++) {
122 resinit
[i
].next
= resfree
;
123 resinit6
[i
].next
= resfree6
;
124 resfree
= &resinit
[i
];
125 resfree6
= &resinit6
[i
];
127 numresfree
= INITRESLIST
-1;
128 numresfree6
= INITRESLIST
-1;
131 * Put the remaining item at the head of the list as our default
132 * entry. Everything in here should be zero for now.
134 resinit
[0].addr
= htonl(INADDR_ANY
);
136 memset(&resinit6
[0].addr6
, 0, sizeof(struct in6_addr
));
137 memset(&resinit6
[0].mask6
, 0, sizeof(struct in6_addr
));
138 restrictlist
= &resinit
[0];
139 restrictlist6
= &resinit6
[0];
144 * fix up stat counters
151 * set default values for RES_LIMIT functionality
153 res_limited_refcnt
= 0;
154 res_limited_refcnt6
= 0;
159 * restrictions - return restrictions for this host
163 struct sockaddr_storage
*srcadr
,
167 struct restrictlist
*rl
;
168 struct restrictlist
*match
= NULL
;
169 struct restrictlist6
*rl6
;
170 struct restrictlist6
*match6
= NULL
;
171 struct in6_addr hostaddr6
;
172 struct in6_addr hostservaddr6
;
178 if (srcadr
->ss_family
== AF_INET
) {
180 * We need the host address in host order. Also need to
181 * know whether this is from the ntp port or not.
183 hostaddr
= SRCADR(srcadr
);
184 isntpport
= (SRCPORT(srcadr
) == NTP_PORT
);
187 * Ignore any packets with a multicast source address
188 * (this should be done early in the receive process,
191 if (IN_CLASSD(SRCADR(srcadr
)))
192 return (int)RES_IGNORE
;
195 * Set match to first entry, which is default entry.
196 * Work our way down from there.
198 match
= restrictlist
;
199 for (rl
= match
->next
; rl
!= NULL
&& rl
->addr
<= hostaddr
;
201 if ((hostaddr
& rl
->mask
) == rl
->addr
) {
202 if ((rl
->mflags
& RESM_NTPONLY
) &&
208 if (match
== restrictlist
)
212 flags
= match
->flags
;
215 /* IPv6 source address */
216 if (srcadr
->ss_family
== AF_INET6
) {
218 * Need to know whether this is from the ntp port or
221 hostaddr6
= GET_INADDR6(*srcadr
);
223 (struct sockaddr_in6
*)srcadr
)->sin6_port
) ==
227 * Ignore any packets with a multicast source address
228 * (this should be done early in the receive process,
231 if (IN6_IS_ADDR_MULTICAST(&hostaddr6
))
232 return (int)RES_IGNORE
;
235 * Set match to first entry, which is default entry.
236 * Work our way down from there.
238 match6
= restrictlist6
;
239 for (rl6
= match6
->next
; rl6
!= NULL
&&
240 (memcmp(&(rl6
->addr6
), &hostaddr6
,
241 sizeof(hostaddr6
)) <= 0); rl6
= rl6
->next
) {
242 SET_IPV6_ADDR_MASK(&hostservaddr6
, &hostaddr6
,
244 if (memcmp(&hostservaddr6
, &(rl6
->addr6
),
245 sizeof(hostservaddr6
)) == 0) {
246 if ((rl6
->mflags
& RESM_NTPONLY
) &&
253 if (match6
== restrictlist6
)
257 flags
= match6
->flags
;
261 * The following implements a generalized call gap facility.
262 * Douse the RES_LIMITED bit only if the interval since the last
263 * packet is greater than res_min_interval and the average is
264 * greater thatn res_avg_interval.
266 if (!at_listhead
|| mon_enabled
== MON_OFF
) {
267 flags
&= ~RES_LIMITED
;
272 * At this poin the most recent arrival is first in the
273 * MRU list. Let the first 10 packets in for free until
274 * the average stabilizes.
276 md
= mon_mru_list
.mru_next
;
277 if (md
->avg_interval
== 0)
278 md
->avg_interval
= md
->drop_count
;
280 md
->avg_interval
+= (md
->drop_count
-
281 md
->avg_interval
) / RES_AVG
;
282 if (md
->count
< 10 || (md
->drop_count
>
283 res_min_interval
&& md
->avg_interval
>
285 flags
&= ~RES_LIMITED
;
286 md
->drop_count
= flags
;
293 * hack_restrict - add/subtract/manipulate entries on the restrict list
298 struct sockaddr_storage
*resaddr
,
299 struct sockaddr_storage
*resmask
,
304 register u_int32 addr
= 0;
305 register u_int32 mask
= 0;
306 struct in6_addr addr6
;
307 struct in6_addr mask6
;
308 register struct restrictlist
*rl
= NULL
;
309 register struct restrictlist
*rlprev
= NULL
;
310 register struct restrictlist6
*rl6
= NULL
;
311 register struct restrictlist6
*rlprev6
= NULL
;
312 int i
, addr_cmp
, mask_cmp
;
313 memset(&addr6
, 0, sizeof(struct in6_addr
));
314 memset(&mask6
, 0, sizeof(struct in6_addr
));
316 if (resaddr
->ss_family
== AF_INET
) {
318 * Get address and mask in host byte order
320 addr
= SRCADR(resaddr
);
321 mask
= SRCADR(resmask
);
322 addr
&= mask
; /* make sure low bits zero */
325 * If this is the default address, point at first on
326 * list. Else go searching for it.
332 rlprev
= restrictlist
;
335 if (rl
->addr
> addr
) {
338 } else if (rl
->addr
== addr
) {
339 if (rl
->mask
== mask
) {
351 } else if (rl
->mask
> mask
) {
362 if (resaddr
->ss_family
== AF_INET6
) {
363 mask6
= GET_INADDR6(*resmask
);
364 SET_IPV6_ADDR_MASK(&addr6
,
365 &GET_INADDR6(*resaddr
), &mask6
);
366 if (IN6_IS_ADDR_UNSPECIFIED(&addr6
)) {
370 rlprev6
= restrictlist6
;
372 while (rl6
!= NULL
) {
373 addr_cmp
= memcmp(&rl6
->addr6
, &addr6
,
378 } else if (addr_cmp
== 0) {
379 mask_cmp
= memcmp(&rl6
->mask6
,
380 &mask6
, sizeof(mask6
));
393 } else if (mask_cmp
> 0) {
405 * In case the above wasn't clear :-), either rl now points
406 * at the entry this call refers to, or rl is zero and rlprev
407 * points to the entry prior to where this one should go in
412 * Switch based on operation
414 if (resaddr
->ss_family
== AF_INET
) {
418 * Here we add bits to the flags. If this is a
419 * new restriction add it.
422 if (resfree
== NULL
) {
423 rl
= (struct restrictlist
*)
427 memset((char *)rl
, 0,
428 INCRESLIST
* sizeof(struct
430 for (i
= 0; i
< INCRESLIST
; i
++) {
435 numresfree
= INCRESLIST
;
444 rl
->mflags
= (u_short
)mflags
;
446 if (rlprev
== NULL
) {
447 rl
->next
= restrictlist
;
450 rl
->next
= rlprev
->next
;
455 if ((rl
->flags
^ (u_short
)flags
) &
457 res_limited_refcnt
++;
460 rl
->flags
|= (u_short
)flags
;
463 case RESTRICT_UNFLAG
:
465 * Remove some bits from the flags. If we didn't
466 * find this one, just return.
469 if ((rl
->flags
^ (u_short
)flags
) &
471 res_limited_refcnt
--;
472 if (res_limited_refcnt
== 0)
475 rl
->flags
&= (u_short
)~flags
;
479 case RESTRICT_REMOVE
:
480 case RESTRICT_REMOVEIF
:
482 * Remove an entry from the table entirely if we
483 * found one. Don't remove the default entry and
484 * don't remove an interface entry.
487 && rl
->addr
!= htonl(INADDR_ANY
)
488 && !(rl
->mflags
& RESM_INTERFACE
&& op
!= RESTRICT_REMOVEIF
)) {
489 if (rlprev
!= NULL
) {
490 rlprev
->next
= rl
->next
;
492 restrictlist
= rl
->next
;
495 if (rl
->flags
& RES_LIMITED
) {
496 res_limited_refcnt
--;
497 if (res_limited_refcnt
== 0)
500 memset((char *)rl
, 0,
501 sizeof(struct restrictlist
));
512 } else if (resaddr
->ss_family
== AF_INET6
) {
516 * Here we add bits to the flags. If this is a
517 * new restriction add it.
520 if (resfree6
== NULL
) {
522 restrictlist6
*)emalloc(
523 INCRESLIST
* sizeof(struct
525 memset((char *)rl6
, 0,
526 INCRESLIST
* sizeof(struct
529 for (i
= 0; i
< INCRESLIST
;
531 rl6
->next
= resfree6
;
535 numresfree6
= INCRESLIST
;
538 resfree6
= rl6
->next
;
542 rl6
->mflags
= (u_short
)mflags
;
543 if (rlprev6
!= NULL
) {
544 rl6
->next
= rlprev6
->next
;
547 rl6
->next
= restrictlist6
;
552 if ((rl6
->flags
^ (u_short
)flags
) &
554 res_limited_refcnt6
++;
557 rl6
->flags
|= (u_short
)flags
;
560 case RESTRICT_UNFLAG
:
562 * Remove some bits from the flags. If we didn't
563 * find this one, just return.
566 if ((rl6
->flags
^ (u_short
)flags
) &
568 res_limited_refcnt6
--;
569 if (res_limited_refcnt6
== 0)
572 rl6
->flags
&= (u_short
)~flags
;
576 case RESTRICT_REMOVE
:
577 case RESTRICT_REMOVEIF
:
579 * Remove an entry from the table entirely if we
580 * found one. Don't remove the default entry and
581 * don't remove an interface entry.
584 !IN6_IS_ADDR_UNSPECIFIED(&rl6
->addr6
)
585 && !(rl6
->mflags
& RESM_INTERFACE
&& op
!= RESTRICT_REMOVEIF
)) {
586 if (rlprev6
!= NULL
) {
587 rlprev6
->next
= rl6
->next
;
589 restrictlist6
= rl6
->next
;
592 if (rl6
->flags
& RES_LIMITED
) {
593 res_limited_refcnt6
--;
594 if (res_limited_refcnt6
== 0)
597 memset((char *)rl6
, 0,
598 sizeof(struct restrictlist6
));
599 rl6
->next
= resfree6
;