xref: /netbsd-src/external/bsd/ntp/dist/ntpd/ntp_peer.c (revision eabc0478de71e4e011a5b4e0392741e01d491794)
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