1c0b746e5SOllivier Robert /* 2c0b746e5SOllivier Robert * ntp_monitor.c - monitor who is using the ntpd server 3c0b746e5SOllivier Robert */ 4c0b746e5SOllivier Robert #ifdef HAVE_CONFIG_H 5c0b746e5SOllivier Robert #include <config.h> 6c0b746e5SOllivier Robert #endif 7c0b746e5SOllivier Robert 8c0b746e5SOllivier Robert #include <stdio.h> 9c0b746e5SOllivier Robert #include <sys/types.h> 10c0b746e5SOllivier Robert #include <signal.h> 11c0b746e5SOllivier Robert # ifdef HAVE_SYS_IOCTL_H 12c0b746e5SOllivier Robert # include <sys/ioctl.h> 13c0b746e5SOllivier Robert # endif 14c0b746e5SOllivier Robert # include <sys/time.h> 15c0b746e5SOllivier Robert 16c0b746e5SOllivier Robert #include "ntpd.h" 17c0b746e5SOllivier Robert #include "ntp_io.h" 18c0b746e5SOllivier Robert #include "ntp_if.h" 19c0b746e5SOllivier Robert #include "ntp_stdlib.h" 20c0b746e5SOllivier Robert 21c0b746e5SOllivier Robert /* 22c0b746e5SOllivier Robert * I'm still not sure I like what I've done here. It certainly consumes 23c0b746e5SOllivier Robert * memory like it is going out of style, and also may not be as low 24c0b746e5SOllivier Robert * overhead as I'd imagined. 25c0b746e5SOllivier Robert * 26c0b746e5SOllivier Robert * Anyway, we record statistics based on source address, mode and version 27c0b746e5SOllivier Robert * (for now, anyway. Check the code). The receive procedure calls us with 28c0b746e5SOllivier Robert * the incoming rbufp before it does anything else. 29c0b746e5SOllivier Robert * 30c0b746e5SOllivier Robert * Each entry is doubly linked into two lists, a hash table and a 31c0b746e5SOllivier Robert * most-recently-used list. When a packet arrives it is looked up 32c0b746e5SOllivier Robert * in the hash table. If found, the statistics are updated and the 33c0b746e5SOllivier Robert * entry relinked at the head of the MRU list. If not found, a new 34c0b746e5SOllivier Robert * entry is allocated, initialized and linked into both the hash 35c0b746e5SOllivier Robert * table and at the head of the MRU list. 36c0b746e5SOllivier Robert * 37c0b746e5SOllivier Robert * Memory is usually allocated by grabbing a big chunk of new memory 38c0b746e5SOllivier Robert * and cutting it up into littler pieces. The exception to this when we 39c0b746e5SOllivier Robert * hit the memory limit. Then we free memory by grabbing entries off 40c0b746e5SOllivier Robert * the tail for the MRU list, unlinking from the hash table, and 41c0b746e5SOllivier Robert * reinitializing. 42c0b746e5SOllivier Robert * 43c0b746e5SOllivier Robert * trimmed back memory consumption ... jdg 8/94 44c0b746e5SOllivier Robert */ 45c0b746e5SOllivier Robert 46c0b746e5SOllivier Robert /* 47c0b746e5SOllivier Robert * Limits on the number of structures allocated. This limit is picked 48c0b746e5SOllivier Robert * with the illicit knowlege that we can only return somewhat less 49c0b746e5SOllivier Robert * than 8K bytes in a mode 7 response packet, and that each structure 50c0b746e5SOllivier Robert * will require about 20 bytes of space in the response. 51c0b746e5SOllivier Robert * 52c0b746e5SOllivier Robert * ... I don't believe the above is true anymore ... jdg 53c0b746e5SOllivier Robert */ 54c0b746e5SOllivier Robert #ifndef MAXMONMEM 55c0b746e5SOllivier Robert #define MAXMONMEM 600 /* we allocate up to 600 structures */ 56c0b746e5SOllivier Robert #endif 57c0b746e5SOllivier Robert #ifndef MONMEMINC 58c0b746e5SOllivier Robert #define MONMEMINC 40 /* allocate them 40 at a time */ 59c0b746e5SOllivier Robert #endif 60c0b746e5SOllivier Robert 61c0b746e5SOllivier Robert /* 62c0b746e5SOllivier Robert * Hashing stuff 63c0b746e5SOllivier Robert */ 64c0b746e5SOllivier Robert #define MON_HASH_SIZE 128 65c0b746e5SOllivier Robert #define MON_HASH_MASK (MON_HASH_SIZE-1) 66c0b746e5SOllivier Robert #define MON_HASH(addr) ((int)(ntohl((addr)) & MON_HASH_MASK)) 67c0b746e5SOllivier Robert 68c0b746e5SOllivier Robert /* 69c0b746e5SOllivier Robert * Pointers to the hash table, the MRU list and the count table. Memory 70c0b746e5SOllivier Robert * for the hash and count tables is only allocated if monitoring is turned on. 71c0b746e5SOllivier Robert */ 72c0b746e5SOllivier Robert static struct mon_data *mon_hash[MON_HASH_SIZE]; /* array of list ptrs */ 73c0b746e5SOllivier Robert struct mon_data mon_mru_list; 74c0b746e5SOllivier Robert struct mon_data mon_fifo_list; 75c0b746e5SOllivier Robert /* 76c0b746e5SOllivier Robert * List of free structures structures, and counters of free and total 77c0b746e5SOllivier Robert * structures. The free structures are linked with the hash_next field. 78c0b746e5SOllivier Robert */ 79c0b746e5SOllivier Robert static struct mon_data *mon_free; /* the free list or null if none */ 80c0b746e5SOllivier Robert 81c0b746e5SOllivier Robert static int mon_total_mem; /* total number of structures allocated */ 82c0b746e5SOllivier Robert static int mon_mem_increments; /* number of times we've called malloc() */ 83c0b746e5SOllivier Robert 84c0b746e5SOllivier Robert /* 85c0b746e5SOllivier Robert * Initialization state. We may be monitoring, we may not. If 86c0b746e5SOllivier Robert * we aren't, we may not even have allocated any memory yet. 87c0b746e5SOllivier Robert */ 88c0b746e5SOllivier Robert int mon_enabled; 89c0b746e5SOllivier Robert static int mon_have_memory; 90c0b746e5SOllivier Robert 91c0b746e5SOllivier Robert static void mon_getmoremem P((void)); 92c0b746e5SOllivier Robert static void remove_from_hash P((struct mon_data *)); 93c0b746e5SOllivier Robert 94c0b746e5SOllivier Robert /* 95c0b746e5SOllivier Robert * init_mon - initialize monitoring global data 96c0b746e5SOllivier Robert */ 97c0b746e5SOllivier Robert void 98c0b746e5SOllivier Robert init_mon(void) 99c0b746e5SOllivier Robert { 100c0b746e5SOllivier Robert /* 101c0b746e5SOllivier Robert * Don't do much of anything here. We don't allocate memory 102c0b746e5SOllivier Robert * until someone explicitly starts us. 103c0b746e5SOllivier Robert */ 104c0b746e5SOllivier Robert mon_enabled = MON_OFF; 105c0b746e5SOllivier Robert mon_have_memory = 0; 106c0b746e5SOllivier Robert 107c0b746e5SOllivier Robert mon_total_mem = 0; 108c0b746e5SOllivier Robert mon_mem_increments = 0; 109c0b746e5SOllivier Robert mon_free = NULL; 110c0b746e5SOllivier Robert memset((char *)&mon_hash[0], 0, sizeof mon_hash); 111c0b746e5SOllivier Robert memset((char *)&mon_mru_list, 0, sizeof mon_mru_list); 112c0b746e5SOllivier Robert memset((char *)&mon_fifo_list, 0, sizeof mon_fifo_list); 113c0b746e5SOllivier Robert } 114c0b746e5SOllivier Robert 115c0b746e5SOllivier Robert 116c0b746e5SOllivier Robert /* 117c0b746e5SOllivier Robert * mon_start - start up the monitoring software 118c0b746e5SOllivier Robert */ 119c0b746e5SOllivier Robert void 120c0b746e5SOllivier Robert mon_start( 121c0b746e5SOllivier Robert int mode 122c0b746e5SOllivier Robert ) 123c0b746e5SOllivier Robert { 124c0b746e5SOllivier Robert 125c0b746e5SOllivier Robert if (mon_enabled != MON_OFF) { 126c0b746e5SOllivier Robert mon_enabled |= mode; 127c0b746e5SOllivier Robert return; 128c0b746e5SOllivier Robert } 129c0b746e5SOllivier Robert if (mode == MON_OFF) 130c0b746e5SOllivier Robert return; /* Ooops.. */ 131c0b746e5SOllivier Robert 132c0b746e5SOllivier Robert if (!mon_have_memory) { 133c0b746e5SOllivier Robert mon_total_mem = 0; 134c0b746e5SOllivier Robert mon_mem_increments = 0; 135c0b746e5SOllivier Robert mon_free = NULL; 136c0b746e5SOllivier Robert mon_getmoremem(); 137c0b746e5SOllivier Robert mon_have_memory = 1; 138c0b746e5SOllivier Robert } 139c0b746e5SOllivier Robert 140c0b746e5SOllivier Robert mon_mru_list.mru_next = &mon_mru_list; 141c0b746e5SOllivier Robert mon_mru_list.mru_prev = &mon_mru_list; 142c0b746e5SOllivier Robert 143c0b746e5SOllivier Robert mon_fifo_list.fifo_next = &mon_fifo_list; 144c0b746e5SOllivier Robert mon_fifo_list.fifo_prev = &mon_fifo_list; 145c0b746e5SOllivier Robert 146c0b746e5SOllivier Robert mon_enabled = mode; 147c0b746e5SOllivier Robert } 148c0b746e5SOllivier Robert 149c0b746e5SOllivier Robert 150c0b746e5SOllivier Robert /* 151c0b746e5SOllivier Robert * mon_stop - stop the monitoring software 152c0b746e5SOllivier Robert */ 153c0b746e5SOllivier Robert void 154c0b746e5SOllivier Robert mon_stop( 155c0b746e5SOllivier Robert int mode 156c0b746e5SOllivier Robert ) 157c0b746e5SOllivier Robert { 158c0b746e5SOllivier Robert register struct mon_data *md, *md_next; 159c0b746e5SOllivier Robert register int i; 160c0b746e5SOllivier Robert 161c0b746e5SOllivier Robert if (mon_enabled == MON_OFF) 162c0b746e5SOllivier Robert return; 163c0b746e5SOllivier Robert if ((mon_enabled & mode) == 0 || mode == MON_OFF) 164c0b746e5SOllivier Robert return; 165c0b746e5SOllivier Robert 166c0b746e5SOllivier Robert mon_enabled &= ~mode; 167c0b746e5SOllivier Robert if (mon_enabled != MON_OFF) 168c0b746e5SOllivier Robert return; 169c0b746e5SOllivier Robert 170c0b746e5SOllivier Robert /* 171c0b746e5SOllivier Robert * Put everything back on the free list 172c0b746e5SOllivier Robert */ 173c0b746e5SOllivier Robert for (i = 0; i < MON_HASH_SIZE; i++) { 174c0b746e5SOllivier Robert md = mon_hash[i]; /* get next list */ 175c0b746e5SOllivier Robert mon_hash[i] = NULL; /* zero the list head */ 176c0b746e5SOllivier Robert while (md != NULL) { 177c0b746e5SOllivier Robert md_next = md->hash_next; 178c0b746e5SOllivier Robert md->hash_next = mon_free; 179c0b746e5SOllivier Robert mon_free = md; 180c0b746e5SOllivier Robert md = md_next; 181c0b746e5SOllivier Robert } 182c0b746e5SOllivier Robert } 183c0b746e5SOllivier Robert 184c0b746e5SOllivier Robert mon_mru_list.mru_next = &mon_mru_list; 185c0b746e5SOllivier Robert mon_mru_list.mru_prev = &mon_mru_list; 186c0b746e5SOllivier Robert 187c0b746e5SOllivier Robert mon_fifo_list.fifo_next = &mon_fifo_list; 188c0b746e5SOllivier Robert mon_fifo_list.fifo_prev = &mon_fifo_list; 189c0b746e5SOllivier Robert } 190c0b746e5SOllivier Robert 191c0b746e5SOllivier Robert 192c0b746e5SOllivier Robert /* 193c0b746e5SOllivier Robert * ntp_monitor - record stats about this packet 194c0b746e5SOllivier Robert */ 195c0b746e5SOllivier Robert void 196c0b746e5SOllivier Robert ntp_monitor( 197c0b746e5SOllivier Robert struct recvbuf *rbufp 198c0b746e5SOllivier Robert ) 199c0b746e5SOllivier Robert { 200c0b746e5SOllivier Robert register struct pkt *pkt; 201c0b746e5SOllivier Robert register struct mon_data *md; 202c0b746e5SOllivier Robert register u_long netnum; 203c0b746e5SOllivier Robert register int hash; 204c0b746e5SOllivier Robert register int mode; 205c0b746e5SOllivier Robert 206c0b746e5SOllivier Robert if (mon_enabled == MON_OFF) 207c0b746e5SOllivier Robert return; 208c0b746e5SOllivier Robert 209c0b746e5SOllivier Robert pkt = &rbufp->recv_pkt; 210c0b746e5SOllivier Robert netnum = NSRCADR(&rbufp->recv_srcadr); 211c0b746e5SOllivier Robert hash = MON_HASH(netnum); 212c0b746e5SOllivier Robert mode = PKT_MODE(pkt->li_vn_mode); 213c0b746e5SOllivier Robert 214c0b746e5SOllivier Robert md = mon_hash[hash]; 215c0b746e5SOllivier Robert while (md != NULL) { 216c0b746e5SOllivier Robert if (md->rmtadr == netnum && 217c0b746e5SOllivier Robert /* ?? md->interface == rbufp->dstadr && ?? */ 218c0b746e5SOllivier Robert md->mode == (u_char)mode) { 219c0b746e5SOllivier Robert md->lasttime = current_time; 220c0b746e5SOllivier Robert md->count++; 221c0b746e5SOllivier Robert md->version = PKT_VERSION(pkt->li_vn_mode); 222c0b746e5SOllivier Robert md->rmtport = NSRCPORT(&rbufp->recv_srcadr); 223c0b746e5SOllivier Robert 224c0b746e5SOllivier Robert /* 225c0b746e5SOllivier Robert * Shuffle him to the head of the 226c0b746e5SOllivier Robert * mru list. What a crock. 227c0b746e5SOllivier Robert */ 228c0b746e5SOllivier Robert md->mru_next->mru_prev = md->mru_prev; 229c0b746e5SOllivier Robert md->mru_prev->mru_next = md->mru_next; 230c0b746e5SOllivier Robert md->mru_next = mon_mru_list.mru_next; 231c0b746e5SOllivier Robert md->mru_prev = &mon_mru_list; 232c0b746e5SOllivier Robert mon_mru_list.mru_next->mru_prev = md; 233c0b746e5SOllivier Robert mon_mru_list.mru_next = md; 234c0b746e5SOllivier Robert 235c0b746e5SOllivier Robert return; 236c0b746e5SOllivier Robert } 237c0b746e5SOllivier Robert md = md->hash_next; 238c0b746e5SOllivier Robert } 239c0b746e5SOllivier Robert 240c0b746e5SOllivier Robert /* 241c0b746e5SOllivier Robert * If we got here, this is the first we've heard of this 242c0b746e5SOllivier Robert * guy. Get him some memory, either from the free list 243c0b746e5SOllivier Robert * or from the tail of the MRU list. 244c0b746e5SOllivier Robert */ 245c0b746e5SOllivier Robert if (mon_free == NULL && mon_total_mem >= MAXMONMEM) { 246c0b746e5SOllivier Robert /* 247c0b746e5SOllivier Robert * Get it from MRU list 248c0b746e5SOllivier Robert */ 249c0b746e5SOllivier Robert md = mon_mru_list.mru_prev; 250c0b746e5SOllivier Robert md->mru_prev->mru_next = &mon_mru_list; 251c0b746e5SOllivier Robert mon_mru_list.mru_prev = md->mru_prev; 252c0b746e5SOllivier Robert 253c0b746e5SOllivier Robert remove_from_hash(md); 254c0b746e5SOllivier Robert 255c0b746e5SOllivier Robert /* 256c0b746e5SOllivier Robert * Get it from FIFO list 257c0b746e5SOllivier Robert */ 258c0b746e5SOllivier Robert md->fifo_prev->fifo_next = md->fifo_next; 259c0b746e5SOllivier Robert md->fifo_next->fifo_prev = md->fifo_prev; 260c0b746e5SOllivier Robert 261c0b746e5SOllivier Robert } else { 262c0b746e5SOllivier Robert if (mon_free == NULL) /* if free list empty */ 263c0b746e5SOllivier Robert mon_getmoremem(); /* then get more */ 264c0b746e5SOllivier Robert md = mon_free; 265c0b746e5SOllivier Robert mon_free = md->hash_next; 266c0b746e5SOllivier Robert } 267c0b746e5SOllivier Robert 268c0b746e5SOllivier Robert /* 269c0b746e5SOllivier Robert * Got one, initialize it 270c0b746e5SOllivier Robert */ 271c0b746e5SOllivier Robert md->lasttime = md->firsttime = current_time; 272c0b746e5SOllivier Robert md->lastdrop = 0; 273c0b746e5SOllivier Robert md->count = 1; 274c0b746e5SOllivier Robert md->rmtadr = netnum; 275c0b746e5SOllivier Robert md->rmtport = NSRCPORT(&rbufp->recv_srcadr); 276c0b746e5SOllivier Robert md->mode = (u_char) mode; 277c0b746e5SOllivier Robert md->version = PKT_VERSION(pkt->li_vn_mode); 278c0b746e5SOllivier Robert md->interface = rbufp->dstadr; 279c0b746e5SOllivier Robert md->cast_flags = ((rbufp->dstadr->flags & INT_MULTICAST) && 280c0b746e5SOllivier Robert rbufp->fd == md->interface->fd) ? MDF_MCAST: rbufp->fd == 281c0b746e5SOllivier Robert md->interface->bfd ? MDF_BCAST : MDF_UCAST; 282c0b746e5SOllivier Robert 283c0b746e5SOllivier Robert /* 284c0b746e5SOllivier Robert * Drop him into front of the hash table. 285c0b746e5SOllivier Robert * Also put him on top of the MRU list 286c0b746e5SOllivier Robert * and at bottom of FIFO list 287c0b746e5SOllivier Robert */ 288c0b746e5SOllivier Robert 289c0b746e5SOllivier Robert md->hash_next = mon_hash[hash]; 290c0b746e5SOllivier Robert mon_hash[hash] = md; 291c0b746e5SOllivier Robert 292c0b746e5SOllivier Robert md->mru_next = mon_mru_list.mru_next; 293c0b746e5SOllivier Robert md->mru_prev = &mon_mru_list; 294c0b746e5SOllivier Robert mon_mru_list.mru_next->mru_prev = md; 295c0b746e5SOllivier Robert mon_mru_list.mru_next = md; 296c0b746e5SOllivier Robert 297c0b746e5SOllivier Robert md->fifo_prev = mon_fifo_list.fifo_prev; 298c0b746e5SOllivier Robert md->fifo_next = &mon_fifo_list; 299c0b746e5SOllivier Robert mon_fifo_list.fifo_prev->fifo_next = md; 300c0b746e5SOllivier Robert mon_fifo_list.fifo_prev = md; 301c0b746e5SOllivier Robert } 302c0b746e5SOllivier Robert 303c0b746e5SOllivier Robert 304c0b746e5SOllivier Robert /* 305c0b746e5SOllivier Robert * mon_getmoremem - get more memory and put it on the free list 306c0b746e5SOllivier Robert */ 307c0b746e5SOllivier Robert static void 308c0b746e5SOllivier Robert mon_getmoremem(void) 309c0b746e5SOllivier Robert { 310c0b746e5SOllivier Robert register struct mon_data *md; 311c0b746e5SOllivier Robert register int i; 312c0b746e5SOllivier Robert struct mon_data *freedata; /* 'old' free list (null) */ 313c0b746e5SOllivier Robert 314c0b746e5SOllivier Robert md = (struct mon_data *)emalloc(MONMEMINC * sizeof(struct mon_data)); 315c0b746e5SOllivier Robert freedata = mon_free; 316c0b746e5SOllivier Robert mon_free = md; 317c0b746e5SOllivier Robert 318c0b746e5SOllivier Robert for (i = 0; i < (MONMEMINC-1); i++) { 319c0b746e5SOllivier Robert md->hash_next = (md + 1); 320c0b746e5SOllivier Robert md++; 321c0b746e5SOllivier Robert } 322c0b746e5SOllivier Robert 323c0b746e5SOllivier Robert /* 324c0b746e5SOllivier Robert * md now points at the last. Link in the rest of the chain. 325c0b746e5SOllivier Robert */ 326c0b746e5SOllivier Robert md->hash_next = freedata; 327c0b746e5SOllivier Robert 328c0b746e5SOllivier Robert mon_total_mem += MONMEMINC; 329c0b746e5SOllivier Robert mon_mem_increments++; 330c0b746e5SOllivier Robert } 331c0b746e5SOllivier Robert 332c0b746e5SOllivier Robert static void 333c0b746e5SOllivier Robert remove_from_hash( 334c0b746e5SOllivier Robert struct mon_data *md 335c0b746e5SOllivier Robert ) 336c0b746e5SOllivier Robert { 337c0b746e5SOllivier Robert register int hash; 338c0b746e5SOllivier Robert register struct mon_data *md_prev; 339c0b746e5SOllivier Robert 340c0b746e5SOllivier Robert hash = MON_HASH(md->rmtadr); 341c0b746e5SOllivier Robert if (mon_hash[hash] == md) { 342c0b746e5SOllivier Robert mon_hash[hash] = md->hash_next; 343c0b746e5SOllivier Robert } else { 344c0b746e5SOllivier Robert md_prev = mon_hash[hash]; 345c0b746e5SOllivier Robert while (md_prev->hash_next != md) { 346c0b746e5SOllivier Robert md_prev = md_prev->hash_next; 347c0b746e5SOllivier Robert if (md_prev == NULL) { 348c0b746e5SOllivier Robert /* logic error */ 349c0b746e5SOllivier Robert return; 350c0b746e5SOllivier Robert } 351c0b746e5SOllivier Robert } 352c0b746e5SOllivier Robert md_prev->hash_next = md->hash_next; 353c0b746e5SOllivier Robert } 354c0b746e5SOllivier Robert } 355