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-2024 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, write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 */
23
24#ifdef HAVE_CONFIG_H
25#include "config.h"
26#endif
27
28#include "syshead.h"
29
30#include "otime.h"
31
32#include "memdbg.h"
33
34time_t now = 0; /* GLOBAL */
35
36static time_t now_adj = 0; /* GLOBAL */
37time_t now_usec = 0; /* GLOBAL */
38
39/*
40 * Try to filter out time instability caused by the system
41 * clock backtracking or jumping forward.
42 */
43
44void
45update_now(const time_t system_time)
46{
47 const int forward_threshold = 86400; /* threshold at which to dampen forward jumps */
48 const int backward_trigger = 10; /* backward jump must be >= this many seconds before we adjust */
49 time_t real_time = system_time + now_adj;
50
51 if (real_time > now)
52 {
53 const time_t overshoot = real_time - now - 1;
54 if (overshoot > forward_threshold && now_adj >= overshoot)
55 {
56 now_adj -= overshoot;
57 real_time -= overshoot;
58 }
59 now = real_time;
60 }
61 else if (real_time < now - backward_trigger)
62 {
63 now_adj += (now - real_time);
64 }
65}
66
67void
68update_now_usec(struct timeval *tv)
69{
70 const time_t last = now;
71 update_now(tv->tv_sec);
72 if (now > last || (now == last && tv->tv_usec > now_usec))
73 {
74 now_usec = tv->tv_usec;
75 }
76}
77
78/*
79 * Return a numerical string describing a struct timeval.
80 */
81const char *
82tv_string(const struct timeval *tv, struct gc_arena *gc)
83{
84 struct buffer out = alloc_buf_gc(64, gc);
85 buf_printf(&out, "[%" PRIi64 "/%ld]",
86 (int64_t)tv->tv_sec,
87 (long)tv->tv_usec);
88 return BSTR(&out);
89}
90
91/*
92 * Return an ascii string describing an absolute
93 * date/time in a struct timeval.
94 *
95 */
96const char *
97tv_string_abs(const struct timeval *tv, struct gc_arena *gc)
98{
99 return time_string((time_t) tv->tv_sec,
100 (long) tv->tv_usec,
101 true,
102 gc);
103}
104
105/* format a time_t as ascii, or use current time if 0 */
106
107const char *
109{
110 struct buffer out = alloc_buf_gc(64, gc);
111 struct timeval tv;
112
113 if (t)
114 {
115 tv.tv_sec = t;
116 tv.tv_usec = usec;
117 }
118 else
119 {
120 gettimeofday(&tv, NULL);
121 }
122
123 t = tv.tv_sec;
124 struct tm *tm = localtime(&t);
125
126 buf_printf(&out, "%04d-%02d-%02d %02d:%02d:%02d",
127 tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday,
128 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/*
139 * Limit the frequency of an event stream.
140 *
141 * Used to control maximum rate of new
142 * incoming connections.
143 */
144
145struct frequency_limit *
147{
148 struct frequency_limit *f;
149
150 ASSERT(max >= 0 && per >= 0);
151
152 ALLOC_OBJ(f, struct frequency_limit);
153 f->max = max;
154 f->per = per;
155 f->n = 0;
156 f->reset = 0;
157 return f;
158}
159
160void
162{
163 free(f);
164}
165
166bool
168{
169 if (f->per)
170 {
171 bool ret;
172 if (now >= f->reset + f->per)
173 {
174 f->reset = now;
175 f->n = 0;
176 }
177 ret = (++f->n <= f->max);
178 return ret;
179 }
180 else
181 {
182 return true;
183 }
184}
185
186#ifdef TIME_TEST
187void
188time_test(void)
189{
190 struct timeval tv;
191 time_t t;
192 int i;
193 for (i = 0; i < 10000; ++i)
194 {
195 t = time(NULL);
196 gettimeofday(&tv, NULL);
197#if 1
198 msg(M_INFO, "t=%" PRIi64 " s=%" PRIi64 " us=%ld",
199 (int64_t)t,
200 (int64_t)tv.tv_sec,
201 (long)tv.tv_usec);
202#endif
203 }
204}
205#endif
bool buf_printf(struct buffer *buf, const char *format,...)
Definition buffer.c:240
struct buffer alloc_buf_gc(size_t size, struct gc_arena *gc)
Definition buffer.c:88
#define ALLOC_OBJ(dptr, type)
Definition buffer.h:1055
#define BSTR(buf)
Definition buffer.h:129
#define M_INFO
Definition errlevel.h:55
#define msg(flags,...)
Definition error.h:144
#define ASSERT(x)
Definition error.h:195
const char * time_string(time_t t, long usec, bool show_usec, struct gc_arena *gc)
Definition otime.c:108
time_t now_usec
Definition otime.c:37
struct frequency_limit * frequency_limit_init(int max, int per)
Definition otime.c:146
void update_now(const time_t system_time)
Definition otime.c:45
void update_now_usec(struct timeval *tv)
Definition otime.c:68
time_t now
Definition otime.c:34
void frequency_limit_free(struct frequency_limit *f)
Definition otime.c:161
const char * tv_string(const struct timeval *tv, struct gc_arena *gc)
Definition otime.c:82
const char * tv_string_abs(const struct timeval *tv, struct gc_arena *gc)
Definition otime.c:97
bool frequency_limit_event_allowed(struct frequency_limit *f)
Definition otime.c:167
static time_t now_adj
Definition otime.c:36
void time_test(void)
Wrapper structure for dynamically allocated memory.
Definition buffer.h:61
int len
Length in bytes of the actual content within the allocated memory.
Definition buffer.h:66
Garbage collection arena used to keep track of dynamically allocated memory.
Definition buffer.h:117
struct gc_arena gc
Definition test_ssl.c:155