📄 ntp_peer.c
字号:
/* * 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"#include <ntp_random.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 0 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 * 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. */#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] = {/* { UNSPEC, ACTIVE, PASSIVE, CLIENT, SERVER, BCAST } *//*NONE*/{ AM_ERR, AM_NEWPASS, AM_NOMATCH, 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},/*BCL*/ { AM_ERR, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH, 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[NTP_HASH_SIZE]; /* peer hash table */int peer_hash_count[NTP_HASH_SIZE]; /* peers in each bucket */struct peer *assoc_hash[NTP_HASH_SIZE]; /* association ID hash table */int assoc_hash_count[NTP_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; /* mobilized associations */int peer_preempt; /* preemptable 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. */voidinit_peer(void){ register int i; /* * Clear hash table and counters. */ for (i = 0; i < NTP_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 */ while ((current_association_ID = ntp_random() & 0xffff) == 0);}/* * getmorepeermem - add more peer structures to the free list */static voidgetmorepeermem(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[NTP_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 pkt_mode, int *action ){ register struct peer *peer; int hash; findpeer_calls++; hash = NTP_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); /* * 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 & NTP_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 */voidclear_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 < NTP_HASH_SIZE; n++) { for (peer = peer_hash[n]; peer != 0; peer = next_peer) { next_peer = peer->next; if (!(peer->cast_flags & (MDF_ACAST | MDF_MCAST | MDF_BCAST))) { peer->hpoll = peer->minpoll; peer_clear(peer, "STEP"); } } }#ifdef DEBUG if (debug) printf("clear_all: at %lu\n", current_time);#endif}/* * unpeer - remove peer structure from hash table and free structure */voidunpeer( 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 %d\n", peer_to_remove->associd, peer_associations, peer_preempt);#endif hash = NTP_HASH_ADDR(&peer_to_remove->srcadr); peer_hash_count[hash]--; peer_demobilizations++; peer_associations--; if (peer_to_remove->flags & FLAG_PREEMPT) peer_preempt--;#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 & NTP_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_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); } } /*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -