From 1fd6a2262f38936a9beecfd3797995e3bad7fd13 Mon Sep 17 00:00:00 2001 From: bergware Date: Sat, 7 Jun 2025 13:44:19 +0200 Subject: [PATCH] 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 6fe1cdb78..b6072ab56 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 e5b7be2eb..6a3bf8f0b 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 @@ class Array2XML { 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 @@ class Array2XML { $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 @@ class Array2XML { $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 3d3f0c5d5..f576a78d2 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 @@ $arrValidNetworks = getValidNetworks(); $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 @@ if ($snapshots!=null && count($snapshots) && !$boolNew) { - + @@ -2017,13 +2020,17 @@ foreach ($arrConfig['evdev'] as $i => $arrEvdev) { 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 900c05733..cbc2bc279 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() { $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 118ee6f19..54aa3a168 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 a48d4da84..8afecd4e8 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 3061220fd..f702a4588 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 13632d0af..389e388a0 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 835b8dd3e..aa12699d5 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 8e16249ce..d35744aff 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 7fee9fe62..9fef5aad5 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 331a021fb..db826a52f 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 & +
_(Rename disabled, snapshot(s) exists)_. .