aboutsummaryrefslogtreecommitdiff
path: root/contrib/ntp/ntpd/ntp_peer.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/ntp/ntpd/ntp_peer.c')
-rw-r--r--contrib/ntp/ntpd/ntp_peer.c202
1 files changed, 126 insertions, 76 deletions
diff --git a/contrib/ntp/ntpd/ntp_peer.c b/contrib/ntp/ntpd/ntp_peer.c
index c1716ffe0d83..69c1eff45822 100644
--- a/contrib/ntp/ntpd/ntp_peer.c
+++ b/contrib/ntp/ntpd/ntp_peer.c
@@ -39,7 +39,7 @@
#define AM_MODES 7 /* number of rows and columns */
#define NO_PEER 0 /* action when no peer is found */
-int AM[AM_MODES][AM_MODES] = {
+const s_char AM[AM_MODES][AM_MODES] = {
/* packet->mode */
/* peer { UNSPEC, ACTIVE, PASSIVE, CLIENT, SERVER, BCAST } */
/* mode */
@@ -58,7 +58,7 @@ int AM[AM_MODES][AM_MODES] = {
/*BCL*/ { AM_ERR, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH, AM_PROCPKT},
};
-#define MATCH_ASSOC(x, y) AM[(x)][(y)]
+#define MATCH_ASSOC(x, y) (AM[CLAMP((x), 0, AM_MODES)][CLAMP((y), 0, AM_MODES)])
/*
* These routines manage the allocation of memory to peer structures
@@ -91,8 +91,8 @@ int peer_free_count; /* count of free structures */
* Association ID. We initialize this value randomly, then assign a new
* value every time an association is mobilized.
*/
-static associd_t current_association_ID; /* association ID */
-static associd_t initial_association_ID; /* association ID */
+static associd_t current_association_ID; /* actually next poss. ID */
+static associd_t initial_association_ID;
/*
* Memory allocation watermarks.
@@ -256,7 +256,7 @@ findexistingpeer_addr(
/*
- * findexistingpeer - search by address and return a pointer to a peer.
+ * findexistingpeer - search by name+family or address.
*/
struct peer *
findexistingpeer(
@@ -294,7 +294,7 @@ findexistingpeer(
* enough. Authentication alone does not help here, since it does not
* protect the UDP layer and leaves us open for a replay attack.
*
- * So we do not update the adresses and wait until the next interface
+ * So we do not update the addresses and wait until the next interface
* list update does the right thing for us.
*/
struct peer *
@@ -347,18 +347,20 @@ findpeer(
}
/* if an error was returned, exit back right here. */
- if (*action == AM_ERR)
+ if (*action == AM_ERR) {
return NULL;
+ }
/* if a match is found, we stop our search. */
- if (*action != AM_NOMATCH)
+ if (*action != AM_NOMATCH) {
break;
+ }
}
/* If no matching association is found... */
- if (NULL == p)
+ if (NULL == p) {
*action = MATCH_ASSOC(NO_PEER, pkt_mode);
-
+ }
return p;
}
@@ -542,7 +544,8 @@ unpeer(
)
{
mprintf_event(PEVNT_DEMOBIL, peer, "assoc %u", peer->associd);
- restrict_source(&peer->srcadr, 1, 0);
+ restrict_source(&peer->srcadr, TRUE, 0);
+ peer->flags |= FLAG_DISABLED;
set_peerdstadr(peer, NULL);
peer_demobilizations++;
peer_associations--;
@@ -645,6 +648,24 @@ set_peerdstadr(
return;
/*
+ * Do not change the local address of a link-local
+ * peer address.
+ */
+ if ( p->dstadr != NULL && is_linklocal(&p->dstadr->sin)
+ && dstadr != NULL) {
+ return;
+ }
+
+ /*
+ * Do not set the local address for a link-local IPv6 peer
+ * to one with a different scope ID.
+ */
+ if ( dstadr != NULL && IS_IPV6(&p->srcadr)
+ && SCOPE(&dstadr->sin) != SCOPE(&p->srcadr)) {
+ return;
+ }
+
+ /*
* Don't accept updates to a separate multicast receive-only
* endpt while a BCLNT peer is running its unicast protocol.
*/
@@ -658,11 +679,14 @@ set_peerdstadr(
p->dstadr->peercnt--;
UNLINK_SLIST(unlinked, p->dstadr->peers, p, ilink,
struct peer);
+ }
+ if ( !IS_MCAST(&p->srcadr) && !(FLAG_DISABLED & p->flags)
+ && !initializing) {
msyslog(LOG_INFO, "%s local addr %s -> %s",
- stoa(&p->srcadr), latoa(p->dstadr),
- latoa(dstadr));
+ stoa(&p->srcadr), eptoa(p->dstadr),
+ eptoa(dstadr));
}
-
+
p->dstadr = dstadr;
/* link to list if we have an address after assignment */
@@ -741,14 +765,20 @@ refresh_all_peerinterfaces(void)
struct peer *p;
/*
- * this is called when the interface list has changed
- * give all peers a chance to find a better interface
- * but only if either they don't have an address already
- * or if the one they have hasn't worked for a while.
+ * This is called when the interface list has changed.
+ * Give peers a chance to find a better interface.
*/
for (p = peer_list; p != NULL; p = p->p_link) {
- if (!(p->dstadr && (p->reach & 0x3))) // Bug 2849 XOR 2043
- peer_refresh_interface(p);
+ /*
+ * Bug 2849 XOR 2043
+ * Change local address only if the peer doesn't
+ * have a local address already or if the one
+ * they have hasn't worked for a while.
+ */
+ if (p->dstadr != NULL && (p->reach & 0x3)) {
+ continue;
+ }
+ peer_refresh_interface(p);
}
}
@@ -777,7 +807,6 @@ newpeer(
u_int hash;
int ip_count = 0;
-
DEBUG_REQUIRE(srcadr);
#ifdef AUTOKEY
@@ -789,7 +818,9 @@ newpeer(
return (NULL);
} else if (flags & FLAG_SKEY) {
- msyslog(LOG_ERR, "Autokey not configured");
+ msyslog(LOG_ERR, "Rejecting Autokey with %s,"
+ " built without support.",
+ stoa(srcadr));
return (NULL);
}
}
@@ -831,13 +862,34 @@ newpeer(
}
/*
+ * In any case, do not create an association with a duplicate
+ * remote address (srcadr) except for undefined (zero) address.
+ * Arguably this should be part of the logic above but
+ * [Bug 3888] exposed a situation with manycastclient where
+ * duplicate associations happened.
+ */
+ if (NULL == peer) {
+ for (peer = peer_list;
+ peer != NULL;
+ peer = peer->p_link) {
+ if ( SOCK_EQ(srcadr, &peer->srcadr)
+ && !SOCK_UNSPEC(srcadr)
+ && !SOCK_UNSPEC(&peer->srcadr)) {
+ /* leave peer non-NULL */
+ break;
+ }
+ }
+ }
+
+ /*
* If a peer is found, this would be a duplicate and we don't
* allow that. This avoids duplicate ephemeral (broadcast/
* multicast) and preemptible (manycast and pool) client
* associations.
*/
if (peer != NULL) {
- DPRINTF(2, ("newpeer(%s) found existing association\n",
+ DPRINTF(2, ("%s(%s) found existing association\n",
+ __func__,
(hostname)
? hostname
: stoa(srcadr)));
@@ -845,7 +897,7 @@ newpeer(
}
#if 0
-DPRINTF(1, ("newpeer(%s) found no existing and %d other associations\n",
+ DPRINTF(1, ("newpeer(%s) found no existing and %d other associations\n",
(hostname)
? hostname
: stoa(srcadr),
@@ -884,15 +936,19 @@ DPRINTF(1, ("newpeer(%s) found no existing and %d other associations\n",
peer_preempt++;
/*
- * Assign an association ID and increment the system variable.
+ * Assign an available association ID. Zero is reserved.
*/
+ do {
+ while (0 == ++current_association_ID) {
+ /* EMPTY */
+ }
+ } while (NULL != findpeerbyassoc(current_association_ID));
peer->associd = current_association_ID;
- if (++current_association_ID == 0)
- ++current_association_ID;
peer->srcadr = *srcadr;
- if (hostname != NULL)
+ if (hostname != NULL) {
peer->hostname = estrdup(hostname);
+ }
peer->hmode = hmode;
peer->version = version;
peer->flags = flags;
@@ -901,66 +957,67 @@ DPRINTF(1, ("newpeer(%s) found no existing and %d other associations\n",
select_peerinterface(peer, srcadr, dstadr));
/*
- * It is an error to set minpoll less than NTP_MINPOLL or to
- * set maxpoll greater than NTP_MAXPOLL. However, minpoll is
- * clamped not greater than NTP_MAXPOLL and maxpoll is clamped
- * not less than NTP_MINPOLL without complaint. Finally,
- * minpoll is clamped not greater than maxpoll.
+ * Zero for minpoll or maxpoll means use defaults.
*/
- if (minpoll == 0)
- peer->minpoll = NTP_MINDPOLL;
- else
- peer->minpoll = min(minpoll, NTP_MAXPOLL);
- if (maxpoll == 0)
- peer->maxpoll = NTP_MAXDPOLL;
- else
- peer->maxpoll = max(maxpoll, NTP_MINPOLL);
- if (peer->minpoll > peer->maxpoll)
- peer->minpoll = peer->maxpoll;
+ peer->maxpoll = (0 == maxpoll)
+ ? NTP_MAXDPOLL
+ : maxpoll;
+ peer->minpoll = (0 == minpoll)
+ ? NTP_MINDPOLL
+ : minpoll;
+
+ /*
+ * Clamp maxpoll and minpoll within NTP_MINPOLL and NTP_MAXPOLL,
+ * and further clamp minpoll less than or equal maxpoll.
+ */
+ peer->maxpoll = CLAMP(peer->maxpoll, NTP_MINPOLL, NTP_MAXPOLL);
+ peer->minpoll = CLAMP(peer->minpoll, NTP_MINPOLL, peer->maxpoll);
- if (peer->dstadr != NULL)
+ if (peer->dstadr != NULL) {
DPRINTF(3, ("newpeer(%s): using fd %d and our addr %s\n",
stoa(srcadr), peer->dstadr->fd,
stoa(&peer->dstadr->sin)));
- else
- DPRINTF(3, ("newpeer(%s): local interface currently not bound\n",
+ } else {
+ DPRINTF(3, ("newpeer(%s): local addr unavailable\n",
stoa(srcadr)));
-
+ }
/*
* Broadcast needs the socket enabled for broadcast
*/
- if ((MDF_BCAST & cast_flags) && peer->dstadr != NULL)
+ if ((MDF_BCAST & cast_flags) && peer->dstadr != NULL) {
enable_broadcast(peer->dstadr, srcadr);
-
+ }
/*
* Multicast needs the socket interface enabled for multicast
*/
- if ((MDF_MCAST & cast_flags) && peer->dstadr != NULL)
+ if ((MDF_MCAST & cast_flags) && peer->dstadr != NULL) {
enable_multicast_if(peer->dstadr, srcadr);
-
+ }
#ifdef AUTOKEY
if (key > NTP_MAXKEY)
peer->flags |= FLAG_SKEY;
#endif /* AUTOKEY */
peer->ttl = ttl;
peer->keyid = key;
- if (ident != NULL)
+ if (ident != NULL) {
peer->ident = estrdup(ident);
+ }
peer->precision = sys_precision;
peer->hpoll = peer->minpoll;
- if (cast_flags & MDF_ACAST)
+ if (cast_flags & MDF_ACAST) {
peer_clear(peer, "ACST");
- else if (cast_flags & MDF_POOL)
+ } else if (cast_flags & MDF_POOL) {
peer_clear(peer, "POOL");
- else if (cast_flags & MDF_MCAST)
+ } else if (cast_flags & MDF_MCAST) {
peer_clear(peer, "MCST");
- else if (cast_flags & MDF_BCAST)
+ } else if (cast_flags & MDF_BCAST) {
peer_clear(peer, "BCST");
- else
+ } else {
peer_clear(peer, "INIT");
- if (mode_ntpdate)
+ }
+ if (mode_ntpdate) {
peer_ntpdate++;
-
+ }
/*
* Note time on statistics timers.
*/
@@ -976,8 +1033,6 @@ DPRINTF(1, ("newpeer(%s) found no existing and %d other associations\n",
* the peer timer, since the clock may have requirements
* for this.
*/
- if (maxpoll == 0)
- peer->maxpoll = peer->minpoll;
if (!refclock_newpeer(peer)) {
/*
* Dump it, something screwed up
@@ -1006,7 +1061,7 @@ DPRINTF(1, ("newpeer(%s) found no existing and %d other associations\n",
assoc_hash_count[hash]++;
LINK_SLIST(peer_list, peer, p_link);
- restrict_source(&peer->srcadr, 0, 0);
+ restrict_source(&peer->srcadr, FALSE, 0);
mprintf_event(PEVNT_MOBIL, peer, "assoc %d", peer->associd);
DPRINTF(1, ("newpeer: %s->%s mode %u vers %u poll %u %u flags 0x%x 0x%x ttl %u key %08x\n",
latoa(peer->dstadr), stoa(&peer->srcadr), peer->hmode,
@@ -1093,8 +1148,9 @@ findmanycastpeer(
for (peer = peer_list; peer != NULL; peer = peer->p_link)
if (MDF_SOLICIT_MASK & peer->cast_flags) {
NTOHL_FP(&pkt->org, &p_org);
- if (L_ISEQU(&p_org, &peer->aorg))
+ if (L_ISEQU(&p_org, &peer->aorg)) {
break;
+ }
}
return peer;
@@ -1103,17 +1159,11 @@ findmanycastpeer(
/* peer_cleanup - clean peer list prior to shutdown */
void peer_cleanup(void)
{
- struct peer *peer;
- associd_t assoc;
-
- for (assoc = initial_association_ID; assoc != current_association_ID; assoc++) {
- if (assoc != 0U) {
- peer = findpeerbyassoc(assoc);
- if (peer != NULL)
- unpeer(peer);
- }
- }
- peer = findpeerbyassoc(current_association_ID);
- if (peer != NULL)
- unpeer(peer);
+ struct peer *peer;
+ struct peer *nextpeer;
+
+ for (peer = peer_list; peer != NULL; peer = nextpeer) {
+ nextpeer = peer->p_link;
+ unpeer(peer);
+ }
}