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