[chrony-dev] NTP "extended information" draft WIP implementation |
[ Thread Index |
Date Index
| More chrony.tuxfamily.org/chrony-dev Archives
]
Hi,
Attached is a patch sequence for implementing Harlan Stenn's draft
"Extended Information" NTPv4 extension as a mechanism to distribute TAI
offsets between nodes. This should be considered beta quality at best
- it hasn't been thoroughly debugged, and there is undoubtedly
significant room for improvement.
The patch stream can be broken in to basically three parts:
The first part (1-5) adds storage and propagation of TAI offset to the
reference, source, and client layers.
The second part (6-8) extends the NTP packet processing to support
generation and interpretation of NTPv4 extensions.
The third part (9-10) actually implements the extended information
generation and interpretation, gated behind a configure option.
Design notes:
-> It iterates over the extensions twice -- once to look for the MAC, if
present, and then again later to actually process the extensions.
There's probably a way to do this with a single pass, but some
extensions may require a valid MAC before they can be used, so I took
the easy but inefficient approach as a starting point.
-> process_packet_extensions() currently returns the one thing it
actually extracts so far (TAI) via a function argument. Probably a more
extensible system ought to be considered if there are more extensions
forthcoming.
-> It might've been better to add a runtime configuration file option
instead of a compile time decision to enable the draft extension support.
-> I didn't spend a lot of time considering which outbound packets ought
to have the extension added - the decision there is very likely wrong
for the general case.
If any of this work is helpful, please feel free to make use of it!
Any comments, suggestions, or criticisms would be greatly appreciated.
Thanks,
-Will
From 8434875a87921bc9b1a5654ddf59ff5e5d57fc76 Mon Sep 17 00:00:00 2001
From: Will Miles <wmiles@xxxxxxx>
Date: Fri, 22 Sep 2017 14:11:29 -0400
Subject: [PATCH 01/10] reference: Add REF_GetTaiOffset to retrieve current TAI
offset
---
reference.c | 8 ++++++++
reference.h | 3 +++
2 files changed, 11 insertions(+)
diff --git a/reference.c b/reference.c
index 8138b8c..9f38908 100644
--- a/reference.c
+++ b/reference.c
@@ -327,6 +327,14 @@ REF_GetLeapMode(void)
/* ================================================== */
+int
+REF_GetTaiOffset(void)
+{
+ return our_tai_offset;
+}
+
+/* ================================================== */
+
static double
Sqr(double x)
{
diff --git a/reference.h b/reference.h
index e376770..d38cc40 100644
--- a/reference.h
+++ b/reference.h
@@ -72,6 +72,9 @@ extern void REF_SetModeEndHandler(REF_ModeEndHandler handler);
/* Get leap second handling mode */
extern REF_LeapMode REF_GetLeapMode(void);
+/* Get current TAI offset */
+extern int REF_GetTaiOffset(void);
+
/* Function which takes a local cooked time and returns the estimated
time of the reference. It also returns the other parameters
required for forming the outgoing NTP packet.
--
2.13.0
From 937f76a538d3d23163a824f89d9d2cff36100c81 Mon Sep 17 00:00:00 2001
From: Will Miles <wmiles@xxxxxxx>
Date: Wed, 20 Sep 2017 14:48:37 -0400
Subject: [PATCH 02/10] source: Create a placeholder for per-source TAI offset
---
ntp_core.c | 2 +-
refclock.c | 2 +-
sources.c | 5 ++++-
sources.h | 2 +-
test/unit/sources.c | 2 +-
5 files changed, 8 insertions(+), 5 deletions(-)
diff --git a/ntp_core.c b/ntp_core.c
index d73111f..131c61f 100644
--- a/ntp_core.c
+++ b/ntp_core.c
@@ -1719,7 +1719,7 @@ receive_packet(NCR_Instance inst, NTP_Local_Address *local_addr,
offset, delay, dispersion,
root_delay, root_dispersion,
MAX(message->stratum, inst->min_stratum),
- (NTP_Leap) pkt_leap);
+ (NTP_Leap) pkt_leap, 0);
SRC_SelectSource(inst->source);
diff --git a/refclock.c b/refclock.c
index 6ca9118..53e6b1f 100644
--- a/refclock.c
+++ b/refclock.c
@@ -639,7 +639,7 @@ poll_timeout(void *arg)
SRC_UpdateReachability(inst->source, 1);
SRC_AccumulateSample(inst->source, &sample_time, offset,
- inst->delay, dispersion, inst->delay, dispersion, stratum, inst->leap_status);
+ inst->delay, dispersion, inst->delay, dispersion, stratum, inst->leap_status, 0);
SRC_SelectSource(inst->source);
log_sample(inst, &sample_time, 1, 0, 0.0, offset, dispersion);
diff --git a/sources.c b/sources.c
index 67b61e7..6caee67 100644
--- a/sources.c
+++ b/sources.c
@@ -92,6 +92,7 @@ typedef enum {
struct SRC_Instance_Record {
SST_Stats stats;
NTP_Leap leap_status; /* Leap status */
+ int tai_offset; /* TAI offset, or 0 if unknown */
int index; /* Index back into the array of source */
uint32_t ref_id; /* The reference ID of this source
(i.e. from its IP address, NOT the
@@ -344,12 +345,14 @@ void SRC_AccumulateSample
double root_delay,
double root_dispersion,
int stratum,
- NTP_Leap leap_status)
+ NTP_Leap leap_status,
+ int tai_offset)
{
assert(initialised);
inst->leap_status = leap_status;
+ inst->tai_offset = tai_offset;
DEBUG_LOG("ip=[%s] t=%s ofs=%f del=%f disp=%f str=%d",
source_to_string(inst), UTI_TimespecToString(sample_time), -offset,
diff --git a/sources.h b/sources.h
index 60d28fd..725a7d0 100644
--- a/sources.h
+++ b/sources.h
@@ -107,7 +107,7 @@ extern SST_Stats SRC_GetSourcestats(SRC_Instance instance);
*/
-extern void SRC_AccumulateSample(SRC_Instance instance, struct timespec *sample_time, double offset, double peer_delay, double peer_dispersion, double root_delay, double root_dispersion, int stratum, NTP_Leap leap_status);
+extern void SRC_AccumulateSample(SRC_Instance instance, struct timespec *sample_time, double offset, double peer_delay, double peer_dispersion, double root_delay, double root_dispersion, int stratum, NTP_Leap leap_status, int tai_offset);
/* This routine sets the source as receiving reachability updates */
extern void SRC_SetActive(SRC_Instance inst);
diff --git a/test/unit/sources.c b/test/unit/sources.c
index 341e22e..bbd4daa 100644
--- a/test/unit/sources.c
+++ b/test/unit/sources.c
@@ -73,7 +73,7 @@ test_unit(void)
offset, delay, disp);
SRC_AccumulateSample(srcs[j], &ts, offset, delay, disp, delay, disp,
- 1, LEAP_Normal);
+ 1, LEAP_Normal, 0);
}
for (k = 0; k <= j; k++) {
--
2.13.0
From 5695612bc8c4eeef0ccbfdc9b7fce8a543a5687b Mon Sep 17 00:00:00 2001
From: Will Miles <wmiles@xxxxxxx>
Date: Wed, 20 Sep 2017 14:53:26 -0400
Subject: [PATCH 03/10] reference: Allow SetReference to supply a tai offset
---
reference.c | 26 +++++++++++++++-----------
reference.h | 3 ++-
sources.c | 3 ++-
3 files changed, 19 insertions(+), 13 deletions(-)
diff --git a/reference.c b/reference.c
index 9f38908..60fda68 100644
--- a/reference.c
+++ b/reference.c
@@ -141,7 +141,7 @@ static double last_ref_update_interval;
/* ================================================== */
static NTP_Leap get_tz_leap(time_t when, int *tai_offset);
-static void update_leap_status(NTP_Leap leap, time_t now, int reset);
+static void update_leap_status(NTP_Leap leap, int tai_offset, time_t now, int reset);
/* ================================================== */
@@ -169,7 +169,7 @@ handle_slew(struct timespec *raw,
and also reset the leap timeout to undo the shift in the scheduler */
if (change_type != LCL_ChangeAdjust && our_leap_sec && !leap_in_progress) {
LCL_ReadRawTime(&now);
- update_leap_status(our_leap_status, now.tv_sec, 1);
+ update_leap_status(our_leap_status, our_tai_offset, now.tv_sec, 1);
}
}
@@ -283,7 +283,7 @@ REF_Initialise(void)
void
REF_Finalise(void)
{
- update_leap_status(LEAP_Unsynchronised, 0, 0);
+ update_leap_status(LEAP_Unsynchronised, 0, 0, 0);
if (drift_file) {
update_drift_file(LCL_ReadAbsoluteFrequency(), our_skew);
@@ -786,13 +786,12 @@ set_leap_timeout(time_t now)
/* ================================================== */
static void
-update_leap_status(NTP_Leap leap, time_t now, int reset)
+update_leap_status(NTP_Leap leap, int tai_offset, time_t now, int reset)
{
NTP_Leap tz_leap;
- int leap_sec, tai_offset;
+ int leap_sec;
leap_sec = 0;
- tai_offset = 0;
if (leap_tzname && now) {
tz_leap = get_tz_leap(now, &tai_offset);
@@ -813,7 +812,11 @@ update_leap_status(NTP_Leap leap, time_t now, int reset)
leap = LEAP_Normal;
}
}
-
+
+ /* If no offset was supplied, use our current value */
+ if (tai_offset == 0)
+ tai_offset = our_tai_offset;
+
if ((leap_sec != our_leap_sec || tai_offset != our_tai_offset)
&& !REF_IsLeapSecondClose()) {
our_leap_sec = leap_sec;
@@ -949,7 +952,8 @@ REF_SetReference(int stratum,
double frequency,
double skew,
double root_delay,
- double root_dispersion
+ double root_dispersion,
+ int tai_offset
)
{
double previous_skew, new_skew;
@@ -1079,7 +1083,7 @@ REF_SetReference(int stratum,
our_residual_freq = frequency;
}
- update_leap_status(leap, raw_now.tv_sec, 0);
+ update_leap_status(leap, tai_offset, raw_now.tv_sec, 0);
maybe_log_offset(our_offset, raw_now.tv_sec);
if (step_offset != 0.0) {
@@ -1146,7 +1150,7 @@ REF_SetManualReference
only supposed to be used with the local source option, really.
Log as MANU in the tracking log, packets will have NTP_REFID_LOCAL. */
REF_SetReference(0, LEAP_Unsynchronised, 1, 0x4D414E55UL, NULL,
- ref_time, offset, 0.0, frequency, skew, 0.0, 0.0);
+ ref_time, offset, 0.0, frequency, skew, 0.0, 0.0, 0);
}
/* ================================================== */
@@ -1174,7 +1178,7 @@ REF_SetUnsynchronised(void)
schedule_fb_drift(&now);
}
- update_leap_status(LEAP_Unsynchronised, 0, 0);
+ update_leap_status(LEAP_Unsynchronised, 0, 0, 0);
our_ref_ip.family = IPADDR_INET4;
our_ref_ip.addr.in4 = 0;
our_stratum = 0;
diff --git a/reference.h b/reference.h
index d38cc40..72dd714 100644
--- a/reference.h
+++ b/reference.h
@@ -149,7 +149,8 @@ extern void REF_SetReference
double frequency,
double skew,
double root_delay,
- double root_dispersion
+ double root_dispersion,
+ int tai_offset
);
extern void REF_SetManualReference
diff --git a/sources.c b/sources.c
index 6caee67..4cbad02 100644
--- a/sources.c
+++ b/sources.c
@@ -615,6 +615,7 @@ SRC_SelectSource(SRC_Instance updated_inst)
double best_lo, best_hi, distance, sel_src_distance, max_score;
double first_sample_ago, max_reach_sample_ago;
NTP_Leap leap_status;
+ int tai_offset = 0;
if (updated_inst)
updated_inst->updates++;
@@ -1083,7 +1084,7 @@ SRC_SelectSource(SRC_Instance updated_inst)
sources[selected_source_index]->ip_addr,
&ref_time, src_offset, src_offset_sd,
src_frequency, src_skew,
- src_root_delay, src_root_dispersion);
+ src_root_delay, src_root_dispersion, tai_offset);
}
/* ================================================== */
--
2.13.0
From 80e2aa0414b2d75d0acecc96deae5d87a9936c8e Mon Sep 17 00:00:00 2001
From: Will Miles <wmiles@xxxxxxx>
Date: Thu, 21 Sep 2017 12:46:34 -0400
Subject: [PATCH 04/10] source: Send best TAI offset to reference clock
---
sources.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/sources.c b/sources.c
index 4cbad02..1aabaca 100644
--- a/sources.c
+++ b/sources.c
@@ -1017,6 +1017,9 @@ SRC_SelectSource(SRC_Instance updated_inst)
if (max_score < sources[i]->sel_score) {
max_score = sources[i]->sel_score;
max_score_index = i;
+ /* Use the TAI offset of the best source supplying one */
+ if (sources[i]->tai_offset)
+ tai_offset = sources[i]->tai_offset;
}
}
--
2.13.0
From f431bf373440a49bc6efe2b845b2b177e68564d7 Mon Sep 17 00:00:00 2001
From: Will Miles <wmiles@xxxxxxx>
Date: Fri, 22 Sep 2017 13:27:09 -0400
Subject: [PATCH 05/10] client: Include TAI offset in source report
---
candm.h | 3 ++-
client.c | 4 +++-
cmdmon.c | 1 +
ntp_core.c | 7 +++++--
reports.h | 1 +
5 files changed, 12 insertions(+), 4 deletions(-)
diff --git a/candm.h b/candm.h
index b03448c..492c0ce 100644
--- a/candm.h
+++ b/candm.h
@@ -679,7 +679,8 @@ typedef struct {
uint32_t total_tx_count;
uint32_t total_rx_count;
uint32_t total_valid_count;
- uint32_t reserved[4];
+ int32_t tai_offset;
+ uint32_t reserved[3];
int32_t EOR;
} RPY_NTPData;
diff --git a/client.c b/client.c
index 5c3a99e..287b126 100644
--- a/client.c
+++ b/client.c
@@ -2319,7 +2319,8 @@ process_cmd_ntpdata(char *line)
"RX timestamping : %N\n"
"Total TX : %U\n"
"Total RX : %U\n"
- "Total valid RX : %U\n",
+ "Total valid RX : %U\n"
+ "TAI offset : %d\n",
UTI_IPToString(&remote_addr), (unsigned long)UTI_IPToRefid(&remote_addr),
ntohs(reply.data.ntp_data.remote_port),
UTI_IPToString(&local_addr), (unsigned long)UTI_IPToRefid(&local_addr),
@@ -2347,6 +2348,7 @@ process_cmd_ntpdata(char *line)
(unsigned long)ntohl(reply.data.ntp_data.total_tx_count),
(unsigned long)ntohl(reply.data.ntp_data.total_rx_count),
(unsigned long)ntohl(reply.data.ntp_data.total_valid_count),
+ ntohl(reply.data.ntp_data.tai_offset),
REPORT_END);
}
diff --git a/cmdmon.c b/cmdmon.c
index 4ed2189..b148b0d 100644
--- a/cmdmon.c
+++ b/cmdmon.c
@@ -1235,6 +1235,7 @@ handle_ntp_data(CMD_Request *rx_message, CMD_Reply *tx_message)
tx_message->data.ntp_data.total_tx_count = htonl(report.total_tx_count);
tx_message->data.ntp_data.total_rx_count = htonl(report.total_rx_count);
tx_message->data.ntp_data.total_valid_count = htonl(report.total_valid_count);
+ tx_message->data.ntp_data.tai_offset = htonl(report.tai_offset);
memset(tx_message->data.ntp_data.reserved, 0xff, sizeof (tx_message->data.ntp_data.reserved));
}
diff --git a/ntp_core.c b/ntp_core.c
index 131c61f..cbd14ff 100644
--- a/ntp_core.c
+++ b/ntp_core.c
@@ -1439,6 +1439,9 @@ receive_packet(NCR_Instance inst, NTP_Local_Address *local_addr,
measurement in seconds */
double error_in_estimate;
+ /* Remote TAI offset value */
+ int tai_offset = 0;
+
NTP_Local_Timestamp local_receive, local_transmit;
double remote_interval, local_interval, response_time;
double delay_time, precision;
@@ -1719,7 +1722,7 @@ receive_packet(NCR_Instance inst, NTP_Local_Address *local_addr,
offset, delay, dispersion,
root_delay, root_dispersion,
MAX(message->stratum, inst->min_stratum),
- (NTP_Leap) pkt_leap, 0);
+ (NTP_Leap) pkt_leap, tai_offset);
SRC_SelectSource(inst->source);
@@ -1809,7 +1812,7 @@ receive_packet(NCR_Instance inst, NTP_Local_Address *local_addr,
inst->report.authenticated = inst->auth_mode != AUTH_NONE;
inst->report.tx_tss_char = tss_chars[local_transmit.source];
inst->report.rx_tss_char = tss_chars[local_receive.source];
-
+ inst->report.tai_offset = tai_offset;
inst->report.total_valid_count++;
}
diff --git a/reports.h b/reports.h
index 6a24670..7e40908 100644
--- a/reports.h
+++ b/reports.h
@@ -153,6 +153,7 @@ typedef struct {
uint16_t tests;
int interleaved;
int authenticated;
+ int32_t tai_offset;
char tx_tss_char;
char rx_tss_char;
uint32_t total_tx_count;
--
2.13.0
From bf682bead99459c75b648168c184c7ce621307ee Mon Sep 17 00:00:00 2001
From: Will Miles <wmiles@xxxxxxx>
Date: Thu, 31 Aug 2017 13:03:55 -0400
Subject: [PATCH 06/10] ntp: Modify auth generation to support adding NTPv4
extensions
---
keys.c | 3 ++-
ntp.h | 10 +++-------
ntp_core.c | 17 ++++++++++-------
test/unit/ntp_core.c | 18 +++++++++++++-----
4 files changed, 28 insertions(+), 20 deletions(-)
diff --git a/keys.c b/keys.c
index 74b57c4..799a88f 100644
--- a/keys.c
+++ b/keys.c
@@ -110,7 +110,8 @@ determine_hash_delay(uint32_t key_id)
for (i = 0; i < 10; i++) {
LCL_ReadRawTime(&before);
KEY_GenerateAuth(key_id, (unsigned char *)&pkt, NTP_NORMAL_PACKET_LENGTH,
- (unsigned char *)&pkt.auth_data, sizeof (pkt.auth_data));
+ (unsigned char *)&pkt + NTP_NORMAL_PACKET_LENGTH + sizeof(NTP_int32),
+ NTP_MAX_MAC_LENGTH - 4);
LCL_ReadRawTime(&after);
diff = UTI_DiffTimespecsToDouble(&after, &before);
diff --git a/ntp.h b/ntp.h
index 801f264..3dafb61 100644
--- a/ntp.h
+++ b/ntp.h
@@ -93,15 +93,11 @@ typedef struct {
NTP_int64 receive_ts;
NTP_int64 transmit_ts;
- /* Optional extension fields, we don't send packets with them yet */
- /* uint8_t extensions[] */
-
- /* Optional message authentication code (MAC) */
- NTP_int32 auth_keyid;
- uint8_t auth_data[NTP_MAX_MAC_LENGTH - 4];
+ /* Optional fields, extensions + MAC */
+ uint8_t extensions[NTP_MIN_EXTENSION_LENGTH + NTP_MAX_MAC_LENGTH];
} NTP_Packet;
-#define NTP_NORMAL_PACKET_LENGTH (int)offsetof(NTP_Packet, auth_keyid)
+#define NTP_NORMAL_PACKET_LENGTH (int)offsetof(NTP_Packet, extensions)
/* The buffer used to hold a datagram read from the network */
typedef struct {
diff --git a/ntp_core.c b/ntp_core.c
index cbd14ff..3249c8f 100644
--- a/ntp_core.c
+++ b/ntp_core.c
@@ -897,10 +897,11 @@ transmit_packet(NTP_Mode my_mode, /* The mode this machine wants to be */
)
{
NTP_Packet message;
- int auth_len, mac_len, length, ret, precision;
+ int auth_len, mac_len, ext_len, length, ret, precision;
struct timespec local_receive, local_transmit;
double smooth_offset, local_transmit_err;
NTP_int64 ts_fuzz;
+ NTP_int32 auth_keyid = htonl(key_id);
/* Parameters read from reference module */
int are_we_synchronised, our_stratum, smooth_time;
@@ -918,6 +919,7 @@ transmit_packet(NTP_Mode my_mode, /* The mode this machine wants to be */
if (interleaved && (!local_tx || UTI_IsZeroTimespec(&local_tx->ts)))
interleaved = 0;
+ ext_len = 0;
smooth_time = 0;
smooth_offset = 0.0;
@@ -1014,7 +1016,7 @@ transmit_packet(NTP_Mode my_mode, /* The mode this machine wants to be */
if (smooth_time)
UTI_AddDoubleToTimespec(&local_transmit, smooth_offset, &local_transmit);
- length = NTP_NORMAL_PACKET_LENGTH;
+ length = NTP_NORMAL_PACKET_LENGTH + ext_len;
/* Authenticate the packet */
@@ -1029,16 +1031,17 @@ transmit_packet(NTP_Mode my_mode, /* The mode this machine wants to be */
if (auth_mode == AUTH_SYMMETRIC) {
auth_len = KEY_GenerateAuth(key_id, (unsigned char *) &message,
- offsetof(NTP_Packet, auth_keyid),
- (unsigned char *)&message.auth_data,
- sizeof (message.auth_data));
+ length,
+ &message.extensions[ext_len + sizeof(auth_keyid)],
+ NTP_MAX_MAC_LENGTH - 4);
if (!auth_len) {
DEBUG_LOG("Could not generate auth data with key %"PRIu32, key_id);
return 0;
}
- message.auth_keyid = htonl(key_id);
- mac_len = sizeof (message.auth_keyid) + auth_len;
+ /* Assign auth keyid */
+ memcpy(&message.extensions[ext_len], &auth_keyid, sizeof(auth_keyid));
+ mac_len = sizeof (auth_keyid) + auth_len;
/* Truncate MACs in NTPv4 packets to allow deterministic parsing
of extension fields (RFC 7822) */
diff --git a/test/unit/ntp_core.c b/test/unit/ntp_core.c
index b227017..7d4dd1c 100644
--- a/test/unit/ntp_core.c
+++ b/test/unit/ntp_core.c
@@ -139,9 +139,12 @@ send_response(int interleaved, int authenticated, int allow_update, int valid_ts
}
if (authenticated) {
- res->auth_keyid = req->auth_keyid;
- KEY_GenerateAuth(ntohl(res->auth_keyid), (unsigned char *)res, NTP_NORMAL_PACKET_LENGTH,
- res->auth_data, 16);
+ /* Copy the auth key */
+ NTP_int32 auth_keyid;
+ memcpy(&auth_keyid, (char*)req + req_length - (4+16), sizeof(auth_keyid));
+ memcpy(res->extensions, &auth_keyid, sizeof(auth_keyid));
+ KEY_GenerateAuth(ntohl(auth_keyid), (unsigned char *)res, NTP_NORMAL_PACKET_LENGTH,
+ &res->extensions[sizeof(auth_keyid)], 16);
res_length = NTP_NORMAL_PACKET_LENGTH + 4 + 16;
} else {
res_length = NTP_NORMAL_PACKET_LENGTH;
@@ -150,10 +153,15 @@ send_response(int interleaved, int authenticated, int allow_update, int valid_ts
if (!valid_auth) {
switch (random() % 3) {
case 0:
- res->auth_keyid++;
+ {
+ NTP_int32 auth_keyid;
+ memcpy(&auth_keyid, res->extensions, sizeof(auth_keyid));
+ ++auth_keyid;
+ memcpy(res->extensions, &auth_keyid, sizeof(auth_keyid));
+ }
break;
case 1:
- res->auth_data[random() % 16]++;
+ res->extensions[sizeof(NTP_int32) + (random() % 16)]++;
break;
case 2:
res_length = NTP_NORMAL_PACKET_LENGTH;
--
2.13.0
From 42a2fbd11227ed629e9f4a089adaf698dd177544 Mon Sep 17 00:00:00 2001
From: Will Miles <wmiles@xxxxxxx>
Date: Thu, 31 Aug 2017 16:52:35 -0400
Subject: [PATCH 07/10] ntp: Ensure RFC7822 is met for extensions with no MAC
---
ntp.h | 4 ++++
ntp_core.c | 12 +++++++++++-
2 files changed, 15 insertions(+), 1 deletion(-)
diff --git a/ntp.h b/ntp.h
index 3dafb61..5bb3fed 100644
--- a/ntp.h
+++ b/ntp.h
@@ -55,6 +55,10 @@ typedef uint32_t NTP_int32;
extension fields in one packet) */
#define NTP_MAX_EXTENSIONS_LENGTH 1024
+/* The minimum length of the last extension, if no MAC is included, per
+ RFC 7822 */
+#define NTP_MIN_EXTENSION_LENGTH_NO_MAC 28
+
/* The minimum and maximum supported length of MAC */
#define NTP_MIN_MAC_LENGTH (4 + 16)
#define NTP_MAX_MAC_LENGTH (4 + MAX_HASH_LENGTH)
diff --git a/ntp_core.c b/ntp_core.c
index 3249c8f..e34f1e1 100644
--- a/ntp_core.c
+++ b/ntp_core.c
@@ -897,7 +897,7 @@ transmit_packet(NTP_Mode my_mode, /* The mode this machine wants to be */
)
{
NTP_Packet message;
- int auth_len, mac_len, ext_len, length, ret, precision;
+ int auth_len, mac_len, ext_len, last_ext_len, length, ret, precision;
struct timespec local_receive, local_transmit;
double smooth_offset, local_transmit_err;
NTP_int64 ts_fuzz;
@@ -919,6 +919,7 @@ transmit_packet(NTP_Mode my_mode, /* The mode this machine wants to be */
if (interleaved && (!local_tx || UTI_IsZeroTimespec(&local_tx->ts)))
interleaved = 0;
+ last_ext_len = 0;
ext_len = 0;
smooth_time = 0;
smooth_offset = 0.0;
@@ -1004,6 +1005,15 @@ transmit_packet(NTP_Mode my_mode, /* The mode this machine wants to be */
UTI_ZeroNtp64(&message.receive_ts);
}
+ if ((auth_mode != AUTH_SYMMETRIC) && (auth_mode != AUTH_MSSNTP)
+ && (ext_len > 0) && (last_ext_len < NTP_MIN_EXTENSION_LENGTH_NO_MAC)) {
+ /* Per RFC 7822, extend the last extension field to the minimum length */
+ memset(&message.extensions[ext_len], 0, NTP_MIN_EXTENSION_LENGTH_NO_MAC - last_ext_len);
+ length = htons(NTP_MIN_EXTENSION_LENGTH_NO_MAC);
+ memcpy(&message.extensions[ext_len - last_ext_len + sizeof(int16_t)],&length, sizeof(int16_t));
+ ext_len += NTP_MIN_EXTENSION_LENGTH_NO_MAC - last_ext_len;
+ }
+
do {
/* Prepare random bits which will be added to the transmit timestamp */
UTI_GetNtp64Fuzz(&ts_fuzz, precision);
--
2.13.0
From c6e2c09013f5a4c5afc34580ad45ee14c7306086 Mon Sep 17 00:00:00 2001
From: Will Miles <wmiles@xxxxxxx>
Date: Thu, 5 Oct 2017 16:13:06 -0400
Subject: [PATCH 08/10] ntp: Add infrastructure for processing NTPv4 extensions
---
ntp_core.c | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-------
1 file changed, 57 insertions(+), 7 deletions(-)
diff --git a/ntp_core.c b/ntp_core.c
index e34f1e1..bfd2818 100644
--- a/ntp_core.c
+++ b/ntp_core.c
@@ -1257,7 +1257,7 @@ is_zero_data(unsigned char *data, int length)
static int
check_packet_auth(NTP_Packet *pkt, int length,
- AuthenticationMode *auth_mode, uint32_t *key_id)
+ AuthenticationMode *auth_mode, uint32_t *key_id, int *auth_start)
{
int i, version, remainder, ext_length, max_mac_length;
unsigned char *data;
@@ -1294,6 +1294,9 @@ check_packet_auth(NTP_Packet *pkt, int length,
remainder > NTP_MAX_V4_MAC_LENGTH)
pkt->lvm = NTP_LVM(NTP_LVM_TO_LEAP(pkt->lvm), 3, NTP_LVM_TO_MODE(pkt->lvm));
+ if (auth_start)
+ *auth_start = i;
+
return 1;
}
}
@@ -1328,6 +1331,9 @@ check_packet_auth(NTP_Packet *pkt, int length,
else if (remainder == 72 && is_zero_data(data + i + 8, remainder - 8))
*auth_mode = AUTH_MSSNTP_EXT;
}
+
+ if (auth_start)
+ *auth_start = i;
} else {
*auth_mode = AUTH_NONE;
*key_id = 0;
@@ -1338,6 +1344,42 @@ check_packet_auth(NTP_Packet *pkt, int length,
/* ================================================== */
+static void
+process_packet_extensions(unsigned char *data, int length,
+ int auth_ok, int* tai)
+{
+ int i, remainder, ext_length;
+ uint16_t ext_id;
+
+ i = 0;
+ while (1) {
+ remainder = length - i;
+ if(remainder >= NTP_MIN_EXTENSION_LENGTH) {
+ ext_length = ntohs(*(uint16_t *)(data + i + 2));
+
+ if (ext_length >= NTP_MIN_EXTENSION_LENGTH &&
+ ext_length <= remainder && ext_length % 4 == 0) {
+ ext_id = ntohs(*(uint16_t *)(data + i));
+
+ switch (ext_id) {
+ /* Extension processing goes here */
+ default:
+ /* ignore */
+ break;
+ }
+
+ i += ext_length;
+ continue;
+ }
+ }
+
+ /* Not enough bytes left */
+ break;
+ }
+}
+
+/* ================================================== */
+
static int
check_delay_ratio(NCR_Instance inst, SST_Stats stats,
struct timespec *sample_time, double delay)
@@ -1405,11 +1447,12 @@ receive_packet(NCR_Instance inst, NTP_Local_Address *local_addr,
{
SST_Stats stats;
- int pkt_leap, pkt_version;
+ int pkt_leap, pkt_version, pkt_auth_ok;
uint32_t pkt_refid, pkt_key_id;
double pkt_root_delay;
double pkt_root_dispersion;
AuthenticationMode pkt_auth_mode;
+ int pkt_auth_start;
/* The local time to which the (offset, delay, dispersion) triple will
be taken to relate. For client/server operation this is practically
@@ -1470,6 +1513,8 @@ receive_packet(NCR_Instance inst, NTP_Local_Address *local_addr,
pkt_refid = ntohl(message->reference_id);
pkt_root_delay = UTI_Ntp32ToDouble(message->root_delay);
pkt_root_dispersion = UTI_Ntp32ToDouble(message->root_dispersion);
+ pkt_auth_ok = 0;
+ pkt_auth_start = length;
/* Check if the packet is valid per RFC 5905, section 8.
The test values are 1 when passed and 0 when failed. */
@@ -1498,10 +1543,10 @@ receive_packet(NCR_Instance inst, NTP_Local_Address *local_addr,
from this peer/server and the packet doesn't have it, the authentication
is bad, or it's authenticated with a different key than expected, it's got
to fail. If we don't expect the packet to be authenticated, just ignore
- the test. */
- test5 = inst->auth_mode == AUTH_NONE ||
- (check_packet_auth(message, length, &pkt_auth_mode, &pkt_key_id) &&
- pkt_auth_mode == inst->auth_mode && pkt_key_id == inst->auth_key_id);
+ the test; we run it anyways, because some extensions demand authentication. */
+ pkt_auth_ok = check_packet_auth(message, length, &pkt_auth_mode, &pkt_key_id, &pkt_auth_start);
+ test5 = (inst->auth_mode == AUTH_NONE) ||
+ (pkt_auth_ok && pkt_auth_mode == inst->auth_mode && pkt_key_id == inst->auth_key_id);
/* Test 6 checks for unsynchronised server */
test6 = pkt_leap != LEAP_Unsynchronised &&
@@ -1726,6 +1771,11 @@ receive_packet(NCR_Instance inst, NTP_Local_Address *local_addr,
SRC_UpdateReachability(inst->source, synced_packet);
+ if (pkt_version == 4) {
+ process_packet_extensions(message->extensions,
+ pkt_auth_start - NTP_NORMAL_PACKET_LENGTH, pkt_auth_ok, &tai_offset);
+ }
+
if (good_packet) {
/* Do this before we accumulate a new sample into the stats registers, obviously */
estimated_offset = SST_PredictOffset(stats, &sample_time);
@@ -2050,7 +2100,7 @@ NCR_ProcessRxUnknown(NTP_Remote_Address *remote_addr, NTP_Local_Address *local_a
}
/* Check if the packet includes MAC that authenticates properly */
- valid_auth = check_packet_auth(message, length, &auth_mode, &key_id);
+ valid_auth = check_packet_auth(message, length, &auth_mode, &key_id, NULL);
/* If authentication failed, select whether and how we should respond */
if (!valid_auth) {
--
2.13.0
From 66241e86132c218b2f29fa2f0188ed759a551ad3 Mon Sep 17 00:00:00 2001
From: Will Miles <wmiles@xxxxxxx>
Date: Fri, 22 Sep 2017 14:12:32 -0400
Subject: [PATCH 09/10] ntp: Add option for sending "extended information" NTP
extension
This is an implementation of the "Extended Information" extension
Ref: https://tools.ietf.org/html/draft-stenn-ntp-extended-information-00
---
configure | 11 ++++++++++-
ntp_core.c | 9 +++++++++
ntp_extended.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
ntp_extended.h | 45 ++++++++++++++++++++++++++++++++++++++++++
stubs.c | 12 ++++++++++++
5 files changed, 138 insertions(+), 1 deletion(-)
create mode 100644 ntp_extended.c
create mode 100644 ntp_extended.h
diff --git a/configure b/configure
index 7b57992..d382ab9 100755
--- a/configure
+++ b/configure
@@ -103,6 +103,7 @@ For better control, use the options below.
--without-clock-gettime Don't use clock_gettime() even if it is available
--disable-timestamping Disable support for SW/HW timestamping
--enable-ntp-signd Enable support for MS-SNTP authentication in Samba
+ --enable-ntp-extended Enable support for NTP Extended Information Extension Draft
--with-ntp-era=SECONDS Specify earliest assumed NTP time in seconds
since 1970-01-01 [50*365 days ago]
--with-user=USER Specify default chronyd user [root]
@@ -224,6 +225,7 @@ try_recvmmsg=1
feat_timestamping=1
try_timestamping=0
feat_ntp_signd=0
+feat_ntp_extended=0
ntp_era_split=""
default_user="root"
default_hwclockfile=""
@@ -339,6 +341,9 @@ do
--enable-ntp-signd)
feat_ntp_signd=1
;;
+ --enable-ntp-extended)
+ feat_ntp_extended=1
+ ;;
--with-ntp-era=* )
ntp_era_split=`echo $option | sed -e 's/^.*=//;'`
;;
@@ -477,6 +482,10 @@ if [ $feat_ntp = "1" ]; then
add_def FEAT_SIGND
EXTRA_OBJECTS="$EXTRA_OBJECTS ntp_signd.o"
fi
+ if [ $feat_ntp_extended = "1" ]; then
+ add_def FEAT_EXTENDED
+ EXTRA_OBJECTS="$EXTRA_OBJECTS ntp_extended.o"
+ fi
else
feat_asyncdns=0
feat_timestamping=0
@@ -948,7 +957,7 @@ add_def MAIL_PROGRAM "\"$mail_program\""
common_features="`get_features IPV6 DEBUG`"
chronyc_features="`get_features READLINE`"
-chronyd_features="`get_features CMDMON NTP REFCLOCK RTC PRIVDROP SCFILTER SECHASH SIGND ASYNCDNS`"
+chronyd_features="`get_features CMDMON NTP REFCLOCK RTC PRIVDROP SCFILTER SECHASH SIGND EXTENDED ASYNCDNS`"
add_def CHRONYC_FEATURES "\"$chronyc_features $common_features\""
add_def CHRONYD_FEATURES "\"$chronyd_features $common_features\""
echo "Features : $chronyd_features $chronyc_features $common_features"
diff --git a/ntp_core.c b/ntp_core.c
index bfd2818..ea6cba9 100644
--- a/ntp_core.c
+++ b/ntp_core.c
@@ -31,6 +31,7 @@
#include "array.h"
#include "ntp_core.h"
+#include "ntp_extended.h"
#include "ntp_io.h"
#include "ntp_signd.h"
#include "memory.h"
@@ -953,6 +954,14 @@ transmit_packet(NTP_Mode my_mode, /* The mode this machine wants to be */
}
precision = LCL_GetSysPrecisionAsLog();
+
+#ifdef FEAT_EXTENDED
+ length = NEX_GenerateExtension(&message.extensions[ext_len], sizeof(message.extensions)-ext_len, interleaved);
+ if (length) {
+ last_ext_len = length;
+ ext_len += last_ext_len;
+ }
+#endif /* FEAT_EXTENDED */
}
if (smooth_time && !UTI_IsZeroTimespec(&local_rx->ts)) {
diff --git a/ntp_extended.c b/ntp_extended.c
new file mode 100644
index 0000000..9f0ae1a
--- /dev/null
+++ b/ntp_extended.c
@@ -0,0 +1,62 @@
+/*
+ chronyd/chronyc - Programs for keeping computer clocks accurate.
+
+ **********************************************************************
+ * Copyright (C) Will Miles 2017
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ **********************************************************************
+
+ =======================================================================
+
+ Support for NTP Extension Field: Extended Information Version 1
+ */
+
+#include "config.h"
+
+#include "ntp_extended.h"
+#include "reference.h"
+#include "util.h"
+
+
+#define EXTENDED_INFORMATION_TAI_OFFSET_PRESENT 0x01
+#define EXTENDED_INFORMATION_INTERLEAVE_MODE_PRESENT 0x02
+
+#define EXTENDED_INFORMATION_INTERLEAVE_MODE 0x0100
+
+/* ================================================== */
+
+int
+NEX_GenerateExtension(uint8_t* ext, size_t ext_len, int interleaved)
+{
+ uint16_t* base = (uint16_t*) ext;
+ int tai_offset;
+
+ /* Validate sufficient space */
+ if (ext_len < NTP_MIN_EXTENSION_LENGTH)
+ return 0;
+
+ tai_offset = REF_GetTaiOffset();
+
+ /* Build extension data structure */
+ base[0] = htons(NTP_EXTENSION_EXTENDED_INFORMATION_ID);
+ base[1] = htons(NTP_MIN_EXTENSION_LENGTH); // size of extension - only 8 bytes used, though
+ base[2] = htons(EXTENDED_INFORMATION_INTERLEAVE_MODE_PRESENT | (tai_offset ? EXTENDED_INFORMATION_TAI_OFFSET_PRESENT : 0));
+ base[3] = htons( (interleaved ? EXTENDED_INFORMATION_INTERLEAVE_MODE : 0) | tai_offset);
+ memset(&base[4], 0, NTP_MIN_EXTENSION_LENGTH - 8);
+
+ return NTP_MIN_EXTENSION_LENGTH;
+}
+
diff --git a/ntp_extended.h b/ntp_extended.h
new file mode 100644
index 0000000..1271cfb
--- /dev/null
+++ b/ntp_extended.h
@@ -0,0 +1,45 @@
+/*
+ chronyd/chronyc - Programs for keeping computer clocks accurate.
+
+ **********************************************************************
+ * Copyright (C) Will Miles 2017
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ **********************************************************************
+
+ =======================================================================
+
+ Header for Network Time Protocol Extended Information Extension Field
+
+ */
+
+#ifndef GOT_NTP_EXTENDED_H
+#define GOT_NTP_EXTENDED_H
+
+#include "ntp.h"
+
+#define NTP_EXTENSION_EXTENDED_INFORMATION 0x0009
+#define NTP_EXTENSION_MAC_OPTIONAL 0x2000
+#define NTP_EXTENSION_EXTENDED_INFORMATION_VERSION 0x0100
+
+#define NTP_EXTENSION_EXTENDED_INFORMATION_ID (NTP_EXTENSION_EXTENDED_INFORMATION | NTP_EXTENSION_MAC_OPTIONAL | NTP_EXTENSION_EXTENDED_INFORMATION_VERSION)
+#define NTP_EXTENSION_EXTENDED_INFORMATION_ID_MAC (NTP_EXTENSION_EXTENDED_INFORMATION | NTP_EXTENSION_EXTENDED_INFORMATION_VERSION)
+
+/* Function to add the Extended Information Version 1 extension field to
+ * an NTP_Packet. Returns number of bytes written.
+ */
+extern int NEX_GenerateExtension(uint8_t* ext, size_t ext_len, int interleaved);
+
+#endif
diff --git a/stubs.c b/stubs.c
index eac81c0..e56b8f1 100644
--- a/stubs.c
+++ b/stubs.c
@@ -36,6 +36,7 @@
#include "nameserv.h"
#include "nameserv_async.h"
#include "ntp_core.h"
+#include "ntp_extended.h"
#include "ntp_io.h"
#include "ntp_sources.h"
#include "ntp_signd.h"
@@ -416,3 +417,14 @@ NSD_SignAndSendPacket(uint32_t key_id, NTP_Packet *packet, NTP_Remote_Address *r
}
#endif /* !FEAT_SIGND */
+
+
+#ifndef FEAT_EXTENDED
+
+int
+NEX_GenerateExtension(uint8_t* ext, size_t ext_len, int interleaved)
+{
+ return 0;
+}
+
+#endif /* !FEAT_EXTENDED */
--
2.13.0
From af0d53d3acff305dbc6912359f168c1583b82b4f Mon Sep 17 00:00:00 2001
From: Will Miles <wmiles@xxxxxxx>
Date: Fri, 22 Sep 2017 13:55:59 -0400
Subject: [PATCH 10/10] ntp: Accept TAI offset from Extended Information
extension
---
ntp_core.c | 29 +++++++++++++++++++++--------
ntp_extended.c | 23 +++++++++++++++++++++++
ntp_extended.h | 9 ++++++---
test/unit/ntp_core.c | 4 ++--
4 files changed, 52 insertions(+), 13 deletions(-)
diff --git a/ntp_core.c b/ntp_core.c
index ea6cba9..be127f3 100644
--- a/ntp_core.c
+++ b/ntp_core.c
@@ -1305,7 +1305,7 @@ check_packet_auth(NTP_Packet *pkt, int length,
if (auth_start)
*auth_start = i;
-
+
return 1;
}
}
@@ -1340,9 +1340,9 @@ check_packet_auth(NTP_Packet *pkt, int length,
else if (remainder == 72 && is_zero_data(data + i + 8, remainder - 8))
*auth_mode = AUTH_MSSNTP_EXT;
}
-
+
if (auth_start)
- *auth_start = i;
+ *auth_start = i;
} else {
*auth_mode = AUTH_NONE;
*key_id = 0;
@@ -1365,13 +1365,21 @@ process_packet_extensions(unsigned char *data, int length,
remainder = length - i;
if(remainder >= NTP_MIN_EXTENSION_LENGTH) {
ext_length = ntohs(*(uint16_t *)(data + i + 2));
-
if (ext_length >= NTP_MIN_EXTENSION_LENGTH &&
ext_length <= remainder && ext_length % 4 == 0) {
ext_id = ntohs(*(uint16_t *)(data + i));
-
switch (ext_id) {
- /* Extension processing goes here */
+#ifdef FEAT_EXTENDED
+ case NTP_EXTENSION_EXTENDED_INFORMATION_ID_MAC:
+ if (!auth_ok)
+ break; /* Ignore if unauthenticated */
+ /* Otherwise fall through */
+ case NTP_EXTENSION_EXTENDED_INFORMATION_ID:
+ if (tai) {
+ *tai = NEX_GetTAI(data + i +4, ext_length - 4);
+ }
+ break;
+#endif
default:
/* ignore */
break;
@@ -1460,7 +1468,7 @@ receive_packet(NCR_Instance inst, NTP_Local_Address *local_addr,
uint32_t pkt_refid, pkt_key_id;
double pkt_root_delay;
double pkt_root_dispersion;
- AuthenticationMode pkt_auth_mode;
+ AuthenticationMode pkt_auth_mode;
int pkt_auth_start;
/* The local time to which the (offset, delay, dispersion) triple will
@@ -1554,7 +1562,7 @@ receive_packet(NCR_Instance inst, NTP_Local_Address *local_addr,
to fail. If we don't expect the packet to be authenticated, just ignore
the test; we run it anyways, because some extensions demand authentication. */
pkt_auth_ok = check_packet_auth(message, length, &pkt_auth_mode, &pkt_key_id, &pkt_auth_start);
- test5 = (inst->auth_mode == AUTH_NONE) ||
+ test5 = (inst->auth_mode == AUTH_NONE) ||
(pkt_auth_ok && pkt_auth_mode == inst->auth_mode && pkt_key_id == inst->auth_key_id);
/* Test 6 checks for unsynchronised server */
@@ -1779,6 +1787,11 @@ receive_packet(NCR_Instance inst, NTP_Local_Address *local_addr,
inst->tx_count = 0;
SRC_UpdateReachability(inst->source, synced_packet);
+
+ if (pkt_version == 4) {
+ process_packet_extensions(message->extensions,
+ pkt_auth_start - NTP_NORMAL_PACKET_LENGTH, pkt_auth_ok, &tai_offset);
+ }
if (pkt_version == 4) {
process_packet_extensions(message->extensions,
diff --git a/ntp_extended.c b/ntp_extended.c
index 9f0ae1a..192765c 100644
--- a/ntp_extended.c
+++ b/ntp_extended.c
@@ -31,6 +31,7 @@
#include "util.h"
+
#define EXTENDED_INFORMATION_TAI_OFFSET_PRESENT 0x01
#define EXTENDED_INFORMATION_INTERLEAVE_MODE_PRESENT 0x02
@@ -60,3 +61,25 @@ NEX_GenerateExtension(uint8_t* ext, size_t ext_len, int interleaved)
return NTP_MIN_EXTENSION_LENGTH;
}
+/* ================================================== */
+
+int8_t
+NEX_GetTAI(uint8_t* ext, size_t len)
+{
+ uint16_t flags, value;
+
+ /* Validate length */
+ if (len < 4)
+ return 0;
+
+ uint16_t* base = (uint16_t*) ext;
+ flags = htons(*base);
+ value = htons(*(base + 1));
+
+ if (flags & EXTENDED_INFORMATION_TAI_OFFSET_PRESENT)
+ {
+ return (int8_t) (value & 0xFF);
+ }
+
+ return 0;
+}
diff --git a/ntp_extended.h b/ntp_extended.h
index 1271cfb..c70d143 100644
--- a/ntp_extended.h
+++ b/ntp_extended.h
@@ -37,9 +37,12 @@
#define NTP_EXTENSION_EXTENDED_INFORMATION_ID (NTP_EXTENSION_EXTENDED_INFORMATION | NTP_EXTENSION_MAC_OPTIONAL | NTP_EXTENSION_EXTENDED_INFORMATION_VERSION)
#define NTP_EXTENSION_EXTENDED_INFORMATION_ID_MAC (NTP_EXTENSION_EXTENDED_INFORMATION | NTP_EXTENSION_EXTENDED_INFORMATION_VERSION)
-/* Function to add the Extended Information Version 1 extension field to
- * an NTP_Packet. Returns number of bytes written.
- */
+/* Function to add the Extended Information Version 1 extension field to an NTP_Packet */
+/* Returns number of bytes written */
extern int NEX_GenerateExtension(uint8_t* ext, size_t ext_len, int interleaved);
+/* Parses the TAI member out of an Extended Information Version 1, if present */
+/* Otherwise returns 0 */
+extern int8_t NEX_GetTAI(uint8_t* field, size_t len);
+
#endif
diff --git a/test/unit/ntp_core.c b/test/unit/ntp_core.c
index 7d4dd1c..23f7e36 100644
--- a/test/unit/ntp_core.c
+++ b/test/unit/ntp_core.c
@@ -139,9 +139,9 @@ send_response(int interleaved, int authenticated, int allow_update, int valid_ts
}
if (authenticated) {
- /* Copy the auth key */
+ /* Copy the auth key */
NTP_int32 auth_keyid;
- memcpy(&auth_keyid, (char*)req + req_length - (4+16), sizeof(auth_keyid));
+ memcpy(&auth_keyid, (char*)req + req_length - (4+16), sizeof(auth_keyid));
memcpy(res->extensions, &auth_keyid, sizeof(auth_keyid));
KEY_GenerateAuth(ntohl(auth_keyid), (unsigned char *)res, NTP_NORMAL_PACKET_LENGTH,
&res->extensions[sizeof(auth_keyid)], 16);
--
2.13.0