plugins: remove obsolete, switch to 24.1 branch, sync

This commit is contained in:
Franco Fichtner 2024-01-31 08:03:13 +01:00
parent 6eb9417ac5
commit 69f3f03b28
97 changed files with 2 additions and 5999 deletions

View File

@ -7,7 +7,6 @@ Copyright (c) 2023 Bernhard Frenking <bernhard@frenking.eu>
Copyright (c) 2023 Cannon Matthews <cannonmatthews@google.com>
Copyright (c) 2019 Cloudfence - Julio Camargo (JCC)
Copyright (c) 2005-2006 Colin Smith <ethethlay@gmail.com>
Copyright (c) 2020 D. Domig
Copyright (c) 2021 Dan Lundqvist
Copyright (c) 2021 David Berry
Copyright (c) 2017-2018 David Harrigan
@ -50,7 +49,6 @@ Copyright (c) 2021 Nicola Pellegrini
Copyright (c) 2022 Nikolaj Brinch Jørgensen
Copyright (c) 2021 Nim G
Copyright (c) 2023 Oliver Hartl
Copyright (c) 2022 Patrik Kernstock <patrik@kernstock.net>
Copyright (c) 2022 Robbert Rijkse
Copyright (c) 2023 sattamjh
Copyright (c) 2004-2012 Scott Ullrich <sullrich@gmail.com>

View File

@ -45,7 +45,7 @@ VERSIONBIN= ${LOCALBASE}/sbin/opnsense-version
_PLUGIN_ABI!= ${VERSIONBIN} -a
PLUGIN_ABI?= ${_PLUGIN_ABI}
.else
PLUGIN_ABI?= 23.7
PLUGIN_ABI?= 24.1
.endif
PHPBIN= ${LOCALBASE}/bin/php

View File

@ -47,7 +47,6 @@ misc/theme-rebellion -- A suitably dark theme
misc/theme-tukan -- The tukan theme - blue/white
misc/theme-vicuna -- The vicuna theme - blue sapphire
net/chrony -- Chrony time synchronisation
net/firewall -- Firewall API supplemental package (pending removal)
net/freeradius -- RADIUS Authentication, Authorization and Accounting Server
net/frr -- The FRRouting Protocol Suite
net/ftp-proxy -- Control ftp-proxy processes
@ -64,10 +63,8 @@ net/siproxd -- Siproxd is a proxy daemon for the SIP protocol
net/sslh -- sslh configuration front-end
net/tayga -- Tayga NAT64
net/udpbroadcastrelay -- Control ubpbroadcastrelay processes
net/upnp -- Universal Plug and Play Service
net/upnp -- Universal Plug and Play (UPnP IGD & PCP/NAT-PMP) Service
net/vnstat -- Network traffic monitor
net/wireguard -- WireGuard VPN service kernel implementation (pending removal)
net/wireguard-go -- WireGuard VPN service Go implementation (pending removal)
net/wol -- Wake on LAN Service
net/zerotier -- Virtual Networks That Just Work
net-mgmt/collectd -- Collect system and application performance metrics periodically
@ -94,7 +91,6 @@ security/tinc -- Tinc VPN
security/tor -- The Onion Router
security/wazuh-agent -- Agent for the open source security platform Wazuh
sysutils/apcupsd -- APCUPSD - APC UPS daemon
sysutils/api-backup -- EoL, core endpoint is /api/core/backup/download/this (pending removal)
sysutils/apuled -- PC Engine APU LED control (development only)
sysutils/dec-hw -- Deciso hardware specific information
sysutils/dmidecode -- Display hardware information on the dashboard

View File

@ -1,8 +0,0 @@
PLUGIN_NAME= firewall
PLUGIN_VERSION= 1.5
PLUGIN_COMMENT= Firewall API supplemental package
PLUGIN_OBSOLETE= yes
PLUGIN_MAINTAINER= ad@opnsense.org
PLUGIN_TIER= 2
.include "../../Mk/plugins.mk"

View File

@ -1,4 +0,0 @@
This package extends the standard OPNsense firewall system with endpoints for machine to machine management tasks.
Gui components are initially only intended to ease testing and to explain current functionality.
In the long term this might replace the default firewall in OPNsense.

View File

@ -1,48 +0,0 @@
<?php
/*
* Copyright (C) 2020 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.
*/
/**
* @param $fw
*/
function pfplugin_firewall($fw)
{
$mdlFilter = new OPNsense\Firewall\Filter();
foreach ($mdlFilter->rules->rule->sortedBy(["sequence"]) as $key => $rule) {
$content = $rule->serialize();
$content["#ref"] = "ui/firewall/filter#" . (string)$rule->getAttributes()['uuid'];
$fw->registerFilterRule($rule->getPriority(), $content);
}
foreach ($mdlFilter->snatrules->rule->sortedBy(["sequence"]) as $key => $rule) {
$fw->registerSNatRule(50, $rule->serialize());
}
foreach ($mdlFilter->npt->rule->sortedBy(["sequence"]) as $key => $rule) {
$fw->registerNptRule(50, $rule->serialize());
}
}

View File

@ -1,178 +0,0 @@
<?php
/*
* Copyright (C) 2020 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.
*/
namespace OPNsense\Firewall\Api;
use OPNsense\Base\ApiMutableModelControllerBase;
use OPNsense\Core\Backend;
use OPNsense\Core\Config;
use OPNsense\Firewall\Alias;
use OPNsense\Firewall\Category;
/**
* Class FilterBaseController implements actions for various types
* @package OPNsense\Firewall\Api
*/
abstract class FilterBaseController extends ApiMutableModelControllerBase
{
protected static $internalModelName = 'filter';
protected static $internalModelClass = 'OPNsense\Firewall\Filter';
protected static $categorysource = null;
/**
* list categories and usage
* @return array
*/
public function listCategoriesAction()
{
$response = ['rows' => []];
$catcount = [];
if (!empty(static::$categorysource)) {
$node = $this->getModel();
foreach (explode('.', static::$categorysource) as $ref) {
$node = $node->$ref;
}
foreach ($node->iterateItems() as $item) {
if (!empty((string)$item->categories)) {
foreach (explode(',', (string)$item->categories) as $cat) {
if (!isset($catcount[$cat])) {
$catcount[$cat] = 0;
}
$catcount[$cat] += 1;
}
}
}
}
foreach ((new Category())->categories->category->iterateItems() as $key => $category) {
$response['rows'][] = [
"uuid" => $key,
"name" => (string)$category->name,
"color" => (string)$category->color,
"used" => isset($catcount[$key]) ? $catcount[$key] : 0
];
}
array_multisort(array_column($response['rows'], "name"), SORT_ASC, SORT_NATURAL, $response['rows']);
return $response;
}
/**
* list of available network options
* @return array
*/
public function listNetworkSelectOptionsAction()
{
$result = [
'single' => [
'label' => gettext("Single host or Network")
],
'aliases' => [
'label' => gettext("Aliases"),
'items' => []
],
'networks' => [
'label' => gettext("Networks"),
'items' => [
'any' => gettext('any'),
'(self)' => gettext("This Firewall")
]
]
];
foreach ((Config::getInstance()->object())->interfaces->children() as $ifname => $ifdetail) {
$descr = htmlspecialchars(!empty($ifdetail->descr) ? $ifdetail->descr : strtoupper($ifname));
$result['networks']['items'][$ifname] = $descr . " " . gettext("net");
if (!isset($ifdetail->virtual)) {
$result['networks']['items'][$ifname . "ip"] = $descr . " " . gettext("address");
}
}
foreach ((new Alias())->aliases->alias->iterateItems() as $alias) {
if (strpos((string)$alias->type, "port") === false) {
$result['aliases']['items'][(string)$alias->name] = (string)$alias->name;
}
}
return $result;
}
public function applyAction($rollback_revision = null)
{
if ($this->request->isPost()) {
if ($rollback_revision != null) {
// background rollback timer
(new Backend())->configdpRun('pfplugin rollback_timer', [$rollback_revision], true);
}
return array("status" => (new Backend())->configdRun('filter reload'));
} else {
return array("status" => "error");
}
}
public function cancelRollbackAction($rollback_revision)
{
if ($this->request->isPost()) {
return array(
"status" => (new Backend())->configdpRun('pfplugin cancel_rollback', [$rollback_revision])
);
} else {
return array("status" => "error");
}
}
public function savepointAction()
{
if ($this->request->isPost()) {
// trigger a save, so we know revision->time matches our running config
Config::getInstance()->save();
return array(
"status" => "ok",
"retention" => (string)Config::getInstance()->backupCount(),
"revision" => (string)Config::getInstance()->object()->revision->time
);
} else {
return array("status" => "error");
}
}
public function revertAction($revision)
{
if ($this->request->isPost()) {
Config::getInstance()->lock();
$filename = Config::getInstance()->getBackupFilename($revision);
if (!$filename) {
Config::getInstance()->unlock();
return ["status" => gettext("unknown (or removed) savepoint")];
}
$this->getModel()->rollback($revision);
Config::getInstance()->unlock();
(new Backend())->configdRun('filter reload');
return ["status" => "ok"];
} else {
return array("status" => "error");
}
}
}

View File

@ -1,67 +0,0 @@
<?php
/*
* Copyright (C) 2020 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.
*/
namespace OPNsense\Firewall\Api;
class FilterController extends FilterBaseController
{
protected static $categorysource = "rules.rule";
public function searchRuleAction()
{
$category = $this->request->get('category');
$filter_funct = function ($record) use ($category) {
return empty($category) || array_intersect(explode(',', $record->categories), $category);
};
return $this->searchBase("rules.rule", ['enabled', 'sequence', 'description'], "sequence", $filter_funct);
}
public function setRuleAction($uuid)
{
return $this->setBase("rule", "rules.rule", $uuid);
}
public function addRuleAction()
{
return $this->addBase("rule", "rules.rule");
}
public function getRuleAction($uuid = null)
{
return $this->getBase("rule", "rules.rule", $uuid);
}
public function delRuleAction($uuid)
{
return $this->delBase("rules.rule", $uuid);
}
public function toggleRuleAction($uuid, $enabled = null)
{
return $this->toggleBase("rules.rule", $uuid, $enabled);
}
}

View File

@ -1,72 +0,0 @@
<?php
/*
* Copyright (C) 2023 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.
*/
namespace OPNsense\Firewall\Api;
class NptController extends FilterBaseController
{
protected static $categorysource = "npt.rule";
public function searchRuleAction()
{
$category = $this->request->get('category');
$filter_funct = function ($record) use ($category) {
return empty($category) || array_intersect(explode(',', $record->categories), $category);
};
return $this->searchBase(
"npt.rule",
['enabled', 'sequence', 'source_net', 'destination_net', 'trackif', 'description'],
"sequence",
$filter_funct
);
}
public function setRuleAction($uuid)
{
return $this->setBase("rule", "npt.rule", $uuid);
}
public function addRuleAction()
{
return $this->addBase("rule", "npt.rule");
}
public function getRuleAction($uuid = null)
{
return $this->getBase("rule", "npt.rule", $uuid);
}
public function delRuleAction($uuid)
{
return $this->delBase("npt.rule", $uuid);
}
public function toggleRuleAction($uuid, $enabled = null)
{
return $this->toggleBase("npt.rule", $uuid, $enabled);
}
}

View File

@ -1,67 +0,0 @@
<?php
/*
* Copyright (C) 2020 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.
*/
namespace OPNsense\Firewall\Api;
class SourceNatController extends FilterBaseController
{
protected static $categorysource = "snatrules.rule";
public function searchRuleAction()
{
$category = $this->request->get('category');
$filter_funct = function ($record) use ($category) {
return empty($category) || array_intersect(explode(',', $record->categories), $category);
};
return $this->searchBase("snatrules.rule", ['enabled', 'sequence', 'description'], "sequence", $filter_funct);
}
public function setRuleAction($uuid)
{
return $this->setBase("rule", "snatrules.rule", $uuid);
}
public function addRuleAction()
{
return $this->addBase("rule", "snatrules.rule");
}
public function getRuleAction($uuid = null)
{
return $this->getBase("rule", "snatrules.rule", $uuid);
}
public function delRuleAction($uuid)
{
return $this->delBase("snatrules.rule", $uuid);
}
public function toggleRuleAction($uuid, $enabled = null)
{
return $this->toggleBase("snatrules.rule", $uuid, $enabled);
}
}

View File

@ -1,50 +0,0 @@
<?php
/*
* Copyright (C) 2020 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.
*/
namespace OPNsense\Firewall;
class FilterController extends \OPNsense\Base\IndexController
{
public function indexAction()
{
$this->view->pick('OPNsense/Firewall/filter');
$this->view->SavePointBtns = true;
$this->view->ruleController = "filter";
$this->view->gridFields = [
[
'id' => 'enabled', 'formatter' => 'rowtoggle' ,'width' => '6em', 'heading' => gettext('Enabled')
],
[
'id' => 'sequence','width' => '9em', 'heading' => gettext('Sequence')
],
[
'id' => 'description', 'heading' => gettext('Description')
]
];
$this->view->formDialogFilterRule = $this->getForm("dialogFilterRule");
}
}

View File

@ -1,59 +0,0 @@
<?php
/*
* Copyright (C) 2023 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.
*/
namespace OPNsense\Firewall;
class NptController extends \OPNsense\Base\IndexController
{
public function indexAction()
{
$this->view->pick('OPNsense/Firewall/filter');
$this->view->ruleController = "npt";
$this->view->gridFields = [
[
'id' => 'enabled', 'formatter' => 'rowtoggle' ,'width' => '6em', 'heading' => gettext('Enabled')
],
[
'id' => 'sequence','width' => '9em', 'heading' => gettext('Sequence')
],
[
'id' => 'source_net', 'heading' => gettext('Internal IPv6 Prefix')
],
[
'id' => 'destination_net', 'heading' => gettext('External IPv6 Prefix')
],
[
'id' => 'trackif', 'heading' => gettext('Track if')
],
[
'id' => 'description', 'heading' => gettext('Description')
]
];
$this->view->formDialogFilterRule = $this->getForm("dialogNptRule");
}
}

View File

@ -1,50 +0,0 @@
<?php
/*
* Copyright (C) 2020 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.
*/
namespace OPNsense\Firewall;
class SourceNatController extends \OPNsense\Base\IndexController
{
public function indexAction()
{
$this->view->pick('OPNsense/Firewall/filter');
$this->view->SavePointBtns = true;
$this->view->ruleController = "source_nat";
$this->view->gridFields = [
[
'id' => 'enabled', 'formatter' => 'rowtoggle' ,'width' => '6em', 'heading' => gettext('Enabled')
],
[
'id' => 'sequence','width' => '9em', 'heading' => gettext('Sequence')
],
[
'id' => 'description', 'heading' => gettext('Description')
]
];
$this->view->formDialogFilterRule = $this->getForm("dialogSNatRule");
}
}

View File

@ -1,114 +0,0 @@
<form>
<field>
<id>rule.enabled</id>
<label>enabled</label>
<type>checkbox</type>
<help>Enable this rule</help>
</field>
<field>
<id>rule.sequence</id>
<label>Sequence</label>
<type>text</type>
</field>
<field>
<id>rule.action</id>
<label>Action</label>
<type>dropdown</type>
<help>Choose what to do with packets that match the criteria specified below.
Hint: the difference between block and reject is that with reject, a packet (TCP RST or ICMP port unreachable for UDP) is returned to the sender, whereas with block the packet is dropped silently. In either case, the original packet is discarded.
</help>
</field>
<field>
<id>rule.quick</id>
<label>Quick</label>
<type>checkbox</type>
<help>
If a packet matches a rule specifying quick, then that rule is considered the last matching rule and the specified action is taken.
When a rule does not have quick enabled, the last matching rule wins.
</help>
</field>
<field>
<id>rule.interface</id>
<label>Interface</label>
<type>select_multiple</type>
</field>
<field>
<id>rule.direction</id>
<label>Direction</label>
<type>dropdown</type>
<help>
Direction of the traffic. The default policy is to filter inbound traffic, which sets the policy to the interface originally receiving the traffic.
</help>
</field>
<field>
<id>rule.ipprotocol</id>
<label>TCP/IP Version</label>
<type>dropdown</type>
</field>
<field>
<id>rule.protocol</id>
<label>Protocol</label>
<type>dropdown</type>
</field>
<field>
<id>rule.source_net</id>
<label>Source</label>
<type>text</type>
</field>
<field>
<id>rule.source_port</id>
<label>Source port</label>
<type>text</type>
<advanced>true</advanced>
<help>Source port number or well known name (imap, imaps, http, https, ...), for ranges use a dash</help>
</field>
<field>
<id>rule.source_not</id>
<label>Source / Invert</label>
<type>checkbox</type>
<help>Use this option to invert the sense of the match.</help>
</field>
<field>
<id>rule.destination_net</id>
<label>Destination</label>
<type>text</type>
</field>
<field>
<id>rule.destination_not</id>
<label>Destination / Invert</label>
<type>checkbox</type>
<help>Use this option to invert the sense of the match.</help>
</field>
<field>
<id>rule.destination_port</id>
<label>Destination port</label>
<type>text</type>
<help>Destination port number or well known name (imap, imaps, http, https, ...), for ranges use a dash</help>
</field>
<field>
<id>rule.gateway</id>
<label>Gateway</label>
<type>dropdown</type>
<help>
Leave as 'default' to use the system routing table. Or choose a gateway to utilize policy based routing.
</help>
</field>
<field>
<id>rule.log</id>
<label>Log</label>
<type>checkbox</type>
<help>Log packets that are handled by this rule</help>
</field>
<field>
<id>rule.categories</id>
<label>Categories</label>
<type>select_multiple</type>
<style>tokenize</style>
<help>For grouping purposes you may select multiple groups here to organize items.</help>
</field>
<field>
<id>rule.description</id>
<label>Description</label>
<type>text</type>
</field>
</form>

View File

@ -1,53 +0,0 @@
<form>
<field>
<id>rule.enabled</id>
<label>enabled</label>
<type>checkbox</type>
<help>Enable this rule</help>
</field>
<field>
<id>rule.sequence</id>
<label>Sequence</label>
<type>text</type>
</field>
<field>
<id>rule.log</id>
<label>Log</label>
<type>checkbox</type>
<help>Log packets that are handled by this rule</help>
</field>
<field>
<id>rule.interface</id>
<label>Interface</label>
<type>dropdown</type>
</field>
<field>
<id>rule.source_net</id>
<label>Internal IPv6 Prefix (source)</label>
<type>text</type>
</field>
<field>
<id>rule.destination_net</id>
<label>External IPv6 Prefix (target)</label>
<type>text</type>
<help>Enter the external IPv6 prefix for this network prefix translation. Leave empty to auto-detect the prefix address using the specified tracking interface instead. The prefix size specified for the internal prefix will also be applied to the external prefix.</help>
</field>
<field>
<id>rule.trackif</id>
<label>Track interface</label>
<type>dropdown</type>
<help>Use prefix defined on the selected interface instead of the interface this rule applies to when target prefix is not provided.</help>
</field>
<field>
<id>rule.categories</id>
<label>Categories</label>
<type>select_multiple</type>
<style>tokenize</style>
<help>For grouping purposes you may select multiple groups here to organize items.</help>
</field>
<field>
<id>rule.description</id>
<label>Description</label>
<type>text</type>
</field>
</form>

