Merge branch 'master' into vnstat-multi-interface

This commit is contained in:
Ben Smithurst 2025-01-25 22:58:15 +00:00
commit dead6b006d
121 changed files with 1111 additions and 1316 deletions

View file

@ -7,14 +7,14 @@ Copyright (c) 2021 Andreas Stuerz
Copyright (c) 2021 Axelrtgs
Copyright (c) 2023 Bernhard Frenking <bernhard@frenking.eu>
Copyright (c) 2023 Cannon Matthews <cannonmatthews@google.com>
Copyright (c) 2023-2024 Cedrik Pischem
Copyright (c) 2023-2025 Cedrik Pischem
Copyright (c) 2019 Cloudfence - Julio Camargo (JCC)
Copyright (c) 2005-2006 Colin Smith <ethethlay@gmail.com>
Copyright (c) 2021 Dan Lundqvist
Copyright (c) 2021 David Berry
Copyright (c) 2017-2018 David Harrigan
Copyright (c) 2021 David Hughes
Copyright (c) 2014-2024 Deciso B.V.
Copyright (c) 2014-2025 Deciso B.V.
Copyright (c) 2020 devNan0 <nan0@nan0.dev>
Copyright (c) 2023 Dmitry Shinkaruk
Copyright (c) 2024 DollarSign23
@ -25,7 +25,7 @@ Copyright (c) 2017-2020 Fabian Franz
Copyright (c) 2019 Felix Matouschek <felix@matouschek.org>
Copyright (c) 2024 Francisco Dimattia <info@tecnoservicio.com.ar>
Copyright (c) 2014-2024 Franco Fichtner <franco@opnsense.org>
Copyright (c) 2016-2024 Frank Wall
Copyright (c) 2016-2025 Frank Wall
Copyright (c) 2021 Github-jjw
Copyright (c) 2023 Greg Glockner <greg@glockners.net>
Copyright (c) 2024 Hasan Ucak <hasan@sunnyvalley.io>
@ -51,7 +51,7 @@ Copyright (c) 2022 Marvo2011
Copyright (c) 2017-2024 Michael Muenz <m.muenz@gmail.com>
Copyright (c) 2024 Michał Brzeziński
Copyright (c) 2024 Mike Shuey
Copyright (c) 2023 Mikhail Kharisov
Copyright (c) 2023-2024 Mikhail Kharisov
Copyright (c) 2023 mleinart
Copyright (c) 2024 MVZ Labor Ludwigsburg GbR
Copyright (c) 2021-2024 Nicola Pellegrini
@ -72,6 +72,7 @@ Copyright (c) 2020 Starkstromkonsument
Copyright (c) 2023-2024 Thomas Cekal <thomas@cekal.org>
Copyright (c) 2020 Tobias Boehnert
Copyright (c) 2024 txr13
Copyright (c) 2024 W516
Copyright (c) 2022 Wouter Deurholt
Copyright (c) 2015 YoungJoo.Kim <vozltx@gmail.com>
All rights reserved.

View file

@ -1,4 +1,4 @@
# Copyright (c) 2016-2024 Franco Fichtner <franco@opnsense.org>
# Copyright (c) 2016-2025 Franco Fichtner <franco@opnsense.org>
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
@ -45,7 +45,7 @@ VERSIONBIN= ${LOCALBASE}/sbin/opnsense-version
_PLUGIN_ABI!= ${VERSIONBIN} -a
PLUGIN_ABI?= ${_PLUGIN_ABI}
.else
PLUGIN_ABI?= 24.7
PLUGIN_ABI?= 25.1
.endif
PLUGIN_MAINS= master main
@ -161,3 +161,8 @@ push:
@git checkout ${PLUGIN_STABLE}
@git push
@git checkout ${PLUGIN_MAIN}
reset:
@git checkout ${PLUGIN_STABLE}
@git reset --hard HEAD~1
@git checkout ${PLUGIN_MAIN}

View file

@ -1,5 +1,6 @@
PLUGIN_NAME= ddclient
PLUGIN_VERSION= 1.26
PLUGIN_REVISION= 1
PLUGIN_DEPENDS= ddclient py${PLUGIN_PYTHON}-boto3
PLUGIN_COMMENT= Dynamic DNS client
PLUGIN_MAINTAINER= ad@opnsense.org

View file

@ -91,6 +91,13 @@
<label>Interface to monitor</label>
<type>dropdown</type>
</field>
<field>
<id>account.dynipv6host</id>
<label>Dynamic ipv6 host</label>
<type>text</type>
<advanced>true</advanced>
<help>Swap the interface identifier of the ipv6 address with the given partial ipv6 address (the least significant 64 bits of the address)</help>
</field>
<field>
<id>account.checkip_timeout</id>
<label>Check ip timeout</label>

View file

@ -165,6 +165,11 @@
</check001>
</Constraints>
</checkip>
<dynipv6host type="TextField">
<Required>N</Required>
<mask>/^::(([0-9a-fA-F]{1,4}:){0,3}[0-9a-fA-F]{1,4})?$/u</mask>
<ValidationMessage>Entry is not a valid partial ipv6 address definition (e.g. ::1000).</ValidationMessage>
</dynipv6host>
<checkip_timeout type="IntegerField">
<Default>10</Default>
<Required>Y</Required>

View file

@ -118,7 +118,8 @@ class BaseAccount:
service = self.settings.get('checkip'),
proto = 'https' if self.settings.get('force_ssl', False) else 'http',
timeout = str(self.settings.get('checkip_timeout', '10')),
interface = self.settings['interface'] if self.settings.get('interface' ,'').strip() != '' else None
interface = self.settings['interface'] if self.settings.get('interface' ,'').strip() != '' else None,
dynipv6host = self.settings['dynipv6host'] if self.settings.get('dynipv6host' ,'').strip() != '' else None
)
if self._current_address == None:

View file

