diff --git a/emhttp/plugins/dynamix.docker.manager/include/DockerClient.php b/emhttp/plugins/dynamix.docker.manager/include/DockerClient.php
index 6e1b9403a..26e1a0b15 100644
--- a/emhttp/plugins/dynamix.docker.manager/include/DockerClient.php
+++ b/emhttp/plugins/dynamix.docker.manager/include/DockerClient.php
@@ -1,6 +1,6 @@
$docroot ??= ($_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp');
-require_once "$docroot/plugins/dynamix.docker.manager/include/Helpers.php";
require_once "$docroot/webGui/include/Wrappers.php";
+require_once "$docroot/plugins/dynamix.docker.manager/include/Helpers.php";
// add translations
if (_var($_SERVER,'REQUEST_URI')!='docker' && substr(_var($_SERVER,'REQUEST_URI'),0,7)!='/Docker') {
@@ -35,22 +35,10 @@ $dockerManPaths = [
'webui-info' => "$docroot/state/plugins/dynamix.docker.manager/docker.json"
];
-// load network variables if needed.
-$system = '/sys/class/net';
-$port = file_exists("$system/br0") ? 'br0' : (file_exists("$system/bond0") ? 'bond0' : 'eth0');
-$host = exec ("ip -br -4 addr show $port scope global | sed -r 's/\/[0-9]+//g' | awk '{print $3;exit}'");
-
-if (empty($host) && file_exists("$system/wlan0")) $host = exec ("ip -br -4 addr show wlan0 scope global | sed -r 's/\/[0-9]+//g' | awk '{print $3;exit}'");
-
-// get network drivers
-$driver = DockerUtil::driver();
-
-// determine active port name
-$port = file_exists('/sys/class/net/br0') ? 'BR0' : (file_exists('/sys/class/net/bond0') ? 'BOND0' : 'ETH0');
-
// Docker configuration file - guaranteed to exist
$docker_cfgfile = '/boot/config/docker.cfg';
if (file_exists($docker_cfgfile)) {
+ $port = strtoupper(DockerUtil::port());
exec("grep -Pom2 '_SUBNET_|_{$port}(_[0-9]+)?=' $docker_cfgfile",$cfg);
if (isset($cfg[0]) && $cfg[0]=='_SUBNET_' && empty($cfg[1])) {
# interface has changed, update configuration
@@ -279,9 +267,8 @@ class DockerTemplates {
}
private function getControlURL(&$ct, $myIP, $WebUI) {
- global $host;
$port = &$ct['Ports'][0];
- $myIP = $myIP ?: $this->getTemplateValue($ct['Image'],'MyIP') ?: (_var($ct,'NetworkMode')=='host'||_var($port,'NAT') ? $host : (_var($port,'IP') ?: DockerUtil::myIP($ct['Name'])));
+ $myIP = $myIP ?: $this->getTemplateValue($ct['Image'],'MyIP') ?: (_var($ct,'NetworkMode')=='host'||_var($port,'NAT') ? DockerUtils::host() : (_var($port,'IP') ?: DockerUtil::myIP($ct['Name'])));
// Get the WebUI address from the templates as a fallback
$WebUI = preg_replace("%\[IP\]%", $myIP, $WebUI ?? $this->getTemplateValue($ct['Image'], 'WebUI'));
if (preg_match("%\[PORT:(\d+)\]%", $WebUI, $matches)) {
@@ -305,9 +292,11 @@ class DockerTemplates {
}
public function getAllInfo($reload=false,$com=true,$communityApplications=false) {
- global $driver, $dockerManPaths, $host;
+ global $dockerManPaths;
$DockerClient = new DockerClient();
$DockerUpdate = new DockerUpdate();
+ $driver = DockerUtil::driver();
+ $host = DockerUtil::host();
//$DockerUpdate->verbose = $this->verbose;
$info = DockerUtil::loadJSON($dockerManPaths['webui-info']);
$autoStart = array_map('var_split', @file($dockerManPaths['autostart-file'],FILE_IGNORE_NEW_LINES) ?: []);
@@ -959,7 +948,8 @@ class DockerClient {
}
public function getDockerContainers() {
- global $driver, $host;
+ $driver = DockerUtil::driver();
+ $host = DockerUtil::host();
// Return cached values
if (is_array($this::$containersCache)) return $this::$containersCache;
$this::$containersCache = [];
@@ -1176,5 +1166,20 @@ class DockerUtil {
public static function ctMap($ct, $type='Name') {
return static::docker("inspect --format='{{.$type}}' $ct");
}
+
+ public static function port() {
+ if (lan_port('br0')) return 'br0';
+ if (lan_port('bond0')) return 'bond0';
+ if (lan_port('eth0')) return 'eth0';
+ if (lan_port('wlan0')) return 'wlan0';
+ return '';
+ }
+
+ public static function host() {
+ $port = static::port();
+ if (!$port) return '';
+ $port = lan_port($port,true)==0 && lan_port('wlan0') ? 'wlan0' : $port;
+ return exec("ip -br -4 addr show $port scope global | sed -r 's/\/[0-9]+//g' | awk '{print $3;exit}'");
+ }
}
?>
diff --git a/emhttp/plugins/dynamix.docker.manager/include/DockerContainers.php b/emhttp/plugins/dynamix.docker.manager/include/DockerContainers.php
index 3b12a9507..8cc1d6670 100644
--- a/emhttp/plugins/dynamix.docker.manager/include/DockerContainers.php
+++ b/emhttp/plugins/dynamix.docker.manager/include/DockerContainers.php
@@ -1,6 +1,6 @@
$docroot ??= ($_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp');
-require_once "$docroot/webGui/include/Helpers.php";
require_once "$docroot/plugins/dynamix.docker.manager/include/DockerClient.php";
+require_once "$docroot/webGui/include/Helpers.php";
// add translations
$_SERVER['REQUEST_URI'] = 'docker';
@@ -40,6 +40,9 @@ if (file_exists($user_prefs)) {
unset($sort);
}
+// get host interface IP address
+$host = DockerUtil::host();
+
// Read container info
$allInfo = $DockerTemplates->getAllInfo();
$docker = [];
@@ -144,23 +147,25 @@ foreach ($containers as $ct) {
$ports_internal = [];
$ports_external = [];
if (isset($ct['Ports']['vlan'])) {
- foreach ($ct['Ports']['vlan'] as $i)
+ foreach ($ct['Ports']['vlan'] as $i) {
$ports_external[] = sprintf('%s', $i);
+ }
$ports_internal[0] = sprintf('%s', 'all');
}
foreach($ct['Networks'] as $netName => $netVals) {
$networks[] = $netName;
$network_ips[] = $running ? $netVals['IPAddress'] : null;
-
if (isset($ct['Networks']['host'])) {
$ports_external[] = sprintf('%s', $netVals['IPAddress']);
$ports_internal[0] = sprintf('%s', 'all');
- } else if (!isset($ct['Ports']['vlan']) || strpos($ct['NetworkMode'], 'container:') != 0) {
+ } elseif (!isset($ct['Ports']['vlan']) || strpos($ct['NetworkMode'],'container:')!==false) {
foreach ($ct['Ports'] as $port) {
- if (_var($port,'PublicPort') && _var($port,'Driver') == 'bridge')
+ if (_var($port,'PublicPort') && _var($port,'Driver') == 'bridge') {
$ports_external[] = sprintf('%s:%s', $host, strtoupper(_var($port,'PublicPort')));
- if ((!isset($ct['Networks']['host'])) || (!isset($ct['Networks']['vlan'])))
+ }
+ if ((!isset($ct['Networks']['host'])) || (!isset($ct['Networks']['vlan']))) {
$ports_internal[] = sprintf('%s:%s', _var($port,'PrivatePort'), strtoupper(_var($port,'Type')));
+ }
}
}
}
@@ -246,7 +251,7 @@ foreach ($containers as $ct) {
if (!empty($TS_version)) {
if (!empty($TS_latest_version)) {
if (version_compare($TS_version, $TS_latest_version, '<')) {
- $TSinfo .= "
"._("Tailscale:")."v" . $TS_version . " ➔ v" . $TS_latest_version . " "._("available!")."
";
+ $TSinfo .= ""._("Tailscale:")."v".$TS_version." ➔ v".$TS_latest_version." "._("available!")."
";
} else {
$TSinfo .= ""._("Tailscale").":v".$TS_version."
";
}
diff --git a/emhttp/plugins/dynamix.docker.manager/include/Helpers.php b/emhttp/plugins/dynamix.docker.manager/include/Helpers.php
index 28dab85c6..706790bee 100644
--- a/emhttp/plugins/dynamix.docker.manager/include/Helpers.php
+++ b/emhttp/plugins/dynamix.docker.manager/include/Helpers.php
@@ -1,6 +1,6 @@
getDockerContainers() as $ct) {
$list = $port = [];
diff --git a/emhttp/plugins/dynamix/include/Wrappers.php b/emhttp/plugins/dynamix/include/Wrappers.php
index 37e4be227..36e5c4d63 100644
--- a/emhttp/plugins/dynamix/include/Wrappers.php
+++ b/emhttp/plugins/dynamix/include/Wrappers.php
@@ -1,6 +1,6 @@
=')) return $remote;
}
}
+
function _var(&$name, $key=null, $default='') {
return is_null($key) ? ($name ?? $default) : ($name[$key] ?? $default);
}
+
function celsius($temp) {
return round(($temp-32)*5/9);
}
+
function fahrenheit($temp) {
return round(9/5*$temp)+32;
}
+
function displayTemp($temp) {
global $display;
return (is_numeric($temp) && _var($display,'unit')=='F') ? fahrenheit($temp) : $temp;
}
+
function get_value(&$name, $key, $default) {
global $var;
$value = $name[$key] ?? -1;
return $value!==-1 ? $value : ($var[$key] ?? $default);
}
+
function get_ctlr_options(&$type, &$disk) {
if (!$type) return;
$ports = [];
@@ -106,12 +119,15 @@ function get_ctlr_options(&$type, &$disk) {
if (isset($disk['smPort3'])) $ports[] = $disk['smPort3'];
$type .= ($ports ? ','.implode($disk['smGlue'] ?? ',',$ports) : '');
}
+
function port_name($port) {
return substr($port,-2)!='n1' ? $port : substr($port,0,-2);
}
+
function exceed($value, $limit, $top=100) {
return is_numeric($value) && $limit>0 ? ($value>$limit && $value<=$top) : false;
}
+
function ipaddr($ethX='eth0', $prot=4) {
global $$ethX;
switch (_var($$ethX,'PROTOCOL:0')) {
@@ -128,16 +144,20 @@ function ipaddr($ethX='eth0', $prot=4) {
return _var($$ethX,'IPADDR:0');
}
}
+
function no_tilde($name) {
global $_tilde_ ,$_proxy_;
return str_replace($_tilde_,$_proxy_,$name);
}
+
function prefix($key) {
return preg_replace('/\d+$/','',$key);
}
+
function pool_name($key) {
return preg_replace('/(\d+$|~.*$)/', '', $key);
}
+
function native($name, $full=0) {
global $_tilde_, $_arrow_;
switch ($full) {
@@ -145,11 +165,13 @@ function native($name, $full=0) {
case 1: return strpos($name,$_tilde_)!==false ? "$_arrow_ ".explode($_tilde_,$name)[1] : $name;
}
}
+
function isSubpool($name) {
global $subpools, $_tilde_;
$subpool = my_explode($_tilde_,$name)[1];
return in_array($subpool,$subpools) ? $subpool : false;
}
+
function get_nvme_info($device, $info) {
switch ($info) {
case 'temp':
@@ -167,15 +189,18 @@ function get_nvme_info($device, $info) {
return exec("smartctl -c /dev/$device 2>/dev/null | grep -Pom1 '^ *$state [+-] +\K[^W]+'");
}
}
+
// convert strftime to date format
function my_date($fmt, $time) {
$legacy = ['%c' => 'D j M Y h:i A','%A' => 'l','%Y' => 'Y','%B' => 'F','%e' => 'j','%d' => 'd','%m' => 'm','%I' => 'h','%H' => 'H','%M' => 'i','%S' => 's','%p' => 'a','%R' => 'H:i', '%F' => 'Y-m-d', '%T' => 'H:i:s'];
return date(strtr($fmt,$legacy), $time);
}
+
// ensure params passed to logger are properly escaped
function my_logger($message, $logger='webgui') {
exec('logger -t '.escapeshellarg($logger).' -- '.escapeshellarg($message));
}
+
// Original PHP code by Chirp Internet: www.chirpinternet.eu
// Please acknowledge use of this code by including this header.
// https://www.the-art-of-web.com/php/http-get-contents/
@@ -226,6 +251,7 @@ function http_get_contents(string $url, array $opts = [], array &$getinfo = NULL
curl_close($ch);
return $out;
}
+
/**
* Detect network connectivity via Network Connectivity Status Indicator
* @return bool
@@ -235,4 +261,10 @@ function check_network_connectivity(): bool {
$out = http_get_contents($url);
return ($out=="Microsoft NCSI");
}
+
+function lan_port($port, $state=false) {
+ $system = '/sys/class/net';
+ $exist = file_exists("$system/$port");
+ return !$state ? $exist : ($exist ? file_get_contents("$system/$port/carrier") : false);
+}
?>
diff --git a/sbin/create_network_ini b/sbin/create_network_ini
index fb5a1bd55..645aa1a37 100755
--- a/sbin/create_network_ini
+++ b/sbin/create_network_ini
@@ -2,8 +2,8 @@
#
# script: create_network_ini
#
-# Copyright 2005-2023, Lime Technology
-# Copyright 2012-2023, Bergware International.
+# Copyright 2005-2025, Lime Technology
+# Copyright 2012-2025, Bergware International.
#
# create initial network.ini file on system start
# create system welcome message
@@ -241,15 +241,15 @@ if [[ -z $interface || "eth0 br0 bond0 wlan0" =~ $interface ]]; then
# find management interface
[[ -e /sys/class/net/bond0 ]] && dev=bond0 || dev=eth0
[[ -e /sys/class/net/br0 ]] && dev=br0
- IPv4=$(ip -br -4 addr show $dev scope global | sed -r 's/metric [0-9]+//g; s/\/[0-9]+//g' | awk '{print $3;exit}')
- IPv6=$(ip -br -6 addr show $dev scope global -temporary -deprecated | sed -r 's/metric [0-9]+//g; s/\/[0-9]+//g' | awk '{print $3;exit}')
+ IPv4=$(ip -br -4 addr show $dev scope global | sed -r 's/\/[0-9]+//g' | awk '{print $3;exit}')
+ IPv6=$(ip -br -6 addr show $dev scope global -temporary -deprecated | sed -r 's/\/[0-9]+//g' | awk '{print $3;exit}')
# show current IP assignment
[[ -n $IPv4 ]] && echo " IPv4 address: $IPv4" >>/etc/issue || echo " IPv4 address: not set" >>/etc/issue
[[ -n $IPv6 ]] && echo " IPv6 address: $IPv6" >>/etc/issue || echo " IPv6 address: not set" >>/etc/issue
if [[ -e /sys/class/net/wlan0 ]]; then
echo "Wireless network:" >>/etc/issue
- IPv4=$(ip -br -4 addr show wlan0 scope global | sed -r 's/metric [0-9]+//g; s/\/[0-9]+//g' | awk '{print $3;exit}')
- IPv6=$(ip -br -6 addr show wlan0 scope global -temporary -deprecated | sed -r 's/metric [0-9]+//g; s/\/[0-9]+//g' | awk '{print $3;exit}')
+ IPv4=$(ip -br -4 addr show wlan0 scope global | sed -r 's/\/[0-9]+//g' | awk '{print $3;exit}')
+ IPv6=$(ip -br -6 addr show wlan0 scope global -temporary -deprecated | sed -r 's/\/[0-9]+//g' | awk '{print $3;exit}')
[[ -n $IPv4 ]] && echo " IPv4 address: $IPv4" >>/etc/issue || echo " IPv4 address: not set" >>/etc/issue
[[ -n $IPv6 ]] && echo " IPv6 address: $IPv6" >>/etc/issue || echo " IPv6 address: not set" >>/etc/issue
fi