Merge pull request #833 from bergware/master

Add WireGuard GUI
This commit is contained in:
tom mortensen
2021-05-07 14:03:19 -07:00
committed by GitHub
11 changed files with 2727 additions and 47 deletions
+169 -16
View File
@@ -127,7 +127,7 @@ it may only be exported using SMB protocol.
An unRAID disk array consists of a single parity disk and a number of data disks. The data
disks are exclusively used to store user data, and the parity disk provides the redundancy necessary
to recover from any singe disk failure.
to recover from any single disk failure.
Note that we are careful to use the term *disk* when referring to an array storage device. We
use the term *hard drive* (or sometimes just *drive*) when referring to an actual hard disk drive (HDD)
@@ -164,7 +164,7 @@ drive and jot it down somewhere; you will need this information later.
build, then the Main page will show no disks installed. This doesn't mean the system can't detect your
hard drives; it just means that none have been assigned yet.
3. Remember the serial numbers you recored back in step 1? For parity and each data disk, select the
3. Remember the serial numbers you recorded back in step 1? For parity and each data disk, select the
proper hard drive based on its serial number from the drop down list.
#### Hot Plug
@@ -246,7 +246,7 @@ A value of zero will disable the critical threshold (including notifications).
**Balance** will run the *btrfs balance* program to restripe the extents across all pool devices, for example,
to convert the pool from raid1 to raid0 or vice-versa.
When a *full balance* is perfomred, it basically rewrites everything in the current filesystem.
When a *full balance* is performed, it basically rewrites everything in the current filesystem.
A *mode conversion* affects the btrfs data extents; metadata always uses raid1 and is converted to raid1 if necessary by any balance operation.
@@ -551,7 +551,7 @@ Determines whether a directory is allowed to expand onto multiple disks.
**Automatically split any directory as required**
When a new file or subdirectory needs to be created in a share, Unraid OS first chooses which disk
it should be created on, according to the configured *Allocation method*. If the parent directory containing
the new file or or subdirectory does not exist on this disk, then Unraid OS will first create all necessary
the new file or subdirectory does not exist on this disk, then Unraid OS will first create all necessary
parent directories, and then create the new file or subdirectory.
**Automatically split only the top level directory as required**
@@ -592,7 +592,7 @@ enough free space exists on the Cache disk/pool.
If there is insufficient space on the Cache disk/pool, then new files and directories are created on the array.
When the *mover* is invoked, files and subdirectories are transferred off the Cache disk/pool and onto the array.
**Only** indicates that all new files and subdirectories must be writen to the Cache disk/pool.
**Only** indicates that all new files and subdirectories must be written to the Cache disk/pool.
If there is insufficient free space on the Cache disk/pool, *create* operations will fail with *out of space* status.
*Mover* will take no action so any existing files for this share that are on the array are left there.
@@ -651,7 +651,7 @@ The default setting of **auto** allows clients that support case sensitive filen
to tell the Samba server on a per-packet basis that they wish to access the file system in a case-sensitive manner (to support UNIX
case sensitive semantics). No Windows system supports case-sensitive filenames so setting this option to **auto** is the same as
setting it to No for them; however, the case of filenames passed by a Windows client will be preserved. This setting can result
in reduced peformance with very large directories because Samba must do a filename search and match on passed names.
in reduced performance with very large directories because Samba must do a filename search and match on passed names.
A setting of **Yes** means that files are created with the case that the client passes, and only accessible using this same case.
This will speed very large directory access, but some Windows applications may not function properly with this setting. For
@@ -815,7 +815,7 @@ If set to 'Yes' then the [Spinup Groups](/Help) feature is enabled.
:disk_default_partition_format_help:
Defines the type of partition layout to create when formatting hard drives 2TB in size and
smaller **only**. (All devices larger then 2TB are always set up with GPT partition tables.)
smaller **only**. (All devices larger than 2TB are always set up with GPT partition tables.)
**MBR: unaligned** setting will create MBR-style partition table, where the single
partition 1 will start in the **63rd sector** from the start of the disk. This is the *traditional*
@@ -823,7 +823,7 @@ setting for virtually all MBR-style partition tables.
**MBR: 4K-aligned** setting will create an MBR-style partition table, where the single
partition 1 will start in the **64th sector** from the start of the disk. Since the sector size is 512 bytes,
this will *align* the start of partition 1 on a 4K-byte boundry. This is required for proper
this will *align* the start of partition 1 on a 4K-byte boundary. This is required for proper
support of so-called *Advanced Format* drives.
Unless you have a specific requirement do not change this setting from the default **MBR: 4K-aligned**.
@@ -973,7 +973,7 @@ This can be an image file with a specific size or a dedicated folder.
:docker_vdisk_size_help:
If the system needs to create a new docker image file, this is the default size to use specified in GB.
To resize an existing image file, specify the new size here. Next time the Docker service is started the file (and file system) will increased to the new size (but never decreased).
To resize an existing image file, specify the new size here. Next time the Docker service is started the file (and file system) will be increased to the new size (but never decreased).
:end
:docker_vdisk_location_help:
@@ -1300,7 +1300,7 @@ Enter your local network Workgroup name. Usually this is "WORKGROUP".
:end
:smb_local_master_help:
If set to 'Yes' then the server will fully participate in browser elections, and in the absense
If set to 'Yes' then the server will fully participate in browser elections, and in the absence
of other servers, will usually become the local Master Browser.
:end
@@ -1469,7 +1469,7 @@ This is the libvirt volume.
:vms_libvirt_vdisk_size_help:
If the system needs to create a new libvirt image file, this is the default size to use specified in GB.
To resize an existing image file, specify the new size here. Next time the Libvirt service is started the file (and file system) will increased to the new size (but never decreased).
To resize an existing image file, specify the new size here. Next time the Libvirt service is started the file (and file system) will be increased to the new size (but never decreased).
:end
:vms_libvirt_location_help:
@@ -1545,7 +1545,7 @@ If repair is needed you should check the *Correct file system errors* and run a
:end
:eth_interface_description_help:
Use this optional field to provide addditional information about the purpose of the connection.
Use this optional field to provide additional information about the purpose of the connection.
:end
:eth_mac_address_help:
@@ -1581,7 +1581,7 @@ This mode transmits everything on all slave interfaces. This mode is least used
This mode is known as *Dynamic Link Aggregation*. It creates aggregation groups that share the same speed and duplex settings.
It requires a switch that supports IEEE 802.3ad dynamic link.
Slave selection for outgoing traffic is done according to the transmit hash policy, which may be changed from the default simple XOR policy via the xmit_hash_policy option.
Note that not all transmit policies may be 802.3ad compliant, particularly inregards to the packet mis-ordering requirements of section 43.2.4 of the 802.3ad standard.
Note that not all transmit policies may be 802.3ad compliant, particularly in regards to the packet mis-ordering requirements of section 43.2.4 of the 802.3ad standard.
Different peer implementations will have varying tolerances for noncompliance.
**Mode 5 (balance-tlb)**<br>
@@ -1722,7 +1722,7 @@ or enter a valid IPv6 route in the format *nnnn:nnnn:nnnn::nnnn/xxx*, e.g. *fe80
Select the gateway from the dropdown list or enter a valid IPv4/IPv6 address as gateway value.
The metric value is optional, it defaults to 1. Use it to select the prefered gateway when more than one entry of the same route exist.
The metric value is optional, it defaults to 1. Use it to select the preferred gateway when more than one entry of the same route exists.
:end
:apc_ups_daemon_help:
@@ -1757,10 +1757,10 @@ Define a *UPS type*, which corresponds to the type of UPS you have (see the Desc
:end
:apc_ups_device_help:
Enter the *device* which correspondes to your situation, only applicable when *UPS type* is not set to USB.
Enter the *device* which corresponds to your situation, only applicable when *UPS type* is not set to USB.
+ **apcsmart** - /dev/tty**
+ **net** - hostname:port. Hostname is the IP address of the NIS server. The deafult port is 3551
+ **net** - hostname:port. Hostname is the IP address of the NIS server. The default port is 3551
+ **snmp** - hostname:port:vendor:community. Hostname is the ip address or hostname of the UPS on the network. Vendor can be can be "APC" or "APC_NOTRAP". "APC_NOTRAP" will disable SNMP trap catching; you usually want "APC". Port is usually 161. Community is usually "private"
+ **dumb** - /dev/tty**
+ **pcnet** - ipaddr:username:passphrase:port. ipaddr is the IP address of the UPS management card. username and passphrase are the credentials for which the card has been configured. port is the port number on which to listen for messages from the UPS, normally 3052. If this parameter is empty or missing, the default of 3052 will be used
@@ -2082,3 +2082,156 @@ This displays the output of the `lsscsi` command. The numeric identifiers are u
Note that linux groups ATA, SATA and SAS devices with true SCSI devices.
:end
; unraid.net help - added March 11, 2021
:unraidnet_wanpanel_help:
WAN Port is the external TCP port number setup on your router to NAT/Port Forward traffic from the internet to this
Unraid server SSL port for secure web traffic.
:end
:unraidnet_inactivespanel_help:
Click Activate to set up a local git repo for your local USB Flash boot device and connect to a dedicated remote on unraid.net tied to this server.
:end
:unraidnet_changespanel_help:
The Not Up-to-date status indicates there are local files which are changed vs. the remote on unraid.net.
Click Update to push changes to the remote.
Click Changes to see what has changed.
:end
:unraidnet_uptodatepanel_help:
The Up-to-date status indicates your local configuration matches that stored on the unraid.net remote.
:end
:unraidnet_activepanel_help:
Click Deactivate to pause communication with your remote on unraid.net.
Click Reinitialize to erase all change history in both local and unraid.net remote.
:end
; WireGuard help text
:wg_local_name_help:
Use this field to set a name for this connection and make it easily recognizable. The same name will appear in the configuration of any peers.
:end
:wg_generate_keypair_help:
Use the **Generate Keypair** button to automatically create a uniqe private and public key combination.<br>
Or paste in an existing private key, generated by WireGuard. Do **NOT** share this private key with others!
:end
:wg_local_tunnel_network_pool_help:
WireGuard tunnels need an internal IP address. Assign a network pool using the default IPv4 network <?=$netpool['wg0']?>/24
or the default IPv6 network <?=$netpool6['wg0']?>/64 or assign your own network pool from which automatic assignment can be done for both this server and any peers.
The *tunnel network pool* must be a unique network not already existing on the server or any of the peers.
:end
:wg_local_tunnel_network_pool_X_help:
WireGuard tunnels need an internal IP address. Assign a network pool using the default IPv4 network <?=$netpool['wgX']?>/24 or
the default IPv6 network <?=$netpool6['wgX']?>/64 or assign your own network pool from which automatic assignment can be done for both this server and any peers.
The *tunnel network pool* must be a unique network not already existing on the server or any of the peers.
:end
:wg_local_tunnel_address_help:
This field is auto filled-in when a local tunnel network pool is created. It is allowed to overwrite the assignment, but this is normally not necessary. Use with care when changing manually.
:end
:wg_local_tunnel_address_help:
This field is auto filled-in when a local tunnel network pool is created. It is allowed to overwrite the assignment, but this is normally not necessary. Use with care when changing manually.
:end
:wg_local_endpoint_help:
This field is automatically filled in with the public management domain name *www.&lt;hash&gt;.unraid.net* or the public address of the server.<br>
This allows VPN tunnels to be established from external peers to the server.<br>
Configure the correct port forwarding on your router (default port is <?=$netport['wg0']?> but this may be changed) to allow any incoming connections to reach the server.
Users with a registered domain name can use this field to specify how their server is known on the Internet. E.g. www.myserver.mydomain.<br>
Again make sure your router is properly set up.
Note to Cloudflare users: the Cloudflare proxy is designed for http traffic, it is not able to proxy VPN traffic. You must disable the Cloudflare proxy in order to use VPN with your domain.
:end
:wg_local_endpoint_X_help:
This field is automatically filled in with the public management domain name *www.&lt;hash&gt;.unraid.net* or the public address of the server.<br>
This allows VPN tunnels to be established from external peers to the server.<br>
Configure the correct port forwarding on your router (default port is <?=$netport['wgX']?> but this may be changed) to allow any incoming connections to reach the server.
Users with a registered domain name can use this field to specify how their server is known on the Internet. E.g. www.myserver.mydomain.<br>
Again make sure your router is properly set up.
Note to Cloudflare users: the Cloudflare proxy is designed for http traffic, it is not able to proxy VPN traffic. You must disable the Cloudflare proxy in order to use VPN with your domain.
:end
:wg_local_server_uses_nat_help:
When NAT is enabled, the server uses its own LAN address when forwarding traffic from the tunnel to other devices in the LAN network.
Use this setting when no router modifications are desired, but this approach doesn't work with Docker containers using custom IP addressess.
When NAT is disabled, the server uses the WireGuard tunnel address when forwarding traffic.
In this case it is required that the default gateway (router) has a static route configured to refer tunnel address back to the server.
:end
:wg_local_gateway_uses_upnp_help:
Defaults to YES if the local gateway has UPnP enabled and is responding to requests.<br>
When UPnP is enabled, it is not necessary to configure port forwarding on the router to allow incoming tunnel connections. This is done automatically.
:end
:wg_local_tunnel_firewall_help:
The firewall function controls remote access over the WireGuard tunnel to specific hosts and/or subnets.<br>
The default rule is "deny" and blocks addresses specified in this field, while allowing all others.<br>
Changing the rule to "allow" inverts the selection, meaning only the specified addresses are allowed and all others are blocked.<br>
Use a comma as separator when more than one IP address is entered.
:end
:wg_mtu_size_help:
Leave this to the default automatic mode to select the MTU size. This MTU size is common for all peer connections.
:end
:wg_peer_configuration_help:
The <i class='fa fa-fw fa-eye'></i> icon is used to view a peer's configuration. A configuration can be downloaded or read directly for instant set up of the peer.<br>
The icon is disabled when no peer configuration exists or the user has made changes to the existing settings which are not applied yet.
The <i class='fa fa-fw fa-key'></i> icon is used to show or hide the private, public and preshared keys. Note that these fields are always shown when no keys are set.
:end
:wg_peer_name_help:
Use this field to set a name for this peer connection and make it easily recognizable. The same name will appear in the configuration of the peer at the opposite side.
:end
: wg_peer_preshared_key_help:
For added security a preshared key can be used. Use the **Generate Key** button to automatically create a unique preshared key.<br>
This key is the same at both server and peer side and is added to the peer configuration as well.
:end
:wg_peer_tunnel_address_help:
This field is auto filled-in when a local tunnel network pool is created. It is allowed to overwrite the assignment, but this is normally not necessary. Use with care when changing manually.<br>
Each peer must have a unique tunnel IP address.
:end
:wg_peer_endpoint_help:
When this field is left empty, the server operates in *passive mode* to establish the tunnel. It must be the peer which starts the tunnel.
When an IP address is entered to connect to the peer, the server operates in *active mode* and establishes the tunnel to the peer as soon as there is data to send.
*Note: this field is mandatory for "server-to-server" and "LAN-to-LAN" connections*
:end
:wg_peer_allowed_ips_help:
This field is automatically filled in with the tunnel address of the peer. This allows the server to reach the peer over the tunnel.<br>
When the peer is another server or router with additional networks, then their subnets can be added here to make these networks reachable over the tunnel.
:end
:wg_peer_dns_server_help:
Use this entry to overwrite the current DNS server assignment of the Peer
:end
:wg_persistent_keepalive_help:
By default a WireGuard tunnel stays silent when no traffic is present, which may cause the connection to drop.
Normally this isn't a problem since a WireGuard tunnel is automatically re-established when it is needed.<br>
A keepalive timer will hold the connection open, for most situations a timer value of 20 seconds is suitable.
Note that for mobile devices this will use more data and drain your battery faster.
:end
+31 -31
View File
@@ -48,7 +48,7 @@ $dockerd = pgrep('dockerd');
$libvirtd = pgrep('libvirtd');
$apcupsd = file_exists('/var/run/apcupsd.pid');
$conf = glob('/etc/wireguard/wg*.conf');
$wireguard = is_executable('/usr/bin/wg') && file_exists('/var/log/plugins/dynamix.wireguard.plg') && count($conf);
$wireguard = is_executable('/usr/bin/wg') && count($conf);
$started = $var['fsState']=='Started';
$sleep = isset($display['sleep']);
$array_size = $array_used = 0;
@@ -693,33 +693,6 @@ function moreInfo(data,table) {
if (data[4]>0) info.push(data[4]+" _(utilization warning)_"+(data[4]==1?'':'s'));
return info.length ? "<div class='last'><i class='icon-u-triangle failed'></i><span class='failed'>"+table+" _(has)_ "+info.join('. ')+".</span></div>" : "";
}
<?if ($wireguard):?>
function update1() {
$.post('/webGui/include/update.wireguard.php',{'#cmd':'stats','#vtun':'*'},function(data){
var n = {};
var row = data.split('\0');
for (var i=0; i < row.length; i++) {
var info = row[i].split(';');
vtun = info[0];
if (typeof n[vtun]=='undefined') n[vtun] = 0; else n[vtun]++;
if (info[1] == 0) {
$('td#'+vtun+'-hs-'+n[vtun]).text("_(not received)_");
} else if (info[1] > 86400) {
var d = parseInt(info[1]/86400);
var s = d==1 ? " _(day)_" : " _(days)_";
$('td#'+vtun+'-hs-'+n[vtun]).text(simplef("_(%s ago)_",d+s));
} else {
var h = parseInt(info[1]/3600).pad();
var m = parseInt(info[1]/60%60).pad();
var s = parseInt(info[1]%60).pad();
$('td#'+vtun+'-hs-'+n[vtun]).text(simplef("_(%s ago)_",h+':'+m+':'+s));
}
$('td#'+vtun+'-rx-'+n[vtun]).html(info[2]+'&nbsp;<i class="fa fa-fw fa-arrow-down"></i><span class="tx">'+info[3]+'&nbsp;<i class="fa fa-fw fa-arrow-up"></i></span>');
}
setTimeout(update1,1000);
});
}
<?endif;?>
function update5() {
<?if ($fans):?>
$.post('<?=$url?>',{cmd:'fan'},function(data) {
@@ -1002,6 +975,33 @@ $.each(json["cpuload"],function(k,v) {
$('#'+k).finish().animate({width:load},{step:function(){$('#'+k).css('overflow','visible').removeClass().addClass(color);}});
});
});
<?if ($wireguard):?>
var statistics = new NchanSubscriber('/sub/wireguard');
statistics.on('message', function(data) {
var n = {};
var rows = data.split('\0');
for (var i=0,row; row=rows[i]; i++) {
var info = row.split(';');
var vtun = info[0];
if (typeof n[vtun]=='undefined') n[vtun] = 0; else n[vtun]++;
if (info[1] == 0) {
$('td#'+vtun+'-hs-'+n[vtun]).text("_(not received)_");
} else if (info[1] > 86400) {
var d = parseInt(info[1]/86400);
var s = d==1 ? " _(day)_" : " _(days)_";
$('td#'+vtun+'-hs-'+n[vtun]).text(sprintf("_(%s ago)_",d+s));
} else {
var h = parseInt(info[1]/3600).pad();
var m = parseInt(info[1]/60%60).pad();
var s = parseInt(info[1]%60).pad();
$('td#'+vtun+'-hs-'+n[vtun]).text(sprintf("_(%s ago)_",h+':'+m+':'+s));
}
$('td#'+vtun+'-rx-'+n[vtun]).html(info[2]+'&nbsp;<i class="fa fa-fw fa-arrow-down"></i><span class="tx">'+info[3]+'&nbsp;<i class="fa fa-fw fa-arrow-up"></i></span>');
}
});
<?endif;?>
var sortableHelper = function(e,ui){
var width = [];
var table = ui.parent();
@@ -1050,9 +1050,6 @@ $(function() {
dropdown('enter_share');
<?endif;?>
dropdown('enter_view');
<?if ($wireguard):?>
update1();
<?endif;?>
update5();
update15();
update60();
@@ -1090,6 +1087,9 @@ $(function() {
portMenu();
loadlist(true);
cpuload.start();
<?if ($wireguard):?>
statistics.start();
<?endif;?>
sortTable($('#db-box1'),$.cookie('db-box1'));
sortTable($('#db-box2'),$.cookie('db-box2'));
sortTable($('#db-box3'),$.cookie('db-box3'));
+5
View File
@@ -0,0 +1,5 @@
Menu="NetworkServices"
Type="xmenu"
Title="VPN Manager"
Icon="icon-vpn"
Tabs="false"
File diff suppressed because it is too large Load Diff
+456
View File
@@ -0,0 +1,456 @@
Menu="parentname:nnn"
Title="Tunnel wgX"
Tag="icon-vpn"
---
<?PHP
/* Copyright 2005-2021, Lime Technology
* Copyright 2012-2021, 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.
*/
?>
<?
$check_wgX = in_array('wgX',$active) ? 'true' : 'false';
$start_wgX = in_array('wgX',$autostart);
$peer_wgX = $wgX = [];
$netpool['wgX'] = long2ip(ip2long($netpool['wg0'])+XXX*256);
$netpool6['wgX'] = str_replace(':0:0:',':XXX:0:',$netpool6['wg0']);
$netport['wgX'] = $netport['wg0']+XXX;
// read current configuration
[$conf_wgX,$cfg_wgX,$this_wgX,$vpn_wgX] = readConf($peer_wgX,$wgX,'wgX');
?>
<script>
netbase['wgX'] = <?=$netbase['wgX']?>;
netpool['wgX'] = '<?=$netpool['wgX']?>';
netport['wgX'] = '<?=$netport['wgX']?>';
netbase6['wgX'] = '<?=$netbase6['wgX']?>';
netpool6['wgX'] = '<?=$netpool6['wgX']?>';
tstate['wgX'] = "<?=$check_wgX ? 'active' : ''?>";
$(function(){
var ctrl = "<span class='status vhshift hshift'><i id='block-wgX' class='fa fa-fw fa-chevron-up' style='cursor:pointer' onclick='blockToggle(&quot;wgX&quot;)'></i></span>";
ctrl += "<span class='even wide'><span class='status vshift label'>_(Autostart)_</span><span class='status vhshift'><input type='checkbox' id='start-wgX' style='display:none'<?=$start_wgX?' checked':''?>></span></span>";
ctrl += "<span class='even'><span class='status vhshift'><input type='checkbox' id='view-wgX' style='display:none'></span></span>";
ctrl += "<span class='even'><span class='status vhshift'><input type='checkbox' id='toggle-wgX' style='display:none'></span></span>";
var form = $(document.wgX);
getPublicIP($('#endpoint-wgX').val(),'wgX',$('#protocol-wgX').val());
$('div#title').each(function(){if ($(this).html().indexOf('status vhshift')==-1) {$(this).find('span.left').append(ctrl);return false;}});
$('#start-wgX').switchButton({labels_placement:'left',off_label:"_(Off)_",on_label:"_(On)_"});
$('#start-wgX').change(function(){
var start = $('#start-wgX').is(':checked') ? 'on' : 'off';
$.post('/webGui/include/update.wireguard.php',{'#cmd':'autostart','#start':start,'#vtun':'wgX'});
});
$('#toggle-wgX').switchButton({labels_placement:'left',off_label:"_(Inactive)_",on_label:"_(Active)_",checked:<?=$check_wgX?>});
$('#toggle-wgX').change(function(e){
<?if ($this_wgX):?>
e.preventDefault();
e.stopPropagation();
var wg = $('#toggle-wgX').is(':checked') ? 'start' : 'stop';
$.post('/webGui/include/update.wireguard.php',{'#cmd':'toggle','#wg':wg,'#vtun':'wgX'},function(ok){
if (wg=='start') {
if (ok) tstate['wgX']='active'; else $('#toggle-wgX').switchButton({checked:false});
} else {
if (ok) tstate['wgX']=''; else $('#toggle-wgX').switchButton({checked:true});
}
<?if ($wgX['UPNP:0']===''):?>
$.post('/webGui/include/update.wireguard.php',{'#cmd':'upnpc','#xml':xml,'#vtun':'wgX','#link':'<?=$link?>','#ip':'<?=$server?>','#wg':tstate['wgX']},function(data){$('span.upnp.wgX').text(data);});
<?endif;?>
});
<?else:?>
$('#toggle-wgX').prop('checked',false).trigger('change');
<?endif;?>
});
if ($.cookie('view-wgX')=='advanced') {
$('.advanced.wgX').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.wgX.key'+i).show();
$(this).removeClass('key-off').addClass('key-off');
}});
}
$('#view-wgX').switchButton({labels_placement:'left',off_label:"_(Basic)_",on_label:"_(Advanced)_",checked:$.cookie('view-wgX')=='advanced'});
$('#view-wgX').change(function(){
if ($.cookie('view-wgX')==null) {
// advanced view
$.cookie('view-wgX','advanced',{expires:3650});
$('.advanced.wgX').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.wgX.key'+i).show('slow');
$(this).removeClass('key-off').addClass('key-off');
}});
} else {
// basic view
$.removeCookie('view-wgX');
$('.advanced.wgX').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.wgX.key'+i).hide('slow');
$(this).removeClass('key-off');
}});
}
});
showRemark(form);
setProtocol(form,'wgX');
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-wgX')) $('div#block-wgX').show(); else $('i#block-wgX').removeClass('fa-chevron-up').addClass('fa-chevron-down');
if (xml) {
$('div.upnp.wgX').show();
<?if ($wgX['UPNP:0']===''):?>
$.post('/webGui/include/update.wireguard.php',{'#cmd':'upnpc','#xml':xml,'#vtun':'wgX','#link':'<?=$link?>','#ip':'<?=$server?>','#wg':$.cookie('my-wgX')},function(data){$('span.upnp.wgX').text(data);});
<?endif;?>
} else {
form.find('select[name="UPNP:0"]').val('no');
}
var vpn = false, lan = false
form.find('select[name^="TYPE:"]').each(function(){
var i = $(this).attr('name').split(':')[1];
vpn |= $(this).val()=='7';
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) form.find('select[name="NAT:0"]').val('no').prop('disabled',true);
else if (form.find('select[name="NAT:0"]').val()=='no' && lan) $('span#my-static1-wgX').show();
else if (lan) $('span#my-static2-wgX').show();
});
</script>
<div markdown="1" id="block-wgX" style="display:none">
<form markdown="1" name="wgX" autocomplete="off" method="POST" action="/update.php" target="progressFrame" onsubmit="prepareSettings($(this),'wgX')">
<input type="hidden" name="#include" value="/webGui/include/update.wireguard.php">
<input type="hidden" name="#file" value="<?=$conf_wgX?>">
<input type="hidden" name="#cfg" value="<?=$cfg_wgX?>">
<input type="hidden" name="#cmd" value="update">
<input type="hidden" name="#name" value="<?=$tower?>">
<input type="hidden" name="#vtun" value="wgX">
<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="input"><input type="text" name="Name:0" class="wide" maxlength="99" value="<?=$wgX["Name:0"]?>" pattern="<?=$validname?>" title="_(Use only letters A-Z, digits or space,dash,underscore)_" placeholder="(_(optional)_)"></span>
<span class="pin"><i class="fa fa-fw fa-eye eye0<?=$this_wgX?'':' key-off'?>" style="cursor:pointer" onclick="WGconfig(this,'wgX','')" title="_(View Local Config)_"></i>
<i class="fa fa-fw fa-key zone0<?=$wgX['PublicKey:0']?'':' key-off'?>" style="cursor:pointer" onclick="openClose($(document.wgX),null,'div.key0')" title="_(Toggle keys)_"></i>
<i id="chevron-wgX-0" class="fa fa-fw fa-chevron-down" style="cursor:pointer" onclick="openClose($(document.wgX),this,'div.zone0')" title="_(Toggle view)_"></i></span>
:wg_local_name_help:
<div markdown="1" class="keys wgX key0"<?=$wgX['PublicKey:0']?' style="display:none">':'>'?>
_(Local private key)_:
: <span class="input"><input type="text" name="PrivateKey:0" class="wide private-0" maxlength="64" value="<?=$wgX['PrivateKey:0']?>" onchange="highlight($(document.wgX),this,0)" placeholder="(_(mandatory)_)" required></span>
<input type="button" class="form" value="_(Generate Keypair)_" onclick="keypair($(document.wgX),'0')">
:wg_generate_keypair_help:
_(Local public key)_:
: <span class="input"><input type="text" name="PublicKey:0" class="wide public-0" maxlength="64" value="<?=$wgX['PublicKey:0']?>" onchange="highlight($(document.wgX),this,0)" placeholder="(_(mandatory)_)" required></span>
:wg_generate_keypair_help:
</div>
<div markdown="1" class="advanced wgX zone0" style="display:none">
_(Network protocol)_:
: <span class="input"><select id="protocol-wgX" name="PROT:0" class="subnet" onchange="setProtocol($(document.wgX),'wgX',true)">
<?=mk_option($wgX['PROT:0'], "", _("IPv4 only"))?>
<?=mk_option($wgX['PROT:0'], "6", _("IPv6 only"))?>
<?=mk_option($wgX['PROT:0'], "46", _("IPv4 + IPv6"))?>
</select></span>
<div markdown="1" class="ipv4 wgX" style="display:none">
_(Local tunnel network pool)_:
<input type="hidden" name="Network:0" value="">
: <span class="input"><input type="text" name="gui:Network:0" class="subnet" maxlength="15" value="<?=explode('/',$wgX['Network:0'])[0]?>" onchange="setPool($(document.wgX),'wgX')" pattern="<?=$validIP4?>" title="_(IPv4 network)_" placeholder="<?=$netpool['wgX']?>">/
<input type="number" name="gui:Mask:0" class="mask" min="1" max="32" value="<?=explode('/',$wgX['Network:0'])[1]?>" onchange="if(quickValidate(this)) {setPool($(document.wgX),'wgX')}" placeholder="24"></span>
</div>
<div markdown="1" class="ipv6 wgX" style="display:none">
_(Local tunnel network pool IPv6)_:
<input type="hidden" name="Network6:0" value="">
: <span class="input"><input type="text" name="gui:Network6:0" class="subnet" maxlength="40" value="<?=explode('/',$wgX['Network6:0'])[0]?>" onchange="setPool6($(document.wgX),'wgX')" pattern="<?=$validIP6?>" title="_(IPv6 network)_" placeholder="<?=$netpool6['wgX']?>">/
<input type="number" name="gui:Mask6:0" class="mask" min="1" max="128" value="<?=explode('/',$wgX['Network6:0'])[1]?>" onchange="if(quickValidate(this)) {setPool6($(document.wgX),'wgX')}" placeholder="64"></span>
</div>
:wg_local_tunnel_network_pool_X_help:
<div markdown="1" class="ipv4 wgX" style="display:none">
_(Local tunnel address)_:
: <span class="input"><input type="text" name="Address:0" class="subnet" maxlength="15" value="<?=$wgX['Address:0']?:long2ip($netbase['wgX']+1)?>" onchange="verifyInSubnet(this);" pattern="<?=$validIP4?>" title="_(IPv4 address)_"></span>
:wg_local_tunnel_address_help:
</div>
<div markdown="1" class="ipv6 wgX" style="display:none">
_(Local tunnel address IPv6)_:
: <span class="input"><input type="text" name="Address6:0" class="subnet" maxlength="40" value="<?=$wgX['Address6:0']?:($netbase6['wgX'].'1')?>" onchange="verifyInSubnet6(this);" pattern="<?=$validIP6?>" title="_(IPv6 address)_"></span>
:wg_local_tunnel_address_help:
</div>
</div>
_(Local endpoint)_:
: <span class="input"><input type="text" id="endpoint-wgX" name="Endpoint:0" class="subnet" value="<?=$vpn_wgX?'':$wgX['Endpoint:0']?>" onchange="toLC(this);quickValidate(this);" pattern="<?=$validText?>" title="_(IP address or FQDN)_" placeholder="<?=$vpn_wgX?'(not used)':preg_replace('/^(www\.).+(\.unraid.net)$/','$1<hash>$2',$public)?>">:
<input type="number" name="gui:ListenPort:0" class="port" min="1" max="65535" value="<?=$vpn_wgX?'':$wgX['ListenPort:0']?>" onchange="if(quickValidate(this)) {portRemark($(document.wgX),'wgX',this.value)}" placeholder="<?=$vpn_wgX?'':$netport['wgX']?>"></span>
<span class="remark block" style="display:none">_(Remark)_: _(configure your router with port forwarding of port)_ **<span id="my-port-wgX"><?=$wgX['ListenPort:0']?:$netport['wgX']?></span>/_(UDP)_** _(to)_ **<?=$server?>:<?=$wgX['ListenPort:0']?:$netport['wgX']?>**</span><span class="upnp wgX block"></span>
<input type="hidden" name="ListenPort:0" value=""><dl id="endpoint4-wgX" style="display:none"></dl><dl id="endpoint6-wgX" style="display:none"></dl>
:wg_local_endpoint_X_help:
<div markdown="1" class="advanced wgX zone0" style="display:none">
_(Local server uses NAT)_:
: <span class="input"><select name="NAT:0" class="narrow" onchange="showRoute($(document.wgX),'wgX',0)">
<?=mk_option($wgX['NAT:0'], "", _("Yes"))?>
<?=mk_option($wgX['NAT:0'], "no", _("No"))?>
</select></span>
<span id="my-static1-wgX" class="block" style="display:none">_(Remark)_: _(configure your router with a static route of)_ **<?=$wgX['Network:0']?>** _(to)_ **<?=$server?>**</span><span id="my-static2-wgX" class="block" style="display:none">_(Remark)_: _(docker containers on custom networks need static routing)_ **<?=$wgX['Network:0']?>** _(to)_ **<?=$server?>**</span>
:wg_local_server_uses_nat_help:
<div markdown="1" class="upnp wg0" style="display:none">
_(Local gateway uses UPnP)_:
: <span class="input"><select name="UPNP:0" class="narrow" onchange="showRemark($(document.wgX))">
<?=mk_option($wgX['UPNP:0'], "", _("Yes"))?>
<?=mk_option($wgX['UPNP:0'], "no", _("No"))?>
</select></span>
:wg_local_gateway_uses_upnp_help:
</div>
_(Local tunnel firewall)_:
: <span class="input"><input type="text" name="DROP:0" class="wide" value="<?=$wgX['DROP:0']?>" onchange="quickValidate(this);" pattern="<?=$validList?>" title="_(Comma separated list of IPv4 and IPv6 IP addresses)_, _(CIDR optional)_" placeholder="(_(optional)_)"></span>
_(Rule)_: <select name="RULE:0" class="auto">
<?=mk_option($wgX['RULE:0'], "", _("Deny"))?>
<?=mk_option($wgX['RULE:0'], "1", _("Allow"))?>
</select>
:wg_local_tunnel_firewall_help:
_(MTU size)_:
: <span class="input"><input type="number" name="MTU:0" class="trim" min="68" max="9198" value="<?=$wgX['MTU:0']?>" onchange="quickValidate(this);" placeholder="(_(automatic)_)">_(bytes)_</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-wgX" style="display:none"></div>
<?foreach ($peer_wgX as $i):?>
<div markdown="1" id="index-wgX-<?=$i?>" class="shade-<?=$display['theme']?>">
_(Peer name)_:
: <span class="input"><input type="text" name="Name:<?=$i?>" class="wide" maxlength="99" value="<?=$wgX["Name:$i"]?>" onchange="quickValidate(this);" pattern="<?=$validname?>" title="_(Use only letters A-Z, digits or space,dash,underscore)_" placeholder="(_(optional)_)"></span>
<input type="button" class="form" value="_(Delete Peer)_" onclick="delPeer($(document.wgX),'#index-wgX-<?=$i?>')">
<span class="pin"><i class="fa fa-fw fa-eye eye<?=$i?><?=(file_exists("$etc/peers/peer-$tower-wgX-$i.conf")&&(int)$wgX["TYPE:$i"]!=7)?'':' key-off'?>" style="cursor:pointer" onclick="WGconfig(this,'peer-<?=$tower?>-wgX-<?=$i?>','/peers')" title="_(View Peer Config)_"></i>
<i class="fa fa-fw fa-key zone<?=$i?><?=$wgX["PublicKey:$i"]?'':' key-off'?>" style="cursor:pointer" onclick="openClose($(document.wgX),null,'div.key<?=$i?>')" title="_(Toggle keys)_"></i>
<i id="chevron-wgX-<?=$i?>" class="fa fa-fw fa-chevron-down" style="cursor:pointer" onclick="openClose($(document.wgX),this,'div.zone<?=$i?>')" title="_(Toggle view)_"></i></span>
:wg_peer_name_help:
_(Peer type of access)_:
: <span class="input"><select name="TYPE:<?=$i?>" class="auto" onchange="updatePeer($(document.wgX),<?=$i?>,this.value,'wgX')">
<?=mk_option($wgX["TYPE:$i"], "0", _("Remote access to server"))?>
<?=mk_option($wgX["TYPE:$i"], "1", _("Remote access to LAN"))?>
<?=mk_option($wgX["TYPE:$i"], "2", _("Server to server access"))?>
<?=mk_option($wgX["TYPE:$i"], "3", _("LAN to LAN access"))?>
<?=mk_option($wgX["TYPE:$i"], "4", _("Server hub & spoke access"))?>
<?=mk_option($wgX["TYPE:$i"], "5", _("LAN hub & spoke access"))?>
<?=mk_option($wgX["TYPE:$i"], "6", _("Remote tunneled access"))?>
<?=mk_option($wgX["TYPE:$i"], "7", _("VPN tunneled access"),count($peer_wgX)==1?'':'disabled')?>
</select></span>
<span id="access-type-<?=$i?>" class="access-type"></span>
<?if ($i==1):?>
> ![](<?=autov('/webGui/images/wireguard-help.png')?>)
<?endif;?>
<div markdown="1" class="keys wgX key<?=$i?>"<?=$wgX["PublicKey:$i"]?' style="display:none">':'>'?>
_(Peer private key)_:
: <span class="input"><input type="text" name="PrivateKey:<?=$i?>" class="wide private-<?=$i?>" maxlength="64" value="<?=$wgX["PrivateKey:$i"]?>" onchange="highlight($(document.wgX),this,<?=$i?>)" placeholder="(_(optional)_)"></span>
<input type="button" class="form" value="_(Generate Keypair)_" onclick="keypair($(document.wgX),'<?=$i?>')">
:wg_generate_keypair_help:
_(Peer public key)_:
: <span class="input"><input type="text" name="PublicKey:<?=$i?>" class="wide public-<?=$i?>" maxlength="64" value="<?=$wgX["PublicKey:$i"]?>" onchange="highlight($(document.wgX),this,<?=$i?>)" placeholder="(_(mandatory)_)" required></span>
:wg_generate_keypair_help:
_(Peer preshared key)_:
: <span class="input"><input type="text" name="PresharedKey:<?=$i?>" class="wide preshared-<?=$i?>" maxlength="64" value="<?=$wgX["PresharedKey:$i"]?>" onchange="highlight($(document.wgX),this,<?=$i?>)" placeholder="(_(optional)_)"></span>
<input type="button" class="form" value="_(Generate Key)_" onclick="presharedkey($(document.wgX),'<?=$i?>')">
: wg_peer_preshared_key_help:
</div>
<div markdown="1" class="advanced wgX zone<?=$i?>" style="display:none">
<div markdown="1" class="ipv4 wgX" style="display:none">
_(Peer tunnel address)_:
: <span class="input"><input type="text" name="Address:<?=$i?>" class="subnet" maxlength="15" value="<?=$wgX["Address:$i"]?>" onchange="if(verifyInSubnet(this)){setAllow($(document.wgX),this.value,<?=$i?>)}" pattern="<?=$validIP4?>" title="_(IPv4 address)_"></span>
<input type="button" class="form ping-button1-<?=$i?>" value="_(Ping)_" onclick="ping($(document.wgX),this,'input[name=&quot;Address:<?=$i?>&quot;]')"<?=$wgX["Address:$i"]?'':' disabled'?>>
</div>
<div markdown="1" class="ipv6 wgX" style="display:none">
_(Peer tunnel address IPv6)_:
: <span class="input"><input type="text" name="Address6:<?=$i?>" class="subnet" maxlength="40" value="<?=$wgX["Address6:$i"]?>" onchange="if(verifyInSubnet6(this)){setAllow6($(document.wgX),this.value,<?=$i?>)}" pattern="<?=$validIP6?>" title="_(IPv6 address)_"></span>
<input type="button" class="form ping-button6-<?=$i?>" value="_(Ping)_" onclick="ping($(document.wgX),this,'input[name=&quot;Address6:<?=$i?>&quot;]')"<?=$wgX["Address6:$i"]?'':' disabled'?>>
</div>
:wg_peer_tunnel_address_help:
_(Peer endpoint)_:
<input type="hidden" name="Endpoint:<?=$i?>" value="">
: <span class="input"><input type="text" name="gui:Endpoint:<?=$i?>" class="subnet" value="<?=$wgX["Endpoint:$i"]?>" pattern="<?=$validText?>" title="_(IP address or FQDN)_" onchange="toLC(this);quickValidate(this);" <?=($vpn_wgX||(int)$wgX["TYPE:$i"]==2||(int)$wgX["TYPE:$i"]==3)?'placeholder="(_(mandatory)_)" required':'placeholder="(_(not used)_)"'?>>:
<input type="number" name="gui:ListenPort:<?=$i?>" class="port" min="1" max="65535" value="<?=$wgX["ListenPort:$i"]?>" onchange="quickValidate(this);"<?=$wgX["Endpoint:$i"]?" placeholder=\"".($wgX['ListenPort:0']?:$netport['wgX'])."\"":""?>></span>
<input type="button" class="form ping-button2-<?=$i?>" value="Ping" onclick="ping($(document.wgX),this,'input[name=&quot;gui:Endpoint:<?=$i?>&quot;]')"<?=$wgX["Endpoint:$i"]?'':' disabled'?>>
:wg_peer_endpoint_help:
_(Peer allowed IPs)_:
: <span class="input"><input type="text" name="AllowedIPs:<?=$i?>" class="wide" value="<?=$wgX["AllowedIPs:$i"]?>" onchange="quickValidate(this);" pattern="<?=$validList?>" title="_(Comma separated list of IPv4 and IPv6 IP addresses)_, _(CIDR optional)_" placeholder="(_(mandatory)_)" required></span>
:wg_peer_allowed_ips_help:
_(Peer DNS server)_:
: <span class="input"><input type="text" name="DNS:<?=$i?>" class="subnet" maxlength="40" value="<?=$wgX["DNS:$i"]?>" onchange="quickValidate(this);" pattern="<?=$validDNSServerList?>" title="_(Comma separated list of IPv4 and IPv6 IP addresses)_" placeholder="(_(optional)_)"></span>
:wg_peer_dns_server_help:
_(Persistent keepalive)_:
: <span class="input"><input type="number" name="PersistentKeepalive:<?=$i?>" class="trim" min="0" max="600" value="<?=$wgX["PersistentKeepalive:$i"]?>" onchange="quickValidate(this);" placeholder="(_(disabled)_)">_(seconds)_</span>
:wg_persistent_keepalive_help:
</div>
<span class="pin">_(Data received)_: <span class="rx-wgX-<?=$i?>">0 B</span>_(Data sent)_: <span class="tx-wgX-<?=$i?>">0 B</span><br>_(Last handshake)_: <span class="hs-wgX-<?=$i?>">_(unknown)_</span></span>
</div>
<?endforeach;?>
&nbsp;
: <input type="submit" value="_(Apply)_" onclick="return(validateForm($(document.wgX),'wgX'))" disabled><input type="button" value="_(Done)_" onclick="done()"><input type="button" value="_(Add Peer)_" onclick="addPeer($(document.wgX),'wgX')"><input type="button" class="advanced wgX" value="_(Delete Tunnel)_" style="float:right;display:none" onclick="delTunnel('wgX')">
</form>
<script markdown="1" type="text/html" id="peer-template-wgX">
<div markdown="1" id="index-wgX-INDEX" class="shade-<?=$display['theme']?>">
_(Peer name)_:
: <span class="input"><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>
<span class="pin"><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-wgX-INDEX" class="fa fa-fw fa-chevron-down" style="cursor:pointer" onclick="openClose($(document.wgX),this,'div.zoneINDEX')" title="_(Toggle view)_"></i></span>
:wg_peer_name_help:
_(Peer type of access)_:
: <span class="input"><select name="TYPE:INDEX" class="auto" onchange="updatePeer($(document.wgX),INDEX,this.value,'wgX')">
<?=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"),'disabled')?>
</select></span>
<span id="access-type-INDEX" class="access-type"></span>
> ![](<?=autov('/webGui/images/wireguard-help.png')?>)
<div markdown="1" class="keys wgX keyINDEX">
_(Peer private key)_:
: <span class="input"><input type="text" name="PrivateKey:INDEX" class="wide private-INDEX" maxlength="64" value="" onchange="highlight($(document.wgX),this,0)" placeholder="(_(optional)_)"></span>
<input type="button" class="form" value="_(Generate Keypair)_" onclick="keypair($(document.wgX),'INDEX')">
:wg_generate_keypair_help:
_(Peer public key)_:
: <span class="input"><input type="text" name="PublicKey:INDEX" class="wide public-INDEX" maxlength="64" onchange="highlight($(document.wgX),this,0)" placeholder="(_(mandatory)_)" value="" required></span>
:wg_generate_keypair_help:
_(Peer preshared key)_:
: <span class="input"><input type="text" name="PresharedKey:INDEX" class="wide preshared-INDEX" maxlength="64" value="" onchange="highlight($(document.wgX),this,0)" placeholder="(_(optional)_)"></span>
<input type="button" class="form" value="_(Generate Key)_" onclick="presharedkey($(document.wgX),'INDEX')">
:wg_peer_preshared_key_help:
</div>
<div markdown="1" class="advanced wgX zoneINDEX" style="display:none">
<div markdown="1" class="ipv4 wgX" style="display:none">
_(Peer tunnel address)_:
: <span class="input"><input type="text" name="Address:INDEX" class="subnet" maxlength="15" value="" onchange="if(verifyInSubnet(this)){setAllow($(document.wgX),this.value,INDEX)}" pattern="<?=$validIP4?>" title="_(IPv4 address)_"></span>
<input type="button" class="form ping-button1-INDEX" value="_(Ping)_" onclick="ping($(document.wgX),this,'input[name=&quot;Address:INDEX&quot;]')" disabled>
</div>
<div markdown="1" class="ipv6 wgX" style="display:none">
_(Peer tunnel address IPv6)_:
: <span class="input"><input type="text" name="Address6:INDEX" class="subnet" maxlength="40" value="" onchange="if(verifyInSubnet6(this)){setAllow6($(document.wgX),this.value,INDEX)}" pattern="<?=$validIP6?>" title="_(IPv6 address)_"></span>
<input type="button" class="form ping-button6-INDEX" value="_(Ping)_" onclick="ping($(document.wgX),this,'input[name=&quot;Address6:INDEX&quot;]')" disabled>
</div>
:wg_peer_tunnel_address_help:
_(Peer endpoint)_:
<input type="hidden" name="Endpoint:INDEX" value="">
: <span class="input"><input type="text" name="gui:Endpoint:INDEX" class="subnet" value="" pattern="<?=$validText?>" title="_(IP address or FQDN)_" onchange="toLC(this);quickValidate(this);" placeholder="(_(not used)_)">:
<input type="number" name="gui:ListenPort:INDEX" class="port" min="1" max="65535" value="" onchange="quickValidate(this);"></span>
<input type="button" class="form ping-button2-INDEX" value="_(Ping)_" onclick="ping($(document.wgX),this,'input[name=&quot;gui:Endpoint:INDEX&quot;]')" disabled>
:wg_peer_endpoint_help:
_(Peer allowed IPs)_:
: <span class="input"><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></span>
:wg_peer_allowed_ips_help:
_(Peer DNS server)_:
: <span class="input"><input type="text" name="DNS:INDEX" class="subnet" maxlength="40" value="" onchange="quickValidate(this);" pattern="<?=$validDNSServerList?>" title="_(Comma separated list of IPv4 and IPv6 IP addresses)_" placeholder="(_(optional)_)"></span>
:wg_peer_dns_server_help:
_(Persistent keepalive)_:
: <span class="input"><input type="number" name="PersistentKeepalive:INDEX" class="trim" min="0" max="600" value="" onchange="quickValidate(this);" placeholder="(_(disabled)_)">_(seconds)_</span>
:wg_persistent_keepalive_help:
</div>
</div>
</script>
</div>
Binary file not shown.

