freebsd-skq/contrib/ntp/ntpd/ntp_peer.c

881 lines
21 KiB
C
Raw Normal View History

1999-12-09 13:01:21 +00:00
/*
* 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"
2004-07-20 15:01:56 +00:00
#ifdef OPENSSL
#include "openssl/rand.h"
#endif /* OPENSSL */
1999-12-09 13:01:21 +00:00
/*
* 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
*
2001-08-29 14:35:15 +00:00
* 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.
1999-12-09 13:01:21 +00:00
*/
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
2001-08-29 14:35:15 +00:00
* 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
1999-12-09 13:01:21 +00:00
* and deallocates the structure.
*/
/*
2001-08-29 14:35:15 +00:00
* Peer hash tables
1999-12-09 13:01:21 +00:00
*/
2001-08-29 14:35:15 +00:00
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 */
1999-12-09 13:01:21 +00:00
/*
2001-08-29 14:35:15 +00:00
* Association ID. We initialize this value randomly, then assign a new
1999-12-09 13:01:21 +00:00
* value every time the peer structure is incremented.
*/
2001-08-29 14:35:15 +00:00
static associd_t current_association_ID; /* association ID */
1999-12-09 13:01:21 +00:00
/*
* Memory allocation watermarks.
*/
2001-08-29 14:35:15 +00:00
#define INIT_PEER_ALLOC 15 /* initialize for 15 peers */
#define INC_PEER_ALLOC 5 /* when run out, add 5 more */
1999-12-09 13:01:21 +00:00
/*
* Miscellaneous statistic counters which may be queried.
*/
2001-08-29 14:35:15 +00:00
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 */
1999-12-09 13:01:21 +00:00
static void getmorepeermem P((void));
/*
* init_peer - initialize peer data structures and counters
*
2001-08-29 14:35:15 +00:00
* N.B. We use the random number routine in here. It had better be
* initialized prior to getting here.
1999-12-09 13:01:21 +00:00
*/
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
*/
2001-08-29 14:35:15 +00:00
current_association_ID = (associd_t)ranp2(16);
1999-12-09 13:01:21 +00:00
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;
2001-08-29 14:35:15 +00:00
peer = (struct peer *)emalloc(INC_PEER_ALLOC *
sizeof(struct peer));
1999-12-09 13:01:21 +00:00
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(
2004-07-20 15:01:56 +00:00
struct sockaddr_storage *addr,
1999-12-09 13:01:21 +00:00
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)
2001-08-29 14:35:15 +00:00
peer = peer_hash[HASH_ADDR(addr)];
1999-12-09 13:01:21 +00:00
else
2001-08-29 14:35:15 +00:00
peer = start_peer->next;
1999-12-09 13:01:21 +00:00
while (peer != 0) {
2004-07-20 15:01:56 +00:00
if (SOCKCMP(addr, &peer->srcadr)
1999-12-09 13:01:21 +00:00
&& NSRCPORT(addr) == NSRCPORT(&peer->srcadr)) {
if (mode == -1)
2001-08-29 14:35:15 +00:00
return (peer);
1999-12-09 13:01:21 +00:00
else if (peer->hmode == mode)
break;
}
peer = peer->next;
}
2001-08-29 14:35:15 +00:00
return (peer);
1999-12-09 13:01:21 +00:00
}
/*
* findpeer - find and return a peer in the hash table.
*/
struct peer *
findpeer(
2004-07-20 15:01:56 +00:00
struct sockaddr_storage *srcadr,
1999-12-09 13:01:21 +00:00
struct interface *dstadr,
int fd,
int pkt_mode,
int *action
)
{
register struct peer *peer;
int hash;
findpeer_calls++;
hash = HASH_ADDR(srcadr);
2004-07-20 15:01:56 +00:00
for (peer = peer_hash[hash]; peer != NULL; peer = peer->next) {
if (SOCKCMP(srcadr, &peer->srcadr)
1999-12-09 13:01:21 +00:00
&& NSRCPORT(srcadr) == NSRCPORT(&peer->srcadr)) {
2001-08-29 14:35:15 +00:00
2004-07-20 15:01:56 +00:00
/*
2001-08-29 14:35:15 +00:00
* if the association matching rules determine
* that this is not a valid combination, then
* look for the next valid peer association.
1999-12-09 13:01:21 +00:00
*/
*action = MATCH_ASSOC(peer->hmode, pkt_mode);
/*
* Sigh! Check if BCLIENT peer in client
2001-08-29 14:35:15 +00:00
* server mode, else return error.
1999-12-09 13:01:21 +00:00
*/
2001-08-29 14:35:15 +00:00
if ((*action == AM_POSSBCL) && !(peer->flags &
FLAG_MCAST))
1999-12-09 13:01:21 +00:00
*action = AM_ERR;
2001-08-29 14:35:15 +00:00
/*
* if an error was returned, exit back right
* here.
*/
1999-12-09 13:01:21 +00:00
if (*action == AM_ERR)
2001-08-29 14:35:15 +00:00
return ((struct peer *)0);
1999-12-09 13:01:21 +00:00
2001-08-29 14:35:15 +00:00
/*
* if a match is found, we stop our search.
*/
1999-12-09 13:01:21 +00:00
if (*action != AM_NOMATCH)
break;
}
}
2001-08-29 14:35:15 +00:00
/*
* If no matching association is found
*/
1999-12-09 13:01:21 +00:00
if (peer == 0) {
*action = MATCH_ASSOC(NO_PEER, pkt_mode);
2001-08-29 14:35:15 +00:00
return ((struct peer *)0);
1999-12-09 13:01:21 +00:00
}
2001-08-29 14:35:15 +00:00
peer->dstadr = dstadr;
return (peer);
1999-12-09 13:01:21 +00:00
}
/*
* findpeerbyassocid - find and return a peer using his association ID
*/
struct peer *
findpeerbyassoc(
2001-08-29 14:35:15 +00:00
u_int assoc
1999-12-09 13:01:21 +00:00
)
{
register struct peer *peer;
int hash;
assocpeer_calls++;
hash = assoc & HASH_MASK;
2001-08-29 14:35:15 +00:00
for (peer = assoc_hash[hash]; peer != 0; peer =
peer->ass_next) {
if (assoc == peer->associd)
return (peer);
1999-12-09 13:01:21 +00:00
}
2001-08-29 14:35:15 +00:00
return (NULL);
1999-12-09 13:01:21 +00:00
}
/*
2001-08-29 14:35:15 +00:00
* clear_all - flush all time values for all associations
1999-12-09 13:01:21 +00:00
*/
void
2001-08-29 14:35:15 +00:00
clear_all(void)
1999-12-09 13:01:21 +00:00
{
struct peer *peer, *next_peer;
int n;
2001-08-29 14:35:15 +00:00
/*
* This routine is called when the clock is stepped, and so all
* previously saved time values are untrusted.
*/
1999-12-09 13:01:21 +00:00
for (n = 0; n < HASH_SIZE; n++) {
for (peer = peer_hash[n]; peer != 0; peer = next_peer) {
next_peer = peer->next;
2004-07-20 15:01:56 +00:00
if (peer->flags & FLAG_CONFIG) {
if (!(peer->cast_flags & (MDF_ACAST |
MDF_MCAST | MDF_BCAST)))
peer_clear(peer, "STEP");
} else {
unpeer(peer);
}
1999-12-09 13:01:21 +00:00
}
}
#ifdef DEBUG
if (debug)
2001-08-29 14:35:15 +00:00
printf("clear_all: at %lu\n", current_time);
1999-12-09 13:01:21 +00:00
#endif
}
2001-08-29 14:35:15 +00:00
1999-12-09 13:01:21 +00:00
/*
* unpeer - remove peer structure from hash table and free structure
*/
void
unpeer(
struct peer *peer_to_remove
)
{
int hash;
2004-07-20 15:01:56 +00:00
#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 */
1999-12-09 13:01:21 +00:00
#ifdef DEBUG
2001-08-29 14:35:15 +00:00
if (debug)
printf("demobilize %u %d\n", peer_to_remove->associd,
peer_associations);
1999-12-09 13:01:21 +00:00
#endif
2004-07-20 15:01:56 +00:00
peer_clear(peer_to_remove, "NULL");
1999-12-09 13:01:21 +00:00
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!",
2004-07-20 15:01:56 +00:00
stoa(&peer->srcadr));
1999-12-09 13:01:21 +00:00
} 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!",
2004-07-20 15:01:56 +00:00
stoa(&peer->srcadr));
1999-12-09 13:01:21 +00:00
} else {
peer->ass_next = peer_to_remove->ass_next;
}
}
peer_to_remove->next = peer_free;
peer_free = peer_to_remove;
peer_free_count++;
2004-07-20 15:01:56 +00:00
peer_associations--;
1999-12-09 13:01:21 +00:00
}
/*
2001-08-29 14:35:15 +00:00
* peer_config - configure a new association
1999-12-09 13:01:21 +00:00
*/
struct peer *
peer_config(
2004-07-20 15:01:56 +00:00
struct sockaddr_storage *srcadr,
1999-12-09 13:01:21 +00:00
struct interface *dstadr,
int hmode,
int version,
int minpoll,
int maxpoll,
2001-08-29 14:35:15 +00:00
u_int flags,
1999-12-09 13:01:21 +00:00
int ttl,
2001-08-29 14:35:15 +00:00
keyid_t key,
u_char *keystr
1999-12-09 13:01:21 +00:00
)
{
register struct peer *peer;
2004-07-20 15:01:56 +00:00
u_char cast_flags;
1999-12-09 13:01:21 +00:00
/*
2001-08-29 14:35:15 +00:00
* 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.
1999-12-09 13:01:21 +00:00
*/
peer = findexistingpeer(srcadr, (struct peer *)0, hmode);
if (dstadr != 0) {
while (peer != 0) {
if (peer->dstadr == dstadr)
2001-08-29 14:35:15 +00:00
break;
1999-12-09 13:01:21 +00:00
peer = findexistingpeer(srcadr, peer, hmode);
}
}
/*
2001-08-29 14:35:15 +00:00
* 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:
2004-07-20 15:01:56 +00:00
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;
}
2001-08-29 14:35:15 +00:00
case MODE_CLIENT:
2004-07-20 15:01:56 +00:00
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;
}
2001-08-29 14:35:15 +00:00
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.
1999-12-09 13:01:21 +00:00
*/
if (peer != 0) {
peer->hmode = (u_char)hmode;
2004-07-20 15:01:56 +00:00
peer->version = (u_char) version;
peer->minpoll = (u_char) minpoll;
peer->maxpoll = (u_char) maxpoll;
1999-12-09 13:01:21 +00:00
peer->flags = flags | FLAG_CONFIG |
(peer->flags & FLAG_REFCLOCK);
2001-08-29 14:35:15 +00:00
peer->cast_flags = cast_flags;
2004-07-20 15:01:56 +00:00
peer->ttl = (u_char) ttl;
1999-12-09 13:01:21 +00:00
peer->keyid = key;
2004-07-20 15:01:56 +00:00
peer->precision = sys_precision;
peer_clear(peer, "RMOT");
2001-08-29 14:35:15 +00:00
return (peer);
1999-12-09 13:01:21 +00:00
}
/*
2001-08-29 14:35:15 +00:00
* Here no match has been found, so presumably this is a new
* persistent association. Mobilize the thing and initialize its
2004-07-20 15:01:56 +00:00
* variables. If emulating ntpdate, force iburst.
1999-12-09 13:01:21 +00:00
*/
2004-07-20 15:01:56 +00:00
if (mode_ntpdate)
flags |= FLAG_IBURST;
1999-12-09 13:01:21 +00:00
peer = newpeer(srcadr, dstadr, hmode, version, minpoll, maxpoll,
2001-08-29 14:35:15 +00:00
flags | FLAG_CONFIG, cast_flags, ttl, key);
return (peer);
1999-12-09 13:01:21 +00:00
}
/*
* newpeer - initialize a new peer association
*/
struct peer *
newpeer(
2004-07-20 15:01:56 +00:00
struct sockaddr_storage *srcadr,
1999-12-09 13:01:21 +00:00
struct interface *dstadr,
int hmode,
int version,
int minpoll,
int maxpoll,
2001-08-29 14:35:15 +00:00
u_int flags,
2004-07-20 15:01:56 +00:00
u_char cast_flags,
1999-12-09 13:01:21 +00:00
int ttl,
2001-08-29 14:35:15 +00:00
keyid_t key
1999-12-09 13:01:21 +00:00
)
{
register struct peer *peer;
register int i;
2004-07-20 15:01:56 +00:00
#ifdef OPENSSL
char statstr[NTP_MAXSTRLEN]; /* statistics for filegen */
#endif /* OPENSSL */
1999-12-09 13:01:21 +00:00
/*
2001-08-29 14:35:15 +00:00
* Allocate a new peer structure. Some dirt here, since some of
* the initialization requires knowlege of our system state.
1999-12-09 13:01:21 +00:00
*/
if (peer_free_count == 0)
2001-08-29 14:35:15 +00:00
getmorepeermem();
1999-12-09 13:01:21 +00:00
peer = peer_free;
peer_free = peer->next;
peer_free_count--;
peer_associations++;
2001-08-29 14:35:15 +00:00
memset((char *)peer, 0, sizeof(struct peer));
1999-12-09 13:01:21 +00:00
2004-07-20 15:01:56 +00:00
/*
* Assign an association ID and increment the system variable.
*/
peer->associd = current_association_ID;
if (++current_association_ID == 0)
++current_association_ID;
1999-12-09 13:01:21 +00:00
/*
2001-08-29 14:35:15 +00:00
* 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.
1999-12-09 13:01:21 +00:00
*/
2001-08-29 14:35:15 +00:00
if (ISREFCLOCKADR(srcadr))
peer->dstadr = loopback_interface;
2004-07-20 15:01:56 +00:00
else if (cast_flags & (MDF_BCLNT | MDF_ACAST | MDF_MCAST | MDF_BCAST)) {
1999-12-09 13:01:21 +00:00
peer->dstadr = findbcastinter(srcadr);
2004-07-20 15:01:56 +00:00
/*
* 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))
2001-08-29 14:35:15 +00:00
peer->dstadr = dstadr;
1999-12-09 13:01:21 +00:00
else
2001-08-29 14:35:15 +00:00
peer->dstadr = findinterface(srcadr);
peer->srcadr = *srcadr;
1999-12-09 13:01:21 +00:00
peer->hmode = (u_char)hmode;
peer->version = (u_char)version;
2001-08-29 14:35:15 +00:00
peer->minpoll = (u_char)max(NTP_MINPOLL, minpoll);
peer->maxpoll = (u_char)min(NTP_MAXPOLL, maxpoll);
2004-07-20 15:01:56 +00:00
peer->flags = flags;
if (key != 0)
peer->flags |= FLAG_AUTHENABLE;
if (key > NTP_MAXKEY)
peer->flags |= FLAG_SKEY;
2001-08-29 14:35:15 +00:00
peer->cast_flags = cast_flags;
2004-07-20 15:01:56 +00:00
peer->ttl = (u_char)ttl;
2001-08-29 14:35:15 +00:00
peer->keyid = key;
1999-12-09 13:01:21 +00:00
peer->precision = sys_precision;
2004-07-20 15:01:56 +00:00
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");
2001-08-29 14:35:15 +00:00
if (mode_ntpdate)
peer_ntpdate++;
1999-12-09 13:01:21 +00:00
/*
* 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++;
2001-08-29 14:35:15 +00:00
return (NULL);
1999-12-09 13:01:21 +00:00
}
}
#endif
/*
2001-08-29 14:35:15 +00:00
* Put the new peer in the hash tables.
1999-12-09 13:01:21 +00:00
*/
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]++;
2004-07-20 15:01:56 +00:00
#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 */
1999-12-09 13:01:21 +00:00
#ifdef DEBUG
2001-08-29 14:35:15 +00:00
if (debug)
printf(
2004-07-20 15:01:56 +00:00
"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),
2001-08-29 14:35:15 +00:00
peer->hmode, peer->version, peer->minpoll,
peer->maxpoll, peer->flags, peer->cast_flags,
2004-07-20 15:01:56 +00:00
peer->ttl, peer->keyid);
1999-12-09 13:01:21 +00:00
#endif
2001-08-29 14:35:15 +00:00
return (peer);
1999-12-09 13:01:21 +00:00
}
/*
* peer_unconfig - remove the configuration bit from a peer
*/
int
peer_unconfig(
2004-07-20 15:01:56 +00:00
struct sockaddr_storage *srcadr,
1999-12-09 13:01:21 +00:00
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++;
2001-08-29 14:35:15 +00:00
1999-12-09 13:01:21 +00:00
/*
2001-08-29 14:35:15 +00:00
* 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.
1999-12-09 13:01:21 +00:00
*/
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);
}
2001-08-29 14:35:15 +00:00
return (num_found);
1999-12-09 13:01:21 +00:00
}
/*
* 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;
2004-07-20 15:01:56 +00:00
peer->rank = 0;
1999-12-09 13:01:21 +00:00
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);
}
2001-08-29 14:35:15 +00:00
2004-07-20 15:01:56 +00:00
#ifdef OPENSSL
2001-08-29 14:35:15 +00:00
/*
* 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.
*/
2004-07-20 15:01:56 +00:00
if (!crypto_flags)
return;
2001-08-29 14:35:15 +00:00
for (n = 0; n < HASH_SIZE; n++) {
for (peer = peer_hash[n]; peer != 0; peer = next_peer) {
next_peer = peer->next;
2004-07-20 15:01:56 +00:00
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) {
2001-08-29 14:35:15 +00:00
key_expire(peer);
2004-07-20 15:01:56 +00:00
peer->crypto &= ~(CRYPTO_FLAG_AUTO |
CRYPTO_FLAG_AGREE);
2001-08-29 14:35:15 +00:00
}
}
}
2004-07-20 15:01:56 +00:00
RAND_bytes((u_char *)&sys_private, 4);
crypto_update();
resetmanycast();
2001-08-29 14:35:15 +00:00
}
2004-07-20 15:01:56 +00:00
#endif /* OPENSSL */
2001-08-29 14:35:15 +00:00
/*
* 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;
2004-07-20 15:01:56 +00:00
poll_update(peer, 0);
2001-08-29 14:35:15 +00:00
}
}
}
}