OpenVPN
otime.c
Go to the documentation of this file.
1/*
2 * OpenVPN -- An application to securely tunnel IP networks
3 * over a single TCP/UDP port, with support for SSL/TLS-based
4 * session authentication and key exchange,
5 * packet encryption, packet authentication, and
6 * packet compression.
7 *
8 * Copyright (C) 2002-2025 OpenVPN Inc <sales@openvpn.net>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2
12 * as published by the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, see <https://www.gnu.org/licenses/>.
21 */
22
23#ifdef HAVE_CONFIG_H
24#include "config.h"
25#endif
26
27#include "syshead.h"
28
29#include "otime.h"
30
31#include "memdbg.h"
32
33time_t now = 0; /* GLOBAL */
34
35static time_t now_adj = 0; /* GLOBAL */
36time_t now_usec = 0; /* GLOBAL */
37
38/*
39 * Try to filter out time instability caused by the system
40 * clock backtracking or jumping forward.
41 */
42
43void
44update_now(const time_t system_time)
45{
46 /* threshold at which to dampen forward jumps */
47 const int forward_threshold = 86400;
48 /* backward jump must be >= this many seconds before we adjust */
49 const int backward_trigger = 10;
50 time_t real_time = system_time + now_adj;
51
52 if (real_time > now)
53 {
54 const time_t overshoot = real_time - now - 1;
55 if (overshoot > forward_threshold && now_adj >= overshoot)
56 {
57 now_adj -= overshoot;
58 real_time -= overshoot;
59 }
60 now = real_time;
61 }
62 else if (real_time < now - backward_trigger)
63 {
64 now_adj += (now - real_time);
65 }
66}
67
68void
69update_now_usec(struct timeval *tv)
70{
71 const time_t last = now;
72 update_now(tv->tv_sec);
73 if (now > last || (now == last && tv->tv_usec > now_usec))
74 {
75 now_usec = tv->tv_usec;
76 }
77}
78
79/*
80 * Return a numerical string describing a struct timeval.
81 */
82const char *
83tv_string(const struct timeval *tv, struct gc_arena *gc)
84{
85 struct buffer out = alloc_buf_gc(64, gc);
86 buf_printf(&out, "[%" PRIi64 "/%ld]", (int64_t)tv->tv_sec, (long)tv->tv_usec);
87 return BSTR(&out);
88}
89
90/*
91 * Return an ascii string describing an absolute
92 * date/time in a struct timeval.
93 *
94 */
95const char *
96tv_string_abs(const struct timeval *tv, struct gc_arena *gc)
97{
98 return time_string((time_t)tv->tv_sec, (long)tv->tv_usec, true, gc);
99}
100
101/* format a time_t as ascii, or use current time if 0 */
102
103const char *
105{
106 struct buffer out = alloc_buf_gc(64, gc);
107 struct timeval tv;
108
109 if (t)
110 {
111 tv.tv_sec = t;
112 tv.tv_usec = usec;
113 }
114 else
115 {
116 gettimeofday(&tv, NULL);
117 }
118
119 t = tv.tv_sec;
120 struct tm *tm = localtime(&t);
121
122 buf_printf(&out, "%04d-%02d-%02d %02d:%02d:%02d", tm->tm_year + 1900, tm->tm_mon + 1,
123 tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
124
125 if (show_usec && tv.tv_usec)
126 {
127 buf_printf(&out, " us=%ld", (long)tv.tv_usec);
128 }
129
130 return BSTR(&out);
131}
132
133/*
134 * Limit the frequency of an event stream.
135 *
136 * Used to control maximum rate of new
137 * incoming connections.
138 */
139
140struct frequency_limit *
142{
143 struct frequency_limit *f;
144
145 ASSERT(max >= 0 && per >= 0);
146
147 ALLOC_OBJ(f, struct frequency_limit);
148 f->max = max;
149 f->per = per;
150 f->n = 0;
151 f->reset = 0;
152 return f;
153}
154
155void
157{
158 free(f);
159}
160
161bool
163{
164 if (f->per)
165 {
166 bool ret;
167 if (now >= f->reset + f->per)
168 {
169 f->reset = now;
170 f->n = 0;
171 }
172 ret = (++f->n <= f->max);
173 return ret;
174 }
175 else
176 {
177 return true;
178 }
179}
180
181#ifdef TIME_TEST
182void
183time_test(void)
184{
185 struct timeval tv;
186 time_t t;
187 int i;
188 for (i = 0; i < 10000; ++i)
189 {
190 t = time(NULL);
191 gettimeofday(&tv, NULL);
192#if 1
193 msg(M_INFO, "t=%" PRIi64 " s=%" PRIi64 " us=%ld", (int64_t)t, (int64_t)tv.tv_sec,
194 (long)tv.tv_usec);
195#endif
196 }
197}
198#endif
bool buf_printf(struct buffer *buf, const char *format,...)
Definition buffer.c:241
struct buffer alloc_buf_gc(size_t size, struct gc_arena *gc)
Definition buffer.c:89
#define ALLOC_OBJ(dptr, type)
Definition buffer.h:1037
#define BSTR(buf)
Definition buffer.h:128
#define M_INFO
Definition errlevel.h:54
#define msg(flags,...)
Definition error.h:150
#define ASSERT(x)
Definition error.h:217
const char * time_string(time_t t, long usec, bool show_usec, struct gc_arena *gc)
Definition otime.c:104
time_t now_usec
Definition otime.c:36
struct frequency_limit * frequency_limit_init(int max, int per)
Definition otime.c:141
void update_now(const time_t system_time)
Definition otime.c:44
void update_now_usec(struct timeval *tv)
Definition otime.c:69
time_t now
Definition otime.c:33
void frequency_limit_free(struct frequency_limit *f)
Definition otime.c:156
const char * tv_string(const struct timeval *tv, struct gc_arena *gc)
Definition otime.c:83
const char * tv_string_abs(const struct timeval *tv, struct gc_arena *gc)
Definition otime.c:96
bool frequency_limit_event_allowed(struct frequency_limit *f)
Definition otime.c:162
static time_t now_adj
Definition otime.c:35
void time_test(void)
Wrapper structure for dynamically allocated memory.
Definition buffer.h:60
int len
Length in bytes of the actual content within the allocated memory.
Definition buffer.h:65
time_t reset
Definition otime.h:35
Garbage collection arena used to keep track of dynamically allocated memory.
Definition buffer.h:116
struct gc_arena gc
Definition test_ssl.c:154