OpenVPN
sig.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 * Copyright (C) 2016-2025 Selva Nair <selva.nair@gmail.com>
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License version 2
13 * as published by the Free Software Foundation.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License along
21 * with this program; if not, see <https://www.gnu.org/licenses/>.
22 */
23
24#ifdef HAVE_CONFIG_H
25#include "config.h"
26#endif
27
28#include "syshead.h"
29
30#include "buffer.h"
31#include "error.h"
32#include "win32.h"
33#include "init.h"
34#include "status.h"
35#include "sig.h"
36#include "occ.h"
37#include "manage.h"
38#include "openvpn.h"
39
40#include "memdbg.h"
41
42/* Handle signals */
43
44struct signal_info siginfo_static; /* GLOBAL */
45
46struct signame
47{
48 int value;
50 const char *upper;
51 const char *lower;
52};
53
54static const struct signame signames[] = { { SIGINT, 5, "SIGINT", "sigint" },
55 { SIGTERM, 4, "SIGTERM", "sigterm" },
56 { SIGHUP, 3, "SIGHUP", "sighup" },
57 { SIGUSR1, 2, "SIGUSR1", "sigusr1" },
58 { SIGUSR2, 1, "SIGUSR2", "sigusr2" } };
59
60/* mask for hard signals from management or windows */
61static unsigned long long ignored_hard_signals_mask;
62
63int
65{
66 int i;
67 for (i = 0; i < (int)SIZE(signames); ++i)
68 {
69 if (!strcmp(signame, signames[i].upper))
70 {
71 return signames[i].value;
72 }
73 }
74 return -1;
75}
76
77static int
79{
80 for (size_t i = 0; i < SIZE(signames); ++i)
81 {
82 if (sig == signames[i].value)
83 {
84 return signames[i].priority;
85 }
86 }
87 return -1;
88}
89
90const char *
91signal_name(const int sig, const bool upper)
92{
93 int i;
94 for (i = 0; i < (int)SIZE(signames); ++i)
95 {
96 if (sig == signames[i].value)
97 {
98 return upper ? signames[i].upper : signames[i].lower;
99 }
100 }
101 return "UNKNOWN";
102}
103
104const char *
105signal_description(const int signum, const char *sigtext)
106{
107 if (sigtext)
108 {
109 return sigtext;
110 }
111 else
112 {
113 return signal_name(signum, false);
114 }
115}
116
122static inline void
124{
125#ifndef _WIN32
126 sigset_t all;
127 sigfillset(&all); /* all signals */
128 sigprocmask(SIG_BLOCK, &all, NULL);
129#endif
130}
131
135static inline void
137{
138#ifndef _WIN32
139 sigset_t none;
140 sigemptyset(&none);
141 sigprocmask(SIG_SETMASK, &none, NULL);
142#endif
143}
144
157static bool
158try_throw_signal(struct signal_info *si, int signum, int source)
159{
160 bool ret = false;
162 {
163 si->signal_received = signum;
164 si->source = source;
165 ret = true;
166 }
167 return ret;
168}
169
174void
175throw_signal(const int signum)
176{
177 if (ignored_hard_signals_mask & (1LL << signum))
178 {
179 msg(D_SIGNAL_DEBUG, "Signal %s is currently ignored", signal_name(signum, true));
180 return;
181 }
183
185 {
186 msg(D_SIGNAL_DEBUG, "Ignoring %s when %s has been received", signal_name(signum, true),
188 }
189 else
190 {
191 msg(D_SIGNAL_DEBUG, "Throw signal (hard): %s ", signal_name(signum, true));
192 }
193
195}
196
203void
204throw_signal_soft(const int signum, const char *signal_text)
205{
207
209 {
210 siginfo_static.signal_text = signal_text;
211 msg(D_SIGNAL_DEBUG, "Throw signal (soft): %s (%s)", signal_name(signum, true), signal_text);
212 }
213 else
214 {
215 msg(D_SIGNAL_DEBUG, "Ignoring %s when %s has been received", signal_name(signum, true),
217 }
218
220}
221
227void
228register_signal(struct signal_info *si, int signum, const char *signal_text)
229{
230 if (si == &siginfo_static) /* attempting to alter the global signal */
231 {
233 }
234
235 if (try_throw_signal(si, signum, SIG_SOURCE_SOFT))
236 {
237 si->signal_text = signal_text;
238 if (signal_text && strcmp(signal_text, "connection-failed") == 0)
239 {
241 }
242 msg(D_SIGNAL_DEBUG | M_NOIPREFIX, "register signal: %s (%s)", signal_name(signum, true), signal_text);
243 }
244 else
245 {
246 msg(D_SIGNAL_DEBUG, "Ignoring %s when %s has been received", signal_name(signum, true),
247 signal_name(si->signal_received, true));
248 }
249
250 if (si == &siginfo_static)
251 {
253 }
254}
255
261int
262signal_reset(struct signal_info *si, int signum)
263{
264 int sig_saved = 0;
265 if (si)
266 {
267 if (si == &siginfo_static) /* attempting to alter the global signal */
268 {
270 }
271
272 sig_saved = si->signal_received;
273 if (!signum || sig_saved == signum)
274 {
275 si->signal_received = 0;
276 si->signal_text = NULL;
278 msg(D_SIGNAL_DEBUG, "signal_reset: signal %s is cleared", signal_name(signum, true));
279 }
280
281 if (si == &siginfo_static)
282 {
284 }
285 }
286 return sig_saved;
287}
288
289void
290print_signal(const struct signal_info *si, const char *title, int msglevel)
291{
292 if (si)
293 {
294 const char *type = (si->signal_text ? si->signal_text : "");
295 const char *t = (title ? title : "process");
296 const char *hs = NULL;
297 switch (si->source)
298 {
299 case SIG_SOURCE_SOFT:
300 hs = "soft";
301 break;
302
303 case SIG_SOURCE_HARD:
304 hs = "hard";
305 break;
306
308 hs = "connection failed(soft)";
309 break;
310
311 default:
312 ASSERT(0);
313 }
314
315 switch (si->signal_received)
316 {
317 case SIGINT:
318 case SIGTERM:
319 msg(msglevel, "%s[%s,%s] received, %s exiting",
320 signal_name(si->signal_received, true), hs, type, t);
321 break;
322
323 case SIGHUP:
324 case SIGUSR1:
325 msg(msglevel, "%s[%s,%s] received, %s restarting",
326 signal_name(si->signal_received, true), hs, type, t);
327 break;
328
329 default:
330 msg(msglevel, "Unknown signal %d [%s,%s] received by %s", si->signal_received, hs,
331 type, t);
332 break;
333 }
334 }
335 else
336 {
337 msg(msglevel, "Unknown signal received");
338 }
339}
340
341/*
342 * Call management interface with restart info
343 */
344void
346{
347#ifdef ENABLE_MANAGEMENT
348 if (management)
349 {
350 int state = -1;
351 switch (si->signal_received)
352 {
353 case SIGINT:
354 case SIGTERM:
355 state = OPENVPN_STATE_EXITING;
356 break;
357
358 case SIGHUP:
359 case SIGUSR1:
361 break;
362 }
363
364 if (state >= 0)
365 {
367 si->signal_text ? si->signal_text
368 : signal_name(si->signal_received, true),
369 NULL, NULL, NULL, NULL);
370 }
371 }
372#endif /* ifdef ENABLE_MANAGEMENT */
373}
374
375#ifndef _WIN32
376/* normal signal handler, when we are in event loop */
377static void
378signal_handler(const int signum)
379{
381}
382#endif
383
384/* set handlers for unix signals */
385
386#define SM_UNDEF 0
387#define SM_PRE_INIT 1
388#define SM_POST_INIT 2
389static int signal_mode; /* GLOBAL */
390
391void
393{
394#ifndef _WIN32
395 sigset_t block_mask;
396 struct sigaction sa;
397 CLEAR(sa);
398
399 sigfillset(&block_mask); /* all signals */
400 sa.sa_handler = signal_handler;
401 sa.sa_mask = block_mask; /* signals blocked inside the handler */
402 sa.sa_flags = SA_RESTART; /* match with the behaviour of signal() on Linux and BSD */
403
405 sigaction(SIGINT, &sa, NULL);
406 sigaction(SIGTERM, &sa, NULL);
407
408 sa.sa_handler = SIG_IGN;
409 sigaction(SIGHUP, &sa, NULL);
410 sigaction(SIGUSR1, &sa, NULL);
411 sigaction(SIGUSR2, &sa, NULL);
412 sigaction(SIGPIPE, &sa, NULL);
413#endif /* _WIN32 */
414 /* clear any pending signals of the ignored type */
415 signal_reset(&siginfo_static, SIGUSR1);
416 signal_reset(&siginfo_static, SIGUSR2);
418}
419
420void
422{
423#ifndef _WIN32
424 sigset_t block_mask;
425 struct sigaction sa;
426 CLEAR(sa);
427
428 sigfillset(&block_mask); /* all signals */
429 sa.sa_handler = signal_handler;
430 sa.sa_mask = block_mask; /* signals blocked inside the handler */
431 sa.sa_flags = SA_RESTART; /* match with the behaviour of signal() on Linux and BSD */
432
434 sigaction(SIGINT, &sa, NULL);
435 sigaction(SIGTERM, &sa, NULL);
436 sigaction(SIGHUP, &sa, NULL);
437 sigaction(SIGUSR1, &sa, NULL);
438 sigaction(SIGUSR2, &sa, NULL);
439 sa.sa_handler = SIG_IGN;
440 sigaction(SIGPIPE, &sa, NULL);
441#endif /* _WIN32 */
442}
443
444void
446{
447#ifndef _WIN32
448 struct sigaction sa;
449 CLEAR(sa);
450 sa.sa_handler = SIG_IGN;
451 sigaction(SIGHUP, &sa, NULL);
452 sigaction(SIGUSR1, &sa, NULL);
453 sigaction(SIGUSR2, &sa, NULL);
454#endif /* _WIN32 */
455 ignored_hard_signals_mask = (1LL << SIGHUP) | (1LL << SIGUSR1) | (1LL << SIGUSR2);
456}
457
458/* called after daemonization to retain signal settings */
459void
461{
463 {
465 }
466 else if (signal_mode == SM_POST_INIT)
467 {
469 }
470}
471
472/*
473 * Print statistics.
474 *
475 * Triggered by SIGUSR2 or F2 on Windows.
476 */
477void
478print_status(struct context *c, struct status_output *so)
479{
480 struct gc_arena gc = gc_new();
481
482 status_reset(so);
483
484 if (dco_enabled(&c->options))
485 {
486 if (dco_get_peer_stats(c, true) < 0)
487 {
488 return;
489 }
490 }
491
492 status_printf(so, "OpenVPN STATISTICS");
493 status_printf(so, "Updated,%s", time_string(0, 0, false, &gc));
494 status_printf(so, "TUN/TAP read bytes," counter_format, c->c2.tun_read_bytes);
495 status_printf(so, "TUN/TAP write bytes," counter_format, c->c2.tun_write_bytes);
496 status_printf(so, "TCP/UDP read bytes," counter_format,
498 status_printf(so, "TCP/UDP write bytes," counter_format,
500 status_printf(so, "Auth read bytes," counter_format, c->c2.link_read_bytes_auth);
501#ifdef USE_COMP
502 if (c->c2.comp_context)
503 {
504 comp_print_stats(c->c2.comp_context, so);
505 }
506#endif
507#ifdef PACKET_TRUNCATION_CHECK
508 status_printf(so, "TUN read truncations," counter_format, c->c2.n_trunc_tun_read);
509 status_printf(so, "TUN write truncations," counter_format, c->c2.n_trunc_tun_write);
510 status_printf(so, "Pre-encrypt truncations," counter_format, c->c2.n_trunc_pre_encrypt);
511 status_printf(so, "Post-decrypt truncations," counter_format, c->c2.n_trunc_post_decrypt);
512#endif
513#ifdef _WIN32
514 if (tuntap_defined(c->c1.tuntap))
515 {
516 const char *extended_msg = tap_win_getinfo(c->c1.tuntap, &gc);
517 if (extended_msg)
518 {
519 status_printf(so, "TAP-WIN32 driver status,\"%s\"", extended_msg);
520 }
521 }
522#endif
523
524 status_printf(so, "END");
525 status_flush(so);
526 gc_free(&gc);
527}
528
529/*
530 * Handle the triggering and time-wait of explicit
531 * exit notification.
532 */
533static void
535{
536 msg(M_INFO, "SIGTERM received, sending exit notification to peer");
537 /* init the timeout to send the OCC_EXIT messages if cc exit is not
538 * enabled and also to exit after waiting for retries of resending of
539 * exit messages */
542
543 /* Windows exit event will continue trigering SIGTERM -- halt it */
545
546 /* Before resetting the signal, ensure hard low priority signals
547 * will be ignored during the exit notification period.
548 */
549 halt_low_priority_signals(); /* Set hard SIGUSR1/SIGHUP/SIGUSR2 to be ignored */
550 signal_reset(c->sig, 0);
551
553
554 /* Check if we are in TLS mode and should send the notification via data
555 * channel */
557 {
559 }
560}
561
562void
582
583/*
584 * Process signals
585 */
586
587void
589{
590 if (c->sig->signal_received == SIGUSR1 && c->options.remap_sigusr1)
591 {
593 }
594}
595
596static void
598{
599 struct status_output *so = status_open(NULL, 0, M_INFO, NULL, 0);
600 print_status(c, so);
601 status_close(so);
602 signal_reset(c->sig, SIGUSR2);
603}
604
605static bool
607{
608 bool ret = true;
610 {
612 ret = false;
613 }
614 return ret;
615}
616
622static void
624{
625 if ((c->sig->signal_received == SIGUSR1 || c->sig->signal_received == SIGHUP)
627 && c->sig->source != SIG_SOURCE_HARD)
628 {
629 msg(M_INFO, "Converting soft %s received during exit notification to SIGTERM",
630 signal_name(c->sig->signal_received, true));
631 register_signal(c->sig, SIGTERM, "exit-with-notification");
632 }
633}
634
635bool
637{
638 bool ret = true;
639
641
642 if (c->sig->signal_received == SIGTERM || c->sig->signal_received == SIGINT)
643 {
644 ret = process_sigterm(c);
645 }
646 else if (c->sig->signal_received == SIGUSR2)
647 {
649 ret = false;
650 }
651 return ret;
652}
static void gc_free(struct gc_arena *a)
Definition buffer.h:1015
static struct gc_arena gc_new(void)
Definition buffer.h:1007
#define counter_format
Definition common.h:30
static int dco_get_peer_stats(struct context *c, const bool raise_sigusr1_on_err)
Definition dco.h:377
#define D_PUSH
Definition errlevel.h:82
#define D_SIGNAL_DEBUG
Definition errlevel.h:118
#define M_INFO
Definition errlevel.h:54
bool send_control_channel_string(struct context *c, const char *str, int msglevel)
Definition forward.c:398
void reset_coarse_timers(struct context *c)
Definition init.c:1315
bool event_timeout_trigger(struct event_timeout *et, struct timeval *tv, const int et_const_retry)
This is the principal function for testing and triggering recurring timers.
Definition interval.c:42
#define ETT_DEFAULT
Definition interval.h:222
static bool event_timeout_defined(const struct event_timeout *et)
Definition interval.h:142
static void event_timeout_init(struct event_timeout *et, interval_t n, const time_t last)
Initialises a timer struct.
Definition interval.h:172
static void event_timeout_clear(struct event_timeout *et)
Clears the timeout and reset all values to 0.
Definition interval.h:153
void management_set_state(struct management *man, const int state, const char *detail, const in_addr_t *tun_local_ip, const struct in6_addr *tun_local_ip6, const struct openvpn_sockaddr *local, const struct openvpn_sockaddr *remote)
Definition manage.c:2778
#define OPENVPN_STATE_RECONNECTING
Definition manage.h:453
#define OPENVPN_STATE_EXITING
Definition manage.h:454
#define OCC_EXIT
Definition occ.h:66
static bool cc_exit_notify_enabled(struct context *c)
Small helper function to determine if we should send the exit notification via control channel.
Definition occ.h:158
#define CLEAR(x)
Definition basic.h:32
#define SIZE(x)
Definition basic.h:29
#define M_NOIPREFIX
Definition error.h:101
#define msg(flags,...)
Definition error.h:150
#define ASSERT(x)
Definition error.h:217
static bool dco_enabled(const struct options *o)
Returns whether the current configuration has dco enabled.
Definition options.h:936
const char * time_string(time_t t, long usec, bool show_usec, struct gc_arena *gc)
Definition otime.c:104
time_t now
Definition otime.c:33
static int signal_mode
Definition sig.c:389
bool process_signal(struct context *c)
Definition sig.c:636
static void remap_restart_signals(struct context *c)
If a soft restart signal is received during exit-notification, it implies the event loop cannot conti...
Definition sig.c:623
static void unblock_async_signals(void)
Unblock all unix signals.
Definition sig.c:136
void signal_restart_status(const struct signal_info *si)
Definition sig.c:345
void post_init_signal_catch(void)
Definition sig.c:421
void throw_signal_soft(const int signum, const char *signal_text)
Throw a soft global signal.
Definition sig.c:204
void print_status(struct context *c, struct status_output *so)
Definition sig.c:478
const char * signal_name(const int sig, const bool upper)
Definition sig.c:91
static bool process_sigterm(struct context *c)
Definition sig.c:606
#define SM_PRE_INIT
Definition sig.c:387
int signal_reset(struct signal_info *si, int signum)
Clear the signal if its current value equals signum.
Definition sig.c:262
void process_explicit_exit_notification_timer_wakeup(struct context *c)
Definition sig.c:563
static unsigned long long ignored_hard_signals_mask
Definition sig.c:61
void pre_init_signal_catch(void)
Definition sig.c:392
void remap_signal(struct context *c)
Definition sig.c:588
#define SM_POST_INIT
Definition sig.c:388
const char * signal_description(const int signum, const char *sigtext)
Definition sig.c:105
void restore_signal_state(void)
Definition sig.c:460
void throw_signal(const int signum)
Throw a hard signal.
Definition sig.c:175
static const struct signame signames[]
Definition sig.c:54
int parse_signal(const char *signame)
Definition sig.c:64
struct signal_info siginfo_static
Definition sig.c:44
void halt_low_priority_signals(void)
Definition sig.c:445
static void block_async_signals(void)
Block (i.e., defer) all unix signals.
Definition sig.c:123
static void process_explicit_exit_notification_init(struct context *c)
Definition sig.c:534
void register_signal(struct signal_info *si, int signum, const char *signal_text)
Register a soft signal in the signal_info struct si respecting priority.
Definition sig.c:228
void print_signal(const struct signal_info *si, const char *title, int msglevel)
Definition sig.c:290
static bool try_throw_signal(struct signal_info *si, int signum, int source)
Private function for registering a signal in the specified signal_info struct.
Definition sig.c:158
static int signal_priority(int sig)
Definition sig.c:78
static void process_sigusr2(struct context *c)
Definition sig.c:597
static void halt_non_edge_triggered_signals(void)
Definition sig.h:91
#define SIG_SOURCE_CONNECTION_FAILED
Definition sig.h:34
#define SIG_SOURCE_SOFT
Definition sig.h:29
#define SIG_SOURCE_HARD
Definition sig.h:30
void status_printf(struct status_output *so, const char *format,...)
Definition status.c:213
struct status_output * status_open(const char *filename, const int refresh_freq, const int msglevel, const struct virtual_output *vout, const unsigned int flags)
Definition status.c:60
void status_flush(struct status_output *so)
Definition status.c:148
void status_reset(struct status_output *so)
Definition status.c:139
bool status_close(struct status_output *so)
Definition status.c:179
int explicit_exit_notification
Definition options.h:147
struct tuntap * tuntap
Tun/tap virtual network interface.
Definition openvpn.h:172
counter_type link_read_bytes
Definition openvpn.h:266
counter_type link_write_bytes
Definition openvpn.h:269
counter_type dco_read_bytes
Definition openvpn.h:267
counter_type tun_read_bytes
Definition openvpn.h:264
counter_type dco_write_bytes
Definition openvpn.h:270
int occ_op
Definition openvpn.h:299
counter_type tun_write_bytes
Definition openvpn.h:265
counter_type link_read_bytes_auth
Definition openvpn.h:268
struct timeval timeval
Time to next event of timers and similar.
Definition openvpn.h:396
time_t explicit_exit_notification_time_wait
Definition openvpn.h:416
struct event_timeout explicit_exit_notification_interval
Definition openvpn.h:417
Contains all state information for one tunnel.
Definition openvpn.h:474
struct signal_info * sig
Internal error signaling object.
Definition openvpn.h:503
struct context_2 c2
Level 2 context.
Definition openvpn.h:517
struct options options
Options loaded from command line or configuration file.
Definition openvpn.h:475
struct context_1 c1
Level 1 context.
Definition openvpn.h:516
Garbage collection arena used to keep track of dynamically allocated memory.
Definition buffer.h:116
struct connection_entry ce
Definition options.h:290
int remap_sigusr1
Definition options.h:393
const char * signal_text
Definition sig.h:44
volatile int signal_received
Definition sig.h:42
volatile int source
Definition sig.h:43
Definition sig.c:47
const char * lower
Definition sig.c:51
int value
Definition sig.c:48
const char * upper
Definition sig.c:50
int priority
Definition sig.c:49
struct gc_arena gc
Definition test_ssl.c:154
const char * tap_win_getinfo(const struct tuntap *tt, struct gc_arena *gc)
Definition tun.c:6413
static bool tuntap_defined(const struct tuntap *tt)
Definition tun.h:254