Detect system time change to avoid lease expirity

This commit is contained in:
Pavel Zhukov 2019-07-12 08:42:03 +02:00
parent b90ab3805f
commit 526575adf5
2 changed files with 291 additions and 2 deletions

View File

@ -0,0 +1,284 @@
From 32a891273f44ee1ca202c65c40beb508d1b2aa80 Mon Sep 17 00:00:00 2001
From: Pavel Zhukov <pzhukov@redhat.com>
Date: Thu, 11 Jul 2019 17:43:00 +0200
Subject: [PATCH] Detect system time jumps
Cc: pzhukov@redhat.com
In case if system time was changed backward it's possible to have ip
address dropped by the kernel due to lifetime expirity. Try to detect
this situation using either monotonic time or saved timestamp and execute
go_reboot() procedure to request lease extention
---
bind/bind-9.11.2-P1/lib/isc/include/isc/result.h | 4 +--
bind/bind-9.11.2-P1/lib/isc/include/isc/util.h | 4 +++
bind/bind-9.11.2-P1/lib/isc/result.c | 2 ++
bind/bind-9.11.2-P1/lib/isc/unix/app.c | 41 ++++++++++++++++++++--
.../bind-9.11.2-P1/lib/isc/unix/include/isc/time.h | 20 +++++++++++
bind/bind-9.11.2-P1/lib/isc/unix/time.c | 22 ++++++++++++
client/dhclient.c | 6 ++++
common/dispatch.c | 11 +++++-
includes/dhcpd.h | 3 +-
server/dhcpd.c | 6 ++++
10 files changed, 113 insertions(+), 6 deletions(-)
diff --git a/bind/bind-9.11.2-P1/lib/isc/include/isc/result.h b/bind/bind-9.11.2-P1/lib/isc/include/isc/result.h
index 6f7ecf2..c7ef53c 100644
--- a/bind/bind-9.11.2-P1/lib/isc/include/isc/result.h
+++ b/bind/bind-9.11.2-P1/lib/isc/include/isc/result.h
@@ -81,9 +81,9 @@
#define ISC_R_UNSET 61 /*%< unset */
#define ISC_R_MULTIPLE 62 /*%< multiple */
#define ISC_R_WOULDBLOCK 63 /*%< would block */
-
+#define ISC_R_TIMESHIFTED 64 /*%< system time changed */
/*% Not a result code: the number of results. */
-#define ISC_R_NRESULTS 64
+#define ISC_R_NRESULTS 66
ISC_LANG_BEGINDECLS
diff --git a/bind/bind-9.11.2-P1/lib/isc/include/isc/util.h b/bind/bind-9.11.2-P1/lib/isc/include/isc/util.h
index f2cda26..9d54396 100644
--- a/bind/bind-9.11.2-P1/lib/isc/include/isc/util.h
+++ b/bind/bind-9.11.2-P1/lib/isc/include/isc/util.h
@@ -238,6 +238,10 @@
* Time
*/
#define TIME_NOW(tp) RUNTIME_CHECK(isc_time_now((tp)) == ISC_R_SUCCESS)
+#ifdef CLOCK_BOOTTIME
+#define TIME_MONOTONIC(tp) RUNTIME_CHECK(isc_time_boottime((tp)) == ISC_R_SUCCESS)
+#endif
+
/*%
* Misc.
diff --git a/bind/bind-9.11.2-P1/lib/isc/result.c b/bind/bind-9.11.2-P1/lib/isc/result.c
index 071dac0..e362735 100644
--- a/bind/bind-9.11.2-P1/lib/isc/result.c
+++ b/bind/bind-9.11.2-P1/lib/isc/result.c
@@ -96,6 +96,7 @@ static const char *description[ISC_R_NRESULTS] = {
"unset", /*%< 61 */
"multiple", /*%< 62 */
"would block", /*%< 63 */
+ "time changed", /*%< 64 */
};
static const char *identifier[ISC_R_NRESULTS] = {
@@ -163,6 +164,7 @@ static const char *identifier[ISC_R_NRESULTS] = {
"ISC_R_UNSET",
"ISC_R_MULTIPLE",
"ISC_R_WOULDBLOCK",
+ "ISC_R_TIMESHIFTED",
};
#define ISC_RESULT_RESULTSET 2
diff --git a/bind/bind-9.11.2-P1/lib/isc/unix/app.c b/bind/bind-9.11.2-P1/lib/isc/unix/app.c
index 5546922..7d95ad5 100644
--- a/bind/bind-9.11.2-P1/lib/isc/unix/app.c
+++ b/bind/bind-9.11.2-P1/lib/isc/unix/app.c
@@ -438,15 +438,51 @@ isc__app_ctxonrun(isc_appctx_t *ctx0, isc_mem_t *mctx, isc_task_t *task,
static isc_result_t
evloop(isc__appctx_t *ctx) {
isc_result_t result;
+ isc_time_t now;
+#ifdef CLOCK_BOOTTIME
+ isc_time_t monotonic;
+ isc_uint64_t diff = 0;
+#else
+ isc_time_t prev;
+ TIME_NOW(&prev);
+#endif
+
+
+
while (!ctx->want_shutdown) {
int n;
- isc_time_t when, now;
+ isc_time_t when;
+
struct timeval tv, *tvp;
isc_socketwait_t *swait;
isc_boolean_t readytasks;
isc_boolean_t call_timer_dispatch = ISC_FALSE;
+ isc_uint64_t us;
+
+#ifdef CLOCK_BOOTTIME
+ // TBD macros for following three lines
+ TIME_NOW(&now);
+ TIME_MONOTONIC(&monotonic);
+ INSIST(now.seconds > monotonic.seconds)
+ us = isc_time_microdiff (&now, &monotonic);
+ if (us < diff){
+ us = diff - us;
+ if (us > 1000000){ // ignoring shifts less than one second
+ return ISC_R_TIMESHIFTED;
+ };
+ diff = isc_time_microdiff (&now, &monotonic);
+ } else {
+ diff = isc_time_microdiff (&now, &monotonic);
+ // not implemented
+ }
+#else
+ TIME_NOW(&now);
+ if (isc_time_compare (&now, &prev) < 0)
+ return ISC_R_TIMESHIFTED;
+ TIME_NOW(&prev);
+#endif
/*
* Check the reload (or suspend) case first for exiting the
* loop as fast as possible in case:
@@ -471,9 +507,10 @@ evloop(isc__appctx_t *ctx) {
if (result != ISC_R_SUCCESS)
tvp = NULL;
else {
- isc_uint64_t us;
+
TIME_NOW(&now);
+
us = isc_time_microdiff(&when, &now);
if (us == 0)
call_timer_dispatch = ISC_TRUE;
diff --git a/bind/bind-9.11.2-P1/lib/isc/unix/include/isc/time.h b/bind/bind-9.11.2-P1/lib/isc/unix/include/isc/time.h
index 939db5d..e798ee6 100644
--- a/bind/bind-9.11.2-P1/lib/isc/unix/include/isc/time.h
+++ b/bind/bind-9.11.2-P1/lib/isc/unix/include/isc/time.h
@@ -127,6 +127,26 @@ isc_time_isepoch(const isc_time_t *t);
*\li 't' is a valid pointer.
*/
+#ifdef CLOCK_BOOTTIME
+isc_result_t
+isc_time_boottime(isc_time_t *t);
+/*%<
+ * Set 't' to monotonic time from previous boot
+ * it's not affected by system time change. It also
+ * includes the time system was suspended
+ *
+ * Requires:
+ *\li 't' is a valid pointer.
+ *
+ * Returns:
+ *
+ *\li Success
+ *\li Unexpected error
+ * Getting the time from the system failed.
+ */
+#endif /* CLOCK_BOOTTIME */
+
+
isc_result_t
isc_time_now(isc_time_t *t);
/*%<
diff --git a/bind/bind-9.11.2-P1/lib/isc/unix/time.c b/bind/bind-9.11.2-P1/lib/isc/unix/time.c
index 5900846..1197337 100644
--- a/bind/bind-9.11.2-P1/lib/isc/unix/time.c
+++ b/bind/bind-9.11.2-P1/lib/isc/unix/time.c
@@ -452,3 +452,25 @@ isc_time_formatISO8601ms(const isc_time_t *t, char *buf, unsigned int len) {
t->nanoseconds / NS_PER_MS);
}
}
+
+
+#ifdef CLOCK_BOOTTIME
+isc_result_t
+isc_time_boottime(isc_time_t *t) {
+ struct timespec ts;
+
+ char strbuf[ISC_STRERRORSIZE];
+
+ if (clock_gettime (CLOCK_BOOTTIME, &ts) != 0){
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__, "%s", strbuf);
+ return (ISC_R_UNEXPECTED);
+ }
+
+ t->seconds = ts.tv_sec;
+ t->nanoseconds = ts.tv_nsec;
+
+ return (ISC_R_SUCCESS);
+
+};
+#endif
diff --git a/client/dhclient.c b/client/dhclient.c
index 4e5546a..6085b8e 100644
--- a/client/dhclient.c
+++ b/client/dhclient.c
@@ -5398,6 +5398,12 @@ isc_result_t dhcp_set_control_state (control_object_state_t oldstate,
case server_awaken:
state_reboot (client);
break;
+
+ case server_time_changed:
+ if (client->active){
+ state_reboot (client);
+ }
+ break;
}
}
}
diff --git a/common/dispatch.c b/common/dispatch.c
index d7fe200..8a24499 100644
--- a/common/dispatch.c
+++ b/common/dispatch.c
@@ -118,7 +118,6 @@ dispatch(void)
* signal. It will return ISC_R_RELOAD in that
* case. That is a normal behavior.
*/
-
if (status == ISC_R_RELOAD) {
/*
* dhcp_set_control_state() will do the job.
@@ -129,6 +128,16 @@ dispatch(void)
if (status == ISC_R_SUCCESS)
status = ISC_R_RELOAD;
}
+
+
+ if (status == ISC_R_TIMESHIFTED){
+ status = dhcp_set_control_state(server_time_changed,
+ server_time_changed);
+ status = ISC_R_RELOAD;
+ log_info ("System time has been changed. Unable to use existing leases. Restarting");
+ // do nothing, restart context
+ };
+
} while (status == ISC_R_RELOAD);
log_fatal ("Dispatch routine failed: %s -- exiting",
diff --git a/includes/dhcpd.h b/includes/dhcpd.h
index 635c510..ec6c227 100644
--- a/includes/dhcpd.h
+++ b/includes/dhcpd.h
@@ -524,7 +524,8 @@ typedef enum {
server_running = 1,
server_shutdown = 2,
server_hibernate = 3,
- server_awaken = 4
+ server_awaken = 4,
+ server_time_changed = 5
} control_object_state_t;
typedef struct {
diff --git a/server/dhcpd.c b/server/dhcpd.c
index e06f6b4..778ef8d 100644
--- a/server/dhcpd.c
+++ b/server/dhcpd.c
@@ -1779,6 +1779,12 @@ isc_result_t dhcp_set_control_state (control_object_state_t oldstate,
{
struct timeval tv;
+ if (newstate == server_time_changed){
+ log_error ("System time has been changed. Leases information unreliable!");
+ return ISC_R_SUCCESS;
+ }
+
+
if (newstate != server_shutdown)
return DHCP_R_INVALIDARG;
/* Re-entry. */
--
2.14.5

View File

@ -15,7 +15,7 @@
Summary: Dynamic host configuration protocol software
Name: dhcp
Version: 4.4.1
Release: 13%{?dist}
Release: 14%{?dist}
# NEVER CHANGE THE EPOCH on this package. The previous maintainer (prior to
# dcantrell maintaining the package) made incorrect use of the epoch and
# that's why it is at 12 now. It should have never been used, but it was.
@ -56,6 +56,8 @@ Patch20: 0020-Discover-all-hwaddress-for-xid-uniqueness.patch
Patch21: 0021-Load-leases-DB-in-non-replay-mode-only.patch
Patch22: 0022-Backport-sd-notify-patch-for-systemd-support-1687040.patch
Patch999: 0023-Detect-system-time-jumps.patch
BuildRequires: autoconf
@ -256,7 +258,7 @@ make -j1
%if ! 0%{?_module_build}
pushd doc
make -j1 devel
make %{?_smp_mflags} devel
popd
%endif
@ -521,6 +523,9 @@ done
%endif
%changelog
* Thu Jul 11 2019 Pavel Zhukov <pzhukov@redhat.com> - 12:4.4.1-14
- Detect time change and request lease renewal
* Mon May 20 2019 Pavel Zhukov <pzhukov@redhat.com> - 12:4.4.1-13
- Unpack bind prior to patching
- Provide noarch libs