[Git][NTPsec/ntpsec][master] Allow refclock sample processing to use 4-digit year timestamps.

Eric S. Raymond gitlab at mg.gitlab.com
Wed Aug 30 14:02:20 UTC 2017


Eric S. Raymond pushed to branch master at NTPsec / ntpsec


Commits:
472eecff by Eric S. Raymond at 2017-08-30T10:02:08-04:00
Allow refclock sample processing to use 4-digit year timestamps.

This is actually a pretty big deal.  Before this change the refclock sample
processing simply ignored the year part of timestamps passed in from, e.g.,
GPS devices.  As a defensive adaptation to devices that shipped only 2 digit
timestamps this made sense - the century was, in effect, deduced from the
receive timestamp of the sample.

But this meant that interpretation of the sample was contingent on the
system clock being correct, and bad things could happen if it was
trashed or (especially) zeroed, returning it to 1970.  After that you
couldn't use a refclock reliably until you'd already achieved time
sync with a network peer.

With this change, an ntpd receiving proper 4-digit timestamps (e.g. from
the NMEA driver) no longer needs the system clock to be correct, and can
run without remote peers.  Recovery from a trashed system clock can happen.

A unit test verifying this capability is included in the patch.

- - - - -


5 changed files:

- include/ntp_stdlib.h
- libntp/clocktime.c
- ntpd/ntp_refclock.c
- ntpd/refclock_truetime.c
- tests/libntp/clocktime.c


Changes:

=====================================
include/ntp_stdlib.h
=====================================
--- a/include/ntp_stdlib.h
+++ b/include/ntp_stdlib.h
@@ -48,7 +48,7 @@ extern	bool	authreadkeys	(const char *);
 extern	void	authtrust	(keyid_t, bool);
 extern	bool	authusekey	(keyid_t, int, const uint8_t *);
 
-extern	int	clocktime	(int, int, int, int, int, uint32_t, uint32_t *, uint32_t *);
+extern	int	clocktime	(int, int, int, int, int, int, uint32_t, uint32_t *, uint32_t *);
 extern	void	init_auth	(void);
 extern	void	init_network	(void);
 extern	void	auth_prealloc_symkeys(int);


=====================================
libntp/clocktime.c
=====================================
--- a/libntp/clocktime.c
+++ b/libntp/clocktime.c
@@ -31,9 +31,13 @@ static int32_t   ntp_to_year(uint32_t);
 static uint32_t year_to_ntp(int32_t);
 
 /*
- * Take a time spec given as day-of-year, hour, minute and second as
+ * Take a time spec given as year, day-of-year, hour, minute and second as
  * well as a GMT offset in hours and convert it to a NTP time stamp in
- * '*ts_ui'. The value will be in the range (rec_ui-0.5yrs) to
+ * '*ts_ui'.  There are two cases: ether the year is > 99, in which
+ * case it is used, or it is < 99 in which case we ignore it and try
+ * to deduce a year,
+ *
+ * The value will be in the range (rec_ui-0.5yrs) to
  * (rec_ui+0.5yrs). A hint for the current start-of-year will be
  * read from '*yearstart'.
  *
@@ -49,13 +53,14 @@ static uint32_t year_to_ntp(int32_t);
  */
 int
 clocktime(
+	int	year	 ,	/* year */
 	int	yday	 ,	/* day-of-year */
 	int	hour	 ,	/* hour of day */
 	int	minute	 ,	/* minute of hour */
 	int	second	 ,	/* second of minute */
 	int	tzoff	 ,	/* hours west of GMT */
 	uint32_t rec_ui	 ,	/* pivot value */
-	uint32_t *yearstart,	/* cached start-of-year */
+	uint32_t *yearstart,	/* cached start-of-year, secs from NTP epoch */
 	uint32_t *ts_ui	 )	/* effective time stamp */
 {
 	uint32_t ystt[3];	/* year start */
@@ -72,6 +77,19 @@ clocktime(
 			     MINSPERHR * ((int32_t)hour + (int32_t)tzoff +
 					  HRSPERDAY * ((int32_t)yday - 1))));
 	/*
+	 * Year > 1970 - from a 4-digit year stamp, must be greater
+	 * than POSIX epoch. Means we're not dependent on the pivot
+	 * value (derived from the packet receipt timestamp, and thus
+	 * ultimately from the system clock) to be correct.  These
+	 * two lines thus make it possible to recover from a trashed
+	 * or zeroed system clock.
+	 */
+	if (year > 1970)
+	    *yearstart = year_to_ntp(year);
+
+        /*
+	 * Year was too small to make sense, probably from a 2-digit
+	 * year stamp.
 	 * Based on the cached year start, do a first attempt. Be
 	 * happy and return if this gets us better than NEARTIME to
 	 * the receive time stamp. Do this only if the cached year


=====================================
ntpd/ntp_refclock.c
=====================================
--- a/ntpd/ntp_refclock.c
+++ b/ntpd/ntp_refclock.c
@@ -409,7 +409,7 @@ refclock_process_f(
 	 * filesystem time for the years and does not use the years of
 	 * the timecode.
 	 */
