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>