From 05899b36a5762530f45bd1098dcbf79a86d4f6f0 Mon Sep 17 00:00:00 2001 From: bergware Date: Thu, 8 May 2025 15:57:46 +0200 Subject: [PATCH 01/54] Network: improved automatic metric assignment --- emhttp/plugins/dynamix/Eth0.page | 28 +++++++++++++--------------- emhttp/plugins/dynamix/EthX.page | 12 ++++++------ 2 files changed, 19 insertions(+), 21 deletions(-) diff --git a/emhttp/plugins/dynamix/Eth0.page b/emhttp/plugins/dynamix/Eth0.page index 7b4858ea9..680f9fbd7 100644 --- a/emhttp/plugins/dynamix/Eth0.page +++ b/emhttp/plugins/dynamix/Eth0.page @@ -55,15 +55,13 @@ function index($key) { return filter_var($key, FILTER_SANITIZE_NUMBER_INT); } -function metric($eth, $prot, $index) { +function metric($eth) { $system = '/sys/class/net'; - $bridge = str_replace('eth','br', $eth); - $bond = str_replace('eth','bond', $eth); + $bridge = str_replace('eth', 'br', $eth); + $bond = str_replace('eth', 'bond', $eth); $port = file_exists("$system/$bridge") ? $bridge : (file_exists("$system/$bond") ? $bond : $eth); - $metric = exec("ip -$prot route show default dev $port 2>/dev/null | grep -Pom1 ' metric \K\d+'"); - if ($metric) return $metric + $index; - exec("ip -$prot route show default 2>/dev/null | grep -Po ' metric \K\d+'",$metrics); - return (count($metrics) ? max($metrics) : 0) + $index + 1; + $index = exec("cat $system/$port/ifindex 2>/dev/null"); + return 1000 + ($index ?: exec("cat $system/*/ifindex | sort -n | tail -1") + 1); } // remove non-existing ethernet ports @@ -476,9 +474,9 @@ function addVLAN(port) { } function removeVLAN(element) { - var id = $(element).prop('id').split('-'); + var form = $(element).closest('form'); $(element).remove(); - $('#view-'+id[1]).find('select').first().trigger('change'); + form.find('select').first().trigger('change'); } function showVLAN(port) { @@ -729,7 +727,7 @@ _(IPv4 address)_: _(IPv4 default gateway)_: : " class="narrow" pattern="" title="_(IPv4 address A.B.C.D)_"> - " class="slim"> ** + " class="slim"> ** :eth_ipv4_default_gateway_help: @@ -752,7 +750,7 @@ _(IPv6 address)_: _(IPv6 default gateway)_: : " pattern="" title="_(IPv6 address nnnn:xxxx::yyyy)_"> - " class="slim"> ** + " class="slim"> ** :eth_ipv6_default_gateway_help: @@ -830,7 +828,7 @@ _(IPv4 address)_:
_(IPv4 default gateway)_: : " class="narrow" pattern="" title="_(IPv4 address A.B.C.D)_"> - ',4,$i)?>" class="slim"> ** + " class="slim"> ** :eth_ipv4_default_gateway_help: @@ -859,7 +857,7 @@ _(IPv6 address)_:
_(IPv6 default gateway)_: : " pattern="" title="_(IPv6 address nnnn:xxxx::yyyy)_"> - ',6,$i)?>" class="slim"> ** + " class="slim"> ** :eth_ipv6_default_gateway_help: @@ -921,7 +919,7 @@ _(IPv4 address)_:
_(IPv4 default gateway)_: : - ** + **
@@ -942,7 +940,7 @@ _(IPv6 address)_:
_(IPv6 default gateway)_: : - ** + **
diff --git a/emhttp/plugins/dynamix/EthX.page b/emhttp/plugins/dynamix/EthX.page index be1713f3b..27d369ebe 100644 --- a/emhttp/plugins/dynamix/EthX.page +++ b/emhttp/plugins/dynamix/EthX.page @@ -186,7 +186,7 @@ _(IPv4 address)_:
_(IPv4 default gateway)_: : " class="narrow" pattern="" title="_(IPv4 address A.B.C.D)_"> - " class="slim"> ** + " class="slim"> ** :eth_ipv4_default_gateway_help: @@ -213,7 +213,7 @@ _(IPv6 address)_:
_(IPv6 default gateway)_: : " pattern="" title="_(IPv6 address nnnn:xxxx::yyyy)_"> - " class="slim"> ** + " class="slim"> ** :eth_ipv6_default_gateway_help: @@ -293,7 +293,7 @@ _(IPv4 address)_:
_(IPv4 default gateway)_: : " class="narrow" pattern="" title="_(IPv4 address A.B.C.D)_"> - ',4,$i)?>" class="slim"> ** + " class="slim"> ** :eth_ipv4_default_gateway_help: @@ -320,7 +320,7 @@ _(IPv6 address)_:
_(IPv6 default gateway)_: : " pattern="" title="_(IPv6 address nnnn:xxxx::yyyy)_"> - ',6,$i)?>" class="slim"> ** + " class="slim"> ** :eth_ipv6_default_gateway_help: @@ -383,7 +383,7 @@ _(IPv4 address)_:
_(IPv4 default gateway)_: : - ** + **
@@ -404,7 +404,7 @@ _(IPv6 address)_:
_(IPv6 default gateway)_: : - ** + **
From b52defdbda9e0f98219888ffa1dec80840aa29e8 Mon Sep 17 00:00:00 2001 From: bergware Date: Thu, 8 May 2025 15:58:16 +0200 Subject: [PATCH 02/54] Network: updated routing table --- emhttp/plugins/dynamix/include/RoutingTable.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/emhttp/plugins/dynamix/include/RoutingTable.php b/emhttp/plugins/dynamix/include/RoutingTable.php index 2bfa73efb..1741cbc99 100644 --- a/emhttp/plugins/dynamix/include/RoutingTable.php +++ b/emhttp/plugins/dynamix/include/RoutingTable.php @@ -26,8 +26,8 @@ case 'Add Route': if ($gateway && $route) exec("/etc/rc.d/rc.inet1 ".escapeshellarg("{$gateway}_{$route}_{$metric}_add")); break; default: - exec("ip -4 route show table all|grep -Pv '^(127\\.0\\.0\\.0)|table local|unreachable'",$ipv4); - exec("ip -6 route show table all|grep -Pv '^([am:]|(f[ef][0-9][0-9])::)|table local|unreachable'",$ipv6); + exec("ip -4 route show table all | grep -Pv '^(127\\.0\\.0\\.0)|table local|unreachable|linkdown|broadcast'",$ipv4); + exec("ip -6 route show table all | grep -Pv '^([am:]|(f[ef][0-9][0-9])::)|table local|unreachable|linkdown'",$ipv6); foreach ($ipv4 as $info) { $cell = explode(' ',$info); $route = $cell[0]; From 582cefbfc144b18dbe698fc49b4ae315ac27be7f Mon Sep 17 00:00:00 2001 From: bergware Date: Thu, 8 May 2025 15:59:10 +0200 Subject: [PATCH 03/54] Services: move sleep to upper layer to improve accuracy --- emhttp/plugins/dynamix/scripts/reload_services | 3 --- emhttp/plugins/dynamix/scripts/update_services | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/emhttp/plugins/dynamix/scripts/reload_services b/emhttp/plugins/dynamix/scripts/reload_services index a1fe713cb..babe9c7c1 100755 --- a/emhttp/plugins/dynamix/scripts/reload_services +++ b/emhttp/plugins/dynamix/scripts/reload_services @@ -8,9 +8,6 @@ queue(){ atq | grep -Pom1 '^\d+' } -# delayed execution -sleep ${1:-1} - JOB=$(queue) if [[ -n $JOB ]]; then atrm $JOB 2>/dev/null diff --git a/emhttp/plugins/dynamix/scripts/update_services b/emhttp/plugins/dynamix/scripts/update_services index a89950733..4fbebbb2a 100755 --- a/emhttp/plugins/dynamix/scripts/update_services +++ b/emhttp/plugins/dynamix/scripts/update_services @@ -15,6 +15,6 @@ else log "no queued job present" fi -echo "/usr/local/emhttp/webGui/scripts/reload_services ${1:-1}" | at -M now 2>/dev/null +echo "sleep ${1:-1}; /usr/local/emhttp/webGui/scripts/reload_services" | at -M now 2>/dev/null log "queue new job $(queue), wait for ${1:-1}s" exit 0 From cb42fcf436a4037f67429a9e85b559ffcfef26c3 Mon Sep 17 00:00:00 2001 From: bergware Date: Thu, 8 May 2025 16:00:40 +0200 Subject: [PATCH 04/54] Docker: allow host access on wireless interface --- etc/rc.d/rc.docker | 73 ++++++++++++++++++++++++---------------------- 1 file changed, 38 insertions(+), 35 deletions(-) diff --git a/etc/rc.d/rc.docker b/etc/rc.d/rc.docker index 6a9719d35..954e61d63 100755 --- a/etc/rc.d/rc.docker +++ b/etc/rc.d/rc.docker @@ -10,7 +10,7 @@ # VMs, bare metal, OpenStack clusters, public clouds and more. # # LimeTech - modified for Unraid OS -# Bergware - modified for Unraid OS, January 2025 +# Bergware - modified for Unraid OS, May 2025 DAEMON="Docker daemon" UNSHARE="/usr/bin/unshare" @@ -35,6 +35,11 @@ TMP=/var/tmp/network.tmp # run & log functions . /etc/rc.d/rc.runlog +# return interface index +index(){ + cat $SYSTEM/$1/ifindex 2>/dev/null +} + # wait for interface to go up carrier(){ local n e @@ -213,9 +218,9 @@ container_add_route(){ local NET=${CT[1]#*[} local LAN=${NET%:*} if [[ $PID -gt 0 && "eth0 br0 bond0 wlan0" =~ $LAN ]]; then - local THISIP=$(ip -4 -br addr show dev $LAN scope global | awk '{print $3;exit}') + local THISIP=$(ip -4 -br addr show scope global primary dev $LAN | awk '{print $3;exit}') for CFG in /etc/wireguard/wg*.cfg ; do - local NETWORK=$(ip -4 show route dev $LAN $THISIP | awk '{print $1;exit}') + local NETWORK=$(ip -4 show route $THISIP dev $LAN | awk '{print $1;exit}') [[ -n $NETWORK ]] && nsenter -n -t $PID ip -4 route add $NETWORK via ${THISIP%/*} dev $LAN 2>/dev/null done fi @@ -341,7 +346,7 @@ docker_network_start(){ fi # add auto defined networks SUBNET=; GATEWAY=; SERVER=; RANGE=; - [[ -z ${!AUTO} || ${!AUTO} =~ "4" ]] && IPV4=$(ip -4 -br addr show $NETWORK scope global | awk '{print $3;exit}') || IPV4= + [[ -z ${!AUTO} || ${!AUTO} =~ "4" ]] && IPV4=$(ip -4 -br addr show scope global primary dev $NETWORK | awk '{print $3;exit}') || IPV4= if [[ -n $IPV4 ]]; then SUBNET=$(ip -4 route show $IPV4 dev $NETWORK | awk '{print $1;exit}') SERVER=${IPV4%/*} @@ -351,7 +356,7 @@ docker_network_start(){ GATEWAY=$(ip -4 route show default dev $NETWORK | awk '{print $3;exit}') fi SUBNET6=; GATEWAY6=; SERVER6=; - [[ -z ${!AUTO} || ${!AUTO} =~ "6" ]] && IPV6=$(ip -6 -br addr show $NETWORK scope global -temporary -deprecated | awk '{print $3;exit}') || IPV6= + [[ -z ${!AUTO} || ${!AUTO} =~ "6" ]] && IPV6=$(ip -6 -br addr show scope global primary -deprecated dev $NETWORK | awk '{print $3;exit}') || IPV6= if [[ -n $IPV6 ]]; then # get IPV6 subnet, preset to /64 if single host address is given [[ ${IPV6#*/} == 128 ]] && SUBNET6=$(echo $IPV6 | sed -r 's/^([^:]+):([^:]+):([^:]+):([^:]+).*$/\1:\2:\3:\4::\/64/') || SUBNET6=$(ip -6 route show $IPV6 dev $NETWORK | awk '{print $1;exit}') @@ -448,48 +453,44 @@ docker_network_start(){ # hack to let containers talk to host if [[ $TYPE == br ]]; then LINK=shim-$NETWORK - GW=($(ip -4 route show default dev $NETWORK | awk '{print $3,$5;exit}')) if [[ $DOCKER_ALLOW_ACCESS == yes && -n $IPV4 ]]; then - # create shim interface and copy parent IPv4 address to shim interface + NET="$IPV4 metric $((1000 - 1 + $(index $NETWORK)))" + # create shim interface [[ -e $SYSTEM/$LINK ]] || run ip link add link $NETWORK name $LINK type $ATTACH mode $MODE - run ip addr flush dev $LINK scope global - run ip -4 addr add $IPV4 dev $LINK metric 0 # disable IPv6 on shim interface echo 1 >$CONF6/$LINK/disable_ipv6 + run ip -6 addr flush dev $LINK + # copy parent IPv4 address to shim interface + run ip addr add $NET dev $LINK run ip link set $LINK up - if [[ -n $GW ]]; then - if [[ -z ${GW[1]} ]]; then - METRIC=1 - METRICS=$(ip -4 route show default | grep -Po 'metric \K\d+') - while [[ " $METRICS " =~ " $METRIC " ]]; do ((METRIC++)); done - # update existing route to avoid conflict with shim route - run ip -4 route del default via $GW dev $NETWORK - run ip -4 route add default via $GW dev $NETWORK metric $METRIC - fi - run ip -4 route add default via $GW dev $LINK metric 0 - fi log "created network $LINK for host access" elif [[ -e $SYSTEM/$LINK ]]; then # remove shim interface - [[ -n $GW ]] && ip -4 route del default via $GW dev $LINK run ip addr flush dev $LINK run ip link set $LINK down run ip link del $LINK fi - elif [[ $TYPE != wlan ]]; then + else + if [[ $TYPE == wlan ]]; then + VHOST=shim-$NETWORK + INDEX=3000 + else + VHOST=vhost${NETWORK//[^0-9.]/} + INDEX=1000 + fi + INDEX=$(($INDEX - 1 + $(index $NETWORK))) if [[ $DOCKER_ALLOW_ACCESS == yes && -n $IPV4 ]]; then - run ip addr flush dev $VHOST scope global - # copy IPv4 address to vhost interface - run ip -4 addr add $IPV4 dev $VHOST metric 0 + # disable IPv6 on vhost interface + echo 1 >$CONF6/$VHOST/disable_ipv6 + run ip -6 addr flush dev $VHOST + # copy parent IPv4 address to vhost interface + IPS="$(ip -4 -br addr show scope global dev $VHOST | awk '{$1="";$2="";print;exit}' | sed -r 's/ metric [0-9]+//g')" + [[ ! $IPS =~ $IPV4 ]] && run ip addr add $IPV4 metric $INDEX dev $VHOST log "prepared network $VHOST for host access" else - VHOST=vhost${NETWORK//[^0-9.]/} if [[ -e $SYSTEM/$VHOST ]]; then - # remove IP addresses of vhost - run ip addr flush dev $VHOST scope global - # remove routing of vhost - run ip -4 route flush dev $VHOST - run ip -6 route flush dev $VHOST + # remove parent IPv4 address from vhost interface + run ip addr del $IPV4 metric $INDEX dev $VHOST fi fi fi @@ -516,23 +517,25 @@ docker_network_stop(){ fi driver ${NIC//[0-9]/} for NETWORK in $(network $ATTACH ${NIC//[^0-9]/}); do - [[ $STOCK =~ ${NETWORK%%[0-9]*} || $DOCKER_USER_NETWORKS != preserve ]] && docker network rm $NETWORK >/dev/null + [[ $STOCK =~ ${NETWORK%%[0-9]*} || $DOCKER_USER_NETWORKS != preserve ]] && docker network rm $NETWORK &>/dev/null TYPE=${NETWORK//[0-9.]/} if [[ $TYPE == br ]]; then LINK=shim-$NETWORK if [[ -e $SYSTEM/$LINK ]]; then - GW=$(ip -4 route show default dev $LINK | awk '{print $3;exit}') - [[ -n $GW ]] && run ip -4 route del default via $GW dev $LINK run ip addr flush dev $LINK run ip link set $LINK down run ip link del $LINK fi - else + elif [[ $TYPE != wlan ]]; then VHOST=vhost${NETWORK//[^0-9.]/} [[ -e $SYSTEM/$VHOST ]] && run ip addr flush dev $VHOST fi done done + if [[ -e $SYSTEM/shim-wlan0 ]]; then + NET=$(ip -4 -br addr show scope global primary dev shim-wlan0 | awk '{print $3,$4,$5;exit}') + [[ -n $NET ]] && run ip addr del $NET dev shim-wlan0 + fi log "Network stopped." } From a4bcc9e3b0c78f9dd6d4fcdcc8a157b0e31c9e42 Mon Sep 17 00:00:00 2001 From: bergware Date: Thu, 8 May 2025 16:01:37 +0200 Subject: [PATCH 05/54] Network: improved ip selection for interface --- etc/rc.d/rc.inet1 | 84 ++++++++++++++++++++++---------------- etc/rc.d/rc.library.source | 8 ++-- etc/rc.d/rc.nginx | 10 ++--- etc/rc.d/rc.wireless | 45 +++++++++++++------- 4 files changed, 87 insertions(+), 60 deletions(-) diff --git a/etc/rc.d/rc.inet1 b/etc/rc.d/rc.inet1 index 6670cbbfc..d20fa8485 100755 --- a/etc/rc.d/rc.inet1 +++ b/etc/rc.d/rc.inet1 @@ -7,7 +7,7 @@ # @(#)/etc/rc.d/rc.inet1 10.2 Sun Jul 24 12:45:56 PDT 2005 (pjv) # LimeTech - modified for Unraid OS -# Bergware - modified for Unraid OS, February 2025 +# Bergware - modified for Unraid OS, May 2025 # Adapted by Bergware for use in Unraid OS - April 2016 # - improved interface configuration @@ -81,6 +81,9 @@ # - added metric value to interface IP assignment # - fixed DNS entries get removed when configuring interface other then eth0 +# Adapted by Bergware for use in Unraid OS - May 2025 +# - improved metric value to interface IP assignment + ########### # LOGGING # ########### @@ -122,7 +125,7 @@ done # LOOPBACK FUNCTIONS # ###################### -# function to bring up loopback interface +# bring up loopback interface lo_up(){ if [[ -e $SYSTEM/lo ]]; then if ! ip -4 addr show lo | grep -qw 'inet'; then @@ -137,7 +140,7 @@ lo_up(){ fi } -# function to take down loopback interface +# take down loopback interface lo_down(){ if [[ -e $SYSTEM/lo ]]; then run ip link set lo down @@ -150,12 +153,17 @@ lo_down(){ # INTERFACE FUNCTIONS # ####################### -# function to get link mtu size +# return interface index +index(){ + cat $SYSTEM/$1/ifindex 2>/dev/null +} + +# get link mtu size get_mtu(){ ip link show $1 | grep -Po 'mtu \K\d+' } -# function to set/reset link mtu size +# set/reset link mtu size set_mtu(){ if [[ -n ${MTU[$i]} ]]; then # set MTU to specified value @@ -166,8 +174,8 @@ set_mtu(){ fi } -# function to wait for carrier of interface -carrier_up(){ +# wait for carrier of interface +carrier(){ local n for n in {1..10}; do [[ $(cat $SYSTEM/$1/carrier 2>/dev/null) == 1 ]] && return 0 || sleep 1 @@ -175,7 +183,7 @@ carrier_up(){ return 1 } -# function to create bond interface +# create bond interface bond_up(){ [[ -d /proc/net/bonding ]] || modprobe bonding mode=${BONDING_MODE[$i]} miimon=${BONDING_MIIMON[$i]} run ip link add name ${BONDNAME[$i]} type bond mode ${BONDING_MODE[$i]} miimon ${BONDING_MIIMON[$i]} @@ -194,7 +202,7 @@ bond_up(){ [[ -n $PRIMARY ]] && run ip link set name ${BONDNAME[$i]} type bond primary $PRIMARY } -# function to delete bond interface +# delete bond interface bond_down(){ if [[ -e $SYSTEM/${BONDNAME[$i]} ]]; then # loop thru attached interfaces in bond @@ -208,7 +216,7 @@ bond_down(){ fi } -# function to create bridge interface +# create bridge interface br_up(){ for ((j=0;j<${VLANS[$i]:-1};j++)); do [[ $j -eq 0 ]] && BRIDGE=${BRNAME[$i]} || BRIDGE=${BRNAME[$i]}.${VLANID[$i,$j]} @@ -235,7 +243,7 @@ br_up(){ done } -# function to delete bridge interface +# delete bridge interface br_down(){ for ((j=0;j<${VLANS[$i]:-1};j++)); do # loop thru main bridge and bridge VLAN interfaces @@ -253,7 +261,7 @@ br_down(){ done } -# function to create VLAN interfaces +# create VLAN interfaces vlan_up(){ for PORT in ${BRNICS[$i]:-${IFNAME[$i]}}; do for ((j=1;j<${VLANS[$i]};j++)); do @@ -265,7 +273,7 @@ vlan_up(){ done } -# function to delete VLAN interfaces +# delete VLAN interfaces vlan_down(){ for PORT in ${BRNICS[$i]:-${IFNAME[$i]}}; do for VLAN in $(ls --indicator-style=none $SYSTEM | grep -Po "$PORT\.\d+"); do @@ -275,7 +283,7 @@ vlan_down(){ done } -# function to create macvtap interfaces +# create macvtap interfaces macvtap_up(){ PARENT=${IFNAME[$i]} [[ -n ${BONDNICS[$i]} ]] && PARENT=${BONDNAME[$i]} @@ -283,16 +291,18 @@ macvtap_up(){ MAC=$(echo $(hostname)-$VTAP | md5sum | sed -r 's/^(..)(..)(..)(..)(..).*$/02:\1:\2:\3:\4:\5/') run ip link add link $PARENT name $VTAP address $MAC type macvtap mode bridge set_mtu $VTAP + echo 1 >$CONF6/$VTAP/disable_ipv6 run ip link set $VTAP up for ((j=1;j<${VLANS[$i]:-0};j++)); do VLAN=${VLANID[$i,$j]} run ip link add link $PARENT.$VLAN name $VTAP.$VLAN address $MAC type macvtap mode bridge set_mtu $VTAP.$VLAN + echo 1 >$CONF6/$VTAP.$VLAN/disable_ipv6 run ip link set $VTAP.$VLAN up done } -# function to delete macvtap interfaces +# delete macvtap interfaces macvtap_down(){ PARENT=${IFNAME[$i]} [[ -n ${BONDNICS[$i]} ]] && PARENT=${BONDNAME[$i]} @@ -308,26 +318,26 @@ macvtap_down(){ run ip link del $VTAP } -# function to enable/disable ipv6 protocol per interface +# enable/disable ipv6 protocol per interface ipv6_up(){ [[ -d $CONF6/${IFACE/$1/$2} ]] && echo $4 >$CONF6/${IFACE/$1/$2}/disable_ipv6 [[ -d $CONF6/${IFACE/$1/$3} ]] && echo $4 >$CONF6/${IFACE/$1/$3}/disable_ipv6 } -# function to enable/disable ipv6 assignment per interface +# enable/disable ipv6 assignment per interface ipv6_ra(){ echo $2 >$CONF6/$1/accept_ra echo $2 >$CONF6/$1/accept_ra_defrtr echo $3 >$CONF6/$1/autoconf } -# function to enable/disable ipv6 assignment per interface +# enable/disable ipv6 assignment per interface ipv6_conf(){ [[ -d $CONF6/${IFACE/$1/$2} ]] && ipv6_ra ${IFACE/$1/$2} $4 $5 [[ -d $CONF6/${IFACE/$1/$3} ]] && ipv6_ra ${IFACE/$1/$3} $4 $5 } -# function to enable/disable ipv6 assignment per interface +# enable/disable ipv6 assignment per interface ipv6_addr(){ [[ -d $CONF6/$IFACE ]] && ipv6_ra $IFACE $1 $2 [[ -d $CONF6/$VHOST ]] && ipv6_ra $VHOST $1 $2 @@ -342,7 +352,7 @@ ipv6_addr(){ sleep 1 } -# function to assign IP address +# assign IP address ipaddr_up(){ if [[ -z $RENEW ]]; then # disable IPv6 per interface when IPv4 only @@ -371,7 +381,7 @@ ipaddr_up(){ [[ $IP == ipv4 ]] && DHCP_OPTIONS="$DHCP_OPTIONS -4" [[ $IP == ipv6 ]] && DHCP_OPTIONS="$DHCP_OPTIONS -6" [[ $IP != ipv4 && -n $PRIV6 && -d $CONF6/$IFACE ]] && echo $PRIV6 >$CONF6/$IFACE/use_tempaddr - if carrier_up $IFACE; then + if carrier $IFACE; then # interface is UP log "interface $IFACE is UP, polling up to 60 sec for DHCP $IP server" if ! run timeout 60 dhcpcd -w $DHCP_OPTIONS $IFACE; then @@ -385,21 +395,23 @@ ipaddr_up(){ fi elif [[ $DHCP == no ]]; then # bring up interface using static IP address - if carrier_up $IFACE; then STATE="UP"; else STATE="DOWN"; fi + if carrier $IFACE; then STATE="UP"; else STATE="DOWN"; fi log "interface $IFACE is $STATE, setting static $IP address" ipv6_addr 0 1 + INDEX=$(index $IFACE) + INDEX=$((1000 + ${INDEX:-$(($(index * | sort -n | tail -1) + 1))})) if [[ $IP != ipv6 ]]; then [[ $j -eq 0 ]] && ADDR=${IPADDR[$i]} || ADDR=${IPADDR[$i,$j]} if [[ -n $ADDR ]]; then [[ $j -eq 0 ]] && MASK=${NETMASK[$i]} || MASK=${NETMASK[$i,$j]} - [[ -n $MASK ]] && run ip -4 addr add $(unzero $ADDR)/$MASK dev $IFACE metric ${DHCP_METRIC:-1} + [[ -n $MASK ]] && run ip -4 addr add $(unzero $ADDR)/$MASK metric $INDEX dev $IFACE fi fi if [[ $IP != ipv4 ]]; then [[ $j -eq 0 ]] && ADDR6=${IPADDR6[$i]} || ADDR6=${IPADDR6[$i,$j]} if [[ -n $ADDR6 ]]; then [[ $j -eq 0 ]] && MASK6=${NETMASK6[$i]} || MASK6=${NETMASK6[$i,$j]} - [[ -n $MASK6 ]] && run ip -6 addr add $(unzero6 $ADDR6)/$MASK6 dev $IFACE metric ${DHCP_METRIC:-1} + [[ -n $MASK6 ]] && run ip -6 addr add $(unzero6 $ADDR6)/$MASK6 metric $INDEX dev $IFACE [[ -n $PRIV6 && -d $CONF6/$IFACE ]] && echo 0 >$CONF6/$IFACE/use_tempaddr fi fi @@ -410,7 +422,7 @@ ipaddr_up(){ fi } -# function to release IP addresses and routes +# release IP addresses and routes ipaddr_conf(){ if [[ -e $SYSTEM/${IFACE/$1/$2} ]]; then run ip -$4 addr flush dev ${IFACE/$1/$2} @@ -422,7 +434,7 @@ ipaddr_conf(){ fi } -# function to release IP addresses and routes +# release IP addresses and routes ipaddr_flush(){ run ip -$1 addr flush dev $IFACE run ip -$1 route flush dev $IFACE @@ -436,7 +448,7 @@ ipaddr_flush(){ fi } -# function to release IP addresses and routes +# release IP addresses and routes ipaddr_down(){ if [[ $DHCP == yes ]]; then DHCP_OPTIONS="-q -k" @@ -453,7 +465,7 @@ ipaddr_down(){ fi } -# function to bring up network interface +# bring up network interface if_up(){ # set index of INTERFACE in array i=0 @@ -555,7 +567,7 @@ if_up(){ done } -# function to take down network interface +# take down network interface if_down(){ # set index of INTERFACE in array i=0 @@ -612,7 +624,7 @@ if_down(){ # GATEWAY FUNCTIONS # ##################### -# function to add default gateway per interface +# add default gateway per interface gateway_up(){ for GW in ${GATEWAY[@]}; do [[ -z $GW ]] && continue @@ -640,7 +652,7 @@ gateway_up(){ done } -# function to delete default gateway per interface +# delete default gateway per interface gateway_down(){ for GW in ${GATEWAY[@]}; do [[ -z $GW ]] && continue @@ -664,7 +676,7 @@ gateway_down(){ done } -# function to start network +# start network start(){ lo_up for INTERFACE in ${IFNAME[@]}; do @@ -673,7 +685,7 @@ start(){ gateway_up } -# function to stop network +# stop network stop(){ gateway_down for INTERFACE in ${IFNAME[@]}; do @@ -682,7 +694,7 @@ stop(){ lo_down } -# function to show network status +# show network status status(){ echo "INTERFACE STATE INFORMATION" echo "========================================================================" @@ -693,7 +705,7 @@ status(){ # STATIC ROUTE FUNCTIONS # ########################## -# function to add static route +# add static route route_up(){ [[ -n $3 ]] && METRIC="metric $3" || METRIC= if [[ $2 == default ]]; then @@ -711,7 +723,7 @@ route_up(){ fi } -# function to delete static route +# delete static route route_down(){ [[ -n $3 ]] && METRIC="metric $3" || METRIC= if [[ $2 == default ]]; then diff --git a/etc/rc.d/rc.library.source b/etc/rc.d/rc.library.source index 99861be3b..fb5f5f9d0 100644 --- a/etc/rc.d/rc.library.source +++ b/etc/rc.d/rc.library.source @@ -5,7 +5,7 @@ # Library used by nfsd, ntpd, rpc, samba, nginx, sshd, avahidaemon, show_interfaces # # Bergware - created for Unraid OS, December 2023 -# Bergware - updated January 2025 +# Bergware - updated May 2025 WIREGUARD="/etc/wireguard" NETWORK_INI="/var/local/emhttp/network.ini" @@ -56,8 +56,8 @@ good(){ show(){ case $# in - 1) ip -br addr show scope global -temporary -deprecated to $1 2>/dev/null | awk '{gsub("@.+","",$1);print $1;exit}' ;; - 2) ip -br addr show scope global -temporary -deprecated $1 $2 2>/dev/null | awk '{$1=$2="";print;exit}' | sed -r 's/ metric [0-9]+//g' ;; + 1) ip -br addr show scope global primary -deprecated to $1 2>/dev/null | awk '{gsub("@.+","",$1);print $1;exit}' ;; + 2) ip -br addr show scope global primary -deprecated $1 $2 2>/dev/null | awk '{$1=$2="";print;exit}' | sed -r 's/ metric [0-9]+//g' ;; esac } @@ -160,7 +160,7 @@ check(){ fi [[ $(ipv $ADDR) == 4 ]] && IPV4=yes || IPV6=yes done - done <<< $(ip -br addr show scope global -temporary -deprecated | awk '$1~"^(br|bond|eth|wlan|wg)[0-9]+(.[0-9]+)?" && $3!="" {gsub("@.+","",$1);$2="";print}' | sed -r 's/ metric [0-9]+//g' | sort) + done <<< $(ip -br addr show scope global primary -deprecated | awk '$1~"^(br|bond|eth|wlan|wg)[0-9]+(.[0-9]+)?" && $3!="" {gsub("@.+","",$1);$2="";print}' | sed -r 's/ metric [0-9]+//g' | sort) # add loopback interface if [[ "smb nfs" =~ "$CALLER" ]]; then [[ $IPV4 == yes ]] && BIND+=(127.0.0.1) diff --git a/etc/rc.d/rc.nginx b/etc/rc.d/rc.nginx index 0f903a569..cf8e46adf 100755 --- a/etc/rc.d/rc.nginx +++ b/etc/rc.d/rc.nginx @@ -6,7 +6,7 @@ # Written for Slackware Linux by Cherife Li . # LimeTech - modified for Unraid OS -# Bergware - modified for Unraid OS, October 2023 +# Bergware - modified for Unraid OS, May 2025 # reference: # LANNAME 'tower' @@ -537,12 +537,12 @@ build_ssl(){ # fetch LAN IP address (read management interface eth0) [[ -e $SYSTEM/bond0 ]] && DEV=bond0 || DEV=eth0 [[ -e $SYSTEM/br0 ]] && DEV=br0 - LANIP=$(ip -4 -br addr show $DEV scope global | sed -r 's/\/[0-9]+//g' | awk '{print $3;exit}') - LANIP6=$(ip -6 -br addr show $DEV scope global -temporary -deprecated | sed -r 's/\/[0-9]+//g' | awk '{print $3;exit}') + LANIP=$(ip -4 -br addr show scope global primary dev $DEV | awk '{print $3;exit}' | sed -r 's/\/[0-9]+//') + LANIP6=$(ip -6 -br addr show scope global primary -deprecated dev $DEV | awk '{print $3;exit}' | sed -r 's/\/[0-9]+//') # try wireless connection if no IP address on interface eth0 - [[ -z $LANIP && -e $SYSTEM/wlan0 ]] && LANIP=$(ip -4 -br addr show wlan0 scope global | sed -r 's/\/[0-9]+//g' | awk '{print $3;exit}') - [[ -z $LANIP6 && -e $SYSTEM/wlan0 ]] && LANIP6=$(ip -6 -br addr show wlan0 scope global -temporary -deprecated | sed -r 's/\/[0-9]+//g' | awk '{print $3;exit}') + [[ -z $LANIP && -e $SYSTEM/wlan0 ]] && LANIP=$(ip -4 -br addr show scope global primary dev wlan0 | awk '{print $3;exit}' | sed -r 's/\/[0-9]+//') + [[ -z $LANIP6 && -e $SYSTEM/wlan0 ]] && LANIP6=$(ip -6 -br addr show scope global primary -deprecated dev wlan0 | awk '{print $3;exit}' | sed -r 's/\/[0-9]+//') # regenerate self-signed cert if local TLD changes */ SELFCERTPATH=$SSL/certs/${LANNAME}_unraid_bundle.pem diff --git a/etc/rc.d/rc.wireless b/etc/rc.d/rc.wireless index c2f419784..531ed7c91 100755 --- a/etc/rc.d/rc.wireless +++ b/etc/rc.d/rc.wireless @@ -12,6 +12,7 @@ INI="/var/local/emhttp/wireless.ini" CFG="/boot/config/wireless.cfg" OPENSSL="/usr/local/emhttp/webGui/scripts/open_ssl" STARTWIFI="/usr/local/emhttp/webGui/scripts/wireless" +SERVICES="/usr/local/emhttp/webGui/scripts/update_services" WPA="/etc/wpa_supplicant.conf" # system network references @@ -28,6 +29,11 @@ CONF6="/proc/sys/net/ipv6/conf" [[ -r $INI ]] && . $INI PORT=${PORT:-wlan0} +# return interface index +index(){ + cat $SYSTEM/$1/ifindex 2>/dev/null +} + # translate security to informational text trans(){ case "$1" in @@ -126,13 +132,15 @@ ipaddr_up(){ if carrier $PORT; then STATE="UP"; else STATE="DOWN"; fi log "interface $PORT is $STATE, setting static $IP address" ipv6_addr $PORT 0 1 + INDEX=$(index $PORT) + INDEX=$((3000 + ${INDEX:-$(($(index * | sort -n | tail -1) + 1))})) if [[ $IP == ipv4 ]]; then - [[ -n $IP4 && -n $MASK4 ]] && run ip -4 addr add $(unzero $IP4)/$MASK4 dev $PORT metric 3004 - [[ -n $GATEWAY4 ]] && run ip -4 route add default via $GATEWAY4 dev $PORT metric 3004 + [[ -n $IP4 && -n $MASK4 ]] && run ip -4 addr add $(unzero $IP4)/$MASK4 metric $INDEX dev $PORT + [[ -n $GATEWAY4 ]] && run ip -4 route add default via $GATEWAY4 metric $INDEX dev $PORT fi if [[ $IP == ipv6 ]]; then - [[ -n $IP6 && -n $MASK6 ]] && run ip -6 addr add $(unzero6 $IP6)/$MASK6 dev $PORT metric 3004 - [[ -n $GATEWAY6 ]] && run ip -6 route add default via $GATEWAY6 dev $PORT metric 3004 + [[ -n $IP6 && -n $MASK6 ]] && run ip -6 addr add $(unzero6 $IP6)/$MASK6 metric $INDEX dev $PORT + [[ -n $GATEWAY6 ]] && run ip -6 route add default via $GATEWAY6 metric $INDEX dev $PORT fi fi if [[ $DNS == yes ]]; then @@ -148,17 +156,13 @@ ipaddr_up(){ ipaddr_down(){ if [[ $DHCP == yes ]]; then # release DHCP assigned address and default route - OPTIONS="-q -k" + OPTIONS="-q -k -$1" [[ $DNS == yes ]] && OPTIONS="$OPTIONS -C resolv.conf" - [[ $IP == ipv4 ]] && OPTIONS="$OPTIONS -4" - [[ $IP == ipv6 ]] && OPTIONS="$OPTIONS -6" run dhcpcd $OPTIONS $PORT elif [[ $DHCP == no ]]; then # release static assigned address and default route - [[ $IP == ipv4 ]] && run ip -4 addr flush dev $PORT - [[ $IP == ipv4 ]] && run ip -4 route flush default dev $PORT - [[ $IP == ipv6 ]] && run ip -6 addr flush dev $PORT - [[ $IP == ipv6 ]] && run ip -6 route flush default dev $PORT + run ip -$1 addr flush dev $PORT + run ip -$1 route flush default dev $PORT fi } @@ -253,19 +257,25 @@ wifi_stop(){ log "$DAEMON... No Wifi present." return fi - IP=ipv4 + IPV4=$(ip -4 -br addr show scope global primary dev $PORT | awk '{print $3;exit}') + INDEX=$((3000 - 1 + $(index $PORT))) DHCP=$DHCP4 DNS=$DNS4 - ipaddr_down + SRV4=$DNS + SRV6= + ipaddr_down 4 if [[ -n $DHCP6 ]]; then - IP=ipv6 DHCP=$DHCP6 DNS=$DNS6 - ipaddr_down + SRV6=$DNS + ipaddr_down 6 fi + run ip addr del $IPV4 metric $INDEX dev $PORT run pkill wpa_supplicant run iw dev $PORT disconnect run rm -f $INI + # restart services when static assignments + [[ $SRV4 == no && (-z $SRV6 || $SRV6 == no) ]] && $SERVICE 5 if ! wifi_running; then REPLY="Stopped"; else REPLY="Failed"; fi log "$DAEMON... $REPLY." } @@ -309,6 +319,8 @@ wifi_join(){ IP=ipv4 DHCP=$DHCP4 DNS=$DNS4 + SRV4=$DNS + SRV6= ipaddr_up # IPv6 address assignment (if enabled) if [[ -n $DHCP6 ]]; then @@ -316,10 +328,13 @@ wifi_join(){ IP=ipv6 DHCP=$DHCP6 DNS=$DNS6 + SRV6=$DNS ipaddr_up else echo 1 >$CONF6/$PORT/disable_ipv6 fi + # restart services when static assignments + [[ $SRV4 == no && (-z $SRV6 || $SRV6 == no) ]] && $SERVICE 5 if wifi_running; then if [[ -z $CC ]]; then CC=($(iw reg get | grep -Po '^country \K..')) From f90db2d0ac5f96ee17ac80cd40149fd1ac477944 Mon Sep 17 00:00:00 2001 From: bergware Date: Thu, 8 May 2025 16:02:09 +0200 Subject: [PATCH 06/54] Network: monitor interfaces with static IP assignment --- sbin/create_network_ini | 105 ++++++++++++++++++++++++++++++---------- sbin/monitor_interface | 70 +++++++++++++++++++++++++++ 2 files changed, 149 insertions(+), 26 deletions(-) create mode 100644 sbin/monitor_interface diff --git a/sbin/create_network_ini b/sbin/create_network_ini index afe6c39e1..b9e70fb0f 100755 --- a/sbin/create_network_ini +++ b/sbin/create_network_ini @@ -14,22 +14,41 @@ [[ (-z $reason && -z $1) || (-n $reason && ! "BOUND6 IPV4LL EXPIRE" =~ $reason) ]] && exit 0 INI=/var/local/emhttp/network.ini.new +STA=/var/local/emhttp/statics.ini.new CFG=/boot/config/network.cfg -SYS=/sys/class/net +DOCKER=/boot/config/docker.cfg +SYSTEM=/sys/class/net declare -A VLANID USE_DHCP IPADDR NETMASK GATEWAY METRIC USE_DHCP6 IPADDR6 NETMASK6 GATEWAY6 PRIVACY6 METRIC6 DESCRIPTION PROTOCOL # run & log functions . /etc/rc.d/rc.runlog -mask(){ - [[ -z $1 ]] && return - # convert prefix to netmask - set -- $((5-($1/8))) 255 255 255 255 $(((255<<(8-($1%8)))&255)) 0 0 0 - [[ $1 -gt 1 ]] && shift $1 || shift - echo $1.$2.$3.$4 +# return variable value from file +var(){ + [[ -r "$2" ]] && grep -Pom1 "^$1=\"\K[^\"]+" "$2" } +# return interface index +index(){ + cat $SYSTEM/$1/ifindex 2>/dev/null +} + +# convert netmask to prefix +mask2cidr(){ + [[ -z $1 ]] && return + local MASK=$(eval eval echo "'\$((('{"${1//./,}"}'>>'{7..0}')%2))'") + eval echo '$(('"${MASK// /+}"'))' +} + +# convert prefix to netmask +cidr2mask(){ + [[ -z $1 ]] && return + local MASK=$(eval echo '$(((1<<32)-1<<32-$1>>'{3..0}'*8&255))') + echo "${MASK// /.}" +} + +# return dns nameserver entry dns() { [[ $1 == 4 ]] && ADDR='(\d{1,3}\.){3}\d+' || ADDR='([0-9a-fA-F]{1,4}::?){1,7}[0-9a-fA-F]*' grep -Po "^nameserver \K$ADDR" /etc/resolv.conf @@ -48,8 +67,10 @@ else BONDING=yes BRIDGING=yes fi + # prepare empty file echo -n >$INI +echo -n >$STA # loop thru all defined interfaces (=1 in case of legacy) for ((i=0; i<${SYSNICS:-1}; i++)); do @@ -57,7 +78,7 @@ for ((i=0; i<${SYSNICS:-1}; i++)); do ETH=${IFACE/#bond/eth} ETH=${ETH/#br/eth} # don't store when non-existing - [[ -e $SYS/$ETH ]] || continue + [[ -e $SYSTEM/$ETH ]] || continue echo "[$ETH]" >>$INI if [[ $i -eq 0 ]]; then # process legacy settings @@ -125,12 +146,13 @@ for ((i=0; i<${SYSNICS:-1}; i++)); do echo "PROTOCOL:0=\"${PROTOCOL[$i]}\"" >>$INI echo "USE_DHCP:0=\"${USE_DHCP[$i]}\"" >>$INI echo "USE_GW4:0=\"${USE_GW4[$i]}\"" >>$INI + DATA= if [[ ${USE_DHCP[$i]} == yes ]]; then # get dhcp assigned ipv4 address & mask - NET=($(ip -4 -br addr show $IFACE | awk '{sub("/"," ",$3);print $3;exit}')) + NET=($(ip -4 -br addr show scope global primary dev $IFACE | awk '{sub("/"," ",$3);print $3;exit}')) GW=$(ip -4 route show default dev $IFACE | awk '{print $3;exit}') echo "IPADDR:0=\"${NET[0]}\"" >>$INI - echo "NETMASK:0=\"$(mask ${NET[1]})\"" >>$INI + echo "NETMASK:0=\"$(cidr2mask ${NET[1]})\"" >>$INI echo "GATEWAY:0=\"$GW\"" >>$INI echo "METRIC:0=\"${METRIC[$i]}\"" >>$INI else @@ -139,12 +161,14 @@ for ((i=0; i<${SYSNICS:-1}; i++)); do echo "NETMASK:0=\"${NETMASK[$i]}\"" >>$INI echo "GATEWAY:0=\"${GATEWAY[$i]}\"" >>$INI echo "METRIC:0=\"${METRIC[$i]}\"" >>$INI + # store static ipv4 assignment + [[ -n ${IPADDR[$i]} ]] && DATA="$IFACE ${IPADDR[$i]}/$(mask2cidr ${NETMASK[$i]}) ${METRIC[$i]:-0}" fi echo "USE_DHCP6:0=\"${USE_DHCP6[$i]}\"" >>$INI echo "USE_GW6:0=\"${USE_GW6[$i]}\"" >>$INI if [[ ${USE_DHCP6[$i]} == yes ]]; then # get auto assigned ipv6 address & prefix - NET6=($(ip -6 -br addr show $IFACE scope global -temporary -deprecated | awk '{sub("/"," ",$3);print $3;exit}')) + NET6=($(ip -6 -br addr show scope global primary -deprecated dev $IFACE | awk '{sub("/"," ",$3);print $3;exit}')) GW6=$(ip -6 route show default dev $IFACE | awk '{print $3;exit}') echo "IPADDR6:0=\"${NET6[0]}\"" >>$INI echo "NETMASK6:0=\"${NET6[1]}\"" >>$INI @@ -158,7 +182,10 @@ for ((i=0; i<${SYSNICS:-1}; i++)); do echo "GATEWAY6:0=\"${GATEWAY6[$i]}\"" >>$INI echo "METRIC6:0=\"${METRIC6[$i]}\"" >>$INI echo "PRIVACY6:0=\"\"" >>$INI + # store static ipv4 assignment + [[ -n ${IPADDR6[$i]} ]] && DATA="${DATA:-$IFACE} ${IPADDR6[$i]}/${NETMASK6[$i]} ${METRIC6[$i]:-0}" fi + [[ -n $DATA ]] && echo "$DATA" >>$STA echo "USE_MTU=\"${USE_MTU[$i]}\"" >>$INI echo "MTU=\"${MTU[$i]}\"" >>$INI if [[ -n ${VLANS[$i]} ]]; then @@ -170,13 +197,14 @@ for ((i=0; i<${SYSNICS:-1}; i++)); do echo "PROTOCOL:$j=\"${PROTOCOL[$i,$j]}\"" >>$INI echo "USE_DHCP:$j=\"${USE_DHCP[$i,$j]}\"" >>$INI echo "USE_GW4:$j=\"${USE_GW4[$i,$j]}\"" >>$INI + DATA= if [[ ${USE_DHCP[$i,$j]} == yes ]]; then DEV=$IFACE.${VLANID[$i,$j]} - # get dhcp assigned ipv4 address & mask - NET=($(ip -4 -br addr show $DEV | awk '{sub("/"," ",$3);print $3;exit}')) + # get dhcp assigned ipv4 address & cidr2mask + NET=($(ip -4 -br addr show scope global primary dev $DEV | awk '{sub("/"," ",$3);print $3;exit}')) GW=$(ip -4 route show default dev $DEV | awk '{print $3;exit}') echo "IPADDR:$j=\"${NET[0]}\"" >>$INI - echo "NETMASK:$j=\"$(mask ${NET[1]})\"" >>$INI + echo "NETMASK:$j=\"$(cidr2mask ${NET[1]})\"" >>$INI echo "GATEWAY:$j=\"$GW\"" >>$INI echo "METRIC:$j=\"${METRIC[$i,$j]}\"" >>$INI else @@ -185,13 +213,15 @@ for ((i=0; i<${SYSNICS:-1}; i++)); do echo "NETMASK:$j=\"${NETMASK[$i,$j]}\"" >>$INI echo "GATEWAY:$j=\"${GATEWAY[$i,$j]}\"" >>$INI echo "METRIC:$j=\"${METRIC[$i,$j]}\"" >>$INI + # store static ipv6 assignment + [[ -n ${IPADDR[$i,$j]} ]] && DATA="$DEV ${IPADDR[$i,$j]}/$(mask2cidr ${NETMASK[$i,$j]}) ${METRIC[$i,$j]:-0}" fi echo "USE_DHCP6:$j=\"${USE_DHCP6[$i,$j]}\"" >>$INI echo "USE_GW6:$j=\"${USE_GW6[$i,$j]}\"" >>$INI if [[ ${USE_DHCP6[$i,$j]} == yes ]]; then DEV=$IFACE.${VLANID[$i,$j]} # get auto assigned ipv6 address & prefix - NET6=($(ip -6 -br addr show $DEV scope global -temporary -deprecated | awk '{sub("/"," ",$3);print $3;exit}')) + NET6=($(ip -6 -br addr show scope global primary -deprecated dev $DEV | awk '{sub("/"," ",$3);print $3;exit}')) GW6=$(ip -6 route show default dev $DEV | awk '{print $3;exit}') echo "IPADDR6:$j=\"${NET6[0]}\"" >>$INI echo "NETMASK6:$j=\"${NET6[1]}\"" >>$INI @@ -205,7 +235,11 @@ for ((i=0; i<${SYSNICS:-1}; i++)); do echo "GATEWAY6:$j=\"${GATEWAY6[$i,$j]}\"" >>$INI echo "METRIC6:$j=\"${METRIC6[$i,$j]}\"" >>$INI echo "PRIVACY6:$j=\"\"" >>$INI + # store static ipv6 assignment + [[ -n ${IPADDR6[$i,$j]} ]] && DATA="${DATA:-$DEV} ${IPADDR6[$i,$j]}/${NETMASK6[$i,$j]} ${METRIC6[$i,$j]:-0}" fi + # static IP assignments handled by rc.monitor + [[ -n $DATA ]] && echo "$DATA" >>$STA done else # interface without VLANs @@ -214,6 +248,25 @@ for ((i=0; i<${SYSNICS:-1}; i++)); do done # atomically update file mv $INI ${INI%.*} +mv $STA ${STA%.*} + +# add or remove IPv4 assignment from attached interface when Docker custom network access is allowed +[[ ${interface:0:2} == br || $interface == wlan0 ]] && LINK=shim-$interface || LINK=vhost${interface//[^0-9.]/} +if [[ -e $SYSTEM/$LINK && $(var DOCKER_ALLOW_ACCESS $DOCKER) == yes ]]; then + IPV4=$(ip -4 -br addr show scope global primary dev $interface | awk '{print $3;exit}') + [[ $interface == wlan0 ]] && INDEX=3000 || INDEX=1000 + INDEX=$(($INDEX - 1 + $(index $interface))) + case $reason in + 'BOUND' | 'BOUND6') + # re-add IPv4 address of parent (if docker is running) + [[ -S /var/run/docker.sock ]] && ip addr add $IPV4 metric $INDEX dev $LINK + ;; + 'EXPIRE') + # remove IPv4 address of parent + ip addr del $IPV4 metric $INDEX dev $LINK + ;; + esac +fi log "interface=${interface:-$1}, reason=$reason, protocol=$protocol" # delayed execution @@ -224,19 +277,19 @@ if [[ -z $interface || "eth0 br0 bond0 wlan0" =~ $interface ]]; then . /etc/unraid-version echo -e "Unraid Server OS version: $version" >/etc/issue # find management interface - [[ -e $SYS/bond0 ]] && dev=bond0 || dev=eth0 - [[ -e $SYS/br0 ]] && dev=br0 - IPv4=$(ip -4 -br addr show $dev scope global | awk '{print $3;exit}' | sed -r 's/\/[0-9]+//') - IPv6=$(ip -6 -br addr show $dev scope global -temporary -deprecated | awk '{print $3;exit}' | sed -r 's/\/[0-9]+//') + [[ -e $SYSTEM/bond0 ]] && DEV=bond0 || DEV=eth0 + [[ -e $SYSTEM/br0 ]] && DEV=br0 + IPV4=$(ip -4 -br addr show scope global primary dev $DEV | awk '{print $3;exit}' | sed -r 's/\/[0-9]+//') + IPV6=$(ip -6 -br addr show scope global primary -deprecated dev $DEV | awk '{print $3;exit}' | sed -r 's/\/[0-9]+//') # 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/wlan0 ]]; then + [[ -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 $SYSTEM/wlan0 ]]; then echo "Wireless network:" >>/etc/issue - IPv4=$(ip -4 -br addr show wlan0 scope global | awk '{print $3;exit}' | sed -r 's/\/[0-9]+//') - IPv6=$(ip -6 -br addr show wlan0 scope global -temporary -deprecated | awk '{print $3;exit}' | sed -r 's/\/[0-9]+//') - [[ -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 + IPV4=$(ip -4 -br addr show scope global primary dev wlan0 | awk '{print $3;exit}' | sed -r 's/\/[0-9]+//') + IPV6=$(ip -6 -br addr show scope global primary -deprecated dev wlan0 | awk '{print $3;exit}' | sed -r 's/\/[0-9]+//') + [[ -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 echo >>/etc/issue fi diff --git a/sbin/monitor_interface b/sbin/monitor_interface new file mode 100644 index 000000000..041f02856 --- /dev/null +++ b/sbin/monitor_interface @@ -0,0 +1,70 @@ +#!/bin/bash +# +# script: monitor_interface +# +# Monitors a given list of interfaces and add or remove static IP addresses to these interfaces. +# The list of interfaces is provided in the file '/var/local/emhttp/statics.ini' +# This file is maintained by the script 'create_network_ini' which keep track of all IP assignments. +# +# By removing static IP addresses from inactive interfaces, these interfaces do not longer interfere with wireless. +# In other words the wired connection can be pulled without consequences. +# +# Bergware - modified for Unraid OS, May 2025 + +FILE=/var/local/emhttp/statics.ini +SYSTEM=/sys/class/net + +state(){ + cat $SYSTEM/$1/operstate 2>/dev/null +} + +md5(){ + [[ -r $FILE ]] && md5sum $FILE | awk '{print $1;exit}' +} + +switch(){ + local n + [[ -z $1 ]] && return 1 + # state change should stay stable for at least 5 seconds + for n in {1..5}; do + [[ $(state $1) == $2 ]] && return 1 || sleep 1 + done + return 0 +} + +init(){ + PORT=(); IPV4=(); METRIC4=(); IPV6=(); METRIC6=(); STATE=(); + if [[ -r $FILE ]]; then + # initialize values from file, maintained by 'create_network_ini' + while IFS=$'\n' read -r ROW; do + ROW=($ROW) + PORT+=(${ROW[0]}) + IPV4+=(${ROW[1]:--}) + METRIC4+=(${ROW[2]:--}) + IPV6+=(${ROW[3]:--}) + METRIC6+=(${ROW[4]:--}) + STATE+=($(state ${ROW[0]})) + done <$FILE + fi + MD5=$(md5) +} + +while :; do + # monitor file content changes + [[ $MD5 != $(md5) ]] && init + for i in ${!PORT[@]}; do + # did interface state change? + if switch ${PORT[$i]} ${STATE[$i]}; then + STATE[$i]=$(state ${PORT[$i]}) + if [[ ${STATE[$i]} == up ]]; then + [[ ${IPV4[$i]} != '-' ]] && ip addr add ${IPV4[$i]} metric ${METRIC4[$i]} dev ${PORT[$i]} + [[ ${IPV6[$i]} != '-' ]] && ip addr add ${IPV6[$i]} metric ${METRIC6[$i]} dev ${PORT[$i]} + elif [[ ${STATE[$i]} == down ]]; then + ip addr flush scope global dev ${PORT[$i]} + fi + fi + done + # check every 3 seconds + sleep 3 +done & +disown %% From 1b4e0fdbe522f44ee17e10f18ed8294a44b0c3cb Mon Sep 17 00:00:00 2001 From: bergware Date: Thu, 8 May 2025 16:02:35 +0200 Subject: [PATCH 07/54] Network: added interface monitoring script --- etc/rc.d/rc.local | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/etc/rc.d/rc.local b/etc/rc.d/rc.local index af02d607c..b78cfd588 100755 --- a/etc/rc.d/rc.local +++ b/etc/rc.d/rc.local @@ -80,9 +80,14 @@ fi /usr/local/emhttp/webGui/scripts/notify smtp-init /usr/local/emhttp/webGui/scripts/notify cron-init +# start interface state monitoring +if [[ -x /usr/local/sbin/monitor_interface ]]; then + /usr/local/sbin/monitor_interface &>/dev/null +fi + # start nchan monitoring -> stop all running nchan processes when no subscribers are connected if [[ -x /usr/local/sbin/monitor_nchan ]]; then - /usr/local/sbin/monitor_nchan + /usr/local/sbin/monitor_nchan &>/dev/null fi # First boot following Unraid Server OS update: delete plugin file From d8c5b24d6ae3616817227e9f851ddf8f11277688 Mon Sep 17 00:00:00 2001 From: bergware Date: Thu, 8 May 2025 16:03:16 +0200 Subject: [PATCH 08/54] Make script executable --- sbin/monitor_interface | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 sbin/monitor_interface diff --git a/sbin/monitor_interface b/sbin/monitor_interface old mode 100644 new mode 100755 From ea2ba286b0cb811fded00c4da0958cde50ee699d Mon Sep 17 00:00:00 2001 From: bergware Date: Thu, 8 May 2025 16:17:23 +0200 Subject: [PATCH 09/54] Update rc.wireless --- etc/rc.d/rc.wireless | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/etc/rc.d/rc.wireless b/etc/rc.d/rc.wireless index 531ed7c91..0fcdbdb77 100755 --- a/etc/rc.d/rc.wireless +++ b/etc/rc.d/rc.wireless @@ -257,8 +257,7 @@ wifi_stop(){ log "$DAEMON... No Wifi present." return fi - IPV4=$(ip -4 -br addr show scope global primary dev $PORT | awk '{print $3;exit}') - INDEX=$((3000 - 1 + $(index $PORT))) + IPV4=$(ip -4 -br addr show scope global primary dev $PORT | awk '{print $3,$4,$5;exit}') DHCP=$DHCP4 DNS=$DNS4 SRV4=$DNS @@ -270,7 +269,7 @@ wifi_stop(){ SRV6=$DNS ipaddr_down 6 fi - run ip addr del $IPV4 metric $INDEX dev $PORT + run ip addr del $IPV4 dev $PORT run pkill wpa_supplicant run iw dev $PORT disconnect run rm -f $INI From 83a364e52e4d8338c3c3ea59f30bbb112af8764c Mon Sep 17 00:00:00 2001 From: bergware Date: Thu, 8 May 2025 16:20:47 +0200 Subject: [PATCH 10/54] Revert "Update rc.wireless" This reverts commit ea2ba286b0cb811fded00c4da0958cde50ee699d. --- etc/rc.d/rc.wireless | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/etc/rc.d/rc.wireless b/etc/rc.d/rc.wireless index 0fcdbdb77..531ed7c91 100755 --- a/etc/rc.d/rc.wireless +++ b/etc/rc.d/rc.wireless @@ -257,7 +257,8 @@ wifi_stop(){ log "$DAEMON... No Wifi present." return fi - IPV4=$(ip -4 -br addr show scope global primary dev $PORT | awk '{print $3,$4,$5;exit}') + IPV4=$(ip -4 -br addr show scope global primary dev $PORT | awk '{print $3;exit}') + INDEX=$((3000 - 1 + $(index $PORT))) DHCP=$DHCP4 DNS=$DNS4 SRV4=$DNS @@ -269,7 +270,7 @@ wifi_stop(){ SRV6=$DNS ipaddr_down 6 fi - run ip addr del $IPV4 dev $PORT + run ip addr del $IPV4 metric $INDEX dev $PORT run pkill wpa_supplicant run iw dev $PORT disconnect run rm -f $INI From 288dca6137a5a519c49d49bf2a1e9f9711adef5f Mon Sep 17 00:00:00 2001 From: bergware Date: Thu, 8 May 2025 16:30:16 +0200 Subject: [PATCH 11/54] Update rc.wireless --- etc/rc.d/rc.wireless | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/etc/rc.d/rc.wireless b/etc/rc.d/rc.wireless index 531ed7c91..6daf3d873 100755 --- a/etc/rc.d/rc.wireless +++ b/etc/rc.d/rc.wireless @@ -270,7 +270,7 @@ wifi_stop(){ SRV6=$DNS ipaddr_down 6 fi - run ip addr del $IPV4 metric $INDEX dev $PORT + run ip addr del $IPV4 metric $INDEX dev shim-$PORT run pkill wpa_supplicant run iw dev $PORT disconnect run rm -f $INI From 3d239370090e749f4dea07abf89ba8cdd397ac3a Mon Sep 17 00:00:00 2001 From: bergware Date: Thu, 8 May 2025 17:11:14 +0200 Subject: [PATCH 12/54] Update rc.wireless --- etc/rc.d/rc.wireless | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/etc/rc.d/rc.wireless b/etc/rc.d/rc.wireless index 6daf3d873..297d6d44c 100755 --- a/etc/rc.d/rc.wireless +++ b/etc/rc.d/rc.wireless @@ -257,8 +257,6 @@ wifi_stop(){ log "$DAEMON... No Wifi present." return fi - IPV4=$(ip -4 -br addr show scope global primary dev $PORT | awk '{print $3;exit}') - INDEX=$((3000 - 1 + $(index $PORT))) DHCP=$DHCP4 DNS=$DNS4 SRV4=$DNS @@ -270,7 +268,9 @@ wifi_stop(){ SRV6=$DNS ipaddr_down 6 fi - run ip addr del $IPV4 metric $INDEX dev shim-$PORT + IPV4=$(ip -4 -br addr show scope global primary dev shim-$PORT | awk '{print $3,$4,$5;exit}') + [[ -n $IPV4 ]] && run ip addr del $IPV4 dev shim-$PORT + run ip addr flush dev $PORT run pkill wpa_supplicant run iw dev $PORT disconnect run rm -f $INI From 1b596c938fe98e22f5754a7e1e67323ac8718185 Mon Sep 17 00:00:00 2001 From: bergware Date: Thu, 8 May 2025 17:24:16 +0200 Subject: [PATCH 13/54] Update rc.wireless --- etc/rc.d/rc.wireless | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/etc/rc.d/rc.wireless b/etc/rc.d/rc.wireless index 297d6d44c..6f6e688b3 100755 --- a/etc/rc.d/rc.wireless +++ b/etc/rc.d/rc.wireless @@ -10,6 +10,7 @@ DAEMON="WiFi network" CALLER="wifi" INI="/var/local/emhttp/wireless.ini" CFG="/boot/config/wireless.cfg" +DOCKER="/boot/config/docker.cfg" OPENSSL="/usr/local/emhttp/webGui/scripts/open_ssl" STARTWIFI="/usr/local/emhttp/webGui/scripts/wireless" SERVICES="/usr/local/emhttp/webGui/scripts/update_services" @@ -29,6 +30,11 @@ CONF6="/proc/sys/net/ipv6/conf" [[ -r $INI ]] && . $INI PORT=${PORT:-wlan0} +# return variable value from file +var(){ + [[ -r "$2" ]] && grep -Pom1 "^$1=\"\K[^\"]+" "$2" +} + # return interface index index(){ cat $SYSTEM/$1/ifindex 2>/dev/null @@ -135,7 +141,13 @@ ipaddr_up(){ INDEX=$(index $PORT) INDEX=$((3000 + ${INDEX:-$(($(index * | sort -n | tail -1) + 1))})) if [[ $IP == ipv4 ]]; then - [[ -n $IP4 && -n $MASK4 ]] && run ip -4 addr add $(unzero $IP4)/$MASK4 metric $INDEX dev $PORT + if [[ -n $IP4 && -n $MASK4 ]]; then + run ip -4 addr add $(unzero $IP4)/$MASK4 metric $INDEX dev $PORT + # re-add IPv4 address of parent (if docker is running) + if [[ $(var DOCKER_ALLOW_ACCESS $DOCKER) == yes && -S /var/run/docker.sock ]]; then + ip addr add $(unzero $IP4)/$MASK4 metric $(($INDEX - 1)) dev shim-$PORT + fi + fi [[ -n $GATEWAY4 ]] && run ip -4 route add default via $GATEWAY4 metric $INDEX dev $PORT fi if [[ $IP == ipv6 ]]; then From b7ccdb36c12539da7e77fee378a12e86dd860e59 Mon Sep 17 00:00:00 2001 From: bergware Date: Thu, 8 May 2025 17:24:19 +0200 Subject: [PATCH 14/54] Update create_network_ini --- sbin/create_network_ini | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/sbin/create_network_ini b/sbin/create_network_ini index b9e70fb0f..03396adab 100755 --- a/sbin/create_network_ini +++ b/sbin/create_network_ini @@ -13,11 +13,11 @@ [[ (-z $reason && -z $1) || (-n $reason && ! "BOUND6 IPV4LL EXPIRE" =~ $reason) ]] && exit 0 -INI=/var/local/emhttp/network.ini.new -STA=/var/local/emhttp/statics.ini.new -CFG=/boot/config/network.cfg -DOCKER=/boot/config/docker.cfg -SYSTEM=/sys/class/net +INI="/var/local/emhttp/network.ini.new" +STA="/var/local/emhttp/statics.ini.new" +CFG="/boot/config/network.cfg" +DOCKER="/boot/config/docker.cfg" +SYSTEM="/sys/class/net" declare -A VLANID USE_DHCP IPADDR NETMASK GATEWAY METRIC USE_DHCP6 IPADDR6 NETMASK6 GATEWAY6 PRIVACY6 METRIC6 DESCRIPTION PROTOCOL From ea94ff2e31a46b2887ca868addfdaf2040eabfdb Mon Sep 17 00:00:00 2001 From: bergware Date: Thu, 8 May 2025 17:42:52 +0200 Subject: [PATCH 15/54] Update rc.wireless --- etc/rc.d/rc.wireless | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/etc/rc.d/rc.wireless b/etc/rc.d/rc.wireless index 6f6e688b3..8e16249ce 100755 --- a/etc/rc.d/rc.wireless +++ b/etc/rc.d/rc.wireless @@ -287,7 +287,7 @@ wifi_stop(){ run iw dev $PORT disconnect run rm -f $INI # restart services when static assignments - [[ $SRV4 == no && (-z $SRV6 || $SRV6 == no) ]] && $SERVICE 5 + [[ $SRV4 == no && (-z $SRV6 || $SRV6 == no) ]] && $SERVICES 5 if ! wifi_running; then REPLY="Stopped"; else REPLY="Failed"; fi log "$DAEMON... $REPLY." } @@ -346,7 +346,7 @@ wifi_join(){ echo 1 >$CONF6/$PORT/disable_ipv6 fi # restart services when static assignments - [[ $SRV4 == no && (-z $SRV6 || $SRV6 == no) ]] && $SERVICE 5 + [[ $SRV4 == no && (-z $SRV6 || $SRV6 == no) ]] && $SERVICES 5 if wifi_running; then if [[ -z $CC ]]; then CC=($(iw reg get | grep -Po '^country \K..')) From 756d008c507ab6b2a727f8322acc3554a1f8d490 Mon Sep 17 00:00:00 2001 From: bergware Date: Thu, 8 May 2025 17:45:17 +0200 Subject: [PATCH 16/54] Update rc.docker --- etc/rc.d/rc.docker | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/etc/rc.d/rc.docker b/etc/rc.d/rc.docker index 954e61d63..08c4f43a5 100755 --- a/etc/rc.d/rc.docker +++ b/etc/rc.d/rc.docker @@ -220,7 +220,7 @@ container_add_route(){ if [[ $PID -gt 0 && "eth0 br0 bond0 wlan0" =~ $LAN ]]; then local THISIP=$(ip -4 -br addr show scope global primary dev $LAN | awk '{print $3;exit}') for CFG in /etc/wireguard/wg*.cfg ; do - local NETWORK=$(ip -4 show route $THISIP dev $LAN | awk '{print $1;exit}') + local NETWORK=$(ip -4 route show $THISIP dev $LAN | awk '{print $1;exit}') [[ -n $NETWORK ]] && nsenter -n -t $PID ip -4 route add $NETWORK via ${THISIP%/*} dev $LAN 2>/dev/null done fi From 3208c8c0f1542556841fb428edc5c310f2a48d26 Mon Sep 17 00:00:00 2001 From: SimonFair <39065407+SimonFair@users.noreply.github.com> Date: Thu, 8 May 2025 16:51:14 +0100 Subject: [PATCH 17/54] Fix boot issue starting VM manager. --- sbin/qemu | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sbin/qemu b/sbin/qemu index da3c4945f..79415243a 100755 --- a/sbin/qemu +++ b/sbin/qemu @@ -7,7 +7,7 @@ if [ $DISABLE == "yes" ] exit 1 ; fi PCI="no" -PCI=$(/usr/local/emhttp/plugins/dynamix.vm.manager/scripts/pcicheck.php "$@"); +#PCI=$(/usr/local/emhttp/plugins/dynamix.vm.manager/scripts/pcicheck.php "$@"); if [ $PCI == "yes" ] then printf '\n%s\n' "Start/autostart is disabled PCI Change detected." >&2 ## Send message to stderr. From 012e486414c394e506f1c3301f07f24289a5302f Mon Sep 17 00:00:00 2001 From: bergware Date: Thu, 8 May 2025 23:33:32 +0200 Subject: [PATCH 18/54] docker: better handling of IPv6 /128 subnets --- etc/rc.d/rc.docker | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/etc/rc.d/rc.docker b/etc/rc.d/rc.docker index 08c4f43a5..8739014dc 100755 --- a/etc/rc.d/rc.docker +++ b/etc/rc.d/rc.docker @@ -356,10 +356,10 @@ docker_network_start(){ GATEWAY=$(ip -4 route show default dev $NETWORK | awk '{print $3;exit}') fi SUBNET6=; GATEWAY6=; SERVER6=; - [[ -z ${!AUTO} || ${!AUTO} =~ "6" ]] && IPV6=$(ip -6 -br addr show scope global primary -deprecated dev $NETWORK | awk '{print $3;exit}') || IPV6= + # get IPv6 address - ignore any /128 networks + [[ -z ${!AUTO} || ${!AUTO} =~ "6" ]] && IPV6=$(ip -6 -br addr show scope global primary -deprecated dev $NETWORK | awk -v RS='[[:space:]]+' '(NR>2){print}' | grep -Pvm1 '^.+/128|^$') || IPV6= if [[ -n $IPV6 ]]; then - # get IPV6 subnet, preset to /64 if single host address is given - [[ ${IPV6#*/} == 128 ]] && SUBNET6=$(echo $IPV6 | sed -r 's/^([^:]+):([^:]+):([^:]+):([^:]+).*$/\1:\2:\3:\4::\/64/') || SUBNET6=$(ip -6 route show $IPV6 dev $NETWORK | awk '{print $1;exit}') + SUBNET6=$(ip -6 route show $IPV6 dev $NETWORK | awk '{print $1;exit}') SERVER6=${IPV6%/*} GATEWAY6=$(ip -6 route show default dev $NETWORK | awk '{print $3;exit}') # replace link local address for first address in subnet From 30a7f6eb90f81177257cc2ad0f227bf6b29a1ac4 Mon Sep 17 00:00:00 2001 From: Eli Bosley Date: Fri, 9 May 2025 08:25:38 -0400 Subject: [PATCH 19/54] feat: add tweaks for the Unraid API - enables API support for 7.2 - do not merge before the API is integrated, will break notifications - includes authentication fix for now --- emhttp/auth-request.php | 41 +++++- emhttp/plugins/dynamix/LogViewer.page | 8 + .../dynamix/include/DefaultPageLayout.php | 138 +++++++++--------- .../DefaultPageLayout/BodyInlineJS.php | 27 +--- .../DefaultPageLayout/GUIModeSessionFix.php | 26 ++++ .../include/DefaultPageLayout/Header.php | 4 - .../include/DefaultPageLayout/ToastSetup.php | 1 + 7 files changed, 145 insertions(+), 100 deletions(-) create mode 100644 emhttp/plugins/dynamix/LogViewer.page create mode 100644 emhttp/plugins/dynamix/include/DefaultPageLayout/GUIModeSessionFix.php create mode 100644 emhttp/plugins/dynamix/include/DefaultPageLayout/ToastSetup.php diff --git a/emhttp/auth-request.php b/emhttp/auth-request.php index 59f663118..e32448694 100644 --- a/emhttp/auth-request.php +++ b/emhttp/auth-request.php @@ -14,6 +14,32 @@ if (isset($_COOKIE[session_name()])) { session_write_close(); } +// Function to recursively find JS files in a directory +function findJsFiles($directory) { + if (!is_dir($directory)) { + return []; + } + + $jsFiles = []; + $iterator = new RecursiveIteratorIterator( + new RecursiveDirectoryIterator($directory, RecursiveDirectoryIterator::SKIP_DOTS) + ); + + foreach ($iterator as $file) { + if ($file->isFile() && $file->getExtension() === 'js') { + $path = $file->getPathname(); + $baseDir = '/usr/local/emhttp'; + if (strpos($path, $baseDir) === 0) { + $path = substr($path, strlen($baseDir)); + } + $jsFiles[] = $path; + } + } + + return $jsFiles; +} + +// Base whitelist of files $arrWhitelist = [ '/webGui/styles/clear-sans-bold-italic.eot', '/webGui/styles/clear-sans-bold-italic.woff', @@ -39,8 +65,21 @@ $arrWhitelist = [ '/webGui/images/case-model.png', '/webGui/images/green-on.png', '/webGui/images/red-on.png', - '/webGui/images/yellow-on.png' + '/webGui/images/yellow-on.png', + '/webGui/images/UN-logotype-gradient.svg' ]; + +// Add JS files from the unraid-components directory +$webComponentsDirectory = '/usr/local/emhttp/plugins/dynamix.my.servers/unraid-components/'; +$jsFiles = findJsFiles($webComponentsDirectory); + +// Add logo asset if needed +// Note: In the original JS, there was a getters.paths().webgui.logo.assetPath that we'd add +// Since we don't have access to that here, you may need to add the specific logo path if known + +// Merge the JS files with the whitelist +$arrWhitelist = array_merge($arrWhitelist, $jsFiles); + if (in_array(preg_replace(['/\?v=\d+$/','/\?\d+$/'],'',$_SERVER['REQUEST_URI']),$arrWhitelist)) { // authorized http_response_code(200); diff --git a/emhttp/plugins/dynamix/LogViewer.page b/emhttp/plugins/dynamix/LogViewer.page new file mode 100644 index 000000000..fb9eb150c --- /dev/null +++ b/emhttp/plugins/dynamix/LogViewer.page @@ -0,0 +1,8 @@ +Menu="UNRAID-OS" +Title="Log Viewer (new)" +Icon="icon-log" +Tag="list" +--- + + + \ No newline at end of file diff --git a/emhttp/plugins/dynamix/include/DefaultPageLayout.php b/emhttp/plugins/dynamix/include/DefaultPageLayout.php index 0bdf4ec2c..76b5d2931 100644 --- a/emhttp/plugins/dynamix/include/DefaultPageLayout.php +++ b/emhttp/plugins/dynamix/include/DefaultPageLayout.php @@ -28,22 +28,22 @@ $entity = $notify['entity'] & 1 == 1; $alerts = '/tmp/plugins/my_alerts.txt'; $wlan0 = file_exists('/sys/class/net/wlan0'); -$safemode = _var($var,'safeMode')=='yes'; +$safemode = _var($var, 'safeMode') == 'yes'; $banner = "$config/webGui/banner.png"; $notes = '/var/tmp/unRAIDServer.txt'; if (!file_exists($notes)) { - file_put_contents($notes, shell_exec("$docroot/plugins/dynamix.plugin.manager/scripts/plugin changes $docroot/plugins/unRAIDServer/unRAIDServer.plg")); + file_put_contents($notes, shell_exec("$docroot/plugins/dynamix.plugin.manager/scripts/plugin changes $docroot/plugins/unRAIDServer/unRAIDServer.plg")); } $taskPages = find_pages('Tasks'); $buttonPages = find_pages('Buttons'); $pages = []; // finds subpages if (!empty($myPage['text'])) $pages[$myPage['name']] = $myPage; -if (_var($myPage,'Type')=='xmenu') $pages = array_merge($pages, find_pages($myPage['name'])); +if (_var($myPage, 'Type') == 'xmenu') $pages = array_merge($pages, find_pages($myPage['name'])); // nchan related actions -$nchan = ['webGui/nchan/notify_poller','webGui/nchan/session_check']; +$nchan = ['webGui/nchan/notify_poller', 'webGui/nchan/session_check']; if ($wlan0) $nchan[] = 'webGui/nchan/wlan0'; // build nchan scripts from found pages $allPages = array_merge($taskPages, $buttonPages, $pages); @@ -52,96 +52,94 @@ foreach ($allPages as $page) { } // act on nchan scripts if (count($pages)) { - $running = file_exists($nchan_pid) ? file($nchan_pid,FILE_IGNORE_NEW_LINES|FILE_SKIP_EMPTY_LINES) : []; + $running = file_exists($nchan_pid) ? file($nchan_pid, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES) : []; $start = array_diff($nchan, $running); // returns any new scripts to be started $stop = array_diff($running, $nchan); // returns any old scripts to be stopped $running = array_merge($start, $running); // update list of current running nchan scripts // start nchan scripts which are new foreach ($start as $row) { - $script = explode(':',$row)[0]; + $script = explode(':', $row)[0]; exec("$docroot/$script &>/dev/null &"); } // stop nchan scripts with the :stop option foreach ($stop as $row) { - [$script,$opt] = my_explode(':',$row); + [$script, $opt] = my_explode(':', $row); if ($opt == 'stop') { exec("pkill -f $docroot/$script &>/dev/null &"); - array_splice($running,array_search($row,$running),1); + array_splice($running, array_search($row, $running), 1); } } - if (count($running)) file_put_contents($nchan_pid,implode("\n",$running)."\n"); else @unlink($nchan_pid); + if (count($running)) file_put_contents($nchan_pid, implode("\n", $running) . "\n"); + else @unlink($nchan_pid); } ?> -lang="" class="getThemeHtmlClass() ?>"> +lang="" class="getThemeHtmlClass() ?>"> + -<?=_var($var, 'NAME')?>/<?=_var($myPage, 'name')?> - - - - - - - - -"> -"> -"> -"> -"> -"> + <?= _var($var, 'NAME') ?>/<?= _var($myPage, 'name') ?> + + + + + + + + + "> + "> + "> + "> + "> + "> -"> -"> -"> -"> + "> + "> + "> + "> - + isSidebarTheme()) { + echo generate_sidebar_icon_css($taskPages, $buttonPages); + } + ?> + - + - - + + - + + ' . parse_text($button['text'])); + } -'.parse_text($button['text'])); -} + foreach ($pages as $page) { + annotate($page['file']); + includePageStylesheets($page); + } + ?> -foreach ($pages as $page) { - annotate($page['file']); - includePageStylesheets($page); -} -?> - - + + + @@ -149,5 +147,7 @@ foreach ($pages as $page) { + - + + \ No newline at end of file diff --git a/emhttp/plugins/dynamix/include/DefaultPageLayout/BodyInlineJS.php b/emhttp/plugins/dynamix/include/DefaultPageLayout/BodyInlineJS.php index ae5f5eb67..be71c6f72 100644 --- a/emhttp/plugins/dynamix/include/DefaultPageLayout/BodyInlineJS.php +++ b/emhttp/plugins/dynamix/include/DefaultPageLayout/BodyInlineJS.php @@ -71,32 +71,7 @@ defaultPage.on('message', function(msg,meta) { $('#statusbar').html(status); break; case 2: - // notifications - var bell1 = 0, bell2 = 0, bell3 = 0; - $.each($.parseJSON(msg), function(i, notify){ - switch (notify.importance) { - case 'alert' : bell1++; break; - case 'warning': bell2++; break; - case 'normal' : bell3++; break; - } - - if (notify.show) { - $.jGrowl(notify.subject+'
'+notify.description,{ - group: notify.importance, - header: notify.event+': '+notify.timestamp, - theme: notify.file, - beforeOpen: function(e,m,o){if ($('div.jGrowl-notification').hasClass(notify.file)) return(false);}, - afterOpen: function(e,m,o){if (notify.link) $(e).css('cursor','pointer');}, - click: function(e,m,o){if (notify.link) location.replace(notify.link);}, - close: function(e,m,o){$.post('/webGui/include/Notify.php',{cmd:'hide',file:""+notify.file,csrf_token:csrf_token},function(){$.post('/webGui/include/Notify.php',{cmd:'archive',file:notify.file,csrf_token:csrf_token});});} - }); - } - - }); - $('#bell').removeClass('red-orb yellow-orb green-orb').prop('title'," ["+bell1+']\n'+" ["+bell2+']\n'+" ["+bell3+']'); - if (bell1) $('#bell').addClass('red-orb'); else - if (bell2) $('#bell').addClass('yellow-orb'); else - if (bell3) $('#bell').addClass('green-orb'); + // notifications - moved to the Unraid API break; } }); diff --git a/emhttp/plugins/dynamix/include/DefaultPageLayout/GUIModeSessionFix.php b/emhttp/plugins/dynamix/include/DefaultPageLayout/GUIModeSessionFix.php new file mode 100644 index 000000000..516284e1e --- /dev/null +++ b/emhttp/plugins/dynamix/include/DefaultPageLayout/GUIModeSessionFix.php @@ -0,0 +1,26 @@ + \ No newline at end of file diff --git a/emhttp/plugins/dynamix/include/DefaultPageLayout/Header.php b/emhttp/plugins/dynamix/include/DefaultPageLayout/Header.php index 4a33aef78..2bd197073 100644 --- a/emhttp/plugins/dynamix/include/DefaultPageLayout/Header.php +++ b/emhttp/plugins/dynamix/include/DefaultPageLayout/Header.php @@ -1,9 +1,5 @@