diff --git a/ntp_core.c b/ntp_core.c index 7ade227..6137731 100644 --- a/ntp_core.c +++ b/ntp_core.c @@ -227,6 +227,9 @@ static ARR_Instance broadcasts; /* Maximum allowed time for server to process client packet */ #define MAX_SERVER_INTERVAL 4.0 +/* Maximum acceptable delay in transmission for timestamp correction */ +#define MAX_TX_DELAY 1.0 + /* Minimum and maximum allowed poll interval */ #define MIN_POLL 0 #define MAX_POLL 24 @@ -944,7 +947,7 @@ transmit_packet(NTP_Mode my_mode, /* The mode this machine wants to be */ UTI_TimespecToNtp64(&local_transmit, &message.transmit_ts, &ts_fuzz); } - ret = NIO_SendPacket(&message, where_to, from, length); + ret = NIO_SendPacket(&message, where_to, from, length, local_tx != NULL); if (local_tx) { *local_tx = local_transmit; @@ -1189,7 +1192,8 @@ check_packet_auth(NTP_Packet *pkt, int length, /* ================================================== */ static int -receive_packet(NTP_Packet *message, struct timespec *now, double now_err, NCR_Instance inst, NTP_Local_Address *local_addr, int length) +receive_packet(NTP_Packet *message, struct timespec *rx_ts, double rx_ts_err, + NCR_Instance inst, NTP_Local_Address *local_addr, int length) { int pkt_leap; uint32_t pkt_refid, pkt_key_id; @@ -1315,7 +1319,7 @@ receive_packet(NTP_Packet *message, struct timespec *now, double now_err, NCR_In symmetric associations using authentication */ if (test5) { inst->remote_orig = message->transmit_ts; - inst->local_rx = *now; + inst->local_rx = *rx_ts; } /* This protects against replay of the last packet we sent */ @@ -1331,7 +1335,7 @@ receive_packet(NTP_Packet *message, struct timespec *now, double now_err, NCR_In UTI_AverageDiffTimespecs(&remote_receive, &remote_transmit, &remote_average, &remote_interval); - UTI_AverageDiffTimespecs(&inst->local_tx, now, + UTI_AverageDiffTimespecs(&inst->local_tx, rx_ts, &local_average, &local_interval); /* In our case, we work out 'delay' as the worst case delay, @@ -1362,7 +1366,7 @@ receive_packet(NTP_Packet *message, struct timespec *now, double now_err, NCR_In skew = (source_freq_hi - source_freq_lo) / 2.0; /* and then calculate peer dispersion */ - dispersion = precision + now_err + skew * fabs(local_interval); + dispersion = precision + rx_ts_err + skew * fabs(local_interval); /* Additional tests required to pass before accumulating the sample */ @@ -1392,7 +1396,7 @@ receive_packet(NTP_Packet *message, struct timespec *now, double now_err, NCR_In pkt_refid != UTI_IPToRefid(&local_addr->ip_addr); } else { offset = delay = dispersion = 0.0; - sample_time = *now; + sample_time = *rx_ts; testA = testB = testC = testD = 0; } @@ -1534,8 +1538,8 @@ receive_packet(NTP_Packet *message, struct timespec *now, double now_err, NCR_In | Bcast Client 6 | DSCRD | DSCRD | DSCRD | DSCRD | PROC | +------------------+-------+-------+-------+-------+-------+ - Association mode 0 is implemented in NCR_ProcessUnknown(), other modes - in NCR_ProcessKnown(). + Association mode 0 is implemented in NCR_ProcessRxUnknown(), other modes + in NCR_ProcessRxKnown(). Broadcast, manycast and ephemeral symmetric passive associations are not supported yet. @@ -1546,10 +1550,10 @@ receive_packet(NTP_Packet *message, struct timespec *now, double now_err, NCR_In and it relates to a source we have an ongoing protocol exchange with */ int -NCR_ProcessKnown +NCR_ProcessRxKnown (NTP_Packet *message, /* the received message */ - struct timespec *now, /* timestamp at time of receipt */ - double now_err, + struct timespec *rx_ts, /* timestamp at time of receipt */ + double rx_ts_err, NCR_Instance inst, /* the instance record for this peer/server */ NTP_Local_Address *local_addr, /* the receiving address */ int length /* the length of the received packet */ @@ -1660,10 +1664,10 @@ NCR_ProcessKnown return 0; } - return receive_packet(message, now, now_err, inst, local_addr, length); + return receive_packet(message, rx_ts, rx_ts_err, inst, local_addr, length); } else if (proc_as_unknown) { - NCR_ProcessUnknown(message, now, now_err, &inst->remote_addr, - local_addr, length); + NCR_ProcessRxUnknown(message, rx_ts, rx_ts_err, &inst->remote_addr, + local_addr, length); /* It's not a reply to our request, don't return success */ return 0; } else { @@ -1678,10 +1682,10 @@ NCR_ProcessKnown and it relates to a source we don't know (not our server or peer) */ void -NCR_ProcessUnknown +NCR_ProcessRxUnknown (NTP_Packet *message, /* the received message */ - struct timespec *now, /* timestamp at time of receipt */ - double now_err, /* assumed error in the timestamp */ + struct timespec *rx_ts, /* timestamp at time of receipt */ + double rx_ts_err, /* assumed error in the timestamp */ NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr, int length /* the length of the received packet */ @@ -1726,7 +1730,7 @@ NCR_ProcessUnknown return; } - log_index = CLG_LogNTPAccess(&remote_addr->ip_addr, now); + log_index = CLG_LogNTPAccess(&remote_addr->ip_addr, rx_ts); /* Don't reply to all requests if the rate is excessive */ if (log_index >= 0 && CLG_LimitNTPResponseRate(log_index)) { @@ -1760,12 +1764,77 @@ NCR_ProcessUnknown - don't save our transmit timestamp as we aren't maintaining state about this client */ transmit_packet(my_mode, message->poll, NTP_LVM_TO_VERSION(message->lvm), - auth_mode, key_id, &message->transmit_ts, now, NULL, NULL, + auth_mode, key_id, &message->transmit_ts, rx_ts, NULL, NULL, remote_addr, local_addr); } /* ================================================== */ +static void +update_tx_timestamp(struct timespec *tx_ts, struct timespec *new_tx_ts, + NTP_int64 *local_ntp_tx, NTP_Packet *message) +{ + double delay; + + if (UTI_IsZeroTimespec(tx_ts)) { + DEBUG_LOG(LOGF_NtpCore, "Unexpected TX update"); + return; + } + + /* Check if this is the last packet that was sent */ + if (message->transmit_ts.hi != local_ntp_tx->hi || + message->transmit_ts.lo != local_ntp_tx->lo) { + DEBUG_LOG(LOGF_NtpCore, "TX timestamp mismatch"); + return; + } + + delay = UTI_DiffTimespecsToDouble(new_tx_ts, tx_ts); + + if (delay < 0.0 || delay > MAX_TX_DELAY) { + DEBUG_LOG(LOGF_NtpCore, "Unacceptable TX delay %.9f", delay); + return; + } + + *tx_ts = *new_tx_ts; + + DEBUG_LOG(LOGF_NtpCore, "Updated TX timestamp delay=%.9f", delay); +} + +/* ================================================== */ + +void +NCR_ProcessTxKnown(NTP_Packet *message, struct timespec *tx_ts, double tx_ts_err, + NCR_Instance inst, NTP_Local_Address *local_addr, int length) +{ + NTP_Mode pkt_mode; + + if (!check_packet_format(message, length)) + 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) { + NCR_ProcessTxUnknown(message, tx_ts, tx_ts_err, &inst->remote_addr, + local_addr, length); + return; + } + + update_tx_timestamp(&inst->local_tx, tx_ts, &inst->local_ntp_tx, message); +} + +/* ================================================== */ + +void +NCR_ProcessTxUnknown(NTP_Packet *message, struct timespec *tx_ts, double tx_ts_err, + NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr, int length) +{ + /* Nothing to do yet */ + DEBUG_LOG(LOGF_NtpCore, "Process TX unknown"); +} + +/* ================================================== */ + void NCR_SlewTimes(NCR_Instance inst, struct timespec *when, double dfreq, double doffset) { diff --git a/ntp_core.h b/ntp_core.h index 2fd0841..9e8e76e 100644 --- a/ntp_core.h +++ b/ntp_core.h @@ -63,11 +63,25 @@ extern void NCR_ChangeRemoteAddress(NCR_Instance inst, NTP_Remote_Address *remot /* This routine is called when a new packet arrives off the network, and it relates to a source we have an ongoing protocol exchange with */ -extern int NCR_ProcessKnown(NTP_Packet *message, struct timespec *now, double now_err, NCR_Instance data, NTP_Local_Address *local_addr, int length); +extern int NCR_ProcessRxKnown(NTP_Packet *message, struct timespec *rx_ts, double rx_ts_err, + NCR_Instance inst, NTP_Local_Address *local_addr, int length); /* This routine is called when a new packet arrives off the network, and we do not recognize its source */ -extern void NCR_ProcessUnknown(NTP_Packet *message, struct timespec *now, double now_err, NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr, int length); +extern void NCR_ProcessRxUnknown(NTP_Packet *message, struct timespec *rx_ts, double rx_ts_err, + NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr, + int length); + +/* This routine is called when a packet is sent to a source we have + an ongoing protocol exchange with */ +extern void NCR_ProcessTxKnown(NTP_Packet *message, struct timespec *tx_ts, double tx_ts_err, + NCR_Instance inst, NTP_Local_Address *local_addr, int length); + +/* This routine is called when a packet is sent to a destination we + do not recognize */ +extern void NCR_ProcessTxUnknown(NTP_Packet *message, struct timespec *tx_ts, double tx_ts_err, + NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr, + int length); /* Slew receive and transmit times in instance records */ extern void NCR_SlewTimes(NCR_Instance inst, struct timespec *when, double dfreq, double doffset); diff --git a/ntp_io.c b/ntp_io.c index b688f0a..22618e9 100644 --- a/ntp_io.c +++ b/ntp_io.c @@ -548,17 +548,16 @@ NIO_IsServerSocket(int sock_fd) /* ================================================== */ static void -process_receive(struct msghdr *hdr, int length, int sock_fd) +process_message(struct msghdr *hdr, int length, int sock_fd) { NTP_Remote_Address remote_addr; NTP_Local_Address local_addr; struct cmsghdr *cmsg; - struct timespec sch_ts, rx_ts; - double sch_err, rx_err; + struct timespec local_ts, sched_ts; + double local_ts_err; - SCH_GetLastEventTime(&sch_ts, &sch_err, NULL); - rx_ts = sch_ts; - rx_err = sch_err; + SCH_GetLastEventTime(&local_ts, &local_ts_err, NULL); + sched_ts = local_ts; if (hdr->msg_namelen > sizeof (union sockaddr_in46)) { DEBUG_LOG(LOGF_NtpIO, "Truncated source address"); @@ -605,7 +604,7 @@ process_receive(struct msghdr *hdr, int length, int sock_fd) memcpy(&tv, CMSG_DATA(cmsg), sizeof(tv)); UTI_TimevalToTimespec(&tv, &ts); - LCL_CookTime(&ts, &rx_ts, &rx_err); + LCL_CookTime(&ts, &local_ts, &local_ts_err); } #endif @@ -614,23 +613,22 @@ process_receive(struct msghdr *hdr, int length, int sock_fd) struct timespec ts; memcpy(&ts, CMSG_DATA(cmsg), sizeof (ts)); - LCL_CookTime(&ts, &rx_ts, &rx_err); + LCL_CookTime(&ts, &local_ts, &local_ts_err); } #endif } - DEBUG_LOG(LOGF_NtpIO, "Received %d bytes from %s:%d to %s fd %d delay %.9f", + DEBUG_LOG(LOGF_NtpIO, "Received %d bytes from %s:%d to %s fd=%d delay=%.9f", length, UTI_IPToString(&remote_addr.ip_addr), remote_addr.port, UTI_IPToString(&local_addr.ip_addr), local_addr.sock_fd, - UTI_DiffTimespecsToDouble(&sch_ts, &rx_ts)); - + UTI_DiffTimespecsToDouble(&sched_ts, &local_ts)); /* Just ignore the packet if it's not of a recognized length */ if (length < NTP_NORMAL_PACKET_LENGTH || length > sizeof (NTP_Receive_Buffer)) return; - NSR_ProcessReceive((NTP_Packet *)hdr->msg_iov[0].iov_base, &rx_ts, rx_err, - &remote_addr, &local_addr, length); + NSR_ProcessRx((NTP_Packet *)hdr->msg_iov[0].iov_base, &local_ts, local_ts_err, + &remote_addr, &local_addr, length); } /* ================================================== */ @@ -668,7 +666,7 @@ read_from_socket(int sock_fd, int event, void *anything) for (i = 0; i < n; i++) { hdr = ARR_GetElement(recv_headers, i); - process_receive(&hdr->msg_hdr, hdr->msg_len, sock_fd); + process_message(&hdr->msg_hdr, hdr->msg_len, sock_fd); } /* Restore the buffers to their original state */ @@ -680,7 +678,7 @@ read_from_socket(int sock_fd, int event, void *anything) int NIO_SendPacket(NTP_Packet *packet, NTP_Remote_Address *remote_addr, - NTP_Local_Address *local_addr, int length) + NTP_Local_Address *local_addr, int length, int process_tx) { union sockaddr_in46 remote; struct msghdr msg; diff --git a/ntp_io.h b/ntp_io.h index cbdee56..1bdcf12 100644 --- a/ntp_io.h +++ b/ntp_io.h @@ -54,6 +54,7 @@ extern void NIO_CloseServerSocket(int sock_fd); extern int NIO_IsServerSocket(int sock_fd); /* Function to transmit a packet */ -extern int NIO_SendPacket(NTP_Packet *packet, NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr, int length); +extern int NIO_SendPacket(NTP_Packet *packet, NTP_Remote_Address *remote_addr, + NTP_Local_Address *local_addr, int length, int process_tx); #endif /* GOT_NTP_IO_H */ diff --git a/ntp_signd.c b/ntp_signd.c index 9e81f49..1469668 100644 --- a/ntp_signd.c +++ b/ntp_signd.c @@ -193,7 +193,7 @@ process_response(SignInstance *inst) /* Send the signed NTP packet */ NIO_SendPacket(&inst->response.signed_packet, &inst->remote_addr, &inst->local_addr, ntohl(inst->response.length) + sizeof (inst->response.length) - - offsetof(SigndResponse, signed_packet)); + offsetof(SigndResponse, signed_packet), 0); /* Update exponential moving average of the authentication delay */ delay = CLAMP(MIN_AUTH_DELAY, delay, MAX_AUTH_DELAY); diff --git a/ntp_sources.c b/ntp_sources.c index c5251ae..e42f32a 100644 --- a/ntp_sources.c +++ b/ntp_sources.c @@ -776,7 +776,8 @@ NSR_GetLocalRefid(IPAddr *address) /* This routine is called by ntp_io when a new packet arrives off the network, possibly with an authentication tail */ void -NSR_ProcessReceive(NTP_Packet *message, struct timespec *now, double now_err, NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr, int length) +NSR_ProcessRx(NTP_Packet *message, struct timespec *rx_ts, double rx_ts_err, + NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr, int length) { SourceRecord *record; struct SourcePool *pool; @@ -788,7 +789,7 @@ NSR_ProcessReceive(NTP_Packet *message, struct timespec *now, double now_err, NT if (found == 2) { /* Must match IP address AND port number */ record = get_record(slot); - if (!NCR_ProcessKnown(message, now, now_err, record->data, local_addr, length)) + if (!NCR_ProcessRxKnown(message, rx_ts, rx_ts_err, record->data, local_addr, length)) return; if (record->tentative) { @@ -809,7 +810,26 @@ NSR_ProcessReceive(NTP_Packet *message, struct timespec *now, double now_err, NT } } } else { - NCR_ProcessUnknown(message, now, now_err, remote_addr, local_addr, length); + NCR_ProcessRxUnknown(message, rx_ts, rx_ts_err, remote_addr, local_addr, length); + } +} + +/* ================================================== */ + +void +NSR_ProcessTx(NTP_Packet *message, struct timespec *tx_ts, double tx_ts_err, + NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr, int length) +{ + SourceRecord *record; + int slot, found; + + find_slot(remote_addr, &slot, &found); + + if (found == 2) { /* Must match IP address AND port number */ + record = get_record(slot); + NCR_ProcessTxKnown(message, tx_ts, tx_ts_err, record->data, local_addr, length); + } else { + NCR_ProcessTxUnknown(message, tx_ts, tx_ts_err, remote_addr, local_addr, length); } } diff --git a/ntp_sources.h b/ntp_sources.h index f85156b..924a7a5 100644 --- a/ntp_sources.h +++ b/ntp_sources.h @@ -87,7 +87,13 @@ extern void NSR_RefreshAddresses(void); extern uint32_t NSR_GetLocalRefid(IPAddr *address); /* This routine is called by ntp_io when a new packet arrives off the network */ -extern void NSR_ProcessReceive(NTP_Packet *message, struct timespec *now, double now_err, NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr, int length); +extern void NSR_ProcessRx(NTP_Packet *message, struct timespec *rx_ts, double tx_ts_err, + NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr, int length); + +/* This routine is called by ntp_io when a packet was sent to the network and + an accurate transmit timestamp was captured */ +extern void NSR_ProcessTx(NTP_Packet *message, struct timespec *tx_ts, double tx_ts_err, + NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr, int length); /* Initialisation function */ extern void NSR_Initialise(void);