nts: rework NTS-KE retry interval

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.
This commit is contained in:
Miroslav Lichvar 2020-03-25 17:01:27 +01:00
parent bcdbbbd694
commit 66dc2b6d6b
7 changed files with 68 additions and 8 deletions

View file

@ -56,6 +56,10 @@
#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];

View file

@ -393,3 +393,11 @@ NKC_GetNtsData(NKC_Instance inst,
return i;
}
/* ================================================== */
int
NKC_GetRetryFactor(NKC_Instance inst)
{
return NKSN_GetRetryFactor(inst->session);
}

View 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

View 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;
}

View 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

View 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;
}

View 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);