371a1e
From 348947b3d573e2187db61fb43919d2260dcfc135 Mon Sep 17 00:00:00 2001
1050b1
From: Pavel Zhukov <pzhukov@redhat.com>
1050b1
Date: Wed, 24 Jul 2019 17:15:55 +0200
1050b1
Subject: [PATCH] Detect system time jumps
1050b1
1050b1
In case if system time was changed backward it's possible to have ip
1050b1
address dropped by the kernel due to lifetime expirity. Try to detect
1050b1
this situation using either monotonic time or saved timestamp and execute
1050b1
go_reboot() procedure to request lease extention
1050b1
---
371a1e
 lib/isc/include/isc/result.h    |  3 ++-
371a1e
 lib/isc/include/isc/util.h      |  3 +++
1050b1
 lib/isc/result.c                |  2 ++
371a1e
 lib/isc/unix/app.c              | 39 +++++++++++++++++++++++++++++----
371a1e
 lib/isc/unix/include/isc/time.h | 20 +++++++++++++++++
371a1e
 lib/isc/unix/time.c             | 22 +++++++++++++++++++
371a1e
 6 files changed, 84 insertions(+), 5 deletions(-)
1050b1
1050b1
diff --git a/lib/isc/include/isc/result.h b/lib/isc/include/isc/result.h
371a1e
index 0fd4971..2add549 100644
1050b1
--- a/lib/isc/include/isc/result.h
1050b1
+++ b/lib/isc/include/isc/result.h
371a1e
@@ -87,9 +87,10 @@
371a1e
 #define ISC_R_CRYPTOFAILURE		65	/*%< cryptography library failure */
371a1e
 #define ISC_R_DISCQUOTA			66	/*%< disc quota */
371a1e
 #define ISC_R_DISCFULL			67	/*%< disc full */
371a1e
+#define ISC_R_TIMESHIFTED               68      /*%< system time changed */
371a1e
 
1050b1
 /*% Not a result code: the number of results. */
371a1e
-#define ISC_R_NRESULTS 			68
371a1e
+#define ISC_R_NRESULTS 			69
1050b1
 
1050b1
 ISC_LANG_BEGINDECLS
1050b1
 
1050b1
diff --git a/lib/isc/include/isc/util.h b/lib/isc/include/isc/util.h
371a1e
index 973c348..8160dd3 100644
1050b1
--- a/lib/isc/include/isc/util.h
1050b1
+++ b/lib/isc/include/isc/util.h
371a1e
@@ -289,6 +289,9 @@ extern void mock_assert(const int result, const char* const expression,
1050b1
  * Time
1050b1
  */
1050b1
 #define TIME_NOW(tp) 	RUNTIME_CHECK(isc_time_now((tp)) == ISC_R_SUCCESS)
1050b1
+#ifdef CLOCK_BOOTTIME
1050b1
+#define TIME_MONOTONIC(tp) 	RUNTIME_CHECK(isc_time_boottime((tp)) == ISC_R_SUCCESS)
1050b1
+#endif
1050b1
 
1050b1
 /*%
371a1e
  * Alignment
1050b1
diff --git a/lib/isc/result.c b/lib/isc/result.c
371a1e
index abb6ed2..8c95a93 100644
1050b1
--- a/lib/isc/result.c
1050b1
+++ b/lib/isc/result.c
371a1e
@@ -103,6 +103,7 @@ static const char *description[ISC_R_NRESULTS] = {
371a1e
 	"crypto failure",			/*%< 65 */
371a1e
 	"disc quota",				/*%< 66 */
371a1e
 	"disc full",				/*%< 67 */
371a1e
+        "time changed",                         /*%< 68 */
1050b1
 };
1050b1
 