View File

@ -1,101 +0,0 @@
<form>
<field>
<id>rule.enabled</id>
<label>enabled</label>
<type>checkbox</type>
<help>Enable this rule</help>
</field>
<field>
<id>rule.nonat</id>
<label>Do not NAT</label>
<type>checkbox</type>
<help>Enabling this option will disable NAT for traffic matching this rule and stop processing Outbound NAT rules.</help>
</field>
<field>
<id>rule.sequence</id>
<label>Sequence</label>
<type>text</type>
</field>
<field>
<id>rule.interface</id>
<label>Interface</label>
<type>dropdown</type>
</field>
<field>
<id>rule.ipprotocol</id>
<label>TCP/IP Version</label>
<type>dropdown</type>
</field>
<field>
<id>rule.protocol</id>
<label>Protocol</label>
<type>dropdown</type>
</field>
<field>
<id>rule.source_net</id>
<label>Source</label>
<type>text</type>
</field>
<field>
<id>rule.source_port</id>
<label>Source port</label>
<type>text</type>
<advanced>true</advanced>
<help>Source port number or well known name (imap, imaps, http, https, ...), for ranges use a dash</help>
</field>
<field>
<id>rule.source_not</id>
<label>Source / Invert</label>
<type>checkbox</type>
<help>Use this option to invert the sense of the match.</help>
</field>
<field>
<id>rule.destination_net</id>
<label>Destination</label>
<type>text</type>
</field>
<field>
<id>rule.destination_not</id>
<label>Destination / Invert</label>
<type>checkbox</type>
<help>Use this option to invert the sense of the match.</help>
</field>
<field>
<id>rule.destination_port</id>
<label>Destination port</label>
<type>text</type>
<help>Destination port number or well known name (imap, imaps, http, https, ...), for ranges use a dash</help>
</field>
<field>
<id>rule.target</id>
<label>Translation / target</label>
<type>text</type>
<help>
Packets matching this rule will be mapped to the IP address given here.
</help>
</field>
<field>
<id>rule.target_port</id>
<label>Translation port</label>
<type>text</type>
<help>Destination port number or well known name (imap, imaps, http, https, ...)</help>
</field>
<field>
<id>rule.log</id>
<label>Log</label>
<type>checkbox</type>
<help>Log packets that are handled by this rule</help>
</field>
<field>
<id>rule.categories</id>
<label>Categories</label>
<type>select_multiple</type>
<style>tokenize</style>
<help>For grouping purposes you may select multiple groups here to organize items.</help>
</field>
<field>
<id>rule.description</id>
<label>Description</label>
<type>text</type>
</field>
</form>

View File

@ -1,23 +0,0 @@
<acl>
<page-filter-api>
<name>Firewall: Automation: Filter</name>
<patterns>
<pattern>ui/firewall/filter/*</pattern>
<pattern>api/firewall/filter/*</pattern>
</patterns>
</page-filter-api>
<page-filter-snat-api>
<name>Firewall: Automation: Source NAT</name>
<patterns>
<pattern>ui/firewall/source_nat/*</pattern>
<pattern>api/firewall/source_nat/*</pattern>
</patterns>
</page-filter-snat-api>
<page-firewall-nat-npt>
<name>Firewall: Automation: NPTv6</name>
<patterns>
<pattern>ui/firewall/npt/*</pattern>
<pattern>api/firewall/npt/*</pattern>
</patterns>
</page-firewall-nat-npt>
</acl>

View File

@ -1,138 +0,0 @@
<?php
/*
* Copyright (C) 2020 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.
*/
namespace OPNsense\Firewall\FieldTypes;
use OPNsense\Core\Config;
use OPNsense\Base\FieldTypes\ArrayField;
use OPNsense\Base\FieldTypes\ContainerField;
/**
* Class FilterRuleContainerField
* @package OPNsense\Firewall\FieldTypes
*/
class FilterRuleContainerField extends ContainerField
{
/**
* map rules
* @return array
*/
public function serialize()
{
$result = array();
$map_manual = ['source_net', 'source_not', 'source_port', 'destination_net', 'destination_not',
'destination_port', 'enabled', 'description', 'sequence', 'action'];
// 1-on-1 map (with type conversion if needed)
foreach ($this->iterateItems() as $key => $node) {
if (!in_array($key, $map_manual)) {
if (is_a($node, "OPNsense\\Base\\FieldTypes\\BooleanField")) {
$result[$key] = !empty((string)$node);
} elseif (is_a($node, "OPNsense\\Base\\FieldTypes\\ProtocolField")) {
if ((string)$node != 'any') {
$result[$key] = (string)$node;
}
} else {
$result[$key] = (string)$node;
}
}
}
// source / destination mapping
$result['source'] = array();
if (!empty((string)$this->source_net)) {
$result['source']['network'] = (string)$this->source_net;
if (!empty((string)$this->source_not)) {
$result['source']['not'] = true;
}
if (!empty((string)$this->source_port)) {
$result['source']['port'] = (string)$this->source_port;
}
}
$result['destination'] = array();
if (!empty((string)$this->destination_net)) {
$result['destination']['network'] = (string)$this->destination_net;
if (!empty((string)$this->destination_not)) {
$result['destination']['not'] = true;
}
if (!empty((string)$this->destination_port)) {
$result['destination']['port'] = (string)$this->destination_port;
}
}
// field mappings and differences
$result['disabled'] = empty((string)$this->enabled);
$result['descr'] = (string)$this->description;
$result['type'] = (string)$this->action;
if (strpos((string)$this->interface, ",") !== false) {
$result['floating'] = true;
}
return $result;
}
/**
* rule priority is threaded equally to the legacy rules, first "floating" then groups and single interface
* rules are handled last
* @return int priority in the ruleset, sequence should determine sort order.
*/
public function getPriority()
{
$configObj = Config::getInstance()->object();
$interface = (string)$this->interface;
if (strpos($interface, ",") !== false) {
// floating (multiple interfaces involved)
return 1000;
} elseif (
!empty($configObj->interfaces) &&
!empty($configObj->interfaces->$interface) &&
!empty($configObj->interfaces->$interface->type) &&
$configObj->interfaces->$interface->type == 'group'
) {
// group type
return 2000;
} else {
// default
return 3000;
}
}
}
/**
* Class FilterRuleField
* @package OPNsense\Firewall\FieldTypes
*/
class FilterRuleField extends ArrayField
{
/**
* @inheritDoc
*/
public function newContainerField($ref, $tagname)
{
$container_node = new FilterRuleContainerField($ref, $tagname);
$parentmodel = $this->getParentModel();
$container_node->setParentModel($parentmodel);
return $container_node;
}
}

View File

@ -1,111 +0,0 @@
<?php
/*
* Copyright (C) 2020 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.
*/
namespace OPNsense\Firewall\FieldTypes;
use OPNsense\Base\FieldTypes\ArrayField;
use OPNsense\Base\FieldTypes\ContainerField;
/**
* Class SourceNatRuleContainerField
* @package OPNsense\Firewall\FieldTypes
*/
class SourceNatRuleContainerField extends ContainerField
{
/**
* map source nat rules
* @return array
*/
public function serialize()
{
$result = [];
$source_mapper = [
'enabled' => false,
'source_net' => false,
'source_not' => false,
'source_port' => 'sourceport',
'destination_net' => false,
'destination_not' => false,
'destination_port' => 'dstport',
'target_port' => 'natport',
'description' => 'descr'
];
// 1-on-1 map (with type conversion if needed)
foreach ($this->iterateItems() as $key => $node) {
$target_fieldname = isset($source_mapper[$key]) ? $source_mapper[$key] : $key;
if ($target_fieldname) {
if (is_a($node, "OPNsense\\Base\\FieldTypes\\BooleanField")) {
$result[$target_fieldname] = !empty((string)$node);
} elseif (is_a($node, "OPNsense\\Base\\FieldTypes\\ProtocolField")) {
if ((string)$node != 'any') {
$result[$target_fieldname] = (string)$node;
}
} else {
$result[$target_fieldname] = (string)$node;
}
}
}
$result['disabled'] = empty((string)$this->enabled);
// source / destination mapping, doesn't use port construct like it would for rules.
$result['source'] = array();
if (!empty((string)$this->source_net)) {
$result['source']['network'] = (string)$this->source_net;
if (!empty((string)$this->source_not)) {
$result['source']['not'] = true;
}
}
$result['destination'] = array();
if (!empty((string)$this->destination_net)) {
$result['destination']['network'] = (string)$this->destination_net;
if (!empty((string)$this->destination_not)) {
$result['destination']['not'] = true;
}
}
return $result;
}
}
/**
* Class SourceNatRuleField
* @package OPNsense\Firewall\FieldTypes
*/
class SourceNatRuleField extends ArrayField
{
/**
* @inheritDoc
*/
public function newContainerField($ref, $tagname)
{
$container_node = new SourceNatRuleContainerField($ref, $tagname);
$parentmodel = $this->getParentModel();
$container_node->setParentModel($parentmodel);
return $container_node;
}
}

View File

@ -1,164 +0,0 @@
<?php
/*
* Copyright (C) 2020 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.
*/
namespace OPNsense\Firewall;
use OPNsense\Core\Config;
use Phalcon\Messages\Message;
use OPNsense\Base\BaseModel;
use OPNsense\Firewall\Util;
class Filter extends BaseModel
{
/**
* @inheritDoc
*/
public function performValidation($validateFullModel = false)
{
$config = Config::getInstance()->object();
// standard model validations
$messages = parent::performValidation($validateFullModel);
foreach ([$this->rules->rule, $this->snatrules->rule] as $rules) {
foreach ($rules->iterateItems() as $rule) {
if ($validateFullModel || $rule->isFieldChanged()) {
// port / protocol validation
if (!empty((string)$rule->source_port) && !in_array($rule->protocol, ['TCP', 'UDP'])) {
$messages->appendMessage(new Message(
gettext("Source ports are only valid for tcp or udp type rules."),
$rule->source_port->__reference
));
}
if (!empty((string)$rule->destination_port) && !in_array($rule->protocol, ['TCP', 'UDP'])) {
$messages->appendMessage(new Message(
gettext("Destination ports are only valid for tcp or udp type rules."),
$rule->destination_port->__reference
));
}
// validate protocol family
$dest_is_addr = Util::isSubnet($rule->destination_net) || Util::isIpAddress($rule->destination_net);
$dest_proto = strpos($rule->destination_net, ':') === false ? "inet" : "inet6";
if ($dest_is_addr && $dest_proto != $rule->ipprotocol) {
$messages->appendMessage(new Message(
gettext("Destination address type should match selected TCP/IP protocol version."),
$rule->destination_net->__reference
));
}
$src_is_addr = Util::isSubnet($rule->source_net) || Util::isIpAddress($rule->source_net);
$src_proto = strpos($rule->source_net, ':') === false ? "inet" : "inet6";
if ($src_is_addr && $src_proto != $rule->ipprotocol) {
$messages->appendMessage(new Message(
gettext("Source address type should match selected TCP/IP protocol version."),
$rule->source_net->__reference
));
}
// Additional source nat validations
if ($rule->target !== null) {
$target_is_addr = Util::isSubnet($rule->target) || Util::isIpAddress($rule->target);
$target_proto = strpos($rule->target, ':') === false ? "inet" : "inet6";
if ($target_is_addr && $target_proto != $rule->ipprotocol) {
$messages->appendMessage(new Message(
gettext("Target address type should match selected TCP/IP protocol version."),
$rule->target->__reference
));
}
if (!empty((string)$rule->target_port) && !in_array($rule->protocol, ['TCP', 'UDP'])) {
$messages->appendMessage(new Message(
gettext("Target ports are only valid for tcp or udp type rules."),
$rule->target_port->__reference
));
}
}
}
}
}
foreach ($this->npt->rule->iterateItems() as $rule) {
if ($validateFullModel || $rule->isFieldChanged()) {
if (!empty((string)$rule->trackif)) {
if (!empty((string)$rule->destination_net)) {
$messages->appendMessage(new Message(
gettext('A track interface is only allowed without an external prefix.'),
$rule->trackif->__reference
));
}
if (
(empty($config->interfaces->{$rule->interface}->ipaddrv6) ||
$config->interfaces->{$rule->interface}->ipaddrv6 != 'dhcp6') ||
empty($config->interfaces->{$rule->trackif}->{'track6-interface'}) ||
$config->interfaces->{$rule->trackif}->{'track6-interface'} != (string)$rule->interface
) {
$messages->appendMessage(new Message(
gettext('This interface is not tracking the current rule interface.'),
$rule->trackif->__reference
));
}
}
if (!empty((string)$rule->destination_net) && !empty((string)$rule->source_net)) {
/* defaults to /128 */
$dparts = explode('/', (string)$rule->destination_net . '/128');
$sparts = explode('/', (string)$rule->source_net . '/128');
if ($dparts[1] != $sparts[1]) {
$messages->appendMessage(new Message(
gettext("External subnet should match internal subnet."),
$rule->destination_net->__reference
));
}
}
}
}
return $messages;
}
/**
* Rollback this model to a previous version.
* Make sure to remove this object afterwards, since its contents won't be updated.
* @param $revision float|string revision number
* @return bool action performed (backup revision existed)
*/
public function rollback($revision)
{
$filename = Config::getInstance()->getBackupFilename($revision);
if ($filename) {
// fiddle with the dom, copy OPNsense->Firewall->Filter from backup to current config
$sourcexml = simplexml_load_file($filename);
if ($sourcexml->OPNsense->Firewall->Filter) {
$sourcedom = dom_import_simplexml($sourcexml->OPNsense->Firewall->Filter);
$targetxml = Config::getInstance()->object();
$targetdom = dom_import_simplexml($targetxml->OPNsense->Firewall->Filter);
$node = $targetdom->ownerDocument->importNode($sourcedom, true);
$targetdom->parentNode->replaceChild($node, $targetdom);
Config::getInstance()->save();
return true;
}
}
return false;
}
}

View File

@ -1,263 +0,0 @@
<model>
<mount>//OPNsense/Firewall/Filter</mount>
<version>1.0.2</version>
<migration_prefix>MFP</migration_prefix>
<description>
OPNsense firewall filter rules
</description>
<items>
<rules>
<rule type=".\FilterRuleField">
<enabled type="BooleanField">
<Default>1</Default>
<Required>Y</Required>
</enabled>
<sequence type="IntegerField">
<MinimumValue>1</MinimumValue>
<MaximumValue>99999</MaximumValue>
<ValidationMessage>provide a valid sequence for sorting</ValidationMessage>
<Required>Y</Required>
<Default>1</Default>
</sequence>
<action type="OptionField">
<Required>Y</Required>
<Default>pass</Default>
<OptionValues>
<pass>Pass</pass>
<block>Block</block>
<reject>Reject</reject>
</OptionValues>
</action>
<quick type="BooleanField">
<Default>1</Default>
<Required>Y</Required>
</quick>
<interface type="InterfaceField">
<Multiple>Y</Multiple>
<AllowDynamic>Y</AllowDynamic>
</interface>
<direction type="OptionField">
<Required>Y</Required>
<Default>in</Default>
<OptionValues>
<in>In</in>
<out>Out</out>
</OptionValues>
</direction>
<ipprotocol type="OptionField">
<Required>Y</Required>
<Default>inet</Default>
<OptionValues>
<inet>IPv4</inet>
<inet6>IPv6</inet6>
</OptionValues>
</ipprotocol>
<protocol type="ProtocolField">
<Required>Y</Required>
<Default>any</Default>
</protocol>
<!-- XXX: should map internally to 'source' => array('network' => $source_net, "not" => true|false) -->
<source_net type="NetworkAliasField">
<Default>any</Default>
<Required>Y</Required>
</source_net>
<source_not type="BooleanField">
<Default>0</Default>
<Required>Y</Required>
</source_not>
<source_port type="PortField">
<EnableWellKnown>Y</EnableWellKnown>
<EnableRanges>Y</EnableRanges>
<EnableAlias>Y</EnableAlias>
<ValidationMessage>Please specify a valid portnumber, name, alias or range</ValidationMessage>
</source_port>
<!-- XXX: should map internally to 'source' => array('destination' => destination_net, "not" => true|false) -->
<destination_net type="NetworkAliasField">
<Default>any</Default>
<Required>Y</Required>
</destination_net>
<destination_not type="BooleanField">
<Default>0</Default>
<Required>Y</Required>
</destination_not>
<destination_port type="PortField">
<EnableWellKnown>Y</EnableWellKnown>
<EnableRanges>Y</EnableRanges>
<EnableAlias>Y</EnableAlias>
<ValidationMessage>Please specify a valid portnumber, name, alias or range</ValidationMessage>
</destination_port>
<gateway type="JsonKeyValueStoreField">
<ConfigdPopulateAct>interface gateways list</ConfigdPopulateAct>
<SourceFile>/tmp/gateway_list.json</SourceFile>
<ConfigdPopulateTTL>20</ConfigdPopulateTTL>
<ValidationMessage>Specify a valid gateway from the list matching the networks ip protocol.</ValidationMessage>
</gateway>
<log type="BooleanField">
<Default>0</Default>
<Required>Y</Required>
</log>
<categories type="ModelRelationField">
<Model>
<rulesets>
<source>OPNsense.Firewall.Category</source>
<items>categories.category</items>
<display>name</display>
</rulesets>
</Model>
<Multiple>Y</Multiple>
<ValidationMessage>Related category not found.</ValidationMessage>
</categories>
<description type="TextField">
<Required>N</Required>
<mask>/^([\t\n\v\f\r 0-9a-zA-Z.\-,_\x{00A0}-\x{FFFF}]){0,255}$/u</mask>
<ValidationMessage>Description should be a string between 1 and 255 characters</ValidationMessage>
</description>
</rule>
</rules>
<snatrules>
<rule type=".\SourceNatRuleField">
<enabled type="BooleanField">
<Default>1</Default>
<Required>Y</Required>
</enabled>
<nonat type="BooleanField">
<Default>0</Default>
<Required>Y</Required>
</nonat>
<sequence type="IntegerField">
<MinimumValue>1</MinimumValue>
<MaximumValue>99999</MaximumValue>
<ValidationMessage>provide a valid sequence for sorting</ValidationMessage>
<Required>Y</Required>
<Default>1</Default>
</sequence>
<interface type="InterfaceField">
<Required>Y</Required>
<Default>lan</Default>
<AllowDynamic>Y</AllowDynamic>
</interface>
<ipprotocol type="OptionField">
<Required>Y</Required>
<Default>inet</Default>
<OptionValues>
<inet>IPv4</inet>
<inet6>IPv6</inet6>
</OptionValues>
</ipprotocol>
<protocol type="ProtocolField">
<Required>Y</Required>
<Default>any</Default>
</protocol>
<source_net type="NetworkAliasField">
<Default>any</Default>
<Required>Y</Required>
</source_net>
<source_not type="BooleanField">
<Default>0</Default>
<Required>Y</Required>
</source_not>
<source_port type="PortField">
<EnableWellKnown>Y</EnableWellKnown>
<EnableRanges>Y</EnableRanges>
<EnableAlias>Y</EnableAlias>
<ValidationMessage>Please specify a valid portnumber, name, alias or range</ValidationMessage>
</source_port>
<destination_net type="NetworkAliasField">
<Default>any</Default>
<Required>Y</Required>
</destination_net>
<destination_not type="BooleanField">
<Default>0</Default>
<Required>Y</Required>
</destination_not>
<destination_port type="PortField">
<EnableWellKnown>Y</EnableWellKnown>
<EnableRanges>Y</EnableRanges>
<EnableAlias>Y</EnableAlias>
<ValidationMessage>Please specify a valid portnumber, name, alias or range</ValidationMessage>
</destination_port>
<target type="NetworkAliasField">
<Default>wanip</Default>
<Required>Y</Required>
</target>
<target_port type="PortField">
<EnableWellKnown>Y</EnableWellKnown>
<EnableRanges>Y</EnableRanges>
</target_port>
<log type="BooleanField">
<Default>0</Default>
<Required>Y</Required>
</log>
<categories type="ModelRelationField">
<Model>
<rulesets>
<source>OPNsense.Firewall.Category</source>
<items>categories.category</items>
<display>name</display>
</rulesets>
</Model>
<Multiple>Y</Multiple>
<ValidationMessage>Related category not found.</ValidationMessage>
</categories>
<description type="TextField">
<Required>N</Required>
<mask>/^([\t\n\v\f\r 0-9a-zA-Z.\-,_\x{00A0}-\x{FFFF}]){0,255}$/u</mask>
<ValidationMessage>Description should be a string between 1 and 255 characters</ValidationMessage>
</description>
</rule>
</snatrules>
<npt>
<rule type=".\SourceNatRuleField">
<enabled type="BooleanField">
<Default>1</Default>
<Required>Y</Required>
</enabled>
<log type="BooleanField">
<Default>0</Default>
<Required>Y</Required>
</log>
<sequence type="IntegerField">
<MinimumValue>1</MinimumValue>
<MaximumValue>99999</MaximumValue>
<ValidationMessage>provide a valid sequence for sorting</ValidationMessage>
<Required>Y</Required>
<Default>1</Default>
</sequence>
<interface type="InterfaceField">
<Required>Y</Required>
<Default>lan</Default>
<AllowDynamic>Y</AllowDynamic>
</interface>
<source_net type="NetworkField">
<Required>Y</Required>
<AddressFamily>ipv6</AddressFamily>
<NetMaskRequired>N</NetMaskRequired>
<WildcardEnabled>N</WildcardEnabled>
</source_net>
<destination_net type="NetworkField">
<AddressFamily>ipv6</AddressFamily>
<NetMaskRequired>N</NetMaskRequired>
<WildcardEnabled>N</WildcardEnabled>
</destination_net>
<trackif type="InterfaceField">
</trackif>
<categories type="ModelRelationField">
<Model>
<rulesets>
<source>OPNsense.Firewall.Category</source>
<items>categories.category</items>
<display>name</display>
</rulesets>
</Model>
<Multiple>Y</Multiple>
<ValidationMessage>Related category not found.</ValidationMessage>
</categories>
<description type="TextField">
<Required>N</Required>
<mask>/^([\t\n\v\f\r 0-9a-zA-Z.\-,_\x{00A0}-\x{FFFF}]){0,255}$/u</mask>
<ValidationMessage>Description should be a string between 1 and 255 characters</ValidationMessage>
</description>
</rule>
</npt>
</items>
</model>

