static void transmit_timeout(void *arg);
static double get_transmit_delay(NCR_Instance inst, int on_tx, double last_tx);
static double get_separation(int poll);
+static int parse_packet(NTP_Packet *packet, int length, NTP_PacketInfo *info);
/* ================================================== */
NTP_Local_Address *from /* From what address to send it */
)
{
+ NTP_PacketInfo info;
NTP_Packet message;
- int auth_len, max_auth_len, length, ret, precision;
+ int auth_len, max_auth_len, ret, precision;
struct timespec local_receive, local_transmit;
double smooth_offset, local_transmit_err;
NTP_int64 ts_fuzz;
}
do {
+ if (!parse_packet(&message, NTP_HEADER_LENGTH, &info))
+ return 0;
+
/* Prepare random bits which will be added to the transmit timestamp */
UTI_GetNtp64Fuzz(&ts_fuzz, precision);
if (smooth_time)
UTI_AddDoubleToTimespec(&local_transmit, smooth_offset, &local_transmit);
- length = NTP_HEADER_LENGTH;
-
/* Authenticate the packet */
if (auth_mode == AUTH_SYMMETRIC || auth_mode == AUTH_MSSNTP) {
/* Truncate long MACs in NTPv4 packets to allow deterministic parsing
of extension fields (RFC 7822) */
max_auth_len = (version == 4 ?
- NTP_MAX_V4_MAC_LENGTH : (sizeof (message) - length)) - 4;
+ NTP_MAX_V4_MAC_LENGTH : (sizeof (message) - info.length)) - 4;
- auth_len = KEY_GenerateAuth(key_id, (unsigned char *)&message, length,
- (unsigned char *)&message + length + 4, max_auth_len);
+ auth_len = KEY_GenerateAuth(key_id, (unsigned char *)&message, info.length,
+ (unsigned char *)&message + info.length + 4, max_auth_len);
if (!auth_len) {
DEBUG_LOG("Could not generate auth data with key %"PRIu32, key_id);
return 0;
}
- *(uint32_t *)((unsigned char *)&message + length) = htonl(key_id);
- length += 4 + auth_len;
+ *(uint32_t *)((unsigned char *)&message + info.length) = htonl(key_id);
+ info.length += 4 + auth_len;
} else if (auth_mode == AUTH_MSSNTP) {
/* MS-SNTP packets are signed (asynchronously) by ntp_signd */
- return NSD_SignAndSendPacket(key_id, &message, where_to, from, length);
+ return NSD_SignAndSendPacket(key_id, &message, &info, where_to, from);
}
} else {
UTI_TimespecToNtp64(interleaved ? &local_tx->ts : &local_transmit,
UTI_IsEqualAnyNtp64(&message.transmit_ts, &message.receive_ts,
&message.originate_ts, local_ntp_tx));
- ret = NIO_SendPacket(&message, where_to, from, length, local_tx != NULL);
+ ret = NIO_SendPacket(&message, where_to, from, info.length, local_tx != NULL);
if (local_tx) {
local_tx->ts = local_transmit;
/* ================================================== */
static int
-check_packet_format(NTP_Packet *message, int length)
+parse_packet(NTP_Packet *packet, int length, NTP_PacketInfo *info)
{
- int version;
+ info->length = length;
+ info->version = NTP_LVM_TO_VERSION(packet->lvm);
+ info->mode = NTP_LVM_TO_MODE(packet->lvm);
/* Check version and length */
- version = NTP_LVM_TO_VERSION(message->lvm);
- if (version < NTP_MIN_COMPAT_VERSION || version > NTP_MAX_COMPAT_VERSION) {
- DEBUG_LOG("NTP packet has invalid version %d", version);
+ if (info->version < NTP_MIN_COMPAT_VERSION || info->version > NTP_MAX_COMPAT_VERSION) {
+ DEBUG_LOG("NTP packet has invalid version %d", info->version);
return 0;
}
/* ================================================== */
static int
-check_packet_auth(NTP_Packet *pkt, int length,
+check_packet_auth(NTP_Packet *pkt, NTP_PacketInfo *info,
AuthenticationMode *auth_mode, uint32_t *key_id)
{
- int i, version, remainder, ext_length, max_mac_length;
+ int i, remainder, ext_length, max_mac_length;
unsigned char *data;
uint32_t id;
/* Go through extension fields and see if there is a valid MAC */
- version = NTP_LVM_TO_VERSION(pkt->lvm);
i = NTP_HEADER_LENGTH;
data = (void *)pkt;
while (1) {
- remainder = length - i;
+ remainder = info->length - i;
/* Check if the remaining data is a valid MAC. There is a limit on MAC
length in NTPv4 packets to allow deterministic parsing of extension
compatibility with older chrony clients. This needs to be done before
trying to parse the data as an extension field. */
- max_mac_length = version == 4 && remainder <= NTP_MAX_V4_MAC_LENGTH ?
+ max_mac_length = info->version == 4 && remainder <= NTP_MAX_V4_MAC_LENGTH ?
NTP_MAX_V4_MAC_LENGTH : NTP_MAX_MAC_LENGTH;
if (remainder >= NTP_MIN_MAC_LENGTH && remainder <= max_mac_length) {
/* If it's an NTPv4 packet with long MAC and no extension fields,
rewrite the version in the packet to respond with long MAC too */
- if (version == 4 && NTP_HEADER_LENGTH + remainder == length &&
+ if (info->version == 4 && NTP_HEADER_LENGTH + remainder == info->length &&
remainder > NTP_MAX_V4_MAC_LENGTH)
- pkt->lvm = NTP_LVM(NTP_LVM_TO_LEAP(pkt->lvm), 3, NTP_LVM_TO_MODE(pkt->lvm));
+ info->version = 3;
return 1;
}
/* Check if this is a valid NTPv4 extension field and skip it. It should
have a 16-bit type, 16-bit length, and data padded to 32 bits. */
- if (version == 4 && remainder >= NTP_MIN_EF_LENGTH) {
+ if (info->version == 4 && remainder >= NTP_MIN_EF_LENGTH) {
ext_length = ntohs(*(uint16_t *)(data + i + 2));
if (ext_length >= NTP_MIN_EF_LENGTH &&
ext_length <= remainder && ext_length % 4 == 0) {
/* Check if it is an MS-SNTP authenticator field or extended authenticator
field with zeroes as digest */
- if (version == 3 && *key_id) {
+ if (info->version == 3 && *key_id) {
if (remainder == 20 && is_zero_data(data + i + 4, remainder - 4))
*auth_mode = AUTH_MSSNTP;
else if (remainder == 72 && is_zero_data(data + i + 8, remainder - 8))
static int
receive_packet(NCR_Instance inst, NTP_Local_Address *local_addr,
- NTP_Local_Timestamp *rx_ts, NTP_Packet *message, int length)
+ NTP_Local_Timestamp *rx_ts, NTP_Packet *message, NTP_PacketInfo *info)
{
NTP_Sample sample;
SST_Stats stats;
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) &&
+ (check_packet_auth(message, info, &pkt_auth_mode, &pkt_key_id) &&
pkt_auth_mode == inst->auth_mode && pkt_key_id == inst->auth_key_id);
/* Test 6 checks for unsynchronised server */
NCR_ProcessRxKnown(NCR_Instance inst, NTP_Local_Address *local_addr,
NTP_Local_Timestamp *rx_ts, NTP_Packet *message, int length)
{
- int pkt_mode, proc_packet, proc_as_unknown;
+ int proc_packet, proc_as_unknown;
+ NTP_PacketInfo info;
- if (!check_packet_format(message, length))
+ if (!parse_packet(message, length, &info))
return 0;
- pkt_mode = NTP_LVM_TO_MODE(message->lvm);
proc_packet = 0;
proc_as_unknown = 0;
/* Now, depending on the mode we decide what to do */
- switch (pkt_mode) {
+ switch (info.mode) {
case MODE_ACTIVE:
switch (inst->mode) {
case MODE_ACTIVE:
return 0;
}
- return receive_packet(inst, local_addr, rx_ts, message, length);
+ return receive_packet(inst, local_addr, rx_ts, message, &info);
} else if (proc_as_unknown) {
NCR_ProcessRxUnknown(&inst->remote_addr, local_addr, rx_ts, message, length);
/* It's not a reply to our request, don't return success */
return 0;
} else {
- DEBUG_LOG("NTP packet discarded pkt_mode=%d our_mode=%u", pkt_mode, inst->mode);
+ DEBUG_LOG("NTP packet discarded mode=%d our_mode=%u", (int)info.mode, inst->mode);
return 0;
}
}
NCR_ProcessRxUnknown(NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr,
NTP_Local_Timestamp *rx_ts, NTP_Packet *message, int length)
{
- NTP_Mode pkt_mode, my_mode;
+ NTP_PacketInfo info;
+ NTP_Mode my_mode;
NTP_int64 *local_ntp_rx, *local_ntp_tx;
NTP_Local_Timestamp local_tx, *tx_ts;
- int pkt_version, valid_auth, log_index, interleaved, poll;
+ int valid_auth, log_index, interleaved, poll;
AuthenticationMode auth_mode;
uint32_t key_id;
return;
}
- if (!check_packet_format(message, length))
+ if (!parse_packet(message, length, &info))
return;
if (!ADF_IsAllowed(access_auth_table, &remote_addr->ip_addr)) {
return;
}
- pkt_mode = NTP_LVM_TO_MODE(message->lvm);
- pkt_version = NTP_LVM_TO_VERSION(message->lvm);
-
- switch (pkt_mode) {
+ switch (info.mode) {
case MODE_ACTIVE:
/* We are symmetric passive, even though we don't ever lock to him */
my_mode = MODE_PASSIVE;
/* Check if it is an NTPv1 client request (NTPv1 packets have a reserved
field instead of the mode field and the actual mode is determined from
the port numbers). Don't ever respond with a mode 0 packet! */
- if (pkt_version == 1 && remote_addr->port != NTP_PORT) {
+ if (info.version == 1 && remote_addr->port != NTP_PORT) {
my_mode = MODE_SERVER;
break;
}
/* Fall through */
default:
/* Discard */
- DEBUG_LOG("NTP packet discarded pkt_mode=%u", pkt_mode);
+ DEBUG_LOG("NTP packet discarded mode=%d", (int)info.mode);
return;
}
}
/* 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, &info, &auth_mode, &key_id);
/* If authentication failed, select whether and how we should respond */
if (!valid_auth) {
poll = MAX(poll, message->poll);
/* Send a reply */
- transmit_packet(my_mode, interleaved, poll, pkt_version,
+ transmit_packet(my_mode, interleaved, poll, info.version,
auth_mode, key_id, &message->receive_ts, &message->transmit_ts,
rx_ts, tx_ts, local_ntp_rx, NULL, remote_addr, local_addr);
NCR_ProcessTxKnown(NCR_Instance inst, NTP_Local_Address *local_addr,
NTP_Local_Timestamp *tx_ts, NTP_Packet *message, int length)
{
- NTP_Mode pkt_mode;
+ NTP_PacketInfo info;
- if (!check_packet_format(message, length))
+ if (!parse_packet(message, length, &info))
return;
- pkt_mode = NTP_LVM_TO_MODE(message->lvm);
-
/* Server and passive mode packets are responses to unknown sources */
- if (pkt_mode != MODE_CLIENT && pkt_mode != MODE_ACTIVE) {
+ if (info.mode != MODE_CLIENT && info.mode != MODE_ACTIVE) {
NCR_ProcessTxUnknown(&inst->remote_addr, local_addr, tx_ts, message, length);
return;
}
{
NTP_int64 *local_ntp_rx, *local_ntp_tx;
NTP_Local_Timestamp local_tx;
+ NTP_PacketInfo info;
int log_index;
- if (!check_packet_format(message, length))
+ if (!parse_packet(message, length, &info))
return;
- if (NTP_LVM_TO_MODE(message->lvm) == MODE_BROADCAST)
+ if (info.mode == MODE_BROADCAST)
return;
log_index = CLG_GetClientIndex(&remote_addr->ip_addr);
if (log_index < 0)
return;
- if (SMT_IsEnabled() && NTP_LVM_TO_MODE(message->lvm) == MODE_SERVER)
+ if (SMT_IsEnabled() && info.mode == MODE_SERVER)
UTI_AddDoubleToTimespec(&tx_ts->ts, SMT_GetOffset(&tx_ts->ts), &tx_ts->ts);
CLG_GetNtpTimestamps(log_index, &local_ntp_rx, &local_ntp_tx);