Annotation of embedaddon/ntp/ntpd/ntp_restrict.c, revision 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>