Backport networking fixes to 7.1

This commit is contained in:
ljm42
2025-05-28 14:43:43 -07:00
parent ed4bd3db1b
commit 7f02d3fb7d
14 changed files with 399 additions and 275 deletions

View File

@@ -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)_:
: <input type="text" name="GATEWAY:0" maxlength="15" autocomplete="off" spellcheck="false" value="<?=_var($eth0,"GATEWAY:0")?>" class="narrow" pattern="<?=$validIP4?>" title="_(IPv4 address A.B.C.D)_">
<input type="text" name="METRIC:0" min="0" max="9999" autocomplete="off" spellcheck="false" value="<?=_var($eth0,"METRIC:0")?:metric('eth0',4,0)?>" class="slim"><i class="fa fa-sort-numeric-asc"></i> *<?=$metric?>*
<input type="text" name="METRIC:0" min="0" max="9999" autocomplete="off" spellcheck="false" value="<?=_var($eth0,"METRIC:0")?:metric('eth0')?>" class="slim"><i class="fa fa-sort-numeric-asc"></i> *<?=$metric?>*
:eth_ipv4_default_gateway_help:
@@ -752,7 +750,7 @@ _(IPv6 address)_:
_(IPv6 default gateway)_:
: <input type="text" name="GATEWAY6:0" maxlength="39" autocomplete="off" spellcheck="false" value="<?=_var($eth0,"GATEWAY6:0")?>" pattern="<?=$validIP6?>" title="_(IPv6 address nnnn:xxxx::yyyy)_">
<input type="text" name="METRIC6:0" min="0" max="9999" autocomplete="off" spellcheck="false" value="<?=_var($eth0,"METRIC6:0")?:metric('eth0',6,0)?>" class="slim"><i class="fa fa-sort-numeric-asc"></i> *<?=$metric?>*
<input type="text" name="METRIC6:0" min="0" max="9999" autocomplete="off" spellcheck="false" value="<?=_var($eth0,"METRIC6:0")?:metric('eth0')?>" class="slim"><i class="fa fa-sort-numeric-asc"></i> *<?=$metric?>*
:eth_ipv6_default_gateway_help:
@@ -830,7 +828,7 @@ _(IPv4 address)_:
<div markdown="1" class="more-gw4-eth0-<?=$i?> hide">
_(IPv4 default gateway)_:
: <input type="text" name="GATEWAY:<?=$i?>" maxlength="15" autocomplete="off" spellcheck="false" value="<?=_var($eth0,"GATEWAY:$i")?>" class="narrow" pattern="<?=$validIP4?>" title="_(IPv4 address A.B.C.D)_">
<input type="text" name="METRIC:<?=$i?>" min="0" max="9999" autocomplete="off" spellcheck="false" value="<?=_var($eth0,"METRIC:$i")?:metric('eth0.<?=_var($eth0,"VLANID:$i")?>',4,$i)?>" class="slim"><i class="fa fa-sort-numeric-asc"></i> *<?=$metric?>*
<input type="text" name="METRIC:<?=$i?>" min="0" max="9999" autocomplete="off" spellcheck="false" value="<?=_var($eth0,"METRIC:$i")?:metric('eth0.'._var($eth0,"VLANID:$i"))?>" class="slim"><i class="fa fa-sort-numeric-asc"></i> *<?=$metric?>*
:eth_ipv4_default_gateway_help:
@@ -859,7 +857,7 @@ _(IPv6 address)_:
<div markdown="1" class="more-gw6-eth0-<?=$i?> hide">
_(IPv6 default gateway)_:
: <input type="text" name="GATEWAY6:<?=$i?>" maxlength="39" autocomplete="off" spellcheck="false" value="<?=_var($eth0,"GATEWAY6:$i")?>" pattern="<?=$validIP6?>" title="_(IPv6 address nnnn:xxxx::yyyy)_">
<input type="text" name="METRIC6:<?=$i?>" min="0" max="9999" autocomplete="off" spellcheck="false" value="<?=_var($eth0,"METRIC6:$i")?:metric('eth0.<?=_var($eth0,"VLANID:$i")?>',6,$i)?>" class="slim"><i class="fa fa-sort-numeric-asc"></i> *<?=$metric?>*
<input type="text" name="METRIC6:<?=$i?>" min="0" max="9999" autocomplete="off" spellcheck="false" value="<?=_var($eth0,"METRIC6:$i")?:metric('eth0.'._var($eth0,"VLANID:$i"))?>" class="slim"><i class="fa fa-sort-numeric-asc"></i> *<?=$metric?>*
:eth_ipv6_default_gateway_help:
@@ -921,7 +919,7 @@ _(IPv4 address)_:
<div markdown="1" class="more-gw4-eth0-INDEX hide">
_(IPv4 default gateway)_:
: <input type="text" name="GATEWAY:INDEX" maxlength="15" autocomplete="off" spellcheck="false" value="" class="narrow" pattern="<?=$validIP4?>" title="_(IPv4 address A.B.C.D)_">
<input type="text" name="METRIC:INDEX" min="1" max="9999" autocomplete="off" spellcheck="false" value="<?=metric('eth0.INDEX',4,$i+1)?>" class="slim"><i class="fa fa-sort-numeric-asc"></i> *<?=$metric?>*
<input type="text" name="METRIC:INDEX" min="1" max="9999" autocomplete="off" spellcheck="false" value="<?=metric('eth0.INDEX')?>" class="slim"><i class="fa fa-sort-numeric-asc"></i> *<?=$metric?>*
</div>
</div>
@@ -942,7 +940,7 @@ _(IPv6 address)_:
<div markdown="1" class="more-gw6-eth0-INDEX hide">
_(IPv6 default gateway)_:
: <input type="text" name="GATEWAY6:INDEX" maxlength="39" autocomplete="off" spellcheck="false" value="" pattern="<?=$validIP6?>" title="_(IPv6 address nnnn:xxxx::yyyy)_">
<input type="text" name="METRIC6:INDEX" min="1" max="9999" autocomplete="off" spellcheck="false" value="<?=metric('eth0.INDEX',6,$i+1)?>" class="slim"><i class="fa fa-sort-numeric-asc"></i> *<?=$metric?>*
<input type="text" name="METRIC6:INDEX" min="1" max="9999" autocomplete="off" spellcheck="false" value="<?=metric('eth0.INDEX')?>" class="slim"><i class="fa fa-sort-numeric-asc"></i> *<?=$metric?>*
</div>
</div>

