Patrick Welche <prlw1@cam.ac.uk>
[netbsd-mini2440.git] / external / bsd / ntp / dist / ntpd / ntp_restrict.c
blob2b8b772dc9b07a9a97488a48e0163258caaae8f3
1 /* $NetBSD$ */
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
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
73 * stat counters.
75 static struct restrictlist *resfree;
76 static struct restrictlist6 *resfree6;
77 static int numresfree; /* number of struct on free list */
78 static int numresfree6; /* number of struct on free list 2 */
80 static u_long res_calls;
81 static u_long res_found;
82 static u_long res_not_found;
85 * Count number of restriction entries referring to RES_LIMITED controls
86 * activation/deactivation of monitoring (with respect to RES_LIMITED
87 * control)
89 static u_long res_limited_refcnt;
90 static u_long res_limited_refcnt6;
93 * Our initial allocation of lists entries.
95 static struct restrictlist resinit[INITRESLIST];
96 static struct restrictlist6 resinit6[INITRESLIST];
100 * init_restrict - initialize the restriction data structures
102 void
103 init_restrict(void)
105 register int i;
108 * Zero the list and put all but one on the free list
110 resfree = 0;
111 memset((char *)resinit, 0, sizeof resinit);
112 resfree6 = 0;
113 memset((char *)resinit6, 0, sizeof resinit6);
114 for (i = 1; i < INITRESLIST; i++) {
115 resinit[i].next = resfree;
116 resinit6[i].next = resfree6;
117 resfree = &resinit[i];
118 resfree6 = &resinit6[i];
120 numresfree = INITRESLIST-1;
121 numresfree6 = INITRESLIST-1;
124 * Put the remaining item at the head of the list as our default
125 * entry. Everything in here should be zero for now.
127 resinit[0].addr = htonl(INADDR_ANY);
128 resinit[0].mask = 0;
129 memset(&resinit6[0].addr6, 0, sizeof(struct in6_addr));
130 memset(&resinit6[0].mask6, 0, sizeof(struct in6_addr));
131 restrictlist = &resinit[0];
132 restrictlist6 = &resinit6[0];
133 restrictcount = 1;
134 restrictcount = 2;
137 * fix up stat counters
139 res_calls = 0;
140 res_found = 0;
141 res_not_found = 0;
144 * set default values for RES_LIMIT functionality
146 res_limited_refcnt = 0;
147 res_limited_refcnt6 = 0;
152 * restrictions - return restrictions for this host
155 restrictions(
156 sockaddr_u *srcadr
159 struct restrictlist *rl;
160 struct restrictlist *match = NULL;
161 struct restrictlist6 *rl6;
162 struct restrictlist6 *match6 = NULL;
163 struct in6_addr hostaddr6;
164 struct in6_addr hostservaddr6;
165 u_int32 hostaddr;
166 int flags = 0;
167 int isntpport;
169 res_calls++;
170 /* IPv4 source address */
171 if (IS_IPV4(srcadr)) {
174 * We need the host address in host order. Also need to
175 * know whether this is from the ntp port or not.
177 hostaddr = SRCADR(srcadr);
178 isntpport = (NTP_PORT == SRCPORT(srcadr));
181 * Ignore any packets with a multicast source address
182 * (this should be done early in the receive process,
183 * not later!)
185 if (IN_CLASSD(SRCADR(srcadr)))
186 return (int)RES_IGNORE;
189 * Set match to first entry, which is default entry.
190 * Work our way down from there.
192 match = restrictlist;
193 for (rl = match->next; rl != 0 && rl->addr <= hostaddr;
194 rl = rl->next)
195 if ((hostaddr & rl->mask) == rl->addr) {
196 if ((rl->mflags & RESM_NTPONLY) &&
197 !isntpport)
198 continue;
199 match = rl;
201 match->count++;
202 if (match == restrictlist)
203 res_not_found++;
204 else
205 res_found++;
206 flags = match->flags;
209 /* IPv6 source address */
210 if (IS_IPV6(srcadr)) {
213 * We need the host address in network order. Also need
214 * to know whether this is from the ntp port or not.
216 hostaddr6 = SOCK_ADDR6(srcadr);
217 isntpport = (NTP_PORT == SRCPORT(srcadr));
220 * Ignore any packets with a multicast source address
221 * (this should be done early in the receive process,
222 * not later!)
224 if (IN6_IS_ADDR_MULTICAST(&hostaddr6))
225 return (int)RES_IGNORE;
228 * Set match to first entry, which is default entry.
229 * Work our way down from there.
231 match6 = restrictlist6;
232 for (rl6 = match6->next; rl6 != 0 &&
233 (memcmp(&(rl6->addr6), &hostaddr6,
234 sizeof(hostaddr6)) <= 0); rl6 = rl6->next) {
235 SET_IPV6_ADDR_MASK(&hostservaddr6, &hostaddr6,
236 &rl6->mask6);
237 if (memcmp(&hostservaddr6, &(rl6->addr6),
238 sizeof(hostservaddr6)) == 0) {
239 if ((rl6->mflags & RESM_NTPONLY) &&
240 !isntpport)
241 continue;
242 match6 = rl6;
245 match6->count++;
246 if (match6 == restrictlist6)
247 res_not_found++;
248 else
249 res_found++;
250 flags = match6->flags;
252 return (flags);
257 * hack_restrict - add/subtract/manipulate entries on the restrict list
259 void
260 hack_restrict(
261 int op,
262 sockaddr_u *resaddr,
263 sockaddr_u *resmask,
264 int mflags,
265 int flags
268 register u_int32 addr = 0;
269 register u_int32 mask = 0;
270 struct in6_addr addr6;
271 struct in6_addr mask6;
272 register struct restrictlist *rl = NULL;
273 register struct restrictlist *rlprev = NULL;
274 register struct restrictlist6 *rl6 = NULL;
275 register struct restrictlist6 *rlprev6 = NULL;
276 int i, addr_cmp, mask_cmp;
277 memset(&addr6, 0, sizeof(struct in6_addr));
278 memset(&mask6, 0, sizeof(struct in6_addr));
280 if (IS_IPV4(resaddr)) {
282 DPRINTF(1, ("restrict: addr %08x mask %08x mflags %08x flags %08x\n",
283 SRCADR(resaddr), SRCADR(resmask), mflags, flags));
286 * Get address and mask in host byte order
288 addr = SRCADR(resaddr);
289 mask = SRCADR(resmask);
290 addr &= mask; /* make sure low bits zero */
293 * If this is the default address, point at first on
294 * list. Else go searching for it.
296 if (addr == 0) {
297 rlprev = 0;
298 rl = restrictlist;
299 } else {
300 rlprev = restrictlist;
301 rl = rlprev->next;
302 while (rl != 0) {
303 if (rl->addr > addr) {
304 rl = 0;
305 break;
306 } else if (rl->addr == addr) {
307 if (rl->mask == mask) {
308 if ((mflags &
309 RESM_NTPONLY) ==
310 (rl->mflags &
311 RESM_NTPONLY))
312 break;
314 if (!(mflags &
315 RESM_NTPONLY)) {
316 rl = 0;
317 break;
319 } else if (rl->mask > mask) {
320 rl = 0;
321 break;
324 rlprev = rl;
325 rl = rl->next;
330 if (IS_IPV6(resaddr)) {
331 mask6 = SOCK_ADDR6(resmask);
332 SET_IPV6_ADDR_MASK(&addr6,
333 PSOCK_ADDR6(resaddr), &mask6);
334 if (IN6_IS_ADDR_UNSPECIFIED(&addr6)) {
335 rlprev6 = NULL;
336 rl6 = restrictlist6;
337 } else {
338 rlprev6 = restrictlist6;
339 rl6 = rlprev6->next;
340 while (rl6 != 0) {
341 addr_cmp = memcmp(&rl6->addr6, &addr6,
342 sizeof(addr6));
343 if (addr_cmp > 0) {
344 rl6 = 0;
345 break;
347 } else if (addr_cmp == 0) {
348 mask_cmp = memcmp(&rl6->mask6,
349 &mask6, sizeof(mask6));
350 if (mask_cmp == 0) {
351 if ((mflags &
352 RESM_NTPONLY) ==
353 (rl6->mflags &
354 RESM_NTPONLY))
355 break;
357 if (!(mflags &
358 RESM_NTPONLY)) {
359 rl6 = 0;
360 break;
362 } else if (mask_cmp > 0) {
363 rl6 = 0;
364 break;
367 rlprev6 = rl6;
368 rl6 = rl6->next;
374 * In case the above wasn't clear :-), either rl now points
375 * at the entry this call refers to, or rl is zero and rlprev
376 * points to the entry prior to where this one should go in
377 * the sort.
380 * Switch based on operation
382 if (IS_IPV4(resaddr)) {
383 switch (op) {
384 case RESTRICT_FLAGS:
387 * Here we add bits to the flags. If this is a
388 * new restriction add it.
390 if (rl == 0) {
391 if (numresfree == 0) {
392 rl = (struct restrictlist *)
393 emalloc(INCRESLIST *
394 sizeof(struct
395 restrictlist));
396 memset((char *)rl, 0,
397 INCRESLIST * sizeof(struct
398 restrictlist));
399 for (i = 0; i < INCRESLIST;
400 i++) {
401 rl->next = resfree;
402 resfree = rl;
403 rl++;
405 numresfree = INCRESLIST;
407 rl = resfree;
408 resfree = rl->next;
409 numresfree--;
410 rl->addr = addr;
411 rl->mask = mask;
412 rl->mflags = (u_short)mflags;
413 if (rlprev == NULL) {
414 rl->next = restrictlist;
415 restrictlist = rl;
416 } else {
417 rl->next = rlprev->next;
418 rlprev->next = rl;
420 restrictcount++;
422 if ((rl->flags ^ (u_short)flags) &
423 RES_LIMITED) {
424 res_limited_refcnt++;
425 mon_start(MON_RES);
427 rl->flags |= (u_short)flags;
428 break;
430 case RESTRICT_UNFLAG:
433 * Remove some bits from the flags. If we didn't
434 * find this one, just return.
436 if (rl != 0) {
437 if ((rl->flags ^ (u_short)flags) &
438 RES_LIMITED) {
439 res_limited_refcnt--;
440 if (res_limited_refcnt == 0)
441 mon_stop(MON_RES);
443 rl->flags &= (u_short)~flags;
445 break;
447 case RESTRICT_REMOVE:
448 case RESTRICT_REMOVEIF:
451 * Remove an entry from the table entirely if we
452 * found one. Don't remove the default entry and
453 * don't remove an interface entry.
455 if (rl != 0
456 && rl->addr != htonl(INADDR_ANY)
457 && !(rl->mflags & RESM_INTERFACE && op !=
458 RESTRICT_REMOVEIF)) {
459 if (rlprev != NULL) {
460 rlprev->next = rl->next;
461 } else {
462 restrictlist = rl->next;
464 restrictcount--;
465 if (rl->flags & RES_LIMITED) {
466 res_limited_refcnt--;
467 if (res_limited_refcnt == 0)
468 mon_stop(MON_RES);
470 memset((char *)rl, 0,
471 sizeof(struct restrictlist));
473 rl->next = resfree;
474 resfree = rl;
475 numresfree++;
477 break;
479 default:
480 break;
482 } else if (IS_IPV6(resaddr)) {
483 switch (op) {
484 case RESTRICT_FLAGS:
487 * Here we add bits to the flags. If this is a
488 * new restriction add it.
490 if (rl6 == 0) {
491 if (numresfree6 == 0) {
492 rl6 = (struct
493 restrictlist6 *)emalloc(
494 INCRESLIST * sizeof(struct
495 restrictlist6));
496 memset((char *)rl6, 0,
497 INCRESLIST * sizeof(struct
498 restrictlist6));
500 for (i = 0; i < INCRESLIST;
501 i++) {
502 rl6->next = resfree6;
503 resfree6 = rl6;
504 rl6++;
506 numresfree6 = INCRESLIST;
508 rl6 = resfree6;
509 resfree6 = rl6->next;
510 numresfree6--;
511 rl6->addr6 = addr6;
512 rl6->mask6 = mask6;
513 rl6->mflags = (u_short)mflags;
514 if (rlprev6 != NULL) {
515 rl6->next = rlprev6->next;
516 rlprev6->next = rl6;
517 } else {
518 rl6->next = restrictlist6;
519 restrictlist6 = rl6;
521 restrictcount6++;
523 if ((rl6->flags ^ (u_short)flags) &
524 RES_LIMITED) {
525 res_limited_refcnt6++;
526 mon_start(MON_RES);
528 rl6->flags |= (u_short)flags;
529 break;
531 case RESTRICT_UNFLAG:
534 * Remove some bits from the flags. If we didn't
535 * find this one, just return.
537 if (rl6 != 0) {
538 if ((rl6->flags ^ (u_short)flags) &
539 RES_LIMITED) {
540 res_limited_refcnt6--;
541 if (res_limited_refcnt6 == 0)
542 mon_stop(MON_RES);
544 rl6->flags &= (u_short)~flags;
546 break;
548 case RESTRICT_REMOVE:
549 case RESTRICT_REMOVEIF:
552 * Remove an entry from the table entirely if we
553 * found one. Don't remove the default entry and
554 * don't remove an interface entry.
556 if (rl6 != 0 &&
557 !IN6_IS_ADDR_UNSPECIFIED(&rl6->addr6)
558 && !(rl6->mflags & RESM_INTERFACE && op !=
559 RESTRICT_REMOVEIF)) {
560 if (rlprev6 != NULL) {
561 rlprev6->next = rl6->next;
562 } else {
563 restrictlist6 = rl6->next;
565 restrictcount6--;
566 if (rl6->flags & RES_LIMITED) {
567 res_limited_refcnt6--;
568 if (res_limited_refcnt6 == 0)
569 mon_stop(MON_RES);
571 memset((char *)rl6, 0,
572 sizeof(struct restrictlist6));
573 rl6->next = resfree6;
574 resfree6 = rl6;
575 numresfree6++;
577 break;
579 default:
580 break;