-	if (!clocktime(pp->day, pp->hour, pp->minute, pp->second, GMT,
+	if (!clocktime(pp->year, pp->day, pp->hour, pp->minute, pp->second, GMT,
 		       lfpuint(pp->lastrec), &pp->yearstart, &sec))
 		return false;
 


=====================================
ntpd/refclock_truetime.c
=====================================
--- a/ntpd/refclock_truetime.c
+++ b/ntpd/refclock_truetime.c
@@ -491,7 +491,7 @@ true_receive(
 			 * find out what time it really is. Include
 			 * the count from the PCL720
 			 */
-			if (!clocktime(pp->day, pp->hour, pp->minute, 
+			if (!clocktime(pp->year, pp->day, pp->hour, pp->minute,
 				       pp->second, GMT, lfpuint(pp->lastrec),
 				       &pp->yearstart, &sec)) {
 				refclock_report(peer, CEVNT_BADTIME);


=====================================
tests/libntp/clocktime.c
=====================================
--- a/tests/libntp/clocktime.c
+++ b/tests/libntp/clocktime.c
@@ -29,18 +29,35 @@ TEST_TEAR_DOWN(clocktime) {
 // test cases
 
 TEST(clocktime, CurrentYear) {
-	// Timestamp: 2010-06-24 12:50:00Z
+	// Timestamp: 2010-06-24 12:50:00Z, no year passed in
 	const uint32_t timestamp = 3486372600UL;
 	const uint32_t expected	= timestamp; // exactly the same.
 
-	const int yday=175, hour=12, minute=50, second=0, tzoff=0;
+	const int year=0, yday=175, hour=12, minute=50, second=0, tzoff=0;
 
 	uint32_t yearstart=0;
 	uint32_t actual;
 
-	TEST_ASSERT_TRUE(clocktime(yday, hour, minute, second, tzoff, timestamp,
-						  &yearstart, &actual));
+	TEST_ASSERT_TRUE(clocktime(year, yday, hour, minute, second,
+				   tzoff, timestamp, &yearstart, &actual));
 	TEST_ASSERT_EQUAL(expected, actual);
+	TEST_ASSERT_EQUAL(yearstart, 3471292800);
+}
+
+TEST(clocktime, CurrentYearExplicit) {
+	// Timestamp: 2010-06-24 12:50:00Z, explicit year passed in
+	const uint32_t timestamp = 3486372600UL;
+	const uint32_t expected	= timestamp; // exactly the same.
+
+	const int year=2010, yday=175, hour=12, minute=50, second=0, tzoff=0;
+
+	uint32_t yearstart=0;
+	uint32_t actual;
+
+	TEST_ASSERT_TRUE(clocktime(year, yday, hour, minute, second,
+				   tzoff, timestamp, &yearstart, &actual));
+	TEST_ASSERT_EQUAL(expected, actual);
+	TEST_ASSERT_EQUAL(yearstart, 3471292800);
 }
 
 TEST(clocktime, CurrentYearFuzz) {
@@ -55,13 +72,13 @@ TEST(clocktime, CurrentYearFuzz) {
 	const uint32_t timestamp = 3486372600UL; // 2010-06-24 12:50:00Z
 	const uint32_t expected	= 3486369600UL; // 2010-06-24 12:00:00Z
 
-	const int yday=175, hour=12, minute=0, second=0, tzoff=0;
+	const int year=0, yday=175, hour=12, minute=0, second=0, tzoff=0;
 
 	uint32_t yearstart=0;
 	uint32_t actual;
 
-	TEST_ASSERT_TRUE(clocktime(yday, hour, minute, second, tzoff, timestamp,
-						  &yearstart, &actual));
+	TEST_ASSERT_TRUE(clocktime(year, yday, hour, minute, second,
+				   tzoff, timestamp, &yearstart, &actual));
 	TEST_ASSERT_EQUAL(expected, actual);
 }
 
@@ -75,13 +92,13 @@ TEST(clocktime, TimeZoneOffset) {
 	const uint32_t timestamp = 3486369600UL;
 	const uint32_t expected	= timestamp;
 
-	const int yday=175, hour=4, minute=0, second=0, tzoff=8;
+	const int year=0, yday=175, hour=4, minute=0, second=0, tzoff=8;
 
 	uint32_t yearstart=0;
 	uint32_t actual;
 
-	TEST_ASSERT_TRUE(clocktime(yday, hour, minute, second, tzoff, timestamp,
-						  &yearstart, &actual));
+	TEST_ASSERT_TRUE(clocktime(year, yday, hour, minute, second,
+				   tzoff, timestamp, &yearstart, &actual));
 	TEST_ASSERT_EQUAL(expected, actual);
 }
 
@@ -94,13 +111,13 @@ TEST(clocktime, WrongYearStart) {
 	const uint32_t timestamp = 3471418800UL;
 	const uint32_t expected	= timestamp;
 
-	const int yday=2, hour=11, minute=0, second=0, tzoff=0;
+	const int year=0, yday=2, hour=11, minute=0, second=0, tzoff=0;
 
 	uint32_t yearstart = 302024100UL; // Yearstart of 2009.
 	uint32_t actual;
 
-	TEST_ASSERT_TRUE(clocktime(yday, hour, minute, second, tzoff, timestamp,
-						  &yearstart, &actual));
+	TEST_ASSERT_TRUE(clocktime(year, yday, hour, minute, second,
+				   tzoff, timestamp, &yearstart, &actual));
 	TEST_ASSERT_EQUAL(expected, actual);
 }
 
@@ -113,13 +130,13 @@ TEST(clocktime, PreviousYear) {
 	const uint32_t timestamp = 3471296400UL;
 	const uint32_t expected	= 3471289200UL;
 
-	const int yday=365, hour=23, minute=0, second=0, tzoff=0;
+	const int year=0, yday=365, hour=23, minute=0, second=0, tzoff=0;
 
 	uint32_t yearstart = 0;
 	uint32_t actual;
 
-	TEST_ASSERT_TRUE(clocktime(yday, hour, minute, second, tzoff, timestamp,
-						  &yearstart, &actual));
+	TEST_ASSERT_TRUE(clocktime(year, yday, hour, minute, second,
+				   tzoff, timestamp, &yearstart, &actual));
 	TEST_ASSERT_EQUAL(expected, actual);
 }
 
@@ -132,12 +149,12 @@ TEST(clocktime, NextYear) {
 	const uint32_t timestamp = 3471289200UL;
 	const uint32_t expected	= 3471296400UL;
 
-	const int yday=1, hour=1, minute=0, second=0, tzoff=0;
+	const int year=0, yday=1, hour=1, minute=0, second=0, tzoff=0;
 	uint32_t yearstart = 0;
 	uint32_t actual;
 
-	TEST_ASSERT_TRUE(clocktime(yday, hour, minute, second, tzoff, timestamp,
-						  &yearstart, &actual));
+	TEST_ASSERT_TRUE(clocktime(year, yday, hour, minute, second,
+				   tzoff, timestamp, &yearstart, &actual));
 	TEST_ASSERT_EQUAL(expected, actual);
 }
 
@@ -145,12 +162,12 @@ TEST(clocktime, NoReasonableConversion) {
 	/* Timestamp is: 2010-01-02 11:00:00Z */
 	const uint32_t timestamp = 3471418800UL;
 
-	const int yday=100, hour=12, minute=0, second=0, tzoff=0;
+	const int year=0, yday=100, hour=12, minute=0, second=0, tzoff=0;
 	uint32_t yearstart = 0;
 	uint32_t actual;
 
-	TEST_ASSERT_FALSE(clocktime(yday, hour, minute, second, tzoff, timestamp,
-						   &yearstart, &actual));
+	TEST_ASSERT_FALSE(clocktime(year, yday, hour, minute, second,
+				    tzoff, timestamp, &yearstart, &actual));
 }
 
 TEST(clocktime, AlwaysInLimit) {
@@ -175,7 +192,7 @@ TEST(clocktime, AlwaysInLimit) {
 			ydayinc = prime_incs[whichprime];
 			for (hour = -204; hour < 204; hour += 2) {
 				for (minute = -60; minute < 60; minute++) {
-					clocktime(yday, hour, minute, 30, 0,
+				    clocktime(0, yday, hour, minute, 30, 0,
 						  timestamp, &yearstart, &actual);
 					diff = actual - timestamp;
 					if (diff >= 0x80000000UL) {
@@ -190,6 +207,7 @@ TEST(clocktime, AlwaysInLimit) {
 
 TEST_GROUP_RUNNER(clocktime) {
 	RUN_TEST_CASE(clocktime, CurrentYear);
+	RUN_TEST_CASE(clocktime, CurrentYearExplicit);
 	RUN_TEST_CASE(clocktime, CurrentYearFuzz);
 	RUN_TEST_CASE(clocktime, TimeZoneOffset);
 	RUN_TEST_CASE(clocktime, WrongYearStart);



View it on GitLab: https://gitlab.com/NTPsec/ntpsec/commit/472eecff48f9d203d785667bf39995b4f4f51bf1

---
View it on GitLab: https://gitlab.com/NTPsec/ntpsec/commit/472eecff48f9d203d785667bf39995b4f4f51bf1
You're receiving this email because of your account on gitlab.com.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.ntpsec.org/pipermail/vc/attachments/20170830/a70b705f/attachment.html>


More information about the vc mailing list