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