View File

@ -1,15 +0,0 @@
<menu>
<Firewall>
<Automation cssClass="fa fa-gear">
<Filter order="50" url="/ui/firewall/filter/">
<FilterRef url="/ui/firewall/filter#*" visibility="hidden"/>
</Filter>
<SourceNat order="100" VisibleName="Source NAT" url="/ui/firewall/source_nat/">
<FilterRef url="/ui/firewall/source_nat#*" visibility="hidden"/>
</SourceNat>
<Npt order="150" VisibleName="NPTv6" url="/ui/firewall/npt/">
<FilterRef url="/ui/firewall/npt#*" visibility="hidden"/>
</Npt>
</Automation>
</Firewall>
</menu>

View File

@ -1,59 +0,0 @@
<?php
/**
* Copyright (C) 2020 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.
*
*/
namespace OPNsense\Firewall\Migrations;
use OPNsense\Core\Config;
use OPNsense\Base\BaseModelMigration;
class MFP1_0_0 extends BaseModelMigration
{
public function post($model)
{
// Move OPNsense->Firewall->FilterRule ---> OPNsense->Firewall->Filter
$cfgObj = Config::getInstance()->object();
if (
!empty($cfgObj->OPNsense) && !empty($cfgObj->OPNsense->Firewall)
&& !empty($cfgObj->OPNsense->Firewall->FilterRule)
) {
// model migration created a new, empty rules section
if (empty($cfgObj->OPNsense->Firewall->Filter->rules)) {
unset($cfgObj->OPNsense->Firewall->Filter->rules);
$targetdom = dom_import_simplexml($cfgObj->OPNsense->Firewall->Filter);
foreach ($cfgObj->OPNsense->Firewall->FilterRule->children() as $child) {
$sourcedom = dom_import_simplexml($child);
$targetdom->appendChild($sourcedom);
}
unset($cfgObj->OPNsense->Firewall->FilterRule);
Config::getInstance()->save();
}
}
}
}

View File

@ -1,250 +0,0 @@
<script>
$( document ).ready(function() {
let initial_load = true;
let grid = $("#grid-rules").UIBootgrid({
search:'/api/firewall/{{ruleController}}/search_rule/',
get:'/api/firewall/{{ruleController}}/get_rule/',
set:'/api/firewall/{{ruleController}}/set_rule/',
add:'/api/firewall/{{ruleController}}/add_rule/',
del:'/api/firewall/{{ruleController}}/del_rule/',
toggle:'/api/firewall/{{ruleController}}/toggle_rule/',
options:{
requestHandler: function(request){
if ( $('#category_filter').val().length > 0) {
request['category'] = $('#category_filter').val();
}
return request;
}
}
});
grid.on("loaded.rs.jquery.bootgrid", function (e){
// reload categories before grid load
ajaxCall('/api/firewall/{{ruleController}}/list_categories', {}, function(data, status){
if (data.rows !== undefined) {
let current_selection = $("#category_filter").val();
$("#category_filter").empty();
for (i=0; i < data.rows.length ; ++i) {
let row = data.rows[i];
let opt_val = $('<div/>').html(row.name).text();
let bgcolor = row.color != "" ? row.color : '31708f;'; // set category color
let option = $("<option/>").val(row.uuid).html(row.name);
if (row.used > 0) {
option.attr(
'data-content',
"<span>"+opt_val + "</span>"+
"<span style='background:#"+bgcolor+";' class='badge pull-right'>" + row.used + "</span>"
);
option.attr('id', row.uuid);
}
$("#category_filter").append(option);
}
$("#category_filter").val(current_selection);
$("#category_filter").selectpicker('refresh');
}
});
});
// open edit dialog when opened with a uuid reference
if (window.location.hash !== "" && window.location.hash.split("-").length >= 4) {
grid.on('loaded.rs.jquery.bootgrid', function(){
if (initial_load) {
$(".command-edit:eq(0)").clone(true).data('row-id', window.location.hash.substr(1)).click();
initial_load = false;
}
});
}
$("#reconfigureAct").SimpleActionButton();
$("#savepointAct").SimpleActionButton({
onAction: function(data, status){
stdDialogInform(
"{{ lang._('Savepoint created') }}",
data['revision'],
"{{ lang._('Close') }}"
);
}
});
$("#revertAction").on('click', function(){
BootstrapDialog.show({
type: BootstrapDialog.TYPE_DEFAULT,
title: "{{ lang._('Revert to savepoint') }}",
message: "<p>{{ lang._('Enter a savepoint to rollback to.') }}</p>" +
'<div class="form-group" style="display: block;">' +
'<input id="revertToTime" type="text" class="form-control"/>' +
'<span class="error text-danger" id="revertToTimeError"></span>'+
'</div>',
buttons: [{
label: "{{ lang._('Revert') }}",
cssClass: 'btn-primary',
action: function(dialogRef) {
ajaxCall("/api/firewall/{{ruleController}}/revert/" + $("#revertToTime").val(), {}, function (data, status) {
if (data.status !== "ok") {
$("#revertToTime").parent().addClass("has-error");
$("#revertToTimeError").html(data.status);
} else {
std_bootgrid_reload("grid-rules");
dialogRef.close();
}
});
}
}],
onshown: function(dialogRef) {
$("#revertToTime").parent().removeClass("has-error");
$("#revertToTimeError").html("");
$("#revertToTime").val("");
}
});
});
// move filter into action header
$("#type_filter_container").detach().prependTo('#grid-rules-header > .row > .actionBar > .actions');
$("#category_filter").change(function(){
$('#grid-rules').bootgrid('reload');
});
// replace all "net" selectors with details retrieved from "list_network_select_options" endpoint
ajaxGet('/api/firewall/{{ruleController}}/list_network_select_options', [], function(data, status){
// fetch options
let options = [];
if (data.single) {
Object.keys(data).forEach((key, idx) => {
if (data[key].items !== undefined) {
let optgrp = $("<optgroup/>").attr('label', data[key].label);
Object.keys(data[key].items).forEach((key2, idx2) => {
let this_item = data[key].items[key2];
optgrp.append($("<option/>").val(key2).text(this_item));
});
options.push(optgrp);
} else {
options.push($("<option/>").val('').text(data[key].label));
}
});
}
if (options.length == 0) {
// unable to fetch options.
return;
}
$(".net_selector").each(function(){
let $items = $("#network_select").clone().show();
let $this_input = $items.find('input');
let $this_select = $items.find('select');
for (i=0; i < options.length; ++i) {
$this_select.append(options[i].clone());
}
$this_select.attr('for', $(this).attr('id')).selectpicker();
$this_select.change(function(){
let $value = $(this).val();
if ($value !== '') {
$this_input.val($value);
$this_input.hide();
} else {
$this_input.show();
}
});
$this_input.attr('id', $(this).attr('id'));
$this_input.change(function(){
$this_select.val($(this).val());
if ($this_select.val() === null || $this_select.val() == '') {
$this_select.val('');
$this_input.show();
} else {
$this_input.hide();
}
$this_select.selectpicker('refresh');
});
$this_input.show();
$(this).replaceWith($items);
});
});
});
</script>
<ul class="nav nav-tabs" data-tabs="tabs" id="maintabs">
<li class="active"><a data-toggle="tab" href="#rules">{{ lang._('Rules') }}</a></li>
</ul>
<div class="tab-content content-box">
<div id="rules" class="tab-pane fade in active">
<div class="hidden">
<!-- filter per type container -->
<div id="type_filter_container" class="btn-group">
<select id="category_filter" data-title="{{ lang._('Categories') }}" class="selectpicker" data-live-search="true" data-size="5" multiple data-width="200px">
</select>
</div>
</div>
<!-- tab page "rules" -->
<table id="grid-rules" class="table table-condensed table-hover table-striped" data-editDialog="DialogFilterRule" data-editAlert="FilterRuleChangeMessage">
<thead>
<tr>
<th data-column-id="uuid" data-type="string" data-identifier="true" data-visible="false">{{ lang._('ID') }}</th>
{% for fieldlist in gridFields %}
<th
data-column-id="{{fieldlist['id']}}"
data-width="{{fieldlist['width']|default('')}}"
data-type="{{fieldlist['type']|default('string')}}"
data-formatter="{{fieldlist['formatter']|default('')}}"
>{{fieldlist['heading']|default('')}}</th>
{% endfor %}
<th data-column-id="commands" data-width="7em" data-formatter="commands" data-sortable="false">{{ lang._('Commands') }}</th>
</tr>
</thead>
<tbody>
</tbody>
<tfoot>
<tr>
<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>
<div class="col-md-12">
<div id="FilterRuleChangeMessage" class="alert alert-info" style="display: none" role="alert">
{{ lang._('After changing settings, please remember to apply them with the button below') }}
</div>
<hr/>
<button class="btn btn-primary" id="reconfigureAct"
data-endpoint='/api/firewall/{{ruleController}}/apply'
data-label="{{ lang._('Apply') }}"
data-error-title="{{ lang._('Filter load error') }}"
type="button"
></button>
{% if SavePointBtns is defined %}
<div class="pull-right">
<button class="btn" id="savepointAct"
data-endpoint='/api/firewall/{{ruleController}}/savepoint'
data-label="{{ lang._('Savepoint') }}"
data-error-title="{{ lang._('snapshot error') }}"
type="button"
></button>
<button class="btn" id="revertAction">
{{ lang._('Revert') }}
</button>
</div>
{% endif %}
<br/><br/>
</div>
</div>
</div>
<div id="network_select" style="display: none;" >
<table style="max-width: 348px">
<tr>
<td>
<select data-live-search="true" data-size="5" data-width="348px">
</select>
</td>
</tr>
<tr>
<td>
<input style="display:none;" type="text"/>
</td>
</tr>
</table>
</div>
{{ partial("layout_partials/base_dialog",['fields':formDialogFilterRule,'id':'DialogFilterRule','label':lang._('Edit rule')])}}

View File

@ -1,40 +0,0 @@
#!/usr/local/bin/php
<?php
/*
* Copyright (C) 2020 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.
*/
if (count($argv) >= 2) {
$revision = preg_replace("/[^0-9.]/", "", $argv[1]);
if (!empty($revision)) {
$lckfile = "/tmp/pfplugin_{$revision}.lock";
if (file_exists($lckfile)) {
unlink($lckfile);
exit(0);
}
}
}
exit(1);

View File

@ -1,54 +0,0 @@
#!/usr/local/bin/php
<?php
/*
* Copyright (C) 2020 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.
*/
require_once('script/load_phalcon.php');
if (count($argv) >= 2) {
$revision = preg_replace("/[^0-9.]/", "", $argv[1]);
if (!empty($revision)) {
$lckfile = "/tmp/pfplugin_{$revision}.lock";
file_put_contents($lckfile, "");
// give the api 60 seconds to callback
for ($i=0; $i < 60 ; ++$i) {
if (!file_exists($lckfile)) {
// got feedback
exit(0);
}
sleep(1);
}
@unlink($lckfile);
// no feedback, revert
$mdlFilter = new OPNsense\Firewall\Filter();
if ($mdlFilter->rollback($revision)) {
(new OPNsense\Core\Backend())->configdRun('filter reload');
} else {
syslog(LOG_WARNING, "unable to revert to unexisting revision : {$revision}");
}
}
}

View File

@ -1,11 +0,0 @@
[rollback_timer]
command:/usr/local/bin/flock -n -E 0 -o /tmp/pfplugin_rollback_timer.lock /usr/local/opnsense/scripts/pfplugin/rollback_timer
parameters: %s
type:script
message:wait for api feedback or revert to previous filter plugin config
[cancel_rollback]
command: /usr/local/opnsense/scripts/pfplugin/rollback_cancel
parameters: %s
type:script_output
message:cancel pfplugin rollback

View File

@ -1,10 +0,0 @@
PLUGIN_NAME= wireguard-go
PLUGIN_VERSION= 1.13
PLUGIN_REVISION= 8
PLUGIN_COMMENT= WireGuard VPN service Go implementation
PLUGIN_CONFLICTS= wireguard
PLUGIN_OBSOLETE= yes
PLUGIN_DEPENDS= wireguard-go wireguard-tools
PLUGIN_MAINTAINER= m.muenz@gmail.com
.include "../../Mk/plugins.mk"

View File

