Merge pull request #8 from RaspAP/feature/wireguard

Wireguard server install + peer config
This commit is contained in:
Bill Zimmerman 2021-03-09 18:52:35 +01:00 committed by GitHub
commit 792a7d7e6a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
23 changed files with 741 additions and 12 deletions

View file

@ -0,0 +1,22 @@
<?php
require '../../includes/csrf.php';
require_once '../../includes/config.php';
$entity = $_POST['entity'];
if (isset($entity)) {
// generate public/private key pairs for entity
$pubkey = RASPI_WIREGUARD_PATH.$entity.'-public.key';
$privkey = RASPI_WIREGUARD_PATH.$entity.'-private.key';
$pubkey_tmp = '/tmp/'.$entity.'-public.key';
$privkey_tmp = '/tmp/'.$entity.'-private.key';
exec("sudo wg genkey | tee $privkey_tmp | wg pubkey > $pubkey_tmp", $return);
$wgdata['pubkey'] = str_replace("\n",'',file_get_contents($pubkey_tmp));
exec("sudo mv $privkey_tmp $privkey", $return);
exec("sudo mv $pubkey_tmp $pubkey", $return);
echo json_encode($wgdata);
}

View file

@ -75,6 +75,9 @@ h5.card-title {
font-family: Verdana, Geneva, sans-serif; font-family: Verdana, Geneva, sans-serif;
} }
.sidebar-light hr.sidebar-divider {
padding-top: 0.5rem;
}
ul.nav-tabs, .nav-tabs .nav-link { ul.nav-tabs, .nav-tabs .nav-link {
background-color: #f6f6ef; background-color: #f6f6ef;
@ -154,6 +157,7 @@ ul.nav-tabs, .nav-tabs .nav-link {
.info-item-xs { .info-item-xs {
font-size: 0.7rem; font-size: 0.7rem;
margin-left: 0.3rem; margin-left: 0.3rem;
line-height: 1.5em;
} }
.info-item-wifi { .info-item-wifi {
@ -190,6 +194,10 @@ ul.nav-tabs, .nav-tabs .nav-link {
} }
} }
.fas.fa-circle {
font-size: 0.5rem;
}
.logoutput { .logoutput {
width:100%; width:100%;
height:300px; height:300px;

28
app/img/wg-qr-code.php Normal file
View file

@ -0,0 +1,28 @@
<?php
require_once '../../includes/config.php';
require_once '../../includes/defaults.php';
require_once '../../includes/functions.php';
// prevent direct file access
if (!isset($_SERVER['HTTP_REFERER'])) {
header('HTTP/1.0 403 Forbidden');
exit;
}
exec("sudo cat " .RASPI_WIREGUARD_PATH.'client.conf', $return);
$peer_conf = implode(PHP_EOL,$return);
$peer_conf.= PHP_EOL;
$command = "qrencode -t svg -m 0 -o - " . mb_escapeshellarg($peer_conf);
$svg = shell_exec($command);
$etag = hash('sha256', $peer_conf);
$content_length = strlen($svg);
$last_modified = date("Y-m-d H:i:s");
header("Content-Type: image/svg+xml");
header("Content-Length: $content_length");
header("Last-Modified: $last_modified");
header("ETag: \"$etag\"");
header("X-QR-Code-Content: $peer_conf");
echo shell_exec($command);

View file

@ -10,11 +10,6 @@ if (!isset($_SERVER['HTTP_REFERER'])) {
exit; exit;
} }
function qr_encode($str)
{
return preg_replace('/(?<!\\\)([\":;,])/', '\\\\\1', $str);
}
$hostapd = parse_ini_file(RASPI_HOSTAPD_CONFIG, false, INI_SCANNER_RAW); $hostapd = parse_ini_file(RASPI_HOSTAPD_CONFIG, false, INI_SCANNER_RAW);
// assume wpa encryption and get the passphrase // assume wpa encryption and get the passphrase

View file

@ -348,6 +348,36 @@ function updateBlocklist() {
function clearBlocklistStatus() { function clearBlocklistStatus() {
$('#cbxblocklist-status').removeClass('check-updated').addClass('check-hidden'); $('#cbxblocklist-status').removeClass('check-updated').addClass('check-hidden');
} }
// Handler for the wireguard generate key button
$('.wg-keygen').click(function(){
var entity_pub = $(this).parent('div').prev('input[type="text"]');
var entity_priv = $(this).parent('div').next('input[type="hidden"]');
var updated = entity_pub.attr('name')+"-pubkey-status";
$.post('ajax/networking/get_wgkey.php',{'entity':entity_pub.attr('name') },function(data){
var jsonData = JSON.parse(data);
entity_pub.val(jsonData.pubkey);
$('#' + updated).removeClass('check-hidden').addClass('check-updated').delay(500).animate({ opacity: 1 }, 700);
})
})
// Event listener for Bootstrap's form validation
window.addEventListener('load', function() {
// Fetch all the forms we want to apply custom Bootstrap validation styles to
var forms = document.getElementsByClassName('needs-validation');
// Loop over them and prevent submission
var validation = Array.prototype.filter.call(forms, function(form) {
form.addEventListener('submit', function(event) {
//console.log(event.submitter);
if (form.checkValidity() === false) {
event.preventDefault();
event.stopPropagation();
}
form.classList.add('was-validated');
}, false);
});
}, false);
// Static Array method // Static Array method
Array.range = (start, end) => Array.from({length: (end - start)}, (v, k) => k + start); Array.range = (start, end) => Array.from({length: (end - start)}, (v, k) => k + start);

View file

@ -21,6 +21,8 @@ define('RASPI_WPA_CTRL_INTERFACE', '/var/run/wpa_supplicant');
define('RASPI_OPENVPN_CLIENT_CONFIG', '/etc/openvpn/client/client.conf'); define('RASPI_OPENVPN_CLIENT_CONFIG', '/etc/openvpn/client/client.conf');
define('RASPI_OPENVPN_CLIENT_LOGIN', '/etc/openvpn/client/login.conf'); define('RASPI_OPENVPN_CLIENT_LOGIN', '/etc/openvpn/client/login.conf');
define('RASPI_OPENVPN_SERVER_CONFIG', '/etc/openvpn/server/server.conf'); define('RASPI_OPENVPN_SERVER_CONFIG', '/etc/openvpn/server/server.conf');
define('RASPI_WIREGUARD_PATH', '/etc/wireguard/');
define('RASPI_WIREGUARD_CONFIG', RASPI_WIREGUARD_PATH.'wg0.conf');
define('RASPI_TORPROXY_CONFIG', '/etc/tor/torrc'); define('RASPI_TORPROXY_CONFIG', '/etc/tor/torrc');
define('RASPI_LIGHTTPD_CONFIG', '/etc/lighttpd/lighttpd.conf'); define('RASPI_LIGHTTPD_CONFIG', '/etc/lighttpd/lighttpd.conf');
define('RASPI_ACCESS_CHECK_IP', '1.1.1.1'); define('RASPI_ACCESS_CHECK_IP', '1.1.1.1');
@ -37,6 +39,7 @@ define('RASPI_NETWORK_ENABLED', true);
define('RASPI_DHCP_ENABLED', true); define('RASPI_DHCP_ENABLED', true);
define('RASPI_ADBLOCK_ENABLED', false); define('RASPI_ADBLOCK_ENABLED', false);
define('RASPI_OPENVPN_ENABLED', false); define('RASPI_OPENVPN_ENABLED', false);
define('RASPI_WIREGUARD_ENABLED', false);
define('RASPI_TORPROXY_ENABLED', false); define('RASPI_TORPROXY_ENABLED', false);
define('RASPI_CONFAUTH_ENABLED', true); define('RASPI_CONFAUTH_ENABLED', true);
define('RASPI_CHANGETHEME_ENABLED', true); define('RASPI_CHANGETHEME_ENABLED', true);

View file

@ -33,6 +33,22 @@
"uap0": { "uap0": {
"dhcp-range": [ "192.168.50.50,192.168.50.150,12h" ] "dhcp-range": [ "192.168.50.50,192.168.50.150,12h" ]
} }
},
"wireguard": {
"server": {
"Address": [ "10.8.2.1/24" ],
"ListenPort": [ "51820" ],
"DNS": [ "9.9.9.9" ],
"PostUp": [ "iptables -A FORWARD -i wlan0 -o wg0 -j ACCEPT; iptables -A FORWARD -i wg0 -o wlan0 -m state --state RELATED,ESTABLISHED -j ACCEPT; iptables -t nat -A POSTROUTING -o wg0 -j MASQUERADE" ],
"PostDown": [ "iptables -D FORWARD -i wlan0 -o wg0 -j ACCEPT; iptables -D FORWARD -i wg0 -o wlan0 -m state --state RELATED,ESTABLISHED -j ACCEPT; iptables -t nat -D POSTROUTING -o wg0 -j MASQUERADE" ]
},
"peer": {
"Address": [ "10.8.1.2/24" ],
"Endpoint": [ "10.8.2.1:51820" ],
"ListenPort": [ "21841" ],
"AllowedIPs": ["10.8.2.0/24"],
"PersistentKeepalive": [ "15" ]
}
} }
} }

