]> git.ipfire.org Git - thirdparty/chrony.git/commitdiff
nts: rework NTS-KE retry interval
authorMiroslav Lichvar <mlichvar@redhat.com>
Wed, 25 Mar 2020 16:01:27 +0000 (17:01 +0100)
committerMiroslav Lichvar <mlichvar@redhat.com>
Thu, 26 Mar 2020 14:30:27 +0000 (15:30 +0100)
Make the NTS-KE retry interval exponentially increasing, using a factor
provided by the NKE session. Use shorter intervals when the server is
refusing TCP connections or the connection is closed or timing out
before the TLS handshake.

nts_ke.h
nts_ke_client.c
nts_ke_client.h
nts_ke_session.c
nts_ke_session.h
nts_ntp_client.c
test/unit/nts_ntp_client.c

index f00fcef15c55de754614039533e1007e167a5108..55cf47ed649ada2459b3516ddfd90a2ba76eb602 100644 (file)
--- a/nts_ke.h
+++ b/nts_ke.h
 #define NKE_MAX_COOKIES                 8
 #define NKE_MAX_KEY_LENGTH SIV_MAX_KEY_LENGTH
 
+#define NKE_RETRY_FACTOR2_CONNECT       4
+#define NKE_RETRY_FACTOR2_TLS           10
+#define NKE_MAX_RETRY_INTERVAL2         19
+
 typedef struct {
   int length;
   unsigned char key[NKE_MAX_KEY_LENGTH];
index 29421de1272af88a9a47d3e6db2bf658ab2fd536..517b06cd17e7062d3c7141de293046b900826b34 100644 (file)
@@ -393,3 +393,11 @@ NKC_GetNtsData(NKC_Instance inst,
 
   return i;
 }
+
+/* ================================================== */
+
+int
+NKC_GetRetryFactor(NKC_Instance inst)
+{
+  return NKSN_GetRetryFactor(inst->session);
+}
index 8d58775909f93e54a26c8809d6d6019a0c8c0b16..7622252b9988cc2ac1ea99cf1357c40b0b431952 100644 (file)
@@ -55,4 +55,7 @@ extern int NKC_GetNtsData(NKC_Instance inst,
                           NKE_Cookie *cookies, int *num_cookies, int max_cookies,
                           IPSockAddr *ntp_address);
 
+/* Get a factor to calculate retry interval (in log2 seconds) */
+extern int NKC_GetRetryFactor(NKC_Instance inst);
+
 #endif
index 224355f73ad4ee850c3bac51dba6fdc75deb4cb9..bd1b00126211899dde779c9cf4d542411d408a48 100644 (file)
@@ -75,6 +75,7 @@ struct NKSN_Instance_Record {
   char *label;
   gnutls_session_t tls_session;
   SCH_TimeoutID timeout_id;
+  int retry_factor;
 
   struct Message message;
   int new_message;
@@ -382,6 +383,12 @@ handle_event(NKSN_Instance inst, int event)
           LOG(inst->server ? LOGS_DEBUG : LOGS_ERR,
               "TLS handshake with %s failed : %s", inst->label, gnutls_strerror(r));
           stop_session(inst);
+
+          /* Increase the retry interval if the handshake did not fail due
+             to the other end closing the connection */
+          if (r != GNUTLS_E_PULL_ERROR && r != GNUTLS_E_PREMATURE_TERMINATION)
+            inst->retry_factor = NKE_RETRY_FACTOR2_TLS;
+
           return 0;
         }
 
@@ -391,6 +398,8 @@ handle_event(NKSN_Instance inst, int event)
         return 0;
       }
 
