From d321201cc0d96ec3f5dbfdd78d37575994e173fc Mon Sep 17 00:00:00 2001 From: bergware Date: Tue, 25 Feb 2025 02:14:03 +0100 Subject: [PATCH] Network enhancements - Remove non-existing ports from configuration file - New option for additional ports: "Enable default gateway" - Check refinements, do not execute on non-existing ports --- emhttp/plugins/dynamix/Eth0.page | 66 ++++++++++++++++--- emhttp/plugins/dynamix/EthX.page | 8 ++- emhttp/plugins/dynamix/include/CheckPort.php | 10 +-- emhttp/plugins/dynamix/include/PortToggle.php | 7 +- emhttp/plugins/dynamix/scripts/netconfig | 30 +++++---- sbin/create_network_ini | 5 ++ 6 files changed, 97 insertions(+), 29 deletions(-) diff --git a/emhttp/plugins/dynamix/Eth0.page b/emhttp/plugins/dynamix/Eth0.page index f7ea8b6cb..bd2d1ab7c 100644 --- a/emhttp/plugins/dynamix/Eth0.page +++ b/emhttp/plugins/dynamix/Eth0.page @@ -70,7 +70,7 @@ $service = exec('pgrep --ns $$ libvirt') ? _('VM manager') : ''; $service .= exec('pgrep --ns $$ docker') ? ($service ? ' '._('and').' ' : '')._('Docker service') : ''; // eth0 port status -$no_eth0 = exec("ip link show eth0|grep -Pom1 '(NO-CARRIER|state DOWN)'"); +$no_eth0 = exec("ip -br link show eth0 | grep -om1 ' DOWN '"); // get VLAN interfaces $vlan_eth0 = $sort_eth0 = []; @@ -194,18 +194,22 @@ function prepareSettings(form) { var i = $(this).prop('name').split(':')[1]; var protocol = $(form).find('select[name="PROTOCOL:'+i+'"]').val() || 'ipv4'; var metric = $(form).find('input[name="METRIC:'+i+'"]').val(); + var gw4 = (port=='eth0') ? true : $(form).find('input[name="USE_GW:'+i+'"]').prop('checked'); if (protocol != 'ipv6' && $(this).val()=='yes') { $(form).find('input[name="IPADDR:'+i+'"]').prop('disabled',false).val(''); $(form).find('input[name="GATEWAY:'+i+'"]').prop('disabled',false).val(''); + $(form).find('input[name="METRIC:'+i+'"]').prop('disabled',false).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 metric = $(form).find('input[name="METRIC6:'+i+'"]').val(); + var gw6 = (port=='eth0') ? true : $(form).find('input[name="USE_GW6:'+i+'"]').prop('checked'); if (protocol != 'ipv4' && $(this).val()=='yes') { $(form).find('input[name="IPADDR6:'+i+'"]').prop('disabled',false).val(''); $(form).find('input[name="GATEWAY6:'+i+'"]').prop('disabled',false).val(''); + $(form).find('input[name="METRIC6:'+i+'"]').prop('disabled',false).val(gw6?'':'0'); } if ($(this).val()!='yes') $(form).find('input[name="PRIVACY6:'+i+'"]').prop('disabled',false).val(''); }); @@ -232,6 +236,8 @@ function selectProtocol(form,index,step) { var more4 = $('.'+'more-ipv4-'+port+'-'+i); var more6 = $('.'+'more-ipv6-'+port+'-'+i); var priv6 = $('.'+'priv-ipv6-'+port+'-'+i); + var gw4 = $('.'+'gw4-'+port+'-'+i); + var gw6 = $('.'+'gw6-'+port+'-'+i); switch (protocol) { case 'ipv4': net4.show(); net6.hide(); break; case 'ipv6': net4.hide(); net6.show(); break; @@ -244,8 +250,29 @@ function selectProtocol(form,index,step) { var dhcp4 = $(form).find('select[name="USE_DHCP:'+i+'"]').val(); var dhcp6 = $(form).find('select[name="USE_DHCP6:'+i+'"]').val(); - if (dhcp4=='no') more4.show(); else more4.hide(); - if (dhcp6=='no') {more6.show(); priv6.hide();} else if (dhcp6=='yes') {more6.hide(); priv6.show();} else {more6.hide(); priv6.hide();} + if (dhcp4=='no') { + more4.show(); + gw4.hide(); + } else if (dhcp4=='yes') { + more4.hide(); + gw4.show(); + } else { + more4.hide(); + gw4.hide(); + } + if (dhcp6=='no') { + more6.show(); + priv6.hide(); + gw6.hide(); + } else if (dhcp6=='yes') { + more6.hide(); + priv6.show(); + gw6.show(); + } else { + more6.hide(); + priv6.hide(); + gw6.hide(); + } checkNetworkSettings(form,i); }); @@ -256,6 +283,8 @@ function selectProtocol(form,index,step) { var more4 = $('.'+'more-ipv4-'+port+'-'+index); var more6 = $('.'+'more-ipv6-'+port+'-'+index); var priv6 = $('.'+'priv-ipv6-'+port+'-'+index); + var gw4 = $('.'+'gw4-'+port+'-'+index); + var gw6 = $('.'+'gw6-'+port+'-'+index); switch (protocol) { case 'ipv4': net4.show(step); net6.hide(step); if (port=='eth0') {$('#dns4').show(step); $('#dns6').hide(step);} break; case 'ipv6': net4.hide(step); net6.show(step); if (port=='eth0') {$('#dns4').hide(step); $('#dns6').show(step);} break; @@ -263,8 +292,29 @@ function selectProtocol(form,index,step) { } var dhcp4 = $(form).find('select[name="USE_DHCP:'+index+'"]').val(); var dhcp6 = $(form).find('select[name="USE_DHCP6:'+index+'"]').val(); - if (dhcp4=='no') more4.show(step); else more4.hide(step); - if (dhcp6=='no') {more6.show(step); priv6.hide(step);} else if (dhcp6=='yes') {more6.hide(step); priv6.show(step);} else {more6.hide(step); priv6.hide(step);} + if (dhcp4=='no') { + more4.show(step); + gw4.hide(); + } else if (dhcp4=='yes') { + more4.hide(step); + gw4.show(); + } else { + more4.hide(step); + gw4.hide(); + } + if (dhcp6=='no') { + more6.show(step); + priv6.hide(step); + gw6.hide(); + } else if (dhcp6=='yes') { + more6.hide(step); + priv6.show(step); + gw6.show(); + } else { + more6.hide(step); + priv6.hide(step); + gw6.hide(); + } checkNetworkSettings(form,index); } } @@ -406,10 +456,10 @@ function disableForm(form) { } function portcheck(port) { - $.post('/webGui/include/CheckPort.php',{port:port},function(text) { + $.post('/webGui/include/CheckPort.php',{port:port},function(msg) { var html = $('#user-notice').html(); - if (!html || html.indexOf(port)>0) showNotice(text); - setTimeout(function(){portcheck(port);},10000); + if (!html || html.indexOf(port)>0) showNotice(msg); + setTimeout(function(){portcheck(port);},5000); }); } diff --git a/emhttp/plugins/dynamix/EthX.page b/emhttp/plugins/dynamix/EthX.page index 3ea64ffcc..afa4b2fda 100644 --- a/emhttp/plugins/dynamix/EthX.page +++ b/emhttp/plugins/dynamix/EthX.page @@ -28,7 +28,7 @@ if (strpos($locked,'bond')===0 || strpos($locked,'br')===0) { [$master_ethX,$root] = my_explode(' ',$locked); $reason = _('member of')." $master_ethX ("._('see interface')." $root)"; $class = 'green-text'; -} elseif (!exec("ip link show ethX|grep -om1 'UP>'")) { +} elseif (exec("ip -br link show ethX | grep -om1 ' DOWN '")) { $reason = _("shutdown")." ("._("inactive").")"; $class = 'blue-text'; $cmd = 'Up'; @@ -169,6 +169,7 @@ _(IPv4 address assignment)_: + >_(Enable default gateway)_ :eth_ipv4_address_assignment_help: @@ -195,6 +196,7 @@ _(IPv6 address assignment)_: + >_(Enable default gateway)_ :eth_ipv6_address_assignment_help: @@ -269,6 +271,7 @@ _(IPv4 address assignment)_: + >_(Enable default gateway)_ :eth_ipv4_address_assignment_help: @@ -295,6 +298,7 @@ _(IPv6 address assignment)_: + >_(Enable default gateway)_ :eth_ipv6_address_assignment_help: @@ -357,6 +361,7 @@ _(IPv4 address assignment)_: + _(Enable default gateway)_
_(IPv4 address)_: @@ -377,6 +382,7 @@ _(IPv6 address assignment)_: + _(Enable default gateway)_
_(IPv6 address)_: diff --git a/emhttp/plugins/dynamix/include/CheckPort.php b/emhttp/plugins/dynamix/include/CheckPort.php index 4fc99a840..ce21066a4 100644 --- a/emhttp/plugins/dynamix/include/CheckPort.php +++ b/emhttp/plugins/dynamix/include/CheckPort.php @@ -1,6 +1,6 @@ "._('Interface')." ".str_replace('eth', _('Ethernet Port')." ", $port)." "._('is down').". "._('Check cable')."!"; +$port = ($_POST['port'] ?? 'eth0') ?: 'eth0'; +if (exec("ip -br link show ".escapeshellarg($port)." | grep -om1 'NO-CARRIER'")) { + echo "",_('Interface')," - ",_('Ethernet Port')," ",preg_replace('/[^0-9]/','',$port)," ",_('is down'),". ",_('Check cable'),"!"; } ?> diff --git a/emhttp/plugins/dynamix/include/PortToggle.php b/emhttp/plugins/dynamix/include/PortToggle.php index 0746c4147..18be3da36 100644 --- a/emhttp/plugins/dynamix/include/PortToggle.php +++ b/emhttp/plugins/dynamix/include/PortToggle.php @@ -1,6 +1,6 @@ ' : ''; $wait = 5; while ($wait > 0) { - if (exec("ip link show ".escapeshellarg($port)."|grep -om1 'UP>'")==$pass) break; + if (exec("ip -br link show ".escapeshellarg($port)." | awk '{print \$2;exit}'")==strtoupper($cmd)) break; sleep(1); $wait--; } diff --git a/emhttp/plugins/dynamix/scripts/netconfig b/emhttp/plugins/dynamix/scripts/netconfig index 81d12d4ab..b8341993f 100755 --- a/emhttp/plugins/dynamix/scripts/netconfig +++ b/emhttp/plugins/dynamix/scripts/netconfig @@ -24,15 +24,20 @@ $dns = $set === 'renew'; $ini = parse_ini_file('/var/local/emhttp/network.ini',true); ksort($ini,SORT_NATURAL); $cfg = '/boot/config/network.cfg'; +function port_exists($port) { + $sys = '/sys/class/net'; + return file_exists("$sys/$port"); +} + function port($x) { - $sys = "/sys/class/net"; - return file_exists("$sys/br{$x}") ? "br{$x}" : (file_exists("$sys/bond{$x}") ? "bond{$x}" : "eth{$x}"); + $sys = '/sys/class/net'; + return file_exists("$sys/br{$x}") ? "br{$x}" : (file_exists("$sys/bond{$x}") ? "bond{$x}" : (file_exists("$sys/eth{$x}") ? "eth{$x}" : false)); } function update_wireguard($ifname) { - if (!in_array($ifname,['br0','bond0','eth0'])) return; $nic = port(0); - exec("wg show interfaces|tr ' ' '\n'",$active); + if (!in_array($ifname,['br0','bond0','eth0']) || !$nic) return; + exec("wg show interfaces | tr ' ' '\n'",$active); foreach (glob("/etc/wireguard/*.conf",GLOB_NOSORT) as $wg) { $vtun = basename($wg,'.conf'); // interface has changed? @@ -71,7 +76,7 @@ if ($run) { if ($dns) { $cmd = 'start_renew'; $ifname = port(0); - exec("/etc/rc.d/rc.inet1 ".escapeshellarg("{$ifname}_stop_renew")." >/dev/null"); + if ($ifname) exec("/etc/rc.d/rc.inet1 ".escapeshellarg("{$ifname}_stop_renew")." >/dev/null"); } else { $cmd = 'start'; $old = []; @@ -85,18 +90,18 @@ if ($run) { if ($set=='eth0') $ifname = $old['BRIDGING']=='yes' ? ($old['BRNAME'] ?? 'br0') : ($old['BONDING']=='yes' ? ($old['BONDNAME'] ?? 'bond0') : $set); } } - exec("/etc/rc.d/rc.inet1 ".escapeshellarg("{$ifname}_stop")." >/dev/null"); + if (port_exists($ifname)) exec("/etc/rc.d/rc.inet1 ".escapeshellarg("{$ifname}_stop")." >/dev/null"); if ($ini[$set]['BONDING']=='yes') { // release additional NICs in bond foreach (bond_nics($ini[$set],$set) as $nic) { if (isset($old['SYSNICS'])) $nic = ifname($nic); - if ($nic && $nic!=$ifname) exec("/etc/rc.d/rc.inet1 ".escapeshellarg("{$nic}_stop")." >/dev/null"); + if ($nic && $nic!=$ifname && port_exists($nic)) exec("/etc/rc.d/rc.inet1 ".escapeshellarg("{$nic}_stop")." >/dev/null"); } } elseif ($ini[$set]['BRIDGING']=='yes') { // release additional NICs in bridge foreach (bridge_nics($ini[$set],$set) as $nic) { if (isset($old['SYSNICS'])) $nic = ifname($nic); - if ($nic && $nic!=$ifname) exec("/etc/rc.d/rc.inet1 ".escapeshellarg("{$nic}_stop")." >/dev/null"); + if ($nic && $nic!=$ifname && port_exists($nic)) exec("/etc/rc.d/rc.inet1 ".escapeshellarg("{$nic}_stop")." >/dev/null"); } } } @@ -107,6 +112,7 @@ $i = 0; $new = ["# Generated settings:"]; foreach ($ini as $name => $port) { $bonding = $port['BONDING']=='yes'; $bridging = $port['BRIDGING']=='yes'; + if (!port_exists($name)) continue; if ($bonding && in_array($name,bond_nics($port,$name))) continue; if ($bridging && in_array($name,bridge_nics($port,$name))) continue; $trunk = $port['TYPE']=='trunk'; @@ -148,9 +154,11 @@ file_put_contents($cfg,implode("\r\n",$new)."\r\n"); // start interface with updated (new) configuration // don't execute when only interface description has changed if ($run) { - exec("/etc/rc.d/rc.inet1 ".escapeshellarg("{$ifname}_{$cmd}")." >/dev/null"); - exec("/usr/local/sbin/create_network_ini ".escapeshellarg($ifname)." &>/dev/null &"); - if (!$dns) update_wireguard($ifname); + if (port_exists($ifname)) { + exec("/etc/rc.d/rc.inet1 ".escapeshellarg("{$ifname}_{$cmd}")." >/dev/null"); + exec("/usr/local/sbin/create_network_ini ".escapeshellarg($ifname)." &>/dev/null &"); + if (!$dns) update_wireguard($ifname); + } } exit(0); ?> diff --git a/sbin/create_network_ini b/sbin/create_network_ini index 0c1459f8b..318f968fb 100755 --- a/sbin/create_network_ini +++ b/sbin/create_network_ini @@ -54,6 +54,7 @@ for ((i=0; i<${SYSNICS:-1}; i++)); do IFACE=${IFNAME[$i]:-eth$i} ETH=${IFACE/#bond/eth} ETH=${ETH/#br/eth} + [[ -e $SYS/$ETH ]] || continue echo "[$ETH]" >>$INI if [[ $i -eq 0 ]]; then # process legacy settings @@ -120,6 +121,7 @@ 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_GW:0=\"${USE_GW[$i]}\"" >>$INI if [[ ${USE_DHCP[$i]} == yes ]]; then # get dhcp assigned ipv4 address & mask NET=($(ip -br -4 addr show $IFACE|awk '{sub("/"," ",$3);print $3;exit}')) @@ -136,6 +138,7 @@ for ((i=0; i<${SYSNICS:-1}; i++)); do echo "METRIC:0=\"${METRIC[$i]}\"" >>$INI 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 -br -6 addr show $IFACE scope global|awk '{sub("/"," ",$NF);print $NF;exit}')) @@ -162,6 +165,7 @@ for ((i=0; i<${SYSNICS:-1}; i++)); do 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_GW:$j=\"${USE_GW[$i,$j]}\"" >>$INI if [[ ${USE_DHCP[$i,$j]} == yes ]]; then DEV=$IFACE.${VLANID[$i,$j]} # get dhcp assigned ipv4 address & mask @@ -179,6 +183,7 @@ for ((i=0; i<${SYSNICS:-1}; i++)); do echo "METRIC:$j=\"${METRIC[$i,$j]}\"" >>$INI 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