BIN
dist/raspap/css/fonts/RaspAP.eot vendored Executable file

Binary file not shown.

12
dist/raspap/css/fonts/RaspAP.svg vendored Executable file
View file

@ -0,0 +1,12 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
<svg xmlns="http://www.w3.org/2000/svg">
<metadata>Generated by IcoMoon</metadata>
<defs>
<font id="RaspAP" horiz-adv-x="1024">
<font-face units-per-em="1024" ascent="960" descent="-64" />
<missing-glyph horiz-adv-x="1024" />
<glyph unicode="&#x20;" horiz-adv-x="512" d="" />
<glyph unicode="&#xe900;" glyph-name="wireguard" d="M1023.147 463.147c0 0 23.595 496.853-522.453 496.853-482.859 0-497.963-476.587-497.963-476.587s-70.997-547.413 509.141-547.413c556.501 0 511.275 527.147 511.275 527.147zM347.947 636.757c102.4 62.72 233.344 24.363 282.368-69.888 9.301-17.877 10.496-45.355 4.608-64.128-20.352-64.683-68.309-100.949-134.187-116.395 19.413 16.64 34.859 35.499 39.808 61.525 1.195 5.504 1.88 11.827 1.88 18.31 0 20.027-6.533 38.528-17.584 53.488l0.174-0.246c-16.797 22.874-43.588 37.556-73.809 37.556-11.257 0-22.038-2.037-31.995-5.763l0.63 0.207c-40.533-15.36-62.72-52.395-58.752-97.877 3.712-42.24 35.797-69.632 95.787-80.043-8.96-4.736-15.872-8.235-22.613-11.989-27.988-15.524-51.374-35.995-69.74-60.451l-0.404-0.562c-6.101-8.192-10.24-8.875-19.541-3.2-120.619 73.771-128.384 258.859 3.371 339.456zM257.707 180.992c-19.413-4.949-38.187-12.203-57.984-18.688 9.685 65.365 86.229 125.568 150.997 118.699-18.043-24.598-29.583-54.982-31.551-87.945l-0.022-0.46c-21.504-3.968-41.813-6.613-61.44-11.605zM669.995 819.2c19.115-0.725 38.315-0.427 57.472-0.853 5.287-0.363 10.162-1.075 14.91-2.128l-0.659 0.123c-4.574-6.938-9.348-12.986-14.582-18.599l0.076 0.082c-6.827-6.4-14.549-12.629-24.448-2.944-2.347 2.347-7.979 1.792-12.075 1.877-19.072 0.213-38.144 0.853-57.173 0.128-17.856-0.589-34.82-2.396-51.386-5.353l2.149 0.318c-3.072-0.555-7.595-10.667-6.229-14.421 3.328-8.832 8.149-18.56 15.317-24.192 26.411-20.907 54.485-39.595 81.067-60.288 25.771-20.139 49.792-42.24 64.427-72.533 19.029-39.595 19.627-81.067 11.392-122.752-13.739-69.547-48.939-127.147-105.941-169.045-22.955-16.853-51.413-26.453-77.696-38.528-23.168-10.667-46.933-19.84-70.144-30.379-41.813-19.029-65.28-64.427-58.411-111.573 6.357-43.307 44.373-79.445 87.851-86.912 52.181-8.96 106.069 25.003 118.827 78.080 14.336 59.605-18.048 112.896-78.72 129.024l-10.923 2.816c16.213 7.253 30.208 12.416 43.179 19.541q33.835 18.645 66.475 39.467c6.4 4.096 9.856 4.096 15.36-0.597 41.685-36.096 66.56-80.981 73.557-135.979 11.52-91.093-31.573-174.763-112.896-217.643-125.781-66.347-279.765 9.173-307.541 148.651-23.808 119.467 60.501 227.84 162.005 248.747 43.648 9.003 83.541 27.179 114.56 60.8 20.053 21.675 29.739 40.277 33.067 48.683 5.86 14.568 9.259 31.458 9.259 49.142 0 0.094 0 0.187 0 0.281v-0.014c-0.72 15.473-4.371 29.921-10.408 43.044l0.296-0.719c-10.581 24.149-51.2 62.549-61.227 70.656l-95.573 74.837c-3.371 2.773-7.168 2.56-15.36 2.005-9.813-0.683-34.773-2.048-45.525 0.768 8.704 6.613 32.427 16.213 42.667 23.893-30.976 20.907-66.304 13.397-98.773 19.627 7.509 13.995 44.629 35.456 65.749 37.888-1.455 13.545-3.483 25.484-6.166 37.173l0.406-2.101c-1.28 4.736-6.571 9.387-11.221 12.075-11.179 6.571-23.083 11.989-35.968 18.517 10.935 7.156 24.244 11.558 38.555 11.945l0.101 0.002c1.66 0.068 3.608 0.107 5.566 0.107 11.77 0 23.21-1.408 34.163-4.064l-0.987 0.202c23.040-5.248 41.387-1.792 59.691 13.824-14.421 5.803-28.843 11.093-42.795 17.365-16.163 7.396-29.343 14.415-42.082 22.091l1.89-1.056c36.267-5.035 71.296-18.645 108.373-13.653l0.939 5.035-86.101 20.053c51.328 4.693 99.115 5.461 144.384-16.555 12.757-6.229 26.027-11.349 38.272-18.432 5.973-3.413 9.941-10.24 14.848-15.573 3.84-4.181 6.997-9.813 11.776-12.373 18.091-9.6 37.973-9.984 58.283-9.515l0.427 6.827c20.437-6.4 43.392-29.952 43.392-47.147-33.109 0-66.133 0.128-99.2-0.171-3.541 0-7.040-2.603-10.539-4.011 3.328-1.963 6.613-5.461 10.027-5.589zM627.328 868.139c-1.461-0.899-2.42-2.488-2.42-4.302 0-1.516 0.67-2.876 1.731-3.799l0.006-0.005c1.344-2.305 3.804-3.83 6.62-3.83 1.429 0 2.767 0.393 3.91 1.076l-0.035-0.019c3.2 1.621 6.315 3.328 10.155 5.333-3.072 2.645-5.547 4.864-8.107 6.955-4.523 3.712-8.235 1.365-11.861-1.408z" />
<glyph unicode="&#xe901;" glyph-name="raspap" horiz-adv-x="1031" d="M540.058 281.983c0-104.182-84.446-188.637-188.625-188.637-104.176 0-188.62 84.455-188.62 188.637 0 104.171 84.444 188.625 188.62 188.625 104.179 0 188.625-84.455 188.625-188.625zM351.437 550.062c-147.818 0-268.074-120.259-268.074-268.080 0-147.826 120.257-268.091 268.074-268.091s268.077 120.265 268.077 268.091c0 147.821-120.259 268.080-268.077 268.080zM351.437-58.985c-188 0-340.95 152.958-340.95 340.967 0 188.003 152.95 340.956 340.95 340.956 188.003 0 340.953-152.953 340.953-340.956 0-188.009-152.95-340.967-340.953-340.967zM404.82 698.222c185.52 0 339.484-137.497 365.479-315.929l79.208-5.253c-24.125 224.046-214.339 399.077-444.686 399.077-10.909 0-21.723-0.412-32.433-1.186l5.16-77.823c9.017 0.661 18.093 1.113 27.272 1.113zM404.989 874.303c285.73 0 520.41-222.659 539.731-503.584l78.375-5.205c-16.843 326.355-287.644 586.685-618.106 586.685-14.884 0-29.644-0.561-44.264-1.6l5.157-77.719c12.919 0.928 25.958 1.424 39.106 1.424z" />
</font></defs></svg>

