mirror of
https://github.com/unraid/webgui.git
synced 2026-01-10 11:40:12 -06:00
Merge remote-tracking branch 'upstream/master'
This commit is contained in:
@@ -2474,3 +2474,32 @@ If set to 'Yes' the bash history will persist reboots, set to 'No' to disable.
|
||||
|
||||
**Note:** Disabling and Enabling will remove the entire bash history.
|
||||
:end
|
||||
|
||||
|
||||
:WOL_enable_help:
|
||||
If set to yes Unraidwold daemon is set to run.
|
||||
:end
|
||||
|
||||
:WOL_docker_help:
|
||||
If set to yes when wake on lan packets are received checks are carrried out for dockers otherwise dockers will be ignored.
|
||||
:end
|
||||
|
||||
:WOL_run_VM_help:
|
||||
If set to yes when wake on lan packets are received checks are carrried out for virtual machines otherwise virtual machines will be ignored.
|
||||
:end
|
||||
|
||||
:WOL_run_LXC_help:
|
||||
If set to yes when wake on lan packets are received checks are carrried out for LXC otherwise LXC will be ignored. The LXC plugin needs to be installed for LXC to be processed.
|
||||
:end
|
||||
|
||||
:WOL_interface_help:
|
||||
Specify the interface to the daemon to bind to. Some interfaces may not be able to recieve etherframe packets. Recommend to bind to a physical interface.
|
||||
:end
|
||||
|
||||
:WOL_promiscuous_mode_help:
|
||||
Enable to set the NIC not to filer packets.
|
||||
:end
|
||||
|
||||
:WOL_log_file_help:
|
||||
Default is to log to syslog but if you want a different log location set the file name.
|
||||
:end
|
||||
@@ -50,7 +50,7 @@
|
||||
'uuid' => $lv->domain_generate_uuid(),
|
||||
'clock' => 'localtime',
|
||||
'arch' => 'x86_64',
|
||||
'machine' => 'pc',
|
||||
'machine' => 'pc-i440fx',
|
||||
'mem' => 1024 * 1024,
|
||||
'maxmem' => 1024 * 1024,
|
||||
'password' => '',
|
||||
|
||||
121
emhttp/plugins/dynamix/WOL.page
Normal file
121
emhttp/plugins/dynamix/WOL.page
Normal file
@@ -0,0 +1,121 @@
|
||||
Menu="UNRAID-OS"
|
||||
Title="Wake On LAN"
|
||||
Icon="fa-bell"
|
||||
Tag="server"
|
||||
---
|
||||
<?PHP
|
||||
/* Copyright 2005-2023, Lime Technology
|
||||
* Copyright 2012-2023, 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.
|
||||
*/
|
||||
|
||||
if (count($_POST)) {
|
||||
$cfg = NULL ;
|
||||
if ($_POST['#apply'] == "_(Save)_") {
|
||||
foreach($_POST as $postkey=>$data) {
|
||||
if ($postkey=="#apply") continue;
|
||||
$keys = explode(";",$postkey);
|
||||
if (count($keys) >1) $update_file[$keys[1]][$keys[2]][$keys[0]]=$data;
|
||||
}
|
||||
|
||||
foreach($update_file as $type => $types) {
|
||||
foreach($types as $name => $details) {
|
||||
if ($details['user_mac'] == "") $details['user_mac'] = "None Defined";
|
||||
if ($details['user_mac'] == "None Defined" && $details['enable'] == "enable") unset($update_file[$type][$name]) ;
|
||||
}
|
||||
}
|
||||
}
|
||||
unset($_POST) ;
|
||||
file_put_contents("/boot/config/wol.json",json_encode($update_file));
|
||||
#echo '<meta http-equiv="refresh" content="0;url=/Tools">';
|
||||
echo '<meta http-equiv="refresh" content="0">';
|
||||
#unset($_SESSION['csrf_token']);
|
||||
|
||||
|
||||
|
||||
}
|
||||
?>
|
||||
<script src="/webGui/javascript/jquery.tablesorter.widgets.js"></script>
|
||||
|
||||
<script>
|
||||
function showWOL(options, init = false) {
|
||||
option = options;
|
||||
if (init) {
|
||||
$('#wolsearch').prop('disabled', true);
|
||||
$.post('/webGui/include/WOL.php',{table:'t1load',option:"all"},function(data){
|
||||
clearTimeout(timers.refresh);
|
||||
filter = [];
|
||||
$("#t1").trigger("destroy");
|
||||
$('#t1').html(data.html);
|
||||
$('#t1').tablesorter({
|
||||
sortList: [[0,0]],
|
||||
sortAppend: [[0,0]],
|
||||
widgets: ['stickyHeaders','filter','zebra'],
|
||||
widgetOptions: {
|
||||
// on black and white, offset is height of #menu
|
||||
// on azure and gray, offset is height of #header
|
||||
stickyHeaders_offset: ($('#menu').height() < 50) ? $('#menu').height() : $('#header').height(),
|
||||
filter_columnFilters: false,
|
||||
zebra: ["normal-row","alt-row"]
|
||||
}
|
||||
});
|
||||
$('div.spinner.fixed').hide('slow');
|
||||
$('#wolsearch').prop('disabled', false);
|
||||
$('#select').prop('disabled', false);
|
||||
$('#rebuild').prop('disabled', data.init);
|
||||
},"json");
|
||||
} else {
|
||||
filter = [];
|
||||
filterWOL();
|
||||
}
|
||||
}
|
||||
|
||||
function filterWOL() {
|
||||
var totalColumns = $('#t1')[0].config.columns;
|
||||
var filter = [];
|
||||
filter[totalColumns] = $('#wolsearch').val(); // this searches all columns
|
||||
$('#t1').trigger('search', [filter]);
|
||||
}
|
||||
|
||||
function showWOLupdate() {
|
||||
$('#rebuild').prop('disabled', true);
|
||||
$('#t1').html("");
|
||||
$('#wolsearch').prop('disabled', true);
|
||||
$('#select').prop('disabled', true);
|
||||
$('div.spinner.fixed').show('slow');
|
||||
$.post('/webGui/include/WOL.php',{table:'t1create',option:"all"},function(data){
|
||||
$('#rebuild').prop('disabled', false);
|
||||
showWOL("all",true);
|
||||
$('div.spinner.fixed').hide('slow');
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function maccreate(name) {
|
||||
|
||||
$.getJSON("/plugins/dynamix.vm.manager/include/VMajax.php?action=generate-mac", function( data ) {
|
||||
if (data.mac) {
|
||||
$('#'+name).val(data.mac);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
showWOL("all",true);
|
||||
</script>
|
||||
|
||||
:WOL_intro_help:
|
||||
|
||||
<form autocomplete="off" onsubmit="return false;"><span><input class="t1 search" id="wolsearch" type="search" placeholder="Search..." onchange="filterWOL();"></span></form>
|
||||
<pre><form name="WOL" id="WOL" method="POST" class="js-confirm-leave" >
|
||||
<table name="t1"id='t1' class="t1 unraid tablesorter" >
|
||||
<tr><td><div class="spinner"></div></td></tr></table></pre><br>
|
||||
<input type="button" value="_(Done)_" onclick="done()">
|
||||
<input type="submit" name="#apply" id='#apply' value="_(Save)_" >
|
||||
</form>
|
||||
|
||||
94
emhttp/plugins/dynamix/WOLSettings.page
Normal file
94
emhttp/plugins/dynamix/WOLSettings.page
Normal file
@@ -0,0 +1,94 @@
|
||||
Menu="OtherSettings"
|
||||
Type="xmenu"
|
||||
Title="Wake on Lan Settings"
|
||||
Icon="fa-bell"
|
||||
Tag="share-alt"
|
||||
---
|
||||
<?PHP
|
||||
/* Copyright 2005-2023, Lime Technology
|
||||
* Copyright 2012-2023, 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.
|
||||
*/
|
||||
?>
|
||||
<?
|
||||
exec("ls --indicator-style=none /sys/class/net|grep -P '^eth[1-9][0-9]*$'",$ports);
|
||||
$disabled = _var($var,'fsState')!='Stopped' ? 'disabled' : '';
|
||||
$width = [166,300];
|
||||
$file = '/boot/config/wol.cfg';
|
||||
$current = parse_ini_file($file);
|
||||
if (!isset($current['LOGFILE'])) $current['LOGFILE'] = "syslog"
|
||||
?>
|
||||
<script>
|
||||
showStatus('pid','unraidwold');
|
||||
</script>
|
||||
<form markdown="1" name="WOLsettings" method="POST" action="/update.php" target="progressFrame" >
|
||||
<input type="hidden" name="#file" value="<?=$file;?>">
|
||||
<input type="hidden" name="#command" value="/webGui/scripts/WOL_action">
|
||||
<input type="hidden" name="#arg[1]" value="load">
|
||||
|
||||
_(Enable Wake on Lan)_:
|
||||
: <select name="WOLENABLED" >
|
||||
<?=mk_option($current['WOLENABLED'], "no", _('No'))?>
|
||||
<?=mk_option($current['WOLENABLED'], "yes", _('Yes'))?>
|
||||
</select>
|
||||
|
||||
:WOL_enable_help:
|
||||
|
||||
_(Enable Docker actions)_:
|
||||
|
||||
: <select name="RUNDOCKER" >
|
||||
<?=mk_option($current['RUNDOCKER'], "y", _('Yes'))?>
|
||||
<?=mk_option($current['RUNDOCKER'], "n", _('No'))?>
|
||||
</select>
|
||||
|
||||
:WOL_run_docker_help:
|
||||
|
||||
_(Enable LXC actions)_:
|
||||
: <select name="RUNLXC" >
|
||||
<?=mk_option($current['RUNLXC'], "y", _('Yes'))?>
|
||||
<?=mk_option($current['RUNLXC'], "n", _('No'))?>
|
||||
</select>
|
||||
|
||||
:WOL_run_LXC_help:
|
||||
|
||||
_(Enable VM actions)_:
|
||||
: <select name="RUNVM" >
|
||||
<?=mk_option($current['RUNVM'], "y", _('Yes'))?>
|
||||
<?=mk_option($current['RUNVM'], "n", _('No'))?>
|
||||
</select>
|
||||
|
||||
:WOL_run_VM_help:
|
||||
|
||||
_(Interface to listern on)_:
|
||||
: <select id="INTERFACE" name="INTERFACE" >
|
||||
<?=mk_option(_var($eth0,'INTERFACE'),'eth0','eth0','selected')?>
|
||||
<?foreach ($ports as $port):?>
|
||||
<?if (!locked('eth0',$port)) echo mk_option_check($current['INTERFACE'],$port,$port)?>
|
||||
<?endforeach;?>
|
||||
</select>
|
||||
|
||||
:WOL_interface_help:
|
||||
|
||||
_(Interface promiscuous mode)_:
|
||||
: <select id="IFMODE" name="IFMODE" >
|
||||
<?=mk_option($current['IFMODE'], "n", _('No'))?>
|
||||
<?=mk_option($current['IFMODE'], "y", _('Yes'))?>
|
||||
</select>
|
||||
|
||||
:WOL_promiscuous_mode_help:
|
||||
|
||||
_(Log file)_:
|
||||
: <input name="LOGFILE" class="narrow"type="text" value=<?=$current['LOGFILE']?>>
|
||||
|
||||
|
||||
:WOL_log_file_help:
|
||||
|
||||
|
||||
: <input type="submit" value="_(Apply)_" disabled><input type="button" value="_(Done)_" onclick="done()">
|
||||
</form>
|
||||
3
emhttp/plugins/dynamix/event/array_started/WOLStart
Executable file
3
emhttp/plugins/dynamix/event/array_started/WOLStart
Executable file
@@ -0,0 +1,3 @@
|
||||
#!/bin/bash
|
||||
|
||||
/usr/local/emhttp/plugins/dynamix/include/script/WOL_action load &
|
||||
3
emhttp/plugins/dynamix/event/stopping/WOLStop
Executable file
3
emhttp/plugins/dynamix/event/stopping/WOLStop
Executable file
@@ -0,0 +1,3 @@
|
||||
#!/bin/bash
|
||||
|
||||
/usr/local/emhttp/plugins/dynamix/include/script/WOL_action stop &
|
||||
112
emhttp/plugins/dynamix/include/WOL.php
Normal file
112
emhttp/plugins/dynamix/include/WOL.php
Normal file
@@ -0,0 +1,112 @@
|
||||
<?PHP
|
||||
/* Copyright 2005-2023, Lime Technology
|
||||
* Copyright 2012-2023, 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.
|
||||
*/
|
||||
?>
|
||||
<?
|
||||
global $lv;
|
||||
$docroot ??= ($_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp');
|
||||
require_once "$docroot/webGui/include/Helpers.php";
|
||||
require_once "$docroot/webGui/include/SysDriversHelpers.php";
|
||||
require_once "$docroot/plugins/dynamix.plugin.manager/include/PluginHelpers.php";
|
||||
require_once "$docroot/plugins/dynamix.vm.manager/include/libvirt_helpers.php";
|
||||
// add translations
|
||||
$_SERVER['REQUEST_URI'] = 'tools';
|
||||
require_once "$docroot/webGui/include/Translations.php";
|
||||
require_once "$docroot/plugins/dynamix.docker.manager/include/DockerClient.php";
|
||||
require_once "/usr/local/emhttp/plugins/dynamix.vm.manager/include/libvirt.php";
|
||||
$vms = $lv->get_domains();
|
||||
sort($vms,SORT_NATURAL);
|
||||
foreach($vms as $vm){
|
||||
$arrEntries['VM'][$vm]['interfaces'] = $lv->get_nic_info($vm);
|
||||
$arrEntries['VM'][$vm]['name'] = $vm;
|
||||
}
|
||||
|
||||
$DockerClient = new DockerClient();
|
||||
$containers = $DockerClient->getDockerJSON("/containers/json?all=1");
|
||||
foreach($containers as $ct)
|
||||
$arrEntries['Docker'][substr($ct["Names"][0],1)] = [
|
||||
'interfaces' => ['0 '=> ['mac' => isset($ct["NetworkSettings"]["Networks"]["bridge"]["MacAddress"]) ? $ct["NetworkSettings"]["Networks"]["bridge"]["MacAddress"] : ""]],
|
||||
'name' => substr($ct["Names"][0],1),
|
||||
];
|
||||
|
||||
$lxc = explode("\n",shell_exec("lxc-ls -1")) ;
|
||||
$lxcpath = trim(shell_exec("lxc-config lxc.lxcpath"));
|
||||
foreach ($lxc as $lxcname) {
|
||||
if ($lxcname == "") continue;
|
||||
$value = explode("=",shell_exec("cat $lxcpath/$lxcname/config | grep 'hwaddr'"));
|
||||
$arrEntries['LXC'][$lxcname]['interfaces'][0]['mac'] = trim($value[1]);
|
||||
$arrEntries['LXC'][$lxcname]['name'] = $lxcname;
|
||||
}
|
||||
|
||||
if (is_file("/boot/config/wol.json")) $user_mac = json_decode(file_get_contents("/boot/config/wol.json"),true); else $user_mac = [];
|
||||
|
||||
foreach($arrEntries as $key => $data) {
|
||||
$type=$key;
|
||||
foreach($data as $data2){
|
||||
$name=$data2['name'];
|
||||
if (isset($user_mac[$type][$name])) {
|
||||
$name=$name;
|
||||
#var_dump($name);
|
||||
$arrEntries[$type][$name]['enable'] = $user_mac[$type][$name]['enable'];
|
||||
$arrEntries[$type][$name]['user_mac'] = strtolower($user_mac[$type][$name]['user_mac']);
|
||||
} else {
|
||||
$arrEntries[$type][$name]['enable'] = 'enable';
|
||||
$arrEntries[$type][$name]['user_mac'] = 'None Defined';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch ($_POST['table']) {
|
||||
|
||||
case 't1load':
|
||||
$arrMacs = $arrEntries;
|
||||
$html = "<thead><tr><th>"._('Service')."</th><th>"._('Name')."</th><th>"._('Mac Address')."</th><th>"._('Enabled')."</th><th>"._('User Mac Address')."</th></tr></thead>";
|
||||
$html .= "<tbody>";
|
||||
ksort($arrMacs);
|
||||
foreach($arrMacs as $systype => $m) {
|
||||
foreach($m as $macaddr) {
|
||||
if ($systype == "") continue;
|
||||
|
||||
$html .= "<tr id='row$systype'>";
|
||||
$macs = "";
|
||||
foreach($macaddr['interfaces'] as $intdetail)
|
||||
{
|
||||
$macs .= " {$intdetail['mac']}" ;
|
||||
}
|
||||
$html .= "<td>$systype</td>";
|
||||
$selecttypename="enable;".$systype.";".$macaddr['name'];
|
||||
$mactypename=htmlspecialchars("user_mac;".$systype.";".$macaddr['name']);
|
||||
$mactypeid=htmlspecialchars("user_mac".$systype."".$macaddr['name']);
|
||||
$user_mac_str = '<input type="text" name="'.$mactypename.'" id="'.$mactypeid.'" class="narrow" value="'.htmlspecialchars($macaddr['user_mac']).'" title="'._("random mac, you can supply your own").'" /><a><i onclick="maccreate(\''.$mactypeid.'\')" class="fa fa-refresh mac_generate" title="re-generate random mac address"></i></a>';
|
||||
$html .= "<td>{$macaddr['name']}</td><td id=\"status$systype\">$macs</td><td>";
|
||||
$html .="<select name='$selecttypename' class='audio narrow'>";
|
||||
$html .= mk_option($macaddr["enable"] , "disable", _("Disabled"));
|
||||
$html .= mk_option($macaddr["enable"] , "enable", _("Enabled"));
|
||||
$html .= "</select></td><td>".$user_mac_str."</td></tr>";
|
||||
$text = "";
|
||||
}
|
||||
}
|
||||
$html .= "</tbody>";
|
||||
|
||||
$rtn = array();
|
||||
$rtn['html'] = $html;
|
||||
echo json_encode($rtn);
|
||||
break;
|
||||
|
||||
case "macaddress":
|
||||
$seed = 1;
|
||||
$prefix = '52:54:AA';
|
||||
$prefix.':'.$lv->macbyte(($seed * rand()) % 256).':'.$lv->macbyte(($seed * rand()) % 256).':'.$lv->macbyte(($seed * rand()) % 256);
|
||||
echo json_encode(['mac' => $prefix]);
|
||||
break;
|
||||
|
||||
}
|
||||
?>
|
||||
174
emhttp/plugins/dynamix/include/WOLrun.php
Executable file
174
emhttp/plugins/dynamix/include/WOLrun.php
Executable file
@@ -0,0 +1,174 @@
|
||||
#!/usr/bin/php
|
||||
<?php
|
||||
|
||||
|
||||
$docroot = $docroot ?? $_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp';
|
||||
require_once "$docroot/webGui/include/Helpers.php";
|
||||
require_once "$docroot/webGui/include/Custom.php";
|
||||
require_once "$docroot/plugins/dynamix.vm.manager/include/libvirt_helpers.php";
|
||||
require_once "$docroot/plugins/dynamix.vm.manager/include/libvirt.php";
|
||||
require_once "$docroot/plugins/dynamix.plugin.manager/include/PluginHelpers.php";
|
||||
require_once "$docroot/plugins/dynamix.docker.manager/include/DockerClient.php";
|
||||
|
||||
function getContainerStats($container, $option) {
|
||||
exec("lxc-info " . $container, $content);
|
||||
foreach($content as $index => $string) {
|
||||
if (strpos($string, $option) !== FALSE)
|
||||
return trim(explode(':', $string)[1]);
|
||||
}
|
||||
}
|
||||
|
||||
$mac = $argv[1];
|
||||
|
||||
$libvirtd_running = is_file('/var/run/libvirt/libvirtd.pid') ;
|
||||
$dockerd_running = is_file('/var/run/dockerd.pid');
|
||||
$lxc_ls_exist = is_file('/usr/bin/lxc-ls');
|
||||
#$RUNDOCKER = $RUNLXC = $RUNVM = true;
|
||||
extract(parse_ini_file("/boot/config/wol.cfg")) ;
|
||||
if (!isset($RUNLXC)) $RUNLXC = "y";
|
||||
if (!isset($RUNVM)) $RUNVM = "y";
|
||||
if (!isset($RUNDocker)) $RUNDocker = "y";
|
||||
|
||||
$arrEntries = [] ;
|
||||
if ($libvirtd_running && $RUNVM == "y") {
|
||||
$vms = $lv->get_domains();
|
||||
sort($vms,SORT_NATURAL);
|
||||
foreach($vms as $vm){
|
||||
$arrEntries['VM'][$vm]['interfaces'] = $lv->get_nic_info($vm);
|
||||
$arrEntries['VM'][$vm]['name'] = $vm;
|
||||
}
|
||||
}
|
||||
if ($dockerd_running && $RUNDOCKER == "y") {
|
||||
$DockerClient = new DockerClient();
|
||||
$containers = $DockerClient->getDockerJSON("/containers/json?all=1");
|
||||
foreach($containers as $container)
|
||||
$arrEntries['Docker'][ substr($container["Names"][0],1) ] = [
|
||||
'interfaces' => ['0' => ['mac' => isset($container["NetworkSettings"]["Networks"]["bridge"]["MacAddress"]) ? $container["NetworkSettings"]["Networks"]["bridge"]["MacAddress"]:""]],
|
||||
'name' => substr($container["Names"][0],1),
|
||||
'state' => $container["State"],
|
||||
];
|
||||
}
|
||||
|
||||
if ($lxc_ls_exist && $RUNLXC == "y") {
|
||||
$lxc = explode("\n",shell_exec("lxc-ls -1")) ;
|
||||
$lxcpath = trim(shell_exec("lxc-config lxc.lxcpath"));
|
||||
foreach ($lxc as $lxcname) {
|
||||
if ($lxcname == "") continue;
|
||||
$values = explode("=",shell_exec("cat $lxcpath/$lxcname/config | grep 'hwaddr'"));
|
||||
$arrEntries['LXC'][$lxcname]['interfaces'][0]['mac'] = trim($values[1]);
|
||||
$arrEntries['LXC'][$lxcname]['name'] = $lxcname;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_file("/boot/config/wol.json")) $user_mac = json_decode(file_get_contents("/boot/config/wol.json"),true); else $user_mac = [];
|
||||
|
||||
foreach($arrEntries as $typekey => $typedata)
|
||||
{
|
||||
foreach($typedata as $typeEntry){
|
||||
$name=$typeEntry['name'];
|
||||
if (isset($user_mac[$typekey][$name])) {
|
||||
|
||||
$name=$name;
|
||||
|
||||
$arrEntries[$typekey][$name]['enable'] = $user_mac[$typekey][$name]['enable'];
|
||||
$arrEntries[$typekey][$name]['user_mac'] = strtolower($user_mac[$typekey][$name]['user_mac']);
|
||||
|
||||
} else {
|
||||
$arrEntries[$typekey][$name]['enable'] = "enable";
|
||||
$arrEntries[$typekey][$name]['user_mac'] = 'None Defined';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$mac_list=[];
|
||||
foreach($arrEntries as $type => $detail)
|
||||
{
|
||||
foreach($detail as $name => $entryDetail)
|
||||
{
|
||||
foreach($entryDetail['interfaces'] as $interfaces)
|
||||
{
|
||||
if($interfaces['mac'] == "" && $entryDetail['user_mac'] == "None Defined") continue;
|
||||
if (isset($entryDetail['state'])) $state = $entryDetail['state']; else $state = "";
|
||||
if (isset($entryDetail['enable']) && !$entryDetail['enable'] ) $enable = false; else $enable = true;
|
||||
if ($entryDetail['user_mac'] != "None Defined") {
|
||||
$mac_list[$entryDetail['user_mac']] = [
|
||||
'type' => $type,
|
||||
'name' => $name,
|
||||
'state' => $state,
|
||||
'enable' => $entryDetail['enable'],
|
||||
];
|
||||
}
|
||||
if ($interfaces['mac'] != "") {
|
||||
$mac_list[$interfaces['mac']] = [
|
||||
'type' => $type,
|
||||
'name' => $name,
|
||||
'state' => $state,
|
||||
'enable' => $entryDetail['enable'],
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
$found = array_key_exists($mac,$mac_list);
|
||||
|
||||
|
||||
if ($found && $mac_list[$mac]['enable'] == "enable") {
|
||||
echo _("Found "). $mac . " ".$mac_list[$mac]['type']." ".$mac_list[$mac]['name'];
|
||||
switch ($mac_list[$mac]['type']) {
|
||||
|
||||
case "VM":
|
||||
if ($libvirtd_running && $RUNVM == "y") {
|
||||
$res = $lv->get_domain_by_name($mac_list[$mac]['name']);
|
||||
$dom = $lv->domain_get_info($res);
|
||||
$state = $lv->domain_state_translate($dom['state']);
|
||||
switch ($state) {
|
||||
case 'running':
|
||||
break;
|
||||
case 'paused':
|
||||
case 'pmsuspended':
|
||||
$lv->domain_resume("{$mac_list[$mac]['name']}");
|
||||
break;
|
||||
default:
|
||||
$lv->domain_start("{$mac_list[$mac]['name']}");
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "LXC":
|
||||
if ($lxc_ls_exist && $RUNLXC == "y") {
|
||||
$state = getContainerStats($mac_list[$mac]['name'], "State");
|
||||
switch ($state) {
|
||||
case 'RUNNING':
|
||||
break;
|
||||
case 'FROZEN':
|
||||
shell_exec("lxc-unfreeze {$mac_list[$mac]['name']}");
|
||||
break;
|
||||
default:
|
||||
shell_exec("lxc-start {$mac_list[$mac]['name']}");
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "Docker":
|
||||
if ($dockerd_running && $RUNDOCKER == "y") {
|
||||
|
||||
switch ($mac_list[$mac]['state']) {
|
||||
|
||||
case "exited":
|
||||
case "created":
|
||||
shell_exec("docker start {$mac_list[$mac]['name']}");
|
||||
break;
|
||||
case "paused":
|
||||
shell_exec("docker unpause {$mac_list[$mac]['name']}");
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if ($mac_list[$mac]['enable'] == "disable") echo $mac . " " . _(" has not been actioned as set to disabled");
|
||||
else echo _("Not Found ")." ". $mac . " "._(" ignoring or Maybe actions disabled for type(Docker/VM/LXC)");
|
||||
}
|
||||
|
||||
?>
|
||||
93
emhttp/plugins/dynamix/scripts/WOL_action
Executable file
93
emhttp/plugins/dynamix/scripts/WOL_action
Executable file
@@ -0,0 +1,93 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# script: WOL_action
|
||||
#
|
||||
# Startup script for unraidwold
|
||||
#
|
||||
# Simon Fairweather - Initial Script October 2023
|
||||
|
||||
DAEMON="unraidwold"
|
||||
BINARY="/usr/local/sbin/unraidwold"
|
||||
|
||||
# run & log functions
|
||||
. /etc/rc.d/rc.runlog
|
||||
. /boot/config/wol.cfg
|
||||
|
||||
unraidwold_running(){
|
||||
sleep 0.1
|
||||
ps axc | grep -q ' unraidwold'
|
||||
}
|
||||
|
||||
unraidwold_start(){
|
||||
log "Starting $DAEMON..."
|
||||
local REPLY
|
||||
if unraidwold_running; then
|
||||
REPLY="Already started"
|
||||
else
|
||||
nohup $BINARY $1 $2 $3 $4 $5 $6 > /dev/null &
|
||||
fi
|
||||
log "$DAEMON... $REPLY."
|
||||
}
|
||||
|
||||
unraidwold_stop(){
|
||||
log "Stopping $DAEMON..."
|
||||
local REPLY
|
||||
if ! unraidwold_running; then
|
||||
REPLY="Already stopped"
|
||||
else
|
||||
killall -TERM $DAEMON
|
||||
if ! unraidwold_running; then REPLY="Stopped"; else REPLY="Failed"; fi
|
||||
fi
|
||||
log "$DAEMON... $REPLY."
|
||||
}
|
||||
|
||||
unraidwold_status(){
|
||||
if unraidwold_running; then
|
||||
echo "$DAEMON is currently running."
|
||||
else
|
||||
echo "$DAEMON is not running."
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
unraidwold_load()
|
||||
{
|
||||
if unraidwold_running; then
|
||||
unraidwold_stop
|
||||
fi
|
||||
sleep 1
|
||||
if [ "$WOLENABLED" == "yes" ]; then
|
||||
interfacemode=""
|
||||
logoptions=""
|
||||
|
||||
if [ "$IFMODE" == "y" ]; then
|
||||
interfacemode="--promiscuous"
|
||||
fi
|
||||
|
||||
if [ "$LOGFILE" != "syslog" ]; then
|
||||
logoptions="--log $LOGFILE"
|
||||
fi
|
||||
|
||||
unraidwold_start --interface $INTERFACE $interfacemode $logoptions
|
||||
fi
|
||||
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
'start')
|
||||
unraidwold_start $2 $3 $4 $5 $6
|
||||
;;
|
||||
'stop')
|
||||
unraidwold_stop
|
||||
;;
|
||||
'status')
|
||||
unraidwold_status
|
||||
;;
|
||||
'load')
|
||||
unraidwold_load
|
||||
;;
|
||||
*)
|
||||
echo "Usage: $BDAEMON start|stop|restart|status"
|
||||
exit 1
|
||||
esac
|
||||
exit 0
|
||||
11
emhttp/plugins/dynamix/sheets/WOL.css
Normal file
11
emhttp/plugins/dynamix/sheets/WOL.css
Normal file
@@ -0,0 +1,11 @@
|
||||
table#t1{margin-top:0;font-family:clear-sans}
|
||||
table#t1 thead tr th{font-weight:bold}
|
||||
table#t1 tbody tr td{padding:4px 20px 4px 0;margin:0;text-align:left;white-space:normal}
|
||||
table#t1 tbody tr td:nth-child(1){width:10%}
|
||||
table#t1 tbody tr td:nth-child(2){width:30%}
|
||||
table#t1 tbody tr td:nth-child(3){width:15%}
|
||||
table#t1 tbody tr td:nth-child(4){width:20%}
|
||||
table#t1 tbody tr td:nth-child(5){width:25%;padding-right:0}
|
||||
table.t1.tablesorter .filtered{display:none}
|
||||
.tablesorter-header-inner{font-family:clear-sans;font-weight:bold}
|
||||
#macform .mac_generate{cursor:pointer;margin-left:-5px;color:#08C;font-size:1.3rem;transform:translate(0px, 2px)}
|
||||
26
src/unraidwold/LICENSE
Normal file
26
src/unraidwold/LICENSE
Normal file
@@ -0,0 +1,26 @@
|
||||
BSD 2-Clause License
|
||||
|
||||
Copyright (c) 2021, Scott Ellis
|
||||
All rights reserved.
|
||||
Copyright (c) 2023, Limetech,Simon Fairweather
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
1
src/unraidwold/go.mod
Normal file
1
src/unraidwold/go.mod
Normal file
@@ -0,0 +1 @@
|
||||
module github.com/SimonFair/unraidwold/v2
|
||||
63
src/unraidwold/go.sum
Normal file
63
src/unraidwold/go.sum
Normal file
@@ -0,0 +1,63 @@
|
||||
github.com/antchfx/xmlquery v1.3.15 h1:aJConNMi1sMha5G8YJoAIF5P+H+qG1L73bSItWHo8Tw=
|
||||
github.com/antchfx/xmlquery v1.3.15/go.mod h1:zMDv5tIGjOxY/JCNNinnle7V/EwthZ5IT8eeCGJKRWA=
|
||||
github.com/antchfx/xpath v1.2.3 h1:CCZWOzv5bAqjVv0offZ2LVgVYFbeldKQVuLNbViZdes=
|
||||
github.com/antchfx/xpath v1.2.3/go.mod h1:i54GszH55fYfBmoZXapTHN8T8tkcHfRgLyVwwqzXNcs=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/digitalocean/go-libvirt v0.0.0-20221205150000-2939327a8519 h1:OpkN/n40cmKenDQS+IOAeW9DLhYy4DADSeZnouCEV/E=
|
||||
github.com/digitalocean/go-libvirt v0.0.0-20221205150000-2939327a8519/go.mod h1:WyJJyfmJ0gWJvjV+ZH4DOgtOYZc1KOvYyBXWCLKxsUU=
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8=
|
||||
github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.5.0 h1:GyT4nK/YDHSqa1c4753ouYCDajOYKTja9Xb/OHtgvSw=
|
||||
golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.4.0 h1:Zr2JFtRQNX3BCZ8YtxRE9hNJYC8J6I1MVbMg6owUp18=
|
||||
golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.6.0 h1:3XmdazWV+ubf7QgHSTWeykHOci5oeekaGJBLkrkaw4k=
|
||||
golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
236
src/unraidwold/unraidwold.go
Normal file
236
src/unraidwold/unraidwold.go
Normal file
@@ -0,0 +1,236 @@
|
||||
// Copyright (c) 2021, Scott Ellis
|
||||
// All rights reserved.
|
||||
// Copyright (c) 2023 Limetech, Simon Fairweather.
|
||||
//
|
||||
// Unraid Wake-on-LAN(V1.0.0)
|
||||
//
|
||||
// Listens for a WOL magic packet (UDP) and ether frame type 0x0842
|
||||
// If a matching VM/Docker or LXC is found, it is started (if not already running) and resumed if paused
|
||||
//
|
||||
// Filters on ether proto 0x0842 or udp port 9
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"log/syslog"
|
||||
"os"
|
||||
"os/exec"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
|
||||
"github.com/google/gopacket"
|
||||
"github.com/google/gopacket/pcap"
|
||||
"github.com/google/gopacket/layers"
|
||||
|
||||
)
|
||||
|
||||
var logger *log.Logger
|
||||
|
||||
func main() {
|
||||
var logOutput io.Writer
|
||||
var (
|
||||
appVersion bool
|
||||
interfaceName string
|
||||
logFile string
|
||||
promiscuous bool
|
||||
)
|
||||
|
||||
flag.BoolVar(&appVersion, "version", false, "Print the version and copyright information")
|
||||
flag.StringVar(&interfaceName, "interface", "", "Network interface name (required)")
|
||||
flag.StringVar(&logFile, "log", "", "Log file path")
|
||||
flag.BoolVar(&promiscuous, "promiscuous", false, "Enable promiscuous mode")
|
||||
|
||||
flag.Parse()
|
||||
|
||||
versionInfo := "Unraid Wake-on-LAN (V1.0.0)\nCopyright (c) 2021, Scott Ellis\nAll rights reserved.\nCopyright (c) 2023 Limetech, Simon Fairweather.\n"
|
||||
|
||||
// Check if the version flag is set
|
||||
if appVersion {
|
||||
fmt.Println(versionInfo)
|
||||
return
|
||||
}
|
||||
|
||||
// Check if the required --interface flag is provided
|
||||
if interfaceName == "" {
|
||||
fmt.Println("Error: The --interface flag is required")
|
||||
flag.PrintDefaults()
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
deviceError := deviceExists(interfaceName)
|
||||
if (! deviceError) {
|
||||
fmt.Println("Error: The --interface network address is not valid")
|
||||
flag.PrintDefaults()
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
|
||||
// Set up logging
|
||||
|
||||
if logFile != "" {
|
||||
// If a log file is specified, create or append to the file
|
||||
file, err := os.OpenFile(logFile, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
|
||||
defer file.Close()
|
||||
if err != nil {
|
||||
logger.Fatal(err)
|
||||
}
|
||||
//defer file.Close()
|
||||
logOutput = io.MultiWriter(file, os.Stdout) // Log to both file and stdout
|
||||
} else {
|
||||
// If no log file is specified, log to syslog
|
||||
syslogWriter, err := syslog.New(syslog.LOG_INFO|syslog.LOG_DAEMON, "Unraidwold")
|
||||
if err != nil {
|
||||
logger.Fatal(err)
|
||||
}
|
||||
logOutput = syslogWriter
|
||||
}
|
||||
|
||||
// Create a logger that writes to the specified output
|
||||
logger = log.New(logOutput, "", log.LstdFlags)
|
||||
|
||||
|
||||
var filter = "ether proto 0x0842 or udp port 9"
|
||||
|
||||
// Create a PID file
|
||||
pidFile := "/var/run/unraidwold.pid" // Change the path as needed
|
||||
err := writePIDFile(pidFile)
|
||||
if err != nil {
|
||||
logger.Fatal(err)
|
||||
}
|
||||
logger.Println("Processing WOL Requests.")
|
||||
// Check if promiscuous mode is enabled
|
||||
if promiscuous {
|
||||
logger.Println("Promiscuous mode is enabled")
|
||||
}
|
||||
|
||||
|
||||
handle, err := pcap.OpenLive(interfaceName, 1600, promiscuous, pcap.BlockForever)
|
||||
if err != nil {
|
||||
logger.Fatal(err)
|
||||
}
|
||||
if err := handle.SetBPFFilter(filter); err != nil {
|
||||
log.Fatalf("Something in the BPF went wrong!: %v", err)
|
||||
}
|
||||
defer handle.Close()
|
||||
|
||||
signalChan := make(chan os.Signal, 1)
|
||||
doneChan := make(chan bool, 1)
|
||||
signal.Notify(signalChan, syscall.SIGINT, syscall.SIGTERM)
|
||||
|
||||
go processPackets(handle, signalChan, doneChan)
|
||||
|
||||
// Wait for a signal to exit
|
||||
<-doneChan
|
||||
//fmt.Println("Exiting...")
|
||||
removePIDFile(pidFile)
|
||||
logger.Println("Stopping WOL Daemon.")
|
||||
// Close down.
|
||||
os.Exit(1)
|
||||
//return
|
||||
}
|
||||
|
||||
func writePIDFile(pidFile string) error {
|
||||
pid := os.Getpid()
|
||||
pidStr := fmt.Sprintf("%d\n", pid)
|
||||
return ioutil.WriteFile(pidFile, []byte(pidStr), 0644)
|
||||
}
|
||||
|
||||
func removePIDFile(pidFile string) {
|
||||
err := os.Remove(pidFile)
|
||||
if err != nil {
|
||||
logger.Printf("Error removing PID file: %v\n", err)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func processPackets(handle *pcap.Handle, signalChan chan os.Signal, doneChan chan bool) error {
|
||||
var mac string
|
||||
|
||||
source := gopacket.NewPacketSource(handle, handle.LinkType())
|
||||
for {
|
||||
select {
|
||||
case packet := <-source.Packets():
|
||||
ethLayer := packet.Layer(layers.LayerTypeEthernet)
|
||||
udpLayer := packet.Layer(layers.LayerTypeUDP)
|
||||
|
||||
if ethLayer != nil {
|
||||
ethernetPacket, _ := ethLayer.(*layers.Ethernet)
|
||||
if ethernetPacket.EthernetType == 0x0842 {
|
||||
payload := ethernetPacket.Payload
|
||||
mac = fmt.Sprintf("%02x:%02x:%02x:%02x:%02x:%02x", payload[6], payload[7], payload[8], payload[9], payload[10], payload[11])
|
||||
}
|
||||
}
|
||||
|
||||
if udpLayer != nil {
|
||||
udpPacket, _ := udpLayer.(*layers.UDP)
|
||||
if udpPacket.DstPort == layers.UDPPort(9) {
|
||||
appPacket := packet.ApplicationLayer()
|
||||
if appPacket != nil {
|
||||
payload := appPacket.Payload()
|
||||
mac = fmt.Sprintf("%02x:%02x:%02x:%02x:%02x:%02x", payload[12], payload[13], payload[14], payload[15], payload[16], payload[17])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
go runcmd(mac)
|
||||
|
||||
case sig := <-signalChan:
|
||||
fmt.Printf("Received signal: %v\n", sig)
|
||||
doneChan <- true
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func runcmd(mac string) bool {
|
||||
app := "/usr/local/emhttp/plugins/dynamix/include/WOLrun.php"
|
||||
arg := mac
|
||||
cmd := exec.Command(app, arg)
|
||||
stdout, err := cmd.Output()
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
return false
|
||||
}
|
||||
// Print the output
|
||||
logger.Println(string(stdout))
|
||||
return true
|
||||
}
|
||||
|
||||
// Return the first MAC address seen in the UDP WOL packet
|
||||
func GrabMACAddrUDP(packet gopacket.Packet) (string, error) {
|
||||
app := packet.ApplicationLayer()
|
||||
if app != nil {
|
||||
payload := app.Payload()
|
||||
mac := fmt.Sprintf("%02x:%02x:%02x:%02x:%02x:%02x", payload[12], payload[13], payload[14], payload[15], payload[16], payload[17])
|
||||
//fmt.Printf("found MAC: %s\n", mac)
|
||||
return mac, nil
|
||||
}
|
||||
return "", errors.New("no MAC found in packet")
|
||||
}
|
||||
|
||||
// Check if the network device exists
|
||||
func deviceExists(interfacename string) bool {
|
||||
if interfacename == "" {
|
||||
fmt.Printf("No valid interface to listen on specified\n\n")
|
||||
return false
|
||||
}
|
||||
devices, err := pcap.FindAllDevs()
|
||||
|
||||
if err != nil {
|
||||
log.Panic(err)
|
||||
}
|
||||
|
||||
for _, device := range devices {
|
||||
if device.Name == interfacename {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
10
src/unraidwold/wolbuild
Normal file
10
src/unraidwold/wolbuild
Normal file
@@ -0,0 +1,10 @@
|
||||
mkdir -p unraidwol
|
||||
cd unraidwol/
|
||||
DATA_DIR=$(pwd)
|
||||
cd ${DATA_DIR}
|
||||
git clone https://github.com/SimonFair/unraidwol
|
||||
cd ${DATA_DIR}/unraidwol
|
||||
git checkout main
|
||||
PATH="$PATH:/usr/local/go/bin"
|
||||
go mod tidy
|
||||
go build
|
||||
Reference in New Issue
Block a user