diff --git a/src/opnsense/scripts/openvpn/kill_session.py b/src/opnsense/scripts/openvpn/kill_session.py
new file mode 100755
index 000000000..0bf0a103a
--- /dev/null
+++ b/src/opnsense/scripts/openvpn/kill_session.py
@@ -0,0 +1,82 @@
+#!/usr/local/bin/python3
+
+"""
+ Copyright (c) 2023 Ad Schellevis
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+"""
+
+import argparse
+import glob
+import socket
+import re
+import os
+import ujson
+socket.setdefaulttimeout(5)
+
+
+
+def ovpn_cmd(filename, cmd):
+ try:
+ sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
+ sock.connect(filename)
+ except socket.error:
+ return None
+
+ sock.send(('%s\n'%cmd).encode())
+ buffer = ''
+ while True:
+ try:
+ buffer += sock.recv(65536).decode()
+ except socket.timeout:
+ break
+ eob = buffer[-200:]
+ if eob.find('END') > -1 or eob.find('ERROR') > -1 or eob.find('SUCCESS') > -1:
+ break
+ sock.close()
+ return buffer
+
+
+if __name__ == '__main__':
+ parser = argparse.ArgumentParser()
+ parser.add_argument('server_id', help='server/client id (where to find socket)', type=int)
+ parser.add_argument('session_id', help='session id (address+port) or common name')
+ args = parser.parse_args()
+ socket_name = None
+ for filename in glob.glob("/var/etc/openvpn/*.sock"):
+ basename = os.path.basename(filename)
+ if basename in ['client%d.sock'%args.server_id, 'server%d.sock'%args.server_id]:
+ socket_name = filename
+ break
+ if socket_name:
+ res = ovpn_cmd(socket_name, 'kill %s\n' % args.session_id)
+ if res.find('SUCCESS:') >= 0:
+ clients = 0
+ for tmp in res.strip().split('\n')[-1].split():
+ if tmp.isdigit():
+ clients = int(tmp)
+ print(ujson.encode({'status': 'killed', 'clients': clients}))
+ else:
+ print(ujson.encode({'status': 'not_found'}))
+ else:
+ print(ujson.encode({'status': 'server_not_found'}))
diff --git a/src/opnsense/scripts/openvpn/ovpn_status.py b/src/opnsense/scripts/openvpn/ovpn_status.py
index 37b96a5ce..7d6613364 100755
--- a/src/opnsense/scripts/openvpn/ovpn_status.py
+++ b/src/opnsense/scripts/openvpn/ovpn_status.py
@@ -99,7 +99,7 @@ def ovpn_state(filename):
if len(tmp) > 2 and tmp[0].isdigit():
response['timestamp'] = int(tmp[0])
response['status'] = tmp[1].lower()
- response['virtual_addr'] = tmp[3] if len(tmp) > 3 else ""
+ response['virtual_address'] = tmp[3] if len(tmp) > 3 else ""
response['remote_host'] = tmp[4] if len(tmp) > 4 else ""
return response
diff --git a/src/opnsense/service/conf/actions.d/actions_openvpn.conf b/src/opnsense/service/conf/actions.d/actions_openvpn.conf
index 96dcb104b..8283fb473 100644
--- a/src/opnsense/service/conf/actions.d/actions_openvpn.conf
+++ b/src/opnsense/service/conf/actions.d/actions_openvpn.conf
@@ -3,3 +3,10 @@ command:/usr/local/opnsense/scripts/openvpn/ovpn_status.py
parameters: --option %s
type:script_output
message:Query OpenVPN status (%s)
+
+
+[kill]
+command:/usr/local/opnsense/scripts/openvpn/kill_session.py
+parameters: %s %s
+type:script_output
+message:Kill OpenVPN session %s - %s
diff --git a/src/www/status_openvpn.php b/src/www/status_openvpn.php
deleted file mode 100644
index 6f12af934..000000000
--- a/src/www/status_openvpn.php
+++ /dev/null
@@ -1,304 +0,0 @@
-
- * Copyright (C) 2010 Jim Pingle
- * Copyright (C) 2008 Shrew Soft Inc.
- * Copyright (C) 2005 Scott Ullrich
- * Copyright (C) 2005 Colin Smith
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
- * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
- * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
- * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-require_once("guiconfig.inc");
-require_once("interfaces.inc");
-require_once("plugins.inc.d/openvpn.inc");
-
-function kill_client($port, $client = null)
-{
- $tcpsrv = "unix:///var/etc/openvpn/{$port}.sock";
- $errval = '';
- $errstr = '';
-
- /* open a tcp connection to the management port of each server */
- $fp = @stream_socket_client($tcpsrv, $errval, $errstr, 1);
- $killed = -1;
- if ($fp) {
- stream_set_timeout($fp, 1);
- fputs($fp, "kill {$client}\n");
- while (!feof($fp)) {
- $line = fgets($fp, 1024);
-
- $info = stream_get_meta_data($fp);
- if ($info['timed_out']) {
- break;
- }
- /* parse header list line */
- if (strpos($line, "INFO:") !== false) {
- continue;
- }
- if (strpos($line, "SUCCESS") !== false) {
- $killed = 0;
- }
- break;
- }
- fclose($fp);
- }
- return $killed;
-}
-
-if ($_SERVER['REQUEST_METHOD'] === 'GET') {
- $vpnid = 0;
-} elseif ($_SERVER['REQUEST_METHOD'] === 'POST') {
- if (isset($_POST['action']) && $_POST['action'] == 'kill') {
- $port = $_POST['port'];
- $remipp = $_POST['remipp'];
- $common_name = $_POST['common_name'];
- if (!empty($port) && !empty($remipp)) {
- $retval = kill_client($port, $remipp);
- if ($retval == -1 && !empty($common_name)) {
- // kill by common name when the address couldn't be killed
- $retval = kill_client($port, $common_name);
- echo html_safe("|{$port}|{$common_name}|{$retval}|");
- } else {
- echo html_safe("|{$port}|{$remipp}|{$retval}|");
- }
- } else {
- echo gettext("invalid input");
- }
- exit;
- }
-}
-
-$openvpn_status = json_decode(configd_run('openvpn connections client,server'), true) ?? [];
-$openvpn_cfg = openvpn_config();
-legacy_html_escape_form_data($openvpn_status);
-legacy_html_escape_form_data($openvpn_cfg);
-
-include("head.inc"); ?>
-
-
-
-
-
-
-
-