4 * ntp_restrict.c - determine host restrictions
11 #include <sys/types.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
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) \
49 for (idx = 0; idx < 16; idx++) { \
50 (dst)->s6_addr[idx] = \
51 (u_char) ((src)->s6_addr[idx] & (msk)->s6_addr[idx]); \
56 * Memory allocation parameters. We allocate INITRESLIST entries
57 * initially, and add INCRESLIST entries to the free list whenever
60 #define INITRESLIST 10
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 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
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
108 * Zero the list and put all but one on the free list
111 memset((char *)resinit
, 0, sizeof resinit
);
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
);
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];
137 * fix up stat counters
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
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
;
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,
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
;
195 if ((hostaddr
& rl
->mask
) == rl
->addr
) {
196 if ((rl
->mflags
& RESM_NTPONLY
) &&
202 if (match
== restrictlist
)
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,
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
,
237 if (memcmp(&hostservaddr6
, &(rl6
->addr6
),
238 sizeof(hostservaddr6
)) == 0) {
239 if ((rl6
->mflags
& RESM_NTPONLY
) &&
246 if (match6
== restrictlist6
)
250 flags
= match6
->flags
;
257 * hack_restrict - add/subtract/manipulate entries on the restrict list
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.
300 rlprev
= restrictlist
;
303 if (rl
->addr
> addr
) {
306 } else if (rl
->addr
== addr
) {
307 if (rl
->mask
== mask
) {
319 } else if (rl
->mask
> mask
) {
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
)) {
338 rlprev6
= restrictlist6
;
341 addr_cmp
= memcmp(&rl6
->addr6
, &addr6
,
347 } else if (addr_cmp
== 0) {
348 mask_cmp
= memcmp(&rl6
->mask6
,
349 &mask6
, sizeof(mask6
));
362 } else if (mask_cmp
> 0) {
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
380 * Switch based on operation
382 if (IS_IPV4(resaddr
)) {
387 * Here we add bits to the flags. If this is a
388 * new restriction add it.
391 if (numresfree
== 0) {
392 rl
= (struct restrictlist
*)
396 memset((char *)rl
, 0,
397 INCRESLIST
* sizeof(struct
399 for (i
= 0; i
< INCRESLIST
;
405 numresfree
= INCRESLIST
;
412 rl
->mflags
= (u_short
)mflags
;
413 if (rlprev
== NULL
) {
414 rl
->next
= restrictlist
;
417 rl
->next
= rlprev
->next
;
422 if ((rl
->flags
^ (u_short
)flags
) &
424 res_limited_refcnt
++;
427 rl
->flags
|= (u_short
)flags
;
430 case RESTRICT_UNFLAG
:
433 * Remove some bits from the flags. If we didn't
434 * find this one, just return.
437 if ((rl
->flags
^ (u_short
)flags
) &
439 res_limited_refcnt
--;
440 if (res_limited_refcnt
== 0)
443 rl
->flags
&= (u_short
)~flags
;
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.
456 && rl
->addr
!= htonl(INADDR_ANY
)
457 && !(rl
->mflags
& RESM_INTERFACE
&& op
!=
458 RESTRICT_REMOVEIF
)) {
459 if (rlprev
!= NULL
) {
460 rlprev
->next
= rl
->next
;
462 restrictlist
= rl
->next
;
465 if (rl
->flags
& RES_LIMITED
) {
466 res_limited_refcnt
--;
467 if (res_limited_refcnt
== 0)
470 memset((char *)rl
, 0,
471 sizeof(struct restrictlist
));
482 } else if (IS_IPV6(resaddr
)) {
487 * Here we add bits to the flags. If this is a
488 * new restriction add it.
491 if (numresfree6
== 0) {
493 restrictlist6
*)emalloc(
494 INCRESLIST
* sizeof(struct
496 memset((char *)rl6
, 0,
497 INCRESLIST
* sizeof(struct
500 for (i
= 0; i
< INCRESLIST
;
502 rl6
->next
= resfree6
;
506 numresfree6
= INCRESLIST
;
509 resfree6
= rl6
->next
;
513 rl6
->mflags
= (u_short
)mflags
;
514 if (rlprev6
!= NULL
) {
515 rl6
->next
= rlprev6
->next
;
518 rl6
->next
= restrictlist6
;
523 if ((rl6
->flags
^ (u_short
)flags
) &
525 res_limited_refcnt6
++;
528 rl6
->flags
|= (u_short
)flags
;
531 case RESTRICT_UNFLAG
:
534 * Remove some bits from the flags. If we didn't
535 * find this one, just return.
538 if ((rl6
->flags
^ (u_short
)flags
) &
540 res_limited_refcnt6
--;
541 if (res_limited_refcnt6
== 0)
544 rl6
->flags
&= (u_short
)~flags
;
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.
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
;
563 restrictlist6
= rl6
->next
;
566 if (rl6
->flags
& RES_LIMITED
) {
567 res_limited_refcnt6
--;
568 if (res_limited_refcnt6
== 0)
571 memset((char *)rl6
, 0,
572 sizeof(struct restrictlist6
));
573 rl6
->next
= resfree6
;