Expand PMF_FN_* macros.
[netbsd-mini2440.git] / dist / ntp / ntpd / ntp_restrict.c
blob8367eef8b91dcb4b32e1c7904bc7bb168909b86f
1 /* $NetBSD: ntp_restrict.c,v 1.6 2007/01/06 19:45:23 kardel Exp $ */
3 /*
4 * ntp_restrict.c - determine host restrictions
5 */
6 #ifdef HAVE_CONFIG_H
7 #include <config.h>
8 #endif
10 #include <stdio.h>
11 #include <sys/types.h>
13 #include "ntpd.h"
14 #include "ntp_if.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
24 * the address.
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) \
47 do { \
48 int idx; \
49 for (idx = 0; idx < 16; idx++) { \
50 (dst)->s6_addr[idx] = \
51 (u_char) ((src)->s6_addr[idx] & (msk)->s6_addr[idx]); \
52 } \
53 } while (0)
56 * Memory allocation parameters. We allocate INITRESLIST entries
57 * initially, and add INCRESLIST entries to the free list whenever
58 * we run out.
60 #define INITRESLIST 10
61 #define INCRESLIST 5
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
75 * stat counters.
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
95 * control)
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
109 void
110 init_restrict(void)
112 register int i;
115 * Zero the list and put all but one on the free list
117 resfree = NULL;
118 memset((char *)resinit, 0, sizeof resinit);
119 resfree6 = NULL;
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);
135 resinit[0].mask = 0;
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];
140 restrictcount = 1;
141 restrictcount = 2;
144 * fix up stat counters
146 res_calls = 0;
147 res_found = 0;
148 res_not_found = 0;
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
162 restrictions(
163 struct sockaddr_storage *srcadr,
164 int at_listhead
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;
173 u_int32 hostaddr;
174 int flags = 0;
175 int isntpport;
177 res_calls++;
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,
189 * later!)
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;
200 rl = rl->next)
201 if ((hostaddr & rl->mask) == rl->addr) {
202 if ((rl->mflags & RESM_NTPONLY) &&
203 !isntpport)
204 continue;
205 match = rl;
207 match->count++;
208 if (match == restrictlist)
209 res_not_found++;
210 else
211 res_found++;
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
219 * not.
221 hostaddr6 = GET_INADDR6(*srcadr);
222 isntpport = (ntohs((
223 (struct sockaddr_in6 *)srcadr)->sin6_port) ==
224 NTP_PORT);
227 * Ignore any packets with a multicast source address
228 * (this should be done early in the receive process,
229 * later!)
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,
243 &rl6->mask6);
244 if (memcmp(&hostservaddr6, &(rl6->addr6),
245 sizeof(hostservaddr6)) == 0) {
246 if ((rl6->mflags & RESM_NTPONLY) &&
247 !isntpport)
248 continue;
249 match6 = rl6;
252 match6->count++;
253 if (match6 == restrictlist6)
254 res_not_found++;
255 else
256 res_found++;
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;
268 } else {
269 struct mon_data *md;
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;
279 else
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 >
284 res_avg_interval))
285 flags &= ~RES_LIMITED;
286 md->drop_count = flags;
288 return (flags);
293 * hack_restrict - add/subtract/manipulate entries on the restrict list
295 void
296 hack_restrict(
297 int op,
298 struct sockaddr_storage *resaddr,
299 struct sockaddr_storage *resmask,
300 int mflags,
301 int flags
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.
328 if (addr == 0) {
329 rlprev = NULL;
330 rl = restrictlist;
331 } else {
332 rlprev = restrictlist;
333 rl = rlprev->next;
334 while (rl != NULL) {
335 if (rl->addr > addr) {
336 rl = NULL;
337 break;
338 } else if (rl->addr == addr) {
339 if (rl->mask == mask) {
340 if ((mflags &
341 RESM_NTPONLY) ==
342 (rl->mflags &
343 RESM_NTPONLY))
344 break;
346 if (!(mflags &
347 RESM_NTPONLY)) {
348 rl = NULL;
349 break;
351 } else if (rl->mask > mask) {
352 rl = NULL;
353 break;
356 rlprev = rl;
357 rl = rl->next;
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)) {
367 rlprev6 = NULL;
368 rl6 = restrictlist6;
369 } else {
370 rlprev6 = restrictlist6;
371 rl6 = rlprev6->next;
372 while (rl6 != NULL) {
373 addr_cmp = memcmp(&rl6->addr6, &addr6,
374 sizeof(addr6));
375 if (addr_cmp > 0) {
376 rl6 = NULL;
377 break;
378 } else if (addr_cmp == 0) {
379 mask_cmp = memcmp(&rl6->mask6,
380 &mask6, sizeof(mask6));
381 if (mask_cmp == 0) {
382 if ((mflags &
383 RESM_NTPONLY) ==
384 (rl6->mflags &
385 RESM_NTPONLY))
386 break;
388 if (!(mflags &
389 RESM_NTPONLY)) {
390 rl6 = NULL;
391 break;
393 } else if (mask_cmp > 0) {
394 rl6 = NULL;
395 break;
398 rlprev6 = rl6;
399 rl6 = rl6->next;
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
408 * the sort.
412 * Switch based on operation
414 if (resaddr->ss_family == AF_INET) {
415 switch (op) {
416 case RESTRICT_FLAGS:
418 * Here we add bits to the flags. If this is a
419 * new restriction add it.
421 if (rl == NULL) {
422 if (resfree == NULL) {
423 rl = (struct restrictlist *)
424 emalloc(INCRESLIST *
425 sizeof(struct
426 restrictlist));
427 memset((char *)rl, 0,
428 INCRESLIST * sizeof(struct
429 restrictlist));
430 for (i = 0; i < INCRESLIST; i++) {
431 rl->next = resfree;
432 resfree = rl;
433 rl++;
435 numresfree = INCRESLIST;
438 rl = resfree;
439 resfree = rl->next;
440 numresfree--;
442 rl->addr = addr;
443 rl->mask = mask;
444 rl->mflags = (u_short)mflags;
446 if (rlprev == NULL) {
447 rl->next = restrictlist;
448 restrictlist = rl;
449 } else {
450 rl->next = rlprev->next;
451 rlprev->next = rl;
453 restrictcount++;
455 if ((rl->flags ^ (u_short)flags) &
456 RES_LIMITED) {
457 res_limited_refcnt++;
458 mon_start(MON_RES);
460 rl->flags |= (u_short)flags;
461 break;
463 case RESTRICT_UNFLAG:
465 * Remove some bits from the flags. If we didn't
466 * find this one, just return.
468 if (rl != NULL) {
469 if ((rl->flags ^ (u_short)flags) &
470 RES_LIMITED) {
471 res_limited_refcnt--;
472 if (res_limited_refcnt == 0)
473 mon_stop(MON_RES);
475 rl->flags &= (u_short)~flags;
477 break;
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.
486 if (rl != NULL
487 && rl->addr != htonl(INADDR_ANY)
488 && !(rl->mflags & RESM_INTERFACE && op != RESTRICT_REMOVEIF)) {
489 if (rlprev != NULL) {
490 rlprev->next = rl->next;
491 } else {
492 restrictlist = rl->next;
494 restrictcount--;
495 if (rl->flags & RES_LIMITED) {
496 res_limited_refcnt--;
497 if (res_limited_refcnt == 0)
498 mon_stop(MON_RES);
500 memset((char *)rl, 0,
501 sizeof(struct restrictlist));
503 rl->next = resfree;
504 resfree = rl;
505 numresfree++;
507 break;
509 default:
510 break;
512 } else if (resaddr->ss_family == AF_INET6) {
513 switch (op) {
514 case RESTRICT_FLAGS:
516 * Here we add bits to the flags. If this is a
517 * new restriction add it.
519 if (rl6 == NULL) {
520 if (resfree6 == NULL) {
521 rl6 = (struct
522 restrictlist6 *)emalloc(
523 INCRESLIST * sizeof(struct
524 restrictlist6));
525 memset((char *)rl6, 0,
526 INCRESLIST * sizeof(struct
527 restrictlist6));
529 for (i = 0; i < INCRESLIST;
530 i++) {
531 rl6->next = resfree6;
532 resfree6 = rl6;
533 rl6++;
535 numresfree6 = INCRESLIST;
537 rl6 = resfree6;
538 resfree6 = rl6->next;
539 numresfree6--;
540 rl6->addr6 = addr6;
541 rl6->mask6 = mask6;
542 rl6->mflags = (u_short)mflags;
543 if (rlprev6 != NULL) {
544 rl6->next = rlprev6->next;
545 rlprev6->next = rl6;
546 } else {
547 rl6->next = restrictlist6;
548 restrictlist6 = rl6;
550 restrictcount6++;
552 if ((rl6->flags ^ (u_short)flags) &
553 RES_LIMITED) {
554 res_limited_refcnt6++;
555 mon_start(MON_RES);
557 rl6->flags |= (u_short)flags;
558 break;
560 case RESTRICT_UNFLAG:
562 * Remove some bits from the flags. If we didn't
563 * find this one, just return.
565 if (rl6 != NULL) {
566 if ((rl6->flags ^ (u_short)flags) &
567 RES_LIMITED) {
568 res_limited_refcnt6--;
569 if (res_limited_refcnt6 == 0)
570 mon_stop(MON_RES);
572 rl6->flags &= (u_short)~flags;
574 break;
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.
583 if (rl6 != NULL &&
584 !IN6_IS_ADDR_UNSPECIFIED(&rl6->addr6)
585 && !(rl6->mflags & RESM_INTERFACE && op != RESTRICT_REMOVEIF)) {
586 if (rlprev6 != NULL) {
587 rlprev6->next = rl6->next;
588 } else {
589 restrictlist6 = rl6->next;
591 restrictcount6--;
592 if (rl6->flags & RES_LIMITED) {
593 res_limited_refcnt6--;
594 if (res_limited_refcnt6 == 0)
595 mon_stop(MON_RES);
597 memset((char *)rl6, 0,
598 sizeof(struct restrictlist6));
599 rl6->next = resfree6;
600 resfree6 = rl6;
601 numresfree6++;
603 break;
605 default:
606 break;