@ -1,78 +0,0 @@
WireGuard® is an extremely simple yet fast and modern VPN
that utilizes state-of-the-art cryptography. It aims to be
faster, simpler, leaner, and more useful than IPSec, while
avoiding the massive headache. It intends to be considerably
more performant than OpenVPN. WireGuard is designed as a
general purpose VPN for running on embedded interfaces and
super computers alike, fit for many different circumstances.
Initially released for the Linux kernel, it is now
cross-platform and widely deployable. It is currently under
heavy development, but already it might be regarded as the
most secure, easiest to use, and simplest VPN solution in
the industry.
WWW: https://www.wireguard.com/
Changelog
---------
1.13
* Reworked widget and assorted cleanups (contributed by Patrik Kernstock)
* Improve widget public key overlapping (contributed by Victor Haggqvist)
1.12
* Adjust validation for naming local instance and endpoints
1.11
* Add script for renewal of Wireguard DNS-based entries for stale connections (#2956)
* Trim whitespace around new public and private keys in config (#2982)
1.10
* Remove instance limit
1.9
* Rename interface label in filter rules (#2577)
1.8
* Empty port in Endpoint is allowed
1.7
* Make tunnel address (wg interface address) optional
1.6
* Move DNS setting to advanced
* Make listen port optional
1.5
* Allow synchronization of config
1.4
* Add IPv6 gateway support (contributed by Alexander Korinek)
1.3
* Client/peer name validation to use HostnameField
1.2
* Dashboard widget (contributed by D. Domig)
1.1
* Allow adding interface route for PBR
1.0
* Support for most features like S2S, Roadwarrior
* DNS, MTU, PSK
* Allow to disable setting routes for PBR

View File

@ -1,110 +0,0 @@
<?php
/*
* Copyright (C) 2018 Michael Muenz <m.muenz@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
function wireguard_enabled()
{
$model = new \OPNsense\Wireguard\General();
return (string)$model->enabled == '1';
}
function wireguard_services()
{
$services = [];
if (!wireguard_enabled()) {
return $services;
}
$service = [
'description' => gettext('WireGuard VPN'),
'configd' => [
'restart' => ['wireguard restart'],
'start' => ['wireguard start'],
'stop' => ['wireguard stop'],
],
'name' => 'wireguard-go',
];
$services[] = $service;
return $services;
}
function wireguard_interfaces()
{
$interfaces = [];
if (!wireguard_enabled()) {
return $interfaces;
}
$interfaces['wireguard'] = [
'descr' => gettext('WireGuard (Group)'),
'if' => 'wireguard',
'virtual' => true,
'enable' => true,
'type' => 'group',
'networks' => [],
];
return $interfaces;
}
function wireguard_xmlrpc_sync()
{
$result = [];
$result['id'] = 'wireguard';
$result['section'] = 'OPNsense.wireguard';
$result['description'] = gettext('WireGuard');
$result['services'] = ['wireguard-go'];
return [$result];
}
function wireguard_devices()
{
$names = [];
foreach ((new OPNsense\Wireguard\Server())->servers->server->iterateItems() as $key => $node) {
if (!empty((string)$node->enabled)) {
$device = 'wg' . $node->instance;
$names[$device] = [
'descr' => sprintf('%s (WireGuard - %s)', $device, (string)$node->name),
'ifdescr' => (string)$node->name,
'name' => $device,
];
}
}
return [[
'configurable' => false,
'pattern' => '^wg',
'type' => 'wireguard',
'volatile' => true,
'names' => $names,
]];
}

View File

@ -1,4 +0,0 @@
#!/bin/sh
# start again to fix problems with failed name resolution (no need to restart)
configctl -dq wireguard start

View File

@ -1,70 +0,0 @@
<?php
/**
* Copyright (C) 2018 Michael Muenz <m.muenz@gmail.com>
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
namespace OPNsense\Wireguard\Api;
use OPNsense\Base\ApiMutableModelControllerBase;
class ClientController extends ApiMutableModelControllerBase
{
protected static $internalModelName = 'client';
protected static $internalModelClass = '\OPNsense\Wireguard\Client';
public function searchClientAction()
{
return $this->searchBase('clients.client', array("enabled", "name", "pubkey", "tunneladdress", "serveraddress", "serverport"));
}
public function getClientAction($uuid = null)
{
$this->sessionClose();
return $this->getBase('client', 'clients.client', $uuid);
}
public function addClientAction()
{
return $this->addBase('client', 'clients.client');
}
public function delClientAction($uuid)
{
return $this->delBase('clients.client', $uuid);
}
public function setClientAction($uuid)
{
return $this->setBase('client', 'clients.client', $uuid);
}
public function toggleClientAction($uuid)
{
return $this->toggleBase('clients.client', $uuid);
}
}

View File

@ -1,138 +0,0 @@
<?php
/**
* Copyright (C) 2018 Michael Muenz <m.muenz@gmail.com>
* Copyright (C) 2022 Patrik Kernstock <patrik@kernstock.net>
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
namespace OPNsense\Wireguard\Api;
use OPNsense\Base\ApiMutableModelControllerBase;
use OPNsense\Core\Config;
use OPNsense\Core\Backend;
class GeneralController extends ApiMutableModelControllerBase
{
protected static $internalModelClass = '\OPNsense\Wireguard\General';
protected static $internalModelName = 'general';
public function getStatusAction()
{
// get wireguard configuration
$config = Config::getInstance()->object();
$config = $config->OPNsense->wireguard;
// craft peers array
$peers = [];
$peers_uuid_pubkey = [];
// enabled, name, pubkey
foreach ($config->client->clients->client as $client) {
$peerUuid = (string)$client->attributes()['uuid'];
$peers_uuid_pubkey[$peerUuid] = (string) $client->pubkey;
$peers[$peerUuid] = [
"name" => (string) $client->name,
"enabled" => (int) $client->enabled,
"publicKey" => (string) $client->pubkey,
];
}
// prepare and initialize the server array
$status = [];
$peer_pubkey_reference = [];
foreach ($config->server->servers->server as $server) {
if ($server->enabled != "1") {
continue;
}
// build basic server array
$interface = "wg" . $server->instance;
$status[$interface] = [
"instance" => (int) $server->instance,
"interface" => (string) $interface,
"enabled" => (int) $server->enabled,
"name" => (string) $server->name,
"peers" => [],
];
// parse and add peers with initial values to array
if (strlen($server->peers) > 0) {
// there is at least one peer defined
$serverPeers = explode(",", (string) $server->peers);
// iteriate over each peer uuid
foreach ($serverPeers as $peerUuid) {
// skipping removed peer that is still referenced in server
if (!isset($peers[$peerUuid])) {
continue;
}
// remember interface and pubkey <> peer-uuid reference for referencing handshake logic below
$peer_pubkey_reference[$interface][$peers_uuid_pubkey[$peerUuid]] = $peerUuid;
// merge peer info and initial values for handshake data
$status[$interface]["peers"][$peerUuid] = array_merge(
$peers[$peerUuid],
[
"lastHandshake" => "0000-00-00 00:00:00+00:00",
]
);
}
}
}
// Get latest handshakes by running CLI command locally
$data = (new Backend())->configdRun("wireguard showhandshake");
// parse and set handshake to status datastructure
$data = trim($data);
if (strlen($data) !== 0) {
$wgHandshakes = explode("\n", $data);
foreach ($wgHandshakes as $handshake) {
$item = explode("\t", trim($handshake));
// set interface name and publickey
$interface = trim($item[0]);
$pubkey = trim($item[1]);
// calculate handshake time based on local timezone
$epoch = $item[2];
if ($epoch > 0) {
$dt = new \DateTime("@$epoch");
$dt->setTimezone(new \DateTimeZone(date_default_timezone_get()));
$latest = $dt->format("Y-m-d H:i:sP");
// set handshake
$peerUuid = $peer_pubkey_reference[$interface][$pubkey];
if (!empty($peerUuid)) {
$status[$interface]["peers"][$peerUuid]["lastHandshake"] = $latest;
}
}
}
}
return [
"items" => $status
];
}
}

View File

@ -1,108 +0,0 @@
<?php
/*
* Copyright (C) 2018 Michael Muenz <m.muenz@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
namespace OPNsense\Wireguard\Api;
use OPNsense\Base\ApiMutableModelControllerBase;
use OPNsense\Core\Backend;
class ServerController extends ApiMutableModelControllerBase
{
protected static $internalModelName = 'server';
protected static $internalModelClass = '\OPNsense\Wireguard\Server';
public function searchServerAction()
{
$search = $this->searchBase('servers.server', array("enabled", "instance", "peers", "name", "networks", "pubkey", "port", "tunneladdress"));
// prepend "wg" to all instance IDs to use as interface name
foreach ($search["rows"] as $key => $server) {
$search["rows"][$key]["interface"] = "wg" . $server["instance"];
}
return $search;
}
public function getServerAction($uuid = null)
{
$this->sessionClose();
return $this->getBase('server', 'servers.server', $uuid);
}
public function addServerAction($uuid = null)
{
if ($this->request->isPost() && $this->request->hasPost("server")) {
if ($uuid != null) {
$node = $this->getModel()->getNodeByReference('servers.server.' . $uuid);
} else {
$node = $this->getModel()->servers->server->Add();
}
$node->setNodes($this->request->getPost("server"));
if (empty((string)$node->pubkey) && empty((string)$node->privkey)) {
// generate new keypair
$backend = new Backend();
$keyspriv = $backend->configdpRun("wireguard genkey", 'private');
$keyspub = $backend->configdpRun("wireguard genkey", 'public');
$node->privkey = trim($keyspriv);
$node->pubkey = trim($keyspub);
}
return $this->validateAndSave($node, 'server');
}
return array("result" => "failed");
}
public function delServerAction($uuid)
{
return $this->delBase('servers.server', $uuid);
}
public function setServerAction($uuid = null)
{
if ($this->request->isPost() && $this->request->hasPost("server")) {
if ($uuid != null) {
$node = $this->getModel()->getNodeByReference('servers.server.' . $uuid);
} else {
$node = $this->getModel()->servers->server->Add();
}
$node->setNodes($this->request->getPost("server"));
if (empty((string)$node->pubkey) && empty((string)$node->privkey)) {
// generate new keypair
$backend = new Backend();
$keyspriv = $backend->configdpRun("wireguard genkey", 'private');
$keyspub = $backend->configdpRun("wireguard genkey", 'public');
$node->privkey = trim($keyspriv);
$node->pubkey = trim($keyspub);
}
return $this->validateAndSave($node, 'server');
}
return array("result" => "failed");
}
public function toggleServerAction($uuid)
{
return $this->toggleBase('servers.server', $uuid);
}
}

View File

@ -1,76 +0,0 @@
<?php
/*
* Copyright (C) 2018 Michael Muenz <m.muenz@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
namespace OPNsense\Wireguard\Api;
use OPNsense\Base\ApiMutableServiceControllerBase;
use OPNsense\Core\Backend;
use OPNsense\Wireguard\General;
/**
* Class ServiceController
* @package OPNsense\Wireguard
*/
class ServiceController extends ApiMutableServiceControllerBase
{
protected static $internalServiceClass = '\OPNsense\Wireguard\General';
protected static $internalServiceTemplate = 'OPNsense/Wireguard';
protected static $internalServiceEnabled = 'enabled';
protected static $internalServiceName = 'wireguard';
/**
* hook group interface registration on reconfigure
* @return bool
*/
protected function invokeInterfaceRegistration()
{
return true;
}
/**
* show wireguard config
* @return array
*/
public function showconfAction()
{
$backend = new Backend();
$response = $backend->configdRun("wireguard showconf");
return array("response" => $response);
}
/**
* show wireguard handshakes
* @return array
*/
public function showhandshakeAction()
{
$backend = new Backend();
$response = $backend->configdRun("wireguard showhandshake");
return array("response" => $response);
}
}

View File

@ -1,40 +0,0 @@
<?php
/*
Copyright (C) 2018 Michael Muenz <m.muenz@gmail.com>
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
namespace OPNsense\Wireguard;
class GeneralController extends \OPNsense\Base\IndexController
{
public function indexAction()
{
$this->view->generalForm = $this->getForm("general");
$this->view->formDialogEditWireguardClient = $this->getForm("dialogEditWireguardClient");
$this->view->formDialogEditWireguardServer = $this->getForm("dialogEditWireguardServer");
$this->view->pick('OPNsense/Wireguard/general');
}
}

View File

@ -1,52 +0,0 @@
<form>
<field>
<id>client.enabled</id>
<label>Enabled</label>
<type>checkbox</type>
<help>This will enable or disable the client config.</help>
</field>
<field>
<id>client.name</id>
<label>Name</label>
<type>text</type>
<help>Set the name for this instance.</help>
</field>
<field>
<id>client.pubkey</id>
<label>Public Key</label>
<type>text</type>
<help>Public key of this instance.</help>
</field>
<field>
<id>client.psk</id>
<label>Shared Secret</label>
<type>text</type>
<help>Shared secret (PSK) for this peer. You can generate a key using "wg genpsk" on a client with WireGuard installed.</help>
</field>
<field>
<id>client.tunneladdress</id>
<label>Allowed IPs</label>
<style>tokenize</style>
<type>select_multiple</type>
<allownew>true</allownew>
<help>List of addresses allowed to pass trough the tunnel adapter. Please use CIDR notation like 10.0.0.1/24.</help>
</field>
<field>
<id>client.serveraddress</id>
<label>Endpoint Address</label>
<type>text</type>
<help>Set public IP address the endpoint listens to.</help>
</field>
<field>
<id>client.serverport</id>
<label>Endpoint Port</label>
<type>text</type>
<help>Set port the endpoint listens to.</help>
</field>
<field>
<id>client.keepalive</id>
<label>Keepalive Interval</label>
<type>text</type>
<help>Set persistent keepalive interval in seconds.</help>
</field>
</form>

View File

@ -1,82 +0,0 @@
<form>
<field>
<id>server.enabled</id>
<label>Enabled</label>
<type>checkbox</type>
<help>This will enable or disable the server config.</help>
</field>
<field>
<id>server.name</id>
<label>Name</label>
<type>text</type>
<help>Set the name for this instance.</help>
</field>
<field>
<id>server.instance</id>
<label>Instance</label>
<type>info</type>
<help>This is the instance number to give the wg interface a unique name (wgX).</help>
</field>
<field>
<id>server.pubkey</id>
<label>Public Key</label>
<type>text</type>
<help>Public key of this instance. You can specify your own one, or a key will be generated after saving.</help>
</field>
<field>
<id>server.privkey</id>
<label>Private Key</label>
<type>text</type>
<help>Private key of this instance. You can specify your own one, or a key will be generated after saving. Please keep this key safe.</help>
</field>
<field>
<id>server.port</id>
<label>Listen Port</label>
<type>text</type>
<help>Optionally set a fixed port for this instance to listen on. The standard port range starts at 51820.</help>
</field>
<field>
<id>server.mtu</id>
<label>MTU</label>
<type>text</type>
<advanced>true</advanced>
<help>Set the interface MTU for this interface. Leaving empty uses the MTU from main interface which is fine for most setups.</help>
</field>
<field>
<id>server.dns</id>
<label>DNS Server</label>
<type>select_multiple</type>
<style>tokenize</style>
<allownew>true</allownew>
<advanced>true</advanced>
<help>Set the interface specific DNS server.</help>
</field>
<field>
<id>server.tunneladdress</id>
<label>Tunnel Address</label>
<style>tokenize</style>
<type>select_multiple</type>
<allownew>true</allownew>
<help>List of addresses to configure on the tunnel adapter. Please use CIDR notation like 10.0.0.1/24.</help>
</field>
<field>
<id>server.peers</id>
<label>Peers</label>
<type>select_multiple</type>
<allownew>true</allownew>
<help>List of peers for this server.</help>
</field>
<field>
<id>server.disableroutes</id>
<label>Disable Routes</label>
<type>checkbox</type>
<help>This will prevent installing routes. Usually you only enable this to do own routing decisions via a local gateway and gateway rules.</help>
</field>
<field>
<id>server.gateway</id>
<label>Gateway</label>
<type>text</type>
<advanced>true</advanced>
<help>Set the gateway IP here when using Disable Routes feature. You also have to add this as a gateway in OPNsense.</help>
</field>
</form>

View File

@ -1,8 +0,0 @@
<form>
<field>
<id>general.enabled</id>
<label>Enable WireGuard</label>
<type>checkbox</type>
<help>This will activate WireGuard and start all enabled instances.</help>
</field>
</form>

View File

@ -1,9 +0,0 @@
<acl>
<page-wireguard-config>
<name>VPN: Wireguard</name>
<patterns>
<pattern>ui/wireguard/*</pattern>
<pattern>api/wireguard/*</pattern>
</patterns>
</page-wireguard-config>
</acl>

View File

@ -1,31 +0,0 @@
<?php
/*
Copyright (C) 2018 Michael Muenz <m.muenz@gmail.com>
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
namespace OPNsense\Wireguard;
use OPNsense\Base\BaseModel;
class Client extends BaseModel
{
}

View File

@ -1,47 +0,0 @@
<model>
<mount>//OPNsense/wireguard/client</mount>
<description>Wireguard Client configuration</description>
<version>0.0.7</version>
<items>
<clients>
<client type="ArrayField">
<enabled type="BooleanField">
<default>1</default>
<Required>Y</Required>
</enabled>
<name type="TextField">
<default></default>
<Required>Y</Required>
<mask>/^([0-9a-zA-Z._\-]){1,64}$/u</mask>
<ValidationMessage>Should be a string between 1 and 64 characters. Allowed characters are alphanumeric characters, dash and underscores.</ValidationMessage>
</name>
<pubkey type="Base64Field">
<Required>Y</Required>
<ValidationMessage>Should be a base64-encoded 32 byte string.</ValidationMessage>
</pubkey>
<psk type="Base64Field">
<Required>N</Required>
<ValidationMessage>Should be a base64-encoded 32 byte string.</ValidationMessage>
</psk>
<tunneladdress type="NetworkField">
<default></default>
<FieldSeparator>,</FieldSeparator>
<Required>Y</Required>
<asList>Y</asList>
</tunneladdress>
<serveraddress type="HostnameField">
<Required>N</Required>
</serveraddress>
<serverport type="PortField">
<Required>N</Required>
</serverport>
<keepalive type="IntegerField">
<MinimumValue>1</MinimumValue>
<MaximumValue>86400</MaximumValue>
<ValidationMessage>Please specify a value between 1 and 86400.</ValidationMessage>
<Required>N</Required>
</keepalive>
</client>
</clients>
</items>
</model>

View File

@ -1,35 +0,0 @@
<?php
/*
Copyright (C) 2018 Michael Muenz <m.muenz@gmail.com>
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
namespace OPNsense\Wireguard;
use OPNsense\Base\BaseModel;
class General extends BaseModel
{
}

View File

@ -1,11 +0,0 @@
<model>
<mount>//OPNsense/wireguard/general</mount>
<description>WireGuard configuration</description>
<version>0.0.1</version>
<items>
<enabled type="BooleanField">
<default>0</default>
<Required>Y</Required>
</enabled>
</items>
</model>

View File

@ -1,5 +0,0 @@
<menu>
<VPN>
<WireGuard cssClass="fa fa-lock fa-fw" url="/ui/wireguard/general/index" order="150" />
</VPN>
</menu>

View File

@ -1,31 +0,0 @@
<?php
/*
Copyright (C) 2018 Michael Muenz <m.muenz@gmail.com>
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
namespace OPNsense\Wireguard;
use OPNsense\Base\BaseModel;
class Server extends BaseModel
{
}

View File

@ -1,77 +0,0 @@
<model>
<mount>//OPNsense/wireguard/server</mount>
<description>Wireguard Server configuration</description>
<version>0.0.4</version>
<items>
<servers>
<server type="ArrayField">
<enabled type="BooleanField">
<default>1</default>
<Required>Y</Required>
</enabled>
<name type="TextField">
<default></default>
<Required>Y</Required>
<mask>/^([0-9a-zA-Z._\-]){1,64}$/u</mask>
<ValidationMessage>Should be a string between 1 and 64 characters. Allowed characters are alphanumeric characters, dash and underscores.</ValidationMessage>
</name>
<instance type="AutoNumberField">
<Required>Y</Required>
</instance>
<pubkey type="TextField">
<Required>N</Required>
</pubkey>
<privkey type="TextField">
<Required>N</Required>
</privkey>
<port type="PortField">
<Required>N</Required>
</port>
<mtu type="IntegerField">
<MinimumValue>1</MinimumValue>
<MaximumValue>9300</MaximumValue>
<Required>N</Required>
</mtu>
<dns type="CSVListField">
<Required>N</Required>
<mask>/^([a-fA-F0-9\.:\[\]]*?,)*([a-fA-F0-9\.:\[\]]*)$/</mask>
<ValidationMessage>Please use valid IPv4 or IPv6 addresses.</ValidationMessage>
</dns>
<tunneladdress type="NetworkField">
<default></default>
<FieldSeparator>,</FieldSeparator>
<Required>N</Required>
<asList>Y</asList>
</tunneladdress>
<disableroutes type="BooleanField">
<default>0</default>
<Required>Y</Required>
<Constraints>
<check001>
<ValidationMessage>You have to enable Disable Routes option.</ValidationMessage>
<type>DependConstraint</type>
<addFields>
<field1>gateway</field1>
</addFields>
</check001>
</Constraints>
</disableroutes>
<gateway type="NetworkField">
<Required>N</Required>
</gateway>
<peers type="ModelRelationField">
<Model>
<template>
<source>OPNsense.Wireguard.Client</source>
<items>clients.client</items>
<display>name</display>
</template>
</Model>
<Multiple>Y</Multiple>
<Required>N</Required>
<ValidationMessage>Choose an Peer.</ValidationMessage>
</peers>
</server>
</servers>
</items>
</model>

View File

@ -1,199 +0,0 @@
{#
# OPNsense (c) 2014-2018 by Deciso B.V.
# OPNsense (c) 2018 Michael Muenz <m.muenz@gmail.com>
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without modification,
# are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
# AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
# OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#}
<!-- 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="#servers">{{ lang._('Local') }}</a></li>
<li><a data-toggle="tab" href="#clients">{{ lang._('Endpoints') }}</a></li>
<li><a data-toggle="tab" href="#showconf">{{ lang._('Status') }}</a></li>
<li><a data-toggle="tab" href="#showhandshake">{{ lang._('Handshakes') }}</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_general_settings'])}}
<div class="col-md-12">
<hr />
<button class="btn btn-primary" id="saveAct" type="button"><b>{{ lang._('Apply') }}</b> <i id="saveAct_progress"></i></button>
</div>
</div>
</div>
<div id="clients" class="tab-pane fade in">
<table id="grid-clients" class="table table-responsive" data-editDialog="dialogEditWireguardClient">
<thead>
<tr>
<th data-column-id="enabled" data-type="string" data-formatter="rowtoggle">{{ lang._('Enabled') }}</th>
<th data-column-id="name" data-type="string" data-visible="true">{{ lang._('Name') }}</th>
<th data-column-id="serveraddress" data-type="string" data-visible="true">{{ lang._('Endpoint Address') }}</th>
<th data-column-id="serverport" data-type="string" data-visible="true">{{ lang._('Endpoint Port') }}</th>
<th data-column-id="tunneladdress" data-type="string" data-visible="true">{{ lang._('Allowed IPs') }}</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>
</thead>
<tbody>
</tbody>
<tfoot>
<tr>
<td colspan="6"></td>
<td>
<button data-action="add" type="button" class="btn btn-xs btn-default"><span class="fa fa-plus"></span></button>
</td>
</tr>
</tfoot>
</table>
<div class="col-md-12">
<hr />
<button class="btn btn-primary" id="saveAct_client" type="button"><b>{{ lang._('Apply') }}</b> <i id="saveAct_client_progress"></i></button>
<br /><br />
</div>
</div>
<div id="servers" class="tab-pane fade in">
<table id="grid-servers" class="table table-responsive" data-editDialog="dialogEditWireguardServer">
<thead>
<tr>
<th data-column-id="enabled" data-type="string" data-formatter="rowtoggle">{{ lang._('Enabled') }}</th>
<th data-column-id="name" data-type="string" data-visible="true">{{ lang._('Name') }}</th>
<th data-column-id="interface" data-type="string" data-visible="true">{{ lang._('Interface') }}</th>
<th data-column-id="tunneladdress" data-type="string" data-visible="true">{{ lang._('Tunnel Address') }}</th>
<th data-column-id="port" data-type="string" data-visible="true">{{ lang._('Port') }}</th>
<th data-column-id="peers" data-type="string" data-visible="true">{{ lang._('Endpoints') }}</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>
</thead>
<tbody>
</tbody>
<tfoot>
<tr>
<td colspan="7"></td>
<td>
<button data-action="add" type="button" class="btn btn-xs btn-default"><span class="fa fa-plus"></span></button>
</td>
</tr>
</tfoot>
</table>
<div class="col-md-12">
<hr />
<button class="btn btn-primary" id="saveAct_server" type="button"><b>{{ lang._('Apply') }}</b> <i id="saveAct_server_progress"></i></button>
<br /><br />
</div>
</div>
<div id="showconf" class="tab-pane fade in">
<pre id="listshowconf"></pre>
</div>
<div id="showhandshake" class="tab-pane fade in">
<pre id="listshowhandshake"></pre>
</div>
</div>
{{ partial("layout_partials/base_dialog",['fields':formDialogEditWireguardClient,'id':'dialogEditWireguardClient','label':lang._('Edit Endpoint')])}}
{{ partial("layout_partials/base_dialog",['fields':formDialogEditWireguardServer,'id':'dialogEditWireguardServer','label':lang._('Edit Local Configuration')])}}
<script>
// Put API call into a function, needed for auto-refresh
function update_showconf() {
ajaxCall(url="/api/wireguard/service/showconf", sendData={}, callback=function(data,status) {
$("#listshowconf").text(data['response']);
});
}
function update_showhandshake() {
ajaxCall(url="/api/wireguard/service/showhandshake", sendData={}, callback=function(data,status) {
$("#listshowhandshake").text(data['response']);
});
}
$( document ).ready(function() {
var data_get_map = {'frm_general_settings':"/api/wireguard/general/get"};
mapDataToFormUI(data_get_map).done(function(data){
formatTokenizersUI();
$('.selectpicker').selectpicker('refresh');
});
$("#grid-clients").UIBootgrid(
{
'search':'/api/wireguard/client/searchClient',
'get':'/api/wireguard/client/getClient/',
'set':'/api/wireguard/client/setClient/',
'add':'/api/wireguard/client/addClient/',
'del':'/api/wireguard/client/delClient/',
'toggle':'/api/wireguard/client/toggleClient/'
}
);
$("#grid-servers").UIBootgrid(
{
'search':'/api/wireguard/server/searchServer',
'get':'/api/wireguard/server/getServer/',
'set':'/api/wireguard/server/setServer/',
'add':'/api/wireguard/server/addServer/',
'del':'/api/wireguard/server/delServer/',
'toggle':'/api/wireguard/server/toggleServer/'
}
);
// Call update funcs once when page loaded
update_showconf();
update_showhandshake();
// Call function update_neighbor with a auto-refresh of 5 seconds
setInterval(update_showconf, 5000);
setInterval(update_showhandshake, 5000);
$("#saveAct").click(function(){
saveFormToEndpoint(url="/api/wireguard/general/set", formid='frm_general_settings',callback_ok=function(){
$("#saveAct_progress").addClass("fa fa-spinner fa-pulse");
ajaxCall(url="/api/wireguard/service/reconfigure", sendData={}, callback=function(data,status) {
$("#saveAct_progress").removeClass("fa fa-spinner fa-pulse");
});
});
});
$("#saveAct_client").click(function(){
saveFormToEndpoint(url="/api/wireguard/client/set", formid='frm_general_settings',callback_ok=function(){
$("#saveAct_client_progress").addClass("fa fa-spinner fa-pulse");
ajaxCall(url="/api/wireguard/service/reconfigure", sendData={}, callback=function(data,status) {
$("#saveAct_client_progress").removeClass("fa fa-spinner fa-pulse");
});
});
});
$("#saveAct_server").click(function(){
saveFormToEndpoint(url="/api/wireguard/server/set", formid='frm_general_settings',callback_ok=function(){
$("#saveAct_server_progress").addClass("fa fa-spinner fa-pulse");
ajaxCall(url="/api/wireguard/service/reconfigure", sendData={}, callback=function(data,status) {
$("#saveAct_server_progress").removeClass("fa fa-spinner fa-pulse");
});
});
});
});
</script>

View File

@ -1,55 +0,0 @@
#!/bin/sh
# Copyright (c) 2018 Michael Muenz <m.muenz@gmail.com>
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
TMPDIR="/tmp"
GENPRIV="/usr/local/bin/wg genkey"
GENPUB="/usr/local/bin/wg pubkey"
cleanup() {
# Delete old files
rm -f $TMPDIR/wireguard.*
}
private() {
# Generate a private key and put it to /tmp
umask 077 && ${GENPRIV} | tee ${TMPDIR}/wireguard.priv
}
public() {
# Generate a public key and put it to /tmp
${GENPUB} < ${TMPDIR}/wireguard.priv | tee ${TMPDIR}/wireguard.pub
}
case "$1" in
private)
cleanup
private
;;
public)
public
;;
esac

View File

@ -1,11 +0,0 @@
#!/bin/sh
if [ -f /etc/rc.conf.d/wireguard ]; then
. /etc/rc.conf.d/wireguard
fi
for interface in ${wireguard_interfaces}; do
ifconfig ${interface} group wireguard
done
/usr/local/etc/rc.routing_configure

View File

@ -1,45 +0,0 @@
#!/usr/local/bin/bash
# SPDX-License-Identifier: GPL-2.0
#
# Copyright (C) 2015-2020 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
set -e
shopt -s nocasematch
shopt -s extglob
export LC_ALL=C
for CONFIG_FILE in /usr/local/etc/wireguard/*.conf; do
[[ $CONFIG_FILE =~ /?([a-zA-Z0-9_=+.-]{1,15})\.conf$ ]]
INTERFACE="${BASH_REMATCH[1]}"
process_peer() {
[[ $PEER_SECTION -ne 1 || -z $PUBLIC_KEY || -z $ENDPOINT ]] && return 0
[[ $(wg show "$INTERFACE" latest-handshakes) =~ ${PUBLIC_KEY//+/\\+}\ ([0-9]+) ]] || return 0
(( ($EPOCHSECONDS - ${BASH_REMATCH[1]}) > 135 )) || return 0
wg set "$INTERFACE" peer "$PUBLIC_KEY" endpoint "$ENDPOINT"
reset_peer_section
}
reset_peer_section() {
PEER_SECTION=0
PUBLIC_KEY=""
ENDPOINT=""
}
reset_peer_section
while read -r line || [[ -n $line ]]; do
stripped="${line%%\#*}"
key="${stripped%%=*}"; key="${key##*([[:space:]])}"; key="${key%%*([[:space:]])}"
value="${stripped#*=}"; value="${value##*([[:space:]])}"; value="${value%%*([[:space:]])}"
[[ $key == "["* ]] && { process_peer; reset_peer_section; }
[[ $key == "[Peer]" ]] && PEER_SECTION=1
if [[ $PEER_SECTION -eq 1 ]]; then
case "$key" in
PublicKey) PUBLIC_KEY="$value"; continue ;;
Endpoint) ENDPOINT="$value"; continue ;;
esac
fi
done < "$CONFIG_FILE"
process_peer
done

View File

@ -1,4 +0,0 @@
#!/bin/sh
mkdir -p /var/run/wireguard
chmod 755 /var/run/wireguard

View File

@ -1,43 +0,0 @@
[start]
command:/usr/local/etc/rc.d/wireguard start; /usr/local/opnsense/scripts/OPNsense/Wireguard/post.sh
parameters:
type:script
message:Starting WireGuard
[stop]
command:/usr/local/etc/rc.d/wireguard stop
parameters:
type:script
message:Stopping WireGuard
[restart]
command:/usr/local/etc/rc.d/wireguard restart; /usr/local/opnsense/scripts/OPNsense/Wireguard/post.sh
parameters:
type:script
message:Restarting WireGuard
description: Restart WireGuard
[renew]
command:/usr/local/opnsense/scripts/OPNsense/Wireguard/resolve-dns.bash
parameters:
type:script
message:Renew DNS for WireGuard
description:Renew DNS for WireGuard on stale connections
[genkey]
command:/usr/local/opnsense/scripts/OPNsense/Wireguard/genkey.sh
parameters: %s
type:script_output
message:Generating WireGuard keys
[showconf]
command:/usr/local/bin/wg show all
parameters:
type:script_output
message:Show WireGuard config
[showhandshake]
command:/usr/local/bin/wg show all latest-handshakes
parameters:
type:script_output
message:Show WireGuard handshakes

View File

@ -1,2 +0,0 @@
wireguard:/etc/rc.conf.d/wireguard
wireguard-server.conf:/usr/local/etc/wireguard/wg[OPNsense.wireguard.server.servers.server.%.instance].conf

View File

@ -1,15 +0,0 @@
{% if helpers.exists('OPNsense.wireguard.general.enabled') and OPNsense.wireguard.general.enabled == '1' %}
wireguard_setup="/usr/local/opnsense/scripts/OPNsense/Wireguard/setup.sh"
wireguard_enable="YES"
{% if helpers.exists('OPNsense.wireguard.server.servers.server') %}
{% set activeservers=[] %}
{% for servers in helpers.toList('OPNsense.wireguard.server.servers.server') %}
{% if servers.enabled == '1' %}
{% do activeservers.append("wg" + servers.instance) %}
{% endif %}
{% endfor %}
{% endif %}
wireguard_interfaces="{{ activeservers | join(' ') }}"
{% else %}
wireguard_enable="NO"
{% endif %}

View File

@ -1,53 +0,0 @@
{% if helpers.exists('OPNsense.wireguard.general.enabled') and OPNsense.wireguard.general.enabled == '1' %}
{% if helpers.exists('OPNsense.wireguard.server.servers.server') %}
{% for server_list in helpers.toList('OPNsense.wireguard.server.servers.server') %}
{% if TARGET_FILTERS['OPNsense.wireguard.server.servers.server.' ~ loop.index0] or TARGET_FILTERS['OPNsense.wireguard.server.servers.server'] %}
{% if server_list.enabled == '1' %}
[Interface]
PrivateKey = {{ server_list.privkey }}
{% if server_list.tunneladdress|default('') != '' %}
Address = {{ server_list.tunneladdress }}
{% endif %}
{% if server_list.port|default('') != '' %}
ListenPort = {{ server_list.port }}
{% endif %}
{% if server_list.dns|default('') != '' %}
DNS = {{ server_list.dns }}
{% endif %}
{% if server_list.mtu|default('') != '' %}
MTU = {{ server_list.mtu }}
{% endif %}
{% if server_list.disableroutes == '1' %}
Table = off
{% endif %}
{% if server_list.disableroutes == '1' and server_list.gateway|default('') != '' %}
PostUp = route {{- ' -6' if ':' in server_list.gateway }} add {{ server_list.gateway }} -iface %i
PostDown = route {{- ' -6' if ':' in server_list.gateway }} del {{ server_list.gateway }} -iface %i
{% endif %}
{% if server_list.peers|default('') != '' %}
{% for peerlist in server_list.peers.split(",") %}
{% set peerlist2_data = helpers.getUUID(peerlist) %}
{% if peerlist2_data != {} and peerlist2_data.enabled == '1' %}
[Peer]
# friendly_name = {{ peerlist2_data.name }}
PublicKey = {{ peerlist2_data.pubkey }}
{% if peerlist2_data.psk|default('') != '' %}
PresharedKey = {{ peerlist2_data.psk }}
{% endif %}
{% if peerlist2_data.serveraddress|default('') != '' %}
Endpoint = {{ peerlist2_data.serveraddress }}{% if peerlist2_data.serverport|default('') != '' %}:{{ peerlist2_data.serverport }}{% else %}:51820{% endif %}
{% endif %}
AllowedIPs = {{ peerlist2_data.tunneladdress }}
{% if peerlist2_data.keepalive|default('') != '' %}
PersistentKeepalive = {{ peerlist2_data.keepalive }}
{% endif %}
{% endif %}
{% endfor %}
{% endif %}
{% endif %}
{% endif %}
{% endfor %}
{% endif %}
{% endif %}

View File

@ -1,4 +0,0 @@
<?php
$wireguard_title = gettext('WireGuard');
$wireguard_title_link = 'ui/wireguard/general/index';

View File

@ -1,120 +0,0 @@
<?php
/*
* Copyright (C) 2020 Deciso B.V.
* Copyright (C) 2020 D. Domig
* Copyright (C) 2022 Patrik Kernstock <patrik@kernstock.net>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
require_once("guiconfig.inc");
require_once("widgets/include/wireguard.inc");
$enabled = ($config["OPNsense"]["wireguard"]["general"]["enabled"] === "1" ? true : false);
?>
<table class="table table-striped table-condensed">
<thead>
<tr>
<th><?= gettext("Name") ?></th>
<th><?= gettext("Interface") ?></th>
<th><?= gettext("Endpoint") ?></th>
<th><?= gettext("Public Key") ?></th>
<th><?= gettext("Latest Handshake") ?></th>
</tr>
</thead>
<tbody id="wg-table-tbody">
<?php if (!$enabled): ?>
<tr>
<td colspan="5"><?= gettext("No WireGuard instance defined or enabled.") ?></td>
</tr>
<?php endif; ?>
</tbody>
</table>
<script>
$(window).on("load", function() {
function wgGenerateRow(name, interface, peerName, publicKey, latestHandshake, status)
{
var tr = ''
+'<tr>'
+' <td>' + name + '</td>'
+' <td>' + interface + '</td>'
+' <td>' + peerName + '</td>'
+' <td style="overflow: hidden; text-overflow: ellipsis;" title="' + publicKey + '">' + publicKey + '</td>'
+' <td>' + latestHandshake + '</td>'
+'</tr>';
return tr;
}
function wgUpdateStatusIf(obj)
{
// check if at least one peer is set. If not, ignore it.
if (Object.keys(obj.peers).length == 0) {
return '';
}
// generate row based on data
row = '';
for (var peerId in obj.peers) {
var peer = obj.peers[peerId];
// generate table row
row += wgGenerateRow(
obj.name,
obj.interface,
peer.name,
peer.publicKey,
peer.lastHandshake,
status
);
}
return row;
}
function wgUpdateStatus()
{
var table = '';
ajaxGet("/api/wireguard/general/getStatus", {}, function(data, status) {
if (status === 'success') {
for (var interface in data.items) {
table += wgUpdateStatusIf(data.items[interface]);
}
}
// update table accordingly
document.getElementById("wg-table-tbody").innerHTML = table;
setTimeout(wgUpdateStatus, 10000);
});
};
<?php if ($enabled): ?>
wgUpdateStatus();
<?php endif; ?>
});
</script>

View File

@ -1,9 +0,0 @@
PLUGIN_NAME= wireguard
PLUGIN_VERSION= 2.6
PLUGIN_COMMENT= WireGuard VPN service kernel implementation
PLUGIN_DEPENDS= wireguard-kmod
PLUGIN_CONFLICTS= wireguard-go
PLUGIN_OBSOLETE= yes
PLUGIN_MAINTAINER= ad@opnsense.org
.include "../../Mk/plugins.mk"

View File

@ -1,127 +0,0 @@
WireGuard® is an extremely simple yet fast and modern VPN
that utilizes state-of-the-art cryptography. It aims to be
faster, simpler, leaner, and more useful than IPSec, while
avoiding the massive headache. It intends to be considerably
more performant than OpenVPN. WireGuard is designed as a
general purpose VPN for running on embedded interfaces and
super computers alike, fit for many different circumstances.
Initially released for the Linux kernel, it is now
cross-platform and widely deployable. It is currently under
heavy development, but already it might be regarded as the
most secure, easiest to use, and simplest VPN solution in
the industry.
WWW: https://www.wireguard.com/
Changelog
---------
2.6
* Consider missing CARP VHID as disabled
2.5
* Fix error with empty tunnel address in instance (contributed by Monviech)
* Switch "setconf" to "syncconf" on (re)configuration
* Fix regression of UUID return in setClientAction()
* Reload the packet filter after reconfiguration
* Allow instance selection from peer
* Use "syncconf" on newwanip event
* CARP event handling improvements
* Minor UX and woring improvements
2.4
* Only invoke routes for attached WireGuard instances
* Make bootup device creation more robust
* Correct interface group registration
2.3
* Create WireGuard devices earlier to allow of to pick up NAT rules correctly
* Consolidate the GUI with regard to WireGuard terminology
2.2
* Add VHID (CARP) tracking support
2.1
* Only reload when interface configuration did not change
* Implement 'newwanip' and 'vpn' plugin facilities
* Refactor dashboard widget
2.0
* Remove wireguard-go support and cleanup some go specific code as it's not being used anymore anyway
* Service control handler similar to OpenVPN, which offers control per instance/interface and keeps track of changed interfaces (configure only restarts the changed ones).
* Add some basic logging for the service handling and a view to inspect it.
* Configuration logs are being flushed to the correct log automatically as mwexecf() sends errors to syslog (which in this scope sends to wireguard)
* Reimplement https://github.com/WireGuard/wireguard-tools/tree/master/contrib/reresolve-dns using Python in reresolve-dns.py
* Enforce wireguard-tools rc script to be disabled when still installed, this should prevent bootup issues
* Move 'interface' calculated field to model for easy reusability
* Move diagnostics to VPN: WireGuard: Diagnostics
* Change keypair generation to a separate API call and form button to ease copy/paste when adding new servers.
* Change plugin maintainer
1.13
* Reworked widget and assorted cleanups (contributed by Patrik Kernstock)
* Improve widget public key overlapping (contributed by Victor Haggqvist)
1.12
* Adjust validation for naming local instance and endpoints
1.11
* Add script for renewal of Wireguard DNS-based entries for stale connections (#2956)
* Trim whitespace around new public and private keys in config (#2982)
1.10
* Remove instance limit
1.9
* Rename interface label in filter rules (#2577)
1.8
* Empty port in Endpoint is allowed
1.7
* Make tunnel address (wg interface address) optional
1.6
* Move DNS setting to advanced
* Make listen port optional
1.5
* Allow synchronization of config
1.4
* Add IPv6 gateway support (contributed by Alexander Korinek)
1.3
* Client/peer name validation to use HostnameField
1.2
* Dashboard widget (contributed by D. Domig)
1.1
* Allow adding interface route for PBR
1.0
* Support for most features like S2S, Roadwarrior
* DNS, MTU, PSK
* Allow to disable setting routes for PBR

View File

@ -1,194 +0,0 @@
<?php
/*
* Copyright (C) 2023 Deciso B.V.
* Copyright (C) 2018 Michael Muenz <m.muenz@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
function wireguard_enabled()
{
return (string)(new \OPNsense\Wireguard\General())->enabled == '1';
}
function wireguard_services()
{
$services = [];
if (!wireguard_enabled()) {
return $services;
}
foreach ((new OPNsense\Wireguard\Server())->servers->server->iterateItems() as $key => $node) {
if (!empty((string)$node->enabled)) {
$services[] = [
'description' => 'WireGuard ' . htmlspecialchars($node->name),
'configd' => [
'start' => ["wireguard start {$key}"],
'restart' => ["wireguard restart {$key}"],
'stop' => ["wireguard stop {$key}"],
],
'nocheck' => true, /* no daemon to check */
'id' => $key,
'name' => "wireguard"
];
}
}
return $services;
}
function wireguard_syslog()
{
return [
'wireguard' => ['facility' => ['wireguard']]
];
}
function wireguard_interfaces()
{
$interfaces = [];
if (!wireguard_enabled()) {
return $interfaces;
}
$interfaces['wireguard'] = [
'descr' => gettext('WireGuard (Group)'),
'if' => 'wireguard',
'virtual' => true,
'enable' => true,
'type' => 'group',
'networks' => [],
];
return $interfaces;
}
function wireguard_xmlrpc_sync()
{
$result = [];
$result['id'] = 'wireguard';
$result['section'] = 'OPNsense.wireguard';
$result['description'] = gettext('WireGuard');
$result['services'] = ['wireguard'];
return [$result];
}
function wireguard_devices()
{
$names = [];
foreach ((new OPNsense\Wireguard\Server())->servers->server->iterateItems() as $key => $node) {
if (!empty((string)$node->enabled)) {
$names[(string)$node->interface] = [
'descr' => sprintf('%s (WireGuard - %s)', (string)$node->interface, (string)$node->name),
'ifdescr' => (string)$node->name,
'name' => (string)$node->interface
];
}
}
return [[
'function' => 'wireguard_prepare', /* XXX only (empty) device creation */
'configurable' => false,
'pattern' => '^wg',
'type' => 'wireguard',
'volatile' => true,
'names' => $names,
]];
}
function wireguard_prepare($device)
{
foreach ((new OPNsense\Wireguard\Server())->servers->server->iterateItems() as $node) {
if ($device != (string)$node->interface) {
continue;
}
/* deleting the stat file marks the interface for eventual reconfiguration */
@unlink((string)$node->statFilename);
if (!does_interface_exist($device)) {
mwexecf('/sbin/ifconfig wg create name %s', $device);
mwexecf('/sbin/ifconfig %s group wireguard', $device);
}
return $device;
}
return null;
}
function wireguard_configure()
{
return [
'newwanip' => ['wireguard_sync:2'],
'vpn' => ['wireguard_configure_do:2'],
];
}
function wireguard_configure_do($verbose = false, $unused = '')
{
if (!wireguard_enabled()) {
return;
}
service_log('Configuring WireGuard VPN...', $verbose);
configd_run('wireguard configure');
service_log("done.\n", $verbose);
}
function wireguard_sync($verbose = false, $unused = '')
{
if (!wireguard_enabled()) {
return;
}
$instances = [];
foreach ((new OPNsense\Wireguard\Server())->servers->server->iterateItems() as $node) {
if (!empty((string)$node->enabled)) {
$instances[(string)$node->interface] = (string)$node->cnfFilename;
}
}
if (!count($instances)) {
return;
}
service_log('Synchronizing WireGuard VPN...', $verbose);
openlog('wireguard', LOG_ODELAY, LOG_AUTH);
foreach ($instances as $device => $config) {
mwexecf('/usr/bin/wg syncconf %s %s', [$device, $config]);
}
closelog();
reopenlog();
service_log("done.\n", $verbose);
}

