src/openvpn/otime.c
6fbf66fa
 /*
  *  OpenVPN -- An application to securely tunnel IP networks
  *             over a single TCP/UDP port, with support for SSL/TLS-based
  *             session authentication and key exchange,
  *             packet encryption, packet authentication, and
  *             packet compression.
  *
49979459
  *  Copyright (C) 2002-2018 OpenVPN Inc <sales@openvpn.net>
6fbf66fa
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License version 2
  *  as published by the Free Software Foundation.
  *
  *  This program is distributed in the hope that it will be useful,
  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *  GNU General Public License for more details.
  *
caa54ac3
  *  You should have received a copy of the GNU General Public License along
  *  with this program; if not, write to the Free Software Foundation, Inc.,
  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
6fbf66fa
  */
 
c110b289
 #ifdef HAVE_CONFIG_H
 #include "config.h"
 #elif defined(_MSC_VER)
 #include "config-msvc.h"
 #endif
 
6fbf66fa
 #include "syshead.h"
 
 #include "otime.h"
 
 #include "memdbg.h"
 
0475d17e
 time_t now = 0;            /* GLOBAL */
 
3d163bc5
 #if TIME_BACKTRACK_PROTECTION
0475d17e
 
e5239fc2
 static time_t now_adj = 0; /* GLOBAL */
0475d17e
 time_t now_usec = 0;       /* GLOBAL */
 
e5239fc2
 /*
  * Try to filter out time instability caused by the system
  * clock backtracking or jumping forward.
  */
 
 void
81d882d5
 update_now(const time_t system_time)
e5239fc2
 {
81d882d5
     const int forward_threshold = 86400; /* threshold at which to dampen forward jumps */
     const int backward_trigger  = 10;  /* backward jump must be >= this many seconds before we adjust */
     time_t real_time = system_time + now_adj;
e5239fc2
 
81d882d5
     if (real_time > now)
e5239fc2
     {
81d882d5
         const time_t overshoot = real_time - now - 1;
         if (overshoot > forward_threshold && now_adj >= overshoot)
e5239fc2
         {
81d882d5
             now_adj -= overshoot;
             real_time -= overshoot;
e5239fc2
         }
81d882d5
         now = real_time;
     }
     else if (real_time < now - backward_trigger)
     {
         now_adj += (now - real_time);
e5239fc2
     }
 }
 
 void
81d882d5
 update_now_usec(struct timeval *tv)
e5239fc2
 {
81d882d5
     const time_t last = now;
     update_now(tv->tv_sec);
     if (now > last || (now == last && tv->tv_usec > now_usec))
     {
         now_usec = tv->tv_usec;
     }
e5239fc2
 }
 
3d163bc5
 #endif /* TIME_BACKTRACK_PROTECTION */
6fbf66fa
 
81d882d5
 /*
6fbf66fa
  * Return a numerical string describing a struct timeval.
  */
 const char *
81d882d5
 tv_string(const struct timeval *tv, struct gc_arena *gc)
6fbf66fa
 {
81d882d5
     struct buffer out = alloc_buf_gc(64, gc);
06ad53e0
     buf_printf(&out, "[%"PRIi64"/%ld]",
                (int64_t)tv->tv_sec,
31b5c0e9
                (long)tv->tv_usec);
81d882d5
     return BSTR(&out);
6fbf66fa
 }
 
81d882d5
 /*
6fbf66fa
  * Return an ascii string describing an absolute
  * date/time in a struct timeval.
81d882d5
  *
6fbf66fa
  */
 const char *
81d882d5
 tv_string_abs(const struct timeval *tv, struct gc_arena *gc)
6fbf66fa
 {
81d882d5
     return time_string((time_t) tv->tv_sec,
31b5c0e9
                        (long) tv->tv_usec,
81d882d5
                        true,
                        gc);
6fbf66fa
 }
 
 /* format a time_t as ascii, or use current time if 0 */
 
 const char *
81d882d5
 time_string(time_t t, int usec, bool show_usec, struct gc_arena *gc)
6fbf66fa
 {
81d882d5
     struct buffer out = alloc_buf_gc(64, gc);
     struct timeval tv;
6fbf66fa
 
81d882d5
     if (t)
6fbf66fa
     {
81d882d5
         tv.tv_sec = t;
         tv.tv_usec = usec;
6fbf66fa
     }
81d882d5
     else
6fbf66fa
     {
81d882d5
         gettimeofday(&tv, NULL);
6fbf66fa
     }
 
81d882d5
     t = tv.tv_sec;
     buf_printf(&out, "%s", ctime(&t));
     buf_rmtail(&out, '\n');
6fbf66fa
 
81d882d5
     if (show_usec && tv.tv_usec)
     {
31b5c0e9
         buf_printf(&out, " us=%ld", (long)tv.tv_usec);
81d882d5
     }
6fbf66fa
 
81d882d5
     return BSTR(&out);
6fbf66fa
 }
 
 /*
  * Limit the frequency of an event stream.
  *
  * Used to control maximum rate of new
  * incoming connections.
  */
 
 struct frequency_limit *
81d882d5
 frequency_limit_init(int max, int per)
6fbf66fa
 {
81d882d5
     struct frequency_limit *f;
6fbf66fa
 
81d882d5
     ASSERT(max >= 0 && per >= 0);
6fbf66fa
 
81d882d5
     ALLOC_OBJ(f, struct frequency_limit);
     f->max = max;
     f->per = per;
     f->n = 0;
     f->reset = 0;
     return f;
6fbf66fa
 }
 
 void
81d882d5
 frequency_limit_free(struct frequency_limit *f)
6fbf66fa
 {
81d882d5
     free(f);
6fbf66fa
 }
 
 bool
81d882d5
 frequency_limit_event_allowed(struct frequency_limit *f)
6fbf66fa
 {
81d882d5
     if (f->per)
     {
         bool ret;
         if (now >= f->reset + f->per)
         {
             f->reset = now;
             f->n = 0;
         }
         ret = (++f->n <= f->max);
         return ret;
     }
     else
6fbf66fa
     {
81d882d5
         return true;
6fbf66fa
     }
 }
 
428b8279
 #ifdef TIME_TEST
 void
81d882d5
 time_test(void)
428b8279
 {
81d882d5
     struct timeval tv;
     time_t t;
     int i;
     for (i = 0; i < 10000; ++i)
428b8279
     {
81d882d5
         t = time(NULL);
         gettimeofday(&tv, NULL);
428b8279
 #if 1
06ad53e0
         msg(M_INFO, "t=%"PRIi64" s=%"PRIi64" us=%ld",
             (int64_t)t,
             (int64_t)tv.tv_sec,
31b5c0e9
             (long)tv.tv_usec);
428b8279
 #endif
     }
 }
 #endif