From 2b38e234340e9f9c7de2126510f3884cac17a7a4 Mon Sep 17 00:00:00 2001 From: ljm42 Date: Wed, 12 Feb 2025 09:21:11 -0700 Subject: [PATCH 01/30] backport: Change TS Sidecar routine Backport #2014 to 7.0 --- share/docker/tailscale_container_hook | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/share/docker/tailscale_container_hook b/share/docker/tailscale_container_hook index cd990c6556..177f11653e 100755 --- a/share/docker/tailscale_container_hook +++ b/share/docker/tailscale_container_hook @@ -36,8 +36,8 @@ if [ "$(id -u)" != "0" ]; then error_handler fi -if [ -f /usr/local/bin/tailscale ] || [ -f /usr/local/bin/tailscaled ]; then - echo "Official Tailscale Sidecar container detected!" +if [ "${OFFICIAL_TAILSCALE_SIDECAR}" = "true" ]; then + echo "Official Tailscale Sidecar container routine enabled!" echo OFFICIAL_TS_SIDECAR="true" apk update >/dev/null 2>&1 From ca98e7f4ac2c1a4688b6e7392f0f8983624bd26e Mon Sep 17 00:00:00 2001 From: SimonFair <39065407+SimonFair@users.noreply.github.com> Date: Wed, 12 Feb 2025 21:08:11 +0000 Subject: [PATCH 02/30] Add ZFS fix for dataset creation. --- emhttp/plugins/dynamix/include/Helpers.php | 39 +++++++++++++++++----- 1 file changed, 31 insertions(+), 8 deletions(-) diff --git a/emhttp/plugins/dynamix/include/Helpers.php b/emhttp/plugins/dynamix/include/Helpers.php index 7bdf736d90..68474afcfd 100644 --- a/emhttp/plugins/dynamix/include/Helpers.php +++ b/emhttp/plugins/dynamix/include/Helpers.php @@ -302,32 +302,48 @@ function delete_file(...$file) { array_map('unlink',array_filter($file,'file_exists')); } function my_mkdir($dirname,$permissions = 0777,$recursive = false,$own = "nobody",$grp = "users") { - if (is_dir($dirname)) return(false); + write_logging("Check if dir exists\n"); + if (is_dir($dirname)) {write_logging("Dir exists\n"); return(false);} + write_logging("Dir does not exist\n"); $parent = $dirname; + write_logging("Getting $parent\n"); while (!is_dir($parent)){ + if (!is_dir($parent)) write_logging("Not parent $parent\n"); else write_logging("Parent $parent is\n"); if (!$recursive) return(false); $pathinfo2 = pathinfo($parent); $parent = $pathinfo2["dirname"]; } + write_logging("Parent $parent\n"); if (strpos($dirname,'/mnt/user/')===0) { + write_logging("Getting real disks\n"); $realdisk = trim(shell_exec("getfattr --absolute-names --only-values -n system.LOCATION ".escapeshellarg($parent)." 2>/dev/null")); if (!empty($realdisk)) { $dirname = str_replace('/mnt/user/', "/mnt/$realdisk/", $dirname); $parent = str_replace('/mnt/user/', "/mnt/$realdisk/", $parent); } } - $fstype = trim(shell_exec(" stat -f -c '%T' $parent")); + $fstype = trim(shell_exec(" stat -f -c '%T' $parent")); $rtncode = false; + write_logging("fstype:$fstype parent $parent dir name $dirname\n"); switch ($fstype) { case "zfs": - $zfsdataset = trim(shell_exec("zfs list -H -o name $parent")) ; - $zfsdataset .= str_replace($parent,"",$dirname); - if ($recursive) $rtncode=exec("zfs create -p \"$zfsdataset\"");else $rtncode=exec("zfs create \"$zfsdataset\""); - if (!$rtncode) mkdir($dirname, $permissions, $recursive); else chmod($zfsdataset,$permissions); + if (is_dir($parent.'/.zfs')) { + write_logging("ZFS Volume\n"); + $zfsdataset = trim(shell_exec("zfs list -H -o name $parent")); + write_logging("Shell $zfsdataset\n"); + $zfsdataset .= str_replace($parent,"",$dirname); + write_logging("Dataset $zfsdataset\n"); + $zfsoutput = array(); + if ($recursive) exec("zfs create -p \"$zfsdataset\"",$zfsoutput,$rtncode);else exec("zfs create \"$zfsdataset\"",$zfsoutput,$rtncode); + write_logging("Output: {$zfsoutput[0]} $rtncode"); + if ($rtncode == 0) write_logging( " ZFS Command OK\n"); else write_logging( "ZFS Command Fail\n"); + } else {write_logging("Not ZFS dataset\n");$rtncode = 1;} + if ($rtncode > 0) { mkdir($dirname, $permissions, $recursive); write_logging( "created dir:$dirname\n");} else chmod($zfsdataset,$permissions); break; case "btrfs": - if ($recursive) $rtncode=exec("btrfs subvolume create --parents \"$dirname\""); else $rtncode=exec("btrfs subvolume create \"$dirname\""); - if (!$rtncode) mkdir($dirname, $permissions, $recursive); else chmod($dirname,$permissions); + $btrfsoutput = array(); + if ($recursive) exec("btrfs subvolume create --parents \"$dirname\"",$btrfsoutput,$rtncode); else exec("btrfs subvolume create \"$dirname\"",$btrfsoutput,$rtncode); + if ($rtncode > 0) mkdir($dirname, $permissions, $recursive); else chmod($dirname,$permissions); break; default: mkdir($dirname, $permissions, $recursive); @@ -388,6 +404,13 @@ function get_realvolume($path) { } return $reallocation; } + +function write_logging($value) { + $debug = is_file("/tmp/my_mkdir_debug"); + if (!$debug) return; + file_put_contents('/tmp/my_mkdir_output', $value, FILE_APPEND); +} + function device_exists($name) { global $disks,$devs; From b858c7e1ca2bf883ebae224450787de03bcd791f Mon Sep 17 00:00:00 2001 From: Christoph Date: Thu, 13 Feb 2025 08:53:29 +0100 Subject: [PATCH 03/30] Update DockerClient.php - make sure to only pull update status from Docker containers managed by `dockerman` --- .../dynamix.docker.manager/include/DockerClient.php | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/emhttp/plugins/dynamix.docker.manager/include/DockerClient.php b/emhttp/plugins/dynamix.docker.manager/include/DockerClient.php index b30b6d331b..b22685e0c8 100644 --- a/emhttp/plugins/dynamix.docker.manager/include/DockerClient.php +++ b/emhttp/plugins/dynamix.docker.manager/include/DockerClient.php @@ -389,16 +389,17 @@ public function getAllInfo($reload=false,$com=true,$communityApplications=false) $tmp['Project'] = $tmp['Project'] ?? $this->getTemplateValue($image, 'Project'); $tmp['DonateLink'] = $tmp['DonateLink'] ?? $this->getTemplateValue($image, 'DonateLink'); $tmp['ReadMe'] = $tmp['ReadMe'] ?? $this->getTemplateValue($image, 'ReadMe'); - if (empty($tmp['updated']) || $reload) { - if ($reload) $DockerUpdate->reloadUpdateStatus($image); - $tmp['updated'] = var_export($DockerUpdate->getUpdateStatus($image),true); - } if (!$com) $tmp['updated'] = 'undef'; - if ($ct['Manager'] !== 'dockerman') + if ($ct['Manager'] !== 'dockerman') { $tmp['template'] = null; - else if (empty($tmp['template']) || $reload) { + $tmp['updated'] = null; + } else if (empty($tmp['template']) || $reload) { $tmp['template'] = $this->getUserTemplate($name); if ($reload) $DockerUpdate->updateUserTemplate($name); + if (empty($tmp['updated']) || $reload) { + if ($reload) $DockerUpdate->reloadUpdateStatus($image); + $tmp['updated'] = var_export($DockerUpdate->getUpdateStatus($image),true); + } } //$this->debug("\n$name"); //foreach ($tmp as $c => $d) $this->debug(sprintf(' %-10s: %s', $c, $d)); From 12a290aed87ed7792ca89008b0d98cbc97df222e Mon Sep 17 00:00:00 2001 From: Christoph Date: Thu, 13 Feb 2025 08:54:56 +0100 Subject: [PATCH 04/30] Update DockerContainers.php - only display update status for containers managed by `dockerman` --- .../dynamix.docker.manager/include/DockerContainers.php | 6 ------ 1 file changed, 6 deletions(-) diff --git a/emhttp/plugins/dynamix.docker.manager/include/DockerContainers.php b/emhttp/plugins/dynamix.docker.manager/include/DockerContainers.php index 267207e9dc..b1aec04991 100644 --- a/emhttp/plugins/dynamix.docker.manager/include/DockerContainers.php +++ b/emhttp/plugins/dynamix.docker.manager/include/DockerContainers.php @@ -195,10 +195,8 @@ function my_lang_log($text) { echo ""; } elseif (!empty($composestack)) { echo "
"._("Compose")."
"; - echo " "._('up-to-date').""; } else { echo "
"._("3rd Party")."
"; - echo " "._('up-to-date').""; } break; case 1: @@ -207,10 +205,8 @@ function my_lang_log($text) { echo " "._('apply update').""; } elseif (!empty($composestack)) { echo "
Compose
"; - echo " "._('update available').""; } else { echo "
3rd Party
"; - echo " "._('update available').""; } break; case 2: @@ -223,10 +219,8 @@ function my_lang_log($text) { echo ""; } elseif (!empty($composestack)) { echo "
"._("Compose")."
"; - echo " "._('not available').""; } else { echo "
"._("3rd Party")."
"; - echo " "._('not available').""; } break; } From 5b4528f79ab54238a19fa2b3043628a88ce0a1f5 Mon Sep 17 00:00:00 2001 From: Squidly271 Date: Sat, 15 Feb 2025 15:05:55 -0500 Subject: [PATCH 05/30] Disallow TS Integration on Host / Container Networks --- .../include/CreateDocker.php | 24 ++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/emhttp/plugins/dynamix.docker.manager/include/CreateDocker.php b/emhttp/plugins/dynamix.docker.manager/include/CreateDocker.php index 6f8d0a981a..f5ec0cea1e 100644 --- a/emhttp/plugins/dynamix.docker.manager/include/CreateDocker.php +++ b/emhttp/plugins/dynamix.docker.manager/include/CreateDocker.php @@ -1151,14 +1151,21 @@ function prepareCategory() { -
+
_(Use Tailscale)_: : onchange="showTailscale(this)"> :docker_tailscale_help:
+ +
+_(Use Tailscale)_: +: _(Option disabled as Network type is not bridge or custom)_ + +:docker_tailscale_help: +
_(NOTE)_: : _(This option will install Tailscale and dependencies into the container.)_ @@ -1534,8 +1541,13 @@ function showSubnet(bridge) { $('#netCONT').val(''); } // make sure to re-trigger Tailscale check when network is changed - if ($('#contTailscale').prop('checked')) { - showTailscale(true); + if (bridge.match(/^(host|container)$/i) !== null) { + $('#contTailscale').click().switchButton({checked: false}).prop('checked',false); + $(".TSNetworkAllowed").hide(); + $(".TSNetworkNotAllowed").show(); + } else { + $(".TSNetworkAllowed").show(); + $(".TSNetworkNotAllowed").hide(); } } @@ -1687,6 +1699,12 @@ function showTSAdvanced(checked) { } function showTailscale(source) { + var bridge = $('select[name="contNetwork"]').val(); + if (bridge.match(/^(host|container)$/i) !== null) { + $('#contTailscale').click().switchButton({checked: false}).prop('checked',false); + $(".TSNetworkAllowed").hide(); + $(".TSNetworkNotAllowed").show(); + } if (!$.trim($('#TSallowlanaccess').val())) { $('#TSallowlanaccess').val('false'); } From dd885b0b65cf9147127daaf72bee3179e4c5d33e Mon Sep 17 00:00:00 2001 From: Tom Mortensen Date: Tue, 18 Feb 2025 22:21:01 -0800 Subject: [PATCH 06/30] Array Operation: fix: correct usage of sweet-alert presenting invalid configurations and warnings fix: hide "Clear Stats" button when disk I/O is visible --- emhttp/plugins/dynamix/ArrayOperation.page | 56 ++++++++++++++++------ emhttp/plugins/dynamix/DeviceInfo.page | 0 2 files changed, 41 insertions(+), 15 deletions(-) mode change 100755 => 100644 emhttp/plugins/dynamix/DeviceInfo.page diff --git a/emhttp/plugins/dynamix/ArrayOperation.page b/emhttp/plugins/dynamix/ArrayOperation.page index 0c79a61bd4..fc633f83a7 100644 --- a/emhttp/plugins/dynamix/ArrayOperation.page +++ b/emhttp/plugins/dynamix/ArrayOperation.page @@ -4,8 +4,8 @@ Tag="snowflake-o" Nchan="device_list,disk_load,parity_list" --- ",_('Retype passphrase'),":"; echo "",_('Keyfile'),":"; } + function maintenance_mode() { echo ""; echo ""; @@ -55,6 +56,7 @@ function maintenance_mode() { echo "",_('Maintenance mode')," - ",_('if checked, Start array but do not mount disks'),""; echo ""; } + function status_indicator() { global $var; switch (_var($var,'mdColor')) { @@ -65,15 +67,18 @@ function status_indicator() { } echo "$help"; } + function missing_cache() { global $disks; $missing = false; foreach (cache_filter($disks) as $disk) $missing |= (strpos(_var($disk,'status'),'_MISSING')!==false); return $missing; } + function resync($d) { return in_array($d,['P','Q']) ? 'Parity-Sync' : 'Data-Rebuild'; } + function print_error($error) { return sprintf(_('Finding **%s** error'.($error==1?'':'s')),$error?:'0'); } @@ -111,27 +116,33 @@ function toggle_state(device,name,action) { devices.stop(); $.post('/webGui/include/ToggleState.php',{device:device,name:name,action:action},function(){setTimeout(function(){devices.start();},1000);if (button) $(button).prop('disabled',false);}); } + function display_diskio() { if ($.cookie('diskio')===undefined) { - $('span.number').show(); $('span.diskio').hide(); - } else { $('span.diskio').show(); $('span.number').hide(); + } else { + $('span.number').show(); $('span.diskio').hide(); } } + function toggle_diskio(init) { if (!init) { if ($.cookie('diskio')===undefined) $.cookie('diskio','diskio',{expires:3650}); else $.removeCookie('diskio'); } if ($.cookie('diskio')===undefined) { - $('i.toggle').removeClass('fa-tachometer').addClass('fa-list'); - } else { $('i.toggle').removeClass('fa-list').addClass('fa-tachometer'); + $('#clearstats').addClass('hidden'); + } else { + $('i.toggle').removeClass('fa-tachometer').addClass('fa-list'); + $('#clearstats').removeClass('hidden'); } display_diskio(); } + function base64(str) { return window.btoa(unescape(encodeURIComponent(str))); } + function selectInput(form) { form.input.value = 'file'; @@ -175,19 +186,21 @@ function selectInput(form) { item.prop('disabled',!form.file.value); } } + function getFileContent(event,form) { var input = event.target; var reader = new FileReader(); reader.onload = function(){form.file.value=reader.result;selectInput(form);}; reader.readAsDataURL(input.files[0]); } -function prepareInput(form,button) { - if (button) button.disabled = true; + +function prepareInput(form,button,parityWarn) { + button.disabled = true; $.post('/webGui/include/Report.php',{cmd:'state',pools:''},function(state) { if (state.length==0) { $(form).append(''); if (form.input === undefined) { - form.submit(); + parityWarn ? parityWarning(form,button) : form.submit(); return; } form.input.disabled = true; @@ -216,11 +229,12 @@ function prepareInput(form,button) { data['file'] = form.file.value; $.post('/update.php',data,function(){form.submit();}); } else { - swal({title:"_(Wrong Pool State)_",text:state,type:'error',html:true,confirmButtonText:"_(Ok)_"}); + swal({title:"_(Wrong Pool State)_",text:state,type:'error',html:true,confirmButtonText:"_(Ok)_"},function(){button.disabled=false;}); } }); } -function parityWarning(form) { + +function parityWarning(form,button) { if (form.md_invalidslot.checked) { var text = "_(*Dual parity* valid requires **ALL** disks in their original slots)_"; @@ -230,12 +244,16 @@ function parityWarning(form) { } else { var text = "_(*Parity* disk(s) content will be overwritten)_"; } - swal({title:"_(Proceed to start)_",text:text,html:true,type:'warning',showCancelButton:true,confirmButtonText:"_(Proceed)_",cancelButtonText:"_(Cancel)_"},function(){prepareInput(form);}); + swal({title:"_(Proceed to start)_",text:text,html:true,type:'warning',showCancelButton:true,confirmButtonText:"_(Proceed)_",cancelButtonText:"_(Cancel)_"},function(confirmed){ + confirmed ? form.submit() : button.disabled=false; + }); } + function tab0() { $.removeCookie('one'); $.cookie('tab','tab0'); } + function stopArray(form) { $(form).append(''); @@ -244,6 +262,7 @@ function stopArray(form) { form.submit(); } + function stopParity(form,text) { $(form).append(''); @@ -252,6 +271,7 @@ function stopParity(form,text) { form.submit(); } + function pauseParity(form) { $.post('/webGui/include/ParityControl.php',{action:'pause'},function(){ $('#pauseButton').val("_(Resume)_").prop('disabled',true).prop('onclick',null).off('click').click(function(){resumeParity(form);}); @@ -259,6 +279,7 @@ function pauseParity(form) { form.submit(); }); } + function resumeParity(form) { $.post('/webGui/include/ParityControl.php',{action:'resume'},function(){ $('#pauseButton').val("_(Pause)_").prop('disabled',true).prop('onclick',null).off('click').click(function(){pauseParity(form);}); @@ -266,9 +287,11 @@ function resumeParity(form) { form.submit(); }); } + function parityHistory() { openChanges("parity_history", "_(Parity Operation History)_", "phistory"); } + function shutdown_now(form,cmd) { $(form).append(''); @@ -281,9 +304,11 @@ function shutdown_now(form,cmd) { form.submit(); } + function toggleApply(checked) { $('input[name="#apply"]').prop('disabled',!checked); } + $('.tabs').append(ctrl); if ($.cookie('tab')=='tab0') $('i.toggle').hide(); @@ -292,7 +317,6 @@ $('#tab'+$('input[name$="tabs"]').length).click(function(){tab0(); $('i.toggle') $('div[class=title]:not(":last, .disable_diskio")').each(function(){$(this).append(ctrl);}); $('.tooltip_diskio').tooltipster({delay:100,trigger:'custom',triggerOpen:{mouseenter:true},triggerClose:{click:false,scroll:true,mouseleave:true}}); -toggle_diskio(true); var mymonitor = new NchanSubscriber('/sub/mymonitor',{subscriber:'websocket'}); @@ -422,7 +446,9 @@ setTimeout(function(){paritymonitor.start();},5000); $(function(){ var form = document.arrayOps; if (form.input !== undefined) selectInput(form); + toggle_diskio(true); }); + function formatWarning(val) { if (val==true) { swal({ @@ -640,7 +666,7 @@ window.onunload = function(){ **_(Start)_** _(will record all disk information and bring the array on-line)_.
_(The array will be immediately available, but **unprotected** since *parity* has not been assigned)_. - **_(Stopped)_**. _(Configuration valid)_. + **_(Stopped)_**. _(Configuration valid)_. **_(Start)_** _(will record all disk information, bring the array on-line, and start Parity-Sync)_.
_(The array will be immediately available, but **unprotected** until Parity-Sync completes)_.
_(Parity is already valid)_. @@ -720,7 +746,7 @@ endswitch; - +
**_(Spin Up)_** _(will immediately spin up all disks)_.
**_(Spin Down)_** _(will immediately spin down all disks)_.
**_(Clear Stats)_** _(will immediately clear all disk statistics)_.
diff --git a/emhttp/plugins/dynamix/DeviceInfo.page b/emhttp/plugins/dynamix/DeviceInfo.page old mode 100755 new mode 100644 From 688eff2b01da96c47497f8a643c62e8a61f1bf80 Mon Sep 17 00:00:00 2001 From: Christoph Date: Fri, 21 Feb 2025 08:27:50 +0100 Subject: [PATCH 07/30] Update tailscale_container_hook - Allow changing the target address from Tailscale Serve --- share/docker/tailscale_container_hook | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/share/docker/tailscale_container_hook b/share/docker/tailscale_container_hook index 177f11653e..817e22eb10 100755 --- a/share/docker/tailscale_container_hook +++ b/share/docker/tailscale_container_hook @@ -361,12 +361,15 @@ if [ ! -z "${TAILSCALE_SERVE_PORT}" ]; then if [ -z "${TAILSCALE_SERVE_PROTOCOL_PORT}" ]; then TAILSCALE_SERVE_PROTOCOL_PORT="=443" fi + if [ -z "${TAILSCALE_SERVE_TARGET}" ]; then + TAILSCALE_SERVE_TARGET="http://localhost" + fi if [ "${TAILSCALE_FUNNEL}" = "true" ]; then echo "Enabling Funnel! See https://tailscale.com/kb/1223/funnel" - eval tailscale funnel --bg --"${TAILSCALE_SERVE_PROTOCOL}"${TAILSCALE_SERVE_PROTOCOL_PORT}${TAILSCALE_SERVE_PATH} http://localhost:"${TAILSCALE_SERVE_PORT}${TAILSCALE_SERVE_LOCALPATH}" | grep -v "To disable the proxy" + eval tailscale funnel --bg --"${TAILSCALE_SERVE_PROTOCOL}"${TAILSCALE_SERVE_PROTOCOL_PORT}${TAILSCALE_SERVE_PATH} ${TAILSCALE_SERVE_TARGET}:"${TAILSCALE_SERVE_PORT}${TAILSCALE_SERVE_LOCALPATH}" | grep -v "To disable the proxy" else echo "Enabling Serve! See https://tailscale.com/kb/1312/serve" - eval tailscale serve --bg --"${TAILSCALE_SERVE_PROTOCOL}"${TAILSCALE_SERVE_PROTOCOL_PORT}${TAILSCALE_SERVE_PATH} http://localhost:"${TAILSCALE_SERVE_PORT}${TAILSCALE_SERVE_LOCALPATH}" | grep -v "To disable the proxy" + eval tailscale serve --bg --"${TAILSCALE_SERVE_PROTOCOL}"${TAILSCALE_SERVE_PROTOCOL_PORT}${TAILSCALE_SERVE_PATH} ${TAILSCALE_SERVE_TARGET}:"${TAILSCALE_SERVE_PORT}${TAILSCALE_SERVE_LOCALPATH}" | grep -v "To disable the proxy" fi if [ "${TAILSCALE_SERVE_PROTOCOL}" = "https" ]; then TS_DNSNAME="$(tailscale status --json | jq -r '.Self.DNSName' | sed 's/\.$//')" From 8a04c224a9bd42e4117f1b9f509d10ca5c927990 Mon Sep 17 00:00:00 2001 From: Christoph Date: Fri, 21 Feb 2025 08:58:14 +0100 Subject: [PATCH 08/30] Update CreateDocker.php - Allow changing target in WebUI --- .../dynamix.docker.manager/include/CreateDocker.php | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/emhttp/plugins/dynamix.docker.manager/include/CreateDocker.php b/emhttp/plugins/dynamix.docker.manager/include/CreateDocker.php index f5ec0cea1e..86bc219c20 100644 --- a/emhttp/plugins/dynamix.docker.manager/include/CreateDocker.php +++ b/emhttp/plugins/dynamix.docker.manager/include/CreateDocker.php @@ -1307,6 +1307,14 @@ function prepareCategory() {
+
+_(Tailscale Serve Target)_: +: placeholder="_(Leave empty if unsure)_"> + +:docker_tailscale_serve_target_help: + +
+
_(Tailscale Serve Protocol)_: : placeholder="_(Leave empty if unsure, defaults to https)_"> @@ -1677,6 +1685,7 @@ function showTSAdvanced(checked) { $('.TSservepath').hide(); $('.TSserveprotocol').hide(); $('.TSserveprotocolport').hide(); + $('.TSservetarget').hide(); $('.TSservelocalpath').hide(); $('.TSwebui').hide(); $('.TStroubleshooting').hide(); @@ -1690,6 +1699,7 @@ function showTSAdvanced(checked) { $('.TSservepath').show(); $('.TSserveprotocol').show(); $('.TSserveprotocolport').show(); + $('.TSservetarget').show(); $('.TSservelocalpath').show(); $('.TSwebui').show(); $('.TStroubleshooting').show(); From 0c82a45ef64670eb3651260ad1bf0262199060e5 Mon Sep 17 00:00:00 2001 From: Christoph Date: Fri, 21 Feb 2025 09:03:44 +0100 Subject: [PATCH 09/30] Update Helpers.php - Necessary changes for TStarget --- emhttp/plugins/dynamix.docker.manager/include/Helpers.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/emhttp/plugins/dynamix.docker.manager/include/Helpers.php b/emhttp/plugins/dynamix.docker.manager/include/Helpers.php index 28dab85c60..d2cc6b0566 100644 --- a/emhttp/plugins/dynamix.docker.manager/include/Helpers.php +++ b/emhttp/plugins/dynamix.docker.manager/include/Helpers.php @@ -117,6 +117,7 @@ function postToXML($post, $setOwnership=false) { $xml->TailscaleWebUI = xml_encode(generateTSwebui($post['TSwebui'], $post['TSserve'], $post['contWebUI'])); if (isset($post['TSserve']) && strtolower($post['TSserve']) !== 'no') { $xml->TailscaleServePort = xml_encode($post['TSserveport']); + $xml->TailscaleServeTarget = xml_encode($post['TSservetarget']); $xml->TailscaleServeLocalPath = xml_encode($post['TSservelocalpath']); $xml->TailscaleServeProtocol = xml_encode($post['TSserveprotocol']); $xml->TailscaleServeProtocolPort = xml_encode($post['TSserveprotocolport']); @@ -171,6 +172,7 @@ function xmlToVar($xml) { $out['TailscaleUserspaceNetworking'] = xml_decode($xml->TailscaleUserspaceNetworking ?? ''); $out['TailscaleServe'] = xml_decode($xml->TailscaleServe ?? ''); $out['TailscaleServePort'] = xml_decode($xml->TailscaleServePort ?? ''); + $out['TailscaleServeTarget'] = xml_decode($xml->TailscaleServeTarget ?? ''); $out['TailscaleServeLocalPath'] = xml_decode($xml->TailscaleServeLocalPath ?? ''); $out['TailscaleServeProtocol'] = xml_decode($xml->TailscaleServeProtocol ?? ''); $out['TailscaleServeProtocolPort'] = xml_decode($xml->TailscaleServeProtocolPort ?? ''); @@ -364,6 +366,7 @@ function xmlToCommand($xml, $create_paths=false) { $TS_state_dir = ''; $TS_serve_funnel = ''; $TS_serve_port = ''; + $TS_server_target = ''; $TS_serve_local_path = ''; $TS_serve_protocol = ''; $TS_serve_protocol_port = ''; @@ -397,6 +400,7 @@ function xmlToCommand($xml, $create_paths=false) { } $TS_serve_funnel = ($xml['TailscaleServe'] == 'funnel') ? '-e TAILSCALE_FUNNEL=true' : ''; $TS_serve_port = !empty($xml['TailscaleServePort']) ? '-e TAILSCALE_SERVE_PORT=' . escapeshellarg($xml['TailscaleServePort']) : ''; + $TS_serve_target = !empty($xml['TailscaleServeTarget']) ? '-e TAILSCALE_SERVE_TARGET=' . escapeshellarg($xml['TailscaleServeTarget']) : ''; $TS_serve_local_path = !empty($xml['TailscaleServeLocalPath']) ? '-e TAILSCALE_SERVE_LOCALPATH=' . escapeshellarg($xml['TailscaleServeLocalPath']) : ''; $TS_serve_protocol = !empty($xml['TailscaleServeProtocol']) ? '-e TAILSCALE_SERVE_PROTOCOL=' . escapeshellarg($xml['TailscaleServeProtocol']) : ''; $TS_serve_protocol_port = !empty($xml['TailscaleServeProtocolPort']) ? '-e TAILSCALE_SERVE_PROTOCOL_PORT=' . escapeshellarg($xml['TailscaleServeProtocolPort']) : ''; @@ -474,8 +478,8 @@ function xmlToCommand($xml, $create_paths=false) { $pid_limit = ""; } - $cmd = sprintf($docroot.'/plugins/dynamix.docker.manager/scripts/docker create %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s', - $cmdName, $TS_entrypoint, $cmdNetwork, $cmdMyIP, $cmdCPUset, $pid_limit, $cmdPrivileged, implode(' -e ', $Variables), $TS_hostname, $TS_exitnode, $TS_exitnode_ip, $TS_lan_access, $TS_routes, $TS_accept_routes, $TS_ssh, $TS_userspace_networking, $TS_serve_funnel, $TS_serve_port, $TS_serve_local_path, $TS_serve_protocol, $TS_serve_protocol_port, $TS_serve_path, $TS_daemon_params, $TS_extra_params, $TS_state_dir, $TS_troubleshooting, $TS_postargs, implode(' -l ', $Labels), $TS_web_ui, $TS_hostname_label, implode(' -p ', $Ports), implode(' -v ', $Volumes), $TS_hook, $TS_cap, $TS_tundev, implode(' --device=', $Devices), $xml['ExtraParams'], escapeshellarg($xml['Repository']), $xml['PostArgs']); + $cmd = sprintf($docroot.'/plugins/dynamix.docker.manager/scripts/docker create %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s', + $cmdName, $TS_entrypoint, $cmdNetwork, $cmdMyIP, $cmdCPUset, $pid_limit, $cmdPrivileged, implode(' -e ', $Variables), $TS_hostname, $TS_exitnode, $TS_exitnode_ip, $TS_lan_access, $TS_routes, $TS_accept_routes, $TS_ssh, $TS_userspace_networking, $TS_serve_funnel, $TS_serve_port, $TS_serve_target, $TS_serve_local_path, $TS_serve_protocol, $TS_serve_protocol_port, $TS_serve_path, $TS_daemon_params, $TS_extra_params, $TS_state_dir, $TS_troubleshooting, $TS_postargs, implode(' -l ', $Labels), $TS_web_ui, $TS_hostname_label, implode(' -p ', $Ports), implode(' -v ', $Volumes), $TS_hook, $TS_cap, $TS_tundev, implode(' --device=', $Devices), $xml['ExtraParams'], escapeshellarg($xml['Repository']), $xml['PostArgs']); return [preg_replace('/\s\s+/', ' ', $cmd), $xml['Name'], $xml['Repository']]; } function stopContainer($name, $t=false, $echo=true) { From 2cd5132badd8a507ecafdd72e1db6bc526fa6a12 Mon Sep 17 00:00:00 2001 From: Christoph Date: Fri, 21 Feb 2025 09:13:48 +0100 Subject: [PATCH 10/30] Update helptext.txt - Add helptext for Serve target --- emhttp/languages/en_US/helptext.txt | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/emhttp/languages/en_US/helptext.txt b/emhttp/languages/en_US/helptext.txt index 57d748267f..7b5527b511 100644 --- a/emhttp/languages/en_US/helptext.txt +++ b/emhttp/languages/en_US/helptext.txt @@ -2413,7 +2413,7 @@ The system attempted to determine the correct port automatically. If it used the In most cases this port is all you will need to specify in order to Serve the website in this container, although additional options are available below for more complex containers. This value is passed to the `` portion of this command which starts serve or funnel:
-`tailscale [serve|funnel] --bg -- http://localhost:`
+`tailscale [serve|funnel] --bg -- :`
For more details see the Tailscale Serve Command Line documentation. :end @@ -2421,27 +2421,34 @@ For more details see the ` portion of this command which starts serve or funnel:
+`tailscale [serve|funnel] --bg -- :`
+For more details see the
Tailscale Serve Command Line documentation.
+Please note that only `localhost` or `127.0.0.1` are supported. +:end + :docker_tailscale_serve_local_path_help: When not specified, this value defaults to an empty string. It is passed to the `` portion of this command which starts serve or funnel:
-`tailscale [serve|funnel] --bg -- http://localhost:`
+`tailscale [serve|funnel] --bg -- :`
For more details see the Tailscale Serve Command Line documentation. :end :docker_tailscale_serve_protocol_help: When not specified, this value defaults to "https". It is passed to the `` portion of this command which starts serve or funnel:
-`tailscale [serve|funnel] --bg --= http://localhost:`
+`tailscale [serve|funnel] --bg --= :`
For more details see the Tailscale Serve Command Line documentation. :end :docker_tailscale_serve_protocol_port_help: When not specified, this value defaults to "=443". It is passed to the `` portion of this command which starts serve or funnel:
-`tailscale [serve|funnel] --bg -- http://localhost:`
+`tailscale [serve|funnel] --bg -- :`
For more details see the Tailscale Serve Command Line documentation. :end :docker_tailscale_serve_path_help: When not specified, this value defaults to an empty string. It is passed to the `` portion of this command which starts serve or funnel:
-`tailscale [serve|funnel] --bg -- http://localhost:`
+`tailscale [serve|funnel] --bg -- :`
For more details see the Tailscale Serve Command Line documentation. :end From 85efeedbd7564d388049136eb2f4ad91f8b986a4 Mon Sep 17 00:00:00 2001 From: Christoph Date: Fri, 21 Feb 2025 09:18:21 +0100 Subject: [PATCH 11/30] Update Helpers.php fix typo --- emhttp/plugins/dynamix.docker.manager/include/Helpers.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/emhttp/plugins/dynamix.docker.manager/include/Helpers.php b/emhttp/plugins/dynamix.docker.manager/include/Helpers.php index d2cc6b0566..037852c1df 100644 --- a/emhttp/plugins/dynamix.docker.manager/include/Helpers.php +++ b/emhttp/plugins/dynamix.docker.manager/include/Helpers.php @@ -366,7 +366,7 @@ function xmlToCommand($xml, $create_paths=false) { $TS_state_dir = ''; $TS_serve_funnel = ''; $TS_serve_port = ''; - $TS_server_target = ''; + $TS_serve_target = ''; $TS_serve_local_path = ''; $TS_serve_protocol = ''; $TS_serve_protocol_port = ''; From 96113fd311e2078291ae6b4486375b5bd682c02a Mon Sep 17 00:00:00 2001 From: Mainfrezzer <35963833+Mainfrezzer@users.noreply.github.com> Date: Sat, 22 Feb 2025 00:58:16 +0100 Subject: [PATCH 12/30] Backport: Avoid automatic shutdown while being logged in and visiting Boot.php --- emhttp/plugins/dynamix/include/Boot.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/emhttp/plugins/dynamix/include/Boot.php b/emhttp/plugins/dynamix/include/Boot.php index c2b6a69871..8400954d54 100644 --- a/emhttp/plugins/dynamix/include/Boot.php +++ b/emhttp/plugins/dynamix/include/Boot.php @@ -157,6 +157,9 @@ function power_on() { {$var['fsProgress']}" : "
 "; @@ -187,5 +190,6 @@ function power_on() { echo '
'; echo '
'; echo ''; +} ?> From 72e1c8a907eb7965cfb3236bf44b38418fae3ea4 Mon Sep 17 00:00:00 2001 From: Mainfrezzer <35963833+Mainfrezzer@users.noreply.github.com> Date: Sun, 23 Feb 2025 07:13:10 +0100 Subject: [PATCH 13/30] restore default behaviour in prior versions --- emhttp/plugins/dynamix/include/Boot.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/emhttp/plugins/dynamix/include/Boot.php b/emhttp/plugins/dynamix/include/Boot.php index 8400954d54..15e7c243a8 100644 --- a/emhttp/plugins/dynamix/include/Boot.php +++ b/emhttp/plugins/dynamix/include/Boot.php @@ -190,6 +190,10 @@ function power_on() { echo '
'; echo '
'; echo ''; +}else{ +?> +echo + From 2211cb3f20f52149f84b9f23cb062a40c58b9c99 Mon Sep 17 00:00:00 2001 From: Squidly271 Date: Mon, 24 Feb 2025 06:33:07 -0500 Subject: [PATCH 14/30] Backport Refactor: Disallow TS on host/container networks --- .../plugins/dynamix.docker.manager/include/CreateDocker.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/emhttp/plugins/dynamix.docker.manager/include/CreateDocker.php b/emhttp/plugins/dynamix.docker.manager/include/CreateDocker.php index 86bc219c20..9ae69149a9 100644 --- a/emhttp/plugins/dynamix.docker.manager/include/CreateDocker.php +++ b/emhttp/plugins/dynamix.docker.manager/include/CreateDocker.php @@ -1550,7 +1550,7 @@ function showSubnet(bridge) { } // make sure to re-trigger Tailscale check when network is changed if (bridge.match(/^(host|container)$/i) !== null) { - $('#contTailscale').click().switchButton({checked: false}).prop('checked',false); + $('#contTailscale').siblings('.switch-button-background').click(); $(".TSNetworkAllowed").hide(); $(".TSNetworkNotAllowed").show(); } else { @@ -1711,7 +1711,7 @@ function showTSAdvanced(checked) { function showTailscale(source) { var bridge = $('select[name="contNetwork"]').val(); if (bridge.match(/^(host|container)$/i) !== null) { - $('#contTailscale').click().switchButton({checked: false}).prop('checked',false); + $('#contTailscale').prop('checked',false); $(".TSNetworkAllowed").hide(); $(".TSNetworkNotAllowed").show(); } From d0b6b25261752a7ad6b5593d53eb021492cf52fa Mon Sep 17 00:00:00 2001 From: Tom Mortensen Date: Mon, 24 Feb 2025 09:09:36 -0800 Subject: [PATCH 15/30] Use exit instead of return to prevent php warnings --- emhttp/plugins/dynamix/ShareEdit.page | 2 +- emhttp/plugins/dynamix/UserEdit.page | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/emhttp/plugins/dynamix/ShareEdit.page b/emhttp/plugins/dynamix/ShareEdit.page index 53c206b318..2a41849e3f 100644 --- a/emhttp/plugins/dynamix/ShareEdit.page +++ b/emhttp/plugins/dynamix/ShareEdit.page @@ -17,7 +17,7 @@ Tag="share-alt-square" done()"; - return; + exit; } $width = [123,300]; diff --git a/emhttp/plugins/dynamix/UserEdit.page b/emhttp/plugins/dynamix/UserEdit.page index b9d846184b..ad044a999e 100644 --- a/emhttp/plugins/dynamix/UserEdit.page +++ b/emhttp/plugins/dynamix/UserEdit.page @@ -17,7 +17,7 @@ Tag="user" done()"; - return; + exit; } $user = "/boot/config/plugins/dynamix/users/$name.png"; $void = ""; From f589c63ce8c7676efbf4c6eeb4aace5e08b5b2e5 Mon Sep 17 00:00:00 2001 From: Squidly271 Date: Mon, 24 Feb 2025 16:25:52 -0500 Subject: [PATCH 16/30] Backport: Fix: Don't allow autostart on containers with host network and TS --- .../scripts/docker_init | 33 ++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/emhttp/plugins/dynamix.docker.manager/scripts/docker_init b/emhttp/plugins/dynamix.docker.manager/scripts/docker_init index 27e7b363a1..71c2a70a2f 100755 --- a/emhttp/plugins/dynamix.docker.manager/scripts/docker_init +++ b/emhttp/plugins/dynamix.docker.manager/scripts/docker_init @@ -1,2 +1,33 @@ -#!/bin/bash +#!/usr/bin/php +load("/boot/config/plugins/dockerMan/templates-user/my-{$cont[0]}.xml"); + if ( ! $doc ) { + $newAuto[] = $container; + continue; + } + if ( ($doc->getElementsByTagName("Network")->item(0)->nodeValue ?? false) == "host" ) { + if ( ($doc->getElementsByTagName("TailscaleEnabled")->item(0)->nodeValue ?? false) == true ) { + exec("logger ".escapeshellarg("Autostart disabled on {$cont[0]} due to tailscale integration with host network.")); + exec("logger ".escapeshellarg("This is a security risk due to the possibility of unauthenticated access to your server's GUI and resources")); + continue; + } + } + $newAuto[] = $container; +} +file_put_contents("/var/lib/docker/unraid-autostart",implode("\n",$newAuto)); +?> From dc34d4c58b87c9856913fc063f93b87086247a93 Mon Sep 17 00:00:00 2001 From: Squidly271 Date: Mon, 24 Feb 2025 16:54:14 -0500 Subject: [PATCH 17/30] Refactor coderabbit suggestions --- emhttp/plugins/dynamix.docker.manager/scripts/docker_init | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/emhttp/plugins/dynamix.docker.manager/scripts/docker_init b/emhttp/plugins/dynamix.docker.manager/scripts/docker_init index 71c2a70a2f..7c58681d79 100755 --- a/emhttp/plugins/dynamix.docker.manager/scripts/docker_init +++ b/emhttp/plugins/dynamix.docker.manager/scripts/docker_init @@ -15,8 +15,7 @@ foreach ($autostart as $container) { } $doc = new DOMDocument(); - $doc->load("/boot/config/plugins/dockerMan/templates-user/my-{$cont[0]}.xml"); - if ( ! $doc ) { + if (!$doc->load("/boot/config/plugins/dockerMan/templates-user/my-{$cont[0]}.xml")) { $newAuto[] = $container; continue; } From 7c9fca7693300dacb449c74c9e2fff72b4994bc9 Mon Sep 17 00:00:00 2001 From: Squidly271 Date: Tue, 25 Feb 2025 08:09:09 -0500 Subject: [PATCH 18/30] Prevent manual start of containers with Host and TS Enabled --- .../dynamix.docker.manager/include/Events.php | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/emhttp/plugins/dynamix.docker.manager/include/Events.php b/emhttp/plugins/dynamix.docker.manager/include/Events.php index a16c1d4184..2b117e8ca6 100644 --- a/emhttp/plugins/dynamix.docker.manager/include/Events.php +++ b/emhttp/plugins/dynamix.docker.manager/include/Events.php @@ -1,6 +1,6 @@ $DockerClient->startContainer($container)]; + if ($container) { + $info = $DockerClient->getDockerContainers(); + $key = array_search($container,array_column($info,"Id")); + if ($info[$key]['NetworkMode'] == "host" && $info[$key]['Cmd'] == "/opt/unraid/tailscale") { + $arrResponse = ['success'=> _('For security reasons, containers with Network Type "Host" should not have Tailscale enabled. Please disable Tailscale in this container or change the Network Type of the container.')]; + break; + } + $arrResponse = ['success' => $DockerClient->startContainer($container)]; + } break; case 'pause': if ($container) $arrResponse = ['success' => $DockerClient->pauseContainer($container)]; From ce81abaf8308d6acae0170840fa4787675b4695a Mon Sep 17 00:00:00 2001 From: Squidly271 Date: Tue, 25 Feb 2025 08:11:24 -0500 Subject: [PATCH 19/30] Prevent Start All of containers with Host and TS Enabled --- .../include/ContainerManager.php | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/emhttp/plugins/dynamix.docker.manager/include/ContainerManager.php b/emhttp/plugins/dynamix.docker.manager/include/ContainerManager.php index 90f2f770a1..2bd77548ef 100644 --- a/emhttp/plugins/dynamix.docker.manager/include/ContainerManager.php +++ b/emhttp/plugins/dynamix.docker.manager/include/ContainerManager.php @@ -1,6 +1,6 @@ getDockerContainers(); if (file_exists($user_prefs)) { $prefs = parse_ini_file($user_prefs); $sort = []; foreach ($containers as $ct) $sort[] = array_search($ct,$prefs) ?? 999; array_multisort($sort, ($action=='start'?SORT_ASC:SORT_DESC), SORT_NUMERIC, $containers); } - foreach ($containers as $ct) { + if ( $action == "start") { + $key = array_search($ct,array_column($info,"Name")); + if ($info[$key]['NetworkMode'] == "host" && $info[$key]['Cmd'] == "/opt/unraid/tailscale") + continue; + } DockerUtil::docker("$action $ct >/dev/null"); addRoute($ct); } From 8e94d8f6b92842292197856e68d0ce7896239a5e Mon Sep 17 00:00:00 2001 From: Squidly271 Date: Tue, 25 Feb 2025 10:25:59 -0500 Subject: [PATCH 20/30] Error handling --- .../plugins/dynamix.docker.manager/include/ContainerManager.php | 1 + 1 file changed, 1 insertion(+) diff --git a/emhttp/plugins/dynamix.docker.manager/include/ContainerManager.php b/emhttp/plugins/dynamix.docker.manager/include/ContainerManager.php index 2bd77548ef..2f95ff1146 100644 --- a/emhttp/plugins/dynamix.docker.manager/include/ContainerManager.php +++ b/emhttp/plugins/dynamix.docker.manager/include/ContainerManager.php @@ -30,6 +30,7 @@ foreach ($containers as $ct) { if ( $action == "start") { $key = array_search($ct,array_column($info,"Name")); + if ( $key === false ) continue; if ($info[$key]['NetworkMode'] == "host" && $info[$key]['Cmd'] == "/opt/unraid/tailscale") continue; } From af23f28e194a558c775e6e27fdb8c383cad1729a Mon Sep 17 00:00:00 2001 From: Squidly271 Date: Tue, 25 Feb 2025 10:26:54 -0500 Subject: [PATCH 21/30] Error handling --- emhttp/plugins/dynamix.docker.manager/include/Events.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/emhttp/plugins/dynamix.docker.manager/include/Events.php b/emhttp/plugins/dynamix.docker.manager/include/Events.php index 2b117e8ca6..75bbff32ab 100644 --- a/emhttp/plugins/dynamix.docker.manager/include/Events.php +++ b/emhttp/plugins/dynamix.docker.manager/include/Events.php @@ -33,6 +33,10 @@ if ($container) { $info = $DockerClient->getDockerContainers(); $key = array_search($container,array_column($info,"Id")); + if ( $key === false ) { + $arrResponse = ['success' => _('Container not found. Try reloading this page to fix.')]; + break; + } if ($info[$key]['NetworkMode'] == "host" && $info[$key]['Cmd'] == "/opt/unraid/tailscale") { $arrResponse = ['success'=> _('For security reasons, containers with Network Type "Host" should not have Tailscale enabled. Please disable Tailscale in this container or change the Network Type of the container.')]; break; From 41fd9b9d9a434fd8e139f16aca01323a5d7c14aa Mon Sep 17 00:00:00 2001 From: Squidly271 Date: Tue, 25 Feb 2025 10:46:43 -0500 Subject: [PATCH 22/30] Add notification --- emhttp/plugins/dynamix.docker.manager/scripts/docker_init | 1 + 1 file changed, 1 insertion(+) diff --git a/emhttp/plugins/dynamix.docker.manager/scripts/docker_init b/emhttp/plugins/dynamix.docker.manager/scripts/docker_init index 7c58681d79..e970744caf 100755 --- a/emhttp/plugins/dynamix.docker.manager/scripts/docker_init +++ b/emhttp/plugins/dynamix.docker.manager/scripts/docker_init @@ -23,6 +23,7 @@ foreach ($autostart as $container) { if ( ($doc->getElementsByTagName("TailscaleEnabled")->item(0)->nodeValue ?? false) == true ) { exec("logger ".escapeshellarg("Autostart disabled on {$cont[0]} due to tailscale integration with host network.")); exec("logger ".escapeshellarg("This is a security risk due to the possibility of unauthenticated access to your server's GUI and resources")); + exec("/usr/local/emhttp/plugins/dynamix/scripts/notify -e 'Autostart Disabled' -s 'Autostart Disabled' -d ".escapeshellarg("Autostart disabled automatically on {$cont[0]}")." -m ".escapeshellarg("Autostart has been automatically disabled on {$cont[0]} due to a security issue with container on network type host and tailscale integration enabled. You should either switch the network type or disabled tailscale integration on this container")." -i 'alert' -l '/Docker'"); continue; } } From ca7b71b9f88f3f2dee214bf14217231de0dc2526 Mon Sep 17 00:00:00 2001 From: Squidly271 Date: Tue, 25 Feb 2025 15:22:16 -0500 Subject: [PATCH 23/30] Backport Last container wouldn't autostart --- emhttp/plugins/dynamix.docker.manager/scripts/docker_init | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/emhttp/plugins/dynamix.docker.manager/scripts/docker_init b/emhttp/plugins/dynamix.docker.manager/scripts/docker_init index e970744caf..bc010031d7 100755 --- a/emhttp/plugins/dynamix.docker.manager/scripts/docker_init +++ b/emhttp/plugins/dynamix.docker.manager/scripts/docker_init @@ -4,6 +4,7 @@ $autostart = @file("/var/lib/docker/unraid-autostart",FILE_IGNORE_NEW_LINES); if ( ! $autostart ) exit(); +$flag = false; $newAuto = []; foreach ($autostart as $container) { if (! trim($container) ) continue; @@ -24,10 +25,12 @@ foreach ($autostart as $container) { exec("logger ".escapeshellarg("Autostart disabled on {$cont[0]} due to tailscale integration with host network.")); exec("logger ".escapeshellarg("This is a security risk due to the possibility of unauthenticated access to your server's GUI and resources")); exec("/usr/local/emhttp/plugins/dynamix/scripts/notify -e 'Autostart Disabled' -s 'Autostart Disabled' -d ".escapeshellarg("Autostart disabled automatically on {$cont[0]}")." -m ".escapeshellarg("Autostart has been automatically disabled on {$cont[0]} due to a security issue with container on network type host and tailscale integration enabled. You should either switch the network type or disabled tailscale integration on this container")." -i 'alert' -l '/Docker'"); + $flag = true; continue; } } $newAuto[] = $container; } -file_put_contents("/var/lib/docker/unraid-autostart",implode("\n",$newAuto)); +if ( $flag ) + file_put_contents("/var/lib/docker/unraid-autostart",implode("\n",$newAuto."\n"); ?> From b5d4705d02bb4f5a58e7a39d55c4b8aef645914b Mon Sep 17 00:00:00 2001 From: Squidly271 Date: Tue, 25 Feb 2025 15:31:34 -0500 Subject: [PATCH 24/30] Update docker_init --- emhttp/plugins/dynamix.docker.manager/scripts/docker_init | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/emhttp/plugins/dynamix.docker.manager/scripts/docker_init b/emhttp/plugins/dynamix.docker.manager/scripts/docker_init index bc010031d7..8431d2a254 100755 --- a/emhttp/plugins/dynamix.docker.manager/scripts/docker_init +++ b/emhttp/plugins/dynamix.docker.manager/scripts/docker_init @@ -32,5 +32,5 @@ foreach ($autostart as $container) { $newAuto[] = $container; } if ( $flag ) - file_put_contents("/var/lib/docker/unraid-autostart",implode("\n",$newAuto."\n"); + file_put_contents("/var/lib/docker/unraid-autostart",implode("\n",$newAuto)."\n"); ?> From 1b6447b6757d42e70b5da74f64bda7a4176ee6b8 Mon Sep 17 00:00:00 2001 From: ljm42 Date: Mon, 3 Mar 2025 12:42:30 -0700 Subject: [PATCH 25/30] Wireguard: increase size of DNS field Allow both ipv4 and ipv6 addresses --- emhttp/plugins/dynamix/WG0.page | 4 ++-- emhttp/plugins/dynamix/WGX.page | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/emhttp/plugins/dynamix/WG0.page b/emhttp/plugins/dynamix/WG0.page index addd0942ec..71a31743fa 100644 --- a/emhttp/plugins/dynamix/WG0.page +++ b/emhttp/plugins/dynamix/WG0.page @@ -1415,7 +1415,7 @@ _(Peer allowed IPs)_: :wg_peer_allowed_ips_help: _(Peer DNS server)_: -: " onchange="quickValidate(this);" pattern="" title="_(Comma separated list of IPv4 and IPv6 IP addresses)_" > +: " onchange="quickValidate(this);" pattern="" title="_(Comma separated list of IPv4 and IPv6 IP addresses)_" > :wg_peer_dns_server_help: @@ -1509,7 +1509,7 @@ _(Peer allowed IPs)_: :wg_peer_allowed_ips_help: _(Peer DNS server)_: -: +: :wg_peer_dns_server_help: diff --git a/emhttp/plugins/dynamix/WGX.page b/emhttp/plugins/dynamix/WGX.page index cfea1fa52c..a8f5a98d0e 100644 --- a/emhttp/plugins/dynamix/WGX.page +++ b/emhttp/plugins/dynamix/WGX.page @@ -359,7 +359,7 @@ _(Peer allowed IPs)_: :wg_peer_allowed_ips_help: _(Peer DNS server)_: -: " onchange="quickValidate(this);" pattern="" title="_(Comma separated list of IPv4 and IPv6 IP addresses)_"> +: " onchange="quickValidate(this);" pattern="" title="_(Comma separated list of IPv4 and IPv6 IP addresses)_"> :wg_peer_dns_server_help: @@ -451,7 +451,7 @@ _(Peer allowed IPs)_: :wg_peer_allowed_ips_help: _(Peer DNS server)_: -: +: :wg_peer_dns_server_help: From d43f84fcdac7eede71eec608a68de2628cd8f10b Mon Sep 17 00:00:00 2001 From: Squidly271 Date: Wed, 12 Mar 2025 20:06:07 -0400 Subject: [PATCH 26/30] Backport Fix: Disallow HTML within plugin attributes --- emhttp/plugins/dynamix.plugin.manager/scripts/plugin | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/emhttp/plugins/dynamix.plugin.manager/scripts/plugin b/emhttp/plugins/dynamix.plugin.manager/scripts/plugin index 3f1bc9272f..9475180032 100755 --- a/emhttp/plugins/dynamix.plugin.manager/scripts/plugin +++ b/emhttp/plugins/dynamix.plugin.manager/scripts/plugin @@ -1,6 +1,6 @@ #!/usr/bin/php -q From 83499a1e22be0193d746570a5fc14330a04635e5 Mon Sep 17 00:00:00 2001 From: Squidly271 Date: Tue, 18 Mar 2025 13:17:16 -0400 Subject: [PATCH 27/30] Refactor: Backport Remove Unraid.Patch page --- emhttp/plugins/dynamix/unraidPatch.page | 29 ------------------------- 1 file changed, 29 deletions(-) delete mode 100644 emhttp/plugins/dynamix/unraidPatch.page diff --git a/emhttp/plugins/dynamix/unraidPatch.page b/emhttp/plugins/dynamix/unraidPatch.page deleted file mode 100644 index d0734c8209..0000000000 --- a/emhttp/plugins/dynamix/unraidPatch.page +++ /dev/null @@ -1,29 +0,0 @@ -Menu="About" -Title="Unraid Patch" ---- - - - -
_(Click **Install** to download and install the **Unraid Patch** plugin)_
- -
- - -  -: -
From 558d5f9d2c435f8f49fa7943ba38eb93226a0a66 Mon Sep 17 00:00:00 2001 From: ljm42 Date: Fri, 18 Apr 2025 09:01:25 -0700 Subject: [PATCH 28/30] Backport: fix: remove unraid-api.txt from diags Backport #2158 to 7.0 --- emhttp/plugins/dynamix/scripts/diagnostics | 6 ------ 1 file changed, 6 deletions(-) diff --git a/emhttp/plugins/dynamix/scripts/diagnostics b/emhttp/plugins/dynamix/scripts/diagnostics index fd728b59f8..2932719f11 100755 --- a/emhttp/plugins/dynamix/scripts/diagnostics +++ b/emhttp/plugins/dynamix/scripts/diagnostics @@ -706,12 +706,6 @@ if (file_exists($wgquick)) { run("todos <$wgquick >".escapeshellarg($log)); } -// generate unraid-api.txt -if (file_exists("/usr/local/sbin/unraid-api")) { - $log = "/$diag/system/unraid-api.txt"; - run("unraid-api report | todos >".escapeshellarg($log)); -} - // generate testparm.txt $testparm = run("testparm -s 2>/dev/null"); if (!$all) From ce36d8c0a57cb3db2157fe84fc332279738f64c3 Mon Sep 17 00:00:00 2001 From: ljm42 Date: Fri, 18 Apr 2025 11:34:38 -0700 Subject: [PATCH 29/30] Backport: fix: diagnostics: anonymize IPv6 addresses in lsof.txt Backport part of #2070 to 7.0 --- emhttp/plugins/dynamix/scripts/diagnostics | 3 +++ 1 file changed, 3 insertions(+) diff --git a/emhttp/plugins/dynamix/scripts/diagnostics b/emhttp/plugins/dynamix/scripts/diagnostics index fd728b59f8..32bc0aac40 100755 --- a/emhttp/plugins/dynamix/scripts/diagnostics +++ b/emhttp/plugins/dynamix/scripts/diagnostics @@ -450,6 +450,9 @@ run("dmidecode -qt0 2>/dev/null|todos >>".escapeshellarg("/$diag/system/motherbo run("cat /proc/meminfo 2>/dev/null|todos >".escapeshellarg("/$diag/system/meminfo.txt")); run("dmidecode --type 17 2>/dev/null|todos >>".escapeshellarg("/$diag/system/meminfo.txt")); +// mask IP addresses in lsof.txt +maskIP("/$diag/system/lsof.txt"); + // create ethernet information information (suppress errors) foreach ($ports as $port) { run("ethtool ".escapeshellarg($port)." 2>/dev/null|todos >>".escapeshellarg("/$diag/system/ethtool.txt")); From 6a2169ec7f9adf717679b3f31b637416239af459 Mon Sep 17 00:00:00 2001 From: ljm42 Date: Sat, 31 May 2025 10:21:25 -0700 Subject: [PATCH 30/30] Backport to 7.0: fix for encryption passphrase sometimes incorrect --- emhttp/plugins/dynamix/ArrayOperation.page | 32 ++++++---- emhttp/plugins/dynamix/DiskSettings.page | 31 +++++++--- emhttp/plugins/dynamix/include/Helpers.php | 21 ++++--- emhttp/plugins/dynamix/include/KeyUpload.php | 18 ++---- emhttp/plugins/dynamix/include/Wrappers.php | 16 ++--- .../dynamix/include/update.encryption.php | 62 ++++++++++--------- emhttp/plugins/dynamix/nchan/device_list | 10 ++- 7 files changed, 108 insertions(+), 82 deletions(-) diff --git a/emhttp/plugins/dynamix/ArrayOperation.page b/emhttp/plugins/dynamix/ArrayOperation.page index fc633f83a7..f0a8bcfe26 100644 --- a/emhttp/plugins/dynamix/ArrayOperation.page +++ b/emhttp/plugins/dynamix/ArrayOperation.page @@ -17,27 +17,37 @@ Nchan="device_list,disk_load,parity_list" ?> 0; $poolsOnly = (_var($var,'SYS_ARRAY_SLOTS') == 0 ) ? true : false; /* only one of $present, $missing, or $wrong will be true, or all will be false */ -$forced = $present = $wrong = false; -foreach ($disks as $disk) { - if (strpos(_var($disk,'fsType'),'luks:')!==false || (_var($disk,'fsType')=='auto' && strpos(_var($var,'defaultFsType'),'luks:')!==false)) $forced = true; - if (_var($disk,'luksState',0)==1) $present = true; - if (_var($disk,'luksState',0)==2) $missing = true; - if (_var($disk,'luksState',0)==3) $wrong = true; +$forced = $present = $missing = $wrong = false; + +foreach (luks_filter($disks) as $disk) { + $fsType = _var($disk,'fsType'); + $luks = str_starts_with($fsType,'luks:'); + $auto = $fsType == 'auto'; + if ($luks || ($auto && str_starts_with(_var($var,'defaultFsType'),'luks:'))) $forced = true; + if ($luks || $auto) switch (_var($disk,'luksState',0)) { + case 1: $present = true; break; + case 2: $missing = true; break; + case 3: $wrong = true; break; + } } + $encrypt = $forced || $present || $missing || $wrong; if ($forced && ($present || $missing || $wrong)) $forced = false; function check_encryption() { global $forced, $missing, $wrong; - if ($forced) $status = _('Enter new key'); - elseif ($missing) $status = _('Missing key'); - elseif ($wrong) $status = _('Wrong key'); - else return; + if ($forced) + $status = _('Enter new key'); + elseif ($missing) + $status = _('Missing key'); + elseif ($wrong) + $status = _('Wrong key'); + else + return; echo "",_('Encryption status').":$statuspermit reformat"; echo "",_('Encryption input').":"; echo " diff --git a/emhttp/plugins/dynamix/include/Helpers.php b/emhttp/plugins/dynamix/include/Helpers.php index 68474afcfd..a985174c4d 100644 --- a/emhttp/plugins/dynamix/include/Helpers.php +++ b/emhttp/plugins/dynamix/include/Helpers.php @@ -1,6 +1,6 @@ 0) { mkdir($dirname, $permissions, $recursive); write_logging( "created dir:$dirname\n");} else chmod($zfsdataset,$permissions); @@ -396,8 +402,8 @@ function my_rmdir($dirname) { return($return); } function get_realvolume($path) { - if (strpos($path,"/mnt/user/",0) === 0) - $reallocation = trim(shell_exec("getfattr --absolute-names --only-values -n system.LOCATION ".escapeshellarg($path)." 2>/dev/null")); + if (strpos($path,"/mnt/user/",0) === 0) + $reallocation = trim(shell_exec("getfattr --absolute-names --only-values -n system.LOCATION ".escapeshellarg($path)." 2>/dev/null")); else { $realexplode = explode("/",str_replace("/mnt/","",$path)); $reallocation = $realexplode[0]; @@ -411,8 +417,7 @@ function write_logging($value) { file_put_contents('/tmp/my_mkdir_output', $value, FILE_APPEND); } -function device_exists($name) -{ +function device_exists($name) { global $disks,$devs; return (array_key_exists($name, $disks) && !str_contains(_var($disks[$name],'status'),'_NP')) || (array_key_exists($name, $devs)); } diff --git a/emhttp/plugins/dynamix/include/KeyUpload.php b/emhttp/plugins/dynamix/include/KeyUpload.php index 193af71f5b..dd2bce1cf9 100644 --- a/emhttp/plugins/dynamix/include/KeyUpload.php +++ b/emhttp/plugins/dynamix/include/KeyUpload.php @@ -1,6 +1,6 @@ diff --git a/emhttp/plugins/dynamix/include/Wrappers.php b/emhttp/plugins/dynamix/include/Wrappers.php index 37e4be2277..07e3ab0062 100644 --- a/emhttp/plugins/dynamix/include/Wrappers.php +++ b/emhttp/plugins/dynamix/include/Wrappers.php @@ -1,6 +1,6 @@ /dev/null | grep -Pom2 '^[wc]ctemp +: \K\d+'",$temp); - return [$temp[0]-273, $temp[1]-273]; + return count($temp) >= 2 ? [$temp[0]-273, $temp[1]-273] : [0, 0]; case 'cctemp': return exec("nvme id-ctrl /dev/$device 2>/dev/null | grep -Pom1 '^cctemp +: \K\d+'")-273; case 'wctemp': @@ -235,4 +234,7 @@ function check_network_connectivity(): bool { $out = http_get_contents($url); return ($out=="Microsoft NCSI"); } +function shieldarg(...$args) { + return implode(' ', array_map('escapeshellarg', $args)); +} ?> diff --git a/emhttp/plugins/dynamix/include/update.encryption.php b/emhttp/plugins/dynamix/include/update.encryption.php index 1bb9376469..eb49c36b6e 100644 --- a/emhttp/plugins/dynamix/include/update.encryption.php +++ b/emhttp/plugins/dynamix/include/update.encryption.php @@ -1,6 +1,6 @@ 1) exec("cryptsetup luksRemoveKey /dev/$disk $key &>/dev/null"); + if ($slots > 1) exec("cryptsetup luksRemoveKey ".shieldarg("/dev/$disk", $key)." &>/dev/null"); } + function diskname($name) { global $disks; - foreach ($disks as $disk) if (strncmp($name,$disk['device'],strlen($disk['device']))==0) return $disk['name']; + foreach ($disks as $disk) if (strncmp($name, $disk['device'], strlen($disk['device'])) == 0) return $disk['name']; return $name; } -function reply($text,$type) { - global $oldkey,$newkey,$delkey; + +function reply($text, $type) { + global $oldkey, $newkey; $reply = _var($_POST,'#reply'); - if (realpath(dirname($reply))=='/var/tmp') file_put_contents($reply,$text."\0".$type); + if (realpath(dirname($reply)) == '/var/tmp') file_put_contents($reply, $text."\0".$type); delete_file($oldkey); - if (_var($_POST,'newinput','text')=='text' || $delkey) delete_file($newkey); + if (_var($_POST,'newinput','text') == 'text') delete_file($newkey); die(); } if (isset($_POST['oldinput'])) { switch ($_POST['oldinput']) { case 'text': - file_put_contents($oldkey,base64_decode(_var($_POST,'oldluks'))); + file_put_contents($oldkey, base64_decode(_var($_POST,'oldluks'))); break; case 'file': - file_put_contents($oldkey,base64_decode(explode(';base64,',_var($_POST,'olddata','x;base64,'))[1])); + file_put_contents($oldkey, base64_decode(explode(';base64,',_var($_POST,'olddata','x;base64,'))[1])); break; } } else { - if (is_file($newkey)) copy($newkey,$oldkey); + if (is_file($newkey)) copy($newkey, $oldkey); } if (is_file($oldkey)) { $disk = $crypto[0]; // check first disk only (key is the same for all disks) - exec("cryptsetup luksOpen --test-passphrase --key-file $oldkey /dev/$disk &>/dev/null",$null,$error); + exec("cryptsetup luksOpen --test-passphrase --key-file ".shieldarg($oldkey, "/dev/$disk")." &>/dev/null", $null, $error); } else $error = 1; if ($error > 0) reply(_('Incorrect existing key'),'warning'); @@ -86,25 +88,25 @@ function reply($text,$type) { if (isset($_POST['newinput'])) { switch ($_POST['newinput']) { case 'text': - file_put_contents($newkey,base64_decode(_var($_POST,'newluks'))); + file_put_contents($newkey, base64_decode(_var($_POST,'newluks'))); $luks = 'luksKey'; - $data = _var($_POST,'newluks'); + $data = str_replace('+', '%2B', _var($_POST,'newluks')); break; case 'file': - file_put_contents($newkey,base64_decode(explode(';base64,',_var($_POST,'newdata','x;base64,'))[1])); + file_put_contents($newkey, base64_decode(explode(';base64,',_var($_POST,'newdata','x;base64,'))[1])); $luks = 'luksKey=&luksKeyfile'; $data = $newkey; break; } $good = $bad = []; foreach ($crypto as $disk) { - exec("cryptsetup luksAddKey --key-file $oldkey /dev/$disk $newkey &>/dev/null",$null,$error); - if ($error==0) $good[] = $disk; else $bad[] = diskname($disk); + exec("cryptsetup luksAddKey --key-file ".shieldarg($oldkey, "/dev/$disk", $newkey)." &>/dev/null", $null, $error); + if ($error == 0) $good[] = $disk; else $bad[] = diskname($disk); } - if (count($bad)==0) { + if (count($bad) == 0) { // all okay, remove the old key - foreach ($good as $disk) removeKey($oldkey,$disk); - exec("emcmd 'changeDisk=apply&$luks=$data'"); + foreach ($good as $disk) removeKey($oldkey, $disk); + exec("emcmd ".escapeshellarg("changeDisk=apply&$luks=$data")); reply(_('Key successfully changed'),'success'); } else { // something went wrong, restore key diff --git a/emhttp/plugins/dynamix/nchan/device_list b/emhttp/plugins/dynamix/nchan/device_list index e7b67feca3..4f221f9c8e 100755 --- a/emhttp/plugins/dynamix/nchan/device_list +++ b/emhttp/plugins/dynamix/nchan/device_list @@ -1,7 +1,7 @@ #!/usr/bin/php -q "._('Device to be encrypted').""; break; case 1: