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
103#if defined(__GNUC__) || defined(__clang__)
104#pragma GCC diagnostic push
105#pragma GCC diagnostic ignored "-Wconversion"
106#endif
107
108const char *
110{
111 struct buffer out = alloc_buf_gc(64, gc);
112 struct timeval tv;
113
114 if (t)
115 {
116 tv.tv_sec = t;
117 tv.tv_usec = usec;
118 }
119 else
120 {
121 gettimeofday(&tv, NULL);
122 }
123
124 t = tv.tv_sec;
125 struct tm *tm = localtime(&t);
126
127 buf_printf(&out, "%04d-%02d-%02d %02d:%02d:%02d", tm->tm_year + 1900, tm->tm_mon + 1,
128 tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
129
130 if (show_usec && tv.tv_usec)
131 {
132 buf_printf(&out, " us=%ld", (long)tv.tv_usec);
133 }
134
135 return BSTR(&out);
136}
137
138#if defined(__GNUC__) || defined(__clang__)
139#pragma GCC diagnostic pop
140#endif
141
142/*
143 * Limit the frequency of an event stream.
144 *
145 * Used to control maximum rate of new
146 * incoming connections.
147 */
148
149struct frequency_limit *
151{
152 struct frequency_limit *f;
153
154 ASSERT(max >= 0 && per >= 0);
155
156 ALLOC_OBJ(f, struct frequency_limit);
157 f->max = max;
158 f->per = per;
159 f->n = 0;
160 f->reset = 0;
161 return f;
162}
163
164void
166{
167 free(f);
168}
169
170bool
172{
173 if (f->per)
174 {
175 bool ret;
176 if (now >= f->reset + f->per)
177 {
178 f->reset = now;
179 f->n = 0;
180 }
181 ret = (++f->n <= f->max);
182 return ret;
183 }
184 else
185 {
186 return true;
187 }
188}
189
190#ifdef TIME_TEST
191void
192time_test(void)
193{
194 struct timeval tv;
195 time_t t;
196 int i;
197 for (i = 0; i < 10000; ++i)
198 {
199 t = time(NULL);
200 gettimeofday(&tv, NULL);
201#if 1
202 msg(M_INFO, "t=%" PRIi64 " s=%" PRIi64 " us=%ld", (int64_t)t, (int64_t)tv.tv_sec,
203 (long)tv.tv_usec);
204#endif
205 }
206}
207#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:152
#define ASSERT(x)
Definition error.h:219
const char * time_string(time_t t, long usec, bool show_usec, struct gc_arena *gc)
Definition otime.c:109
time_t now_usec
Definition otime.c:36
struct frequency_limit * frequency_limit_init(int max, int per)
Definition otime.c:150
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:165
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:171
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
Garbage collection arena used to keep track of dynamically allocated memory.
Definition buffer.h:116
struct gc_arena gc
Definition test_ssl.c:131