ntp_restrict.c revision 267654
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 = NULL;
116	memset((char *)resinit, 0, sizeof resinit);
117	resfree6 = NULL;
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	int at_listhead
163	)
164{
165	struct restrictlist *rl;
166	struct restrictlist *match = NULL;
167	struct restrictlist6 *rl6;
168	struct restrictlist6 *match6 = NULL;
169	struct in6_addr hostaddr6;
170	struct in6_addr hostservaddr6;
171	u_int32	hostaddr;
172	int	flags = 0;
173	int	isntpport;
174
175	res_calls++;
176	if (srcadr->ss_family == AF_INET) {
177		/*
178		 * We need the host address in host order.  Also need to
179		 * know whether this is from the ntp port or not.
180		 */
181		hostaddr = SRCADR(srcadr);
182		isntpport = (SRCPORT(srcadr) == NTP_PORT);
183
184		/*
185		 * Ignore any packets with a multicast source address
186		 * (this should be done early in the receive process,
187		 * later!)
188		 */
189		if (IN_CLASSD(SRCADR(srcadr)))
190			return (int)RES_IGNORE;
191
192		/*
193		 * Set match to first entry, which is default entry.
194		 * Work our way down from there.
195		 */
196		match = restrictlist;
197		for (rl = match->next; rl != NULL && rl->addr <= hostaddr;
198		    rl = rl->next)
199			if ((hostaddr & rl->mask) == rl->addr) {
200				if ((rl->mflags & RESM_NTPONLY) &&
201				    !isntpport)
202					continue;
203				match = rl;
204			}
205		match->count++;
206		if (match == restrictlist)
207			res_not_found++;
208		else
209			res_found++;
210		flags = match->flags;
211	}
212
213	/* IPv6 source address */
214	if (srcadr->ss_family == AF_INET6) {
215		/*
216		 * Need to know whether this is from the ntp port or
217		 * not.
218		 */
219		hostaddr6 = GET_INADDR6(*srcadr);
220		isntpport = (ntohs((
221		    (struct sockaddr_in6 *)srcadr)->sin6_port) ==
222		    NTP_PORT);
223
224		/*
225		 * Ignore any packets with a multicast source address
226		 * (this should be done early in the receive process,
227		 * later!)
228		 */
229		if (IN6_IS_ADDR_MULTICAST(&hostaddr6))
230			return (int)RES_IGNORE;
231
232		/*
233		 * Set match to first entry, which is default entry.
234		 *  Work our way down from there.
235		 */
236		match6 = restrictlist6;
237		for (rl6 = match6->next; rl6 != NULL &&
238		    (memcmp(&(rl6->addr6), &hostaddr6,
239		    sizeof(hostaddr6)) <= 0); rl6 = rl6->next) {
240			SET_IPV6_ADDR_MASK(&hostservaddr6, &hostaddr6,
241			    &rl6->mask6);
242			if (memcmp(&hostservaddr6, &(rl6->addr6),
243			    sizeof(hostservaddr6)) == 0) {
244				if ((rl6->mflags & RESM_NTPONLY) &&
245				    !isntpport)
246					continue;
247				match6 = rl6;
248			}
249		}
250		match6->count++;
251		if (match6 == restrictlist6)
252			res_not_found++;
253		else
254			res_found++;
255		flags = match6->flags;
256	}
257
258	/*
259	 * The following implements a generalized call gap facility.
260	 * Douse the RES_LIMITED bit only if the interval since the last
261	 * packet is greater than res_min_interval and the average is
262	 * greater thatn res_avg_interval.
263	 */
264	if (!at_listhead || mon_enabled == MON_OFF) {
265		flags &= ~RES_LIMITED;
266	} else {
267		struct mon_data *md;
268
269		/*
270		 * At this poin the most recent arrival is first in the
271		 * MRU list. Let the first 10 packets in for free until
272		 * the average stabilizes.
273		 */
274		md = mon_mru_list.mru_next;
275		if (md->avg_interval == 0)
276			md->avg_interval = md->drop_count;
277		else
278			md->avg_interval += (md->drop_count -
279			    md->avg_interval) / RES_AVG;
280		if (md->count < 10 || (md->drop_count >
281		    res_min_interval && md->avg_interval >
282		    res_avg_interval))
283			flags &= ~RES_LIMITED;
284		md->drop_count = flags;
285	}
286	return (flags);
287}
288
289
290/*
291 * hack_restrict - add/subtract/manipulate entries on the restrict list
292 */
293void
294hack_restrict(
295	int op,
296	struct sockaddr_storage *resaddr,
297	struct sockaddr_storage *resmask,
298	int mflags,
299	int flags
300	)
301{
302	register u_int32 addr = 0;
303	register u_int32 mask = 0;
304	struct in6_addr addr6;
305	struct in6_addr mask6;
306	register struct restrictlist *rl = NULL;
307	register struct restrictlist *rlprev = NULL;
308	register struct restrictlist6 *rl6 = NULL;
309	register struct restrictlist6 *rlprev6 = NULL;
310	int i, addr_cmp, mask_cmp;
311	memset(&addr6, 0, sizeof(struct in6_addr));
312	memset(&mask6, 0, sizeof(struct in6_addr));
313
314	if (resaddr->ss_family == AF_INET) {
315		/*
316		 * Get address and mask in host byte order
317		 */
318		addr = SRCADR(resaddr);
319		mask = SRCADR(resmask);
320		addr &= mask;		/* make sure low bits zero */
321
322		/*
323		 * If this is the default address, point at first on
324		 * list. Else go searching for it.
325		 */
326		if (addr == 0) {
327			rlprev = NULL;
328			rl = restrictlist;
329		} else {
330			rlprev = restrictlist;
331			rl = rlprev->next;
332			while (rl != NULL) {
333				if (rl->addr > addr) {
334					rl = NULL;
335					break;
336				} else if (rl->addr == addr) {
337					if (rl->mask == mask) {
338						if ((mflags &
339						    RESM_NTPONLY) ==
340						    (rl->mflags &
341						    RESM_NTPONLY))
342							break;
343
344						if (!(mflags &
345						    RESM_NTPONLY)) {
346							rl = NULL;
347							break;
348						}
349					} else if (rl->mask > mask) {
350						rl = NULL;
351						break;
352					}
353				}
354				rlprev = rl;
355				rl = rl->next;
356			}
357		}
358	}
359
360	if (resaddr->ss_family == AF_INET6) {
361		mask6 = GET_INADDR6(*resmask);
362		SET_IPV6_ADDR_MASK(&addr6,
363		    &GET_INADDR6(*resaddr), &mask6);
364		if (IN6_IS_ADDR_UNSPECIFIED(&addr6)) {
365			rlprev6 = NULL;
366			rl6 = restrictlist6;
367		} else {
368			rlprev6 = restrictlist6;
369			rl6 = rlprev6->next;
370			while (rl6 != NULL) {
371				addr_cmp = memcmp(&rl6->addr6, &addr6,
372				    sizeof(addr6));
373				if (addr_cmp > 0) {
374					rl6 = NULL;
375					break;
376				} else if (addr_cmp == 0) {
377					mask_cmp = memcmp(&rl6->mask6,
378					    &mask6, sizeof(mask6));
379					if (mask_cmp == 0) {
380						if ((mflags &
381						    RESM_NTPONLY) ==
382						    (rl6->mflags &
383						    RESM_NTPONLY))
384							break;
385
386						if (!(mflags &
387						    RESM_NTPONLY)) {
388							rl6 = NULL;
389							break;
390						}
391					} else if (mask_cmp > 0) {
392						rl6 = NULL;
393						break;
394					}
395				}
396				rlprev6 = rl6;
397				rl6 = rl6->next;
398			}
399		}
400	}
401
402	/*
403	 * In case the above wasn't clear :-), either rl now points
404	 * at the entry this call refers to, or rl is zero and rlprev
405	 * points to the entry prior to where this one should go in
406	 * the sort.
407	 */
408
409	/*
410	 * Switch based on operation
411	 */
412	if (resaddr->ss_family == AF_INET) {
413		switch (op) {
414		case RESTRICT_FLAGS:
415			/*
416			 * Here we add bits to the flags. If this is a
417			 * new restriction add it.
418			 */
419			if (rl == NULL) {
420				if (resfree == NULL) {
421					rl = (struct restrictlist *)
422					    emalloc(INCRESLIST *
423					    sizeof(struct
424					    restrictlist));
425					memset((char *)rl, 0,
426					    INCRESLIST * sizeof(struct
427					    restrictlist));
428					for (i = 0; i < INCRESLIST; i++) {
429						rl->next = resfree;
430						resfree = rl;
431						rl++;
432					}
433					numresfree = INCRESLIST;
434				}
435
436				rl = resfree;
437				resfree = rl->next;
438				numresfree--;
439
440				rl->addr = addr;
441				rl->mask = mask;
442				rl->mflags = (u_short)mflags;
443
444				if (rlprev == NULL) {
445					rl->next = restrictlist;
446					restrictlist = rl;
447				} else {
448					rl->next = rlprev->next;
449					rlprev->next = rl;
450				}
451				restrictcount++;
452			}
453			if ((rl->flags ^ (u_short)flags) &
454			    RES_LIMITED) {
455				res_limited_refcnt++;
456				mon_start(MON_RES);
457			}
458			rl->flags |= (u_short)flags;
459			break;
460
461		case RESTRICT_UNFLAG:
462			/*
463			 * Remove some bits from the flags. If we didn't
464			 * find this one, just return.
465			 */
466			if (rl != NULL) {
467				if ((rl->flags ^ (u_short)flags) &
468				    RES_LIMITED) {
469					res_limited_refcnt--;
470					if (res_limited_refcnt == 0)
471						mon_stop(MON_RES);
472				}
473				rl->flags &= (u_short)~flags;
474			}
475			break;
476
477		case RESTRICT_REMOVE:
478		case RESTRICT_REMOVEIF:
479			/*
480			 * Remove an entry from the table entirely if we
481			 * found one. Don't remove the default entry and
482			 * don't remove an interface entry.
483			 */
484			if (rl != NULL
485			    && rl->addr != htonl(INADDR_ANY)
486			    && !(rl->mflags & RESM_INTERFACE && op != RESTRICT_REMOVEIF)) {
487				if (rlprev != NULL) {
488					rlprev->next = rl->next;
489				} else {
490					restrictlist = rl->next;
491				}
492				restrictcount--;
493				if (rl->flags & RES_LIMITED) {
494					res_limited_refcnt--;
495					if (res_limited_refcnt == 0)
496						mon_stop(MON_RES);
497				}
498				memset((char *)rl, 0,
499				    sizeof(struct restrictlist));
500
501				rl->next = resfree;
502				resfree = rl;
503				numresfree++;
504			}
505			break;
506
507		default:
508			break;
509		}
510	} else if (resaddr->ss_family == AF_INET6) {
511		switch (op) {
512		case RESTRICT_FLAGS:
513			/*
514			 * Here we add bits to the flags. If this is a
515			 * new restriction add it.
516			 */
517			if (rl6 == NULL) {
518				if (resfree6 == NULL) {
519					rl6 = (struct
520					    restrictlist6 *)emalloc(
521					    INCRESLIST * sizeof(struct
522					    restrictlist6));
523					memset((char *)rl6, 0,
524					    INCRESLIST * sizeof(struct
525					    restrictlist6));
526
527					for (i = 0; i < INCRESLIST;
528					    i++) {
529						rl6->next = resfree6;
530						resfree6 = rl6;
531						rl6++;
532					}
533					numresfree6 = INCRESLIST;
534				}
535				rl6 = resfree6;
536				resfree6 = rl6->next;
537				numresfree6--;
538				rl6->addr6 = addr6;
539				rl6->mask6 = mask6;
540				rl6->mflags = (u_short)mflags;
541				if (rlprev6 != NULL) {
542					rl6->next = rlprev6->next;
543					rlprev6->next = rl6;
544				} else {
545					rl6->next = restrictlist6;
546					restrictlist6 = rl6;
547				}
548				restrictcount6++;
549			}
550			if ((rl6->flags ^ (u_short)flags) &
551			    RES_LIMITED) {
552				res_limited_refcnt6++;
553				mon_start(MON_RES);
554			}
555			rl6->flags |= (u_short)flags;
556			break;
557
558		case RESTRICT_UNFLAG:
559			/*
560			 * Remove some bits from the flags. If we didn't
561			 * find this one, just return.
562			 */
563			if (rl6 != NULL) {
564				if ((rl6->flags ^ (u_short)flags) &
565				    RES_LIMITED) {
566					res_limited_refcnt6--;
567					if (res_limited_refcnt6 == 0)
568						mon_stop(MON_RES);
569				}
570				rl6->flags &= (u_short)~flags;
571			}
572			break;
573
574		case RESTRICT_REMOVE:
575		case RESTRICT_REMOVEIF:
576			/*
577			 * Remove an entry from the table entirely if we
578			 * found one. Don't remove the default entry and
579			 * don't remove an interface entry.
580			 */
581			if (rl6 != NULL &&
582			    !IN6_IS_ADDR_UNSPECIFIED(&rl6->addr6)
583			    && !(rl6->mflags & RESM_INTERFACE && op != RESTRICT_REMOVEIF)) {
584				if (rlprev6 != NULL) {
585					rlprev6->next = rl6->next;
586				} else {
587					restrictlist6 = rl6->next;
588				}
589				restrictcount6--;
590				if (rl6->flags & RES_LIMITED) {
591					res_limited_refcnt6--;
592					if (res_limited_refcnt6 == 0)
593						mon_stop(MON_RES);
594				}
595				memset((char *)rl6, 0,
596				    sizeof(struct restrictlist6));
597				rl6->next = resfree6;
598				resfree6 = rl6;
599				numresfree6++;
600			}
601			break;
602
603		default:
604			break;
605		}
606	}
607}
608