xref: /netbsd/external/bsd/ntp/dist/ntpd/ntp_restrict.c (revision 6550d01e)
1 /*	$NetBSD: ntp_restrict.c,v 1.1.1.1 2009/12/13 16:55:41 kardel Exp $	*/
2 
3 /*
4  * ntp_restrict.c - determine host restrictions
5  */
6 #ifdef HAVE_CONFIG_H
7 #include <config.h>
8 #endif
9 
10 #include <stdio.h>
11 #include <sys/types.h>
12 
13 #include "ntpd.h"
14 #include "ntp_if.h"
15 #include "ntp_stdlib.h"
16 
17 /*
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.
25  *
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.
33  *
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.
40  */
41 /*
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
45  */
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)
54 
55 /*
56  * Memory allocation parameters.  We allocate INITRESLIST entries
57  * initially, and add INCRESLIST entries to the free list whenever
58  * we run out.
59  */
60 #define	INITRESLIST	10
61 #define	INCRESLIST	5
62 
63 /*
64  * The restriction list
65  */
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*/
70 
71 /*
72  * The free list and associated counters.  Also some uninteresting
73  * stat counters.
74  */
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 */
79 
80 static u_long res_calls;
81 static u_long res_found;
82 static u_long res_not_found;
83 
84 /*
85  * Count number of restriction entries referring to RES_LIMITED controls
86  * activation/deactivation of monitoring (with respect to RES_LIMITED
87  * control)
88  */
89 static	u_long res_limited_refcnt;
90 static	u_long res_limited_refcnt6;
91 
92 /*
93  * Our initial allocation of lists entries.
94  */
95 static	struct restrictlist resinit[INITRESLIST];
96 static	struct restrictlist6 resinit6[INITRESLIST];
97 
98 
99 /*
100  * init_restrict - initialize the restriction data structures
101  */
102 void
103 init_restrict(void)
104 {
105 	register int i;
106 
107 	/*
108 	 * Zero the list and put all but one on the free list
109 	 */
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];
119 	}
120 	numresfree = INITRESLIST-1;
121 	numresfree6 = INITRESLIST-1;
122 
123 	/*
124 	 * Put the remaining item at the head of the list as our default
125 	 * entry. Everything in here should be zero for now.
126 	 */
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;
135 
136 	/*
137 	 * fix up stat counters
138 	 */
139 	res_calls = 0;
140 	res_found = 0;
141 	res_not_found = 0;
142 
143 	/*
144 	 * set default values for RES_LIMIT functionality
145 	 */
146 	res_limited_refcnt = 0;
147 	res_limited_refcnt6 = 0;
148 }
149 
150 
151 /*
152  * restrictions - return restrictions for this host
153  */
154 int
155 restrictions(
156 	sockaddr_u *srcadr
157 	)
158 {
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;
168 
169 	res_calls++;
170 	/* IPv4 source address */
171 	if (IS_IPV4(srcadr)) {
172 
173 		/*
174 		 * We need the host address in host order. Also need to
175 		 * know whether this is from the ntp port or not.
176 		 */
177 		hostaddr = SRCADR(srcadr);
178 		isntpport = (NTP_PORT == SRCPORT(srcadr));
179 
180 		/*
181 		 * Ignore any packets with a multicast source address
182 		 * (this should be done early in the receive process,
183 		 * not later!)
184 		 */
185 		if (IN_CLASSD(SRCADR(srcadr)))
186 			return (int)RES_IGNORE;
187 
188 		/*
189 		 * Set match to first entry, which is default entry.
190 		 * Work our way down from there.
191 		 */
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;
200 			}
201 		match->count++;
202 		if (match == restrictlist)
203 			res_not_found++;
204 		else
205 			res_found++;
206 		flags = match->flags;
207 	}
208 
209 	/* IPv6 source address */
210 	if (IS_IPV6(srcadr)) {
211 
212 		/*
213 		 * We need the host address in network order. Also need
214 		 * to know whether this is from the ntp port or not.
215 		 */
216 		hostaddr6 = SOCK_ADDR6(srcadr);
217 		isntpport = (NTP_PORT == SRCPORT(srcadr));
218 
219 		/*
220 		 * Ignore any packets with a multicast source address
221 		 * (this should be done early in the receive process,
222 		 * not later!)
223 		 */
224 		if (IN6_IS_ADDR_MULTICAST(&hostaddr6))
225 			return (int)RES_IGNORE;
226 
227 		/*
228 		 * Set match to first entry, which is default entry.
229 		 *  Work our way down from there.
230 		 */
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;
243 			}
244 		}
245 		match6->count++;
246 		if (match6 == restrictlist6)
247 			res_not_found++;
248 		else
249 			res_found++;
250 		flags = match6->flags;
251 	}
252 	return (flags);
253 }
254 
255 
256 /*
257  * hack_restrict - add/subtract/manipulate entries on the restrict list
258  */
259 void
260 hack_restrict(
261 	int op,
262 	sockaddr_u *resaddr,
263 	sockaddr_u *resmask,
264 	int mflags,
265 	int flags
266 	)
267 {
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));
279 
280 	if (IS_IPV4(resaddr)) {
281 
282 		DPRINTF(1, ("restrict: addr %08x mask %08x mflags %08x flags %08x\n",
283 			    SRCADR(resaddr), SRCADR(resmask), mflags, flags));
284 
285 		/*
286 		 * Get address and mask in host byte order
287 		 */
288 		addr = SRCADR(resaddr);
289 		mask = SRCADR(resmask);
290 		addr &= mask;		/* make sure low bits zero */
291 
292 		/*
293 		 * If this is the default address, point at first on
294 		 * list. Else go searching for it.
295 		 */
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;
313 
314 						if (!(mflags &
315 						    RESM_NTPONLY)) {
316 							rl = 0;
317 							break;
318 						}
319 					} else if (rl->mask > mask) {
320 						rl = 0;
321 						break;
322 					}
323 				}
324 				rlprev = rl;
325 				rl = rl->next;
326 			}
327 		}
328 	}
329 
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;
346 
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;
356 
357 						if (!(mflags &
358 						    RESM_NTPONLY)) {
359 							rl6 = 0;
360 							break;
361 						}
362 					} else if (mask_cmp > 0) {
363 						rl6 = 0;
364 						break;
365 					}
366 				}
367 				rlprev6 = rl6;
368 				rl6 = rl6->next;
369 			}
370 		}
371 	}
372 
373 	/*
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.
378 	 */
379 	/*
380 	 * Switch based on operation
381 	 */
382 	if (IS_IPV4(resaddr)) {
383 		switch (op) {
384 		case RESTRICT_FLAGS:
385 
386 			/*
387 			 * Here we add bits to the flags. If this is a
388 			 * new restriction add it.
389 			 */
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++;
404 					}
405 					numresfree = INCRESLIST;
406 				}
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;
419 				}
420 				restrictcount++;
421 			}
422 			if ((rl->flags ^ (u_short)flags) &
423 			    RES_LIMITED) {
424 				res_limited_refcnt++;
425 				mon_start(MON_RES);
426 			}
427 			rl->flags |= (u_short)flags;
428 			break;
429 
430 		case RESTRICT_UNFLAG:
431 
432 			/*
433 			 * Remove some bits from the flags. If we didn't
434 			 * find this one, just return.
435 			 */
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);
442 				}
443 				rl->flags &= (u_short)~flags;
444 			}
445 			break;
446 
447 		case RESTRICT_REMOVE:
448 		case RESTRICT_REMOVEIF:
449 
450 			/*
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.
454 			 */
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;
463 				}
464 				restrictcount--;
465 				if (rl->flags & RES_LIMITED) {
466 					res_limited_refcnt--;
467 					if (res_limited_refcnt == 0)
468 						mon_stop(MON_RES);
469 				}
470 				memset((char *)rl, 0,
471 				    sizeof(struct restrictlist));
472 
473 				rl->next = resfree;
474 				resfree = rl;
475 				numresfree++;
476 			}
477 			break;
478 
479 		default:
480 			break;
481 		}
482 	} else if (IS_IPV6(resaddr)) {
483 		switch (op) {
484 		case RESTRICT_FLAGS:
485 
486 			/*
487 			 * Here we add bits to the flags. If this is a
488 			 * new restriction add it.
489 			 */
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));
499 
500 					for (i = 0; i < INCRESLIST;
501 					    i++) {
502 						rl6->next = resfree6;
503 						resfree6 = rl6;
504 						rl6++;
505 					}
506 					numresfree6 = INCRESLIST;
507 				}
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;
520 				}
521 				restrictcount6++;
522 			}
523 			if ((rl6->flags ^ (u_short)flags) &
524 			    RES_LIMITED) {
525 				res_limited_refcnt6++;
526 				mon_start(MON_RES);
527 			}
528 			rl6->flags |= (u_short)flags;
529 			break;
530 
531 		case RESTRICT_UNFLAG:
532 
533 			/*
534 			 * Remove some bits from the flags. If we didn't
535 			 * find this one, just return.
536 			 */
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);
543 				}
544 				rl6->flags &= (u_short)~flags;
545 			}
546 			break;
547 
548 		case RESTRICT_REMOVE:
549 		case RESTRICT_REMOVEIF:
550 
551 			/*
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.
555 			 */
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;
564 				}
565 				restrictcount6--;
566 				if (rl6->flags & RES_LIMITED) {
567 					res_limited_refcnt6--;
568 					if (res_limited_refcnt6 == 0)
569 						mon_stop(MON_RES);
570 				}
571 				memset((char *)rl6, 0,
572 				    sizeof(struct restrictlist6));
573 				rl6->next = resfree6;
574 				resfree6 = rl6;
575 				numresfree6++;
576 			}
577 			break;
578 
579 		default:
580 			break;
581 		}
582 	}
583 }
584