From 2ff4154159c1d00b382c2b865ed7f49306dea657 Mon Sep 17 00:00:00 2001 From: Grigory Trenin Date: Mon, 18 May 2026 17:40:45 -0400 Subject: [PATCH] Distinguish reason codes in AnyConnect BYE packets Cisco AnyConnect clients may send a BYE packet with a 0x91 payload, followed by ASCII text "Reconnecting the VPN tunnel." Resolves: #732 Signed-off-by: Grigory Trenin --- NEWS | 1 + src/vpn.h | 6 ++++++ src/worker-vpn.c | 22 +++++++++++++++------- 3 files changed, 22 insertions(+), 7 deletions(-) diff --git a/NEWS b/NEWS index ca879ccf..77e030b7 100644 --- a/NEWS +++ b/NEWS @@ -3,6 +3,7 @@ configurable PAM service names, enabling per-vhost PAM stacks (#718) - ocserv-fw-nftables: dropped runtime dependency on ipcalc/ipcalc-ng (#709) - Fixed sudden disconnects after authentication for AnyConnect clients (#706) +- Distinguish disconnect reasons in AnyConnect BYE packets (#732) - Vhosts now inherit configuration options from the default vhost if they are not overridden (#705) - `tunnel-all-dns` now works correctly when set in per-user/group config (#708) diff --git a/src/vpn.h b/src/vpn.h index 4360292a..715f849d 100644 --- a/src/vpn.h +++ b/src/vpn.h @@ -119,6 +119,12 @@ inline static const char *proto_to_str(fw_proto_t proto) #define AC_PKT_COMPRESSED 8 /* Compressed data */ #define AC_PKT_TERM_SERVER 9 /* Server kick */ +/* Disconnect reason for AC_PKT_DISCONN */ +#define AC_BYE_USER_DISCONNECT 0xb0 /* User requested to disconnect */ +#define AC_BYE_LOCAL_ERROR 0x70 /* E.g., unable to modify routing table */ +#define AC_BYE_VPN_RECONNECT 0x91 /* VPN tunnel is reconnecting */ +#define AC_BYE_VPN_PAUSE 0xd1 /* VPN tunnel is paused */ + #define REKEY_METHOD_SSL 1 #define REKEY_METHOD_NEW_TUNNEL 2 diff --git a/src/worker-vpn.c b/src/worker-vpn.c index 04796a21..830b6249 100644 --- a/src/worker-vpn.c +++ b/src/worker-vpn.c @@ -2679,19 +2679,27 @@ static int parse_data(struct worker_st *ws, uint8_t *buf, size_t buf_size, * an intention to reconnect (e.g., because network was * changed). We separate the error codes to ensure we do * not interpret the intention incorrectly (see #281). */ - if (plain_size > 0 && plain[0] == 0xb0) { - exit_worker_reason(ws, REASON_USER_DISCONNECT); - } else { - if (plain_size > 0) { + if (plain_size > 0) { + const uint8_t bye_reason = plain[0]; + + switch (bye_reason) { + case AC_BYE_USER_DISCONNECT: + oclog(ws, LOG_DEBUG, + "User requested to disconnect"); + exit_worker_reason(ws, REASON_USER_DISCONNECT); + case AC_BYE_VPN_RECONNECT: + oclog(ws, LOG_DEBUG, + "VPN tunnel is reconnecting"); + exit_worker_reason(ws, REASON_TEMP_DISCONNECT); + default: oclog_hex(ws, LOG_DEBUG, "bye packet with unknown payload", plain, plain_size, 0); return -1; } - - exit_worker_reason(ws, REASON_TEMP_DISCONNECT); } - break; + exit_worker_reason(ws, REASON_TEMP_DISCONNECT); + case AC_PKT_COMPRESSED: /* decompress */ if (is_dtls == 0) { /* CSTP */