View File

@ -1,3 +0,0 @@
#!/bin/sh
configctl -dq wireguard configure $1

View File

@ -1,115 +0,0 @@
<?php
/*
* Copyright (C) 2023 Deciso B.V.
* Copyright (C) 2018 Michael Muenz <m.muenz@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
namespace OPNsense\Wireguard\Api;
use OPNsense\Base\ApiMutableModelControllerBase;
use OPNsense\Core\Config;
use OPNsense\Wireguard\Server;
class ClientController extends ApiMutableModelControllerBase
{
protected static $internalModelName = 'client';
protected static $internalModelClass = '\OPNsense\Wireguard\Client';
public function searchClientAction()
{
return $this->searchBase(
'clients.client',
["enabled", "name", "pubkey", "tunneladdress", "serveraddress", "serverport"]
);
}
public function getClientAction($uuid = null)
{
$result = $this->getBase('client', 'clients.client', $uuid);
if (!empty($result['client'])) {
$result['client']['servers'] = [];
foreach ((new Server())->servers->server->iterateItems() as $key => $node) {
$result['client']['servers'][$key] = [
'value' => (string)$node->name,
'selected' => in_array($uuid, explode(',', (string)$node->peers)) ? '1' : '0'
];
}
}
return $result;
}
public function addClientAction()
{
return $this->setClientAction(null);
}
public function delClientAction($uuid)
{
return $this->delBase('clients.client', $uuid);
}
public function setClientAction($uuid)
{
$add_uuid = null;
if (!empty($this->request->getPost(static::$internalModelName)) && $this->request->isPost()) {
$servers = [];
if (!empty($this->request->getPost(static::$internalModelName)['servers'])) {
$servers = explode(',', $this->request->getPost(static::$internalModelName)['servers']);
}
Config::getInstance()->lock();
$mdl = new Server();
if (empty($uuid)) {
// add new client, generate uuid
$uuid = $mdl->servers->generateUUID();
$add_uuid = $uuid;
}
foreach ($mdl->servers->server->iterateItems() as $key => $node) {
$peers = array_filter(explode(',', (string)$node->peers));
if (in_array($uuid, $peers) && !in_array($key, $servers)) {
$node->peers = implode(',', array_diff($peers, [$uuid]));
} elseif (!in_array($uuid, $peers) && in_array($key, $servers)) {
$node->peers = implode(',', array_merge($peers, [$uuid]));
}
}
/**
* Save to in memory model.
* Ignore validations as $uuid might be new or trigger an existing validation issue.
* Persisting the data is handled by setBase()
*/
$mdl->serializeToConfig(false, true);
}
$result = $this->setBase('client', 'clients.client', $uuid);
if (!empty($add_uuid) && $result['result'] == 'saved') {
$result['uuid'] = $add_uuid;
}
return $result;
}
public function toggleClientAction($uuid)
{
return $this->toggleBase('clients.client', $uuid);
}
}