+      inst->retry_factor = NKE_RETRY_FACTOR2_TLS;
+
       if (DEBUG) {
         char *description = gnutls_session_get_desc(inst->tls_session);
         DEBUG_LOG("Handshake with %s completed %s",
@@ -644,6 +653,7 @@ NKSN_CreateInstance(int server_mode, const char *server_name,
   inst->label = NULL;
   inst->tls_session = NULL;
   inst->timeout_id = 0;
+  inst->retry_factor = NKE_RETRY_FACTOR2_CONNECT;
 
   return inst;
 }
@@ -677,6 +687,7 @@ NKSN_StartSession(NKSN_Instance inst, int sock_fd, const char *label,
 
   inst->label = Strdup(label);
   inst->timeout_id = SCH_AddTimeoutByDelay(timeout, session_timeout, inst);
+  inst->retry_factor = NKE_RETRY_FACTOR2_CONNECT;
 
   reset_message(&inst->message);
   inst->new_message = 0;
@@ -783,3 +794,11 @@ NKSN_StopSession(NKSN_Instance inst)
 {
   stop_session(inst);
 }
+
+/* ================================================== */
+
+int
+NKSN_GetRetryFactor(NKSN_Instance inst)
+{
+  return inst->retry_factor;
+}
index bf1b4695f87e0014eb162ed749eddc68167a8e92..49d95b4f70e761d1c493eef491549cc8d7f0f978 100644 (file)
@@ -80,4 +80,8 @@ extern int NKSN_IsStopped(NKSN_Instance inst);
 /* Stop the session */
 extern void NKSN_StopSession(NKSN_Instance inst);
 
+/* Get a factor to calculate retry interval (in log2 seconds)
+   based on the session state or how it was terminated */
+extern int NKSN_GetRetryFactor(NKSN_Instance inst);
+
 #endif
index 2feff7eea6dae5150bb9f553d7e6668d0ecfd71b..1e23f77c7338010e6975ac384b8c5e0e5221c95a 100644 (file)
@@ -54,7 +54,8 @@ struct NNC_Instance_Record {
   SIV_Instance siv_s2c;
   NKC_Instance nke;
 
-  double last_nke_attempt;
+  int nke_attempts;
+  double next_nke_attempt;
   double last_nke_success;
   NKE_Cookie cookies[NTS_MAX_COOKIES];
   int num_cookies;
@@ -70,7 +71,8 @@ struct NNC_Instance_Record {
 static void
 reset_instance(NNC_Instance inst)
 {
-  inst->last_nke_attempt = -MIN_NKE_RETRY_INTERVAL;
+  inst->nke_attempts = 0;
+  inst->next_nke_attempt = 0.0;
   inst->last_nke_success = 0.0;
   inst->num_cookies = 0;
   inst->cookie_index = 0;
@@ -167,6 +169,21 @@ set_ntp_address(NNC_Instance inst, NTP_Remote_Address *negotiated_address)
 
 /* ================================================== */
 
+static void
+update_next_nke_attempt(NNC_Instance inst, double now)
+{
+  int factor, interval;
+
+  if (!inst->nke)
+    return;
+
+  factor = NKC_GetRetryFactor(inst->nke);
+  interval = MIN(factor + inst->nke_attempts - 1, NKE_MAX_RETRY_INTERVAL2);
+  inst->next_nke_attempt = now + UTI_Log2ToDouble(interval);
+}
+
+/* ================================================== */
+
 static int
 get_nke_data(NNC_Instance inst)
 {
@@ -181,8 +198,9 @@ get_nke_data(NNC_Instance inst)
   now = SCH_GetLastEventMonoTime();
 
   if (!inst->nke) {
-    if (now - inst->last_nke_attempt < MIN_NKE_RETRY_INTERVAL) {
-      DEBUG_LOG("Limiting NTS-KE request rate");
+    if (now < inst->next_nke_attempt) {
+      DEBUG_LOG("Limiting NTS-KE request rate (%f seconds)",
+                inst->next_nke_attempt - now);
       return 0;
     }
 
@@ -194,12 +212,15 @@ get_nke_data(NNC_Instance inst)
 
     inst->nke = NKC_CreateInstance(&inst->nts_address, inst->name);
 
+    inst->nke_attempts++;
+    update_next_nke_attempt(inst, now);
+
     if (!NKC_Start(inst->nke))
       return 0;
-
-    inst->last_nke_attempt = now;
   }
 
+  update_next_nke_attempt(inst, now);
+
   if (NKC_IsActive(inst->nke))
     return 0;
 
@@ -418,7 +439,8 @@ NNC_CheckResponseAuth(NNC_Instance inst, NTP_Packet *packet,
 
   /* At this point we know the client interoperates with the server.  Allow a
      new NTS-KE session to be started as soon as the cookies run out. */
-  inst->last_nke_attempt = -MIN_NKE_RETRY_INTERVAL;
+  inst->nke_attempts = 0;
+  inst->next_nke_attempt = 0.0;
 
   return 1;
 }
index 06050f8a7436d9d93c4c0436538188cacdc36b9c..2503c2ff3b794c6776ec55ce6cbb9721c563288a 100644 (file)
@@ -85,7 +85,7 @@ get_request(NNC_Instance inst)
   TEST_CHECK(!NNC_GenerateRequestAuth(inst, &packet, &info));
 
   while (!NNC_PrepareForAuth(inst)) {
-    inst->last_nke_attempt = random() % 100000 - 50000;
+    inst->next_nke_attempt = SCH_GetLastEventMonoTime() + random() % 10 - 7;
   }
 
   TEST_CHECK(inst->num_cookies > 0);