From ed4bd3db1bb4cde9253470bccf25e2780f0fa7d4 Mon Sep 17 00:00:00 2001 From: Tom Mortensen Date: Sat, 10 May 2025 23:31:45 -0700 Subject: [PATCH 01/38] mover: add second 'find' pass to clean up leftover empty directories --- sbin/mover | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sbin/mover b/sbin/mover index e956cb7bf8..23ad65978a 100755 --- a/sbin/mover +++ b/sbin/mover @@ -27,7 +27,9 @@ CFGPATH="/boot/config/shares" DEBUGGING="" move() { - /usr/bin/find "$1" -depth 2>/dev/null | /usr/libexec/unraid/move $DEBUGGING + find "$1" -depth 2>/dev/null | /usr/libexec/unraid/move $2 $DEBUGGING + # second pass to clean up leftover empty directories + find "$1" -depth 2>/dev/null | /usr/libexec/unraid/move $2 $DEBUGGING } start() { @@ -104,7 +106,7 @@ empty() { for SHAREPATH in /mnt/$DISK/* ; do SHARE=$(basename "$SHAREPATH") if [[ -d "$SHAREPATH" && -f "$CFGPATH/$SHARE.cfg" ]]; then - find "$SHAREPATH" -depth 2>/dev/null | /usr/libexec/unraid/move -e $DEBUGGING + move "$SHAREPATH" "-e" fi done From 7f02d3fb7dac0a025fe991bfa05e6dca88ce77ea Mon Sep 17 00:00:00 2001 From: ljm42 Date: Wed, 28 May 2025 14:43:43 -0700 Subject: [PATCH 02/38] Backport networking fixes to 7.1 --- emhttp/plugins/dynamix/Eth0.page | 28 ++- emhttp/plugins/dynamix/EthX.page | 12 +- .../plugins/dynamix/include/RoutingTable.php | 4 +- .../plugins/dynamix/scripts/reload_services | 3 - .../plugins/dynamix/scripts/update_services | 2 +- etc/rc.d/rc.docker | 205 +++++++----------- etc/rc.d/rc.inet1 | 108 ++++----- etc/rc.d/rc.library.source | 8 +- etc/rc.d/rc.local | 9 +- etc/rc.d/rc.nginx | 12 +- etc/rc.d/rc.wireless | 57 +++-- sbin/create_network_ini | 114 +++++++--- sbin/monitor_interface | 69 ++++++ sbin/monitor_nchan | 41 ++-- 14 files changed, 398 insertions(+), 274 deletions(-) create mode 100644 sbin/monitor_interface diff --git a/emhttp/plugins/dynamix/Eth0.page b/emhttp/plugins/dynamix/Eth0.page index 7b4858ea9a..680f9fbd76 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 be1713f3b5..27d369ebe9 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)_: : - ** + **
diff --git a/emhttp/plugins/dynamix/include/RoutingTable.php b/emhttp/plugins/dynamix/include/RoutingTable.php index 2bfa73efb3..1741cbc99c 100644 --- a/emhttp/plugins/dynamix/include/RoutingTable.php +++ b/emhttp/plugins/dynamix/include/RoutingTable.php @@ -26,8 +26,8 @@ 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]; diff --git a/emhttp/plugins/dynamix/scripts/reload_services b/emhttp/plugins/dynamix/scripts/reload_services index a1fe713cbd..babe9c7c15 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 a899507330..4fbebbb2a7 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 diff --git a/etc/rc.d/rc.docker b/etc/rc.d/rc.docker index 6a9719d35d..13632d0afb 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,22 @@ TMP=/var/tmp/network.tmp # run & log functions . /etc/rc.d/rc.runlog +# return interface index +index(){ + cat $SYSTEM/$1/ifindex 2>/dev/null +} + +# return active interface +active(){ + if [[ -e $SYSTEM/${1/eth/br} ]]; then + echo ${1/eth/br} + elif [[ -e $SYSTEM/${1/eth/bond} ]]; then + echo ${1/eth/bond} + else + echo $1 + fi +} + # wait for interface to go up carrier(){ local n e @@ -49,20 +65,13 @@ carrier(){ # initialize docker settings docker_read_options(){ # determine active port name - [[ -e $SYSTEM/bond0 ]] && PORT=bond0 || PORT=eth0 - [[ -e $SYSTEM/br0 ]] && PORT=br0 + PORT=$(active eth0) [[ ! $(carrier $PORT) && $(carrier wlan0 1) ]] && PORT=wlan0 # Set defaults used by the docker daemon if [[ -f $DOCKER_CFG ]]; then for NIC in $NICS; do - if [[ ${NIC:0:3} == eth ]]; then - if [[ -e $SYSTEM/${NIC/eth/br} ]]; then - NIC=${NIC/eth/br} - elif [[ -e $SYSTEM/${NIC/eth/bond} ]]; then - NIC=${NIC/eth/bond} - fi - fi + [[ ${NIC:0:3} == eth ]] && NIC=$(active $NIC) CFG=($(grep -Pom2 "_SUBNET_|_${NIC^^}(_[0-9]+)?=" $DOCKER_CFG)) if [[ ${CFG[0]} == _SUBNET_ && -z ${CFG[1]} ]]; then # interface has changed, update configuration @@ -103,7 +112,7 @@ docker_read_options(){ [[ -n $MTU && $MTU -ne 1500 ]] && DOCKER_OPTS="--mtu=$MTU $DOCKER_OPTS" # Enable IPv6 for docker bridge network - if [[ -n $(ip -6 route show default dev $PORT) ]]; then + if [[ -n $(ip -6 route show to default dev $PORT) ]]; then DOCKER0='fd17::/64' DOCKER_OPTS="--ipv6 --fixed-cidr-v6=$DOCKER0 $DOCKER_OPTS" IPV6_FORWARD=${IPV6_FORWARD:=accept} @@ -165,6 +174,8 @@ driver(){ ATTACH='macvlan' MODE='bridge' fi + # wlan0 has forced ipvlan + [[ $1 == wlan && $2 == forced ]] && ATTACH=ipvlan } # Custom networks @@ -172,6 +183,11 @@ network(){ docker network ls --filter driver="$1" --format='{{.Name}}' 2>/dev/null | grep -P "^[a-z]+$2(\$|\.)" | tr '\n' ' ' } +# Does the ipv4 address exist? +ipv4_exist(){ + ip -4 -br addr show to $2 dev $1 | awk '{print $3;exit}' +} + # Is container running? container_running(){ local CONTAINER @@ -213,9 +229,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 route show to $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 @@ -246,8 +262,7 @@ docker_network_start(){ if ! docker_running; then return 1; fi # get container settings for custom networks to reconnect later declare -A NETRESTORE CTRESTORE - CONTAINERS=$(docker container ls -a --format='{{.Names}}' | tr '\n' ' ') - for CONTAINER in $CONTAINERS; do + for CONTAINER in $(docker container ls -a --format='{{.Names}}'); do # the file case (due to fat32) might be different so use find to match XMLFILE=$(find /boot/config/plugins/dockerMan/templates-user -maxdepth 1 -iname my-${CONTAINER}.xml) if [[ -n $XMLFILE ]]; then @@ -255,13 +270,7 @@ docker_network_start(){ MAIN= # update custom network reference (if changed) for NIC in $NICS; do - if [[ ${NIC:0:3} == eth ]]; then - if [[ -e $SYSTEM/${NIC/eth/br} ]]; then - NIC=${NIC/eth/br} - elif [[ -e $SYSTEM/${NIC/eth/bond} ]]; then - NIC=${NIC/eth/bond} - fi - fi + [[ ${NIC:0:3} == eth ]] && NIC=$(active $NIC) X=${NIC//[^0-9]/} REF=$(grep -Pom1 "\K(br|bond|eth|wlan)$X" $XMLFILE) [[ $X == 0 && ! $(carrier $NIC 1) ]] && continue @@ -307,24 +316,18 @@ docker_network_start(){ done # detach custom networks for NIC in $NICS; do - if [[ ${NIC:0:3} == eth ]]; then - if [[ -e $SYSTEM/${NIC/eth/br} ]]; then - NIC=${NIC/eth/br} - elif [[ -e $SYSTEM/${NIC/eth/bond} ]]; then - NIC=${NIC/eth/bond} - fi - fi + [[ ${NIC:0:3} == eth ]] && NIC=$(active $NIC) X=${NIC//[^0-9]/} driver ${NIC//[0-9]/} for NETWORK in $(network $DETACH $X); 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 done # get existing custom networks for NETWORK in $(network $ATTACH $X); do if [[ $STOCK =~ ${NETWORK%%[0-9]*} ]]; then - [[ $EXCLUDE =~ "$NETWORK " || ! $ACTIVE =~ "$NETWORK " ]] && docker network rm $NETWORK >/dev/null + [[ $EXCLUDE =~ "$NETWORK " || ! $ACTIVE =~ "$NETWORK " ]] && docker network rm $NETWORK &>/dev/null else - [[ $DOCKER_USER_NETWORKS != preserve ]] && docker network rm $NETWORK >/dev/null + [[ $DOCKER_USER_NETWORKS != preserve ]] && docker network rm $NETWORK &>/dev/null fi done NETWORKS=$(network $ATTACH $X) @@ -336,27 +339,27 @@ docker_network_start(){ AUTO=${NETWORK/./_} AUTO=DOCKER_AUTO_${AUTO^^} if [[ ${!AUTO} == no ]]; then - [[ $NETWORKS =~ "$NETWORK " ]] && docker network rm $NETWORK >/dev/null + [[ $NETWORKS =~ "$NETWORK " ]] && docker network rm $NETWORK &>/dev/null continue 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}') + SUBNET=$(ip -4 route show to $IPV4 dev $NETWORK | awk '{print $1;exit}') SERVER=${IPV4%/*} DHCP=${NETWORK/./_} DHCP=DOCKER_DHCP_${DHCP^^} RANGE=${!DHCP} - GATEWAY=$(ip -4 route show default dev $NETWORK | awk '{print $3;exit}') + GATEWAY=$(ip -4 route show to 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= + # 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 to $IPV6 dev $NETWORK | awk '{print $1;exit}') SERVER6=${IPV6%/*} - GATEWAY6=$(ip -6 route show default dev $NETWORK | awk '{print $3;exit}') + GATEWAY6=$(ip -6 route show to default dev $NETWORK | awk '{print $3;exit}') # replace link local address for first address in subnet [[ ${GATEWAY6:0:4} == fe80 ]] && GATEWAY6=${SUBNET6%/*}1 fi @@ -378,38 +381,7 @@ docker_network_start(){ GATEWAY6=${!GATEWAY6} SERVER6=; fi - # custom network already existing and changed? - if [[ $NETWORKS =~ "$NETWORK " ]]; then - UPDATE=; - SUBNETS=($(docker network inspect --format='{{range .IPAM.Config}}{{.Subnet}} {{end}}' $NETWORK 2>/dev/null)) - RANGES=($(docker network inspect --format='{{range .IPAM.Config}}{{.IPRange}} {{end}}' $NETWORK 2>/dev/null)) - GATEWAYS=($(docker network inspect --format='{{range .IPAM.Config}}{{.Gateway}} {{end}}' $NETWORK 2>/dev/null)) - SERVERS=($(docker network inspect --format='{{range .IPAM.Config}}{{range $IPAddr := .AuxiliaryAddresses}}{{$IPAddr}}{{end}} {{end}}' $NETWORK 2>/dev/null)) - # distribute ipv4 and ipv6 assignments - [[ ${SUBNETS[0]} =~ '.' ]] && SUBNET0=${SUBNETS[0]} || SUBNET1=${SUBNETS[0]} - [[ -n ${SUBNETS[1]} && ${SUBNETS[1]} =~ '.' ]] && SUBNET0=${SUBNETS[1]} || SUBNET1=${SUBNETS[1]} - [[ ${RANGES[0]} =~ '.' ]] && RANGE0=${RANGES[0]} || RANGE1=${RANGES[0]} - [[ -n ${RANGES[1]} && ${RANGES[1]} =~ '.' ]] && RANGE0=${RANGES[1]} || RANGE1=${RANGES[1]} - [[ ${GATEWAYS[0]} =~ '.' ]] && GATEWAY0=${GATEWAYS[0]} || GATEWAY1=${GATEWAYS[0]} - [[ -n ${GATEWAYS[1]} && ${GATEWAYS[1]} =~ '.' ]] && GATEWAY0=${GATEWAYS[1]} || GATEWAY1=${GATEWAYS[1]} - [[ ${SERVERS[0]} =~ '.' ]] && SERVER0=${SERVERS[0]} || SERVER1=${SERVERS[0]} - [[ -n ${SERVERS[1]} && ${SERVERS[1]} =~ '.' ]] && SERVER0=${SERVERS[1]} || SERVER1=${SERVERS[1]} - # check for changes - [[ $SUBNET != $SUBNET0 || $SUBNET6 != $SUBNET1 ]] && UPDATE=1 - [[ $RANGE != $RANGE0 ]] && UPDATE=1 - [[ (-n $GATEWAY && $GATEWAY != $GATEWAY0) || (-n $GATEWAY6 && $GATEWAY6 != $GATEWAY1) ]] && UPDATE=1 - [[ (-n $SERVER && $SERVER != $SERVER0) || (-n $SERVER6 && $SERVER6 != $SERVER1) ]] && UPDATE=1 - if [[ -z $UPDATE ]]; then - # no changes, ignore - SUBNET=; SUBNET6=; - else - # changed, remove first - docker network rm $NETWORK >/dev/null - fi - fi # set parameters for custom network creation - N4=$SUBNET; R4=$RANGE; - N6=$SUBNET6; [[ -n $SUBNET && -n $GATEWAY ]] && GATEWAY="--gateway=$GATEWAY" || GATEWAY=; [[ -n $SUBNET && -n $SERVER ]] && SERVER="--aux-address=server=$SERVER" || SERVER=; [[ -n $SUBNET && -n $RANGE ]] && RANGE="--ip-range=$RANGE" || RANGE=; @@ -419,15 +391,15 @@ docker_network_start(){ [[ -n $SUBNET6 ]] && SUBNET6="--ipv6 --subnet=$SUBNET6" if [[ -n $SUBNET || -n $SUBNET6 ]]; then TYPE=${NETWORK//[0-9.]/} - driver $TYPE - if [[ $TYPE == br ]]; then + driver $TYPE forced + if [[ $TYPE == br || $TYPE == wlan ]]; then VHOST=$NETWORK - elif [[ $TYPE == wlan ]]; then - VHOST=$NETWORK - ATTACH=ipvlan else - [[ $DOCKER_ALLOW_ACCESS == yes && -n $IPV4 ]] && VHOST=vhost${NETWORK//[^0-9.]/} || VHOST=$NETWORK + [[ -n $IPV4 && $DOCKER_ALLOW_ACCESS == yes ]] && VHOST=vhost${NETWORK//[^0-9.]/} || VHOST=$NETWORK fi + # delete and recreate unconditionally + log "Processing... $NETWORK" + docker network rm $NETWORK &>/dev/null docker network create -d $ATTACH $SUBNET $GATEWAY $SERVER $RANGE $SUBNET6 $GATEWAY6 $SERVER6 -o parent=$VHOST $NETWORK | xargs docker network inspect -f "created network $ATTACH {{.Name}} with subnets: {{range .IPAM.Config}}{{.Subnet}}; {{end}}" 2>/dev/null | log # connect containers to this new network for CONNECT in ${NETRESTORE[$NETWORK]}; do @@ -448,57 +420,50 @@ 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 + IPV4="$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 $IPV4 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 - 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 - log "prepared network $VHOST for host access" + else + if [[ $TYPE == wlan ]]; then + VHOST=shim-$NETWORK + INDEX=3000 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 - fi + INDEX=1000 + fi + INDEX=$(($INDEX - 1 + $(index $NETWORK))) + if [[ -n $IPV4 && $DOCKER_ALLOW_ACCESS == yes ]]; then + # 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 + [[ -z $(ipv4_exist $VHOST ${IPV4%/*}) ]] && run ip addr add $IPV4 metric $INDEX dev $VHOST + log "created network $VHOST for host access" + elif [[ -n $IPV4 && -e $SYSTEM/$VHOST && -n $(ipv4_exist $VHOST ${IPV4%/*}) ]]; then + # remove parent IPv4 address from vhost interface + run ip addr del $IPV4 metric $INDEX dev $VHOST fi fi fi done # create IPv6 forward accept rule if [[ $IPV6_FORWARD == accept ]]; then - log "creating forward accept rule for IPv6 network" ip6tables -P FORWARD ACCEPT + log "created forward accept rule for IPv6 network" fi log "Network started." } @@ -506,33 +471,31 @@ docker_network_start(){ docker_network_stop(){ log "Stopping network..." if ! docker_running; then return 1; fi + # Read docker configuration file + [[ -f $DOCKER_CFG ]] && . $DOCKER_CFG for NIC in $NICS; do - if [[ ${NIC:0:3} == eth ]]; then - if [[ -e $SYSTEM/${NIC/eth/br} ]]; then - NIC=${NIC/eth/br} - elif [[ -e $SYSTEM/${NIC/eth/bond} ]]; then - NIC=${NIC/eth/bond} - fi - fi - driver ${NIC//[0-9]/} + [[ ${NIC:0:3} == eth ]] && NIC=$(active $NIC) + driver ${NIC//[0-9]/} forced 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 + IPV4=$(ip -4 -br addr show scope global primary dev shim-wlan0 | awk '{print $3,$4,$5;exit}') + [[ -n $IPV4 ]] && run ip addr del $IPV4 dev shim-wlan0 + fi log "Network stopped." } @@ -549,7 +512,7 @@ docker_container_start(){ if [[ $OUT =~ "Error:" ]]; then log "$CONTAINER: $OUT" & else - run container_add_route $CONTAINER + container_add_route $CONTAINER log "$CONTAINER: started successfully!" & if [[ $WAIT -gt 0 ]]; then log "$CONTAINER: wait $WAIT seconds" & @@ -650,7 +613,6 @@ case "$1" in docker_service_start docker_network_start docker_container_start &>/dev/null & - disown ;; 'stop') docker_container_stop @@ -670,7 +632,6 @@ case "$1" in docker_service_start docker_network_start docker_container_start &>/dev/null & - disown ;; 'status') docker_status diff --git a/etc/rc.d/rc.inet1 b/etc/rc.d/rc.inet1 index 6670cbbfc0..835b8dd3ec 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,22 +125,18 @@ 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 - run ip -4 addr add 127.0.0.1/8 dev lo - fi - if ! ip -6 addr show lo | grep -qw 'inet6'; then - run ip -6 addr add ::1/128 dev lo - fi + [[ -z $(ip -4 -br addr show lo | awk '{print $3;exit}') ]] && run ip -4 addr add 127.0.0.1/8 dev lo + [[ -z $(ip -6 -br addr show lo | awk '{print $3;exit}') ]] && run ip -6 addr add ::1/128 dev lo run ip link set lo up else [[ $DEBUG_ETH_UP == yes ]] && log "interface lo not present, can't bring 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 +149,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 +170,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 +179,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 +198,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 +212,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 +239,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 +257,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 +269,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 +279,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 +287,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 +314,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 +348,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 +377,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 +391,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 +418,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 +430,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 +444,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 +461,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 +563,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 +620,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 @@ -623,7 +631,7 @@ gateway_up(){ IP=${PROTOCOL[$x]:-ipv4} AD=${METRIC[$x]} [[ -n $AD ]] && AD="metric $AD" - EXIST=$(ip -4 route show default via $(unzero $GW) dev $DEV | grep "$AD ") + EXIST=$(ip -4 route show to default via $(unzero $GW) dev $DEV | grep "$AD ") [[ $IP != ipv6 && -z $EXIST ]] && run ip -4 route add default via $(unzero $GW) dev $DEV $AD done for GW6 in ${GATEWAY6[@]}; do @@ -635,12 +643,12 @@ gateway_up(){ IP=${PROTOCOL[$x]:-ipv4} AD6=${METRIC6[$x]} [[ -n $AD6 ]] && AD6="metric $AD6" - EXIST=$(ip -6 route show default via $(unzero6 $GW6) dev $DEV | grep "$AD6 ") + EXIST=$(ip -6 route show to default via $(unzero6 $GW6) dev $DEV | grep "$AD6 ") [[ $IP != ipv4 && -z $EXIST ]] && run ip -6 route add default via $(unzero6 $GW6) dev $DEV $AD6 done } -# function to delete default gateway per interface +# delete default gateway per interface gateway_down(){ for GW in ${GATEWAY[@]}; do [[ -z $GW ]] && continue @@ -649,7 +657,7 @@ gateway_down(){ i=(${x/,/ }) [[ -z ${i[1]} ]] && DEV=${IFNAME[$i]} || DEV=${IFNAME[$i]}.${VLANID[$x]} IP=${PROTOCOL[$x]:-ipv4} - EXIST=$(ip -4 route show default dev $DEV) + EXIST=$(ip -4 route show to default dev $DEV) [[ $IP != ipv6 && -n $EXIST ]] && run ip -4 route flush default dev $DEV done for GW6 in ${GATEWAY6[@]}; do @@ -659,12 +667,12 @@ gateway_down(){ i=(${x/,/ }) [[ -z ${i[1]} ]] && DEV=${IFNAME[$i]} || DEV=${IFNAME[$i]}.${VLANID[$x]} IP=${PROTOCOL[$x]:-ipv4} - EXIST=$(ip -6 route show default dev $DEV) + EXIST=$(ip -6 route show to default dev $DEV) [[ $IP != ipv4 && -n $EXIST ]] && run ip -6 route flush default dev $DEV done } -# function to start network +# start network start(){ lo_up for INTERFACE in ${IFNAME[@]}; do @@ -673,7 +681,7 @@ start(){ gateway_up } -# function to stop network +# stop network stop(){ gateway_down for INTERFACE in ${IFNAME[@]}; do @@ -682,7 +690,7 @@ stop(){ lo_down } -# function to show network status +# show network status status(){ echo "INTERFACE STATE INFORMATION" echo "========================================================================" @@ -693,38 +701,38 @@ status(){ # STATIC ROUTE FUNCTIONS # ########################## -# function to add static route +# add static route route_up(){ [[ -n $3 ]] && METRIC="metric $3" || METRIC= if [[ $2 == default ]]; then # determine IP protocol & optional device [[ -n ${1##*:*} ]] && IP=-4 || IP=-6 [[ -z ${1##*-*} ]] && DEV="dev ${1#*-}" || DEV= - EXIST=$(ip $IP route show default via ${1%-*} $DEV | grep "$METRIC ") + EXIST=$(ip $IP route show to default via ${1%-*} $DEV | grep "$METRIC ") [[ -z $EXIST ]] && run ip $IP route add default via ${1%-*} $DEV $METRIC elif [[ -n $2 ]]; then # determine IP protocol & gateway syntax [[ -n ${2##*:*} ]] && IP=-4 || IP=-6 [[ -e $SYSTEM/$1 ]] && GW="dev $1" || GW="via $1" - EXIST=$(ip $IP route show $2 $GW | grep "$METRIC ") + EXIST=$(ip $IP route show to $2 $GW | grep "$METRIC ") [[ -z $EXIST ]] && run ip $IP route add $2 $GW $METRIC fi } -# function to delete static route +# delete static route route_down(){ [[ -n $3 ]] && METRIC="metric $3" || METRIC= if [[ $2 == default ]]; then # determine IP protocol & optional device [[ -n ${1##*:*} ]] && IP=-4 || IP=-6 [[ -z ${1##*-*} ]] && DEV="dev ${1#*-}" || DEV= - EXIST=$(ip $IP route show default via ${1%-*} $DEV) + EXIST=$(ip $IP route show to default via ${1%-*} $DEV) [[ -n $EXIST ]] && run ip $IP route del default via ${1%-*} $DEV $METRIC elif [[ -n $2 ]]; then # determine IP protocol & gateway syntax [[ -n ${2##*:*} ]] && IP=-4 || IP=-6 [[ -e $SYSTEM/$1 ]] && GW="dev $1" || GW="via $1" - EXIST=$(ip $IP route show $2 $GW) + EXIST=$(ip $IP route show to $2 $GW) [[ -n $EXIST ]] && run ip $IP route del $2 $GW $METRIC fi } diff --git a/etc/rc.d/rc.library.source b/etc/rc.d/rc.library.source index 99861be3b4..fb5f5f9d03 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.local b/etc/rc.d/rc.local index af02d607c2..b43f02b5c1 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 @@ -184,7 +189,7 @@ else if [[ -f "$PRIORITY_PLUGIN_PATH" ]]; then /usr/local/sbin/plugin install "$PRIORITY_PLUGIN_PATH" | log fi - done + done # Install remaining plugins shopt -s nullglob for PLUGIN in $CONFIG/plugins/*.plg; do diff --git a/etc/rc.d/rc.nginx b/etc/rc.d/rc.nginx index 0f903a5699..c9298385ea 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 @@ -716,7 +716,7 @@ nginx_start(){ # side-load unraid-api unraid_api_control start # resume nchan publishers - /usr/local/sbin/monitor_nchan start + /usr/local/sbin/monitor_nchan start rm -f /tmp/publishPaused if nginx_running; then REPLY="Started"; else REPLY="Failed"; fi diff --git a/etc/rc.d/rc.wireless b/etc/rc.d/rc.wireless index c2f419784e..8e16249ce2 100755 --- a/etc/rc.d/rc.wireless +++ b/etc/rc.d/rc.wireless @@ -10,8 +10,10 @@ 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" WPA="/etc/wpa_supplicant.conf" # system network references @@ -28,6 +30,16 @@ 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 +} + # translate security to informational text trans(){ case "$1" in @@ -126,13 +138,21 @@ 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 + 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 - [[ -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 +168,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 +269,25 @@ wifi_stop(){ log "$DAEMON... No Wifi present." return fi - IP=ipv4 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 + 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 + # restart services when static assignments + [[ $SRV4 == no && (-z $SRV6 || $SRV6 == no) ]] && $SERVICES 5 if ! wifi_running; then REPLY="Stopped"; else REPLY="Failed"; fi log "$DAEMON... $REPLY." } @@ -309,6 +331,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 +340,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) ]] && $SERVICES 5 if wifi_running; then if [[ -z $CC ]]; then CC=($(iw reg get | grep -Po '^country \K..')) diff --git a/sbin/create_network_ini b/sbin/create_network_ini index afe6c39e17..7fee9fe628 100755 --- a/sbin/create_network_ini +++ b/sbin/create_network_ini @@ -13,23 +13,42 @@ [[ (-z $reason && -z $1) || (-n $reason && ! "BOUND6 IPV4LL EXPIRE" =~ $reason) ]] && exit 0 -INI=/var/local/emhttp/network.ini.new -CFG=/boot/config/network.cfg -SYS=/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 # run & log functions . /etc/rc.d/rc.runlog -mask(){ +# 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 - # 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 + 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 @@ -127,10 +148,10 @@ for ((i=0; i<${SYSNICS:-1}; i++)); do echo "USE_GW4:0=\"${USE_GW4[$i]}\"" >>$INI 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}')) - GW=$(ip -4 route show default dev $IFACE | awk '{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 to 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,13 +160,16 @@ 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 + IPV4="$(ip -4 -br addr show scope global primary dev $IFACE | awk '{$2="";print;exit}')" + [[ -n $IPV4 ]] && echo "$IPV4" >>$STA 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}')) - GW6=$(ip -6 route show default dev $IFACE | awk '{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 to default dev $IFACE | awk '{print $3;exit}') echo "IPADDR6:0=\"${NET6[0]}\"" >>$INI echo "NETMASK6:0=\"${NET6[1]}\"" >>$INI echo "GATEWAY6:0=\"$GW6\"" >>$INI @@ -158,6 +182,9 @@ 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 ipv6 assignment + IPV6="$(ip -6 -br addr show scope global primary -deprecated dev $IFACE | awk '{$2="";print;exit}')" + [[ -n $IPV6 ]] && echo "$IPV6" >>$STA fi echo "USE_MTU=\"${USE_MTU[$i]}\"" >>$INI echo "MTU=\"${MTU[$i]}\"" >>$INI @@ -172,11 +199,11 @@ for ((i=0; i<${SYSNICS:-1}; i++)); do echo "USE_GW4:$j=\"${USE_GW4[$i,$j]}\"" >>$INI 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}')) - GW=$(ip -4 route show default dev $DEV | awk '{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 to 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,14 +212,17 @@ 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 ipv4 assignment + IPV4="$(ip -4 -br addr show scope global primary dev $DEV | awk '{$2="";print;exit}')" + [[ -n $IPV4 ]] && echo "$IPV4" >>$STA 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}')) - GW6=$(ip -6 route show default dev $DEV | awk '{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 to default dev $DEV | awk '{print $3;exit}') echo "IPADDR6:$j=\"${NET6[0]}\"" >>$INI echo "NETMASK6:$j=\"${NET6[1]}\"" >>$INI echo "GATEWAY6:$j=\"$GW6\"" >>$INI @@ -205,6 +235,9 @@ 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 + IPV6="$(ip -6 -br addr show scope global primary -deprecated dev $DEV | awk '{$2="";print;exit}')" + [[ -n $IPV6 ]] && echo "$IPV6" >>$STA fi done else @@ -214,6 +247,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 +276,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 0000000000..331a021fb7 --- /dev/null +++ b/sbin/monitor_interface @@ -0,0 +1,69 @@ +#!/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 status + [[ -z $1 ]] && return 1 + status=3 + # state should stay different for at least 3 seconds + for n in {1..3}; do + [[ $(state $1) != $2 ]] && ((status--)) + sleep 1 + done + [[ $status -eq 0 ]] +} + +init(){ + PORT=(); STATE=(); + if [[ -r $FILE ]]; then + # initialize values from file, maintained by 'create_network_ini' + while IFS=$'\n' read -r ROW; do + PORT+=("$ROW") + STATE+=($(state ${ROW%% *})) + done <$FILE + fi + MD5=$(md5) +} + +while :; do + # monitor file content changes + [[ $MD5 != $(md5) ]] && init + LAST= + for i in ${!PORT[@]}; do + INT=${PORT[$i]%% *} + # did interface state change? + if switch $INT ${STATE[$i]}; then + NEW=$(state $INT) + STATE[$i]=$NEW + if [[ $NEW == up ]]; then + ip addr add dev ${PORT[$i]} + elif [[ $NEW == down && $INT != $LAST ]]; then + ip addr flush scope global dev $INT + fi + fi + LAST=$INT + done + # check every 3 seconds + sleep 3 +done & diff --git a/sbin/monitor_nchan b/sbin/monitor_nchan index 76d50e7691..dc61e7debc 100755 --- a/sbin/monitor_nchan +++ b/sbin/monitor_nchan @@ -7,6 +7,21 @@ status=http://localhost/pub/session?buffer_length=1 # nchan information about G nchan_list=/tmp/nchan_list.tmp nchan_id=$(basename "$0") +nchan_subs(){ + curl -m2 --unix-socket $nginx $status 2>/dev/null | grep -Pom1 'subscribers: \K\d+' +} + +nchan_idle(){ + local n idle subs + idle=3 + for n in {1..3}; do + subs=$(nchan_subs) + [[ -z $subs || $subs =~ ^[0-9]+$ && $subs -eq 0 ]] && ((idle--)) + sleep 3 + done + [[ $idle -eq 0 ]] +} + nchan_stop() { echo -n >$nchan_list while IFS=$'\n' read -r nchan; do @@ -49,26 +64,18 @@ start=$(date +%s) while :; do # only act when GUI registered nchan processes are running if [[ -s $nchan_pid ]]; then - # get number of GUI nchan subscribers - subs=$(curl --unix-socket $nginx $status 2>/dev/null | grep -Pom1 'subscribers: \K\d+') - if [[ -z $subs || $subs -eq 0 ]]; then - sleep 5 - # steady state? - subs=$(curl --unix-socket $nginx $status 2>/dev/null | grep -Pom1 'subscribers: \K\d+') - if [[ -z $subs || $subs -eq 0 ]]; then - now=$(date +%s) - # log at 1 hour interval - if [[ $((now-start)) -ge 3600 ]]; then - logger -t $nchan_id -- "Stop running nchan processes" - start=$now - fi - nchan_stop - # empty GUI registered list & statistics - rm -f $nchan_pid $disk_load + if nchan_idle; then + now=$(date +%s) + # log at 1 hour interval + if [[ $((now-start)) -ge 3600 ]]; then + logger -t $nchan_id -- "Stop running nchan processes" + start=$now fi + nchan_stop + # empty GUI registered list & statistics + rm -f $nchan_pid $disk_load fi fi # check every 30 seconds sleep 30 done & -disown %% From c710cf4a1afb90f4a8d30410d41a92afbc7fc1e1 Mon Sep 17 00:00:00 2001 From: ljm42 Date: Fri, 30 May 2025 09:55:22 -0700 Subject: [PATCH 03/38] backport CodeRabbit suggestions from #2215 --- emhttp/plugins/dynamix/scripts/update_services | 12 ++++++++++-- sbin/monitor_nchan | 2 +- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/emhttp/plugins/dynamix/scripts/update_services b/emhttp/plugins/dynamix/scripts/update_services index 4fbebbb2a7..652e555b2d 100755 --- a/emhttp/plugins/dynamix/scripts/update_services +++ b/emhttp/plugins/dynamix/scripts/update_services @@ -15,6 +15,14 @@ else log "no queued job present" fi -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" +# Validate delay parameter is numeric +if [[ -n $1 && ! $1 =~ ^[0-9]+$ ]]; then + log "invalid delay parameter: $1, using default" + DELAY=1 +else + DELAY=${1:-1} +fi + +echo "sleep $DELAY; /usr/local/emhttp/webGui/scripts/reload_services" | at -M now 2>/dev/null +log "queue new job $(queue), wait for ${DELAY}s" exit 0 diff --git a/sbin/monitor_nchan b/sbin/monitor_nchan index dc61e7debc..297af5632a 100755 --- a/sbin/monitor_nchan +++ b/sbin/monitor_nchan @@ -16,7 +16,7 @@ nchan_idle(){ idle=3 for n in {1..3}; do subs=$(nchan_subs) - [[ -z $subs || $subs =~ ^[0-9]+$ && $subs -eq 0 ]] && ((idle--)) + [[ -z $subs || ( $subs =~ ^[0-9]+$ && $subs -eq 0 ) ]] && ((idle--)) sleep 3 done [[ $idle -eq 0 ]] From 7363f4e500d6d2b2fe9d8dbbb64a7a3768526650 Mon Sep 17 00:00:00 2001 From: Squidly271 Date: Fri, 30 May 2025 21:08:59 -0400 Subject: [PATCH 04/38] Fix: Revert allow docker context menus above or below Revert as browser zoom levels (and mobile) can result in the context menu appearing above with the top items rendered off the screen. Better to not render the last item(s) by always having the menu appear below than the important ones rendered above and unable to select --- emhttp/plugins/dynamix.docker.manager/javascript/docker.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/emhttp/plugins/dynamix.docker.manager/javascript/docker.js b/emhttp/plugins/dynamix.docker.manager/javascript/docker.js index 7b170ac088..f08ea86ed8 100644 --- a/emhttp/plugins/dynamix.docker.manager/javascript/docker.js +++ b/emhttp/plugins/dynamix.docker.manager/javascript/docker.js @@ -2,7 +2,7 @@ var eventURL = '/plugins/dynamix.docker.manager/include/Events.php'; function addDockerContainerContext(container, image, template, started, paused, update, autostart, webui, tswebui, shell, id, Support, Project, Registry, donateLink, ReadMe) { var opts = []; - context.settings({right:false,above:'auto'}); + context.settings({right:false,above:false}); if (started && !paused) { if (webui !== '' && webui != '#') opts.push({text:_('WebUI'), icon:'fa-globe', action:function(e){e.preventDefault();window.open(webui,'_blank');}}); if (tswebui !== '' && tswebui != '#') opts.push({text:_('Tailscale WebUI'), icon:'fa-globe', action:function(e){e.preventDefault();window.open(tswebui,'_blank');}}); From ef49c7e6b5f0c022f28e37f5565d1fded8dc8f4d Mon Sep 17 00:00:00 2001 From: ljm42 Date: Sat, 31 May 2025 10:17:09 -0700 Subject: [PATCH 05/38] Backport to 7.1: fix for encryption passphrase sometimes incorrect after updating * Backport networking default gateway unselected after refreshing page * Backport docker: DHCP range for custom networks starts at /25 instead of /16 --- .../DockerSettings.page | 2 +- emhttp/plugins/dynamix/ArrayOperation.page | 32 ++++++---- emhttp/plugins/dynamix/DiskSettings.page | 31 +++++++--- emhttp/plugins/dynamix/Eth0.page | 2 +- emhttp/plugins/dynamix/EthX.page | 4 +- emhttp/plugins/dynamix/include/Helpers.php | 21 ++++--- emhttp/plugins/dynamix/include/KeyUpload.php | 18 ++---- emhttp/plugins/dynamix/include/Wrappers.php | 32 +++++----- .../dynamix/include/update.encryption.php | 62 ++++++++++--------- emhttp/plugins/dynamix/nchan/device_list | 10 ++- 10 files changed, 120 insertions(+), 94 deletions(-) diff --git a/emhttp/plugins/dynamix.docker.manager/DockerSettings.page b/emhttp/plugins/dynamix.docker.manager/DockerSettings.page index 0203a7f896..6fe1cdb781 100644 --- a/emhttp/plugins/dynamix.docker.manager/DockerSettings.page +++ b/emhttp/plugins/dynamix.docker.manager/DockerSettings.page @@ -381,7 +381,7 @@ _(IPv4 custom network on interface)_ (_(optional)_): : > **_(Subnet)_:** >/ + **_(Gateway)_:** " title="_(IPv4 address A.B.C.D)_"> > diff --git a/emhttp/plugins/dynamix/ArrayOperation.page b/emhttp/plugins/dynamix/ArrayOperation.page index 33189fbb29..d77c3faf74 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/Eth0.page b/emhttp/plugins/dynamix/Eth0.page index 680f9fbd76..a48d4da848 100644 --- a/emhttp/plugins/dynamix/Eth0.page +++ b/emhttp/plugins/dynamix/Eth0.page @@ -813,7 +813,7 @@ _(IPv4 address assignment)_: - > + > :eth_ipv4_address_assignment_help: diff --git a/emhttp/plugins/dynamix/EthX.page b/emhttp/plugins/dynamix/EthX.page index 27d369ebe9..3061220fd2 100644 --- a/emhttp/plugins/dynamix/EthX.page +++ b/emhttp/plugins/dynamix/EthX.page @@ -171,7 +171,7 @@ _(IPv4 address assignment)_: - > + > :eth_ipv4_address_assignment_help: @@ -278,7 +278,7 @@ _(IPv4 address assignment)_: - > + > :eth_ipv4_address_assignment_help: 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 77c9a9ee61..b430ee17f1 100644 --- a/emhttp/plugins/dynamix/include/Wrappers.php +++ b/emhttp/plugins/dynamix/include/Wrappers.php @@ -25,14 +25,13 @@ function file_put_contents_atomic($filename,$data) { while (true) { $suffix = rand(); - if ( ! is_file("$filename$suffix") ) - break; + if (!is_file("$filename$suffix")) break; } $renResult = false; $writeResult = @file_put_contents("$filename$suffix",$data) === strlen($data); - if ( $writeResult ) + if ($writeResult) $renResult = @rename("$filename$suffix",$filename); - if ( ! $writeResult || ! $renResult ) { + if (!$writeResult || !$renResult) { my_logger("File_put_contents_atomic failed to write / rename $filename"); @unlink("$filename$suffix"); return false; @@ -74,13 +73,13 @@ function agent_fullname($agent, $state) { function get_plugin_attr($attr, $file) { global $docroot; exec("$docroot/plugins/dynamix.plugin.manager/scripts/plugin ".escapeshellarg($attr)." ".escapeshellarg($file), $result, $error); - if ($error===0) return $result[0]; + if ($error === 0) return $result[0]; } function plugin_update_available($plugin, $os=false) { $local = get_plugin_attr('version', "/var/log/plugins/$plugin.plg"); $remote = get_plugin_attr('version', "/tmp/plugins/$plugin.plg"); - if ($remote && strcmp($remote,$local)>0) { + if ($remote && strcmp($remote,$local) > 0) { if ($os) return $remote; if (!$unraid = get_plugin_attr('Unraid', "/tmp/plugins/$plugin.plg")) return $remote; $server = get_plugin_attr('version', "/var/log/plugins/unRAIDServer.plg"); @@ -102,7 +101,7 @@ function fahrenheit($temp) { function displayTemp($temp) { global $display; - return (is_numeric($temp) && _var($display,'unit')=='F') ? fahrenheit($temp) : $temp; + return (is_numeric($temp) && _var($display,'unit') == 'F') ? fahrenheit($temp) : $temp; } function get_value(&$name, $key, $default) { @@ -217,11 +216,10 @@ function my_logger($message, $logger='webgui') { * @param ?array $getinfo Empty array passed by reference, will contain results of curl_getinfo and curl_error, or null if not needed * @return string|false $out The fetched content */ -function http_get_contents(string $url, array $opts = [], ?array &$getinfo = NULL) { +function http_get_contents(string $url, array $opts=[], ?array &$getinfo=NULL) { $ch = curl_init(); - if(isset($getinfo)) { - curl_setopt($ch, CURLINFO_HEADER_OUT, TRUE); - } + if (isset($getinfo)) + curl_setopt($ch, CURLINFO_HEADER_OUT, true); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_FRESH_CONNECT, true); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); @@ -232,8 +230,8 @@ function http_get_contents(string $url, array $opts = [], ?array &$getinfo = NUL curl_setopt($ch, CURLOPT_REFERER, ""); curl_setopt($ch, CURLOPT_FAILONERROR, true); curl_setopt($ch, CURLOPT_USERAGENT, 'Unraid'); - if(is_array($opts) && $opts) { - foreach($opts as $key => $val) { + if (is_array($opts) && count($opts) > 0) { + foreach ($opts as $key => $val) { curl_setopt($ch, $key, $val); } } @@ -247,8 +245,8 @@ function http_get_contents(string $url, array $opts = [], ?array &$getinfo = NUL $getinfo = curl_getinfo($ch); } if ($errno = curl_errno($ch)) { - $msg = "Curl error $errno: " . (curl_error($ch) ?: curl_strerror($errno)) . ". Requested url: '$url'"; - if(isset($getinfo)) { + $msg = "Curl error $errno: ".(curl_error($ch) ?: curl_strerror($errno)).". Requested url: '$url'"; + if (isset($getinfo)) { $getinfo['error'] = $msg; } my_logger($msg, "http_get_contents"); @@ -272,4 +270,8 @@ function lan_port($port, $state=false) { $exist = file_exists("$system/$port"); return !$state ? $exist : ($exist ? (@file_get_contents("$system/$port/carrier") ?: 0) : false); } + +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 4b291d0322..e16bacf3d3 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: From adce4957aaa4a82ac4695ffce5ec41d5201f35a1 Mon Sep 17 00:00:00 2001 From: ljm42 Date: Wed, 4 Jun 2025 08:09:29 -0700 Subject: [PATCH 06/38] Backport: Encryption: fix regression error - keyfile not deleted --- emhttp/plugins/dynamix/include/KeyUpload.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/emhttp/plugins/dynamix/include/KeyUpload.php b/emhttp/plugins/dynamix/include/KeyUpload.php index dd2bce1cf9..75846a9a02 100644 --- a/emhttp/plugins/dynamix/include/KeyUpload.php +++ b/emhttp/plugins/dynamix/include/KeyUpload.php @@ -18,7 +18,7 @@ if ($file) { file_put_contents($luks, base64_decode(explode(';base64,',$file)[1])); -} elseif ($text && file_exists($luks)) { +} elseif (file_exists($luks)) { unlink($luks); } $save = false; From 553c398b7b4f4e8616491df501a81a4b076ac1be Mon Sep 17 00:00:00 2001 From: Tom Mortensen Date: Mon, 2 Jun 2025 09:50:23 -0700 Subject: [PATCH 07/38] feat: mover: second pass: only process directories --- sbin/mover | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sbin/mover b/sbin/mover index 23ad65978a..bab99064bd 100755 --- a/sbin/mover +++ b/sbin/mover @@ -29,7 +29,7 @@ DEBUGGING="" move() { find "$1" -depth 2>/dev/null | /usr/libexec/unraid/move $2 $DEBUGGING # second pass to clean up leftover empty directories - find "$1" -depth 2>/dev/null | /usr/libexec/unraid/move $2 $DEBUGGING + find "$1" -depth -type d 2>/dev/null | /usr/libexec/unraid/move $2 $DEBUGGING } start() { From 0a5242f24bdf7b0acc68a47223d2f6042d42d092 Mon Sep 17 00:00:00 2001 From: Tom Mortensen Date: Wed, 4 Jun 2025 09:32:27 -0700 Subject: [PATCH 08/38] ./sbin/monitor_interface needs to be 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 1fd6a2262f38936a9beecfd3797995e3bad7fd13 Mon Sep 17 00:00:00 2001 From: bergware Date: Sat, 7 Jun 2025 13:44:19 +0200 Subject: [PATCH 09/38] Backport miscellaneous fixes to Unraid 7.1 --- .../DockerSettings.page | 140 +++++------------- .../include/libvirt_helpers.php | 11 +- .../templates/Custom.form.php | 19 ++- .../templates/XML_Expert.form.php | 8 +- emhttp/plugins/dynamix/BrowseButton.page | 7 +- emhttp/plugins/dynamix/Eth0.page | 14 +- emhttp/plugins/dynamix/EthX.page | 8 +- etc/rc.d/rc.docker | 21 +-- etc/rc.d/rc.inet1 | 34 +++-- etc/rc.d/rc.wireless | 15 +- sbin/create_network_ini | 30 ++-- sbin/monitor_interface | 87 +++++++---- 12 files changed, 179 insertions(+), 215 deletions(-) diff --git a/emhttp/plugins/dynamix.docker.manager/DockerSettings.page b/emhttp/plugins/dynamix.docker.manager/DockerSettings.page index 6fe1cdb781..b6072ab567 100644 --- a/emhttp/plugins/dynamix.docker.manager/DockerSettings.page +++ b/emhttp/plugins/dynamix.docker.manager/DockerSettings.page @@ -25,23 +25,23 @@ exec("/etc/rc.d/rc.docker status >/dev/null",$dummy,$DockerStopped); function strposX($s, $c, $n=1) { $p = 0; - while ($n && $p=strpos($s,$c,$p)!==false) {$n--; $p+=strlen($c);} + while ($n && $p = strpos($s,$c,$p) !== false) {$n--; $p += strlen($c);} return $p; } unset($custom,$other); -exec("ls --indicator-style=none /sys/class/net|grep -P '^br[0-9]'",$custom); -exec("ls --indicator-style=none /sys/class/net|grep -P '^(bond|eth|wlan)[0-9]'",$other); -$bridge = count($custom)>0; +exec("ls --indicator-style=none /sys/class/net | grep -P '^br[0-9]'",$custom); +exec("ls --indicator-style=none /sys/class/net | grep -P '^(bond|eth|wlan)[0-9]'",$other); +$bridge = count($custom) > 0; $slaves = []; foreach ($other as $network) { - if (substr($network,0,4)=='bond') { + if (substr($network,0,4) == 'bond') { $br = str_replace('bond','br',$network); $bond = "/sys/class/net/$network/bonding/slaves"; if (file_exists($bond)) $slaves = array_merge($slaves,explode(' ',str_replace("\n","",file_get_contents($bond)))); if (!in_array($br,$custom)) $custom[] = $network; - } elseif (substr($network,0,3)=='eth') { + } elseif ($bridge && substr($network,0,3) == 'eth') { $br = str_replace('eth','br',$network); $bond = str_replace('eth','bond',$network); if (!in_array($br,$custom) && !in_array($bond,$custom)) $custom[] = $network; @@ -50,18 +50,18 @@ foreach ($other as $network) { } } -$include = $include6 = $address = $address6 = $gateway = $gateway6 = $unset = $protocol = []; -$wide = false; -$wlan = (array)@parse_ini_file('/var/local/emhttp/wireless.ini'); +$include = $include6 = $address = $address6 = $gateway = $gateway6 = $unset = $protocol = []; +$wide = false; +$wlan = (array)@parse_ini_file('/var/local/emhttp/wireless.ini'); foreach ($custom as $network) { if (in_array($network,$slaves)) continue; - $ip4 = exec("ip -4 -br addr show $network scope global | awk '{print $3;exit}'"); - $ip6 = exec("ip -6 -br addr show $network scope global -temporary -deprecated | awk '{print $3;exit}'"); - $gw4 = $ip4 ? exec("ip -4 route show dev $network default | awk '{print $3;exit}'") : ''; - $gw6 = $ip6 ? exec("ip -6 route show dev $network default | awk '{print $3;exit}'") : ''; - $route4 = $ip4 ? exec("ip -4 route show dev $network $ip4 | awk '{print $1;exit}'") : ''; - $route6 = $ip6 ? exec("ip -6 route show dev $network | awk '/^".substr($ip6,0,strposX($ip6,':',4))."/{print $1;exit}'") : ''; + $ip4 = exec("ip -4 -br addr show scope global primary dev $network | awk '{print $3;exit}'"); + $ip6 = exec("ip -6 -br addr show scope global primary -deprecated dev $network | awk '{print $3;exit}'"); + $gw4 = $ip4 ? exec("ip -4 route show to default dev $network | awk '{print $3;exit}'") : ''; + $gw6 = $ip6 ? exec("ip -6 route show to default dev $network | awk '{print $3;exit}'") : ''; + $route4 = $ip4 ? exec("ip -4 route show dev $network | awk '$1 !~ /^default/ {print $1;exit}'") : ''; + $route6 = $ip6 ? exec("ip -6 route show dev $network | awk '$1 !~ /^(default|f[a-f])/ {print $1;exit}'") : ''; if (substr($network,0,4) != 'wlan') { [$eth,$vlan] = my_explode('.',$network); $eth = str_replace(['bond','br'],'eth',$eth); @@ -89,6 +89,7 @@ foreach ($custom as $network) { } if ($protocol[$network] != 'ipv4') $wide = true; } + $ip4class = $wide ? 'ip6' : 'ip4'; $gw4class = $wide ? 'gw6' : 'gw4'; @@ -114,15 +115,6 @@ function base_net($route) { return substr(explode('/',$route)[0],0,-2); } -function hide_wlan($network) { - return $network=='wlan0' && lan_port(DockerUtil::port(),true)==1; -} - -function hide_eth($network) { - $mgmt_port = ['br0','bond0','eth0']; - return in_array($network,$mgmt_port) && lan_port('wlan0',true)==1; -} - $bgcolor = strstr('white,azure',$display['theme']) ? '#f2f2f2' : '#1c1c1c'; //Check if docker.cfg does exist @@ -275,8 +267,8 @@ _(Template Authoring Mode)_: _(Docker custom network type)_: :  _(Please read the Help carefully)_. _(Misconfiguration can cause problems)_. :docker_custom_network_type_help: @@ -302,14 +294,9 @@ _(Preserve user defined networks)_: $net = normalize($network); $docker_auto = "DOCKER_AUTO_$net"; $docker_dhcp = "DOCKER_DHCP_$net"; -$hide_wlan = hide_wlan($network); ?> - -
- - _(IPv4 custom network on interface)_ (_(optional)_): (_(optional)_): **_(DHCP pool)_:**. "; - for ($n=$net[$b]; $n<=$max[$b]; $n++) echo mk_option($net_user[$b],$n,$n,$n%$step==0?'':'class="hide"'); + for ($n = $net[$b]; $n <= $max[$b]; $n++) echo mk_option($net_user[$b],$n,$n,$n%$step==0?'':'class="hide"'); echo ""; } echo "/ "; echo "($size "._('hosts').")"; echo ""; ?> - -
- @@ -370,48 +354,35 @@ $port = normalize($network); [$range,$size] = my_explode('/',_var($dockercfg,"DOCKER_RANGE_$port")); $disabled = $subnet ? '':'disabled'; $dhcpDisabled = $range ? '':'disabled'; -$hide_eth = hide_eth($network); ?> - - -
- + _(IPv4 custom network on interface)_ (_(optional)_): : > **_(Subnet)_:** >/ + **_(Gateway)_:** " title="_(IPv4 address A.B.C.D)_"> > **_(DHCP pool)_:** >/ + ( _(hosts)_) - - -
:docker_exclude_interface_vlan_ipv4_help: - - -
$route):?> - -
- + _(IPv6 custom network on interface)_ (_(optional)_): (_(optional)_): **_(Subnet)_:** **_(Gateway)_:** - -
@@ -444,12 +413,8 @@ $port = normalize($network); [$range6,$size6] = my_explode('/',_var($dockercfg,"DOCKER_RANGE6_$port")); $disabled = $subnet6 ? '':'disabled'; $dhcpDisabled = $range6 ? '':'disabled'; -$hide_eth = hide_eth($network); ?> - -
- _(IPv6 custom network on interface)_ (_(optional)_): : > @@ -458,9 +423,6 @@ _(IPv6 custom network on interface)_ (_(optional)_): **_(Gateway)_:**" title="_(IPv6 address nnnn:xxxx::yyyy)_"> - -
- @@ -518,32 +480,24 @@ _(Preserve user defined networks)_: $route):?> - -
- _(IPv4 custom network on interface)_ : : **_(Subnet)_:** **_(Gateway)_:** **_(DHCP pool)_:**   ( _(hosts)_) - -
- - -
- _(IPv4 custom network on interface)_ : : **_(Subnet)_:** / **_(Gateway)_:** **_(DHCP pool)_:**   ( _(hosts)_) - -
- $route):?> +if (isset($dockercfg[$docker_dhcp6]) || empty($dockercfg["DOCKER_AUTO_$net"]) || $dockercfg["DOCKER_AUTO_$net"] != 'no'):?> - -
- _(IPv6 custom network on interface)_ : : **_(Subnet)_:** **_(Gateway)_:** - -
- - -
- _(IPv6 custom network on interface)_ : : **_(Subnet)_:** / **_(Gateway)_:** - -
-
diff --git a/emhttp/plugins/dynamix.vm.manager/include/libvirt_helpers.php b/emhttp/plugins/dynamix.vm.manager/include/libvirt_helpers.php index e5b7be2ebc..6a3bf8f0bd 100644 --- a/emhttp/plugins/dynamix.vm.manager/include/libvirt_helpers.php +++ b/emhttp/plugins/dynamix.vm.manager/include/libvirt_helpers.php @@ -1230,9 +1230,8 @@ function getHostCPUModel() { function getValidNetworks() { global $lv; $arrValidNetworks = []; + exec("ls --indicator-style=none /sys/class/net | grep -Po '^virbr[0-9]+'",$arrBridges); exec("ls --indicator-style=none /sys/class/net | grep -Po '^(br|bond|eth|wlan)[0-9]+(\.[0-9]+)?'",$arrBridges); - // add 'virbr0' as default first choice - array_unshift($arrBridges, 'virbr0'); // remove redundant references of bridge and bond interfaces $remove = []; foreach ($arrBridges as $name) { @@ -1240,7 +1239,7 @@ function getValidNetworks() { $remove = array_merge($remove, (array)@file("/sys/class/net/$name/bonding/slaves",FILE_IGNORE_NEW_LINES)); } elseif (substr($name,0,2) == 'br') { $remove = array_merge($remove, array_map(function($n){return end(explode('/',$n));}, glob("/sys/class/net/$name/brif/*"))); - } + } } $arrValidNetworks['bridges'] = array_diff($arrBridges, $remove); @@ -1845,15 +1844,15 @@ function vm_clone($vm, $clone ,$overwrite,$start,$edit, $free, $waitID) { $rtn = $lv->domain_define($xml); if (is_resource($rtn)) { - $arrResponse = ['success' => true]; + $arrResponse = ['success' => true]; write("addLog\0".htmlspecialchars(_("Creating XML successful"))); - } else { + } else { $lastvmerror = $lv->get_last_error(); $arrResponse = ['xml' => $xml,'error' => $lastvmerror]; write("addLog\0".htmlspecialchars(_("Creating XML Error:$lastvmerror"))); file_put_contents("/tmp/vmclonertn.debug", json_encode($arrResponse,JSON_PRETTY_PRINT)); } - + return($rtn); } diff --git a/emhttp/plugins/dynamix.vm.manager/templates/Custom.form.php b/emhttp/plugins/dynamix.vm.manager/templates/Custom.form.php index 3d3f0c5d5d..f576a78d24 100644 --- a/emhttp/plugins/dynamix.vm.manager/templates/Custom.form.php +++ b/emhttp/plugins/dynamix.vm.manager/templates/Custom.form.php @@ -40,6 +40,9 @@ $strCPUModel = getHostCPUModel(); $templateslocation = "/boot/config/plugins/dynamix.vm.manager/savedtemplates.json"; +// get MAC address of wireless interface (if existing) +$mac = file_exists('/sys/class/net/wlan0/address') ? trim(file_get_contents('/sys/class/net/wlan0/address')) : ''; + if (is_file($templateslocation)){ $arrAllTemplates["User-templates"] = ""; $ut = json_decode(file_get_contents($templateslocation),true); @@ -352,7 +355,7 @@ - + @@ -2017,13 +2020,17 @@ var storageType = ""; var storageLoc = ""; -function updateMAC(index,port) { - $('input[name="nic['+index+'][mac]"').prop('disabled',port=='wlan0'); - $('i.mac_generate.'+index).prop('disabled',port=='wlan0'); +function updateMAC(index, port) { + var wlan0 = ''; // mac address of wlan0 + var mac = $('input[name="nic['+index+'][mac]"'); + mac.prop('disabled', port=='wlan0'); + $('i.mac_generate.'+index).prop('disabled', port=='wlan0'); $('span.wlan0').removeClass('hidden'); - if (port != 'wlan0') { + if (port == 'wlan0') { + mac.val(wlan0); + } else { $('span.wlan0').addClass('hidden'); - $('i.mac_generate.'+index).click(); + if (wlan0 && mac.val()==wlan0) $('i.mac_generate.'+index).click(); } } diff --git a/emhttp/plugins/dynamix.vm.manager/templates/XML_Expert.form.php b/emhttp/plugins/dynamix.vm.manager/templates/XML_Expert.form.php index 900c057334..cbc2bc279a 100644 --- a/emhttp/plugins/dynamix.vm.manager/templates/XML_Expert.form.php +++ b/emhttp/plugins/dynamix.vm.manager/templates/XML_Expert.form.php @@ -45,7 +45,7 @@ exit; } - + // create new VM template if (isset($_POST['createvmtemplate'])) { $reply = addtemplatexml($_POST); @@ -116,7 +116,7 @@ - + @@ -217,12 +217,12 @@ function completeIfInTag(cm) { $button.val($button.attr('busyvalue')); swal({ title: "_(Template Name)_", - text: "_(Enter name:\nIf name already exists it will be replaced.)_", + text: "_(Enter name)_:\n_(If name already exists it will be replaced)_.", type: "input", showCancelButton: true, closeOnConfirm: false, //animation: "slide-from-top", - inputPlaceholder: "_(Leaving blank will use OS name.)_" + inputPlaceholder: "_(Leaving blank will use OS name)_." }, function(inputValue){ postdata=postdata+"&templatename="+inputValue; diff --git a/emhttp/plugins/dynamix/BrowseButton.page b/emhttp/plugins/dynamix/BrowseButton.page index 118ee6f19f..54aa3a1685 100644 --- a/emhttp/plugins/dynamix/BrowseButton.page +++ b/emhttp/plugins/dynamix/BrowseButton.page @@ -47,19 +47,16 @@ var dfm_read = {}; function dfm_footer(action, text) { switch (action) { case 'show': - $('#countdown').show(); $('#user-notice').show(); break; case 'hide': - $('#countdown').hide(); $('#user-notice').hide(); break; case 'write': - if ($('#countdown').html() == '') $('#countdown').html(''); - $('#user-notice').html(text); + let icon = ''; + $('#user-notice').html(icon + text); break; case 'clear': - $('#countdown').html(''); $('#user-notice').html(''); break; } diff --git a/emhttp/plugins/dynamix/Eth0.page b/emhttp/plugins/dynamix/Eth0.page index a48d4da848..8afecd4e89 100644 --- a/emhttp/plugins/dynamix/Eth0.page +++ b/emhttp/plugins/dynamix/Eth0.page @@ -15,7 +15,7 @@ Tag="icon-ethernet" */ ?> /dev/null"); - return 1000 + ($index ?: exec("cat $system/*/ifindex | sort -n | tail -1") + 1); + return $index ?: exec("cat $system/*/ifindex | sort -n | tail -1") + 1; } // remove non-existing ethernet ports @@ -204,7 +204,7 @@ function prepareSettings(form) { $(form).find('select[name^="USE_DHCP:"]').each(function() { var i = $(this).prop('name').split(':')[1]; var protocol = $(form).find('select[name="PROTOCOL:'+i+'"]').val() || 'ipv4'; - var gw4 = (port == 'eth0') ? true : $(form).find('input[name="USE_GW4:'+i+'"]').prop('checked'); + var gw4 = (port == 'eth0' && i == 0) ? true : $(form).find('input[name="USE_GW4:'+i+'"]').prop('checked'); if (protocol != 'ipv6' && $(this).val() != 'no') { $(form).find('input[name="IPADDR:'+i+'"]').val(''); $(form).find('input[name="GATEWAY:'+i+'"]').val(''); @@ -214,7 +214,7 @@ function prepareSettings(form) { $(form).find('select[name^="USE_DHCP6:"]').each(function() { var i = $(this).prop('name').split(':')[1]; var protocol = $(form).find('select[name="PROTOCOL:'+i+'"]').val() || 'ipv4'; - var gw6 = (port == 'eth0') ? true : $(form).find('input[name="USE_GW6:'+i+'"]').prop('checked'); + var gw6 = (port == 'eth0' && i == 0) ? true : $(form).find('input[name="USE_GW6:'+i+'"]').prop('checked'); if (protocol != 'ipv4' && $(this).val() != 'no') { $(form).find('input[name="IPADDR6:'+i+'"]').val(''); $(form).find('input[name="GATEWAY6:'+i+'"]').val(''); @@ -813,7 +813,7 @@ _(IPv4 address assignment)_: - > + > :eth_ipv4_address_assignment_help: @@ -844,7 +844,7 @@ _(IPv6 address assignment)_: - > + > :eth_ipv6_address_assignment_help: diff --git a/emhttp/plugins/dynamix/EthX.page b/emhttp/plugins/dynamix/EthX.page index 3061220fd2..f702a4588f 100644 --- a/emhttp/plugins/dynamix/EthX.page +++ b/emhttp/plugins/dynamix/EthX.page @@ -171,7 +171,7 @@ _(IPv4 address assignment)_: - > + > :eth_ipv4_address_assignment_help: @@ -200,7 +200,7 @@ _(IPv6 address assignment)_: - > + > :eth_ipv6_address_assignment_help: @@ -278,7 +278,7 @@ _(IPv4 address assignment)_: - > + > :eth_ipv4_address_assignment_help: @@ -307,7 +307,7 @@ _(IPv6 address assignment)_: - > + > :eth_ipv6_address_assignment_help: diff --git a/etc/rc.d/rc.docker b/etc/rc.d/rc.docker index 13632d0afb..389e388a09 100755 --- a/etc/rc.d/rc.docker +++ b/etc/rc.d/rc.docker @@ -35,11 +35,6 @@ TMP=/var/tmp/network.tmp # run & log functions . /etc/rc.d/rc.runlog -# return interface index -index(){ - cat $SYSTEM/$1/ifindex 2>/dev/null -} - # return active interface active(){ if [[ -e $SYSTEM/${1/eth/br} ]]; then @@ -346,7 +341,7 @@ docker_network_start(){ SUBNET=; GATEWAY=; SERVER=; RANGE=; [[ -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 to $IPV4 dev $NETWORK | awk '{print $1;exit}') + SUBNET=$(ip -4 route show dev $NETWORK | awk '$1 !~ /^default/ {print $1;exit}') SERVER=${IPV4%/*} DHCP=${NETWORK/./_} DHCP=DOCKER_DHCP_${DHCP^^} @@ -355,9 +350,9 @@ docker_network_start(){ fi SUBNET6=; GATEWAY6=; SERVER6=; # 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= + [[ -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 '^f[a-f]|^$') || IPV6= if [[ -n $IPV6 ]]; then - SUBNET6=$(ip -6 route show to $IPV6 dev $NETWORK | awk '{print $1;exit}') + SUBNET6=$(ip -6 route show dev $NETWORK | awk '$1 !~ /^(default|f[a-f])/ {print $1;exit}') SERVER6=${IPV6%/*} GATEWAY6=$(ip -6 route show to default dev $NETWORK | awk '{print $3;exit}') # replace link local address for first address in subnet @@ -421,14 +416,13 @@ docker_network_start(){ if [[ $TYPE == br ]]; then LINK=shim-$NETWORK if [[ $DOCKER_ALLOW_ACCESS == yes && -n $IPV4 ]]; then - IPV4="$IPV4 metric $((1000 - 1 + $(index $NETWORK)))" # create shim interface [[ -e $SYSTEM/$LINK ]] || run ip link add link $NETWORK name $LINK type $ATTACH mode $MODE # 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 $IPV4 dev $LINK + run ip addr add $IPV4 dev $LINK metric 0 run ip link set $LINK up log "created network $LINK for host access" elif [[ -e $SYSTEM/$LINK ]]; then @@ -440,22 +434,19 @@ docker_network_start(){ 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 [[ -n $IPV4 && $DOCKER_ALLOW_ACCESS == yes ]]; then # 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 - [[ -z $(ipv4_exist $VHOST ${IPV4%/*}) ]] && run ip addr add $IPV4 metric $INDEX dev $VHOST + [[ -z $(ipv4_exist $VHOST ${IPV4%/*}) ]] && run ip addr add $IPV4 dev $VHOST metric 0 log "created network $VHOST for host access" elif [[ -n $IPV4 && -e $SYSTEM/$VHOST && -n $(ipv4_exist $VHOST ${IPV4%/*}) ]]; then # remove parent IPv4 address from vhost interface - run ip addr del $IPV4 metric $INDEX dev $VHOST + run ip addr del $IPV4 dev $VHOST metric 0 fi fi fi diff --git a/etc/rc.d/rc.inet1 b/etc/rc.d/rc.inet1 index 835b8dd3ec..aa12699d50 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, May 2025 +# Bergware - modified for Unraid OS, June 2025 # Adapted by Bergware for use in Unraid OS - April 2016 # - improved interface configuration @@ -84,6 +84,10 @@ # Adapted by Bergware for use in Unraid OS - May 2025 # - improved metric value to interface IP assignment +# Adapted by Bergware for use in Unraid OS - June 2025 +# - revert metric assignment to static addresses +# - remove duplicate ipv6 parameters + ########### # LOGGING # ########### @@ -324,26 +328,26 @@ ipv6_up(){ ipv6_ra(){ echo $2 >$CONF6/$1/accept_ra echo $2 >$CONF6/$1/accept_ra_defrtr - echo $3 >$CONF6/$1/autoconf + echo $2 >$CONF6/$1/autoconf } # 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 + [[ -d $CONF6/${IFACE/$1/$2} ]] && ipv6_ra ${IFACE/$1/$2} $4 + [[ -d $CONF6/${IFACE/$1/$3} ]] && ipv6_ra ${IFACE/$1/$3} $4 } # enable/disable ipv6 assignment per interface ipv6_addr(){ - [[ -d $CONF6/$IFACE ]] && ipv6_ra $IFACE $1 $2 - [[ -d $CONF6/$VHOST ]] && ipv6_ra $VHOST $1 $2 + [[ -d $CONF6/$IFACE ]] && ipv6_ra $IFACE $1 + [[ -d $CONF6/$VHOST ]] && ipv6_ra $VHOST $1 # repeat action on related interfaces if [[ ${IFACE:0:4} == bond ]]; then - ipv6_conf bond br eth $1 $2 + ipv6_conf bond br eth $1 elif [[ ${IFACE:0:2} == br ]]; then - ipv6_conf br bond eth $1 $2 + ipv6_conf br bond eth $1 else - ipv6_conf eth bond br $1 $2 + ipv6_conf eth bond br $1 fi sleep 1 } @@ -366,7 +370,7 @@ ipaddr_up(){ fi if [[ $DHCP == yes ]]; then # bring up interface using DHCP/SLAAC - [[ -z $RENEW ]] && ipv6_addr 1 1 + [[ -z $RENEW ]] && ipv6_addr 1 DHCP_OPTIONS="-q -n -p -t ${DHCP_TIMEOUT[$i]:-10}" [[ -n $DHCP_HOSTNAME ]] && DHCP_OPTIONS="$DHCP_OPTIONS -h $DHCP_HOSTNAME" [[ $DHCP_KEEP_RESOLV == yes ]] && DHCP_OPTIONS="$DHCP_OPTIONS -C resolv.conf" @@ -393,27 +397,25 @@ ipaddr_up(){ # bring up interface using static IP address 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))})) + ipv6_addr 0 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 metric $INDEX dev $IFACE + [[ -n $MASK ]] && run ip -4 addr add $(unzero $ADDR)/$MASK dev $IFACE metric 1 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 metric $INDEX dev $IFACE + [[ -n $MASK6 ]] && run ip -6 addr add $(unzero6 $ADDR6)/$MASK6 dev $IFACE metric 1 [[ -n $PRIV6 && -d $CONF6/$IFACE ]] && echo 0 >$CONF6/$IFACE/use_tempaddr fi fi else # bring up interface without IP address - ipv6_addr 0 0 + ipv6_addr 0 ipaddr_down fi } diff --git a/etc/rc.d/rc.wireless b/etc/rc.d/rc.wireless index 8e16249ce2..d35744affe 100755 --- a/etc/rc.d/rc.wireless +++ b/etc/rc.d/rc.wireless @@ -6,6 +6,9 @@ # # Bergware - created for Unraid OS, January 2025 +# Adapted by Bergware for use in Unraid OS - June 2025 +# - put metric value at end of assignment + DAEMON="WiFi network" CALLER="wifi" INI="/var/local/emhttp/wireless.ini" @@ -142,17 +145,17 @@ ipaddr_up(){ INDEX=$((3000 + ${INDEX:-$(($(index * | sort -n | tail -1) + 1))})) if [[ $IP == ipv4 ]]; then if [[ -n $IP4 && -n $MASK4 ]]; then - run ip -4 addr add $(unzero $IP4)/$MASK4 metric $INDEX dev $PORT + run ip -4 addr add $(unzero $IP4)/$MASK4 dev $PORT metric $INDEX # 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 + ip addr add $(unzero $IP4)/$MASK4 dev shim-$PORT metric $(($INDEX - 1)) fi fi - [[ -n $GATEWAY4 ]] && run ip -4 route add default via $GATEWAY4 metric $INDEX dev $PORT + [[ -n $GATEWAY4 ]] && run ip -4 route add default via $GATEWAY4 dev $PORT metric $INDEX fi if [[ $IP == ipv6 ]]; then - [[ -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 + [[ -n $IP6 && -n $MASK6 ]] && run ip -6 addr add $(unzero6 $IP6)/$MASK6 dev $PORT metric $INDEX + [[ -n $GATEWAY6 ]] && run ip -6 route add default via $GATEWAY6 dev $PORT metric $INDEX fi fi if [[ $DNS == yes ]]; then @@ -283,7 +286,7 @@ wifi_stop(){ 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 pkill --ns $$ wpa_supplicant run iw dev $PORT disconnect run rm -f $INI # restart services when static assignments diff --git a/sbin/create_network_ini b/sbin/create_network_ini index 7fee9fe628..9fef5aad5b 100755 --- a/sbin/create_network_ini +++ b/sbin/create_network_ini @@ -145,7 +145,6 @@ for ((i=0; i<${SYSNICS:-1}; i++)); do echo "DESCRIPTION:0=\"${DESCRIPTION[$i]}\"" >>$INI echo "PROTOCOL:0=\"${PROTOCOL[$i]}\"" >>$INI echo "USE_DHCP:0=\"${USE_DHCP[$i]}\"" >>$INI - echo "USE_GW4:0=\"${USE_GW4[$i]}\"" >>$INI if [[ ${USE_DHCP[$i]} == yes ]]; then # get dhcp assigned ipv4 address & mask NET=($(ip -4 -br addr show scope global primary dev $IFACE | awk '{sub("/"," ",$3);print $3;exit}')) @@ -162,10 +161,12 @@ for ((i=0; i<${SYSNICS:-1}; i++)); do echo "METRIC:0=\"${METRIC[$i]}\"" >>$INI # store static ipv4 assignment IPV4="$(ip -4 -br addr show scope global primary dev $IFACE | awk '{$2="";print;exit}')" - [[ -n $IPV4 ]] && echo "$IPV4" >>$STA + if [[ -n $IPV4 ]]; then + echo "$IPV4" >>$STA + echo "$IFACE GW4 $(ip -4 route show to default dev $IFACE)" >>$STA + fi 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 scope global primary -deprecated dev $IFACE | awk '{sub("/"," ",$3);print $3;exit}')) @@ -184,21 +185,23 @@ for ((i=0; i<${SYSNICS:-1}; i++)); do echo "PRIVACY6:0=\"\"" >>$INI # store static ipv6 assignment IPV6="$(ip -6 -br addr show scope global primary -deprecated dev $IFACE | awk '{$2="";print;exit}')" - [[ -n $IPV6 ]] && echo "$IPV6" >>$STA + if [[ -n $IPV6 ]]; then + echo "$IPV6" >>$STA + echo "$IFACE GW6 $(ip -6 route show to default dev $IFACE)" >>$STA + fi fi echo "USE_MTU=\"${USE_MTU[$i]}\"" >>$INI echo "MTU=\"${MTU[$i]}\"" >>$INI if [[ -n ${VLANS[$i]} ]]; then # process VLAN interfaces echo "TYPE=\"trunk\"" >>$INI - for ((j=1;j<${VLANS[$i]};j++)); do + for ((j=1; j<${VLANS[$i]}; j++)); do echo "VLANID:$j=\"${VLANID[$i,$j]}\"" >>$INI echo "DESCRIPTION:$j=\"${DESCRIPTION[$i,$j]}\"" >>$INI 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 + DEV=$IFACE.${VLANID[$i,$j]} if [[ ${USE_DHCP[$i,$j]} == yes ]]; then - DEV=$IFACE.${VLANID[$i,$j]} # 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 to default dev $DEV | awk '{print $3;exit}') @@ -214,12 +217,14 @@ for ((i=0; i<${SYSNICS:-1}; i++)); do echo "METRIC:$j=\"${METRIC[$i,$j]}\"" >>$INI # store static ipv4 assignment IPV4="$(ip -4 -br addr show scope global primary dev $DEV | awk '{$2="";print;exit}')" - [[ -n $IPV4 ]] && echo "$IPV4" >>$STA + if [[ -n $IPV4 ]]; then + echo "${IPV4/@$IFACE/}" >>$STA + echo "$DEV GW4 $(ip -4 route show to default dev $DEV)" >>$STA + fi fi echo "USE_DHCP6:$j=\"${USE_DHCP6[$i,$j]}\"" >>$INI - echo "USE_GW6:$j=\"${USE_GW6[$i,$j]}\"" >>$INI + DEV=$IFACE.${VLANID[$i,$j]} if [[ ${USE_DHCP6[$i,$j]} == yes ]]; then - DEV=$IFACE.${VLANID[$i,$j]} # get auto assigned ipv6 address & prefix NET6=($(ip -6 -br addr show scope global primary -deprecated dev $DEV | awk '{sub("/"," ",$3);print $3;exit}')) GW6=$(ip -6 route show to default dev $DEV | awk '{print $3;exit}') @@ -237,7 +242,10 @@ for ((i=0; i<${SYSNICS:-1}; i++)); do echo "PRIVACY6:$j=\"\"" >>$INI # store static ipv6 assignment IPV6="$(ip -6 -br addr show scope global primary -deprecated dev $DEV | awk '{$2="";print;exit}')" - [[ -n $IPV6 ]] && echo "$IPV6" >>$STA + if [[ -n $IPV6 ]]; then + echo "${IPV6/@$IFACE/}" >>$STA + echo "$DEV GW6 $(ip -6 route show to default dev $DEV)" >>$STA + fi fi done else diff --git a/sbin/monitor_interface b/sbin/monitor_interface index 331a021fb7..db826a52fe 100755 --- a/sbin/monitor_interface +++ b/sbin/monitor_interface @@ -14,56 +14,79 @@ 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 status - [[ -z $1 ]] && return 1 - status=3 - # state should stay different for at least 3 seconds - for n in {1..3}; do - [[ $(state $1) != $2 ]] && ((status--)) +wlan(){ + [[ -e $SYSTEM/wlan0 ]] +} + +carrier(){ + cat $SYSTEM/$1/carrier 2>/dev/null +} + +state(){ + local n NEW OLD HOLD + OLD=$(carrier $1) + HOLD=4 + # new state should hold for at least 4 seconds + for n in {1..4}; do sleep 1 + NEW=$(carrier $1) + [[ $NEW != $OLD ]] && ((HOLD--)) done - [[ $status -eq 0 ]] + [[ $HOLD -eq 0 ]] && echo $NEW || echo $OLD } init(){ - PORT=(); STATE=(); + TASK=() if [[ -r $FILE ]]; then # initialize values from file, maintained by 'create_network_ini' while IFS=$'\n' read -r ROW; do - PORT+=("$ROW") - STATE+=($(state ${ROW%% *})) + TASK+=("$ROW") done <$FILE fi MD5=$(md5) } while :; do - # monitor file content changes - [[ $MD5 != $(md5) ]] && init - LAST= - for i in ${!PORT[@]}; do - INT=${PORT[$i]%% *} - # did interface state change? - if switch $INT ${STATE[$i]}; then - NEW=$(state $INT) - STATE[$i]=$NEW - if [[ $NEW == up ]]; then - ip addr add dev ${PORT[$i]} - elif [[ $NEW == down && $INT != $LAST ]]; then - ip addr flush scope global dev $INT - fi - fi - LAST=$INT - done + if wlan; then + # monitor file content changes + [[ $MD5 != $(md5) ]] && init + LAST= + for i in ${!TASK[@]}; do + ADDR=(${TASK[$i]}) + PORT=${ADDR[0]} + [[ $LAST != $PORT ]] && STATE=$(state $PORT) + case $STATE in + 1) # up + case ${ADDR[1]} in + GW4) + # no existing default and new default is defined? + ROUTE=$(ip -4 route show to default dev $PORT) + [[ -z $ROUTE && "${TASK[$i]}" =~ "default" ]] && ip -4 route add dev ${TASK[$i]/GW4/} + ;; + GW6) + # no existing default and new default is defined? + ROUTE=$(ip -6 route show to default dev $PORT) + [[ -z $ROUTE && "${TASK[$i]}" =~ "default" ]] && ip -6 route add dev ${TASK[$i]/GW6/} + ;; + *) + # IP address not present? create it + [[ "$(ip -br addr show dev $PORT)" =~ "${ADDR[1]}" ]] || ip addr add dev ${TASK[$i]} + ;; + esac + ;; + 0) # down + # IP address present, remove it + [[ "$(ip -br addr show dev $PORT)" =~ "${ADDR[1]}" ]] && ip addr del dev ${TASK[$i]} + ;; + esac + LAST=$PORT + done + fi # check every 3 seconds sleep 3 done & + From 29d098fbab6b0caf0ad4a397a232f0fc562552a3 Mon Sep 17 00:00:00 2001 From: bergware Date: Sat, 7 Jun 2025 19:53:42 +0200 Subject: [PATCH 10/38] VMs: fix missing ']' character --- emhttp/plugins/dynamix.vm.manager/templates/Custom.form.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/emhttp/plugins/dynamix.vm.manager/templates/Custom.form.php b/emhttp/plugins/dynamix.vm.manager/templates/Custom.form.php index f576a78d24..8557119515 100644 --- a/emhttp/plugins/dynamix.vm.manager/templates/Custom.form.php +++ b/emhttp/plugins/dynamix.vm.manager/templates/Custom.form.php @@ -2022,7 +2022,7 @@ function updateMAC(index, port) { var wlan0 = ''; // mac address of wlan0 - var mac = $('input[name="nic['+index+'][mac]"'); + var mac = $('input[name="nic['+index+'][mac]"]'); mac.prop('disabled', port=='wlan0'); $('i.mac_generate.'+index).prop('disabled', port=='wlan0'); $('span.wlan0').removeClass('hidden'); From 09eeb7d63745884d73b803f6675a21ad083b6c7b Mon Sep 17 00:00:00 2001 From: bergware Date: Mon, 9 Jun 2025 00:03:11 +0200 Subject: [PATCH 11/38] Docker networking fixes --- etc/rc.d/rc.docker | 88 +++++++++++++++++++++++++---------------- sbin/create_network_ini | 12 ++++-- sbin/monitor_interface | 27 +++++++++---- 3 files changed, 81 insertions(+), 46 deletions(-) diff --git a/etc/rc.d/rc.docker b/etc/rc.d/rc.docker index 389e388a09..2244eabde5 100755 --- a/etc/rc.d/rc.docker +++ b/etc/rc.d/rc.docker @@ -30,6 +30,7 @@ DOCKER_TIMEOUT=$(awk -F'"' '/^DOCKER_TIMEOUT=/{print $2}' $DOCKER_CFG 2>/dev/nul # network file references INI=/var/local/emhttp/network.ini +STA=/var/local/emhttp/statics.ini TMP=/var/tmp/network.tmp # run & log functions @@ -57,6 +58,18 @@ carrier(){ return 1 } +# add entry to watch list +add_entry(){ + rm -f /var/tmp/${1%% *}.down + [[ -e $STA ]] && echo "$1" >>$STA +} + +# delete enty from watch list +del_entry(){ + [[ -e $STA ]] && sed -i "/^$1 .*/d" $STA + touch /var/tmp/$1.down +} + # initialize docker settings docker_read_options(){ # determine active port name @@ -178,11 +191,6 @@ network(){ docker network ls --filter driver="$1" --format='{{.Name}}' 2>/dev/null | grep -P "^[a-z]+$2(\$|\.)" | tr '\n' ' ' } -# Does the ipv4 address exist? -ipv4_exist(){ - ip -4 -br addr show to $2 dev $1 | awk '{print $3;exit}' -} - # Is container running? container_running(){ local CONTAINER @@ -414,22 +422,29 @@ docker_network_start(){ done # hack to let containers talk to host if [[ $TYPE == br ]]; then - LINK=shim-$NETWORK + SHIM=shim-$NETWORK if [[ $DOCKER_ALLOW_ACCESS == yes && -n $IPV4 ]]; then # create shim interface - [[ -e $SYSTEM/$LINK ]] || run ip link add link $NETWORK name $LINK type $ATTACH mode $MODE - # disable IPv6 on shim interface - echo 1 >$CONF6/$LINK/disable_ipv6 - run ip -6 addr flush dev $LINK + if [[ ! -e $SYSTEM/$SHIM ]]; then + run ip link add link $NETWORK name $SHIM type $ATTACH mode $MODE + run ip link set $SHIM up + # disable IPv6 on shim interface + echo 1 >$CONF6/$SHIM/disable_ipv6 + run ip -6 addr flush dev $SHIM + fi # copy parent IPv4 address to shim interface - run ip addr add $IPV4 dev $LINK metric 0 - run ip link set $LINK up - log "created network $LINK for host access" - elif [[ -e $SYSTEM/$LINK ]]; then - # remove shim interface - run ip addr flush dev $LINK - run ip link set $LINK down - run ip link del $LINK + run ip addr add $IPV4 dev $SHIM metric 0 + add_entry "$SHIM $IPV4 metric 0" + GW4=$(ip -4 route show to default dev $NETWORK | awk '{print $3;exit}') + if [[ -n $GW4 ]]; then + run ip -4 route add default via $GW4 dev $SHIM metric 0 + add_entry "$SHIM GW4 default via $GW4 metric 0" + fi + log "created network $SHIM for host access" + elif [[ -e $SYSTEM/$SHIM ]]; then + # remove shim interface assignment + del_entry $SHIM + run ip -4 addr flush dev $SHIM fi else if [[ $TYPE == wlan ]]; then @@ -442,11 +457,18 @@ docker_network_start(){ echo 1 >$CONF6/$VHOST/disable_ipv6 run ip -6 addr flush dev $VHOST # copy parent IPv4 address to vhost interface - [[ -z $(ipv4_exist $VHOST ${IPV4%/*}) ]] && run ip addr add $IPV4 dev $VHOST metric 0 + run ip addr add $IPV4 dev $VHOST metric 0 + add_entry "$VHOST $IPV4 metric 0" + GW4=$(ip -4 route show to default dev $NETWORK | awk '{print $3;exit}') + if [[ -n $GW4 ]]; then + run ip -4 route add default via $GW4 dev $VHOST metric 0 + add_entry "$VHOST GW4 default via $GW4 metric 0" + fi log "created network $VHOST for host access" - elif [[ -n $IPV4 && -e $SYSTEM/$VHOST && -n $(ipv4_exist $VHOST ${IPV4%/*}) ]]; then - # remove parent IPv4 address from vhost interface - run ip addr del $IPV4 dev $VHOST metric 0 + elif [[ -n $IPV4 && -e $SYSTEM/$VHOST ]]; then + # remove vhost interface assignment + del_entry $VHOST + run ip -4 addr flush dev $VHOST fi fi fi @@ -470,23 +492,21 @@ docker_network_stop(){ for NETWORK in $(network $ATTACH ${NIC//[^0-9]/}); do [[ $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 - run ip addr flush dev $LINK - run ip link set $LINK down - run ip link del $LINK + if [[ $TYPE == br || $TYPE == wlan ]]; then + SHIM=shim-$NETWORK + if [[ -e $SYSTEM/$SHIM ]]; then + del_entry $SHIM + run ip addr flush dev $SHIM fi - elif [[ $TYPE != wlan ]]; then + else VHOST=vhost${NETWORK//[^0-9.]/} - [[ -e $SYSTEM/$VHOST ]] && run ip addr flush dev $VHOST + if [[ -e $SYSTEM/$VHOST ]]; then + del_entry $VHOST + run ip addr flush dev $VHOST + fi fi done done - if [[ -e $SYSTEM/shim-wlan0 ]]; then - IPV4=$(ip -4 -br addr show scope global primary dev shim-wlan0 | awk '{print $3,$4,$5;exit}') - [[ -n $IPV4 ]] && run ip addr del $IPV4 dev shim-wlan0 - fi log "Network stopped." } diff --git a/sbin/create_network_ini b/sbin/create_network_ini index 9fef5aad5b..4938f55392 100755 --- a/sbin/create_network_ini +++ b/sbin/create_network_ini @@ -163,7 +163,8 @@ for ((i=0; i<${SYSNICS:-1}; i++)); do IPV4="$(ip -4 -br addr show scope global primary dev $IFACE | awk '{$2="";print;exit}')" if [[ -n $IPV4 ]]; then echo "$IPV4" >>$STA - echo "$IFACE GW4 $(ip -4 route show to default dev $IFACE)" >>$STA + GW4="$(ip -4 route show to default dev $IFACE)" + [[ -n $GW4 ]] && echo "$IFACE GW4 $GW4" >>$STA fi fi echo "USE_DHCP6:0=\"${USE_DHCP6[$i]}\"" >>$INI @@ -187,7 +188,8 @@ for ((i=0; i<${SYSNICS:-1}; i++)); do IPV6="$(ip -6 -br addr show scope global primary -deprecated dev $IFACE | awk '{$2="";print;exit}')" if [[ -n $IPV6 ]]; then echo "$IPV6" >>$STA - echo "$IFACE GW6 $(ip -6 route show to default dev $IFACE)" >>$STA + GW6="$(ip -6 route show to default dev $IFACE)" + [[ -n $GW6 ]] && echo "$IFACE GW6 $GW6" >>$STA fi fi echo "USE_MTU=\"${USE_MTU[$i]}\"" >>$INI @@ -219,7 +221,8 @@ for ((i=0; i<${SYSNICS:-1}; i++)); do IPV4="$(ip -4 -br addr show scope global primary dev $DEV | awk '{$2="";print;exit}')" if [[ -n $IPV4 ]]; then echo "${IPV4/@$IFACE/}" >>$STA - echo "$DEV GW4 $(ip -4 route show to default dev $DEV)" >>$STA + GW4="$(ip -4 route show to default dev $DEV)" + [[ -n $GW4 ]] && echo "$DEV GW4 $GW4" >>$STA fi fi echo "USE_DHCP6:$j=\"${USE_DHCP6[$i,$j]}\"" >>$INI @@ -244,7 +247,8 @@ for ((i=0; i<${SYSNICS:-1}; i++)); do IPV6="$(ip -6 -br addr show scope global primary -deprecated dev $DEV | awk '{$2="";print;exit}')" if [[ -n $IPV6 ]]; then echo "${IPV6/@$IFACE/}" >>$STA - echo "$DEV GW6 $(ip -6 route show to default dev $DEV)" >>$STA + GW6="$(ip -6 route show to default dev $DEV)" + [[ -n $GW6 ]] && echo "$DEV GW6 $GW6" >>$STA fi fi done diff --git a/sbin/monitor_interface b/sbin/monitor_interface index db826a52fe..94cd4077ab 100755 --- a/sbin/monitor_interface +++ b/sbin/monitor_interface @@ -58,23 +58,34 @@ while :; do for i in ${!TASK[@]}; do ADDR=(${TASK[$i]}) PORT=${ADDR[0]} - [[ $LAST != $PORT ]] && STATE=$(state $PORT) + [[ $LAST != ${PORT%.*} ]] && STATE=$(state ${PORT%.*}) case $STATE in 1) # up case ${ADDR[1]} in GW4) # no existing default and new default is defined? - ROUTE=$(ip -4 route show to default dev $PORT) - [[ -z $ROUTE && "${TASK[$i]}" =~ "default" ]] && ip -4 route add dev ${TASK[$i]/GW4/} + IPV4=$(ip -4 -br addr show scope global primary dev $PORT | awk '{print $3;exit}') + if [[ -n $IPV4 ]]; then + ROUTE=$(ip -4 route show to default dev $PORT) + [[ -z $ROUTE && "${TASK[$i]}" =~ "default" ]] && ip -4 route add dev ${TASK[$i]/GW4/} + fi ;; GW6) # no existing default and new default is defined? - ROUTE=$(ip -6 route show to default dev $PORT) - [[ -z $ROUTE && "${TASK[$i]}" =~ "default" ]] && ip -6 route add dev ${TASK[$i]/GW6/} + IPV6=$(ip -6 -br addr show scope global primary -deprecated dev $PORT | awk '{print $3;exit}') + if [[ -n $IPV6 ]]; then + ROUTE=$(ip -6 route show to default dev $PORT) + [[ -z $ROUTE && "${TASK[$i]}" =~ "default" ]] && ip -6 route add dev ${TASK[$i]/GW6/} + fi ;; *) - # IP address not present? create it - [[ "$(ip -br addr show dev $PORT)" =~ "${ADDR[1]}" ]] || ip addr add dev ${TASK[$i]} + if [[ -f /var/tmp/$PORT.down ]]; then + # Special treatment for shim and vhost interfaces + [[ "$(ip -br addr show dev $PORT)" =~ "${ADDR[1]}" ]] && ip addr flush dev $PORT + else + # IP address not present? create it + [[ "$(ip -br addr show dev $PORT)" =~ "${ADDR[1]}" ]] || ip addr add dev ${TASK[$i]} + fi ;; esac ;; @@ -83,7 +94,7 @@ while :; do [[ "$(ip -br addr show dev $PORT)" =~ "${ADDR[1]}" ]] && ip addr del dev ${TASK[$i]} ;; esac - LAST=$PORT + LAST=${PORT%.*} done fi # check every 3 seconds From 62d0328da938b07bd00d439deb67c7882952794e Mon Sep 17 00:00:00 2001 From: bergware Date: Mon, 9 Jun 2025 00:27:03 +0200 Subject: [PATCH 12/38] rc.inet1: improved gateway creation --- etc/rc.d/rc.inet1 | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/etc/rc.d/rc.inet1 b/etc/rc.d/rc.inet1 index aa12699d50..18f9f59489 100755 --- a/etc/rc.d/rc.inet1 +++ b/etc/rc.d/rc.inet1 @@ -87,6 +87,7 @@ # Adapted by Bergware for use in Unraid OS - June 2025 # - revert metric assignment to static addresses # - remove duplicate ipv6 parameters +# - improve gateway creation ########### # LOGGING # @@ -632,8 +633,13 @@ gateway_up(){ [[ -z ${i[1]} ]] && DEV=${IFNAME[$i]} || DEV=${IFNAME[$i]}.${VLANID[$x]} IP=${PROTOCOL[$x]:-ipv4} AD=${METRIC[$x]} - [[ -n $AD ]] && AD="metric $AD" - EXIST=$(ip -4 route show to default via $(unzero $GW) dev $DEV | grep "$AD ") + if [[ -z $AD ]]; then + EXIST=$(ip -4 route show to default via $(unzero $GW) dev $DEV | grep -vm1 metric) + else + AD="metric $AD" + EXIST=$(ip -4 route show to default via $(unzero $GW) dev $DEV | grep -m1 "$AD ") + fi + [[ -z $AD ]] && AD="metric 1" [[ $IP != ipv6 && -z $EXIST ]] && run ip -4 route add default via $(unzero $GW) dev $DEV $AD done for GW6 in ${GATEWAY6[@]}; do @@ -644,8 +650,13 @@ gateway_up(){ [[ -z ${i[1]} ]] && DEV=${IFNAME[$i]} || DEV=${IFNAME[$i]}.${VLANID[$x]} IP=${PROTOCOL[$x]:-ipv4} AD6=${METRIC6[$x]} - [[ -n $AD6 ]] && AD6="metric $AD6" - EXIST=$(ip -6 route show to default via $(unzero6 $GW6) dev $DEV | grep "$AD6 ") + if [[ -z $AD6 ]]; then + EXIST=$(ip -6 route show to default via $(unzero6 $GW6) dev $DEV | grep -vm1 metric) + else + AD6="metric $AD6" + EXIST=$(ip -6 route show to default via $(unzero6 $GW6) dev $DEV | grep -m1 "$AD6 ") + fi + [[ -z $AD6 ]] && AD6="metric 1" [[ $IP != ipv4 && -z $EXIST ]] && run ip -6 route add default via $(unzero6 $GW6) dev $DEV $AD6 done } From 055313a363eab27470a5859c3513e352d6cc4105 Mon Sep 17 00:00:00 2001 From: bergware Date: Mon, 9 Jun 2025 00:29:56 +0200 Subject: [PATCH 13/38] Update rc.inet1 --- etc/rc.d/rc.inet1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/etc/rc.d/rc.inet1 b/etc/rc.d/rc.inet1 index 18f9f59489..dcfe07faad 100755 --- a/etc/rc.d/rc.inet1 +++ b/etc/rc.d/rc.inet1 @@ -634,12 +634,12 @@ gateway_up(){ IP=${PROTOCOL[$x]:-ipv4} AD=${METRIC[$x]} if [[ -z $AD ]]; then + AD="metric 1" EXIST=$(ip -4 route show to default via $(unzero $GW) dev $DEV | grep -vm1 metric) else AD="metric $AD" EXIST=$(ip -4 route show to default via $(unzero $GW) dev $DEV | grep -m1 "$AD ") fi - [[ -z $AD ]] && AD="metric 1" [[ $IP != ipv6 && -z $EXIST ]] && run ip -4 route add default via $(unzero $GW) dev $DEV $AD done for GW6 in ${GATEWAY6[@]}; do @@ -651,12 +651,12 @@ gateway_up(){ IP=${PROTOCOL[$x]:-ipv4} AD6=${METRIC6[$x]} if [[ -z $AD6 ]]; then + AD6="metric 1" EXIST=$(ip -6 route show to default via $(unzero6 $GW6) dev $DEV | grep -vm1 metric) else AD6="metric $AD6" EXIST=$(ip -6 route show to default via $(unzero6 $GW6) dev $DEV | grep -m1 "$AD6 ") fi - [[ -z $AD6 ]] && AD6="metric 1" [[ $IP != ipv4 && -z $EXIST ]] && run ip -6 route add default via $(unzero6 $GW6) dev $DEV $AD6 done } From 67a1ea3d2e4442af197d2a5fd69519b1d1e0bc29 Mon Sep 17 00:00:00 2001 From: bergware Date: Mon, 9 Jun 2025 01:39:07 +0200 Subject: [PATCH 14/38] More network fixes --- etc/rc.d/rc.docker | 19 ++++++++++++------- sbin/monitor_interface | 2 +- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/etc/rc.d/rc.docker b/etc/rc.d/rc.docker index 2244eabde5..828fb1671d 100755 --- a/etc/rc.d/rc.docker +++ b/etc/rc.d/rc.docker @@ -66,8 +66,8 @@ add_entry(){ # delete enty from watch list del_entry(){ - [[ -e $STA ]] && sed -i "/^$1 .*/d" $STA touch /var/tmp/$1.down + [[ -e $STA ]] && sed -i "/^$1 .*/d" $STA } # initialize docker settings @@ -433,7 +433,7 @@ docker_network_start(){ run ip -6 addr flush dev $SHIM fi # copy parent IPv4 address to shim interface - run ip addr add $IPV4 dev $SHIM metric 0 + run ip -4 addr add $IPV4 dev $SHIM metric 0 add_entry "$SHIM $IPV4 metric 0" GW4=$(ip -4 route show to default dev $NETWORK | awk '{print $3;exit}') if [[ -n $GW4 ]]; then @@ -444,7 +444,8 @@ docker_network_start(){ elif [[ -e $SYSTEM/$SHIM ]]; then # remove shim interface assignment del_entry $SHIM - run ip -4 addr flush dev $SHIM + sleep 0.5 + run ip -4 addr del $IPV4 dev $SHIM metric 0 fi else if [[ $TYPE == wlan ]]; then @@ -457,7 +458,7 @@ docker_network_start(){ echo 1 >$CONF6/$VHOST/disable_ipv6 run ip -6 addr flush dev $VHOST # copy parent IPv4 address to vhost interface - run ip addr add $IPV4 dev $VHOST metric 0 + run ip -4 addr add $IPV4 dev $VHOST metric 0 add_entry "$VHOST $IPV4 metric 0" GW4=$(ip -4 route show to default dev $NETWORK | awk '{print $3;exit}') if [[ -n $GW4 ]]; then @@ -468,7 +469,8 @@ docker_network_start(){ elif [[ -n $IPV4 && -e $SYSTEM/$VHOST ]]; then # remove vhost interface assignment del_entry $VHOST - run ip -4 addr flush dev $VHOST + sleep 0.5 + run ip -4 addr del $IPV4 dev $VHOST metric 0 fi fi fi @@ -490,19 +492,22 @@ docker_network_stop(){ [[ ${NIC:0:3} == eth ]] && NIC=$(active $NIC) driver ${NIC//[0-9]/} forced for NETWORK in $(network $ATTACH ${NIC//[^0-9]/}); do + IPV4=$(ip -4 -br addr show scope global primary dev $NETWORK | awk '{print $3;exit}') [[ $STOCK =~ ${NETWORK%%[0-9]*} || $DOCKER_USER_NETWORKS != preserve ]] && docker network rm $NETWORK &>/dev/null TYPE=${NETWORK//[0-9.]/} if [[ $TYPE == br || $TYPE == wlan ]]; then SHIM=shim-$NETWORK if [[ -e $SYSTEM/$SHIM ]]; then del_entry $SHIM - run ip addr flush dev $SHIM + sleep 0.5 + run ip -4 addr del $IPV4 dev $SHIM metric 0 fi else VHOST=vhost${NETWORK//[^0-9.]/} if [[ -e $SYSTEM/$VHOST ]]; then del_entry $VHOST - run ip addr flush dev $VHOST + sleep 0.5 + run ip -4 addr del $IPV4 dev $VHOST metric 0 fi fi done diff --git a/sbin/monitor_interface b/sbin/monitor_interface index 94cd4077ab..e3d763ee80 100755 --- a/sbin/monitor_interface +++ b/sbin/monitor_interface @@ -81,7 +81,7 @@ while :; do *) if [[ -f /var/tmp/$PORT.down ]]; then # Special treatment for shim and vhost interfaces - [[ "$(ip -br addr show dev $PORT)" =~ "${ADDR[1]}" ]] && ip addr flush dev $PORT + [[ "$(ip -br addr show dev $PORT)" =~ "${ADDR[1]}" ]] && ip -4 addr del dev ${TASK[$i]} else # IP address not present? create it [[ "$(ip -br addr show dev $PORT)" =~ "${ADDR[1]}" ]] || ip addr add dev ${TASK[$i]} From ff7251ebd66f265da026bd91308d6e5fded81ea2 Mon Sep 17 00:00:00 2001 From: bergware Date: Mon, 9 Jun 2025 01:44:13 +0200 Subject: [PATCH 15/38] Update rc.docker --- etc/rc.d/rc.docker | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/etc/rc.d/rc.docker b/etc/rc.d/rc.docker index 828fb1671d..f774455304 100755 --- a/etc/rc.d/rc.docker +++ b/etc/rc.d/rc.docker @@ -68,6 +68,7 @@ add_entry(){ del_entry(){ touch /var/tmp/$1.down [[ -e $STA ]] && sed -i "/^$1 .*/d" $STA + sleep 0.5 } # initialize docker settings @@ -444,7 +445,6 @@ docker_network_start(){ elif [[ -e $SYSTEM/$SHIM ]]; then # remove shim interface assignment del_entry $SHIM - sleep 0.5 run ip -4 addr del $IPV4 dev $SHIM metric 0 fi else @@ -469,7 +469,6 @@ docker_network_start(){ elif [[ -n $IPV4 && -e $SYSTEM/$VHOST ]]; then # remove vhost interface assignment del_entry $VHOST - sleep 0.5 run ip -4 addr del $IPV4 dev $VHOST metric 0 fi fi @@ -499,14 +498,12 @@ docker_network_stop(){ SHIM=shim-$NETWORK if [[ -e $SYSTEM/$SHIM ]]; then del_entry $SHIM - sleep 0.5 run ip -4 addr del $IPV4 dev $SHIM metric 0 fi else VHOST=vhost${NETWORK//[^0-9.]/} if [[ -e $SYSTEM/$VHOST ]]; then del_entry $VHOST - sleep 0.5 run ip -4 addr del $IPV4 dev $VHOST metric 0 fi fi From 469c4973bdc82cea787421c879a630f89c61f105 Mon Sep 17 00:00:00 2001 From: bergware Date: Mon, 9 Jun 2025 01:49:04 +0200 Subject: [PATCH 16/38] Update rc.docker --- 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 f774455304..4d1e3290e6 100755 --- a/etc/rc.d/rc.docker +++ b/etc/rc.d/rc.docker @@ -429,10 +429,10 @@ docker_network_start(){ if [[ ! -e $SYSTEM/$SHIM ]]; then run ip link add link $NETWORK name $SHIM type $ATTACH mode $MODE run ip link set $SHIM up - # disable IPv6 on shim interface - echo 1 >$CONF6/$SHIM/disable_ipv6 - run ip -6 addr flush dev $SHIM fi + # disable IPv6 on shim interface + echo 1 >$CONF6/$SHIM/disable_ipv6 + run ip -6 addr flush dev $SHIM # copy parent IPv4 address to shim interface run ip -4 addr add $IPV4 dev $SHIM metric 0 add_entry "$SHIM $IPV4 metric 0" From c49236d7e0c7f6e64dab29d8f3313ff07539d40a Mon Sep 17 00:00:00 2001 From: bergware Date: Mon, 9 Jun 2025 02:05:41 +0200 Subject: [PATCH 17/38] Update monitor_interface --- sbin/monitor_interface | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sbin/monitor_interface b/sbin/monitor_interface index e3d763ee80..857c249007 100755 --- a/sbin/monitor_interface +++ b/sbin/monitor_interface @@ -81,7 +81,7 @@ while :; do *) if [[ -f /var/tmp/$PORT.down ]]; then # Special treatment for shim and vhost interfaces - [[ "$(ip -br addr show dev $PORT)" =~ "${ADDR[1]}" ]] && ip -4 addr del dev ${TASK[$i]} + [[ -n $(ip -br -4 addr show to ${ADDR[1]} dev $PORT) ]] && ip -4 addr del dev ${TASK[$i]} else # IP address not present? create it [[ "$(ip -br addr show dev $PORT)" =~ "${ADDR[1]}" ]] || ip addr add dev ${TASK[$i]} From 169fdd1f053dedf78e3fa854a0421cc3dabe0a0e Mon Sep 17 00:00:00 2001 From: bergware Date: Mon, 9 Jun 2025 02:08:26 +0200 Subject: [PATCH 18/38] Update monitor_interface --- sbin/monitor_interface | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sbin/monitor_interface b/sbin/monitor_interface index 857c249007..acbdacef46 100755 --- a/sbin/monitor_interface +++ b/sbin/monitor_interface @@ -84,14 +84,14 @@ while :; do [[ -n $(ip -br -4 addr show to ${ADDR[1]} dev $PORT) ]] && ip -4 addr del dev ${TASK[$i]} else # IP address not present? create it - [[ "$(ip -br addr show dev $PORT)" =~ "${ADDR[1]}" ]] || ip addr add dev ${TASK[$i]} + [[ -z $(ip -br addr show to ${ADDR[1]} dev $PORT) ]] && ip addr add dev ${TASK[$i]} fi ;; esac ;; 0) # down # IP address present, remove it - [[ "$(ip -br addr show dev $PORT)" =~ "${ADDR[1]}" ]] && ip addr del dev ${TASK[$i]} + [[ -n $(ip -br addr show to ${ADDR[1]} dev $PORT) ]] && ip addr del dev ${TASK[$i]} ;; esac LAST=${PORT%.*} From 0ac54ef5347e362b2255e343910fc35a45b1c26c Mon Sep 17 00:00:00 2001 From: bergware Date: Mon, 9 Jun 2025 02:15:45 +0200 Subject: [PATCH 19/38] Update monitor_interface --- sbin/monitor_interface | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/sbin/monitor_interface b/sbin/monitor_interface index acbdacef46..e757793586 100755 --- a/sbin/monitor_interface +++ b/sbin/monitor_interface @@ -67,7 +67,7 @@ while :; do IPV4=$(ip -4 -br addr show scope global primary dev $PORT | awk '{print $3;exit}') if [[ -n $IPV4 ]]; then ROUTE=$(ip -4 route show to default dev $PORT) - [[ -z $ROUTE && "${TASK[$i]}" =~ "default" ]] && ip -4 route add dev ${TASK[$i]/GW4/} + [[ -z $ROUTE ]] && ip -4 route add dev ${TASK[$i]/GW4/} fi ;; GW6) @@ -75,16 +75,17 @@ while :; do IPV6=$(ip -6 -br addr show scope global primary -deprecated dev $PORT | awk '{print $3;exit}') if [[ -n $IPV6 ]]; then ROUTE=$(ip -6 route show to default dev $PORT) - [[ -z $ROUTE && "${TASK[$i]}" =~ "default" ]] && ip -6 route add dev ${TASK[$i]/GW6/} + [[ -z $ROUTE ]] && ip -6 route add dev ${TASK[$i]/GW6/} fi ;; *) + IPA=$(ip -br addr show to ${ADDR[1]} dev $PORT) if [[ -f /var/tmp/$PORT.down ]]; then # Special treatment for shim and vhost interfaces - [[ -n $(ip -br -4 addr show to ${ADDR[1]} dev $PORT) ]] && ip -4 addr del dev ${TASK[$i]} + [[ -n $IPA ]] && ip addr del dev ${TASK[$i]} else # IP address not present? create it - [[ -z $(ip -br addr show to ${ADDR[1]} dev $PORT) ]] && ip addr add dev ${TASK[$i]} + [[ -z $IPA ]] && ip addr add dev ${TASK[$i]} fi ;; esac From 68885c93ec6fd5fb76fb4a5b567088c2e6c5e8d8 Mon Sep 17 00:00:00 2001 From: bergware Date: Mon, 9 Jun 2025 03:58:08 +0200 Subject: [PATCH 20/38] Update monitor_interface --- sbin/monitor_interface | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/sbin/monitor_interface b/sbin/monitor_interface index e757793586..46cbb00200 100755 --- a/sbin/monitor_interface +++ b/sbin/monitor_interface @@ -58,10 +58,11 @@ while :; do for i in ${!TASK[@]}; do ADDR=(${TASK[$i]}) PORT=${ADDR[0]} + ADDR=${ADDR[1]%/*} [[ $LAST != ${PORT%.*} ]] && STATE=$(state ${PORT%.*}) case $STATE in 1) # up - case ${ADDR[1]} in + case $ADDR in GW4) # no existing default and new default is defined? IPV4=$(ip -4 -br addr show scope global primary dev $PORT | awk '{print $3;exit}') @@ -79,7 +80,7 @@ while :; do fi ;; *) - IPA=$(ip -br addr show to ${ADDR[1]} dev $PORT) + IPA=$(ip -br addr show to $ADDR dev $PORT) if [[ -f /var/tmp/$PORT.down ]]; then # Special treatment for shim and vhost interfaces [[ -n $IPA ]] && ip addr del dev ${TASK[$i]} @@ -91,8 +92,10 @@ while :; do esac ;; 0) # down - # IP address present, remove it - [[ -n $(ip -br addr show to ${ADDR[1]} dev $PORT) ]] && ip addr del dev ${TASK[$i]} + if [[ $ADDR != GW4 && $ADDR != GW6 ]]; then + # IP address present, remove it + [[ -n $(ip -br addr show to $ADDR dev $PORT) ]] && ip addr del dev ${TASK[$i]} + fi ;; esac LAST=${PORT%.*} From 9a6543134c9c4bb4eac3d6a1fd95be71b0fa9906 Mon Sep 17 00:00:00 2001 From: bergware Date: Mon, 9 Jun 2025 04:22:05 +0200 Subject: [PATCH 21/38] Update monitor_interface --- sbin/monitor_interface | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/sbin/monitor_interface b/sbin/monitor_interface index 46cbb00200..ae7c767b78 100755 --- a/sbin/monitor_interface +++ b/sbin/monitor_interface @@ -9,7 +9,7 @@ # 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 +# Bergware - modified for Unraid OS, June 2025 FILE=/var/local/emhttp/statics.ini SYSTEM=/sys/class/net @@ -58,29 +58,31 @@ while :; do for i in ${!TASK[@]}; do ADDR=(${TASK[$i]}) PORT=${ADDR[0]} - ADDR=${ADDR[1]%/*} [[ $LAST != ${PORT%.*} ]] && STATE=$(state ${PORT%.*}) - case $STATE in - 1) # up - case $ADDR in - GW4) + case ${ADDR[1]} in + GW4) + if [[ $STATE == 1 ]]; then # no existing default and new default is defined? IPV4=$(ip -4 -br addr show scope global primary dev $PORT | awk '{print $3;exit}') if [[ -n $IPV4 ]]; then ROUTE=$(ip -4 route show to default dev $PORT) [[ -z $ROUTE ]] && ip -4 route add dev ${TASK[$i]/GW4/} fi - ;; - GW6) + fi + ;; + GW6) + if [[ $STATE == 1 ]]; then # no existing default and new default is defined? IPV6=$(ip -6 -br addr show scope global primary -deprecated dev $PORT | awk '{print $3;exit}') if [[ -n $IPV6 ]]; then ROUTE=$(ip -6 route show to default dev $PORT) [[ -z $ROUTE ]] && ip -6 route add dev ${TASK[$i]/GW6/} fi - ;; - *) - IPA=$(ip -br addr show to $ADDR dev $PORT) + fi + ;; + *) + if [[ $STATE == 1 ]]; then + IPA=$(ip -br addr show to ${ADDR[1]%/*} dev $PORT) if [[ -f /var/tmp/$PORT.down ]]; then # Special treatment for shim and vhost interfaces [[ -n $IPA ]] && ip addr del dev ${TASK[$i]} @@ -88,13 +90,9 @@ while :; do # IP address not present? create it [[ -z $IPA ]] && ip addr add dev ${TASK[$i]} fi - ;; - esac - ;; - 0) # down - if [[ $ADDR != GW4 && $ADDR != GW6 ]]; then + elif [[ $STATE == 0 ]]; then # IP address present, remove it - [[ -n $(ip -br addr show to $ADDR dev $PORT) ]] && ip addr del dev ${TASK[$i]} + [[ -n $(ip -br addr show to ${ADDR[1]%/*} dev $PORT) ]] && ip addr del dev ${TASK[$i]} fi ;; esac From 10694c2372ec87021038915cc351c685763bcc9e Mon Sep 17 00:00:00 2001 From: bergware Date: Mon, 9 Jun 2025 04:26:35 +0200 Subject: [PATCH 22/38] Update monitor_interface --- sbin/monitor_interface | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/sbin/monitor_interface b/sbin/monitor_interface index ae7c767b78..cf4ddbd6eb 100755 --- a/sbin/monitor_interface +++ b/sbin/monitor_interface @@ -81,7 +81,12 @@ while :; do fi ;; *) - if [[ $STATE == 1 ]]; then + case $STATE in + 0) # down + # IP address present, remove it + [[ -n $(ip -br addr show to ${ADDR[1]%/*} dev $PORT) ]] && ip addr del dev ${TASK[$i]} + ;; + 1) # up IPA=$(ip -br addr show to ${ADDR[1]%/*} dev $PORT) if [[ -f /var/tmp/$PORT.down ]]; then # Special treatment for shim and vhost interfaces @@ -90,11 +95,7 @@ while :; do # IP address not present? create it [[ -z $IPA ]] && ip addr add dev ${TASK[$i]} fi - elif [[ $STATE == 0 ]]; then - # IP address present, remove it - [[ -n $(ip -br addr show to ${ADDR[1]%/*} dev $PORT) ]] && ip addr del dev ${TASK[$i]} - fi - ;; + esac esac LAST=${PORT%.*} done From b19c73de14ca9f93a19ab7b30109487a9c7de8dd Mon Sep 17 00:00:00 2001 From: bergware Date: Mon, 9 Jun 2025 04:46:49 +0200 Subject: [PATCH 23/38] Update monitor_interface --- sbin/monitor_interface | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/sbin/monitor_interface b/sbin/monitor_interface index cf4ddbd6eb..43f8617c42 100755 --- a/sbin/monitor_interface +++ b/sbin/monitor_interface @@ -87,13 +87,9 @@ while :; do [[ -n $(ip -br addr show to ${ADDR[1]%/*} dev $PORT) ]] && ip addr del dev ${TASK[$i]} ;; 1) # up - IPA=$(ip -br addr show to ${ADDR[1]%/*} dev $PORT) - if [[ -f /var/tmp/$PORT.down ]]; then - # Special treatment for shim and vhost interfaces - [[ -n $IPA ]] && ip addr del dev ${TASK[$i]} - else + if [[ ! -f /var/tmp/$PORT.down ]]; then # IP address not present? create it - [[ -z $IPA ]] && ip addr add dev ${TASK[$i]} + [[ -z $(ip -br addr show to ${ADDR[1]%/*} dev $PORT) ]] && ip addr add dev ${TASK[$i]} fi esac esac From 44921f18f2e842cea0ac39dff174b0fc2b545e46 Mon Sep 17 00:00:00 2001 From: bergware Date: Mon, 9 Jun 2025 04:53:39 +0200 Subject: [PATCH 24/38] Update monitor_interface --- sbin/monitor_interface | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/sbin/monitor_interface b/sbin/monitor_interface index 43f8617c42..380935b66b 100755 --- a/sbin/monitor_interface +++ b/sbin/monitor_interface @@ -64,20 +64,14 @@ while :; do if [[ $STATE == 1 ]]; then # no existing default and new default is defined? IPV4=$(ip -4 -br addr show scope global primary dev $PORT | awk '{print $3;exit}') - if [[ -n $IPV4 ]]; then - ROUTE=$(ip -4 route show to default dev $PORT) - [[ -z $ROUTE ]] && ip -4 route add dev ${TASK[$i]/GW4/} - fi + [[ -n $IPV4 && -z $(ip -4 route show to default dev $PORT) ]] && ip -4 route add dev ${TASK[$i]/GW4/} fi ;; GW6) if [[ $STATE == 1 ]]; then # no existing default and new default is defined? IPV6=$(ip -6 -br addr show scope global primary -deprecated dev $PORT | awk '{print $3;exit}') - if [[ -n $IPV6 ]]; then - ROUTE=$(ip -6 route show to default dev $PORT) - [[ -z $ROUTE ]] && ip -6 route add dev ${TASK[$i]/GW6/} - fi + [[ -n $IPV6 && -z $(ip -6 route show to default dev $PORT) ]] && ip -6 route add dev ${TASK[$i]/GW6/} fi ;; *) @@ -87,10 +81,8 @@ while :; do [[ -n $(ip -br addr show to ${ADDR[1]%/*} dev $PORT) ]] && ip addr del dev ${TASK[$i]} ;; 1) # up - if [[ ! -f /var/tmp/$PORT.down ]]; then - # IP address not present? create it - [[ -z $(ip -br addr show to ${ADDR[1]%/*} dev $PORT) ]] && ip addr add dev ${TASK[$i]} - fi + # IP address not present? create it + [[ ! -f /var/tmp/$PORT.down && -z $(ip -br addr show to ${ADDR[1]%/*} dev $PORT) ]] && ip addr add dev ${TASK[$i]} esac esac LAST=${PORT%.*} From 2dc459951c0a850067bf28bd5d392b7f819bfc26 Mon Sep 17 00:00:00 2001 From: bergware Date: Mon, 9 Jun 2025 07:58:34 +0200 Subject: [PATCH 25/38] Networking: fix default gateway selection --- emhttp/plugins/dynamix/Eth0.page | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/emhttp/plugins/dynamix/Eth0.page b/emhttp/plugins/dynamix/Eth0.page index 8afecd4e89..dbebcc4e83 100644 --- a/emhttp/plugins/dynamix/Eth0.page +++ b/emhttp/plugins/dynamix/Eth0.page @@ -204,21 +204,21 @@ function prepareSettings(form) { $(form).find('select[name^="USE_DHCP:"]').each(function() { var i = $(this).prop('name').split(':')[1]; var protocol = $(form).find('select[name="PROTOCOL:'+i+'"]').val() || 'ipv4'; - var gw4 = (port == 'eth0' && i == 0) ? true : $(form).find('input[name="USE_GW4:'+i+'"]').prop('checked'); + var gw4 = $(form).find('input[name="USE_GW4:'+i+'"]').prop('checked'); + if (!gw4) $(form).find('input[name="METRIC:'+i+'"]').val('0'); if (protocol != 'ipv6' && $(this).val() != 'no') { $(form).find('input[name="IPADDR:'+i+'"]').val(''); $(form).find('input[name="GATEWAY:'+i+'"]').val(''); - $(form).find('input[name="METRIC:'+i+'"]').val(gw4?'':'0'); } }); $(form).find('select[name^="USE_DHCP6:"]').each(function() { var i = $(this).prop('name').split(':')[1]; var protocol = $(form).find('select[name="PROTOCOL:'+i+'"]').val() || 'ipv4'; - var gw6 = (port == 'eth0' && i == 0) ? true : $(form).find('input[name="USE_GW6:'+i+'"]').prop('checked'); + var gw6 = $(form).find('input[name="USE_GW6:'+i+'"]').prop('checked'); + if (!gw6) $(form).find('input[name="METRIC6:'+i+'"]').val('0'); if (protocol != 'ipv4' && $(this).val() != 'no') { $(form).find('input[name="IPADDR6:'+i+'"]').val(''); $(form).find('input[name="GATEWAY6:'+i+'"]').val(''); - $(form).find('input[name="METRIC6:'+i+'"]').val(gw6?'':'0'); } if ($(this).val() != 'yes') $(form).find('input[name="PRIVACY6:'+i+'"]').val(''); }); From 33b45fcdf24b000d4a1e887ff017667c4b6ab973 Mon Sep 17 00:00:00 2001 From: bergware Date: Mon, 9 Jun 2025 08:19:12 +0200 Subject: [PATCH 26/38] Update Eth0.page --- emhttp/plugins/dynamix/Eth0.page | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/emhttp/plugins/dynamix/Eth0.page b/emhttp/plugins/dynamix/Eth0.page index dbebcc4e83..549adab772 100644 --- a/emhttp/plugins/dynamix/Eth0.page +++ b/emhttp/plugins/dynamix/Eth0.page @@ -203,9 +203,10 @@ function prepareSettings(form) { }); $(form).find('select[name^="USE_DHCP:"]').each(function() { var i = $(this).prop('name').split(':')[1]; + var x = (port == 'eth0') ? i + 1 : i; var protocol = $(form).find('select[name="PROTOCOL:'+i+'"]').val() || 'ipv4'; var gw4 = $(form).find('input[name="USE_GW4:'+i+'"]').prop('checked'); - if (!gw4) $(form).find('input[name="METRIC:'+i+'"]').val('0'); + if (!gw4) $(form).find('input[name="METRIC:'+x+'"]').val('0'); if (protocol != 'ipv6' && $(this).val() != 'no') { $(form).find('input[name="IPADDR:'+i+'"]').val(''); $(form).find('input[name="GATEWAY:'+i+'"]').val(''); @@ -213,9 +214,10 @@ function prepareSettings(form) { }); $(form).find('select[name^="USE_DHCP6:"]').each(function() { var i = $(this).prop('name').split(':')[1]; + var x = (port == 'eth0') ? i + 1 : i; var protocol = $(form).find('select[name="PROTOCOL:'+i+'"]').val() || 'ipv4'; var gw6 = $(form).find('input[name="USE_GW6:'+i+'"]').prop('checked'); - if (!gw6) $(form).find('input[name="METRIC6:'+i+'"]').val('0'); + if (!gw6) $(form).find('input[name="METRIC6:'+x+'"]').val('0'); if (protocol != 'ipv4' && $(this).val() != 'no') { $(form).find('input[name="IPADDR6:'+i+'"]').val(''); $(form).find('input[name="GATEWAY6:'+i+'"]').val(''); From 34f4e140a5be48bfe03a38a4688b476e31a065e4 Mon Sep 17 00:00:00 2001 From: bergware Date: Mon, 9 Jun 2025 08:28:15 +0200 Subject: [PATCH 27/38] Update monitor_interface --- sbin/monitor_interface | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sbin/monitor_interface b/sbin/monitor_interface index 380935b66b..18e18d7f05 100755 --- a/sbin/monitor_interface +++ b/sbin/monitor_interface @@ -64,14 +64,14 @@ while :; do if [[ $STATE == 1 ]]; then # no existing default and new default is defined? IPV4=$(ip -4 -br addr show scope global primary dev $PORT | awk '{print $3;exit}') - [[ -n $IPV4 && -z $(ip -4 route show to default dev $PORT) ]] && ip -4 route add dev ${TASK[$i]/GW4/} + [[ -n $IPV4 && "${TASK[$i]}" =~ "default" && -z $(ip -4 route show to default dev $PORT)]] && ip -4 route add dev ${TASK[$i]/GW4/} fi ;; GW6) if [[ $STATE == 1 ]]; then # no existing default and new default is defined? IPV6=$(ip -6 -br addr show scope global primary -deprecated dev $PORT | awk '{print $3;exit}') - [[ -n $IPV6 && -z $(ip -6 route show to default dev $PORT) ]] && ip -6 route add dev ${TASK[$i]/GW6/} + [[ -n $IPV6 && "${TASK[$i]}" =~ "default" && -z $(ip -6 route show to default dev $PORT) ]] && ip -6 route add dev ${TASK[$i]/GW6/} fi ;; *) From 71e55d58b031786f1d827202ee75a942b0d3f682 Mon Sep 17 00:00:00 2001 From: bergware Date: Mon, 9 Jun 2025 08:32:22 +0200 Subject: [PATCH 28/38] Update monitor_interface --- sbin/monitor_interface | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sbin/monitor_interface b/sbin/monitor_interface index 18e18d7f05..62d781a5ef 100755 --- a/sbin/monitor_interface +++ b/sbin/monitor_interface @@ -64,7 +64,7 @@ while :; do if [[ $STATE == 1 ]]; then # no existing default and new default is defined? IPV4=$(ip -4 -br addr show scope global primary dev $PORT | awk '{print $3;exit}') - [[ -n $IPV4 && "${TASK[$i]}" =~ "default" && -z $(ip -4 route show to default dev $PORT)]] && ip -4 route add dev ${TASK[$i]/GW4/} + [[ -n $IPV4 && "${TASK[$i]}" =~ "default" && -z $(ip -4 route show to default dev $PORT) ]] && ip -4 route add dev ${TASK[$i]/GW4/} fi ;; GW6) From f590db8f74bcecc820325aacd2fd8e994b6e0c03 Mon Sep 17 00:00:00 2001 From: bergware Date: Mon, 9 Jun 2025 10:00:04 +0200 Subject: [PATCH 29/38] Update rc.inet1 --- etc/rc.d/rc.inet1 | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/etc/rc.d/rc.inet1 b/etc/rc.d/rc.inet1 index dcfe07faad..4e1075b094 100755 --- a/etc/rc.d/rc.inet1 +++ b/etc/rc.d/rc.inet1 @@ -632,14 +632,8 @@ gateway_up(){ i=(${x/,/ }) [[ -z ${i[1]} ]] && DEV=${IFNAME[$i]} || DEV=${IFNAME[$i]}.${VLANID[$x]} IP=${PROTOCOL[$x]:-ipv4} - AD=${METRIC[$x]} - if [[ -z $AD ]]; then - AD="metric 1" - EXIST=$(ip -4 route show to default via $(unzero $GW) dev $DEV | grep -vm1 metric) - else - AD="metric $AD" - EXIST=$(ip -4 route show to default via $(unzero $GW) dev $DEV | grep -m1 "$AD ") - fi + AD="metric ${METRIC[$x]:-1}" + EXIST=$(ip -4 route show to default via $(unzero $GW) dev $DEV | grep -m1 "$AD ") [[ $IP != ipv6 && -z $EXIST ]] && run ip -4 route add default via $(unzero $GW) dev $DEV $AD done for GW6 in ${GATEWAY6[@]}; do @@ -649,14 +643,8 @@ gateway_up(){ i=(${x/,/ }) [[ -z ${i[1]} ]] && DEV=${IFNAME[$i]} || DEV=${IFNAME[$i]}.${VLANID[$x]} IP=${PROTOCOL[$x]:-ipv4} - AD6=${METRIC6[$x]} - if [[ -z $AD6 ]]; then - AD6="metric 1" - EXIST=$(ip -6 route show to default via $(unzero6 $GW6) dev $DEV | grep -vm1 metric) - else - AD6="metric $AD6" - EXIST=$(ip -6 route show to default via $(unzero6 $GW6) dev $DEV | grep -m1 "$AD6 ") - fi + AD6="metric ${METRIC6[$x]:-1}" + EXIST=$(ip -6 route show to default via $(unzero6 $GW6) dev $DEV | grep -m1 "$AD6 ") [[ $IP != ipv4 && -z $EXIST ]] && run ip -6 route add default via $(unzero6 $GW6) dev $DEV $AD6 done } From 538890a933f57e5876c5a5935bd26505b3ebfbc6 Mon Sep 17 00:00:00 2001 From: bergware Date: Mon, 9 Jun 2025 10:34:06 +0200 Subject: [PATCH 30/38] Networking: fix default gateway selection --- emhttp/plugins/dynamix/Eth0.page | 10 ++++------ emhttp/plugins/dynamix/EthX.page | 8 ++++---- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/emhttp/plugins/dynamix/Eth0.page b/emhttp/plugins/dynamix/Eth0.page index 549adab772..2750a42d36 100644 --- a/emhttp/plugins/dynamix/Eth0.page +++ b/emhttp/plugins/dynamix/Eth0.page @@ -203,10 +203,9 @@ function prepareSettings(form) { }); $(form).find('select[name^="USE_DHCP:"]').each(function() { var i = $(this).prop('name').split(':')[1]; - var x = (port == 'eth0') ? i + 1 : i; var protocol = $(form).find('select[name="PROTOCOL:'+i+'"]').val() || 'ipv4'; var gw4 = $(form).find('input[name="USE_GW4:'+i+'"]').prop('checked'); - if (!gw4) $(form).find('input[name="METRIC:'+x+'"]').val('0'); + if (gw4 === false) $(form).find('input[name="METRIC:'+i+'"]').val('0'); if (protocol != 'ipv6' && $(this).val() != 'no') { $(form).find('input[name="IPADDR:'+i+'"]').val(''); $(form).find('input[name="GATEWAY:'+i+'"]').val(''); @@ -214,10 +213,9 @@ function prepareSettings(form) { }); $(form).find('select[name^="USE_DHCP6:"]').each(function() { var i = $(this).prop('name').split(':')[1]; - var x = (port == 'eth0') ? i + 1 : i; var protocol = $(form).find('select[name="PROTOCOL:'+i+'"]').val() || 'ipv4'; var gw6 = $(form).find('input[name="USE_GW6:'+i+'"]').prop('checked'); - if (!gw6) $(form).find('input[name="METRIC6:'+x+'"]').val('0'); + if (gw6 === false) $(form).find('input[name="METRIC6:'+i+'"]').val('0'); if (protocol != 'ipv4' && $(this).val() != 'no') { $(form).find('input[name="IPADDR6:'+i+'"]').val(''); $(form).find('input[name="GATEWAY6:'+i+'"]').val(''); @@ -815,7 +813,7 @@ _(IPv4 address assignment)_: - > + > :eth_ipv4_address_assignment_help: @@ -846,7 +844,7 @@ _(IPv6 address assignment)_: - > + > :eth_ipv6_address_assignment_help: diff --git a/emhttp/plugins/dynamix/EthX.page b/emhttp/plugins/dynamix/EthX.page index f702a4588f..8f51c3cf3f 100644 --- a/emhttp/plugins/dynamix/EthX.page +++ b/emhttp/plugins/dynamix/EthX.page @@ -171,7 +171,7 @@ _(IPv4 address assignment)_: - > + > :eth_ipv4_address_assignment_help: @@ -200,7 +200,7 @@ _(IPv6 address assignment)_: - > + > :eth_ipv6_address_assignment_help: @@ -278,7 +278,7 @@ _(IPv4 address assignment)_: - > + > :eth_ipv4_address_assignment_help: @@ -307,7 +307,7 @@ _(IPv6 address assignment)_: - > + > :eth_ipv6_address_assignment_help: From 510cdf4add53653548a40db112b703bc7a08a9be Mon Sep 17 00:00:00 2001 From: bergware Date: Mon, 9 Jun 2025 11:12:52 +0200 Subject: [PATCH 31/38] Update monitor_interface --- sbin/monitor_interface | 60 ++++++++++++++++++++++-------------------- 1 file changed, 31 insertions(+), 29 deletions(-) diff --git a/sbin/monitor_interface b/sbin/monitor_interface index 62d781a5ef..0c13b2c693 100755 --- a/sbin/monitor_interface +++ b/sbin/monitor_interface @@ -18,8 +18,8 @@ md5(){ [[ -r $FILE ]] && md5sum $FILE | awk '{print $1;exit}' } -wlan(){ - [[ -e $SYSTEM/wlan0 ]] +port(){ + [[ -e $SYSTEM/$1 ]] } carrier(){ @@ -51,41 +51,43 @@ init(){ } while :; do - if wlan; then + if port wlan0 ]]; then # monitor file content changes [[ $MD5 != $(md5) ]] && init LAST= for i in ${!TASK[@]}; do ADDR=(${TASK[$i]}) PORT=${ADDR[0]} - [[ $LAST != ${PORT%.*} ]] && STATE=$(state ${PORT%.*}) - case ${ADDR[1]} in - GW4) - if [[ $STATE == 1 ]]; then - # no existing default and new default is defined? - IPV4=$(ip -4 -br addr show scope global primary dev $PORT | awk '{print $3;exit}') - [[ -n $IPV4 && "${TASK[$i]}" =~ "default" && -z $(ip -4 route show to default dev $PORT) ]] && ip -4 route add dev ${TASK[$i]/GW4/} - fi - ;; - GW6) - if [[ $STATE == 1 ]]; then - # no existing default and new default is defined? - IPV6=$(ip -6 -br addr show scope global primary -deprecated dev $PORT | awk '{print $3;exit}') - [[ -n $IPV6 && "${TASK[$i]}" =~ "default" && -z $(ip -6 route show to default dev $PORT) ]] && ip -6 route add dev ${TASK[$i]/GW6/} - fi - ;; - *) - case $STATE in - 0) # down - # IP address present, remove it - [[ -n $(ip -br addr show to ${ADDR[1]%/*} dev $PORT) ]] && ip addr del dev ${TASK[$i]} + if port $PORT; then + [[ $LAST != ${PORT%.*} ]] && STATE=$(state ${PORT%.*}) + case ${ADDR[1]} in + GW4) + if [[ $STATE == 1 ]]; then + # no existing default and new default is defined? + IPV4=$(ip -4 -br addr show scope global primary dev $PORT | awk '{print $3;exit}') + [[ -n $IPV4 && "${TASK[$i]}" =~ "default" && -z $(ip -4 route show to default dev $PORT) ]] && ip -4 route add dev ${TASK[$i]/GW4/} + fi ;; - 1) # up - # IP address not present? create it - [[ ! -f /var/tmp/$PORT.down && -z $(ip -br addr show to ${ADDR[1]%/*} dev $PORT) ]] && ip addr add dev ${TASK[$i]} + GW6) + if [[ $STATE == 1 ]]; then + # no existing default and new default is defined? + IPV6=$(ip -6 -br addr show scope global primary -deprecated dev $PORT | awk '{print $3;exit}') + [[ -n $IPV6 && "${TASK[$i]}" =~ "default" && -z $(ip -6 route show to default dev $PORT) ]] && ip -6 route add dev ${TASK[$i]/GW6/} + fi + ;; + *) + case $STATE in + 0) # down + # IP address present, remove it + [[ -n $(ip -br addr show to ${ADDR[1]%/*} dev $PORT) ]] && ip addr del dev ${TASK[$i]} + ;; + 1) # up + # IP address not present? create it + [[ ! -f /var/tmp/$PORT.down && -z $(ip -br addr show to ${ADDR[1]%/*} dev $PORT) ]] && ip addr add dev ${TASK[$i]} + esac esac - esac - LAST=${PORT%.*} + LAST=${PORT%.*} + fi done fi # check every 3 seconds From 6f7a7cd84c75bcd3cad4a72010e648499bb629fa Mon Sep 17 00:00:00 2001 From: bergware Date: Mon, 9 Jun 2025 11:30:30 +0200 Subject: [PATCH 32/38] Update EthX.page --- emhttp/plugins/dynamix/EthX.page | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/emhttp/plugins/dynamix/EthX.page b/emhttp/plugins/dynamix/EthX.page index 8f51c3cf3f..e00ca39d2a 100644 --- a/emhttp/plugins/dynamix/EthX.page +++ b/emhttp/plugins/dynamix/EthX.page @@ -171,7 +171,7 @@ _(IPv4 address assignment)_: - > + > :eth_ipv4_address_assignment_help: @@ -200,7 +200,7 @@ _(IPv6 address assignment)_: - > + > :eth_ipv6_address_assignment_help: From 162a31e6dcb8e788548dfcb77367644f28145837 Mon Sep 17 00:00:00 2001 From: bergware Date: Mon, 9 Jun 2025 11:36:18 +0200 Subject: [PATCH 33/38] Update monitor_interface --- sbin/monitor_interface | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sbin/monitor_interface b/sbin/monitor_interface index 0c13b2c693..110e92f572 100755 --- a/sbin/monitor_interface +++ b/sbin/monitor_interface @@ -51,7 +51,7 @@ init(){ } while :; do - if port wlan0 ]]; then + if port wlan0; then # monitor file content changes [[ $MD5 != $(md5) ]] && init LAST= From 80305931aefdc08a7469576713f2031358c2af00 Mon Sep 17 00:00:00 2001 From: bergware Date: Mon, 9 Jun 2025 12:32:19 +0200 Subject: [PATCH 34/38] Update Eth0.page --- emhttp/plugins/dynamix/Eth0.page | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/emhttp/plugins/dynamix/Eth0.page b/emhttp/plugins/dynamix/Eth0.page index 2750a42d36..41c0b50526 100644 --- a/emhttp/plugins/dynamix/Eth0.page +++ b/emhttp/plugins/dynamix/Eth0.page @@ -205,21 +205,23 @@ function prepareSettings(form) { var i = $(this).prop('name').split(':')[1]; var protocol = $(form).find('select[name="PROTOCOL:'+i+'"]').val() || 'ipv4'; var gw4 = $(form).find('input[name="USE_GW4:'+i+'"]').prop('checked'); - if (gw4 === false) $(form).find('input[name="METRIC:'+i+'"]').val('0'); if (protocol != 'ipv6' && $(this).val() != 'no') { $(form).find('input[name="IPADDR:'+i+'"]').val(''); $(form).find('input[name="GATEWAY:'+i+'"]').val(''); + $(form).find('input[name="METRIC:'+i+'"]').val(''); } + if (gw4 === false) $(form).find('input[name="METRIC:'+i+'"]').val('0'); }); $(form).find('select[name^="USE_DHCP6:"]').each(function() { var i = $(this).prop('name').split(':')[1]; var protocol = $(form).find('select[name="PROTOCOL:'+i+'"]').val() || 'ipv4'; var gw6 = $(form).find('input[name="USE_GW6:'+i+'"]').prop('checked'); - if (gw6 === false) $(form).find('input[name="METRIC6:'+i+'"]').val('0'); if (protocol != 'ipv4' && $(this).val() != 'no') { $(form).find('input[name="IPADDR6:'+i+'"]').val(''); $(form).find('input[name="GATEWAY6:'+i+'"]').val(''); + $(form).find('input[name="METRIC6:'+i+'"]').val(''); } + if (gw6 === false) $(form).find('input[name="METRIC6:'+i+'"]').val('0'); if ($(this).val() != 'yes') $(form).find('input[name="PRIVACY6:'+i+'"]').val(''); }); if (port == 'eth0') { From aca2542724bbe490fea861e8fec56c32b89def3d Mon Sep 17 00:00:00 2001 From: SimonFair <39065407+SimonFair@users.noreply.github.com> Date: Mon, 9 Jun 2025 13:14:16 +0100 Subject: [PATCH 35/38] Update libvirt_helpers.php --- .../plugins/dynamix.vm.manager/include/libvirt_helpers.php | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/emhttp/plugins/dynamix.vm.manager/include/libvirt_helpers.php b/emhttp/plugins/dynamix.vm.manager/include/libvirt_helpers.php index 6a3bf8f0bd..eaf4e1c060 100644 --- a/emhttp/plugins/dynamix.vm.manager/include/libvirt_helpers.php +++ b/emhttp/plugins/dynamix.vm.manager/include/libvirt_helpers.php @@ -1228,7 +1228,7 @@ function getHostCPUModel() { } function getValidNetworks() { - global $lv; + global $lv,$libvirt_running; $arrValidNetworks = []; exec("ls --indicator-style=none /sys/class/net | grep -Po '^virbr[0-9]+'",$arrBridges); exec("ls --indicator-style=none /sys/class/net | grep -Po '^(br|bond|eth|wlan)[0-9]+(\.[0-9]+)?'",$arrBridges); @@ -1243,8 +1243,7 @@ function getValidNetworks() { } $arrValidNetworks['bridges'] = array_diff($arrBridges, $remove); - // This breaks VMSettings.page if libvirt is not running - /* if ($libvirt_running == "yes") { + if ($libvirt_running == "yes") { $arrVirtual = $lv->libvirt_get_net_list($lv->get_connection()); if (($key = array_search('default', $arrVirtual)) !== false) { @@ -1254,7 +1253,7 @@ function getValidNetworks() { array_unshift($arrVirtual, 'default'); $arrValidNetworks['libvirt'] = array_values($arrVirtual); - }*/ + } return $arrValidNetworks; } From c87b6fd1491a8c47d2124536c0b4173fd04a92d8 Mon Sep 17 00:00:00 2001 From: ljm42 Date: Mon, 16 Jun 2025 10:27:44 -0700 Subject: [PATCH 36/38] backport: File manager: fix file overwrite on move operation backport #2254 --- emhttp/plugins/dynamix/nchan/file_manager | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/emhttp/plugins/dynamix/nchan/file_manager b/emhttp/plugins/dynamix/nchan/file_manager index fb86127241..076a6b09d8 100755 --- a/emhttp/plugins/dynamix/nchan/file_manager +++ b/emhttp/plugins/dynamix/nchan/file_manager @@ -186,7 +186,7 @@ while (true) { } else { $target = validname($target, false); if ($target) { - $f = $exist ? 'f' : 'n'; + $f = $exist ? 'n' : 'f'; exec("mv -{$f}t ".escapeshellarg($target)." ".quoted($source)." 1>$status 2>$error & echo \$!", $pid); } else { $reply['error'] = 'Invalid target name'; From ffcea249f62281386e2f051325db9efb57f9fa17 Mon Sep 17 00:00:00 2001 From: ljm42 Date: Tue, 17 Jun 2025 16:18:18 -0700 Subject: [PATCH 37/38] Backport: Fix: Docker listing could show APIPA IP --- emhttp/plugins/dynamix.docker.manager/include/DockerClient.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/emhttp/plugins/dynamix.docker.manager/include/DockerClient.php b/emhttp/plugins/dynamix.docker.manager/include/DockerClient.php index 21fee16cad..185cb76bf5 100644 --- a/emhttp/plugins/dynamix.docker.manager/include/DockerClient.php +++ b/emhttp/plugins/dynamix.docker.manager/include/DockerClient.php @@ -1178,7 +1178,7 @@ public static function port() { public static function host() { $port = static::port(); if (!$port) return ''; - $port = lan_port($port,true)==0 && lan_port('wlan0') ? 'wlan0' : $port; + $port = lan_port($port,true)!=1 && 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}'"); } } From b53ee6c191bff4bae2d38a7fcb5ed1bec9954a53 Mon Sep 17 00:00:00 2001 From: Tom Mortensen Date: Tue, 17 Jun 2025 22:31:07 -0700 Subject: [PATCH 38/38] fix: prevent changing pool Compression/Autotrim settings when arry is Started --- emhttp/plugins/dynamix/DeviceInfo.page | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/emhttp/plugins/dynamix/DeviceInfo.page b/emhttp/plugins/dynamix/DeviceInfo.page index 955e799c17..362dd063af 100644 --- a/emhttp/plugins/dynamix/DeviceInfo.page +++ b/emhttp/plugins/dynamix/DeviceInfo.page @@ -331,6 +331,7 @@ function selectDiskFsProfile(init) { if (slots == 0) slots = ; var subpool = ""; + var fsStatus = ""; var fsType; if (subpool == '') { @@ -371,7 +372,7 @@ function selectDiskFsProfile(init) { $('#diskCompression').prop('disabled',true); } else { $('#compression').show(t); - $('#diskCompression').prop('disabled',false); + $('#diskCompression').prop('disabled',(fsStatus == 'Mounted')); } @@ -383,7 +384,7 @@ function selectDiskFsProfile(init) { $('#diskAutotrim').prop('disabled',true); } else { $('#autotrim').show(t); - $('#diskAutotrim').prop('disabled',false); + $('#diskAutotrim').prop('disabled',(fsStatus == 'Mounted')); } } @@ -795,7 +796,7 @@ _(Allocation profile)_:
_(Compression)_: -: @@ -804,7 +805,7 @@ _(Compression)_:
_(Autotrim)_: -:
_(Rename disabled, snapshot(s) exists)_. .