View File

@ -1,139 +0,0 @@
<?php
/*
* Copyright (C) 2018 Michael Muenz <m.muenz@gmail.com>
* Copyright (C) 2022 Patrik Kernstock <patrik@kernstock.net>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
namespace OPNsense\Wireguard\Api;
use OPNsense\Base\ApiMutableModelControllerBase;
use OPNsense\Core\Config;
use OPNsense\Core\Backend;
class GeneralController extends ApiMutableModelControllerBase
{
protected static $internalModelClass = '\OPNsense\Wireguard\General';
protected static $internalModelName = 'general';
/**
* XXX: remove in 24.1 unused
*/
public function getStatusAction()
{
// get wireguard configuration
$config = Config::getInstance()->object();
$config = $config->OPNsense->wireguard;
// craft peers array
$peers = [];
$peers_uuid_pubkey = [];
// enabled, name, pubkey
foreach ($config->client->clients->client as $client) {
$peerUuid = (string)$client->attributes()['uuid'];
$peers_uuid_pubkey[$peerUuid] = (string) $client->pubkey;
$peers[$peerUuid] = [
"name" => (string) $client->name,
"enabled" => (int) $client->enabled,
"publicKey" => (string) $client->pubkey,
];
}
// prepare and initialize the server array
$status = [];
$peer_pubkey_reference = [];
foreach ($config->server->servers->server as $server) {
if ($server->enabled != "1") {
continue;
}
// build basic server array
$interface = "wg" . $server->instance;
$status[$interface] = [
"instance" => (int) $server->instance,
"interface" => (string) $interface,
"enabled" => (int) $server->enabled,
"name" => (string) $server->name,
"peers" => [],
];
// parse and add peers with initial values to array
if (strlen($server->peers) > 0) {
// there is at least one peer defined
$serverPeers = explode(",", (string) $server->peers);
// iteriate over each peer uuid
foreach ($serverPeers as $peerUuid) {
// skipping removed peer that is still referenced in server
if (!isset($peers[$peerUuid])) {
continue;
}
// remember interface and pubkey <> peer-uuid reference for referencing handshake logic below
$peer_pubkey_reference[$interface][$peers_uuid_pubkey[$peerUuid]] = $peerUuid;
// merge peer info and initial values for handshake data
$status[$interface]["peers"][$peerUuid] = array_merge(
$peers[$peerUuid],
[
"lastHandshake" => "0000-00-00 00:00:00+00:00",
]
);
}
}
}
// Get latest handshakes by running CLI command locally
$data = (new Backend())->configdRun("wireguard showhandshake");
// parse and set handshake to status datastructure
$data = trim($data);
if (strlen($data) !== 0) {
$wgHandshakes = explode("\n", $data);
foreach ($wgHandshakes as $handshake) {
$item = explode("\t", trim($handshake));
// set interface name and publickey
$interface = trim($item[0]);
$pubkey = trim($item[1]);
// calculate handshake time based on local timezone
$epoch = $item[2];
if ($epoch > 0) {
$dt = new \DateTime("@$epoch");
$dt->setTimezone(new \DateTimeZone(date_default_timezone_get()));
$latest = $dt->format("Y-m-d H:i:sP");
// set handshake
$peerUuid = $peer_pubkey_reference[$interface][$pubkey];
if (!empty($peerUuid)) {
$status[$interface]["peers"][$peerUuid]["lastHandshake"] = $latest;
}
}
}
}
return [
"items" => $status
];
}
}

View File

@ -1,78 +0,0 @@
<?php
/*
* Copyright (C) 2023 Deciso B.V.
* Copyright (C) 2018 Michael Muenz <m.muenz@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
namespace OPNsense\Wireguard\Api;
use OPNsense\Base\ApiMutableModelControllerBase;
use OPNsense\Core\Backend;
class ServerController extends ApiMutableModelControllerBase
{
protected static $internalModelName = 'server';
protected static $internalModelClass = '\OPNsense\Wireguard\Server';
public function keyPairAction()
{
return json_decode((new Backend())->configdRun('wireguard gen_keypair'), true);
}
public function searchServerAction()
{
$search = $this->searchBase(
'servers.server',
["enabled", "instance", "peers", "name", "networks", "pubkey", "port", "tunneladdress", 'interface']
);
return $search;
}
public function getServerAction($uuid = null)
{
return $this->getBase('server', 'servers.server', $uuid);
}
public function addServerAction($uuid = null)
{
return $this->addBase('server', 'servers.server', $uuid);
}
public function delServerAction($uuid)
{
return $this->delBase('servers.server', $uuid);
}
public function setServerAction($uuid = null)
{
return $this->setBase('server', 'servers.server', $uuid);
}
public function toggleServerAction($uuid)
{
return $this->toggleBase('servers.server', $uuid);
}
}

View File

@ -1,123 +0,0 @@
<?php
/*
* Copyright (C) 2023 Deciso B.V.
* Copyright (C) 2018 Michael Muenz <m.muenz@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
namespace OPNsense\Wireguard\Api;
use OPNsense\Base\ApiMutableServiceControllerBase;
use OPNsense\Core\Backend;
use OPNsense\Wireguard\General;
use OPNsense\Wireguard\Client;
use OPNsense\Wireguard\Server;
/**
* Class ServiceController
* @package OPNsense\Wireguard
*/
class ServiceController extends ApiMutableServiceControllerBase
{
protected static $internalServiceClass = '\OPNsense\Wireguard\General';
protected static $internalServiceTemplate = 'OPNsense/Wireguard';
protected static $internalServiceEnabled = 'enabled';
protected static $internalServiceName = 'wireguard';
/**
* @return array
*/
public function reconfigureAction()
{
if (!$this->request->isPost()) {
return ['result' => 'failed'];
}
$this->sessionClose();
$backend = new Backend();
$backend->configdRun('interface invoke registration');
$backend->configdRun('template reload ' . escapeshellarg(static::$internalServiceTemplate));
$backend->configdpRun('wireguard configure');
return ['result' => 'ok'];
}
/**
* show wireguard config
* XXX: remove in 24.1
* @return array
*/
public function showconfAction()
{
$response = (new Backend())->configdRun("wireguard showconf");
return array("response" => $response);
}
/**
* show wireguard handshakes
* XXX: remove in 24.1
* @return array
*/
public function showhandshakeAction()
{
$response = (new Backend())->configdRun("wireguard showhandshake");
return array("response" => $response);
}
/**
* wg show all dump output
* @return array
*/
public function showAction()
{
$payload = json_decode((new Backend())->configdRun("wireguard show") ?? '', true);
$records = !empty($payload) && !empty($payload['records']) ? $payload['records'] : [];
$key_descriptions = [];
$ifnames = [];
foreach ((new Client())->clients->client->iterateItems() as $key => $client) {
$key_descriptions[(string)$client->pubkey] = (string)$client->name;
}
foreach ((new Server())->servers->server->iterateItems() as $key => $server) {
$key_descriptions[(string)$server->pubkey] = (string)$server->name;
$ifnames[(string)$server->interface] = (string)$server->name;
}
foreach ($records as &$record) {
if (!empty($record['public-key']) && !empty($key_descriptions[$record['public-key']])) {
$record['name'] = $key_descriptions[$record['public-key']];
} else {
$record['name'] = '';
}
$record['ifname'] = $ifnames[$record['if']];
}
$filter_funct = null;
$types = $this->request->get('type');
if (!empty($types)) {
$filter_funct = function ($record) use ($types) {
return in_array($record['type'], $types);
};
}
return $this->searchRecordsetBase($records, null, null, $filter_funct);
}
}

View File

@ -1,44 +0,0 @@
<?php
/*
* Copyright (C) 2023 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.
*/
namespace OPNsense\Wireguard;
class DiagnosticsController extends \OPNsense\Base\IndexController
{
protected function templateJSIncludes()
{
$result = parent::templateJSIncludes();
$result[] = '/ui/js/moment-with-locales.min.js';
return $result;
}
public function indexAction()
{
$this->view->pick('OPNsense/Wireguard/diagnostics');
}
}

View File

