summaryrefslogtreecommitdiffstats
path: root/ntpd/ntp_peer.c
diff options
context:
space:
mode:
Diffstat (limited to 'ntpd/ntp_peer.c')
-rw-r--r--ntpd/ntp_peer.c880
1 files changed, 880 insertions, 0 deletions
diff --git a/ntpd/ntp_peer.c b/ntpd/ntp_peer.c
new file mode 100644
index 0000000..cf8a600
--- /dev/null
+++ b/ntpd/ntp_peer.c
@@ -0,0 +1,880 @@
+/*
+ * ntp_peer.c - management of data maintained for peer associations
+ */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <sys/types.h>
+
+#include "ntpd.h"
+#include "ntp_stdlib.h"
+#ifdef OPENSSL
+#include "openssl/rand.h"
+#endif /* OPENSSL */
+
+/*
+ * Table of valid association combinations
+ * ---------------------------------------
+ *
+ * packet->mode
+ * peer->mode | UNSPEC ACTIVE PASSIVE CLIENT SERVER BCAST
+ * ---------- | ---------------------------------------------
+ * NO_PEER | e 1 e 1 1 1
+ * ACTIVE | e 1 1 0 0 0
+ * PASSIVE | e 1 e 0 0 0
+ * CLIENT | e 0 0 0 1 1
+ * SERVER | e 0 0 0 0 0
+ * BCAST | e 0 0 0 0 0
+ * CONTROL | e 0 0 0 0 0
+ * PRIVATE | e 0 0 0 0 0
+ * BCLIENT | e 0 0 0 e 1
+ *
+ * One point to note here: a packet in BCAST mode can potentially match
+ * a peer in CLIENT mode, but we that is a special case and we check for
+ * that early in the decision process. This avoids having to keep track
+ * of what kind of associations are possible etc... We actually
+ * circumvent that problem by requiring that the first b(m)roadcast
+ * received after the change back to BCLIENT mode sets the clock.
+ */
+
+int AM[AM_MODES][AM_MODES] = {
+/* { UNSPEC, ACTIVE, PASSIVE, CLIENT, SERVER, BCAST } */
+
+/*NONE*/{ AM_ERR, AM_NEWPASS, AM_ERR, AM_FXMIT, AM_MANYCAST, AM_NEWBCL},
+
+/*A*/ { AM_ERR, AM_PROCPKT, AM_PROCPKT, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH},
+
+/*P*/ { AM_ERR, AM_PROCPKT, AM_ERR, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH},
+
+/*C*/ { AM_ERR, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH, AM_PROCPKT, AM_POSSBCL},
+
+/*S*/ { AM_ERR, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH},
+
+/*BCST*/{ AM_ERR, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH},
+
+/*CNTL*/{ AM_ERR, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH},
+
+/*PRIV*/{ AM_ERR, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH},
+
+/*BCL*/ { AM_ERR, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH, AM_ERR, AM_PROCPKT},
+};
+
+#define MATCH_ASSOC(x,y) AM[(x)][(y)]
+
+/*
+ * These routines manage the allocation of memory to peer structures
+ * and the maintenance of the peer hash table. The two main entry
+ * points are findpeer(), which looks for matching peer sturctures in
+ * the peer list, newpeer(), which allocates a new peer structure and
+ * adds it to the list, and unpeer(), which demobilizes the association
+ * and deallocates the structure.
+ */
+/*
+ * Peer hash tables
+ */
+struct peer *peer_hash[HASH_SIZE]; /* peer hash table */
+int peer_hash_count[HASH_SIZE]; /* peers in each bucket */
+struct peer *assoc_hash[HASH_SIZE]; /* association ID hash table */
+int assoc_hash_count[HASH_SIZE]; /* peers in each bucket */
+static struct peer *peer_free; /* peer structures free list */
+int peer_free_count; /* count of free structures */
+
+/*
+ * Association ID. We initialize this value randomly, then assign a new
+ * value every time the peer structure is incremented.
+ */
+static associd_t current_association_ID; /* association ID */
+
+/*
+ * Memory allocation watermarks.
+ */
+#define INIT_PEER_ALLOC 15 /* initialize for 15 peers */
+#define INC_PEER_ALLOC 5 /* when run out, add 5 more */
+
+/*
+ * Miscellaneous statistic counters which may be queried.
+ */
+u_long peer_timereset; /* time stat counters zeroed */
+u_long findpeer_calls; /* calls to findpeer */
+u_long assocpeer_calls; /* calls to findpeerbyassoc */
+u_long peer_allocations; /* allocations from free list */
+u_long peer_demobilizations; /* structs freed to free list */
+int total_peer_structs; /* peer structs */
+int peer_associations; /* active associations */
+static struct peer init_peer_alloc[INIT_PEER_ALLOC]; /* init alloc */
+
+static void getmorepeermem P((void));
+
+/*
+ * init_peer - initialize peer data structures and counters
+ *
+ * N.B. We use the random number routine in here. It had better be
+ * initialized prior to getting here.
+ */
+void
+init_peer(void)
+{
+ register int i;
+
+ /*
+ * Clear hash table and counters.
+ */
+ for (i = 0; i < HASH_SIZE; i++) {
+ peer_hash[i] = 0;
+ peer_hash_count[i] = 0;
+ assoc_hash[i] = 0;
+ assoc_hash_count[i] = 0;
+ }
+
+ /*
+ * Clear stat counters
+ */
+ findpeer_calls = peer_allocations = 0;
+ assocpeer_calls = peer_demobilizations = 0;
+
+ /*
+ * Initialize peer memory.
+ */
+ peer_free = 0;
+ for (i = 0; i < INIT_PEER_ALLOC; i++) {
+ init_peer_alloc[i].next = peer_free;
+ peer_free = &init_peer_alloc[i];
+ }
+ total_peer_structs = INIT_PEER_ALLOC;
+ peer_free_count = INIT_PEER_ALLOC;
+
+ /*
+ * Initialize our first association ID
+ */
+ current_association_ID = (associd_t)ranp2(16);
+ if (current_association_ID == 0)
+ current_association_ID = 1;
+}
+
+
+/*
+ * getmorepeermem - add more peer structures to the free list
+ */
+static void
+getmorepeermem(void)
+{
+ register int i;
+ register struct peer *peer;
+
+ peer = (struct peer *)emalloc(INC_PEER_ALLOC *
+ sizeof(struct peer));
+ for (i = 0; i < INC_PEER_ALLOC; i++) {
+ peer->next = peer_free;
+ peer_free = peer;
+ peer++;
+ }
+
+ total_peer_structs += INC_PEER_ALLOC;
+ peer_free_count += INC_PEER_ALLOC;
+}
+
+
+/*
+ * findexistingpeer - return a pointer to a peer in the hash table
+ */
+struct peer *
+findexistingpeer(
+ struct sockaddr_storage *addr,
+ struct peer *start_peer,
+ int mode
+ )
+{
+ register struct peer *peer;
+
+ /*
+ * start_peer is included so we can locate instances of the
+ * same peer through different interfaces in the hash table.
+ */
+ if (start_peer == 0)
+ peer = peer_hash[HASH_ADDR(addr)];
+ else
+ peer = start_peer->next;
+
+ while (peer != 0) {
+ if (SOCKCMP(addr, &peer->srcadr)
+ && NSRCPORT(addr) == NSRCPORT(&peer->srcadr)) {
+ if (mode == -1)
+ return (peer);
+ else if (peer->hmode == mode)
+ break;
+ }
+ peer = peer->next;
+ }
+ return (peer);
+}
+
+
+/*
+ * findpeer - find and return a peer in the hash table.
+ */
+struct peer *
+findpeer(
+ struct sockaddr_storage *srcadr,
+ struct interface *dstadr,
+ int fd,
+ int pkt_mode,
+ int *action
+ )
+{
+ register struct peer *peer;
+ int hash;
+
+ findpeer_calls++;
+ hash = HASH_ADDR(srcadr);
+ for (peer = peer_hash[hash]; peer != NULL; peer = peer->next) {
+ if (SOCKCMP(srcadr, &peer->srcadr)
+ && NSRCPORT(srcadr) == NSRCPORT(&peer->srcadr)) {
+
+ /*
+ * if the association matching rules determine
+ * that this is not a valid combination, then
+ * look for the next valid peer association.
+ */
+ *action = MATCH_ASSOC(peer->hmode, pkt_mode);
+
+ /*
+ * Sigh! Check if BCLIENT peer in client
+ * server mode, else return error.
+ */
+ if ((*action == AM_POSSBCL) && !(peer->flags &
+ FLAG_MCAST))
+ *action = AM_ERR;
+
+ /*
+ * if an error was returned, exit back right
+ * here.
+ */
+ if (*action == AM_ERR)
+ return ((struct peer *)0);
+
+ /*
+ * if a match is found, we stop our search.
+ */
+ if (*action != AM_NOMATCH)
+ break;
+ }
+ }
+
+ /*
+ * If no matching association is found
+ */
+ if (peer == 0) {
+ *action = MATCH_ASSOC(NO_PEER, pkt_mode);
+ return ((struct peer *)0);
+ }
+ peer->dstadr = dstadr;
+ return (peer);
+}
+
+/*
+ * findpeerbyassocid - find and return a peer using his association ID
+ */
+struct peer *
+findpeerbyassoc(
+ u_int assoc
+ )
+{
+ register struct peer *peer;
+ int hash;
+
+ assocpeer_calls++;
+
+ hash = assoc & HASH_MASK;
+ for (peer = assoc_hash[hash]; peer != 0; peer =
+ peer->ass_next) {
+ if (assoc == peer->associd)
+ return (peer);
+ }
+ return (NULL);
+}
+
+
+/*
+ * clear_all - flush all time values for all associations
+ */
+void
+clear_all(void)
+{
+ struct peer *peer, *next_peer;
+ int n;
+
+ /*
+ * This routine is called when the clock is stepped, and so all
+ * previously saved time values are untrusted.
+ */
+ for (n = 0; n < HASH_SIZE; n++) {
+ for (peer = peer_hash[n]; peer != 0; peer = next_peer) {
+ next_peer = peer->next;
+ if (peer->flags & FLAG_CONFIG) {
+ if (!(peer->cast_flags & (MDF_ACAST |
+ MDF_MCAST | MDF_BCAST)))
+ peer_clear(peer, "STEP");
+ } else {
+ unpeer(peer);
+ }
+ }
+ }
+#ifdef DEBUG
+ if (debug)
+ printf("clear_all: at %lu\n", current_time);
+#endif
+}
+
+
+/*
+ * unpeer - remove peer structure from hash table and free structure
+ */
+void
+unpeer(
+ struct peer *peer_to_remove
+ )
+{
+ int hash;
+#ifdef OPENSSL
+ char statstr[NTP_MAXSTRLEN]; /* statistics for filegen */
+
+ if (peer_to_remove->flags & FLAG_SKEY) {
+ sprintf(statstr, "unpeer %d flash %x reach %03o flags %04x",
+ peer_to_remove->associd, peer_to_remove->flash,
+ peer_to_remove->reach, peer_to_remove->flags);
+ record_crypto_stats(&peer_to_remove->srcadr, statstr);
+#ifdef DEBUG
+ if (debug)
+ printf("peer: %s\n", statstr);
+#endif
+ }
+#endif /* OPENSSL */
+#ifdef DEBUG
+ if (debug)
+ printf("demobilize %u %d\n", peer_to_remove->associd,
+ peer_associations);
+#endif
+ peer_clear(peer_to_remove, "NULL");
+ hash = HASH_ADDR(&peer_to_remove->srcadr);
+ peer_hash_count[hash]--;
+ peer_demobilizations++;
+#ifdef REFCLOCK
+ /*
+ * If this peer is actually a clock, shut it down first
+ */
+ if (peer_to_remove->flags & FLAG_REFCLOCK)
+ refclock_unpeer(peer_to_remove);
+#endif
+ peer_to_remove->action = 0; /* disable timeout actions */
+ if (peer_hash[hash] == peer_to_remove)
+ peer_hash[hash] = peer_to_remove->next;
+ else {
+ register struct peer *peer;
+
+ peer = peer_hash[hash];
+ while (peer != 0 && peer->next != peer_to_remove)
+ peer = peer->next;
+
+ if (peer == 0) {
+ peer_hash_count[hash]++;
+ msyslog(LOG_ERR, "peer struct for %s not in table!",
+ stoa(&peer->srcadr));
+ } else {
+ peer->next = peer_to_remove->next;
+ }
+ }
+
+ /*
+ * Remove him from the association hash as well.
+ */
+ hash = peer_to_remove->associd & HASH_MASK;
+ assoc_hash_count[hash]--;
+ if (assoc_hash[hash] == peer_to_remove)
+ assoc_hash[hash] = peer_to_remove->ass_next;
+ else {
+ register struct peer *peer;
+
+ peer = assoc_hash[hash];
+ while (peer != 0 && peer->ass_next != peer_to_remove)
+ peer = peer->ass_next;
+
+ if (peer == 0) {
+ assoc_hash_count[hash]++;
+ msyslog(LOG_ERR,
+ "peer struct for %s not in association table!",
+ stoa(&peer->srcadr));
+ } else {
+ peer->ass_next = peer_to_remove->ass_next;
+ }
+ }
+ peer_to_remove->next = peer_free;
+ peer_free = peer_to_remove;
+ peer_free_count++;
+ peer_associations--;
+}
+
+
+/*
+ * peer_config - configure a new association
+ */
+struct peer *
+peer_config(
+ struct sockaddr_storage *srcadr,
+ struct interface *dstadr,
+ int hmode,
+ int version,
+ int minpoll,
+ int maxpoll,
+ u_int flags,
+ int ttl,
+ keyid_t key,
+ u_char *keystr
+ )
+{
+ register struct peer *peer;
+ u_char cast_flags;
+
+ /*
+ * First search from the beginning for an association with given
+ * remote address and mode. If an interface is given, search
+ * from there to find the association which matches that
+ * destination.
+ */
+ peer = findexistingpeer(srcadr, (struct peer *)0, hmode);
+ if (dstadr != 0) {
+ while (peer != 0) {
+ if (peer->dstadr == dstadr)
+ break;
+ peer = findexistingpeer(srcadr, peer, hmode);
+ }
+ }
+
+ /*
+ * We do a dirty little jig to figure the cast flags. This is
+ * probably not the best place to do this, at least until the
+ * configure code is rebuilt. Note only one flag can be set.
+ */
+ switch (hmode) {
+
+ case MODE_BROADCAST:
+ if(srcadr->ss_family == AF_INET) {
+ if (IN_CLASSD(ntohl(((struct sockaddr_in*)srcadr)->sin_addr.s_addr)))
+ cast_flags = MDF_MCAST;
+ else
+ cast_flags = MDF_BCAST;
+ break;
+ }
+ else {
+ if (IN6_IS_ADDR_MULTICAST(&((struct sockaddr_in6*)srcadr)->sin6_addr))
+ cast_flags = MDF_MCAST;
+ else
+ cast_flags = MDF_BCAST;
+ break;
+ }
+
+ case MODE_CLIENT:
+ if(srcadr->ss_family == AF_INET) {
+ if (IN_CLASSD(ntohl(((struct sockaddr_in*)srcadr)->sin_addr.s_addr)))
+ cast_flags = MDF_ACAST;
+ else
+ cast_flags = MDF_UCAST;
+ break;
+ }
+ else {
+ if (IN6_IS_ADDR_MULTICAST(&((struct sockaddr_in6*)srcadr)->sin6_addr))
+ cast_flags = MDF_ACAST;
+ else
+ cast_flags = MDF_UCAST;
+ break;
+ }
+
+ default:
+ cast_flags = MDF_UCAST;
+ }
+
+ /*
+ * If the peer is already configured, some dope has a duplicate
+ * configureation entry or another dope is wiggling from afar.
+ */
+ if (peer != 0) {
+ peer->hmode = (u_char)hmode;
+ peer->version = (u_char) version;
+ peer->minpoll = (u_char) minpoll;
+ peer->maxpoll = (u_char) maxpoll;
+ peer->flags = flags | FLAG_CONFIG |
+ (peer->flags & FLAG_REFCLOCK);
+ peer->cast_flags = cast_flags;
+ peer->ttl = (u_char) ttl;
+ peer->keyid = key;
+ peer->precision = sys_precision;
+ peer_clear(peer, "RMOT");
+ return (peer);
+ }
+
+ /*
+ * Here no match has been found, so presumably this is a new
+ * persistent association. Mobilize the thing and initialize its
+ * variables. If emulating ntpdate, force iburst.
+ */
+ if (mode_ntpdate)
+ flags |= FLAG_IBURST;
+ peer = newpeer(srcadr, dstadr, hmode, version, minpoll, maxpoll,
+ flags | FLAG_CONFIG, cast_flags, ttl, key);
+ return (peer);
+}
+
+
+/*
+ * newpeer - initialize a new peer association
+ */
+struct peer *
+newpeer(
+ struct sockaddr_storage *srcadr,
+ struct interface *dstadr,
+ int hmode,
+ int version,
+ int minpoll,
+ int maxpoll,
+ u_int flags,
+ u_char cast_flags,
+ int ttl,
+ keyid_t key
+ )
+{
+ register struct peer *peer;
+ register int i;
+#ifdef OPENSSL
+ char statstr[NTP_MAXSTRLEN]; /* statistics for filegen */
+#endif /* OPENSSL */
+
+ /*
+ * Allocate a new peer structure. Some dirt here, since some of
+ * the initialization requires knowlege of our system state.
+ */
+ if (peer_free_count == 0)
+ getmorepeermem();
+ peer = peer_free;
+ peer_free = peer->next;
+ peer_free_count--;
+ peer_associations++;
+ memset((char *)peer, 0, sizeof(struct peer));
+
+ /*
+ * Assign an association ID and increment the system variable.
+ */
+ peer->associd = current_association_ID;
+ if (++current_association_ID == 0)
+ ++current_association_ID;
+
+ /*
+ * Initialize the peer structure and dance the interface jig.
+ * Reference clocks step the loopback waltz, the others
+ * squaredance around the interface list looking for a buddy. If
+ * the dance peters out, there is always the wildcard interface.
+ * This might happen in some systems and would preclude proper
+ * operation with public key cryptography.
+ */
+ if (ISREFCLOCKADR(srcadr))
+ peer->dstadr = loopback_interface;
+ else if (cast_flags & (MDF_BCLNT | MDF_ACAST | MDF_MCAST | MDF_BCAST)) {
+ peer->dstadr = findbcastinter(srcadr);
+ /*
+ * If it was a multicast packet, findbcastinter() may not
+ * find it, so try a little harder.
+ */
+ if (peer->dstadr == ANY_INTERFACE_CHOOSE(srcadr))
+ peer->dstadr = findinterface(srcadr);
+ } else if (dstadr != NULL && dstadr != ANY_INTERFACE_CHOOSE(srcadr))
+ peer->dstadr = dstadr;
+ else
+ peer->dstadr = findinterface(srcadr);
+ peer->srcadr = *srcadr;
+ peer->hmode = (u_char)hmode;
+ peer->version = (u_char)version;
+ peer->minpoll = (u_char)max(NTP_MINPOLL, minpoll);
+ peer->maxpoll = (u_char)min(NTP_MAXPOLL, maxpoll);
+ peer->flags = flags;
+ if (key != 0)
+ peer->flags |= FLAG_AUTHENABLE;
+ if (key > NTP_MAXKEY)
+ peer->flags |= FLAG_SKEY;
+ peer->cast_flags = cast_flags;
+ peer->ttl = (u_char)ttl;
+ peer->keyid = key;
+ peer->precision = sys_precision;
+ if (cast_flags & MDF_ACAST)
+ peer_clear(peer, "ACST");
+ else if (cast_flags & MDF_MCAST)
+ peer_clear(peer, "MCST");
+ else if (cast_flags & MDF_BCAST)
+ peer_clear(peer, "BCST");
+ else
+ peer_clear(peer, "INIT");
+ if (mode_ntpdate)
+ peer_ntpdate++;
+
+ /*
+ * Note time on statistics timers.
+ */
+ peer->timereset = current_time;
+ peer->timereachable = current_time;
+ peer->timereceived = current_time;
+#ifdef REFCLOCK
+ if (ISREFCLOCKADR(&peer->srcadr)) {
+ /*
+ * We let the reference clock support do clock
+ * dependent initialization. This includes setting
+ * the peer timer, since the clock may have requirements
+ * for this.
+ */
+ if (!refclock_newpeer(peer)) {
+ /*
+ * Dump it, something screwed up
+ */
+ peer->next = peer_free;
+ peer_free = peer;
+ peer_free_count++;
+ return (NULL);
+ }
+ }
+#endif
+
+ /*
+ * Put the new peer in the hash tables.
+ */
+ i = HASH_ADDR(&peer->srcadr);
+ peer->next = peer_hash[i];
+ peer_hash[i] = peer;
+ peer_hash_count[i]++;
+ i = peer->associd & HASH_MASK;
+ peer->ass_next = assoc_hash[i];
+ assoc_hash[i] = peer;
+ assoc_hash_count[i]++;
+#ifdef OPENSSL
+ if (peer->flags & FLAG_SKEY) {
+ sprintf(statstr, "newpeer %d", peer->associd);
+ record_crypto_stats(&peer->srcadr, statstr);
+#ifdef DEBUG
+ if (debug)
+ printf("peer: %s\n", statstr);
+#endif
+ }
+#endif /* OPENSSL */
+#ifdef DEBUG
+ if (debug)
+ printf(
+ "newpeer: %s->%s mode %d vers %d poll %d %d flags 0x%x 0x%x ttl %d key %08x\n",
+ peer->dstadr == NULL ? "null" : stoa(&peer->dstadr->sin),
+ stoa(&peer->srcadr),
+ peer->hmode, peer->version, peer->minpoll,
+ peer->maxpoll, peer->flags, peer->cast_flags,
+ peer->ttl, peer->keyid);
+#endif
+ return (peer);
+}
+
+
+/*
+ * peer_unconfig - remove the configuration bit from a peer
+ */
+int
+peer_unconfig(
+ struct sockaddr_storage *srcadr,
+ struct interface *dstadr,
+ int mode
+ )
+{
+ register struct peer *peer;
+ int num_found;
+
+ num_found = 0;
+ peer = findexistingpeer(srcadr, (struct peer *)0, mode);
+ while (peer != 0) {
+ if (peer->flags & FLAG_CONFIG
+ && (dstadr == 0 || peer->dstadr == dstadr)) {
+ num_found++;
+
+ /*
+ * Tricky stuff here. If the peer is polling us
+ * in active mode, turn off the configuration
+ * bit and make the mode passive. This allows us
+ * to avoid dumping a lot of history for peers
+ * we might choose to keep track of in passive
+ * mode. The protocol will eventually terminate
+ * undesirables on its own.
+ */
+ if (peer->hmode == MODE_ACTIVE
+ && peer->pmode == MODE_ACTIVE) {
+ peer->hmode = MODE_PASSIVE;
+ peer->flags &= ~FLAG_CONFIG;
+ } else {
+ unpeer(peer);
+ peer = 0;
+ }
+ }
+ peer = findexistingpeer(srcadr, peer, mode);
+ }
+ return (num_found);
+}
+
+/*
+ * peer_clr_stats - clear peer module stat counters
+ */
+void
+peer_clr_stats(void)
+{
+ findpeer_calls = 0;
+ assocpeer_calls = 0;
+ peer_allocations = 0;
+ peer_demobilizations = 0;
+ peer_timereset = current_time;
+}
+
+/*
+ * peer_reset - reset stat counters in a peer structure
+ */
+void
+peer_reset(
+ struct peer *peer
+ )
+{
+ if (peer == 0)
+ return;
+ peer->sent = 0;
+ peer->received = 0;
+ peer->processed = 0;
+ peer->badauth = 0;
+ peer->bogusorg = 0;
+ peer->oldpkt = 0;
+ peer->seldisptoolarge = 0;
+ peer->selbroken = 0;
+ peer->rank = 0;
+ peer->timereset = current_time;
+}
+
+
+/*
+ * peer_all_reset - reset all peer stat counters
+ */
+void
+peer_all_reset(void)
+{
+ struct peer *peer;
+ int hash;
+
+ for (hash = 0; hash < HASH_SIZE; hash++)
+ for (peer = peer_hash[hash]; peer != 0; peer = peer->next)
+ peer_reset(peer);
+}
+
+
+#ifdef OPENSSL
+/*
+ * expire_all - flush all crypto data and update timestamps.
+ */
+void
+expire_all(void)
+{
+ struct peer *peer, *next_peer;
+ int n;
+
+ /*
+ * This routine is called about once per day from the timer
+ * routine and when the client is first synchronized. Search the
+ * peer list for all associations and flush only the key list
+ * and cookie. If a manycast client association, flush
+ * everything. Then, recompute and sign the agreement public
+ * value, if present.
+ */
+ if (!crypto_flags)
+ return;
+ for (n = 0; n < HASH_SIZE; n++) {
+ for (peer = peer_hash[n]; peer != 0; peer = next_peer) {
+ next_peer = peer->next;
+ if (!(peer->flags & FLAG_SKEY)) {
+ continue;
+ } else if (peer->cast_flags & MDF_ACAST) {
+ peer_clear(peer, "ACST");
+ } else if (peer->hmode == MODE_ACTIVE ||
+ peer->hmode == MODE_PASSIVE) {
+ key_expire(peer);
+ peer->crypto &= ~(CRYPTO_FLAG_AUTO |
+ CRYPTO_FLAG_AGREE);
+ }
+
+ }
+ }
+ RAND_bytes((u_char *)&sys_private, 4);
+ crypto_update();
+ resetmanycast();
+}
+#endif /* OPENSSL */
+
+
+/*
+ * findmanycastpeer - find and return a manycast peer
+ */
+struct peer *
+findmanycastpeer(
+ struct recvbuf *rbufp
+ )
+{
+ register struct peer *peer;
+ struct pkt *pkt;
+ l_fp p_org;
+ int i;
+
+ /*
+ * This routine is called upon arrival of a client-mode message
+ * from a manycast server. Search the peer list for a manycast
+ * client association where the last transmit timestamp matches
+ * the originate timestamp. This assumes the transmit timestamps
+ * for possibly more than one manycast association are unique.
+ */
+ pkt = &rbufp->recv_pkt;
+ for (i = 0; i < HASH_SIZE; i++) {
+ if (peer_hash_count[i] == 0)
+ continue;
+
+ for (peer = peer_hash[i]; peer != 0; peer =
+ peer->next) {
+ if (peer->cast_flags & MDF_ACAST) {
+ NTOHL_FP(&pkt->org, &p_org);
+ if (L_ISEQU(&peer->xmt, &p_org))
+ return (peer);
+ }
+ }
+ }
+ return (NULL);
+}
+
+
+/*
+ * resetmanycast - reset all manycast clients
+ */
+void
+resetmanycast(void)
+{
+ register struct peer *peer;
+ int i;
+
+ /*
+ * This routine is called when the number of client associations
+ * falls below the minimum. Search the peer list for manycast
+ * client associations and reset the ttl and poll interval.
+ */
+ for (i = 0; i < HASH_SIZE; i++) {
+ if (peer_hash_count[i] == 0)
+ continue;
+
+ for (peer = peer_hash[i]; peer != 0; peer =
+ peer->next) {
+ if (peer->cast_flags & MDF_ACAST) {
+ peer->ttl = 0;
+ poll_update(peer, 0);
+ }
+ }
+ }
+}
OpenPOWER on IntegriCloud