ntp_restrict.c revision 54359
1/*
2 * ntp_restrict.c - find out what restrictions this host is running under
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 match's
27 * flags instead.  When you hit the point where the sorted address is
28 * greater than the target, you return with the last set of flags you
29 * found.  Because of the ordering of the list, the most specific match
30 * 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
34 * from your own interfaces.  It was also thought it would sometimes
35 * be useful to keep a misbehaving host or two from abusing your primary
36 * clock.  It has been expanded, however, to suit the needs of those
37 * with more restrictive access policies.
38 */
39
40/*
41 * Memory allocation parameters.  We allocate INITRESLIST entries
42 * initially, and add INCRESLIST entries to the free list whenever
43 * we run out.
44 */
45#define	INITRESLIST	10
46#define	INCRESLIST	5
47
48/*
49 * The restriction list
50 */
51struct restrictlist *restrictlist;
52static	int restrictcount;	/* count of entries in the restriction list */
53
54/*
55 * The free list and associated counters.  Also some uninteresting
56 * stat counters.
57 */
58static	struct restrictlist *resfree;
59static	int numresfree;		/* number of structures on free list */
60
61static	u_long res_calls;
62static	u_long res_found;
63static	u_long res_not_found;
64/* static	u_long res_timereset; */
65
66/*
67 * Parameters of the RES_LIMITED restriction option.
68 * client_limit is the number of hosts allowed per source net
69 * client_limit_period is the number of seconds after which an entry
70 * is no longer considered for client limit determination
71 */
72u_long client_limit;
73u_long client_limit_period;
74/*
75 * count number of restriction entries referring to RES_LIMITED
76 * controls activation/deactivation of monitoring
77 * (with respect to RES_LIMITED control)
78 */
79static	u_long res_limited_refcnt;
80
81/*
82 * Our initial allocation of list entries.
83 */
84static	struct restrictlist resinit[INITRESLIST];
85
86/*
87 * init_restrict - initialize the restriction data structures
88 */
89void
90init_restrict(void)
91{
92	register int i;
93	char bp[80];
94
95	/*
96	 * Zero the list and put all but one on the free list
97	 */
98	resfree = 0;
99	memset((char *)resinit, 0, sizeof resinit);
100
101	for (i = 1; i < INITRESLIST; i++) {
102		resinit[i].next = resfree;
103		resfree = &resinit[i];
104	}
105
106	numresfree = INITRESLIST-1;
107
108	/*
109	 * Put the remaining item at the head of the
110	 * list as our default entry.  Everything in here
111	 * should be zero for now.
112	 */
113	resinit[0].addr = htonl(INADDR_ANY);
114	resinit[0].mask = 0;
115	restrictlist = &resinit[0];
116	restrictcount = 1;
117
118
119	/*
120	 * fix up stat counters
121	 */
122	res_calls = 0;
123	res_found = 0;
124	res_not_found = 0;
125	/* res_timereset = 0; */
126
127	/*
128	 * set default values for RES_LIMIT functionality
129	 */
130	client_limit = 3;
131	client_limit_period = 3600;
132	res_limited_refcnt = 0;
133
134	sprintf(bp, "client_limit=%ld", client_limit);
135	set_sys_var(bp, strlen(bp)+1, RO);
136	sprintf(bp, "client_limit_period=%ld", client_limit_period);
137	set_sys_var(bp, strlen(bp)+1, RO);
138}
139
140
141/*
142 * restrictions - return restrictions for this host
143 */
144int
145restrictions(
146	struct sockaddr_in *srcadr
147	)
148{
149	register struct restrictlist *rl;
150	register struct restrictlist *match;
151	register u_int32 hostaddr;
152	register int isntpport;
153
154	res_calls++;
155	/*
156	 * We need the host address in host order.  Also need to know
157	 * whether this is from the ntp port or not.
158	 */
159	hostaddr = SRCADR(srcadr);
160	isntpport = (SRCPORT(srcadr) == NTP_PORT);
161
162	/*
163	 * Ignore any packets with a multicast source address
164	 * (this should be done early in the receive process, later!)
165	 */
166	if (IN_CLASSD(ntohl(srcadr->sin_addr.s_addr)))
167	    return (int)RES_IGNORE;
168
169	/*
170	 * Set match to first entry, which is default entry.  Work our
171	 * way down from there.
172	 */
173	match = restrictlist;
174
175	for (rl = match->next; rl != 0 && rl->addr <= hostaddr; rl = rl->next)
176	    if ((hostaddr & rl->mask) == rl->addr) {
177		    if ((rl->mflags & RESM_NTPONLY) && !isntpport)
178			continue;
179		    match = rl;
180	    }
181
182	match->count++;
183	if (match == restrictlist)
184	    res_not_found++;
185	else
186	    res_found++;
187
188	/*
189	 * The following implements limiting the number of clients
190	 * accepted from a given network. The notion of "same network"
191	 * is determined by the mask and addr fields of the restrict
192	 * list entry. The monitor mechanism has to be enabled for
193	 * collecting info on current clients.
194	 *
195	 * The policy is as follows:
196	 *	- take the list of clients recorded
197	 *        from the given "network" seen within the last
198	 *        client_limit_period seconds
199	 *      - if there are at most client_limit entries:
200	 *        --> access allowed
201	 *      - otherwise sort by time first seen
202	 *      - current client among the first client_limit seen
203	 *        hosts?
204	 *        if yes: access allowed
205	 *        else:   eccess denied
206	 */
207	if (match->flags & RES_LIMITED) {
208		int lcnt;
209		struct mon_data *md, *this_client;
210
211#ifdef DEBUG
212		if (debug > 2)
213		    printf("limited clients check: %ld clients, period %ld seconds, net is 0x%lX\n",
214			   client_limit, client_limit_period,
215			   (u_long)netof(hostaddr));
216#endif /*DEBUG*/
217		if (mon_enabled == MON_OFF) {
218#ifdef DEBUG
219			if (debug > 4)
220			    printf("no limit - monitoring is off\n");
221#endif
222			return (int)(match->flags & ~RES_LIMITED);
223		}
224
225		/*
226		 * How nice, MRU list provides our current client as the
227		 * first entry in the list.
228		 * Monitoring was verified to be active above, thus we
229		 * know an entry for our client must exist, or some
230		 * brain dead set the memory limit for mon entries to ZERO!!!
231		 */
232		this_client = mon_mru_list.mru_next;
233
234		for (md = mon_fifo_list.fifo_next,lcnt = 0;
235		     md != &mon_fifo_list;
236		     md = md->fifo_next) {
237			if ((current_time - md->lasttime)
238			    > client_limit_period) {
239#ifdef DEBUG
240				if (debug > 5)
241				    printf("checking: %s: ignore: too old: %ld\n",
242					   numtoa(md->rmtadr),
243					   current_time - md->lasttime);
244#endif
245				continue;
246			}
247			if (md->mode == MODE_BROADCAST ||
248			    md->mode == MODE_CONTROL ||
249			    md->mode == MODE_PRIVATE) {
250#ifdef DEBUG
251				if (debug > 5)
252				    printf("checking: %s: ignore mode %d\n",
253					   numtoa(md->rmtadr),
254					   md->mode);
255#endif
256				continue;
257			}
258			if (netof(md->rmtadr) !=
259			    netof(hostaddr)) {
260#ifdef DEBUG
261				if (debug > 5)
262				    printf("checking: %s: different net 0x%lX\n",
263					   numtoa(md->rmtadr),
264					   (u_long)netof(md->rmtadr));
265#endif
266				continue;
267			}
268			lcnt++;
269			if (lcnt >  (int) client_limit ||
270			    md->rmtadr == hostaddr) {
271#ifdef DEBUG
272				if (debug > 5)
273				    printf("considering %s: found host\n",
274					   numtoa(md->rmtadr));
275#endif
276				break;
277			}
278#ifdef DEBUG
279			else {
280				if (debug > 5)
281				    printf("considering %s: same net\n",
282					   numtoa(md->rmtadr));
283			}
284#endif
285
286		}
287#ifdef DEBUG
288		if (debug > 4)
289		    printf("this one is rank %d in list, limit is %lu: %s\n",
290			   lcnt, client_limit,
291			   (lcnt <= (int) client_limit) ? "ALLOW" : "REJECT");
292#endif
293		if (lcnt <= (int) client_limit) {
294			this_client->lastdrop = 0;
295			return (int)(match->flags & ~RES_LIMITED);
296		} else {
297			this_client->lastdrop = current_time;
298		}
299	}
300	return (int)match->flags;
301}
302
303
304/*
305 * hack_restrict - add/subtract/manipulate entries on the restrict list
306 */
307void
308hack_restrict(
309	int op,
310	struct sockaddr_in *resaddr,
311	struct sockaddr_in *resmask,
312	int mflags,
313	int flags
314	)
315{
316	register u_int32 addr;
317	register u_int32 mask;
318	register struct restrictlist *rl;
319	register struct restrictlist *rlprev;
320	int i;
321
322	/*
323	 * Get address and mask in host byte order
324	 */
325	addr = SRCADR(resaddr);
326	mask = SRCADR(resmask);
327	addr &= mask;		/* make sure low bits are zero */
328
329	/*
330	 * If this is the default address, point at first on list.  Else
331	 * go searching for it.
332	 */
333	if (addr == htonl(INADDR_ANY)) {
334		rlprev = 0;
335		rl = restrictlist;
336	} else {
337		rlprev = restrictlist;
338		rl = rlprev->next;
339		while (rl != 0) {
340			if (rl->addr > addr) {
341				rl = 0;
342				break;
343			} else if (rl->addr == addr) {
344				if (rl->mask == mask) {
345					if ((mflags & RESM_NTPONLY)
346					    == (rl->mflags & RESM_NTPONLY))
347					    break;	/* exact match */
348					if (!(mflags & RESM_NTPONLY)) {
349						/*
350						 * No flag fits before flag
351						 */
352						rl = 0;
353						break;
354					}
355					/* continue on */
356				} else if (rl->mask > mask) {
357					rl = 0;
358					break;
359				}
360			}
361			rlprev = rl;
362			rl = rl->next;
363		}
364	}
365	/*
366	 * In case the above wasn't clear :-), either rl now points
367	 * at the entry this call refers to, or rl is zero and rlprev
368	 * points to the entry prior to where this one should go in
369	 * the sort.
370	 */
371
372	/*
373	 * Switch based on operation
374	 */
375	switch (op) {
376	    case RESTRICT_FLAGS:
377		/*
378		 * Here we add bits to the flags.  If this is a new
379		 * restriction add it.
380		 */
381		if (rl == 0) {
382			if (numresfree == 0) {
383				rl = (struct restrictlist *) emalloc(
384					INCRESLIST*sizeof(struct restrictlist));
385				memset((char *)rl, 0,
386				       INCRESLIST*sizeof(struct restrictlist));
387
388				for (i = 0; i < INCRESLIST; i++) {
389					rl->next = resfree;
390					resfree = rl;
391					rl++;
392				}
393				numresfree = INCRESLIST;
394			}
395
396			rl = resfree;
397			resfree = rl->next;
398			numresfree--;
399
400			rl->addr = addr;
401			rl->mask = mask;
402			rl->mflags = (u_short)mflags;
403
404			rl->next = rlprev->next;
405			rlprev->next = rl;
406			restrictcount++;
407		}
408		if ((rl->flags ^ (u_short)flags) & RES_LIMITED) {
409			res_limited_refcnt++;
410			mon_start(MON_RES); /* ensure data gets collected */
411		}
412		rl->flags |= (u_short)flags;
413		break;
414
415	    case RESTRICT_UNFLAG:
416		/*
417		 * Remove some bits from the flags.  If we didn't
418		 * find this one, just return.
419		 */
420		if (rl != 0) {
421			if ((rl->flags ^ (u_short)flags) & RES_LIMITED) {
422				res_limited_refcnt--;
423				if (res_limited_refcnt == 0)
424				    mon_stop(MON_RES);
425			}
426			rl->flags &= (u_short)~flags;
427		}
428		break;
429
430	    case RESTRICT_REMOVE:
431		/*
432		 * Remove an entry from the table entirely if we found one.
433		 * Don't remove the default entry and don't remove an
434		 * interface entry.
435		 */
436		if (rl != 0
437		    && rl->addr != htonl(INADDR_ANY)
438		    && !(rl->mflags & RESM_INTERFACE)) {
439			rlprev->next = rl->next;
440			restrictcount--;
441			if (rl->flags & RES_LIMITED) {
442				res_limited_refcnt--;
443				if (res_limited_refcnt == 0)
444				    mon_stop(MON_RES);
445			}
446			memset((char *)rl, 0, sizeof(struct restrictlist));
447
448			rl->next = resfree;
449			resfree = rl;
450			numresfree++;
451		}
452		break;
453
454	    default:
455		/* Oh, well */
456		break;
457	}
458
459	/* done! */
460}
461