Merge pull request #2007 from bergware/master

Wireless and VM improvements
This commit is contained in:
tom mortensen
2025-02-11 13:01:55 -08:00
committed by GitHub
15 changed files with 2611 additions and 2961 deletions

View File

@@ -1,6 +1,6 @@
<?PHP
/* Copyright 2005-2023, Lime Technology
* Copyright 2012-2023, Bergware International.
/* Copyright 2005-2025, Lime Technology
* Copyright 2012-2025, Bergware International.
* Copyright 2015-2021, Derek Macias, Eric Schultz, Jon Panozzo.
*
* This program is free software; you can redistribute it and/or
@@ -25,8 +25,8 @@ if (substr($_SERVER['REQUEST_URI'],0,4) != '/VMs') {
switch ($display['theme']) {
case 'gray' : $bgcolor = '#121510'; $border = '#606e7f'; $top = -44; break;
case 'azure': $bgcolor = '#edeaef'; $border = '#606e7f'; $top = -44; break;
case 'black': $bgcolor = '#212121'; $border = '#2b2b2b'; $top = -58; break;
default : $bgcolor = '#ededed'; $border = '#e3e3e3'; $top = -58; break;
case 'black': $bgcolor = '#212121'; $border = '#2b2b2b'; $top = -64; break;
default : $bgcolor = '#ededed'; $border = '#e3e3e3'; $top = -64; break;
}
$templateslocation = "/boot/config/plugins/dynamix.vm.manager/savedtemplates.json";
@@ -119,34 +119,35 @@ if (strpos($strSelectedTemplate,"User-") !== false) {
<div id="template_img_chooser_outer">
<div id="template_img_chooser">
<?
$arrImagePaths = [
"$docroot/plugins/dynamix.vm.manager/templates/images/*.png" => '/plugins/dynamix.vm.manager/templates/images/',
"$docroot/boot/config/plugins/dynamix.vm.manager/templates/images/*.png" => '/boot/config/plugins/dynamix.vm.manager/templates/images/'
];
foreach ($arrImagePaths as $strGlob => $strIconURLBase) {
foreach (glob($strGlob) as $png_file) {
echo '<div class="template_img_chooser_inner"><img src="'.$strIconURLBase.basename($png_file).'" basename="'.basename($png_file).'"><p>'.basename($png_file,'.png').'</p></div>';
}
$arrImagePaths = [
"$docroot/plugins/dynamix.vm.manager/templates/images/*.png" => '/plugins/dynamix.vm.manager/templates/images/',
"$docroot/boot/config/plugins/dynamix.vm.manager/templates/images/*.png" => '/boot/config/plugins/dynamix.vm.manager/templates/images/'
];
foreach ($arrImagePaths as $strGlob => $strIconURLBase) {
foreach (glob($strGlob) as $png_file) {
echo '<div class="template_img_chooser_inner"><img src="'.$strIconURLBase.basename($png_file).'" basename="'.basename($png_file).'"><p>'.basename($png_file,'.png').'</p></div>';
}
}
?>
</div>
</div>
</td>
<td></td>
</tr>
<tr>
<td>_(Autostart)_:</td>
<td>
<span class="width"><input type="checkbox" id="domain_autostart" name="domain[autostart]" style="display:none" class="autostart" value="1" <?if ($arrLoad['autostart']) echo 'checked'?>></span>
</td>
<td></td>
</tr>
</table>
<table>
<tr style="line-height: 16px; vertical-align: middle;">
<td>_(Autostart)_:</td>
<td><div style="margin-left:-10px;padding-top:6px"><input type="checkbox" id="domain_autostart" name="domain[autostart]" style="display:none" class="autostart" value="1" <?if ($arrLoad['autostart']) echo 'checked'?>></div></td>
</tr>
</table>
<blockquote class="inline_help">
<p>If you want this VM to start with the array, set this to yes.</p>
</blockquote>
<div id="form_content"><?eval('?>'.parse_file("$docroot/plugins/dynamix.vm.manager/templates/{$arrLoad['form']}",false))?></div>
</form>
</div>
@@ -167,18 +168,17 @@ function isinlineXMLMode() {
return ($.cookie('vmmanager_inline_mode') == 'show');
}
function hidexml(checked)
{
function hidexml(checked) {
var form = document.getElementById("vmform"); // Replace "yourFormId" with the actual ID of your form
var xmlElements = form.getElementsByClassName("xml");
if (checked == 0) xmldisplay = "none"; else xmldisplay = "";
// Unhide each element
for (var i = 0; i < xmlElements.length; i++) {
xmlElements[i].style.display = xmldisplay; // Setting to empty string will revert to default style
}
var xmlElements = form.getElementsByClassName("xml");
if (checked == 0) xmldisplay = "none"; else xmldisplay = "";
// Unhide each element
for (var i = 0; i < xmlElements.length; i++) {
xmlElements[i].style.display = xmldisplay; // Setting to empty string will revert to default style
}
}
$(function() {
$(function(){
$('.autostart').switchButton({
on_label: "_(Yes)_",
off_label: "_(No)_",

File diff suppressed because it is too large Load Diff

View File

@@ -1230,16 +1230,8 @@ class Array2XML {
function getValidNetworks() {
global $lv;
$arrValidNetworks = [];
exec("ls --indicator-style=none /sys/class/net|grep -Po '^((vir)?br|vhost)[0-9]+(\.[0-9]+)?'",$arrBridges);
if (!is_array($arrBridges)) {
$arrBridges = [];
}
// Make sure the default libvirt bridge is first in the list
if (($key = array_search('virbr0', $arrBridges)) !== false) {
unset($arrBridges[$key]);
}
// We always list virbr0 because libvirt might not be started yet (thus the bridge doesn't exists)
exec("ls --indicator-style=none /sys/class/net | grep -Po '^(br|vhost|wlan)[0-9]+(\.[0-9]+)?'",$arrBridges);
// add 'virbr0' as default first choice
array_unshift($arrBridges, 'virbr0');
$arrValidNetworks['bridges'] = array_values($arrBridges);
@@ -1256,6 +1248,7 @@ class Array2XML {
$arrValidNetworks['libvirt'] = array_values($arrVirtual);
}*/
return $arrValidNetworks;
}

