Skip to content

Commit 6f9ba8b

Browse files
ralflicicron2
authored andcommitted
Handle missing DCO peer by restarting the session
Occasionally, CMD_DEL_PEER is not delivered to userspace, preventing the openvpn process from registering the event. To handle this case, we check if calls to the Linux DCO module return an error, and, if so, send a SIGUSR1 signal to reset the session. Most DCO commands that return an error already trigger a SIGUSR1 signal or even call _exit(1). This commit extends that behavior to include dco_get_peer_stats_multi() and dco_get_peer_stats(). Change-Id: Ib118426c5a69256894040c69856a4003d9f4637c Signed-off-by: Ralf Lici <[email protected]> Acked-by: Frank Lichtenheld <[email protected]> Message-Id: <[email protected]> URL: https://www.mail-archive.com/[email protected]/msg31022.html Signed-off-by: Gert Doering <[email protected]>
1 parent 7e55352 commit 6f9ba8b

File tree

8 files changed

+63
-21
lines changed

8 files changed

+63
-21
lines changed

src/openvpn/dco.h

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -231,17 +231,20 @@ void dco_delete_iroutes(struct multi_context *m, struct multi_instance *mi);
231231
/**
232232
* Update traffic statistics for all peers
233233
*
234-
* @param dco DCO device context
235-
* @param m the server context
234+
* @param dco DCO device context
235+
* @param m the server context
236+
* @param raise_sigusr1_on_err whether to raise SIGUSR1 on error
236237
**/
237-
int dco_get_peer_stats_multi(dco_context_t *dco, struct multi_context *m);
238+
int dco_get_peer_stats_multi(dco_context_t *dco, struct multi_context *m,
239+
const bool raise_sigusr1_on_err);
238240

239241
/**
240242
* Update traffic statistics for single peer
241243
*
242-
* @param c instance context of the peer
244+
* @param c instance context of the peer
245+
* @param raise_sigusr1_on_err whether to raise SIGUSR1 on error
243246
**/
244-
int dco_get_peer_stats(struct context *c);
247+
int dco_get_peer_stats(struct context *c, const bool raise_sigusr1_on_err);
245248

246249
/**
247250
* 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)
373376
}
374377

375378
static inline int
376-
dco_get_peer_stats_multi(dco_context_t *dco, struct multi_context *m)
379+
dco_get_peer_stats_multi(dco_context_t *dco, struct multi_context *m,
380+
const bool raise_sigusr1_on_err)
377381
{
378382
return 0;
379383
}
380384

381385
static inline int
382-
dco_get_peer_stats(struct context *c)
386+
dco_get_peer_stats(struct context *c, const bool raise_sigusr1_on_err)
383387
{
384388
return 0;
385389
}

src/openvpn/dco_freebsd.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -713,7 +713,8 @@ dco_update_peer_stat(struct multi_context *m, uint32_t peerid, const nvlist_t *n
713713
}
714714

715715
int
716-
dco_get_peer_stats_multi(dco_context_t *dco, struct multi_context *m)
716+
dco_get_peer_stats_multi(dco_context_t *dco, struct multi_context *m,
717+
const bool raise_sigusr1_on_err)
717718
{
718719

719720
struct ifdrv drv;
@@ -781,7 +782,7 @@ dco_get_peer_stats_multi(dco_context_t *dco, struct multi_context *m)
781782
}
782783

783784
int
784-
dco_get_peer_stats(struct context *c)
785+
dco_get_peer_stats(struct context *c, const bool raise_sigusr1_on_err)
785786
{
786787
/* Not implemented. */
787788
return 0;

src/openvpn/dco_linux.c

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -952,7 +952,8 @@ dco_parse_peer_multi(struct nl_msg *msg, void *arg)
952952
}
953953

954954
int
955-
dco_get_peer_stats_multi(dco_context_t *dco, struct multi_context *m)
955+
dco_get_peer_stats_multi(dco_context_t *dco, struct multi_context *m,
956+
const bool raise_sigusr1_on_err)
956957
{
957958
msg(D_DCO_DEBUG, "%s", __func__);
958959

@@ -963,6 +964,14 @@ dco_get_peer_stats_multi(dco_context_t *dco, struct multi_context *m)
963964
int ret = ovpn_nl_msg_send(dco, nl_msg, dco_parse_peer_multi, m, __func__);
964965

965966
nlmsg_free(nl_msg);
967+
968+
if (raise_sigusr1_on_err && ret < 0)
969+
{
970+
msg(M_WARN, "Error retrieving DCO peer stats: the underlying DCO peer"
971+
"may have been deleted from the kernel without notifying "
972+
"userspace. Restarting the session");
973+
register_signal(m->top.sig, SIGUSR1, "dco peer stats error");
974+
}
966975
return ret;
967976
}
968977

@@ -1008,9 +1017,14 @@ dco_parse_peer(struct nl_msg *msg, void *arg)
10081017
}
10091018

