diff --git a/acquire.c b/acquire.c index 250dca2..6b479f8 100644 --- a/acquire.c +++ b/acquire.c @@ -256,6 +256,7 @@ probe_source(SourceRecord *src) union sockaddr_in46 his_addr; int sock_fd; socklen_t addrlen; + uint32_t ts_fuzz; #if 0 printf("Sending probe to %s sent=%d samples=%d\n", UTI_IPToString(&src->ip_addr), src->n_probes_sent, src->n_samples); @@ -304,8 +305,9 @@ probe_source(SourceRecord *src) } + ts_fuzz = UTI_GetNTPTsFuzz(LCL_GetSysPrecisionAsLog()); LCL_ReadCookedTime(&cooked, NULL); - UTI_TimevalToInt64(&cooked, &pkt.transmit_ts); + UTI_TimevalToInt64(&cooked, &pkt.transmit_ts, ts_fuzz); if (sendto(sock_fd, (void *) &pkt, NTP_NORMAL_PACKET_SIZE, 0, diff --git a/broadcast.c b/broadcast.c index 4004195..8a8e327 100644 --- a/broadcast.c +++ b/broadcast.c @@ -73,7 +73,7 @@ timeout_handler(void *arbitrary) int leap; int are_we_synchronised, our_stratum; NTP_Leap leap_status; - uint32_t our_ref_id; + uint32_t our_ref_id, ts_fuzz; struct timeval our_ref_time; double our_root_delay, our_root_dispersion; struct timeval local_transmit; @@ -107,14 +107,15 @@ timeout_handler(void *arbitrary) message.reference_id = htonl((NTP_int32) our_ref_id); /* Now fill in timestamps */ - UTI_TimevalToInt64(&our_ref_time, &message.reference_ts); + UTI_TimevalToInt64(&our_ref_time, &message.reference_ts, 0); message.originate_ts.hi = 0UL; message.originate_ts.lo = 0UL; message.receive_ts.hi = 0UL; message.receive_ts.lo = 0UL; + ts_fuzz = UTI_GetNTPTsFuzz(message.precision); LCL_ReadCookedTime(&local_transmit, NULL); - UTI_TimevalToInt64(&local_transmit, &message.transmit_ts); + UTI_TimevalToInt64(&local_transmit, &message.transmit_ts, ts_fuzz); NIO_SendNormalPacket(&message, &d->addr); /* Requeue timeout. Don't care if interval drifts gradually, so just do it diff --git a/ntp_core.c b/ntp_core.c index 3827ddd..0fb93e1 100644 --- a/ntp_core.c +++ b/ntp_core.c @@ -419,7 +419,7 @@ transmit_packet(NTP_Mode my_mode, /* The mode this machine wants to be */ /* Parameters read from reference module */ int are_we_synchronised, our_stratum; NTP_Leap leap_status; - uint32_t our_ref_id; + uint32_t our_ref_id, ts_fuzz; struct timeval our_ref_time; double our_root_delay, our_root_dispersion; @@ -458,7 +458,7 @@ transmit_packet(NTP_Mode my_mode, /* The mode this machine wants to be */ message.reference_id = htonl((NTP_int32) our_ref_id); /* Now fill in timestamps */ - UTI_TimevalToInt64(&our_ref_time, &message.reference_ts); + UTI_TimevalToInt64(&our_ref_time, &message.reference_ts, 0); /* Originate - this comes from the last packet the source sent us */ message.originate_ts = *orig_ts; @@ -467,7 +467,10 @@ transmit_packet(NTP_Mode my_mode, /* The mode this machine wants to be */ This timestamp will have been adjusted so that it will now look to the source like we have been running on our latest estimate of frequency all along */ - UTI_TimevalToInt64(local_rx, &message.receive_ts); + UTI_TimevalToInt64(local_rx, &message.receive_ts, 0); + + /* Prepare random bits which will be added to the transmit timestamp. */ + ts_fuzz = UTI_GetNTPTsFuzz(message.precision); /* Transmit - this our local time right now! Also, we might need to store this for our own use later, next time we receive a message @@ -481,7 +484,7 @@ transmit_packet(NTP_Mode my_mode, /* The mode this machine wants to be */ take to generate the authentication data. */ local_transmit.tv_usec += KEY_GetAuthDelay(key_id); UTI_NormaliseTimeval(&local_transmit); - UTI_TimevalToInt64(&local_transmit, &message.transmit_ts); + UTI_TimevalToInt64(&local_transmit, &message.transmit_ts, ts_fuzz); auth_len = KEY_GenerateAuth(key_id, (unsigned char *) &message, offsetof(NTP_Packet, auth_keyid), @@ -492,7 +495,7 @@ transmit_packet(NTP_Mode my_mode, /* The mode this machine wants to be */ sizeof (message.auth_keyid) + auth_len); } } else { - UTI_TimevalToInt64(&local_transmit, &message.transmit_ts); + UTI_TimevalToInt64(&local_transmit, &message.transmit_ts, ts_fuzz); NIO_SendNormalPacket(&message, where_to); } diff --git a/sched.c b/sched.c index ae17783..4dea13d 100644 --- a/sched.c +++ b/sched.c @@ -147,7 +147,7 @@ SCH_Initialise(void) LCL_AddParameterChangeHandler(handle_slew, NULL); LCL_ReadRawTime(&tv); - srandom(tv.tv_sec * tv.tv_usec); + srandom(tv.tv_sec << 16 ^ tv.tv_usec); initialised = 1; diff --git a/util.c b/util.c index 689e4da..2c4a98d 100644 --- a/util.c +++ b/util.c @@ -459,16 +459,31 @@ UTI_AdjustTimeval(struct timeval *old_tv, struct timeval *when, struct timeval * /* ================================================== */ +uint32_t +UTI_GetNTPTsFuzz(int precision) +{ + uint32_t fuzz; + int fuzz_bits; + + fuzz_bits = 32 - 1 + precision; + fuzz = random() % (1 << fuzz_bits); + + return fuzz; +} + +/* ================================================== */ + /* Seconds part of RFC1305 timestamp correponding to the origin of the struct timeval format. */ #define JAN_1970 0x83aa7e80UL void UTI_TimevalToInt64(struct timeval *src, - NTP_int64 *dest) + NTP_int64 *dest, uint32_t fuzz) { unsigned long usec = src->tv_usec; unsigned long sec = src->tv_sec; + uint32_t lo; /* Recognize zero as a special case - it always signifies an 'unknown' value */ @@ -478,7 +493,12 @@ UTI_TimevalToInt64(struct timeval *src, dest->hi = htonl(src->tv_sec + JAN_1970); /* This formula gives an error of about 0.1us worst case */ - dest->lo = htonl(4295 * usec - (usec>>5) - (usec>>9)); + lo = 4295 * usec - (usec>>5) - (usec>>9); + + /* Add the fuzz */ + lo ^= fuzz; + + dest->lo = htonl(lo); } } diff --git a/util.h b/util.h index e2014b8..3f94f77 100644 --- a/util.h +++ b/util.h @@ -88,8 +88,10 @@ extern char *UTI_TimeToLogForm(time_t t); /* Adjust time following a frequency/offset change */ extern void UTI_AdjustTimeval(struct timeval *old_tv, struct timeval *when, struct timeval *new_tv, double *delta, double dfreq, double doffset); +/* Get a random value to fuzz an NTP timestamp in the given precision */ +extern uint32_t UTI_GetNTPTsFuzz(int precision); -extern void UTI_TimevalToInt64(struct timeval *src, NTP_int64 *dest); +extern void UTI_TimevalToInt64(struct timeval *src, NTP_int64 *dest, uint32_t fuzz); extern void UTI_Int64ToTimeval(NTP_int64 *src, struct timeval *dest);