mirror of
https://github.com/unraid/webgui.git
synced 2026-01-04 00:19:57 -06:00
1653 lines
77 KiB
Plaintext
1653 lines
77 KiB
Plaintext
Menu="VPNmanager:100"
|
|
Title="Tunnel wg0"
|
|
Tag="icon-vpn"
|
|
Nchan="wg_poller"
|
|
---
|
|
<?PHP
|
|
/* Copyright 2005-2025, Lime Technology
|
|
* Copyright 2012-2025, Bergware International.
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License version 2,
|
|
* as published by the Free Software Foundation.
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in
|
|
* all copies or substantial portions of the Software.
|
|
*/
|
|
?>
|
|
<?
|
|
$etc = '/etc/wireguard';
|
|
$tmp = '/tmp/list.tmp';
|
|
|
|
unset($subnets,$hosts,$subnets6,$hosts6,$vtuns,$filter,$docker);
|
|
exec("ip -4 route show scope link | awk '/^[^d].+ dev (eth|br|bond|wlan)[0-9]+(\\.[0-9]+)?/{print \$1}'",$subnets);
|
|
exec("ip -6 route show type unicast | awk '\$0 !~ \"expires\" && \$3 !~ \"^shim-\" && /^[^dfm:]/{print \$1}'",$subnets6);
|
|
exec("ip -4 -br addr show scope global | awk '/^(br|bond|eth|wlan)[0-9]+(\\.[0-9]+)?/{split(\$3,ip,\"/\");print ip[1]}'",$hosts);
|
|
exec("ip -6 -br addr show scope global -temporary -deprecated | awk '/^(br|bond|eth|wlan)[0-9]+(\\.[0-9]+)?/{split(\$3,ip,\"/\");print ip[1]}'",$hosts6);
|
|
exec("ls --indicator-style=none $etc/wg*.conf* | grep -Po wg[0-9]+",$vtuns);
|
|
exec("docker network ls --filter driver='macvlan' --filter driver='ipvlan' --format='{{.Name}}' 2>/dev/null",$filter);
|
|
|
|
$nginx = (array)@parse_ini_file('state/nginx.ini');
|
|
|
|
// add subnets defined in Docker custom networks
|
|
if (count($filter)) {
|
|
exec("docker network inspect --format='{{range .IPAM.Config}}{{println .Subnet}}{{end}}' ".implode(' ',$filter),$docker);
|
|
foreach (array_filter($docker) as $network) {
|
|
if (strpos($network,'.')!==false && !in_array($network,$subnets)) $subnets[] = $network;
|
|
elseif (strpos($network,':')!==false && !in_array($network,$subnets6)) $subnets6[] = $network;
|
|
}
|
|
}
|
|
$subnets = implode(',',$subnets);
|
|
$hosts = implode(',',$hosts);
|
|
$subnets6 = implode(',',$subnets6);
|
|
$hosts6 = implode(',',$hosts6);
|
|
|
|
function ifname($eth, $new) {
|
|
return str_replace('eth',$new,$eth);
|
|
}
|
|
|
|
function iflink($eth) {
|
|
if (lan_port(ifname($eth,'br'))) return ifname($eth,'br');
|
|
if (lan_port(ifname($eth,'bond'))) return ifname($eth,'bond');
|
|
return $eth;
|
|
}
|
|
|
|
function concat($array) {
|
|
return implode(',',array_map(function($v){return "'$v'";},$array));
|
|
}
|
|
|
|
function readConf(&$peer_wg, &$wg, $vtun) {
|
|
global $etc,$netbase,$netpool,$netbase6,$netpool6,$validIP4,$validIP6;
|
|
$conf = "$etc/$vtun.conf";
|
|
$cfg = "$etc/$vtun.cfg";
|
|
$file = false;
|
|
$vpn = 0;
|
|
if (file_exists($conf) && filesize($conf) > 0) {
|
|
$entries = array_filter(array_map('trim',preg_split('/\[(Interface|Peer)\]/',file_get_contents($conf))));
|
|
foreach ($entries as $key => $entry) {
|
|
$i = $key-1;
|
|
if ($i) $peer_wg[] = $i;
|
|
$rows = explode("\n",$entry);
|
|
foreach ($rows as $row) {
|
|
[$id,$data] = array_map('trim',my_explode('=',$row));
|
|
switch ($id) {
|
|
case 'PostUp':
|
|
case 'PostDown':
|
|
break;
|
|
case 'Address':
|
|
foreach (array_map('trim',explode(',',$data)) as $ip) {
|
|
if (strpos($ip,'.')!==false) $wg["Address:$i"] = $ip;
|
|
elseif (strpos($ip,':')!==false) $wg["Address6:$i"] = $ip;
|
|
}
|
|
break;
|
|
case 'Endpoint':
|
|
if ($data[0]=='[') {
|
|
[$ip,$port] = my_explode(']:',$data);
|
|
$ip = substr($ip,1);
|
|
} else {
|
|
[$ip,$port] = my_explode(':',$data);
|
|
}
|
|
$wg["Endpoint:$i"] = $ip;
|
|
$wg["ListenPort:$i"] = $port;
|
|
break;
|
|
default:
|
|
if ($id[0]=='#') $wg["Name:$i"] = substr($id,1); else $wg["$id:$i"] = $data;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
$file = true;
|
|
}
|
|
if (file_exists($cfg)) {
|
|
$more = parse_ini_file($cfg);
|
|
foreach ($more as $key => $data) {
|
|
[$id,$i] = my_explode(':',$key);
|
|
if ($id!='Address') continue;
|
|
switch ($more['PROT:0']) {
|
|
case '46':
|
|
[$ip4,$ip6] = array_map('trim',my_explode(',',$data));
|
|
$more[$key] = $ip4;
|
|
$more["Address6:$i"] = $ip6;
|
|
break;
|
|
case '6':
|
|
unset($more[$key]);
|
|
$more["Address6:$i"] = $data;
|
|
break;
|
|
}
|
|
}
|
|
$wg = array_merge($wg,$more);
|
|
[$subnet,$mask] = my_explode('/',_var($wg,'Network:0'));
|
|
[$subnet6,$mask6] = my_explode('/',_var($wg,'Network6:0'));
|
|
$netbase[$vtun] = ip2long($subnet) & (0x100000000-2**(32-$mask));
|
|
$netbase6[$vtun] = $subnet6 ?: $netpool6[$vtun];
|
|
} else {
|
|
$netbase[$vtun] = ip2long($netpool[$vtun]);
|
|
$netbase6[$vtun] = $netpool6[$vtun];
|
|
}
|
|
foreach ($peer_wg as $i) if (_var($wg,"TYPE:$i",0)>=7) {$vpn = $wg["TYPE:$i"]; break;}
|
|
return [$conf,$cfg,$file,$vpn];
|
|
}
|
|
|
|
$public = _var($nginx,'NGINX_WANFQDN');
|
|
$active = explode(' ',exec('wg show interfaces'));
|
|
$autostart = explode(' ',@file_get_contents("$etc/autostart")?:'');
|
|
$build = false;
|
|
$script = "$docroot/webGui/scripts/upnp_port";
|
|
$services = "$docroot/webGui/scripts/update_services";
|
|
$template = "$docroot/webGui/WGX.page";
|
|
$tower = _var($var,'NAME');
|
|
$ethX = 'eth0';
|
|
$server = ipaddr($ethX);
|
|
$dnsserver = _var($$ethX,'DNS_SERVER1');
|
|
|
|
$link = iflink($ethX);
|
|
$vhost = str_replace(['eth','br','bond'],'vhost',$link);
|
|
$wlanUp4 = "iptables -t nat -A POSTROUTING -s <source> -o wlan0 -j MASQUERADE";
|
|
$wlanUp6 = "ip6tables -t nat -A POSTROUTING -s <source> -o wlan0 -j MASQUERADE";
|
|
$wlanDown4 = "iptables -t nat -D POSTROUTING -s <source> -o wlan0 -j MASQUERADE";
|
|
$wlanDown6 = "ip6tables -t nat -D POSTROUTING -s <source> -o wlan0 -j MASQUERADE";
|
|
$postUp0 = "$script add $link WireGuard-<wg> $server <port> <port> udp";
|
|
$postUp1 = "logger -t wireguard -- 'Tunnel WireGuard-<wg> started'; $services";
|
|
$postUp2 = "iptables -t nat -A POSTROUTING -s <source> -o $link -j MASQUERADE; iptables -t nat -A POSTROUTING -s <source> -o $vhost -j MASQUERADE; $wlanUp4";
|
|
$postUp3 = "iptables -N WIREGUARD_DROP_<WG>; iptables -A WIREGUARD -o $link -j WIREGUARD_DROP_<WG>";
|
|
$postUpX = "iptables -A WIREGUARD_DROP_<WG> -s <source> -d <target> -j DROP";
|
|
$postUpZ = "iptables -A WIREGUARD_DROP_<WG> -s <source> -j ACCEPT; iptables -A WIREGUARD_DROP_<WG> -j RETURN";
|
|
$postUp26 = "ip6tables -t nat -A POSTROUTING -s <source> -o $link -j MASQUERADE; ip6tables -t nat -A POSTROUTING -s <source> -o $vhost -j MASQUERADE; $wlanUp6";
|
|
$postUp36 = "ip6tables -N WIREGUARD_DROP_<WG>; ip6tables -A WIREGUARD -o $link -j WIREGUARD_DROP_<WG>";
|
|
$postUpX6 = "ip6tables -A WIREGUARD_DROP_<WG> -s <source> -d <target> -j DROP";
|
|
$postUpZ6 = "ip6tables -A WIREGUARD_DROP_<WG> -s <source> -j ACCEPT; ip6tables -A WIREGUARD_DROP_<WG> -j RETURN";
|
|
$postDown0 = "$script del $link <port> udp";
|
|
$postDown1 = "logger -t wireguard -- 'Tunnel WireGuard-<wg> stopped'; $services";
|
|
$postDown2 = "iptables -t nat -D POSTROUTING -s <source> -o $link -j MASQUERADE; iptables -t nat -D POSTROUTING -s <source> -o $vhost -j MASQUERADE; $wlanDown4";
|
|
$postDown3 = "iptables -F WIREGUARD_DROP_<WG>; iptables -D WIREGUARD -o $link -j WIREGUARD_DROP_<WG>; iptables -X WIREGUARD_DROP_<WG>";
|
|
$postDown26= "ip6tables -t nat -D POSTROUTING -s <source> -o $link -j MASQUERADE; ip6tables -t nat -D POSTROUTING -s <source> -o $vhost -j MASQUERADE; $wlanDown6";
|
|
$postDown36= "ip6tables -F WIREGUARD_DROP_<WG>; ip6tables -D WIREGUARD -o $link -j WIREGUARD_DROP_<WG>; ip6tables -X WIREGUARD_DROP_<WG>";
|
|
|
|
$tld = @file_get_contents("$docroot/webGui/include/tld.key")?:'';
|
|
$validDNS = "([0-9a-z]([0-9a-z\-]{0,61}[0-9a-z])?\.)+($tld)";
|
|
$validIP4 = "(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}";
|
|
$validIP6 = "(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|(:|([0-9a-fA-F]{1,4}:)+):(([0-9a-fA-F]{1,4}:)*[0-9a-fA-F]{1,4})?)";
|
|
$maskIP4 = "([0-9]|[12][0-9]|3[0-2])?";
|
|
$maskIP6 = "([0-9]|[1-9][0-9]|1[01][0-9]|12[0-8])?";
|
|
|
|
$validText = "^($validDNS|$validIP4|$validIP6)$";
|
|
$validList = "^(($validIP4/?$maskIP4|$validIP6/?$maskIP6)(, *)?)+$";
|
|
$validDNSServerList = "^(($validIP4|$validIP6)(, *)?)+$";
|
|
$validname = "^[0-9a-zA-Z \-_]*$";
|
|
|
|
$netbase = $netpool = $netport = [];
|
|
$netbase6 = $netpool6 = [];
|
|
$check_wg0 = in_array('wg0',$active) ? 'true' : 'false';
|
|
$start_wg0 = in_array('wg0',$autostart);
|
|
$peer_wg0 = $wg0 = [];
|
|
|
|
$netpool['wg0'] = '10.253.0.0';
|
|
$netpool6['wg0'] = 'fc00:253:0:0::';
|
|
$netport['wg0'] = 51820;
|
|
|
|
// read current configuration
|
|
[$conf_wg0,$cfg_wg0,$this_wg0,$vpn_wg0] = readConf($peer_wg0,$wg0,'wg0');
|
|
|
|
// gather IPv4 and IPv6 addresses for available interfaces
|
|
$endpoints = [];
|
|
$eth = 'eth0';
|
|
while (isset($$eth)) {
|
|
if (!empty($$eth['IPADDR:0'])) $endpoints[] = $$eth['IPADDR:0'];
|
|
if (!empty($$eth['IPADDR6:0'])) $endpoints[] = $$eth['IPADDR6:0'];
|
|
$eth = 'eth'.(substr($eth,3)+1);
|
|
}
|
|
|
|
// remove obsolete tunnels
|
|
foreach (glob("$docroot/webGui/WG[1-9]*.page",GLOB_NOSORT) as $wgX) {
|
|
if (!in_array(strtolower(basename($wgX,'.page')),$vtuns)) {
|
|
delete_file($wgX);
|
|
$build = true;
|
|
}
|
|
}
|
|
|
|
// add additional tunnels
|
|
foreach ($vtuns as $wgX) {
|
|
if ($wgX == 'wg0') continue;
|
|
$file = "$docroot/webGui/".strtoupper($wgX).".page";
|
|
if (!file_exists($file)) {
|
|
$X = filter_var($wgX,FILTER_SANITIZE_NUMBER_INT);
|
|
$nnn = 100 + $X;
|
|
copy($template,$file);
|
|
exec("sed -i 's/parentname:nnn/VPNmanager:$nnn/;s/XXX/$X/g;s/wgX/$wgX/g' $file");
|
|
chmod($file,0644);
|
|
$build = true;
|
|
}
|
|
}
|
|
?>
|
|
<link type="text/css" rel="stylesheet" href="<?autov('/webGui/styles/jquery.switchbutton.css')?>">
|
|
|
|
<script src="<?autov('/webGui/javascript/jquery.switchbutton.js')?>"></script>
|
|
<script>
|
|
<?if ($build):?>
|
|
refresh();
|
|
<?endif;?>
|
|
Number.prototype.long2ip = function(){return [this>>>24,this>>>16&255,this>>>8&255,this&255].join('.');}
|
|
String.prototype.ip2long = function(){var ip=this.split('.');return (ip[0]<<24)+(ip[1]<<16)+(ip[2]<<8)+(ip[3]*1);}
|
|
String.prototype.desc = function(){return this.substr(this.lastIndexOf('/'));}
|
|
String.prototype.patch = function(s,t){return t?this.replace(/<source>/g,s).replace(/<target>/,t):this.replace(/<source>/g,s);}
|
|
Array.prototype.bind = function(w){return (this.join(';')).replace(/<WG>/g,w).replace(/,/g,';');}
|
|
|
|
var xml = $.cookie('upnp')||'<?=@file_get_contents('/var/tmp/upnp')?>';
|
|
var netbase = {}, netpool = {}, netport = {}, netbase6 = {}, netpool6 = {};
|
|
|
|
netbase['wg0'] = <?=_var($netbase,'wg0')?>;
|
|
netpool['wg0'] = "<?=_var($netpool,'wg0')?>";
|
|
netport['wg0'] = "<?=_var($netport,'wg0')?>";
|
|
netbase6['wg0'] = "<?=_var($netbase6,'wg0')?>";
|
|
netpool6['wg0'] = "<?=_var($netpool6,'wg0')?>";
|
|
|
|
// polyfill to fix reportValidity() for Firefox
|
|
if (!HTMLInputElement.prototype.reportValidity || (navigator.userAgent.indexOf("Firefox") !== -1)) {
|
|
HTMLInputElement.prototype.reportValidity = function () {
|
|
if (this.checkValidity()) {
|
|
return true;
|
|
} else {
|
|
var labelText = "_(Invalid data)_";
|
|
try {
|
|
labelText = $(this).closest('dl').children().first()[0].textContent;
|
|
} catch (err) { }
|
|
// the browser generates the validationMessage, we cannot translate it
|
|
swal({title:labelText,text:this.validationMessage,animation:'none',html:true,type:'error',confirmButtonText:"_(Ok)_"});
|
|
return false;
|
|
}
|
|
};
|
|
}
|
|
|
|
function ipv4(ip) {
|
|
return ip.indexOf('.') > 0;
|
|
}
|
|
|
|
function ipv6(ip) {
|
|
return ip.indexOf(':') > 0;
|
|
}
|
|
|
|
function ipset(ip) {
|
|
return ipv4(ip) ? ip : '['+ip+']';
|
|
}
|
|
|
|
function nodefault(ip) {
|
|
return ip != '0.0.0.0/0';
|
|
}
|
|
|
|
function nodefault6(ip) {
|
|
return ip != '::/0';
|
|
}
|
|
|
|
function validateForm(form,vtun) {
|
|
// this runs when the Apply button is clicked, before built-in form validation and before the form's onsubmit function
|
|
// if any fields do not pass basic validation, ensure they are visible then manually show the validation error
|
|
// this prevents validation errors on hidden fields
|
|
var isValid = true;
|
|
form.find('input').each(function(){
|
|
var i = this.name.match(/.*:(\d+)/) ? this.name.match(/.*:(\d+)/)[1] : -1;
|
|
if (i > -1 && !this.checkValidity()) {
|
|
if ($(this).is(":hidden")) {
|
|
var icon = $('#chevron-'+vtun+'-'+i);
|
|
openClose(form,icon,'div.zone'+i);
|
|
}
|
|
this.reportValidity();
|
|
isValid = false;
|
|
}
|
|
});
|
|
return isValid;
|
|
}
|
|
|
|
function prepareSettings(form,vtun) {
|
|
var subnets = '<?=$subnets?>';
|
|
var hosts = '<?=$hosts?>';
|
|
var subnets6 = '<?=$subnets6?>';
|
|
var hosts6 = '<?=$hosts6?>';
|
|
var protocol = form.find('select[name="PROT:0"]').val();
|
|
var listen = form.find('input[name="gui:ListenPort:0"]').val()||netport[vtun];
|
|
var network = form.find('input[name="gui:Network:0"]').val();
|
|
var mypool = netpool[vtun];
|
|
var network6 = form.find('input[name="gui:Network6:0"]').val();
|
|
var mypool6 = netpool6[vtun];
|
|
var vpn = 0;
|
|
form.find('input[name="Network:0"]').val((network||mypool)+'/'+(form.find('input[name="gui:Mask:0"]').val()||24));
|
|
form.find('input[name="Network6:0"]').val((network6||mypool6)+'/'+(form.find('input[name="gui:Mask6:0"]').val()||64));
|
|
form.find('input[name^="Address:"]').each(function(){
|
|
var i = $(this).attr('name').split(':')[1];
|
|
var address = $(this).val();
|
|
var address6 = form.find('input[name="Address6:'+i+'"]').val();
|
|
switch (protocol) {
|
|
case '46': $(this).val(address+', '+address6); break;
|
|
case '6' : $(this).val(address6); break;
|
|
default : break;
|
|
}
|
|
});
|
|
switch (protocol) {
|
|
case '46':
|
|
form.find('input[name="#subnets1"]').val(form.find('input[name="Address:0"]').val()+', '+form.find('input[name="Address6:0"]').val()+', '+subnets+', '+subnets6);
|
|
form.find('input[name="#subnets2"]').val(form.find('input[name="Address:0"]').val()+', '+form.find('input[name="Address6:0"]').val()+', '+hosts+', '+hosts6);
|
|
form.find('input[name="#shared1"]').val(form.find('input[name="Network:0"]').val()+', '+form.find('input[name="Network6:0"]').val()+', '+subnets+', '+subnets6);
|
|
form.find('input[name="#shared2"]').val(form.find('input[name="Network:0"]').val()+', '+form.find('input[name="Network6:0"]').val()+', '+hosts+', '+hosts6);
|
|
break;
|
|
case '6':
|
|
form.find('input[name="#subnets1"]').val(form.find('input[name="Address6:0"]').val()+', '+subnets6);
|
|
form.find('input[name="#subnets2"]').val(form.find('input[name="Address6:0"]').val()+', '+hosts6);
|
|
form.find('input[name="#shared1"]').val(form.find('input[name="Network6:0"]').val()+', '+subnets6);
|
|
form.find('input[name="#shared2"]').val(form.find('input[name="Network6:0"]').val()+', '+hosts6);
|
|
break;
|
|
default:
|
|
form.find('input[name="#subnets1"]').val(form.find('input[name="Address:0"]').val()+', '+subnets);
|
|
form.find('input[name="#subnets2"]').val(form.find('input[name="Address:0"]').val()+', '+hosts);
|
|
form.find('input[name="#shared1"]').val(form.find('input[name="Network:0"]').val()+', '+subnets);
|
|
form.find('input[name="#shared2"]').val(form.find('input[name="Network:0"]').val()+', '+hosts);
|
|
break;
|
|
}
|
|
form.find('select[name^="TYPE:"]').each(function(){if($(this).val()>=7){vpn=$(this).val();return false};});
|
|
if (vpn==0) form.find('input[name="ListenPort:0"]').val(listen);
|
|
form.find('input[name^="gui:Endpoint:"]').each(function(){
|
|
var i = $(this).attr('name').split(':')[2];
|
|
var endpoint = form.find('input[name="Endpoint:'+i+'"]');
|
|
var port = form.find('input[name="gui:ListenPort:'+i+'"]').val()||listen;
|
|
if ($(this).val()) endpoint.val(ipset($(this).val())+':'+port);
|
|
});
|
|
form.find('input[name^="Address6:"]').each(function(){$(this).prop('disabled',true);});
|
|
form.find('input[name^="gui:"]').each(function(){$(this).prop('disabled',true);});
|
|
form.find('input[name="#wg"]').val(tstate[vtun]);
|
|
form.find('input[name="#internet"]').val(ipset(form.find('input[name="#internet"]').val())+':'+listen);
|
|
var upnp = form.find('select[name="UPNP:0"]');
|
|
var postup = form.find('input[name="PostUp:0:0"]');
|
|
var postdown = form.find('input[name="PostDown:0:0"]');
|
|
var source = form.find('input[name="Network:0"]').val();
|
|
var source6 = form.find('input[name="Network6:0"]').val();
|
|
upnp.prop('disabled',false);
|
|
<?if (!is_executable('/usr/bin/upnpc')):?>
|
|
upnp.val('no');
|
|
<?endif;?>
|
|
if (!xml||vpn > 0||upnp.val()=='no') {
|
|
postup.prop('disabled',true);
|
|
postdown.prop('disabled',true);
|
|
} else {
|
|
postup.val(postup.val().replace(/<wg>/,vtun).replace(/<port>/g,listen));
|
|
postdown.val(postdown.val().replace(/<port>/,listen));
|
|
}
|
|
postup = form.find('input[name="PostUp:0:1"]');
|
|
postup.val(postup.val().replace(/<wg>/,vtun));
|
|
postdown = form.find('input[name="PostDown:0:1"]');
|
|
postdown.val(postdown.val().replace(/<wg>/,vtun));
|
|
postup = form.find('input[name="PostUp:0:2"]');
|
|
postdown = form.find('input[name="PostDown:0:2"]');
|
|
var drop = form.find('input[name="DROP:0"]').val();
|
|
var postup1 = [], postup16 = [];
|
|
var postdown1 = [], postdown16 = [];
|
|
var ip4 = []; ip6 = [];
|
|
if (form.find('select[name="NAT:0"]').val()=='') {
|
|
var postup2 = '<?=$postUp2?>';
|
|
var postup26 = '<?=$postUp26?>';
|
|
var postdown2 = '<?=$postDown2?>';
|
|
var postdown26 = '<?=$postDown26?>';
|
|
switch (protocol) {
|
|
case '46':
|
|
postup1.push(postup2.patch(source));
|
|
postdown1.push(postdown2.patch(source));
|
|
postup16.push(postup26.patch(source6));
|
|
postdown16.push(postdown26.patch(source6));
|
|
break;
|
|
case '6':
|
|
postup16.push(postup26.patch(source6));
|
|
postdown16.push(postdown26.patch(source6));
|
|
break;
|
|
default:
|
|
postup1.push(postup2.patch(source));
|
|
postdown1.push(postdown2.patch(source));
|
|
break;
|
|
}
|
|
}
|
|
if (drop) {
|
|
var postup3 = '<?=$postUp3?>';
|
|
var postupX = '<?=$postUpX?>';
|
|
var postupZ = '<?=$postUpZ?>';
|
|
var postup36 = '<?=$postUp36?>';
|
|
var postupX6 = '<?=$postUpX6?>';
|
|
var postupZ6 = '<?=$postUpZ6?>';
|
|
var postdown3 = '<?=$postDown3?>';
|
|
var postdown36 = '<?=$postDown36?>';
|
|
vtun = vtun.toUpperCase();
|
|
drop = drop.replace(/ /g,'').split(',');
|
|
if (form.find('select[name="RULE:0"]').val()) {
|
|
postupX = postupX.replace('-j DROP','-j ACCEPT');
|
|
postupZ = postupZ.replace('-j ACCEPT','-j DROP');
|
|
postupX6 = postupX6.replace('-j DROP','-j ACCEPT');
|
|
postupZ6 = postupZ6.replace('-j ACCEPT','-j DROP');
|
|
}
|
|
for (var i=0,target; target=drop[i]; i++) {
|
|
switch (protocol) {
|
|
case '46':
|
|
if (ipv4(target)) ip4.push(postupX.patch(source,target));
|
|
if (ipv6(target)) ip6.push(postupX6.patch(source6,target));
|
|
break;
|
|
case '6':
|
|
if (ipv6(target)) ip6.push(postupX6.patch(source6,target));
|
|
break;
|
|
default:
|
|
if (ipv4(target)) ip4.push(postupX.patch(source,target));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
switch (protocol) {
|
|
case '46':
|
|
if (ip4.length > 0) {
|
|
postup1.push(postup3);
|
|
postup1.push(ip4);
|
|
postup1.push(postupZ.patch(source));
|
|
postdown1.push(postdown3);
|
|
}
|
|
if (ip6.length > 0) {
|
|
postup16.push(postup36);
|
|
postup16.push(ip6);
|
|
postup16.push(postupZ6.patch(source6));
|
|
postdown16.push(postdown36);
|
|
}
|
|
postup1.push(postup16);
|
|
postdown1.push(postdown16);
|
|
postup.val(postup1.bind(vtun));
|
|
postdown.val(postdown1.bind(vtun));
|
|
break;
|
|
case '6':
|
|
if (ip6.length > 0) {
|
|
postup16.push(postup36);
|
|
postup16.push(ip6);
|
|
postup16.push(postupZ6.patch(source6));
|
|
postdown16.push(postdown36);
|
|
}
|
|
postup.val(postup16.bind(vtun));
|
|
postdown.val(postdown16.bind(vtun));
|
|
break;
|
|
default:
|
|
if (ip4.length > 0) {
|
|
postup1.push(postup3);
|
|
postup1.push(ip4);
|
|
postup1.push(postupZ.patch(source));
|
|
postdown1.push(postdown3);
|
|
}
|
|
postup.val(postup1.bind(vtun));
|
|
postdown.val(postdown1.bind(vtun));
|
|
break;
|
|
}
|
|
$('div[id^="index-'+vtun+'-"]').each(function(){
|
|
var temp = $(this).find('select[name^="TYPE:"]').val();
|
|
if (temp >= 7) form.find('input[name="#type"]').val(temp);
|
|
});
|
|
if (!postup.val()) postup.prop('disabled',true);
|
|
if (!postdown.val()) postdown.prop('disabled',true);
|
|
}
|
|
|
|
function keypair(form,i) {
|
|
$.post('/webGui/include/update.wireguard.php',{'#cmd':'keypair'},function(keys){
|
|
var key = keys.split('\0');
|
|
form.find('.private-'+i).val(key[0]).trigger('change');
|
|
form.find('.public-'+i).val(key[1]).trigger('change');
|
|
});
|
|
}
|
|
|
|
function presharedkey(form,i) {
|
|
$.post('/webGui/include/update.wireguard.php',{'#cmd':'presharedkey'},function(key){
|
|
form.find('.preshared-'+i).val(key).trigger('change');
|
|
});
|
|
}
|
|
|
|
function clearTunnel(vtun) {
|
|
$.removeCookie('my-'+vtun);
|
|
$.removeCookie('view-'+vtun);
|
|
$.removeCookie('block-'+vtun);
|
|
refresh();
|
|
}
|
|
|
|
function addTunnel() {
|
|
console.log('addTunnel');
|
|
$.post('/webGui/include/update.wireguard.php',{'#cmd':'addtunnel','#name':'<?=$tower?>'},function(){refresh();});
|
|
}
|
|
|
|
function delTunnel(vtun) {
|
|
swal({title:"_(Delete Tunnel)_ "+vtun,text:"_(This removes any connections running over this tunnel)_",type:'warning',animation:'none',html:true,confirmButtonText:"_(Proceed)_",cancelButtonText:"_(Cancel)_",showCancelButton:true},function(){
|
|
$.post('/webGui/include/update.wireguard.php',{'#cmd':'deltunnel','#vtun':vtun,'#name':'<?=$tower?>'},function(ok){
|
|
if (ok==0) {
|
|
clearTunnel(vtun);
|
|
} else {
|
|
setTimeout(function(){swal({title:"_(Delete tunnel failed)_",text:"_(Tunnel has running containers attached)_<br>_(Stop corresponding docker containers)_",animation:'none',html:true,type:'error',confirmButtonText:"_(Ok)_"});},250);
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
function addPeer(form,vtun) {
|
|
// don't add peer if there are errors that would be propagated to the peer
|
|
if (!validateForm(form,vtun)) return false;
|
|
|
|
var index = [0];
|
|
form.find('div[id^="index-'+vtun+'-"]').each(function(){index.push($(this).prop('id').split('-')[2]);});
|
|
var i = Math.max(...index)+1;
|
|
var template = $($('<div/>').loadTemplate($('#peer-template-'+vtun)).html().replace(/INDEX/g,i));
|
|
var peer = i==1 ? $('div#peers-list-'+vtun) : $('[id^="index-'+vtun+'-"]').last();
|
|
$(peer).after(template);
|
|
if (i==1) form.find('select[name="TYPE:1"] option').each(function(){$(this).prop('disabled',false);});
|
|
var address = [], address6 = [];
|
|
var protocol = form.find('select[name="PROT:0"]').val();
|
|
if (protocol!='6') {
|
|
form.find('input[name^="Address:"]').each(function(){if ($(this).val()) address.push($(this).val().ip2long());});
|
|
var ip = (Math.max(...address)+1).long2ip();
|
|
form.find('input[name="Address:'+i+'"]').val(ip);
|
|
}
|
|
if (protocol!='') {
|
|
form.find('input[name^="Address6:"]').each(function(){if ($(this).val()) address6.push($(this).val().split('::')[1]);});
|
|
var ip6 = (form.find('input[name="Network6:0"]').val()||netpool6[vtun])+(address6.sort(function(x,y){return x-y}).pop()*1+1);
|
|
form.find('input[name="Address6:'+i+'"]').val(ip6);
|
|
}
|
|
switch (protocol) {
|
|
case '46':
|
|
var data = ip+', '+ip6;
|
|
form.find('input[name="Address:'+i+'"]').attr('placeholder',"(_(mandatory)_)").prop('required',true);
|
|
form.find('input[name="Address6:'+i+'"]').attr('placeholder',"(_(mandatory)_)").prop('required',true);
|
|
$('div[class="ipv4 '+vtun+'"]').show();
|
|
$('div[class="ipv6 '+vtun+'"]').show();
|
|
break;
|
|
case '6':
|
|
var data = ip6;
|
|
form.find('input[name="Address:'+i+'"]').attr('placeholder',"(_(not used)_)").removeAttr('required').val('');
|
|
form.find('input[name="Address6:'+i+'"]').attr('placeholder',"(_(mandatory)_)").prop('required',true);
|
|
$('div[class="ipv4 '+vtun+'"]').hide();
|
|
$('div[class="ipv6 '+vtun+'"]').show();
|
|
break;
|
|
default:
|
|
var data = ip;
|
|
form.find('input[name="Address:'+i+'"]').attr('placeholder',"(_(mandatory)_)").prop('required',true);
|
|
form.find('input[name="Address6:'+i+'"]').attr('placeholder',"(_(not used)_)").removeAttr('required').val('');
|
|
$('div[class="ipv4 '+vtun+'"]').show();
|
|
$('div[class="ipv6 '+vtun+'"]').hide();
|
|
break;
|
|
}
|
|
form.find('input[name="AllowedIPs:'+i+'"]').val(data);
|
|
form.find('input[name="Address:'+i+'"]').on('input change',function(){form.find('#ping-button1-'+i).prop('disabled',$(this).val()=='');});
|
|
form.find('input[name="Address6:'+i+'"]').on('input change',function(){form.find('#ping-button6-'+i).prop('disabled',$(this).val()=='');});
|
|
form.find('input[name="gui:Endpoint:'+i+'"]').on('input change',function(){form.find('#ping-button2-'+i).prop('disabled',$(this).val()=='');});
|
|
if ($.cookie('view-'+vtun)=='advanced') {
|
|
form.find('div.zone'+i).show();
|
|
form.find('i.fa-chevron-down').last().removeClass().addClass('fa fa-chevron-up');
|
|
}
|
|
form.find('input[class$="zone'+i+'"]').show();
|
|
form.find('input[name="Name:0"]').trigger('change');
|
|
$('blockquote.inline_help').each(function(i) {
|
|
$(this).attr('id','helpinfo'+i);
|
|
var pin = $(this).prev();
|
|
if (!pin.prop('nodeName')) pin = $(this).parent().prev();
|
|
while (pin.prop('nodeName') && pin.prop('nodeName').search(/(table|dl)/i) == -1) pin = pin.prev();
|
|
pin.find('tr:first,dt:last').each(function() {
|
|
var node = $(this);
|
|
var name = node.prop('nodeName').toLowerCase();
|
|
if (name=='dt') {
|
|
while (!node.html() || node.html().search(/(<input|<select|nbsp;)/i) >= 0 || name!='dt') {
|
|
if (name=='dt' && node.is(':first-of-type')) break;
|
|
node = node.prev();
|
|
name = node.prop('nodeName').toLowerCase();
|
|
}
|
|
node.css('cursor','help').prop('onclick',null).off('click').click(function(){$('#helpinfo'+i).toggle('slow');});
|
|
} else {
|
|
if (node.html() && (name!='tr' || node.children('td:first').html())) node.css('cursor','help').prop('onclick',null).off('click').click(function(){$('#helpinfo'+i).toggle('slow');});
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
function delPeer(form,peer) {
|
|
var deleted = form.find('input[name="#deleted"]');
|
|
var comma = deleted.val() ? ',' : '';
|
|
deleted.val(deleted.val()+comma+peer.substr(7));
|
|
form.find(peer).remove();
|
|
form.find('input[name="Name:0"]').trigger('change');
|
|
}
|
|
|
|
function lockEye(form,i) {
|
|
form.find('i[class*="eye'+i+'"]').removeClass('key-off').addClass('key-off');
|
|
}
|
|
|
|
function toLC(field) {
|
|
field.value=(field.value) ? field.value.toLowerCase() : '';
|
|
}
|
|
|
|
function updatePeer(form,i,n,vtun) {
|
|
var unraid = form.find('input[name="#internet"]').val().replace(/^(www\.).+(\.unraid.net)$/,'$1<hash>$2');
|
|
var type = form.find('select[name="TYPE:'+i+'"]').val();
|
|
var icon = $('#chevron-'+vtun+'-'+i);
|
|
var protocol = form.find('select[name="PROT:0"]').val();
|
|
switch (n) {
|
|
case '6':
|
|
var dns = form.find('input[name="DNS:'+i+'"]');
|
|
form.find('input[name="Endpoint:0"]').attr('placeholder',unraid);
|
|
form.find('input[name="gui:ListenPort:0"]').attr('placeholder',netport[vtun]);
|
|
form.find('select[name="NAT:0"]').prop('disabled',false);
|
|
form.find('input[name="gui:Endpoint:'+i+'"]').attr('placeholder',"(_(not used)_)").removeAttr('required').val('');
|
|
form.find('input[name="gui:ListenPort:'+i+'"]').removeAttr('placeholder').val('');
|
|
dns.attr('placeholder',"(_(mandatory)_)").prop('required',true).val(dns.val()||'<?=$dnsserver?>');
|
|
if (!dns.val() && icon.hasClass('fa-chevron-down')) openClose(form,icon,'div.zone'+i);
|
|
break;
|
|
case '7':
|
|
form.find('input[name="Endpoint:0"]').attr('placeholder',"(_(not used)_)");
|
|
form.find('input[name="gui:ListenPort:0"]').removeAttr('placeholder');
|
|
form.find('select[name="NAT:0"]').prop('disabled',true);
|
|
form.find('input[name="gui:Endpoint:'+i+'"]').attr('placeholder',"(_(mandatory)_)").prop('required',true);
|
|
form.find('input[name="gui:ListenPort:'+i+'"]').attr('placeholder',form.find('input[name="gui:ListenPort:0"]').val()||netport[vtun]);
|
|
form.find('input[name="Address:'+i+'"]').attr('placeholder',"(_(not used)_)").removeAttr('required');
|
|
form.find('input[name="Address6:'+i+'"]').attr('placeholder',"(_(not used)_)").removeAttr('required');
|
|
form.find('input[name="DNS:'+i+'"]').attr('placeholder',"(_(not used)_)").removeAttr('required').val('');
|
|
if (icon.hasClass('fa-chevron-down')) openClose(form,icon,'div.zone'+i);
|
|
break;
|
|
default:
|
|
form.find('input[name="Endpoint:0"]').attr('placeholder',unraid);
|
|
form.find('input[name="gui:ListenPort:0"]').attr('placeholder',netport[vtun]);
|
|
form.find('select[name="NAT:0"]').prop('disabled',false);
|
|
if (n=='2'||n=='3') {
|
|
form.find('input[name="gui:Endpoint:'+i+'"]').attr('placeholder',"(_(mandatory)_)").prop('required',true);
|
|
form.find('input[name="gui:ListenPort:'+i+'"]').attr('placeholder',form.find('input[name="gui:ListenPort:0"]').val()||netport[vtun]);
|
|
if (icon.hasClass('fa-chevron-down')) openClose(form,icon,'div.zone'+i);
|
|
} else {
|
|
form.find('input[name="gui:Endpoint:'+i+'"]').attr('placeholder',"(_(not used)_)").removeAttr('required').val('');
|
|
form.find('input[name="gui:ListenPort:'+i+'"]').removeAttr('placeholder').val('');
|
|
}
|
|
form.find('input[name="DNS:'+i+'"]').attr('placeholder',"(_(optional)_)").removeAttr('required');
|
|
break;
|
|
}
|
|
form.find('#addpeer-'+vtun).prop('disabled',n>=7);
|
|
var subnet = form.find('input[name="Address:'+i+'"]').val();
|
|
var subnet6 = form.find('input[name="Address6:'+i+'"]').val();
|
|
switch (protocol) {
|
|
case '46':
|
|
setAllow6(form,subnet6,i);
|
|
setAllow(form,subnet,i);
|
|
break;
|
|
case '6':
|
|
setAllow6(form,subnet6,i);
|
|
break;
|
|
default:
|
|
setAllow(form,subnet,i);
|
|
break;
|
|
}
|
|
showRemark(form);
|
|
showRoute(form,vtun);
|
|
showAccess(form,i,n);
|
|
}
|
|
|
|
function setProtocol(form,vtun,update) {
|
|
switch (form.find('select[name="PROT:0"]').val()) {
|
|
case '46':
|
|
$('div[class="ipv4 '+vtun+'"]').show();
|
|
$('div[class="ipv6 '+vtun+'"]').show();
|
|
form.find('input[name^="Address:"]').each(function(){
|
|
var i = $(this).attr('name').split(':')[1];
|
|
if (i==0) {
|
|
$(this).attr('placeholder',"(_(mandatory)_)").prop('required',true);
|
|
} else {
|
|
if (form.find('select[name="TYPE:'+i+'"]').val()<7) $(this).attr('placeholder',"(_(mandatory)_)").prop('required',true); else $(this).attr('placeholder',"(_(not used)_)").removeAttr('required');
|
|
}
|
|
});
|
|
form.find('input[name^="Address6:"]').each(function(){
|
|
var i = $(this).attr('name').split(':')[1];
|
|
if (i==0) {
|
|
$(this).attr('placeholder',"(_(mandatory)_)").prop('required',true);
|
|
} else {
|
|
if (form.find('select[name="TYPE:'+i+'"]').val()<7) $(this).attr('placeholder',"(_(mandatory)_)").prop('required',true); else $(this).attr('placeholder',"(_(not used)_)").removeAttr('required');
|
|
}
|
|
});
|
|
if (update) {
|
|
form.find('input[name="gui:Network6:0"]').trigger('change');
|
|
form.find('input[name="gui:Network:0"]').trigger('change');
|
|
}
|
|
break;
|
|
case '6':
|
|
$('div[class="ipv4 '+vtun+'"]').hide();
|
|
$('div[class="ipv6 '+vtun+'"]').show();
|
|
form.find('input[name^="Address:"]').each(function(){$(this).attr('placeholder',"(_(not used)_)").removeAttr('required').val('');});
|
|
form.find('input[name^="Address6:"]').each(function(){
|
|
var i = $(this).attr('name').split(':')[1];
|
|
if (i==0) {
|
|
$(this).attr('placeholder',"(_(mandatory)_)").prop('required',true);
|
|
} else {
|
|
if (form.find('select[name="TYPE:'+i+'"]').val()<7) $(this).attr('placeholder',"(_(mandatory)_)").prop('required',true); else $(this).attr('placeholder',"(_(not used)_)").removeAttr('required');
|
|
}
|
|
});
|
|
if (update) {
|
|
form.find('input[name="gui:Network6:0"]').trigger('change');
|
|
}
|
|
break;
|
|
default:
|
|
$('div[class="ipv4 '+vtun+'"]').show();
|
|
$('div[class="ipv6 '+vtun+'"]').hide();
|
|
form.find('input[name^="Address6:"]').each(function(){$(this).attr('placeholder',"(_(not used)_)").removeAttr('required').val('');});
|
|
form.find('input[name^="Address:"]').each(function(){
|
|
var i = $(this).attr('name').split(':')[1];
|
|
if (i==0) {
|
|
$(this).attr('placeholder',"(_(mandatory)_)").prop('required',true);
|
|
} else {
|
|
if (form.find('select[name="TYPE:'+i+'"]').val()<7) $(this).attr('placeholder',"(_(mandatory)_)").prop('required',true); else $(this).attr('placeholder',"(_(not used)_)").removeAttr('required');
|
|
}
|
|
});
|
|
if (update) {
|
|
form.find('input[name="gui:Network:0"]').trigger('change');
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
function quickValidate(field) {
|
|
try {
|
|
var form = $(field).parents('form');
|
|
var i = field.name.match(/.*:(\d+)/)[1];
|
|
lockEye(form,i);
|
|
} catch (err) { }
|
|
return field.reportValidity();
|
|
}
|
|
|
|
function setPool(form,vtun) {
|
|
// perform standard field validation on Network and Mask before custom validation
|
|
field = form.find('input[name="gui:Network:0"]')[0];
|
|
field.setCustomValidity('');
|
|
if (!quickValidate(field)) return false;
|
|
field2 = form.find('input[name="gui:Mask:0"]')[0];
|
|
if (!quickValidate(field2)) return false;
|
|
// ensure Local tunnel network pool is a pool address
|
|
var network = form.find('input[name="gui:Network:0"]').val();
|
|
var mask = form.find('select[name="gui:Mask:0"]').val()||24;
|
|
var networkSubnet = network.ip2long() & (0x100000000-2**(32-mask));
|
|
if (network && network.ip2long() !== networkSubnet) {
|
|
network = networkSubnet.long2ip();
|
|
form.find('input[name="gui:Network:0"]').val(network);
|
|
}
|
|
// ensure Local tunnel network pool is not already in use on this server
|
|
var subnets = '<?=$subnets?>';
|
|
if (network && subnets.includes(network+"/")) {
|
|
field.setCustomValidity("_(The Local tunnel network pool cannot be in)_ "+subnets);
|
|
field.reportValidity();
|
|
return false;
|
|
}
|
|
// remove existing IPv4 addresses in AllowedIP list
|
|
form.find('input[name^="AllowedIPs:"]').each(function(){
|
|
var list = $(this).val().replace(/ +/g,'').split(',');
|
|
list = list.filter(ipv6);
|
|
$(this).val(list.join(', '));
|
|
});
|
|
// update existing IPv4 addresses with new pool address
|
|
netbase[vtun] = (network||netpool[vtun]).ip2long() & (0x100000000-2**(32-mask));
|
|
var assign = netbase[vtun];
|
|
form.find('input[name^="Address:"]').each(function(){
|
|
++assign;
|
|
var i = $(this).attr('name').split(':')[1];
|
|
$(this).val((assign).long2ip()).trigger('change');
|
|
});
|
|
}
|
|
|
|
function setPool6(form,vtun) {
|
|
// perform standard field validation on Network6 and Mask6 before custom validation
|
|
field = form.find('input[name="gui:Network6:0"]')[0];
|
|
field.setCustomValidity('');
|
|
if (!quickValidate(field)) return false;
|
|
field2 = form.find('input[name="gui:Mask6:0"]')[0];
|
|
if (!quickValidate(field2)) return false;
|
|
// ensure Local tunnel network pool is a pool address
|
|
var network6 = form.find('input[name="gui:Network6:0"]').val();
|
|
var mask6 = form.find('select[name="gui:Mask6:0"]').val()||64;
|
|
// this logic only handles IPv6 mask of 64. for other masks, assume the user knows what they are doing.
|
|
if (network6 && mask6 === 64) {
|
|
var network6Subnet = network6.match(/((.*?):){4}/) ? network6.match(/((.*?):){4}/)[0].slice(0,-1) : "";
|
|
if (network6Subnet && network6 !== network6Subnet+"::") {
|
|
network6 = network6Subnet+"::";
|
|
form.find('input[name="gui:Network6:0"]').val(network6);
|
|
}
|
|
}
|
|
// ensure Local tunnel network pool is not already in use on this server
|
|
var subnets6 = '<?=$subnets6?>';
|
|
if (network6 && subnets6.includes(network6+"/")) {
|
|
field.setCustomValidity("_(The Local tunnel network pool IPv6 cannot be in)_ "+subnets6);
|
|
field.reportValidity();
|
|
return false;
|
|
}
|
|
// remove existing IPv6 addresses in AllowedIP list
|
|
form.find('input[name^="AllowedIPs:"]').each(function(){
|
|
var list = $(this).val().replace(/ +/g,'').split(',');
|
|
list = list.filter(ipv4);
|
|
$(this).val(list.join(', '));
|
|
});
|
|
// update existing IPv6 addresses with new pool address
|
|
netbase6[vtun] = network6||netpool6[vtun];
|
|
var assign = 0;
|
|
form.find('input[name^="Address6:"]').each(function(){
|
|
++assign;
|
|
var i = $(this).attr('name').split(':')[1];
|
|
$(this).val(netbase6[vtun]+assign).trigger('change');
|
|
});
|
|
}
|
|
|
|
function verifyInSubnet(field) {
|
|
// perform standard field validation before custom validation
|
|
field.setCustomValidity('');
|
|
if (!quickValidate(field)) return false;
|
|
// ensure this IP address is in the Local tunnel network pool
|
|
var form = $(field).parents('form');
|
|
// note: if network or mask are invalid, subnet calculation will be unpredictable
|
|
// not going to validate them here as the UI would be confusing
|
|
var network = form.find('input[name="gui:Network:0"]').val()||form.find('input[name="gui:Network:0"]').prop('placeholder');
|
|
var mask = form.find('input[name="gui:Mask:0"]').val()||24;
|
|
var addr = $(field).val();
|
|
var networkSubnet = network.ip2long() & (0x100000000-2**(32-mask));
|
|
var addrSubnet = addr.ip2long() & (0x100000000-2**(32-mask));
|
|
if (networkSubnet !== addrSubnet) {
|
|
field.setCustomValidity(addr+" _(is not in the)_ "+networkSubnet.long2ip()+"/"+mask+" _(subnet)_");
|
|
field.reportValidity();
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
function verifyInSubnet6(field) {
|
|
// perform standard field validation before custom validation
|
|
field.setCustomValidity('');
|
|
if (!quickValidate(field)) return false;
|
|
// ensure this IPv6 address is in the Local tunnel network pool IPv6
|
|
var form = $(field).parents('form');
|
|
var network6 = form.find('input[name="gui:Network6:0"]').val()||form.find('input[name="gui:Network6:0"]').prop('placeholder');
|
|
var mask6 = form.find('input[name="gui:Mask6:0"]').val()||64;
|
|
if (mask6 !== 64) {
|
|
// this logic only handles IPv6 mask of 64. for other masks, assume the user knows what they are doing.
|
|
return true;
|
|
}
|
|
var network6Subnet = network6.match(/((.*?):){4}/) ? network6.match(/((.*?):){4}/)[0].slice(0,-1) : "";
|
|
var addr6 = $(field).val();
|
|
var addr6Subnet = addr6.match(/((.*?):){4}/) ? addr6.match(/((.*?):){4}/)[0].slice(0,-1) : "";
|
|
if (!network6Subnet || network6Subnet !== addr6Subnet) {
|
|
field.setCustomValidity(addr6+" _(is not in the)_ "+network6Subnet+"/"+mask6+" _(subnet)_");
|
|
field.reportValidity();
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
function setAllow(form,subnet,i) {
|
|
var input = form.find('input[name="AllowedIPs:'+i+'"]');
|
|
var type = form.find('select[name="TYPE:'+i+'"]').val();
|
|
var prot = form.find('select[name="PROT:0"]').val();
|
|
if (type < 7) {
|
|
var list = input.val().replace(/ +/g,'').split(',');
|
|
var n = prot=='46' ? 0 : (list.length > 1 ? 2 : 1);
|
|
list.splice(0,n);
|
|
list.unshift(subnet);
|
|
list = [...new Set(list)];
|
|
list = list.filter(nodefault);
|
|
if (n > 0) list = list.filter(ipv4);
|
|
} else {
|
|
var list = prot!='46' ? ['0.0.0.0/0'] : ['0.0.0.0/0','::/0'];
|
|
}
|
|
input.val(list.join(', '));
|
|
lockEye(form,i);
|
|
}
|
|
|
|
function setAllow6(form,subnet6,i) {
|
|
var input = form.find('input[name="AllowedIPs:'+i+'"]');
|
|
var type = form.find('select[name="TYPE:'+i+'"]').val();
|
|
var prot = form.find('select[name="PROT:0"]').val();
|
|
if (type < 7) {
|
|
var list = input.val().replace(/ +/g,'').split(',');
|
|
var n = prot=='46' ? 0 : (list.length > 1 ? 2 : 1);
|
|
list.splice(0,n);
|
|
list.unshift(subnet6);
|
|
list = [...new Set(list)];
|
|
list = list.filter(nodefault6);
|
|
if (n > 0) list = list.filter(ipv6);
|
|
} else {
|
|
var list = prot!='46' ? ['::/0'] : ['0.0.0.0/0','::/0'];
|
|
}
|
|
input.val(list.join(', '));
|
|
lockEye(form,i);
|
|
}
|
|
|
|
function ping(form,button,field) {
|
|
$(button).val('Pinging...');
|
|
$.post('/webGui/include/update.wireguard.php',{'#cmd':'ping','#addr':form.find(field).val().replace(/\/.+$/,'')},function(reply){
|
|
if (reply) {
|
|
$(button).addClass('ok').val("_(Replied)_");
|
|
} else {
|
|
$(button).addClass('nok').val("_(No Reply)_");
|
|
}
|
|
setTimeout(function(){$(button).removeClass('ok nok').val("_(Ping)_")},3000);
|
|
});
|
|
}
|
|
|
|
function WGconfig(icon,file,path) {
|
|
if (!$(icon).hasClass('key-off')) openChanges('wg_config '+file+' '+path, "_(WireGuard Configuration)_");
|
|
}
|
|
|
|
function highlight(form,input,i) {
|
|
$(input).css({'color':'#e68a00'});
|
|
lockEye(form,i);
|
|
}
|
|
|
|
function showRemark(form) {
|
|
var upnp = form.find('select[name="UPNP:0"]').val();
|
|
var vpn = 0;
|
|
form.find('select[name^="TYPE:"]').each(function(){if ($(this).val()>=7 && vpn==0) vpn = $(this).val();});
|
|
if (upnp=='' || vpn > 0) form.find('span.remark').hide(); else form.find('span.remark').show();
|
|
if (upnp=='' && vpn < 7) form.find('span.upnp').show(); else form.find('span.upnp').hide();
|
|
}
|
|
|
|
function showRoute(form,vtun,i) {
|
|
var nat = form.find('select[name="NAT:0"]').val();
|
|
var vpn = 0, lan = false;
|
|
form.find('select[name^="TYPE:"]').each(function(){
|
|
if ($(this).val()>=7 && vpn==0) vpn = $(this).val();
|
|
else lan |= $(this).val()=='6' || $(this).val() % 2;
|
|
});
|
|
if (nat=='no' && vpn==0 && lan) {
|
|
$('span#my-static1-'+vtun).show();
|
|
$('span#my-static2-'+vtun).hide();
|
|
} else {
|
|
$('span#my-static1-'+vtun).hide();
|
|
if (lan) $('span#my-static2-'+vtun).show(); else $('span#my-static2-'+vtun).hide();
|
|
}
|
|
if (i!=null) lockEye(form,i);
|
|
}
|
|
|
|
function showAccess(form,i,n) {
|
|
switch (n) {
|
|
case '0':
|
|
switch (form.find('select[name="PROT:0"]').val()) {
|
|
case '6' : var peer_addr = form.find('input[name="Address6:0"]').val()+"</b>"; break;
|
|
case '46': var peer_addr = form.find('input[name="Address:0"]').val()+"</b> _(or)_ <b>"+form.find('input[name="Address6:0"]').val()+"</b>"; break;
|
|
default : var peer_addr = form.find('input[name="Address:0"]').val()+"</b>"; break;
|
|
}
|
|
form.find('span#access-type-'+i).html("_(Remark)_: _(connect to this server using IP address)_ <b>"+peer_addr);
|
|
break;
|
|
case '1':
|
|
case '2':
|
|
case '3':
|
|
case '6': form.find('span#access-type-'+i).html("_(Remark)_: _(ensure the peer network is different from)_ <b><?=exec("ip -4 route show dev $link scope link|awk '{print \$1;exit}'")?></b>"); break;
|
|
case '4':
|
|
switch (form.find('select[name="PROT:0"]').val()) {
|
|
case '6' : var peer_net = form.find('input[name="gui:Network6:0"]').val()+'/'+(form.find('input[name="gui:Mask6:0"]').val()||64)+"</b>"; break;
|
|
case '46': var peer_net = form.find('input[name="gui:Network:0"]').val()+'/'+(form.find('input[name="gui:Mask:0"]').val()||24)+"</b> _(or)_ <b>"+form.find('input[name="gui:Network6:0"]').val()+'/'+(form.find('input[name="gui:Mask6:0"]').val()||64)+"</b>"; break;
|
|
default : var peer_net = form.find('input[name="gui:Network:0"]').val()+'/'+(form.find('input[name="gui:Mask:0"]').val()||24)+"</b>"; break;
|
|
}
|
|
form.find('span#access-type-'+i).html("_(Remark)_: _(connect to any device on the VPN tunnel)_ <b>"+peer_net);
|
|
break;
|
|
case '5': form.find('span#access-type-'+i).html("_(Remark)_: _(ensure the peer networks are different from)_ <b><?=exec("ip -4 route show dev $link scope link|awk '{print \$1;exit}'")?></b>"); break;
|
|
case '7': form.find('span#access-type-'+i).html("_(Remark)_: _(this must be the only peer in the tunnel and sole active tunnel when in use)_"); break;
|
|
case '8': form.find('span#access-type-'+i).html("_(Remark)_: _(VPN tunnel for docker containers only)_"); break;
|
|
}
|
|
}
|
|
|
|
function portRemark(form,vtun,val) {
|
|
$('#my-port-'+vtun).text(val);
|
|
var port = form.find('input[name="gui:ListenPort:0"]').val()||netport[vtun];
|
|
form.find('input[name^="gui:ListenPort:"]').each(function(i) {
|
|
if (i>0 && form.find('input[name="gui:Endpoint:'+i+'"]').val()) $(this).attr('placeholder',port);
|
|
});
|
|
}
|
|
|
|
function openClose(form,icon,zone) {
|
|
if (icon) {
|
|
form.find(zone).toggle('slow');
|
|
if ($(icon).hasClass('fa-chevron-down')) {
|
|
// advanced view
|
|
form.find(zone.replace('div','input')).show('slow');
|
|
$(icon).removeClass('fa-chevron-down').addClass('fa-chevron-up');
|
|
if (!form.find('input[name="PublicKey:'+zone.replace('div.zone','')+'"]').val()) {
|
|
form.find(zone.replace('zone','key')).show();
|
|
form.find(zone.replace('div','i')).removeClass('key-off').addClass('key-off');
|
|
}
|
|
} else {
|
|
// basic view
|
|
$(icon).removeClass('fa-chevron-up').addClass('fa-chevron-down');
|
|
if (form.find('input[name="PublicKey:'+zone.replace('div.zone','')+'"]').val()) {
|
|
form.find(zone.replace('div','input')).hide('slow');
|
|
form.find(zone.replace('zone','key')).hide();
|
|
form.find(zone.replace('div','i')).removeClass('key-off');
|
|
}
|
|
}
|
|
} else {
|
|
if (!form.find(zone.replace('div.key','i.zone')).hasClass('key-off')) form.find(zone).toggle('slow');
|
|
}
|
|
}
|
|
|
|
function blockToggle(vtun) {
|
|
$('div#block-'+vtun).toggle('slow');
|
|
if ($('i#block-'+vtun).hasClass('fa-chevron-up')) {
|
|
$('i#block-'+vtun).removeClass('fa-chevron-up').addClass('fa-chevron-down');
|
|
$.cookie('block-'+vtun,'hide',{expires:3650});
|
|
} else {
|
|
$('i#block-'+vtun).removeClass('fa-chevron-down').addClass('fa-chevron-up');
|
|
$.removeCookie('block-'+vtun);
|
|
}
|
|
}
|
|
|
|
function importFile(file) {
|
|
var reader = new FileReader();
|
|
reader.readAsText(file,'UTF-8');
|
|
reader.onload = function(e){$.post('/webGui/include/update.wireguard.php',{'#cmd':'import','#name':'<?=$tower?>','#data':e.target.result},function(vtun){clearTunnel(vtun);});};
|
|
}
|
|
|
|
function isPublic(ipv4) {
|
|
var rfc1918 = ['10.0.0.0/8','172.16.0.0/12','192.168.0.0/16'];
|
|
for (var i=0,rfc; rfc=rfc1918[i]; i++) {
|
|
var subnet = rfc.split('/');
|
|
if (subnet[0].ip2long() == ipv4.ip2long() & (0x100000000-2**(32-subnet[1]))) return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
function getPublicIP(ip,wg,protocol) {
|
|
$.post('/webGui/include/update.wireguard.php',{'#cmd':'public','#ip':ip,'#prot':protocol},function(x){
|
|
var endpoints = [<?=concat($endpoints)?>];
|
|
var ips = x.split(';');
|
|
var wgx_ipv4 = ips[0];
|
|
var ext_ipv4 = ips[1];
|
|
var wgx_ipv6 = ips[2];
|
|
var ext_ipv6 = ips[3];
|
|
if ((protocol==''||protocol=='46') && ext_ipv4 && ip) {
|
|
if (!wgx_ipv4) {
|
|
if (!wgx_ipv6) $('#endpoint4-'+wg).html("<dt> </dt><dd></span> <span class='inline-block'>_(Remark)_: _(The Local endpoint does not resolve to an IPv4 address)_. _(In most cases, this should be your public WAN IPv4)_: <b>"+ext_ipv4+"</b></dd>\n").show();
|
|
} else if (wgx_ipv4 != ext_ipv4) {
|
|
$('#endpoint4-'+wg).html("<dt> </dt><dd></span> <span class='inline-block'>_(Remark)_: _(The Local endpoint resolves to)_ <b>"+wgx_ipv4+".</b> _(In most cases, this should be your public WAN IPv4 instead)_: <b>"+ext_ipv4+"</b></dd>\n").show();
|
|
} else if (endpoints.includes(wgx_ipv4) && isPublic(wgx_ipv4)) {
|
|
$('#endpoint4-'+wg).html("<dt> </dt><dd></span> <span class='inline-block'>_(Remark)_: _(The Local endpoint resolves to)_ <b>"+wgx_ipv4+".</b> _(Your Unraid Server is reachable from the internet)_</dd>\n").show();
|
|
}
|
|
}
|
|
if ((protocol=='6'||protocol=='46') && ext_ipv6 && ip) {
|
|
if (!wgx_ipv6) {
|
|
if (!wgx_ipv4) $('#endpoint6-'+wg).html("<dt> </dt><dd></span> <span class='inline-block'>_(Remark)_: _(The Local endpoint does not resolve to an IPv6 address)_. _(In most cases, this should be your public WAN IPv6)_: <b>"+ext_ipv6+"</b></dd>\n").show();
|
|
} else if (wgx_ipv6 != ext_ipv6) {
|
|
$('#endpoint6-'+wg).html("<dt> </dt><dd></span> <span class='inline-block'>_(Remark)_: _(The Local endpoint resolves to)_ <b>"+wgx_ipv6+".</b> _(In most cases, this should be your public WAN IPv6 instead)_: <b>"+ext_ipv6+"</b></dd>\n").show();
|
|
} else if (endpoints.includes(wgx_ipv6)) {
|
|
$('#endpoint6-'+wg).html("<dt> </dt><dd></span> <span class='inline-block'>_(Remark)_: _(The Local endpoint resolves to)_ <b>"+wgx_ipv6+".</b> _(Your Unraid Server is reachable from the internet)_</dd>\n").show();
|
|
}
|
|
}
|
|
<?if (!$public):?>
|
|
$('input[name="#internet"]').val(ext_ipv4||ext_ipv6);
|
|
$('input[name="Endpoint:0"]').each(function(){if ($(this).attr('placeholder')=='') $(this).attr('placeholder',ext_ipv4||ext_ipv6);});
|
|
<?endif;?>
|
|
});
|
|
}
|
|
|
|
// keep tunnel states in global variable
|
|
var tstate = [];
|
|
tstate['wg0'] = "<?=$check_wg0 ? 'active' : 'passive'?>";
|
|
|
|
var statistics = new NchanSubscriber('/sub/wireguard',{subscriber:'websocket'});
|
|
statistics.on('message', function(data) {
|
|
var list = [], n = [];
|
|
var x = 0; var vtun = '';
|
|
// get all existing tunnels
|
|
$('div[id^="block-wg"]').each(function(){list.push($(this).prop('id').split('-')[1]);});
|
|
// update active tunnels
|
|
var rows = JSON.parse(data);
|
|
for (var i=0,info; info=rows[i]; i++) {
|
|
if (info[0] != vtun) {
|
|
vtun = info[0];
|
|
// remove tunnel from inactive list
|
|
for (var n=0,done; done=list[n]; n++) if (vtun==done) list.splice(n,1);
|
|
x = 1;
|
|
} else x++;
|
|
if (info[1] > 0) {
|
|
var hr = parseInt(info[1]/3600);
|
|
var mn = parseInt(info[1]/60%60);
|
|
var sc = parseInt(info[1]%60);
|
|
$('.hs-'+vtun+'-'+x).text(sprintf("_(%s ago)_",plus(hr,"_(hour)_","_(hours)_",false)+plus(mn,"_(minute)_","_(minutes)_",false)+plus(sc,"_(second)_","_(seconds)_",true)));
|
|
} else {
|
|
$('.hs-'+vtun+'-'+x).text("_(not received)_");
|
|
}
|
|
$('.rx-'+vtun+'-'+x).text(info[2]);
|
|
$('.tx-'+vtun+'-'+x).text(info[3]);
|
|
}
|
|
// update inactive tunnels
|
|
for (var i=0,vtun; vtun=list[i]; i++) {
|
|
$('span[class^="hs-'+vtun+'"]').text("_(tunnel is inactive)_");
|
|
$('span[class^="tx-'+vtun+'"]').text('---');
|
|
$('span[class^="rx-'+vtun+'"]').text('---');
|
|
}
|
|
});
|
|
|
|
$(function(){
|
|
var form = $(document.wg0);
|
|
var ctrl = "<span class='js-wg-ctrl inline-flex flex-row items-center gap-3'>";
|
|
ctrl += "<span class='inline-flex flex-row items-center gap-2'><span class='label'>_(Autostart)_</span><span class=''><input type='checkbox' id='start-wg0' style='display:none'<?=$start_wg0?' checked':''?>></span></span>";
|
|
ctrl += "<span class='inline-flex flex-row items-center gap-2'><span class=''><input type='checkbox' id='view-wg0' style='display:none'></span></span>";
|
|
ctrl += "<span class='inline-flex flex-row items-center gap-2'><span class=''><input type='checkbox' id='toggle-wg0' style='display:none'></span></span>";
|
|
ctrl += "<span class='inline-flex flex-row items-center gap-2'><i id='block-wg0' class='fa fa-fw fa-chevron-up' style='cursor:pointer' onclick='blockToggle("wg0")'></i></span>";
|
|
ctrl += "</span>";
|
|
statistics.start();
|
|
getPublicIP($('#endpoint-wg0').val(),'wg0',$('#protocol-wg0').val());
|
|
$('div.content').prepend('<div class="preset"><small>"WireGuard" and the "WireGuard" logo are registered trademarks of Jason A. Donenfeld</small><div class="inline-flex flex-row items-center gap-2"><input type="button" value="_(Import Tunnel)_" onclick="$('input#file').trigger('click');"><input type="button" value="_(Add Tunnel)_" onclick="addTunnel()";<?=$this_wg0?"":" disabled"?>></div></div>');
|
|
$('div.title').eq(0).find('.right').append(ctrl);
|
|
$.post('/webGui/include/update.wireguard.php',{'#cmd':'upnp','#gw':"<?=$$ethX['GATEWAY:0']?>",'#link':"<?=$link?>"},function(url){
|
|
if (url) {
|
|
$('div.upnp').show();
|
|
$.cookie('upnp',url,{expires:3650});
|
|
var upnp = 'ON';
|
|
} else {
|
|
$('div.upnp').hide();
|
|
$.removeCookie('upnp');
|
|
var upnp = 'OFF';
|
|
}
|
|
$('span.upnp').each(function(){
|
|
var vtun = $(this).attr('class').split(' ')[1];
|
|
$.post('/webGui/include/update.wireguard.php',{'#cmd':'upnpc','#xml':xml,'#vtun':vtun,'#link':'<?=$link?>','#ip':'<?=$server?>','#wg':tstate[vtun]},function(data){$('span.upnp.'+vtun).text(data);});
|
|
});
|
|
if (xml.desc() != url.desc()) {
|
|
xml = url;
|
|
swal({title:"_(UPnP state changed to)_ "+upnp,text:"_(Please consider re-applying all configurations)_<br>(_(enable advanced settings view)_)",type:'warning',animation:'none',html:true});
|
|
}
|
|
});
|
|
$('#start-wg0').switchButton({labels_placement:'left',off_label:"_(Off)_",on_label:"_(On)_",clear:false});
|
|
$('#start-wg0').change(function(){
|
|
var start = $('#start-wg0').is(':checked') ? 'on' : 'off';
|
|
$.post('/webGui/include/update.wireguard.php',{'#cmd':'autostart','#start':start,'#vtun':'wg0'});
|
|
});
|
|
$('#toggle-wg0').switchButton({labels_placement:'left',off_label:"_(Inactive)_",on_label:"_(Active)_",checked:<?=$check_wg0?>});
|
|
$('#toggle-wg0').change(function(e){
|
|
<?if ($this_wg0):?>
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
var wg = $('#toggle-wg0').is(':checked') ? 'start' : 'stop';
|
|
var type = 0;
|
|
$('div[id^="index-wg0-"]').each(function(){
|
|
var temp = $(this).find('select[name^="TYPE:"]').val();
|
|
if (temp >= 7 && type==0) type = temp;
|
|
});
|
|
$.post('/webGui/include/update.wireguard.php',{'#cmd':'toggle','#wg':wg,'#vtun':'wg0','#type':type},function(ok){
|
|
if (wg=='start') {
|
|
if (ok==0) tstate['wg0']='active'; else $('#toggle-wg0').switchButton({checked:false});
|
|
} else {
|
|
if (ok==0) tstate['wg0']=''; else $('#toggle-wg0').switchButton({checked:true});
|
|
}
|
|
<?if (empty($wg0['UPNP:0'])):?>
|
|
$.post('/webGui/include/update.wireguard.php',{'#cmd':'upnpc','#xml':xml,'#vtun':'wg0','#link':'<?=$link?>','#ip':'<?=$server?>','#wg':tstate['wg0']},function(data){$('span.upnp.wg0').text(data);});
|
|
<?endif;?>
|
|
});
|
|
<?else:?>
|
|
$('#toggle-wg0').prop('checked',false).trigger('change');
|
|
<?endif;?>
|
|
});
|
|
if ($.cookie('view-wg0')=='advanced') {
|
|
$('.advanced.wg0').show();
|
|
form.find('i.fa-chevron-down').removeClass('fa-chevron-down').addClass('fa-chevron-up');
|
|
form.find('input[class*="zone"]').show();
|
|
form.find('i[class*="zone"]').each(function(i){if (!form.find('input[name="PublicKey:'+i+'"]').val()) {
|
|
$('div.wg0.key'+i).show();
|
|
$(this).removeClass('key-off').addClass('key-off');
|
|
}});
|
|
}
|
|
$('#view-wg0').switchButton({labels_placement:'left',off_label:"_(Basic)_",on_label:"_(Advanced)_",checked:$.cookie('view-wg0')=='advanced'});
|
|
$('#view-wg0').change(function(){
|
|
if ($.cookie('view-wg0')==null) {
|
|
// advanced view
|
|
$.cookie('view-wg0','advanced',{expires:3650});
|
|
$('.advanced.wg0').show('slow');
|
|
form.find('input[class*="zone"]').show('slow');
|
|
form.find('i.fa-chevron-down').removeClass('fa-chevron-down').addClass('fa-chevron-up');
|
|
form.find('i[class*="zone"]').each(function(i){if (!form.find('input[name="PublicKey:'+i+'"]').val()) {
|
|
$('div.wg0.key'+i).show('slow');
|
|
$(this).removeClass('key-off').addClass('key-off');
|
|
}});
|
|
} else {
|
|
// basic view
|
|
$.removeCookie('view-wg0');
|
|
$('.advanced.wg0').hide('slow');
|
|
form.find('i.fa-chevron-up').removeClass('fa-chevron-up').addClass('fa-chevron-down');
|
|
form.find('i[class*="zone"]').each(function(i){if (form.find('input[name="PublicKey:'+i+'"]').val()) {
|
|
form.find('input[class$="zone'+i+'"]').hide('slow');
|
|
$('div.wg0.key'+i).hide('slow');
|
|
$(this).removeClass('key-off');
|
|
}});
|
|
}
|
|
});
|
|
showRemark(form);
|
|
setProtocol(form,'wg0');
|
|
form.find('input[name^="Address:"]').each(function(){
|
|
var i = $(this).attr('name').split(':')[1];
|
|
if (i > 0) $(this).on('input change',function(){form.find('.ping-button1-'+i).prop('disabled',$(this).val()=='');});
|
|
});
|
|
form.find('input[name^="Address6:"]').each(function(){
|
|
var i = $(this).attr('name').split(':')[1];
|
|
if (i > 0) $(this).on('input change',function(){form.find('.ping-button6-'+i).prop('disabled',$(this).val()=='');});
|
|
});
|
|
form.find('input[name^="gui:Endpoint:"]').each(function(){
|
|
var i = $(this).attr('name').split(':')[2];
|
|
$(this).on('input change',function(){
|
|
form.find('.ping-button2-'+i).prop('disabled',$(this).val()=='');
|
|
});
|
|
});
|
|
if (!$.cookie('block-wg0')) $('div#block-wg0').show(); else $('i#block-wg0').removeClass('fa-chevron-up').addClass('fa-chevron-down');
|
|
if (xml) {
|
|
$('div.upnp.wg0').show();
|
|
<?if (empty($wg0['UPNP:0'])):?>
|
|
$.post('/webGui/include/update.wireguard.php',{'#cmd':'upnpc','#xml':xml,'#vtun':'wg0','#link':'<?=$link?>','#ip':'<?=$server?>','#wg':$.cookie('my-wg0')||''},function(data){$('span.upnp.wg0').text(data);});
|
|
<?endif;?>
|
|
} else {
|
|
form.find('select[name="UPNP:0"]').val('no');
|
|
}
|
|
var vpn = 0, lan = false
|
|
form.find('select[name^="TYPE:"]').each(function(){
|
|
var i = $(this).attr('name').split(':')[1];
|
|
if ($(this).val()>=7 && vpn==0) vpn = $(this).val();
|
|
lan |= $(this).val()=='6' || $(this).val() % 2;
|
|
form.find('input[name="DNS:'+i+'"]').attr('placeholder',$(this).val()>=7 ? "(_(not used)_)" : "(_(optional)_)");
|
|
showAccess(form,i,$(this).val());
|
|
});
|
|
if (vpn > 0) {
|
|
form.find('select[name="NAT:0"]').val('no').prop('disabled',true);
|
|
form.find('#addpeer-wg0').prop('disabled',true);
|
|
}
|
|
else if (form.find('select[name="NAT:0"]').val()=='no' && lan) $('span#my-static1-wg0').show();
|
|
else if (lan) $('span#my-static2-wg0').show();
|
|
<?if (file_exists($tmp)):?>
|
|
setTimeout(function(){swal({title:"_(Peer update required)_",text:"<b><u>_(List of peers)_</u></b><br><span style='display:inline-block;text-align:left'><?=file_get_contents($tmp)?></span>",type:'warning',animation:'none',html:true});},200);
|
|
<?delete_file($tmp);?>
|
|
<?endif;?>
|
|
});
|
|
</script>
|
|
|
|
<input type='file' id='file' accept='.conf' onchange='importFile(this.files[0])' style='display:none'>
|
|
<div markdown="1" id="block-wg0" style="display:none">
|
|
<form markdown="1" name="wg0" autocomplete="off" method="POST" action="/update.php" target="progressFrame" onsubmit="prepareSettings($(this),'wg0')">
|
|
<input type="hidden" name="#include" value="/webGui/include/update.wireguard.php">
|
|
<input type="hidden" name="#file" value="<?=$conf_wg0?>">
|
|
<input type="hidden" name="#cfg" value="<?=$cfg_wg0?>">
|
|
<input type="hidden" name="#cmd" value="update">
|
|
<input type="hidden" name="#name" value="<?=$tower?>">
|
|
<input type="hidden" name="#vtun" value="wg0">
|
|
<input type="hidden" name="#type" value="0">
|
|
<input type="hidden" name="#wg" value="">
|
|
<input type="hidden" name="#internet" value="<?=$public?>">
|
|
<input type="hidden" name="#subnets1" value="">
|
|
<input type="hidden" name="#subnets2" value="">
|
|
<input type="hidden" name="#shared1" value="">
|
|
<input type="hidden" name="#shared2" value="">
|
|
<input type="hidden" name="#deleted" value="">
|
|
<input type="hidden" name="#locale" value="<?=$locale?>">
|
|
|
|
_(Local name)_:
|
|
: <span class="flex flex-row items-center gap-2">
|
|
<input type="text" name="Name:0" class="wide" maxlength="99" value="<?=_var($wg0,"Name:0")?>" pattern="<?=$validname?>" title="_(Use only letters A-Z, digits or space,dash,underscore)_" placeholder="(_(optional)_)">
|
|
<span class="flex flex-row items-center gap-2">
|
|
<i class="fa fa-fw fa-eye eye0<?=$this_wg0?'':' key-off'?>" style="cursor:pointer" onclick="WGconfig(this,'wg0','')" title="_(View Local Config)_"></i>
|
|
<i class="fa fa-fw fa-key zone0<?=isset($wg0['PublicKey:0'])?'':' key-off'?>" style="cursor:pointer" onclick="openClose($(document.wg0),null,'div.key0')" title="_(Toggle keys)_"></i>
|
|
<i id="chevron-wg0-0" class="fa fa-fw fa-chevron-down" style="cursor:pointer" onclick="openClose($(document.wg0),this,'div.zone0')" title="_(Toggle view)_"></i>
|
|
</span>
|
|
</span>
|
|
|
|
:wg_local_name_help:
|
|
|
|
<div markdown="1" class="keys wg0 key0" style="<?= isset($wg0['PublicKey:0']) ? 'display:none' : '' ?>">
|
|
_(Local private key)_:
|
|
: <input type="text" name="PrivateKey:0" class="wide private-0" maxlength="64" value="<?=_var($wg0,'PrivateKey:0')?>" onchange="highlight($(document.wg0),this,0)" placeholder="(_(mandatory)_)" required>
|
|
<span class="inline-block">
|
|
<input type="button" class="form" value="_(Generate Keypair)_" onclick="keypair($(document.wg0),'0')">
|
|
</span>
|
|
|
|
:wg_generate_keypair_help:
|
|
|
|
_(Local public key)_:
|
|
: <input type="text" name="PublicKey:0" class="wide public-0" maxlength="64" value="<?=_var($wg0,'PublicKey:0')?>" onchange="highlight($(document.wg0),this,0)" placeholder="(_(mandatory)_)" required>
|
|
<span class="inline-block">
|
|
<input type="button" class="form" value="_(Generate Keypair)_" onclick="keypair($(document.wg0),'0')">
|
|
</span>
|
|
|
|
:wg_generate_keypair_help:
|
|
|
|
</div>
|
|
<div markdown="1" class="advanced wg0 zone0" style="display:none">
|
|
_(Network protocol)_:
|
|
: <span class="input"><select id="protocol-wg0" name="PROT:0" onchange="setProtocol($(document.wg0),'wg0',true)">
|
|
<?=mk_option(_var($wg0,'PROT:0'), "", "_(IPv4 only)_")?>
|
|
<?=mk_option(_var($wg0,'PROT:0'), "6", "_(IPv6 only)_")?>
|
|
<?=mk_option(_var($wg0,'PROT:0'), "46", "_(IPv4 + IPv6)_")?>
|
|
</select></span>
|
|
|
|
<div markdown="1" class="ipv4 wg0" style="display:none">
|
|
_(Local tunnel network pool)_:
|
|
: <input type="hidden" name="Network:0" value="">
|
|
<span class="flex flex-row items-center gap-2">
|
|
<input type="text" name="gui:Network:0" maxlength="15" value="<?=explode('/',_var($wg0,'Network:0'))[0]?>" onchange="setPool($(document.wg0),'wg0')" pattern="<?=$validIP4?>" title="_(IPv4 network)_" placeholder="<?=_var($netpool,'wg0')?>">
|
|
<span>/</span>
|
|
<input type="number" name="gui:Mask:0" class="mask" min="1" max="32" value="<?=my_explode('/',_var($wg0,'Network:0'))[1]?>" onchange="if(quickValidate(this)) {setPool($(document.wg0),'wg0')}" placeholder="24">
|
|
</span>
|
|
|
|
</div>
|
|
<div markdown="1" class="ipv6 wg0" style="display:none">
|
|
_(Local tunnel network pool IPv6)_:
|
|
: <input type="hidden" name="Network6:0" value="">
|
|
<span class="flex flex-row items-center gap-2">
|
|
<input type="text" name="gui:Network6:0" maxlength="40" value="<?=explode('/',_var($wg0,'Network6:0'))[0]?>" onchange="setPool6($(document.wg0),'wg0')" pattern="<?=$validIP6?>" title="_(IPv6 network)_" placeholder="<?=_var($netpool6,'wg0')?>">
|
|
<span>/</span>
|
|
<input type="number" name="gui:Mask6:0" class="mask" min="1" max="128" value="<?=my_explode('/',_var($wg0,'Network6:0'))[1]?>" onchange="if(quickValidate(this)) {setPool6($(document.wg0),'wg0')}" placeholder="64">
|
|
</span>
|
|
|
|
</div>
|
|
:wg_local_tunnel_network_pool_help:
|
|
|
|
<div markdown="1" class="ipv4 wg0" style="display:none">
|
|
_(Local tunnel address)_:
|
|
: <input type="text" name="Address:0" maxlength="15" value="<?=_var($wg0,'Address:0')?:long2ip(_var($netbase,'wg0')+1)?>" onchange="verifyInSubnet(this)" pattern="<?=$validIP4?>" title="_(IPv4 address)_">
|
|
|
|
:wg_local_tunnel_address_help:
|
|
|
|
</div>
|
|
<div markdown="1" class="ipv6 wg0" style="display:none">
|
|
_(Local tunnel address IPv6)_:
|
|
: <input type="text" name="Address6:0" maxlength="40" value="<?=_var($wg0,'Address6:0')?:(_var($netbase6,'wg0').'1')?>" onchange="verifyInSubnet6(this)" pattern="<?=$validIP6?>" title="_(IPv6 address)_">
|
|
|
|
:wg_local_tunnel_address_help:
|
|
|
|
</div>
|
|
</div>
|
|
_(Local endpoint)_:
|
|
: <span class="flex flex-row items-center gap-2">
|
|
<input type="text" class="width:10%;" id="endpoint-wg0" name="Endpoint:0" value="<?=$vpn_wg0?'':_var($wg0,'Endpoint:0')?>" onchange="toLC(this);quickValidate(this);" pattern="<?=$validText?>" title="_(IP address or FQDN)_" placeholder="<?=$vpn_wg0?'(_(not used)_)':preg_replace('/^(.+?\.)[0-9a-zA-Z]+(\.(my)?unraid.net)$/','$1<hash>$2',$public)?>">
|
|
<span>:</span>
|
|
<input type="number" name="gui:ListenPort:0" class="port" min="1" max="65535" value="<?=$vpn_wg0?'':_var($wg0,'ListenPort:0')?>" onchange="if(quickValidate(this)) {portRemark($(document.wg0),'wg0',this.value)}" placeholder="<?=$vpn_wg0?'':_var($netport,'wg0')?>">
|
|
</span>
|
|
<span class="remark inline-block" style="display:none">_(Remark)_: _(configure your router with port forwarding of port)_ **<span id="my-port-wg0"><?=_var($wg0,'ListenPort:0')?:_var($netport,'wg0')?></span>/_(UDP)_** _(to)_ **<?=$server?>:<?=_var($wg0,'ListenPort:0')?:_var($netport,'wg0')?>**</span><span class="upnp wg0 inline-block"></span>
|
|
<input type="hidden" name="ListenPort:0" value="">
|
|
<dl id="endpoint4-wg0" style="display:none"></dl>
|
|
<dl id="endpoint6-wg0" style="display:none"></dl>
|
|
|
|
:wg_local_endpoint_help:
|
|
|
|
<div markdown="1" class="advanced wg0 zone0" style="display:none">
|
|
_(Local server uses NAT)_:
|
|
: <select name="NAT:0" onchange="showRoute($(document.wg0),'wg0',0)">
|
|
<?=mk_option(_var($wg0,'NAT:0'), "", _("Yes"))?>
|
|
<?=mk_option(_var($wg0,'NAT:0'), "no", _("No"))?>
|
|
</select>
|
|
<span id="my-static1-wg0" class="inline-block" style="display:none">_(Remark)_: _(configure your router with a static route of)_ **<?=_var($wg0,'Network:0')?>** _(to)_ **<?=$server?>**</span>
|
|
<span id="my-static2-wg0" class="inline-block" style="display:none">_(Remark)_: _(docker containers on custom networks need static routing)_ **<?=_var($wg0,'Network:0')?>** _(to)_ **<?=$server?>**</span>
|
|
|
|
:wg_local_server_uses_nat_help:
|
|
|
|
<div markdown="1" class="upnp wg0" style="display:none">
|
|
_(Local gateway uses UPnP)_:
|
|
: <select name="UPNP:0" onchange="showRemark($(document.wg0))">
|
|
<?=mk_option(_var($wg0,'UPNP:0'), "", _("Yes"))?>
|
|
<?=mk_option(_var($wg0,'UPNP:0'), "no", _("No"))?>
|
|
</select>
|
|
|
|
:wg_local_gateway_uses_upnp_help:
|
|
|
|
</div>
|
|
_(Local tunnel firewall)_:
|
|
: <span class="flex flex-row items-center gap-2">
|
|
<input type="text" name="DROP:0" class="wide" value="<?=_var($wg0,'DROP:0')?>" onchange="quickValidate(this);" pattern="<?=$validList?>" title="_(Comma separated list of IPv4 and IPv6 IP addresses)_, _(CIDR optional)_" placeholder="(_(optional)_)">
|
|
<span class="flex flex-row items-center gap-2">
|
|
<span>_(Rule)_: </span>
|
|
<select name="RULE:0" class="auto">
|
|
<?=mk_option(_var($wg0,'RULE:0'), "", _("Deny"))?>
|
|
<?=mk_option(_var($wg0,'RULE:0'), "1", _("Allow"))?>
|
|
</select>
|
|
</span>
|
|
</span>
|
|
|
|
:wg_local_tunnel_firewall_help:
|
|
|
|
_(MTU size)_:
|
|
: <span class="flex flex-row items-center gap-2">
|
|
<input type="number" name="MTU:0" class="trim" min="68" max="9198" value="<?=_var($wg0,'MTU:0')?>" onchange="quickValidate(this);" placeholder="(_(auto)_)">
|
|
<span>_(bytes)_</span>
|
|
</span>
|
|
|
|
:wg_mtu_size_help:
|
|
|
|
<!--
|
|
_(DNS servers)_:
|
|
: <span class="input"><input type="text" name="DNS:0" class="wide" value="" placeholder="(_(optional)_)"></span>
|
|
|
|
> Not used at the moment. It gives errors when used together with Unraid.
|
|
-->
|
|
</div>
|
|
<input type="hidden" name="PostUp:0:0" value="<?=$postUp0?>">
|
|
<input type="hidden" name="PostUp:0:1" value="<?=$postUp1?>">
|
|
<input type="hidden" name="PostUp:0:2" value="">
|
|
<input type="hidden" name="PostDown:0:0" value="<?=$postDown0?>">
|
|
<input type="hidden" name="PostDown:0:1" value="<?=$postDown1?>">
|
|
<input type="hidden" name="PostDown:0:2" value="">
|
|
|
|
:wg_peer_configuration_help:
|
|
|
|
<div id="peers-list-wg0" style="display:none"></div>
|
|
<?foreach ($peer_wg0 as $i):?>
|
|
<div markdown="1" id="index-wg0-<?=$i?>" class="shade">
|
|
_(Peer name)_:
|
|
: <span class="flex flex-row items-center gap-2">
|
|
<input type="text" name="Name:<?=$i?>" class="wide" maxlength="99" value="<?=_var($wg0,"Name:$i")?>" onchange="quickValidate(this);" pattern="<?=$validname?>" title="_(Use only letters A-Z, digits or space,dash,underscore)_" placeholder="(_(optional)_)">
|
|
<span class="flex flex-row items-center gap-2">
|
|
<i class="fa fa-fw fa-eye eye<?=$i?><?=(file_exists("$etc/peers/peer-$tower-wg0-$i.conf")&&isset($wg0["TYPE:$i"])&&$wg0["TYPE:$i"]<=6)?'':' key-off'?>" style="cursor:pointer" onclick="WGconfig(this,'peer-<?=$tower?>-wg0-<?=$i?>','/peers')" title="_(View Peer Config)_"></i>
|
|
<i class="fa fa-fw fa-key zone<?=$i?><?=isset($wg0["PublicKey:$i"])?'':' key-off'?>" style="cursor:pointer" onclick="openClose($(document.wg0),null,'div.key<?=$i?>')" title="_(Toggle keys)_"></i>
|
|
<i id="chevron-wg0-<?=$i?>" class="fa fa-fw fa-chevron-down" style="cursor:pointer" onclick="openClose($(document.wg0),this,'div.zone<?=$i?>')" title="_(Toggle view)_"></i>
|
|
</span>
|
|
</span>
|
|
<span class="inline-block">
|
|
<input type="button" class="form" value="_(Delete Peer)_" onclick="delPeer($(document.wg0),'#index-wg0-<?=$i?>')">
|
|
</span>
|
|
|
|
:wg_peer_name_help:
|
|
|
|
_(Peer type of access)_:
|
|
: <select name="TYPE:<?=$i?>" class="auto" onchange="updatePeer($(document.wg0),<?=$i?>,this.value,'wg0')">
|
|
<?=mk_option(_var($wg0,"TYPE:$i"), "0", _("Remote access to server"))?>
|
|
<?=mk_option(_var($wg0,"TYPE:$i"), "1", _("Remote access to LAN"))?>
|
|
<?=mk_option(_var($wg0,"TYPE:$i"), "2", _("Server to server access"))?>
|
|
<?=mk_option(_var($wg0,"TYPE:$i"), "3", _("LAN to LAN access"))?>
|
|
<?=mk_option(_var($wg0,"TYPE:$i"), "4", _("Server hub & spoke access"))?>
|
|
<?=mk_option(_var($wg0,"TYPE:$i"), "5", _("LAN hub & spoke access"))?>
|
|
<?=mk_option(_var($wg0,"TYPE:$i"), "6", _("Remote tunneled access"))?>
|
|
<?=mk_option(_var($wg0,"TYPE:$i"), "7", _("VPN tunneled access for system"),count($peer_wg0)==1?'':'disabled')?>
|
|
<?=mk_option(_var($wg0,"TYPE:$i"), "8", _("VPN tunneled access for docker"),count($peer_wg0)==1?'':'disabled')?>
|
|
</select>
|
|
<span id="access-type-<?=$i?>"</span>
|
|
|
|
<?if ($i==1):?>
|
|
> ?>)
|
|
<?endif;?>
|
|
|
|
<div markdown="1" class="keys wg0 key<?=$i?>"<?=isset($wg0["PublicKey:$i"])?' style="display:none">':'>'?>
|
|
_(Peer private key)_:
|
|
: <input type="text" name="PrivateKey:<?=$i?>" class="wide private-<?=$i?>" maxlength="64" value="<?=_var($wg0,"PrivateKey:$i")?>" onchange="highlight($(document.wg0),this,<?=$i?>)" placeholder="(_(optional)_)">
|
|
<span class="inline-block">
|
|
<input type="button" class="form" value="_(Generate Keypair)_" onclick="keypair($(document.wg0),'<?=$i?>')">
|
|
</span>
|
|
|
|
:wg_generate_keypair_help:
|
|
|
|
_(Peer public key)_:
|
|
: <input type="text" name="PublicKey:<?=$i?>" class="wide public-<?=$i?>" maxlength="64" value="<?=_var($wg0,"PublicKey:$i")?>" onchange="highlight($(document.wg0),this,<?=$i?>)" placeholder="(_(mandatory)_)" required>
|
|
|
|
:wg_generate_keypair_help:
|
|
|
|
_(Peer preshared key)_:
|
|
: <input type="text" name="PresharedKey:<?=$i?>" class="wide preshared-<?=$i?>" maxlength="64" value="<?=_var($wg0,"PresharedKey:$i")?>" onchange="highlight($(document.wg0),this,<?=$i?>)" placeholder="(_(optional)_)">
|
|
<span class="inline-block">
|
|
<input type="button" class="form" value="_(Generate Key)_" onclick="presharedkey($(document.wg0),'<?=$i?>')">
|
|
</span>
|
|
|
|
:wg_peer_preshared_key_help:
|
|
|
|
</div>
|
|
<div markdown="1" class="advanced wg0 zone<?=$i?>" style="display:none">
|
|
<div markdown="1" class="ipv4 wg0" style="display:none">
|
|
_(Peer tunnel address)_:
|
|
: <input type="text" name="Address:<?=$i?>" maxlength="15" value="<?=_var($wg0,"Address:$i")?>" onchange="if(verifyInSubnet(this)){setAllow($(document.wg0),this.value,<?=$i?>)}" pattern="<?=$validIP4?>" title="_(IPv4 address)_">
|
|
<span class="inline-block">
|
|
<input type="button" class="form ping-button1-<?=$i?>" value="_(Ping)_" onclick="ping($(document.wg0),this,'input[name="Address:<?=$i?>"]')"<?=isset($wg0["Address:$i"])?'':' disabled'?>>
|
|
</span>
|
|
</div>
|
|
<div markdown="1" class="ipv6 wg0" style="display:none">
|
|
_(Peer tunnel address IPv6)_:
|
|
: <input type="text" name="Address6:<?=$i?>" maxlength="40" value="<?=_var($wg0,"Address6:$i")?>" onchange="if(verifyInSubnet6(this)){setAllow6($(document.wg0),this.value,<?=$i?>)}" pattern="<?=$validIP6?>" title="_(IPv6 address)_">
|
|
<span class="inline-block">
|
|
<input type="button" class="form ping-button6-<?=$i?>" value="_(Ping)_" onclick="ping($(document.wg0),this,'input[name="Address6:<?=$i?>"]')"<?=isset($wg0["Address6:$i"])?'':' disabled'?>>
|
|
</span>
|
|
</div>
|
|
:wg_peer_tunnel_address_help:
|
|
|
|
_(Peer endpoint)_:
|
|
: <input type="hidden" name="Endpoint:<?=$i?>" value="">
|
|
<span class="flex flex-row items-center gap-2">
|
|
<input type="text" name="gui:Endpoint:<?=$i?>" value="<?=_var($wg0,"Endpoint:$i")?>" pattern="<?=$validText?>" title="_(IP address or FQDN)_" onchange="toLC(this);quickValidate(this);" <?=($vpn_wg0||(int)_var($wg0,"TYPE:$i",0)==2||(int)_var($wg0,"TYPE:$i",0)==3)?'placeholder="(_(mandatory)_)" required':'placeholder="(_(not used)_)"'?>>
|
|
<span>:</span>
|
|
<input type="number" name="gui:ListenPort:<?=$i?>" class="port" min="1" max="65535" value="<?=_var($wg0,"ListenPort:$i")?>" onchange="quickValidate(this);"<?=isset($wg0["Endpoint:$i"])?" placeholder=\"".(_var($wg0,'ListenPort:0')?:_var($netport,'wg0'))."\"":""?>>
|
|
</span>
|
|
<span class="inline-block">
|
|
<input type="button" class="form ping-button2-<?=$i?>" value="_(Ping)_" onclick="ping($(document.wg0),this,'input[name="gui:Endpoint:<?=$i?>"]')"<?=isset($wg0["Endpoint:$i"])?'':' disabled'?>>
|
|
</span>
|
|
|
|
:wg_peer_endpoint_help:
|
|
|
|
_(Peer allowed IPs)_:
|
|
: <input type="text" name="AllowedIPs:<?=$i?>" class="wide" value="<?=_var($wg0,"AllowedIPs:$i")?>" onchange="quickValidate(this);" pattern="<?=$validList?>" title="_(Comma separated list of IPv4 and IPv6 IP addresses)_, _(CIDR optional)_" placeholder="(_(mandatory)_)" required>
|
|
|
|
:wg_peer_allowed_ips_help:
|
|
|
|
_(Peer DNS server)_:
|
|
: <input type="text" name="DNS:<?=$i?>" maxlength="60" value="<?=_var($wg0,"DNS:$i")?>" onchange="quickValidate(this);" pattern="<?=$validDNSServerList?>" title="_(Comma separated list of IPv4 and IPv6 IP addresses)_" <?=(int)_var($wg0,"TYPE:$i",0)!=6?'placeholder="(_(optional)_)"':'placeholder="(_(mandatory)_)" required'?>>
|
|
|
|
:wg_peer_dns_server_help:
|
|
|
|
_(Persistent keepalive)_:
|
|
: <span class="flex flex-row items-center gap-2">
|
|
<input type="number" name="PersistentKeepalive:<?=$i?>" class="trim" min="0" max="600" value="<?=_var($wg0,"PersistentKeepalive:$i")?>" onchange="quickValidate(this);" placeholder="(_(disabled)_)">
|
|
<span>_(seconds)_</span>
|
|
</span>
|
|
|
|
:wg_persistent_keepalive_help:
|
|
|
|
</div>
|
|
|
|
_(Data received)_:
|
|
: <span class="rx-wg0-<?=$i?>">0 B</span>
|
|
|
|
_(Data sent)_:
|
|
: <span class="tx-wg0-<?=$i?>">0 B</span>
|
|
|
|
_(Last handshake)_:
|
|
: <span class="hs-wg0-<?=$i?>">_(unknown)_</span>
|
|
</div>
|
|
<?endforeach;?>
|
|
|
|
|
|
: <span class="inline-block">
|
|
<input type="submit" value="_(Apply)_" onclick="return(validateForm($(document.wg0),'wg0'))" disabled>
|
|
<input type="button" value="_(Done)_" onclick="done()">
|
|
<input type="button" id="addpeer-wg0" value="_(Add Peer)_" onclick="addPeer($(document.wg0),'wg0')">
|
|
<input type="button" class="advanced wg0" value="_(Delete Tunnel)_" style="display:none" onclick="delTunnel('wg0')"<?=file_exists($conf_wg0)?'':' disabled'?>>
|
|
</span>
|
|
</form>
|
|
|
|
<script markdown="1" type="text/html" id="peer-template-wg0">
|
|
<div markdown="1" id="index-wg0-INDEX" class="shade">
|
|
_(Peer name)_:
|
|
: <span class="flex flex-row items-center gap-2">
|
|
<input type="text" name="Name:INDEX" class="wide" maxlength="99" value="" onchange="quickValidate(this);" pattern="<?=$validname?>" title="_(Use only letters A-Z, digits or space,dash,underscore)_" placeholder="(_(optional)_)">
|
|
<span class="flex flex-row items-center gap-2">
|
|
<i class="fa fa-fw fa-eye eyeINDEX key-off" title="_(Show Peer Config)_"></i>
|
|
<i class="fa fa-fw fa-key zoneINDEX key-off" title="_(Toggle keys)_"></i>
|
|
<i id="chevron-wg0-INDEX" class="fa fa-fw fa-chevron-down" style="cursor:pointer" onclick="openClose($(document.wg0),this,'div.zoneINDEX')" title="_(Toggle view)_"></i>
|
|
</span>
|
|
</span>
|
|
|
|
:wg_peer_name_help:
|
|
|
|
_(Peer type of access)_:
|
|
: <select name="TYPE:INDEX" class="auto" onchange="updatePeer($(document.wg0),INDEX,this.value,'wg0')">
|
|
<?=mk_option(0, "0", _("Remote access to server"))?>
|
|
<?=mk_option(0, "1", _("Remote access to LAN"))?>
|
|
<?=mk_option(0, "2", _("Server to server access"))?>
|
|
<?=mk_option(0, "3", _("LAN to LAN access"))?>
|
|
<?=mk_option(0, "4", _("Server hub & spoke access"))?>
|
|
<?=mk_option(0, "5", _("LAN hub & spoke access"))?>
|
|
<?=mk_option(0, "6", _("Remote tunneled access"))?>
|
|
<?=mk_option(0, "7", _("VPN tunneled access for system"),'disabled')?>
|
|
<?=mk_option(0, "8", _("VPN tunneled access for docker"),'disabled')?>
|
|
</select>
|
|
<span id="access-type-INDEX" class="access-type"></span>
|
|
|
|
> ?>)
|
|
|
|
<div markdown="1" class="keys wg0 keyINDEX">
|
|
_(Peer private key)_:
|
|
: <input type="text" name="PrivateKey:INDEX" class="wide private-INDEX" maxlength="64" value="" onchange="highlight($(document.wg0),this,0)" placeholder="(_(optional)_)">
|
|
<span class="inline-block">
|
|
<input type="button" class="form" value="_(Generate Keypair)_" onclick="keypair($(document.wg0),'INDEX')">
|
|
</span>
|
|
|
|
:wg_generate_keypair_help:
|
|
|
|
_(Peer public key)_:
|
|
: <input type="text" name="PublicKey:INDEX" class="wide public-INDEX" maxlength="64" onchange="highlight($(document.wg0),this,0)" placeholder="(_(mandatory)_)" value="" required>
|
|
|
|
:wg_generate_keypair_help:
|
|
|
|
_(Peer preshared key)_:
|
|
: <input type="text" name="PresharedKey:INDEX" class="wide preshared-INDEX" maxlength="64" value="" onchange="highlight($(document.wg0),this,0)" placeholder="(_(optional)_)">
|
|
<span class="inline-block">
|
|
<input type="button" class="form" value="_(Generate Key)_" onclick="presharedkey($(document.wg0),'INDEX')">
|
|
</span>
|
|
|
|
:wg_peer_preshared_key_help:
|
|
|
|
</div>
|
|
<div markdown="1" class="advanced wg0 zoneINDEX" style="display:none">
|
|
<div markdown="1" class="ipv4 wg0" style="display:none">
|
|
_(Peer tunnel address)_:
|
|
: <input type="text" name="Address:INDEX" maxlength="15" value="" onchange="if(verifyInSubnet(this)){setAllow($(document.wg0),this.value,INDEX)}" pattern="<?=$validIP4?>" title="_(IPv4 address)_">
|
|
<span class="inline-block">
|
|
<input type="button" class="form ping-button1-INDEX" value="_(Ping)_" onclick="ping($(document.wg0),this,'input[name="Address:INDEX"]')" disabled>
|
|
</span>
|
|
</div>
|
|
<div markdown="1" class="ipv6 wg0" style="display:none">
|
|
_(Peer tunnel address IPv6)_:
|
|
: <input type="text" name="Address6:INDEX" maxlength="40" value="" onchange="if(verifyInSubnet6(this)){setAllow6($(document.wg0),this.value,INDEX)}" pattern="<?=$validIP6?>" title="_(IPv6 address)_">
|
|
<span class="inline-block">
|
|
<input type="button" class="form ping-button6-INDEX" value="_(Ping)_" onclick="ping($(document.wg0),this,'input[name="Address6:INDEX"]')" disabled>
|
|
</span>
|
|
</div>
|
|
:wg_peer_tunnel_address_help:
|
|
|
|
_(Peer endpoint)_:
|
|
: <input type="hidden" name="Endpoint:INDEX" value="">
|
|
<span class="flex flex-row items-center gap-2">
|
|
<input type="text" name="gui:Endpoint:INDEX" value="" pattern="<?=$validText?>" title="_(IP address or FQDN)_" onchange="toLC(this);quickValidate(this);" placeholder="(_(not used)_)">
|
|
<span>:</span>
|
|
<input type="number" name="gui:ListenPort:INDEX" class="port" min="1" max="65535" value="" onchange="quickValidate(this);">
|
|
</span>
|
|
<span class="inline-block">
|
|
<input type="button" class="form ping-button2-INDEX" value="_(Ping)_" onclick="ping($(document.wg0),this,'input[name="gui:Endpoint:INDEX"]')" disabled>
|
|
</span>
|
|
|
|
:wg_peer_endpoint_help:
|
|
|
|
_(Peer allowed IPs)_:
|
|
: <input type="text" name="AllowedIPs:INDEX" class="wide" value="" onchange="quickValidate(this);" pattern="<?=$validList?>" title="_(Comma separated list of IPv4 and IPv6 IP addresses)_, _(CIDR optional)_" placeholder="(_(mandatory)_)" required>
|
|
|
|
:wg_peer_allowed_ips_help:
|
|
|
|
_(Peer DNS server)_:
|
|
: <input type="text" name="DNS:INDEX" maxlength="60" value="" onchange="quickValidate(this);" pattern="<?=$validDNSServerList?>" title="_(Comma separated list of IPv4 and IPv6 IP addresses)_" placeholder="(_(optional)_)">
|
|
|
|
:wg_peer_dns_server_help:
|
|
|
|
_(Persistent keepalive)_:
|
|
: <span class="flex flex-row items-center gap-2">
|
|
<input type="number" name="PersistentKeepalive:INDEX" class="trim" min="0" max="600" value="" onchange="quickValidate(this);" placeholder="(_(disabled)_)">
|
|
<span>_(seconds)_</span>
|
|
</span>
|
|
|
|
:wg_persistent_keepalive_help:
|
|
|
|
</div>
|
|
</div>
|
|
</script>
|
|
</div>
|