diff --git a/src/openvpn/dco.h b/src/openvpn/dco.h index 35ceace3aac..ed194cc5017 100644 --- a/src/openvpn/dco.h +++ b/src/openvpn/dco.h @@ -231,17 +231,20 @@ void dco_delete_iroutes(struct multi_context *m, struct multi_instance *mi); /** * Update traffic statistics for all peers * - * @param dco DCO device context - * @param m the server context + * @param dco DCO device context + * @param m the server context + * @param raise_sigusr1_on_err whether to raise SIGUSR1 on error **/ -int dco_get_peer_stats_multi(dco_context_t *dco, struct multi_context *m); +int dco_get_peer_stats_multi(dco_context_t *dco, struct multi_context *m, + const bool raise_sigusr1_on_err); /** * Update traffic statistics for single peer * - * @param c instance context of the peer + * @param c instance context of the peer + * @param raise_sigusr1_on_err whether to raise SIGUSR1 on error **/ -int dco_get_peer_stats(struct context *c); +int dco_get_peer_stats(struct context *c, const bool raise_sigusr1_on_err); /** * Retrieve the list of ciphers supported by the current platform @@ -373,13 +376,14 @@ dco_delete_iroutes(struct multi_context *m, struct multi_instance *mi) } static inline int -dco_get_peer_stats_multi(dco_context_t *dco, struct multi_context *m) +dco_get_peer_stats_multi(dco_context_t *dco, struct multi_context *m, + const bool raise_sigusr1_on_err) { return 0; } static inline int -dco_get_peer_stats(struct context *c) +dco_get_peer_stats(struct context *c, const bool raise_sigusr1_on_err) { return 0; } diff --git a/src/openvpn/dco_freebsd.c b/src/openvpn/dco_freebsd.c index 0e536de8050..b8816c63bd4 100644 --- a/src/openvpn/dco_freebsd.c +++ b/src/openvpn/dco_freebsd.c @@ -713,7 +713,8 @@ dco_update_peer_stat(struct multi_context *m, uint32_t peerid, const nvlist_t *n } int -dco_get_peer_stats_multi(dco_context_t *dco, struct multi_context *m) +dco_get_peer_stats_multi(dco_context_t *dco, struct multi_context *m, + const bool raise_sigusr1_on_err) { struct ifdrv drv; @@ -781,7 +782,7 @@ dco_get_peer_stats_multi(dco_context_t *dco, struct multi_context *m) } int -dco_get_peer_stats(struct context *c) +dco_get_peer_stats(struct context *c, const bool raise_sigusr1_on_err) { /* Not implemented. */ return 0; diff --git a/src/openvpn/dco_linux.c b/src/openvpn/dco_linux.c index 68c1a8d3271..b0a85fdaf36 100644 --- a/src/openvpn/dco_linux.c +++ b/src/openvpn/dco_linux.c @@ -952,7 +952,8 @@ dco_parse_peer_multi(struct nl_msg *msg, void *arg) } int -dco_get_peer_stats_multi(dco_context_t *dco, struct multi_context *m) +dco_get_peer_stats_multi(dco_context_t *dco, struct multi_context *m, + const bool raise_sigusr1_on_err) { msg(D_DCO_DEBUG, "%s", __func__); @@ -963,6 +964,14 @@ dco_get_peer_stats_multi(dco_context_t *dco, struct multi_context *m) int ret = ovpn_nl_msg_send(dco, nl_msg, dco_parse_peer_multi, m, __func__); nlmsg_free(nl_msg); + + if (raise_sigusr1_on_err && ret < 0) + { + msg(M_WARN, "Error retrieving DCO peer stats: the underlying DCO peer" + "may have been deleted from the kernel without notifying " + "userspace. Restarting the session"); + register_signal(m->top.sig, SIGUSR1, "dco peer stats error"); + } return ret; } @@ -1008,9 +1017,14 @@ dco_parse_peer(struct nl_msg *msg, void *arg) } int -dco_get_peer_stats(struct context *c) +dco_get_peer_stats(struct context *c, const bool raise_sigusr1_on_err) { - uint32_t peer_id = c->c2.tls_multi->dco_peer_id; + int peer_id = c->c2.tls_multi->dco_peer_id; + if (peer_id == -1) + { + return 0; + } + msg(D_DCO_DEBUG, "%s: peer-id %d", __func__, peer_id); if (!c->c1.tuntap) @@ -1030,6 +1044,14 @@ dco_get_peer_stats(struct context *c) nla_put_failure: nlmsg_free(nl_msg); + + if (raise_sigusr1_on_err && ret < 0) + { + msg(M_WARN, "Error retrieving DCO peer stats: the underlying DCO peer" + "may have been deleted from the kernel without notifying " + "userspace. Restarting the session"); + register_signal(c->sig, SIGUSR1, "dco peer stats error"); + } return ret; } diff --git a/src/openvpn/dco_win.c b/src/openvpn/dco_win.c index 45cb919277c..8b47124631b 100644 --- a/src/openvpn/dco_win.c +++ b/src/openvpn/dco_win.c @@ -712,14 +712,15 @@ dco_do_read(dco_context_t *dco) } int -dco_get_peer_stats_multi(dco_context_t *dco, struct multi_context *m) +dco_get_peer_stats_multi(dco_context_t *dco, struct multi_context *m, + const bool raise_sigusr1_on_err) { /* Not implemented. */ return 0; } int -dco_get_peer_stats(struct context *c) +dco_get_peer_stats(struct context *c, const bool raise_sigusr1_on_err) { struct tuntap *tt = c->c1.tuntap; diff --git a/src/openvpn/forward.c b/src/openvpn/forward.c index b0253443aa3..fce7ac8bb5e 100644 --- a/src/openvpn/forward.c +++ b/src/openvpn/forward.c @@ -488,7 +488,7 @@ check_add_routes(struct context *c) static void check_inactivity_timeout(struct context *c) { - if (dco_enabled(&c->options) && dco_get_peer_stats(c) == 0) + if (dco_enabled(&c->options) && dco_get_peer_stats(c, true) == 0) { int64_t tot_bytes = c->c2.tun_read_bytes + c->c2.tun_write_bytes; int64_t new_bytes = tot_bytes - c->c2.inactivity_bytes; @@ -497,7 +497,6 @@ check_inactivity_timeout(struct context *c) { c->c2.inactivity_bytes = tot_bytes; event_timeout_reset(&c->c2.inactivity_interval); - return; } } diff --git a/src/openvpn/manage.c b/src/openvpn/manage.c index 484042ada70..0e73942762a 100644 --- a/src/openvpn/manage.c +++ b/src/openvpn/manage.c @@ -4146,8 +4146,13 @@ management_check_bytecount(struct context *c, struct management *man, struct tim counter_type dco_read_bytes = 0; counter_type dco_write_bytes = 0; - if (dco_enabled(&c->options) && (dco_get_peer_stats(c) == 0)) + if (dco_enabled(&c->options)) { + if (dco_get_peer_stats(c, true) < 0) + { + return; + } + dco_read_bytes = c->c2.dco_read_bytes; dco_write_bytes = c->c2.dco_write_bytes; } @@ -4166,7 +4171,8 @@ management_check_bytecount(struct context *c, struct management *man, struct tim void man_persist_client_stats(struct management *man, struct context *c) { - if (dco_enabled(&c->options) && (dco_get_peer_stats(c) == 0)) + /* no need to raise SIGUSR1 since we are already closing the instance */ + if (dco_enabled(&c->options) && (dco_get_peer_stats(c, false) == 0)) { management_bytes_client(man, c->c2.dco_read_bytes, c->c2.dco_write_bytes); } diff --git a/src/openvpn/multi.c b/src/openvpn/multi.c index 85a1712e233..9d244be6d79 100644 --- a/src/openvpn/multi.c +++ b/src/openvpn/multi.c @@ -548,7 +548,10 @@ setenv_stats(struct multi_context *m, struct context *c) { if (dco_enabled(&m->top.options)) { - dco_get_peer_stats_multi(&m->top.c1.tuntap->dco, m); + if (dco_get_peer_stats_multi(&m->top.c1.tuntap->dco, m, false) < 0) + { + return; + } } setenv_counter(c->c2.es, "bytes_received", c->c2.link_read_bytes + c->c2.dco_read_bytes); @@ -856,7 +859,10 @@ multi_print_status(struct multi_context *m, struct status_output *so, const int if (dco_enabled(&m->top.options)) { - dco_get_peer_stats_multi(&m->top.c1.tuntap->dco, m); + if (dco_get_peer_stats_multi(&m->top.c1.tuntap->dco, m, true) < 0) + { + return; + } } if (version == 1) diff --git a/src/openvpn/sig.c b/src/openvpn/sig.c index 8323f0d97f2..b0f8935d430 100644 --- a/src/openvpn/sig.c +++ b/src/openvpn/sig.c @@ -489,7 +489,10 @@ print_status(struct context *c, struct status_output *so) if (dco_enabled(&c->options)) { - dco_get_peer_stats(c); + if (dco_get_peer_stats(c, true) < 0) + { + return; + } } status_printf(so, "OpenVPN STATISTICS");