Annotation of embedaddon/ntp/ntpd/ntp_peer.c, revision 1.1

1.1     ! misho       1: /*
        !             2:  * ntp_peer.c - management of data maintained for peer associations
        !             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_lists.h"
        !            13: #include "ntp_stdlib.h"
        !            14: #include "ntp_control.h"
        !            15: #include <ntp_random.h>
        !            16: #ifdef OPENSSL
        !            17: #include "openssl/rand.h"
        !            18: #endif /* OPENSSL */
        !            19: 
        !            20: #ifdef SYS_WINNT
        !            21: int accept_wildcard_if_for_winnt;
        !            22: #else
        !            23: const int accept_wildcard_if_for_winnt = FALSE;
        !            24: #endif
        !            25: 
        !            26: /*
        !            27:  *                  Table of valid association combinations
        !            28:  *                  ---------------------------------------
        !            29:  *
        !            30:  *                             packet->mode
        !            31:  * peer->mode      | UNSPEC  ACTIVE PASSIVE  CLIENT  SERVER  BCAST
        !            32:  * ----------      | ---------------------------------------------
        !            33:  * NO_PEER         |   e       1       0       1       1       1
        !            34:  * ACTIVE          |   e       1       1       0       0       0
        !            35:  * PASSIVE         |   e       1       e       0       0       0
        !            36:  * CLIENT          |   e       0       0       0       1       0
        !            37:  * SERVER          |   e       0       0       0       0       0
        !            38:  * BCAST           |   e       0       0       0       0       0
        !            39:  * BCLIENT         |   e       0       0       0       e       1
        !            40:  *
        !            41:  * One point to note here: a packet in BCAST mode can potentially match
        !            42:  * a peer in CLIENT mode, but we that is a special case and we check for
        !            43:  * that early in the decision process.  This avoids having to keep track
        !            44:  * of what kind of associations are possible etc...  We actually
        !            45:  * circumvent that problem by requiring that the first b(m)roadcast
        !            46:  * received after the change back to BCLIENT mode sets the clock.
        !            47:  */
        !            48: #define AM_MODES       7       /* number of rows and columns */
        !            49: #define NO_PEER                0       /* action when no peer is found */
        !            50: 
        !            51: int AM[AM_MODES][AM_MODES] = {
        !            52: /*     { UNSPEC,   ACTIVE,     PASSIVE,    CLIENT,     SERVER,     BCAST } */
        !            53: 
        !            54: /*NONE*/{ AM_ERR, AM_NEWPASS, AM_NOMATCH, AM_FXMIT,   AM_MANYCAST, AM_NEWBCL},
        !            55: 
        !            56: /*A*/  { AM_ERR, AM_PROCPKT, AM_PROCPKT, AM_NOMATCH, AM_NOMATCH,  AM_NOMATCH},
        !            57: 
        !            58: /*P*/  { AM_ERR, AM_PROCPKT, AM_ERR,     AM_NOMATCH, AM_NOMATCH,  AM_NOMATCH},
        !            59: 
        !            60: /*C*/  { AM_ERR, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH, AM_PROCPKT,  AM_NOMATCH},
        !            61: 
        !            62: /*S*/  { AM_ERR, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH,  AM_NOMATCH},
        !            63: 
        !            64: /*BCST*/{ AM_ERR, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH,  AM_NOMATCH},
        !            65: 
        !            66: /*BCL*/ { AM_ERR, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH,  AM_PROCPKT},
        !            67: };
        !            68: 
        !            69: #define MATCH_ASSOC(x, y)      AM[(x)][(y)]
        !            70: 
        !            71: /*
        !            72:  * These routines manage the allocation of memory to peer structures
        !            73:  * and the maintenance of the peer hash table. The three main entry
        !            74:  * points are findpeer(), which looks for matching peer structures in
        !            75:  * the peer list, newpeer(), which allocates a new peer structure and
        !            76:  * adds it to the list, and unpeer(), which demobilizes the association
        !            77:  * and deallocates the structure.
        !            78:  */
        !            79: /*
        !            80:  * Peer hash tables
        !            81:  */
        !            82: struct peer *peer_hash[NTP_HASH_SIZE]; /* peer hash table */
        !            83: int    peer_hash_count[NTP_HASH_SIZE]; /* peers in each bucket */
        !            84: struct peer *assoc_hash[NTP_HASH_SIZE];        /* association ID hash table */
        !            85: int    assoc_hash_count[NTP_HASH_SIZE]; /* peers in each bucket */
        !            86: static struct peer *peer_free;         /* peer structures free list */
        !            87: int    peer_free_count;                /* count of free structures */
        !            88: 
        !            89: /*
        !            90:  * Association ID.  We initialize this value randomly, then assign a new
        !            91:  * value every time the peer structure is incremented.
        !            92:  */
        !            93: static associd_t current_association_ID; /* association ID */
        !            94: 
        !            95: /*
        !            96:  * Memory allocation watermarks.
        !            97:  */
        !            98: #define        INIT_PEER_ALLOC         15      /* initialize for 15 peers */
        !            99: #define        INC_PEER_ALLOC          5       /* when run out, add 5 more */
        !           100: 
        !           101: /*
        !           102:  * Miscellaneous statistic counters which may be queried.
        !           103:  */
        !           104: u_long peer_timereset;                 /* time stat counters zeroed */
        !           105: u_long findpeer_calls;                 /* calls to findpeer */
        !           106: u_long assocpeer_calls;                /* calls to findpeerbyassoc */
        !           107: u_long peer_allocations;               /* allocations from free list */
        !           108: u_long peer_demobilizations;           /* structs freed to free list */
        !           109: int    total_peer_structs;             /* peer structs */
        !           110: int    peer_associations;              /* mobilized associations */
        !           111: int    peer_preempt;                   /* preemptable associations */
        !           112: static struct peer init_peer_alloc[INIT_PEER_ALLOC]; /* init alloc */
        !           113: 
        !           114: static void        getmorepeermem       (void);
        !           115: static struct interface *select_peerinterface (struct peer *, sockaddr_u *, struct interface *, u_char);
        !           116: 
        !           117: static int score(struct peer *);
        !           118: 
        !           119: /*
        !           120:  * init_peer - initialize peer data structures and counters
        !           121:  *
        !           122:  * N.B. We use the random number routine in here. It had better be
        !           123:  * initialized prior to getting here.
        !           124:  */
        !           125: void
        !           126: init_peer(void)
        !           127: {
        !           128:        register int i;
        !           129: 
        !           130:        /*
        !           131:         * Clear hash tables and counters.
        !           132:         */
        !           133:        memset(peer_hash, 0, sizeof(peer_hash));
        !           134:        memset(peer_hash_count, 0, sizeof(peer_hash_count));
        !           135:        memset(assoc_hash, 0, sizeof(assoc_hash));
        !           136:        memset(assoc_hash_count, 0, sizeof(assoc_hash_count));
        !           137: 
        !           138:        /*
        !           139:         * Clear stat counters
        !           140:         */
        !           141:        findpeer_calls = peer_allocations = 0;
        !           142:        assocpeer_calls = peer_demobilizations = 0;
        !           143: 
        !           144:        /*
        !           145:         * Initialize peer memory.
        !           146:         */
        !           147:        peer_free = NULL;
        !           148:        for (i = 0; i < INIT_PEER_ALLOC; i++)
        !           149:                LINK_SLIST(peer_free, &init_peer_alloc[i], next);
        !           150:        total_peer_structs = INIT_PEER_ALLOC;
        !           151:        peer_free_count = INIT_PEER_ALLOC;
        !           152: 
        !           153:        /*
        !           154:         * Initialize our first association ID
        !           155:         */
        !           156:        while ((current_association_ID = ntp_random() & 0xffff) == 0);
        !           157: }
        !           158: 
        !           159: 
        !           160: /*
        !           161:  * getmorepeermem - add more peer structures to the free list
        !           162:  */
        !           163: static void
        !           164: getmorepeermem(void)
        !           165: {
        !           166:        register int i;
        !           167:        register struct peer *peer;
        !           168: 
        !           169:        peer = (struct peer *)emalloc(INC_PEER_ALLOC *
        !           170:            sizeof(struct peer));
        !           171:        for (i = 0; i < INC_PEER_ALLOC; i++) {
        !           172:                LINK_SLIST(peer_free, peer, next);
        !           173:                peer++;
        !           174:        }
        !           175: 
        !           176:        total_peer_structs += INC_PEER_ALLOC;
        !           177:        peer_free_count += INC_PEER_ALLOC;
        !           178: }
        !           179: 
        !           180: 
        !           181: /*
        !           182:  * findexistingpeer - return a pointer to a peer in the hash table
        !           183:  */
        !           184: struct peer *
        !           185: findexistingpeer(
        !           186:        sockaddr_u *    addr,
        !           187:        struct peer *   start_peer,
        !           188:        int             mode,
        !           189:        u_char          cast_flags
        !           190:        )
        !           191: {
        !           192:        register struct peer *peer;
        !           193: 
        !           194:        /*
        !           195:         * start_peer is included so we can locate instances of the
        !           196:         * same peer through different interfaces in the hash table.
        !           197:         * Without MDF_BCLNT, a match requires the same mode and remote
        !           198:         * address.  MDF_BCLNT associations start out as MODE_CLIENT
        !           199:         * if broadcastdelay is not specified, and switch to
        !           200:         * MODE_BCLIENT after estimating the one-way delay.  Duplicate
        !           201:         * associations are expanded in definition to match any other
        !           202:         * MDF_BCLNT with the same srcadr (remote, unicast address).
        !           203:         */
        !           204:        if (NULL == start_peer)
        !           205:                peer = peer_hash[NTP_HASH_ADDR(addr)];
        !           206:        else
        !           207:                peer = start_peer->next;
        !           208:        
        !           209:        while (peer != NULL) {
        !           210:                if (ADDR_PORT_EQ(addr, &peer->srcadr)
        !           211:                    && (-1 == mode || peer->hmode == mode ||
        !           212:                        ((MDF_BCLNT & peer->cast_flags) &&
        !           213:                         (MDF_BCLNT & cast_flags))))
        !           214:                        break;
        !           215:                peer = peer->next;
        !           216:        }
        !           217: 
        !           218:        return peer;
        !           219: }
        !           220: 
        !           221: 
        !           222: /*
        !           223:  * findpeer - find and return a peer match for a received datagram in
        !           224:  *           the peer_hash table.
        !           225:  */
        !           226: struct peer *
        !           227: findpeer(
        !           228:        struct recvbuf *rbufp,
        !           229:        int             pkt_mode,
        !           230:        int *           action
        !           231:        )
        !           232: {
        !           233:        struct peer *   p;
        !           234:        sockaddr_u *    srcadr;
        !           235:        u_int           hash;
        !           236:        struct pkt *    pkt;
        !           237:        l_fp            pkt_org;
        !           238: 
        !           239:        findpeer_calls++;
        !           240:        srcadr = &rbufp->recv_srcadr;
        !           241:        hash = NTP_HASH_ADDR(srcadr);
        !           242:        for (p = peer_hash[hash]; p != NULL; p = p->next) {
        !           243:                if (SOCK_EQ(srcadr, &p->srcadr) &&
        !           244:                    NSRCPORT(srcadr) == NSRCPORT(&p->srcadr)) {
        !           245: 
        !           246:                        /*
        !           247:                         * if the association matching rules determine
        !           248:                         * that this is not a valid combination, then
        !           249:                         * look for the next valid peer association.
        !           250:                         */
        !           251:                        *action = MATCH_ASSOC(p->hmode, pkt_mode);
        !           252: 
        !           253:                        /*
        !           254:                         * A response to our manycastclient solicitation
        !           255:                         * might be misassociated with an ephemeral peer
        !           256:                         * already spun for the server.  If the packet's
        !           257:                         * org timestamp doesn't match the peer's, check
        !           258:                         * if it matches the ACST prototype peer's.  If
        !           259:                         * so it is a redundant solicitation response,
        !           260:                         * return AM_ERR to discard it.  [Bug 1762]
        !           261:                         */
        !           262:                        if (MODE_SERVER == pkt_mode &&
        !           263:                            AM_PROCPKT == *action) {
        !           264:                                pkt = &rbufp->recv_pkt;
        !           265:                                NTOHL_FP(&pkt->org, &pkt_org);
        !           266:                                if (!L_ISEQU(&p->aorg, &pkt_org) &&
        !           267:                                    findmanycastpeer(rbufp))
        !           268:                                        *action = AM_ERR;
        !           269:                        }
        !           270: 
        !           271:                        /*
        !           272:                         * if an error was returned, exit back right
        !           273:                         * here.
        !           274:                         */
        !           275:                        if (*action == AM_ERR)
        !           276:                                return NULL;
        !           277: 
        !           278:                        /*
        !           279:                         * if a match is found, we stop our search.
        !           280:                         */
        !           281:                        if (*action != AM_NOMATCH)
        !           282:                                break;
        !           283:                }
        !           284:        }
        !           285: 
        !           286:        /*
        !           287:         * If no matching association is found
        !           288:         */
        !           289:        if (NULL == p) {
        !           290:                *action = MATCH_ASSOC(NO_PEER, pkt_mode);
        !           291:        } else if (p->dstadr != rbufp->dstadr) {
        !           292:                set_peerdstadr(p, rbufp->dstadr);
        !           293:                if (p->dstadr == rbufp->dstadr) {
        !           294:                        DPRINTF(1, ("Changed %s local address to match response\n",
        !           295:                                    stoa(&p->srcadr)));
        !           296:                        return findpeer(rbufp, pkt_mode, action);
        !           297:                }
        !           298:        }
        !           299:        return p;
        !           300: }
        !           301: 
        !           302: /*
        !           303:  * findpeerbyassocid - find and return a peer using his association ID
        !           304:  */
        !           305: struct peer *
        !           306: findpeerbyassoc(
        !           307:        u_int assoc
        !           308:        )
        !           309: {
        !           310:        struct peer *p;
        !           311:        u_int hash;
        !           312: 
        !           313:        assocpeer_calls++;
        !           314: 
        !           315:        hash = assoc & NTP_HASH_MASK;
        !           316:        for (p = assoc_hash[hash]; p != NULL; p = p->ass_next) {
        !           317:                if (assoc == p->associd)
        !           318:                        return p;
        !           319:        }
        !           320:        return NULL;
        !           321: }
        !           322: 
        !           323: 
        !           324: /*
        !           325:  * clear_all - flush all time values for all associations
        !           326:  */
        !           327: void
        !           328: clear_all(void)
        !           329: {
        !           330:        struct peer *peer, *next_peer;
        !           331:        int n;
        !           332: 
        !           333:        /*
        !           334:         * This routine is called when the clock is stepped, and so all
        !           335:         * previously saved time values are untrusted.
        !           336:         */
        !           337:        for (n = 0; n < NTP_HASH_SIZE; n++) {
        !           338:                for (peer = peer_hash[n]; peer != 0; peer = next_peer) {
        !           339:                        next_peer = peer->next;
        !           340:                        if (!(peer->cast_flags & (MDF_ACAST |
        !           341:                            MDF_MCAST | MDF_BCAST))) {
        !           342:                                peer_clear(peer, "STEP");
        !           343:                        }
        !           344:                }
        !           345:        }
        !           346: #ifdef DEBUG
        !           347:        if (debug)
        !           348:                printf("clear_all: at %lu\n", current_time);
        !           349: #endif
        !           350: }
        !           351: 
        !           352: 
        !           353: /*
        !           354:  * score_all() - determine if an association can be demobilized
        !           355:  */
        !           356: int
        !           357: score_all(
        !           358:        struct peer *peer       /* peer structure pointer */
        !           359:        )
        !           360: {
        !           361:        struct peer *speer, *next_peer;
        !           362:        int     n;
        !           363:        int     temp, tamp;
        !           364: 
        !           365:        /*
        !           366:         * This routine finds the minimum score for all ephemeral
        !           367:         * assocations and returns > 0 if the association can be
        !           368:         * demobilized.
        !           369:         */
        !           370:        tamp = score(peer);
        !           371:        temp = 100;
        !           372:        for (n = 0; n < NTP_HASH_SIZE; n++) {
        !           373:                for (speer = peer_hash[n]; speer != 0; speer =
        !           374:                    next_peer) {
        !           375:                        int     x;
        !           376: 
        !           377:                        next_peer = speer->next;
        !           378:                        if ((x = score(speer)) < temp && (peer->flags &
        !           379:                            FLAG_PREEMPT))
        !           380:                                temp = x;
        !           381:                }
        !           382:        }
        !           383: #ifdef DEBUG
        !           384:        if (debug)
        !           385:                printf("score_all: at %lu score %d min %d\n",
        !           386:                    current_time, tamp, temp);
        !           387: #endif
        !           388:        if (tamp != temp)
        !           389:                temp = 0;
        !           390:        return (temp);
        !           391: }
        !           392: 
        !           393: 
        !           394: /*
        !           395:  * score() - calculate preemption score
        !           396:  */
        !           397: static int
        !           398: score(
        !           399:        struct peer *peer       /* peer structure pointer */
        !           400:        )
        !           401: {
        !           402:        int     temp;
        !           403: 
        !           404:        /*
        !           405:         * This routine calculates the premption score from the peer
        !           406:         * error bits and status. Increasing values are more cherished.
        !           407:         */
        !           408:        temp = 0;
        !           409:        if (!(peer->flash & TEST10))
        !           410:                temp++;                 /* 1 good synch and stratum */
        !           411:        if (!(peer->flash & TEST13))
        !           412:                temp++;                 /* 2 reachable */
        !           413:        if (!(peer->flash & TEST12))
        !           414:                temp++;                 /* 3 no loop */
        !           415:        if (!(peer->flash & TEST11))
        !           416:                temp++;                 /* 4 good distance */
        !           417:        if (peer->status >= CTL_PST_SEL_SELCAND)
        !           418:                temp++;                 /* 5 in the hunt */
        !           419:        if (peer->status != CTL_PST_SEL_EXCESS)
        !           420:                temp++;                 /* 6 not spare tire */
        !           421:        return (temp);                  /* selection status */
        !           422: }
        !           423: 
        !           424: 
        !           425: /*
        !           426:  * unpeer - remove peer structure from hash table and free structure
        !           427:  */
        !           428: void
        !           429: unpeer(
        !           430:        struct peer *peer_to_remove
        !           431:        )
        !           432: {
        !           433:        register struct peer *unlinked;
        !           434:        int     hash;
        !           435:        char    tbuf[80];
        !           436: 
        !           437:        snprintf(tbuf, sizeof(tbuf), "assoc %d",
        !           438:            peer_to_remove->associd);
        !           439:        report_event(PEVNT_DEMOBIL, peer_to_remove, tbuf);
        !           440:        set_peerdstadr(peer_to_remove, NULL);
        !           441:        hash = NTP_HASH_ADDR(&peer_to_remove->srcadr);
        !           442:        peer_hash_count[hash]--;
        !           443:        peer_demobilizations++;
        !           444:        peer_associations--;
        !           445:        if (peer_to_remove->flags & FLAG_PREEMPT)
        !           446:                peer_preempt--;
        !           447: #ifdef REFCLOCK
        !           448:        /*
        !           449:         * If this peer is actually a clock, shut it down first
        !           450:         */
        !           451:        if (peer_to_remove->flags & FLAG_REFCLOCK)
        !           452:                refclock_unpeer(peer_to_remove);
        !           453: #endif
        !           454:        peer_to_remove->action = 0;     /* disable timeout actions */
        !           455: 
        !           456:        UNLINK_SLIST(unlinked, peer_hash[hash], peer_to_remove, next,
        !           457:            struct peer);
        !           458: 
        !           459:        if (NULL == unlinked) {
        !           460:                peer_hash_count[hash]++;
        !           461:                msyslog(LOG_ERR, "peer struct for %s not in table!",
        !           462:                    stoa(&peer_to_remove->srcadr));
        !           463:        }
        !           464: 
        !           465:        /*
        !           466:         * Remove him from the association hash as well.
        !           467:         */
        !           468:        hash = peer_to_remove->associd & NTP_HASH_MASK;
        !           469:        assoc_hash_count[hash]--;
        !           470: 
        !           471:        UNLINK_SLIST(unlinked, assoc_hash[hash], peer_to_remove,
        !           472:            ass_next, struct peer);
        !           473: 
        !           474:        if (NULL == unlinked) {
        !           475:                assoc_hash_count[hash]++;
        !           476:                msyslog(LOG_ERR,
        !           477:                    "peer struct for %s not in association table!",
        !           478:                    stoa(&peer_to_remove->srcadr));
        !           479:        }
        !           480: 
        !           481:        LINK_SLIST(peer_free, peer_to_remove, next);
        !           482:        peer_free_count++;
        !           483: }
        !           484: 
        !           485: 
        !           486: /*
        !           487:  * peer_config - configure a new association
        !           488:  */
        !           489: struct peer *
        !           490: peer_config(
        !           491:        sockaddr_u *srcadr,
        !           492:        struct interface *dstadr,
        !           493:        int hmode,
        !           494:        int version,
        !           495:        int minpoll,
        !           496:        int maxpoll,
        !           497:        u_int flags,
        !           498:        int ttl,
        !           499:        keyid_t key,
        !           500:        u_char *keystr
        !           501:        )
        !           502: {
        !           503:        u_char cast_flags;
        !           504: 
        !           505:        /*
        !           506:         * We do a dirty little jig to figure the cast flags. This is
        !           507:         * probably not the best place to do this, at least until the
        !           508:         * configure code is rebuilt. Note only one flag can be set.
        !           509:         */
        !           510:        switch (hmode) {
        !           511:        case MODE_BROADCAST:
        !           512:                if (IS_MCAST(srcadr))
        !           513:                        cast_flags = MDF_MCAST;
        !           514:                else
        !           515:                        cast_flags = MDF_BCAST;
        !           516:                break;
        !           517: 
        !           518:        case MODE_CLIENT:
        !           519:                if (IS_MCAST(srcadr))
        !           520:                        cast_flags = MDF_ACAST;
        !           521:                else
        !           522:                        cast_flags = MDF_UCAST;
        !           523:                break;
        !           524: 
        !           525:        default:
        !           526:                cast_flags = MDF_UCAST;
        !           527:        }
        !           528: 
        !           529:        /*
        !           530:         * Mobilize the association and initialize its variables. If
        !           531:         * emulating ntpdate, force iburst.
        !           532:         */
        !           533:        if (mode_ntpdate)
        !           534:                flags |= FLAG_IBURST;
        !           535:        return(newpeer(srcadr, dstadr, hmode, version, minpoll, maxpoll,
        !           536:            flags | FLAG_CONFIG, cast_flags, ttl, key));
        !           537: }
        !           538: 
        !           539: /*
        !           540:  * setup peer dstadr field keeping it in sync with the interface
        !           541:  * structures
        !           542:  */
        !           543: void
        !           544: set_peerdstadr(
        !           545:        struct peer *   p,
        !           546:        endpt *         dstadr
        !           547:        )
        !           548: {
        !           549:        struct peer *   unlinked;
        !           550: 
        !           551:        if (p->dstadr == dstadr)
        !           552:                return;
        !           553: 
        !           554:        /*
        !           555:         * Don't accept updates to a separate multicast receive-only
        !           556:         * endpt while a BCLNT peer is running its unicast protocol.
        !           557:         */
        !           558:        if (dstadr != NULL && (FLAG_BC_VOL & p->flags) &&
        !           559:            (INT_MCASTIF & dstadr->flags) && MODE_CLIENT == p->hmode) {
        !           560:                return;
        !           561:        }
        !           562:        if (p->dstadr != NULL) {
        !           563:                p->dstadr->peercnt--;
        !           564:                UNLINK_SLIST(unlinked, p->dstadr->peers, p, ilink,
        !           565:                             struct peer);
        !           566:                msyslog(LOG_INFO, "%s interface %s -> %s",
        !           567:                        stoa(&p->srcadr), stoa(&p->dstadr->sin),
        !           568:                        (dstadr != NULL)
        !           569:                            ? stoa(&dstadr->sin)
        !           570:                            : "(none)");
        !           571:        }
        !           572:        p->dstadr = dstadr;
        !           573:        if (dstadr != NULL) {
        !           574:                LINK_SLIST(dstadr->peers, p, ilink);
        !           575:                dstadr->peercnt++;
        !           576:        }
        !           577: }
        !           578: 
        !           579: /*
        !           580:  * attempt to re-rebind interface if necessary
        !           581:  */
        !           582: static void
        !           583: peer_refresh_interface(
        !           584:        struct peer *peer
        !           585:        )
        !           586: {
        !           587:        endpt * niface;
        !           588:        endpt * piface;
        !           589: 
        !           590:        niface = select_peerinterface(peer, &peer->srcadr, NULL,
        !           591:                                      peer->cast_flags);
        !           592: 
        !           593:        DPRINTF(4, (
        !           594:            "peer_refresh_interface: %s->%s mode %d vers %d poll %d %d flags 0x%x 0x%x ttl %d key %08x: new interface: ",
        !           595:            peer->dstadr == NULL ? "<null>" :
        !           596:            stoa(&peer->dstadr->sin), stoa(&peer->srcadr),
        !           597:            peer->hmode, peer->version, peer->minpoll,
        !           598:            peer->maxpoll, peer->flags, peer->cast_flags,
        !           599:            peer->ttl, peer->keyid));
        !           600:        if (niface != NULL) {
        !           601:                DPRINTF(4, (
        !           602:                    "fd=%d, bfd=%d, name=%.16s, flags=0x%x, ifindex=%u, sin=%s",
        !           603:                    niface->fd,  niface->bfd, niface->name,
        !           604:                    niface->flags, niface->ifindex,
        !           605:                    stoa(&niface->sin)));
        !           606:                if (niface->flags & INT_BROADCAST)
        !           607:                        DPRINTF(4, (", bcast=%s",
        !           608:                                stoa(&niface->bcast)));
        !           609:                DPRINTF(4, (", mask=%s\n", stoa(&niface->mask)));
        !           610:        } else {
        !           611:                DPRINTF(4, ("<NONE>\n"));
        !           612:        }
        !           613: 
        !           614:        piface = peer->dstadr;
        !           615:        set_peerdstadr(peer, niface);
        !           616:        if (peer->dstadr) {
        !           617:                /*
        !           618:                 * clear crypto if we change the local address
        !           619:                 */
        !           620:                if (peer->dstadr != piface && !(peer->cast_flags &
        !           621:                    MDF_ACAST) && peer->pmode != MODE_BROADCAST)
        !           622:                        peer_clear(peer, "XFAC");
        !           623: 
        !           624:                /*
        !           625:                 * Broadcast needs the socket enabled for broadcast
        !           626:                 */
        !           627:                if (peer->cast_flags & MDF_BCAST) {
        !           628:                        enable_broadcast(peer->dstadr, &peer->srcadr);
        !           629:                }
        !           630: 
        !           631:                /*
        !           632:                 * Multicast needs the socket interface enabled for
        !           633:                 * multicast
        !           634:                 */
        !           635:                if (peer->cast_flags & MDF_MCAST) {
        !           636:                        enable_multicast_if(peer->dstadr,
        !           637:                            &peer->srcadr);
        !           638:                }
        !           639:        }
        !           640: }
        !           641: 
        !           642: /*
        !           643:  * refresh_all_peerinterfaces - see that all interface bindings are up
        !           644:  * to date
        !           645:  */
        !           646: void
        !           647: refresh_all_peerinterfaces(void)
        !           648: {
        !           649:        struct peer *peer, *next_peer;
        !           650:        int n;
        !           651: 
        !           652:        /*
        !           653:         * this is called when the interface list has changed
        !           654:         * give all peers a chance to find a better interface
        !           655:         */
        !           656:        for (n = 0; n < NTP_HASH_SIZE; n++) {
        !           657:                for (peer = peer_hash[n]; peer != 0; peer = next_peer) {
        !           658:                        next_peer = peer->next;
        !           659:                        peer_refresh_interface(peer);
        !           660:                }
        !           661:        }
        !           662: }
        !           663: 
        !           664:        
        !           665: /*
        !           666:  * find an interface suitable for the src address
        !           667:  */
        !           668: static endpt *
        !           669: select_peerinterface(
        !           670:        struct peer *   peer,
        !           671:        sockaddr_u *    srcadr,
        !           672:        endpt *         dstadr,
        !           673:        u_char          cast_flags
        !           674:        )
        !           675: {
        !           676:        endpt *ep;
        !           677:        endpt *wild;
        !           678: 
        !           679:        wild = ANY_INTERFACE_CHOOSE(srcadr);
        !           680: 
        !           681:        /*
        !           682:         * Initialize the peer structure and dance the interface jig.
        !           683:         * Reference clocks step the loopback waltz, the others
        !           684:         * squaredance around the interface list looking for a buddy. If
        !           685:         * the dance peters out, there is always the wildcard interface.
        !           686:         * This might happen in some systems and would preclude proper
        !           687:         * operation with public key cryptography.
        !           688:         */
        !           689:        if (ISREFCLOCKADR(srcadr)) {
        !           690:                ep = loopback_interface;
        !           691:        } else if (cast_flags & 
        !           692:                   (MDF_BCLNT | MDF_ACAST | MDF_MCAST | MDF_BCAST)) {
        !           693:                ep = findbcastinter(srcadr);
        !           694:                if (ep != NULL)
        !           695:                        DPRINTF(4, ("Found *-cast interface %s for address %s\n",
        !           696:                                stoa(&ep->sin), stoa(srcadr)));
        !           697:                else
        !           698:                        DPRINTF(4, ("No *-cast local address found for address %s\n",
        !           699:                                stoa(srcadr)));
        !           700:        } else {
        !           701:                ep = dstadr;
        !           702:                if (NULL == ep)
        !           703:                        ep = wild;
        !           704:        } 
        !           705:        /*
        !           706:         * If it is a multicast address, findbcastinter() may not find
        !           707:         * it.  For unicast, we get to find the interface when dstadr is
        !           708:         * given to us as the wildcard (ANY_INTERFACE_CHOOSE).  Either
        !           709:         * way, try a little harder.
        !           710:         */
        !           711:        if (wild == ep)
        !           712:                ep = findinterface(srcadr);
        !           713:        /*
        !           714:         * we do not bind to the wildcard interfaces for output 
        !           715:         * as our (network) source address would be undefined and
        !           716:         * crypto will not work without knowing the own transmit address
        !           717:         */
        !           718:        if (ep != NULL && INT_WILDCARD & ep->flags)
        !           719:                if (!accept_wildcard_if_for_winnt)  
        !           720:                        ep = NULL;
        !           721: 
        !           722:        return ep;
        !           723: }
        !           724: 
        !           725: /*
        !           726:  * newpeer - initialize a new peer association
        !           727:  */
        !           728: struct peer *
        !           729: newpeer(
        !           730:        sockaddr_u *srcadr,
        !           731:        struct interface *dstadr,
        !           732:        int     hmode,
        !           733:        int     version,
        !           734:        int     minpoll,
        !           735:        int     maxpoll,
        !           736:        u_int   flags,
        !           737:        u_char  cast_flags,
        !           738:        int     ttl,
        !           739:        keyid_t key
        !           740:        )
        !           741: {
        !           742:        struct peer *peer;
        !           743:        u_int   hash;
        !           744:        char    tbuf[80];
        !           745: 
        !           746: #ifdef OPENSSL
        !           747:        /*
        !           748:         * If Autokey is requested but not configured, complain loudly.
        !           749:         */
        !           750:        if (!crypto_flags) {
        !           751:                if (key > NTP_MAXKEY) {
        !           752:                        return (NULL);
        !           753: 
        !           754:                } else if (flags & FLAG_SKEY) {
        !           755:                        msyslog(LOG_ERR, "Autokey not configured");
        !           756:                        return (NULL);
        !           757:                } 
        !           758:        }
        !           759: #endif /* OPENSSL */
        !           760: 
        !           761:        /*
        !           762:         * First search from the beginning for an association with given
        !           763:         * remote address and mode. If an interface is given, search
        !           764:         * from there to find the association which matches that
        !           765:         * destination. If the given interface is "any", track down the
        !           766:         * actual interface, because that's what gets put into the peer
        !           767:         * structure.
        !           768:         */
        !           769:        if (dstadr != NULL) {
        !           770:                peer = findexistingpeer(srcadr, NULL, hmode, cast_flags);
        !           771:                while (peer != NULL) {
        !           772:                        if (peer->dstadr == dstadr ||
        !           773:                            ((MDF_BCLNT & cast_flags) &&
        !           774:                             (MDF_BCLNT & peer->cast_flags)))
        !           775:                                break;
        !           776: 
        !           777:                        if (dstadr == ANY_INTERFACE_CHOOSE(srcadr) &&
        !           778:                            peer->dstadr == findinterface(srcadr))
        !           779:                                break;
        !           780: 
        !           781:                        peer = findexistingpeer(srcadr, peer, hmode,
        !           782:                                                cast_flags);
        !           783:                }
        !           784:        } else {
        !           785:                /* no endpt address given */
        !           786:                peer = findexistingpeer(srcadr, NULL, hmode, cast_flags);
        !           787:        }
        !           788: 
        !           789:        /*
        !           790:         * If a peer is found, this would be a duplicate and we don't
        !           791:         * allow that. This avoids duplicate ephemeral (broadcast/
        !           792:         * multicast) and preemptible (manycast and pool) client
        !           793:         * associations.
        !           794:         */
        !           795:        if (peer != NULL)
        !           796:                return (NULL);
        !           797: 
        !           798:        /*
        !           799:         * Allocate a new peer structure. Some dirt here, since some of
        !           800:         * the initialization requires knowlege of our system state.
        !           801:         */
        !           802:        if (peer_free_count == 0)
        !           803:                getmorepeermem();
        !           804:        UNLINK_HEAD_SLIST(peer, peer_free, next);
        !           805:        peer_free_count--;
        !           806:        peer_associations++;
        !           807:        if (flags & FLAG_PREEMPT)
        !           808:                peer_preempt++;
        !           809:        memset(peer, 0, sizeof(*peer));
        !           810: 
        !           811:        /*
        !           812:         * Assign an association ID and increment the system variable.
        !           813:         */
        !           814:        peer->associd = current_association_ID;
        !           815:        if (++current_association_ID == 0)
        !           816:                ++current_association_ID;
        !           817: 
        !           818:        DPRINTF(3, ("newpeer: cast flags: 0x%x for address: %s\n",
        !           819:                    cast_flags, stoa(srcadr)));
        !           820: 
        !           821:        peer->srcadr = *srcadr;
        !           822:        set_peerdstadr(peer, select_peerinterface(peer, srcadr, dstadr,
        !           823:            cast_flags));
        !           824:        peer->hmode = (u_char)hmode;
        !           825:        peer->version = (u_char)version;
        !           826:        peer->flags = flags;
        !           827: 
        !           828:        /*
        !           829:         * It is an error to set minpoll less than NTP_MINPOLL or to
        !           830:         * set maxpoll greater than NTP_MAXPOLL. However, minpoll is
        !           831:         * clamped not greater than NTP_MAXPOLL and maxpoll is clamped
        !           832:         * not less than NTP_MINPOLL without complaint. Finally,
        !           833:         * minpoll is clamped not greater than maxpoll.
        !           834:         */
        !           835:        if (minpoll == 0)
        !           836:                peer->minpoll = NTP_MINDPOLL;
        !           837:        else
        !           838:                peer->minpoll = (u_char)min(minpoll, NTP_MAXPOLL);
        !           839:        if (maxpoll == 0)
        !           840:                peer->maxpoll = NTP_MAXDPOLL;
        !           841:        else
        !           842:                peer->maxpoll = (u_char)max(maxpoll, NTP_MINPOLL);
        !           843:        if (peer->minpoll > peer->maxpoll)
        !           844:                peer->minpoll = peer->maxpoll;
        !           845: 
        !           846:        if (peer->dstadr)
        !           847:                DPRINTF(3, ("newpeer: using fd %d and our addr %s\n",
        !           848:                            peer->dstadr->fd, stoa(&peer->dstadr->sin)));
        !           849:        else
        !           850:                DPRINTF(3, ("newpeer: local interface currently not bound\n")); 
        !           851: 
        !           852:        /*
        !           853:         * Broadcast needs the socket enabled for broadcast
        !           854:         */
        !           855:        if ((cast_flags & MDF_BCAST) && peer->dstadr)
        !           856:                enable_broadcast(peer->dstadr, srcadr);
        !           857: 
        !           858:        /*
        !           859:         * Multicast needs the socket interface enabled for multicast
        !           860:         */
        !           861:        if ((cast_flags & MDF_MCAST) && peer->dstadr)
        !           862:                enable_multicast_if(peer->dstadr, srcadr);
        !           863: 
        !           864: #ifdef OPENSSL
        !           865:        if (key > NTP_MAXKEY)
        !           866:                peer->flags |= FLAG_SKEY;
        !           867: #endif /* OPENSSL */
        !           868:        peer->cast_flags = cast_flags;
        !           869:        peer->ttl = (u_char)ttl;
        !           870:        peer->keyid = key;
        !           871:        peer->precision = sys_precision;
        !           872:        peer->hpoll = peer->minpoll;
        !           873:        if (cast_flags & MDF_ACAST)
        !           874:                peer_clear(peer, "ACST");
        !           875:        else if (cast_flags & MDF_MCAST)
        !           876:                peer_clear(peer, "MCST");
        !           877:        else if (cast_flags & MDF_BCAST)
        !           878:                peer_clear(peer, "BCST");
        !           879:        else
        !           880:                peer_clear(peer, "INIT");
        !           881:        if (mode_ntpdate)
        !           882:                peer_ntpdate++;
        !           883: 
        !           884:        /*
        !           885:         * Note time on statistics timers.
        !           886:         */
        !           887:        peer->timereset = current_time;
        !           888:        peer->timereachable = current_time;
        !           889:        peer->timereceived = current_time;
        !           890: 
        !           891: #ifdef REFCLOCK
        !           892:        if (ISREFCLOCKADR(&peer->srcadr)) {
        !           893: 
        !           894:                /*
        !           895:                 * We let the reference clock support do clock
        !           896:                 * dependent initialization.  This includes setting
        !           897:                 * the peer timer, since the clock may have requirements
        !           898:                 * for this.
        !           899:                 */
        !           900:                if (maxpoll == 0)
        !           901:                        peer->maxpoll = peer->minpoll;
        !           902:                if (!refclock_newpeer(peer)) {
        !           903:                        /*
        !           904:                         * Dump it, something screwed up
        !           905:                         */
        !           906:                        set_peerdstadr(peer, NULL);
        !           907:                        LINK_SLIST(peer_free, peer, next);
        !           908:                        peer_free_count++;
        !           909:                        return (NULL);
        !           910:                }
        !           911:        }
        !           912: #endif
        !           913: 
        !           914:        /*
        !           915:         * Put the new peer in the hash tables.
        !           916:         */
        !           917:        hash = NTP_HASH_ADDR(&peer->srcadr);
        !           918:        LINK_SLIST(peer_hash[hash], peer, next);
        !           919:        peer_hash_count[hash]++;
        !           920:        hash = peer->associd & NTP_HASH_MASK;
        !           921:        LINK_SLIST(assoc_hash[hash], peer, ass_next);
        !           922:        assoc_hash_count[hash]++;
        !           923:        snprintf(tbuf, sizeof(tbuf), "assoc %d", peer->associd);
        !           924:        report_event(PEVNT_MOBIL, peer, tbuf);
        !           925:        DPRINTF(1, ("newpeer: %s->%s mode %d vers %d poll %d %d flags 0x%x 0x%x ttl %d key %08x\n",
        !           926:            peer->dstadr == NULL ? "<null>" : stoa(&peer->dstadr->sin),
        !           927:            stoa(&peer->srcadr), peer->hmode, peer->version,
        !           928:            peer->minpoll, peer->maxpoll, peer->flags, peer->cast_flags,
        !           929:            peer->ttl, peer->keyid));
        !           930:        return (peer);
        !           931: }
        !           932: 
        !           933: 
        !           934: /*
        !           935:  * peer_clr_stats - clear peer module statiistics counters
        !           936:  */
        !           937: void
        !           938: peer_clr_stats(void)
        !           939: {
        !           940:        findpeer_calls = 0;
        !           941:        assocpeer_calls = 0;
        !           942:        peer_allocations = 0;
        !           943:        peer_demobilizations = 0;
        !           944:        peer_timereset = current_time;
        !           945: }
        !           946: 
        !           947: /*
        !           948:  * peer_reset - reset statistics counters
        !           949:  */
        !           950: void
        !           951: peer_reset(
        !           952:        struct peer *peer
        !           953:        )
        !           954: {
        !           955:        if (peer == NULL)
        !           956:                return;
        !           957: 
        !           958:        peer->timereset = current_time;
        !           959:        peer->sent = 0;
        !           960:        peer->received = 0;
        !           961:        peer->processed = 0;
        !           962:        peer->badauth = 0;
        !           963:        peer->bogusorg = 0;
        !           964:        peer->oldpkt = 0;
        !           965:        peer->seldisptoolarge = 0;
        !           966:        peer->selbroken = 0;
        !           967: }
        !           968: 
        !           969: 
        !           970: /*
        !           971:  * peer_all_reset - reset all peer statistics counters
        !           972:  */
        !           973: void
        !           974: peer_all_reset(void)
        !           975: {
        !           976:        struct peer *peer;
        !           977:        int hash;
        !           978: 
        !           979:        for (hash = 0; hash < NTP_HASH_SIZE; hash++)
        !           980:            for (peer = peer_hash[hash]; peer != 0; peer = peer->next)
        !           981:                peer_reset(peer);
        !           982: }
        !           983: 
        !           984: 
        !           985: /*
        !           986:  * findmanycastpeer - find and return a manycast peer
        !           987:  */
        !           988: struct peer *
        !           989: findmanycastpeer(
        !           990:        struct recvbuf *rbufp   /* receive buffer pointer */
        !           991:        )
        !           992: {
        !           993:        register struct peer *peer;
        !           994:        struct pkt *pkt;
        !           995:        l_fp p_org;
        !           996:        int i;
        !           997: 
        !           998:        /*
        !           999:         * This routine is called upon arrival of a server-mode message
        !          1000:         * from a manycast client. Search the peer list for a manycast
        !          1001:         * client association where the last transmit timestamp matches
        !          1002:         * the originate timestamp. This assumes the transmit timestamps
        !          1003:         * for possibly more than one manycast association are unique.
        !          1004:         */
        !          1005:        pkt = &rbufp->recv_pkt;
        !          1006:        for (i = 0; i < NTP_HASH_SIZE; i++) {
        !          1007:                if (peer_hash_count[i] == 0)
        !          1008:                        continue;
        !          1009: 
        !          1010:                for (peer = peer_hash[i]; peer != 0; peer =
        !          1011:                    peer->next) {
        !          1012:                        if (peer->cast_flags & MDF_ACAST) {
        !          1013:                                NTOHL_FP(&pkt->org, &p_org);
        !          1014:                                if (L_ISEQU(&p_org, &peer->aorg))
        !          1015:                                        return (peer);
        !          1016:                        }
        !          1017:                }
        !          1018:        }
        !          1019:        return (NULL);
        !          1020: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>