1*eabc0478Schristos /* $NetBSD: ntp_peer.c,v 1.14 2024/08/18 20:47:17 christos Exp $ */ 2abb0f93cSkardel 3abb0f93cSkardel /* 4abb0f93cSkardel * ntp_peer.c - management of data maintained for peer associations 5abb0f93cSkardel */ 6abb0f93cSkardel #ifdef HAVE_CONFIG_H 7abb0f93cSkardel #include <config.h> 8abb0f93cSkardel #endif 9abb0f93cSkardel 10abb0f93cSkardel #include <stdio.h> 11abb0f93cSkardel #include <sys/types.h> 12abb0f93cSkardel 13abb0f93cSkardel #include "ntpd.h" 14abb0f93cSkardel #include "ntp_lists.h" 15abb0f93cSkardel #include "ntp_stdlib.h" 16abb0f93cSkardel #include "ntp_control.h" 17abb0f93cSkardel #include <ntp_random.h> 18abb0f93cSkardel 19abb0f93cSkardel /* 20abb0f93cSkardel * Table of valid association combinations 21abb0f93cSkardel * --------------------------------------- 22abb0f93cSkardel * 23abb0f93cSkardel * packet->mode 24abb0f93cSkardel * peer->mode | UNSPEC ACTIVE PASSIVE CLIENT SERVER BCAST 25abb0f93cSkardel * ---------- | --------------------------------------------- 26abb0f93cSkardel * NO_PEER | e 1 0 1 1 1 27abb0f93cSkardel * ACTIVE | e 1 1 0 0 0 28abb0f93cSkardel * PASSIVE | e 1 e 0 0 0 29abb0f93cSkardel * CLIENT | e 0 0 0 1 0 30abb0f93cSkardel * SERVER | e 0 0 0 0 0 31abb0f93cSkardel * BCAST | e 0 0 0 0 0 32abb0f93cSkardel * BCLIENT | e 0 0 0 e 1 33abb0f93cSkardel * 34abb0f93cSkardel * One point to note here: a packet in BCAST mode can potentially match 35abb0f93cSkardel * a peer in CLIENT mode, but we that is a special case and we check for 36abb0f93cSkardel * that early in the decision process. This avoids having to keep track 37abb0f93cSkardel * of what kind of associations are possible etc... We actually 38abb0f93cSkardel * circumvent that problem by requiring that the first b(m)roadcast 39abb0f93cSkardel * received after the change back to BCLIENT mode sets the clock. 40abb0f93cSkardel */ 41abb0f93cSkardel #define AM_MODES 7 /* number of rows and columns */ 42abb0f93cSkardel #define NO_PEER 0 /* action when no peer is found */ 43abb0f93cSkardel 44*eabc0478Schristos const s_char AM[AM_MODES][AM_MODES] = { 452950cc38Schristos /* packet->mode */ 462950cc38Schristos /* peer { UNSPEC, ACTIVE, PASSIVE, CLIENT, SERVER, BCAST } */ 472950cc38Schristos /* mode */ 48abb0f93cSkardel /*NONE*/{ AM_ERR, AM_NEWPASS, AM_NOMATCH, AM_FXMIT, AM_MANYCAST, AM_NEWBCL}, 49abb0f93cSkardel 50abb0f93cSkardel /*A*/ { AM_ERR, AM_PROCPKT, AM_PROCPKT, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH}, 51abb0f93cSkardel 52abb0f93cSkardel /*P*/ { AM_ERR, AM_PROCPKT, AM_ERR, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH}, 53abb0f93cSkardel 54abb0f93cSkardel /*C*/ { AM_ERR, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH, AM_PROCPKT, AM_NOMATCH}, 55abb0f93cSkardel 56abb0f93cSkardel /*S*/ { AM_ERR, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH}, 57abb0f93cSkardel 58abb0f93cSkardel /*BCST*/{ AM_ERR, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH}, 59abb0f93cSkardel 60abb0f93cSkardel /*BCL*/ { AM_ERR, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH, AM_PROCPKT}, 61abb0f93cSkardel }; 62abb0f93cSkardel 63*eabc0478Schristos #define MATCH_ASSOC(x, y) (AM[CLAMP((x), 0, AM_MODES)][CLAMP((y), 0, AM_MODES)]) 64abb0f93cSkardel 65abb0f93cSkardel /* 66abb0f93cSkardel * These routines manage the allocation of memory to peer structures 672950cc38Schristos * and the maintenance of three data structures involving all peers: 682950cc38Schristos * 692950cc38Schristos * - peer_list is a single list with all peers, suitable for scanning 702950cc38Schristos * operations over all peers. 712950cc38Schristos * - peer_adr_hash is an array of lists indexed by hashed peer address. 722950cc38Schristos * - peer_aid_hash is an array of lists indexed by hashed associd. 732950cc38Schristos * 742950cc38Schristos * They also maintain a free list of peer structures, peer_free. 752950cc38Schristos * 762950cc38Schristos * The three main entry points are findpeer(), which looks for matching 772950cc38Schristos * peer structures in the peer list, newpeer(), which allocates a new 782950cc38Schristos * peer structure and adds it to the list, and unpeer(), which 792950cc38Schristos * demobilizes the association and deallocates the structure. 80abb0f93cSkardel */ 81abb0f93cSkardel /* 82abb0f93cSkardel * Peer hash tables 83abb0f93cSkardel */ 84abb0f93cSkardel struct peer *peer_hash[NTP_HASH_SIZE]; /* peer hash table */ 85abb0f93cSkardel int peer_hash_count[NTP_HASH_SIZE]; /* peers in each bucket */ 86abb0f93cSkardel struct peer *assoc_hash[NTP_HASH_SIZE]; /* association ID hash table */ 87abb0f93cSkardel int assoc_hash_count[NTP_HASH_SIZE];/* peers in each bucket */ 882950cc38Schristos struct peer *peer_list; /* peer structures list */ 89abb0f93cSkardel static struct peer *peer_free; /* peer structures free list */ 90abb0f93cSkardel int peer_free_count; /* count of free structures */ 91abb0f93cSkardel 92abb0f93cSkardel /* 93abb0f93cSkardel * Association ID. We initialize this value randomly, then assign a new 942950cc38Schristos * value every time an association is mobilized. 95abb0f93cSkardel */ 96*eabc0478Schristos static associd_t current_association_ID; /* actually next poss. ID */ 97*eabc0478Schristos static associd_t initial_association_ID; 98abb0f93cSkardel 99abb0f93cSkardel /* 100abb0f93cSkardel * Memory allocation watermarks. 101abb0f93cSkardel */ 1022950cc38Schristos #define INIT_PEER_ALLOC 8 /* static preallocation */ 1032950cc38Schristos #define INC_PEER_ALLOC 4 /* add N more when empty */ 104abb0f93cSkardel 105abb0f93cSkardel /* 106abb0f93cSkardel * Miscellaneous statistic counters which may be queried. 107abb0f93cSkardel */ 108abb0f93cSkardel u_long peer_timereset; /* time stat counters zeroed */ 109abb0f93cSkardel u_long findpeer_calls; /* calls to findpeer */ 110abb0f93cSkardel u_long assocpeer_calls; /* calls to findpeerbyassoc */ 111abb0f93cSkardel u_long peer_allocations; /* allocations from free list */ 112abb0f93cSkardel u_long peer_demobilizations; /* structs freed to free list */ 113abb0f93cSkardel int total_peer_structs; /* peer structs */ 114abb0f93cSkardel int peer_associations; /* mobilized associations */ 115abb0f93cSkardel int peer_preempt; /* preemptable associations */ 116abb0f93cSkardel static struct peer init_peer_alloc[INIT_PEER_ALLOC]; /* init alloc */ 117abb0f93cSkardel 1182950cc38Schristos static struct peer * findexistingpeer_name(const char *, u_short, 1192950cc38Schristos struct peer *, int); 1202950cc38Schristos static struct peer * findexistingpeer_addr(sockaddr_u *, 1212950cc38Schristos struct peer *, int, 1224eea345dSchristos u_char, int *); 1232950cc38Schristos static void free_peer(struct peer *, int); 124abb0f93cSkardel static void getmorepeermem(void); 125abb0f93cSkardel static int score(struct peer *); 126abb0f93cSkardel 1272950cc38Schristos 128abb0f93cSkardel /* 129abb0f93cSkardel * init_peer - initialize peer data structures and counters 130abb0f93cSkardel * 131abb0f93cSkardel * N.B. We use the random number routine in here. It had better be 132abb0f93cSkardel * initialized prior to getting here. 133abb0f93cSkardel */ 134abb0f93cSkardel void 135abb0f93cSkardel init_peer(void) 136abb0f93cSkardel { 1372950cc38Schristos int i; 138abb0f93cSkardel 139abb0f93cSkardel /* 1402950cc38Schristos * Initialize peer free list from static allocation. 141abb0f93cSkardel */ 1422950cc38Schristos for (i = COUNTOF(init_peer_alloc) - 1; i >= 0; i--) 1432950cc38Schristos LINK_SLIST(peer_free, &init_peer_alloc[i], p_link); 1442950cc38Schristos total_peer_structs = COUNTOF(init_peer_alloc); 1452950cc38Schristos peer_free_count = COUNTOF(init_peer_alloc); 146abb0f93cSkardel 147abb0f93cSkardel /* 148abb0f93cSkardel * Initialize our first association ID 149abb0f93cSkardel */ 1502950cc38Schristos do 1512950cc38Schristos current_association_ID = ntp_random() & ASSOCID_MAX; 1522950cc38Schristos while (!current_association_ID); 1537476e6e4Schristos initial_association_ID = current_association_ID; 154abb0f93cSkardel } 155abb0f93cSkardel 156abb0f93cSkardel 157abb0f93cSkardel /* 158abb0f93cSkardel * getmorepeermem - add more peer structures to the free list 159abb0f93cSkardel */ 160abb0f93cSkardel static void 161abb0f93cSkardel getmorepeermem(void) 162abb0f93cSkardel { 1632950cc38Schristos int i; 1642950cc38Schristos struct peer *peers; 165abb0f93cSkardel 166ccc794f0Schristos peers = eallocarray(INC_PEER_ALLOC, sizeof(*peers)); 1672950cc38Schristos 1682950cc38Schristos for (i = INC_PEER_ALLOC - 1; i >= 0; i--) 1692950cc38Schristos LINK_SLIST(peer_free, &peers[i], p_link); 170abb0f93cSkardel 171abb0f93cSkardel total_peer_structs += INC_PEER_ALLOC; 172abb0f93cSkardel peer_free_count += INC_PEER_ALLOC; 173abb0f93cSkardel } 174abb0f93cSkardel 175abb0f93cSkardel 1762950cc38Schristos static struct peer * 1772950cc38Schristos findexistingpeer_name( 1782950cc38Schristos const char * hostname, 1792950cc38Schristos u_short hname_fam, 1802950cc38Schristos struct peer * start_peer, 1812950cc38Schristos int mode 1822950cc38Schristos ) 1832950cc38Schristos { 1842950cc38Schristos struct peer *p; 1852950cc38Schristos 1862950cc38Schristos if (NULL == start_peer) 1872950cc38Schristos p = peer_list; 1882950cc38Schristos else 1892950cc38Schristos p = start_peer->p_link; 1902950cc38Schristos for (; p != NULL; p = p->p_link) 1912950cc38Schristos if (p->hostname != NULL 1922950cc38Schristos && (-1 == mode || p->hmode == mode) 1932950cc38Schristos && (AF_UNSPEC == hname_fam 1942950cc38Schristos || AF_UNSPEC == AF(&p->srcadr) 1952950cc38Schristos || hname_fam == AF(&p->srcadr)) 1962950cc38Schristos && !strcasecmp(p->hostname, hostname)) 1972950cc38Schristos break; 1982950cc38Schristos return p; 1992950cc38Schristos } 2002950cc38Schristos 2012950cc38Schristos 2022950cc38Schristos static 203abb0f93cSkardel struct peer * 2042950cc38Schristos findexistingpeer_addr( 205abb0f93cSkardel sockaddr_u * addr, 206abb0f93cSkardel struct peer * start_peer, 2073123f114Skardel int mode, 2084eea345dSchristos u_char cast_flags, 2094eea345dSchristos int * ip_count 210abb0f93cSkardel ) 211abb0f93cSkardel { 2122950cc38Schristos struct peer *peer; 2132950cc38Schristos 2144eea345dSchristos DPRINTF(2, ("findexistingpeer_addr(%s, %s, %d, 0x%x, %p)\n", 2152950cc38Schristos sptoa(addr), 2162950cc38Schristos (start_peer) 2172950cc38Schristos ? sptoa(&start_peer->srcadr) 2182950cc38Schristos : "NULL", 2194eea345dSchristos mode, (u_int)cast_flags, ip_count)); 220abb0f93cSkardel 221abb0f93cSkardel /* 222abb0f93cSkardel * start_peer is included so we can locate instances of the 223abb0f93cSkardel * same peer through different interfaces in the hash table. 2243123f114Skardel * Without MDF_BCLNT, a match requires the same mode and remote 2253123f114Skardel * address. MDF_BCLNT associations start out as MODE_CLIENT 2263123f114Skardel * if broadcastdelay is not specified, and switch to 2273123f114Skardel * MODE_BCLIENT after estimating the one-way delay. Duplicate 2283123f114Skardel * associations are expanded in definition to match any other 2293123f114Skardel * MDF_BCLNT with the same srcadr (remote, unicast address). 230abb0f93cSkardel */ 231abb0f93cSkardel if (NULL == start_peer) 232abb0f93cSkardel peer = peer_hash[NTP_HASH_ADDR(addr)]; 233abb0f93cSkardel else 2342950cc38Schristos peer = start_peer->adr_link; 235abb0f93cSkardel 236abb0f93cSkardel while (peer != NULL) { 2372950cc38Schristos DPRINTF(3, ("%s %s %d %d 0x%x 0x%x ", sptoa(addr), 2382950cc38Schristos sptoa(&peer->srcadr), mode, peer->hmode, 2392950cc38Schristos (u_int)cast_flags, (u_int)peer->cast_flags)); 2404eea345dSchristos if (ip_count) { 2414eea345dSchristos if (SOCK_EQ(addr, &peer->srcadr)) { 2424eea345dSchristos (*ip_count)++; 2434eea345dSchristos } 2444eea345dSchristos } 2452950cc38Schristos if ((-1 == mode || peer->hmode == mode || 2463123f114Skardel ((MDF_BCLNT & peer->cast_flags) && 2472950cc38Schristos (MDF_BCLNT & cast_flags))) && 2482950cc38Schristos ADDR_PORT_EQ(addr, &peer->srcadr)) { 2492950cc38Schristos DPRINTF(3, ("found.\n")); 250abb0f93cSkardel break; 2512950cc38Schristos } 2522950cc38Schristos DPRINTF(3, ("\n")); 2532950cc38Schristos peer = peer->adr_link; 254abb0f93cSkardel } 2553123f114Skardel 2563123f114Skardel return peer; 257abb0f93cSkardel } 258abb0f93cSkardel 259abb0f93cSkardel 260abb0f93cSkardel /* 261*eabc0478Schristos * findexistingpeer - search by name+family or address. 2622950cc38Schristos */ 2632950cc38Schristos struct peer * 2642950cc38Schristos findexistingpeer( 2652950cc38Schristos sockaddr_u * addr, 2662950cc38Schristos const char * hostname, 2672950cc38Schristos struct peer * start_peer, 2682950cc38Schristos int mode, 2694eea345dSchristos u_char cast_flags, 2704eea345dSchristos int * ip_count 2712950cc38Schristos ) 2722950cc38Schristos { 2732950cc38Schristos if (hostname != NULL) 2742950cc38Schristos return findexistingpeer_name(hostname, AF(addr), 2752950cc38Schristos start_peer, mode); 2762950cc38Schristos else 2772950cc38Schristos return findexistingpeer_addr(addr, start_peer, mode, 2784eea345dSchristos cast_flags, ip_count); 2792950cc38Schristos } 2802950cc38Schristos 2812950cc38Schristos 2822950cc38Schristos /* 2833123f114Skardel * findpeer - find and return a peer match for a received datagram in 2843123f114Skardel * the peer_hash table. 28503cfe0ffSchristos * 28603cfe0ffSchristos * [Bug 3072] To faciliate a faster reorganisation after routing changes 28703cfe0ffSchristos * the original code re-assigned the peer address to be the destination 28803cfe0ffSchristos * of the received packet and initiated another round on a mismatch. 28903cfe0ffSchristos * Unfortunately this leaves us wide open for a DoS attack where the 29003cfe0ffSchristos * attacker directs a packet with forged destination address to us -- 29103cfe0ffSchristos * this results in a wrong interface assignment, actually creating a DoS 29203cfe0ffSchristos * situation. 29303cfe0ffSchristos * 29403cfe0ffSchristos * This condition would persist until the next update of the interface 29503cfe0ffSchristos * list, but a continued attack would put us out of business again soon 29603cfe0ffSchristos * enough. Authentication alone does not help here, since it does not 29703cfe0ffSchristos * protect the UDP layer and leaves us open for a replay attack. 29803cfe0ffSchristos * 299*eabc0478Schristos * So we do not update the addresses and wait until the next interface 30003cfe0ffSchristos * list update does the right thing for us. 301abb0f93cSkardel */ 302abb0f93cSkardel struct peer * 303abb0f93cSkardel findpeer( 3043123f114Skardel struct recvbuf *rbufp, 305abb0f93cSkardel int pkt_mode, 306abb0f93cSkardel int * action 307abb0f93cSkardel ) 308abb0f93cSkardel { 3093123f114Skardel struct peer * p; 3103123f114Skardel sockaddr_u * srcadr; 311abb0f93cSkardel u_int hash; 3123123f114Skardel struct pkt * pkt; 3133123f114Skardel l_fp pkt_org; 314abb0f93cSkardel 315abb0f93cSkardel findpeer_calls++; 3163123f114Skardel srcadr = &rbufp->recv_srcadr; 317abb0f93cSkardel hash = NTP_HASH_ADDR(srcadr); 3182950cc38Schristos for (p = peer_hash[hash]; p != NULL; p = p->adr_link) { 319abb0f93cSkardel 32003cfe0ffSchristos /* [Bug 3072] ensure interface of peer matches */ 321ccc794f0Schristos /* [Bug 3356] ... if NOT a broadcast peer! */ 322ccc794f0Schristos if (p->hmode != MODE_BCLIENT && p->dstadr != rbufp->dstadr) 32303cfe0ffSchristos continue; 32403cfe0ffSchristos 32503cfe0ffSchristos /* ensure peer source address matches */ 32603cfe0ffSchristos if ( ! ADDR_PORT_EQ(srcadr, &p->srcadr)) 32703cfe0ffSchristos continue; 32803cfe0ffSchristos 32903cfe0ffSchristos /* If the association matching rules determine that this 33003cfe0ffSchristos * is not a valid combination, then look for the next 33103cfe0ffSchristos * valid peer association. 332abb0f93cSkardel */ 3333123f114Skardel *action = MATCH_ASSOC(p->hmode, pkt_mode); 3343123f114Skardel 33503cfe0ffSchristos /* A response to our manycastclient solicitation might 33603cfe0ffSchristos * be misassociated with an ephemeral peer already spun 33703cfe0ffSchristos * for the server. If the packet's org timestamp 33803cfe0ffSchristos * doesn't match the peer's, check if it matches the 33903cfe0ffSchristos * ACST prototype peer's. If so it is a redundant 34003cfe0ffSchristos * solicitation response, return AM_ERR to discard it. 34103cfe0ffSchristos * [Bug 1762] 3423123f114Skardel */ 34303cfe0ffSchristos if (MODE_SERVER == pkt_mode && AM_PROCPKT == *action) { 3443123f114Skardel pkt = &rbufp->recv_pkt; 3453123f114Skardel NTOHL_FP(&pkt->org, &pkt_org); 3463123f114Skardel if (!L_ISEQU(&p->aorg, &pkt_org) && 3473123f114Skardel findmanycastpeer(rbufp)) 3483123f114Skardel *action = AM_ERR; 3493123f114Skardel } 350abb0f93cSkardel 35103cfe0ffSchristos /* if an error was returned, exit back right here. */ 352*eabc0478Schristos if (*action == AM_ERR) { 3533123f114Skardel return NULL; 354*eabc0478Schristos } 355abb0f93cSkardel 35603cfe0ffSchristos /* if a match is found, we stop our search. */ 357*eabc0478Schristos if (*action != AM_NOMATCH) { 358abb0f93cSkardel break; 359abb0f93cSkardel } 360*eabc0478Schristos } 361abb0f93cSkardel 36203cfe0ffSchristos /* If no matching association is found... */ 363*eabc0478Schristos if (NULL == p) { 364abb0f93cSkardel *action = MATCH_ASSOC(NO_PEER, pkt_mode); 365*eabc0478Schristos } 3663123f114Skardel return p; 367abb0f93cSkardel } 368abb0f93cSkardel 369abb0f93cSkardel /* 3702950cc38Schristos * findpeerbyassoc - find and return a peer using his association ID 371abb0f93cSkardel */ 372abb0f93cSkardel struct peer * 373abb0f93cSkardel findpeerbyassoc( 3742950cc38Schristos associd_t assoc 375abb0f93cSkardel ) 376abb0f93cSkardel { 3773123f114Skardel struct peer *p; 378abb0f93cSkardel u_int hash; 379abb0f93cSkardel 380abb0f93cSkardel assocpeer_calls++; 381abb0f93cSkardel hash = assoc & NTP_HASH_MASK; 3822950cc38Schristos for (p = assoc_hash[hash]; p != NULL; p = p->aid_link) 3833123f114Skardel if (assoc == p->associd) 3842950cc38Schristos break; 3853123f114Skardel return p; 386abb0f93cSkardel } 387abb0f93cSkardel 388abb0f93cSkardel 389abb0f93cSkardel /* 390abb0f93cSkardel * clear_all - flush all time values for all associations 391abb0f93cSkardel */ 392abb0f93cSkardel void 393abb0f93cSkardel clear_all(void) 394abb0f93cSkardel { 3952950cc38Schristos struct peer *p; 396abb0f93cSkardel 397abb0f93cSkardel /* 398abb0f93cSkardel * This routine is called when the clock is stepped, and so all 399abb0f93cSkardel * previously saved time values are untrusted. 400abb0f93cSkardel */ 4012950cc38Schristos for (p = peer_list; p != NULL; p = p->p_link) 4022950cc38Schristos if (!(MDF_TXONLY_MASK & p->cast_flags)) 4032950cc38Schristos peer_clear(p, "STEP"); 4042950cc38Schristos 4052950cc38Schristos DPRINTF(1, ("clear_all: at %lu\n", current_time)); 406abb0f93cSkardel } 407abb0f93cSkardel 408abb0f93cSkardel 409abb0f93cSkardel /* 410abb0f93cSkardel * score_all() - determine if an association can be demobilized 411abb0f93cSkardel */ 412abb0f93cSkardel int 413abb0f93cSkardel score_all( 414abb0f93cSkardel struct peer *peer /* peer structure pointer */ 415abb0f93cSkardel ) 416abb0f93cSkardel { 4172950cc38Schristos struct peer *speer; 418abb0f93cSkardel int temp, tamp; 4192950cc38Schristos int x; 420abb0f93cSkardel 421abb0f93cSkardel /* 4222950cc38Schristos * This routine finds the minimum score for all preemptible 4232950cc38Schristos * associations and returns > 0 if the association can be 424abb0f93cSkardel * demobilized. 425abb0f93cSkardel */ 426abb0f93cSkardel tamp = score(peer); 427abb0f93cSkardel temp = 100; 4282950cc38Schristos for (speer = peer_list; speer != NULL; speer = speer->p_link) 4292950cc38Schristos if (speer->flags & FLAG_PREEMPT) { 4302950cc38Schristos x = score(speer); 4312950cc38Schristos if (x < temp) 432abb0f93cSkardel temp = x; 433abb0f93cSkardel } 4342950cc38Schristos DPRINTF(1, ("score_all: at %lu score %d min %d\n", 4352950cc38Schristos current_time, tamp, temp)); 4362950cc38Schristos 437abb0f93cSkardel if (tamp != temp) 438abb0f93cSkardel temp = 0; 4392950cc38Schristos 4402950cc38Schristos return temp; 441abb0f93cSkardel } 442abb0f93cSkardel 443abb0f93cSkardel 444abb0f93cSkardel /* 445abb0f93cSkardel * score() - calculate preemption score 446abb0f93cSkardel */ 447abb0f93cSkardel static int 448abb0f93cSkardel score( 449abb0f93cSkardel struct peer *peer /* peer structure pointer */ 450abb0f93cSkardel ) 451abb0f93cSkardel { 452abb0f93cSkardel int temp; 453abb0f93cSkardel 454abb0f93cSkardel /* 455abb0f93cSkardel * This routine calculates the premption score from the peer 456abb0f93cSkardel * error bits and status. Increasing values are more cherished. 457abb0f93cSkardel */ 458abb0f93cSkardel temp = 0; 459abb0f93cSkardel if (!(peer->flash & TEST10)) 460abb0f93cSkardel temp++; /* 1 good synch and stratum */ 461abb0f93cSkardel if (!(peer->flash & TEST13)) 462abb0f93cSkardel temp++; /* 2 reachable */ 463abb0f93cSkardel if (!(peer->flash & TEST12)) 464abb0f93cSkardel temp++; /* 3 no loop */ 465abb0f93cSkardel if (!(peer->flash & TEST11)) 466abb0f93cSkardel temp++; /* 4 good distance */ 467abb0f93cSkardel if (peer->status >= CTL_PST_SEL_SELCAND) 468abb0f93cSkardel temp++; /* 5 in the hunt */ 469abb0f93cSkardel if (peer->status != CTL_PST_SEL_EXCESS) 470abb0f93cSkardel temp++; /* 6 not spare tire */ 471abb0f93cSkardel return (temp); /* selection status */ 472abb0f93cSkardel } 473abb0f93cSkardel 474abb0f93cSkardel 475abb0f93cSkardel /* 4762950cc38Schristos * free_peer - internal routine to free memory referred to by a struct 4772950cc38Schristos * peer and return it to the peer free list. If unlink is 4782950cc38Schristos * nonzero, unlink from the various lists. 479abb0f93cSkardel */ 4802950cc38Schristos static void 4812950cc38Schristos free_peer( 4822950cc38Schristos struct peer * p, 4832950cc38Schristos int unlink_peer 484abb0f93cSkardel ) 485abb0f93cSkardel { 4862950cc38Schristos struct peer * unlinked; 487abb0f93cSkardel int hash; 488abb0f93cSkardel 4892950cc38Schristos if (unlink_peer) { 4902950cc38Schristos hash = NTP_HASH_ADDR(&p->srcadr); 491abb0f93cSkardel peer_hash_count[hash]--; 492abb0f93cSkardel 4932950cc38Schristos UNLINK_SLIST(unlinked, peer_hash[hash], p, adr_link, 494abb0f93cSkardel struct peer); 495abb0f93cSkardel if (NULL == unlinked) { 496abb0f93cSkardel peer_hash_count[hash]++; 4972950cc38Schristos msyslog(LOG_ERR, "peer %s not in address table!", 4982950cc38Schristos stoa(&p->srcadr)); 499abb0f93cSkardel } 500abb0f93cSkardel 501abb0f93cSkardel /* 502abb0f93cSkardel * Remove him from the association hash as well. 503abb0f93cSkardel */ 5042950cc38Schristos hash = p->associd & NTP_HASH_MASK; 505abb0f93cSkardel assoc_hash_count[hash]--; 506abb0f93cSkardel 5072950cc38Schristos UNLINK_SLIST(unlinked, assoc_hash[hash], p, aid_link, 5082950cc38Schristos struct peer); 509abb0f93cSkardel if (NULL == unlinked) { 510abb0f93cSkardel assoc_hash_count[hash]++; 511abb0f93cSkardel msyslog(LOG_ERR, 5122950cc38Schristos "peer %s not in association ID table!", 5132950cc38Schristos stoa(&p->srcadr)); 514abb0f93cSkardel } 515abb0f93cSkardel 5162950cc38Schristos /* Remove him from the overall list. */ 5172950cc38Schristos UNLINK_SLIST(unlinked, peer_list, p, p_link, 5182950cc38Schristos struct peer); 5192950cc38Schristos if (NULL == unlinked) 5202950cc38Schristos msyslog(LOG_ERR, "%s not in peer list!", 5212950cc38Schristos stoa(&p->srcadr)); 5222950cc38Schristos } 5232950cc38Schristos 5242950cc38Schristos if (p->hostname != NULL) 5252950cc38Schristos free(p->hostname); 5262950cc38Schristos 5272950cc38Schristos if (p->ident != NULL) 5282950cc38Schristos free(p->ident); 5292950cc38Schristos 5302950cc38Schristos if (p->addrs != NULL) 5312950cc38Schristos free(p->addrs); /* from copy_addrinfo_list() */ 5322950cc38Schristos 5332950cc38Schristos /* Add his corporeal form to peer free list */ 5342950cc38Schristos ZERO(*p); 5352950cc38Schristos LINK_SLIST(peer_free, p, p_link); 536abb0f93cSkardel peer_free_count++; 537abb0f93cSkardel } 538abb0f93cSkardel 539abb0f93cSkardel 540abb0f93cSkardel /* 5412950cc38Schristos * unpeer - remove peer structure from hash table and free structure 5422950cc38Schristos */ 5432950cc38Schristos void 5442950cc38Schristos unpeer( 5452950cc38Schristos struct peer *peer 5462950cc38Schristos ) 5472950cc38Schristos { 5482950cc38Schristos mprintf_event(PEVNT_DEMOBIL, peer, "assoc %u", peer->associd); 549*eabc0478Schristos restrict_source(&peer->srcadr, TRUE, 0); 550*eabc0478Schristos peer->flags |= FLAG_DISABLED; 5512950cc38Schristos set_peerdstadr(peer, NULL); 5522950cc38Schristos peer_demobilizations++; 5532950cc38Schristos peer_associations--; 5542950cc38Schristos if (FLAG_PREEMPT & peer->flags) 5552950cc38Schristos peer_preempt--; 5562950cc38Schristos #ifdef REFCLOCK 5572950cc38Schristos /* 5582950cc38Schristos * If this peer is actually a clock, shut it down first 5592950cc38Schristos */ 5602950cc38Schristos if (FLAG_REFCLOCK & peer->flags) 5612950cc38Schristos refclock_unpeer(peer); 5622950cc38Schristos #endif 5632950cc38Schristos 5642950cc38Schristos free_peer(peer, TRUE); 5652950cc38Schristos } 5662950cc38Schristos 5672950cc38Schristos 5682950cc38Schristos /* 569abb0f93cSkardel * peer_config - configure a new association 570abb0f93cSkardel */ 571abb0f93cSkardel struct peer * 572abb0f93cSkardel peer_config( 573abb0f93cSkardel sockaddr_u * srcadr, 5742950cc38Schristos const char * hostname, 5752950cc38Schristos endpt * dstadr, 5764eea345dSchristos int ippeerlimit, 5772950cc38Schristos u_char hmode, 5782950cc38Schristos u_char version, 5792950cc38Schristos u_char minpoll, 5802950cc38Schristos u_char maxpoll, 581abb0f93cSkardel u_int flags, 5822950cc38Schristos u_int32 ttl, 583abb0f93cSkardel keyid_t key, 5842950cc38Schristos const char * ident /* autokey group */ 585abb0f93cSkardel ) 586abb0f93cSkardel { 587abb0f93cSkardel u_char cast_flags; 588abb0f93cSkardel 589abb0f93cSkardel /* 590abb0f93cSkardel * We do a dirty little jig to figure the cast flags. This is 591abb0f93cSkardel * probably not the best place to do this, at least until the 592abb0f93cSkardel * configure code is rebuilt. Note only one flag can be set. 593abb0f93cSkardel */ 594abb0f93cSkardel switch (hmode) { 595abb0f93cSkardel case MODE_BROADCAST: 596abb0f93cSkardel if (IS_MCAST(srcadr)) 597abb0f93cSkardel cast_flags = MDF_MCAST; 598abb0f93cSkardel else 599abb0f93cSkardel cast_flags = MDF_BCAST; 600abb0f93cSkardel break; 601abb0f93cSkardel 602abb0f93cSkardel case MODE_CLIENT: 6032950cc38Schristos if (hostname != NULL && SOCK_UNSPEC(srcadr)) 6042950cc38Schristos cast_flags = MDF_POOL; 6052950cc38Schristos else if (IS_MCAST(srcadr)) 606abb0f93cSkardel cast_flags = MDF_ACAST; 607abb0f93cSkardel else 608abb0f93cSkardel cast_flags = MDF_UCAST; 609abb0f93cSkardel break; 610abb0f93cSkardel 611abb0f93cSkardel default: 612abb0f93cSkardel cast_flags = MDF_UCAST; 613abb0f93cSkardel } 614abb0f93cSkardel 615abb0f93cSkardel /* 616abb0f93cSkardel * Mobilize the association and initialize its variables. If 6172950cc38Schristos * emulating ntpdate, force iburst. For pool and manycastclient 6182950cc38Schristos * strip FLAG_PREEMPT as the prototype associations are not 6192950cc38Schristos * themselves preemptible, though the resulting associations 6202950cc38Schristos * are. 621abb0f93cSkardel */ 6222950cc38Schristos flags |= FLAG_CONFIG; 623abb0f93cSkardel if (mode_ntpdate) 624abb0f93cSkardel flags |= FLAG_IBURST; 6252950cc38Schristos if ((MDF_ACAST | MDF_POOL) & cast_flags) 6262950cc38Schristos flags &= ~FLAG_PREEMPT; 6274eea345dSchristos return newpeer(srcadr, hostname, dstadr, ippeerlimit, hmode, version, 6282950cc38Schristos minpoll, maxpoll, flags, cast_flags, ttl, key, ident); 629abb0f93cSkardel } 630abb0f93cSkardel 631abb0f93cSkardel /* 632abb0f93cSkardel * setup peer dstadr field keeping it in sync with the interface 633abb0f93cSkardel * structures 634abb0f93cSkardel */ 635abb0f93cSkardel void 636abb0f93cSkardel set_peerdstadr( 6373123f114Skardel struct peer * p, 6383123f114Skardel endpt * dstadr 639abb0f93cSkardel ) 640abb0f93cSkardel { 641abb0f93cSkardel struct peer * unlinked; 642abb0f93cSkardel 64303cfe0ffSchristos DEBUG_INSIST(p != NULL); 64403cfe0ffSchristos 64503cfe0ffSchristos if (p == NULL) 64603cfe0ffSchristos return; 64703cfe0ffSchristos 64803cfe0ffSchristos /* check for impossible or identical assignment */ 6493123f114Skardel if (p->dstadr == dstadr) 6503123f114Skardel return; 651abb0f93cSkardel 652abb0f93cSkardel /* 653*eabc0478Schristos * Do not change the local address of a link-local 654*eabc0478Schristos * peer address. 655*eabc0478Schristos */ 656*eabc0478Schristos if ( p->dstadr != NULL && is_linklocal(&p->dstadr->sin) 657*eabc0478Schristos && dstadr != NULL) { 658*eabc0478Schristos return; 659*eabc0478Schristos } 660*eabc0478Schristos 661*eabc0478Schristos /* 662*eabc0478Schristos * Do not set the local address for a link-local IPv6 peer 663*eabc0478Schristos * to one with a different scope ID. 664*eabc0478Schristos */ 665*eabc0478Schristos if ( dstadr != NULL && IS_IPV6(&p->srcadr) 666*eabc0478Schristos && SCOPE(&dstadr->sin) != SCOPE(&p->srcadr)) { 667*eabc0478Schristos return; 668*eabc0478Schristos } 669*eabc0478Schristos 670*eabc0478Schristos /* 6713123f114Skardel * Don't accept updates to a separate multicast receive-only 6723123f114Skardel * endpt while a BCLNT peer is running its unicast protocol. 673abb0f93cSkardel */ 6743123f114Skardel if (dstadr != NULL && (FLAG_BC_VOL & p->flags) && 6753123f114Skardel (INT_MCASTIF & dstadr->flags) && MODE_CLIENT == p->hmode) { 676abb0f93cSkardel return; 677abb0f93cSkardel } 67803cfe0ffSchristos 67903cfe0ffSchristos /* unlink from list if we have an address prior to assignment */ 6803123f114Skardel if (p->dstadr != NULL) { 6813123f114Skardel p->dstadr->peercnt--; 6823123f114Skardel UNLINK_SLIST(unlinked, p->dstadr->peers, p, ilink, 6833123f114Skardel struct peer); 684*eabc0478Schristos } 685*eabc0478Schristos if ( !IS_MCAST(&p->srcadr) && !(FLAG_DISABLED & p->flags) 686*eabc0478Schristos && !initializing) { 6872950cc38Schristos msyslog(LOG_INFO, "%s local addr %s -> %s", 688*eabc0478Schristos stoa(&p->srcadr), eptoa(p->dstadr), 689*eabc0478Schristos eptoa(dstadr)); 690abb0f93cSkardel } 69103cfe0ffSchristos 6923123f114Skardel p->dstadr = dstadr; 69303cfe0ffSchristos 69403cfe0ffSchristos /* link to list if we have an address after assignment */ 69503cfe0ffSchristos if (p->dstadr != NULL) { 6963123f114Skardel LINK_SLIST(dstadr->peers, p, ilink); 6973123f114Skardel dstadr->peercnt++; 698abb0f93cSkardel } 699abb0f93cSkardel } 700abb0f93cSkardel 701abb0f93cSkardel /* 702abb0f93cSkardel * attempt to re-rebind interface if necessary 703abb0f93cSkardel */ 704abb0f93cSkardel static void 705abb0f93cSkardel peer_refresh_interface( 7062950cc38Schristos struct peer *p 707abb0f93cSkardel ) 708abb0f93cSkardel { 7093123f114Skardel endpt * niface; 7103123f114Skardel endpt * piface; 711abb0f93cSkardel 7122950cc38Schristos niface = select_peerinterface(p, &p->srcadr, NULL); 713abb0f93cSkardel 7143123f114Skardel DPRINTF(4, ( 7152950cc38Schristos "peer_refresh_interface: %s->%s mode %d vers %d poll %d %d flags 0x%x 0x%x ttl %u key %08x: new interface: ", 7162950cc38Schristos p->dstadr == NULL ? "<null>" : 7172950cc38Schristos stoa(&p->dstadr->sin), stoa(&p->srcadr), p->hmode, 7182950cc38Schristos p->version, p->minpoll, p->maxpoll, p->flags, p->cast_flags, 7192950cc38Schristos p->ttl, p->keyid)); 720abb0f93cSkardel if (niface != NULL) { 7213123f114Skardel DPRINTF(4, ( 7223123f114Skardel "fd=%d, bfd=%d, name=%.16s, flags=0x%x, ifindex=%u, sin=%s", 723abb0f93cSkardel niface->fd, niface->bfd, niface->name, 7243123f114Skardel niface->flags, niface->ifindex, 7253123f114Skardel stoa(&niface->sin))); 726abb0f93cSkardel if (niface->flags & INT_BROADCAST) 7273123f114Skardel DPRINTF(4, (", bcast=%s", 7283123f114Skardel stoa(&niface->bcast))); 7293123f114Skardel DPRINTF(4, (", mask=%s\n", stoa(&niface->mask))); 730abb0f93cSkardel } else { 7313123f114Skardel DPRINTF(4, ("<NONE>\n")); 732abb0f93cSkardel } 733abb0f93cSkardel 7342950cc38Schristos piface = p->dstadr; 7352950cc38Schristos set_peerdstadr(p, niface); 7362950cc38Schristos if (p->dstadr != NULL) { 737abb0f93cSkardel /* 738abb0f93cSkardel * clear crypto if we change the local address 739abb0f93cSkardel */ 7402950cc38Schristos if (p->dstadr != piface && !(MDF_ACAST & p->cast_flags) 7412950cc38Schristos && MODE_BROADCAST != p->pmode) 7422950cc38Schristos peer_clear(p, "XFAC"); 743abb0f93cSkardel 744abb0f93cSkardel /* 745abb0f93cSkardel * Broadcast needs the socket enabled for broadcast 746abb0f93cSkardel */ 7472950cc38Schristos if (MDF_BCAST & p->cast_flags) 7482950cc38Schristos enable_broadcast(p->dstadr, &p->srcadr); 749abb0f93cSkardel 750abb0f93cSkardel /* 751abb0f93cSkardel * Multicast needs the socket interface enabled for 752abb0f93cSkardel * multicast 753abb0f93cSkardel */ 7542950cc38Schristos if (MDF_MCAST & p->cast_flags) 7552950cc38Schristos enable_multicast_if(p->dstadr, &p->srcadr); 756abb0f93cSkardel } 757abb0f93cSkardel } 7582950cc38Schristos 759abb0f93cSkardel 760abb0f93cSkardel /* 761abb0f93cSkardel * refresh_all_peerinterfaces - see that all interface bindings are up 762abb0f93cSkardel * to date 763abb0f93cSkardel */ 764abb0f93cSkardel void 765abb0f93cSkardel refresh_all_peerinterfaces(void) 766abb0f93cSkardel { 7672950cc38Schristos struct peer *p; 768abb0f93cSkardel 769abb0f93cSkardel /* 770*eabc0478Schristos * This is called when the interface list has changed. 771*eabc0478Schristos * Give peers a chance to find a better interface. 772abb0f93cSkardel */ 773af12ab5eSchristos for (p = peer_list; p != NULL; p = p->p_link) { 774*eabc0478Schristos /* 775*eabc0478Schristos * Bug 2849 XOR 2043 776*eabc0478Schristos * Change local address only if the peer doesn't 777*eabc0478Schristos * have a local address already or if the one 778*eabc0478Schristos * they have hasn't worked for a while. 779*eabc0478Schristos */ 780*eabc0478Schristos if (p->dstadr != NULL && (p->reach & 0x3)) { 781*eabc0478Schristos continue; 782*eabc0478Schristos } 7832950cc38Schristos peer_refresh_interface(p); 784abb0f93cSkardel } 785af12ab5eSchristos } 786abb0f93cSkardel 787abb0f93cSkardel 788abb0f93cSkardel /* 789abb0f93cSkardel * newpeer - initialize a new peer association 790abb0f93cSkardel */ 791abb0f93cSkardel struct peer * 792abb0f93cSkardel newpeer( 793abb0f93cSkardel sockaddr_u * srcadr, 7942950cc38Schristos const char * hostname, 7952950cc38Schristos endpt * dstadr, 7964eea345dSchristos int ippeerlimit, 7972950cc38Schristos u_char hmode, 7982950cc38Schristos u_char version, 7992950cc38Schristos u_char minpoll, 8002950cc38Schristos u_char maxpoll, 801abb0f93cSkardel u_int flags, 802abb0f93cSkardel u_char cast_flags, 8032950cc38Schristos u_int32 ttl, 8042950cc38Schristos keyid_t key, 8052950cc38Schristos const char * ident 806abb0f93cSkardel ) 807abb0f93cSkardel { 808abb0f93cSkardel struct peer * peer; 809abb0f93cSkardel u_int hash; 8104eea345dSchristos int ip_count = 0; 8114eea345dSchristos 812af12ab5eSchristos DEBUG_REQUIRE(srcadr); 813af12ab5eSchristos 8142950cc38Schristos #ifdef AUTOKEY 815abb0f93cSkardel /* 816abb0f93cSkardel * If Autokey is requested but not configured, complain loudly. 817abb0f93cSkardel */ 818abb0f93cSkardel if (!crypto_flags) { 819abb0f93cSkardel if (key > NTP_MAXKEY) { 820abb0f93cSkardel return (NULL); 821abb0f93cSkardel 822abb0f93cSkardel } else if (flags & FLAG_SKEY) { 823*eabc0478Schristos msyslog(LOG_ERR, "Rejecting Autokey with %s," 824*eabc0478Schristos " built without support.", 825*eabc0478Schristos stoa(srcadr)); 826abb0f93cSkardel return (NULL); 827abb0f93cSkardel } 828abb0f93cSkardel } 8292950cc38Schristos #endif /* AUTOKEY */ 8302950cc38Schristos 8312950cc38Schristos /* 8322950cc38Schristos * For now only pool associations have a hostname. 8332950cc38Schristos */ 834af12ab5eSchristos INSIST(NULL == hostname || (MDF_POOL & cast_flags)); 835abb0f93cSkardel 836abb0f93cSkardel /* 837abb0f93cSkardel * First search from the beginning for an association with given 838abb0f93cSkardel * remote address and mode. If an interface is given, search 839abb0f93cSkardel * from there to find the association which matches that 840abb0f93cSkardel * destination. If the given interface is "any", track down the 841abb0f93cSkardel * actual interface, because that's what gets put into the peer 842abb0f93cSkardel * structure. 843abb0f93cSkardel */ 844abb0f93cSkardel if (dstadr != NULL) { 8452950cc38Schristos peer = findexistingpeer(srcadr, hostname, NULL, hmode, 8464eea345dSchristos cast_flags, &ip_count); 847abb0f93cSkardel while (peer != NULL) { 8484eea345dSchristos if ( peer->dstadr == dstadr 8494eea345dSchristos || ( (MDF_BCLNT & cast_flags) 8504eea345dSchristos && (MDF_BCLNT & peer->cast_flags))) 851abb0f93cSkardel break; 852abb0f93cSkardel 853abb0f93cSkardel if (dstadr == ANY_INTERFACE_CHOOSE(srcadr) && 854abb0f93cSkardel peer->dstadr == findinterface(srcadr)) 855abb0f93cSkardel break; 856abb0f93cSkardel 8572950cc38Schristos peer = findexistingpeer(srcadr, hostname, peer, 8584eea345dSchristos hmode, cast_flags, &ip_count); 859abb0f93cSkardel } 8603123f114Skardel } else { 8613123f114Skardel /* no endpt address given */ 8622950cc38Schristos peer = findexistingpeer(srcadr, hostname, NULL, hmode, 8634eea345dSchristos cast_flags, &ip_count); 864abb0f93cSkardel } 865abb0f93cSkardel 866abb0f93cSkardel /* 867*eabc0478Schristos * In any case, do not create an association with a duplicate 868*eabc0478Schristos * remote address (srcadr) except for undefined (zero) address. 869*eabc0478Schristos * Arguably this should be part of the logic above but 870*eabc0478Schristos * [Bug 3888] exposed a situation with manycastclient where 871*eabc0478Schristos * duplicate associations happened. 872*eabc0478Schristos */ 873*eabc0478Schristos if (NULL == peer) { 874*eabc0478Schristos for (peer = peer_list; 875*eabc0478Schristos peer != NULL; 876*eabc0478Schristos peer = peer->p_link) { 877*eabc0478Schristos if ( SOCK_EQ(srcadr, &peer->srcadr) 878*eabc0478Schristos && !SOCK_UNSPEC(srcadr) 879*eabc0478Schristos && !SOCK_UNSPEC(&peer->srcadr)) { 880*eabc0478Schristos /* leave peer non-NULL */ 881*eabc0478Schristos break; 882*eabc0478Schristos } 883*eabc0478Schristos } 884*eabc0478Schristos } 885*eabc0478Schristos 886*eabc0478Schristos /* 887abb0f93cSkardel * If a peer is found, this would be a duplicate and we don't 8883123f114Skardel * allow that. This avoids duplicate ephemeral (broadcast/ 8893123f114Skardel * multicast) and preemptible (manycast and pool) client 890abb0f93cSkardel * associations. 891abb0f93cSkardel */ 8922950cc38Schristos if (peer != NULL) { 893*eabc0478Schristos DPRINTF(2, ("%s(%s) found existing association\n", 894*eabc0478Schristos __func__, 8952950cc38Schristos (hostname) 8962950cc38Schristos ? hostname 8972950cc38Schristos : stoa(srcadr))); 8982950cc38Schristos return NULL; 8992950cc38Schristos } 900abb0f93cSkardel 901cdfa2a7eSchristos #if 0 9024eea345dSchristos DPRINTF(1, ("newpeer(%s) found no existing and %d other associations\n", 9034eea345dSchristos (hostname) 9044eea345dSchristos ? hostname 9054eea345dSchristos : stoa(srcadr), 9064eea345dSchristos ip_count)); 907cdfa2a7eSchristos #endif 9084eea345dSchristos 9094eea345dSchristos /* Check ippeerlimit wrt ip_count */ 9104eea345dSchristos if (ippeerlimit > -1) { 9114eea345dSchristos if (ip_count + 1 > ippeerlimit) { 9124eea345dSchristos DPRINTF(2, ("newpeer(%s) denied - ippeerlimit %d\n", 9134eea345dSchristos (hostname) 9144eea345dSchristos ? hostname 9154eea345dSchristos : stoa(srcadr), 9164eea345dSchristos ippeerlimit)); 9174eea345dSchristos return NULL; 9184eea345dSchristos } 9194eea345dSchristos } else { 9204eea345dSchristos DPRINTF(1, ("newpeer(%s) - ippeerlimit %d ignored\n", 9214eea345dSchristos (hostname) 9224eea345dSchristos ? hostname 9234eea345dSchristos : stoa(srcadr), 9244eea345dSchristos ippeerlimit)); 9254eea345dSchristos } 9264eea345dSchristos 927abb0f93cSkardel /* 928abb0f93cSkardel * Allocate a new peer structure. Some dirt here, since some of 929abb0f93cSkardel * the initialization requires knowlege of our system state. 930abb0f93cSkardel */ 931abb0f93cSkardel if (peer_free_count == 0) 932abb0f93cSkardel getmorepeermem(); 9332950cc38Schristos UNLINK_HEAD_SLIST(peer, peer_free, p_link); 934af12ab5eSchristos INSIST(peer != NULL); 935abb0f93cSkardel peer_free_count--; 936abb0f93cSkardel peer_associations++; 9372950cc38Schristos if (FLAG_PREEMPT & flags) 938abb0f93cSkardel peer_preempt++; 939abb0f93cSkardel 940abb0f93cSkardel /* 941*eabc0478Schristos * Assign an available association ID. Zero is reserved. 942abb0f93cSkardel */ 943*eabc0478Schristos do { 944*eabc0478Schristos while (0 == ++current_association_ID) { 945*eabc0478Schristos /* EMPTY */ 946*eabc0478Schristos } 947*eabc0478Schristos } while (NULL != findpeerbyassoc(current_association_ID)); 948abb0f93cSkardel peer->associd = current_association_ID; 949abb0f93cSkardel 950abb0f93cSkardel peer->srcadr = *srcadr; 951*eabc0478Schristos if (hostname != NULL) { 9522950cc38Schristos peer->hostname = estrdup(hostname); 953*eabc0478Schristos } 9542950cc38Schristos peer->hmode = hmode; 9552950cc38Schristos peer->version = version; 956abb0f93cSkardel peer->flags = flags; 9572950cc38Schristos peer->cast_flags = cast_flags; 9582950cc38Schristos set_peerdstadr(peer, 9592950cc38Schristos select_peerinterface(peer, srcadr, dstadr)); 960abb0f93cSkardel 961abb0f93cSkardel /* 962*eabc0478Schristos * Zero for minpoll or maxpoll means use defaults. 963abb0f93cSkardel */ 964*eabc0478Schristos peer->maxpoll = (0 == maxpoll) 965*eabc0478Schristos ? NTP_MAXDPOLL 966*eabc0478Schristos : maxpoll; 967*eabc0478Schristos peer->minpoll = (0 == minpoll) 968*eabc0478Schristos ? NTP_MINDPOLL 969*eabc0478Schristos : minpoll; 970abb0f93cSkardel 971*eabc0478Schristos /* 972*eabc0478Schristos * Clamp maxpoll and minpoll within NTP_MINPOLL and NTP_MAXPOLL, 973*eabc0478Schristos * and further clamp minpoll less than or equal maxpoll. 974*eabc0478Schristos */ 975*eabc0478Schristos peer->maxpoll = CLAMP(peer->maxpoll, NTP_MINPOLL, NTP_MAXPOLL); 976*eabc0478Schristos peer->minpoll = CLAMP(peer->minpoll, NTP_MINPOLL, peer->maxpoll); 977*eabc0478Schristos 978*eabc0478Schristos if (peer->dstadr != NULL) { 9792950cc38Schristos DPRINTF(3, ("newpeer(%s): using fd %d and our addr %s\n", 9802950cc38Schristos stoa(srcadr), peer->dstadr->fd, 9812950cc38Schristos stoa(&peer->dstadr->sin))); 982*eabc0478Schristos } else { 983*eabc0478Schristos DPRINTF(3, ("newpeer(%s): local addr unavailable\n", 9842950cc38Schristos stoa(srcadr))); 985*eabc0478Schristos } 986abb0f93cSkardel /* 987abb0f93cSkardel * Broadcast needs the socket enabled for broadcast 988abb0f93cSkardel */ 989*eabc0478Schristos if ((MDF_BCAST & cast_flags) && peer->dstadr != NULL) { 990abb0f93cSkardel enable_broadcast(peer->dstadr, srcadr); 991*eabc0478Schristos } 992abb0f93cSkardel /* 993abb0f93cSkardel * Multicast needs the socket interface enabled for multicast 994abb0f93cSkardel */ 995*eabc0478Schristos if ((MDF_MCAST & cast_flags) && peer->dstadr != NULL) { 996abb0f93cSkardel enable_multicast_if(peer->dstadr, srcadr); 997*eabc0478Schristos } 9982950cc38Schristos #ifdef AUTOKEY 999abb0f93cSkardel if (key > NTP_MAXKEY) 1000abb0f93cSkardel peer->flags |= FLAG_SKEY; 10012950cc38Schristos #endif /* AUTOKEY */ 10022950cc38Schristos peer->ttl = ttl; 1003abb0f93cSkardel peer->keyid = key; 1004*eabc0478Schristos if (ident != NULL) { 10052950cc38Schristos peer->ident = estrdup(ident); 1006*eabc0478Schristos } 1007abb0f93cSkardel peer->precision = sys_precision; 1008abb0f93cSkardel peer->hpoll = peer->minpoll; 1009*eabc0478Schristos if (cast_flags & MDF_ACAST) { 1010abb0f93cSkardel peer_clear(peer, "ACST"); 1011*eabc0478Schristos } else if (cast_flags & MDF_POOL) { 10122950cc38Schristos peer_clear(peer, "POOL"); 1013*eabc0478Schristos } else if (cast_flags & MDF_MCAST) { 1014abb0f93cSkardel peer_clear(peer, "MCST"); 1015*eabc0478Schristos } else if (cast_flags & MDF_BCAST) { 1016abb0f93cSkardel peer_clear(peer, "BCST"); 1017*eabc0478Schristos } else { 1018abb0f93cSkardel peer_clear(peer, "INIT"); 1019*eabc0478Schristos } 1020*eabc0478Schristos if (mode_ntpdate) { 1021abb0f93cSkardel peer_ntpdate++; 1022*eabc0478Schristos } 1023abb0f93cSkardel /* 1024abb0f93cSkardel * Note time on statistics timers. 1025abb0f93cSkardel */ 1026abb0f93cSkardel peer->timereset = current_time; 1027abb0f93cSkardel peer->timereachable = current_time; 1028abb0f93cSkardel peer->timereceived = current_time; 1029abb0f93cSkardel 1030abb0f93cSkardel if (ISREFCLOCKADR(&peer->srcadr)) { 10312950cc38Schristos #ifdef REFCLOCK 1032abb0f93cSkardel /* 1033abb0f93cSkardel * We let the reference clock support do clock 1034abb0f93cSkardel * dependent initialization. This includes setting 1035abb0f93cSkardel * the peer timer, since the clock may have requirements 1036abb0f93cSkardel * for this. 1037abb0f93cSkardel */ 1038abb0f93cSkardel if (!refclock_newpeer(peer)) { 1039abb0f93cSkardel /* 1040abb0f93cSkardel * Dump it, something screwed up 1041abb0f93cSkardel */ 1042abb0f93cSkardel set_peerdstadr(peer, NULL); 10432950cc38Schristos free_peer(peer, 0); 10442950cc38Schristos return NULL; 1045abb0f93cSkardel } 10462950cc38Schristos #else /* REFCLOCK */ 10472950cc38Schristos msyslog(LOG_ERR, "refclock %s isn't supported. ntpd was compiled without refclock support.", 10482950cc38Schristos stoa(&peer->srcadr)); 10492950cc38Schristos set_peerdstadr(peer, NULL); 10502950cc38Schristos free_peer(peer, 0); 10512950cc38Schristos return NULL; 10522950cc38Schristos #endif /* REFCLOCK */ 1053abb0f93cSkardel } 1054abb0f93cSkardel 1055abb0f93cSkardel /* 1056abb0f93cSkardel * Put the new peer in the hash tables. 1057abb0f93cSkardel */ 1058abb0f93cSkardel hash = NTP_HASH_ADDR(&peer->srcadr); 10592950cc38Schristos LINK_SLIST(peer_hash[hash], peer, adr_link); 1060abb0f93cSkardel peer_hash_count[hash]++; 1061abb0f93cSkardel hash = peer->associd & NTP_HASH_MASK; 10622950cc38Schristos LINK_SLIST(assoc_hash[hash], peer, aid_link); 1063abb0f93cSkardel assoc_hash_count[hash]++; 10642950cc38Schristos LINK_SLIST(peer_list, peer, p_link); 10652950cc38Schristos 1066*eabc0478Schristos restrict_source(&peer->srcadr, FALSE, 0); 10672950cc38Schristos mprintf_event(PEVNT_MOBIL, peer, "assoc %d", peer->associd); 10682950cc38Schristos DPRINTF(1, ("newpeer: %s->%s mode %u vers %u poll %u %u flags 0x%x 0x%x ttl %u key %08x\n", 10692950cc38Schristos latoa(peer->dstadr), stoa(&peer->srcadr), peer->hmode, 10702950cc38Schristos peer->version, peer->minpoll, peer->maxpoll, peer->flags, 10712950cc38Schristos peer->cast_flags, peer->ttl, peer->keyid)); 10722950cc38Schristos return peer; 1073abb0f93cSkardel } 1074abb0f93cSkardel 1075abb0f93cSkardel 1076abb0f93cSkardel /* 10772950cc38Schristos * peer_clr_stats - clear peer module statistics counters 1078abb0f93cSkardel */ 1079abb0f93cSkardel void 1080abb0f93cSkardel peer_clr_stats(void) 1081abb0f93cSkardel { 1082abb0f93cSkardel findpeer_calls = 0; 1083abb0f93cSkardel assocpeer_calls = 0; 1084abb0f93cSkardel peer_allocations = 0; 1085abb0f93cSkardel peer_demobilizations = 0; 1086abb0f93cSkardel peer_timereset = current_time; 1087abb0f93cSkardel } 1088abb0f93cSkardel 10892950cc38Schristos 1090abb0f93cSkardel /* 1091abb0f93cSkardel * peer_reset - reset statistics counters 1092abb0f93cSkardel */ 1093abb0f93cSkardel void 1094abb0f93cSkardel peer_reset( 1095abb0f93cSkardel struct peer *peer 1096abb0f93cSkardel ) 1097abb0f93cSkardel { 1098abb0f93cSkardel if (peer == NULL) 1099abb0f93cSkardel return; 1100abb0f93cSkardel 1101abb0f93cSkardel peer->timereset = current_time; 1102abb0f93cSkardel peer->sent = 0; 1103abb0f93cSkardel peer->received = 0; 1104abb0f93cSkardel peer->processed = 0; 1105abb0f93cSkardel peer->badauth = 0; 1106abb0f93cSkardel peer->bogusorg = 0; 1107abb0f93cSkardel peer->oldpkt = 0; 1108abb0f93cSkardel peer->seldisptoolarge = 0; 1109abb0f93cSkardel peer->selbroken = 0; 1110abb0f93cSkardel } 1111abb0f93cSkardel 1112abb0f93cSkardel 1113abb0f93cSkardel /* 1114abb0f93cSkardel * peer_all_reset - reset all peer statistics counters 1115abb0f93cSkardel */ 1116abb0f93cSkardel void 1117abb0f93cSkardel peer_all_reset(void) 1118abb0f93cSkardel { 1119abb0f93cSkardel struct peer *peer; 1120abb0f93cSkardel 11212950cc38Schristos for (peer = peer_list; peer != NULL; peer = peer->p_link) 1122abb0f93cSkardel peer_reset(peer); 1123abb0f93cSkardel } 1124abb0f93cSkardel 1125abb0f93cSkardel 1126abb0f93cSkardel /* 11272950cc38Schristos * findmanycastpeer - find and return a manycastclient or pool 11282950cc38Schristos * association matching a received response. 1129abb0f93cSkardel */ 1130abb0f93cSkardel struct peer * 1131abb0f93cSkardel findmanycastpeer( 1132abb0f93cSkardel struct recvbuf *rbufp /* receive buffer pointer */ 1133abb0f93cSkardel ) 1134abb0f93cSkardel { 11352950cc38Schristos struct peer *peer; 1136abb0f93cSkardel struct pkt *pkt; 1137abb0f93cSkardel l_fp p_org; 1138abb0f93cSkardel 1139abb0f93cSkardel /* 11402950cc38Schristos * This routine is called upon arrival of a server-mode response 11412950cc38Schristos * to a manycastclient multicast solicitation, or to a pool 11422950cc38Schristos * server unicast solicitation. Search the peer list for a 11432950cc38Schristos * manycastclient association where the last transmit timestamp 11442950cc38Schristos * matches the response packet's originate timestamp. There can 11452950cc38Schristos * be multiple manycastclient associations, or multiple pool 11462950cc38Schristos * solicitation assocations, so this assumes the transmit 11472950cc38Schristos * timestamps are unique for such. 1148abb0f93cSkardel */ 1149abb0f93cSkardel pkt = &rbufp->recv_pkt; 11502950cc38Schristos for (peer = peer_list; peer != NULL; peer = peer->p_link) 11512950cc38Schristos if (MDF_SOLICIT_MASK & peer->cast_flags) { 1152abb0f93cSkardel NTOHL_FP(&pkt->org, &p_org); 1153*eabc0478Schristos if (L_ISEQU(&p_org, &peer->aorg)) { 11542950cc38Schristos break; 1155abb0f93cSkardel } 1156*eabc0478Schristos } 11572950cc38Schristos 11582950cc38Schristos return peer; 1159abb0f93cSkardel } 11607476e6e4Schristos 11617476e6e4Schristos /* peer_cleanup - clean peer list prior to shutdown */ 11627476e6e4Schristos void peer_cleanup(void) 11637476e6e4Schristos { 11647476e6e4Schristos struct peer *peer; 1165*eabc0478Schristos struct peer *nextpeer; 11667476e6e4Schristos 1167*eabc0478Schristos for (peer = peer_list; peer != NULL; peer = nextpeer) { 1168*eabc0478Schristos nextpeer = peer->p_link; 11697476e6e4Schristos unpeer(peer); 11707476e6e4Schristos } 11717476e6e4Schristos } 1172