1 /*
2 chronyd/chronyc - Programs for keeping computer clocks accurate.
3
4 **********************************************************************
5 * Copyright (C) Richard P. Curnow 1997-2003
6 * Copyright (C) Miroslav Lichvar 2009, 2015-2017, 2021
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of version 2 of the GNU General Public License as
10 * published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 *
21 **********************************************************************
22
23 =======================================================================
24
25 This module keeps a count of the number of successful accesses by
26 clients, and the times of the last accesses.
27
28 This can be used for status reporting, and (in the case of a
29 server), if it needs to know which clients have made use of its data
30 recently.
31
32 */
33
34 #include "config.h"
35
36 #include "sysincl.h"
37
38 #include "array.h"
39 #include "clientlog.h"
40 #include "conf.h"
41 #include "local.h"
42 #include "memory.h"
43 #include "ntp.h"
44 #include "reports.h"
45 #include "util.h"
46 #include "logging.h"
47
48 #define MAX_SERVICES 3
49
50 typedef struct {
51 IPAddr ip_addr;
52 uint32_t last_hit[MAX_SERVICES];
53 uint32_t hits[MAX_SERVICES];
54 uint16_t drops[MAX_SERVICES];
55 uint16_t tokens[MAX_SERVICES];
56 int8_t rate[MAX_SERVICES];
57 int8_t ntp_timeout_rate;
58 uint8_t drop_flags;
59 } Record;
60
61 /* Hash table of records, there is a fixed number of records per slot */
62 static ARR_Instance records;
63
64 #define SLOT_BITS 4
65
66 /* Number of records in one slot of the hash table */
67 #define SLOT_SIZE (1U << SLOT_BITS)
68
69 /* Minimum number of slots */
70 #define MIN_SLOTS 1
71
72 /* Maximum number of slots, this is a hard limit */
73 #define MAX_SLOTS (1U << (24 - SLOT_BITS))
74
75 /* Number of slots in the hash table */
76 static unsigned int slots;
77
78 /* Maximum number of slots given memory allocation limit */
79 static unsigned int max_slots;
80
81 /* Times of last hits are saved as 32-bit fixed point values */
82 #define TS_FRAC 4
83 #define INVALID_TS 0
84
85 /* Static offset included in conversion to the fixed-point timestamps to
86 randomise their alignment */
87 static uint32_t ts_offset;
88
89 /* Request rates are saved in the record as 8-bit scaled log2 values */
90 #define RATE_SCALE 4
91 #define MIN_RATE (-14 * RATE_SCALE)
92 #define INVALID_RATE -128
93
94 /* Response rates are controlled by token buckets. The capacity and
95 number of tokens spent on response are determined from configured
96 minimum inverval between responses (in log2) and burst length. */
97
98 #define MIN_LIMIT_INTERVAL (-15 - TS_FRAC)
99 #define MAX_LIMIT_INTERVAL 12
100 #define MIN_LIMIT_BURST 1
101 #define MAX_LIMIT_BURST 255
102
103 static uint16_t max_tokens[MAX_SERVICES];
104 static uint16_t tokens_per_hit[MAX_SERVICES];
105
106 /* Reduction of token rates to avoid overflow of 16-bit counters. Negative
107 shift is used for coarse limiting with intervals shorter than -TS_FRAC. */
108 static int token_shift[MAX_SERVICES];
109
110 /* Rates at which responses are randomly allowed (in log2) when the
111 buckets don't have enough tokens. This is necessary in order to
112 prevent an attacker sending requests with spoofed source address
113 from blocking responses to the address completely. */
114
115 #define MIN_LEAK_RATE 1
116 #define MAX_LEAK_RATE 4
117
118 static int leak_rate[MAX_SERVICES];
119
120 /* Limit intervals in log2 */
121 static int limit_interval[MAX_SERVICES];
122
123 /* Flag indicating whether facility is turned on or not */
124 static int active;
125
126 /* RX and TX timestamp saved for clients using interleaved mode */
127 typedef struct {
128 uint64_t rx_ts;
129 uint16_t flags;
130 uint16_t slew_epoch;
131 int32_t tx_ts_offset;
132 } NtpTimestamps;
133
134 /* Flags for NTP timestamps */
135 #define NTPTS_DISABLED 1
136 #define NTPTS_VALID_TX 2
137
138 /* RX->TX map using a circular buffer with ordered timestamps */
139 typedef struct {
140 ARR_Instance timestamps;
141 uint32_t first;
142 uint32_t size;
143 uint32_t max_size;
144 uint32_t cached_index;
145 uint64_t cached_rx_ts;
146 uint16_t slew_epoch;
147 double slew_offset;
148 } NtpTimestampMap;
149
150 static NtpTimestampMap ntp_ts_map;
151
152 /* Maximum interval of NTP timestamps in future after a backward step */
153 #define NTPTS_FUTURE_LIMIT (1LL << 32) /* 1 second */
154
155 /* Maximum number of timestamps moved in the array to insert a new timestamp */
156 #define NTPTS_INSERT_LIMIT 64
157
158 /* Global statistics */
159 static uint32_t total_hits[MAX_SERVICES];
160 static uint32_t total_drops[MAX_SERVICES];
161 static uint32_t total_ntp_auth_hits;
162 static uint32_t total_ntp_interleaved_hits;
163 static uint32_t total_record_drops;
164
165 #define NSEC_PER_SEC 1000000000U
166
167 /* ================================================== */
168
169 static int expand_hashtable(void);
170 static void handle_slew(struct timespec *raw, struct timespec *cooked, double dfreq,
171 double doffset, LCL_ChangeType change_type, void *anything);
172
173 /* ================================================== */
174
175 static int
compare_ts(uint32_t x,uint32_t y)176 compare_ts(uint32_t x, uint32_t y)
177 {
178 if (x == y)
179 return 0;
180 if (y == INVALID_TS)
181 return 1;
182 return (int32_t)(x - y) > 0 ? 1 : -1;
183 }
184
185 /* ================================================== */
186
187 static int
compare_total_hits(Record * x,Record * y)188 compare_total_hits(Record *x, Record *y)
189 {
190 uint32_t x_hits, y_hits;
191 int i;
192
193 for (i = 0, x_hits = y_hits = 0; i < MAX_SERVICES; i++) {
194 x_hits += x->hits[i];
195 y_hits += y->hits[i];
196 }
197
198 return x_hits > y_hits ? 1 : -1;
199 }
200
201 /* ================================================== */
202
203 static Record *
get_record(IPAddr * ip)204 get_record(IPAddr *ip)
205 {
206 uint32_t last_hit = 0, oldest_hit = 0;
207 Record *record, *oldest_record;
208 unsigned int first, i, j;
209
210 if (!active || (ip->family != IPADDR_INET4 && ip->family != IPADDR_INET6))
211 return NULL;
212
213 while (1) {
214 /* Get index of the first record in the slot */
215 first = UTI_IPToHash(ip) % slots * SLOT_SIZE;
216
217 for (i = 0, oldest_record = NULL; i < SLOT_SIZE; i++) {
218 record = ARR_GetElement(records, first + i);
219
220 if (!UTI_CompareIPs(ip, &record->ip_addr, NULL))
221 return record;
222
223 if (record->ip_addr.family == IPADDR_UNSPEC)
224 break;
225
226 for (j = 0; j < MAX_SERVICES; j++) {
227 if (j == 0 || compare_ts(last_hit, record->last_hit[j]) < 0)
228 last_hit = record->last_hit[j];
229 }
230
231 if (!oldest_record || compare_ts(oldest_hit, last_hit) > 0 ||
232 (oldest_hit == last_hit && compare_total_hits(oldest_record, record) > 0)) {
233 oldest_record = record;
234 oldest_hit = last_hit;
235 }
236 }
237
238 /* If the slot still has an empty record, use it */
239 if (record->ip_addr.family == IPADDR_UNSPEC)
240 break;
241
242 /* Resize the table if possible and try again as the new slot may
243 have some empty records */
244 if (expand_hashtable())
245 continue;
246
247 /* There is no other option, replace the oldest record */
248 record = oldest_record;
249 total_record_drops++;
250 break;
251 }
252
253 record->ip_addr = *ip;
254 for (i = 0; i < MAX_SERVICES; i++)
255 record->last_hit[i] = INVALID_TS;
256 for (i = 0; i < MAX_SERVICES; i++)
257 record->hits[i] = 0;
258 for (i = 0; i < MAX_SERVICES; i++)
259 record->drops[i] = 0;
260 for (i = 0; i < MAX_SERVICES; i++)
261 record->tokens[i] = max_tokens[i];
262 for (i = 0; i < MAX_SERVICES; i++)
263 record->rate[i] = INVALID_RATE;
264 record->ntp_timeout_rate = INVALID_RATE;
265 record->drop_flags = 0;
266
267 return record;
268 }
269
270 /* ================================================== */
271
272 static int
expand_hashtable(void)273 expand_hashtable(void)
274 {
275 ARR_Instance old_records;
276 Record *old_record, *new_record;
277 unsigned int i;
278
279 old_records = records;
280
281 if (2 * slots > max_slots)
282 return 0;
283
284 records = ARR_CreateInstance(sizeof (Record));
285
286 slots = MAX(MIN_SLOTS, 2 * slots);
287 assert(slots <= max_slots);
288
289 ARR_SetSize(records, slots * SLOT_SIZE);
290
291 /* Mark all new records as empty */
292 for (i = 0; i < slots * SLOT_SIZE; i++) {
293 new_record = ARR_GetElement(records, i);
294 new_record->ip_addr.family = IPADDR_UNSPEC;
295 }
296
297 if (!old_records)
298 return 1;
299
300 /* Copy old records to the new hash table */
301 for (i = 0; i < ARR_GetSize(old_records); i++) {
302 old_record = ARR_GetElement(old_records, i);
303 if (old_record->ip_addr.family == IPADDR_UNSPEC)
304 continue;
305
306 new_record = get_record(&old_record->ip_addr);
307
308 assert(new_record);
309 *new_record = *old_record;
310 }
311
312 ARR_DestroyInstance(old_records);
313
314 return 1;
315 }
316
317 /* ================================================== */
318
319 static void
set_bucket_params(int interval,int burst,uint16_t * max_tokens,uint16_t * tokens_per_packet,int * token_shift)320 set_bucket_params(int interval, int burst, uint16_t *max_tokens,
321 uint16_t *tokens_per_packet, int *token_shift)
322 {
323 interval = CLAMP(MIN_LIMIT_INTERVAL, interval, MAX_LIMIT_INTERVAL);
324 burst = CLAMP(MIN_LIMIT_BURST, burst, MAX_LIMIT_BURST);
325
326 if (interval >= -TS_FRAC) {
327 /* Find the smallest shift with which the maximum number fits in 16 bits */
328 for (*token_shift = 0; *token_shift < interval + TS_FRAC; (*token_shift)++) {
329 if (burst << (TS_FRAC + interval - *token_shift) < 1U << 16)
330 break;
331 }
332 } else {
333 /* Coarse rate limiting */
334 *token_shift = interval + TS_FRAC;
335 *tokens_per_packet = 1;
336 burst = MAX(1U << -*token_shift, burst);
337 }
338
339 *tokens_per_packet = 1U << (TS_FRAC + interval - *token_shift);
340 *max_tokens = *tokens_per_packet * burst;
341
342 DEBUG_LOG("Tokens max %d packet %d shift %d",
343 *max_tokens, *tokens_per_packet, *token_shift);
344 }
345
346 /* ================================================== */
347
348 void
CLG_Initialise(void)349 CLG_Initialise(void)
350 {
351 int i, interval, burst, lrate, slots2;
352
353 for (i = 0; i < MAX_SERVICES; i++) {
354 max_tokens[i] = 0;
355 tokens_per_hit[i] = 0;
356 token_shift[i] = 0;
357 leak_rate[i] = 0;
358 limit_interval[i] = MIN_LIMIT_INTERVAL;
359
360 switch (i) {
361 case CLG_NTP:
362 if (!CNF_GetNTPRateLimit(&interval, &burst, &lrate))
363 continue;
364 break;
365 case CLG_NTSKE:
366 if (!CNF_GetNtsRateLimit(&interval, &burst, &lrate))
367 continue;
368 break;
369 case CLG_CMDMON:
370 if (!CNF_GetCommandRateLimit(&interval, &burst, &lrate))
371 continue;
372 break;
373 default:
374 assert(0);
375 }
376
377 set_bucket_params(interval, burst, &max_tokens[i], &tokens_per_hit[i], &token_shift[i]);
378 leak_rate[i] = CLAMP(MIN_LEAK_RATE, lrate, MAX_LEAK_RATE);
379 limit_interval[i] = CLAMP(MIN_LIMIT_INTERVAL, interval, MAX_LIMIT_INTERVAL);
380 }
381
382 active = !CNF_GetNoClientLog();
383 if (!active) {
384 for (i = 0; i < MAX_SERVICES; i++) {
385 if (leak_rate[i] != 0)
386 LOG_FATAL("Rate limiting cannot be enabled with noclientlog");
387 }
388 return;
389 }
390
391 /* Calculate the maximum number of slots that can be allocated in the
392 configured memory limit. Take into account expanding of the hash
393 table where two copies exist at the same time. */
394 max_slots = CNF_GetClientLogLimit() /
395 ((sizeof (Record) + sizeof (NtpTimestamps)) * SLOT_SIZE * 3 / 2);
396 max_slots = CLAMP(MIN_SLOTS, max_slots, MAX_SLOTS);
397 for (slots2 = 0; 1U << (slots2 + 1) <= max_slots; slots2++)
398 ;
399
400 DEBUG_LOG("Max records %u", 1U << (slots2 + SLOT_BITS));
401
402 slots = 0;
403 records = NULL;
404
405 expand_hashtable();
406
407 UTI_GetRandomBytes(&ts_offset, sizeof (ts_offset));
408 ts_offset %= NSEC_PER_SEC / (1U << TS_FRAC);
409
410 ntp_ts_map.timestamps = NULL;
411 ntp_ts_map.first = 0;
412 ntp_ts_map.size = 0;
413 ntp_ts_map.max_size = 1U << (slots2 + SLOT_BITS);
414 ntp_ts_map.cached_index = 0;
415 ntp_ts_map.cached_rx_ts = 0ULL;
416 ntp_ts_map.slew_epoch = 0;
417 ntp_ts_map.slew_offset = 0.0;
418
419 LCL_AddParameterChangeHandler(handle_slew, NULL);
420 }
421
422 /* ================================================== */
423
424 void
CLG_Finalise(void)425 CLG_Finalise(void)
426 {
427 if (!active)
428 return;
429
430 ARR_DestroyInstance(records);
431 if (ntp_ts_map.timestamps)
432 ARR_DestroyInstance(ntp_ts_map.timestamps);
433
434 LCL_RemoveParameterChangeHandler(handle_slew, NULL);
435 }
436
437 /* ================================================== */
438
439 static uint32_t
get_ts_from_timespec(struct timespec * ts)440 get_ts_from_timespec(struct timespec *ts)
441 {
442 uint32_t sec = ts->tv_sec, nsec = ts->tv_nsec;
443
444 nsec += ts_offset;
445 if (nsec >= NSEC_PER_SEC) {
446 nsec -= NSEC_PER_SEC;
447 sec++;
448 }
449
450 /* This is fast and accurate enough */
451 return sec << TS_FRAC | (140740U * (nsec >> 15)) >> (32 - TS_FRAC);
452 }
453
454 /* ================================================== */
455
456 static void
update_record(CLG_Service service,Record * record,struct timespec * now)457 update_record(CLG_Service service, Record *record, struct timespec *now)
458 {
459 uint32_t interval, now_ts, prev_hit, tokens;
460 int interval2, tshift, mtokens;
461 int8_t *rate;
462
463 now_ts = get_ts_from_timespec(now);
464
465 prev_hit = record->last_hit[service];
466 record->last_hit[service] = now_ts;
467 record->hits[service]++;
468
469 interval = now_ts - prev_hit;
470
471 if (prev_hit == INVALID_TS || (int32_t)interval < 0)
472 return;
473
474 tshift = token_shift[service];
475 mtokens = max_tokens[service];
476
477 if (tshift >= 0)
478 tokens = (now_ts >> tshift) - (prev_hit >> tshift);
479 else if (now_ts - prev_hit > mtokens)
480 tokens = mtokens;
481 else
482 tokens = (now_ts - prev_hit) << -tshift;
483 record->tokens[service] = MIN(record->tokens[service] + tokens, mtokens);
484
485 /* Convert the interval to scaled and rounded log2 */
486 if (interval) {
487 interval += interval >> 1;
488 for (interval2 = -RATE_SCALE * TS_FRAC; interval2 < -MIN_RATE;
489 interval2 += RATE_SCALE) {
490 if (interval <= 1)
491 break;
492 interval >>= 1;
493 }
494 } else {
495 interval2 = -RATE_SCALE * (TS_FRAC + 1);
496 }
497
498 /* For the NTP service, update one of the two rates depending on whether
499 the previous request of the client had a reply or it timed out */
500 rate = service == CLG_NTP && record->drop_flags & (1U << service) ?
501 &record->ntp_timeout_rate : &record->rate[service];
502
503 /* Update the rate in a rough approximation of exponential moving average */
504 if (*rate == INVALID_RATE) {
505 *rate = -interval2;
506 } else {
507 if (*rate < -interval2) {
508 (*rate)++;
509 } else if (*rate > -interval2) {
510 if (*rate > RATE_SCALE * 5 / 2 - interval2)
511 *rate = RATE_SCALE * 5 / 2 - interval2;
512 else
513 *rate = (*rate - interval2 - 1) / 2;
514 }
515 }
516 }
517
518 /* ================================================== */
519
520 static int
get_index(Record * record)521 get_index(Record *record)
522 {
523 return record - (Record *)ARR_GetElements(records);
524 }
525
526 /* ================================================== */
527
528 int
CLG_GetClientIndex(IPAddr * client)529 CLG_GetClientIndex(IPAddr *client)
530 {
531 Record *record;
532
533 record = get_record(client);
534 if (record == NULL)
535 return -1;
536
537 return get_index(record);
538 }
539
540 /* ================================================== */
541
542 static void
check_service_number(CLG_Service service)543 check_service_number(CLG_Service service)
544 {
545 assert(service >= 0 && service <= MAX_SERVICES);
546 }
547
548 /* ================================================== */
549
550 int
CLG_LogServiceAccess(CLG_Service service,IPAddr * client,struct timespec * now)551 CLG_LogServiceAccess(CLG_Service service, IPAddr *client, struct timespec *now)
552 {
553 Record *record;
554
555 check_service_number(service);
556
557 total_hits[service]++;
558
559 record = get_record(client);
560 if (record == NULL)
561 return -1;
562
563 update_record(service, record, now);
564
565 DEBUG_LOG("service %d hits %"PRIu32" rate %d trate %d tokens %d",
566 (int)service, record->hits[service], record->rate[service],
567 service == CLG_NTP ? record->ntp_timeout_rate : INVALID_RATE,
568 record->tokens[service]);
569
570 return get_index(record);
571 }
572
573 /* ================================================== */
574
575 static int
limit_response_random(int leak_rate)576 limit_response_random(int leak_rate)
577 {
578 static uint32_t rnd;
579 static int bits_left = 0;
580 int r;
581
582 if (bits_left < leak_rate) {
583 UTI_GetRandomBytes(&rnd, sizeof (rnd));
584 bits_left = 8 * sizeof (rnd);
585 }
586
587 /* Return zero on average once per 2^leak_rate */
588 r = rnd % (1U << leak_rate) ? 1 : 0;
589 rnd >>= leak_rate;
590 bits_left -= leak_rate;
591
592 return r;
593 }
594
595 /* ================================================== */
596
597 int
CLG_LimitServiceRate(CLG_Service service,int index)598 CLG_LimitServiceRate(CLG_Service service, int index)
599 {
600 Record *record;
601 int drop;
602
603 check_service_number(service);
604
605 if (tokens_per_hit[service] == 0)
606 return 0;
607
608 record = ARR_GetElement(records, index);
609 record->drop_flags &= ~(1U << service);
610
611 if (record->tokens[service] >= tokens_per_hit[service]) {
612 record->tokens[service] -= tokens_per_hit[service];
613 return 0;
614 }
615
616 drop = limit_response_random(leak_rate[service]);
617
618 /* Poorly implemented NTP clients can send requests at a higher rate
619 when they are not getting replies. If the request rate seems to be more
620 than twice as much as when replies are sent, give up on rate limiting to
621 reduce the amount of traffic. Invert the sense of the leak to respond to
622 most of the requests, but still keep the estimated rate updated. */
623 if (service == CLG_NTP && record->ntp_timeout_rate != INVALID_RATE &&
624 record->ntp_timeout_rate > record->rate[service] + RATE_SCALE)
625 drop = !drop;
626
627 if (!drop) {
628 record->tokens[service] = 0;
629 return 0;
630 }
631
632 record->drop_flags |= 1U << service;
633 record->drops[service]++;
634 total_drops[service]++;
635
636 return 1;
637 }
638
639 /* ================================================== */
640
641 void
CLG_LogAuthNtpRequest(void)642 CLG_LogAuthNtpRequest(void)
643 {
644 total_ntp_auth_hits++;
645 }
646
647 /* ================================================== */
648
649 int
CLG_GetNtpMinPoll(void)650 CLG_GetNtpMinPoll(void)
651 {
652 return limit_interval[CLG_NTP];
653 }
654
655 /* ================================================== */
656
657 static NtpTimestamps *
get_ntp_tss(uint32_t index)658 get_ntp_tss(uint32_t index)
659 {
660 return ARR_GetElement(ntp_ts_map.timestamps,
661 (ntp_ts_map.first + index) & (ntp_ts_map.max_size - 1));
662 }
663
664 /* ================================================== */
665
666 static int
find_ntp_rx_ts(uint64_t rx_ts,uint32_t * index)667 find_ntp_rx_ts(uint64_t rx_ts, uint32_t *index)
668 {
669 uint64_t rx_x, rx_lo, rx_hi, step;
670 uint32_t i, x, lo, hi;
671
672 if (ntp_ts_map.cached_rx_ts == rx_ts && rx_ts != 0ULL) {
673 *index = ntp_ts_map.cached_index;
674 return 1;
675 }
676
677 if (ntp_ts_map.size == 0) {
678 *index = 0;
679 return 0;
680 }
681
682 lo = 0;
683 hi = ntp_ts_map.size - 1;
684 rx_lo = get_ntp_tss(lo)->rx_ts;
685 rx_hi = get_ntp_tss(hi)->rx_ts;
686
687 /* Check for ts < lo before ts > hi to trim timestamps from "future" later
688 if both conditions are true to not break the order of the endpoints.
689 Compare timestamps by their difference to allow adjacent NTP eras. */
690 if ((int64_t)(rx_ts - rx_lo) < 0) {
691 *index = 0;
692 return 0;
693 } else if ((int64_t)(rx_ts - rx_hi) > 0) {
694 *index = ntp_ts_map.size;
695 return 0;
696 }
697
698 /* Perform a combined linear interpolation and binary search */
699
700 for (i = 0; ; i++) {
701 if (rx_ts == rx_hi) {
702 *index = ntp_ts_map.cached_index = hi;
703 ntp_ts_map.cached_rx_ts = rx_ts;
704 return 1;
705 } else if (rx_ts == rx_lo) {
706 *index = ntp_ts_map.cached_index = lo;
707 ntp_ts_map.cached_rx_ts = rx_ts;
708 return 1;
709 } else if (lo + 1 == hi) {
710 *index = hi;
711 return 0;
712 }
713
714 if (hi - lo > 3 && i % 2 == 0) {
715 step = (rx_hi - rx_lo) / (hi - lo);
716 if (step == 0)
717 step = 1;
718 x = lo + (rx_ts - rx_lo) / step;
719 } else {
720 x = lo + (hi - lo) / 2;
721 }
722
723 if (x <= lo)
724 x = lo + 1;
725 else if (x >= hi)
726 x = hi - 1;
727
728 rx_x = get_ntp_tss(x)->rx_ts;
729
730 if ((int64_t)(rx_x - rx_ts) <= 0) {
731 lo = x;
732 rx_lo = rx_x;
733 } else {
734 hi = x;
735 rx_hi = rx_x;
736 }
737 }
738 }
739
740 /* ================================================== */
741
742 static uint64_t
ntp64_to_int64(NTP_int64 * ts)743 ntp64_to_int64(NTP_int64 *ts)
744 {
745 return (uint64_t)ntohl(ts->hi) << 32 | ntohl(ts->lo);
746 }
747
748 /* ================================================== */
749
750 static void
int64_to_ntp64(uint64_t ts,NTP_int64 * ntp_ts)751 int64_to_ntp64(uint64_t ts, NTP_int64 *ntp_ts)
752 {
753 ntp_ts->hi = htonl(ts >> 32);
754 ntp_ts->lo = htonl(ts);
755 }
756
757 /* ================================================== */
758
759 static uint32_t
push_ntp_tss(uint32_t index)760 push_ntp_tss(uint32_t index)
761 {
762 if (ntp_ts_map.size < ntp_ts_map.max_size) {
763 ntp_ts_map.size++;
764 } else {
765 ntp_ts_map.first = (ntp_ts_map.first + 1) % (ntp_ts_map.max_size);
766 if (index > 0)
767 index--;
768 }
769
770 return index;
771 }
772
773 /* ================================================== */
774
775 static void
set_ntp_tx_offset(NtpTimestamps * tss,NTP_int64 * rx_ts,struct timespec * tx_ts)776 set_ntp_tx_offset(NtpTimestamps *tss, NTP_int64 *rx_ts, struct timespec *tx_ts)
777 {
778 struct timespec ts;
779
780 if (!tx_ts) {
781 tss->flags &= ~NTPTS_VALID_TX;
782 return;
783 }
784
785 UTI_Ntp64ToTimespec(rx_ts, &ts);
786 UTI_DiffTimespecs(&ts, tx_ts, &ts);
787
788 if (ts.tv_sec < -2 || ts.tv_sec > 1) {
789 tss->flags &= ~NTPTS_VALID_TX;
790 return;
791 }
792
793 tss->tx_ts_offset = (int32_t)ts.tv_nsec + (int32_t)ts.tv_sec * (int32_t)NSEC_PER_SEC;
794 tss->flags |= NTPTS_VALID_TX;
795 }
796
797 /* ================================================== */
798
799 static void
get_ntp_tx(NtpTimestamps * tss,struct timespec * tx_ts)800 get_ntp_tx(NtpTimestamps *tss, struct timespec *tx_ts)
801 {
802 int32_t offset = tss->tx_ts_offset;
803 NTP_int64 ntp_ts;
804
805 if (tss->flags & NTPTS_VALID_TX) {
806 int64_to_ntp64(tss->rx_ts, &ntp_ts);
807 UTI_Ntp64ToTimespec(&ntp_ts, tx_ts);
808 if (offset >= (int32_t)NSEC_PER_SEC) {
809 offset -= NSEC_PER_SEC;
810 tx_ts->tv_sec++;
811 }
812 tx_ts->tv_nsec += offset;
813 UTI_NormaliseTimespec(tx_ts);
814 } else {
815 UTI_ZeroTimespec(tx_ts);
816 }
817 }
818
819 /* ================================================== */
820
821 void
CLG_SaveNtpTimestamps(NTP_int64 * rx_ts,struct timespec * tx_ts)822 CLG_SaveNtpTimestamps(NTP_int64 *rx_ts, struct timespec *tx_ts)
823 {
824 NtpTimestamps *tss;
825 uint32_t i, index;
826 uint64_t rx;
827
828 if (!active)
829 return;
830
831 /* Allocate the array on first use */
832 if (!ntp_ts_map.timestamps) {
833 ntp_ts_map.timestamps = ARR_CreateInstance(sizeof (NtpTimestamps));
834 ARR_SetSize(ntp_ts_map.timestamps, ntp_ts_map.max_size);
835 }
836
837 rx = ntp64_to_int64(rx_ts);
838
839 if (rx == 0ULL)
840 return;
841
842 /* Disable the RX timestamp if it already exists to avoid responding
843 with a wrong TX timestamp */
844 if (find_ntp_rx_ts(rx, &index)) {
845 get_ntp_tss(index)->flags |= NTPTS_DISABLED;
846 return;
847 }
848
849 assert(index <= ntp_ts_map.size);
850
851 if (index == ntp_ts_map.size) {
852 /* Increase the size or drop the oldest timestamp to make room for
853 the new timestamp */
854 index = push_ntp_tss(index);
855 } else {
856 /* Trim timestamps in distant future after backward step */
857 while (index < ntp_ts_map.size &&
858 get_ntp_tss(ntp_ts_map.size - 1)->rx_ts - rx > NTPTS_FUTURE_LIMIT)
859 ntp_ts_map.size--;
860
861 /* Insert the timestamp if it is close to the latest timestamp.
862 Otherwise, replace the closest older or the oldest timestamp. */
863 if (index + NTPTS_INSERT_LIMIT >= ntp_ts_map.size) {
864 index = push_ntp_tss(index);
865 for (i = ntp_ts_map.size - 1; i > index; i--)
866 *get_ntp_tss(i) = *get_ntp_tss(i - 1);
867 } else {
868 if (index > 0)
869 index--;
870 }
871 }
872
873 ntp_ts_map.cached_index = index;
874 ntp_ts_map.cached_rx_ts = rx;
875
876 tss = get_ntp_tss(index);
877 tss->rx_ts = rx;
878 tss->flags = 0;
879 tss->slew_epoch = ntp_ts_map.slew_epoch;
880 set_ntp_tx_offset(tss, rx_ts, tx_ts);
881
882 DEBUG_LOG("Saved RX+TX index=%"PRIu32" first=%"PRIu32" size=%"PRIu32,
883 index, ntp_ts_map.first, ntp_ts_map.size);
884 }
885
886 /* ================================================== */
887
888 static void
handle_slew(struct timespec * raw,struct timespec * cooked,double dfreq,double doffset,LCL_ChangeType change_type,void * anything)889 handle_slew(struct timespec *raw, struct timespec *cooked, double dfreq,
890 double doffset, LCL_ChangeType change_type, void *anything)
891 {
892 /* Drop all timestamps on unknown step */
893 if (change_type == LCL_ChangeUnknownStep) {
894 ntp_ts_map.size = 0;
895 ntp_ts_map.cached_rx_ts = 0ULL;
896 }
897
898 ntp_ts_map.slew_epoch++;
899 ntp_ts_map.slew_offset = doffset;
900 }
901
902 /* ================================================== */
903
904 void
CLG_UndoNtpTxTimestampSlew(NTP_int64 * rx_ts,struct timespec * tx_ts)905 CLG_UndoNtpTxTimestampSlew(NTP_int64 *rx_ts, struct timespec *tx_ts)
906 {
907 uint32_t index;
908
909 if (!ntp_ts_map.timestamps)
910 return;
911
912 if (!find_ntp_rx_ts(ntp64_to_int64(rx_ts), &index))
913 return;
914
915 /* If the RX timestamp was captured before the last correction of the clock,
916 remove the adjustment from the TX timestamp */
917 if ((uint16_t)(get_ntp_tss(index)->slew_epoch + 1U) == ntp_ts_map.slew_epoch)
918 UTI_AddDoubleToTimespec(tx_ts, ntp_ts_map.slew_offset, tx_ts);
919 }
920
921 /* ================================================== */
922
923 void
CLG_UpdateNtpTxTimestamp(NTP_int64 * rx_ts,struct timespec * tx_ts)924 CLG_UpdateNtpTxTimestamp(NTP_int64 *rx_ts, struct timespec *tx_ts)
925 {
926 uint32_t index;
927
928 if (!ntp_ts_map.timestamps)
929 return;
930
931 if (!find_ntp_rx_ts(ntp64_to_int64(rx_ts), &index))
932 return;
933
934 set_ntp_tx_offset(get_ntp_tss(index), rx_ts, tx_ts);
935 }
936
937 /* ================================================== */
938
939 int
CLG_GetNtpTxTimestamp(NTP_int64 * rx_ts,struct timespec * tx_ts)940 CLG_GetNtpTxTimestamp(NTP_int64 *rx_ts, struct timespec *tx_ts)
941 {
942 NtpTimestamps *tss;
943 uint32_t index;
944
945 if (!ntp_ts_map.timestamps)
946 return 0;
947
948 if (!find_ntp_rx_ts(ntp64_to_int64(rx_ts), &index))
949 return 0;
950
951 tss = get_ntp_tss(index);
952
953 if (tss->flags & NTPTS_DISABLED)
954 return 0;
955
956 get_ntp_tx(tss, tx_ts);
957
958 return 1;
959 }
960
961 /* ================================================== */
962
963 void
CLG_DisableNtpTimestamps(NTP_int64 * rx_ts)964 CLG_DisableNtpTimestamps(NTP_int64 *rx_ts)
965 {
966 uint32_t index;
967
968 if (!ntp_ts_map.timestamps)
969 return;
970
971 if (find_ntp_rx_ts(ntp64_to_int64(rx_ts), &index))
972 get_ntp_tss(index)->flags |= NTPTS_DISABLED;
973
974 /* This assumes the function is called only to prevent multiple
975 interleaved responses to the same timestamp */
976 total_ntp_interleaved_hits++;
977 }
978
979 /* ================================================== */
980
981 int
CLG_GetNumberOfIndices(void)982 CLG_GetNumberOfIndices(void)
983 {
984 if (!active)
985 return -1;
986
987 return ARR_GetSize(records);
988 }
989
990 /* ================================================== */
991
get_interval(int rate)992 static int get_interval(int rate)
993 {
994 if (rate == INVALID_RATE)
995 return 127;
996
997 rate += rate > 0 ? RATE_SCALE / 2 : -RATE_SCALE / 2;
998
999 return rate / -RATE_SCALE;
1000 }
1001
1002 /* ================================================== */
1003
get_last_ago(uint32_t x,uint32_t y)1004 static uint32_t get_last_ago(uint32_t x, uint32_t y)
1005 {
1006 if (y == INVALID_TS || (int32_t)(x - y) < 0)
1007 return -1;
1008
1009 return (x - y) >> TS_FRAC;
1010 }
1011
1012 /* ================================================== */
1013
1014 int
CLG_GetClientAccessReportByIndex(int index,int reset,uint32_t min_hits,RPT_ClientAccessByIndex_Report * report,struct timespec * now)1015 CLG_GetClientAccessReportByIndex(int index, int reset, uint32_t min_hits,
1016 RPT_ClientAccessByIndex_Report *report, struct timespec *now)
1017 {
1018 Record *record;
1019 uint32_t now_ts;
1020 int i, r;
1021
1022 if (!active || index < 0 || index >= ARR_GetSize(records))
1023 return 0;
1024
1025 record = ARR_GetElement(records, index);
1026
1027 if (record->ip_addr.family == IPADDR_UNSPEC)
1028 return 0;
1029
1030 if (min_hits == 0) {
1031 r = 1;
1032 } else {
1033 for (i = r = 0; i < MAX_SERVICES; i++) {
1034 if (record->hits[i] >= min_hits) {
1035 r = 1;
1036 break;
1037 }
1038 }
1039 }
1040
1041 if (r) {
1042 now_ts = get_ts_from_timespec(now);
1043
1044 report->ip_addr = record->ip_addr;
1045 report->ntp_hits = record->hits[CLG_NTP];
1046 report->nke_hits = record->hits[CLG_NTSKE];
1047 report->cmd_hits = record->hits[CLG_CMDMON];
1048 report->ntp_drops = record->drops[CLG_NTP];
1049 report->nke_drops = record->drops[CLG_NTSKE];
1050 report->cmd_drops = record->drops[CLG_CMDMON];
1051 report->ntp_interval = get_interval(record->rate[CLG_NTP]);
1052 report->nke_interval = get_interval(record->rate[CLG_NTSKE]);
1053 report->cmd_interval = get_interval(record->rate[CLG_CMDMON]);
1054 report->ntp_timeout_interval = get_interval(record->ntp_timeout_rate);
1055 report->last_ntp_hit_ago = get_last_ago(now_ts, record->last_hit[CLG_NTP]);
1056 report->last_nke_hit_ago = get_last_ago(now_ts, record->last_hit[CLG_NTSKE]);
1057 report->last_cmd_hit_ago = get_last_ago(now_ts, record->last_hit[CLG_CMDMON]);
1058 }
1059
1060 if (reset) {
1061 for (i = 0; i < MAX_SERVICES; i++) {
1062 record->hits[i] = 0;
1063 record->drops[i] = 0;
1064 }
1065 }
1066
1067 return r;
1068 }
1069
1070 /* ================================================== */
1071
1072 void
CLG_GetServerStatsReport(RPT_ServerStatsReport * report)1073 CLG_GetServerStatsReport(RPT_ServerStatsReport *report)
1074 {
1075 report->ntp_hits = total_hits[CLG_NTP];
1076 report->nke_hits = total_hits[CLG_NTSKE];
1077 report->cmd_hits = total_hits[CLG_CMDMON];
1078 report->ntp_drops = total_drops[CLG_NTP];
1079 report->nke_drops = total_drops[CLG_NTSKE];
1080 report->cmd_drops = total_drops[CLG_CMDMON];
1081 report->log_drops = total_record_drops;
1082 report->ntp_auth_hits = total_ntp_auth_hits;
1083 report->ntp_interleaved_hits = total_ntp_interleaved_hits;
1084 report->ntp_timestamps = ntp_ts_map.size;
1085 report->ntp_span_seconds = ntp_ts_map.size > 1 ?
1086 (get_ntp_tss(ntp_ts_map.size - 1)->rx_ts -
1087 get_ntp_tss(0)->rx_ts) >> 32 : 0;
1088 }
1089