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
164 struct restrictlist *rl;
165 struct restrictlist *match = NULL;
166 struct restrictlist6 *rl6;
167 struct restrictlist6 *match6 = NULL;
168 struct in6_addr hostaddr6;
169 struct in6_addr hostservaddr6;
175 if (srcadr->ss_family == AF_INET) {
177 * We need the host address in host order. Also need to
178 * know whether this is from the ntp port or not.
180 hostaddr = SRCADR(srcadr);
181 isntpport = (SRCPORT(srcadr) == NTP_PORT);
184 * Ignore any packets with a multicast source address
185 * (this should be done early in the receive process,
188 if (IN_CLASSD(SRCADR(srcadr)))
189 return (int)RES_IGNORE;
192 * Set match to first entry, which is default entry.
193 * Work our way down from there.
195 match = restrictlist;
196 for (rl = match->next; rl != 0 && rl->addr <= hostaddr;
198 if ((hostaddr & rl->mask) == rl->addr) {
199 if ((rl->mflags & RESM_NTPONLY) &&
205 if (match == restrictlist)
209 flags = match->flags;
212 /* IPv6 source address */
213 if (srcadr->ss_family == AF_INET6) {
215 * Need to know whether this is from the ntp port or
218 hostaddr6 = GET_INADDR6(*srcadr);
220 (struct sockaddr_in6 *)srcadr)->sin6_port) ==
224 * Ignore any packets with a multicast source address
225 * (this should be done early in the receive process,
228 if (IN6_IS_ADDR_MULTICAST(&hostaddr6))
229 return (int)RES_IGNORE;
232 * Set match to first entry, which is default entry.
233 * Work our way down from there.
235 match6 = restrictlist6;
236 for (rl6 = match6->next; rl6 != 0 &&
237 (memcmp(&(rl6->addr6), &hostaddr6,
238 sizeof(hostaddr6)) <= 0); rl6 = rl6->next) {
239 SET_IPV6_ADDR_MASK(&hostservaddr6, &hostaddr6,
241 if (memcmp(&hostservaddr6, &(rl6->addr6),
242 sizeof(hostservaddr6)) == 0) {
243 if ((rl6->mflags & RESM_NTPONLY) &&
250 if (match6 == restrictlist6)
254 flags = match6->flags;
258 * The following implements a generalized call gap facility.
259 * Douse the RES_LIMITED bit only if the interval since the last
260 * packet is greater than res_min_interval and the average is
261 * greater thatn res_avg_interval.
263 if (mon_enabled == MON_OFF) {
264 flags &= ~RES_LIMITED;
269 * At this poin the most recent arrival is first in the
270 * MRU list. Let the first 10 packets in for free until
271 * the average stabilizes.
273 md = mon_mru_list.mru_next;
274 if (md->avg_interval == 0)
275 md->avg_interval = md->drop_count;
277 md->avg_interval += (md->drop_count -
278 md->avg_interval) / RES_AVG;
279 if (md->count < 10 || (md->drop_count >
280 res_min_interval && md->avg_interval >
282 flags &= ~RES_LIMITED;
283 md->drop_count = flags;
290 * hack_restrict - add/subtract/manipulate entries on the restrict list
295 struct sockaddr_storage *resaddr,
296 struct sockaddr_storage *resmask,
301 register u_int32 addr = 0;
302 register u_int32 mask = 0;
303 struct in6_addr addr6;
304 struct in6_addr mask6;
305 register struct restrictlist *rl = NULL;
306 register struct restrictlist *rlprev = NULL;
307 register struct restrictlist6 *rl6 = NULL;
308 register struct restrictlist6 *rlprev6 = NULL;
309 int i, addr_cmp, mask_cmp;
310 memset(&addr6, 0, sizeof(struct in6_addr));
311 memset(&mask6, 0, sizeof(struct in6_addr));
313 if (resaddr->ss_family == AF_INET) {
315 * Get address and mask in host byte order
317 addr = SRCADR(resaddr);
318 mask = SRCADR(resmask);
319 addr &= mask; /* make sure low bits zero */
322 * If this is the default address, point at first on
323 * list. Else go searching for it.
329 rlprev = restrictlist;
332 if (rl->addr > addr) {
335 } else if (rl->addr == addr) {
336 if (rl->mask == mask) {
348 } else if (rl->mask > mask) {
359 if (resaddr->ss_family == AF_INET6) {
360 mask6 = GET_INADDR6(*resmask);
361 SET_IPV6_ADDR_MASK(&addr6,
362 &GET_INADDR6(*resaddr), &mask6);
363 if (IN6_IS_ADDR_UNSPECIFIED(&addr6)) {
367 rlprev6 = restrictlist6;
370 addr_cmp = memcmp(&rl6->addr6, &addr6,
375 } else if (addr_cmp == 0) {
376 mask_cmp = memcmp(&rl6->mask6,
377 &mask6, sizeof(mask6));
390 } else if (mask_cmp > 0) {
402 * In case the above wasn't clear :-), either rl now points
403 * at the entry this call refers to, or rl is zero and rlprev
404 * points to the entry prior to where this one should go in
409 * Switch based on operation
411 if (resaddr->ss_family == AF_INET) {
415 * Here we add bits to the flags. If this is a
416 * new restriction add it.
419 if (numresfree == 0) {
420 rl = (struct restrictlist *)
424 memset((char *)rl, 0,
425 INCRESLIST * sizeof(struct
427 for (i = 0; i < INCRESLIST; i++) {
432 numresfree = INCRESLIST;
441 rl->mflags = (u_short)mflags;
443 rl->next = rlprev->next;
447 if ((rl->flags ^ (u_short)flags) &
449 res_limited_refcnt++;
452 rl->flags |= (u_short)flags;
455 case RESTRICT_UNFLAG:
457 * Remove some bits from the flags. If we didn't
458 * find this one, just return.
461 if ((rl->flags ^ (u_short)flags) &
463 res_limited_refcnt--;
464 if (res_limited_refcnt == 0)
467 rl->flags &= (u_short)~flags;
471 case RESTRICT_REMOVE:
473 * Remove an entry from the table entirely if we
474 * found one. Don't remove the default entry and
475 * don't remove an interface entry.
478 && rl->addr != htonl(INADDR_ANY)
479 && !(rl->mflags & RESM_INTERFACE)) {
480 rlprev->next = rl->next;
482 if (rl->flags & RES_LIMITED) {
483 res_limited_refcnt--;
484 if (res_limited_refcnt == 0)
487 memset((char *)rl, 0,
488 sizeof(struct restrictlist));
499 } else if (resaddr->ss_family == AF_INET6) {
503 * Here we add bits to the flags. If this is a
504 * new restriction add it.
507 if (numresfree6 == 0) {
509 restrictlist6 *)emalloc(
510 INCRESLIST * sizeof(struct
512 memset((char *)rl6, 0,
513 INCRESLIST * sizeof(struct
516 for (i = 0; i < INCRESLIST;
518 rl6->next = resfree6;
522 numresfree6 = INCRESLIST;
525 resfree6 = rl6->next;
529 rl6->mflags = (u_short)mflags;
530 rl6->next = rlprev6->next;
534 if ((rl6->flags ^ (u_short)flags) &
536 res_limited_refcnt6++;
539 rl6->flags |= (u_short)flags;
542 case RESTRICT_UNFLAG:
544 * Remove some bits from the flags. If we didn't
545 * find this one, just return.
548 if ((rl6->flags ^ (u_short)flags) &
550 res_limited_refcnt6--;
551 if (res_limited_refcnt6 == 0)
554 rl6->flags &= (u_short)~flags;
558 case RESTRICT_REMOVE:
560 * Remove an entry from the table entirely if we
561 * found one. Don't remove the default entry and
562 * don't remove an interface entry.
565 !IN6_IS_ADDR_UNSPECIFIED(&rl6->addr6)
566 && !(rl6->mflags & RESM_INTERFACE)) {
567 rlprev6->next = rl6->next;
569 if (rl6->flags & RES_LIMITED) {
570 res_limited_refcnt6--;
571 if (res_limited_refcnt6 == 0)
574 memset((char *)rl6, 0,
575 sizeof(struct restrictlist6));
576 rl6->next = resfree6;