xref: /freebsd/contrib/ntp/ntpd/ntp_restrict.c (revision 9336e0699bda8a301cd2bfa37106b6ec5e32012e)
1 /*
2  * ntp_restrict.c - determine host restrictions
3  */
4 #ifdef HAVE_CONFIG_H
5 #include <config.h>
6 #endif
7 
8 #include <stdio.h>
9 #include <sys/types.h>
10 
11 #include "ntpd.h"
12 #include "ntp_if.h"
13 #include "ntp_stdlib.h"
14 
15 /*
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
22  * the address.
23  *
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.
31  *
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.
38  */
39 /*
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
43  */
44 #define SET_IPV6_ADDR_MASK(dst, src, msk) \
45 	do { \
46 		int idx; \
47 		for (idx = 0; idx < 16; idx++) { \
48 			(dst)->s6_addr[idx] = \
49 			    (u_char) ((src)->s6_addr[idx] & (msk)->s6_addr[idx]); \
50 		} \
51 	} while (0)
52 
53 /*
54  * Memory allocation parameters.  We allocate INITRESLIST entries
55  * initially, and add INCRESLIST entries to the free list whenever
56  * we run out.
57  */
58 #define	INITRESLIST	10
59 #define	INCRESLIST	5
60 
61 #define RES_AVG		8.	/* interpacket averaging factor */
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 structures on free list */
78 static	int numresfree6;	/* number of structures 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  * Parameters of the RES_LIMITED restriction option.
86  */
87 u_long res_avg_interval = 5;	/* min average interpacket interval */
88 u_long res_min_interval = 1;	/* min interpacket interval */
89 
90 /*
91  * Count number of restriction entries referring to RES_LIMITED controls
92  * activation/deactivation of monitoring (with respect to RES_LIMITED
93  * control)
94  */
95 static	u_long res_limited_refcnt;
96 static	u_long res_limited_refcnt6;
97 
98 /*
99  * Our initial allocation of lists entries.
100  */
101 static	struct restrictlist resinit[INITRESLIST];
102 static	struct restrictlist6 resinit6[INITRESLIST];
103 
104 /*
105  * init_restrict - initialize the restriction data structures
106  */
107 void
108 init_restrict(void)
109 {
110 	register int i;
111 
112 	/*
113 	 * Zero the list and put all but one on the free list
114 	 */
115 	resfree = 0;
116 	memset((char *)resinit, 0, sizeof resinit);
117 	resfree6 = 0;
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];
124 	}
125 	numresfree = INITRESLIST-1;
126 	numresfree6 = INITRESLIST-1;
127 
128 	/*
129 	 * Put the remaining item at the head of the list as our default
130 	 * entry. Everything in here should be zero for now.
131 	 */
132 	resinit[0].addr = htonl(INADDR_ANY);
133 	resinit[0].mask = 0;
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];
138 	restrictcount = 1;
139 	restrictcount = 2;
140 
141 	/*
142 	 * fix up stat counters
143 	 */
144 	res_calls = 0;
145 	res_found = 0;
146 	res_not_found = 0;
147 
148 	/*
149 	 * set default values for RES_LIMIT functionality
150 	 */
151 	res_limited_refcnt = 0;
152 	res_limited_refcnt6 = 0;
153 }
154 
155 
156 /*
157  * restrictions - return restrictions for this host
158  */
159 int
160 restrictions(
161 	struct sockaddr_storage *srcadr
162 	)
163 {
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;
170 	u_int32	hostaddr;
171 	int	flags = 0;
172 	int	isntpport;
173 
174 	res_calls++;
175 	if (srcadr->ss_family == AF_INET) {
176 		/*
177 		 * We need the host address in host order.  Also need to
178 		 * know whether this is from the ntp port or not.
179 		 */
180 		hostaddr = SRCADR(srcadr);
181 		isntpport = (SRCPORT(srcadr) == NTP_PORT);
182 
183 		/*
184 		 * Ignore any packets with a multicast source address
185 		 * (this should be done early in the receive process,
186 		 * later!)
187 		 */
188 		if (IN_CLASSD(SRCADR(srcadr)))
189 			return (int)RES_IGNORE;
190 
191 		/*
192 		 * Set match to first entry, which is default entry.
193 		 * Work our way down from there.
194 		 */
195 		match = restrictlist;
196 		for (rl = match->next; rl != 0 && rl->addr <= hostaddr;
197 		    rl = rl->next)
198 			if ((hostaddr & rl->mask) == rl->addr) {
199 				if ((rl->mflags & RESM_NTPONLY) &&
200 				    !isntpport)
201 					continue;
202 				match = rl;
203 			}
204 		match->count++;
205 		if (match == restrictlist)
206 			res_not_found++;
207 		else
208 			res_found++;
209 		flags = match->flags;
210 	}
211 
212 	/* IPv6 source address */
213 	if (srcadr->ss_family == AF_INET6) {
214 		/*
215 		 * Need to know whether this is from the ntp port or
216 		 * not.
217 		 */
218 		hostaddr6 = GET_INADDR6(*srcadr);
219 		isntpport = (ntohs((
220 		    (struct sockaddr_in6 *)srcadr)->sin6_port) ==
221 		    NTP_PORT);
222 
223 		/*
224 		 * Ignore any packets with a multicast source address
225 		 * (this should be done early in the receive process,
226 		 * later!)
227 		 */
228 		if (IN6_IS_ADDR_MULTICAST(&hostaddr6))
229 			return (int)RES_IGNORE;
230 
231 		/*
232 		 * Set match to first entry, which is default entry.
233 		 *  Work our way down from there.
234 		 */
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,
240 			    &rl6->mask6);
241 			if (memcmp(&hostservaddr6, &(rl6->addr6),
242 			    sizeof(hostservaddr6)) == 0) {
243 				if ((rl6->mflags & RESM_NTPONLY) &&
244 				    !isntpport)
245 					continue;
246 				match6 = rl6;
247 			}
248 		}
249 		match6->count++;
250 		if (match6 == restrictlist6)
251 			res_not_found++;
252 		else
253 			res_found++;
254 		flags = match6->flags;
255 	}
256 
257 	/*
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.
262 	 */
263 	if (mon_enabled == MON_OFF) {
264 		flags &= ~RES_LIMITED;
265 	} else {
266 		struct mon_data *md;
267 
268 		/*
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.
272 		 */
273 		md = mon_mru_list.mru_next;
274 		if (md->avg_interval == 0)
275 			md->avg_interval = md->drop_count;
276 		else
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 >
281 		    res_avg_interval))
282 			flags &= ~RES_LIMITED;
283 		md->drop_count = flags;
284 	}
285 	return (flags);
286 }
287 
288 
289 /*
290  * hack_restrict - add/subtract/manipulate entries on the restrict list
291  */
292 void
293 hack_restrict(
294 	int op,
295 	struct sockaddr_storage *resaddr,
296 	struct sockaddr_storage *resmask,
297 	int mflags,
298 	int flags
299 	)
300 {
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));
312 
313 	if (resaddr->ss_family == AF_INET) {
314 		/*
315 		 * Get address and mask in host byte order
316 		 */
317 		addr = SRCADR(resaddr);
318 		mask = SRCADR(resmask);
319 		addr &= mask;		/* make sure low bits zero */
320 
321 		/*
322 		 * If this is the default address, point at first on
323 		 * list. Else go searching for it.
324 		 */
325 		if (addr == 0) {
326 			rlprev = 0;
327 			rl = restrictlist;
328 		} else {
329 			rlprev = restrictlist;
330 			rl = rlprev->next;
331 			while (rl != 0) {
332 				if (rl->addr > addr) {
333 					rl = 0;
334 					break;
335 				} else if (rl->addr == addr) {
336 					if (rl->mask == mask) {
337 						if ((mflags &
338 						    RESM_NTPONLY) ==
339 						    (rl->mflags &
340 						    RESM_NTPONLY))
341 							break;
342 
343 						if (!(mflags &
344 						    RESM_NTPONLY)) {
345 							rl = 0;
346 							break;
347 						}
348 					} else if (rl->mask > mask) {
349 						rl = 0;
350 						break;
351 					}
352 				}
353 				rlprev = rl;
354 				rl = rl->next;
355 			}
356 		}
357 	}
358 
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)) {
364 			rlprev6 = 0;
365 			rl6 = restrictlist6;
366 		} else {
367 			rlprev6 = restrictlist6;
368 			rl6 = rlprev6->next;
369 			while (rl6 != 0) {
370 				addr_cmp = memcmp(&rl6->addr6, &addr6,
371 				    sizeof(addr6));
372 				if (addr_cmp > 0) {
373 					rl6 = 0;
374 					break;
375 				} else if (addr_cmp == 0) {
376 					mask_cmp = memcmp(&rl6->mask6,
377 					    &mask6, sizeof(mask6));
378 					if (mask_cmp == 0) {
379 						if ((mflags &
380 						    RESM_NTPONLY) ==
381 						    (rl6->mflags &
382 						    RESM_NTPONLY))
383 							break;
384 
385 						if (!(mflags &
386 						    RESM_NTPONLY)) {
387 							rl6 = 0;
388 							break;
389 						}
390 					} else if (mask_cmp > 0) {
391 						rl6 = 0;
392 						break;
393 					}
394 				}
395 				rlprev6 = rl6;
396 				rl6 = rl6->next;
397 			}
398 		}
399 	}
400 
401 	/*
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
405 	 * the sort.
406 	 */
407 
408 	/*
409 	 * Switch based on operation
410 	 */
411 	if (resaddr->ss_family == AF_INET) {
412 		switch (op) {
413 		case RESTRICT_FLAGS:
414 			/*
415 			 * Here we add bits to the flags. If this is a
416 			 * new restriction add it.
417 			 */
418 			if (rl == 0) {
419 				if (numresfree == 0) {
420 					rl = (struct restrictlist *)
421 					    emalloc(INCRESLIST *
422 					    sizeof(struct
423 					    restrictlist));
424 					memset((char *)rl, 0,
425 					    INCRESLIST * sizeof(struct
426 					    restrictlist));
427 					for (i = 0; i < INCRESLIST; i++) {
428 						rl->next = resfree;
429 						resfree = rl;
430 						rl++;
431 					}
432 					numresfree = INCRESLIST;
433 				}
434 
435 				rl = resfree;
436 				resfree = rl->next;
437 				numresfree--;
438 
439 				rl->addr = addr;
440 				rl->mask = mask;
441 				rl->mflags = (u_short)mflags;
442 
443 				rl->next = rlprev->next;
444 				rlprev->next = rl;
445 				restrictcount++;
446 			}
447 			if ((rl->flags ^ (u_short)flags) &
448 			    RES_LIMITED) {
449 				res_limited_refcnt++;
450 				mon_start(MON_RES);
451 			}
452 			rl->flags |= (u_short)flags;
453 			break;
454 
455 		case RESTRICT_UNFLAG:
456 			/*
457 			 * Remove some bits from the flags. If we didn't
458 			 * find this one, just return.
459 			 */
460 			if (rl != 0) {
461 				if ((rl->flags ^ (u_short)flags) &
462 				    RES_LIMITED) {
463 					res_limited_refcnt--;
464 					if (res_limited_refcnt == 0)
465 						mon_stop(MON_RES);
466 				}
467 				rl->flags &= (u_short)~flags;
468 			}
469 			break;
470 
471 		case RESTRICT_REMOVE:
472 			/*
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.
476 			 */
477 			if (rl != 0
478 			    && rl->addr != htonl(INADDR_ANY)
479 			    && !(rl->mflags & RESM_INTERFACE)) {
480 				rlprev->next = rl->next;
481 				restrictcount--;
482 				if (rl->flags & RES_LIMITED) {
483 					res_limited_refcnt--;
484 					if (res_limited_refcnt == 0)
485 						mon_stop(MON_RES);
486 				}
487 				memset((char *)rl, 0,
488 				    sizeof(struct restrictlist));
489 
490 				rl->next = resfree;
491 				resfree = rl;
492 				numresfree++;
493 			}
494 			break;
495 
496 		default:
497 			break;
498 		}
499 	} else if (resaddr->ss_family == AF_INET6) {
500 		switch (op) {
501 		case RESTRICT_FLAGS:
502 			/*
503 			 * Here we add bits to the flags. If this is a
504 			 * new restriction add it.
505 			 */
506 			if (rl6 == 0) {
507 				if (numresfree6 == 0) {
508 					rl6 = (struct
509 					    restrictlist6 *)emalloc(
510 					    INCRESLIST * sizeof(struct
511 					    restrictlist6));
512 					memset((char *)rl6, 0,
513 					    INCRESLIST * sizeof(struct
514 					    restrictlist6));
515 
516 					for (i = 0; i < INCRESLIST;
517 					    i++) {
518 						rl6->next = resfree6;
519 						resfree6 = rl6;
520 						rl6++;
521 					}
522 					numresfree6 = INCRESLIST;
523 				}
524 				rl6 = resfree6;
525 				resfree6 = rl6->next;
526 				numresfree6--;
527 				rl6->addr6 = addr6;
528 				rl6->mask6 = mask6;
529 				rl6->mflags = (u_short)mflags;
530 				rl6->next = rlprev6->next;
531 				rlprev6->next = rl6;
532 				restrictcount6++;
533 			}
534 			if ((rl6->flags ^ (u_short)flags) &
535 			    RES_LIMITED) {
536 				res_limited_refcnt6++;
537 				mon_start(MON_RES);
538 			}
539 			rl6->flags |= (u_short)flags;
540 			break;
541 
542 		case RESTRICT_UNFLAG:
543 			/*
544 			 * Remove some bits from the flags. If we didn't
545 			 * find this one, just return.
546 			 */
547 			if (rl6 != 0) {
548 				if ((rl6->flags ^ (u_short)flags) &
549 				    RES_LIMITED) {
550 					res_limited_refcnt6--;
551 					if (res_limited_refcnt6 == 0)
552 						mon_stop(MON_RES);
553 				}
554 				rl6->flags &= (u_short)~flags;
555 			}
556 			break;
557 
558 		case RESTRICT_REMOVE:
559 			/*
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.
563 			 */
564 			if (rl6 != 0 &&
565 			    !IN6_IS_ADDR_UNSPECIFIED(&rl6->addr6)
566 			    && !(rl6->mflags & RESM_INTERFACE)) {
567 				rlprev6->next = rl6->next;
568 				restrictcount6--;
569 				if (rl6->flags & RES_LIMITED) {
570 					res_limited_refcnt6--;
571 					if (res_limited_refcnt6 == 0)
572 						mon_stop(MON_RES);
573 				}
574 				memset((char *)rl6, 0,
575 				    sizeof(struct restrictlist6));
576 				rl6->next = resfree6;
577 				resfree6 = rl6;
578 				numresfree6++;
579 			}
580 			break;
581 
582 		default:
583 			break;
584 		}
585 	}
586 }
587