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-2024 OpenVPN Inc <sales@openvpn.net>
9 * Copyright (C) 2016-2024 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, write to the Free Software Foundation, Inc.,
22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23 */
24
25#ifdef HAVE_CONFIG_H
26#include "config.h"
27#endif
28
29#include "syshead.h"
30
31#include "buffer.h"
32#include "error.h"
33#include "win32.h"
34#include "init.h"
35#include "status.h"
36#include "sig.h"
37#include "occ.h"
38#include "manage.h"
39#include "openvpn.h"
40
41#include "memdbg.h"
42
43/* Handle signals */
44
45struct signal_info siginfo_static; /* GLOBAL */
46
47struct signame {
48 int value;
50 const char *upper;
51 const char *lower;
52};
53
54static const struct signame signames[] = {
55 { SIGINT, 5, "SIGINT", "sigint"},
56 { SIGTERM, 4, "SIGTERM", "sigterm" },
57 { SIGHUP, 3, "SIGHUP", "sighup" },
58 { SIGUSR1, 2, "SIGUSR1", "sigusr1" },
59 { SIGUSR2, 1, "SIGUSR2", "sigusr2" }
60};
61
62/* mask for hard signals from management or windows */
63static unsigned long long ignored_hard_signals_mask;
64
65int
67{
68 int i;
69 for (i = 0; i < (int)SIZE(signames); ++i)
70 {
71 if (!strcmp(signame, signames[i].upper))
72 {
73 return signames[i].value;
74 }
75 }
76 return -1;
77}
78
79static int
81{
82 for (size_t i = 0; i < SIZE(signames); ++i)
83 {
84 if (sig == signames[i].value)
85 {
86 return signames[i].priority;
87 }
88 }
89 return -1;
90}
91
92const char *
93signal_name(const int sig, const bool upper)
94{
95 int i;
96 for (i = 0; i < (int)SIZE(signames); ++i)
97 {
98 if (sig == signames[i].value)
99 {
100 return upper ? signames[i].upper : signames[i].lower;
101 }
102 }
103 return "UNKNOWN";
104}
105
106const char *
107signal_description(const int signum, const char *sigtext)
108{
109 if (sigtext)
110 {
111 return sigtext;
112 }
113 else
114 {
115 return signal_name(signum, false);
116 }
117}
118
124static inline void
126{
127#ifndef _WIN32
128 sigset_t all;
129 sigfillset(&all); /* all signals */
130 sigprocmask(SIG_BLOCK, &all, NULL);
131#endif
132}
133
137static inline void
139{
140#ifndef _WIN32
141 sigset_t none;
142 sigemptyset(&none);
143 sigprocmask(SIG_SETMASK, &none, NULL);
144#endif
145}
146
159static bool
160try_throw_signal(struct signal_info *si, int signum, int source)
161{
162 bool ret = false;
164 {
165 si->signal_received = signum;
166 si->source = source;
167 ret = true;
168 }
169 return ret;
170}
171
176void
177throw_signal(const int signum)
178{
179 if (ignored_hard_signals_mask & (1LL << signum))
180 {
181 msg(D_SIGNAL_DEBUG, "Signal %s is currently ignored", signal_name(signum, true));
182 return;
183 }
185
187 {
188 msg(D_SIGNAL_DEBUG, "Ignoring %s when %s has been received", signal_name(signum, true),
190 }
191 else
192 {
193 msg(D_SIGNAL_DEBUG, "Throw signal (hard): %s ", signal_name(signum, true));
194 }
195
197}
198
205void
206throw_signal_soft(const int signum, const char *signal_text)
207{
209
211 {
212 siginfo_static.signal_text = signal_text;
213 msg(D_SIGNAL_DEBUG, "Throw signal (soft): %s (%s)", signal_name(signum, true),
214 signal_text);
215 }
216 else
217 {
218 msg(D_SIGNAL_DEBUG, "Ignoring %s when %s has been received", signal_name(signum, true),
220 }
221
223}
224
230void
231register_signal(struct signal_info *si, int signum, const char *signal_text)
232{
233 if (si == &siginfo_static) /* attempting to alter the global signal */
234 {
236 }
237
238 if (try_throw_signal(si, signum, SIG_SOURCE_SOFT))
239 {
240 si->signal_text = signal_text;
241 if (signal_text && strcmp(signal_text, "connection-failed") == 0)
242 {
244 }
245 msg(D_SIGNAL_DEBUG, "register signal: %s (%s)", signal_name(signum, true),
246 signal_text);
247 }
248 else
249 {
250 msg(D_SIGNAL_DEBUG, "Ignoring %s when %s has been received", signal_name(signum, true),
251 signal_name(si->signal_received, true));
252 }
253
254 if (si == &siginfo_static)
255 {
257 }
258}
259
265int
266signal_reset(struct signal_info *si, int signum)
267{
268 int sig_saved = 0;
269 if (si)
270 {
271 if (si == &siginfo_static) /* attempting to alter the global signal */
272 {
274 }
275
276 sig_saved = si->signal_received;
277 if (!signum || sig_saved == signum)
278 {
279 si->signal_received = 0;
280 si->signal_text = NULL;
282 msg(D_SIGNAL_DEBUG, "signal_reset: signal %s is cleared", signal_name(signum, true));
283 }
284
285 if (si == &siginfo_static)
286 {
288 }
289 }
290 return sig_saved;
291}
292
293void
294print_signal(const struct signal_info *si, const char *title, int msglevel)
295{
296 if (si)
297 {
298 const char *type = (si->signal_text ? si->signal_text : "");
299 const char *t = (title ? title : "process");
300 const char *hs = NULL;
301 switch (si->source)
302 {
303 case SIG_SOURCE_SOFT:
304 hs = "soft";
305 break;
306
307 case SIG_SOURCE_HARD:
308 hs = "hard";
309 break;
310
312 hs = "connection failed(soft)";
313 break;
314
315 default:
316 ASSERT(0);
317 }
318
319 switch (si->signal_received)
320 {
321 case SIGINT:
322 case SIGTERM:
323 msg(msglevel, "%s[%s,%s] received, %s exiting",
324 signal_name(si->signal_received, true), hs, type, t);
325 break;
326
327 case SIGHUP:
328 case SIGUSR1:
329 msg(msglevel, "%s[%s,%s] received, %s restarting",
330 signal_name(si->signal_received, true), hs, type, t);
331 break;
332
333 default:
334 msg(msglevel, "Unknown signal %d [%s,%s] received by %s", si->signal_received, hs, type, t);
335 break;
336 }
337 }
338 else
339 {
340 msg(msglevel, "Unknown signal received");
341 }
342}
343
344/*
345 * Call management interface with restart info
346 */
347void
349{
350#ifdef ENABLE_MANAGEMENT
351 if (management)
352 {
353 int state = -1;
354 switch (si->signal_received)
355 {
356 case SIGINT:
357 case SIGTERM:
358 state = OPENVPN_STATE_EXITING;
359 break;
360
361 case SIGHUP:
362 case SIGUSR1:
364 break;
365 }
366
367 if (state >= 0)
368 {
370 state,
371 si->signal_text ? si->signal_text : signal_name(si->signal_received, true),
372 NULL,
373 NULL,
374 NULL,
375 NULL);
376 }
377 }
378#endif /* ifdef ENABLE_MANAGEMENT */
379}
380
381#ifndef _WIN32
382/* normal signal handler, when we are in event loop */
383static void
384signal_handler(const int signum)
385{
387}
388#endif
389
390/* set handlers for unix signals */
391
392#define SM_UNDEF 0
393#define SM_PRE_INIT 1
394#define SM_POST_INIT 2
395static int signal_mode; /* GLOBAL */
396
397void
399{
400#ifndef _WIN32
401 sigset_t block_mask;
402 struct sigaction sa;
403 CLEAR(sa);
404
405 sigfillset(&block_mask); /* all signals */
406 sa.sa_handler = signal_handler;
407 sa.sa_mask = block_mask; /* signals blocked inside the handler */
408 sa.sa_flags = SA_RESTART; /* match with the behaviour of signal() on Linux and BSD */
409
411 sigaction(SIGINT, &sa, NULL);
412 sigaction(SIGTERM, &sa, NULL);
413
414 sa.sa_handler = SIG_IGN;
415 sigaction(SIGHUP, &sa, NULL);
416 sigaction(SIGUSR1, &sa, NULL);
417 sigaction(SIGUSR2, &sa, NULL);
418 sigaction(SIGPIPE, &sa, NULL);
419#endif /* _WIN32 */
420 /* clear any pending signals of the ignored type */
421 signal_reset(&siginfo_static, SIGUSR1);
422 signal_reset(&siginfo_static, SIGUSR2);
424}
425
426void
428{
429#ifndef _WIN32
430 sigset_t block_mask;
431 struct sigaction sa;
432 CLEAR(sa);
433
434 sigfillset(&block_mask); /* all signals */
435 sa.sa_handler = signal_handler;
436 sa.sa_mask = block_mask; /* signals blocked inside the handler */
437 sa.sa_flags = SA_RESTART; /* match with the behaviour of signal() on Linux and BSD */
438
440 sigaction(SIGINT, &sa, NULL);
441 sigaction(SIGTERM, &sa, NULL);
442 sigaction(SIGHUP, &sa, NULL);
443 sigaction(SIGUSR1, &sa, NULL);
444 sigaction(SIGUSR2, &sa, NULL);
445 sa.sa_handler = SIG_IGN;
446 sigaction(SIGPIPE, &sa, NULL);
447#endif /* _WIN32 */
448}
449
450void
452{
453#ifndef _WIN32
454 struct sigaction sa;
455 CLEAR(sa);
456 sa.sa_handler = SIG_IGN;
457 sigaction(SIGHUP, &sa, NULL);
458 sigaction(SIGUSR1, &sa, NULL);
459 sigaction(SIGUSR2, &sa, NULL);
460#endif /* _WIN32 */
461 ignored_hard_signals_mask = (1LL << SIGHUP) | (1LL << SIGUSR1) | (1LL << SIGUSR2);
462}
463
464/* called after daemonization to retain signal settings */
465void
467{
469 {
471 }
472 else if (signal_mode == SM_POST_INIT)
473 {
475 }
476}
477
478/*
479 * Print statistics.
480 *
481 * Triggered by SIGUSR2 or F2 on Windows.
482 */
483void
484print_status(struct context *c, struct status_output *so)
485{
486 struct gc_arena gc = gc_new();
487
488 status_reset(so);
489
490 if (dco_enabled(&c->options))
491 {
492 if (dco_get_peer_stats(c, true) < 0)
493 {
494 return;
495 }
496 }
497
498 status_printf(so, "OpenVPN STATISTICS");
499 status_printf(so, "Updated,%s", time_string(0, 0, false, &gc));
500 status_printf(so, "TUN/TAP read bytes," counter_format, c->c2.tun_read_bytes);
501 status_printf(so, "TUN/TAP write bytes," counter_format, c->c2.tun_write_bytes);
502 status_printf(so, "TCP/UDP read bytes," counter_format, c->c2.link_read_bytes + c->c2.dco_read_bytes);
503 status_printf(so, "TCP/UDP write bytes," counter_format, c->c2.link_write_bytes + c->c2.dco_write_bytes);
504 status_printf(so, "Auth read bytes," counter_format, c->c2.link_read_bytes_auth);
505#ifdef USE_COMP
506 if (c->c2.comp_context)
507 {
508 comp_print_stats(c->c2.comp_context, so);
509 }
510#endif
511#ifdef PACKET_TRUNCATION_CHECK
512 status_printf(so, "TUN read truncations," counter_format, c->c2.n_trunc_tun_read);
513 status_printf(so, "TUN write truncations," counter_format, c->c2.n_trunc_tun_write);
514 status_printf(so, "Pre-encrypt truncations," counter_format, c->c2.n_trunc_pre_encrypt);
515 status_printf(so, "Post-decrypt truncations," counter_format, c->c2.n_trunc_post_decrypt);
516#endif
517#ifdef _WIN32
518 if (tuntap_defined(c->c1.tuntap))
519 {
520 const char *extended_msg = tap_win_getinfo(c->c1.tuntap, &gc);
521 if (extended_msg)
522 {
523 status_printf(so, "TAP-WIN32 driver status,\"%s\"", extended_msg);
524 }
525 }
526#endif
527
528 status_printf(so, "END");
529 status_flush(so);
530 gc_free(&gc);
531}
532
533/*
534 * Handle the triggering and time-wait of explicit
535 * exit notification.
536 */
537static void
539{
540 msg(M_INFO, "SIGTERM received, sending exit notification to peer");
541 /* init the timeout to send the OCC_EXIT messages if cc exit is not
542 * enabled and also to exit after waiting for retries of resending of
543 * exit messages */
546
547 /* Windows exit event will continue trigering SIGTERM -- halt it */
549
550 /* Before resetting the signal, ensure hard low priority signals
551 * will be ignored during the exit notification period.
552 */
553 halt_low_priority_signals(); /* Set hard SIGUSR1/SIGHUP/SIGUSR2 to be ignored */
554 signal_reset(c->sig, 0);
555
557
558 /* Check if we are in TLS mode and should send the notification via data
559 * channel */
561 {
563 }
564}
565
566void
585
586/*
587 * Process signals
588 */
589
590void
592{
593 if (c->sig->signal_received == SIGUSR1 && c->options.remap_sigusr1)
594 {
596 }
597}
598
599static void
601{
602 struct status_output *so = status_open(NULL, 0, M_INFO, NULL, 0);
603 print_status(c, so);
604 status_close(so);
605 signal_reset(c->sig, SIGUSR2);
606}
607
608static bool
610{
611 bool ret = true;
614 {
616 ret = false;
617 }
618 return ret;
619}
620
626static void
628{
629 if ((c->sig->signal_received == SIGUSR1 || c->sig->signal_received == SIGHUP)
631 && c->sig->source != SIG_SOURCE_HARD)
632 {
633 msg(M_INFO, "Converting soft %s received during exit notification to SIGTERM",
634 signal_name(c->sig->signal_received, true));
635 register_signal(c->sig, SIGTERM, "exit-with-notification");
636 }
637}
638
639bool
641{
642 bool ret = true;
643
645
646 if (c->sig->signal_received == SIGTERM || c->sig->signal_received == SIGINT)
647 {
648 ret = process_sigterm(c);
649 }
650 else if (c->sig->signal_received == SIGUSR2)
651 {
653 ret = false;
654 }
655 return ret;
656}
static void gc_free(struct gc_arena *a)
Definition buffer.h:1033
static struct gc_arena gc_new(void)
Definition buffer.h:1025
#define counter_format
Definition common.h:31
static int dco_get_peer_stats(struct context *c, const bool raise_sigusr1_on_err)
Definition dco.h:386
#define D_PUSH
Definition errlevel.h:83
#define D_SIGNAL_DEBUG
Definition errlevel.h:119
#define M_INFO
Definition errlevel.h:55
bool send_control_channel_string(struct context *c, const char *str, int msglevel)
Definition forward.c:410
void reset_coarse_timers(struct context *c)
Definition init.c:1342
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:43
#define ETT_DEFAULT
Definition interval.h:224
static bool event_timeout_defined(const struct event_timeout *et)
Definition interval.h:144
static void event_timeout_init(struct event_timeout *et, interval_t n, const time_t last)
Initialises a timer struct.
Definition interval.h:174
static void event_timeout_clear(struct event_timeout *et)
Clears the timeout and reset all values to 0.
Definition interval.h:155
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:2749
#define OPENVPN_STATE_RECONNECTING
Definition manage.h:474
#define OPENVPN_STATE_EXITING
Definition manage.h:475
#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:160
#define CLEAR(x)
Definition basic.h:33
#define SIZE(x)
Definition basic.h:30
#define msg(flags,...)
Definition error.h:144
#define ASSERT(x)
Definition error.h:195
static bool dco_enabled(const struct options *o)
Returns whether the current configuration has dco enabled.
Definition options.h:929
const char * time_string(time_t t, long usec, bool show_usec, struct gc_arena *gc)
Definition otime.c:108
time_t now
Definition otime.c:34
static int signal_mode
Definition sig.c:395
bool process_signal(struct context *c)
Definition sig.c:640
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:627
static void unblock_async_signals(void)
Unblock all unix signals.
Definition sig.c:138
void signal_restart_status(const struct signal_info *si)
Definition sig.c:348
void post_init_signal_catch(void)
Definition sig.c:427
void throw_signal_soft(const int signum, const char *signal_text)
Throw a soft global signal.
Definition sig.c:206
void print_status(struct context *c, struct status_output *so)
Definition sig.c:484
const char * signal_name(const int sig, const bool upper)
Definition sig.c:93
static bool process_sigterm(struct context *c)
Definition sig.c:609
#define SM_PRE_INIT
Definition sig.c:393
int signal_reset(struct signal_info *si, int signum)
Clear the signal if its current value equals signum.
Definition sig.c:266
void process_explicit_exit_notification_timer_wakeup(struct context *c)
Definition sig.c:567
static unsigned long long ignored_hard_signals_mask
Definition sig.c:63
void pre_init_signal_catch(void)
Definition sig.c:398
void remap_signal(struct context *c)
Definition sig.c:591
#define SM_POST_INIT
Definition sig.c:394
const char * signal_description(const int signum, const char *sigtext)
Definition sig.c:107
void restore_signal_state(void)
Definition sig.c:466
void throw_signal(const int signum)
Throw a hard signal.
Definition sig.c:177
static const struct signame signames[]
Definition sig.c:54
int parse_signal(const char *signame)
Definition sig.c:66
struct signal_info siginfo_static
Definition sig.c:45
void halt_low_priority_signals(void)
Definition sig.c:451
static void block_async_signals(void)
Block (i.e., defer) all unix signals.
Definition sig.c:125
static void process_explicit_exit_notification_init(struct context *c)
Definition sig.c:538
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:231
void print_signal(const struct signal_info *si, const char *title, int msglevel)
Definition sig.c:294
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:160
static int signal_priority(int sig)
Definition sig.c:80
static void process_sigusr2(struct context *c)
Definition sig.c:600
static void halt_non_edge_triggered_signals(void)
Definition sig.h:92
#define SIG_SOURCE_CONNECTION_FAILED
Definition sig.h:35
#define SIG_SOURCE_SOFT
Definition sig.h:30
#define SIG_SOURCE_HARD
Definition sig.h:31
void status_printf(struct status_output *so, const char *format,...)
Definition status.c:222
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:61
void status_flush(struct status_output *so)
Definition status.c:157
void status_reset(struct status_output *so)
Definition status.c:148
bool status_close(struct status_output *so)
Definition status.c:188
int explicit_exit_notification
Definition options.h:148
struct tuntap * tuntap
Tun/tap virtual network interface.
Definition openvpn.h:171
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:500
struct context_2 c2
Level 2 context.
Definition openvpn.h:514
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:513
Garbage collection arena used to keep track of dynamically allocated memory.
Definition buffer.h:117
struct connection_entry ce
Definition options.h:288
int remap_sigusr1
Definition options.h:391
const char * signal_text
Definition sig.h:45
volatile int signal_received
Definition sig.h:43
volatile int source
Definition sig.h:44
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:155
const char * tap_win_getinfo(const struct tuntap *tt, struct gc_arena *gc)
Definition tun.c:6770
static bool tuntap_defined(const struct tuntap *tt)
Definition tun.h:254