After

Width:  |  Height:  |  Size: 5 KiB

BIN
dist/raspap/css/fonts/RaspAP.ttf vendored Executable file

Binary file not shown.

BIN
dist/raspap/css/fonts/RaspAP.woff vendored Executable file

Binary file not shown.

54
dist/raspap/css/style.css vendored Normal file
View file

@ -0,0 +1,54 @@
/*!
* RaspAP-Brands Brand Icons - https://raspap.com
* License - https://github.com/billz/RaspAP-Brands-webgui/blob/master/LICENSE
*/
@font-face {
font-family: 'RaspAP';
src: url('fonts/RaspAP.eot?e76qs3');
src: url('fonts/RaspAP.eot?e76qs3#iefix') format('embedded-opentype'),
url('fonts/RaspAP.ttf?e76qs3') format('truetype'),
url('fonts/RaspAP.woff?e76qs3') format('woff'),
url('fonts/RaspAP.svg?e76qs3#RaspAP') format('svg');
font-weight: normal;
font-style: normal;
font-display: block;
}
[class^="ra-"], [class*=" ra-"] {
/* use !important to prevent issues with browser extensions that change ..webfonts */
font-family: 'RaspAP' !important;
speak: none;
font-style: normal;
font-weight: normal;
font-variant: normal;
text-transform: none;
line-height: 1;
/* Better Font Rendering =========== */
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.ra-wireguard:before {
font-size: 1.2rem;
content: "\e900";
color: #d1d3e2;
vertical-align: middle;
}
.card-header .ra-wireguard:before {
color: #fff;
}
.sidebar .nav-item.active .nav-link
span.ra-wireguard:before {
color: #6e707e;
}
.ra-raspap:before {
font-size: 4.35rem;
content: "\e901";
color: #d8224c;
margin-left: 0.1em;
}

View file

@ -26,6 +26,8 @@ $defaults = [
'RASPI_OPENVPN_CLIENT_CONFIG' => '/etc/openvpn/client/client.conf', 'RASPI_OPENVPN_CLIENT_CONFIG' => '/etc/openvpn/client/client.conf',
'RASPI_OPENVPN_CLIENT_LOGIN' => '/etc/openvpn/client/login.conf', 'RASPI_OPENVPN_CLIENT_LOGIN' => '/etc/openvpn/client/login.conf',
'RASPI_OPENVPN_SERVER_CONFIG' => '/etc/openvpn/server/server.conf', 'RASPI_OPENVPN_SERVER_CONFIG' => '/etc/openvpn/server/server.conf',
'RASPI_WIREGUARD_PATH' => '/etc/wireguard/',
'RASPI_WIREGUARD_CONFIG' => RASPI_WIREGUARD_PATH.'wg0.conf',
'RASPI_TORPROXY_CONFIG' => '/etc/tor/torrc', 'RASPI_TORPROXY_CONFIG' => '/etc/tor/torrc',
'RASPI_LIGHTTPD_CONFIG' => '/etc/lighttpd/lighttpd.conf', 'RASPI_LIGHTTPD_CONFIG' => '/etc/lighttpd/lighttpd.conf',
'RASPI_ACCESS_CHECK_IP' => '1.1.1.1', 'RASPI_ACCESS_CHECK_IP' => '1.1.1.1',
@ -42,6 +44,7 @@ $defaults = [
'RASPI_DHCP_ENABLED' => true, 'RASPI_DHCP_ENABLED' => true,
'RASPI_ADBLOCK_ENABLED' => false, 'RASPI_ADBLOCK_ENABLED' => false,
'RASPI_OPENVPN_ENABLED' => false, 'RASPI_OPENVPN_ENABLED' => false,
'RASPI_WIREGUARD_ENABLED' => false,
'RASPI_TORPROXY_ENABLED' => false, 'RASPI_TORPROXY_ENABLED' => false,
'RASPI_CONFAUTH_ENABLED' => true, 'RASPI_CONFAUTH_ENABLED' => true,
'RASPI_CHANGETHEME_ENABLED' => true, 'RASPI_CHANGETHEME_ENABLED' => true,

View file

@ -715,6 +715,33 @@ function getBridgedState()
return $arrHostapdConf['BridgedEnable']; return $arrHostapdConf['BridgedEnable'];
} }
/**
* Validates the format of a CIDR notation string
*
* @param string $cidr
* @return bool
*/
function validateCidr($cidr)
{
$parts = explode('/', $cidr);
if(count($parts) != 2) {
return false;
}
$ip = $parts[0];
$netmask = intval($parts[1]);
if($netmask < 0) {
return false;
}
if(filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
return $netmask <= 32;
}
if(filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
return $netmask <= 128;
}
return false;
}
// Validates a host or FQDN // Validates a host or FQDN
function validate_host($host) { function validate_host($host) {
return preg_match('/^([a-z\d](-*[a-z\d])*)(\.([a-z\d](-*[a-z\d])*))*$/i', $host); return preg_match('/^([a-z\d](-*[a-z\d])*)(\.([a-z\d](-*[a-z\d])*))*$/i', $host);
@ -730,3 +757,11 @@ function getNightmode(){
} }
} }
// Sanitizes a string for QR encoding
// @param string $str
// @return string
function qr_encode($str)
{
return preg_replace('/(?<!\\\)([\":;,])/', '\\\\\1', $str);
}

