mirror of
https://github.com/opnsense/plugins.git
synced 2026-05-28 04:34:15 -04:00
Merge 5e4f4cab00 into cb9a5d6d69
This commit is contained in:
commit
6d524aa57c
26 changed files with 887 additions and 0 deletions
24
net/cloudflared/LICENSE
Normal file
24
net/cloudflared/LICENSE
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
BSD 2-Clause License
|
||||
|
||||
Copyright (c) 2026, Alan Martines
|
||||
|
||||
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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT HOLDER OR CONTRIBUTORS 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.
|
||||
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 (cloudflared) integration
|
||||
PLUGIN_MAINTAINER= alancpmartines@hotmail.com
|
||||
PLUGIN_DEPENDS= fetch
|
||||
|
||||
.include "../../Mk/plugins.mk"
|
||||
17
net/cloudflared/pkg-descr
Normal file
17
net/cloudflared/pkg-descr
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
Cloudflare Tunnel (cloudflared) integration for OPNsense.
|
||||
|
||||
Provides a native MVC interface to manage token-based Cloudflare Zero
|
||||
Trust tunnels without opening firewall ports or requiring a static IP.
|
||||
Follows Method 1: Token-based Setup using binaries from the kjake
|
||||
FreeBSD fork of cloudflared.
|
||||
|
||||
Features:
|
||||
- Token-based tunnel authentication via Cloudflare Zero Trust
|
||||
- Integrated binary installer with automatic FreeBSD version and
|
||||
architecture detection
|
||||
- QUIC kernel tuning (kern.ipc.maxsockbuf, net.inet.udp.recvspace)
|
||||
- Post-quantum encryption support (--post-quantum)
|
||||
- Real-time tunnel health status in the UI
|
||||
- Appears in System: Diagnostics: Services
|
||||
|
||||
WWW: https://github.com/AlanMartines/os-cloudflared
|
||||
53
net/cloudflared/src/etc/inc/plugins.inc.d/cloudflared.inc
Normal file
53
net/cloudflared/src/etc/inc/plugins.inc.d/cloudflared.inc
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (C) 2026 Alan Martines <alancpmartines@hotmail.com>
|
||||
* 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()
|
||||
{
|
||||
$model = new \OPNsense\Cloudflared\Cloudflared();
|
||||
return (string)$model->general->enabled == '1';
|
||||
}
|
||||
|
||||
function cloudflared_services()
|
||||
{
|
||||
$services = [];
|
||||
|
||||
if (cloudflared_enabled()) {
|
||||
$services[] = [
|
||||
'description' => gettext('Cloudflare Tunnel'),
|
||||
'configd' => [
|
||||
'restart' => ['cloudflared restart'],
|
||||
'start' => ['cloudflared start'],
|
||||
'stop' => ['cloudflared stop'],
|
||||
],
|
||||
'name' => 'cloudflared',
|
||||
'pidfile' => '/var/run/cloudflared.pid',
|
||||
];
|
||||
}
|
||||
|
||||
return $services;
|
||||
}
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
<?php
|
||||
|
||||
namespace OPNsense\Cloudflared\Api;
|
||||
|
||||
use OPNsense\Base\ApiMutableServiceControllerBase;
|
||||
use OPNsense\Core\Backend;
|
||||
|
||||
class ServiceController extends ApiMutableServiceControllerBase
|
||||
{
|
||||
protected static $internalServiceClass = 'OPNsense\Cloudflared\Cloudflared';
|
||||
protected static $internalServiceEnabled = 'general.enabled';
|
||||
protected static $internalServiceTemplate = 'OPNsense/Cloudflared';
|
||||
protected static $internalServiceName = 'cloudflared';
|
||||
|
||||
/**
|
||||
* Reconfigura o serviço: cria diretórios, recarrega templates,
|
||||
* aplica sysctl tunables e reinicia o serviço.
|
||||
*/
|
||||
public function reconfigureAction()
|
||||
{
|
||||
if ($this->request->isPost()) {
|
||||
$backend = new Backend();
|
||||
$backend->configdRun("cloudflared reconfigure");
|
||||
return ['status' => 'ok'];
|
||||
}
|
||||
return ['status' => 'failed'];
|
||||
}
|
||||
|
||||
public function tunnelStatusAction()
|
||||
{
|
||||
$backend = new Backend();
|
||||
$response = $backend->configdRun("cloudflared tunnel_status");
|
||||
$data = json_decode(trim($response), true);
|
||||
if ($data === null) {
|
||||
return ['tunnel' => 'unknown'];
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function installAction()
|
||||
{
|
||||
if ($this->request->isPost()) {
|
||||
$backend = new Backend();
|
||||
$response = $backend->configdRun("cloudflared install_binary");
|
||||
if ($response === null) {
|
||||
return ['response' => 'ERROR: configd did not respond. Run "service configd restart" on OPNsense.'];
|
||||
}
|
||||
$response = trim($response);
|
||||
if ($response === '' || $response === 'FAILED') {
|
||||
return ['response' => 'ERROR: Action not found. Run "service configd restart" on OPNsense to reload actions.'];
|
||||
}
|
||||
return ['response' => $response];
|
||||
}
|
||||
return ['response' => 'error'];
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
<?php
|
||||
|
||||
namespace OPNsense\Cloudflared\Api;
|
||||
|
||||
use OPNsense\Base\ApiMutableModelControllerBase;
|
||||
use OPNsense\Cloudflared\Cloudflared;
|
||||
|
||||
class SettingsController extends ApiMutableModelControllerBase
|
||||
{
|
||||
protected static $internalModelName = 'Cloudflared';
|
||||
protected static $internalModelClass = 'OPNsense\Cloudflared\Cloudflared';
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Copyright (C) 2026 Alan Martines <alancpmartines@hotmail.com>
|
||||
* 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\IndexController as BaseIndexController;
|
||||
|
||||
class IndexController extends BaseIndexController
|
||||
{
|
||||
public function indexAction()
|
||||
{
|
||||
$this->view->generalForm = $this->getForm("general");
|
||||
$this->view->pick('OPNsense/Cloudflared/index');
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
<form>
|
||||
<field>
|
||||
<id>Cloudflared.general.enabled</id>
|
||||
<label>Enable</label>
|
||||
<type>checkbox</type>
|
||||
<help>Enable Cloudflare Tunnel</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>Cloudflared.general.token</id>
|
||||
<label>Tunnel Token</label>
|
||||
<type>password</type>
|
||||
<help>The token for your Cloudflare Tunnel. Get it from one.dash.cloudflare.com > Access > Tunnels.</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>Cloudflared.general.no_autoupdate</id>
|
||||
<label>Disable Auto-Update</label>
|
||||
<type>checkbox</type>
|
||||
<help>Pass --no-autoupdate to cloudflared. Recommended when managing updates manually via the Install/Update Binary button.</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>Cloudflared.general.post_quantum</id>
|
||||
<label>Enable Post-Quantum Encryption</label>
|
||||
<type>checkbox</type>
|
||||
<help>Pass --post-quantum to enable post-quantum cryptography for the tunnel connection.</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>Cloudflared.general.kern_ipc_maxsockbuf</id>
|
||||
<label>Max Socket Buffer (kern.ipc.maxsockbuf)</label>
|
||||
<type>text</type>
|
||||
<help>Recommended value for QUIC performance. Default is 16777216.</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>Cloudflared.general.net_inet_udp_recvspace</id>
|
||||
<label>UDP Recv Space (net.inet.udp.recvspace)</label>
|
||||
<type>text</type>
|
||||
<help>Recommended value for QUIC performance. Default is 8388608.</help>
|
||||
</field>
|
||||
</form>
|
||||
93
net/cloudflared/src/opnsense/mvc/app/languages/en_US.po
Normal file
93
net/cloudflared/src/opnsense/mvc/app/languages/en_US.po
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: os-cloudflared\n"
|
||||
"Language: en_US\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
# Menu & ACL
|
||||
msgid "Cloudflare Tunnel"
|
||||
msgstr "Cloudflare Tunnel"
|
||||
|
||||
msgid "Settings"
|
||||
msgstr "Settings"
|
||||
|
||||
msgid "Allow access to Cloudflare Tunnel settings"
|
||||
msgstr "Allow access to Cloudflare Tunnel settings"
|
||||
|
||||
msgid "Allow access to Cloudflare Tunnel service status/control"
|
||||
msgstr "Allow access to Cloudflare Tunnel service status/control"
|
||||
|
||||
# General Form
|
||||
msgid "General Settings"
|
||||
msgstr "General Settings"
|
||||
|
||||
msgid "Enable"
|
||||
msgstr "Enable"
|
||||
|
||||
msgid "Tunnel Token"
|
||||
msgstr "Tunnel Token"
|
||||
|
||||
msgid "Disable Auto-Update"
|
||||
msgstr "Disable Auto-Update"
|
||||
|
||||
msgid "Enable Post-Quantum Encryption"
|
||||
msgstr "Enable Post-Quantum Encryption"
|
||||
|
||||
msgid "Max Socket Buffer (kern.ipc.maxsockbuf)"
|
||||
msgstr "Max Socket Buffer (kern.ipc.maxsockbuf)"
|
||||
|
||||
msgid "UDP Recv Space (net.inet.udp.recvspace)"
|
||||
msgstr "UDP Recv Space (net.inet.udp.recvspace)"
|
||||
|
||||
msgid "Enable Cloudflare Tunnel"
|
||||
msgstr "Enable Cloudflare Tunnel"
|
||||
|
||||
msgid "The token for your Cloudflare Tunnel. Get it from one.dash.cloudflare.com > Access > Tunnels."
|
||||
msgstr "The token for your Cloudflare Tunnel. Get it from one.dash.cloudflare.com > Access > Tunnels."
|
||||
|
||||
msgid "Pass --no-autoupdate to cloudflared. Recommended when managing updates manually via the Install/Update Binary button."
|
||||
msgstr "Pass --no-autoupdate to cloudflared. Recommended when managing updates manually via the Install/Update Binary button."
|
||||
|
||||
msgid "Pass --post-quantum to enable post-quantum cryptography for the tunnel connection."
|
||||
msgstr "Pass --post-quantum to enable post-quantum cryptography for the tunnel connection."
|
||||
|
||||
msgid "Recommended value for QUIC performance. Default is 16777216."
|
||||
msgstr "Recommended value for QUIC performance. Default is 16777216."
|
||||
|
||||
msgid "Recommended value for QUIC performance. Default is 8388608."
|
||||
msgstr "Recommended value for QUIC performance. Default is 8388608."
|
||||
|
||||
# UI Buttons
|
||||
msgid "Apply"
|
||||
msgstr "Apply"
|
||||
|
||||
msgid "Install/Update Binary"
|
||||
msgstr "Install/Update Binary"
|
||||
|
||||
msgid "Start"
|
||||
msgstr "Start"
|
||||
|
||||
msgid "Stop"
|
||||
msgstr "Stop"
|
||||
|
||||
msgid "Restart"
|
||||
msgstr "Restart"
|
||||
|
||||
msgid "Running"
|
||||
msgstr "Running"
|
||||
|
||||
msgid "Stopped"
|
||||
msgstr "Stopped"
|
||||
|
||||
msgid "No response from server. Check if configd is running."
|
||||
msgstr "No response from server. Check if configd is running."
|
||||
|
||||
msgid "Tunnel"
|
||||
msgstr "Tunnel"
|
||||
|
||||
msgid "Healthy"
|
||||
msgstr "Healthy"
|
||||
|
||||
msgid "Connecting"
|
||||
msgstr "Connecting"
|
||||
93
net/cloudflared/src/opnsense/mvc/app/languages/pt_BR.po
Normal file
93
net/cloudflared/src/opnsense/mvc/app/languages/pt_BR.po
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: os-cloudflared\n"
|
||||
"Language: pt_BR\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
# Menu & ACL
|
||||
msgid "Cloudflare Tunnel"
|
||||
msgstr "Cloudflare Tunnel"
|
||||
|
||||
msgid "Settings"
|
||||
msgstr "Configurações"
|
||||
|
||||
msgid "Allow access to Cloudflare Tunnel settings"
|
||||
msgstr "Permitir acesso às configurações do Cloudflare Tunnel"
|
||||
|
||||
msgid "Allow access to Cloudflare Tunnel service status/control"
|
||||
msgstr "Permitir acesso ao status/controle do serviço Cloudflare Tunnel"
|
||||
|
||||
# General Form
|
||||
msgid "General Settings"
|
||||
msgstr "Configurações Gerais"
|
||||
|
||||
msgid "Enable"
|
||||
msgstr "Habilitar"
|
||||
|
||||
msgid "Tunnel Token"
|
||||
msgstr "Token do Túnel"
|
||||
|
||||
msgid "Disable Auto-Update"
|
||||
msgstr "Desativar Atualização Automática"
|
||||
|
||||
msgid "Enable Post-Quantum Encryption"
|
||||
msgstr "Habilitar Criptografia Pós-Quântica"
|
||||
|
||||
msgid "Max Socket Buffer (kern.ipc.maxsockbuf)"
|
||||
msgstr "Buffer Máximo de Socket (kern.ipc.maxsockbuf)"
|
||||
|
||||
msgid "UDP Recv Space (net.inet.udp.recvspace)"
|
||||
msgstr "Espaço de Recebimento UDP (net.inet.udp.recvspace)"
|
||||
|
||||
msgid "Enable Cloudflare Tunnel"
|
||||
msgstr "Habilitar Cloudflare Tunnel"
|
||||
|
||||
msgid "The token for your Cloudflare Tunnel. Get it from one.dash.cloudflare.com > Access > Tunnels."
|
||||
msgstr "O token do seu Cloudflare Tunnel. Obtenha em one.dash.cloudflare.com > Access > Tunnels."
|
||||
|
||||
msgid "Pass --no-autoupdate to cloudflared. Recommended when managing updates manually via the Install/Update Binary button."
|
||||
msgstr "Passa --no-autoupdate ao cloudflared. Recomendado quando as atualizações são gerenciadas manualmente pelo botão Instalar/Atualizar Binário."
|
||||
|
||||
msgid "Pass --post-quantum to enable post-quantum cryptography for the tunnel connection."
|
||||
msgstr "Passa --post-quantum para habilitar criptografia pós-quântica na conexão do túnel."
|
||||
|
||||
msgid "Recommended value for QUIC performance. Default is 16777216."
|
||||
msgstr "Valor recomendado para desempenho do QUIC. O padrão é 16777216."
|
||||
|
||||
msgid "Recommended value for QUIC performance. Default is 8388608."
|
||||
msgstr "Valor recomendado para desempenho do QUIC. O padrão é 8388608."
|
||||
|
||||
# UI Buttons
|
||||
msgid "Apply"
|
||||
msgstr "Aplicar"
|
||||
|
||||
msgid "Install/Update Binary"
|
||||
msgstr "Instalar/Atualizar Binário"
|
||||
|
||||
msgid "Start"
|
||||
msgstr "Iniciar"
|
||||
|
||||
msgid "Stop"
|
||||
msgstr "Parar"
|
||||
|
||||
msgid "Restart"
|
||||
msgstr "Reiniciar"
|
||||
|
||||
msgid "Running"
|
||||
msgstr "Executando"
|
||||
|
||||
msgid "Stopped"
|
||||
msgstr "Parado"
|
||||
|
||||
msgid "No response from server. Check if configd is running."
|
||||
msgstr "Sem resposta do servidor. Verifique se o configd está em execução."
|
||||
|
||||
msgid "Tunnel"
|
||||
msgstr "Túnel"
|
||||
|
||||
msgid "Healthy"
|
||||
msgstr "Saudável"
|
||||
|
||||
msgid "Connecting"
|
||||
msgstr "Conectando"
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
<acl>
|
||||
<page-services-cloudflared>
|
||||
<name>Services: Cloudflare Tunnel</name>
|
||||
<patterns>
|
||||
<pattern>ui/cloudflared/*</pattern>
|
||||
<pattern>api/cloudflared/*</pattern>
|
||||
</patterns>
|
||||
</page-services-cloudflared>
|
||||
</acl>
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
<?php
|
||||
|
||||
namespace OPNsense\Cloudflared;
|
||||
|
||||
use OPNsense\Base\BaseModel;
|
||||
|
||||
class Cloudflared extends BaseModel
|
||||
{
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
<model>
|
||||
<mount>//OPNsense/Cloudflared</mount>
|
||||
<description>Cloudflare Tunnel</description>
|
||||
<items>
|
||||
<general>
|
||||
<enabled type="BooleanField">
|
||||
<default>0</default>
|
||||
</enabled>
|
||||
<token type="TextField">
|
||||
<Required>Y</Required>
|
||||
<maskMatch>/^[a-zA-Z0-9\._\-]+$/</maskMatch>
|
||||
</token>
|
||||
<no_autoupdate type="BooleanField">
|
||||
<default>1</default>
|
||||
</no_autoupdate>
|
||||
<post_quantum type="BooleanField">
|
||||
<default>0</default>
|
||||
</post_quantum>
|
||||
<kern_ipc_maxsockbuf type="IntegerField">
|
||||
<default>16777216</default>
|
||||
</kern_ipc_maxsockbuf>
|
||||
<net_inet_udp_recvspace type="IntegerField">
|
||||
<default>8388608</default>
|
||||
</net_inet_udp_recvspace>
|
||||
</general>
|
||||
</items>
|
||||
</model>
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
<menu>
|
||||
<Services>
|
||||
<Cloudflared order="490" VisibleName="Cloudflare Tunnel" cssClass="fa fa-cloud fa-fw" url="/ui/cloudflared/"/>
|
||||
</Services>
|
||||
</menu>
|
||||
|
|
@ -0,0 +1,178 @@
|
|||
{#
|
||||
# Copyright (C) 2026 Alan Martines <alancpmartines@hotmail.com>
|
||||
# All rights reserved.
|
||||
#}
|
||||
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
var data_get_map = {'frm_general': "/api/cloudflared/settings/get"};
|
||||
mapDataToFormUI(data_get_map).done(function(data) {
|
||||
$('.selectpicker').selectpicker('refresh');
|
||||
|
||||
// Adiciona botão de mostrar/ocultar ao campo token
|
||||
var tokenInput = $("#Cloudflared\\.general\\.token");
|
||||
tokenInput.wrap('<div class="input-group"></div>');
|
||||
tokenInput.after(
|
||||
'<span class="input-group-btn">' +
|
||||
'<button class="btn btn-default" type="button" id="toggleTokenBtn" title="{{ lang._('Show/Hide') }}">' +
|
||||
'<i class="fa fa-eye" id="toggleTokenIcon"></i>' +
|
||||
'</button>' +
|
||||
'</span>'
|
||||
);
|
||||
$("#toggleTokenBtn").click(function() {
|
||||
var inp = $("#Cloudflared\\.general\\.token");
|
||||
var icon = $("#toggleTokenIcon");
|
||||
if (inp.attr("type") === "password") {
|
||||
inp.attr("type", "text");
|
||||
icon.removeClass("fa-eye").addClass("fa-eye-slash");
|
||||
} else {
|
||||
inp.attr("type", "password");
|
||||
icon.removeClass("fa-eye-slash").addClass("fa-eye");
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
var i18n = {
|
||||
running: "{{ lang._('Running') }}",
|
||||
stopped: "{{ lang._('Stopped') }}",
|
||||
healthy: "{{ lang._('Healthy') }}",
|
||||
connecting: "{{ lang._('Connecting') }}",
|
||||
tunnel_status: "{{ lang._('Tunnel') }}"
|
||||
};
|
||||
|
||||
// Salvar e reconfigura o serviço
|
||||
$("#saveAct").click(function() {
|
||||
$("#saveAct_progress").addClass("fa fa-spinner fa-pulse");
|
||||
saveFormToEndpoint("/api/cloudflared/settings/set", 'frm_general', function() {
|
||||
ajaxCall("/api/cloudflared/service/reconfigure", {}, function() {
|
||||
updateServiceStatus(i18n);
|
||||
$("#saveAct_progress").removeClass("fa fa-spinner fa-pulse").addClass("fa fa-check text-success");
|
||||
setTimeout(function() {
|
||||
$("#saveAct_progress").removeClass("fa fa-check text-success");
|
||||
}, 2000);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// Instalar / atualizar binário
|
||||
$("#installBtn").click(function() {
|
||||
$("#installBtn").prop('disabled', true);
|
||||
$("#installIcon").addClass('fa-spinner fa-spin').removeClass('fa-download');
|
||||
ajaxCall("/api/cloudflared/service/install", {}, function(data, status) {
|
||||
$("#installBtn").prop('disabled', false);
|
||||
$("#installIcon").addClass('fa-download').removeClass('fa-spinner fa-spin');
|
||||
var output = (data && data.response) ? data.response.trim() : '';
|
||||
var dlgType = (output.indexOf("successful") !== -1)
|
||||
? BootstrapDialog.TYPE_SUCCESS
|
||||
: BootstrapDialog.TYPE_DANGER;
|
||||
BootstrapDialog.show({
|
||||
type: dlgType,
|
||||
title: "{{ lang._('Install/Update Binary') }}",
|
||||
message: $('<pre/>').text(output || "{{ lang._('No response from server. Check if configd is running.') }}"),
|
||||
buttons: [{ label: 'OK', action: function(d) { d.close(); } }]
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// Controle de serviço
|
||||
$("#startBtn").click(function() {
|
||||
ajaxCall("/api/cloudflared/service/start", {}, function() { updateServiceStatus(i18n); });
|
||||
});
|
||||
$("#stopBtn").click(function() {
|
||||
ajaxCall("/api/cloudflared/service/stop", {}, function() { updateServiceStatus(i18n); });
|
||||
});
|
||||
$("#restartBtn").click(function() {
|
||||
ajaxCall("/api/cloudflared/service/restart", {}, function() { updateServiceStatus(i18n); });
|
||||
});
|
||||
|
||||
updateServiceStatus(i18n);
|
||||
});
|
||||
|
||||
function updateServiceStatus(i18n) {
|
||||
ajaxCall("/api/cloudflared/service/status", {}, function(data) {
|
||||
var running = data && data.status === "running";
|
||||
if (running) {
|
||||
$("#svc_status").html(
|
||||
'<span class="label label-success">'
|
||||
+ '<i class="fa fa-play fa-fw"></i> ' + i18n.running
|
||||
+ '</span>'
|
||||
);
|
||||
$("#startBtn").hide();
|
||||
$("#stopBtn, #restartBtn").show();
|
||||
updateTunnelStatus(i18n);
|
||||
} else {
|
||||
$("#svc_status").html(
|
||||
'<span class="label label-danger">'
|
||||
+ '<i class="fa fa-stop fa-fw"></i> ' + i18n.stopped
|
||||
+ '</span>'
|
||||
);
|
||||
$("#tunnel_health").html('');
|
||||
$("#startBtn").show();
|
||||
$("#stopBtn, #restartBtn").hide();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function updateTunnelStatus(i18n) {
|
||||
ajaxCall("/api/cloudflared/service/tunnel_status", {}, function(data) {
|
||||
var state = data && data.tunnel ? data.tunnel : 'unknown';
|
||||
var html = '';
|
||||
if (state === 'healthy') {
|
||||
html = ' <span class="label label-success">'
|
||||
+ '<i class="fa fa-cloud fa-fw"></i> ' + i18n.tunnel_status + ': ' + i18n.healthy
|
||||
+ '</span>';
|
||||
} else if (state === 'connecting') {
|
||||
html = ' <span class="label label-warning">'
|
||||
+ '<i class="fa fa-cloud fa-fw"></i> ' + i18n.tunnel_status + ': ' + i18n.connecting
|
||||
+ '</span>';
|
||||
}
|
||||
$("#tunnel_health").html(html);
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<ul class="nav nav-tabs" data-tabs="tabs" id="maintabs">
|
||||
<li class="active"><a data-toggle="tab" href="#general">{{ lang._('General Settings') }}</a></li>
|
||||
</ul>
|
||||
|
||||
<div class="tab-content content-box">
|
||||
<div id="general" class="tab-pane fade in active">
|
||||
<div class="content-box-main">
|
||||
{{ partial("layout_partials/base_form",['fields':generalForm,'id':'frm_general'])}}
|
||||
<div class="col-md-12" style="padding-bottom: 15px;">
|
||||
<hr />
|
||||
<button class="btn btn-primary" id="saveAct" type="button">
|
||||
<b>{{ lang._('Apply') }}</b> <i id="saveAct_progress"></i>
|
||||
</button>
|
||||
<button class="btn btn-default" id="installBtn" type="button">
|
||||
<i id="installIcon" class="fa fa-download fa-fw"></i>
|
||||
<b>{{ lang._('Install/Update Binary') }}</b>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="content-box" style="padding: 8px 15px; margin-top: 1em;">
|
||||
<table style="width: 100%">
|
||||
<tr>
|
||||
<td>
|
||||
<b>{{ lang._('Cloudflare Tunnel') }}</b>
|
||||
|
||||
<span id="svc_status"><i class="fa fa-spinner fa-spin"></i></span>
|
||||
<span id="tunnel_health"></span>
|
||||
</td>
|
||||
<td style="text-align: right">
|
||||
<button class="btn btn-xs btn-default" id="startBtn" type="button" style="display:none;">
|
||||
<i class="fa fa-play fa-fw"></i> {{ lang._('Start') }}
|
||||
</button>
|
||||
<button class="btn btn-xs btn-default" id="stopBtn" type="button" style="display:none;">
|
||||
<i class="fa fa-stop fa-fw"></i> {{ lang._('Stop') }}
|
||||
</button>
|
||||
<button class="btn btn-xs btn-default" id="restartBtn" type="button" style="display:none;">
|
||||
<i class="fa fa-repeat fa-fw"></i> {{ lang._('Restart') }}
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
#!/bin/sh
|
||||
|
||||
log_msg() {
|
||||
logger -t cloudflared-install "$1"
|
||||
echo "$1"
|
||||
}
|
||||
|
||||
DEST="/usr/local/bin/cloudflared"
|
||||
GITHUB_API="https://api.github.com/repos/kjake/cloudflared/releases/latest"
|
||||
API_CACHE="/tmp/cloudflared_release.json"
|
||||
|
||||
OS_VERSION=$(uname -r | cut -d'.' -f1)
|
||||
ARCH=$(uname -m)
|
||||
|
||||
log_msg "Detected FreeBSD ${OS_VERSION} / ${ARCH}"
|
||||
|
||||
# Fetch latest release metadata
|
||||
log_msg "Fetching latest release version from GitHub..."
|
||||
fetch -o "${API_CACHE}" "${GITHUB_API}" > /dev/null 2>&1
|
||||
|
||||
if [ ! -s "${API_CACHE}" ]; then
|
||||
log_msg "ERROR: Could not reach GitHub API. Check internet connectivity."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Parse tag_name using Python (reliable on single-line JSON)
|
||||
LATEST_TAG=$(python3 -c "import json,sys; print(json.load(open('${API_CACHE}'))['tag_name'])" 2>/dev/null)
|
||||
|
||||
if [ -z "${LATEST_TAG}" ]; then
|
||||
log_msg "ERROR: Could not parse release version from GitHub API response."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
rm -f "${API_CACHE}"
|
||||
log_msg "Latest version: ${LATEST_TAG}"
|
||||
|
||||
BINARY_NAME="cloudflared-freebsd${OS_VERSION}-${ARCH}"
|
||||
BINARY_URL="https://github.com/kjake/cloudflared/releases/download/${LATEST_TAG}/${BINARY_NAME}"
|
||||
|
||||
log_msg "Downloading ${BINARY_NAME}..."
|
||||
fetch -o "${DEST}" "${BINARY_URL}" > /dev/null 2>&1
|
||||
|
||||
if [ $? -eq 0 ] && [ -s "${DEST}" ]; then
|
||||
chmod +x "${DEST}"
|
||||
log_msg "Installation of cloudflared ${LATEST_TAG} successful."
|
||||
else
|
||||
rm -f "${DEST}"
|
||||
log_msg "ERROR: Download failed. Binary may not exist for FreeBSD ${OS_VERSION} / ${ARCH}."
|
||||
log_msg "URL attempted: ${BINARY_URL}"
|
||||
exit 1
|
||||
fi
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
#!/bin/sh
|
||||
|
||||
log_msg() {
|
||||
logger -t cloudflared-reconfigure "$1"
|
||||
echo "$1"
|
||||
}
|
||||
|
||||
log_msg "Starting cloudflared reconfiguration..."
|
||||
|
||||
# Dados estáticos: criar diretórios apenas se não existirem
|
||||
if [ ! -d /usr/local/etc/cloudflared ]; then
|
||||
mkdir -p /usr/local/etc/cloudflared
|
||||
chmod 750 /usr/local/etc/cloudflared
|
||||
log_msg "Created /usr/local/etc/cloudflared"
|
||||
fi
|
||||
|
||||
if [ ! -d /usr/local/etc/sysctl.conf.d ]; then
|
||||
mkdir -p /usr/local/etc/sysctl.conf.d
|
||||
log_msg "Created /usr/local/etc/sysctl.conf.d"
|
||||
fi
|
||||
|
||||
# Dados dinâmicos: recarregar templates (rc.conf.d e token sempre atualizados)
|
||||
log_msg "Reloading configuration templates..."
|
||||
/usr/local/sbin/configctl template reload OPNsense/Cloudflared
|
||||
|
||||
# Proteger token: chmod 600 (nunca deve ser world-readable)
|
||||
if [ -f /usr/local/etc/cloudflared/token ]; then
|
||||
chmod 600 /usr/local/etc/cloudflared/token
|
||||
log_msg "Token file permissions set to 600."
|
||||
fi
|
||||
|
||||
# Apply sysctl tunables se existirem
|
||||
if [ -f /usr/local/etc/sysctl.conf.d/cloudflared.conf ]; then
|
||||
log_msg "Applying sysctl tunables..."
|
||||
while IFS= read -r line; do
|
||||
case "$line" in
|
||||
\#*|'') continue ;;
|
||||
esac
|
||||
key=$(echo "$line" | cut -d'=' -f1)
|
||||
val=$(echo "$line" | cut -d'=' -f2-)
|
||||
if sysctl -w "${key}=${val}" > /dev/null 2>&1; then
|
||||
log_msg "sysctl ${key}=${val} applied."
|
||||
else
|
||||
log_msg "WARNING: sysctl ${key}=${val} failed (may require reboot)."
|
||||
fi
|
||||
done < /usr/local/etc/sysctl.conf.d/cloudflared.conf
|
||||
fi
|
||||
|
||||
# Verificar se o binário existe antes de tentar iniciar
|
||||
if [ ! -x /usr/local/bin/cloudflared ]; then
|
||||
log_msg "WARNING: /usr/local/bin/cloudflared not found. Use 'Install/Update Binary' first."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Reiniciar serviço
|
||||
log_msg "Restarting cloudflared service..."
|
||||
service cloudflared restart
|
||||
|
||||
log_msg "Reconfiguration complete."
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
#!/bin/sh
|
||||
|
||||
# Verifica se o processo está rodando via PID file
|
||||
if [ ! -f /var/run/cloudflared.pid ]; then
|
||||
echo '{"tunnel":"stopped"}'
|
||||
exit 0
|
||||
fi
|
||||
|
||||
PID=$(cat /var/run/cloudflared.pid 2>/dev/null)
|
||||
if [ -z "${PID}" ] || ! kill -0 "${PID}" 2>/dev/null; then
|
||||
echo '{"tunnel":"stopped"}'
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Consulta o health check local do cloudflared (padrão: localhost:2000)
|
||||
# HTTP 200 = tunnel conectado ao Cloudflare
|
||||
# HTTP 503 / falha = processo rodando mas ainda conectando
|
||||
fetch -T 3 -qo /dev/null "http://localhost:2000/healthcheck" 2>/dev/null
|
||||
if [ $? -eq 0 ]; then
|
||||
echo '{"tunnel":"healthy"}'
|
||||
else
|
||||
echo '{"tunnel":"connecting"}'
|
||||
fi
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
[start]
|
||||
command:/usr/local/etc/rc.d/cloudflared start
|
||||
parameters:
|
||||
type:script
|
||||
message:Starting Cloudflare Tunnel
|
||||
|
||||
[stop]
|
||||
command:/usr/local/etc/rc.d/cloudflared stop
|
||||
parameters:
|
||||
type:script
|
||||
message:Stopping Cloudflare Tunnel
|
||||
|
||||
[restart]
|
||||
command:/usr/local/etc/rc.d/cloudflared restart
|
||||
parameters:
|
||||
type:script
|
||||
message:Restarting Cloudflare Tunnel
|
||||
|
||||
[status]
|
||||
command:/usr/local/etc/rc.d/cloudflared status;exit 0
|
||||
parameters:
|
||||
type:script_output
|
||||
message:Probing Cloudflare Tunnel
|
||||
|
||||
[reconfigure]
|
||||
command:/bin/sh /usr/local/opnsense/scripts/OPNsense/Cloudflared/reconfigure.sh
|
||||
parameters:
|
||||
type:script
|
||||
message:Reconfiguring Cloudflare Tunnel
|
||||
|
||||
[install_binary]
|
||||
command:/bin/sh /usr/local/opnsense/scripts/OPNsense/Cloudflared/install_binary.sh;exit 0
|
||||
parameters:
|
||||
type:script_output
|
||||
message:Installing Cloudflare Tunnel binary
|
||||
|
||||
[tunnel_status]
|
||||
command:/bin/sh /usr/local/opnsense/scripts/OPNsense/Cloudflared/tunnel_status.sh;exit 0
|
||||
parameters:
|
||||
type:script_output
|
||||
message:Checking Cloudflare Tunnel status
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
rc.conf.d:/etc/rc.conf.d/cloudflared
|
||||
cloudflared.token:/usr/local/etc/cloudflared/token
|
||||
tunables.conf:/usr/local/etc/sysctl.conf.d/cloudflared.conf
|
||||
|
|
@ -0,0 +1 @@
|
|||
{% if helpers.exists('OPNsense.Cloudflared.general.token') %}{{ OPNsense.Cloudflared.general.token|trim }}{% endif %}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
#
|
||||
# This file is automatically generated. Do not manually edit this file.
|
||||
#
|
||||
{% if helpers.exists('OPNsense.Cloudflared.general.enabled') and OPNsense.Cloudflared.general.enabled == '1' %}
|
||||
cloudflared_enable="YES"
|
||||
{% else %}
|
||||
cloudflared_enable="NO"
|
||||
{% endif %}
|
||||
cloudflared_mode="tunnel{% if helpers.exists('OPNsense.Cloudflared.general.no_autoupdate') and OPNsense.Cloudflared.general.no_autoupdate == '1' %} --no-autoupdate{% endif %} run{% if helpers.exists('OPNsense.Cloudflared.general.post_quantum') and OPNsense.Cloudflared.general.post_quantum == '1' %} --post-quantum{% endif %}"
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
#
|
||||
# This file is automatically generated. Do not manually edit this file.
|
||||
#
|
||||
kern.ipc.maxsockbuf={% if helpers.exists('OPNsense.Cloudflared.general.kern_ipc_maxsockbuf') %}{{ OPNsense.Cloudflared.general.kern_ipc_maxsockbuf }}{% else %}16777216{% endif %}
|
||||
|
||||
net.inet.udp.recvspace={% if helpers.exists('OPNsense.Cloudflared.general.net_inet_udp_recvspace') %}{{ OPNsense.Cloudflared.general.net_inet_udp_recvspace }}{% else %}8388608{% endif %}
|
||||
0
net/cloudflared/src/usr/local/etc/cloudflared/.keep
Normal file
0
net/cloudflared/src/usr/local/etc/cloudflared/.keep
Normal file
32
net/cloudflared/src/usr/local/etc/rc.d/cloudflared
Normal file
32
net/cloudflared/src/usr/local/etc/rc.d/cloudflared
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
#!/bin/sh
|
||||
|
||||
# PROVIDE: cloudflared
|
||||
# REQUIRE: NETWORKING SERVERS
|
||||
# KEYWORD: shutdown
|
||||
|
||||
. /etc/rc.subr
|
||||
|
||||
name="cloudflared"
|
||||
rcvar="cloudflared_enable"
|
||||
logfile="/var/log/cloudflared.log"
|
||||
pidfile="/var/run/cloudflared.pid"
|
||||
procname="/usr/local/bin/cloudflared"
|
||||
|
||||
load_rc_config $name
|
||||
|
||||
: ${cloudflared_enable:="NO"}
|
||||
: ${cloudflared_mode:="tunnel"}
|
||||
|
||||
# Load token from secure file
|
||||
# --metrics é flag global do cloudflared: deve vir antes do subcomando tunnel
|
||||
if [ -f /usr/local/etc/cloudflared/token ]; then
|
||||
token=$(cat /usr/local/etc/cloudflared/token)
|
||||
command_args="--metrics localhost:2000 ${cloudflared_mode} --token ${token}"
|
||||
else
|
||||
command_args="--metrics localhost:2000 ${cloudflared_mode}"
|
||||
fi
|
||||
|
||||
command="/usr/sbin/daemon"
|
||||
command_args="-o ${logfile} -p ${pidfile} -f ${procname} ${command_args}"
|
||||
|
||||
run_rc_command "$1"
|
||||
0
net/cloudflared/src/usr/local/etc/sysctl.conf.d/.keep
Normal file
0
net/cloudflared/src/usr/local/etc/sysctl.conf.d/.keep
Normal file
Loading…
Reference in a new issue