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/*
62 * The restriction list
63 */
64struct restrictlist *restrictlist;
65struct restrictlist6 *restrictlist6;
66static int restrictcount;	/* count of entries in the res list */
67static int restrictcount6;	/* count of entries in the res list 2*/
68
69/*
70 * The free list and associated counters.  Also some uninteresting
71 * stat counters.
72 */
73static struct restrictlist *resfree;
74static struct restrictlist6 *resfree6;
75static int numresfree;		/* number of struct on free list */
76static int numresfree6;	/* number of struct on free list 2 */
77
78static u_long res_calls;
79static u_long res_found;
80static u_long res_not_found;
81
82/*
83 * Count number of restriction entries referring to RES_LIMITED controls
84 * activation/deactivation of monitoring (with respect to RES_LIMITED
85 * control)
86 */
87static	u_long res_limited_refcnt;
88static	u_long res_limited_refcnt6;
89
90/*
91 * Our initial allocation of lists entries.
92 */
93static	struct restrictlist resinit[INITRESLIST];
94static	struct restrictlist6 resinit6[INITRESLIST];
95
96
97/*
98 * init_restrict - initialize the restriction data structures
99 */
100void
101init_restrict(void)
102{
103	register int i;
104
105	/*
106	 * Zero the list and put all but one on the free list
107	 */
108	resfree = 0;
109	memset((char *)resinit, 0, sizeof resinit);
110	resfree6 = 0;
111	memset((char *)resinit6, 0, sizeof resinit6);
112	for (i = 1; i < INITRESLIST; i++) {
113		resinit[i].next = resfree;
114		resinit6[i].next = resfree6;
115		resfree = &resinit[i];
116		resfree6 = &resinit6[i];
117	}
118	numresfree = INITRESLIST-1;
119	numresfree6 = INITRESLIST-1;
120
121	/*
122	 * Put the remaining item at the head of the list as our default
123	 * entry. Everything in here should be zero for now.
124	 */
125	resinit[0].addr = htonl(INADDR_ANY);
126	resinit[0].mask = 0;
127	memset(&resinit6[0].addr6, 0, sizeof(struct in6_addr));
128	memset(&resinit6[0].mask6, 0, sizeof(struct in6_addr));
129	restrictlist = &resinit[0];
130	restrictlist6 = &resinit6[0];
131	restrictcount = 1;
132	restrictcount = 2;
133
134	/*
135	 * fix up stat counters
136	 */
137	res_calls = 0;
138	res_found = 0;
139	res_not_found = 0;
140
141	/*
142	 * set default values for RES_LIMIT functionality
143	 */
144	res_limited_refcnt = 0;
145	res_limited_refcnt6 = 0;
146}
147
148
149/*
150 * restrictions - return restrictions for this host
151 */
152int
153restrictions(
154	sockaddr_u *srcadr
155	)
156{
157	struct restrictlist *rl;
158	struct restrictlist *match = NULL;
159	struct restrictlist6 *rl6;
160	struct restrictlist6 *match6 = NULL;
161	struct in6_addr hostaddr6;
162	struct in6_addr hostservaddr6;
163	u_int32	hostaddr;
164	int	flags = 0;
165	int	isntpport;
166
167	res_calls++;
168	/* IPv4 source address */
169	if (IS_IPV4(srcadr)) {
170
171		/*
172		 * We need the host address in host order. Also need to
173		 * know whether this is from the ntp port or not.
174		 */
175		hostaddr = SRCADR(srcadr);
176		isntpport = (NTP_PORT == SRCPORT(srcadr));
177
178		/*
179		 * Ignore any packets with a multicast source address
180		 * (this should be done early in the receive process,
181		 * not later!)
182		 */
183		if (IN_CLASSD(SRCADR(srcadr)))
184			return (int)RES_IGNORE;
185
186		/*
187		 * Set match to first entry, which is default entry.
188		 * Work our way down from there.
189		 */
190		match = restrictlist;
191		for (rl = match->next; rl != 0 && rl->addr <= hostaddr;
192		    rl = rl->next)
193			if ((hostaddr & rl->mask) == rl->addr) {
194				if ((rl->mflags & RESM_NTPONLY) &&
195				    !isntpport)
196					continue;
197				match = rl;
198			}
199		match->count++;
200		if (match == restrictlist)
201			res_not_found++;
202		else
203			res_found++;
204		flags = match->flags;
205	}
206
207	/* IPv6 source address */
208	if (IS_IPV6(srcadr)) {
209
210		/*
211		 * We need the host address in network order. Also need
212		 * to know whether this is from the ntp port or not.
213		 */
214		hostaddr6 = SOCK_ADDR6(srcadr);
215		isntpport = (NTP_PORT == SRCPORT(srcadr));
216
217		/*
218		 * Ignore any packets with a multicast source address
219		 * (this should be done early in the receive process,
220		 * not later!)
221		 */
222		if (IN6_IS_ADDR_MULTICAST(&hostaddr6))
223			return (int)RES_IGNORE;
224
225		/*
226		 * Set match to first entry, which is default entry.
227		 *  Work our way down from there.
228		 */
229		match6 = restrictlist6;
230		for (rl6 = match6->next; rl6 != 0 &&
231		    (memcmp(&(rl6->addr6), &hostaddr6,
232		    sizeof(hostaddr6)) <= 0); rl6 = rl6->next) {
233			SET_IPV6_ADDR_MASK(&hostservaddr6, &hostaddr6,
234			    &rl6->mask6);
235			if (memcmp(&hostservaddr6, &(rl6->addr6),
236			    sizeof(hostservaddr6)) == 0) {
237				if ((rl6->mflags & RESM_NTPONLY) &&
238				    !isntpport)
239					continue;
240				match6 = rl6;
241			}
242		}
243		match6->count++;
244		if (match6 == restrictlist6)
245			res_not_found++;
246		else
247			res_found++;
248		flags = match6->flags;
249	}
250	return (flags);
251}
252
253
254/*
255 * hack_restrict - add/subtract/manipulate entries on the restrict list
256 */
257void
258hack_restrict(
259	int op,
260	sockaddr_u *resaddr,
261	sockaddr_u *resmask,
262	int mflags,
263	int flags
264	)
265{
266	register u_int32 addr = 0;
267	register u_int32 mask = 0;
268	struct in6_addr addr6;
269	struct in6_addr mask6;
270	register struct restrictlist *rl = NULL;
271	register struct restrictlist *rlprev = NULL;
272	register struct restrictlist6 *rl6 = NULL;
273	register struct restrictlist6 *rlprev6 = NULL;
274	int i, addr_cmp, mask_cmp;
275	memset(&addr6, 0, sizeof(struct in6_addr));
276	memset(&mask6, 0, sizeof(struct in6_addr));
277
278	if (IS_IPV4(resaddr)) {
279
280		DPRINTF(1, ("restrict: addr %08x mask %08x mflags %08x flags %08x\n",
281			    SRCADR(resaddr), SRCADR(resmask), mflags, flags));
282
283		/*
284		 * Get address and mask in host byte order
285		 */
286		addr = SRCADR(resaddr);
287		mask = SRCADR(resmask);
288		addr &= mask;		/* make sure low bits zero */
289
290		/*
291		 * If this is the default address, point at first on
292		 * list. Else go searching for it.
293		 */
294		if (addr == 0) {
295			rlprev = 0;
296			rl = restrictlist;
297		} else {
298			rlprev = restrictlist;
299			rl = rlprev->next;
300			while (rl != 0) {
301				if (rl->addr > addr) {
302					rl = 0;
303					break;
304				} else if (rl->addr == addr) {
305					if (rl->mask == mask) {
306						if ((mflags &
307						    RESM_NTPONLY) ==
308						    (rl->mflags &
309						    RESM_NTPONLY))
310							break;
311
312						if (!(mflags &
313						    RESM_NTPONLY)) {
314							rl = 0;
315							break;
316						}
317					} else if (rl->mask > mask) {
318						rl = 0;
319						break;
320					}
321				}
322				rlprev = rl;
323				rl = rl->next;
324			}
325		}
326	}
327
328	if (IS_IPV6(resaddr)) {
329		mask6 = SOCK_ADDR6(resmask);
330		SET_IPV6_ADDR_MASK(&addr6,
331		    PSOCK_ADDR6(resaddr), &mask6);
332		if (IN6_IS_ADDR_UNSPECIFIED(&addr6)) {
333			rlprev6 = NULL;
334			rl6 = restrictlist6;
335		} else {
336			rlprev6 = restrictlist6;
337			rl6 = rlprev6->next;
338			while (rl6 != 0) {
339				addr_cmp = memcmp(&rl6->addr6, &addr6,
340				    sizeof(addr6));
341				if (addr_cmp > 0) {
342					rl6 = 0;
343					break;
344
345				} else if (addr_cmp == 0) {
346					mask_cmp = memcmp(&rl6->mask6,
347					    &mask6, sizeof(mask6));
348					if (mask_cmp == 0) {
349						if ((mflags &
350						    RESM_NTPONLY) ==
351						    (rl6->mflags &
352						    RESM_NTPONLY))
353							break;
354
355						if (!(mflags &
356						    RESM_NTPONLY)) {
357							rl6 = 0;
358							break;
359						}
360					} else if (mask_cmp > 0) {
361						rl6 = 0;
362						break;
363					}
364				}
365				rlprev6 = rl6;
366				rl6 = rl6->next;
367			}
368		}
369	}
370
371	/*
372	 * In case the above wasn't clear :-), either rl now points
373	 * at the entry this call refers to, or rl is zero and rlprev
374	 * points to the entry prior to where this one should go in
375	 * the sort.
376	 */
377	/*
378	 * Switch based on operation
379	 */
380	if (IS_IPV4(resaddr)) {
381		switch (op) {
382		case RESTRICT_FLAGS:
383
384			/*
385			 * Here we add bits to the flags. If this is a
386			 * new restriction add it.
387			 */
388			if (rl == 0) {
389				if (numresfree == 0) {
390					rl = (struct restrictlist *)
391					    emalloc(INCRESLIST *
392					    sizeof(struct
393					    restrictlist));
394					memset((char *)rl, 0,
395					    INCRESLIST * sizeof(struct
396					    restrictlist));
397					for (i = 0; i < INCRESLIST;
398					    i++) {
399						rl->next = resfree;
400						resfree = rl;
401						rl++;
402					}
403					numresfree = INCRESLIST;
404				}
405				rl = resfree;
406				resfree = rl->next;
407				numresfree--;
408				rl->addr = addr;
409				rl->mask = mask;
410				rl->mflags = (u_short)mflags;
411				if (rlprev == NULL) {
412					rl->next = restrictlist;
413					restrictlist = rl;
414				} else {
415					rl->next = rlprev->next;
416					rlprev->next = rl;
417				}
418				restrictcount++;
419			}
420			if ((rl->flags ^ (u_short)flags) &
421			    RES_LIMITED) {
422				res_limited_refcnt++;
423				mon_start(MON_RES);
424			}
425			rl->flags |= (u_short)flags;
426			break;
427
428		case RESTRICT_UNFLAG:
429
430			/*
431			 * Remove some bits from the flags. If we didn't
432			 * find this one, just return.
433			 */
434			if (rl != 0) {
435				if ((rl->flags ^ (u_short)flags) &
436				    RES_LIMITED) {
437					res_limited_refcnt--;
438					if (res_limited_refcnt == 0)
439						mon_stop(MON_RES);
440				}
441				rl->flags &= (u_short)~flags;
442			}
443			break;
444
445		case RESTRICT_REMOVE:
446		case RESTRICT_REMOVEIF:
447
448			/*
449			 * Remove an entry from the table entirely if we
450			 * found one. Don't remove the default entry and
451			 * don't remove an interface entry.
452			 */
453			if (rl != 0
454			    && rl->addr != htonl(INADDR_ANY)
455			    && !(rl->mflags & RESM_INTERFACE && op !=
456			    RESTRICT_REMOVEIF)) {
457				if (rlprev != NULL) {
458					rlprev->next = rl->next;
459				} else {
460					restrictlist = rl->next;
461				}
462				restrictcount--;
463				if (rl->flags & RES_LIMITED) {
464					res_limited_refcnt--;
465					if (res_limited_refcnt == 0)
466						mon_stop(MON_RES);
467				}
468				memset((char *)rl, 0,
469				    sizeof(struct restrictlist));
470
471				rl->next = resfree;
472				resfree = rl;
473				numresfree++;
474			}
475			break;
476
477		default:
478			break;
479		}
480	} else if (IS_IPV6(resaddr)) {
481		switch (op) {
482		case RESTRICT_FLAGS:
483
484			/*
485			 * Here we add bits to the flags. If this is a
486			 * new restriction add it.
487			 */
488			if (rl6 == 0) {
489				if (numresfree6 == 0) {
490					rl6 = (struct
491					    restrictlist6 *)emalloc(
492					    INCRESLIST * sizeof(struct
493					    restrictlist6));
494					memset((char *)rl6, 0,
495					    INCRESLIST * sizeof(struct
496					    restrictlist6));
497
498					for (i = 0; i < INCRESLIST;
499					    i++) {
500						rl6->next = resfree6;
501						resfree6 = rl6;
502						rl6++;
503					}
504					numresfree6 = INCRESLIST;
505				}
506				rl6 = resfree6;
507				resfree6 = rl6->next;
508				numresfree6--;
509				rl6->addr6 = addr6;
510				rl6->mask6 = mask6;
511				rl6->mflags = (u_short)mflags;
512				if (rlprev6 != NULL) {
513					rl6->next = rlprev6->next;
514					rlprev6->next = rl6;
515				} else {
516					rl6->next = restrictlist6;
517					restrictlist6 = rl6;
518				}
519				restrictcount6++;
520			}
521			if ((rl6->flags ^ (u_short)flags) &
522			    RES_LIMITED) {
523				res_limited_refcnt6++;
524				mon_start(MON_RES);
525			}
526			rl6->flags |= (u_short)flags;
527			break;
528
529		case RESTRICT_UNFLAG:
530
531			/*
532			 * Remove some bits from the flags. If we didn't
533			 * find this one, just return.
534			 */
535			if (rl6 != 0) {
536				if ((rl6->flags ^ (u_short)flags) &
537				    RES_LIMITED) {
538					res_limited_refcnt6--;
539					if (res_limited_refcnt6 == 0)
540						mon_stop(MON_RES);
541				}
542				rl6->flags &= (u_short)~flags;
543			}
544			break;
545
546		case RESTRICT_REMOVE:
547		case RESTRICT_REMOVEIF:
548
549			/*
550			 * Remove an entry from the table entirely if we
551			 * found one. Don't remove the default entry and
552			 * don't remove an interface entry.
553			 */
554			if (rl6 != 0 &&
555			    !IN6_IS_ADDR_UNSPECIFIED(&rl6->addr6)
556			    && !(rl6->mflags & RESM_INTERFACE && op !=
557			    RESTRICT_REMOVEIF)) {
558				if (rlprev6 != NULL) {
559					rlprev6->next = rl6->next;
560				} else {
561					restrictlist6 = rl6->next;
562				}
563				restrictcount6--;
564				if (rl6->flags & RES_LIMITED) {
565					res_limited_refcnt6--;
566					if (res_limited_refcnt6 == 0)
567						mon_stop(MON_RES);
568				}
569				memset((char *)rl6, 0,
570				    sizeof(struct restrictlist6));
571				rl6->next = resfree6;
572				resfree6 = rl6;
573				numresfree6++;
574			}
575			break;
576
577		default:
578			break;
579		}
580	}
581}
582