222
includes/wireguard.php Normal file
View file

@ -0,0 +1,222 @@
<?php
require_once 'includes/status_messages.php';
require_once 'config.php';
/**
* Displays wireguard server & peer configuration
*/
function DisplayWireGuardConfig()
{
$status = new StatusMessages();
if (!RASPI_MONITOR_ENABLED) {
if (isset($_POST['savewgsettings'])) {
SaveWireGuardConfig($status);
} elseif (isset($_POST['startwg'])) {
$status->addMessage('Attempting to start WireGuard', 'info');
exec('sudo /bin/systemctl start wg-quick@wg0', $return);
foreach ($return as $line) {
$status->addMessage($line, 'info');
}
} elseif (isset($_POST['stopwg'])) {
$status->addMessage('Attempting to stop WireGuard', 'info');
exec('sudo /bin/systemctl stop wg-quick@wg0', $return);
foreach ($return as $line) {
$status->addMessage($line, 'info');
}
}
}
// fetch wg config
exec('sudo cat '. RASPI_WIREGUARD_CONFIG, $return);
$conf = ParseConfig($return);
$wg_srvpubkey = exec('sudo cat '. RASPI_WIREGUARD_PATH .'wg-server-public.key', $return);
$wg_srvport = ($conf['ListenPort'] == '') ? getDefaultNetValue('wireguard','server','ListenPort') : $conf['ListenPort'];
$wg_srvipaddress = ($conf['Address'] == '') ? getDefaultNetValue('wireguard','server','Address') : $conf['Address'];
$wg_srvdns = ($conf['DNS'] == '') ? getDefaultNetValue('wireguard','server','DNS') : $conf['DNS'];
$wg_peerpubkey = exec('sudo cat '. RASPI_WIREGUARD_PATH .'wg-peer-public.key', $return);
if (sizeof($conf) >0) {
$wg_senabled = true;
}
// todo: iterate multiple peer configs
exec('sudo cat '. RASPI_WIREGUARD_PATH.'client.conf', $preturn);
$conf = ParseConfig($preturn);
$wg_pipaddress = ($conf['Address'] == '') ? getDefaultNetValue('wireguard','peer','Address') : $conf['Address'];
$wg_plistenport = ($conf['ListenPort'] == '') ? getDefaultNetValue('wireguard','peer','ListenPort') : $conf['ListenPort'];
$wg_pendpoint = ($conf['Endpoint'] == '') ? getDefaultNetValue('wireguard','peer','Endpoint') : $conf['Endpoint'];
$wg_pallowedips = ($conf['AllowedIPs'] == '') ? getDefaultNetValue('wireguard','peer','AllowedIPs') : $conf['AllowedIPs'];
$wg_pkeepalive = ($conf['PersistentKeepalive'] == '') ? getDefaultNetValue('wireguard','peer','PersistentKeepalive') : $conf['PersistentKeepalive'];
if (sizeof($conf) >0) {
$wg_penabled = true;
}
// fetch service status
exec('pidof wg-crypt-wg0 | wc -l', $wgstatus);
$serviceStatus = $wgstatus[0] == 0 ? "down" : "up";
$wg_state = ($wgstatus[0] > 0);
echo renderTemplate(
"wireguard", compact(
"status",
"wg_state",
"serviceStatus",
"wg_log",
"peer_id",
"wg_srvpubkey",
"wg_srvport",
"wg_srvipaddress",
"wg_srvdns",
"wg_senabled",
"wg_penabled",
"wg_pipaddress",
"wg_plistenport",
"wg_peerpubkey",
"wg_pendpoint",
"wg_pallowedips",
"wg_pkeepalive"
)
);
}
/**
* Validate user input, save wireguard configuration
*
* @param object $status
* @return boolean
*/
function SaveWireGuardConfig($status)
{
// Set defaults
$good_input = true;
$peer_id = 1;
// Validate server input
if ($_POST['wg_senabled'] == 1) {
if (isset($_POST['wg_srvport'])) {
if (strlen($_POST['wg_srvport']) > 5 || !is_numeric($_POST['wg_srvport'])) {
$status->addMessage('Invalid value for server local port', 'danger');
$good_input = false;
}
}
if (isset($_POST['wg_plistenport'])) {
if (strlen($_POST['wg_plistenport']) > 5 || !is_numeric($_POST['wg_plistenport'])) {
$status->addMessage('Invalid value for peer local port', 'danger');
$good_input = false;
}
}
if (isset($_POST['wg_srvipaddress'])) {
if (!validateCidr($_POST['wg_srvipaddress'])) {
$status->addMessage('Invalid value for server IP address', 'danger');
$good_input = false;
}
}
if (isset($_POST['wg_srvdns'])) {
if (!filter_var($_POST['wg_srvdns'],FILTER_VALIDATE_IP)) {
$status->addMessage('Invalid value for DNS', 'danger');
$good_input = false;
}
}
}
// Validate peer input
if ($_POST['wg_penabled'] == 1) {
if (isset($_POST['wg_pipaddress'])) {
if (!validateCidr($_POST['wg_pipaddress'])) {
$status->addMessage('Invalid value for peer IP address', 'danger');
$good_input = false;
}
}
if (isset($_POST['wg_pendpoint']) && strlen(trim($_POST['wg_pendpoint']) >0 )) {
$wg_pendpoint_seg = substr($_POST['wg_pendpoint'],0,strpos($_POST['wg_pendpoint'],':'));
if (!filter_var($wg_pendpoint_seg,FILTER_VALIDATE_IP)) {
$status->addMessage('Invalid value for endpoint address', 'danger');
$good_input = false;
}
}
if (isset($_POST['wg_pallowedips']) && strlen(trim($_POST['wg_pallowedips']) >0)) {
if (!validateCidr($_POST['wg_pallowedips'])) {
$status->addMessage('Invalid value for allowed IPs', 'danger');
$good_input = false;
}
}
if (isset($_POST['wg_pkeepalive']) && strlen(trim($_POST['wg_pkeepalive']) >0 )) {
if (strlen($_POST['wg_pkeepalive']) > 4 || !is_numeric($_POST['wg_pkeepalive'])) {
$status->addMessage('Invalid value for persistent keepalive', 'danger');
$good_input = false;
}
}
}
// Save settings
if ($good_input) {
// server (wg0.conf)
if ($_POST['wg_senabled'] == 1) {
// fetch server private key from filesytem
$wg_srvprivkey = exec('sudo cat '. RASPI_WIREGUARD_PATH .'wg-server-private.key', $return);
$config[] = '[Interface]';
$config[] = 'Address = '.$_POST['wg_srvipaddress'];
$config[] = 'ListenPort = '.$_POST['wg_srvport'];
$config[] = 'DNS = '.$_POST['wg_srvdns'];
$config[] = 'PrivateKey = '.$wg_srvprivkey;
$config[] = 'PostUp = '.getDefaultNetValue('wireguard','server','PostUp');
$config[] = 'PostDown = '.getDefaultNetValue('wireguard','server','PostDown');
$config[] = '';
$config[] = '[Peer]';
$config[] = 'PublicKey = '.$_POST['wg-peer'];
$config[] = 'AllowedIPs = '.$_POST['wg_pallowedips'];
if ($_POST['wg_pkeepalive'] !== '') {
$config[] = 'PersistentKeepalive = '.trim($_POST['wg_pkeepalive']);
}
$config[] = '';
$config = join(PHP_EOL, $config);
file_put_contents("/tmp/wgdata", $config);
system('sudo cp /tmp/wgdata '.RASPI_WIREGUARD_CONFIG, $return);
} else {
# remove selected conf + keys
system('sudo rm '. RASPI_WIREGUARD_PATH .'wg-server-private.key', $return);
system('sudo rm '. RASPI_WIREGUARD_PATH .'wg-server-public.key', $return);
system('sudo rm '. RASPI_WIREGUARD_CONFIG, $return);
}
// client1 (client.conf)
if ($_POST['wg_penabled'] == 1) {
// fetch peer private key from filesystem
$wg_peerprivkey = exec('sudo cat '. RASPI_WIREGUARD_PATH .'wg-peer-private.key', $return);
$config = [];
$config[] = '[Interface]';
$config[] = 'Address = '.trim($_POST['wg_pipaddress']);
$config[] = 'PrivateKey = '.$wg_peerprivkey;
$config[] = 'ListenPort = '.$_POST['wg_plistenport'];
$config[] = '';
$config[] = '[Peer]';
$config[] = 'PublicKey = '.$_POST['wg-server'];
$config[] = 'AllowedIPs = '.$_POST['wg_pallowedips'];
$config[] = 'Endpoint = '.$_POST['wg_pendpoint'];
if ($_POST['wg_pkeepalive'] !== '') {
$config[] = 'PersistentKeepalive = '.trim($_POST['wg_pkeepalive']);
}
$config[] = '';
$config = join(PHP_EOL, $config);
file_put_contents("/tmp/wgdata", $config);
system('sudo cp /tmp/wgdata '.RASPI_WIREGUARD_PATH.'client.conf', $return);
} else {
# remove selected conf + keys
system('sudo rm '. RASPI_WIREGUARD_PATH .'wg-peer-private.key', $return);
system('sudo rm '. RASPI_WIREGUARD_PATH .'wg-peer-public.key', $return);
system('sudo rm '. RASPI_WIREGUARD_PATH.'client.conf', $return);
}
// handle log option
if ($_POST['wg_log'] == "1") {
exec("sudo /bin/systemctl status wg-quick@wg0 | sudo tee /tmp/wireguard.log > /dev/null");
}
foreach ($return as $line) {
$status->addMessage($line, 'info');
}
if ($return == 0) {
$status->addMessage('WireGuard configuration updated successfully', 'success');
} else {
$status->addMessage('WireGuard configuration failed to be updated', 'danger');
}
}
}