1050b1
 static const char *identifier[ISC_R_NRESULTS] = {
371a1e
@@ -174,6 +175,7 @@ static const char *identifier[ISC_R_NRESULTS] = {
371a1e
 	"ISC_R_CRYPTOFAILURE",
371a1e
 	"ISC_R_DISCQUOTA",
371a1e
 	"ISC_R_DISCFULL",
1050b1
+        "ISC_R_TIMESHIFTED",
1050b1
 };
1050b1
 
1050b1
 #define ISC_RESULT_RESULTSET			2
1050b1
diff --git a/lib/isc/unix/app.c b/lib/isc/unix/app.c
371a1e
index 7e5a0ee..ceab74e 100644
1050b1
--- a/lib/isc/unix/app.c
1050b1
+++ b/lib/isc/unix/app.c
371a1e
@@ -442,15 +442,48 @@ isc__app_ctxonrun(isc_appctx_t *ctx0, isc_mem_t *mctx, isc_task_t *task,
1050b1
 static isc_result_t
1050b1
 evloop(isc__appctx_t *ctx) {
1050b1
 	isc_result_t result;
1050b1
+        isc_time_t now;
1050b1
+#ifdef CLOCK_BOOTTIME
1050b1
+        isc_time_t monotonic;
371a1e
+        uint64_t diff  = 0;
1050b1
+#else
1050b1
+        isc_time_t prev;
1050b1
+        TIME_NOW(&prev;;
1050b1
+#endif
1050b1
+
1050b1
+
1050b1
 
1050b1
 	while (!ctx->want_shutdown) {
1050b1
 		int n;
1050b1
-		isc_time_t when, now;
1050b1
+		isc_time_t when;
1050b1
 		struct timeval tv, *tvp;
1050b1
 		isc_socketwait_t *swait;
371a1e
 		bool readytasks;
371a1e
 		bool call_timer_dispatch = false;
371a1e
-
371a1e
+                uint64_t us;
1050b1
+
1050b1
+#ifdef CLOCK_BOOTTIME
1050b1
+                // TBD macros for following three lines
1050b1
+                TIME_NOW(&now;;
1050b1
+                TIME_MONOTONIC(&monotonic);
1050b1
+                INSIST(now.seconds > monotonic.seconds)
1050b1
+                us = isc_time_microdiff (&now, &monotonic);
371a1e
+                if (us < diff){
1050b1
+                  us = diff - us;
1050b1
+                  if (us > 1000000){ // ignoring shifts less than one second
1050b1
+                    return ISC_R_TIMESHIFTED;
1050b1
+                  };
1050b1
+                  diff = isc_time_microdiff (&now, &monotonic);
1050b1
+                } else {
1050b1
+                  diff = isc_time_microdiff (&now, &monotonic);
1050b1
+                  // not implemented
1050b1
+                }
1050b1
+#else
1050b1
+                TIME_NOW(&now;;
1050b1
+                if (isc_time_compare (&now, &prev) < 0)
1050b1
+                  return ISC_R_TIMESHIFTED;
1050b1
+                TIME_NOW(&prev;;
371a1e
+#endif
1050b1
 		/*
1050b1
 		 * Check the reload (or suspend) case first for exiting the
1050b1
 		 * loop as fast as possible in case:
371a1e
@@ -475,8 +508,6 @@ evloop(isc__appctx_t *ctx) {
1050b1
 			if (result != ISC_R_SUCCESS)
1050b1
 				tvp = NULL;
1050b1
 			else {
371a1e
-				uint64_t us;
371a1e
-
1050b1
 				TIME_NOW(&now;;
1050b1
 				us = isc_time_microdiff(&when, &now;;
1050b1
 				if (us == 0)
1050b1
diff --git a/lib/isc/unix/include/isc/time.h b/lib/isc/unix/include/isc/time.h
371a1e
index b864c29..5dd43c9 100644
1050b1
--- a/lib/isc/unix/include/isc/time.h
1050b1
+++ b/lib/isc/unix/include/isc/time.h
371a1e
@@ -132,6 +132,26 @@ isc_time_isepoch(const isc_time_t *t);
1050b1
  *\li	't' is a valid pointer.
1050b1
  */
1050b1
 
1050b1
+#ifdef CLOCK_BOOTTIME
1050b1
+isc_result_t
1050b1
+isc_time_boottime(isc_time_t *t);
1050b1
+/*%<
1050b1
+ * Set 't' to monotonic time from previous boot
1050b1
+ * it's not affected by system time change. It also
1050b1
+ * includes the time system was suspended
1050b1
+ *
1050b1
+ * Requires:
1050b1
+ *\li	't' is a valid pointer.
1050b1
+ *
1050b1
+ * Returns:
1050b1
+ *
1050b1
+ *\li	Success
1050b1
+ *\li	Unexpected error
1050b1
+ *		Getting the time from the system failed.
1050b1
+ */
1050b1
+#endif /* CLOCK_BOOTTIME */
1050b1
+ 
1050b1
+
1050b1
 isc_result_t
1050b1
 isc_time_now(isc_time_t *t);
1050b1
 /*%<
1050b1
diff --git a/lib/isc/unix/time.c b/lib/isc/unix/time.c
371a1e
index 8edc9df..fe0bb91 100644
1050b1
--- a/lib/isc/unix/time.c
1050b1
+++ b/lib/isc/unix/time.c
371a1e
@@ -498,3 +498,25 @@ isc_time_formatISO8601ms(const isc_time_t *t, char *buf, unsigned int len) {
1050b1
 			 t->nanoseconds / NS_PER_MS);
1050b1
 	}
1050b1
 }
1050b1
+
1050b1
+
1050b1
+#ifdef CLOCK_BOOTTIME
1050b1
+isc_result_t
1050b1
+isc_time_boottime(isc_time_t *t) {
1050b1
+  struct timespec ts;
1050b1
+  
1050b1
+  char strbuf[ISC_STRERRORSIZE];
1050b1
+
1050b1
+  if (clock_gettime (CLOCK_BOOTTIME, &ts) != 0){
1050b1
+    isc__strerror(errno, strbuf, sizeof(strbuf));
1050b1
+    UNEXPECTED_ERROR(__FILE__, __LINE__, "%s", strbuf);
1050b1
+    return (ISC_R_UNEXPECTED);    
1050b1
+  }
1050b1
+
1050b1
+  t->seconds = ts.tv_sec;
1050b1
+  t->nanoseconds = ts.tv_nsec;
1050b1
+
1050b1
+  return (ISC_R_SUCCESS);
1050b1
+  
1050b1
+};
1050b1
+#endif
1050b1
-- 
1050b1
2.20.1
1050b1