Annotation of embedaddon/ntp/ntpd/ntp_restrict.c, revision 1.1.1.1
1.1 misho 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_lists.h"
14: #include "ntp_stdlib.h"
15: #include "ntp_assert.h"
16:
17: /*
18: * This code keeps a simple address-and-mask list of hosts we want
19: * to place restrictions on (or remove them from). The restrictions
20: * are implemented as a set of flags which tell you what the host
21: * can't do. There is a subroutine entry to return the flags. The
22: * list is kept sorted to reduce the average number of comparisons
23: * and make sure you get the set of restrictions most specific to
24: * the address.
25: *
26: * The algorithm is that, when looking up a host, it is first assumed
27: * that the default set of restrictions will apply. It then searches
28: * down through the list. Whenever it finds a match it adopts the
29: * match's flags instead. When you hit the point where the sorted
30: * address is greater than the target, you return with the last set of
31: * flags you found. Because of the ordering of the list, the most
32: * specific match will provide the final set of flags.
33: *
34: * This was originally intended to restrict you from sync'ing to your
35: * own broadcasts when you are doing that, by restricting yourself from
36: * your own interfaces. It was also thought it would sometimes be useful
37: * to keep a misbehaving host or two from abusing your primary clock. It
38: * has been expanded, however, to suit the needs of those with more
39: * restrictive access policies.
40: */
41: /*
42: * We will use two lists, one for IPv4 addresses and one for IPv6
43: * addresses. This is not protocol-independant but for now I can't
44: * find a way to respect this. We'll check this later... JFB 07/2001
45: */
46: #define MASK_IPV6_ADDR(dst, src, msk) \
47: do { \
48: int idx; \
49: for (idx = 0; idx < COUNTOF((dst)->s6_addr); idx++) { \
50: (dst)->s6_addr[idx] = (src)->s6_addr[idx] \
51: & (msk)->s6_addr[idx]; \
52: } \
53: } while (0)
54:
55: /*
56: * We allocate INC_RESLIST{4|6} entries to the free list whenever empty.
57: * Auto-tune these to be just less than 1KB (leaving at least 16 bytes
58: * for allocator overhead).
59: */
60: #define INC_RESLIST4 ((1024 - 16) / V4_SIZEOF_RESTRICT_U)
61: #define INC_RESLIST6 ((1024 - 16) / V6_SIZEOF_RESTRICT_U)
62:
63: /*
64: * The restriction list
65: */
66: restrict_u *restrictlist4;
67: restrict_u *restrictlist6;
68: static int restrictcount; /* count in the restrict lists */
69:
70: /*
71: * The free list and associated counters. Also some uninteresting
72: * stat counters.
73: */
74: static restrict_u *resfree4; /* available entries (free list) */
75: static restrict_u *resfree6;
76:
77: static u_long res_calls;
78: static u_long res_found;
79: static u_long res_not_found;
80:
81: /*
82: * Count number of restriction entries referring to RES_LIMITED, to
83: * control implicit activation/deactivation of the MRU monlist.
84: */
85: static u_long res_limited_refcnt;
86:
87: /*
88: * Our default entries.
89: */
90: static restrict_u restrict_def4;
91: static restrict_u restrict_def6;
92:
93: /*
94: * "restrict source ..." enabled knob and restriction bits.
95: */
96: static int restrict_source_enabled;
97: static u_short restrict_source_flags;
98: static u_short restrict_source_mflags;
99:
100: /*
101: * private functions
102: */
103: static restrict_u * alloc_res4(void);
104: static restrict_u * alloc_res6(void);
105: static void free_res(restrict_u *, int);
106: static void inc_res_limited(void);
107: static void dec_res_limited(void);
108: static restrict_u * match_restrict4_addr(u_int32, u_short);
109: static restrict_u * match_restrict6_addr(const struct in6_addr *,
110: u_short);
111: static restrict_u * match_restrict_entry(const restrict_u *, int);
112: static int res_sorts_before4(restrict_u *, restrict_u *);
113: static int res_sorts_before6(restrict_u *, restrict_u *);
114:
115:
116: /*
117: * init_restrict - initialize the restriction data structures
118: */
119: void
120: init_restrict(void)
121: {
122: /*
123: * The restriction lists begin with a default entry with address
124: * and mask 0, which will match any entry. The lists are kept
125: * sorted by descending address followed by descending mask:
126: *
127: * address mask
128: * 192.168.0.0 255.255.255.0 kod limited noquery nopeer
129: * 192.168.0.0 255.255.0.0 kod limited
130: * 0.0.0.0 0.0.0.0 kod limited noquery
131: *
132: * The first entry which matches an address is used. With the
133: * example restrictions above, 192.168.0.0/24 matches the first
134: * entry, the rest of 192.168.0.0/16 matches the second, and
135: * everything else matches the third (default).
136: *
137: * Note this achieves the same result a little more efficiently
138: * than the documented behavior, which is to keep the lists
139: * sorted by ascending address followed by ascending mask, with
140: * the _last_ matching entry used.
141: *
142: * An additional wrinkle is we may have multiple entries with
143: * the same address and mask but differing match flags (mflags).
144: * At present there is only one, RESM_NTPONLY. Entries with
145: * RESM_NTPONLY are sorted earlier so they take precedence over
146: * any otherwise similar entry without. Again, this is the same
147: * behavior as but reversed implementation compared to the docs.
148: *
149: */
150: LINK_SLIST(restrictlist4, &restrict_def4, link);
151: LINK_SLIST(restrictlist6, &restrict_def6, link);
152: restrictcount = 2;
153: }
154:
155:
156: static restrict_u *
157: alloc_res4(void)
158: {
159: const size_t cb = V4_SIZEOF_RESTRICT_U;
160: const size_t count = INC_RESLIST4;
161: restrict_u * rl;
162: restrict_u * res;
163: int i;
164:
165: UNLINK_HEAD_SLIST(res, resfree4, link);
166: if (res != NULL)
167: return res;
168:
169: rl = emalloc(count * cb);
170: memset(rl, 0, count * cb);
171: /* link all but the first onto free list */
172: res = (void *)((char *)rl + (count - 1) * cb);
173: for (i = count - 1; i > 0; i--) {
174: LINK_SLIST(resfree4, res, link);
175: res = (void *)((char *)res - cb);
176: }
177: NTP_INSIST(rl == res);
178: /* allocate the first */
179: return res;
180: }
181:
182:
183: static restrict_u *
184: alloc_res6(void)
185: {
186: const size_t cb = V6_SIZEOF_RESTRICT_U;
187: const size_t count = INC_RESLIST6;
188: restrict_u * rl;
189: restrict_u * res;
190: int i;
191:
192: UNLINK_HEAD_SLIST(res, resfree6, link);
193: if (res != NULL)
194: return res;
195:
196: rl = emalloc(count * cb);
197: memset(rl, 0, count * cb);
198: /* link all but the first onto free list */
199: res = (void *)((char *)rl + (count - 1) * cb);
200: for (i = count - 1; i > 0; i--) {
201: LINK_SLIST(resfree6, res, link);
202: res = (void *)((char *)res - cb);
203: }
204: NTP_INSIST(rl == res);
205: /* allocate the first */
206: return res;
207: }
208:
209:
210: static void
211: free_res(
212: restrict_u * res,
213: int v6
214: )
215: {
216: restrict_u ** plisthead;
217: restrict_u * unlinked;
218:
219: restrictcount--;
220: if (RES_LIMITED && res->flags)
221: dec_res_limited();
222:
223: if (v6)
224: plisthead = &restrictlist6;
225: else
226: plisthead = &restrictlist4;
227: UNLINK_SLIST(unlinked, *plisthead, res, link, restrict_u);
228: NTP_INSIST(unlinked == res);
229:
230: if (v6) {
231: memset(res, 0, V6_SIZEOF_RESTRICT_U);
232: plisthead = &resfree6;
233: } else {
234: memset(res, 0, V4_SIZEOF_RESTRICT_U);
235: plisthead = &resfree4;
236: }
237: LINK_SLIST(*plisthead, res, link);
238: }
239:
240:
241: static void
242: inc_res_limited(void)
243: {
244: if (!res_limited_refcnt)
245: mon_start(MON_RES);
246: res_limited_refcnt++;
247: }
248:
249:
250: static void
251: dec_res_limited(void)
252: {
253: res_limited_refcnt--;
254: if (!res_limited_refcnt)
255: mon_stop(MON_RES);
256: }
257:
258:
259: static restrict_u *
260: match_restrict4_addr(
261: u_int32 addr,
262: u_short port
263: )
264: {
265: restrict_u * res;
266: restrict_u * next;
267:
268: for (res = restrictlist4; res != NULL; res = next) {
269: next = res->link;
270: if (res->u.v4.addr == (addr & res->u.v4.mask)
271: && (!(RESM_NTPONLY & res->mflags)
272: || NTP_PORT == port))
273: break;
274: }
275: return res;
276: }
277:
278:
279: static restrict_u *
280: match_restrict6_addr(
281: const struct in6_addr * addr,
282: u_short port
283: )
284: {
285: restrict_u * res;
286: restrict_u * next;
287: struct in6_addr masked;
288:
289: for (res = restrictlist6; res != NULL; res = next) {
290: next = res->link;
291: NTP_INSIST(next != res);
292: MASK_IPV6_ADDR(&masked, addr, &res->u.v6.mask);
293: if (ADDR6_EQ(&masked, &res->u.v6.addr)
294: && (!(RESM_NTPONLY & res->mflags)
295: || NTP_PORT == port))
296: break;
297: }
298: return res;
299: }
300:
301:
302: /*
303: * match_restrict_entry - find an exact match on a restrict list.
304: *
305: * Exact match is addr, mask, and mflags all equal.
306: * In order to use more common code for IPv4 and IPv6, this routine
307: * requires the caller to populate a restrict_u with mflags and either
308: * the v4 or v6 address and mask as appropriate. Other fields in the
309: * input restrict_u are ignored.
310: */
311: static restrict_u *
312: match_restrict_entry(
313: const restrict_u * pmatch,
314: int v6
315: )
316: {
317: restrict_u *res;
318: restrict_u *rlist;
319: size_t cb;
320:
321: if (v6) {
322: rlist = restrictlist6;
323: cb = sizeof(pmatch->u.v6);
324: } else {
325: rlist = restrictlist4;
326: cb = sizeof(pmatch->u.v4);
327: }
328:
329: for (res = rlist; res != NULL; res = res->link)
330: if (res->mflags == pmatch->mflags &&
331: !memcmp(&res->u, &pmatch->u, cb))
332: break;
333: return res;
334: }
335:
336:
337: /*
338: * res_sorts_before4 - compare two restrict4 entries
339: *
340: * Returns nonzero if r1 sorts before r2. We sort by descending
341: * address, then descending mask, then descending mflags, so sorting
342: * before means having a higher value.
343: */
344: static int
345: res_sorts_before4(
346: restrict_u *r1,
347: restrict_u *r2
348: )
349: {
350: int r1_before_r2;
351:
352: if (r1->u.v4.addr > r2->u.v4.addr)
353: r1_before_r2 = 1;
354: else if (r1->u.v4.addr < r2->u.v4.addr)
355: r1_before_r2 = 0;
356: else if (r1->u.v4.mask > r2->u.v4.mask)
357: r1_before_r2 = 1;
358: else if (r1->u.v4.mask < r2->u.v4.mask)
359: r1_before_r2 = 0;
360: else if (r1->mflags > r2->mflags)
361: r1_before_r2 = 1;
362: else
363: r1_before_r2 = 0;
364:
365: return r1_before_r2;
366: }
367:
368:
369: /*
370: * res_sorts_before6 - compare two restrict6 entries
371: *
372: * Returns nonzero if r1 sorts before r2. We sort by descending
373: * address, then descending mask, then descending mflags, so sorting
374: * before means having a higher value.
375: */
376: static int
377: res_sorts_before6(
378: restrict_u *r1,
379: restrict_u *r2
380: )
381: {
382: int r1_before_r2;
383: int cmp;
384:
385: cmp = ADDR6_CMP(&r1->u.v6.addr, &r2->u.v6.addr);
386: if (cmp > 0) /* r1->addr > r2->addr */
387: r1_before_r2 = 1;
388: else if (cmp < 0) /* r2->addr > r1->addr */
389: r1_before_r2 = 0;
390: else {
391: cmp = ADDR6_CMP(&r1->u.v6.mask, &r2->u.v6.mask);
392: if (cmp > 0) /* r1->mask > r2->mask*/
393: r1_before_r2 = 1;
394: else if (cmp < 0) /* r2->mask > r1->mask */
395: r1_before_r2 = 0;
396: else if (r1->mflags > r2->mflags)
397: r1_before_r2 = 1;
398: else
399: r1_before_r2 = 0;
400: }
401:
402: return r1_before_r2;
403: }
404:
405:
406: /*
407: * restrictions - return restrictions for this host
408: */
409: u_short
410: restrictions(
411: sockaddr_u *srcadr
412: )
413: {
414: restrict_u *match;
415: struct in6_addr *pin6;
416: u_short flags;
417:
418: res_calls++;
419: flags = 0;
420: /* IPv4 source address */
421: if (IS_IPV4(srcadr)) {
422: /*
423: * Ignore any packets with a multicast source address
424: * (this should be done early in the receive process,
425: * not later!)
426: */
427: if (IN_CLASSD(SRCADR(srcadr)))
428: return (int)RES_IGNORE;
429:
430: match = match_restrict4_addr(SRCADR(srcadr),
431: SRCPORT(srcadr));
432: match->count++;
433: /*
434: * res_not_found counts only use of the final default
435: * entry, not any "restrict default ntpport ...", which
436: * would be just before the final default.
437: */
438: if (&restrict_def4 == match)
439: res_not_found++;
440: else
441: res_found++;
442: flags = match->flags;
443: }
444:
445: /* IPv6 source address */
446: if (IS_IPV6(srcadr)) {
447: pin6 = PSOCK_ADDR6(srcadr);
448:
449: /*
450: * Ignore any packets with a multicast source address
451: * (this should be done early in the receive process,
452: * not later!)
453: */
454: if (IN6_IS_ADDR_MULTICAST(pin6))
455: return (int)RES_IGNORE;
456:
457: match = match_restrict6_addr(pin6, SRCPORT(srcadr));
458: match->count++;
459: if (&restrict_def6 == match)
460: res_not_found++;
461: else
462: res_found++;
463: flags = match->flags;
464: }
465: return (flags);
466: }
467:
468:
469: /*
470: * hack_restrict - add/subtract/manipulate entries on the restrict list
471: */
472: void
473: hack_restrict(
474: int op,
475: sockaddr_u * resaddr,
476: sockaddr_u * resmask,
477: u_short mflags,
478: u_short flags
479: )
480: {
481: int v6;
482: restrict_u match;
483: restrict_u * res;
484: restrict_u ** plisthead;
485:
486: DPRINTF(1, ("restrict: op %d addr %s mask %s mflags %08x flags %08x\n",
487: op, stoa(resaddr), stoa(resmask), mflags, flags));
488:
489: if (NULL == resaddr) {
490: NTP_REQUIRE(NULL == resmask);
491: NTP_REQUIRE(RESTRICT_FLAGS == op);
492: restrict_source_flags = flags;
493: restrict_source_mflags = mflags;
494: restrict_source_enabled = 1;
495: return;
496: }
497:
498: memset(&match, 0, sizeof(match));
499: /* silence VC9 potentially uninit warnings */
500: res = NULL;
501: v6 = 0;
502:
503: if (IS_IPV4(resaddr)) {
504: v6 = 0;
505: /*
506: * Get address and mask in host byte order for easy
507: * comparison as u_int32
508: */
509: match.u.v4.addr = SRCADR(resaddr);
510: match.u.v4.mask = SRCADR(resmask);
511: match.u.v4.addr &= match.u.v4.mask;
512:
513: } else if (IS_IPV6(resaddr)) {
514: v6 = 1;
515: /*
516: * Get address and mask in network byte order for easy
517: * comparison as byte sequences (e.g. memcmp())
518: */
519: match.u.v6.mask = SOCK_ADDR6(resmask);
520: MASK_IPV6_ADDR(&match.u.v6.addr, PSOCK_ADDR6(resaddr),
521: &match.u.v6.mask);
522:
523: } else /* not IPv4 nor IPv6 */
524: NTP_REQUIRE(0);
525:
526: match.flags = flags;
527: match.mflags = mflags;
528: res = match_restrict_entry(&match, v6);
529:
530: switch (op) {
531:
532: case RESTRICT_FLAGS:
533: /*
534: * Here we add bits to the flags. If this is a
535: * new restriction add it.
536: */
537: if (NULL == res) {
538: if (v6) {
539: res = alloc_res6();
540: memcpy(res, &match,
541: V6_SIZEOF_RESTRICT_U);
542: plisthead = &restrictlist6;
543: } else {
544: res = alloc_res4();
545: memcpy(res, &match,
546: V4_SIZEOF_RESTRICT_U);
547: plisthead = &restrictlist4;
548: }
549: LINK_SORT_SLIST(
550: *plisthead, res,
551: (v6)
552: ? res_sorts_before6(res, L_S_S_CUR())
553: : res_sorts_before4(res, L_S_S_CUR()),
554: link, restrict_u);
555: restrictcount++;
556: if (RES_LIMITED & flags)
557: inc_res_limited();
558: } else {
559: if ((RES_LIMITED & flags) &&
560: !(RES_LIMITED & res->flags))
561: inc_res_limited();
562: res->flags |= flags;
563: }
564: break;
565:
566: case RESTRICT_UNFLAG:
567: /*
568: * Remove some bits from the flags. If we didn't
569: * find this one, just return.
570: */
571: if (res != NULL) {
572: if ((RES_LIMITED & res->flags)
573: && (RES_LIMITED & flags))
574: dec_res_limited();
575: res->flags &= ~flags;
576: }
577: break;
578:
579: case RESTRICT_REMOVE:
580: case RESTRICT_REMOVEIF:
581: /*
582: * Remove an entry from the table entirely if we
583: * found one. Don't remove the default entry and
584: * don't remove an interface entry.
585: */
586: if (res != NULL
587: && (RESTRICT_REMOVEIF == op
588: || !(RESM_INTERFACE & res->mflags))
589: && res != &restrict_def4
590: && res != &restrict_def6)
591: free_res(res, v6);
592: break;
593:
594: default: /* unknown op */
595: NTP_INSIST(0);
596: break;
597: }
598:
599: }
600:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>