View File

@@ -1,13 +1,11 @@
body{-webkit-overflow-scrolling:touch}
#vmform table{margin-top:0}
#vmform table{margin-top:0;table-layout:fixed}
#vmform div.title + table{margin-top:0}
#vmform table tr{vertical-align:top;line-height:40px}
#vmform table tr td:nth-child(odd){width:300px;text-align:right;padding-right:10px}
#vmform table tr td:nth-child(even){width:110px}
@media (max-width:1280px){#vmform table tr td:first-child{width:35%;padding-right:4rem}}
@media (min-width:1281px){#vmform table tr td:first-child{width:30%;padding-right:4rem}}
@media (min-width:1921px){#vmform table tr td:first-child{width:25%;padding-right:4rem}}
#vmform table tr td:last-child{width:inherit}
#vmform table tr{vertical-align:top;line-height:4rem;height:4rem}
#vmform table tr td:nth-child(1){width:25%;text-align:right;padding-right:4rem}}
#vmform table tr td:nth-child(2){width:800px}
#vmform textarea{max-width:500px;scrollbar-width:4px}
#vmform textarea::-webkit-scrollbar{height:4px;width:4px}
#vmform .multiple{position:relative}
#vmform .sectionbutton{position:absolute;left:2px;cursor:pointer;opacity:0.4;font-size:1.4rem;line-height:17px;z-index:10;transition-property:opacity,left;transition-duration:0.1s;transition-timing-function:linear}
#vmform .sectionbutton.remove{top:0;opacity:0.3}
@@ -43,4 +41,17 @@ span.advancedview_panel{display:none;line-height:16px;margin-top:1px}
#vmform .disk_preview{display:inline-block;color:#BBB;transform:translate(0px, 1px)}
i.fa-plus-circle,i.fa-minus-circle{margin-left:8px}
input[type=checkbox]{margin-left:0}
#vmform table.timers td.present {width:150px;}
span.width{display:inline-block;width:280px}
span.column1{display:inline-block;width:140px}
span.column2{display:inline-block;width:220px}
input#btnvCPUSelect{font-size:1rem;padding:5px 10px;margin:0 0 0 10px}
span.space{display:inline-block;width:60px}
span.label{display:inline-block;width:110px;text-align:right}
select.narrow{min-width:90px!important}
select.second{margin-left:12px;max-width:90px;margin-right:0}
input.trim{width:98px;min-width:98px}
input.second{margin-left:8px}
.autostart~.switch-button-background{margin-top:8px!important;margin-left:0!important}
.hidden{display:none!important}
.CodeMirror{border:1px solid #eee;cursor:text;margin-top:15px;margin-bottom:10px}
.CodeMirror pre.CodeMirror-placeholder{color:#999}

View File

@@ -1,13 +1,11 @@
body{-webkit-overflow-scrolling:touch}
#vmform table{margin-top:0}
#vmform table{margin-top:0;table-layout:fixed}
#vmform div.title + table{margin-top:0}
#vmform table tr{vertical-align:top;line-height:40px}
#vmform table tr td:nth-child(odd){width:300px;text-align:right;padding-right:10px}
#vmform table tr td:nth-child(even){width:110px}
@media (max-width:1280px){#vmform table tr td:first-child{width:35%;padding-right:4rem}}
@media (min-width:1281px){#vmform table tr td:first-child{width:30%;padding-right:4rem}}
@media (min-width:1921px){#vmform table tr td:first-child{width:25%;padding-right:4rem}}
#vmform table tr td:last-child{width:inherit}
#vmform table tr{vertical-align:top;line-height:4rem;height:4rem}
#vmform table tr td:nth-child(1){width:25%;text-align:right;padding-right:4rem}}
#vmform table tr td:nth-child(2){width:800px}
#vmform textarea{max-width:500px;scrollbar-width:4px}
#vmform textarea::-webkit-scrollbar{height:4px;width:4px}
#vmform .multiple{position:relative}
#vmform .sectionbutton{position:absolute;left:2px;cursor:pointer;opacity:0.4;font-size:1.4rem;line-height:17px;z-index:10;transition-property:opacity,left;transition-duration:0.1s;transition-timing-function:linear}
#vmform .sectionbutton.remove{top:0;opacity:0.3}
@@ -43,4 +41,17 @@ span.advancedview_panel{display:none;line-height:16px;margin-top:1px}
#vmform .disk_preview{display:inline-block;color:#BBB;transform:translate(0px, 1px)}
i.fa-plus-circle,i.fa-minus-circle{margin-left:8px}
input[type=checkbox]{margin-left:0}
#vmform table.timers td.present {width:150px;}
span.width{display:inline-block;width:280px}
span.column1{display:inline-block;width:140px}
span.column2{display:inline-block;width:220px}
input#btnvCPUSelect{font-size:1rem;padding:5px 10px;margin:0 0 0 10px}
span.space{display:inline-block;width:60px}
span.label{display:inline-block;width:110px;text-align:right}
select.narrow{min-width:90px!important}
select.second{margin-left:12px;max-width:90px;margin-right:0}
input.trim{width:98px;min-width:98px}
input.second{margin-left:8px}
.autostart~.switch-button-background{margin-top:8px!important;margin-left:0!important}
.hidden{display:none!important}
.CodeMirror{border:1px solid #eee;cursor:text;margin-top:15px;margin-bottom:10px}
.CodeMirror pre.CodeMirror-placeholder{color:#999}

File diff suppressed because it is too large Load Diff

View File

@@ -4,8 +4,8 @@ Tag="icon-vpn"
Nchan="wg_poller"
---
<?PHP
/* Copyright 2005-2023, Lime Technology
* Copyright 2012-2023, Bergware International.
/* 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,
@@ -20,11 +20,11 @@ $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)[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 -br -4 addr show scope global|awk '/^(br|bond|eth)[0-9]+(\\.[0-9]+)?/{split(\$3,ip,\"/\");print ip[1]}'",$hosts);
exec("ip -br -6 addr show scope global|awk '/^(br|bond|eth)[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("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');
@@ -37,23 +37,25 @@ if (count($filter)) {
elseif (strpos($network,':')!==false && !in_array($network,$subnets6)) $subnets6[] = $network;
}
}
$subnets = implode(',',$subnets);
$hosts = implode(',',$hosts);
$subnets = implode(',',$subnets);
$hosts = implode(',',$hosts);
$subnets6 = implode(',',$subnets6);
$hosts6 = implode(',',$hosts6);
$hosts6 = implode(',',$hosts6);
function ifname($eth, $new) {
return str_replace('eth',$new,$eth);
}
function iflink($eth) {
$system = '/sys/class/net/';
if (file_exists($system.ifname($eth,'br'))) return ifname($eth,'br');
if (file_exists($system.ifname($eth,'bond'))) return ifname($eth,'bond');
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";
@@ -125,6 +127,7 @@ function readConf(&$peer_wg, &$wg, $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")?:'');
@@ -139,22 +142,26 @@ $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";
$postUp3 = "iptables -N WIREGUARD_DROP_<WG>;iptables -A WIREGUARD -o $link -j WIREGUARD_DROP_<WG>";
$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";
$postUp36 = "ip6tables -N WIREGUARD_DROP_<WG>;ip6tables -A WIREGUARD -o $link -j WIREGUARD_DROP_<WG>";
$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";
$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";
$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";
$postDown36= "ip6tables -F WIREGUARD_DROP_<WG>;ip6tables -D WIREGUARD -o $link -j WIREGUARD_DROP_<WG>;ip6tables -X WIREGUARD_DROP_<WG>";
$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)";
@@ -197,6 +204,7 @@ foreach (glob("$docroot/webGui/WG[1-9]*.page",GLOB_NOSORT) as $wgX) {
$build = true;
}
}
// add additional tunnels
foreach ($vtuns as $wgX) {
if ($wgX == 'wg0') continue;
@@ -244,26 +252,32 @@ if (!HTMLInputElement.prototype.reportValidity || (navigator.userAgent.indexOf("
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,html:true,type:'error',confirmButtonText:"_(Ok)_"});
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
@@ -282,6 +296,7 @@ function validateForm(form,vtun) {
});
return isValid;
}
function prepareSettings(form,vtun) {
var subnets = '<?=$subnets?>';
var hosts = '<?=$hosts?>';
@@ -465,6 +480,7 @@ function prepareSettings(form,vtun) {
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');
@@ -472,31 +488,36 @@ function keypair(form,i) {
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() {
$.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',confirmButtonText:"_(Proceed)_",cancelButtonText:"_(Cancel)_",showCancelButton:true},function(){
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)_",html:true,type:'error',confirmButtonText:"_(Ok)_"});},250);
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;
@@ -574,6 +595,7 @@ function addPeer(form,vtun) {
});
});
}
function delPeer(form,peer) {
var deleted = form.find('input[name="#deleted"]');
var comma = deleted.val() ? ',' : '';
@@ -581,12 +603,15 @@ function delPeer(form,peer) {
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();
@@ -648,6 +673,7 @@ function updatePeer(form,i,n,vtun) {
showRoute(form,vtun);
showAccess(form,i,n);
}
function setProtocol(form,vtun,update) {
switch (form.find('select[name="PROT:0"]').val()) {
case '46':
@@ -708,6 +734,7 @@ function setProtocol(form,vtun,update) {
break;
}
}
function quickValidate(field) {
try {
var form = $(field).parents('form');
@@ -716,6 +743,7 @@ function quickValidate(field) {
} 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];
@@ -753,6 +781,7 @@ function setPool(form,vtun) {
$(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];
@@ -793,6 +822,7 @@ function setPool6(form,vtun) {
$(this).val(netbase6[vtun]+assign).trigger('change');
});
}
function verifyInSubnet(field) {
// perform standard field validation before custom validation
field.setCustomValidity('');
@@ -813,6 +843,7 @@ function verifyInSubnet(field) {
}
return true;
}
function verifyInSubnet6(field) {
// perform standard field validation before custom validation
field.setCustomValidity('');
@@ -835,6 +866,7 @@ function verifyInSubnet6(field) {
}
return true;
}
function setAllow(form,subnet,i) {
var input = form.find('input[name="AllowedIPs:'+i+'"]');
var type = form.find('select[name="TYPE:'+i+'"]').val();
@@ -853,6 +885,7 @@ function setAllow(form,subnet,i) {
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();
@@ -871,6 +904,7 @@ function setAllow6(form,subnet6,i) {
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){
@@ -882,13 +916,16 @@ function ping(form,button,field) {
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;
@@ -896,6 +933,7 @@ function showRemark(form) {
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;
@@ -912,6 +950,7 @@ function showRoute(form,vtun,i) {
}
if (i!=null) lockEye(form,i);
}
function showAccess(form,i,n) {
switch (n) {
case '0':
@@ -939,6 +978,7 @@ function showAccess(form,i,n) {
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];
@@ -946,6 +986,7 @@ function portRemark(form,vtun,val) {
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');
@@ -970,6 +1011,7 @@ function openClose(form,icon,zone) {
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')) {
@@ -980,11 +1022,13 @@ function blockToggle(vtun) {
$.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++) {
@@ -993,6 +1037,7 @@ function isPublic(ipv4) {
}
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)?>];
@@ -1090,7 +1135,7 @@ $(function(){
});
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',html:true});
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});
@@ -1196,11 +1241,12 @@ $(function(){
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',html:true});},200);
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')">

View File

@@ -3,8 +3,8 @@ Title="Tunnel wgX"
Tag="icon-vpn"
---
<?PHP
/* Copyright 2005-2023, Lime Technology
* Copyright 2012-2023, Bergware International.
/* 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,

View File

@@ -129,19 +129,24 @@ function exceed($value, $limit, $top=100) {
}
function ipaddr($ethX='eth0', $prot=4) {
global $$ethX;
switch (_var($$ethX,'PROTOCOL:0')) {
case 'ipv4':
return _var($$ethX,'IPADDR:0');
case 'ipv6':
return _var($$ethX,'IPADDR6:0');
case 'ipv4+ipv6':
switch ($prot) {
case 4: return _var($$ethX,'IPADDR:0');
case 6: return _var($$ethX,'IPADDR6:0');
default:return [_var($$ethX,'IPADDR:0'),_var($$ethX,'IPADDR6:0')];}
$wlan = $ethX=='eth0' && lan_port('wlan0') && lan_port('wlan0',true);
switch ($prot) {
case 4:
$ipv4 = exec("ip -4 -br addr show $ethX scope global | awk '{print \$3;exit}' | sed -r 's/\/[0-9]+//'");
if ($wlan) $ipv4 = $ipv4 ?: exec("ip -4 -br addr show wlan0 scope global | awk '{print \$3;exit}' | sed -r 's/\/[0-9]+//'");
return $ipv4;
case 6:
$ipv6 = exec("ip -6 -br addr show $ethX scope global -temporary -deprecated | awk '{print \$3;exit}' | sed -r 's/\/[0-9]+//'");
if ($wlan) $ipv6 = $ipv6 ?: exec("ip -6 -br addr show wlan0 scope global -temporary -deprecated | awk '{print \$3;exit}' | sed -r 's/\/[0-9]+//'");
return $ipv6;
default:
return _var($$ethX,'IPADDR:0');
$ipv4 = exec("ip -4 -br addr show $ethX scope global | awk '{print \$3;exit}' | sed -r 's/\/[0-9]+//'");
$ipv6 = exec("ip -6 -br addr show $ethX scope global -temporary -deprecated | awk '{print \$3;exit}' | sed -r 's/\/[0-9]+//'");
if ($wlan) {
$ipv4 = $ipv4 ?: exec("ip -4 -br addr show wlan0 scope global | awk '{print \$3;exit}' | sed -r 's/\/[0-9]+//'");
$ipv6 = $ipv6 ?: exec("ip -6 -br addr show wlan0 scope global -temporary -deprecated | awk '{print \$3;exit}' | sed -r 's/\/[0-9]+//'");
}
return [$ipv4,$ipv6];
}
}

View File

@@ -6,6 +6,6 @@ if [[ -n $1 ]]; then
fi
for cmd in $SERVICES; do
/etc/rc.d/rc.$cmd update >/dev/null 2>&1
/etc/rc.d/rc.$cmd update &>/dev/null
done
exit 0

View File

@@ -6,5 +6,5 @@ lock=/tmp/atlock.tmp
log "delay = ${1:-1}s"
rm -f $lock
echo "sleep ${1:-1};/usr/local/emhttp/webGui/scripts/reload_services $lock"|at -M now 2>/dev/null
echo "sleep ${1:-1};/usr/local/emhttp/webGui/scripts/reload_services $lock"|at -M now &>/dev/null
exit 0

View File

@@ -409,10 +409,10 @@ docker_network_start(){
if [[ $TYPE == br ]]; then
VHOST=$NETWORK
elif [[ $TYPE == wlan ]]; then
VHOST=shim-$NETWORK
VHOST=$NETWORK
ATTACH=ipvlan
else
VHOST=vhost${NETWORK//[^0-9.]/}
[[ $DOCKER_ALLOW_ACCESS == yes && -n $IPV4 ]] && VHOST=vhost${NETWORK//[^0-9.]/} || VHOST=$NETWORK
fi
docker network create -d $ATTACH $SUBNET $GATEWAY $SERVER $RANGE $SUBNET6 $GATEWAY6 $SERVER6 -o parent=$VHOST $NETWORK | xargs docker network inspect -f "created network $ATTACH {{.Name}} with subnets: {{range .IPAM.Config}}{{.Subnet}}; {{end}}" 2>/dev/null | log
# connect containers to this new network

View File

@@ -30,6 +30,7 @@ CERTPATH="$SSL/certs/certificate_bundle.pem"
TSCERTPATH="$SSL/certs/ts_bundle.pem"
MYSERVERS="/boot/config/plugins/dynamix.my.servers/myservers.cfg"
DEFAULTS="/etc/default/nginx"
SYSTEM="/sys/class/net"
# Load defaults
# Defines NGINX_CUSTOMFA for custom Content-Security-Policy frame-ancestors url
@@ -531,10 +532,14 @@ build_ssl(){
LANMDNS=${LANNAME}${LOCAL_TLD:+.$LOCAL_TLD}
# fetch LAN IP address (read management interface eth0)
sed -n '/^\[eth0\]$/,/^TYPE/p' $NETWORK_INI >$NETWORK_INI.eth0
LANIP=$(scan IPADDR:0 $NETWORK_INI.eth0);
LANIP6=$(scan IPADDR6:0 $NETWORK_INI.eth0);
rm -f $NETWORK_INI.eth0
[[ -e $SYSTEM/bond0 ]] && DEV=bond0 || DEV=eth0
[[ -e $SYSTEM/br0 ]] && DEV=br0
LANIP=$(ip -4 -br addr show $DEV scope global | sed -r 's/\/[0-9]+//g' | awk '{print $3;exit}')
LANIP6=$(ip -6 -br addr show $DEV scope global -temporary -deprecated | sed -r 's/\/[0-9]+//g' | awk '{print $3;exit}')
# try wireless connection if no IP address on interface eth0
[[ -z $LANIP && -e $SYSTEM/wlan0 ]] && LANIP=$(ip -4 -br addr show wlan0 scope global | sed -r 's/\/[0-9]+//g' | awk '{print $3;exit}')
[[ -z $LANIP6 && -e $SYSTEM/wlan0 ]] && LANIP6=$(ip -6 -br addr show wlan0 scope global -temporary -deprecated | sed -r 's/\/[0-9]+//g' | awk '{print $3;exit}')
# regenerate self-signed cert if local TLD changes */
SELFCERTPATH=$SSL/certs/${LANNAME}_unraid_bundle.pem

View File

@@ -81,7 +81,7 @@ ipaddr_up(){
if [[ $DHCP == yes ]]; then
# bring up interface using DHCP/SLAAC
ipv6_addr 1 1
OPTIONS="-q -n -p -t 10"
OPTIONS="-q -n -p -t10 -J"
[[ -n $HOSTNAME ]] && OPTIONS="$OPTIONS -h $HOSTNAME"
[[ $DNS == yes ]] && OPTIONS="$OPTIONS -C resolv.conf"
[[ $IP == ipv4 ]] && OPTIONS="$OPTIONS -4"
@@ -180,7 +180,7 @@ wifi_start(){
local REPLY
if [[ -e $SYSTEM/$PORT ]]; then
LINK=shim-$PORT
[[ -e $SYSTEM/$LINK ]] || run ip link add link $PORT name $LINK type ipvlan mode l2 bridge
[[ -e $SYSTEM/$LINK ]] || run ip link add link $PORT name $LINK type ipvtap mode l2 bridge
run ip link set $PORT up
run ip link set $LINK up
ssl_init

View File

@@ -7,10 +7,10 @@
#
# create initial network.ini file on system start
# create system welcome message
# update files on DHCP events 'BOUND[6] IPV4LL'
# update files on DHCP events 'BOUND[6] IPV4LL EXPIRE'
# update services listening interfaces / addresses
[[ (-z $reason && -z $1) || (-n $reason && ! "BOUND6 IPV4LL" =~ $reason) ]] && exit 0
[[ (-z $reason && -z $1) || (-n $reason && ! "BOUND6 IPV4LL EXPIRE" =~ $reason) ]] && exit 0
INI=/var/local/emhttp/network.ini.new
CFG=/boot/config/network.cfg
@@ -227,7 +227,8 @@ mv $INI ${INI%.*}
log "interface=${interface:-$1}, reason=$reason, protocol=$protocol"
# delayed execution
/usr/local/emhttp/webGui/scripts/update_services 45
[[ $reason == EXPIRE ]] && DELAY=15 || DELAY=45
/usr/local/emhttp/webGui/scripts/update_services $DELAY
# send update information
if [[ -n $DATA && -e /var/run/nginx.socket ]]; then
@@ -241,15 +242,15 @@ if [[ -z $interface || "eth0 br0 bond0 wlan0" =~ $interface ]]; then
# find management interface
[[ -e /sys/class/net/bond0 ]] && dev=bond0 || dev=eth0
[[ -e /sys/class/net/br0 ]] && dev=br0
IPv4=$(ip -br -4 addr show $dev scope global | sed -r 's/\/[0-9]+//g' | awk '{print $3;exit}')
IPv6=$(ip -br -6 addr show $dev scope global -temporary -deprecated | sed -r 's/\/[0-9]+//g' | awk '{print $3;exit}')
IPv4=$(ip -4 -br addr show $dev scope global | sed -r 's/\/[0-9]+//g' | awk '{print $3;exit}')
IPv6=$(ip -6 -br addr show $dev scope global -temporary -deprecated | sed -r 's/\/[0-9]+//g' | awk '{print $3;exit}')
# show current IP assignment
[[ -n $IPv4 ]] && echo " IPv4 address: $IPv4" >>/etc/issue || echo " IPv4 address: not set" >>/etc/issue
[[ -n $IPv6 ]] && echo " IPv6 address: $IPv6" >>/etc/issue || echo " IPv6 address: not set" >>/etc/issue
if [[ -e /sys/class/net/wlan0 ]]; then
echo "Wireless network:" >>/etc/issue
IPv4=$(ip -br -4 addr show wlan0 scope global | sed -r 's/\/[0-9]+//g' | awk '{print $3;exit}')
IPv6=$(ip -br -6 addr show wlan0 scope global -temporary -deprecated | sed -r 's/\/[0-9]+//g' | awk '{print $3;exit}')
IPv4=$(ip -4 -br addr show wlan0 scope global | sed -r 's/\/[0-9]+//g' | awk '{print $3;exit}')
IPv6=$(ip -6 -br addr show wlan0 scope global -temporary -deprecated | sed -r 's/\/[0-9]+//g' | awk '{print $3;exit}')
[[ -n $IPv4 ]] && echo " IPv4 address: $IPv4" >>/etc/issue || echo " IPv4 address: not set" >>/etc/issue
[[ -n $IPv6 ]] && echo " IPv6 address: $IPv6" >>/etc/issue || echo " IPv6 address: not set" >>/etc/issue
fi