Home | History | Annotate | Download | only in events
      1 /*
      2  * kickoff_time_sync.c - network time synchronization
      3  * Copyright (c) 2013 The Chromium Authors. All rights reserved.
      4  * Use of this source code is governed by a BSD-style license that can be
      5  * found in the LICENSE file.
      6  */
      7 
      8 #include "config.h"
      9 
     10 #ifdef USE_POLARSSL
     11 #include <polarssl/entropy.h>
     12 #include <polarssl/ctr_drbg.h>
     13 #else
     14 #include <openssl/rand.h>
     15 #endif
     16 #include <stdlib.h>
     17 #include <time.h>
     18 #include <unistd.h>
     19 #include <event2/event.h>
     20 
     21 #include "src/conf.h"
     22 #include "src/util.h"
     23 #include "src/tlsdate.h"
     24 
     25 #ifdef USE_POLARSSL
     26 static int random_init = 0;
     27 static entropy_context entropy;
     28 static ctr_drbg_context ctr_drbg;
     29 static char *pers = "tlsdated";
     30 #endif
     31 
     32 int
     33 add_jitter (int base, int jitter)
     34 {
     35   int n = 0;
     36   if (!jitter)
     37     return base;
     38 #ifdef USE_POLARSSL
     39   if (0 == random_init)
     40   {
     41     entropy_init(&entropy);
     42     if (0 > ctr_drbg_init(&ctr_drbg, entropy_func, &entropy,
     43                           (unsigned char *) pers, strlen(pers)))
     44     {
     45       pfatal ("Failed to initialize random source");
     46     }
     47     random_init = 1;
     48   }
     49   if (0 != ctr_drbg_random(&ctr_drbg, (unsigned char *)&n, sizeof(n)))
     50     fatal ("ctr_drbg_random() failed");
     51 #else
     52   if (RAND_bytes ( (unsigned char *) &n, sizeof (n)) != 1)
     53     fatal ("RAND_bytes() failed");
     54 #endif
     55   return base + (abs (n) % (2 * jitter)) - jitter;
     56 }
     57 
     58 void
     59 invalidate_time (struct state *state)
     60 {
     61   state->last_sync_type = SYNC_TYPE_RTC;
     62   state->last_time = time (NULL);
     63   /* Note(!) this does not invalidate the clock_delta implicitly.
     64    * This allows forced invalidation to not lose synchronization
     65    * data.
     66    */
     67 }
     68 
     69 void
     70 action_invalidate_time (evutil_socket_t fd, short what, void *arg)
     71 {
     72   struct state *state = arg;
     73   verb_debug ("[event:%s] fired", __func__);
     74   /* If time is already invalid and being acquired, do nothing. */
     75   if (state->last_sync_type == SYNC_TYPE_RTC &&
     76       event_pending (state->events[E_TLSDATE], EV_TIMEOUT, NULL))
     77     return;
     78   /* Time out our trust in network synchronization but don't persist
     79    * the change to disk or notify the system.  Let a network sync
     80    * failure or success do that.
     81    */
     82   invalidate_time (state);
     83   /* Then trigger a network sync if possible. */
     84   action_kickoff_time_sync (-1, EV_TIMEOUT, arg);
     85 }
     86 
     87 int
     88 setup_event_timer_sync (struct state *state)
     89 {
     90   int wait_time = add_jitter (state->opts.steady_state_interval,
     91                               state->opts.jitter);
     92   struct timeval interval = { wait_time, 0 };
     93   state->events[E_STEADYSTATE] = event_new (state->base, -1,
     94                                  EV_TIMEOUT|EV_PERSIST,
     95                                  action_invalidate_time, state);
     96   if (!state->events[E_STEADYSTATE])
     97     {
     98       error ("Failed to create interval event");
     99       return 1;
    100     }
    101   event_priority_set (state->events[E_STEADYSTATE], PRI_ANY);
    102   return event_add (state->events[E_STEADYSTATE], &interval);
    103 }
    104 
    105 /* Begins a network synchronization attempt.  If the local clocks
    106  * are synchronized, then make sure that the _current_ synchronization
    107  * source is set to the real-time clock and note that the clock_delta
    108  * is unreliable.  If the clock was in sync and the last synchronization
    109  * source was the network, then this action does nothing.
    110  *
    111  * In the case of desynchronization, the clock_delta value is used as a
    112  * guard to indicate that even if the synchronization source isn't the
    113  * network, the source is still tracking the clock delta that was
    114  * established from a network source.
    115  * TODO(wad) Change the name of clock_delta to indicate that it is the local
    116  *           clock delta after the last network sync.
    117  */
    118 void action_kickoff_time_sync (evutil_socket_t fd, short what, void *arg)
    119 {
    120   struct state *state = arg;
    121   verb_debug ("[event:%s] fired", __func__);
    122   time_t delta = state->clock_delta;
    123   int jitter = 0;
    124   if (check_continuity (&delta) > 0)
    125     {
    126       info ("[event:%s] clock delta desync detected (%d != %d)", __func__,
    127             state->clock_delta, delta);
    128       /* Add jitter iff we had network synchronization once before. */
    129       if (state->clock_delta)
    130         jitter = add_jitter (30, 30); /* TODO(wad) make configurable */
    131       /* Forget the old delta until we have time again. */
    132       state->clock_delta = 0;
    133       invalidate_time (state);
    134     }
    135   if (state->last_sync_type == SYNC_TYPE_NET)
    136     {
    137       verb_debug ("[event:%s] time in sync. skipping", __func__);
    138       return;
    139     }
    140   /* Keep parity with run_tlsdate: for every wake, allow it to retry again. */
    141   if (state->tries > 0)
    142     {
    143       state->tries -= 1;
    144       /* Don't bother re-triggering tlsdate */
    145       verb_debug ("[event:%s] called while tries are in progress", __func__);
    146       return;
    147     }
    148   /* Don't over-schedule if the first attempt hasn't fired. If a wake event
    149    * impacts the result of a proxy resolution, then the updated value can be
    150    * acquired on the next run. If the wake comes in after E_TLSDATE is
    151    * serviced, then the tries count will be decremented.
    152    */
    153   if (event_pending (state->events[E_TLSDATE], EV_TIMEOUT, NULL))
    154     {
    155       verb_debug ("[event:%s] called while tlsdate is pending", __func__);
    156       return;
    157     }
    158   if (!state->events[E_RESOLVER])
    159     {
    160       trigger_event (state, E_TLSDATE, jitter);
    161       return;
    162     }
    163   /* If the resolver relies on an external response, then make sure that a
    164    * tlsdate event is waiting in the wings if the resolver is too slow.  Even
    165    * if this fires, it won't stop eventual handling of the resolver since it
    166    * doesn't event_del() E_RESOLVER.
    167    */
    168   trigger_event (state, E_TLSDATE, jitter + RESOLVER_TIMEOUT);
    169   trigger_event (state, E_RESOLVER, jitter);
    170 }
    171