From patchwork Tue Oct 27 22:21:08 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Antonio Quartulli X-Patchwork-Id: 10514 Return-Path: Received: from mail01.ipfire.org (mail01.haj.ipfire.org [172.28.1.202]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519) (Client CN "mail01.haj.ipfire.org", Issuer "YR1" (not verified)) by web04.haj.ipfire.org (Postfix) with ESMTPS id 4jDlMX3yTCz3xZj for ; Tue, 27 Oct 2026 22:21:28 +0000 (UTC) Received: from mail02.haj.ipfire.org (mail02.haj.ipfire.org [172.28.1.201]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519) (Client CN "mail02.haj.ipfire.org", Issuer "YE2" (not verified)) by mail01.ipfire.org (Postfix) with ESMTPS id 4jDlMW2vC8z6hP for ; Tue, 27 Oct 2026 22:21:27 +0000 (UTC) Received: from mail02.haj.ipfire.org (localhost [IPv6:::1]) by mail02.haj.ipfire.org (Postfix) with ESMTP id 4jDlMV3Sxzz36WS for ; Tue, 27 Oct 2026 22:21:26 +0000 (UTC) X-Original-To: development@lists.ipfire.org Received: from mail01.ipfire.org (mail01.haj.ipfire.org [IPv6:2001:678:b28::25]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519) (Client CN "mail01.haj.ipfire.org", Issuer "YR1" (not verified)) by mail02.haj.ipfire.org (Postfix) with ESMTPS id 4jDlMG6pfPz2xnL for ; Tue, 27 Oct 2026 22:21:14 +0000 (UTC) Received: from mout-b-110.mailbox.org (mout-b-110.mailbox.org [195.10.208.55]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519 server-signature RSA-PSS (4096 bit raw public key) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "*.mailbox.org", Issuer "Thawte TLS RSA CA G1" (verified OK)) by mail01.ipfire.org (Postfix) with ESMTPS id 4jDlMG061Lz3kH for ; Tue, 27 Oct 2026 22:21:14 +0000 (UTC) Authentication-Results: mail01.ipfire.org; dkim=pass header.d=mandelbit.com header.s=MBO0001 header.b=GGQDjirN; spf=pass (mail01.ipfire.org: domain of antonio@mandelbit.com designates 195.10.208.55 as permitted sender) smtp.mailfrom=antonio@mandelbit.com; dmarc=none ARC-Seal: i=1; a=rsa-sha256; d=lists.ipfire.org; s=202003rsa; cv=none; t=1793139674; b=rPHptH/bSRQ/gMz5MXdpKhNWbJsgMlnSyqWeBqM2HeRdKTFGNvCB+DkNEtnIWhzb5IUHF0 3gmuqA6Qm9UBZsbvVdN2kgM6S2MXVBpkkUTIWV08qpnhrDbsDguq1fkQM02Harv/b5x61b 32BwcMMS8+subCjKj4SrbL9pDOCQU7iAaEFE40+24hgi0ZZpbC+/hEnfEEHNCfAJGOjoWH h8idg/n+s7tesmnJvBVZcj1ARkGexOMF1ioPfRc33U8maBfQpCgHPOjfPRKjVTREQrOJEs KWQy2DQIL9RIGY6Hh3L55UfIOCAWC5KE705tobzrJ2gTL8rRObctqORRqfAc8Q== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=lists.ipfire.org; s=202003rsa; t=1793139674; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references:dkim-signature; bh=OeO54wydn+rtyumPpuSFU3hTzP+hzOelLaCn0AtNnY0=; b=RAdFK5cISfk2cYnXYrsXOI7ilycmYn4LOy1ZCcUuxo6YPPsxGI/L2nX6rMP1gGuoZo8u9j RzQ8cMF5zf3CYRtbhKruhUi/5Me7Tmp1HKfe9wZ5bJw2crldFmRKfoTyVSS1/t1xYEqpSB ebAYaB5aqnb6YQn210e65JhP+la9dY/neWkA0VKDMhjzupjQWvF/87fmL66MoIfUC3zY2Z nT6y/cOk0eosGX0NZeNAlsNzK9WoB8+F6ETh9lttwTJiPxidq1fdhVNYF8AZ6flHDWKibU ohSR3WM1Nu3a0A8xMQiCtYXJJ8hV7YPaQTf5O7m2j2tDLIWyqRqjHS59541INg== ARC-Authentication-Results: i=1; mail01.ipfire.org; dkim=pass header.d=mandelbit.com header.s=MBO0001 header.b=GGQDjirN; spf=pass (mail01.ipfire.org: domain of antonio@mandelbit.com designates 195.10.208.55 as permitted sender) smtp.mailfrom=antonio@mandelbit.com; dmarc=none Received: from smtp1.mailbox.org (smtp1.mailbox.org [IPv6:2001:67c:2050:b231:465::1]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519MLKEM768 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by mout-b-110.mailbox.org (Postfix) with ESMTPS id 4jDlMF36mrzNljY; Tue, 27 Oct 2026 23:21:13 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=mandelbit.com; s=MBO0001; t=1793139673; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=OeO54wydn+rtyumPpuSFU3hTzP+hzOelLaCn0AtNnY0=; b=GGQDjirNBnF2Tuqc59NwrOXnsdgxk3gqeUyJmbT7IhXBUuxbJkWxZGJeNgntnTWNjLTIry UC3PPyk6KwsXBSHnBMqOKIGYqaDDmctaA00xXH2/uPmzExcbDs47QHh1y9F8gpAPGcy60K 2RKTuGhMPbCXgpcIN9yNqALe8QKoh8mdY2kOhWIS3mwUQ8JObfifw+GO4hjJpqVymliGbQ Zp1FEYR6eHiEeKH/7pEV1G4YEArO9cpGtgYYLDFW3KelVHQ5gBhenr9AIvE0xhUiSAWMuo jDHv1agBJN5StEqFBEATj0U6my95lcRvsYGHgtwgsFkVDq/9MigIV99h6VUBAw== From: Antonio Quartulli To: development@lists.ipfire.org Cc: Antonio Quartulli Subject: [PATCH 1/3] ovpn-functions.pl: Add a helper to get the status of N2N connections Date: Tue, 27 Oct 2026 23:21:08 +0100 Message-ID: <20261027222110.2642078-2-antonio@mandelbit.com> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20261027222110.2642078-1-antonio@mandelbit.com> References: <20261027222110.2642078-1-antonio@mandelbit.com> Precedence: list List-Id: List-Subscribe: , List-Unsubscribe: , List-Post: List-Help: Sender: Mail-Followup-To: MIME-Version: 1.0 X-Rspamd-Action: no action X-Spamd-Result: default: False [-2.30 / 11.00]; BAYES_HAM(-3.00)[100.00%]; MID_CONTAINS_FROM(1.00)[]; R_MISSING_CHARSET(0.50)[]; RCVD_IN_DNSWL_LOW(-0.20)[2001:67c:2050:b231:465::1:received,195.10.208.55:from]; R_SPF_ALLOW(-0.20)[+ip4:195.10.208.0/24:c]; R_DKIM_ALLOW(-0.10)[mandelbit.com:s=MBO0001]; MIME_GOOD(-0.10)[text/plain]; MX_GOOD(-0.10)[mxext2.mailbox.org]; R_DKIM_ALIGNED(-0.10)[strict]; ASN(0.00)[asn:199118, ipnet:195.10.208.0/24, country:DE]; RCVD_COUNT_ONE(0.00)[1]; TO_DN_SOME(0.00)[]; ARC_SIGNED(0.00)[lists.ipfire.org:s=202003rsa:i=1]; MIME_TRACE(0.00)[0:+]; ARC_NA(0.00)[]; IP_REPUTATION_HAM(0.00)[asn: 199118(-0.31), country: DE(-0.01), ip: 195.10.208.55(0.00)]; DMARC_NA(0.00)[mandelbit.com]; FROM_EQ_ENVFROM(0.00)[]; FROM_HAS_DN(0.00)[]; DKIM_REPUTATION(0.00)[0]; RCVD_TLS_ALL(0.00)[]; RCPT_COUNT_TWO(0.00)[2]; TO_MATCH_ENVRCPT_SOME(0.00)[]; DKIM_TRACE(0.00)[mandelbit.com:+] X-Rspamd-Server: mail01.haj.ipfire.org X-Rspamd-Queue-Id: 4jDlMG061Lz3kH OpenVPN switches the management state to AUTH and WAIT when a new session is started while a tunnel is up, and keeps it there if that session never completes (e.g. a stray packet from the internet), although the tunnel keeps working. Therefore determine the status from the state history: an N2N connection is up if it has reached CONNECTED and has not restarted since. Signed-off-by: Antonio Quartulli --- config/cfgroot/ovpn-functions.pl | 96 ++++++++++++++++++++++++++++++ config/rootfiles/common/configroot | 1 + lfs/configroot | 1 + 3 files changed, 98 insertions(+) create mode 100644 config/cfgroot/ovpn-functions.pl diff --git a/config/cfgroot/ovpn-functions.pl b/config/cfgroot/ovpn-functions.pl new file mode 100644 index 000000000..3c6c02660 --- /dev/null +++ b/config/cfgroot/ovpn-functions.pl @@ -0,0 +1,96 @@ +#!/usr/bin/perl +############################################################################### +# # +# IPFire.org - A linux based firewall # +# Copyright (C) 2026 Antonio Quartulli # +# # +# This program is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see . # +# # +############################################################################### + +package OpenVPN; + +use strict; +use Net::Telnet; + +# Returns "CONNECTED" or "DISCONNECTED" for the N2N connection whose +# management interface listens on the given port. +# +# The current state alone cannot be trusted: when a new session is started +# while the tunnel is up (a peer that gives up, or just a stray packet from +# the internet), OpenVPN switches the state to AUTH and WAIT and keeps it +# there if that session never completes, although the tunnel keeps working. +# +# Therefore we look at the state history: the tunnel is up if the process +# has reached CONNECTED and has not restarted since. A tunnel that goes down +# is detected by ping-restart, which logs RECONNECTING. +sub n2n_status($) { + my $port = shift; + + # Create a new Telnet session + my $telnet = new Net::Telnet( + Port => $port, + Timeout => 3, + Errmode => "return", + ); + + # Connect + $telnet->open("127.0.0.1") or return "DISCONNECTED"; + + # Fetch the state history + my @output = $telnet->cmd( + String => "state all", + Prompt => "/(?:^|\n)(?:END|ERROR:.*)\n/" + ); + + $telnet->close(); + + # Collect all states, skipping the banner and any notifications + my @states; + + foreach my $line (@output) { + if ($line =~ m/^\d+,([A-Z_]+),/) { + push(@states, $1); + } + } + + return "DISCONNECTED" unless (@states); + + # The history always starts with CONNECTING, unless it has been truncated. + # A truncated history comes from a process that has not been restarted + # for a long time, which does not happen to an unconnected tunnel + # because of ping-restart. OpenVPN keeps the last 100 states only, so + # ~50 stray packets within one ping-restart interval after a restart + # could still make a down tunnel look connected. + my $connected = ($states[0] ne "CONNECTING"); + + foreach my $state (@states) { + if ($state eq "CONNECTED") { + $connected = 1; + + # The process starts (CONNECTING, logged once), restarts + # (RECONNECTING) or exits (EXITING) + } elsif ($state =~ m/^(CONNECTING|RECONNECTING|EXITING)$/) { + $connected = 0; + } + + # Any other state (WAIT, AUTH, ...) is either part of the initial + # connection or an attempt to start a new session that does not + # affect the existing one + } + + return $connected ? "CONNECTED" : "DISCONNECTED"; +} + +1; diff --git a/config/rootfiles/common/configroot b/config/rootfiles/common/configroot index 72e05e865..ffe1ebe72 100644 --- a/config/rootfiles/common/configroot +++ b/config/rootfiles/common/configroot @@ -138,6 +138,7 @@ var/ipfire/network-functions.pl var/ipfire/optionsfw #var/ipfire/optionsfw/settings var/ipfire/ovpn +var/ipfire/ovpn-functions.pl #var/ipfire/ovpn/ccd.conf #var/ipfire/ovpn/ccdroute #var/ipfire/ovpn/ccdroute2 diff --git a/lfs/configroot b/lfs/configroot index 3df566f50..0b14f6501 100644 --- a/lfs/configroot +++ b/lfs/configroot @@ -82,6 +82,7 @@ $(TARGET) : cp $(DIR_SRC)/config/cfgroot/location-functions.pl $(CONFIG_ROOT)/ cp $(DIR_SRC)/config/cfgroot/ipblocklist-functions.pl $(CONFIG_ROOT)/ cp $(DIR_SRC)/config/cfgroot/ids-functions.pl $(CONFIG_ROOT)/ + cp $(DIR_SRC)/config/cfgroot/ovpn-functions.pl $(CONFIG_ROOT)/ cp $(DIR_SRC)/config/cfgroot/wireguard-functions.pl $(CONFIG_ROOT)/ cp $(DIR_SRC)/config/cfgroot/lang.pl $(CONFIG_ROOT)/ cp $(DIR_SRC)/config/cfgroot/countries.pl $(CONFIG_ROOT)/ From patchwork Tue Oct 27 22:21:09 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Antonio Quartulli X-Patchwork-Id: 10513 Return-Path: Received: from mail01.ipfire.org (mail01.haj.ipfire.org [172.28.1.202]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519) (Client CN "mail01.haj.ipfire.org", Issuer "YR1" (not verified)) by web04.haj.ipfire.org (Postfix) with ESMTPS id 4jDlMX3ZWNz3xZg for ; Tue, 27 Oct 2026 22:21:28 +0000 (UTC) Received: from mail02.haj.ipfire.org (mail02.haj.ipfire.org [172.28.1.201]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519) (Client CN "mail02.haj.ipfire.org", Issuer "YE2" (not verified)) by mail01.ipfire.org (Postfix) with ESMTPS id 4jDlMW2zdGz7BZ for ; Tue, 27 Oct 2026 22:21:27 +0000 (UTC) Received: from mail02.haj.ipfire.org (localhost [IPv6:::1]) by mail02.haj.ipfire.org (Postfix) with ESMTP id 4jDlMV3jNwz36WT for ; Tue, 27 Oct 2026 22:21:26 +0000 (UTC) X-Original-To: development@lists.ipfire.org Received: from mail01.ipfire.org (mail01.haj.ipfire.org [172.28.1.202]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519) (Client CN "mail01.haj.ipfire.org", Issuer "YR1" (not verified)) by mail02.haj.ipfire.org (Postfix) with ESMTPS id 4jDlMH43xrz2yrG for ; Tue, 27 Oct 2026 22:21:15 +0000 (UTC) Received: from mout-b-106.mailbox.org (mout-b-106.mailbox.org [IPv6:2001:67c:2050:102:465::106]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519 server-signature RSA-PSS (4096 bit raw public key) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "*.mailbox.org", Issuer "Thawte TLS RSA CA G1" (verified OK)) by mail01.ipfire.org (Postfix) with ESMTPS id 4jDlMG4HYVz4jx for ; Tue, 27 Oct 2026 22:21:14 +0000 (UTC) Authentication-Results: mail01.ipfire.org; dkim=pass header.d=mandelbit.com header.s=MBO0001 header.b="A/BMNmCf"; spf=pass (mail01.ipfire.org: domain of antonio@mandelbit.com designates 2001:67c:2050:102:465::106 as permitted sender) smtp.mailfrom=antonio@mandelbit.com; dmarc=none ARC-Seal: i=1; a=rsa-sha256; d=lists.ipfire.org; s=202003rsa; cv=none; t=1793139674; b=FahEQDa0yu0dT7SnGy8hhBloZwqOgBaTY4mVs2tvAT6RntN2wJkJVxB/OI2q6igt4q/Ki0 RyqmYETNzYcjiodqvkvhDGNFqVwWLHpHwvrA0hzZsDNr/imvDckyP++ohDCXqSJEjRLzpG bJ7dDtHdNRLlSRrlXzqlOIhGJK4m3a71MnzuKDq+oZW8IIBmIqDlOmTUXGe4GJ83ysyTXg 7hKe7aJ8FpwW8kCy/D23aFtmhsY2slVox9ImBAzXwaTDMUb7NBz/6yYKkjPWZ5u/VWxQGm suSc/r3vonS5icO8OxLdyXPfXUQW32embZXofF1jQxbbfDgThy7qFBAGsBn1JQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=lists.ipfire.org; s=202003rsa; t=1793139674; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references:dkim-signature; bh=OuChQEeWelrnBoJu0msaDJJA5I0W+Bl5pzMpYJJ8+9Q=; b=ZXoRyazuEEHYnkj+lQ5P3vPzI3OiWI0XeU0CBi+co5bQ2u/2uTCYmAjD5mb7q2OHLnoq6N WqL5mEP7CCQFQfaJXYCVzVMGjwYzPjgTReG19+hb/1XzSoVNSfZCqM3dA4P+yJnhBYZqGN HfF2zpURIPAQ+qJKX+EpbanJQZpPTSjiFhorgaA8ecuY0qH8uEG+rkbyB3TtsAY6+hJij2 wBlt0zYiMGTd5O0npj4EiIWsbHdUcRg517tcvwW7SAE6iiSjYgC0qhVCOJr/MQqiPi5e+u HAHocCQfCqndmYrraNlzpjbrh0lTcBNOD9OjUMcqaNp+X5QiFuMrdvU5auNyRg== ARC-Authentication-Results: i=1; mail01.ipfire.org; dkim=pass header.d=mandelbit.com header.s=MBO0001 header.b="A/BMNmCf"; spf=pass (mail01.ipfire.org: domain of antonio@mandelbit.com designates 2001:67c:2050:102:465::106 as permitted sender) smtp.mailfrom=antonio@mandelbit.com; dmarc=none Received: from smtp1.mailbox.org (smtp1.mailbox.org [IPv6:2001:67c:2050:b231:465::1]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519MLKEM768 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by mout-b-106.mailbox.org (Postfix) with ESMTPS id 4jDlMF5KvMzNlhJ; Tue, 27 Oct 2026 23:21:13 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=mandelbit.com; s=MBO0001; t=1793139673; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=OuChQEeWelrnBoJu0msaDJJA5I0W+Bl5pzMpYJJ8+9Q=; b=A/BMNmCfOrLIqF6W7BAwYQydn0EwV8k28/WrqBujcho9M8B/05LnkHGhEGwk1ayPg5tPSR sBWqzHHv5J8Z90hqNWZLocMqXpGL3hLnJ6XqOciYEyL15JSVG/yky2hdCAQsZvZfRzBW32 UbWkY1WjUXUdkVz6jENvc3AAcI3OmhuGHr24nkxeedG7kpBdvzlk5jQpzLYqNubRqsr4EW 90Ru2QX1RwnAwx8aVKMZrQNRLMERKWP/m0Me8MFsfdDKCsA7yJGyYHKHU6ROHKw7ARHUL9 YugEHNueTlDjuFDwUnS3TZVGStZLCRiecCPfbR/U7VdZjmgCWGRIZvtmDiVwAg== From: Antonio Quartulli To: development@lists.ipfire.org Cc: Antonio Quartulli Subject: [PATCH 2/3] ovpnmain.cgi/index.cgi: Use OpenVPN::n2n_status() Date: Tue, 27 Oct 2026 23:21:09 +0100 Message-ID: <20261027222110.2642078-3-antonio@mandelbit.com> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20261027222110.2642078-1-antonio@mandelbit.com> References: <20261027222110.2642078-1-antonio@mandelbit.com> Precedence: list List-Id: List-Subscribe: , List-Unsubscribe: , List-Post: List-Help: Sender: Mail-Followup-To: MIME-Version: 1.0 X-Rspamd-Action: no action X-Spamd-Result: default: False [-2.20 / 11.00]; BAYES_HAM(-3.00)[100.00%]; MID_CONTAINS_FROM(1.00)[]; R_MISSING_CHARSET(0.50)[]; R_SPF_ALLOW(-0.20)[+ip6:2001:67c:2050::/48:c]; R_DKIM_ALLOW(-0.10)[mandelbit.com:s=MBO0001]; RCVD_IN_DNSWL_LOW(-0.10)[2001:67c:2050:b231:465::1:received]; MIME_GOOD(-0.10)[text/plain]; MX_GOOD(-0.10)[mxext2.mailbox.org]; R_DKIM_ALIGNED(-0.10)[strict]; ASN(0.00)[asn:199118, ipnet:2001:67c:2050::/48, country:DE]; RCVD_COUNT_ONE(0.00)[1]; TO_DN_SOME(0.00)[]; ARC_SIGNED(0.00)[lists.ipfire.org:s=202003rsa:i=1]; MIME_TRACE(0.00)[0:+]; ARC_NA(0.00)[]; IP_REPUTATION_HAM(0.00)[asn: 199118(-0.31), country: DE(-0.01), ip: 2001:67c:2050:102::(0.00)]; DMARC_NA(0.00)[mandelbit.com]; FROM_EQ_ENVFROM(0.00)[]; FROM_HAS_DN(0.00)[]; DKIM_REPUTATION(0.00)[0]; RCVD_TLS_ALL(0.00)[]; RCPT_COUNT_TWO(0.00)[2]; TO_MATCH_ENVRCPT_SOME(0.00)[]; DKIM_TRACE(0.00)[mandelbit.com:+] X-Rspamd-Server: mail01.haj.ipfire.org X-Rspamd-Queue-Id: 4jDlMG4HYVz4jx Both pages now use the same check, so a working N2N tunnel is no longer shown as DISCONNECTED after an incomplete session attempt. Fixes: #13897 Signed-off-by: Antonio Quartulli --- html/cgi-bin/index.cgi | 12 ++------ html/cgi-bin/ovpnmain.cgi | 58 ++------------------------------------- 2 files changed, 5 insertions(+), 65 deletions(-) diff --git a/html/cgi-bin/index.cgi b/html/cgi-bin/index.cgi index 0f51ba9ff..b5f23a59a 100644 --- a/html/cgi-bin/index.cgi +++ b/html/cgi-bin/index.cgi @@ -20,7 +20,6 @@ ############################################################################### use strict; -use Net::Telnet; use Sort::Naturally; # enable only the following on debugging purpose @@ -31,6 +30,7 @@ require '/var/ipfire/general-functions.pl'; require "${General::swroot}/lang.pl"; require "${General::swroot}/header.pl"; require "${General::swroot}/wireguard-functions.pl"; +require "${General::swroot}/ovpn-functions.pl"; require "/opt/pakfire/lib/functions.pl"; my %cgiparams=(); @@ -504,17 +504,11 @@ END $count++; my $tport = $ovpnconfig{$dkey}[22]; next if ($tport eq ''); - my $tnet = new Net::Telnet ( Timeout=>5, Errmode=>'return', Port=>$tport); - $tnet->open('127.0.0.1'); - my @output = $tnet->cmd(String => 'state', Prompt => '/(END.*\n|ERROR:.*\n)/'); - my @tustate = split(/\,/, $output[1]); - my $display; + my $display = _('DISCONNECTED'); my $display_colour = $Header::colourred; - if ( $tustate[1] eq 'CONNECTED' || ($tustate[1] eq 'WAIT')) { + if (&OpenVPN::n2n_status($tport) eq "CONNECTED") { $display_colour = $Header::colourgreen; $display = _('CONNECTED'); - } else { - $display = $tustate[1]; } if ($count %2){ $col = $color{'color22'}; diff --git a/html/cgi-bin/ovpnmain.cgi b/html/cgi-bin/ovpnmain.cgi index 35561f4e7..d28f895cd 100644 --- a/html/cgi-bin/ovpnmain.cgi +++ b/html/cgi-bin/ovpnmain.cgi @@ -31,7 +31,6 @@ use MIME::Base32; use MIME::Base64; use Net::DNS; use Net::Ping; -use Net::Telnet; use Sort::Naturally; use URI::Encode qw(uri_encode uri_decode);; @@ -39,6 +38,7 @@ require '/var/ipfire/general-functions.pl'; require "${General::swroot}/header.pl"; require "${General::swroot}/countries.pl"; require "${General::swroot}/location-functions.pl"; +require "${General::swroot}/ovpn-functions.pl"; # enable only the following on debugging purpose #use warnings; @@ -1024,60 +1024,6 @@ sub writecollectdconf { &General::system("/usr/local/bin/collectdctrl", "restart"); } -sub openvpn_status($) { - my $port = shift; - - # Create a new Telnet session - my $telnet = new Net::Telnet( - Port => $port, - Timeout => 1, - Errmode => "return", - ); - - # Connect - $telnet->open("127.0.0.1"); - - # Send a command - my @output = $telnet->cmd( - String => "state", - Prompt => "/(END.*\n|ERROR:.*\n)/" - ); - - my ($time, $status) = split(/\,/, $output[1]); - - ### - #CONNECTING -- OpenVPN's initial state. - #WAIT -- (Client only) Waiting for initial response from server. - #AUTH -- (Client only) Authenticating with server. - #GET_CONFIG -- (Client only) Downloading configuration options from server. - #ASSIGN_IP -- Assigning IP address to virtual network interface. - #ADD_ROUTES -- Adding routes to system. - #CONNECTED -- Initialization Sequence Completed. - #RECONNECTING -- A restart has occurred. - #EXITING -- A graceful exit is in progress. - #### - - if ($status eq "CONNECTING") { - return "DISCONNECTED"; - } elsif ($status eq "WAIT") { - return "DISCONNECTED"; - } elsif ($status eq "AUTH") { - return "DISCONNECTED"; - } elsif ($status eq "GET_CONFIG") { - return "DISCONNECTED"; - } elsif ($status eq "ASSIGN_IP") { - return "DISCONNECTED"; - } elsif ($status eq "ADD_ROUTES") { - return "DISCONNECTED"; - } elsif ($status eq "RECONNECTING") { - return "CONNECTED"; - } elsif ($status eq "EXITING") { - return "DISCONNECTED"; - } - - return $status; -} - # Hook to regenerate the configuration files if ($ENV{"REMOTE_ADDR"} eq "") { &writeserverconf(); @@ -5309,7 +5255,7 @@ END my $port = $confighash{$key}[22]; if ($port ne "") { - $connstatus = &openvpn_status($confighash{$key}[22]); + $connstatus = &OpenVPN::n2n_status($port); } } From patchwork Tue Oct 27 22:21:10 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Antonio Quartulli X-Patchwork-Id: 10515 Return-Path: Received: from mail01.ipfire.org (mail01.haj.ipfire.org [172.28.1.202]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519) (Client CN "mail01.haj.ipfire.org", Issuer "YR1" (not verified)) by web04.haj.ipfire.org (Postfix) with ESMTPS id 4jDlMX45HZz3xZk for ; Tue, 27 Oct 2026 22:21:28 +0000 (UTC) Received: from mail02.haj.ipfire.org (mail02.haj.ipfire.org [IPv6:2001:678:b28::201]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519) (Client CN "mail02.haj.ipfire.org", Issuer "YE2" (not verified)) by mail01.ipfire.org (Postfix) with ESMTPS id 4jDlMW2zNrz7BR for ; Tue, 27 Oct 2026 22:21:27 +0000 (UTC) Received: from mail02.haj.ipfire.org (localhost [IPv6:::1]) by mail02.haj.ipfire.org (Postfix) with ESMTP id 4jDlMV3Mj2z36X6 for ; Tue, 27 Oct 2026 22:21:26 +0000 (UTC) X-Original-To: development@lists.ipfire.org Received: from mail01.ipfire.org (mail01.haj.ipfire.org [IPv6:2001:678:b28::25]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519) (Client CN "mail01.haj.ipfire.org", Issuer "YR1" (not verified)) by mail02.haj.ipfire.org (Postfix) with ESMTPS id 4jDlMH440Lz30Gc for ; Tue, 27 Oct 2026 22:21:15 +0000 (UTC) Received: from mout-b-203.mailbox.org (mout-b-203.mailbox.org [IPv6:2001:67c:2050:102:465::203]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519 server-signature RSA-PSS (4096 bit raw public key) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "*.mailbox.org", Issuer "Thawte TLS RSA CA G1" (verified OK)) by mail01.ipfire.org (Postfix) with ESMTPS id 4jDlMG6Vkmz3Gb for ; Tue, 27 Oct 2026 22:21:14 +0000 (UTC) Authentication-Results: mail01.ipfire.org; dkim=pass header.d=mandelbit.com header.s=MBO0001 header.b=IwDrZzYd; spf=pass (mail01.ipfire.org: domain of antonio@mandelbit.com designates 2001:67c:2050:102:465::203 as permitted sender) smtp.mailfrom=antonio@mandelbit.com; dmarc=none ARC-Seal: i=1; a=rsa-sha256; d=lists.ipfire.org; s=202003rsa; cv=none; t=1793139675; b=O+1fSWxW9lzXdjfRzHdphhpRTDqWLs1RUXhsBNzBL2v3NETYr/+PAzeSdrHdyrtwWmZa/A +DESA5cMZByz56mdPAjXO29RY5hAnOyWhvBEAOoFzj1caxhgHijLzzPg8k04wd2/FWSeCw UBS/27FAnI5/F4yI95l0PB1ZYzTpxfJXkc1AGgBCGKxHwapnd+GkjrMk9QmcTvz+uliIOC 9nXeTsbCiQPRnHZkjpKOOz2WsToeUgaFG3h3IB0hz63YVFGTfOMta4zug22CJyjMLMZeo5 eYoONqdhHZpKipYwJL8PUuHXVuEhxm7Dl67pXS5QRaOQjM/1poW0xaDnKBB91A== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=lists.ipfire.org; s=202003rsa; t=1793139675; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references:dkim-signature; bh=j58qZJCWQrzyAIgF+2lhjSeLjSzQVW0AGdXwb0spUCA=; b=sJM9xKzQqNbO2vkUgywbDD/rXikiyX9LlNE+G/PSF+spQHRDoKsjU2e1IsZZHSrOgAeROL CDNvP9Aw/zLzx0TlRStg7xn2dV5Ap6aES313EEA23fzko565igYe9vzJNMbNo7YSLimQsH vXRsTtG/ZSggYjIZh4j/+WyZL33FKN9LBvMaxN55Ef58Ewj/YdEedvMIqZvoB1gKPC78Ji C2AHZpJ6ZkDKACXRlXjhQ7/0KrmKBIyDZE2bonEV8B/YttwPTecRWI9CvGeAcoLta89keA YHCctomHQ0poxlyY74zJDzCXBsifzfICOg0EkHNeEQcHnQy7MVlFMTlqqnSAIQ== ARC-Authentication-Results: i=1; mail01.ipfire.org; dkim=pass header.d=mandelbit.com header.s=MBO0001 header.b=IwDrZzYd; spf=pass (mail01.ipfire.org: domain of antonio@mandelbit.com designates 2001:67c:2050:102:465::203 as permitted sender) smtp.mailfrom=antonio@mandelbit.com; dmarc=none Received: from smtp1.mailbox.org (smtp1.mailbox.org [IPv6:2001:67c:2050:b231:465::1]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519MLKEM768 server-signature RSA-PSS (4096 bits) server-digest SHA512) (No client certificate requested) by mout-b-203.mailbox.org (Postfix) with ESMTPS id 4jDlMG200BzLmHG; Tue, 27 Oct 2026 23:21:14 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=mandelbit.com; s=MBO0001; t=1793139674; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=j58qZJCWQrzyAIgF+2lhjSeLjSzQVW0AGdXwb0spUCA=; b=IwDrZzYdVGgsNbh7zEQ13XlkSRroJCVZKd8Q3Fydlahvs7/xKbJXNPpViBpzwJfnvidaNe FzSIA45xRQjA2aRwfkfcnY1eVQEXC5ShdJXXZjsU5XjJb7zYnbBpCOaQ7iN9doULV1QT1n M2nOQxkubPpCI4ZIKZp40dS+pAcsLgzsEFPuH9IwW37L0OVoJq3uKMAnSreeUhxz1JQ08Z 0LfhatGEh0xLSthyCtl6k+2zXSyNjpe9/j2GqkoyjpWdGkjb/2mgsEOV4+yGhoIYeClfJU j5k8A51jpOtaFn0JiCMnqiUJyB3dH1Nwn2ITUUHgfZSJVk2FumhSwxik3J6VMg== From: Antonio Quartulli To: development@lists.ipfire.org Cc: Antonio Quartulli Subject: [PATCH 3/3] tests: Add tests for OpenVPN::n2n_status() Date: Tue, 27 Oct 2026 23:21:10 +0100 Message-ID: <20261027222110.2642078-4-antonio@mandelbit.com> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20261027222110.2642078-1-antonio@mandelbit.com> References: <20261027222110.2642078-1-antonio@mandelbit.com> Precedence: list List-Id: List-Subscribe: , List-Unsubscribe: , List-Post: List-Help: Sender: Mail-Followup-To: MIME-Version: 1.0 X-Rspamd-Action: no action X-Spamd-Result: default: False [-2.20 / 11.00]; BAYES_HAM(-3.00)[100.00%]; MID_CONTAINS_FROM(1.00)[]; R_MISSING_CHARSET(0.50)[]; R_SPF_ALLOW(-0.20)[+ip6:2001:67c:2050::/48:c]; R_DKIM_ALLOW(-0.10)[mandelbit.com:s=MBO0001]; RCVD_IN_DNSWL_LOW(-0.10)[2001:67c:2050:b231:465::1:received]; MIME_GOOD(-0.10)[text/plain]; MX_GOOD(-0.10)[mxext2.mailbox.org]; R_DKIM_ALIGNED(-0.10)[strict]; ASN(0.00)[asn:199118, ipnet:2001:67c:2050::/48, country:DE]; RCVD_COUNT_ONE(0.00)[1]; TO_DN_SOME(0.00)[]; ARC_SIGNED(0.00)[lists.ipfire.org:s=202003rsa:i=1]; MIME_TRACE(0.00)[0:+]; ARC_NA(0.00)[]; IP_REPUTATION_HAM(0.00)[asn: 199118(-0.31), country: DE(-0.01), ip: 2001:67c:2050:102::(0.00)]; DMARC_NA(0.00)[mandelbit.com]; FROM_EQ_ENVFROM(0.00)[]; FROM_HAS_DN(0.00)[]; DKIM_REPUTATION(0.00)[0]; RCVD_TLS_ALL(0.00)[]; RCPT_COUNT_TWO(0.00)[2]; TO_MATCH_ENVRCPT_SOME(0.00)[]; DKIM_TRACE(0.00)[mandelbit.com:+] X-Rspamd-Server: mail01.haj.ipfire.org X-Rspamd-Queue-Id: 4jDlMG6Vkmz3Gb Run n2n_status() against a fake management interface, including a new session that never completes on an established tunnel (#13897). Signed-off-by: Antonio Quartulli --- .../ovpn-functions.pl/data/auth_pending | 6 ++ .../cfgroot/ovpn-functions.pl/data/connected | 7 ++ .../data/connected_stray_session | 8 ++ .../cfgroot/ovpn-functions.pl/data/empty | 1 + .../cfgroot/ovpn-functions.pl/data/exiting | 7 ++ .../ovpn-functions.pl/data/never_connected | 6 ++ .../ovpn-functions.pl/data/notifications | 11 +++ .../ovpn-functions.pl/data/reconnected | 11 +++ .../ovpn-functions.pl/data/reconnecting | 9 +++ .../cfgroot/ovpn-functions.pl/data/truncated | 3 + .../cfgroot/ovpn-functions.pl/n2n_status.pl | 73 +++++++++++++++++++ .../config/cfgroot/ovpn-functions.pl/test.sh | 70 ++++++++++++++++++ 12 files changed, 212 insertions(+) create mode 100644 tests/config/cfgroot/ovpn-functions.pl/data/auth_pending create mode 100644 tests/config/cfgroot/ovpn-functions.pl/data/connected create mode 100644 tests/config/cfgroot/ovpn-functions.pl/data/connected_stray_session create mode 100644 tests/config/cfgroot/ovpn-functions.pl/data/empty create mode 100644 tests/config/cfgroot/ovpn-functions.pl/data/exiting create mode 100644 tests/config/cfgroot/ovpn-functions.pl/data/never_connected create mode 100644 tests/config/cfgroot/ovpn-functions.pl/data/notifications create mode 100644 tests/config/cfgroot/ovpn-functions.pl/data/reconnected create mode 100644 tests/config/cfgroot/ovpn-functions.pl/data/reconnecting create mode 100644 tests/config/cfgroot/ovpn-functions.pl/data/truncated create mode 100644 tests/config/cfgroot/ovpn-functions.pl/n2n_status.pl create mode 100755 tests/config/cfgroot/ovpn-functions.pl/test.sh diff --git a/tests/config/cfgroot/ovpn-functions.pl/data/auth_pending b/tests/config/cfgroot/ovpn-functions.pl/data/auth_pending new file mode 100644 index 000000000..aca1f1b57 --- /dev/null +++ b/tests/config/cfgroot/ovpn-functions.pl/data/auth_pending @@ -0,0 +1,6 @@ +1793050400,CONNECTING,,,,,, +1793050417,CONNECTED,SUCCESS,10.8.0.1,127.0.0.1,21195,, +1793050448,AUTH_PENDING,,,,,, +1793054017,RECONNECTING,ping-restart,,,,, +1793054022,WAIT,,,,,, +END diff --git a/tests/config/cfgroot/ovpn-functions.pl/data/connected b/tests/config/cfgroot/ovpn-functions.pl/data/connected new file mode 100644 index 000000000..afd358d07 --- /dev/null +++ b/tests/config/cfgroot/ovpn-functions.pl/data/connected @@ -0,0 +1,7 @@ +1793050400,CONNECTING,,,,,, +1793050401,WAIT,,,,,, +1793050402,AUTH,,,,,, +1793050403,GET_CONFIG,,,,,, +1793050404,ASSIGN_IP,,10.8.0.1,,,, +1793050417,CONNECTED,SUCCESS,10.8.0.1,127.0.0.1,21195,, +END diff --git a/tests/config/cfgroot/ovpn-functions.pl/data/connected_stray_session b/tests/config/cfgroot/ovpn-functions.pl/data/connected_stray_session new file mode 100644 index 000000000..78a3a5bd5 --- /dev/null +++ b/tests/config/cfgroot/ovpn-functions.pl/data/connected_stray_session @@ -0,0 +1,8 @@ +1793050400,CONNECTING,,,,,, +1793050401,WAIT,,,,,, +1793050402,AUTH,,,,,, +1793050404,ASSIGN_IP,,10.8.0.1,,,, +1793050417,CONNECTED,SUCCESS,10.8.0.1,127.0.0.1,21195,, +1793054017,AUTH,,,,,, +1793054018,WAIT,,,,,, +END diff --git a/tests/config/cfgroot/ovpn-functions.pl/data/empty b/tests/config/cfgroot/ovpn-functions.pl/data/empty new file mode 100644 index 000000000..dce2c1d51 --- /dev/null +++ b/tests/config/cfgroot/ovpn-functions.pl/data/empty @@ -0,0 +1 @@ +END diff --git a/tests/config/cfgroot/ovpn-functions.pl/data/exiting b/tests/config/cfgroot/ovpn-functions.pl/data/exiting new file mode 100644 index 000000000..cc3fd5300 --- /dev/null +++ b/tests/config/cfgroot/ovpn-functions.pl/data/exiting @@ -0,0 +1,7 @@ +1793050400,CONNECTING,,,,,, +1793050401,WAIT,,,,,, +1793050402,AUTH,,,,,, +1793050404,ASSIGN_IP,,10.8.0.1,,,, +1793050417,CONNECTED,SUCCESS,10.8.0.1,127.0.0.1,21195,, +1793054017,EXITING,SIGTERM,,,,, +END diff --git a/tests/config/cfgroot/ovpn-functions.pl/data/never_connected b/tests/config/cfgroot/ovpn-functions.pl/data/never_connected new file mode 100644 index 000000000..d40357abd --- /dev/null +++ b/tests/config/cfgroot/ovpn-functions.pl/data/never_connected @@ -0,0 +1,6 @@ +1793050400,CONNECTING,,,,,, +1793050401,WAIT,,,,,, +1793050402,AUTH,,,,,, +1793050462,WAIT,,,,,, +1793050463,AUTH,,,,,, +END diff --git a/tests/config/cfgroot/ovpn-functions.pl/data/notifications b/tests/config/cfgroot/ovpn-functions.pl/data/notifications new file mode 100644 index 000000000..a2db8e956 --- /dev/null +++ b/tests/config/cfgroot/ovpn-functions.pl/data/notifications @@ -0,0 +1,11 @@ +>HOLD:Waiting for hold release:0 +1793050400,CONNECTING,,,,,, +>STATE:1793050401,WAIT,,,,,, +1793050401,WAIT,,,,,, +1793050402,AUTH,,,,,, +>LOG:1793050403,I,Peer Connection Initiated +1793050417,CONNECTED,SUCCESS,10.8.0.1,127.0.0.1,21195,, +>STATE:1793054017,AUTH,,,,,, +1793054017,AUTH,,,,,, +1793054018,WAIT,,,,,, +END diff --git a/tests/config/cfgroot/ovpn-functions.pl/data/reconnected b/tests/config/cfgroot/ovpn-functions.pl/data/reconnected new file mode 100644 index 000000000..3b1530458 --- /dev/null +++ b/tests/config/cfgroot/ovpn-functions.pl/data/reconnected @@ -0,0 +1,11 @@ +1793050400,CONNECTING,,,,,, +1793050401,WAIT,,,,,, +1793050402,AUTH,,,,,, +1793050404,ASSIGN_IP,,10.8.0.1,,,, +1793050417,CONNECTED,SUCCESS,10.8.0.1,127.0.0.1,21195,, +1793054017,RECONNECTING,ping-restart,,,,, +1793054022,WAIT,,,,,, +1793054023,AUTH,,,,,, +1793054024,GET_CONFIG,,,,,, +1793054025,CONNECTED,SUCCESS,10.8.0.1,127.0.0.1,21195,, +END diff --git a/tests/config/cfgroot/ovpn-functions.pl/data/reconnecting b/tests/config/cfgroot/ovpn-functions.pl/data/reconnecting new file mode 100644 index 000000000..97c0d32d6 --- /dev/null +++ b/tests/config/cfgroot/ovpn-functions.pl/data/reconnecting @@ -0,0 +1,9 @@ +1793050400,CONNECTING,,,,,, +1793050401,WAIT,,,,,, +1793050402,AUTH,,,,,, +1793050404,ASSIGN_IP,,10.8.0.1,,,, +1793050417,CONNECTED,SUCCESS,10.8.0.1,127.0.0.1,21195,, +1793054017,RECONNECTING,ping-restart,,,,, +1793054022,WAIT,,,,,, +1793054023,AUTH,,,,,, +END diff --git a/tests/config/cfgroot/ovpn-functions.pl/data/truncated b/tests/config/cfgroot/ovpn-functions.pl/data/truncated new file mode 100644 index 000000000..a4137f117 --- /dev/null +++ b/tests/config/cfgroot/ovpn-functions.pl/data/truncated @@ -0,0 +1,3 @@ +1793050417,AUTH,,,,,, +1793050418,WAIT,,,,,, +END diff --git a/tests/config/cfgroot/ovpn-functions.pl/n2n_status.pl b/tests/config/cfgroot/ovpn-functions.pl/n2n_status.pl new file mode 100644 index 000000000..5876ef2f0 --- /dev/null +++ b/tests/config/cfgroot/ovpn-functions.pl/n2n_status.pl @@ -0,0 +1,73 @@ +#!/usr/bin/perl +# +# Runs OpenVPN::n2n_status() against a fake OpenVPN management interface +# and prints the result. +# +# Usage: n2n_status.pl +# +# The fake management interface sends the banner, waits for "state all" +# and replies with the content of the data file. + +use strict; +use warnings; +use IO::Socket::INET; + +my ($functions, $mode) = @ARGV; + +require $functions; + +my $server = IO::Socket::INET->new( + LocalAddr => "127.0.0.1", + LocalPort => 0, + Proto => "tcp", + Listen => 1, + ReuseAddr => 1, +) or die "Could not create socket: $!\n"; + +my $port = $server->sockport(); + +# Nothing listening on the port +if ($mode eq "--no-server") { + $server->close(); + print OpenVPN::n2n_status($port) . "\n"; + exit 0; +} + +my $pid = fork() // die "Could not fork: $!\n"; + +if ($pid == 0) { + my $client = $server->accept() or exit 1; + + # Close the connection right away + if ($mode eq "--close") { + $client->close(); + exit 0; + } + + open(my $fh, "<", $mode) or die "Could not open $mode: $!\n"; + my @reply = <$fh>; + close($fh); + + $client->autoflush(1); + print $client ">INFO:OpenVPN Management Interface Version 5 -- type 'help' for more info\r\n"; + + while (my $line = <$client>) { + last if ($line =~ m/^state all\r?\n/); + } + + foreach my $line (@reply) { + chomp($line); + print $client "$line\r\n"; + } + + # Wait for the client to disconnect + while (<$client>) {} + + exit 0; +} + +$server->close(); + +print OpenVPN::n2n_status($port) . "\n"; + +waitpid($pid, 0); diff --git a/tests/config/cfgroot/ovpn-functions.pl/test.sh b/tests/config/cfgroot/ovpn-functions.pl/test.sh new file mode 100755 index 000000000..2110cf4f7 --- /dev/null +++ b/tests/config/cfgroot/ovpn-functions.pl/test.sh @@ -0,0 +1,70 @@ +#!/bin/bash + +SCRIPT_PATH="$(dirname "$(readlink -f "$0")")" + +ROOT="$(readlink -f "${SCRIPT_PATH}/../../../..")" + +. ${ROOT}/tests/lib.sh + +n2n_status() { + perl "${SCRIPT_PATH}/n2n_status.pl" "${ROOT}/config/cfgroot/ovpn-functions.pl" "$@" +} + +# Run n2n_status() against a fake management interface replying with the given +# state history and check the result +test_n2n_status() { + local data="${1}" + local expected="${2}" + local status + + status="$(n2n_status "${data}")" + + if [[ "${status}" == "${expected}" ]]; then + log_test_succeded "n2n_status() returns '${status}' for '${data##*/}'" + return 0 + else + log_test_failed "n2n_status() returns '${status}' for '${data##*/}' and not '${expected}'" + return 1 + fi +} + +if ! perl -MNet::Telnet -e 1 &>/dev/null; then + log_test_failed "The perl module Net::Telnet is not installed" + exit 1 +fi + +# The tunnel came up +test_n2n_status "${SCRIPT_PATH}/data/connected" "CONNECTED" + +# A new session that never completes does not affect the tunnel (#13897) +test_n2n_status "${SCRIPT_PATH}/data/connected_stray_session" "CONNECTED" + +# Notifications are ignored +test_n2n_status "${SCRIPT_PATH}/data/notifications" "CONNECTED" + +# The tunnel went down and came back up +test_n2n_status "${SCRIPT_PATH}/data/reconnected" "CONNECTED" + +# The process has been running for a long time +test_n2n_status "${SCRIPT_PATH}/data/truncated" "CONNECTED" + +# The tunnel went down +test_n2n_status "${SCRIPT_PATH}/data/reconnecting" "DISCONNECTED" + +# The tunnel never came up +test_n2n_status "${SCRIPT_PATH}/data/never_connected" "DISCONNECTED" + +# A state containing "END" does not end the history early +test_n2n_status "${SCRIPT_PATH}/data/auth_pending" "DISCONNECTED" + +# The process is exiting +test_n2n_status "${SCRIPT_PATH}/data/exiting" "DISCONNECTED" + +# No states at all +test_n2n_status "${SCRIPT_PATH}/data/empty" "DISCONNECTED" + +# The management interface closes the connection +test_n2n_status --close "DISCONNECTED" + +# The management interface is not running +test_n2n_status --no-server "DISCONNECTED"