mirror of
https://github.com/opnsense/plugins.git
synced 2026-05-28 04:34:15 -04:00
Merge 052d2f0183 into cb9a5d6d69
This commit is contained in:
commit
4be7f89c69
22 changed files with 729 additions and 0 deletions
|
|
@ -49,6 +49,7 @@ misc/theme-rebellion -- A suitably dark theme
|
|||
misc/theme-tukan -- The tukan theme - blue/white
|
||||
misc/theme-vicuna -- The vicuna theme - blue sapphire
|
||||
net/chrony -- Chrony time synchronisation
|
||||
net/cloudflared -- Cloudflare Tunnel Service
|
||||
net/freeradius -- RADIUS Authentication, Authorization and Accounting Server
|
||||
net/frr -- The FRRouting Protocol Suite
|
||||
net/ftp-proxy -- Control ftp-proxy processes
|
||||
|
|
|
|||
8
net/cloudflared/Makefile
Normal file
8
net/cloudflared/Makefile
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
PLUGIN_NAME= cloudflared
|
||||
PLUGIN_VERSION= 0.1.0
|
||||
PLUGIN_REVISION= 1
|
||||
PLUGIN_COMMENT= Cloudflare Tunnel integration
|
||||
PLUGIN_MAINTAINER= rick+github@insanityinside.net
|
||||
PLUGIN_DEPENDS= cloudflared
|
||||
|
||||
.include "../../Mk/plugins.mk"
|
||||
7
net/cloudflared/pkg-descr
Normal file
7
net/cloudflared/pkg-descr
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
Integrates the Cloudflare Tunnel daemon (cloudflared) into OPNsense,
|
||||
allowing self-hosted services to be exposed through Cloudflare Zero Trust
|
||||
without requiring inbound firewall rules or a public IP address.
|
||||
|
||||
WWW: https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/
|
||||
|
||||
Inspired by original work by Alan Martines <alancpmartines@hotmail.com>.
|
||||
89
net/cloudflared/src/etc/inc/plugins.inc.d/cloudflared.inc
Normal file
89
net/cloudflared/src/etc/inc/plugins.inc.d/cloudflared.inc
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (C) 2026 Richard Aspden <rick+github@insanityinside.net>
|
||||
* 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.
|
||||
*/
|
||||
|
||||
function cloudflared_enabled()
|
||||
{
|
||||
return (string)(new \OPNsense\Cloudflared\Cloudflared())->general->enabled == '1';
|
||||
}
|
||||
|
||||
function cloudflared_configure()
|
||||
{
|
||||
return [
|
||||
'newwanip' => ['cloudflared_configure_newwanip'],
|
||||
];
|
||||
}
|
||||
|
||||
function cloudflared_configure_newwanip($verbose = false)
|
||||
{
|
||||
if (!cloudflared_enabled()) {
|
||||
return;
|
||||
}
|
||||
if (file_exists('/var/run/cloudflared.pid')) {
|
||||
return;
|
||||
}
|
||||
(new \OPNsense\Core\Backend())->configdRun('cloudflared start');
|
||||
}
|
||||
|
||||
function cloudflared_services()
|
||||
{
|
||||
global $config;
|
||||
|
||||
$services = [];
|
||||
|
||||
if (
|
||||
isset($config['OPNsense']['Cloudflared']['general']['enabled']) &&
|
||||
$config['OPNsense']['Cloudflared']['general']['enabled'] == '1'
|
||||
) {
|
||||
$services[] = [
|
||||
'description' => gettext('Cloudflare Tunnel'),
|
||||
'configd' => [
|
||||
'start' => ['cloudflared start'],
|
||||
'restart' => ['cloudflared restart'],
|
||||
'stop' => ['cloudflared stop'],
|
||||
],
|
||||
'name' => 'cloudflared',
|
||||
'pidfile' => '/var/run/cloudflared.pid',
|
||||
];
|
||||
}
|
||||
|
||||
return $services;
|
||||
}
|
||||
|
||||
function cloudflared_xmlrpc_sync()
|
||||
{
|
||||
$result = [];
|
||||
|
||||
$result[] = [
|
||||
'description' => gettext('Cloudflare Tunnel'),
|
||||
'section' => 'OPNsense.Cloudflared',
|
||||
'id' => 'cloudflared',
|
||||
'services' => ['cloudflared'],
|
||||
];
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (C) 2026 Richard Aspden <rick+github@insanityinside.net>
|
||||
* 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.
|
||||
*/
|
||||
|
||||
namespace OPNsense\Cloudflared\Api;
|
||||
|
||||
use OPNsense\Base\ApiMutableServiceControllerBase;
|
||||
use OPNsense\Core\Backend;
|
||||
|
||||
class ServiceController extends ApiMutableServiceControllerBase
|
||||
{
|
||||
protected static $internalServiceClass = '\OPNsense\Cloudflared\Cloudflared';
|
||||
protected static $internalServiceTemplate = 'OPNsense/Cloudflared';
|
||||
protected static $internalServiceEnabled = 'general.enabled';
|
||||
protected static $internalServiceName = 'cloudflared';
|
||||
|
||||
public function reconfigureAction()
|
||||
{
|
||||
if ($this->request->isPost()) {
|
||||
(new Backend())->configdRun('cloudflared reconfigure');
|
||||
return ['status' => 'ok'];
|
||||
}
|
||||
return ['status' => 'failed'];
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (C) 2026 Richard Aspden <rick+github@insanityinside.net>
|
||||
* 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.
|
||||
*/
|
||||
|
||||
namespace OPNsense\Cloudflared\Api;
|
||||
|
||||
use OPNsense\Base\ApiMutableModelControllerBase;
|
||||
|
||||
class SettingsController extends ApiMutableModelControllerBase
|
||||
{
|
||||
protected static $internalModelClass = '\OPNsense\Cloudflared\Cloudflared';
|
||||
protected static $internalModelName = 'cloudflared';
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (C) 2026 Richard Aspden <rick+github@insanityinside.net>
|
||||
* 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.
|
||||
*/
|
||||
|
||||
namespace OPNsense\Cloudflared;
|
||||
|
||||
class IndexController extends \OPNsense\Base\IndexController
|
||||
{
|
||||
public function indexAction()
|
||||
{
|
||||
$this->view->general = $this->getForm("general");
|
||||
$this->view->pick('OPNsense/Cloudflared/index');
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
<form>
|
||||
<field>
|
||||
<type>header</type>
|
||||
<label>General Settings</label>
|
||||
</field>
|
||||
<field>
|
||||
<id>cloudflared.general.enabled</id>
|
||||
<label>Enable</label>
|
||||
<type>checkbox</type>
|
||||
<help>Enable the Cloudflare Tunnel service.</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>cloudflared.general.token</id>
|
||||
<label>Tunnel Token</label>
|
||||
<type>text</type>
|
||||
<help>Tunnel token from the Cloudflare Zero Trust dashboard (Networks > Tunnels). The token is stored in a root-readable file and passed to cloudflared via an environment variable.</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>cloudflared.general.protocol</id>
|
||||
<label>Protocol</label>
|
||||
<type>dropdown</type>
|
||||
<help>Transport protocol. Leave on auto unless you have a specific reason to force QUIC or HTTP/2.</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>cloudflared.general.post_quantum</id>
|
||||
<label>Post-Quantum Encryption</label>
|
||||
<type>checkbox</type>
|
||||
<help>Enable post-quantum cryptography for the tunnel connection (requires QUIC).</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>cloudflared.general.quic_disable_pmtu_discovery</id>
|
||||
<label>Disable QUIC PMTU Discovery</label>
|
||||
<type>checkbox</type>
|
||||
<help>Disable Path MTU Discovery for QUIC connections. May help in environments where ICMP is blocked.</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>cloudflared.general.log_level</id>
|
||||
<label>Log Level</label>
|
||||
<type>dropdown</type>
|
||||
<help>Verbosity of cloudflared logging. Defaults to info. Use debug for troubleshooting; warn or error for quieter operation.</help>
|
||||
</field>
|
||||
</form>
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (C) 2026 Richard Aspden <rick+github@insanityinside.net>
|
||||
* 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.
|
||||
*/
|
||||
|
||||
namespace OPNsense\System\Status;
|
||||
|
||||
use OPNsense\System\AbstractStatus;
|
||||
use OPNsense\System\SystemStatusCode;
|
||||
|
||||
class CloudflaredOverrideStatus extends AbstractStatus
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
$this->internalPriority = 2;
|
||||
$this->internalPersistent = true;
|
||||
$this->internalIsBanner = true;
|
||||
$this->internalTitle = gettext('Cloudflare Tunnel');
|
||||
$this->internalScope = [
|
||||
'/ui/cloudflared/'
|
||||
];
|
||||
}
|
||||
|
||||
public function collectStatus()
|
||||
{
|
||||
$this->internalMessage = gettext(
|
||||
'Cloudflare Tunnel traffic bypasses OPNsense firewall rules; access control must be enforced in ' .
|
||||
'Cloudflare Access. For optimal QUIC performance, set the recommended kernel tunables. ' .
|
||||
'See the plugin documentation for details.'
|
||||
);
|
||||
$this->internalStatus = SystemStatusCode::NOTICE;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
<acl>
|
||||
<page-cloudflared-general>
|
||||
<name>Services: Cloudflare Tunnel</name>
|
||||
<patterns>
|
||||
<pattern>ui/cloudflared/*</pattern>
|
||||
<pattern>api/cloudflared/*</pattern>
|
||||
</patterns>
|
||||
</page-cloudflared-general>
|
||||
<page-cloudflared-log>
|
||||
<name>Services: Cloudflare Tunnel: Log File</name>
|
||||
<patterns>
|
||||
<pattern>ui/diagnostics/log/core/cloudflared/*</pattern>
|
||||
<pattern>api/diagnostics/log/core/cloudflared/*</pattern>
|
||||
</patterns>
|
||||
</page-cloudflared-log>
|
||||
</acl>
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (C) 2026 Richard Aspden <rick+github@insanityinside.net>
|
||||
* 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.
|
||||
*/
|
||||
|
||||
namespace OPNsense\Cloudflared;
|
||||
|
||||
use OPNsense\Base\BaseModel;
|
||||
|
||||
class Cloudflared extends BaseModel
|
||||
{
|
||||
}
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
<model>
|
||||
<mount>//OPNsense/Cloudflared</mount>
|
||||
<version>1.0.0</version>
|
||||
<description>Cloudflare Tunnel settings</description>
|
||||
<items>
|
||||
<general>
|
||||
<enabled type="BooleanField">
|
||||
<Default>0</Default>
|
||||
<Required>Y</Required>
|
||||
</enabled>
|
||||
<token type="TextField">
|
||||
<Required>Y</Required>
|
||||
<Mask>/^[a-zA-Z0-9\._\-]+$/</Mask>
|
||||
<ValidationMessage>Token may only contain letters, digits, dots, underscores and hyphens.</ValidationMessage>
|
||||
</token>
|
||||
<protocol type="OptionField">
|
||||
<Default>auto</Default>
|
||||
<Required>Y</Required>
|
||||
<OptionValues>
|
||||
<auto>auto</auto>
|
||||
<quic>quic</quic>
|
||||
<http2>http2</http2>
|
||||
</OptionValues>
|
||||
</protocol>
|
||||
<post_quantum type="BooleanField">
|
||||
<Default>0</Default>
|
||||
<Required>Y</Required>
|
||||
</post_quantum>
|
||||
<quic_disable_pmtu_discovery type="BooleanField">
|
||||
<Default>0</Default>
|
||||
<Required>Y</Required>
|
||||
</quic_disable_pmtu_discovery>
|
||||
<log_level type="OptionField">
|
||||
<Default>info</Default>
|
||||
<Required>Y</Required>
|
||||
<OptionValues>
|
||||
<info>info</info>
|
||||
<debug>debug</debug>
|
||||
<warn>warn</warn>
|
||||
<error>error</error>
|
||||
<fatal>fatal</fatal>
|
||||
</OptionValues>
|
||||
</log_level>
|
||||
</general>
|
||||
</items>
|
||||
</model>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<menu>
|
||||
<Services>
|
||||
<Cloudflared VisibleName="Cloudflare Tunnel" cssClass="fa fa-cloud fa-fw">
|
||||
<Settings order="10" url="/ui/cloudflared/"/>
|
||||
<Log VisibleName="Log File" order="20" url="/ui/diagnostics/log/core/cloudflared"/>
|
||||
</Cloudflared>
|
||||
</Services>
|
||||
</menu>
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
{#
|
||||
# Copyright (C) 2026 Richard Aspden <rick+github@insanityinside.net>
|
||||
# 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.
|
||||
#}
|
||||
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
mapDataToFormUI({'frm_GeneralSettings': "/api/cloudflared/settings/get"}).done(function() {
|
||||
$('.selectpicker').selectpicker('refresh');
|
||||
});
|
||||
|
||||
updateServiceControlUI('cloudflared');
|
||||
|
||||
$("#reconfigureAct").SimpleActionButton({
|
||||
onPreAction: function() {
|
||||
const dfObj = $.Deferred();
|
||||
saveFormToEndpoint("/api/cloudflared/settings/set", 'frm_GeneralSettings', dfObj.resolve, true, dfObj.reject);
|
||||
return dfObj;
|
||||
},
|
||||
onAction: function() {
|
||||
updateServiceControlUI('cloudflared');
|
||||
},
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<div class="content-box">
|
||||
{{ partial('layout_partials/base_form', ['fields': general, 'id': 'frm_GeneralSettings']) }}
|
||||
</div>
|
||||
|
||||
{{ partial('layout_partials/base_apply_button', {'data_endpoint': '/api/cloudflared/service/reconfigure', 'data_service_widget': 'cloudflared'}) }}
|
||||
34
net/cloudflared/src/opnsense/scripts/OPNsense/Cloudflared/reconfigure.sh
Executable file
34
net/cloudflared/src/opnsense/scripts/OPNsense/Cloudflared/reconfigure.sh
Executable file
|
|
@ -0,0 +1,34 @@
|
|||
#!/bin/sh
|
||||
|
||||
# Copyright (C) 2026 Richard Aspden <rick+github@insanityinside.net>
|
||||
# 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.
|
||||
|
||||
configctl template reload OPNsense/Cloudflared
|
||||
chmod 600 /etc/rc.conf.d/cloudflared
|
||||
|
||||
if grep -q 'cloudflared_enable="YES"' /etc/rc.conf.d/cloudflared 2>/dev/null; then
|
||||
service cloudflared restart
|
||||
else
|
||||
service cloudflared stop 2>/dev/null || true
|
||||
fi
|
||||
38
net/cloudflared/src/opnsense/scripts/OPNsense/Cloudflared/recover.sh
Executable file
38
net/cloudflared/src/opnsense/scripts/OPNsense/Cloudflared/recover.sh
Executable file
|
|
@ -0,0 +1,38 @@
|
|||
#!/bin/sh
|
||||
|
||||
# Copyright (C) 2026 Richard Aspden <rick+github@insanityinside.net>
|
||||
# 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.
|
||||
|
||||
# Start cloudflared only if it is enabled but not currently running.
|
||||
# Used by the cron recovery job so healthy tunnels are not disrupted.
|
||||
|
||||
if ! grep -q 'cloudflared_enable="YES"' /etc/rc.conf.d/cloudflared 2>/dev/null; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if service cloudflared status > /dev/null 2>&1; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
service cloudflared start
|
||||
|
|
@ -0,0 +1,104 @@
|
|||
"""
|
||||
Copyright (C) 2026 Richard Aspden <rick+github@insanityinside.net>
|
||||
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 re
|
||||
from . import NewBaseLogFormat
|
||||
|
||||
# zerolog 3-letter level codes → syslog numeric severity
|
||||
_SEVERITY = {
|
||||
'DBG': 7,
|
||||
'INF': 6,
|
||||
'WRN': 4,
|
||||
'ERR': 3,
|
||||
'FTL': 2,
|
||||
'PNC': 1,
|
||||
}
|
||||
|
||||
# zerolog: 2026-05-12T11:51:06Z INF message
|
||||
_RE_ZEROLOG = re.compile(
|
||||
r'^(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:Z|[+-]\d{2}:\d{2}))\s+([A-Z]{3})\s+(.*)'
|
||||
)
|
||||
|
||||
# Go stdlib log (e.g. quic-go): 2026/05/12 13:35:44 message — no level field
|
||||
_RE_GOSTDLIB = re.compile(
|
||||
r'^(\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2})\s+(.*)'
|
||||
)
|
||||
|
||||
|
||||
class CloudflaredLogFormat(NewBaseLogFormat):
|
||||
def __init__(self, filename):
|
||||
super().__init__(filename)
|
||||
self._timestamp = None
|
||||
self._severity = None
|
||||
self._message = None
|
||||
|
||||
def match(self, line):
|
||||
if 'cloudflared' not in self._filename:
|
||||
return False
|
||||
return bool(_RE_ZEROLOG.match(line) or _RE_GOSTDLIB.match(line))
|
||||
|
||||
def set_line(self, line):
|
||||
m = _RE_ZEROLOG.match(line)
|
||||
if m:
|
||||
ts_raw = m.group(1)
|
||||
# Normalise Z suffix so fromisoformat() accepts it (Python < 3.11)
|
||||
self._timestamp = ts_raw.replace('Z', '+00:00')
|
||||
self._severity = _SEVERITY.get(m.group(2), 6)
|
||||
self._message = m.group(3)
|
||||
return
|
||||
|
||||
m = _RE_GOSTDLIB.match(line)
|
||||
if m:
|
||||
# Go stdlib format has no level; default to Informational
|
||||
self._timestamp = m.group(1).replace('/', '-', 2).replace(' ', 'T')
|
||||
self._severity = 6
|
||||
self._message = m.group(2)
|
||||
return
|
||||
|
||||
self._timestamp = None
|
||||
self._severity = 6
|
||||
self._message = line
|
||||
|
||||
@property
|
||||
def timestamp(self):
|
||||
return self._timestamp
|
||||
|
||||
@property
|
||||
def process_name(self):
|
||||
# zerolog format has no process field; hardcode so the column isn't blank
|
||||
return 'cloudflared'
|
||||
|
||||
@property
|
||||
def pid(self):
|
||||
return None
|
||||
|
||||
@property
|
||||
def severity(self):
|
||||
return self._severity
|
||||
|
||||
@property
|
||||
def line(self):
|
||||
return self._message
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
[start]
|
||||
command:service cloudflared start
|
||||
parameters:
|
||||
type:script
|
||||
message:Starting Cloudflare Tunnel service
|
||||
|
||||
[stop]
|
||||
command:service cloudflared stop
|
||||
parameters:
|
||||
type:script
|
||||
message:Stopping Cloudflare Tunnel service
|
||||
|
||||
[restart]
|
||||
command:service cloudflared restart
|
||||
parameters:
|
||||
type:script
|
||||
message:Restarting Cloudflare Tunnel service
|
||||
description:Restart Cloudflare Tunnel
|
||||
|
||||
[status]
|
||||
command:service cloudflared status; exit 0
|
||||
parameters:
|
||||
type:script_output
|
||||
message:Requesting Cloudflare Tunnel status
|
||||
|
||||
[recover]
|
||||
command:/usr/local/opnsense/scripts/OPNsense/Cloudflared/recover.sh
|
||||
parameters:
|
||||
type:script
|
||||
message:Recovering Cloudflare Tunnel
|
||||
description:Recover Cloudflare Tunnel (start if not running)
|
||||
|
||||
[reconfigure]
|
||||
command:/usr/local/opnsense/scripts/OPNsense/Cloudflared/reconfigure.sh
|
||||
parameters:
|
||||
type:script
|
||||
message:Reconfiguring Cloudflare Tunnel
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
rc.conf.d:/etc/rc.conf.d/cloudflared
|
||||
config.yml:/usr/local/etc/cloudflared/config.yml
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
metrics: localhost:2000
|
||||
no-autoupdate: true
|
||||
{% if helpers.exists('OPNsense.Cloudflared.general.post_quantum') and OPNsense.Cloudflared.general.post_quantum == '1' %}
|
||||
post-quantum: true
|
||||
{% endif %}
|
||||
{% if helpers.exists('OPNsense.Cloudflared.general.quic_disable_pmtu_discovery') and OPNsense.Cloudflared.general.quic_disable_pmtu_discovery == '1' %}
|
||||
quic-disable-pmtu-discovery: true
|
||||
{% endif %}
|
||||
{% if helpers.exists('OPNsense.Cloudflared.general.protocol') and OPNsense.Cloudflared.general.protocol != 'auto' %}
|
||||
protocol: {{ OPNsense.Cloudflared.general.protocol }}
|
||||
{% endif %}
|
||||
{% if helpers.exists('OPNsense.Cloudflared.general.log_level') and OPNsense.Cloudflared.general.log_level != 'info' %}
|
||||
loglevel: {{ OPNsense.Cloudflared.general.log_level }}
|
||||
{% endif %}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
{% if helpers.exists('OPNsense.Cloudflared.general.enabled') and OPNsense.Cloudflared.general.enabled == '1' %}
|
||||
cloudflared_enable="YES"
|
||||
{% else %}
|
||||
cloudflared_enable="NO"
|
||||
{% endif %}
|
||||
cloudflared_conf="/usr/local/etc/cloudflared/config.yml"
|
||||
{% if helpers.exists('OPNsense.Cloudflared.general.token') %}
|
||||
cloudflared_env="TUNNEL_TOKEN={{ OPNsense.Cloudflared.general.token|trim }}"
|
||||
{% endif %}
|
||||
cloudflared_mode_options="run"
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
###################################################################
|
||||
# Local syslog-ng configuration [cloudflared].
|
||||
###################################################################
|
||||
filter f_local_cloudflared {
|
||||
program("cloudflared");
|
||||
};
|
||||
Loading…
Reference in a new issue