Initial import from FreeBSD RELENG_4:
[dragonfly.git] / contrib / ntp / ntpd / ntp_restrict.c
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;
52 static  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  */
58 static  struct restrictlist *resfree;
59 static  int numresfree;         /* number of structures on free list */
60
61 static  u_long res_calls;
62 static  u_long res_found;
63 static  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  */
72 u_long client_limit;
73 u_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  */
79 static  u_long res_limited_refcnt;
80
81 /*
82  * Our initial allocation of list entries.
83  */
84 static  struct restrictlist resinit[INITRESLIST];
85
86 /*
87  * init_restrict - initialize the restriction data structures
88  */
89 void
90 init_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  */
144 int
145 restrictions(
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  */
307 void
308 hack_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 }