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;