View file

@ -45,6 +45,7 @@ require_once 'includes/themes.php';
require_once 'includes/data_usage.php'; require_once 'includes/data_usage.php';
require_once 'includes/about.php'; require_once 'includes/about.php';
require_once 'includes/openvpn.php'; require_once 'includes/openvpn.php';
require_once 'includes/wireguard.php';
require_once 'includes/torproxy.php'; require_once 'includes/torproxy.php';
$config = getConfig(); $config = getConfig();
@ -82,6 +83,9 @@ $bridgedEnabled = getBridgedState();
<!-- Custom Fonts --> <!-- Custom Fonts -->
<link href="dist/fontawesome-free/css/all.min.css" rel="stylesheet" type="text/css"> <link href="dist/fontawesome-free/css/all.min.css" rel="stylesheet" type="text/css">
<!-- RaspAP Fonts -->
<link href="dist/raspap/css/style.css" rel="stylesheet" type="text/css">
<!-- Custom CSS --> <!-- Custom CSS -->
<link href="<?php echo $theme_url; ?>" title="main" rel="stylesheet"> <link href="<?php echo $theme_url; ?>" title="main" rel="stylesheet">
@ -161,6 +165,11 @@ $bridgedEnabled = getBridgedState();
<?php if (RASPI_OPENVPN_ENABLED) : ?> <?php if (RASPI_OPENVPN_ENABLED) : ?>
<li class="nav-item"> <li class="nav-item">
<a class="nav-link" href="openvpn_conf"><i class="fas fa-key fa-fw mr-2"></i><span class="nav-label"><?php echo _("OpenVPN"); ?></a> <a class="nav-link" href="openvpn_conf"><i class="fas fa-key fa-fw mr-2"></i><span class="nav-label"><?php echo _("OpenVPN"); ?></a>
</li>
<?php endif; ?>
<?php if (RASPI_WIREGUARD_ENABLED) : ?>
<li class="nav-item">
<a class="nav-link" href="wg_conf"><span class="ra-wireguard mr-2"></span><span class="nav-label"><?php echo _("WireGuard"); ?></a>
</li> </li>
<?php endif; ?> <?php endif; ?>
<?php if (RASPI_TORPROXY_ENABLED) : ?> <?php if (RASPI_TORPROXY_ENABLED) : ?>
@ -259,6 +268,9 @@ $bridgedEnabled = getBridgedState();
case "/openvpn_conf": case "/openvpn_conf":
DisplayOpenVPNConfig(); DisplayOpenVPNConfig();
break; break;
case "/wg_conf":
DisplayWireGuardConfig();
break;
case "/torproxy_conf": case "/torproxy_conf":
DisplayTorProxyConfig(); DisplayTorProxyConfig();
break; break;