View File

@@ -186,7 +186,7 @@ _(IPv4 address)_:
<div markdown="1" class="more-gw4-ethX-0 hide">
_(IPv4 default gateway)_:
: <input type="text" name="GATEWAY:0" maxlength="15" autocomplete="off" spellcheck="false" value="<?=_var($ethX,"GATEWAY:0")?>" class="narrow" pattern="<?=$validIP4?>" title="_(IPv4 address A.B.C.D)_">
<input type="text" name="METRIC:0" min="0" max="9999" autocomplete="off" spellcheck="false" value="<?=_var($ethX,"METRIC:0")?:metric('ethX',4,0)?>" class="slim"><i class="fa fa-sort-numeric-asc"></i> *<?=$metric?>*
<input type="text" name="METRIC:0" min="0" max="9999" autocomplete="off" spellcheck="false" value="<?=_var($ethX,"METRIC:0")?:metric('ethX')?>" class="slim"><i class="fa fa-sort-numeric-asc"></i> *<?=$metric?>*
:eth_ipv4_default_gateway_help:
@@ -213,7 +213,7 @@ _(IPv6 address)_:
<div markdown="1" class="more-gw6-ethX-0 hide">
_(IPv6 default gateway)_:
: <input type="text" name="GATEWAY6:0" maxlength="39" autocomplete="off" spellcheck="false" value="<?=_var($ethX,"GATEWAY6:0")?>" pattern="<?=$validIP6?>" title="_(IPv6 address nnnn:xxxx::yyyy)_">
<input type="text" name="METRIC6:0" min="0" max="9999" autocomplete="off" spellcheck="false" value="<?=_var($ethX,"METRIC6:0")?:metric('ethX',6,0)?>" class="slim"><i class="fa fa-sort-numeric-asc"></i> *<?=$metric?>*
<input type="text" name="METRIC6:0" min="0" max="9999" autocomplete="off" spellcheck="false" value="<?=_var($ethX,"METRIC6:0")?:metric('ethX')?>" class="slim"><i class="fa fa-sort-numeric-asc"></i> *<?=$metric?>*
:eth_ipv6_default_gateway_help:
@@ -293,7 +293,7 @@ _(IPv4 address)_:
<div markdown="1" class="more-gw4-ethX-<?=$i?> hide">
_(IPv4 default gateway)_:
: <input type="text" name="GATEWAY:<?=$i?>" maxlength="15" autocomplete="off" spellcheck="false" value="<?=_var($ethX,"GATEWAY:$i")?>" class="narrow" pattern="<?=$validIP4?>" title="_(IPv4 address A.B.C.D)_">
<input type="text" name="METRIC:<?=$i?>" min="0" max="9999" autocomplete="off" spellcheck="false" value="<?=_var($ethX,"METRIC:$i")?:metric('ethX.<?=_var($ethX,"VLANID:$i")?>',4,$i)?>" class="slim"><i class="fa fa-sort-numeric-asc"></i> *<?=$metric?>*
<input type="text" name="METRIC:<?=$i?>" min="0" max="9999" autocomplete="off" spellcheck="false" value="<?=_var($ethX,"METRIC:$i")?:metric('ethX.'._var($ethX,"VLANID:$i"))?>" class="slim"><i class="fa fa-sort-numeric-asc"></i> *<?=$metric?>*
:eth_ipv4_default_gateway_help:
@@ -320,7 +320,7 @@ _(IPv6 address)_:
<div markdown="1" class="more-gw6-ethX-<?=$i?> hide">
_(IPv6 default gateway)_:
: <input type="text" name="GATEWAY6:<?=$i?>" maxlength="39" autocomplete="off" spellcheck="false" value="<?=_var($ethX,"GATEWAY6:$i")?>" pattern="<?=$validIP6?>" title="_(IPv6 address nnnn:xxxx::yyyy)_">
<input type="text" name="METRIC6:<?=$i?>" min="0" max="9999" autocomplete="off" spellcheck="false" value="<?=_var($ethX,"METRIC6:$i")?:metric('ethX.<?=_var($ethX,"VLANID:$i")?>',6,$i)?>" class="slim"><i class="fa fa-sort-numeric-asc"></i> *<?=$metric?>*
<input type="text" name="METRIC6:<?=$i?>" min="0" max="9999" autocomplete="off" spellcheck="false" value="<?=_var($ethX,"METRIC6:$i")?:metric('ethX.'._var($ethX,"VLANID:$i"))?>" class="slim"><i class="fa fa-sort-numeric-asc"></i> *<?=$metric?>*
:eth_ipv6_default_gateway_help:
@@ -383,7 +383,7 @@ _(IPv4 address)_:
<div markdown="1" class="more-gw4-ethX-INDEX hide">
_(IPv4 default gateway)_:
: <input type="text" name="GATEWAY:INDEX" maxlength="15" autocomplete="off" spellcheck="false" value="" class="narrow" pattern="<?=$validIP4?>" title="_(IPv4 address A.B.C.D)_">
<input type="text" name="METRIC:INDEX" min="1" max="9999" autocomplete="off" spellcheck="false" value="<?=metric('ethX.INDEX',4,$i+1)?>" class="slim"><i class="fa fa-sort-numeric-asc"></i> *<?=$metric?>*
<input type="text" name="METRIC:INDEX" min="1" max="9999" autocomplete="off" spellcheck="false" value="<?=metric('ethX.INDEX')?>" class="slim"><i class="fa fa-sort-numeric-asc"></i> *<?=$metric?>*
</div>
</div>
@@ -404,7 +404,7 @@ _(IPv6 address)_:
<div markdown="1" class="more-gw6-ethX-INDEX hide">
_(IPv6 default gateway)_:
: <input type="text" name="GATEWAY6:INDEX" maxlength="39" autocomplete="off" spellcheck="false" value="" pattern="<?=$validIP6?>" title="_(IPv6 address nnnn:xxxx::yyyy)_">
<input type="text" name="METRIC6:INDEX" min="1" max="9999" autocomplete="off" spellcheck="false" value="<?=metric('ethX.INDEX',6,$i+1)?>" class="slim"><i class="fa fa-sort-numeric-asc"></i> *<?=$metric?>*
<input type="text" name="METRIC6:INDEX" min="1" max="9999" autocomplete="off" spellcheck="false" value="<?=metric('ethX.INDEX')?>" class="slim"><i class="fa fa-sort-numeric-asc"></i> *<?=$metric?>*
</div>
</div>

