2 * ntp_restrict.c - determine host restrictions
13 #include "ntp_stdlib.h"
16 * This code keeps a simple address-and-mask list of hosts we want
17 * to place restrictions on (or remove them from). The restrictions
18 * are implemented as a set of flags which tell you what the host
19 * can't do. There is a subroutine entry to return the flags. The
20 * list is kept sorted to reduce the average number of comparisons
21 * and make sure you get the set of restrictions most specific to
24 * The algorithm is that, when looking up a host, it is first assumed
25 * that the default set of restrictions will apply. It then searches
26 * down through the list. Whenever it finds a match it adopts the
27 * match's flags instead. When you hit the point where the sorted
28 * address is greater than the target, you return with the last set of
29 * flags you found. Because of the ordering of the list, the most
30 * specific match will provide the final set of flags.
32 * This was originally intended to restrict you from sync'ing to your
33 * own broadcasts when you are doing that, by restricting yourself from
34 * your own interfaces. It was also thought it would sometimes be useful
35 * to keep a misbehaving host or two from abusing your primary clock. It
36 * has been expanded, however, to suit the needs of those with more
37 * restrictive access policies.
40 * We will use two lists, one for IPv4 addresses and one for IPv6
41 * addresses. This is not protocol-independant but for now I can't
42 * find a way to respect this. We'll check this later... JFB 07/2001
44 #define SET_IPV6_ADDR_MASK(dst, src, msk) \
47 for (idx = 0; idx < 16; idx++) { \
48 (dst)->s6_addr[idx] = \
49 (u_char) ((src)->s6_addr[idx] & (msk)->s6_addr[idx]); \
54 * Memory allocation parameters. We allocate INITRESLIST entries
55 * initially, and add INCRESLIST entries to the free list whenever
58 #define INITRESLIST 10
61 #define RES_AVG 8. /* interpacket averaging factor */
64 * The restriction list
66 struct restrictlist
*restrictlist
;
67 struct restrictlist6
*restrictlist6
;
68 static int restrictcount
; /* count of entries in the res list */
69 static int restrictcount6
; /* count of entries in the res list 2*/
72 * The free list and associated counters. Also some uninteresting
75 static struct restrictlist
*resfree
;
76 static struct restrictlist6
*resfree6
;
77 static int numresfree
; /* number of structures on free list */
78 static int numresfree6
; /* number of structures on free list 2 */
80 static u_long res_calls
;
81 static u_long res_found
;
82 static u_long res_not_found
;
85 * Parameters of the RES_LIMITED restriction option.
87 u_long res_avg_interval
= 5; /* min average interpacket interval */
88 u_long res_min_interval
= 1; /* min interpacket interval */
91 * Count number of restriction entries referring to RES_LIMITED controls
92 * activation/deactivation of monitoring (with respect to RES_LIMITED
95 static u_long res_limited_refcnt
;
96 static u_long res_limited_refcnt6
;
99 * Our initial allocation of lists entries.
101 static struct restrictlist resinit
[INITRESLIST
];
102 static struct restrictlist6 resinit6
[INITRESLIST
];
105 * init_restrict - initialize the restriction data structures
113 * Zero the list and put all but one on the free list
116 memset((char *)resinit
, 0, sizeof resinit
);
118 memset((char *)resinit6
, 0, sizeof resinit6
);
119 for (i
= 1; i
< INITRESLIST
; i
++) {
120 resinit
[i
].next
= resfree
;
121 resinit6
[i
].next
= resfree6
;
122 resfree
= &resinit
[i
];
123 resfree6
= &resinit6
[i
];
125 numresfree
= INITRESLIST
-1;
126 numresfree6
= INITRESLIST
-1;
129 * Put the remaining item at the head of the list as our default
130 * entry. Everything in here should be zero for now.
132 resinit
[0].addr
= htonl(INADDR_ANY
);
134 memset(&resinit6
[0].addr6
, 0, sizeof(struct in6_addr
));
135 memset(&resinit6
[0].mask6
, 0, sizeof(struct in6_addr
));
136 restrictlist
= &resinit
[0];
137 restrictlist6
= &resinit6
[0];
142 * fix up stat counters
149 * set default values for RES_LIMIT functionality
151 res_limited_refcnt
= 0;
152 res_limited_refcnt6
= 0;
157 * restrictions - return restrictions for this host
161 struct sockaddr_storage
*srcadr
,
165 struct restrictlist
*rl
;
166 struct restrictlist
*match
= NULL
;
167 struct restrictlist6
*rl6
;
168 struct restrictlist6
*match6
= NULL
;
169 struct in6_addr hostaddr6
;
170 struct in6_addr hostservaddr6
;
176 if (srcadr
->ss_family
== AF_INET
) {
178 * We need the host address in host order. Also need to
179 * know whether this is from the ntp port or not.
181 hostaddr
= SRCADR(srcadr
);
182 isntpport
= (SRCPORT(srcadr
) == NTP_PORT
);
185 * Ignore any packets with a multicast source address
186 * (this should be done early in the receive process,
189 if (IN_CLASSD(SRCADR(srcadr
)))
190 return (int)RES_IGNORE
;
193 * Set match to first entry, which is default entry.
194 * Work our way down from there.
196 match
= restrictlist
;
197 for (rl
= match
->next
; rl
!= NULL
&& rl
->addr
<= hostaddr
;
199 if ((hostaddr
& rl
->mask
) == rl
->addr
) {
200 if ((rl
->mflags
& RESM_NTPONLY
) &&
206 if (match
== restrictlist
)
210 flags
= match
->flags
;
213 /* IPv6 source address */
214 if (srcadr
->ss_family
== AF_INET6
) {
216 * Need to know whether this is from the ntp port or
219 hostaddr6
= GET_INADDR6(*srcadr
);
221 (struct sockaddr_in6
*)srcadr
)->sin6_port
) ==
225 * Ignore any packets with a multicast source address
226 * (this should be done early in the receive process,
229 if (IN6_IS_ADDR_MULTICAST(&hostaddr6
))
230 return (int)RES_IGNORE
;
233 * Set match to first entry, which is default entry.
234 * Work our way down from there.
236 match6
= restrictlist6
;
237 for (rl6
= match6
->next
; rl6
!= NULL
&&
238 (memcmp(&(rl6
->addr6
), &hostaddr6
,
239 sizeof(hostaddr6
)) <= 0); rl6
= rl6
->next
) {
240 SET_IPV6_ADDR_MASK(&hostservaddr6
, &hostaddr6
,
242 if (memcmp(&hostservaddr6
, &(rl6
->addr6
),
243 sizeof(hostservaddr6
)) == 0) {
244 if ((rl6
->mflags
& RESM_NTPONLY
) &&
251 if (match6
== restrictlist6
)
255 flags
= match6
->flags
;
259 * The following implements a generalized call gap facility.
260 * Douse the RES_LIMITED bit only if the interval since the last
261 * packet is greater than res_min_interval and the average is
262 * greater thatn res_avg_interval.
264 if (!at_listhead
|| mon_enabled
== MON_OFF
) {
265 flags
&= ~RES_LIMITED
;
270 * At this poin the most recent arrival is first in the
271 * MRU list. Let the first 10 packets in for free until
272 * the average stabilizes.
274 md
= mon_mru_list
.mru_next
;
275 if (md
->avg_interval
== 0)
276 md
->avg_interval
= md
->drop_count
;
278 md
->avg_interval
+= (md
->drop_count
-
279 md
->avg_interval
) / RES_AVG
;
280 if (md
->count
< 10 || (md
->drop_count
>
281 res_min_interval
&& md
->avg_interval
>
283 flags
&= ~RES_LIMITED
;
284 md
->drop_count
= flags
;
291 * hack_restrict - add/subtract/manipulate entries on the restrict list
296 struct sockaddr_storage
*resaddr
,
297 struct sockaddr_storage
*resmask
,
302 register u_int32 addr
= 0;
303 register u_int32 mask
= 0;
304 struct in6_addr addr6
;
305 struct in6_addr mask6
;
306 register struct restrictlist
*rl
= NULL
;
307 register struct restrictlist
*rlprev
= NULL
;
308 register struct restrictlist6
*rl6
= NULL
;
309 register struct restrictlist6
*rlprev6
= NULL
;
310 int i
, addr_cmp
, mask_cmp
;
311 memset(&addr6
, 0, sizeof(struct in6_addr
));
312 memset(&mask6
, 0, sizeof(struct in6_addr
));
314 if (resaddr
->ss_family
== AF_INET
) {
316 * Get address and mask in host byte order
318 addr
= SRCADR(resaddr
);
319 mask
= SRCADR(resmask
);
320 addr
&= mask
; /* make sure low bits zero */
323 * If this is the default address, point at first on
324 * list. Else go searching for it.
330 rlprev
= restrictlist
;
333 if (rl
->addr
> addr
) {
336 } else if (rl
->addr
== addr
) {
337 if (rl
->mask
== mask
) {
349 } else if (rl
->mask
> mask
) {
360 if (resaddr
->ss_family
== AF_INET6
) {
361 mask6
= GET_INADDR6(*resmask
);
362 SET_IPV6_ADDR_MASK(&addr6
,
363 &GET_INADDR6(*resaddr
), &mask6
);
364 if (IN6_IS_ADDR_UNSPECIFIED(&addr6
)) {
368 rlprev6
= restrictlist6
;
370 while (rl6
!= NULL
) {
371 addr_cmp
= memcmp(&rl6
->addr6
, &addr6
,
376 } else if (addr_cmp
== 0) {
377 mask_cmp
= memcmp(&rl6
->mask6
,
378 &mask6
, sizeof(mask6
));
391 } else if (mask_cmp
> 0) {
403 * In case the above wasn't clear :-), either rl now points
404 * at the entry this call refers to, or rl is zero and rlprev
405 * points to the entry prior to where this one should go in
410 * Switch based on operation
412 if (resaddr
->ss_family
== AF_INET
) {
416 * Here we add bits to the flags. If this is a
417 * new restriction add it.
420 if (resfree
== NULL
) {
421 rl
= (struct restrictlist
*)
425 memset((char *)rl
, 0,
426 INCRESLIST
* sizeof(struct
428 for (i
= 0; i
< INCRESLIST
; i
++) {
433 numresfree
= INCRESLIST
;
442 rl
->mflags
= (u_short
)mflags
;
444 if (rlprev
== NULL
) {
445 rl
->next
= restrictlist
;
448 rl
->next
= rlprev
->next
;
453 if ((rl
->flags
^ (u_short
)flags
) &
455 res_limited_refcnt
++;
458 rl
->flags
|= (u_short
)flags
;
461 case RESTRICT_UNFLAG
:
463 * Remove some bits from the flags. If we didn't
464 * find this one, just return.
467 if ((rl
->flags
^ (u_short
)flags
) &
469 res_limited_refcnt
--;
470 if (res_limited_refcnt
== 0)
473 rl
->flags
&= (u_short
)~flags
;
477 case RESTRICT_REMOVE
:
478 case RESTRICT_REMOVEIF
:
480 * Remove an entry from the table entirely if we
481 * found one. Don't remove the default entry and
482 * don't remove an interface entry.
485 && rl
->addr
!= htonl(INADDR_ANY
)
486 && !(rl
->mflags
& RESM_INTERFACE
&& op
!= RESTRICT_REMOVEIF
)) {
487 if (rlprev
!= NULL
) {
488 rlprev
->next
= rl
->next
;
490 restrictlist
= rl
->next
;
493 if (rl
->flags
& RES_LIMITED
) {
494 res_limited_refcnt
--;
495 if (res_limited_refcnt
== 0)
498 memset((char *)rl
, 0,
499 sizeof(struct restrictlist
));
510 } else if (resaddr
->ss_family
== AF_INET6
) {
514 * Here we add bits to the flags. If this is a
515 * new restriction add it.
518 if (resfree6
== NULL
) {
520 restrictlist6
*)emalloc(
521 INCRESLIST
* sizeof(struct
523 memset((char *)rl6
, 0,
524 INCRESLIST
* sizeof(struct
527 for (i
= 0; i
< INCRESLIST
;
529 rl6
->next
= resfree6
;
533 numresfree6
= INCRESLIST
;
536 resfree6
= rl6
->next
;
540 rl6
->mflags
= (u_short
)mflags
;
541 if (rlprev6
!= NULL
) {
542 rl6
->next
= rlprev6
->next
;
545 rl6
->next
= restrictlist6
;
550 if ((rl6
->flags
^ (u_short
)flags
) &
552 res_limited_refcnt6
++;
555 rl6
->flags
|= (u_short
)flags
;
558 case RESTRICT_UNFLAG
:
560 * Remove some bits from the flags. If we didn't
561 * find this one, just return.
564 if ((rl6
->flags
^ (u_short
)flags
) &
566 res_limited_refcnt6
--;
567 if (res_limited_refcnt6
== 0)
570 rl6
->flags
&= (u_short
)~flags
;
574 case RESTRICT_REMOVE
:
575 case RESTRICT_REMOVEIF
:
577 * Remove an entry from the table entirely if we
578 * found one. Don't remove the default entry and
579 * don't remove an interface entry.
582 !IN6_IS_ADDR_UNSPECIFIED(&rl6
->addr6
)
583 && !(rl6
->mflags
& RESM_INTERFACE
&& op
!= RESTRICT_REMOVEIF
)) {
584 if (rlprev6
!= NULL
) {
585 rlprev6
->next
= rl6
->next
;
587 restrictlist6
= rl6
->next
;
590 if (rl6
->flags
& RES_LIMITED
) {
591 res_limited_refcnt6
--;
592 if (res_limited_refcnt6
== 0)
595 memset((char *)rl6
, 0,
596 sizeof(struct restrictlist6
));
597 rl6
->next
= resfree6
;