View file

@ -39,7 +39,17 @@ www-data ALL=(ALL) NOPASSWD:/etc/raspap/openvpn/configauth.sh
www-data ALL=(ALL) NOPASSWD:/etc/raspap/openvpn/openvpnlog.sh www-data ALL=(ALL) NOPASSWD:/etc/raspap/openvpn/openvpnlog.sh
www-data ALL=(ALL) NOPASSWD:/bin/chmod o+r /tmp/hostapd.log www-data ALL=(ALL) NOPASSWD:/bin/chmod o+r /tmp/hostapd.log
www-data ALL=(ALL) NOPASSWD:/bin/chmod o+r /tmp/dnsmasq.log www-data ALL=(ALL) NOPASSWD:/bin/chmod o+r /tmp/dnsmasq.log
www-data ALL=(ALL) NOPASSWD:/bin/chmod o+r /tmp/wireguard.log
www-data ALL=(ALL) NOPASSWD:/bin/cp /tmp/dnsmasqdata /etc/dnsmasq.d/090_adblock.conf www-data ALL=(ALL) NOPASSWD:/bin/cp /tmp/dnsmasqdata /etc/dnsmasq.d/090_adblock.conf
www-data ALL=(ALL) NOPASSWD:/bin/cp /tmp/dnsmasq_custom /etc/raspap/adblock/custom.txt www-data ALL=(ALL) NOPASSWD:/bin/cp /tmp/dnsmasq_custom /etc/raspap/adblock/custom.txt
www-data ALL=(ALL) NOPASSWD:/bin/cp /tmp/wgdata /etc/wireguard/*.conf
www-data ALL=(ALL) NOPASSWD:/bin/mv /tmp/wg-*.key /etc/wireguard/wg-*.key
www-data ALL=(ALL) NOPASSWD:/etc/raspap/adblock/update_blocklist.sh www-data ALL=(ALL) NOPASSWD:/etc/raspap/adblock/update_blocklist.sh
www-data ALL=(ALL) NOPASSWD:/usr/bin/tee /tmp/wireguard.log
www-data ALL=(ALL) NOPASSWD:/bin/systemctl * wg-quick@wg0
www-data ALL=(ALL) NOPASSWD:/usr/bin/wg
www-data ALL=(ALL) NOPASSWD:/bin/cat /etc/wireguard/*.conf
www-data ALL=(ALL) NOPASSWD:/bin/cat /etc/wireguard/wg-*.key
www-data ALL=(ALL) NOPASSWD:/bin/rm /etc/wireguard/*.conf
www-data ALL=(ALL) NOPASSWD:/bin/rm /etc/wireguard/wg-*.key

Binary file not shown.

View file

@ -10,7 +10,7 @@ msgstr ""
"Project-Id-Version: 1.2.1\n" "Project-Id-Version: 1.2.1\n"
"Report-Msgid-Bugs-To: Bill Zimmerman <billzimmerman@gmail.com>\n" "Report-Msgid-Bugs-To: Bill Zimmerman <billzimmerman@gmail.com>\n"
"POT-Creation-Date: 2017-10-19 08:56+0000\n" "POT-Creation-Date: 2017-10-19 08:56+0000\n"
"PO-Revision-Date: 2020-03-29 00:05+0000\n" "PO-Revision-Date: 2021-03-08 09:00+0000\n"
"Last-Translator: Bill Zimmerman <billzimmerman@gmail.com>\n" "Last-Translator: Bill Zimmerman <billzimmerman@gmail.com>\n"
"Language-Team: \n" "Language-Team: \n"
"Language: en_US\n" "Language: en_US\n"
@ -725,12 +725,6 @@ msgstr "Cancel"
msgid "Enable this option to log <code>openvpn</code> activity." msgid "Enable this option to log <code>openvpn</code> activity."
msgstr "Enable this option to log <code>openvpn</code> activity." msgstr "Enable this option to log <code>openvpn</code> activity."
msgid "Cancel"
msgstr "Cancel"
msgid "Cancel"
msgstr "Cancel"
#: includes/torproxy.php #: includes/torproxy.php
msgid "TOR is not running" msgid "TOR is not running"
msgstr "TOR is not running" msgstr "TOR is not running"
@ -856,3 +850,83 @@ msgstr "Invalid custom IP address found on line "
msgid "Invalid custom host found on line " msgid "Invalid custom host found on line "
msgstr "Invalid custom host found on line " msgstr "Invalid custom host found on line "
#: includes/wireguard.php
msgid "Tunnel settings"
msgstr "Tunnel settings"
msgid "Enable server"
msgstr "Enable server"
msgid "Enable this option to encrypt traffic by creating a tunnel between RaspAP and configured peers."
msgstr "Enable this option to encrypt traffic by creating a tunnel between RaspAP and configured peers."
msgid "This option adds <code>wg0.conf</code> to the WireGuard configuration."
msgstr "This option adds <code>wg0.conf</code> to the WireGuard configuration."
msgid "Local public key"
msgstr "Local public key"
msgid "Local Port"
msgstr "Local Port"
msgid "IP Address"
msgstr "IP Address"
msgid "DNS"
msgstr "DNS"
msgid "Peer"
msgstr "Peer"
msgid "Enable peer"
msgstr "Enable peer"
msgid "Enable this option to encrypt traffic by creating a tunnel between RaspAP and this peer."
msgstr "Enable this option to encrypt traffic by creating a tunnel between RaspAP and this peer."
msgid "This option adds <code>client.conf</code> to the WireGuard configuration."
msgstr "This option adds <code>client.conf</code> to the WireGuard configuration."
msgid "Peer public key"
msgstr "Peer public key"
msgid "Endpoint address"
msgstr "Endpoint address"
msgid "Allowed IPs"
msgstr "Allowed IPs"
msgid "Persistent keepalive"
msgstr "Persistent keepalive"
msgid "Display WireGuard status"
msgstr "Display WireGuard status"
msgid "Enable this option to display an updated WireGuard status."
msgstr "Enable this option to display an updated WireGuard status."
msgid "Scan this QR code with your client to connect to this tunnel"
msgstr "Scan this QR code with your client to connect to this tunnel"
msgid "Start WireGuard"
msgstr "Start WireGuard"
msgid "Stop WireGuard"
msgstr "Stop WireGuard"
msgid "Information provided by wireguard"
msgstr "Information provided by wireguard"
msgid "Attempting to start WireGuard"
msgstr "Attempting to start WireGuard"
msgid "Attempting to stop WireGuard"
msgstr "Attempting to stop WireGuard"
msgid "WireGuard configuration updated successfully"
msgstr "WireGuard configuration updated successfully"
msgid "WireGuard configuration failed to be updated"
msgstr "WireGuard configuration failed to be updated"

55
templates/wg/general.php Normal file
View file

@ -0,0 +1,55 @@
<!-- wireguard settings tab -->
<div class="tab-pane active" id="wgsettings">
<div class="row">
<div class="col-md-6">
<h4 class="mt-3"><?php echo _("Tunnel settings"); ?></h4>
<div class="input-group">
<div class="custom-control custom-switch">
<input class="custom-control-input" id="server_enabled" type="checkbox" name="wg_senabled" value="1" <?php echo $wg_senabled ? ' checked="checked"' : "" ?> aria-describedby="server-description">
<label class="custom-control-label" for="server_enabled"><?php echo _("Enable server") ?></label>
</div>
<p id="wg-description">
<small><?php echo _("Enable this option to encrypt traffic by creating a tunnel between RaspAP and configured peers.") ?></small>
<small><?php echo _("This option adds <code>wg0.conf</code> to the WireGuard configuration.") ?></small>
</p>
</div>
<div class="row">
<div class="col-xs-3 col-sm-6">
<label for="code"><?php echo _("Local public key"); ?></label>
</div>
<div class="input-group col-md-12 mb-3">
<input type="text" class="form-control" name="wg-server" id="wg-srvpubkey" value="<?php echo htmlspecialchars($wg_srvpubkey, ENT_QUOTES); ?>" />
<div class="input-group-append">
<button class="btn btn-outline-secondary rounded-right wg-keygen" type="button"><i class="fas fa-magic"></i></button>
<span id="wg-server-pubkey-status" class="input-group-addon check-hidden ml-2 mt-1"><i class="fas fa-check"></i></span>
</div>
</div>
</div>
<div class="row">
<div class="form-group col-xs-3 col-sm-3">
<label for="code"><?php echo _("Local Port"); ?></label>
<input type="text" class="form-control" name="wg_srvport" value="<?php echo htmlspecialchars($wg_srvport, ENT_QUOTES); ?>" />
</div>
</div>
<div class="row">
<div class="form-group col-md-6">
<label for="code"><?php echo _("IP Address"); ?></label>
<input type="text" class="form-control" name="wg_srvipaddress" value="<?php echo htmlspecialchars($wg_srvipaddress, ENT_QUOTES); ?>" />
</div>
</div>
<div class="row">
<div class="form-group col-md-6">
<label for="code"><?php echo _("DNS"); ?></label>
<input type="text" class="form-control" name="wg_srvdns" value="<?php echo htmlspecialchars($wg_srvdns, ENT_QUOTES); ?>" />
</div>
</div>
</div>
</div><!-- /.row -->
</div><!-- /.tab-pane | settings tab -->

19
templates/wg/logging.php Normal file
View file

@ -0,0 +1,19 @@
<!-- wireguard logging tab -->
<div class="tab-pane fade" id="wglogging">
<div class="row">
<div class="col-md-12">
<h4 class="mt-3"><?php echo _("Logging"); ?></h4>
<div class="custom-control custom-switch">
<input class="custom-control-input" id="wg_log" type="checkbox" name="wg_log" value="1" <?php echo $wg_log ? ' checked="checked"' : "" ?> aria-describedby="wg_log">
<label class="custom-control-label" for="wg_log"><?php echo _("Display WireGuard status") ?></label>
</div>
<p><small><?php echo _("Enable this option to display an updated WireGuard status.") ?></small></p>
<?php
exec('sudo chmod o+r /tmp/wireguard.log');
$log = file_get_contents('/tmp/wireguard.log');
echo '<textarea class="logoutput my-3">'.htmlspecialchars($log, ENT_QUOTES).'</textarea>';
?>
</div>
</div><!-- /.row -->
</div><!-- /.tab-pane | logging tab -->

78
templates/wg/peers.php Normal file
View file

@ -0,0 +1,78 @@
<!-- wireguard peers tab -->
<div class="tab-pane fade" id="wgpeers">
<div class="row">
<div class="col-md-6">
<h4 class="mt-3"><?php echo _("Peer"); ?></h4>
<div class="input-group">
<input type="hidden" name="peer_id" value="1">
<div class="custom-control custom-switch">
<input class="custom-control-input" id="peer_enabled" type="checkbox" name="wg_penabled" value="1" <?php echo $wg_penabled ? ' checked="checked"' : "" ?> aria-describedby="endpoint-description">
<label class="custom-control-label" for="peer_enabled"><?php echo _("Enable peer") ?></label>
</div>
<p id="wg-description">
<small><?php echo _("Enable this option to encrypt traffic by creating a tunnel between RaspAP and this peer.") ?></small>
<small><?php echo _("This option adds <code>client.conf</code> to the WireGuard configuration.") ?></small>
</p>
</div>
<div class="row">
<div class="col-xs-3 col-sm-6 mt-3">
<label for="code"><?php echo _("Peer public key"); ?></label>
</div>
<div class="input-group col-md-12">
<input type="text" class="form-control" name="wg-peer" id="wg-peerpubkey" value="<?php echo htmlspecialchars($wg_peerpubkey, ENT_QUOTES); ?>" />
<div class="input-group-append">
<button class="btn btn-outline-secondary rounded-right wg-keygen" type="button"><i class="fas fa-magic"></i></button>
<span id="wg-peer-pubkey-status" class="input-group-addon check-hidden ml-2 mt-1"><i class="fas fa-check"></i></span>
</div>
</div>
</div>
<div class="row">
<div class="form-group col-xs-3 col-sm-3 mt-3">
<label for="code"><?php echo _("Local Port"); ?></label>
<input type="text" class="form-control" name="wg_plistenport" value="<?php echo htmlspecialchars($wg_plistenport, ENT_QUOTES); ?>" />
</div>
</div>
<div class="row">
<div class="form-group col-md-6">
<label for="code"><?php echo _("IP Address"); ?></label>
<input type="text" class="form-control" name="wg_pipaddress" value="<?php echo htmlspecialchars($wg_pipaddress, ENT_QUOTES); ?>" />
</div>
</div>
<div class="row">
<div class="form-group col-xs-3 col-sm-6">
<label for="code"><?php echo _("Endpoint address"); ?></label>
<input type="text" class="form-control" name="wg_pendpoint" value="<?php echo htmlspecialchars($wg_pendpoint, ENT_QUOTES); ?>" />
</div>
</div>
<div class="row">
<div class="col-xs-3 col-sm-6">
<label for="code"><?php echo _("Allowed IPs"); ?></label>
<input type="text" class="form-control mb-3" name="wg_pallowedips" value="<?php echo htmlspecialchars($wg_pallowedips, ENT_QUOTES); ?>" />
</div>
</div>
<div class="row">
<div class="col-xs-3 col-sm-6">
<label for="code"><?php echo _("Persistent keepalive"); ?></label>
<input type="text" class="form-control col-sm-3 mb-3" name="wg_pkeepalive" value="<?php echo htmlspecialchars($wg_pkeepalive, ENT_QUOTES); ?>" />
</div>
</div>
</div>
<div class="col-md-6 mt-5">
<figure class="figure">
<?php if ($wg_penabled == true ) : ?>
<img src="app/img/wg-qr-code.php" class="figure-img img-fluid" alt="RaspAP Wifi QR code" style="width:100%;">
<figcaption class="figure-caption"><?php echo _("Scan this QR code with your client to connect to this tunnel"); ?></figcaption>
<?php endif; ?>
</figure>
</div>
</div><!-- /.row -->
</div><!-- /.tab-pane | peers tab -->

53
templates/wireguard.php Normal file
View file

@ -0,0 +1,53 @@
<?php ob_start() ?>
<?php if (!RASPI_MONITOR_ENABLED) : ?>
<input type="submit" class="btn btn-outline btn-primary" name="savewgsettings" value="<?php echo _("Save settings"); ?>">
<?php if ($wg_state) : ?>
<input type="submit" class="btn btn-warning" name="stopwg" value="<?php echo _("Stop WireGuard"); ?>">
<?php else : ?>
<input type="submit" class="btn btn-success" name="startwg" value="<?php echo _("Start WireGuard"); ?>">
<?php endif ?>
<?php endif ?>
<?php $buttons = ob_get_clean(); ob_end_clean() ?>
<div class="row">
<div class="col-lg-12">
<div class="card">
<div class="card-header">
<div class="row">
<div class="col">
<span class="ra-wireguard mr-2"></span><?php echo _("WireGuard"); ?>
</div>
<div class="col">
<button class="btn btn-light btn-icon-split btn-sm service-status float-right">
<span class="icon text-gray-600"><i class="fas fa-circle service-status-<?php echo $serviceStatus ?>"></i></span>
<span class="text service-status">wg <?php echo _($serviceStatus) ?></span>
</button>
</div>
</div><!-- /.row -->
</div><!-- /.card-header -->
<div class="card-body">
<?php $status->showMessages(); ?>
<form role="form" action="/wg_conf" enctype="multipart/form-data" method="POST">
<?php echo CSRFTokenFieldTag() ?>
<!-- Nav tabs -->
<ul class="nav nav-tabs">
<li class="nav-item"><a class="nav-link active" id="settingstab" href="#wgsettings" data-toggle="tab"><?php echo _("Settings"); ?></a></li>
<li class="nav-item"><a class="nav-link" id="peertab" href="#wgpeers" data-toggle="tab"><?php echo _("Peer"); ?></a></li>
<li class="nav-item"><a class="nav-link" id="loggingtab" href="#wglogging" data-toggle="tab"><?php echo _("Logging"); ?></a></li>
</ul>
<!-- Tab panes -->
<div class="tab-content">
<?php echo renderTemplate("wg/general", $__template_data) ?>
<?php echo renderTemplate("wg/peers", $__template_data) ?>
<?php echo renderTemplate("wg/logging", $__template_data) ?>
</div><!-- /.tab-content -->
<?php echo $buttons ?>
</form>
</div><!-- /.card-body -->
<div class="card-footer"><?php echo _("Information provided by wireguard"); ?></div>
</div><!-- /.card -->
</div><!-- /.col-lg-12 -->
</div><!-- /.row -->