From ec32733dab8bb0b1ae906c01dfe216b787cd7d07 Mon Sep 17 00:00:00 2001 From: Mario Fetka Date: Thu, 21 May 2026 17:11:06 +0200 Subject: [PATCH] add drop down menu for interfaces with IPX active --- settings.pl | 108 ++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 97 insertions(+), 11 deletions(-) diff --git a/settings.pl b/settings.pl index 6cb83f2..63977a9 100644 --- a/settings.pl +++ b/settings.pl @@ -34,6 +34,95 @@ sub html_escape( $ ) return $s; } +sub kernel_network_interfaces() +{ + my %interfaces = (); + + if( opendir( my $dh, '/sys/class/net' ) ) + { + foreach my $ifname ( readdir( $dh ) ) + { + next if $ifname =~ /^\./; + next if $ifname =~ /[^-_\.A-Za-z0-9]/; + $interfaces{$ifname} = 1; + } + closedir( $dh ); + } + + return %interfaces; +} + +sub ipx_enabled_interfaces() +{ + my %ipx_interfaces = (); + + # Modern Linux IPX procfs format: + # Network Node_Address Primary Device Frame_Type + # AC100B98 000000000001 Yes Internal None + # 00000022 508140F6AC45 No enp46s0u1u3u3 802.2 + if( open( my $fh, '<', '/proc/net/ipx/interface' ) ) + { + while( my $line = <$fh> ) + { + chomp( $line ); + $line =~ s/^\s+//; + $line =~ s/\s+$//; + + next if $line eq ''; + next if $line =~ /^Network\s+Node_Address\s+Primary\s+Device\s+Frame_Type/i; + + my @fields = split( /\s+/, $line ); + + # Device is the fourth column. Do not scan all tokens, otherwise + # Network/Node/Frame_Type values can accidentally be treated as names. + next if scalar( @fields ) < 5; + + my $dev = $fields[3]; + next if ! defined( $dev ); + next if $dev eq ''; + next if lc( $dev ) eq 'internal'; + next if $dev =~ /[^-_\.A-Za-z0-9]/; + + # Only show real Linux network interfaces. + next if ! -e '/sys/class/net/' . $dev; + + $ipx_interfaces{$dev} = 1; + } + + close( $fh ); + } + + # Fallback for older distributions/tools, if present. This parser is kept + # deliberately conservative and still verifies /sys/class/net/. + if( open( my $fh, '<', '/proc/net/ipx_interfaces' ) ) + { + while( my $line = <$fh> ) + { + chomp( $line ); + $line =~ s/^\s+//; + $line =~ s/\s+$//; + + next if $line eq ''; + next if $line =~ /^(Network|Net|Address|Node|Interface|Device)\b/i; + + foreach my $dev ( split( /\s+/, $line ) ) + { + next if ! defined( $dev ); + next if $dev eq ''; + next if lc( $dev ) eq 'internal'; + next if $dev =~ /[^-_\.A-Za-z0-9]/; + next if ! -e '/sys/class/net/' . $dev; + + $ipx_interfaces{$dev} = 1; + } + } + + close( $fh ); + } + + return sort keys %ipx_interfaces; +} + sub network_interface_options( $ ) { my $current = $_[0]; @@ -43,17 +132,14 @@ sub network_interface_options( $ ) $current = '' unless defined $current; - if( opendir( my $dh, '/sys/class/net' ) ) + # Only show interfaces where IPX is currently active. The current value is + # still preserved below, so an existing config entry is not lost if the + # interface is temporarily down or IPX is not loaded at display time. + foreach my $ifname ( ipx_enabled_interfaces() ) { - foreach my $ifname ( sort readdir( $dh ) ) - { - next if $ifname =~ /^\./; - next if $ifname =~ /[^-_\.A-Za-z0-9]/; - next if $seen{$ifname}; - push( @interfaces, $ifname ); - $seen{$ifname} = 1; - } - closedir( $dh ); + next if $seen{$ifname}; + push( @interfaces, $ifname ); + $seen{$ifname} = 1; } # Keep special/manual values usable even if they are not real kernel interfaces. @@ -69,7 +155,7 @@ sub network_interface_options( $ ) { my $selected = ( $ifname eq $current ) ? ' SELECTED' : ''; my $label = $ifname; - $label = '* (all interfaces)' if $ifname eq '*'; + $label = '* (all IPX interfaces)' if $ifname eq '*'; $label = 'auto' if $ifname eq 'auto'; $html .= '\t\t\t\t\n'; }