View File

@@ -26,8 +26,8 @@ case 'Add Route':
if ($gateway && $route) exec("/etc/rc.d/rc.inet1 ".escapeshellarg("{$gateway}_{$route}_{$metric}_add"));
break;
default:
exec("ip -4 route show table all|grep -Pv '^(127\\.0\\.0\\.0)|table local|unreachable'",$ipv4);
exec("ip -6 route show table all|grep -Pv '^([am:]|(f[ef][0-9][0-9])::)|table local|unreachable'",$ipv6);
exec("ip -4 route show table all | grep -Pv '^(127\\.0\\.0\\.0)|table local|unreachable|linkdown|broadcast'",$ipv4);
exec("ip -6 route show table all | grep -Pv '^([am:]|(f[ef][0-9][0-9])::)|table local|unreachable|linkdown'",$ipv6);
foreach ($ipv4 as $info) {
$cell = explode(' ',$info);
$route = $cell[0];

View File

@@ -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

View File

@@ -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

View File

@@ -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 "<Network>\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

View File

@@ -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
}

View File

@@ -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)

View File

@@ -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

View File

@@ -6,7 +6,7 @@
# Written for Slackware Linux by Cherife Li <cherife-#-dotimes.com>.
# 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

View File

@@ -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..'))

View File

@@ -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(){
[[ -z $1 ]] && return
# convert prefix to netmask
set -- $((5-($1/8))) 255 255 255 255 $(((255<<(8-($1%8)))&255)) 0 0 0
[[ $1 -gt 1 ]] && shift $1 || shift
echo $1.$2.$3.$4
# return variable value from file
var(){
[[ -r "$2" ]] && grep -Pom1 "^$1=\"\K[^\"]+" "$2"
}
# return interface index
index(){
cat $SYSTEM/$1/ifindex 2>/dev/null
}
# convert netmask to prefix
mask2cidr(){
[[ -z $1 ]] && return
local MASK=$(eval eval echo "'\$((('{"${1//./,}"}'>>'{7..0}')%2))'")
eval echo '$(('"${MASK// /+}"'))'
}
# convert prefix to netmask
cidr2mask(){
[[ -z $1 ]] && return
local MASK=$(eval echo '$(((1<<32)-1<<32-$1>>'{3..0}'*8&255))')
echo "${MASK// /.}"
}
# return dns nameserver entry
dns() {
[[ $1 == 4 ]] && ADDR='(\d{1,3}\.){3}\d+' || ADDR='([0-9a-fA-F]{1,4}::?){1,7}[0-9a-fA-F]*'
grep -Po "^nameserver \K$ADDR" /etc/resolv.conf
@@ -48,8 +67,10 @@ else
BONDING=yes
BRIDGING=yes
fi
# prepare empty file
echo -n >$INI
echo -n >$STA
# loop thru all defined interfaces (=1 in case of legacy)
for ((i=0; i<${SYSNICS:-1}; i++)); do
@@ -57,7 +78,7 @@ for ((i=0; i<${SYSNICS:-1}; i++)); do
ETH=${IFACE/#bond/eth}
ETH=${ETH/#br/eth}
# don't store when non-existing
[[ -e $SYS/$ETH ]] || continue
[[ -e $SYSTEM/$ETH ]] || continue
echo "[$ETH]" >>$INI
if [[ $i -eq 0 ]]; then
# process legacy settings
@@ -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

69
sbin/monitor_interface Normal file
View File

@@ -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 &

View File

@@ -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 %%