@ -1,39 +0,0 @@
<?php
/*
* Copyright (C) 2018 Michael Muenz <m.muenz@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
namespace OPNsense\Wireguard;
class GeneralController extends \OPNsense\Base\IndexController
{
public function indexAction()
{
$this->view->generalForm = $this->getForm("general");
$this->view->formDialogEditWireguardClient = $this->getForm("dialogEditWireguardClient");
$this->view->formDialogEditWireguardServer = $this->getForm("dialogEditWireguardServer");
$this->view->pick('OPNsense/Wireguard/general');
}
}

View File

@ -1,58 +0,0 @@
<form>
<field>
<id>client.enabled</id>
<label>Enabled</label>
<type>checkbox</type>
<help>This will enable or disable the peer.</help>
</field>
<field>
<id>client.name</id>
<label>Name</label>
<type>text</type>
<help>Set the name for this peer.</help>
</field>
<field>
<id>client.pubkey</id>
<label>Public key</label>
<type>text</type>
<help>Public key of this peer. You can generate the key using the private key piped to "wg pubkey".</help>
</field>
<field>
<id>client.psk</id>
<label>Pre-shared key</label>
<type>text</type>
<help>Shared secret (PSK) for this peer. You can generate a key using "wg genpsk".</help>
</field>
<field>
<id>client.tunneladdress</id>
<label>Allowed IPs</label>
<style>tokenize</style>
<type>select_multiple</type>
<allownew>true</allownew>
<help>List of addresses allowed to pass trough the tunnel adapter. Please use CIDR notation like 10.0.0.1/24.</help>
</field>
<field>
<id>client.serveraddress</id>
<label>Endpoint address</label>
<type>text</type>
<help>Set public IP address the endpoint listens to.</help>
</field>
<field>
<id>client.serverport</id>
<label>Endpoint port</label>
<type>text</type>
<help>Set port the endpoint listens to.</help>
</field>
<field>
<id>client.servers</id>
<label>Instances</label>
<type>select_multiple</type>
<help>List of instances this peer belongs to.</help>
</field>
<field>
<id>client.keepalive</id>
<label>Keepalive interval</label>
<type>text</type>
<help>Set persistent keepalive interval in seconds.</help>
</field>
</form>

View File

@ -1,87 +0,0 @@
<form>
<field>
<id>server.enabled</id>
<label>Enabled</label>
<type>checkbox</type>
<help>This will enable or disable the instance.</help>
</field>
<field>
<id>server.name</id>
<label>Name</label>
<type>text</type>
<help>Set the name for this instance.</help>
</field>
<field>
<id>server.instance</id>
<label>Instance</label>
<type>info</type>
<help>This is the instance number to give the WireGuard device a unique name (wgX).</help>
</field>
<field>
<id>server.pubkey</id>
<label>Public key</label>
<type>text</type>
<help>Public key of this instance. You can specify your own one, or a key will be generated after saving.</help>
</field>
<field>
<id>server.privkey</id>
<label>Private key</label>
<type>text</type>
<help>Private key of this instance. You can specify your own one, or a key will be generated after saving. Please keep this key safe.</help>
</field>
<field>
<id>server.port</id>
<label>Listen port</label>
<type>text</type>
<help>Optionally set a fixed port for this instance to listen on. The standard port range starts at 51820.</help>
</field>
<field>
<id>server.mtu</id>
<label>MTU</label>
<type>text</type>
<advanced>true</advanced>
<help>Set a specific device MTU for this instance.</help>
</field>
<field>
<id>server.dns</id>
<label>DNS servers</label>
<type>select_multiple</type>
<style>tokenize</style>
<allownew>true</allownew>
<advanced>true</advanced>
<help>Set specific DNS servers for this instance. Use with care.</help>
</field>
<field>
<id>server.tunneladdress</id>
<label>Tunnel address</label>
<style>tokenize</style>
<type>select_multiple</type>
<allownew>true</allownew>
<help>List of addresses to configure on the device. Please use CIDR notation like 10.0.0.1/24.</help>
</field>
<field>
<id>server.carp_depend_on</id>
<label>Depend on (CARP)</label>
<type>dropdown</type>
<help>The CARP VHID to depend on. When this virtual address is not in master state, then the instance will be shutdown.</help>
</field>
<field>
<id>server.peers</id>
<label>Peers</label>
<type>select_multiple</type>
<help>List of peers for this instance.</help>
</field>
<field>
<id>server.disableroutes</id>
<label>Disable routes</label>
<type>checkbox</type>
<help>This will prevent installing routes. Usually you only enable this to do own routing decisions via a local gateway and gateway rules.</help>
</field>
<field>
<id>server.gateway</id>
<label>Gateway</label>
<type>text</type>
<advanced>true</advanced>
<help>Set the gateway IP here when using "Disable routes" feature. You also have to add this as a system gateway.</help>
</field>
</form>

View File

@ -1,8 +0,0 @@
<form>
<field>
<id>general.enabled</id>
<label>Enable WireGuard</label>
<type>checkbox</type>
<help>This will activate WireGuard and start all enabled instances.</help>
</field>
</form>

View File

@ -1,9 +0,0 @@
<acl>
<page-wireguard-config>
<name>VPN: WireGuard</name>
<patterns>
<pattern>ui/wireguard/*</pattern>
<pattern>api/wireguard/*</pattern>
</patterns>
</page-wireguard-config>
</acl>

View File

@ -1,35 +0,0 @@
<?php
/*
* Copyright (C) 2018 Michael Muenz <m.muenz@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
namespace OPNsense\Wireguard;
use OPNsense\Base\BaseModel;
class Client extends BaseModel
{
}

View File

@ -1,36 +0,0 @@
<model>
<mount>//OPNsense/wireguard/client</mount>
<description>WireGuard peer configuration</description>
<version>0.0.7</version>
<items>
<clients>
<client type="ArrayField">
<enabled type="BooleanField">
<Default>1</Default>
<Required>Y</Required>
</enabled>
<name type="TextField">
<Required>Y</Required>
<Mask>/^([0-9a-zA-Z._\-]){1,64}$/u</Mask>
<ValidationMessage>Should be a string between 1 and 64 characters. Allowed characters are alphanumeric characters, dash and underscores.</ValidationMessage>
</name>
<pubkey type="Base64Field">
<Required>Y</Required>
</pubkey>
<psk type="Base64Field"/>
<tunneladdress type="NetworkField">
<FieldSeparator>,</FieldSeparator>
<Required>Y</Required>
<asList>Y</asList>
</tunneladdress>
<serveraddress type="HostnameField"/>
<serverport type="PortField"/>
<keepalive type="IntegerField">
<MinimumValue>1</MinimumValue>
<MaximumValue>86400</MaximumValue>
<ValidationMessage>Please specify a value between 1 and 86400.</ValidationMessage>
</keepalive>
</client>
</clients>
</items>
</model>

View File

@ -1,58 +0,0 @@
<?php
/*
* Copyright (C) 2023 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.
*/
namespace OPNsense\Wireguard\FieldTypes;
use OPNsense\Base\FieldTypes\ArrayField;
use OPNsense\Base\FieldTypes\TextField;
class ServerField extends ArrayField
{
/**
* push internal reusable properties as virtuals
*/
protected function actionPostLoadingEvent()
{
foreach ($this->internalChildnodes as $node) {
if (!$node->getInternalIsVirtual()) {
$files = [
'cnfFilename' => "/usr/local/etc/wireguard/wg{$node->instance}.conf",
'statFilename' => "/usr/local/etc/wireguard/wg{$node->instance}.stat",
'interface' => "wg{$node->instance}",
];
foreach ($files as $name => $payload) {
$new_item = new TextField();
$new_item->setInternalIsVirtual();
$new_item->setValue($payload);
$node->addChildNode($name, $new_item);
}
}
}
return parent::actionPostLoadingEvent();
}
}

View File

@ -1,35 +0,0 @@
<?php
/*
* Copyright (C) 2018 Michael Muenz <m.muenz@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
namespace OPNsense\Wireguard;
use OPNsense\Base\BaseModel;
class General extends BaseModel
{
}

View File

@ -1,11 +0,0 @@
<model>
<mount>//OPNsense/wireguard/general</mount>
<description>WireGuard configuration</description>
<version>0.0.1</version>
<items>
<enabled type="BooleanField">
<Default>0</Default>
<Required>Y</Required>
</enabled>
</items>
</model>

View File

@ -1,9 +0,0 @@
<menu>
<VPN>
<WireGuard cssClass="fa fa-lock fa-fw" order="150">
<Settings order="10" url="/ui/wireguard/general/"/>
<Diagnostics order="20" url="/ui/wireguard/diagnostics/"/>
<LogFile order="70" VisibleName="Log File" url="/ui/diagnostics/log/core/wireguard"/>
</WireGuard>
</VPN>
</menu>

View File

@ -1,35 +0,0 @@
<?php
/*
* Copyright (C) 2018 Michael Muenz <m.muenz@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
namespace OPNsense\Wireguard;
use OPNsense\Base\BaseModel;
class Server extends BaseModel
{
}

View File

@ -1,73 +0,0 @@
<model>
<mount>//OPNsense/wireguard/server</mount>
<description>WireGuard instance configuration</description>
<version>0.0.4</version>
<items>
<servers>
<server type=".\ServerField">
<enabled type="BooleanField">
<Default>1</Default>
<Required>Y</Required>
</enabled>
<name type="TextField">
<Required>Y</Required>
<Mask>/^([0-9a-zA-Z._\-]){1,64}$/u</Mask>
<ValidationMessage>Should be a string between 1 and 64 characters. Allowed characters are alphanumeric characters, dash and underscores.</ValidationMessage>
</name>
<instance type="AutoNumberField">
<Required>Y</Required>
</instance>
<pubkey type="TextField">
<Required>Y</Required>
<ValidationMessage>A public key is required</ValidationMessage>
</pubkey>
<privkey type="TextField">
<Required>Y</Required>
<ValidationMessage>A private key is required</ValidationMessage>
</privkey>
<port type="PortField"/>
<mtu type="IntegerField">
<MinimumValue>1</MinimumValue>
<MaximumValue>9300</MaximumValue>
</mtu>
<dns type="CSVListField">
<Mask>/^([a-fA-F0-9\.:\[\]]*?,)*([a-fA-F0-9\.:\[\]]*)$/</Mask>
<ValidationMessage>Please use valid IPv4 or IPv6 addresses.</ValidationMessage>
</dns>
<tunneladdress type="NetworkField">
<FieldSeparator>,</FieldSeparator>
<asList>Y</asList>
</tunneladdress>
<disableroutes type="BooleanField">
<Default>0</Default>
<Required>Y</Required>
<Constraints>
<check001>
<ValidationMessage>You have to enable Disable Routes option.</ValidationMessage>
<type>DependConstraint</type>
<addFields>
<field1>gateway</field1>
</addFields>
</check001>
</Constraints>
</disableroutes>
<gateway type="NetworkField"/>
<carp_depend_on type="VirtualIPField">
<type>carp</type>
<key>mvc</key>
</carp_depend_on>
<peers type="ModelRelationField">
<Model>
<template>
<source>OPNsense.Wireguard.Client</source>
<items>clients.client</items>
<display>name</display>
</template>
</Model>
<Multiple>Y</Multiple>
<ValidationMessage>Choose an Peer.</ValidationMessage>
</peers>
</server>
</servers>
</items>
</model>

View File

@ -1,97 +0,0 @@
{#
# Copyright (c) 2023 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>
$( document ).ready(function() {
$("#grid-sessions").UIBootgrid({
search:'/api/wireguard/service/show',
options:{
multiSelect: false,
rowSelect: false,
selection: false,
formatters:{
bytes: function(column, row) {
if (row[column.id] && row[column.id] > 0) {
return byteFormat(row[column.id], 2);
}
return row[column.id];
},
epoch: function(column, row) {
if (row[column.id]) {
return moment.unix(row[column.id]).local().format('YYYY-MM-DD HH:mm:ss');
} else {
return '';
}
}
},
requestHandler: function(request){
if ( $('#type_filter').val().length > 0) {
request['type'] = $('#type_filter').val();
}
return request;
},
}
});
$("#type_filter").change(function(){
$('#grid-sessions').bootgrid('reload');
});
$("#type_filter_container").detach().prependTo('#grid-sessions-header > .row > .actionBar > .actions');
});
</script>
<div class="tab-content content-box">
<div class="hidden">
<!-- filter per type container -->
<div id="type_filter_container" class="btn-group">
<select id="type_filter" data-title="{{ lang._('Type') }}" class="selectpicker" multiple="multiple" data-width="200px">
<option value="interface">{{ lang._('Instance') }}</option>
<option value="peer">{{ lang._('Peer') }}</option>
</select>
</div>
</div>
<table id="grid-sessions" class="table table-condensed table-hover table-striped table-responsive">
<thead>
<tr>
<th data-column-id="if" data-type="string" data-width="8em">{{ lang._('Device') }}</th>
<th data-column-id="type" data-type="string" data-width="8em" data-visible="false">{{ lang._('Type') }}</th>
<th data-column-id="status" data-type="string" data-width="8em" >{{ lang._('Status') }}</th>
<th data-column-id="public-key" data-type="string" data-identifier="true">{{ lang._('Public key') }}</th>
<th data-column-id="name" data-type="string">{{ lang._('Name') }}</th>
<th data-column-id="endpoint" data-type="string">{{ lang._('Port / Endpoint') }}</th>
<th data-column-id="latest-handshake" data-formatter="epoch" data-type="numeric">{{ lang._('Handshake') }}</th>
<th data-column-id="transfer-tx" data-formatter="bytes" data-type="numeric">{{ lang._('Send') }}</th>
<th data-column-id="transfer-rx" data-formatter="bytes" data-type="numeric">{{ lang._('Received') }}</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>

View File

@ -1,173 +0,0 @@
{#
# Copyright (c) 2014-2023 Deciso B.V.
# Copyright (c) 2018 Michael Muenz <m.muenz@gmail.com>
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without modification,
# are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
# AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
# OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#}
<script>
$( document ).ready(function() {
var data_get_map = {'frm_general_settings':"/api/wireguard/general/get"};
mapDataToFormUI(data_get_map).done(function(data){
formatTokenizersUI();
$('.selectpicker').selectpicker('refresh');
});
$("#grid-peers").UIBootgrid(
{
'search':'/api/wireguard/client/searchClient',
'get':'/api/wireguard/client/getClient/',
'set':'/api/wireguard/client/setClient/',
'add':'/api/wireguard/client/addClient/',
'del':'/api/wireguard/client/delClient/',
'toggle':'/api/wireguard/client/toggleClient/'
}
);
$("#grid-instances").UIBootgrid(
{
'search':'/api/wireguard/server/searchServer',
'get':'/api/wireguard/server/getServer/',
'set':'/api/wireguard/server/setServer/',
'add':'/api/wireguard/server/addServer/',
'del':'/api/wireguard/server/delServer/',
'toggle':'/api/wireguard/server/toggleServer/'
}
);
$("#reconfigureAct").SimpleActionButton({
onPreAction: function() {
const dfObj = new $.Deferred();
saveFormToEndpoint("/api/wireguard/general/set", 'frm_general_settings', function(){
dfObj.resolve();
});
return dfObj;
}
});
/**
* Move keypair generation button inside the instance form and hook api event
*/
$("#control_label_server\\.pubkey").append($("#keygen_div").detach().show());
$("#keygen").click(function(){
ajaxGet("/api/wireguard/server/key_pair", {}, function(data, status){
if (data.status && data.status === 'ok') {
$("#server\\.pubkey").val(data.pubkey);
$("#server\\.privkey").val(data.privkey);
}
});
})
});
</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="#instances">{{ lang._('Instances') }}</a></li>
<li><a data-toggle="tab" href="#peers">{{ lang._('Peers') }}</a></li>
</ul>
<div class="tab-content content-box tab-content">
<div id="general" class="tab-pane fade in active">
{{ partial("layout_partials/base_form",['fields':generalForm,'id':'frm_general_settings'])}}
</div>
<div id="peers" class="tab-pane fade in">
<table id="grid-peers" class="table table-condensed table-hover table-striped" data-editDialog="dialogEditWireguardClient">
<thead>
<tr>
<th data-column-id="uuid" data-type="string" data-identifier="true" data-visible="false">{{ lang._('ID') }}</th>
<th data-column-id="enabled" data-type="string" data-formatter="rowtoggle">{{ lang._('Enabled') }}</th>
<th data-column-id="name" data-type="string" data-visible="true">{{ lang._('Name') }}</th>
<th data-column-id="serveraddress" data-type="string" data-visible="true">{{ lang._('Endpoint address') }}</th>
<th data-column-id="serverport" data-type="string" data-visible="true">{{ lang._('Endpoint port') }}</th>
<th data-column-id="tunneladdress" data-type="string" data-visible="true">{{ lang._('Allowed IPs') }}</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>
</thead>
<tbody>
</tbody>
<tfoot>
<tr>
<td colspan="6"></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-fw fa-trash-o"></span></button>
</td>
</tr>
</tfoot>
</table>
</div>
<div id="instances" class="tab-pane fade in">
<span id="keygen_div" style="display:none" class="pull-right">
<button id="keygen" type="button" class="btn btn-secondary" title="{{ lang._('Generate new keypair.') }}" data-toggle="tooltip">
<i class="fa fa-fw fa-gear"></i>
</button>
</span>
<table id="grid-instances" class="table table-condensed table-hover table-striped" data-editDialog="dialogEditWireguardServer">
<thead>
<tr>
<th data-column-id="uuid" data-type="string" data-identifier="true" data-visible="false">{{ lang._('ID') }}</th>
<th data-column-id="enabled" data-type="string" data-formatter="rowtoggle">{{ lang._('Enabled') }}</th>
<th data-column-id="name" data-type="string" data-visible="true">{{ lang._('Name') }}</th>
<th data-column-id="interface" data-type="string" data-visible="true">{{ lang._('Device') }}</th>
<th data-column-id="tunneladdress" data-type="string" data-visible="true">{{ lang._('Tunnel Address') }}</th>
<th data-column-id="port" data-type="string" data-visible="true">{{ lang._('Port') }}</th>
<th data-column-id="peers" data-type="string" data-visible="true">{{ lang._('Peers') }}</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>
</thead>
<tbody>
</tbody>
<tfoot>
<tr>
<td colspan="7"></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-fw 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">
<br/>
<button class="btn btn-primary" id="reconfigureAct"
data-endpoint='/api/wireguard/service/reconfigure'
data-label="{{ lang._('Apply') }}"
data-error-title="{{ lang._('Error reconfiguring WireGuard') }}"
type="button"
></button>
<br/><br/>
</div>
</div>
</section>
{{ partial("layout_partials/base_dialog",['fields':formDialogEditWireguardClient,'id':'dialogEditWireguardClient','label':lang._('Edit peer')])}}
{{ partial("layout_partials/base_dialog",['fields':formDialogEditWireguardServer,'id':'dialogEditWireguardServer','label':lang._('Edit instance')])}}

View File

@ -1,46 +0,0 @@
#!/usr/local/bin/python3
"""
Copyright (c) 2023 Ad Schellevis <ad@opnsense.org>
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
"""
import subprocess
import ujson
def keypair():
sp = subprocess.run(['/usr/bin/wg', 'genkey'], capture_output=True, text=True)
if sp.returncode == 0:
privkey = sp.stdout.strip()
sp = subprocess.run(['/usr/bin/wg', 'pubkey'], input=privkey, capture_output=True, text=True)
if sp.returncode == 0:
return {'privkey': privkey, 'pubkey': sp.stdout.strip()}
return None
response = keypair()
if not response:
print(ujson.dumps({'status': 'failed'}))
else:
response['status'] = 'ok'
print(ujson.dumps(response))

View File

@ -1,75 +0,0 @@
#!/usr/local/bin/python3
"""
Copyright (c) 2023 Ad Schellevis <ad@opnsense.org>
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.
"""
# Python implementation to re-resolve dns entries, for reference see:
# https://github.com/WireGuard/wireguard-tools/tree/master/contrib/reresolve-dns
import glob
import os
import time
import subprocess
sp = subprocess.run(['/usr/bin/wg', 'show', 'all', 'latest-handshakes'], capture_output=True, text=True)
ts_now = time.time()
handshakes = {}
for line in sp.stdout.split('\n'):
parts = line.split()
if len(parts) == 3 and parts[2].isdigit():
handshakes["%s-%s" % (parts[0], parts[1])] = ts_now - int(parts[2])
for filename in glob.glob('/usr/local/etc/wireguard/*.conf'):
this_peer = {}
ifname = os.path.basename(filename).split('.')[0]
with open(filename, 'r') as fhandle:
for line in fhandle:
if line.startswith('[Peer]'):
this_peer = {'ifname': ifname}
elif line.startswith('PublicKey'):
this_peer['PublicKey'] = line.split('=', 1)[1].strip()
elif line.startswith('Endpoint'):
this_peer['Endpoint'] = line.split('=', 1)[1].strip()
if 'Endpoint' in this_peer and 'PublicKey' in this_peer:
peer_key = "%(ifname)s-%(PublicKey)s" % this_peer
if handshakes.get(peer_key, 999) > 135:
# skip if there has been a handshake recently
subprocess.run(
[
'/usr/bin/wg',
'set',
ifname,
'peer',
this_peer['PublicKey'],
'endpoint',
this_peer['Endpoint']
],
capture_output=True,
text=True
)
this_peer = {}

View File

