diff --git a/LICENSE b/LICENSE index 0f571629f..6b20bc7aa 100644 --- a/LICENSE +++ b/LICENSE @@ -6,6 +6,7 @@ Copyright (c) 2005-2008 Bill Marquette Copyright (c) 2003-2005 Bob Zoller Copyright (c) 2012 Carlos Cesario Copyright (c) 2005-2006 Colin Smith +Copyright (c) 2020 D. Domig Copyright (c) 2013 Dagorlad Copyright (c) 2006 Daniel S. Haischt Copyright (c) 2012 Darren Embry @@ -37,8 +38,9 @@ Copyright (c) 2012 Marcello Coutinho Copyright (c) 2018 Martin Wasley Copyright (c) 2022 Maurice Walker Copyright (c) 2010-2015 Michael Bostock -Copyright (c) 2019-2021 Michael Muenz +Copyright (c) 2018-2021 Michael Muenz Copyright (c) 2019 Pascal Mathis +Copyright (c) 2022 Patrik Kernstock Copyright (c) 2005-2006 Paul Taylor Copyright (c) 2005-2006 Peter Allgeyer Copyright (c) 2004 Peter Curran diff --git a/plist b/plist index 28e860101..d81c69e43 100644 --- a/plist +++ b/plist @@ -43,6 +43,7 @@ /usr/local/etc/inc/plugins.inc.d/unbound.inc /usr/local/etc/inc/plugins.inc.d/vxlan.inc /usr/local/etc/inc/plugins.inc.d/webgui.inc +/usr/local/etc/inc/plugins.inc.d/wireguard.inc /usr/local/etc/inc/rrd.inc /usr/local/etc/inc/system.inc /usr/local/etc/inc/util.inc @@ -127,6 +128,7 @@ /usr/local/etc/rc.syshook.d/carp/20-openvpn /usr/local/etc/rc.syshook.d/carp/20-openvpn-instances /usr/local/etc/rc.syshook.d/carp/20-ppp +/usr/local/etc/rc.syshook.d/carp/20-wireguard /usr/local/etc/rc.syshook.d/early/05-upgrade /usr/local/etc/rc.syshook.d/early/10-configd /usr/local/etc/rc.syshook.d/early/15-templates @@ -464,6 +466,15 @@ /usr/local/opnsense/mvc/app/controllers/OPNsense/Unbound/forms/dnsbl.xml /usr/local/opnsense/mvc/app/controllers/OPNsense/Unbound/forms/forwarding.xml /usr/local/opnsense/mvc/app/controllers/OPNsense/Unbound/forms/general.xml +/usr/local/opnsense/mvc/app/controllers/OPNsense/Wireguard/Api/ClientController.php +/usr/local/opnsense/mvc/app/controllers/OPNsense/Wireguard/Api/GeneralController.php +/usr/local/opnsense/mvc/app/controllers/OPNsense/Wireguard/Api/ServerController.php +/usr/local/opnsense/mvc/app/controllers/OPNsense/Wireguard/Api/ServiceController.php +/usr/local/opnsense/mvc/app/controllers/OPNsense/Wireguard/DiagnosticsController.php +/usr/local/opnsense/mvc/app/controllers/OPNsense/Wireguard/GeneralController.php +/usr/local/opnsense/mvc/app/controllers/OPNsense/Wireguard/forms/dialogEditWireguardClient.xml +/usr/local/opnsense/mvc/app/controllers/OPNsense/Wireguard/forms/dialogEditWireguardServer.xml +/usr/local/opnsense/mvc/app/controllers/OPNsense/Wireguard/forms/general.xml /usr/local/opnsense/mvc/app/library/Google/API/Drive.php /usr/local/opnsense/mvc/app/library/OPNsense/Auth/API.php /usr/local/opnsense/mvc/app/library/OPNsense/Auth/AuthenticationFactory.php @@ -728,6 +739,15 @@ /usr/local/opnsense/mvc/app/models/OPNsense/Unbound/Migrations/M1_0_8.php /usr/local/opnsense/mvc/app/models/OPNsense/Unbound/Unbound.php /usr/local/opnsense/mvc/app/models/OPNsense/Unbound/Unbound.xml +/usr/local/opnsense/mvc/app/models/OPNsense/Wireguard/ACL/ACL.xml +/usr/local/opnsense/mvc/app/models/OPNsense/Wireguard/Client.php +/usr/local/opnsense/mvc/app/models/OPNsense/Wireguard/Client.xml +/usr/local/opnsense/mvc/app/models/OPNsense/Wireguard/FieldTypes/ServerField.php +/usr/local/opnsense/mvc/app/models/OPNsense/Wireguard/General.php +/usr/local/opnsense/mvc/app/models/OPNsense/Wireguard/General.xml +/usr/local/opnsense/mvc/app/models/OPNsense/Wireguard/Menu/Menu.xml +/usr/local/opnsense/mvc/app/models/OPNsense/Wireguard/Server.php +/usr/local/opnsense/mvc/app/models/OPNsense/Wireguard/Server.xml /usr/local/opnsense/mvc/app/views/OPNsense/CaptivePortal/clients.volt /usr/local/opnsense/mvc/app/views/OPNsense/CaptivePortal/index.volt /usr/local/opnsense/mvc/app/views/OPNsense/CaptivePortal/vouchers.volt @@ -800,6 +820,8 @@ /usr/local/opnsense/mvc/app/views/OPNsense/Unbound/overrides.volt /usr/local/opnsense/mvc/app/views/OPNsense/Unbound/overview.volt /usr/local/opnsense/mvc/app/views/OPNsense/Unbound/stats.volt +/usr/local/opnsense/mvc/app/views/OPNsense/Wireguard/diagnostics.volt +/usr/local/opnsense/mvc/app/views/OPNsense/Wireguard/general.volt /usr/local/opnsense/mvc/app/views/layout_partials/base_dialog.volt /usr/local/opnsense/mvc/app/views/layout_partials/base_dialog_processing.volt /usr/local/opnsense/mvc/app/views/layout_partials/base_form.volt @@ -879,6 +901,10 @@ /usr/local/opnsense/scripts/OPNsense/Monit/carp_status /usr/local/opnsense/scripts/OPNsense/Monit/gateway_alert /usr/local/opnsense/scripts/OPNsense/Monit/setup.sh +/usr/local/opnsense/scripts/Wireguard/gen_keypair.py +/usr/local/opnsense/scripts/Wireguard/reresolve-dns.py +/usr/local/opnsense/scripts/Wireguard/wg-service-control.php +/usr/local/opnsense/scripts/Wireguard/wg_show.py /usr/local/opnsense/scripts/auth/add_user.php /usr/local/opnsense/scripts/auth/list_group_members.php /usr/local/opnsense/scripts/dhcp/cleanup_leases4.php @@ -1110,6 +1136,7 @@ /usr/local/opnsense/service/conf/actions.d/actions_template.conf /usr/local/opnsense/service/conf/actions.d/actions_unbound.conf /usr/local/opnsense/service/conf/actions.d/actions_webgui.conf +/usr/local/opnsense/service/conf/actions.d/actions_wireguard.conf /usr/local/opnsense/service/conf/actions.d/actions_zfs.conf /usr/local/opnsense/service/conf/actions_service.conf /usr/local/opnsense/service/conf/configd.conf @@ -1222,6 +1249,7 @@ /usr/local/opnsense/service/templates/OPNsense/Syslog/local/squid_access.conf /usr/local/opnsense/service/templates/OPNsense/Syslog/local/suricata.conf /usr/local/opnsense/service/templates/OPNsense/Syslog/local/vpn.conf +/usr/local/opnsense/service/templates/OPNsense/Syslog/local/wireguard.conf /usr/local/opnsense/service/templates/OPNsense/Syslog/local/wireless.conf /usr/local/opnsense/service/templates/OPNsense/Syslog/newsyslog.conf /usr/local/opnsense/service/templates/OPNsense/Syslog/rc.conf.d @@ -1246,6 +1274,9 @@ /usr/local/opnsense/service/templates/OPNsense/WebGui/etc.php.ini /usr/local/opnsense/service/templates/OPNsense/WebGui/lib.php.ini /usr/local/opnsense/service/templates/OPNsense/WebGui/php.ini +/usr/local/opnsense/service/templates/OPNsense/Wireguard/+TARGETS +/usr/local/opnsense/service/templates/OPNsense/Wireguard/wireguard +/usr/local/opnsense/service/templates/OPNsense/Wireguard/wireguard-server.conf /usr/local/opnsense/service/tests/__init__.py /usr/local/opnsense/service/tests/config/config.xml /usr/local/opnsense/service/tests/core.py @@ -2090,6 +2121,7 @@ /usr/local/www/widgets/include/system_log.inc /usr/local/www/widgets/include/thermal_sensors.inc /usr/local/www/widgets/include/traffic_graph.inc +/usr/local/www/widgets/include/wireguard.inc /usr/local/www/widgets/widgets/carp_status.widget.php /usr/local/www/widgets/widgets/cpu_usage.widget.php /usr/local/www/widgets/widgets/gateways.widget.php @@ -2107,6 +2139,7 @@ /usr/local/www/widgets/widgets/system_log.widget.php /usr/local/www/widgets/widgets/thermal_sensors.widget.php /usr/local/www/widgets/widgets/traffic_graphs.widget.php +/usr/local/www/widgets/widgets/wireguard.widget.php /usr/local/www/wizard.php /usr/local/www/xmlrpc.php @sample /usr/local/etc/bogons.sample diff --git a/src/etc/inc/plugins.inc.d/wireguard.inc b/src/etc/inc/plugins.inc.d/wireguard.inc new file mode 100644 index 000000000..4474b4089 --- /dev/null +++ b/src/etc/inc/plugins.inc.d/wireguard.inc @@ -0,0 +1,138 @@ + + * 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() +{ + return [['pattern' => '^wg', 'volatile' => true]]; +} + +function wireguard_configure() +{ + return [ + 'newwanip' => ['wireguard_renew: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_renew($verbose = false, $unused = '') +{ + if (!wireguard_enabled()) { + return; + } + + service_log('Renewing WireGuard VPN...', $verbose); + + configd_run('wireguard renew'); + + service_log("done.\n", $verbose); +} diff --git a/src/etc/rc.syshook.d/carp/20-wireguard b/src/etc/rc.syshook.d/carp/20-wireguard new file mode 100755 index 000000000..8c69f6f95 --- /dev/null +++ b/src/etc/rc.syshook.d/carp/20-wireguard @@ -0,0 +1,3 @@ +#!/bin/sh + +configctl -dq wireguard configure diff --git a/src/opnsense/mvc/app/controllers/OPNsense/Wireguard/Api/ClientController.php b/src/opnsense/mvc/app/controllers/OPNsense/Wireguard/Api/ClientController.php new file mode 100644 index 000000000..f8a758561 --- /dev/null +++ b/src/opnsense/mvc/app/controllers/OPNsense/Wireguard/Api/ClientController.php @@ -0,0 +1,73 @@ + + * + * 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', + ["enabled", "name", "pubkey", "tunneladdress", "serveraddress", "serverport"] + ); + } + + public function getClientAction($uuid = null) + { + 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); + } +} diff --git a/src/opnsense/mvc/app/controllers/OPNsense/Wireguard/Api/GeneralController.php b/src/opnsense/mvc/app/controllers/OPNsense/Wireguard/Api/GeneralController.php new file mode 100644 index 000000000..e02afcadf --- /dev/null +++ b/src/opnsense/mvc/app/controllers/OPNsense/Wireguard/Api/GeneralController.php @@ -0,0 +1,141 @@ + + * Copyright (C) 2022 Patrik Kernstock + * + * 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 + ]; + } +} diff --git a/src/opnsense/mvc/app/controllers/OPNsense/Wireguard/Api/ServerController.php b/src/opnsense/mvc/app/controllers/OPNsense/Wireguard/Api/ServerController.php new file mode 100644 index 000000000..c810dd2ae --- /dev/null +++ b/src/opnsense/mvc/app/controllers/OPNsense/Wireguard/Api/ServerController.php @@ -0,0 +1,78 @@ + + * 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); + } +} diff --git a/src/opnsense/mvc/app/controllers/OPNsense/Wireguard/Api/ServiceController.php b/src/opnsense/mvc/app/controllers/OPNsense/Wireguard/Api/ServiceController.php new file mode 100644 index 000000000..1812f83fb --- /dev/null +++ b/src/opnsense/mvc/app/controllers/OPNsense/Wireguard/Api/ServiceController.php @@ -0,0 +1,131 @@ + + * 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'; + + /** + * hook group interface registration on reconfigure + * @return bool + */ + protected function invokeInterfaceRegistration() + { + return true; + } + + /** + * @return array + */ + public function reconfigureAction() + { + if (!$this->request->isPost()) { + return ['result' => 'failed']; + } + + $this->sessionClose(); + $backend = new Backend(); + $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); + } +} diff --git a/src/opnsense/mvc/app/controllers/OPNsense/Wireguard/DiagnosticsController.php b/src/opnsense/mvc/app/controllers/OPNsense/Wireguard/DiagnosticsController.php new file mode 100644 index 000000000..37f723f53 --- /dev/null +++ b/src/opnsense/mvc/app/controllers/OPNsense/Wireguard/DiagnosticsController.php @@ -0,0 +1,44 @@ +view->pick('OPNsense/Wireguard/diagnostics'); + } +} diff --git a/src/opnsense/mvc/app/controllers/OPNsense/Wireguard/GeneralController.php b/src/opnsense/mvc/app/controllers/OPNsense/Wireguard/GeneralController.php new file mode 100644 index 000000000..404fce682 --- /dev/null +++ b/src/opnsense/mvc/app/controllers/OPNsense/Wireguard/GeneralController.php @@ -0,0 +1,40 @@ + + 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'); + } +} diff --git a/src/opnsense/mvc/app/controllers/OPNsense/Wireguard/forms/dialogEditWireguardClient.xml b/src/opnsense/mvc/app/controllers/OPNsense/Wireguard/forms/dialogEditWireguardClient.xml new file mode 100644 index 000000000..231e9c692 --- /dev/null +++ b/src/opnsense/mvc/app/controllers/OPNsense/Wireguard/forms/dialogEditWireguardClient.xml @@ -0,0 +1,52 @@ +
+ + client.enabled + + checkbox + This will enable or disable the client config. + + + client.name + + text + Set the name for this instance. + + + client.pubkey + + text + Public key of this instance. + + + client.psk + + text + Shared secret (PSK) for this peer. You can generate a key using "wg genpsk" on a client with WireGuard installed. + + + client.tunneladdress + + + select_multiple + true + List of addresses allowed to pass trough the tunnel adapter. Please use CIDR notation like 10.0.0.1/24. + + + client.serveraddress + + text + Set public IP address the endpoint listens to. + + + client.serverport + + text + Set port the endpoint listens to. + + + client.keepalive + + text + Set persistent keepalive interval in seconds. + +
diff --git a/src/opnsense/mvc/app/controllers/OPNsense/Wireguard/forms/dialogEditWireguardServer.xml b/src/opnsense/mvc/app/controllers/OPNsense/Wireguard/forms/dialogEditWireguardServer.xml new file mode 100644 index 000000000..8c9b75761 --- /dev/null +++ b/src/opnsense/mvc/app/controllers/OPNsense/Wireguard/forms/dialogEditWireguardServer.xml @@ -0,0 +1,88 @@ +
+ + server.enabled + + checkbox + This will enable or disable the server config. + + + server.name + + text + Set the name for this instance. + + + server.instance + + info + This is the instance number to give the wg interface a unique name (wgX). + + + server.pubkey + + text + Public key of this instance. You can specify your own one, or a key will be generated after saving. + + + server.privkey + + text + Private key of this instance. You can specify your own one, or a key will be generated after saving. Please keep this key safe. + + + server.port + + text + Optionally set a fixed port for this instance to listen on. The standard port range starts at 51820. + + + server.mtu + + text + true + Set the interface MTU for this interface. Leaving empty uses the MTU from main interface which is fine for most setups. + + + server.dns + + select_multiple + + true + true + Set the interface specific DNS server. + + + server.tunneladdress + + + select_multiple + true + List of addresses to configure on the tunnel adapter. Please use CIDR notation like 10.0.0.1/24. + + + server.carp_depend_on + + dropdown + The CARP VHID to depend on. When this virtual address is not in master state, then the instance will be shutdown. + + + server.peers + + select_multiple + true + List of peers for this server. + + + server.disableroutes + + checkbox + This will prevent installing routes. Usually you only enable this to do own routing decisions via a local gateway and gateway rules. + + + server.gateway + + text + true + Set the gateway IP here when using Disable Routes feature. You also have to add this as a gateway in OPNsense. + +
diff --git a/src/opnsense/mvc/app/controllers/OPNsense/Wireguard/forms/general.xml b/src/opnsense/mvc/app/controllers/OPNsense/Wireguard/forms/general.xml new file mode 100644 index 000000000..7a74ebf81 --- /dev/null +++ b/src/opnsense/mvc/app/controllers/OPNsense/Wireguard/forms/general.xml @@ -0,0 +1,8 @@ +
+ + general.enabled + + checkbox + This will activate WireGuard and start all enabled instances. + +
diff --git a/src/opnsense/mvc/app/models/OPNsense/Wireguard/ACL/ACL.xml b/src/opnsense/mvc/app/models/OPNsense/Wireguard/ACL/ACL.xml new file mode 100644 index 000000000..21012db80 --- /dev/null +++ b/src/opnsense/mvc/app/models/OPNsense/Wireguard/ACL/ACL.xml @@ -0,0 +1,9 @@ + + + VPN: Wireguard + + ui/wireguard/* + api/wireguard/* + + + diff --git a/src/opnsense/mvc/app/models/OPNsense/Wireguard/Client.php b/src/opnsense/mvc/app/models/OPNsense/Wireguard/Client.php new file mode 100644 index 000000000..b069a766d --- /dev/null +++ b/src/opnsense/mvc/app/models/OPNsense/Wireguard/Client.php @@ -0,0 +1,31 @@ + + 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 +{ +} diff --git a/src/opnsense/mvc/app/models/OPNsense/Wireguard/Client.xml b/src/opnsense/mvc/app/models/OPNsense/Wireguard/Client.xml new file mode 100644 index 000000000..5ac335f4a --- /dev/null +++ b/src/opnsense/mvc/app/models/OPNsense/Wireguard/Client.xml @@ -0,0 +1,45 @@ + + //OPNsense/wireguard/client + Wireguard Client configuration + 0.0.7 + + + + + 1 + Y + + + Y + /^([0-9a-zA-Z._\-]){1,64}$/u + Should be a string between 1 and 64 characters. Allowed characters are alphanumeric characters, dash and underscores. + + + Y + Should be a base64-encoded 32 byte string. + + + N + Should be a base64-encoded 32 byte string. + + + , + Y + Y + + + N + + + N + + + 1 + 86400 + Please specify a value between 1 and 86400. + N + + + + + diff --git a/src/opnsense/mvc/app/models/OPNsense/Wireguard/FieldTypes/ServerField.php b/src/opnsense/mvc/app/models/OPNsense/Wireguard/FieldTypes/ServerField.php new file mode 100644 index 000000000..a327af5fb --- /dev/null +++ b/src/opnsense/mvc/app/models/OPNsense/Wireguard/FieldTypes/ServerField.php @@ -0,0 +1,58 @@ +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(); + } +} diff --git a/src/opnsense/mvc/app/models/OPNsense/Wireguard/General.php b/src/opnsense/mvc/app/models/OPNsense/Wireguard/General.php new file mode 100644 index 000000000..6caf9eaba --- /dev/null +++ b/src/opnsense/mvc/app/models/OPNsense/Wireguard/General.php @@ -0,0 +1,35 @@ + + 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 +{ +} diff --git a/src/opnsense/mvc/app/models/OPNsense/Wireguard/General.xml b/src/opnsense/mvc/app/models/OPNsense/Wireguard/General.xml new file mode 100644 index 000000000..1868a8885 --- /dev/null +++ b/src/opnsense/mvc/app/models/OPNsense/Wireguard/General.xml @@ -0,0 +1,11 @@ + + //OPNsense/wireguard/general + WireGuard configuration + 0.0.1 + + + 0 + Y + + + diff --git a/src/opnsense/mvc/app/models/OPNsense/Wireguard/Menu/Menu.xml b/src/opnsense/mvc/app/models/OPNsense/Wireguard/Menu/Menu.xml new file mode 100644 index 000000000..f2c15f406 --- /dev/null +++ b/src/opnsense/mvc/app/models/OPNsense/Wireguard/Menu/Menu.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/src/opnsense/mvc/app/models/OPNsense/Wireguard/Server.php b/src/opnsense/mvc/app/models/OPNsense/Wireguard/Server.php new file mode 100644 index 000000000..8fccdd577 --- /dev/null +++ b/src/opnsense/mvc/app/models/OPNsense/Wireguard/Server.php @@ -0,0 +1,31 @@ + + 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 +{ +} diff --git a/src/opnsense/mvc/app/models/OPNsense/Wireguard/Server.xml b/src/opnsense/mvc/app/models/OPNsense/Wireguard/Server.xml new file mode 100644 index 000000000..fe738e8af --- /dev/null +++ b/src/opnsense/mvc/app/models/OPNsense/Wireguard/Server.xml @@ -0,0 +1,82 @@ + + //OPNsense/wireguard/server + Wireguard Server configuration + 0.0.4 + + + + + 1 + Y + + + Y + /^([0-9a-zA-Z._\-]){1,64}$/u + Should be a string between 1 and 64 characters. Allowed characters are alphanumeric characters, dash and underscores. + + + Y + + + Y + A public key is required + + + Y + A private key is required + + + N + + + 1 + 9300 + N + + + N + /^([a-fA-F0-9\.:\[\]]*?,)*([a-fA-F0-9\.:\[\]]*)$/ + Please use valid IPv4 or IPv6 addresses. + + + , + N + Y + + + 0 + Y + + + You have to enable Disable Routes option. + DependConstraint + + gateway + + + + + + N + + + carp + N + mvc + + + + + + Y + N + Choose an Peer. + + + + + diff --git a/src/opnsense/mvc/app/views/OPNsense/Wireguard/diagnostics.volt b/src/opnsense/mvc/app/views/OPNsense/Wireguard/diagnostics.volt new file mode 100644 index 000000000..a8d870f83 --- /dev/null +++ b/src/opnsense/mvc/app/views/OPNsense/Wireguard/diagnostics.volt @@ -0,0 +1,98 @@ +{# + # 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. + #} + + + +
+ + + + + + + + + + + + + + + + + + +
{{ lang._('Interface') }}{{ lang._('Type') }}{{ lang._('Status') }}{{ lang._('Public key') }}{{ lang._('Name') }}{{ lang._('Port / Endpoint') }}{{ lang._('Handshake') }}{{ lang._('Send') }}{{ lang._('Received') }}
+
diff --git a/src/opnsense/mvc/app/views/OPNsense/Wireguard/general.volt b/src/opnsense/mvc/app/views/OPNsense/Wireguard/general.volt new file mode 100644 index 000000000..5960b3b2b --- /dev/null +++ b/src/opnsense/mvc/app/views/OPNsense/Wireguard/general.volt @@ -0,0 +1,170 @@ +{# + # OPNsense (c) 2014-2023 by Deciso B.V. + # OPNsense (c) 2018 Michael Muenz + # 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. + #} + + + + + +
+
+
+ {{ partial("layout_partials/base_form",['fields':generalForm,'id':'frm_general_settings'])}} +
+
+
+ + + + + + + + + + + + + + + + + + + + +
{{ lang._('Enabled') }}{{ lang._('Name') }}{{ lang._('Endpoint Address') }}{{ lang._('Endpoint Port') }}{{ lang._('Allowed IPs') }}{{ lang._('ID') }}{{ lang._('Commands') }}
+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + +
{{ lang._('Enabled') }}{{ lang._('Name') }}{{ lang._('Interface') }}{{ lang._('Tunnel Address') }}{{ lang._('Port') }}{{ lang._('Endpoints') }}{{ lang._('ID') }}{{ lang._('Commands') }}
+ +
+
+
+ +
+
+
+
+ +

+
+
+
+ +{{ 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')])}} diff --git a/src/opnsense/scripts/Wireguard/gen_keypair.py b/src/opnsense/scripts/Wireguard/gen_keypair.py new file mode 100755 index 000000000..beada99c7 --- /dev/null +++ b/src/opnsense/scripts/Wireguard/gen_keypair.py @@ -0,0 +1,46 @@ +#!/usr/local/bin/python3 + +""" + Copyright (c) 2023 Ad Schellevis + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +""" +import 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)) diff --git a/src/opnsense/scripts/Wireguard/reresolve-dns.py b/src/opnsense/scripts/Wireguard/reresolve-dns.py new file mode 100755 index 000000000..219f6d5f2 --- /dev/null +++ b/src/opnsense/scripts/Wireguard/reresolve-dns.py @@ -0,0 +1,75 @@ +#!/usr/local/bin/python3 + +""" + Copyright (c) 2023 Ad Schellevis + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +""" +# 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 = {} diff --git a/src/opnsense/scripts/Wireguard/wg-service-control.php b/src/opnsense/scripts/Wireguard/wg-service-control.php new file mode 100755 index 000000000..e51e05a07 --- /dev/null +++ b/src/opnsense/scripts/Wireguard/wg-service-control.php @@ -0,0 +1,271 @@ +#!/usr/local/bin/php +vip->iterateItems() as $id => $item) { + if ($item->mode == 'carp') { + $uuids[(string)$item->vhid] = $id; + } + } + foreach (legacy_interfaces_details() as $ifdata) { + if (!empty($ifdata['carp'])) { + foreach ($ifdata['carp'] as $data) { + if (isset($uuids[$data['vhid']])) { + $vhids[$uuids[$data['vhid']]] = $data['status']; + } + } + } + } + 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 setconf %s %s', [$server->interface, $server->cnfFilename]); + + foreach (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 interface {$server->name} ({$server->interface}) started"); +} + +/** + * 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 interface {$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]\n\n"; + echo "\t-a all instances\n"; +} elseif (isset($opts['a']) || !empty($args[1])) { + $server_id = $args[1] ?? null; + $action = $args[0]; + + $server_devs = []; + if (!empty((string)(new OPNsense\Wireguard\General())->enabled)) { + $ifdetails = legacy_interfaces_details(); + $vhids = get_vhid_status(); + foreach ((new OPNsense\Wireguard\Server())->servers->server->iterateItems() as $key => $node) { + if (empty((string)$node->enabled)) { + continue; + } + if ($server_id != null && $key != $server_id) { + 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[(string)$node->carp_depend_on]) && + $vhids[(string)$node->carp_depend_on] != 'MASTER' + ) { + $carp_if_flag = 'down'; + } + $server_devs[] = (string)$node->interface; + $statHandle = fopen($node->statFilename, "a+"); + if (flock($statHandle, LOCK_EX)) { + 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': + if ( + @md5_file($node->cnfFilename) != get_stat_hash($statHandle)['file'] || + !isset($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 interface {$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] + $tmp = in_array('up', $ifdetails[(string)$node->interface]['flags']) ? 'up' : 'down'; + if ($tmp != $carp_if_flag) { + mwexecf('/sbin/ifconfig %s %s', [$node->interface, $carp_if_flag]); + } + } + break; + } + flock($statHandle, LOCK_UN); + } + fclose($statHandle); + } + } + + /** + * When -a is specified, cleaup up old or disabled instances (files and interfaces) + */ + if ($server_id == 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); + } + } + } + } + mwexecf('/usr/local/etc/rc.routing_configure'); +} +closelog(); diff --git a/src/opnsense/scripts/Wireguard/wg_show.py b/src/opnsense/scripts/Wireguard/wg_show.py new file mode 100755 index 000000000..987efb443 --- /dev/null +++ b/src/opnsense/scripts/Wireguard/wg_show.py @@ -0,0 +1,72 @@ +#!/usr/local/bin/python3 + +""" + Copyright (c) 2023 Ad Schellevis + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +""" +import 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)) diff --git a/src/opnsense/service/conf/actions.d/actions_wireguard.conf b/src/opnsense/service/conf/actions.d/actions_wireguard.conf new file mode 100644 index 000000000..44c925e86 --- /dev/null +++ b/src/opnsense/service/conf/actions.d/actions_wireguard.conf @@ -0,0 +1,54 @@ +[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 +type:script +message: configure wireguard instances + +[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 diff --git a/src/opnsense/service/templates/OPNsense/Syslog/local/wireguard.conf b/src/opnsense/service/templates/OPNsense/Syslog/local/wireguard.conf new file mode 100644 index 000000000..c3ec362d4 --- /dev/null +++ b/src/opnsense/service/templates/OPNsense/Syslog/local/wireguard.conf @@ -0,0 +1,6 @@ +################################################################### +# Local syslog-ng configuration filter definition [wireguard]. +################################################################### +filter f_local_wireguard { + program("wireguard"); +}; diff --git a/src/opnsense/service/templates/OPNsense/Wireguard/+TARGETS b/src/opnsense/service/templates/OPNsense/Wireguard/+TARGETS new file mode 100644 index 000000000..655def7d1 --- /dev/null +++ b/src/opnsense/service/templates/OPNsense/Wireguard/+TARGETS @@ -0,0 +1,2 @@ +wireguard:/etc/rc.conf.d/wireguard +wireguard-server.conf:/usr/local/etc/wireguard/wg[OPNsense.wireguard.server.servers.server.%.instance].conf diff --git a/src/opnsense/service/templates/OPNsense/Wireguard/wireguard b/src/opnsense/service/templates/OPNsense/Wireguard/wireguard new file mode 100644 index 000000000..40a3c2f45 --- /dev/null +++ b/src/opnsense/service/templates/OPNsense/Wireguard/wireguard @@ -0,0 +1,2 @@ +# disable the wireguard rc scripts when installed, bootup handled via rc.syshook +wireguard_enable="NO" diff --git a/src/opnsense/service/templates/OPNsense/Wireguard/wireguard-server.conf b/src/opnsense/service/templates/OPNsense/Wireguard/wireguard-server.conf new file mode 100644 index 000000000..3c78652de --- /dev/null +++ b/src/opnsense/service/templates/OPNsense/Wireguard/wireguard-server.conf @@ -0,0 +1,48 @@ +{% 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 %} diff --git a/src/www/widgets/include/wireguard.inc b/src/www/widgets/include/wireguard.inc new file mode 100644 index 000000000..f1bae7fe4 --- /dev/null +++ b/src/www/widgets/include/wireguard.inc @@ -0,0 +1,4 @@ + + * 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. + */ +?> + + + + + + + + + + + + + + + + + +
+ + + + +