10101019
int
1011-
dco_get_peer_stats(struct context *c)
1020+
dco_get_peer_stats(struct context *c, const bool raise_sigusr1_on_err)
10121021
{
1013-
uint32_t peer_id = c->c2.tls_multi->dco_peer_id;
1022+
int peer_id = c->c2.tls_multi->dco_peer_id;
1023+
if (peer_id == -1)
1024+
{
1025+
return 0;
1026+
}
1027+
10141028
msg(D_DCO_DEBUG, "%s: peer-id %d", __func__, peer_id);
10151029

10161030
if (!c->c1.tuntap)
@@ -1030,6 +1044,14 @@ dco_get_peer_stats(struct context *c)
10301044

10311045
nla_put_failure:
10321046
nlmsg_free(nl_msg);
1047+
1048+
if (raise_sigusr1_on_err && ret < 0)
1049+
{
1050+
msg(M_WARN, "Error retrieving DCO peer stats: the underlying DCO peer"
1051+
"may have been deleted from the kernel without notifying "
1052+
"userspace. Restarting the session");
1053+
register_signal(c->sig, SIGUSR1, "dco peer stats error");
1054+
}
10331055
return ret;
10341056
}
10351057

src/openvpn/dco_win.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -712,14 +712,15 @@ dco_do_read(dco_context_t *dco)
712712
}
713713

714714
int
715-
dco_get_peer_stats_multi(dco_context_t *dco, struct multi_context *m)
715+
dco_get_peer_stats_multi(dco_context_t *dco, struct multi_context *m,
716+
const bool raise_sigusr1_on_err)
716717
{
717718
/* Not implemented. */
718719
return 0;
719720
}
720721

721722
int
722-
dco_get_peer_stats(struct context *c)
723+
dco_get_peer_stats(struct context *c, const bool raise_sigusr1_on_err)
723724
{
724725
struct tuntap *tt = c->c1.tuntap;
725726

src/openvpn/forward.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -488,7 +488,7 @@ check_add_routes(struct context *c)
488488
static void
489489
check_inactivity_timeout(struct context *c)
490490
{
491-
if (dco_enabled(&c->options) && dco_get_peer_stats(c) == 0)
491+
if (dco_enabled(&c->options) && dco_get_peer_stats(c, true) == 0)
492492
{
493493
int64_t tot_bytes = c->c2.tun_read_bytes + c->c2.tun_write_bytes;
494494
int64_t new_bytes = tot_bytes - c->c2.inactivity_bytes;
@@ -497,7 +497,6 @@ check_inactivity_timeout(struct context *c)
497497
{
498498
c->c2.inactivity_bytes = tot_bytes;
499499
event_timeout_reset(&c->c2.inactivity_interval);
500-
501500
return;
502501
}
503502
}

src/openvpn/manage.c

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4146,8 +4146,13 @@ management_check_bytecount(struct context *c, struct management *man, struct tim
41464146
counter_type dco_read_bytes = 0;
41474147
counter_type dco_write_bytes = 0;
41484148

4149-
if (dco_enabled(&c->options) && (dco_get_peer_stats(c) == 0))
4149+
if (dco_enabled(&c->options))
41504150
{
4151+
if (dco_get_peer_stats(c, true) < 0)
4152+
{
4153+
return;
4154+
}
4155+
41514156
dco_read_bytes = c->c2.dco_read_bytes;
41524157
dco_write_bytes = c->c2.dco_write_bytes;
41534158
}
@@ -4166,7 +4171,8 @@ management_check_bytecount(struct context *c, struct management *man, struct tim
41664171
void
41674172
man_persist_client_stats(struct management *man, struct context *c)
41684173
{
4169-
if (dco_enabled(&c->options) && (dco_get_peer_stats(c) == 0))
4174+
/* no need to raise SIGUSR1 since we are already closing the instance */
4175+
if (dco_enabled(&c->options) && (dco_get_peer_stats(c, false) == 0))
41704176
{
41714177
management_bytes_client(man, c->c2.dco_read_bytes, c->c2.dco_write_bytes);
41724178
}

src/openvpn/multi.c

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -548,7 +548,10 @@ setenv_stats(struct multi_context *m, struct context *c)
548548
{
549549
if (dco_enabled(&m->top.options))
550550
{
551-
dco_get_peer_stats_multi(&m->top.c1.tuntap->dco, m);
551+
if (dco_get_peer_stats_multi(&m->top.c1.tuntap->dco, m, false) < 0)
552+
{
553+
return;
554+
}
552555
}
553556

554557
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
856859

857860
if (dco_enabled(&m->top.options))
858861
{
859-
dco_get_peer_stats_multi(&m->top.c1.tuntap->dco, m);
862+
if (dco_get_peer_stats_multi(&m->top.c1.tuntap->dco, m, true) < 0)
863+
{
864+
return;
865+
}
860866
}
861867

862868
if (version == 1)

src/openvpn/sig.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -489,7 +489,10 @@ print_status(struct context *c, struct status_output *so)
489489

490490
if (dco_enabled(&c->options))
491491
{
492-
dco_get_peer_stats(c);
492+
if (dco_get_peer_stats(c, true) < 0)
493+
{
494+
return;
495+
}
493496
}
494497

495498
status_printf(so, "OpenVPN STATISTICS");

0 commit comments

Comments
 (0)