ntp_restrict.c revision 132451
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 */
66struct restrictlist *restrictlist;
67struct restrictlist6 *restrictlist6;
68static	int restrictcount;	/* count of entries in the res list */
69static	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 */
75static	struct restrictlist *resfree;
76static	struct restrictlist6 *resfree6;
77static	int numresfree;		/* number of structures on free list */
78static	int numresfree6;	/* number of structures on free list 2 */
79
80static	u_long res_calls;
81static	u_long res_found;
82static	u_long res_not_found;
83
84/*
85 * Parameters of the RES_LIMITED restriction option.
86 */
87u_long res_avg_interval = 5;	/* min average interpacket interval */
88u_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 */
95static	u_long res_limited_refcnt;
96static	u_long res_limited_refcnt6;
97
98/*
99 * Our initial allocation of lists entries.
100 */
101static	struct restrictlist resinit[INITRESLIST];
102static	struct restrictlist6 resinit6[INITRESLIST];
103
104/*
105 * init_restrict - initialize the restriction data structures
106 */
107void
108init_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 */
159int
160restrictions(
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 */
292void
293hack_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