@ -1,5 +1,5 @@
"""
Copyright (c) 2022-2023 Ad Schellevis <ad@opnsense.org>
Copyright (c) 2022-2025 Ad Schellevis <ad@opnsense.org>
All rights reserved.
Redistribution and use in source and binary forms, with or without
@ -67,11 +67,29 @@ def extract_address(host, txt):
return ""
def checkip(service, proto='https', timeout='10', interface=None):
def transform_ip(ip, ipv6host=None):
""" Changes ipv6 addresses if interface identifier is given
:param ip: ip address
:param ipv6host: 64 bit interface identifier
:return ipaddress.IPv4Address|ipaddress.IPv6Address
:raises ValueError: If the input can not be converted to an IPaddress
"""
if ipv6host and ip.find(':') > 0:
# extract 64 bit long prefix and add ipv6host [64]bits
return ipaddress.ip_address(
ipaddress.ip_network("%s/64" % ip, strict=False).network_address.exploded[0:19] +
ipaddress.ip_address(ipv6host).exploded[19:]
)
else:
return ipaddress.ip_address(ip)
def checkip(service, proto='https', timeout='10', interface=None, dynipv6host=None):
""" find ip address using external services defined in checkip_service_list
:param proto: protocol
:param timeout: timeout in seconds
:param interface: bind to interface
:param dynipv6host: optional partial ipv6 address
:return: str
"""
if service.startswith('web_'):
@ -84,8 +102,13 @@ def checkip(service, proto='https', timeout='10', interface=None):
params.append(interface)
url = checkip_service_list[service] % proto
params.append(url)
return extract_address(urlparse(url).hostname,
extracted_address = extract_address(urlparse(url).hostname,
subprocess.run(params, capture_output=True, text=True).stdout)
try:
return str(transform_ip(extracted_address, dynipv6host))
except ValueError:
# invalid address
return ""
elif service in ['if', 'if6'] and interface is not None:
# return first non private IPv[4|6] interface address
ifcfg = subprocess.run(['/sbin/ifconfig', interface], capture_output=True, text=True).stdout
@ -94,7 +117,7 @@ def checkip(service, proto='https', timeout='10', interface=None):
parts = line.split()
if (parts[0] == 'inet' and service == 'if') or (parts[0] == 'inet6' and service == 'if6'):
try:
address = ipaddress.ip_address(parts[1])
address = transform_ip(parts[1], dynipv6host)
if address.is_global:
return str(address)
except ValueError:

View file

@ -22,6 +22,7 @@
"zone": "{{ account.zone }}",
"checkip": "{{ account.checkip }}",
"interface": "{% if account.interface %}{{physical_interface(account.interface)}}{% endif %}",
"dynipv6host": "{{ account.dynipv6host }}",
"checkip_timeout": {{ account.checkip_timeout }},
"force_ssl": {{ "true" if account.force_ssl == '1' else "false"}},
"ttl": "{{ account.ttl }}",

View file

@ -1,6 +1,6 @@
PLUGIN_NAME= rspamd
PLUGIN_VERSION= 1.13
PLUGIN_REVISION= 1
PLUGIN_REVISION= 2
PLUGIN_COMMENT= Protect your network from spam
PLUGIN_DEPENDS= rspamd
PLUGIN_MAINTAINER= franz.fabian.94@gmail.com

View file

@ -8,6 +8,7 @@ Plugin Changelog
1.13
* Make local whitelist by e-mail address possible (contributed by itNGO)
* Fix typo in "whitelisted_ip" option (contributed by Alexander Riedel)
* Add phishing exclusion (contributed by Makss39)
1.12

View file

@ -11,5 +11,5 @@
action = "soft reject"; # default greylisted action
ipv4_mask = {{ OPNsense.Rspamd.graylist.ipv4mask|default('19') }};
ipv6_mask = {{ OPNsense.Rspamd.graylist.ipv6mask|default('64') }};
whitelist_ip = "/usr/local/etc/rspamd/local.d/greylist_ip.wl";
whitelisted_ip = "/usr/local/etc/rspamd/local.d/greylist_ip.wl";
{% endif %}

View file

@ -1,5 +1,5 @@
PLUGIN_NAME= theme-rebellion
PLUGIN_VERSION= 1.9.1
PLUGIN_VERSION= 1.9.2
PLUGIN_COMMENT= A suitably dark theme
PLUGIN_MAINTAINER= martin@queens-park.com
PLUGIN_NO_ABI= yes

View file

@ -102,7 +102,7 @@ td {
display: inline-block;
height: 1px;
width: 70%;
background: #121212;
background: #ea7105b8;
color: #f0f0f0;
margin: 5px;
}

View file

@ -1121,7 +1121,7 @@ a.text-primary:hover {
color: #b85904; }
.text-success {
color: #7Ba255; }
color: #5b8a35; }
a.text-success:hover {
color: #628143; }
@ -1152,7 +1152,7 @@ a.bg-primary:hover {
background-color: #b85904; }
.bg-success {
background-color: #7Ba255; }
background-color: #5b8a35; }
a.bg-success:hover {
background-color: #628143; }
@ -1851,7 +1851,7 @@ pre {
table {
background-color: transparent;
color: #ccc; }
color: #f1f1f1; }
th {
text-align: left; }
@ -1956,22 +1956,22 @@ table td[class*=col-], table th[class*=col-] {
background-color: #3b3b3b; }
.table > thead > tr > td.success, .table > thead > tr > th.success {
background-color: #7Ba255; }
background-color: #5b8a35; }
.table > thead > tr.success > td, .table > thead > tr.success > th {
background-color: #7Ba255; }
background-color: #5b8a35; }
.table > tbody > tr > td.success, .table > tbody > tr > th.success {
background-color: #7Ba255; }
background-color: #5b8a35; }
.table > tbody > tr.success > td, .table > tbody > tr.success > th {
background-color: #7Ba255; }
background-color: #5b8a35; }
.table > tfoot > tr > td.success, .table > tfoot > tr > th.success {
background-color: #7Ba255; }
background-color: #5b8a35; }
.table > tfoot > tr.success > td, .table > tfoot > tr.success > th {
background-color: #7Ba255; }
background-color: #5b8a35; }
.table-hover > tbody > tr > td.success:hover, .table-hover > tbody > tr > th.success:hover {
background-color: #6e914c; }
@ -2701,10 +2701,10 @@ textarea.input-lg {
line-height: 30px; }
.has-success .help-block, .has-success .control-label, .has-success .radio, .has-success .checkbox, .has-success .radio-inline, .has-success .checkbox-inline {
color: #7Ba255; }
color: #5b8a35; }
.has-success .form-control {
border-color: #7Ba255;
border-color: #5b8a35;
-webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); }
.has-success .form-control:focus {
@ -2713,12 +2713,12 @@ textarea.input-lg {
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #aec895; }
.has-success .input-group-addon {
color: #7Ba255;
border-color: #7Ba255;
background-color: #7Ba255; }
color: #5b8a35;
border-color: #5b8a35;
background-color: #5b8a35; }
.has-success .form-control-feedback {
color: #7Ba255; }
color: #5b8a35; }
.has-warning .help-block, .has-warning .control-label, .has-warning .radio, .has-warning .checkbox, .has-warning .radio-inline, .has-warning .checkbox-inline {
color: #f0ad4e; }
@ -3023,7 +3023,7 @@ fieldset[disabled] .btn-primary {
.btn-success {
color: #eee;
background-color: #7Ba255;
background-color: #5b8a35;
border-color: #6e914c; }
.btn-success:hover, .btn-success:focus, .btn-success:active, .btn-success.active {
color: #eee;
@ -3042,28 +3042,28 @@ fieldset[disabled] .btn-primary {
background-image: none; }
.btn-success.disabled {
background-color: #7Ba255;
background-color: #5b8a35;
border-color: #6e914c; }
.btn-success.disabled:hover, .btn-success.disabled:focus, .btn-success.disabled:active, .btn-success.disabled.active {
background-color: #7Ba255;
background-color: #5b8a35;
border-color: #6e914c; }
.btn-success[disabled] {
background-color: #7Ba255;
background-color: #5b8a35;
border-color: #6e914c; }
.btn-success[disabled]:hover, .btn-success[disabled]:focus, .btn-success[disabled]:active, .btn-success[disabled].active {
background-color: #7Ba255;
background-color: #5b8a35;
border-color: #6e914c; }
fieldset[disabled] .btn-success {
background-color: #7Ba255;
background-color: #5b8a35;
border-color: #6e914c; }
fieldset[disabled] .btn-success:hover, fieldset[disabled] .btn-success:focus, fieldset[disabled] .btn-success:active, fieldset[disabled] .btn-success.active {
background-color: #7Ba255;
background-color: #5b8a35;
border-color: #6e914c; }
.btn-success .badge {
color: #7Ba255;
color: #5b8a35;
background-color: #eee; }
.btn-info {
@ -4444,7 +4444,7 @@ a.label:hover, a.label:focus {
background-color: #b85904; }
.label-success {
background-color: #7Ba255; }
background-color: #5b8a35; }
.label-success[href]:hover, .label-success[href]:focus {
background-color: #628143; }
@ -4583,8 +4583,8 @@ a.thumbnail:hover, a.thumbnail:focus, a.thumbnail.active {
color: inherit; }
.alert-success {
background-color: #7Ba255;
border-color: #7Ba255;
background-color: #5b8a35;
border-color: #5b8a35;
color: #485f32; }
.alert-success hr {
border-top-color: #6e914c; }
@ -4683,7 +4683,7 @@ a.thumbnail:hover, a.thumbnail:focus, a.thumbnail.active {
box-shadow: none; }
.progress-bar-success {
background-color: #7Ba255; }
background-color: #5b8a35; }
.progress-striped .progress-bar-success {
background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
@ -4823,24 +4823,24 @@ a.list-group-item {
width: 3px; }
.list-group-item-success {
color: #7Ba255;
background-color: #7Ba255; }
color: #5b8a35;
background-color: #5b8a35; }
a.list-group-item-success {
color: #7Ba255; }
color: #5b8a35; }
a.list-group-item-success .list-group-item-heading {
color: inherit; }
a.list-group-item-success:hover, a.list-group-item-success:focus {
color: #7Ba255;
color: #5b8a35;
background-color: #6e914c; }
a.list-group-item-success.active {
color: #222;
background-color: #7Ba255;
border-color: #7Ba255; }
background-color: #5b8a35;
border-color: #5b8a35; }
a.list-group-item-success.active:hover, a.list-group-item-success.active:focus {
color: #222;
background-color: #7Ba255;
border-color: #7Ba255; }
background-color: #5b8a35;
border-color: #5b8a35; }
.list-group-item-info {
color: #ffffff;
@ -5143,18 +5143,18 @@ a.list-group-item-danger {
border-bottom-color: #EA7105; }
.panel-success {
border-color: #7Ba255; }
border-color: #5b8a35; }
.panel-success > .panel-heading {
color: #7Ba255;
background-color: #7Ba255;
border-color: #7Ba255; }
color: #5b8a35;
background-color: #5b8a35;
border-color: #5b8a35; }
.panel-success > .panel-heading + .panel-collapse > .panel-body {
border-top-color: #7Ba255; }
border-top-color: #5b8a35; }
.panel-success > .panel-heading .badge {
color: #7Ba255;
background-color: #7Ba255; }
color: #5b8a35;
background-color: #5b8a35; }
.panel-success > .panel-footer + .panel-collapse > .panel-body {
border-bottom-color: #7Ba255; }
border-bottom-color: #5b8a35; }
.panel-info {
border-color: #3b488e; }

View file

@ -46,8 +46,6 @@ class ServiceController extends ApiControllerBase
public function startAction()
{
if ($this->request->isPost()) {
// close session for long running action
$this->sessionClose();
$backend = new Backend();
$response = $backend->configdRun("collectd start");
return array("response" => $response);
@ -63,8 +61,6 @@ class ServiceController extends ApiControllerBase
public function stopAction()
{
if ($this->request->isPost()) {
// close session for long running action
$this->sessionClose();
$backend = new Backend();
$response = $backend->configdRun("collectd stop");
return array("response" => $response);
@ -80,8 +76,6 @@ class ServiceController extends ApiControllerBase
public function restartAction()
{
if ($this->request->isPost()) {
// close session for long running action
$this->sessionClose();
$backend = new Backend();
$response = $backend->configdRun("collectd restart");
return array("response" => $response);
@ -124,9 +118,6 @@ class ServiceController extends ApiControllerBase
public function reconfigureAction()
{
if ($this->request->isPost()) {
// close session for long running action
$this->sessionClose();
$mdlGeneral = new General();
$backend = new Backend();

View file

@ -43,7 +43,6 @@ class KeyController extends ApiMutableModelControllerBase
}
public function getKeyAction($uuid = null)
{
$this->sessionClose();
return $this->getBase('key', 'keys.key', $uuid);
}
public function addKeyAction()

View file

@ -46,8 +46,6 @@ class ServiceController extends ApiControllerBase
public function startAction()
{
if ($this->request->isPost()) {
// close session for long running action
$this->sessionClose();
$backend = new Backend();
$response = $backend->configdRun("telegraf start");
return array("response" => $response);
@ -63,8 +61,6 @@ class ServiceController extends ApiControllerBase
public function stopAction()
{
if ($this->request->isPost()) {
// close session for long running action
$this->sessionClose();
$backend = new Backend();
$response = $backend->configdRun("telegraf stop");
return array("response" => $response);
@ -80,8 +76,6 @@ class ServiceController extends ApiControllerBase
public function restartAction()
{
if ($this->request->isPost()) {
// close session for long running action
$this->sessionClose();
$backend = new Backend();
$response = $backend->configdRun("telegraf restart");
return array("response" => $response);
@ -124,9 +118,6 @@ class ServiceController extends ApiControllerBase
public function reconfigureAction()
{
if ($this->request->isPost()) {
// close session for long running action
$this->sessionClose();
$mdlGeneral = new General();
$backend = new Backend();

View file

@ -1,5 +1,5 @@
PLUGIN_NAME= freeradius
PLUGIN_VERSION= 1.9.26
PLUGIN_VERSION= 1.9.27
PLUGIN_COMMENT= RADIUS Authentication, Authorization and Accounting Server
PLUGIN_DEPENDS= freeradius3
PLUGIN_MAINTAINER= m.muenz@gmail.com

View file

@ -11,13 +11,19 @@ security, particularly in the academic community, including eduroam.
The server is fast, feature-rich, modular, and scalable.
WWW: https://www.freeradius.org
Plugin Changelog
================
1.9.27
* Allow EAP-TLS with multiple CAs (contributed by RasAlGhul)
1.9.26
* Added support for `require_message_authenticator` in client configuration (contributed by Patrick M. Hausen)
* Added support for "require_message_authenticator" in client configuration (contributed by Patrick M. Hausen)
1.9.25
@ -119,6 +125,3 @@ Plugin Changelog
* Add DHCP support, serving only for DHCP relays
* Allow usage of remote MySQL server
* Rework service status UI
WWW: https://www.freeradius.org

View file

@ -42,7 +42,6 @@ class AvpairController extends ApiMutableModelControllerBase
}
public function getAvpairAction($uuid = null)
{
$this->sessionClose();
return $this->getBase('avpair', 'avpairs.avpair', $uuid);
}
public function addAvpairAction()

View file

@ -76,7 +76,6 @@ class ClientController extends ApiMutableModelControllerBase
public function searchClientAction()
{
$this->sessionClose();
$mdlClient = $this->getModel();
$grid = new UIModelGrid($mdlClient->clients->client);
return $grid->fetchBindRequest(

View file

@ -42,7 +42,6 @@ class DhcpController extends ApiMutableModelControllerBase
}
public function getDhcpAction($uuid = null)
{
$this->sessionClose();
return $this->getBase('dhcp', 'dhcps.dhcp', $uuid);
}
public function addDhcpAction()

View file

@ -42,7 +42,6 @@ class LeaseController extends ApiMutableModelControllerBase
}
public function getLeaseAction($uuid = null)
{
$this->sessionClose();
return $this->getBase('lease', 'leases.lease', $uuid);
}
public function addLeaseAction()

View file

@ -78,7 +78,6 @@ class ProxyController extends ApiMutableModelControllerBase
public function searchRealmAction()
{
$this->sessionClose();
$mdlRealm = $this->getModel();
$grid = new UIModelGrid($mdlRealm->realms->realm);
return $grid->fetchBindRequest(
@ -204,7 +203,6 @@ class ProxyController extends ApiMutableModelControllerBase
}
public function searchHomeserverAction()
{
$this->sessionClose();
$mdlHomeserver = $this->getModel();
$grid = new UIModelGrid($mdlHomeserver->homeservers->homeserver);
return $grid->fetchBindRequest(
@ -306,7 +304,6 @@ class ProxyController extends ApiMutableModelControllerBase
}
public function searchHomeserverpoolAction()
{
$this->sessionClose();
$mdlHomeserverpool = $this->getModel();
$grid = new UIModelGrid($mdlHomeserverpool->homeserverpools->homeserverpool);
return $grid->fetchBindRequest(

View file

@ -119,9 +119,6 @@ class ServiceController extends ApiControllerBase
public function reconfigureAction()
{
if ($this->request->isPost()) {
// close session for long running action
$this->sessionClose();
$mdlGeneral = new General();
$backend = new Backend();

View file

@ -77,7 +77,6 @@ class UserController extends ApiMutableModelControllerBase
public function searchUserAction()
{
$this->sessionClose();
$mdlUser = $this->getModel();
$grid = new UIModelGrid($mdlUser->users->user);
return $grid->fetchBindRequest(

View file

@ -20,7 +20,7 @@
<field>
<id>eap.ca</id>
<label>Root Certificate</label>
<type>dropdown</type>
<type>select_multiple</type>
<help>Choose the Root CA. This CA will be trusted to issue client certificates for authentication.</help>
</field>
<field>

View file

@ -31,6 +31,7 @@
<ca type="CertificateField">
<Type>ca</Type>
<Required>N</Required>
<multiple>Y</multiple>
</ca>
<certificate type="CertificateField">
<Type>cert</Type>

View file

@ -80,17 +80,21 @@ if (isset($configObj->OPNsense->freeradius)) {
$cert_refid = (string)$find_cert->ca;
// if eap has a ca-certificate attached, search for its contents
if ($cert_refid != "") {
foreach ($configObj->ca as $ca) {
if ($cert_refid == (string)$ca->refid) {
// generate cert pem file
$pem_content = trim(str_replace("\n\n", "\n", str_replace(
"\r",
"",
base64_decode((string)$ca->crt)
)));
// multiple comma-separated refid values are possible
$cert_refids = explode(',', $cert_refid);
foreach ($cert_refids as $current_refid) {
foreach ($configObj->ca as $ca) {
if ($current_refid == (string)$ca->refid) {
// generate cert pem file
$pem_content = trim(str_replace("\n\n", "\n", str_replace(
"\r",
"",
base64_decode((string)$ca->crt)
)));
$pem_content .= "\n";
$ca_pem_content .= $pem_content;
$pem_content .= "\n";
$ca_pem_content .= $pem_content;
}
}
}
}

View file

@ -1,8 +1,9 @@
PLUGIN_NAME= frr
PLUGIN_VERSION= 1.42
PLUGIN_REVISION= 1
PLUGIN_COMMENT= The FRRouting Protocol Suite
PLUGIN_DEPENDS= frr8
PLUGIN_MAINTAINER= franz.fabian.94@gmail.com
PLUGIN_MAINTAINER= ad@opnsense.org
PLUGIN_TIER= 2
.include "../../Mk/plugins.mk"

View file

@ -1,7 +1,7 @@
<?php
/*
* Copyright (C) 2015-2017 Deciso B.V.
* Copyright (C) 2015-2025 Deciso B.V.
* Copyright (C) 2017 Fabian Franz
* Copyright (C) 2017-2021 Michael Muenz <m.muenz@gmail.com>
* All rights reserved.
@ -39,17 +39,11 @@ class BfdController extends ApiMutableModelControllerBase
public function searchNeighborAction()
{
return $this->searchBase(
'neighbors.neighbor',
array("enabled",
"description",
"address")
);
return $this->searchBase('neighbors.neighbor');
}
public function getNeighborAction($uuid = null)
{
$this->sessionClose();
return $this->getBase('neighbor', 'neighbors.neighbor', $uuid);
}

View file

@ -1,7 +1,7 @@
<?php
/*
* Copyright (C) 2015-2017 Deciso B.V.
* Copyright (C) 2015-2025 Deciso B.V.
* Copyright (C) 2017 Fabian Franz
* All rights reserved.
*
@ -29,46 +29,10 @@
namespace OPNsense\Quagga\Api;
use OPNsense\Base\ApiControllerBase;
use OPNsense\Quagga\General;
use OPNsense\Core\Config;
use OPNsense\Base\ApiMutableModelControllerBase;
class GeneralController extends ApiControllerBase
class GeneralController extends ApiMutableModelControllerBase
{
public function getAction()
{
// define list of configurable settings
$result = array();
if ($this->request->isGet()) {
$mdlGeneral = new General();
$result['general'] = $mdlGeneral->getNodes();
}
return $result;
}
public function setAction()
{
$result = array("result" => "failed");
if ($this->request->isPost()) {
// load model and update with provided data
$mdlGeneral = new General();
$mdlGeneral->setNodes($this->request->getPost("general"));
// perform validation
$valMsgs = $mdlGeneral->performValidation();
foreach ($valMsgs as $field => $msg) {
if (!array_key_exists("validations", $result)) {
$result["validations"] = array();
}
$result["validations"]["general." . $msg->getField()] = $msg->getMessage();
}
// serialize model to config and save
if ($valMsgs->count() == 0) {
$mdlGeneral->serializeToConfig();
Config::getInstance()->save();
$result["result"] = "saved";
}
}
return $result;
}
protected static $internalModelName = 'general';
protected static $internalModelClass = '\OPNsense\Quagga\General';
}

View file

@ -1,6 +1,7 @@
<?php
/*
* Copyright (C) 2025 Deciso B.V.
* Copyright (C) 2017 Fabian Franz
* Copyright (C) 2019 Michael Muenz <m.muenz@gmail.com>
* All rights reserved.
@ -38,38 +39,34 @@ class OspfsettingsController extends ApiMutableModelControllerBase
public function searchNetworkAction()
{
return $this->searchBase('networks.network', array("enabled", "ipaddr", "netmask", "area"));
return $this->searchBase('networks.network');
}
public function searchInterfaceAction()
{
return $this->searchBase('interfaces.interface', array("enabled", "interfacename", "networktype", "authtype", "area"));
return $this->searchBase('interfaces.interface');
}
public function searchPrefixlistAction()
{
return $this->searchBase('prefixlists.prefixlist', array("enabled", "name", "seqnumber", "action", "network" ));
return $this->searchBase('prefixlists.prefixlist');
}
public function searchRoutemapAction()
{
return $this->searchBase('routemaps.routemap', array("enabled", "name", "action", "id", "match2", "set"));
return $this->searchBase('routemaps.routemap');
}
public function getNetworkAction($uuid = null)
{
$this->sessionClose();
return $this->getBase('network', 'networks.network', $uuid);
}
public function getInterfaceAction($uuid = null)
{
$this->sessionClose();
return $this->getBase('interface', 'interfaces.interface', $uuid);
}
public function getPrefixlistAction($uuid = null)
{
$this->sessionClose();
return $this->getBase('prefixlist', 'prefixlists.prefixlist', $uuid);
}
public function getRoutemapAction($uuid = null)
{
$this->sessionClose();
return $this->getBase('routemap', 'routemaps.routemap', $uuid);
}
public function addNetworkAction()

View file

@ -1,7 +1,7 @@
<?php
/*
* Copyright (C) 2015-2017 Deciso B.V.
* Copyright (C) 2015-2025 Deciso B.V.
* Copyright (C) 2017 Fabian Franz
* All rights reserved.
*
@ -29,121 +29,16 @@
namespace OPNsense\Quagga\Api;
use OPNsense\Base\ApiControllerBase;
use OPNsense\Core\Backend;
use OPNsense\Quagga\General;
use OPNsense\Base\ApiMutableServiceControllerBase;
/**
* Class ServiceController
* @package OPNsense\Quagga
*/
class ServiceController extends ApiControllerBase
class ServiceController extends ApiMutableServiceControllerBase
{
/**
* start quagga service and reload filter rules to pass OSPF
* before the bogon filter kills the routing protocol packets
* @return array
*/
public function startAction()
{
if ($this->request->isPost()) {
$backend = new Backend();
$response = $backend->configdRun('quagga start');
$backend->configdRun('filter reload');
return array('response' => $response);
} else {
return array('response' => array());
}
}
/**
* stop quagga service
* @return array
*/
public function stopAction()
{
if ($this->request->isPost()) {
$backend = new Backend();
$response = $backend->configdRun('quagga stop');
return array('response' => $response);
} else {
return array('response' => array());
}
}
/**
* restart quagga service
* @return array
*/
public function restartAction()
{
if ($this->request->isPost()) {
$backend = new Backend();
$response = $backend->configdRun('quagga restart');
$backend->configdRun('filter reload');
return array('response' => $response);
} else {
return array('response' => array());
}
}
/**
* retrieve status of quagga
* @return array
* @throws \Exception
*/
public function statusAction()
{
$backend = new Backend();
$mdlGeneral = new General();
$response = $backend->configdRun('quagga status');
if (strpos($response, 'not running') > 0) {
if ($mdlGeneral->enabled->__toString() == 1) {
$status = 'stopped';
} else {
$status = 'disabled';
}
} elseif (strpos($response, 'is running') > 0) {
$status = 'running';
} elseif ($mdlGeneral->enabled->__toString() == 0) {
$status = 'disabled';
} else {
$status = 'unknown';
}
return array('status' => $status);
}
/**
* reconfigure quagga, generate config and reload
*/
public function reconfigureAction()
{
if ($this->request->isPost()) {
// close session for long running action
$this->sessionClose();
$mdlGeneral = new General();
$backend = new Backend();
$runStatus = $this->statusAction();
// stop quagga if it is running or not
$this->stopAction();
// generate template
$backend->configdRun('template reload OPNsense/Quagga');
// (res)start daemon
if ($mdlGeneral->enabled->__toString() == 1) {
$this->startAction();
}
return array('status' => 'ok');
} else {
return array('status' => 'failed');
}
}
protected static $internalServiceClass = '\OPNsense\Quagga\General';
protected static $internalServiceTemplate = 'OPNsense/Quagga';
protected static $internalServiceEnabled = 'enabled';
protected static $internalServiceName = 'quagga';
}

View file

@ -1,6 +1,6 @@
{#
OPNsense® is Copyright © 2014 2017 by Deciso B.V.
OPNsense® is Copyright © 2014 2025 by Deciso B.V.
Copyright (C) 2017 Fabian Franz
Copyright (C) 2017 - 2021 Michael Muenz <m.muenz@gmail.com>
All rights reserved.
@ -27,20 +27,46 @@ 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_bfd_settings':"/api/quagga/bfd/get"}).done(function(data){
formatTokenizersUI();
$('.selectpicker').selectpicker('refresh');
updateServiceControlUI('quagga');
});
$("#grid-neighbors").UIBootgrid({
'search':'/api/quagga/bfd/searchNeighbor',
'get':'/api/quagga/bfd/getNeighbor/',
'set':'/api/quagga/bfd/setNeighbor/',
'add':'/api/quagga/bfd/addNeighbor/',
'del':'/api/quagga/bfd/delNeighbor/',
'toggle':'/api/quagga/bfd/toggleNeighbor/'
});
$("#reconfigureAct").SimpleActionButton({
onPreAction: function() {
const dfObj = new $.Deferred();
saveFormToEndpoint("/api/quagga/bfd/set", 'frm_bfd_settings', function () { dfObj.resolve(); }, true, function () { dfObj.reject(); });
return dfObj;
},
onAction: function(data, status) {
updateServiceControlUI('quagga');
}
});
});
</script>
<!-- Navigation bar -->
<ul class="nav nav-tabs" data-tabs="tabs" id="maintabs">
<li class="active"><a data-toggle="tab" href="#general">{{ lang._('General') }}</a></li>
<li><a data-toggle="tab" href="#neighbors">{{ lang._('Neighbors') }}</a></li>
</ul>
<div class="tab-content content-box tab-content">
<div id="general" class="tab-pane fade in active">
<div class="content-box" style="padding-bottom: 1.5em;">
{{ partial("layout_partials/base_form",['fields':bfdForm,'id':'frm_bfd_settings'])}}
<div class="col-md-12">
<hr />
<button class="btn btn-primary" id="saveAct" type="button"><b>{{ lang._('Save') }}</b> <i id="saveAct_progress"></i></button>
</div>
</div>
{{ partial("layout_partials/base_form",['fields':bfdForm,'id':'frm_bfd_settings'])}}
</div>
<div id="neighbors" class="tab-pane fade in">
<table id="grid-neighbors" class="table table-responsive" data-editDialog="DialogEditBFDNeighbor">
@ -57,10 +83,10 @@ POSSIBILITY OF SUCH DAMAGE.
</tbody>
<tfoot>
<tr>
<td colspan="10"></td>
<td colspan="1">
<td></td>
<td>
<button data-action="add" type="button" class="btn btn-xs btn-default"><span class="fa fa-plus"></span></button>
<button type="button" class="btn btn-xs reload_btn btn-primary"><span class="fa fa-refresh reloadAct_progress"></span></button>
<button data-action="deleteSelected" type="button" class="btn btn-xs btn-default"><span class="fa fa-trash-o"></span></button>
</td>
</tr>
</tfoot>
@ -68,51 +94,19 @@ POSSIBILITY OF SUCH DAMAGE.
</div>
</div>
<script>
function quagga_update_status() {
updateServiceControlUI('quagga');
}
$(document).ready(function() {
var data_get_map = {'frm_bfd_settings':"/api/quagga/bfd/get"};
mapDataToFormUI(data_get_map).done(function(data){
formatTokenizersUI();
$('.selectpicker').selectpicker('refresh');
});
quagga_update_status();
// link save button to API set action
$("#saveAct").click(function(){
saveFormToEndpoint(url="/api/quagga/bfd/set",formid='frm_bfd_settings',callback_ok=function(){
$("#saveAct_progress").addClass("fa fa-spinner fa-pulse");
ajaxCall(url="/api/quagga/service/reconfigure", sendData={}, callback=function(data,status) {
quagga_update_status();
$("#saveAct_progress").removeClass("fa fa-spinner fa-pulse");
});
});
});
/* allow a user to manually reload the service (for forms which do not do it automatically) */
$('.reload_btn').click(function reload_handler() {
$(".reloadAct_progress").addClass("fa-spin");
ajaxCall(url="/api/quagga/service/reconfigure", sendData={}, callback=function(data,status) {
quagga_update_status();
$(".reloadAct_progress").removeClass("fa-spin");
});
});
$("#grid-neighbors").UIBootgrid(
{ 'search':'/api/quagga/bfd/searchNeighbor',
'get':'/api/quagga/bfd/getNeighbor/',
'set':'/api/quagga/bfd/setNeighbor/',
'add':'/api/quagga/bfd/addNeighbor/',
'del':'/api/quagga/bfd/delNeighbor/',
'toggle':'/api/quagga/bfd/toggleNeighbor/',
'options':{selection:false, multiSelect:false}
}
);
});
</script>
<section class="page-content-main">
<div class="content-box">
<div class="col-md-12">
<br/>
<button class="btn btn-primary" id="reconfigureAct"
data-endpoint='/api/quagga/service/reconfigure'
data-label="{{ lang._('Apply') }}"
data-error-title="{{ lang._('Error reconfiguring BFD') }}"
type="button"
></button>
<br/><br/>
</div>
</div>
</section>
{{ partial("layout_partials/base_dialog",['fields':formDialogEditBFDNeighbor,'id':'DialogEditBFDNeighbor','label':lang._('Edit Neighbor')])}}

View file

@ -1,6 +1,6 @@
{#
OPNsense® is Copyright © 2014 2024 by Deciso B.V.
OPNsense® is Copyright © 2014 2025 by Deciso B.V.
Copyright (C) 2017 Fabian Franz
Copyright (C) 2017 - 2020 Michael Muenz <m.muenz@gmail.com>
All rights reserved.
@ -27,6 +27,77 @@ 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_bgp_settings':"/api/quagga/bgp/get"}).done(function(data){
formatTokenizersUI();
$('.selectpicker').selectpicker('refresh');
updateServiceControlUI('quagga');
});
$("#reconfigureAct").SimpleActionButton({
onPreAction: function() {
const dfObj = new $.Deferred();
saveFormToEndpoint("/api/quagga/bgp/set", 'frm_bgp_settings', function () { dfObj.resolve(); }, true, function () { dfObj.reject(); });
return dfObj;
},
onAction: function(data, status) {
updateServiceControlUI('quagga');
}
});
$("#grid-neighbors").UIBootgrid({
'search':'/api/quagga/bgp/searchNeighbor',
'get':'/api/quagga/bgp/getNeighbor/',
'set':'/api/quagga/bgp/setNeighbor/',
'add':'/api/quagga/bgp/addNeighbor/',
'del':'/api/quagga/bgp/delNeighbor/',
'toggle':'/api/quagga/bgp/toggleNeighbor/'
});
$("#grid-aspaths").UIBootgrid({
'search':'/api/quagga/bgp/searchAspath',
'get':'/api/quagga/bgp/getAspath/',
'set':'/api/quagga/bgp/setAspath/',
'add':'/api/quagga/bgp/addAspath/',
'del':'/api/quagga/bgp/delAspath/',
'toggle':'/api/quagga/bgp/toggleAspath/'
});
$("#grid-prefixlists").UIBootgrid({
'search':'/api/quagga/bgp/searchPrefixlist',
'get':'/api/quagga/bgp/getPrefixlist/',
'set':'/api/quagga/bgp/setPrefixlist/',
'add':'/api/quagga/bgp/addPrefixlist/',
'del':'/api/quagga/bgp/delPrefixlist/',
'toggle':'/api/quagga/bgp/togglePrefixlist/'
});
$("#grid-communitylists").UIBootgrid({
'search':'/api/quagga/bgp/searchCommunitylist',
'get':'/api/quagga/bgp/getCommunitylist/',
'set':'/api/quagga/bgp/setCommunitylist/',
'add':'/api/quagga/bgp/addCommunitylist/',
'del':'/api/quagga/bgp/delCommunitylist/',
'toggle':'/api/quagga/bgp/toggleCommunitylist/'
});
$("#grid-routemaps").UIBootgrid({
'search':'/api/quagga/bgp/searchRoutemap',
'get':'/api/quagga/bgp/getRoutemap/',
'set':'/api/quagga/bgp/setRoutemap/',
'add':'/api/quagga/bgp/addRoutemap/',
'del':'/api/quagga/bgp/delRoutemap/',
'toggle':'/api/quagga/bgp/toggleRoutemap/'
});
$("#grid-peergroups").UIBootgrid({
'search':'/api/quagga/bgp/searchPeergroup',
'get':'/api/quagga/bgp/getPeergroup/',
'set':'/api/quagga/bgp/setPeergroup/',
'add':'/api/quagga/bgp/addPeergroup/',
'del':'/api/quagga/bgp/delPeergroup/',
'toggle':'/api/quagga/bgp/togglePeergroup/'
});
});
</script>
<!-- Navigation bar -->
<ul class="nav nav-tabs" data-tabs="tabs" id="maintabs">
<li class="active"><a data-toggle="tab" href="#general">{{ lang._('General') }}</a></li>
@ -41,10 +112,6 @@ POSSIBILITY OF SUCH DAMAGE.
<div id="general" class="tab-pane fade in active">
<div class="content-box" style="padding-bottom: 1.5em;">
{{ partial("layout_partials/base_form",['fields':bgpForm,'id':'frm_bgp_settings'])}}
<div class="col-md-12">
<hr />
<button class="btn btn-primary" id="saveAct" type="button"><b>{{ lang._('Save') }}</b> <i id="saveAct_progress"></i></button>
</div>
</div>
</div>
<div id="neighbors" class="tab-pane fade in">
@ -67,11 +134,10 @@ POSSIBILITY OF SUCH DAMAGE.
</tbody>
<tfoot>
<tr>
<td colspan="10"></td>
<td colspan="1">
<td></td>
<td>
<button data-action="add" type="button" class="btn btn-xs btn-default"><span class="fa fa-plus"></span></button>
<!-- <button data-action="deleteSelected" type="button" class="btn btn-xs btn-default"><span class="fa fa-trash-o"></span></button> -->
<button type="button" class="btn btn-xs reload_btn btn-primary"><span class="fa fa-refresh reloadAct_progress"></span></button>
<button data-action="deleteSelected" type="button" class="btn btn-xs btn-default"><span class="fa fa-trash-o"></span></button>
</td>
</tr>
</tfoot>
@ -94,11 +160,10 @@ POSSIBILITY OF SUCH DAMAGE.
</tbody>
<tfoot>
<tr>
<td colspan="5"></td>
<td>
<button data-action="add" type="button" class="btn btn-xs btn-default"><span class="fa fa-plus"></span></button>
<!-- <button data-action="deleteSelected" type="button" class="btn btn-xs btn-default"><span class="fa fa-trash-o"></span></button> -->
<button type="button" class="btn btn-xs reload_btn btn-primary"><span class="fa fa-refresh reloadAct_progress"></span> {{ lang._('Reload Service') }}</button>
<td></td>
<td>
<button data-action="add" type="button" class="btn btn-xs btn-default"><span class="fa fa-plus"></span></button>
<button data-action="deleteSelected" type="button" class="btn btn-xs btn-default"><span class="fa fa-trash-o"></span></button>
</td>
</tr>
</tfoot>
@ -122,11 +187,10 @@ POSSIBILITY OF SUCH DAMAGE.
</tbody>
<tfoot>
<tr>
<td colspan="5"></td>
<td>
<button data-action="add" type="button" class="btn btn-xs btn-default"><span class="fa fa-plus"></span></button>
<!-- <button data-action="deleteSelected" type="button" class="btn btn-xs btn-default"><span class="fa fa-trash-o"></span></button> -->
<button type="button" class="btn btn-xs reload_btn btn-primary"><span class="fa fa-refresh reloadAct_progress"></span> {{ lang._('Reload Service') }}</button>
<td></td>
<td>
<button data-action="add" type="button" class="btn btn-xs btn-default"><span class="fa fa-plus"></span></button>
<button data-action="deleteSelected" type="button" class="btn btn-xs btn-default"><span class="fa fa-trash-o"></span></button>
</td>
</tr>
</tfoot>
@ -150,11 +214,10 @@ POSSIBILITY OF SUCH DAMAGE.
</tbody>
<tfoot>
<tr>
<td colspan="5"></td>
<td>
<button data-action="add" type="button" class="btn btn-xs btn-default"><span class="fa fa-plus"></span></button>
<!-- <button data-action="deleteSelected" type="button" class="btn btn-xs btn-default"><span class="fa fa-trash-o"></span></button> -->
<button type="button" class="btn btn-xs reload_btn btn-primary"><span class="fa fa-refresh reloadAct_progress"></span> {{ lang._('Reload Service') }}</button>
<td></td>
<td>
<button data-action="add" type="button" class="btn btn-xs btn-default"><span class="fa fa-plus"></span></button>
<button data-action="deleteSelected" type="button" class="btn btn-xs btn-default"><span class="fa fa-trash-o"></span></button>
</td>
</tr>
</tfoot>
@ -181,10 +244,10 @@ POSSIBILITY OF SUCH DAMAGE.
</tbody>
<tfoot>
<tr>
<td colspan="5"></td>
<td>
<button data-action="add" type="button" class="btn btn-xs btn-default"><span class="fa fa-plus"></span></button>
<button type="button" class="btn btn-xs reload_btn btn-primary"><span class="fa fa-refresh reloadAct_progress"></span> {{ lang._('Reload Service') }}</button>
<td></td>
<td>
<button data-action="add" type="button" class="btn btn-xs btn-default"><span class="fa fa-plus"></span></button>
<button data-action="deleteSelected" type="button" class="btn btn-xs btn-default"><span class="fa fa-trash-o"></span></button>
</td>
</tr>
</tfoot>
@ -210,10 +273,10 @@ POSSIBILITY OF SUCH DAMAGE.
</tbody>
<tfoot>
<tr>
<td colspan="10"></td>
<td colspan="1">
<td></td>
<td>
<button data-action="add" type="button" class="btn btn-xs btn-default"><span class="fa fa-plus"></span></button>
<button type="button" class="btn btn-xs reload_btn btn-primary"><span class="fa fa-refresh reloadAct_progress"></span></button>
<button data-action="deleteSelected" type="button" class="btn btn-xs btn-default"><span class="fa fa-trash-o"></span></button>
</td>
</tr>
</tfoot>
@ -221,102 +284,20 @@ POSSIBILITY OF SUCH DAMAGE.
</div>
</div>
<script>
function quagga_update_status() {
updateServiceControlUI('quagga');
}
$(document).ready(function() {
var data_get_map = {'frm_bgp_settings':"/api/quagga/bgp/get"};
mapDataToFormUI(data_get_map).done(function(data){
formatTokenizersUI();
$('.selectpicker').selectpicker('refresh');
});
quagga_update_status();
// link save button to API set action
$("#saveAct").click(function(){
saveFormToEndpoint(url="/api/quagga/bgp/set",formid='frm_bgp_settings',callback_ok=function(){
$("#saveAct_progress").addClass("fa fa-spinner fa-pulse");
ajaxCall(url="/api/quagga/service/reconfigure", sendData={}, callback=function(data,status) {
quagga_update_status();
$("#saveAct_progress").removeClass("fa fa-spinner fa-pulse");
});
});
});
/* allow a user to manually reload the service (for forms which do not do it automatically) */
$('.reload_btn').click(function reload_handler() {
$(".reloadAct_progress").addClass("fa-spin");
ajaxCall(url="/api/quagga/service/reconfigure", sendData={}, callback=function(data,status) {
quagga_update_status();
$(".reloadAct_progress").removeClass("fa-spin");
});
});
$("#grid-neighbors").UIBootgrid(
{ 'search':'/api/quagga/bgp/searchNeighbor',
'get':'/api/quagga/bgp/getNeighbor/',
'set':'/api/quagga/bgp/setNeighbor/',
'add':'/api/quagga/bgp/addNeighbor/',
'del':'/api/quagga/bgp/delNeighbor/',
'toggle':'/api/quagga/bgp/toggleNeighbor/',
'options':{selection:false, multiSelect:false}
}
);
$("#grid-aspaths").UIBootgrid(
{ 'search':'/api/quagga/bgp/searchAspath',
'get':'/api/quagga/bgp/getAspath/',
'set':'/api/quagga/bgp/setAspath/',
'add':'/api/quagga/bgp/addAspath/',
'del':'/api/quagga/bgp/delAspath/',
'toggle':'/api/quagga/bgp/toggleAspath/',
'options':{selection:false, multiSelect:false}
}
);
$("#grid-prefixlists").UIBootgrid(
{ 'search':'/api/quagga/bgp/searchPrefixlist',
'get':'/api/quagga/bgp/getPrefixlist/',
'set':'/api/quagga/bgp/setPrefixlist/',
'add':'/api/quagga/bgp/addPrefixlist/',
'del':'/api/quagga/bgp/delPrefixlist/',
'toggle':'/api/quagga/bgp/togglePrefixlist/',
'options':{selection:false, multiSelect:false}
}
);
$("#grid-communitylists").UIBootgrid(
{ 'search':'/api/quagga/bgp/searchCommunitylist',
'get':'/api/quagga/bgp/getCommunitylist/',
'set':'/api/quagga/bgp/setCommunitylist/',
'add':'/api/quagga/bgp/addCommunitylist/',
'del':'/api/quagga/bgp/delCommunitylist/',
'toggle':'/api/quagga/bgp/toggleCommunitylist/',
'options':{selection:false, multiSelect:false}
}
);
$("#grid-routemaps").UIBootgrid(
{ 'search':'/api/quagga/bgp/searchRoutemap',
'get':'/api/quagga/bgp/getRoutemap/',
'set':'/api/quagga/bgp/setRoutemap/',
'add':'/api/quagga/bgp/addRoutemap/',
'del':'/api/quagga/bgp/delRoutemap/',
'toggle':'/api/quagga/bgp/toggleRoutemap/',
'options':{selection:false, multiSelect:false}
}
);
$("#grid-peergroups").UIBootgrid(
{ 'search':'/api/quagga/bgp/searchPeergroup',
'get':'/api/quagga/bgp/getPeergroup/',
'set':'/api/quagga/bgp/setPeergroup/',
'add':'/api/quagga/bgp/addPeergroup/',
'del':'/api/quagga/bgp/delPeergroup/',
'toggle':'/api/quagga/bgp/togglePeergroup/',
'options':{selection:false, multiSelect:false}
}
);
});
</script>
<section class="page-content-main">
<div class="content-box">
<div class="col-md-12">
<br/>
<button class="btn btn-primary" id="reconfigureAct"
data-endpoint='/api/quagga/service/reconfigure'
data-label="{{ lang._('Apply') }}"
data-error-title="{{ lang._('Error reconfiguring BGP') }}"
type="button"
></button>
<br/><br/>
</div>
</div>
</section>
{{ partial("layout_partials/base_dialog",['fields':formDialogEditBGPNeighbor,'id':'DialogEditBGPNeighbor','label':lang._('Edit Neighbor')])}}
{{ partial("layout_partials/base_dialog",['fields':formDialogEditBGPASPaths,'id':'DialogEditBGPASPaths','label':lang._('Edit AS Paths')])}}

View file

@ -1,6 +1,6 @@
{#
OPNsense® is Copyright © 2014 2017 by Deciso B.V.
OPNsense® is Copyright © 2014 2025 by Deciso B.V.
This file is Copyright © 2017 by Fabian Franz
All rights reserved.
@ -26,32 +26,43 @@ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
#}
<div class="content-box" style="padding-bottom: 1.5em;">
{{ partial("layout_partials/base_form",['fields':generalForm,'id':'frm_general_settings'])}}
<div class="col-md-12">
<hr />
<button class="btn btn-primary" id="saveAct" type="button"><b>{{ lang._('Save') }}</b> <i id="saveAct_progress"></i></button>
</div>
</div>
<script>
$( document ).ready(function() {
var data_get_map = {'frm_general_settings':"/api/quagga/general/get"};
mapDataToFormUI(data_get_map).done(function(data){
mapDataToFormUI({'frm_general_settings':"/api/quagga/general/get"}).done(function(data){
formatTokenizersUI();
$('.selectpicker').selectpicker('refresh');
updateServiceControlUI('quagga');
});
updateServiceControlUI('quagga');
// link save button to API set action
$("#saveAct").click(function(){
saveFormToEndpoint(url="/api/quagga/general/set", formid='frm_general_settings',callback_ok=function(){
$("#saveAct_progress").addClass("fa fa-spinner fa-pulse");
ajaxCall(url="/api/quagga/service/reconfigure", sendData={}, callback=function(data,status) {
updateServiceControlUI('quagga');
$("#saveAct_progress").removeClass("fa fa-spinner fa-pulse");
});
}, true);
$("#reconfigureAct").SimpleActionButton({
onPreAction: function() {
const dfObj = new $.Deferred();
saveFormToEndpoint("/api/quagga/general/set", 'frm_general_settings', function () { dfObj.resolve(); }, true, function () { dfObj.reject(); });
return dfObj;
},
onAction: function(data, status) {
updateServiceControlUI('quagga');
}
});
});
</script>
<div class="content-box" style="padding-bottom: 1.5em;">
{{ partial("layout_partials/base_form",['fields':generalForm,'id':'frm_general_settings'])}}
</div>
<section class="page-content-main">
<div class="content-box">
<div class="col-md-12">
<br/>
<button class="btn btn-primary" id="reconfigureAct"
data-endpoint='/api/quagga/service/reconfigure'
data-label="{{ lang._('Apply') }}"
data-error-title="{{ lang._('Error reconfiguring BFD') }}"
type="button"
></button>
<br/><br/>
</div>
</div>
</section>

View file

@ -1,6 +1,6 @@
{#
OPNsense® is Copyright © 2014 2017 by Deciso B.V.
OPNsense® is Copyright © 2014 2025 by Deciso B.V.
This file is Copyright © 2017 by Fabian Franz
All rights reserved.
@ -27,25 +27,78 @@ POSSIBILITY OF SUCH DAMAGE.
#}
<!-- Navigation bar -->
<ul class="nav nav-tabs" data-tabs="tabs" id="maintabs">
<li class="active"><a data-toggle="tab" href="#general">{{ lang._('General') }}</a></li>
<li><a data-toggle="tab" href="#networks">{{ lang._('Networks') }}</a></li>
<li><a data-toggle="tab" href="#interfaces">{{ lang._('Interfaces') }}</a></li>
<li><a data-toggle="tab" href="#prefixlists">{{ lang._('Prefix Lists') }}</a></li>
<li><a data-toggle="tab" href="#routemaps">{{ lang._('Route Maps') }}</a></li>
</ul>
<div class="tab-content content-box tab-content">
<div id="general" class="tab-pane fade in active">
<div class="content-box" style="padding-bottom: 1.5em;">
{{ partial("layout_partials/base_form",['fields':generalForm,'id':'frm_ospf_settings'])}}
<div class="col-md-12">
<hr />
<button class="btn btn-primary" id="saveAct" type="button"><b>{{ lang._('Save') }}</b> <i id="saveAct_progress"></i></button>
</div>
</div>
</div>
<script>
function quagga_update_status() {
updateServiceControlUI('quagga');
}
$( document ).ready(function() {
mapDataToFormUI({'frm_ospf_settings':"/api/quagga/ospfsettings/get"}).done(function(data){
formatTokenizersUI();
$('.selectpicker').selectpicker('refresh');
updateServiceControlUI('quagga');
});
$("#reconfigureAct").SimpleActionButton({
onPreAction: function() {
const dfObj = new $.Deferred();
saveFormToEndpoint("/api/quagga/ospfsettings/set", 'frm_ospf_settings', function () { dfObj.resolve(); }, true, function () { dfObj.reject(); });
return dfObj;
},
onAction: function(data, status) {
updateServiceControlUI('quagga');
}
});
$("#grid-networks").UIBootgrid({
'search':'/api/quagga/ospfsettings/searchNetwork',
'get':'/api/quagga/ospfsettings/getNetwork/',
'set':'/api/quagga/ospfsettings/setNetwork/',
'add':'/api/quagga/ospfsettings/addNetwork/',
'del':'/api/quagga/ospfsettings/delNetwork/',
'toggle':'/api/quagga/ospfsettings/toggleNetwork/'
});
$("#grid-interfaces").UIBootgrid({
'search':'/api/quagga/ospfsettings/searchInterface',
'get':'/api/quagga/ospfsettings/getInterface/',
'set':'/api/quagga/ospfsettings/setInterface/',
'add':'/api/quagga/ospfsettings/addInterface/',
'del':'/api/quagga/ospfsettings/delInterface/',
'toggle':'/api/quagga/ospfsettings/toggleInterface/'
});
$("#grid-prefixlists").UIBootgrid({
'search':'/api/quagga/ospfsettings/searchPrefixlist',
'get':'/api/quagga/ospfsettings/getPrefixlist/',
'set':'/api/quagga/ospfsettings/setPrefixlist/',
'add':'/api/quagga/ospfsettings/addPrefixlist/',
'del':'/api/quagga/ospfsettings/delPrefixlist/',
'toggle':'/api/quagga/ospfsettings/togglePrefixlist/'
});
$("#grid-routemaps").UIBootgrid({
'search':'/api/quagga/ospfsettings/searchRoutemap',
'get':'/api/quagga/ospfsettings/getRoutemap/',
'set':'/api/quagga/ospfsettings/setRoutemap/',
'add':'/api/quagga/ospfsettings/addRoutemap/',
'del':'/api/quagga/ospfsettings/delRoutemap/',
'toggle':'/api/quagga/ospfsettings/toggleRoutemap/'
});
});
</script>
<!-- Navigation bar -->
<ul class="nav nav-tabs" data-tabs="tabs" id="maintabs">
<li class="active"><a data-toggle="tab" href="#general">{{ lang._('General') }}</a></li>
<li><a data-toggle="tab" href="#networks">{{ lang._('Networks') }}</a></li>
<li><a data-toggle="tab" href="#interfaces">{{ lang._('Interfaces') }}</a></li>
<li><a data-toggle="tab" href="#prefixlists">{{ lang._('Prefix Lists') }}</a></li>
<li><a data-toggle="tab" href="#routemaps">{{ lang._('Route Maps') }}</a></li>
</ul>
<div class="tab-content content-box tab-content">
<!-- Tab: General -->
<div id="general" class="tab-pane fade in active">
{{ partial("layout_partials/base_form",['fields':generalForm,'id':'frm_ospf_settings'])}}
</div>
<!-- Tab: Networks -->
<div id="networks" class="tab-pane fade in">
<table id="grid-networks" class="table table-responsive" data-editDialog="DialogEditNetwork">
@ -63,17 +116,15 @@ POSSIBILITY OF SUCH DAMAGE.
</tbody>
<tfoot>
<tr>
<td colspan="5"></td>
<td></td>
<td>
<button data-action="add" type="button" class="btn btn-xs btn-default"><span class="fa fa-plus"></span></button>
<!-- <button data-action="deleteSelected" type="button" class="btn btn-xs btn-default"><span class="fa fa-trash-o"></span></button> -->
<button type="button" class="btn btn-xs reload_btn btn-primary"><span class="fa fa-refresh reloadAct_progress"></span> {{ lang._('Reload Service') }}</button>
<button data-action="add" type="button" class="btn btn-xs btn-default"><span class="fa fa-plus"></span></button>
<button data-action="deleteSelected" type="button" class="btn btn-xs btn-default"><span class="fa fa-trash-o"></span></button>
</td>
</tr>
</tfoot>
</table>
</div>
<!-- Tab: Interfaces -->
<div id="interfaces" class="tab-pane fade in">
<table id="grid-interfaces" class="table table-responsive" data-editDialog="DialogEditInterface">
@ -85,22 +136,22 @@ POSSIBILITY OF SUCH DAMAGE.
<th data-column-id="authtype" data-type="string" data-visible="true">{{ lang._('Authentication Type') }}</th>
<th data-column-id="uuid" data-type="string" data-identifier="true" data-visible="false">{{ lang._('ID') }}</th>
<th data-column-id="commands" data-formatter="commands" data-sortable="false">{{ lang._('Commands') }}</th>
</tr>
</tr>
</thead>
<tbody>
</tbody>
<tfoot>
<tr>
<td colspan="5"></td>
<td></td>
<td>
<button data-action="add" type="button" class="btn btn-xs btn-default"><span class="fa fa-plus"></span></button>
<!-- <button data-action="deleteSelected" type="button" class="btn btn-xs btn-default"><span class="fa fa-trash-o"></span></button> -->
<button type="button" class="btn btn-xs reload_btn btn-primary"><span class="fa fa-refresh reloadAct_progress"></span> {{ lang._('Reload Service') }}</button>
<button data-action="deleteSelected" type="button" class="btn btn-xs btn-default"><span class="fa fa-trash-o"></span></button>
</td>
</tr>
</tfoot>
</table>
</div>
<!-- Tab: Prefixlists -->
<div id="prefixlists" class="tab-pane fade in">
<table id="grid-prefixlists" class="table table-responsive" data-editDialog="DialogEditPrefixLists">
<thead>
@ -118,16 +169,16 @@ POSSIBILITY OF SUCH DAMAGE.
</tbody>
<tfoot>
<tr>
<td colspan="5"></td>
<td></td>
<td>
<button data-action="add" type="button" class="btn btn-xs btn-default"><span class="fa fa-plus"></span></button>
<!-- <button data-action="deleteSelected" type="button" class="btn btn-xs btn-default"><span class="fa fa-trash-o"></span></button> -->
<button type="button" class="btn btn-xs reload_btn btn-primary"><span class="fa fa-refresh reloadAct_progress"></span> {{ lang._('Reload Service') }}</button>
<button data-action="deleteSelected" type="button" class="btn btn-xs btn-default"><span class="fa fa-trash-o"></span></button>
</td>
</tr>
</tfoot>
</table>
</div>
<!-- Tab: Routemaps -->
<div id="routemaps" class="tab-pane fade in">
<table id="grid-routemaps" class="table table-responsive" data-editDialog="DialogEditRouteMaps">
<thead>
@ -146,95 +197,30 @@ POSSIBILITY OF SUCH DAMAGE.
</tbody>
<tfoot>
<tr>
<td colspan="5"></td>
<td></td>
<td>
<button data-action="add" type="button" class="btn btn-xs btn-default"><span class="fa fa-plus"></span></button>
<button type="button" class="btn btn-xs reload_btn btn-primary"><span class="fa fa-refresh reloadAct_progress"></span> {{ lang._('Reload Service') }}</button>
<button data-action="deleteSelected" type="button" class="btn btn-xs btn-default"><span class="fa fa-trash-o"></span></button>
</td>
</tr>
</tfoot>
</table>
</div>
</div>
<section class="page-content-main">
<div class="content-box">
<div class="col-md-12">
<button class="btn btn-primary __mb __mt" id="reconfigureAct"
data-endpoint='/api/quagga/service/reconfigure'
data-label="{{ lang._('Apply') }}"
data-error-title="{{ lang._('Error reconfiguring OSPFv3') }}"
data-service-widget="quagga"
type="button"
></button>
</div>
</div>
<script>
function quagga_update_status() {
updateServiceControlUI('quagga');
}
$( document ).ready(function() {
var data_get_map = {'frm_ospf_settings':"/api/quagga/ospfsettings/get"};
mapDataToFormUI(data_get_map).done(function(data){
formatTokenizersUI();
$('.selectpicker').selectpicker('refresh');
});
quagga_update_status();
// link save button to API set action
$("#saveAct").click(function(){
saveFormToEndpoint(url="/api/quagga/ospfsettings/set",formid='frm_ospf_settings',callback_ok=function(){
$("#saveAct_progress").addClass("fa fa-spinner fa-pulse");
ajaxCall(url="/api/quagga/service/reconfigure", sendData={}, callback=function(data,status) {
quagga_update_status();
$("#saveAct_progress").removeClass("fa fa-spinner fa-pulse");
});
});
});
/* allow a user to manually reload the service (for forms which do not do it automatically) */
$('.reload_btn').click(function reload_handler() {
$(".reloadAct_progress").addClass("fa-spin");
ajaxCall(url="/api/quagga/service/reconfigure", sendData={}, callback=function(data,status) {
quagga_update_status();
$(".reloadAct_progress").removeClass("fa-spin");
});
});
$("#grid-networks").UIBootgrid(
{ 'search':'/api/quagga/ospfsettings/searchNetwork',
'get':'/api/quagga/ospfsettings/getNetwork/',
'set':'/api/quagga/ospfsettings/setNetwork/',
'add':'/api/quagga/ospfsettings/addNetwork/',
'del':'/api/quagga/ospfsettings/delNetwork/',
'toggle':'/api/quagga/ospfsettings/toggleNetwork/',
'options':{selection:false, multiSelect:false}
}
);
$("#grid-interfaces").UIBootgrid(
{ 'search':'/api/quagga/ospfsettings/searchInterface',
'get':'/api/quagga/ospfsettings/getInterface/',
'set':'/api/quagga/ospfsettings/setInterface/',
'add':'/api/quagga/ospfsettings/addInterface/',
'del':'/api/quagga/ospfsettings/delInterface/',
'toggle':'/api/quagga/ospfsettings/toggleInterface/',
'options':{selection:false, multiSelect:false}
}
);
$("#grid-prefixlists").UIBootgrid(
{ 'search':'/api/quagga/ospfsettings/searchPrefixlist',
'get':'/api/quagga/ospfsettings/getPrefixlist/',
'set':'/api/quagga/ospfsettings/setPrefixlist/',
'add':'/api/quagga/ospfsettings/addPrefixlist/',
'del':'/api/quagga/ospfsettings/delPrefixlist/',
'toggle':'/api/quagga/ospfsettings/togglePrefixlist/',
'options':{selection:false, multiSelect:false}
}
);
$("#grid-routemaps").UIBootgrid(
{ 'search':'/api/quagga/ospfsettings/searchRoutemap',
'get':'/api/quagga/ospfsettings/getRoutemap/',
'set':'/api/quagga/ospfsettings/setRoutemap/',
'add':'/api/quagga/ospfsettings/addRoutemap/',
'del':'/api/quagga/ospfsettings/delRoutemap/',
'toggle':'/api/quagga/ospfsettings/toggleRoutemap/',
'options':{selection:false, multiSelect:false}
}
);
});
</script>
</section>
{{ partial("layout_partials/base_dialog",['fields':formDialogEditNetwork,'id':'DialogEditNetwork','label':lang._('Edit Network')])}}
{{ partial("layout_partials/base_dialog",['fields':formDialogEditInterface,'id':'DialogEditInterface','label':lang._('Edit Interface')])}}

View file

@ -1,5 +1,5 @@
{#
# Copyright (c) 2014-2024 Deciso B.V.
# Copyright (c) 2014-2025 Deciso B.V.
# Copyright (c) 2017 Fabian Franz
# Copyright (c) 2017 Michael Muenz <m.muenz@gmail.com>
# All rights reserved.
@ -32,18 +32,17 @@
mapDataToFormUI({'frm_ospf6_settings':"/api/quagga/ospf6settings/get"}).done(function(data){
formatTokenizersUI();
$('.selectpicker').selectpicker('refresh');
updateServiceControlUI('quagga');
});
updateServiceControlUI('quagga');
// link save button to API set action
$("#saveAct").SimpleActionButton({
$("#reconfigureAct").SimpleActionButton({
onPreAction: function() {
const dfObj = new $.Deferred();
saveFormToEndpoint("/api/quagga/ospf6settings/set", 'frm_ospf6_settings', function(){
dfObj.resolve();
});
saveFormToEndpoint("/api/quagga/ospf6settings/set", 'frm_ospf6_settings', function () { dfObj.resolve(); }, true, function () { dfObj.reject(); });
return dfObj;
},
onAction: function(data, status) {
updateServiceControlUI('quagga');
}
});
@ -53,11 +52,7 @@
'set':'/api/quagga/ospf6settings/setNetwork/',
'add':'/api/quagga/ospf6settings/addNetwork/',
'del':'/api/quagga/ospf6settings/delNetwork/',
'toggle':'/api/quagga/ospf6settings/toggleNetwork/',
'options':{
selection:false,
multiSelect:false
}
'toggle':'/api/quagga/ospf6settings/toggleNetwork/'
});
$("#grid-interfaces").UIBootgrid({
'search':'/api/quagga/ospf6settings/searchInterface',
@ -65,11 +60,7 @@
'set':'/api/quagga/ospf6settings/setInterface/',
'add':'/api/quagga/ospf6settings/addInterface/',
'del':'/api/quagga/ospf6settings/delInterface/',
'toggle':'/api/quagga/ospf6settings/toggleInterface/',
'options':{
selection:false,
multiSelect:false
}
'toggle':'/api/quagga/ospf6settings/toggleInterface/'
});
$("#grid-prefixlists").UIBootgrid({
'search':'/api/quagga/ospf6settings/searchPrefixlist',
@ -77,11 +68,7 @@
'set':'/api/quagga/ospf6settings/setPrefixlist/',
'add':'/api/quagga/ospf6settings/addPrefixlist/',
'del':'/api/quagga/ospf6settings/delPrefixlist/',
'toggle':'/api/quagga/ospf6settings/togglePrefixlist/',
'options':{
selection:false,
multiSelect:false
}
'toggle':'/api/quagga/ospf6settings/togglePrefixlist/'
});
$("#grid-routemaps").UIBootgrid({
'search':'/api/quagga/ospf6settings/searchRoutemap',
@ -89,11 +76,7 @@
'set':'/api/quagga/ospf6settings/setRoutemap/',
'add':'/api/quagga/ospf6settings/addRoutemap/',
'del':'/api/quagga/ospf6settings/delRoutemap/',
'toggle':'/api/quagga/ospf6settings/toggleRoutemap/',
'options':{
selection:false,
multiSelect:false
}
'toggle':'/api/quagga/ospf6settings/toggleRoutemap/'
});
// hook checkbox item with conditional options
@ -142,10 +125,11 @@
</tbody>
<tfoot>
<tr>
<td colspan="5"></td>
<td>
<button data-action="add" type="button" class="btn btn-xs btn-default"><span class="fa fa-plus"></span></button>
</td>
<td></td>
<td>
<button data-action="add" type="button" class="btn btn-xs btn-default"><span class="fa fa-plus"></span></button>
<button data-action="deleteSelected" type="button" class="btn btn-xs btn-default"><span class="fa fa-trash-o"></span></button>
</td>
</tr>
</tfoot>
</table>
@ -168,9 +152,10 @@
</tbody>
<tfoot>
<tr>
<td colspan="5"></td>
<td></td>
<td>
<button data-action="add" type="button" class="btn btn-xs btn-default"><span class="fa fa-plus"></span></button>
<button data-action="deleteSelected" type="button" class="btn btn-xs btn-default"><span class="fa fa-trash-o"></span></button>
</td>
</tr>
</tfoot>
@ -195,9 +180,10 @@
</tbody>
<tfoot>
<tr>
<td colspan="5"></td>
<td></td>
<td>
<button data-action="add" type="button" class="btn btn-xs btn-default"><span class="fa fa-plus"></span></button>
<button data-action="deleteSelected" type="button" class="btn btn-xs btn-default"><span class="fa fa-trash-o"></span></button>
</td>
</tr>
</tfoot>
@ -223,9 +209,10 @@
</tbody>
<tfoot>
<tr>
<td colspan="5"></td>
<td></td>
<td>
<button data-action="add" type="button" class="btn btn-xs btn-default"><span class="fa fa-plus"></span></button>
<button data-action="deleteSelected" type="button" class="btn btn-xs btn-default"><span class="fa fa-trash-o"></span></button>
</td>
</tr>
</tfoot>
@ -236,7 +223,7 @@
<section class="page-content-main">
<div class="content-box">
<div class="col-md-12">
<button class="btn btn-primary __mb __mt" id="saveAct"
<button class="btn btn-primary __mb __mt" id="reconfigureAct"
data-endpoint='/api/quagga/service/reconfigure'
data-label="{{ lang._('Apply') }}"
data-error-title="{{ lang._('Error reconfiguring OSPFv3') }}"

View file

@ -1,6 +1,6 @@
{#
OPNsense® is Copyright © 2014 2017 by Deciso B.V.
OPNsense® is Copyright © 2014 2025 by Deciso B.V.
This file is Copyright © 2017 by Fabian Franz
All rights reserved.
@ -27,33 +27,42 @@ POSSIBILITY OF SUCH DAMAGE.
#}
<script>
$( document ).ready(function() {
mapDataToFormUI({'frm_rip_settings':"/api/quagga/rip/get"}).done(function(data){
formatTokenizersUI();
$('.selectpicker').selectpicker('refresh');
updateServiceControlUI('quagga');
});
$("#reconfigureAct").SimpleActionButton({
onPreAction: function() {
const dfObj = new $.Deferred();
saveFormToEndpoint("/api/quagga/rip/set", 'frm_rip_settings', function () { dfObj.resolve(); }, true, function () { dfObj.reject(); });
return dfObj;
},
onAction: function(data, status) {
updateServiceControlUI('quagga');
}
});
});
</script>
<div class="content-box" style="padding-bottom: 1.5em;">
{{ partial("layout_partials/base_form",['fields':ripForm,'id':'frm_rip_settings'])}}
<div class="col-md-12">
<hr />
<button class="btn btn-primary" id="saveAct" type="button"><b>{{ lang._('Save') }}</b> <i id="saveAct_progress"></i></button>
</div>
</div>
<script>
$(document).ready(function() {
var data_get_map = {'frm_rip_settings':"/api/quagga/rip/get"};
mapDataToFormUI(data_get_map).done(function(data){
formatTokenizersUI();
$('.selectpicker').selectpicker('refresh');
});
updateServiceControlUI('quagga');
// link save button to API set action
$("#saveAct").click(function(){
saveFormToEndpoint(url="/api/quagga/rip/set",formid='frm_rip_settings',callback_ok=function(){
$("#saveAct_progress").addClass("fa fa-spinner fa-pulse");
ajaxCall(url="/api/quagga/service/reconfigure", sendData={}, callback=function(data,status) {
updateServiceControlUI('quagga');
$("#saveAct_progress").removeClass("fa fa-spinner fa-pulse");
});
});
});
});
</script>
<section class="page-content-main">
<div class="content-box">
<div class="col-md-12">
<br/>
<button class="btn btn-primary" id="reconfigureAct"
data-endpoint='/api/quagga/service/reconfigure'
data-label="{{ lang._('Apply') }}"
data-error-title="{{ lang._('Error reconfiguring BFD') }}"
type="button"
></button>
<br/><br/>
</div>
</div>
</section>

View file

@ -1,7 +1,7 @@
PLUGIN_NAME= haproxy
PLUGIN_VERSION= 4.4
PLUGIN_VERSION= 4.5
PLUGIN_COMMENT= Reliable, high performance TCP/HTTP load balancer
PLUGIN_DEPENDS= haproxy28 py${PLUGIN_PYTHON}-haproxy-cli
PLUGIN_DEPENDS= haproxy py${PLUGIN_PYTHON}-haproxy-cli
PLUGIN_MAINTAINER= opnsense@moov.de
.include "../../Mk/plugins.mk"

View file

@ -6,6 +6,12 @@ very high loads while needing persistence or Layer7 processing.
Plugin Changelog
================
4.5
Changed:
* upgrade to HAProxy 3.0 release series (#4411)
* migrate cert export to Trust MVC
4.4
Fixed:

View file

@ -89,7 +89,7 @@
<id>action.http_request_redirect</id>
<label>HTTP Redirect</label>
<type>text</type>
<help><![CDATA[Use HAProxy's redirect function to return a HTTP redirection. See <a href="http://docs.haproxy.org/2.8/configuration.html#redirect">HAProxy's documentation</a> for further details and examples.]]></help>
<help><![CDATA[Use HAProxy's redirect function to return a HTTP redirection. See <a href="http://docs.haproxy.org/3.0/configuration.html#redirect">HAProxy's documentation</a> for further details and examples.]]></help>
</field>
<field>
<label>Parameters</label>
@ -128,7 +128,7 @@
<id>action.http_request_add_header_content</id>
<label>Header Content</label>
<type>text</type>
<help><![CDATA[The value that should be set for the specified HTTP header. Note that it is possible to use pre-defined variables, see <a href="http://docs.haproxy.org/2.8/configuration.html#8.2.4">HAProxy's documentation</a> for further details and examples.]]></help>
<help><![CDATA[The value that should be set for the specified HTTP header. Note that it is possible to use pre-defined variables, see <a href="http://docs.haproxy.org/3.0/configuration.html#8.2.4">HAProxy's documentation</a> for further details and examples.]]></help>
</field>
<field>
<label>Parameters</label>
@ -145,7 +145,7 @@
<id>action.http_request_set_header_content</id>
<label>Header Content</label>
<type>text</type>
<help><![CDATA[The value that should be set for the specified HTTP header. Note that it's possible to use pre-defined variables, see <a href="http://docs.haproxy.org/2.8/configuration.html#8.2.4">HAProxy's documentation</a> for further details and examples.]]></help>
<help><![CDATA[The value that should be set for the specified HTTP header. Note that it's possible to use pre-defined variables, see <a href="http://docs.haproxy.org/3.0/configuration.html#8.2.4">HAProxy's documentation</a> for further details and examples.]]></help>
</field>
<field>
<label>Parameters</label>
@ -251,7 +251,7 @@
<id>action.http_response_add_header_content</id>
<label>Header Content</label>
<type>text</type>
<help><![CDATA[The value that should be set for the specified HTTP header. Note that it's possible to use pre-defined variables, see <a href="http://docs.haproxy.org/2.8/configuration.html#8.2.4">HAProxy's documentation</a> for further details and examples.]]></help>
<help><![CDATA[The value that should be set for the specified HTTP header. Note that it's possible to use pre-defined variables, see <a href="http://docs.haproxy.org/3.0/configuration.html#8.2.4">HAProxy's documentation</a> for further details and examples.]]></help>
</field>
<field>
<label>Parameters</label>
@ -268,7 +268,7 @@
<id>action.http_response_set_header_content</id>
<label>Header Content</label>
<type>text</type>
<help><![CDATA[The value that should be set for the specified HTTP header. Note that it's possible to use pre-defined variables, see <a href="http://docs.haproxy.org/2.8/configuration.html#8.2.4">HAProxy's documentation</a> for further details and examples.]]></help>
<help><![CDATA[The value that should be set for the specified HTTP header. Note that it's possible to use pre-defined variables, see <a href="http://docs.haproxy.org/3.0/configuration.html#8.2.4">HAProxy's documentation</a> for further details and examples.]]></help>
</field>
<field>
<label>Parameters</label>
@ -468,6 +468,6 @@
<id>action.fcgi_set_param</id>
<label>Parameter</label>
<type>text</type>
<help><![CDATA[Set a FastCGI parameter that should be passed to the application. Its value must follow HAProxy's <a href="http://docs.haproxy.org/2.8/configuration.html#8.2.4">Custom Log format rules</a>. With this directive, it is possible to overwrite the value of default FastCGI parameters.]]></help>
<help><![CDATA[Set a FastCGI parameter that should be passed to the application. Its value must follow HAProxy's <a href="http://docs.haproxy.org/3.0/configuration.html#8.2.4">Custom Log format rules</a>. With this directive, it is possible to overwrite the value of default FastCGI parameters.]]></help>
</field>
</form>

View file

@ -28,7 +28,7 @@
<id>backend.algorithm</id>
<label>Balancing Algorithm</label>
<type>dropdown</type>
<help><![CDATA[Define the load balancing algorithm to be used in a Backend Pool. See the <a target="_blank" href="http://docs.haproxy.org/2.8/configuration.html#balance">HAProxy documentation</a> for a full description.]]></help>
<help><![CDATA[Define the load balancing algorithm to be used in a Backend Pool. See the <a target="_blank" href="http://docs.haproxy.org/3.0/configuration.html#balance">HAProxy documentation</a> for a full description.]]></help>
<hint>Choose a load balancing algorithm.</hint>
</field>
<field>
@ -42,7 +42,7 @@
<id>backend.proxyProtocol</id>
<label>Proxy Protocol</label>
<type>dropdown</type>
<help><![CDATA[Enforces use of the PROXY protocol over any connection established to the configured servers. The PROXY protocol informs the other end about the layer 3/4 addresses of the incoming connection, so that it can know the client's address or the public address it accessed to, whatever the upper layer protocol. This setting must not be used if the servers are not aware of the PROXY protocol. See the <a target="_blank" href="http://docs.haproxy.org/2.8/configuration.html#send-proxy">HAProxy documentation</a> for a full description.]]></help>
<help><![CDATA[Enforces use of the PROXY protocol over any connection established to the configured servers. The PROXY protocol informs the other end about the layer 3/4 addresses of the incoming connection, so that it can know the client's address or the public address it accessed to, whatever the upper layer protocol. This setting must not be used if the servers are not aware of the PROXY protocol. See the <a target="_blank" href="http://docs.haproxy.org/3.0/configuration.html#send-proxy">HAProxy documentation</a> for a full description.]]></help>
<advanced>true</advanced>
</field>
<field>
@ -186,7 +186,7 @@
<style>tokenize</style>
<allownew>true</allownew>
<sortable>true</sortable>
<help><![CDATA[This may be used to add more information to the forwarded header. Default behavior enables proto parameter and injects original client IP. See he <a target="_blank" href="http://docs.haproxy.org/2.8/configuration.html#option forwarded">HAProxy documentation</a> for a full description.]]></help>
<help><![CDATA[This may be used to add more information to the forwarded header. Default behavior enables proto parameter and injects original client IP. See he <a target="_blank" href="http://docs.haproxy.org/3.0/configuration.html#option forwarded">HAProxy documentation</a> for a full description.]]></help>
</field>
<field>
<id>backend.forwardFor</id>
@ -213,7 +213,7 @@
<id>backend.persistence_cookiemode</id>
<label>Cookie handling</label>
<type>dropdown</type>
<help><![CDATA[Usually it is better to reuse an existing cookie. In this case HAProxy prefixes the cookie with the required information. See the <a target="_blank" href="http://docs.haproxy.org/2.8/configuration.html#4.2-cookie">HAProxy documentation</a> for a full description.]]></help>
<help><![CDATA[Usually it is better to reuse an existing cookie. In this case HAProxy prefixes the cookie with the required information. See the <a target="_blank" href="http://docs.haproxy.org/3.0/configuration.html#4.2-cookie">HAProxy documentation</a> for a full description.]]></help>
</field>
<field>
<id>backend.persistence_cookiename</id>
@ -235,14 +235,14 @@
<id>backend.stickiness_pattern</id>
<label>Table type</label>
<type>dropdown</type>
<help><![CDATA[Choose a request pattern to associate a user to a server. See the <a target="_blank" href="http://docs.haproxy.org/2.8/configuration.html#stick on">HAProxy documentation</a> for a full description.<br/><div class="text-info"><b>NOTE:</b> Consider not using this feature in multi-process mode, it can result in random behaviours.</div>]]></help>
<help><![CDATA[Choose a request pattern to associate a user to a server. See the <a target="_blank" href="http://docs.haproxy.org/3.0/configuration.html#stick on">HAProxy documentation</a> for a full description.<br/><div class="text-info"><b>NOTE:</b> Consider not using this feature in multi-process mode, it can result in random behaviours.</div>]]></help>
<hint>Choose a persistence type.</hint>
</field>
<field>
<id>backend.stickiness_dataTypes</id>
<label>Stored data types</label>
<type>select_multiple</type>
<help><![CDATA[This is used to store additional information in the stick-table. It may be used by ACLs in order to control various criteria related to the activity of the client matching the stick-table. Note that this directly impacts memory usage. See the <a target="_blank" href="http://docs.haproxy.org/2.8/configuration.html#stick-table">HAProxy documentation</a> for a full description.]]></help>
<help><![CDATA[This is used to store additional information in the stick-table. It may be used by ACLs in order to control various criteria related to the activity of the client matching the stick-table. Note that this directly impacts memory usage. See the <a target="_blank" href="http://docs.haproxy.org/3.0/configuration.html#stick-table">HAProxy documentation</a> for a full description.]]></help>
</field>
<field>
<id>backend.stickiness_expire</id>

View file

@ -33,7 +33,7 @@
<id>fcgi.path_info</id>
<label>Path Info</label>
<type>text</type>
<help><![CDATA[Define a regular expression to extract the script-name and the path-info from the URL-decoded path, see <a href="http://docs.haproxy.org/2.8/configuration.html#10.1.1-path-info">HAProxy's documentation</a> for further details and examples.]]></help>
<help><![CDATA[Define a regular expression to extract the script-name and the path-info from the URL-decoded path, see <a href="http://docs.haproxy.org/3.0/configuration.html#10.1.1-path-info">HAProxy's documentation</a> for further details and examples.]]></help>
</field>
<field>
<id>fcgi.log_stderr</id>

View file

@ -350,14 +350,14 @@
<id>frontend.stickiness_pattern</id>
<label>Table type</label>
<type>dropdown</type>
<help><![CDATA[Choose the type of data that should be stored in this stick-table. Note that this stick-table cannot be used for session persistence, it is only used to store additional per-connection data (select below). See the <a target="_blank" href="http://docs.haproxy.org/2.8/configuration.html#stick-table">HAProxy documentation</a> for further information.]]></help>
<help><![CDATA[Choose the type of data that should be stored in this stick-table. Note that this stick-table cannot be used for session persistence, it is only used to store additional per-connection data (select below). See the <a target="_blank" href="http://docs.haproxy.org/3.0/configuration.html#stick-table">HAProxy documentation</a> for further information.]]></help>
<hint>Choose a stick-table type.</hint>
</field>
<field>
<id>frontend.stickiness_dataTypes</id>
<label>Stored data types</label>
<type>select_multiple</type>
<help><![CDATA[This is used to store additional information in the stick-table. It may be used by ACLs in order to control various criteria related to the activity of the client matching the stick-table. Note that this directly impacts memory usage. See the <a target="_blank" href="http://docs.haproxy.org/2.8/configuration.html#stick-table">HAProxy documentation</a> for a full description.]]></help>
<help><![CDATA[This is used to store additional information in the stick-table. It may be used by ACLs in order to control various criteria related to the activity of the client matching the stick-table. Note that this directly impacts memory usage. See the <a target="_blank" href="http://docs.haproxy.org/3.0/configuration.html#stick-table">HAProxy documentation</a> for a full description.]]></help>
</field>
<field>
<id>frontend.stickiness_expire</id>
@ -384,7 +384,7 @@
<id>frontend.stickiness_counter_key</id>
<label>Sticky counter key</label>
<type>text</type>
<help><![CDATA[It describes what elements of the incoming request or connection will be analyzed, extracted, combined, and used to select which table entry to update the counters. Defaults to "src" to track elements of the source IP. See the <a target="_blank" href="http://docs.haproxy.org/2.8/configuration.html#tcp-request connection">HAProxy documentation</a> for a full description.]]></help>
<help><![CDATA[It describes what elements of the incoming request or connection will be analyzed, extracted, combined, and used to select which table entry to update the counters. Defaults to "src" to track elements of the source IP. See the <a target="_blank" href="http://docs.haproxy.org/3.0/configuration.html#tcp-request connection">HAProxy documentation</a> for a full description.]]></help>
<advanced>true</advanced>
</field>
<field>

View file

@ -15,6 +15,6 @@
<id>mapfile.content</id>
<label>Content</label>
<type>textbox</type>
<help><![CDATA[Paste the content of your map file here. See the <a target="_blank" href="http://docs.haproxy.org/2.8/configuration.html#map">HAProxy documentation</a> for a full description.]]></help>
<help><![CDATA[Paste the content of your map file here. See the <a target="_blank" href="http://docs.haproxy.org/3.0/configuration.html#map">HAProxy documentation</a> for a full description.]]></help>
</field>
</form>

View file

@ -717,7 +717,7 @@ POSSIBILITY OF SUCH DAMAGE.
<li>{{ lang._('Lastly, enable HAProxy using the %sService%s settings page.') | format('<b>', '</b>') }}</li>
</ul>
<p>{{ lang._('Please be aware that you need to %smanually%s add the required firewall rules for all configured services.') | format('<b>', '</b>') }}</p>
<p>{{ lang._('Further information is available in the %sofficial HAProxy documentation%s. Be sure to report bugs and request features on our %sGitHub issue page%s. Code contributions are also very welcome!') | format('<a href="http://docs.haproxy.org/2.8/configuration.html" target="_blank">', '</a>', '<a href="https://github.com/opnsense/plugins/issues/" target="_blank">', '</a>') }}</p>
<p>{{ lang._('Further information is available in the %sofficial HAProxy documentation%s. Be sure to report bugs and request features on our %sGitHub issue page%s. Code contributions are also very welcome!') | format('<a href="http://docs.haproxy.org/3.0/configuration.html" target="_blank">', '</a>', '<a href="https://github.com/opnsense/plugins/issues/" target="_blank">', '</a>') }}</p>
<br/>
</div>
</div>
@ -759,7 +759,7 @@ POSSIBILITY OF SUCH DAMAGE.
<li>{{ lang._('%sConditions:%s HAProxy is capable of extracting data from requests, responses and other connection data and match it against predefined patterns. Use these powerful patterns to compose a condition that may be used in multiple Rules.') | format('<b>', '</b>') }}</li>
<li>{{ lang._('%sRules:%s Perform a large set of actions if one or more %sConditions%s match. These Rules may be used in %sBackend Pools%s as well as %sPublic Services%s.') | format('<b>', '</b>', '<b>', '</b>', '<b>', '</b>', '<b>', '</b>') }}</li>
</ul>
<p>{{ lang._("For more information on HAProxy's %sACL feature%s see the %sofficial documentation%s.") | format('<b>', '</b>', '<a href="http://docs.haproxy.org/2.8/configuration.html#7" target="_blank">', '</a>') }}</p>
<p>{{ lang._("For more information on HAProxy's %sACL feature%s see the %sofficial documentation%s.") | format('<b>', '</b>', '<a href="http://docs.haproxy.org/3.0/configuration.html#7" target="_blank">', '</a>') }}</p>
<p>{{ lang._('Note that it is possible to directly add options to the HAProxy configuration by using the "option pass-through", a setting that is available for several configuration items. It allows you to implement configurations that are currently not officially supported by this plugin. It is strongly discouraged to rely on this feature. Please report missing features on our GitHub page!') | format('<b>', '</b>') }}</p>
<br/>
</div>
@ -774,7 +774,7 @@ POSSIBILITY OF SUCH DAMAGE.
<li>{{ lang._('%sGroup:%s A optional list containing one or more users. Groups usually make it easier to manage permissions for a large number of users') | format('<b>', '</b>') }}</li>
</ul>
<p>{{ lang._('Note that users and groups must be selected from the Backend Pool or Public Service configuration in order to be used for authentication. In addition to this users and groups may also be used in Rules/Conditions.') }}</p>
<p>{{ lang._("For more information on HAProxy's %suser/group management%s see the %sofficial documentation%s.") | format('<b>', '</b>', '<a href="http://docs.haproxy.org/2.8/configuration.html#3.4" target="_blank">', '</a>') }}</p>
<p>{{ lang._("For more information on HAProxy's %suser/group management%s see the %sofficial documentation%s.") | format('<b>', '</b>', '<a href="http://docs.haproxy.org/3.0/configuration.html#3.4" target="_blank">', '</a>') }}</p>
<br/>
</div>
</div>
@ -792,7 +792,7 @@ POSSIBILITY OF SUCH DAMAGE.
<li>{{ lang._("%sCache:%s HAProxy's cache which was designed to perform cache on small objects (favicon, css, etc.). This is a minimalist low-maintenance cache which runs in RAM.") | format('<b>', '</b>', '<b>', '</b>') }}</li>
<li>{{ lang._("%sPeers:%s Configure a communication channel between two HAProxy instances. This will propagate entries of any data-types in stick-tables between these HAProxy instances over TCP connections in a multi-master fashion. Useful when aiming for a seamless failover in a HA setup.") | format('<b>', '</b>', '<b>', '</b>') }}</li>
</ul>
<p>{{ lang._("For more details visit HAProxy's official documentation regarding the %sStatistics%s, %sCache%s and %sPeers%s features.") | format('<a href="http://docs.haproxy.org/2.8/configuration.html#stats%20enable" target="_blank">', '</a>', '<a href="http://docs.haproxy.org/2.8/configuration.html#10" target="_blank">', '</a>', '<a href="http://docs.haproxy.org/2.8/configuration.html#3.5" target="_blank">', '</a>') }}</p>
<p>{{ lang._("For more details visit HAProxy's official documentation regarding the %sStatistics%s, %sCache%s and %sPeers%s features.") | format('<a href="http://docs.haproxy.org/3.0/configuration.html#stats%20enable" target="_blank">', '</a>', '<a href="http://docs.haproxy.org/3.0/configuration.html#10" target="_blank">', '</a>', '<a href="http://docs.haproxy.org/3.0/configuration.html#3.5" target="_blank">', '</a>') }}</p>
<br/>
</div>
</div>
@ -810,7 +810,7 @@ POSSIBILITY OF SUCH DAMAGE.
<li>{{ lang._("%sResolvers:%s This feature allows in-depth configuration of how HAProxy handles name resolution and interacts with name resolvers (DNS). Each resolver configuration can be used in %sBackend Pools%s to apply individual name resolution configurations.") | format('<b>', '</b>', '<b>', '</b>') }}</li>
<li>{{ lang._("%sE-Mail Alerts:%s It is possible to send email alerts when the state of servers changes. Each configuration can be used in %sBackend Pools%s to send e-mail alerts to the configured recipient.") | format('<b>', '</b>', '<b>', '</b>') }}</li>
</ul>
<p>{{ lang._("For more details visit HAProxy's official documentation regarding the %sError Messages%s, %sLua Script%s and the %sMap Files%s features. More information on HAProxy's CPU Affinity is also available %shere%s, %shere%s and %shere%s. A detailed explanation of the resolvers feature can be found %shere%s.") | format('<a href="http://docs.haproxy.org/2.8/configuration.html#4-errorfile" target="_blank">', '</a>', '<a href="http://docs.haproxy.org/2.8/configuration.html#lua-load" target="_blank">', '</a>', '<a href="http://docs.haproxy.org/2.8/configuration.html#map" target="_blank">', '</a>' ,'<a href="http://docs.haproxy.org/2.8/configuration.html#cpu-map" target="_blank">', '</a>' ,'<a href="http://docs.haproxy.org/2.8/configuration.html#bind-process" target="_blank">', '</a>' ,'<a href="http://docs.haproxy.org/2.8/configuration.html#process" target="_blank">', '</a>','<a href="http://docs.haproxy.org/2.8/configuration.html#5.3.2" target="_blank">', '</a>') }}</p>
<p>{{ lang._("For more details visit HAProxy's official documentation regarding the %sError Messages%s, %sLua Script%s and the %sMap Files%s features. More information on HAProxy's CPU Affinity is also available %shere%s, %shere%s and %shere%s. A detailed explanation of the resolvers feature can be found %shere%s.") | format('<a href="http://docs.haproxy.org/3.0/configuration.html#4-errorfile" target="_blank">', '</a>', '<a href="http://docs.haproxy.org/3.0/configuration.html#lua-load" target="_blank">', '</a>', '<a href="http://docs.haproxy.org/3.0/configuration.html#map" target="_blank">', '</a>' ,'<a href="http://docs.haproxy.org/3.0/configuration.html#cpu-map" target="_blank">', '</a>' ,'<a href="http://docs.haproxy.org/3.0/configuration.html#bind-process" target="_blank">', '</a>' ,'<a href="http://docs.haproxy.org/3.0/configuration.html#process" target="_blank">', '</a>','<a href="http://docs.haproxy.org/3.0/configuration.html#5.3.2" target="_blank">', '</a>') }}</p>
<br/>
</div>
</div>

View file

@ -2,7 +2,7 @@
<?php
/*
* Copyright (C) 2016-2024 Frank Wall
* Copyright (C) 2016-2025 Frank Wall
* Copyright (C) 2015 Deciso B.V.
* All rights reserved.
*
@ -28,12 +28,11 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
// Use legacy code to export certificates to the filesystem.
require_once('script/load_phalcon.php');
require_once("config.inc");
require_once("certs.inc");
require_once("legacy_bindings.inc");
use OPNsense\Core\Config;
use OPNsense\Trust\Store as CertStore;
$export_path = '/tmp/haproxy/ssl/';
@ -82,8 +81,9 @@ foreach ($configNodes as $key => $value) {
$ocsp_conf = '';
// CRLs require special export
if ($type == 'crl') {
$crl =& lookup_crl($cert_refid);
$pem_content = base64_decode($crl['text']);
if (isset($cert->text)) {
$pem_content = base64_decode($cert->text);
}
} else {
$pem_content = str_replace("\n\n", "\n", str_replace("\r", "", base64_decode((string)$cert->crt)));
$pem_content .= "\n" . str_replace("\n\n", "\n", str_replace("\r", "", base64_decode((string)$cert->prv)));
@ -91,9 +91,8 @@ foreach ($configNodes as $key => $value) {
$ocsp_conf = hasOcspInfo($pem_content) ? ' [ocsp-update on]' : '';
// check if a CA is linked
if (!empty((string)$cert->caref)) {
$cert = (array)$cert;
$ca = ca_chain($cert);
// append the CA to the certificate data
$ca = CertStore::getCaChain((string)$cert->caref);
$pem_content .= "\n" . $ca;
// additionally export CA to it's own file,
// not required for HAProxy, but makes OCSP handling easier

View file

@ -30,8 +30,6 @@
// Use legacy code to export certificates to the filesystem.
require_once("config.inc");
require_once("certs.inc");
require_once("legacy_bindings.inc");
use OPNsense\Core\Config;

View file

@ -30,8 +30,6 @@
// Use legacy code to export certificates to the filesystem.
require_once("config.inc");
require_once("certs.inc");
require_once("legacy_bindings.inc");
use OPNsense\Core\Config;

View file

@ -30,8 +30,6 @@
// Use legacy code to export certificates to the filesystem.
require_once("config.inc");
require_once("certs.inc");
require_once("legacy_bindings.inc");
use OPNsense\Core\Config;

View file

@ -990,10 +990,10 @@ global
{# # check if OCSP is enabled #}
{% if OPNsense.HAProxy.general.tuning.ocspUpdateEnabled|default('') == '1' %}
{% if helpers.exists('OPNsense.HAProxy.general.tuning.ocspUpdateMinDelay') %}
tune.ssl.ocsp-update.mindelay {{OPNsense.HAProxy.general.tuning.ocspUpdateMinDelay}}
ocsp-update.mindelay {{OPNsense.HAProxy.general.tuning.ocspUpdateMinDelay}}
{% endif %}
{% if helpers.exists('OPNsense.HAProxy.general.tuning.ocspUpdateMaxDelay') %}
tune.ssl.ocsp-update.maxdelay {{OPNsense.HAProxy.general.tuning.ocspUpdateMaxDelay}}
ocsp-update.maxdelay {{OPNsense.HAProxy.general.tuning.ocspUpdateMaxDelay}}
{% endif %}
{% endif %}
{% if helpers.exists('OPNsense.HAProxy.general.tuning.resolversPrefer') %}

View file

@ -1,5 +1,6 @@
PLUGIN_NAME= relayd
PLUGIN_VERSION= 2.9
PLUGIN_REVISION= 1
PLUGIN_DEPENDS= relayd
PLUGIN_COMMENT= Relayd Load Balancer
PLUGIN_MAINTAINER= frank.brendel@eurolog.com

View file

@ -71,7 +71,6 @@ class ServiceController extends ApiMutableServiceControllerBase
{
if ($this->request->isPost()) {
$result['status'] = 'ok';
$this->sessionClose();
$backend = new Backend();
@ -96,7 +95,6 @@ class ServiceController extends ApiMutableServiceControllerBase
{
if ($this->request->isPost()) {
if ($this->lock()) {
$this->sessionClose();
$result['function'] = "reconfigure";
$result['status'] = 'failed';
$backend = new Backend();

View file

@ -240,7 +240,6 @@ class SettingsController extends ApiMutableModelControllerBase
*/
public function searchAction($nodeType = null)
{
$this->sessionClose();
if ($this->request->isPost() && $nodeType != null) {
$this->validateNodeType($nodeType);
$grid = new UIModelGrid($this->getModel()->$nodeType);

View file

@ -202,7 +202,6 @@ class StatusController extends ApiControllerBase
{
$result = ["result" => "failed", "function" => "toggle"];
if ($this->request->isPost()) {
$this->sessionClose();
$backend = new Backend();
if (in_array($nodeType, ['redirect', 'table', 'host']) && in_array($action, ['enable', 'disable'])) {
if ($id != null && $id > 0) {
@ -225,7 +224,9 @@ class StatusController extends ApiControllerBase
$relaydMdl->serializeToConfig();
Config::getInstance()->save();
// invoke service controller
return (new ServiceController())->reconfigureAction();
$srv = new ServiceController();
$srv->request = $this->request;
return $srv->reconfigureAction();
}
}
return $result;

View file

@ -1,31 +1,29 @@
{#
Copyright © 2018 by EURO-LOG AG
Copyright (c) 2021 Deciso B.V.
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.
#}
# Copyright (c) 2018 EURO-LOG AG
# Copyright (c) 2021 Deciso B.V.
# 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>
@ -365,7 +363,7 @@ POSSIBILITY OF SUCH DAMAGE.
<th data-column-id="enabled" data-width="6em" data-type="string" data-formatter="rowtoggle">{{ lang._('Enabled') }}</th>
<th data-column-id="name" data-type="string">{{ lang._('Name') }}</th>
<th data-column-id="type" data-type="string">{{ lang._('Type') }}</th>
<th data-column-id="listen_address" data-type="string">{{ lang._('Adress') }}</th>
<th data-column-id="listen_address" data-type="string">{{ lang._('Address') }}</th>
<th data-column-id="listen_startport" data-formatter="listen_port" data-type="string">{{ lang._('Port') }}</th>
<th data-column-id="uuid" data-type="string" data-identifier="true" data-visible="false">{{ lang._('ID') }}</th>
<th data-column-id="commands" data-width="7em" data-formatter="commands" data-sortable="false">{{ lang._('Edit') }} | {{ lang._('Delete') }}</th>

View file

@ -77,7 +77,6 @@ class DomainController extends ApiMutableModelControllerBase
public function searchDomainAction()
{
$this->sessionClose();
$mdlDomain = $this->getModel();
$grid = new UIModelGrid($mdlDomain->domains->domain);
return $grid->fetchBindRequest(

View file

@ -57,8 +57,6 @@ class ServiceController extends ApiControllerBase
public function startAction()
{
if ($this->request->isPost()) {
// close session for long running action
$this->sessionClose();
$backend = new Backend();
$response = $backend->configdRun("siproxd start");
return array("response" => $response);
@ -74,8 +72,6 @@ class ServiceController extends ApiControllerBase
public function stopAction()
{
if ($this->request->isPost()) {
// close session for long running action
$this->sessionClose();
$backend = new Backend();
$response = $backend->configdRun("siproxd stop");
return array("response" => $response);
@ -91,8 +87,6 @@ class ServiceController extends ApiControllerBase
public function restartAction()
{
if ($this->request->isPost()) {
// close session for long running action
$this->sessionClose();
$backend = new Backend();
$response = $backend->configdRun("siproxd restart");
return array("response" => $response);
@ -135,9 +129,6 @@ class ServiceController extends ApiControllerBase
public function reconfigureAction()
{
if ($this->request->isPost()) {
// close session for long running action
$this->sessionClose();
$mdlGeneral = new General();
$backend = new Backend();

View file

@ -77,7 +77,6 @@ class UserController extends ApiMutableModelControllerBase
public function searchUserAction()
{
$this->sessionClose();
$mdlUser = $this->getModel();
$grid = new UIModelGrid($mdlUser->users->user);
return $grid->fetchBindRequest(

View file

@ -1,5 +1,5 @@
PLUGIN_NAME= acme-client
PLUGIN_VERSION= 4.7
PLUGIN_VERSION= 4.8
PLUGIN_COMMENT= ACME Client
PLUGIN_MAINTAINER= opnsense@moov.de
PLUGIN_DEPENDS= acme.sh py${PLUGIN_PYTHON}-dns-lexicon

View file

@ -8,6 +8,18 @@ WWW: https://github.com/acmesh-official/acme.sh
Plugin Changelog
================
4.8
BREAKING CHANGE: Let's Encrypt ends support for the OCSP Must Staple
extension on 30.01.2025. Issuance requests will fail if this option is
still enabled past this date.
Changed:
* Add note regarding the support of OCSP
Fixed:
* SFTP automation unable to transfer certs (#4477)
4.7
Added:
@ -18,10 +30,12 @@ Added:
Changed:
* Convert Synology deploy hook variables to uppercase (#4286)
* Migrate to MVC Trust storage
Fixed:
* SFTP/SSH automation results in fatal PHP error (#4363)
* Typo in INWX password field name
* Certs not fully functional after import into Trust storage (#4401)
4.6

View file

@ -48,7 +48,6 @@ class AccountsController extends ApiMutableModelControllerBase
public function getAction($uuid = null)
{
$this->sessionClose();
return $this->getBase('account', 'accounts.account', $uuid);
}

View file

@ -46,7 +46,6 @@ class ActionsController extends ApiMutableModelControllerBase
public function getAction($uuid = null)
{
$this->sessionClose();
return $this->getBase('action', 'actions.action', $uuid);
}

View file

@ -48,7 +48,6 @@ class CertificatesController extends ApiMutableModelControllerBase
public function getAction($uuid = null)
{
$this->sessionClose();
return $this->getBase('certificate', 'certificates.certificate', $uuid);
}

View file

@ -50,8 +50,6 @@ class ServiceController extends ApiControllerBase
public function startAction()
{
if ($this->request->isPost()) {
// close session for long running action
$this->sessionClose();
$backend = new Backend();
$response = $backend->configdRun("acmeclient http-start");
return array("response" => $response);
@ -67,8 +65,6 @@ class ServiceController extends ApiControllerBase
public function stopAction()
{
if ($this->request->isPost()) {
// close session for long running action
$this->sessionClose();
$backend = new Backend();
$response = $backend->configdRun("acmeclient http-stop");
return array("response" => $response);
@ -84,8 +80,6 @@ class ServiceController extends ApiControllerBase
public function restartAction()
{
if ($this->request->isPost()) {
// close session for long running action
$this->sessionClose();
$backend = new Backend();
$response = $backend->configdRun("acmeclient http-restart");
return array("response" => $response);
@ -128,9 +122,6 @@ class ServiceController extends ApiControllerBase
public function reconfigureAction()
{
if ($this->request->isPost()) {
// close session for long running action
$this->sessionClose();
$force_restart = false;
$mdlAcme = new AcmeClient();

View file

@ -47,7 +47,6 @@ class ValidationsController extends ApiMutableModelControllerBase
public function getAction($uuid = null)
{
$this->sessionClose();
return $this->getBase('validation', 'validations.validation', $uuid);
}

View file

@ -188,7 +188,7 @@
<id>action.acme_synology_dsm_hostname</id>
<label>Synology Hostname</label>
<type>text</type>
<help>Hostname of IP adress of the Synology DSM, i.e. synology.example.com or 192.168.0.1.</help>
<help>Hostname of IP address of the Synology DSM, i.e. synology.example.com or 192.168.0.1.</help>
</field>
<field>
<id>action.acme_synology_dsm_port</id>
@ -340,7 +340,7 @@
<id>action.acme_truenas_hostname</id>
<label>TrueNAS hostname</label>
<type>text</type>
<help>Hostname or IP adress of TrueNAS Core Server.</help>
<help>Hostname or IP address of TrueNAS Core Server.</help>
</field>
<field>
<id>action.acme_truenas_scheme</id>

View file

@ -68,11 +68,15 @@
<type>dropdown</type>
<help><![CDATA[Specify the domain key length: 2048, 3072, 4096, 8192 or ec-256, ec-384.]]></help>
</field>
<field>
<label><![CDATA[NOTE: OCSP is not supported by all CAs.]]></label>
<type>info</type>
</field>
<field>
<id>certificate.ocsp</id>
<label>OCSP Must Staple</label>
<type>checkbox</type>
<help>Generate and add OCSP Must Staple extension to the certificate.</help>
<help>Generate and add OCSP Must Staple extension to the certificate. When this option is enabled and issueance/renewal requests fail, then this extension is probably not supported by the CA.</help>
</field>
<field>
<label>Advanced Settings</label>

View file

@ -1,7 +1,7 @@
<?php
/*
* Copyright (C) 2020-2024 Frank Wall
* Copyright (C) 2020-2025 Frank Wall
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -28,10 +28,12 @@
namespace OPNsense\AcmeClient;
// Load legacy functions
require_once("certs.inc"); // used in import()
require_once("script/load_phalcon.php");
use OPNsense\Core\Config;
use OPNsense\Trust\Ca;
use OPNsense\Trust\Cert;
use OPNsense\Trust\Store as CertStore;
use OPNsense\AcmeClient\LeAccount;
use OPNsense\AcmeClient\LeAutomationFactory;
use OPNsense\AcmeClient\LeValidationFactory;
@ -143,61 +145,54 @@ class LeCertificate extends LeCommon
// Read contents from CA file
$ca_content = @file_get_contents($this->cert_chain_file);
if ($ca_content != false) {
$ca_subject = cert_get_subject($ca_content, false);
$ca_serial = cert_get_serial($ca_content, false);
$ca_cn = LeUtils::local_cert_get_cn($ca_content, false);
$ca_issuer = cert_get_issuer($ca_content, false);
$ca_purpose = cert_get_purpose($ca_content, false);
$ca_details = CertStore::parseX509($ca_content);
$ca_subject = $ca_details['name'];
$ca_serial = $ca_details['serialNumber'];
$ca_cn = $ca_details['commonname'];
$ca_issuer = implode(",", $ca_details['issuer']);
} else {
LeUtils::log_error('unable to read CA certificate content from file');
Config::getInstance()->unlock();
return false;
}
// Prepare CA for import in Cert Manager
// Prepare CA
$caModel = new Ca();
$ca = array();
$ca['crt'] = base64_encode($ca_content);
$ca['refid'] = uniqid();
$ca['descr'] = (string)$ca_cn . ' (ACME Client)';
$ca_found = false;
// Check if CA was previously imported
foreach (Config::getInstance()->object()->ca as $cacrt) {
$cacrt_subject = cert_get_subject($cacrt->crt, true);
$cacrt_issuer = cert_get_issuer($cacrt->crt, true);
foreach ($caModel->ca->iterateItems() as $cacrt) {
$cacrt_content = base64_decode((string)$cacrt->crt);
$cacrt_details = CertStore::parseX509($cacrt_content);
$cacrt_subject = $cacrt_details['name'];
$cacrt_issuer = implode(",", $cacrt_details['issuer']);
if (($ca_subject === $cacrt_subject) and ($ca_issuer === $cacrt_issuer)) {
// Use old refid instead of generating a new one
$ca['refid'] = (string)$cacrt->refid;
// Update existing CA
$cacrt->descr = $ca['descr'];
$ca_found = true;
break;
}
}
// Collect required CA information
$ca_cn = LeUtils::local_cert_get_cn($ca_content, false);
$ca['descr'] = (string)$ca_cn . ' (ACME Client)';
// Prepare CA for import
LeUtils::local_ca_import($ca, $ca_content);
// Check if CA was found in config
if ($ca_found == true) {
// Update existing CA
foreach (Config::getInstance()->object()->ca as $cacrt) {
if ((string)$cacrt->refid == $ca['refid']) {
$cacrt->crt = $ca['crt'];
$cacrt->descr = $ca['descr'];
break;
}
}
} else {
// Create new CA
LeUtils::log("importing ACME CA: {$ca_cn}");
$newca = Config::getInstance()->object()->addChild('ca');
// Create new CA
if ($ca_found == false) {
LeUtils::log("imported ACME CA: {$ca_cn} ({$ca['refid']})");
$newca = $caModel->ca->Add();
foreach (array_keys($ca) as $cacfg) {
$newca->addChild($cacfg, (string)$ca[$cacfg]);
$newca->$cacfg = (string)$ca[$cacfg];
}
$newca->crt = base64_encode($ca_content);
}
// Serialize to config and save
$caModel->serializeToConfig();
Config::getInstance()->save();
/**
* Step 2: import certificate
*/
@ -205,11 +200,11 @@ class LeCertificate extends LeCommon
// Read contents from certificate file
$cert_content = @file_get_contents($this->cert_file);
if ($cert_content != false) {
$cert_subject = cert_get_subject($cert_content, false);
$cert_serial = cert_get_serial($cert_content, false);
$cert_cn = LeUtils::local_cert_get_cn($cert_content, false);
$cert_issuer = cert_get_issuer($cert_content, false);
$cert_purpose = cert_get_purpose($cert_content, false);
$cert_details = CertStore::parseX509($cert_content);
$cert_subject = $cert_details['name'];
$cert_serial = $cert_details['serialNumber'];
$cert_cn = $cert_details['commonname'];
$cert_issuer = implode(",", $cert_details['issuer']);
} else {
LeUtils::log_error('unable to read certificate content from file');
Config::getInstance()->unlock();
@ -217,34 +212,6 @@ class LeCertificate extends LeCommon
return false;
}
// Prepare certificate for import in Cert Manager
$cert = array();
$cert_refid = uniqid();
$cert['refid'] = $cert_refid;
$cert['caref'] = (string)$ca['refid'];
$import_log_message = 'imported';
$cert_found = false;
// Check if cert was previously imported
if (!empty((string)$this->config->certRefId)) {
// Check if the previously imported certificate can still be found
foreach (Config::getInstance()->object()->cert as $cfgCert) {
// Check if IDs match
if ((string)$this->config->certRefId == (string)$cfgCert->refid) {
$cert_found = true;
break;
}
}
// Existing cert?
if ($cert_found) {
// Use old refid instead of generating a new one
$cert_refid = (string)$this->config->certRefId;
$import_log_message = 'updated';
}
} else {
// Not found. Just import as new cert.
}
// Read private key
$key_content = @file_get_contents($this->cert_key_file);
if ($key_content == false) {
@ -254,28 +221,39 @@ class LeCertificate extends LeCommon
return false;
}
// Collect required cert information
$cert_cn = LeUtils::local_cert_get_cn($cert_content, false);
$cert['descr'] = (string)$cert_cn . ' (ACME Client)';
$cert['refid'] = $cert_refid;
// Prepare certificate for import
cert_import($cert, $cert_content, $key_content);
// Overwrite caref in order to use the correct CA (GH #2550).
// This is required because cert_import() uses lookup_ca_by_subject()
// to find a matching CA. If multiple CAs are using the same name, the
// first CA wins, but it may still be the wrong CA.
// Prepare certificate
$certModel = new Cert();
$cert = array();
$cert['refid'] = uniqid();
$cert['caref'] = (string)$ca['refid'];
$cert['descr'] = (string)$cert_cn . ' (ACME Client)';
$import_log_message = 'imported';
$cert_found = false;
// Check if cert was previously imported.
// Otherwise just import as new cert.
if (!empty((string)$this->config->certRefId)) {
// Check if the previously imported certificate can still be found
foreach ($certModel->cert->iterateItems() as $cfgCert) {
// Check if IDs match
if ((string)$this->config->certRefId == (string)$cfgCert->refid) {
// Use old refid instead of generating a new one
$cert['refid'] = (string)$cfgCert->refid;
$import_log_message = 'updated';
$cert_found = true;
break;
}
}
}
// Check if cert was found in config
if ($cert_found == true) {
// Update existing cert
foreach (Config::getInstance()->object()->cert as $cfgCert) {
foreach ($certModel->cert->iterateItems() as $cfgCert) {
if ((string)$cfgCert->refid == $cert['refid']) {
$cfgCert->crt = $cert['crt'];
$cfgCert->prv = $cert['prv'];
$cfgCert->descr = $cert['descr'];
$cfgCert->crt = base64_encode($cert_content);
$cfgCert->prv = base64_encode($key_content);
// Update CA ref, because it may be signed by a different CA.
$cfgCert->caref = $cert['caref'];
break;
@ -283,27 +261,32 @@ class LeCertificate extends LeCommon
}
} else {
// Create new cert
$newcert = Config::getInstance()->object()->addChild('cert');
$newcert = $certModel->cert->Add();
foreach (array_keys($cert) as $certcfg) {
$newcert->addChild($certcfg, (string)$cert[$certcfg]);
$newcert->$certcfg = (string)$cert[$certcfg];
}
$newcert->crt = base64_encode($cert_content);
$newcert->prv = base64_encode($key_content);
}
LeUtils::log("{$import_log_message} ACME X.509 certificate: {$cert_cn}");
LeUtils::log("{$import_log_message} ACME X.509 certificate: {$cert_cn} ({$cert['refid']})");
// Serialize to config and save
// Skip validation because the current in-memory model may not
// know about the CA item that was just created.
$certModel->serializeToConfig(false, true);
Config::getInstance()->save();
/**
* Step 3: update configuration
*/
// Add refid to certObj
$this->config->certRefId = $cert_refid;
// Set update/create time
// Update Acme cert config
$this->config->certRefId = $cert['refid'];
$this->config->lastUpdate = time();
// Serialize to config and save
$this->model->serializeToConfig();
Config::getInstance()->save();
// Reload to get most recent config
Config::getInstance()->forceReload();
$this->loadConfig(self::CONFIG_PATH, $this->uuid);
@ -402,12 +385,12 @@ class LeCertificate extends LeCommon
return false;
}
// Run referenced automations.
$this->runAutomations();
// Update cert status.
$this->setStatus(200);
// Run referenced automations.
$this->runAutomations();
return true;
}

View file

@ -1,7 +1,7 @@
<?php
/*
* Copyright (C) 2017-2024 Frank Wall
* Copyright (C) 2017-2025 Frank Wall
* Copyright (C) 2015 Deciso B.V.
* Copyright (C) 2010 Jim Pingle <jimp@pfsense.org>
* Copyright (C) 2008 Shrew Soft Inc. <mgrooms@shrew.net>
@ -70,86 +70,6 @@ class LeUtils
return vsprintf($format, $args);
}
// Copied from system_camanager.php.
public static function local_ca_import(&$ca, $str, $key = "", $serial = 0)
{
// Get config object.
$config = Config::getInstance()->object();
$ca['crt'] = base64_encode($str);
if (!empty($key)) {
$ca['prv'] = base64_encode($key);
}
if (!empty($serial)) {
$ca['serial'] = $serial;
}
$subject = cert_get_subject($str, false);
$issuer = cert_get_issuer($str, false);
// Find my issuer unless self-signed
if ($issuer != $subject) {
$issuer_crt =& lookup_ca_by_subject($issuer);
if ($issuer_crt) {
$ca['caref'] = $issuer_crt['refid'];
}
}
/* Correct if child certificate was loaded first */
if (is_array($config['ca'])) {
foreach ($config['ca'] as & $oca) {
$issuer = cert_get_issuer($oca['crt']);
if ($ca['refid'] != $oca['refid'] && $issuer == $subject) {
$oca['caref'] = $ca['refid'];
}
}
}
if (is_array($config['cert'])) {
foreach ($config['cert'] as & $cert) {
$issuer = cert_get_issuer($cert['crt']);
if ($issuer == $subject) {
$cert['caref'] = $ca['refid'];
}
}
}
return true;
}
// copied from certs.inc
public static function local_cert_get_cn($crt, $decode = true)
{
$sub = self::local_cert_get_subject_array($crt, $decode);
if (is_array($sub)) {
foreach ($sub as $s) {
if (strtoupper($s['a']) == "CN") {
return $s['v'];
}
}
}
return "";
}
// copied from certs.inc
public static function local_cert_get_subject_array($str_crt, $decode = true)
{
if ($decode) {
$str_crt = base64_decode($str_crt);
}
$inf_crt = openssl_x509_parse($str_crt);
$components = $inf_crt['subject'];
if (!is_array($components)) {
return;
}
$subject_array = array();
foreach ($components as $a => $v) {
$subject_array[] = array('a' => $a, 'v' => $v);
}
return $subject_array;
}
/**
* log runtime information
*/

View file

@ -2,7 +2,7 @@
<?php
/*
* Copyright (C) 2020-2021 Frank Wall
* Copyright (C) 2020-2025 Frank Wall
* Copyright (C) 2019 Juergen Kellerer
* All rights reserved.
*
@ -30,7 +30,6 @@
// Import legacy code
@include_once('config.inc');
@include_once('certs.inc');
@include_once('util.inc');
// Import classes

View file

@ -94,7 +94,6 @@ const EXITCODE_ERROR_UNKNOWN_COMMAND = 254;
// Optional imports
@include_once("config.inc");
@include_once("certs.inc");
@include_once("util.inc");
// Optional autoloader (for local dev environment)

View file

@ -2,6 +2,7 @@
<?php
/*
* Copyright (C) 2025 Frank Wall
* Copyright (C) 2019 Juergen Kellerer
* All rights reserved.
*
@ -124,8 +125,8 @@ const EXITCODE_ERROR_UNKNOWN_COMMAND = 255;
// Optional imports
@include_once("config.inc");
@include_once("certs.inc");
@include_once("util.inc");
require_once("script/load_phalcon.php");
// Optional autoloader (for local dev environment)
if (!function_exists("log_error")) {
@ -135,6 +136,8 @@ if (!function_exists("log_error")) {
}
// Importing classes
use OPNsense\Trust\Cert;
use OPNsense\Trust\Store as CertStore;
use OPNsense\AcmeClient\SftpUploader;
use OPNsense\AcmeClient\SftpClient;
use OPNsense\AcmeClient\SSHKeys;
@ -519,17 +522,18 @@ function findCertificates(array $certificate_ids_or_names, $load_content = true)
function exportCertificates(array $cert_refids): array
{
$result = [];
$config = OPNsense\Core\Config::getInstance()->object();
foreach ($config->cert as $cert) {
$certModel = new Cert();
foreach ($certModel->cert->iterateItems() as $cert) {
$refid = (string)$cert->refid;
$item = [];
if (in_array($refid, $cert_refids)) {
$item["cert"] = str_replace(["\n\n", "\r"], ["\n", ""], base64_decode($cert->crt));
$item["key"] = str_replace(["\n\n", "\r"], ["\n", ""], base64_decode($cert->prv));
$_tmp = CertStore::getCertificate($refid);
$item["cert"] = $_tmp["crt"];
$item["key"] = $_tmp["prv"];
// check if a CA is linked
if (!empty((string)$cert->caref)) {
$cert = (array)$cert;
$item["ca"] = ca_chain($cert);
$item['ca'] = $_tmp['ca']['crt'];
// combine files to export a fullchain.pem
$item["fullchain"] = $item["cert"] . $item["ca"];
}

View file

@ -1,6 +1,6 @@
PLUGIN_NAME= clamav
PLUGIN_VERSION= 1.8
PLUGIN_REVISION= 1
PLUGIN_REVISION= 2
PLUGIN_COMMENT= Antivirus engine for detecting malicious threats
PLUGIN_DEPENDS= clamav
PLUGIN_MAINTAINER= m.muenz@gmail.com

View file

@ -1,5 +1,6 @@
PLUGIN_NAME= maltrail
PLUGIN_VERSION= 1.10
PLUGIN_REVISION= 1
PLUGIN_COMMENT= Malicious traffic detection system
PLUGIN_DEPENDS= maltrail
PLUGIN_MAINTAINER= m.muenz@gmail.com

View file

@ -14,6 +14,7 @@ Changelog
1.10
* Add CHECK_HOST_DOMAINS option
* Fix CUSTOM_TRAILS_DIR (contributed by codiflow)
1.9

View file

@ -36,7 +36,7 @@ SYSLOG_SERVER {{ OPNsense.maltrail.sensor.syslogserver }}:{{ OPNsense.maltrail.s
{% endif %}
SENSOR_NAME $HOSTNAME
CUSTOM_TRAILS_DIR /usr/local/maltrail/trails/custom/
CUSTOM_TRAILS_DIR /usr/local/share/maltrail/trails/custom/
PROCESS_COUNT $CPU_CORES
DISABLE_CPU_AFFINITY false
USE_FEED_UPDATES true

View file

@ -43,7 +43,6 @@ class ExitaclController extends ApiMutableModelControllerBase
}
public function getaclAction($uuid = null)
{
$this->sessionClose();
return $this->getBase('exitpolicy', 'policy', $uuid);
}
public function addaclAction()

View file

@ -82,7 +82,6 @@ class GeneralController extends ApiMutableModelControllerBase
public function gethidservauthAction($uuid = null)
{
$this->sessionClose();
return $this->getBase('client_auth', 'client_authentications.client_auth', $uuid);
}

View file

@ -40,7 +40,6 @@ class HiddenserviceController extends ApiMutableModelControllerBase
}
public function getserviceAction($uuid = null)
{
$this->sessionClose();
return $this->getBase('hiddenservice', 'service', $uuid);
}
public function addserviceAction()

View file

@ -40,7 +40,6 @@ class HiddenserviceaclController extends ApiMutableModelControllerBase
}
public function getaclAction($uuid = null)
{
$this->sessionClose();
return $this->getBase('hiddenserviceacl', 'hiddenserviceacl', $uuid);
}
public function addaclAction()

View file

@ -132,9 +132,6 @@ class ServiceController extends ApiControllerBase
public function reconfigureAction()
{
if ($this->request->isPost()) {
// close session for long running action
$this->sessionClose();
$general = new General();
$backend = new Backend();

View file

@ -40,7 +40,6 @@ class SocksaclController extends ApiMutableModelControllerBase
}
public function getaclAction($uuid = null)
{
$this->sessionClose();
return $this->getBase('policy', 'policy', $uuid);
}
public function addaclAction()

View file

@ -15,7 +15,7 @@
<id>exitpolicy.network</id>
<label>Network</label>
<type>text</type>
<help>Network on which this ACL is applied. Enter 'any' to use wildcard adressing.</help>
<help>Network on which this ACL is applied. Enter 'any' to use wildcard addressing.</help>
</field>
<field>
<id>exitpolicy.startport</id>

View file

@ -1,6 +1,6 @@
PLUGIN_NAME= c-icap
PLUGIN_VERSION= 1.7
PLUGIN_REVISION= 4
PLUGIN_REVISION= 5
PLUGIN_COMMENT= c-icap connects the web proxy with a virus scanner
PLUGIN_DEPENDS= c-icap c-icap-modules
PLUGIN_MAINTAINER= m.muenz@gmail.com

View file

@ -1,5 +1,5 @@
PLUGIN_NAME= caddy
PLUGIN_VERSION= 1.7.6
PLUGIN_VERSION= 1.8.1
PLUGIN_DEPENDS= caddy-custom
PLUGIN_COMMENT= Modern Reverse Proxy with Automatic HTTPS, Dynamic DNS and Layer4 Routing
PLUGIN_MAINTAINER= cedrik@pischem.com

View file

@ -13,6 +13,23 @@ DOC: https://docs.opnsense.org/manual/how-tos/caddy.html
Plugin Changelog
================
1.8.1
* Add: Optional "Authorization" header to forward_auth (opnsense/plugins/issues/4488)
* Add: Persistent banner notification if custom imports are used (opnsense/plugins/issues/4244)
* Cleanup: Implement reusable grid template in views (opnsense/plugins/pull/4454)
1.8.0
* Build: Update Caddy to version 2.9.x and update dependencies (opnsense/plugins/issues/4437)
* Build: Fix caddy-l4 timeout issue (opnsense/plugins/issues/4384)
* Build: Mark DNS Providers optional that are not included per default (opnsense/plugins/pull/4441)
digitalocean, route53, googleclouddns, netlify, ddnss, njalla, tencentcloud
dinahosting, civo, easydns, hosttech; must be added via https://caddyserver.com/docs/command-line#caddy-add-package
* Cleanup: Refactor caddy.inc and add syslog function, change name from Caddy Web Server to Caddy (opnsense/plugins/issues/4426)
* Cleanup: Some small UI tweaks (opnsense/plugins/pull/4442)
* Change: Disable HTTP/3 to mitigate status 400 issue when reverse proxying the OPNsense WebGUI (opnsense/plugins/issues/4471)
1.7.6
* Fix: Web UI can still restart/stop Caddy when running as `www` user (opnsense/plugins/pull/4403)

View file

@ -1,7 +1,7 @@
<?php
/*
* Copyright (C) 2023-2024 Cedrik Pischem
* Copyright (C) 2023-2025 Cedrik Pischem
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -37,7 +37,7 @@ function caddy_services()
$config['Pischem']['caddy']['general']['enabled'] == 1
) {
$services[] = array(
'description' => gettext('Caddy Web Server'),
'description' => gettext('Caddy'),
'configd' => array(
'restart' => array('caddy restart'),
'start' => array('caddy start'),
@ -56,7 +56,7 @@ function caddy_xmlrpc_sync()
$result = array();
$result[] = array(
'description' => gettext('Caddy Web Server'),
'description' => gettext('Caddy'),
'section' => 'Pischem.caddy',
'id' => 'caddy',
'services' => ["caddy"],
@ -64,3 +64,8 @@ function caddy_xmlrpc_sync()
return $result;
}
function caddy_syslog()
{
return ['caddy' => ['facility' => ['caddy']]];
}

View file

@ -1,7 +1,7 @@
<?php
/**
* Copyright (C) 2023-2024 Cedrik Pischem
* Copyright (C) 2023-2025 Cedrik Pischem
*
* All rights reserved.
*
@ -37,7 +37,11 @@ class Layer4Controller extends IndexController
public function indexAction()
{
$this->view->pick('OPNsense/Caddy/layer4');
$this->view->formDialogLayer4 = $this->getForm("dialogLayer4");
$this->view->formDialogLayer4Openvpn = $this->getForm("dialogLayer4Openvpn");
$this->view->formDialogLayer4 = $this->getForm('dialogLayer4');
$this->view->formGridLayer4 = $this->getFormGrid('dialogLayer4', null, 'ConfChangeMessage');
$this->view->formDialogLayer4Openvpn = $this->getForm('dialogLayer4Openvpn');
$this->view->formGridLayer4Openvpn = $this->getFormGrid('dialogLayer4Openvpn', null, 'ConfChangeMessage');
}
}

View file

@ -1,8 +1,7 @@
<?php
/**
* Copyright (C) 2023-2024 Cedrik Pischem
* Copyright (C) 2015 Deciso B.V.
* Copyright (C) 2023-2025 Cedrik Pischem
*
* All rights reserved.
*
@ -38,11 +37,23 @@ class ReverseProxyController extends IndexController
public function indexAction()
{
$this->view->pick('OPNsense/Caddy/reverse_proxy');
$this->view->formDialogReverseProxy = $this->getForm("dialogReverseProxy");
$this->view->formGridReverseProxy = $this->getFormGrid('dialogReverseProxy', null, 'ConfChangeMessage');
$this->view->formDialogSubdomain = $this->getForm("dialogSubdomain");
$this->view->formGridSubdomain = $this->getFormGrid('dialogSubdomain', null, 'ConfChangeMessage');
$this->view->formDialogHandle = $this->getForm("dialogHandle");
$this->view->formGridHandle = $this->getFormGrid('dialogHandle', null, 'ConfChangeMessage');
$this->view->formDialogAccessList = $this->getForm("dialogAccessList");
$this->view->formGridAccessList = $this->getFormGrid('dialogAccessList', null, 'ConfChangeMessage');
$this->view->formDialogBasicAuth = $this->getForm("dialogBasicAuth");
$this->view->formGridBasicAuth = $this->getFormGrid('dialogBasicAuth', null, 'ConfChangeMessage');
$this->view->formDialogHeader = $this->getForm("dialogHeader");
$this->view->formGridHeader = $this->getFormGrid('dialogHeader', null, 'ConfChangeMessage');
}
}

View file

@ -18,6 +18,10 @@
<label>Invert List</label>
<type>checkbox</type>
<help><![CDATA[If checked, the access list logic will be inverted (i.e., the listed IPs will be blocked instead of allowed).]]></help>
<grid_view>
<type>boolean</type>
<formatter>boolean</formatter>
</grid_view>
</field>
<field>
<id>accesslist.HttpResponseCode</id>
@ -26,6 +30,9 @@
<hint>abort</hint>
<help><![CDATA[Set a custom HTTP response code that should be returned to the requesting client when the access list does not match. If empty, the connection is aborted with no response.]]></help>
<advanced>true</advanced>
<grid_view>
<visible>false</visible>
</grid_view>
</field>
<field>
<id>accesslist.HttpResponseMessage</id>
@ -33,6 +40,9 @@
<type>text</type>
<help><![CDATA[Set a custom HTTP response message in addition to the HTTP response code. If empty, the default HTTP response message for the chosen HTTP response code will be used.]]></help>
<advanced>true</advanced>
<grid_view>
<visible>false</visible>
</grid_view>
</field>
<field>
<id>accesslist.description</id>

View file

@ -4,6 +4,11 @@
<label>Enabled</label>
<type>checkbox</type>
<help><![CDATA[Enable this handler.]]></help>
<grid_view>
<width>6em</width>
<type>boolean</type>
<formatter>rowtoggle</formatter>
</grid_view>
</field>
<field>
<id>handle.description</id>
@ -38,6 +43,9 @@
<type>dropdown</type>
<help><![CDATA[Choose a handling type: "handle" (default) will keep the path in all requests. "handle_path" will strip the path from all requests.]]></help>
<advanced>true</advanced>
<grid_view>
<visible>false</visible>
</grid_view>
</field>
<field>
<id>handle.HandlePath</id>
@ -46,6 +54,9 @@
<hint>any</hint>
<help><![CDATA[Enter a path to handle. Choose a pattern like "/*" or "/example/*". Leave empty to handle any paths (recommended). Any request matching this pattern will be handled by the chosen directive.]]></help>
<advanced>true</advanced>
<grid_view>
<visible>false</visible>
</grid_view>
</field>
<field>
<type>header</type>
@ -58,6 +69,9 @@
<type>dropdown</type>
<help><![CDATA[Select an Access List to restrict access to this handler. If unset, any local or remote client is allowed access.]]></help>
<advanced>true</advanced>
<grid_view>
<visible>false</visible>
</grid_view>
</field>
<field>
<id>handle.ForwardAuth</id>
@ -65,6 +79,11 @@
<type>checkbox</type>
<help><![CDATA[Enable or disable Forward Auth. Requires an "Auth Provider" in "General Settings". Headers are set automatically to the standard of the chosen provider. Enabling this option will additionally generate the forward_auth directive in front of the reverse_proxy directive inside the scope of this handler.]]></help>
<advanced>true</advanced>
<grid_view>
<visible>false</visible>
<type>boolean</type>
<formatter>boolean</formatter>
</grid_view>
</field>
<field>
<type>header</type>
@ -87,6 +106,9 @@
<style>style_reverse_proxy</style>
<help><![CDATA[The default versions are highly recommended. Choose a HTTP version for the upstream destination. HTTP/3 (HTTP over QUIC) requires HTTPS, and only establishes connections to webservers that also support HTTP/3.]]></help>
<advanced>true</advanced>
<grid_view>
<visible>false</visible>
</grid_view>
</field>
<field>
<id>handle.header</id>
@ -97,6 +119,9 @@
<style>style_reverse_proxy selectpicker</style>
<help><![CDATA[Select one or multiple headers. Caddy sets "X-Forwarded-For", "X-Forwarded-Proto" and "X-Forwarded-Host" by default, adding them here is not needed. Setting a wrong configuration can be a security risk or break functionality.]]></help>
<advanced>true</advanced>
<grid_view>
<visible>false</visible>
</grid_view>
</field>
<field>
<id>handle.HttpKeepalive</id>
@ -106,6 +131,9 @@
<style>style_reverse_proxy</style>
<help><![CDATA[Leave empty to use default. Keepalive is either 0 (off) or a duration value that specifies how long to keep connections open (timeout) in seconds.]]></help>
<advanced>true</advanced>
<grid_view>
<visible>false</visible>
</grid_view>
</field>
<field>
<id>handle.HttpTls</id>
@ -119,14 +147,12 @@
<type>select_multiple</type>
<style>tokenize</style>
<allownew>true</allownew>
<hint>192.168.1.1</hint>
<help><![CDATA[Enter a domain name or IP address of the upstream destination. If multiple are chosen, they will be load balanced with the default random policy. A health check can be activated by populating "Upstream Fail Duration" in advanced mode. When directive is "redir", only the first domain will be evaluated.]]></help>
</field>
<field>
<id>handle.ToPort</id>
<label>Upstream Port</label>
<type>text</type>
<hint>80</hint>
<help><![CDATA[Leave empty to use the default port or choose a custom port for the upstream destination.]]></help>
</field>
<field>
@ -135,6 +161,9 @@
<type>text</type>
<help><![CDATA[When directive is "reverse_proxy", enter a path prefix like "/guacamole" that should be prepended to the upstream request. This is useful for destinations that have a virtual directory as their base path. When directive is "redir", add the path the request should be redirected to; leaving it empty will append {uri}.]]></help>
<advanced>true</advanced>
<grid_view>
<visible>false</visible>
</grid_view>
</field>
<field>
<id>handle.HttpTlsInsecureSkipVerify</id>
@ -142,6 +171,11 @@
<type>checkbox</type>
<style>style_tls style_reverse_proxy</style>
<help><![CDATA[Caddy uses HTTP by default to connect to the Upstream. If the Upstream is only reachable via HTTPS, this option disables the TLS handshake verification. This makes the connection insecure and vulnerable to man-in-the-middle attacks. In private networks the risk is low, though do not use in production if possible. It is advised to either use plain HTTP, or proper TLS handling by using the options in "Trust".]]></help>
<grid_view>
<visible>false</visible>
<type>boolean</type>
<formatter>boolean</formatter>
</grid_view>
</field>
<field>
<id>handle.HttpTlsTrustedCaCerts</id>
@ -149,6 +183,9 @@
<type>dropdown</type>
<style>style_tls style_reverse_proxy</style>
<help><![CDATA[Choose a CA or self-signed certificate to trust from "System - Trust - Authorities". Useful if the upstream destination only accepts TLS connections and offers a self signed certificate. Adding that certificate here will allow for the encrypted connection to succeed.]]></help>
<grid_view>
<visible>false</visible>
</grid_view>
</field>
<field>
<id>handle.HttpTlsServerName</id>
@ -156,6 +193,9 @@
<type>text</type>
<style>style_tls style_reverse_proxy</style>
<help><![CDATA[Enter a hostname or IP address that matches the SAN "Subject Alternative Name" of the offered upstream certificate. This will change the SNI "Server Name Indication" of Caddy. Setting an IP address as "Upstream Domain", enabling "TLS" and selecting a "TLS Trust Pool", would make the SAN of the offered upstream certificate not match with the SNI of Caddy, since it will be an IP address instead of a hostname. Setting the hostname of the certificate here, fixes this issue. Please note that only SAN certificates are supported; CN "Common Name" will not work.]]></help>
<grid_view>
<visible>false</visible>
</grid_view>
</field>
<field>
<id>handle.HttpNtlm</id>
@ -163,6 +203,11 @@
<type>checkbox</type>
<style>style_tls style_reverse_proxy</style>
<help><![CDATA[Enable or disable NTLM. Needed to reverse proxy an Exchange Server. Warning: NTLM has been deprecated by Microsoft. This option will stay for as long as the optional http.reverse_proxy.transport.http_ntlm module can be compiled without errors.]]></help>
<grid_view>
<visible>false</visible>
<type>boolean</type>
<formatter>boolean</formatter>
</grid_view>
</field>
<field>
<type>header</type>
@ -176,6 +221,9 @@
<style>style_reverse_proxy</style>
<help><![CDATA[lb_policy is the name of the load balancing policy, along with any options. For policies that involve hashing, the highest-random-weight (HRW) algorithm is used to ensure that a client or request with the same hash key is mapped to the same upstream, even if the list of upstreams change.]]></help>
<advanced>true</advanced>
<grid_view>
<visible>false</visible>
</grid_view>
</field>
<field>
<id>handle.lb_retries</id>
@ -185,6 +233,9 @@
<hint>off</hint>
<help><![CDATA[lb_retries is how many times to retry selecting available backends for each request if the next available host is down. If lb_try_duration is also configured, then retries may stop early if the duration is reached. In other words, the retry duration takes precedence over the retry count.]]></help>
<advanced>true</advanced>
<grid_view>
<visible>false</visible>
</grid_view>
</field>
<field>
<id>handle.lb_try_duration</id>
@ -194,6 +245,9 @@
<hint>0</hint>
<help><![CDATA[lb_try_duration is a duration value that defines how long to try selecting available backends for each request if the next available host is down. Clients will wait for up to this long while the load balancer tries to find an available upstream host. A reasonable starting point might be 5s since the HTTP transport's default dial timeout is 3s, so that should allow for at least one retry if the first selected upstream cannot be reached.]]></help>
<advanced>true</advanced>
<grid_view>
<visible>false</visible>
</grid_view>
</field>
<field>
<id>handle.lb_try_interval</id>
@ -203,6 +257,9 @@
<hint>250</hint>
<help><![CDATA[lb_try_interval is a duration value that defines how long to wait between selecting the next host from the pool. Only relevant when a request to an upstream host fails. Be aware that setting this to 0 with a non-zero lb_try_duration can cause the CPU to spin if all backends are down and latency is very low.]]></help>
<advanced>true</advanced>
<grid_view>
<visible>false</visible>
</grid_view>
</field>
<field>
<id>handle.PassiveHealthFailDuration</id>
@ -212,6 +269,9 @@
<hint>off</hint>
<help><![CDATA[fail_duration enables a passive health check when multiple destinations in "Upstream Domain" are set. It is a value that defines how long to remember a failed request. A duration of 1 or more seconds enables passive health checking. A reasonable starting point might be 30s to balance error rates with responsiveness when bringing an unhealthy upstream back online.]]></help>
<advanced>true</advanced>
<grid_view>
<visible>false</visible>
</grid_view>
</field>
<field>
<id>handle.PassiveHealthMaxFails</id>
@ -221,6 +281,9 @@
<hint>1</hint>
<help><![CDATA[max_fails is the maximum number of failed requests within fail_duration that are needed before considering an upstream to be down.]]></help>
<advanced>true</advanced>
<grid_view>
<visible>false</visible>
</grid_view>
</field>
<field>
<id>handle.PassiveHealthUnhealthyStatus</id>
@ -230,6 +293,9 @@
<hint>off</hint>
<help><![CDATA[unhealthy_status counts a request as failed if the response comes back with one of these status codes. Can be a 3-digit status code or a status code class ending in xx, for example: 404 or 5xx.]]></help>
<advanced>true</advanced>
<grid_view>
<visible>false</visible>
</grid_view>
</field>
<field>
<id>handle.PassiveHealthUnhealthyLatency</id>
@ -239,6 +305,9 @@
<hint>off</hint>
<help><![CDATA[unhealthy_latency is a duration value in ms that counts a request as failed if it takes this long to get a response.]]></help>
<advanced>true</advanced>
<grid_view>
<visible>false</visible>
</grid_view>
</field>
<field>
<id>handle.PassiveHealthUnhealthyRequestCount</id>
@ -248,5 +317,8 @@
<hint>off</hint>
<help><![CDATA[unhealthy_request_count is the permissible number of simultaneous requests to a backend before marking it as down. In other words, if a particular backend is currently handling this many requests, then it is considered "overloaded" and other backends will be preferred instead. This should be a reasonably large number; configuring this means that the proxy will have a limit of unhealthy_request_count × upstreams_count total simultaneous requests, and any requests after that point will result in an error due to no upstreams being available.]]></help>
<advanced>true</advanced>
<grid_view>
<visible>false</visible>
</grid_view>
</field>
</form>

View file

@ -16,12 +16,18 @@
<label>Header Value</label>
<type>text</type>
<help><![CDATA[Enter a value for the selected header. One of the most common options is "{upstream_hostport}". It is also possible to use a regular expression to search for a specific value in a header. For example: "^prefix-([A-Za-z0-9]*)$" which uses the regular expression language RE2 included in Go.]]></help>
<grid_view>
<visible>false</visible>
</grid_view>
</field>
<field>
<id>header.HeaderReplace</id>
<label>Header Replace</label>
<type>text</type>
<help><![CDATA[If a regular expression is used to search for a Header Value, the replacement string can be set here. For example: "replaced-$1-suffix" which expands the replacement string, allowing the use of captured values, "$1" being the first capture group.]]></help>
<grid_view>
<visible>false</visible>
</grid_view>
</field>
<field>
<id>header.description</id>

View file

@ -4,6 +4,11 @@
<label>Enabled</label>
<type>checkbox</type>
<help><![CDATA[Enable this Layer4 route.]]></help>
<grid_view>
<width>6em</width>
<type>boolean</type>
<formatter>rowtoggle</formatter>
</grid_view>
</field>
<field>
<id>layer4.Sequence</id>
@ -26,6 +31,9 @@
<label>Routing Type</label>
<type>dropdown</type>
<help><![CDATA[Choose either "listener_wrappers" for multiplexing protocols on the default HTTP and HTTPS ports on OSI Layer 7, or "global" for raw TCP/UDP traffic routing on a custom "Local port" on OSI Layer 4 with optional OSI Layer 7 protocol matching.]]></help>
<grid_view>
<visible>false</visible>
</grid_view>
</field>
<field>
<id>layer4.Protocol</id>
@ -40,6 +48,9 @@
<type>text</type>
<style>style_type</style>
<help><![CDATA[Choose a custom local port to listen on.]]></help>
<grid_view>
<visible>false</visible>
</grid_view>
</field>
<field>
<type>header</type>
@ -65,6 +76,9 @@
<type>dropdown</type>
<style>style_matchers matchers_openvpn</style>
<help><![CDATA[Select the mode matching the OpenVPN Server or Client.]]></help>
<grid_view>
<visible>false</visible>
</grid_view>
</field>
<field>
<id>layer4.FromOpenvpnStaticKey</id>
@ -74,6 +88,9 @@
<hint>Any</hint>
<size>5</size>
<help><![CDATA[Select a Static Key to match. Multiple Static Keys are only supported for tls-crypt2_client mode.]]></help>
<grid_view>
<visible>false</visible>
</grid_view>
</field>
<field>
<id>layer4.InvertMatchers</id>
@ -81,6 +98,11 @@
<type>checkbox</type>
<help><![CDATA[Invert the sense of the matcher. E.g., if the protocol is TLS, inverting will match all traffic that is not TLS. When domains have been chosen, these will be equally inverted.]]></help>
<advanced>true</advanced>
<grid_view>
<visible>false</visible>
<type>boolean</type>
<formatter>boolean</formatter>
</grid_view>
</field>
<field>
<id>layer4.TerminateTls</id>
@ -88,6 +110,11 @@
<type>checkbox</type>
<style>style_matchers matchers_domain</style>
<help><![CDATA[Terminate TLS before routing to the upstream. Since this requires a certificate, ensure there is a domain configured in "Reverse Proxy" that matches the SNI of "Domain". The best matching SAN or wildcard certificate will be used automatically for this route.]]></help>
<grid_view>
<visible>false</visible>
<type>boolean</type>
<formatter>boolean</formatter>
</grid_view>
</field>
<field>
<type>header</type>
@ -113,6 +140,9 @@
<type>dropdown</type>
<help><![CDATA[Add the HA Proxy Protocol header. Either version 1 or 2 can be chosen. The default is off, since it is only needed when the upstream can use the Proxy Protocol header.]]></help>
<advanced>true</advanced>
<grid_view>
<visible>false</visible>
</grid_view>
</field>
<field>
<type>header</type>
@ -126,6 +156,9 @@
<style>style_reverse_proxy</style>
<help><![CDATA[lb_policy is the name of the load balancing policy, along with any options. For policies that involve hashing, the highest-random-weight (HRW) algorithm is used to ensure that a client or request with the same hash key is mapped to the same upstream, even if the list of upstreams change.]]></help>
<advanced>true</advanced>
<grid_view>
<visible>false</visible>
</grid_view>
</field>
<field>
<id>layer4.PassiveHealthFailDuration</id>
@ -135,6 +168,9 @@
<hint>off</hint>
<help><![CDATA[fail_duration enables a passive health check when multiple destinations in "Upstream Domain" are set. It is a value that defines how long to remember a failed request. A duration of 1 or more seconds enables passive health checking. A reasonable starting point might be 30s to balance error rates with responsiveness when bringing an unhealthy upstream back online.]]></help>
<advanced>true</advanced>
<grid_view>
<visible>false</visible>
</grid_view>
</field>
<field>
<id>layer4.PassiveHealthMaxFails</id>
@ -144,6 +180,9 @@
<hint>1</hint>
<help><![CDATA[max_fails is the maximum number of failed requests within fail_duration that are needed before considering an upstream to be down.]]></help>
<advanced>true</advanced>
<grid_view>
<visible>false</visible>
</grid_view>
</field>
<field>
<type>header</type>
@ -156,5 +195,8 @@
<style>tokenize</style>
<allownew>true</allownew>
<help><![CDATA[Enter one or multiple IP addresses and networks. Leaving this empty will allow any remote client to connect. If populated and the remote IP address of a client matches, the connection to the "Upstream Domain" is allowed, otherwise the connection is dropped. Due to restrictions with this matcher, this list can not be inverted.]]></help>
<grid_view>
<visible>false</visible>
</grid_view>
</field>
</form>

View file

@ -9,5 +9,8 @@
<label>Static Key</label>
<type>textbox</type>
<help>Paste an OpenVPN Static key.</help>
<grid_view>
<ignore>true</ignore>
</grid_view>
</field>
</fields>

View file

@ -4,6 +4,11 @@
<label>Enabled</label>
<type>checkbox</type>
<help><![CDATA[Enable this domain.]]></help>
<grid_view>
<width>6em</width>
<type>boolean</type>
<formatter>rowtoggle</formatter>
</grid_view>
</field>
<field>
<id>reverse.description</id>
@ -25,14 +30,12 @@
<id>reverse.FromDomain</id>
<label>Domain</label>
<type>text</type>
<hint>example.com</hint>
<help><![CDATA[Enter a domain name. For a base domain, use "example.com" or "opn.example.com". For a wildcard domain, use "*.example.com". Using a wildcard domain with subdomains requires a "DNS Provider" and the "DNS-01 Challenge" or a custom certificate.]]></help>
</field>
<field>
<id>reverse.FromPort</id>
<label>Port</label>
<type>text</type>
<hint>443</hint>
<help><![CDATA[Leave empty to use ports 80 and 443 with automatic redirection from HTTP to HTTPS or choose a custom port. Don't forget to allow these ports with a Firewall rule. If the default ports have been changed in "General Settings", leaving this empty will use the chosen alternative ports instead.]]></help>
</field>
<field>
@ -41,6 +44,9 @@
<type>dropdown</type>
<style>style_tls</style>
<help><![CDATA[Choose ACME to get automatic certificates with the built in ACME client; no additional plugin required. The "HTTP-01", "TLS-ALPN-01" or "DNS-01" challenge will be used to get automatic "Let's Encrypt" or "ZeroSSL" certificates. Alternatively, choose a custom certificate from "System - Trust - Certificates" for this domain. Make sure the full chain has been imported.]]></help>
<grid_view>
<visible>false</visible>
</grid_view>
</field>
<field>
<id>reverse.AcmePassthrough</id>
@ -48,6 +54,9 @@
<type>text</type>
<help><![CDATA[Enter a domain name or IP address. The HTTP-01 challenge will be redirected to that destination. This enables an ACME Client behind Caddy to serve "/.well-known/acme-challenge/" on port 80. Caddy will reverse proxy the HTTP-01 challenge for this domain, and will still issue a certificate using the TLS-ALPN-01 challenge or DNS-01 challenge for itself. This option can be used for High Availability when using Caddy with a master and backup OPNsense.]]></help>
<advanced>true</advanced>
<grid_view>
<visible>false</visible>
</grid_view>
</field>
<field>
<id>reverse.DnsChallenge</id>
@ -55,23 +64,35 @@
<type>checkbox</type>
<style>style_tls</style>
<help><![CDATA[Enable the DNS-01 Challenge for this domain. Requires a "DNS Provider" in "General Settings". This is only needed for wildcard domains, or when the default challenges can not be used due to restrictive firewall policies.]]></help>
<grid_view>
<visible>false</visible>
<type>boolean</type>
<formatter>boolean</formatter>
</grid_view>
</field>
<field>
<id>reverse.DynDns</id>
<label>Dynamic DNS</label>
<type>checkbox</type>
<help><![CDATA[Enable or disable Dynamic DNS. Requires a "DNS Provider" in "General Settings". The DNS records of this domain will be automatically updated. A wildcard domain will create a "*.example.com" record. A base domain will create a "example.com" or "opn.example.com" record. Some providers need subdomains to set records for domains like "opn.example.com"; in that case use the checkbox in the subdomains tab.]]></help>
<grid_view>
<visible>false</visible>
<type>boolean</type>
<formatter>boolean</formatter>
</grid_view>
</field>
<field>
<type>header</type>
<label>Access</label>
<collapse>true</collapse>
</field>
<field>
<id>reverse.accesslist</id>
<label>Access List</label>
<type>dropdown</type>
<help><![CDATA[Select an Access List to restrict access to this domain. If unset, any local or remote client is allowed access.]]></help>
<grid_view>
<visible>false</visible>
</grid_view>
</field>
<field>
<id>reverse.basicauth</id>
@ -79,11 +100,19 @@
<type>select_multiple</type>
<size>5</size>
<help><![CDATA[Select Users to restrict access to this domain. Basic Auth matches after Access Lists. If unset, any user is allowed access. When using CrowdSec, authorization failures will result in automatic bans.]]></help>
<grid_view>
<visible>false</visible>
</grid_view>
</field>
<field>
<id>reverse.AccessLog</id>
<label>HTTP Access Log</label>
<type>checkbox</type>
<help><![CDATA[Enable HTTP request logging for this domain and its subdomains. This option is mostly used for troubleshooting, audits and CrowdSec. It will log every single request.]]></help>
<grid_view>
<visible>false</visible>
<type>boolean</type>
<formatter>boolean</formatter>
</grid_view>
</field>
</form>

View file

@ -4,6 +4,11 @@
<label>Enabled</label>
<type>checkbox</type>
<help><![CDATA[Enable this subdomain.]]></help>
<grid_view>
<width>6em</width>
<type>boolean</type>
<formatter>rowtoggle</formatter>
</grid_view>
</field>
<field>
<id>subdomain.description</id>
@ -33,6 +38,11 @@
<label>Dynamic DNS</label>
<type>checkbox</type>
<help><![CDATA[Enable or disable Dynamic DNS. Requires a "DNS Provider" in "General Settings". The DNS records of this subdomain will be automatically updated.]]></help>
<grid_view>
<visible>false</visible>
<type>boolean</type>
<formatter>boolean</formatter>
</grid_view>
</field>
<field>
<id>subdomain.AcmePassthrough</id>
@ -40,17 +50,22 @@
<type>text</type>
<help><![CDATA[Enter a domain name or IP address. The HTTP-01 challenge will be redirected to that destination. This enables an ACME Client behind Caddy to serve "/.well-known/acme-challenge/" on port 80. Caddy will reverse proxy the HTTP-01 challenge for this subdomain.]]></help>
<advanced>true</advanced>
<grid_view>
<visible>false</visible>
</grid_view>
</field>
<field>
<type>header</type>
<label>Access</label>
<collapse>true</collapse>
</field>
<field>
<id>subdomain.accesslist</id>
<label>Access List</label>
<type>dropdown</type>
<help><![CDATA[Select an Access List to restrict access to this subdomain. If unset, any local or remote client is allowed access.]]></help>
<grid_view>
<visible>false</visible>
</grid_view>
</field>
<field>
<id>subdomain.basicauth</id>
@ -58,5 +73,8 @@
<type>select_multiple</type>
<size>5</size>
<help><![CDATA[Select Users to restrict access to this subdomain. Basic Auth matches after Access Lists. If unset, any user is allowed access.]]></help>
<grid_view>
<visible>false</visible>
</grid_view>
</field>
</form>

View file

@ -33,10 +33,10 @@
<help><![CDATA[Run this service as "www" user and group, instead of "root". This setting increases security, but comes with the hard restriction that the well-known port range can not be used anymore. After enabling and saving this setting, the service has to be totally restarted. For this, please disable Caddy and press Apply. Afterwards enable Caddy and press Apply. This setting is reversible by following the same steps.]]></help>
</field>
<field>
<id>caddy.general.HttpVersion</id>
<label>HTTP Version</label>
<id>caddy.general.HttpVersions</id>
<label>HTTP Versions</label>
<type>select_multiple</type>
<help><![CDATA[Select the HTTP Version for the frontend listeners. By default, QUIC (HTTP/3) is enabled. This means, UDP/443 will be used by Caddy. To free this protocol port combination for a different service, choose a different combination of protocols that does not include HTTP/3.]]></help>
<help><![CDATA[Select the HTTP versions for the frontend listeners. By default, QUIC (HTTP/3) is disabled.]]></help>
</field>
<field>
<id>caddy.general.HttpPort</id>
@ -98,46 +98,45 @@
<id>caddy.general.TlsDnsProvider</id>
<label>DNS Provider</label>
<type>dropdown</type>
<help><![CDATA[Select the DNS provider for the DNS-01 Challenge and Dynamic DNS. This is mostly needed for Wildcard Certificates, and for Dynamic DNS. To use, enable the checkbox in a "Domain" or "Subdomain". For more information, visit https://github.com/caddy-dns where each module is community maintained.]]></help>
<help><![CDATA[Select the DNS Provider for the DNS-01 Challenge and Dynamic DNS. Providers marked as "optional" must be installed manually, see https://caddyserver.com/docs/command-line#caddy-add-package. For more information, visit https://github.com/caddy-dns where each module is community maintained.]]></help>
</field>
<field>
<type>header</type>
<label>API Fields</label>
</field>
<field>
<id>caddy.general.TlsDnsApiKey</id>
<label>DNS API Standard Field</label>
<label>API Field 1</label>
<type>text</type>
<help><![CDATA[This is the standard field for the API Key. Field can be left empty if optional: Cloudflare "api_token", Duckdns "api_token", DigitalOcean "auth_token", Godaddy "api_token", Gandi "bearer_token", IONOS "api_token", deSEC "token", Route53 "access_key_id", Porkbun "api_key", ACME-DNS "username", Netlify "personal_access_token", Njalla "api_token", Google Cloud DNS "gcp_project", Azure "tenant_id", OVH "endpoint", Namecheap "api_key", PowerDNS "server_url", DDNSS "api_token", Linode "api_token", Tencent Cloud "secret_id", Dinahosting "username", Hexonet "username", Mail-in-a-Box "api_url", DNS Made Easy "api_key", Bunny "access_key", Civo "api_token", Scaleway "secret_key", ACME Proxy "username", INWX "username", Netcup "customer_number", RFC2136 "key_name", Name.com "token", EasyDNS "api_token", Infomaniak "api_token", DirectAdmin "host", Hosttech "api_token", Vultr "api_token", Hetzner "api_token"]]></help>
</field>
<field>
<type>header</type>
<label>Additional Fields</label>
<collapse>true</collapse>
</field>
<field>
<id>caddy.general.TlsDnsSecretApiKey</id>
<label>DNS API Additional Field 1</label>
<label>API Field 2</label>
<type>text</type>
<help><![CDATA[Leave empty if your DNS Provider isn't specified here. Field can be left empty if optional: Duckdns "override_domain", Route53 "secret_access_key", Porkbun "api_secret_key", ACME-DNS "password", Azure "client_id", OVH "application_key", Namecheap "user", PowerDNS "api_token", DDNSS "username", Linode "api_url", Tencent Cloud "secret_key", Dinahosting "password", Hexonet "password", Mail-in-a-Box "email_address", DNS Made Easy "secret_key", Scaleway "organization_id", ACME Proxy "password", INWX "password", Netcup "api_key", RFC2136 "key_alg", Name.com "server", EasyDNS "api_key", DirectAdmin "user".]]></help>
</field>
<field>
<id>caddy.general.TlsDnsOptionalField1</id>
<label>DNS API Additional Field 2</label>
<label>API Field 3</label>
<type>text</type>
<help><![CDATA[Leave empty if your DNS Provider isn't specified here. Field can be left empty if optional: Route53 "hosted_zone_id", ACME-DNS "subdomain", Azure "client_secret", OVH "application_secret", Namecheap "api_endpoint", DDNSS "password", Linode "api_version", Mail-in-a-Box "password", DNS Made Easy "api_endpoint", ACME Proxy "endpoint", INWX "shared_secret", Netcup "api_password", Name.com "user", EasyDNS "api_url", DirectAdmin "login_key", RFC2136 "key".]]></help>
</field>
<field>
<id>caddy.general.TlsDnsOptionalField2</id>
<label>DNS API Additional Field 3</label>
<label>API Field 4</label>
<type>text</type>
<help><![CDATA[Leave empty if your DNS Provider isn't specified here. Field can be left empty if optional: Route53 "profile", ACME-DNS "server_url", Azure "subscription_id", OVH "consumer_key", Namecheap "client_ip", DDNS "password", INWX "endpoint_url", DirectAdmin "insecure_requests", RFC2136 "server".]]></help>
</field>
<field>
<id>caddy.general.TlsDnsOptionalField3</id>
<label>DNS API Additional Field 4</label>
<label>API Field 5</label>
<type>text</type>
<help><![CDATA[Leave empty if your DNS Provider isn't specified here. Field can be left empty if optional: Route53 "region", Azure "resource_group_name".]]></help>
</field>
<field>
<id>caddy.general.TlsDnsOptionalField4</id>
<label>DNS API Additional Field 5</label>
<label>API Field 6</label>
<type>text</type>
<help><![CDATA[Leave empty if your DNS Provider isn't specified here. Field can be left empty if optional: Route53 "session_token".]]></help>
</field>
@ -228,6 +227,13 @@
<type>text</type>
<help><![CDATA[Enter the URI of the authz api endpoint.]]></help>
</field>
<field>
<id>caddy.general.AuthCopyHeaders</id>
<label>Copy Headers</label>
<type>select_multiple</type>
<style>selectpicker</style>
<help><![CDATA[If nothing is selected, the correct default headers for the chosen provider will be used. If you change the default, you must select the required headers manually. "copy_headers" is a list of HTTP header fields to copy from the response to the original request, when the request has a success status code.]]></help>
</field>
</tab>
<activetab>general-settings</activetab>
</form>

Some files were not shown because too many files have changed in this diff Show more