After

Width:  |  Height:  |  Size: 146 KiB

+70
View File
@@ -0,0 +1,70 @@
<?PHP
/* Copyright 2005-2021, Lime Technology
* Copyright 2012-2021, 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.
*/
?>
<?
$docroot = $docroot ?? $_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp';
// add translations
$_SERVER['REQUEST_URI'] = 'settings';
require_once "$docroot/webGui/include/Translations.php";
require_once "$docroot/webGui/include/Helpers.php";
$file = $_GET['file'];
$path = realpath('/etc/wireguard'.$_GET['path']);
$csrf = exec("grep -Pom1 '^csrf_token=\"\K.[^\"]+' /var/local/emhttp/var.ini");
if (!$path || strpos($path,'/boot/config/wireguard')!==0 || !$_GET['csrf_token'] || $_GET['csrf_token']!=$csrf) return;
?>
<link type="text/css" rel="stylesheet" href="<?autov("/webGui/styles/default-fonts.css")?>">
<link type="text/css" rel="stylesheet" href="<?autov("/webGui/styles/default-popup.css")?>">
<script src="<?autov('/webGui/javascript/dynamix.js')?>"></script>
<style>
body{margin:20px 0 0 50px}
pre{margin:0}
div{width:100%;margin-bottom:30px}
img{display:block;margin-bottom:10px}
img:hover{transform:scale(1.1)}
</style>
<script>
function cleanUp(id,file) {
if (document.hasFocus()) {
$('#'+id).val("<?=_('Download')?>").prop('disabled',false);
$.post('/webGui/include/Download.php',{cmd:'delete',file:file,csrf_token:'<?=$_GET['csrf_token']?>'});
} else {
setTimeout(function(){cleanUp(id,file);},1000);
}
}
function download(id,source,file) {
$('#'+id).val("<?=_('Downloading')?>...").prop('disabled',true);
$.post('/webGui/include/Download.php',{cmd:'save',source:source+'.conf',file:file,opts:'qj',csrf_token:'<?=$_GET['csrf_token']?>'},function(){
$.post('/webGui/include/Download.php',{cmd:'save',source:source+'.png',file:file,opts:'qj',csrf_token:'<?=$_GET['csrf_token']?>'},function(zip){
location = zip;
setTimeout(function(){cleanUp(id,file);},1000);
});
});
}
</script>
<body>
<h3><u><?=$_GET['path']?_('Remote peer configuration'):_('Local server configuration')?></u></h3>
<div>
<pre>
<?readfile("$path/$file.conf")?>
</pre>
</div>
<div>
<?if (file_exists("$path/$file.png")):?>
<img src="/webGui/include/WGimage.php?file=<?="$file.png"?>&csrf_token=<?=$_GET['csrf_token']?>&v=<?=filemtime("$path/$file.png")?>">
<?endif;?>
<input type="button" value="Close" onclick="top.Shadowbox.close()">
<input type="button" id="download" value="<?=_('Download')?>" onclick="download(this.id,'<?="$path/$file"?>','<?=$file?>.zip')">
</div>
</body>
+26
View File
@@ -0,0 +1,26 @@
<?PHP
/* Copyright 2005-2021, Lime Technology
* Copyright 2012-2021, 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.
*/
?>
<?
$file = realpath('/etc/wireguard/peers/'.$_GET['file']);
$lastmod = filemtime($file);
$csrf = exec("grep -Pom1 '^csrf_token=\"\K.[^\"]+' /var/local/emhttp/var.ini");
if (!$file || strpos($file,'/boot/config/wireguard')!==0 || !$_GET['csrf_token'] || $_GET['csrf_token']!=$csrf) return;
if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) && strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) >= $lastmod) {
header($_SERVER["SERVER_PROTOCOL"].' 304 Not Modified');
} else {
header('Last-Modified:'.gmdate('D, d M Y H:i:s', $lastmod).' GMT');
header('Content-type:image/png');
readfile($file);
}
?>
File diff suppressed because one or more lines are too long
@@ -0,0 +1,409 @@
<?PHP
/* Copyright 2005-2021, Lime Technology
* Copyright 2012-2021, 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.
*/
?>
<?
$docroot = $docroot ?? $_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp';
// add translations
$_SERVER['REQUEST_URI'] = 'settings';
// special case when script is called on form-submit and processed by update.php
if (!isset($_SESSION['locale'])) $_SESSION['locale'] = $_POST['#locale'];
require_once "$docroot/webGui/include/Translations.php";
$etc = '/etc/wireguard';
$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})?)";
$t1 = '6'; // 6 sec timeout
$t2 = '12'; // 12 sec timeout
function ipv4($ip) {
return strpos($ip,'.')!==false;
}
function ipset($ip) {
return ipv4($ip) ? $ip : "[$ip]";
}
function ipv6($ip) {
return ipv4($ip) ? ':' : ']:';
}
function host($ip) {
return strpos($ip,'/')!==false ? $ip : (ipv4($ip) ? "$ip/32" : "$ip/128");
}
function status($vtun) {
return strpos(exec("wg show interfaces|tr '\n' ' '"),"$vtun ")===false;
}
function vtun() {
global $etc;
$x = 0; while (file_exists("$etc/wg{$x}.conf")) $x++;
return "wg{$x}";
}
function delPeer($vtun, $id='') {
global $etc,$name;
$dir = "$etc/peers";
foreach (glob("$dir/peer-$name-$vtun-$id*",GLOB_NOSORT) as $peer) unlink($peer);
}
function addPeer(&$x) {
global $peers,$var;
$peers[$x] = ['[Interface]']; // [Interface]
if ($var['client']) $peers[$x][] = $var['client']; // #name
if ($var['privateKey']) $peers[$x][] = $var['privateKey']; // PrivateKey
$peers[$x][] = $var['address']; // Address
if ($var['listenport']) $peers[$x][] = $var['listenport']; // ListenPort
if ($var['dns']) $peers[$x][] = $var['dns']; // DNS server
if ($var['mtu']) $peers[$x][] = $var['mtu']; // MTU
$peers[$x][] = '';
$peers[$x][] = "[Peer]"; // [Peer]
if ($var['server']) $peers[$x][] = $var['server']; // #name
if ($var['handshake']) $peers[$x][] = $var['handshake']; // PersistentKeepalive
if ($var['presharedKey']) $peers[$x][] = $var['presharedKey']; // PresharedKey
$peers[$x][] = $var['publicKey']; // PublicKey
if ($var['tunnel']) $peers[$x][] = $var['tunnel']; // Tunnel address
$peers[$x][] = $var['endpoint'] ?: $var['internet']; // Endpoint
$peers[$x][] = $var['allowedIPs']; // AllowedIPs
$x++;
}
function autostart($cmd,$vtun) {
global $etc;
$autostart = "$etc/autostart";
$list = @file_get_contents($autostart) ?: '';
switch ($cmd) {
case 'off':
if ($list && strpos($list,"$vtun ")!==false) file_put_contents($autostart,str_replace("$vtun ","",$list));
break;
case 'on':
if (!$list || strpos($list,"$vtun ")===false) file_put_contents($autostart,$list."$vtun ");
break;
}
}
function createPeerFiles($vtun) {
global $etc,$peers,$name,$gone;
$dir = "$etc/peers";
$tmp = "/tmp/list.tmp";
if (is_dir($dir)) {
if (count($gone)) {
foreach ($gone as $peer) {
// one or more peers are removed, delete the associated files
[$n,$i] = explode('-',$peer);
delPeer($n,$i);
}
$new = 1;
$peer = "$dir/peer-$name-$vtun";
$files = glob("$peer-*.conf",GLOB_NOSORT);
natsort($files);
foreach ($files as $file) {
$id = explode('-',basename($file,'.conf'))[3];
if ($id > $new) {
// rename files to match revised peers list
rename($file, "$peer-$new.conf");
rename(str_replace('.conf','.png',$file), "$peer-$new.png");
}
$new++;
}
}
} else {
mkdir($dir);
}
$list = [];
foreach ($peers as $id => $peer) {
if (empty($peer[1])) break; // tunnel without any peers
$cfg = "$dir/peer-$name-$vtun-$id.conf";
$cfgold = @file_get_contents($cfg) ?: '';
$cfgnew = implode("\n",$peer)."\n";
if ($cfgnew !== $cfgold) {
$list[] = "$vtun: peer $id (".($peer[1][0]=='#' ? substr($peer[1],1) : _('no name')).')';
file_put_contents($cfg,$cfgnew);
$png = str_replace('.conf','.png',$cfg);
exec("qrencode -t PNG -r $cfg -o $png");
}
}
// store the peer names which are updated
if (count($list)) file_put_contents($tmp,implode("<br>",$list)); else @unlink($tmp);
}
function parseInput(&$input,&$x) {
global $conf,$user,$var,$default,$default6;
$section = 0; $addPeer = false;
foreach ($input as $key => $value) {
if ($key[0]=='#') continue;
[$id,$i] = explode(':',$key);
if ($i != $section) {
$conf[] = "\n[Peer]";
// add peers only for peer sections
$addPeer ? addPeer($x) : $addPeer = true;
$section = $i;
}
switch ($id) {
case 'Name':
if ($value) $conf[] = "#$value";
if ($i==0) {
$var['server'] = $value ? "#$value" : false;
} else {
$var['client'] = $value ? "#$value" : false;
}
break;
case 'PrivateKey':
if ($i==0) {
$conf[] = "$id=$value";
} else {
if ($value) $user[] = "$id:$x=\"$value\"";
$var['privateKey'] = $value ? "$id=$value" : false;
}
break;
case 'PublicKey':
if ($i==0) {
$user[] = "$id:0=\"$value\"";
$var['publicKey'] = "$id=$value";
} else {
$conf[] = "$id=$value";
}
break;
case 'DNS':
if ($i>0 && $value) {
$user[] = "$id:$x=\"$value\"";
$var['dns'] = "$id=$value";
} else $var['dns'] = false;
break;
case 'PROT':
$protocol = $value;
$user[] = "$id:0=\"$value\"";
switch ($protocol) {
case '46': $var['default'] = "AllowedIPs=$default, $default6"; break;
case '6' : $var['default'] = "AllowedIPs=$default6"; break;
default : $var['default'] = "AllowedIPs=$default"; break;
}
break;
case 'TYPE':
$list = array_map('trim',explode(',',$value<4 ? ($value%2==1 ? $var['subnets1'] : $var['subnets2']) : ($value<6 ? ($value%2==1 ? $var['shared1'] : $var['shared2']) : $var['default'])));
$var['allowedIPs'] = implode(', ',array_map('host',array_filter($list)));
$var['tunnel'] = ($value==2||$value==3) ? $tunnel : false;
$user[] = "$id:$x=\"$value\"";
break;
case 'Network':
case 'Network6':
case 'UPNP':
case 'DROP':
case 'RULE':
case 'NAT':
$user[] = "$id:0=\"$value\"";
break;
case 'Address':
$hosts = implode(', ',array_map('host',array_filter(explode(', ',$value))));
if ($i==0) {
$conf[] = "$id=$value";
$tunnel = "$id=$hosts";
} else {
$user[] = "$id:$x=\"$value\"";
$var['address'] = "$id=$hosts";
}
break;
case 'MTU':
if ($value) $conf[] = "$id=$value";
$var['mtu'] = $value ? "$id=$value" : false;
break;
case 'Endpoint':
if ($i==0) {
$user[] = "$id:0=\"$value\"";
$var['endpoint'] = $value ? "Endpoint=".ipset($value) : false;
} else {
if ($value) $conf[] = "$id=$value";
$var['listenport'] = $value ? "ListenPort=".explode(ipv6($value),$value)[1] : false;
if ($var['endpoint'] && strpos($var['endpoint'],ipv6($var['endpoint']))===false) $var['endpoint'] .= ":".explode(ipv6($var['internet']),$var['internet'])[1];
}
break;
case 'PersistentKeepalive':
if ($value) $conf[] = "$id=$value";
$var['handshake'] = $value ? "$id=$value" : false;
break;
case 'PresharedKey':
if ($value) $conf[] = "$id=$value";
$var['presharedKey'] = $value ? "$id=$value" : false;
break;
default:
if ($value) $conf[] = "$id=$value";
break;
}
}
}
$default = '0.0.0.0/0';
$default6 = '::/0';
switch ($_POST['#cmd']) {
case 'keypair':
$private = exec("wg genkey");
$public = exec("wg pubkey <<<'$private'");
echo $private."\0".$public;
break;
case 'presharedkey':
echo exec("wg genpsk");
break;
case 'update':
if (!exec("iptables -S|grep -om1 'WIREGUARD$'")) {
exec("iptables -N WIREGUARD;iptables -A FORWARD -j WIREGUARD");
}
if (!exec("ip6tables -S|grep -om1 'WIREGUARD$'")) {
exec("ip6tables -N WIREGUARD;ip6tables -A FORWARD -j WIREGUARD");
}
$cfg = $_POST['#cfg'];
$wg = $_POST['#wg'];
$name = $_POST['#name'];
$vtun = $_POST['#vtun'];
$gone = explode(',',$_POST['#deleted']);
$conf = ['[Interface]'];
$user = $peers = $var = [];
$var['subnets1'] = "AllowedIPs=".implode(', ',(array_unique(explode(', ',$_POST['#subnets1']))));
$var['subnets2'] = "AllowedIPs=".implode(', ',(array_unique(explode(', ',$_POST['#subnets2']))));
$var['shared1'] = "AllowedIPs=".implode(', ',(array_unique(explode(', ',$_POST['#shared1']))));
$var['shared2'] = "AllowedIPs=".implode(', ',(array_unique(explode(', ',$_POST['#shared2']))));
$var['internet'] = "Endpoint=".implode(', ',(array_unique(explode(', ',$_POST['#internet']))));
$x = 1;
parseInput($_POST,$x);
addPeer($x);
exec("wg-quick down $vtun 2>/dev/null");
file_put_contents($file,implode("\n",$conf)."\n");
file_put_contents($cfg,implode("\n",$user)."\n");
createPeerFiles($vtun);
if ($wg) exec("wg-quick up $vtun >/dev/null");
$save = false;
break;
case 'toggle':
$vtun = $_POST['#vtun'];
switch ($_POST['#wg']) {
case 'stop':
exec("timeout $t1 wg-quick down $vtun 2>/dev/null");
echo status($vtun) ? 1 : 0;
break;
case 'start':
exec("timeout $t1 wg-quick up $vtun 2>/dev/null");
echo status($vtun) ? 0 : 1;
break;
}
break;
case 'ping':
$addr = $_POST['#addr'];
echo exec("ping -qc1 -W4 $addr|grep -Po '1 received'");
break;
case 'public':
$ip = $_POST['#ip'];
$v4 = $_POST['#prot']!='6';
$v6 = $_POST['#prot']!='';
$context = stream_context_create(['https'=>['timeout'=>12]]);
$int_ipv4 = $v4 ? (preg_match("/^$validIP4$/", $ip) ? $ip : (@dns_get_record($ip, DNS_A)[0]['ip'] ?: '')) : '';
$ext_ipv4 = $v4 ? (@file_get_contents('https://api.ipify.org',false,$context) ?: '') : '';
$int_ipv6 = $v6 ? (preg_match("/^$validIP6$/", $ip) ? $ip : (@dns_get_record($ip, DNS_AAAA)[0]['ipv6'] ?: '')) : '';
$ext_ipv6 = $v6 ? (@file_get_contents('https://api6.ipify.org',false,$context) ?: '') : '';
echo "$int_ipv4;$ext_ipv4;$int_ipv6;$ext_ipv6";
break;
case 'addtunnel':
$vtun = vtun();
$name = $_POST['#name'];
touch("$etc/$vtun.conf");
exec("wg-quick down $vtun 2>/dev/null");
@unlink("$etc/$vtun.cfg");
delPeer($vtun);
autostart('off',$vtun);
break;
case 'deltunnel':
$vtun = $_POST['#vtun'];
$name = $_POST['#name'];
exec("wg-quick down $vtun 2>/dev/null");
@unlink("$etc/$vtun.conf");
@unlink("$etc/$vtun.cfg");
delPeer($vtun);
autostart('off',$vtun);
break;
case 'import':
$name = $_POST['#name'];
$user = $peers = $var = $import = $sort = [];
$entries = array_filter(array_map('trim',preg_split('/\[(Interface|Peer)\]/',$_POST['#data'])));
foreach($entries as $key => $entry) {
$i = $key-1;
foreach (explode("\n",$entry) as $row) {
if (ltrim($row)[0]!='#') {
[$id,$data] = array_map('trim',explode('=',$row,2));
$import["$id:$i"] = $data;
} elseif ($i>=0) {
$import["Name:$i"] = substr(trim($row),1);
}
}
}
if ($import['PrivateKey:0'] && !$import['PublicKey:0']) $import['PublicKey:0'] = exec("wg pubkey <<<'{$import['PrivateKey:0']}'");
$import['UPNP:0'] = 'no';
$import['NAT:0'] = 'no';
[$subnet,$mask] = explode('/',$import['Address:0']);
if (ipv4($subnet)) {
$mask = ($mask>0 && $mask<32) ? $mask : 24;
$import['Network:0'] = long2ip(ip2long($subnet) & (0x100000000-2**(32-$mask))).'/'.$mask;
$import['Address:0'] = $subnet;
$import['PROT:0'] = '';
} else {
$mask = ($mask>0 && $mask<128) ? $mask : 64;
$import['Network6:0'] = strstr($subnet,'::',true).'::/'.$mask;
$import['Address:0'] = $subnet;
$import['PROT:0'] = '6';
}
$import['Endpoint:0'] = '';
for ($n = 1; $n <= $i; $n++) {
$vpn = strpos($import["AllowedIPs:$n"],$default)!==false || strpos($import["AllowedIPs:$n"],$default6)!==false;
if ($vpn) $import["Address:$n"] = '';
$import["TYPE:$n"] = $vpn ? 7 : 0;
if ($import["TYPE:$n"]==0) $var['subnets1'] = "AllowedIPs=".$import["AllowedIPs:$n"];
}
foreach ($import as $key => $val) $sort[] = explode(':',$key)[1];
array_multisort($sort,$import);
$x = 1;
$conf = ['[Interface]'];
$var['default'] = $import['PROT:0']=='' ? "AllowedIPs=$default" : "AllowedIPs=$default6";
$var['internet'] = "Endpoint=unknown";
parseInput($import,$x);
addPeer($x);
$vtun = vtun();
file_put_contents("$etc/$vtun.conf",implode("\n",$conf)."\n");
file_put_contents("$etc/$vtun.cfg",implode("\n",$user)."\n");
delPeer($vtun);
autostart('off',$vtun);
echo $vtun;
break;
case 'autostart':
autostart($_POST['#start'],$_POST['#vtun']);
break;
case 'upnp':
$upnp = '/var/tmp/upnp';
if (is_executable('/usr/bin/upnpc')) {
$gw = $_POST['#gw'].':';
$link = $_POST['#link'];
$xml = @file_get_contents($upnp) ?: '';
if ($xml) {
exec("timeout $t1 stdbuf -o0 upnpc -u $xml -m $link -l 2>&1|grep -qm1 'refused'",$output,$code);
if ($code!=1) $xml = '';
}
if (!$xml) {
exec("timeout $t2 stdbuf -o0 upnpc -m $link -l 2>/dev/null|grep -Po 'desc: \K.+'",$desc);
foreach ($desc as $url) if ($url && strpos($url,$gw)!==false) {$xml = $url; break;}
}
} else $xml = "";
file_put_contents($upnp,$xml);
echo $xml;
break;
case 'upnpc':
if (!is_executable('/usr/bin/upnpc')) break;
$xml = $_POST['#xml'];
$vtun = $_POST['#vtun'];
$link = $_POST['#link'];
$ip = $_POST['#ip'];
if ($_POST['#wg']=='active') {
exec("timeout $t1 stdbuf -o0 upnpc -u $xml -m $link -l 2>/dev/null|grep -Po \"^(ExternalIPAddress = \K.+|.+\KUDP.+>$ip:[0-9]+ 'WireGuard-$vtun')\"",$upnp);
[$addr,$upnp] = $upnp;
[$type,$rule] = explode(' ',$upnp);
echo $rule ? "UPnP: $addr:$rule/$type" : _("UPnP: forwarding not set");
} else {
echo _("UPnP: tunnel is inactive");
}
break;
}
?>
+52
View File
@@ -0,0 +1,52 @@
#!/usr/bin/php -q
<?PHP
/* Copyright 2005-2021, Lime Technology
* Copyright 2012-2021, 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.
*/
?>
<?
function curl_socket($socket, $url, $postdata = NULL) {
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_UNIX_SOCKET_PATH, $socket);
if ($postdata !== NULL) {
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $postdata);
}
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_exec($ch);
curl_close($ch);
}
function publish($endpoint, $message) {
curl_socket("/var/run/nginx.socket", "http://localhost/pub/$endpoint?buffer_length=1", $message);
}
function my_scale($value, &$unit) {
$units = [' ','Ki','Mi','Gi','Ti','Pi','Ei','Zi','Yi'];
$size = count($units);
$base = $value ? floor(log($value, 1024)) : 0;
if ($base>$size) $base = $size-1;
$value /= pow(1024, $base);
$decimals = $value>=100 ? 0 : ($value>=10 ? 1 : (round($value*100)%100===0 ? 0 : 2));
if (round($value,-1)==1000) {$value = 1; $base++;}
$unit = $units[$base].'B';
return number_format($value, $decimals, '.', $value>9999 ? ',':'');
}
while (true) {
$now = time(); $i = 0;
unset($dump); $vtun = [];
exec('wg show all dump',$dump);
foreach ($dump as $row) {
$row = preg_split('/\s+/',$row);
if (count($row)>5) $vtun[] = $row[0].';'.($row[5] ? $now - $row[5] : 0).';'.my_scale($row[6],$unit)." $unit;".my_scale($row[7],$unit)." $unit";
}
publish('wireguard', implode("\0",$vtun));
sleep(1);
}
?>