source: trunk/third/xntp/xntpd/ntp_restrict.c @ 10832

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