@ -1,303 +0,0 @@
#!/usr/local/bin/php
<?php
/*
* Copyright (C) 2023 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.
*/
require_once('script/load_phalcon.php');
require_once('util.inc');
require_once('config.inc');
require_once('interfaces.inc');
require_once('system.inc');
/**
* collect carp status per vhid
*/
function get_vhid_status()
{
$vhids = [];
$uuids = [];
foreach ((new OPNsense\Interfaces\Vip())->vip->iterateItems() as $id => $item) {
if ($item->mode == 'carp') {
$uuids[(string)$item->vhid] = $id;
$vhids[$id] = ['status' => 'DISABLED', 'vhid' => (string)$item->vhid];
}
}
foreach (legacy_interfaces_details() as $ifdata) {
if (!empty($ifdata['carp'])) {
foreach ($ifdata['carp'] as $data) {
if (isset($uuids[$data['vhid']])) {
$vhids[$uuids[$data['vhid']]] = ['status' => $data['status'], 'vhid' => $data['vhid']];
}
}
}
}
return $vhids;
}
/**
* mimic wg-quick behaviour, but bound to our config
*/
function wg_start($server, $fhandle, $ifcfgflag = 'up')
{
if (!does_interface_exist($server->interface)) {
mwexecf('/sbin/ifconfig wg create name %s', [$server->interface]);
mwexecf('/sbin/ifconfig %s group wireguard', [$server->interface]);
}
mwexecf('/usr/bin/wg syncconf %s %s', [$server->interface, $server->cnfFilename]);
/* The tunneladdress can be empty, so array_filter without callback filters empty strings out. */
foreach (array_filter(explode(',', (string)$server->tunneladdress)) as $alias) {
$proto = strpos($alias, ':') === false ? "inet" : "inet6";
mwexecf('/sbin/ifconfig %s %s %s alias', [$server->interface, $proto, $alias]);
}
if (!empty((string)$server->mtu)) {
mwexecf('/sbin/ifconfig %s mtu %s', [$server->interface, $server->mtu]);
}
mwexecf('/sbin/ifconfig %s %s', [$server->interface, $ifcfgflag]);
if (empty((string)$server->disableroutes)) {
/**
* Add routes for all configured peers, wg-quick seems to parse 'wg show wgX allowed-ips' for this,
* but this should logically congtain the same networks.
*
* XXX: For some reason these routes look a bit off, not very well integrated into OPNsense.
* In the long run it might make sense to have some sort of pluggable model facility
* where these (and maybe other) static routes hook into.
**/
$peers = explode(',', $server->peers);
$routes_to_add = ['inet' => [], 'inet6' => []];
foreach ((new OPNsense\Wireguard\Client())->clients->client->iterateItems() as $key => $client) {
if (empty((string)$client->enabled) || !in_array($key, $peers)) {
continue;
}
foreach (explode(',', (string)$client->tunneladdress) as $tunneladdress) {
$ipproto = strpos($tunneladdress, ":") === false ? "inet" : "inet6";
/* wg-quick seems to prevent /0 being routed and translates this automatically */
if (str_ends_with(trim($tunneladdress), '/0')) {
if ($ipproto == 'inet') {
array_push($routes_to_add[$ipproto], '0.0.0.0/1', '128.0.0.0/1');
} else {
array_push($routes_to_add[$ipproto], '::/1', '8000::/1');
}
} else {
$routes_to_add[$ipproto][] = $tunneladdress;
}
}
}
foreach ($routes_to_add as $ipproto => $routes) {
foreach (array_unique($routes) as $route) {
mwexecf('/sbin/route -q -n add -%s %s -interface %s', [$ipproto, $route, $server->interface]);
}
}
} elseif (!empty((string)$server->gateway)) {
/* Only bind the gateway ip to the tunnel */
$ipprefix = strpos($tunneladdress, ":") === false ? "-4" : "-6";
mwexecf('/sbin/route -q -n add %s %s -iface %s', [$ipprefix, $server->gateway, $server->interface]);
}
// flush checksum to ease change detection
fseek($fhandle, 0);
ftruncate($fhandle, 0);
fwrite($fhandle, @md5_file($server->cnfFilename) . "|" . wg_reconfigure_hash($server));
syslog(LOG_NOTICE, "wireguard instance {$server->name} ({$server->interface}) started");
interfaces_restart_by_device(false, [(string)$server->interface], false);
}
/**
* stop wireguard tunnel, kill the device, the routes should drop automatically.
*/
function wg_stop($server)
{
if (does_interface_exist($server->interface)) {
legacy_interface_destroy($server->interface);
}
syslog(LOG_NOTICE, "wireguard instance {$server->name} ({$server->interface}) stopped");
}
/**
* Calculate a hash which determines if we are able to reconfigure without a restart of the tunnel.
* We currently assume if something changed on the interface or peer routes are being pushed, it's safer to
* restart then reload.
*/
function wg_reconfigure_hash($server)
{
if (empty((string)$server->disableroutes)) {
return md5(uniqid('', true)); // random hash, should always reconfigure
}
return md5(
sprintf(
'%s|%s|%s',
$server->tunneladdress,
$server->mtu,
$server->gateway
)
);
}
/**
* The stat hash file answers two questions, [1] has anything changed, which is answered using an md5 hash of the
* configuration file. The second question, if something has changed, is it safe to only reload the configuration.
* This is answered by wg_reconfigure_hash() for the instance in question.
*/
function get_stat_hash($fhandle)
{
fseek($fhandle, 0);
$payload = stream_get_contents($fhandle) ?? '';
$parts = explode('|', $payload);
return [
'file' => $parts[0] ?? '',
'interface' => $parts[1] ?? ''
];
}
$opts = getopt('ah', [], $optind);
$args = array_slice($argv, $optind);
/* setup syslog logging */
openlog("wireguard", LOG_ODELAY, LOG_AUTH);
if (isset($opts['h']) || empty($args) || !in_array($args[0], ['start', 'stop', 'restart', 'configure'])) {
echo "Usage: wg-service-control.php [-a] [-h] [stop|start|restart|configure] [uuid|vhid]\n\n";
echo "\t-a all instances\n";
} elseif (isset($opts['a']) || !empty($args[1])) {
// either a server id (uuid) or a vhid could be offered
$server_id = $vhid = null;
if (preg_match('/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/', $args[1] ?? '') == 1) {
$server_id = $args[1];
} elseif (!empty($args[1])) {
$vhid = explode('@', $args[1])[0];
}
$action = $args[0];
$server_devs = [];
if (!empty((string)(new OPNsense\Wireguard\General())->enabled)) {
$vhids = get_vhid_status();
foreach ((new OPNsense\Wireguard\Server())->servers->server->iterateItems() as $key => $node) {
$carp_depend_on = (string)$node->carp_depend_on;
if (empty((string)$node->enabled)) {
continue;
} elseif ($server_id != null && $key != $server_id) {
continue;
} elseif ($vhid != null && (!empty($vhids[$carp_depend_on]) && $vhids[$carp_depend_on]['vhid'] != $vhid)) {
continue;
}
/**
* CARP may influence the interface status (up or down).
* In order to fluently switch between roles, one should only have to change the interface flag in this
* case, which means we can still reconfigure an interface in the usual way and just omit sending traffic
* when in BACKUP or INIT mode.
*/
$carp_if_flag = 'up';
if (!empty($vhids[$carp_depend_on]) && $vhids[$carp_depend_on]['status'] != 'MASTER') {
$carp_if_flag = 'down';
}
$server_devs[] = (string)$node->interface;
$statHandle = fopen($node->statFilename, "a+");
if (flock($statHandle, LOCK_EX)) {
$ifdetails = legacy_interfaces_details((string)$node->interface);
switch ($action) {
case 'stop':
wg_stop($node);
break;
case 'start':
wg_start($node, $statHandle, $carp_if_flag);
break;
case 'restart':
wg_stop($node);
wg_start($node, $statHandle, $carp_if_flag);
break;
case 'configure':
$ifstatus = '-';
if (!empty($ifdetails[(string)$node->interface])) {
$ifstatus = in_array('up', $ifdetails[(string)$node->interface]['flags']) ? 'up' : 'down';
}
if (!empty($carp_depend_on) && !empty($vhid)) {
// CARP event traceability when a vhid is being passed
syslog(
LOG_NOTICE,
sprintf(
"Wireguard configure event instance %s (%s) vhid: %s carp: %s interface: %s",
$node->name,
$node->interface,
$vhid,
!empty($vhids[$carp_depend_on]) ? $vhids[$carp_depend_on]['status'] : '-',
$ifstatus
)
);
}
if (
@md5_file($node->cnfFilename) != get_stat_hash($statHandle)['file'] ||
empty($ifdetails[(string)$node->interface])
) {
if (get_stat_hash($statHandle)['interface'] != wg_reconfigure_hash($node)) {
// Fluent reloading not supported for this instance, make sure the user is informed
syslog(
LOG_NOTICE,
"wireguard instance {$node->name} ({$node->interface}) " .
"can not reconfigure without stopping it first."
);
wg_stop($node);
}
wg_start($node, $statHandle, $carp_if_flag);
} else {
// when triggered via a CARP event, check our interface status [UP|DOWN]
if ($ifstatus != $carp_if_flag) {
mwexecf('/sbin/ifconfig %s %s', [$node->interface, $carp_if_flag]);
}
}
break;
}
flock($statHandle, LOCK_UN);
}
fclose($statHandle);
}
}
/**
* When -a is specified, cleanup up old or disabled instances (files and interfaces)
*/
if ($server_id == null && $vhid == null) {
foreach (glob('/usr/local/etc/wireguard/wg*') as $filename) {
$this_dev = explode('.', basename($filename))[0];
if (!in_array($this_dev, $server_devs)) {
@unlink($filename);
if (does_interface_exist($this_dev)) {
legacy_interface_destroy($this_dev);
}
}
}
}
if (count($server_devs)) {
configd_run('filter reload'); /* XXX required for NAT rules, but needs coalescing */
}
}
closelog();

View File

@ -1,72 +0,0 @@
#!/usr/local/bin/python3
"""
Copyright (c) 2023 Ad Schellevis <ad@opnsense.org>
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
"""
import subprocess
import ujson
interfaces = {}
for line in subprocess.run(['/sbin/ifconfig'], capture_output=True, text=True).stdout.split("\n"):
if not line.startswith('\t') and line.find('<') > -1:
ifname = line.split(':')[0]
interfaces[ifname] = 'up' if 'UP' in line.split('<')[1].split('>')[0].split(',') else 'down'
sp = subprocess.run(['/usr/bin/wg', 'show', 'all', 'dump'], capture_output=True, text=True)
result = {'records': []}
if sp.returncode == 0:
for line in sp.stdout.split("\n"):
record = {}
parts = line.split("\t")
# parse fields as explained in 'man wg'
record['if'] = parts[0] if len(parts) else None
if len(parts) == 5:
# intentially skip private key, should not expose it
record['type'] = 'interface'
record['public-key'] = parts[2]
record['listen-port'] = parts[3]
record['fwmark'] = parts[4]
# convenience, copy listen-port to endpoint
record['endpoint'] = parts[3]
record['status'] = interfaces.get(record['if'], 'down')
elif len(parts) == 9:
record['type'] = 'peer'
record['public-key'] = parts[1]
# intentially skip preshared-key, should not expose it
record['endpoint'] = parts[3]
record['allowed-ips'] = parts[4]
record['latest-handshake'] = int(parts[5]) if parts[5].isdigit() else 0
record['transfer-rx'] = int(parts[6]) if parts[6].isdigit() else 0
record['transfer-tx'] = int(parts[7]) if parts[7].isdigit() else 0
record['persistent-keepalive'] = parts[8]
else:
continue
result['records'].append(record)
result['status'] = 'ok'
else:
result['status'] = 'failed'
print(ujson.dumps(result))

View File

@ -1,54 +0,0 @@
[start]
command:/usr/local/opnsense/scripts/Wireguard/wg-service-control.php
parameters: start %s
type:script
message: start wireguard instance %s
[stop]
command:/usr/local/opnsense/scripts/Wireguard/wg-service-control.php
parameters: stop %s
type:script
message: stop wireguard instance %s
[restart]
command:/usr/local/opnsense/scripts/Wireguard/wg-service-control.php
parameters: restart %s
type:script
message: restart wireguard instance %s
[configure]
command:/usr/local/opnsense/scripts/Wireguard/wg-service-control.php
parameters: -a configure %s
type:script
message: configure wireguard instances (%s)
[renew]
command:/usr/local/opnsense/scripts/Wireguard/reresolve-dns.py
parameters:
type:script
message:Renew DNS for WireGuard
description:Renew DNS for WireGuard on stale connections
[gen_keypair]
command:/usr/local/opnsense/scripts/Wireguard/gen_keypair.py
parameters:
type:script_output
message:Generating WireGuard keypair
[show]
command:/usr/local/opnsense/scripts/Wireguard/wg_show.py
parameters:
type:script_output
message:show WireGuard statistics [dump]
[showconf]
command:/usr/bin/wg show all
parameters:
type:script_output
message:Show WireGuard config
[showhandshake]
command:/usr/bin/wg show all latest-handshakes
parameters:
type:script_output
message:Show WireGuard handshakes

View File

@ -1,6 +0,0 @@
###################################################################
# Local syslog-ng configuration filter definition [wireguard].
###################################################################
filter f_local_wireguard {
program("wireguard");
};

View File

@ -1,2 +0,0 @@
wireguard:/etc/rc.conf.d/wireguard
wireguard-server.conf:/usr/local/etc/wireguard/wg[OPNsense.wireguard.server.servers.server.%.instance].conf

View File

@ -1,2 +0,0 @@
# disable the wireguard rc scripts when installed, bootup handled via rc.syshook
wireguard_enable="NO"

View File

@ -1,48 +0,0 @@
{% if helpers.exists('OPNsense.wireguard.general.enabled') and OPNsense.wireguard.general.enabled == '1' %}
{% if helpers.exists('OPNsense.wireguard.server.servers.server') %}
{% for server_list in helpers.toList('OPNsense.wireguard.server.servers.server') %}
{% if TARGET_FILTERS['OPNsense.wireguard.server.servers.server.' ~ loop.index0] or TARGET_FILTERS['OPNsense.wireguard.server.servers.server'] %}
{% if server_list.enabled == '1' %}
####################################################
# Interface settings, not used by `wg` #
# Only used for reference and detection of changes #
# in the configuration #
####################################################
# Address = {{server_list.tunneladdress|default('')}}
# DNS = {{ server_list.dns|default('')}}
# MTU = {{ server_list.mtu|default('') }}
# disableroutes = {{server_list.disableroutes}}
# gateway = {{server_list.gateway}}
[Interface]
PrivateKey = {{ server_list.privkey }}
{% if server_list.port|default('') != '' %}
ListenPort = {{ server_list.port }}
{% endif %}
{% if server_list.peers|default('') != '' %}
{% for peerlist in server_list.peers.split(",") %}
{% set peerlist2_data = helpers.getUUID(peerlist) %}
{% if peerlist2_data != {} and peerlist2_data.enabled == '1' %}
[Peer]
# friendly_name = {{ peerlist2_data.name }}
PublicKey = {{ peerlist2_data.pubkey }}
{% if peerlist2_data.psk|default('') != '' %}
PresharedKey = {{ peerlist2_data.psk }}
{% endif %}
{% if peerlist2_data.serveraddress|default('') != '' %}
Endpoint = {{ peerlist2_data.serveraddress }}{% if peerlist2_data.serverport|default('') != '' %}:{{ peerlist2_data.serverport }}{% else %}:51820{% endif %}
{% endif %}
AllowedIPs = {{ peerlist2_data.tunneladdress }}
{% if peerlist2_data.keepalive|default('') != '' %}
PersistentKeepalive = {{ peerlist2_data.keepalive }}
{% endif %}
{% endif %}
{% endfor %}
{% endif %}
{% endif %}
{% endif %}
{% endfor %}
{% endif %}
{% endif %}

View File

@ -1,4 +0,0 @@
<?php
$wireguard_title = gettext('WireGuard');
$wireguard_title_link = 'ui/wireguard/general';

View File

@ -1,95 +0,0 @@
<?php
/*
* Copyright (C) 2020-2023 Deciso B.V.
* Copyright (C) 2020 D. Domig
* Copyright (C) 2022 Patrik Kernstock <patrik@kernstock.net>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
?>
<table class="table table-striped table-condensed" id="wg-table">
<thead>
<tr>
<th><?= gettext("Instance") ?></th>
<th><?= gettext("Peer") ?></th>
<th><?= gettext("Public Key") ?></th>
<th><?= gettext("Latest Handshake") ?></th>
</tr>
</thead>
<tbody>
</tbody>
<tfoot style="display: none;">
<tr>
<td colspan="4"><?= gettext("No WireGuard instance defined or enabled.") ?></td>
</tr>
</tfoot>
</table>
<style>
.psk_td {
max-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
cursor: pointer;
text-decoration: underline;
}
</style>
<script>
$(window).on("load", function() {
function wgUpdateStatus()
{
ajaxGet("/api/wireguard/service/show", {}, function(data, status) {
let $target = $("#wg-table > tbody").empty();
if (data.rows !== undefined && data.rows.length > 0) {
$("#wg-table > tfoot").hide();
for (let i=0; data.rows.length > i; ++i) {
let row = data.rows[i];
let $tr = $("<tr/>");
let ifname = row.ifname ? row.if + ' (' + row.ifname + ') ' : row.if;
$tr.append($("<td>").append(ifname));
$tr.append($("<td>").append(row.name));
$tr.append($("<td class='psk_td'>").append(row['public-key']));
let latest_handhake = '';
if (row['latest-handshake']) {
latest_handhake = moment.unix(row['latest-handshake']).local().format('YYYY-MM-DD HH:mm:ss');
}
$tr.append($("<td>").append(latest_handhake));
$target.append($tr);
}
$(".psk_td").each(function(){
$(this).tooltip({title: $(this).text(), container: 'body', trigger: 'hover'});
});
} else{
$("#wg-table > tfoot").show();
}
setTimeout(wgUpdateStatus, 10000);
});
};
wgUpdateStatus();
});
</script>

View File

@ -1,7 +0,0 @@
PLUGIN_NAME= api-backup
PLUGIN_VERSION= 1.1
PLUGIN_OBSOLETE= yes
PLUGIN_COMMENT= EoL, core endpoint is /api/core/backup/download/this
PLUGIN_MAINTAINER= franz.fabian.94@gmail.com
.include "../../Mk/plugins.mk"

View File

@ -1,12 +0,0 @@
Provide the functionality to download the config.xml
Plugin Changelog
================
1.1
* add json download functionality
1.0
* initial release

View File

@ -1,90 +0,0 @@
<?php
/*
* Copyright (C) 2023 Frank Wall
* Copyright (C) 2018 Fabian Franz
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
namespace OPNsense\Backup\Api;
use OPNsense\Base\ApiControllerBase;
class BackupController extends ApiControllerBase
{
const CONFIG_XML = '/conf/config.xml';
/**
* download system config
* @param string $format set to 'json' to get a base64 encoded config backup
* @return array|mixed
*/
public function downloadAction($format = 'plain')
{
$data = file_get_contents(self::CONFIG_XML);
$status = $data === false ? 'error' : 'success';
if ($format == 'json') {
$response = array(
'status' => $status,
'filename' => 'config.xml',
'filetype' => 'application/xml',
'content' => base64_encode($data),
);
return $response;
} else {
$this->response->setStatusCode(200, "OK");
$this->response->setContentType('application/xml', 'UTF-8');
$this->response->setHeader("Content-Disposition", "attachment; filename=\"config.xml\"");
$data = file_get_contents(self::CONFIG_XML);
$this->response->setContent($data);
}
}
/**
* process API results, serialize return data to json.
* @param $dispatcher
* @return string json data
*/
public function afterExecuteRoute($dispatcher)
{
// check if reponse headers are already set
if ($this->response->getHeaders()->get("Status") != null) {
// Headers already set, send unmodified response.
} else {
// process response, serialize to json object
$data = $dispatcher->getReturnedValue();
if (is_array($data)) {
$this->response->setContentType('application/json', 'UTF-8');
if ($this->isExternalClient()) {
$this->response->setContent(json_encode($data));
} else {
$this->response->setContent(htmlspecialchars(json_encode($data), ENT_NOQUOTES));
}
}
}
return $this->response->send();
}
}

View File

@ -1,8 +0,0 @@
<acl>
<page-Backup>
<name>Backup API</name>
<patterns>
<pattern>api/backup/*</pattern>
</patterns>
</page-Backup>
</acl>