From 77c950bc1eb7897b70b204654d6ad6fb0751abbc Mon Sep 17 00:00:00 2001 From: MacRimi Date: Tue, 8 Jul 2025 22:42:12 +0200 Subject: [PATCH] Update network_menu.sh --- scripts/menus/network_menu.sh | 680 ++++++++++++++++++++++++++-------- 1 file changed, 522 insertions(+), 158 deletions(-) diff --git a/scripts/menus/network_menu.sh b/scripts/menus/network_menu.sh index 787d98f..d5ccef3 100644 --- a/scripts/menus/network_menu.sh +++ b/scripts/menus/network_menu.sh @@ -6,17 +6,13 @@ # Copyright : (c) 2024 MacRimi # License : MIT (https://raw.githubusercontent.com/MacRimi/ProxMenux/main/LICENSE) # Version : 1.1 -# Last Updated: 06/07/2025 +# Last Updated: 08/07/2025 # ========================================================== # Description: -# ProxMenu is an advanced yet user-friendly network management tool for Proxmox VE. -# Core features: -# - View and analyze network interfaces, bridges, and routing table -# - Test Internet and LAN connectivity -# - Diagnose and repair basic network issues -# - Backup, restore, and clean network configuration -# - Safely restart the network service +# Advanced network management and troubleshooting tool for Proxmox VE. +# Features include interface detection, bridge management, connectivity testing, +# network diagnostics, configuration backup/restore, and automated repairs. # Configuration ============================================ REPO_URL="https://raw.githubusercontent.com/MacRimi/ProxMenux/main" @@ -33,22 +29,24 @@ load_language initialize_cache # ========================================================== - +# Utility Functions create_backup_dir() { [ ! -d "$BACKUP_DIR" ] && mkdir -p "$BACKUP_DIR" } backup_network_config() { create_backup_dir - local timestamp=$(date +"%Y%m%d_%H%M%S") - cp /etc/network/interfaces "$BACKUP_DIR/interfaces_backup_$timestamp" + local timestamp=$(date +"%Y-%m-%d_%H-%M-%S") + local backup_file="$BACKUP_DIR/interfaces_backup_$timestamp" + cp /etc/network/interfaces "$backup_file" msg_ok "$(translate "Network configuration backed up")" + echo "$backup_file" } # ========================================================== - +# Network Detection Functions detect_physical_interfaces() { - ip -o link show | awk -F': ' '$2 !~ /^(lo|veth|dummy|bond|tap|tun)/ && $2 !~ /vmbr/ {print $2}' | sort + ip -o link show | awk -F': ' '$2 !~ /^(lo|veth|dummy|bond|tap|tun|docker|br-)/ && $2 !~ /vmbr/ {print $2}' | sort } detect_bridge_interfaces() { @@ -63,15 +61,15 @@ get_interface_info() { local interface="$1" local info="" - + # Get IP address local ip=$(ip -4 addr show "$interface" 2>/dev/null | grep -oP '(?<=inet\s)\d+(\.\d+){3}/\d+' | head -1) [ -z "$ip" ] && ip="$(translate "No IP")" - + # Get status local status=$(ip link show "$interface" 2>/dev/null | grep -o "state [A-Z]*" | cut -d' ' -f2) [ -z "$status" ] && status="UNKNOWN" - + # Get MAC address local mac=$(ip link show "$interface" 2>/dev/null | grep -o "link/ether [a-f0-9:]*" | cut -d' ' -f2) [ -z "$mac" ] && mac="$(translate "No MAC")" @@ -79,7 +77,7 @@ get_interface_info() { } # ========================================================== - +# Network Information Functions show_interface_details() { local interfaces=($(detect_all_interfaces)) local info_text="" @@ -97,7 +95,7 @@ show_interface_details() { info_text+=" $(translate "MAC Address"): $mac\n\n" done - dialog --title "$(translate "Interface Details")" \ + dialog --backtitle "ProxMenux" --title "$(translate "Interface Details")" \ --msgbox "$info_text" 20 70 } @@ -115,7 +113,7 @@ show_bridge_status() { local details=$(get_interface_info "$bridge") IFS='|' read -r name ip status mac <<< "$details" - + # Get bridge ports local ports=$(grep -A5 "iface $bridge" /etc/network/interfaces 2>/dev/null | grep "bridge-ports" | cut -d' ' -f2-) [ -z "$ports" ] && ports="$(translate "None")" @@ -126,23 +124,54 @@ show_bridge_status() { done fi - dialog --title "$(translate "Bridge Status")" \ + dialog --backtitle "ProxMenux" --title "$(translate "Bridge Status")" \ --msgbox "$bridge_info" 18 70 } -show_routing_table() { +show_routing_table_() { local route_info="" route_info+="$(translate "Routing Table")\n" route_info+="$(printf '=%.0s' {1..30})\n\n" route_info+="$(ip route show)\n\n" route_info+="$(translate "Default Gateway"): $(ip route | grep default | awk '{print $3}' | head -1)\n" - dialog --title "$(translate "Routing Information")" \ + dialog --backtitle "ProxMenux" --title "$(translate "Routing Information")" \ --msgbox "$route_info" 15 80 } -# ========================================================== +show_routing_table() { + local route_info="" + local default_gw=$(ip route | grep default | awk '{print $3}' | head -1) + local routes=$(ip route show) + local route_count=$(echo "$routes" | wc -l) + + route_info+="πŸ—ΊοΈ $(translate "Routing Table")\n" + route_info+="$(printf '═%.0s' {1..60})\n\n" + + if [ -z "$routes" ]; then + route_info+="⚠️ $(translate "No routing information found.")\n\n" + else + route_info+="$(translate "Total routes"): $route_count\n\n" + + while read -r line; do + if [[ "$line" == *"default"* ]]; then + route_info+="➑️ $line\n" + else + route_info+=" β€’ $line\n" + fi + done <<< "$routes" + route_info+="\n" + route_info+="🌍 $(translate "Default Gateway"): ${default_gw:-$(translate "Not found")}\n" + fi + + dialog --backtitle "ProxMenux" --title "$(translate "Routing Information")" \ + --msgbox "$route_info" 20 85 +} + + +# ========================================================== +# Network Testing Functions test_connectivity() { local test_results="" local tests=( @@ -166,14 +195,14 @@ test_connectivity() { fi done - + # DNS Resolution test if nslookup google.com >/dev/null 2>&1; then test_results+="βœ“ $(translate "DNS Resolution"): $(translate "OK")\n" else test_results+="βœ— $(translate "DNS Resolution"): $(translate "FAILED")\n" fi cleanup - dialog --title "$(translate "Connectivity Test")" \ + dialog --backtitle "ProxMenux" --title "$(translate "Connectivity Test")" \ --msgbox "$test_results" 15 60 } @@ -187,194 +216,294 @@ advanced_network_diagnostics() { diag_info+="$(translate "Advanced Network Diagnostics")\n" diag_info+="$(printf '=%.0s' {1..40})\n\n" - + # Network statistics diag_info+="$(translate "Active Connections"): $(ss -tuln | wc -l)\n" diag_info+="$(translate "Listening Ports"): $(ss -tln | grep LISTEN | wc -l)\n" diag_info+="$(translate "Network Interfaces"): $(ip link show | grep -c "^[0-9]")\n\n" - + # Check for common issues diag_info+="$(translate "Common Issues Check"):\n" - + # Check if NetworkManager is running (shouldn't be on Proxmox) if systemctl is-active --quiet NetworkManager 2>/dev/null; then diag_info+="⚠ $(translate "NetworkManager is running (may cause conflicts)")\n" + + if dialog --title "$(translate "NetworkManager Detected")" \ + --yesno "$(translate "NetworkManager is running, which may conflict with Proxmox.")\n\n$(translate "Do you want to disable and remove it now?")" 10 70; then + + dialog --infobox "$(translate "Disabling and removing NetworkManager...")" 6 60 + systemctl stop NetworkManager >/dev/null 2>&1 + systemctl disable NetworkManager >/dev/null 2>&1 + apt-get purge -y network-manager >/dev/null 2>&1 + + diag_info+="βœ“ $(translate "NetworkManager has been removed successfully")\n" + else + diag_info+="ℹ️ $(translate "User chose not to remove NetworkManager")\n" + fi else diag_info+="βœ“ $(translate "NetworkManager not running")\n" fi - + # Check for duplicate IPs local ips=($(ip -4 addr show | grep -oP '(?<=inet\s)\d+(\.\d+){3}' | sort | uniq -d)) if [ ${#ips[@]} -gt 0 ]; then diag_info+="⚠ $(translate "Duplicate IP addresses found"): ${ips[*]}\n" else diag_info+="βœ“ $(translate "No duplicate IP addresses")\n" fi + cleanup - dialog --title "$(translate "Network Diagnostics")" \ + + dialog --backtitle "ProxMenux" --title "$(translate "Network Diagnostics")" \ --msgbox "$diag_info" 18 70 } + +# ========================================================== +# SAFE Network Analysis Functions (NO AUTO-REPAIR) # ========================================================== -repair_bridge_configuration() { +analyze_bridge_configuration() { show_proxmenux_logo - msg_info "$(translate "Analyzing Bridge Configuration")" + msg_info "$(translate "Analyzing Bridge Configuration - READ ONLY MODE")" sleep 1 local physical_interfaces=($(detect_physical_interfaces)) local bridges=($(detect_bridge_interfaces)) - local issues_found="" - local proposed_changes="" + local analysis_report="" + local issues_found=0 + local suggestions="" - + analysis_report+="πŸ” $(translate "BRIDGE CONFIGURATION ANALYSIS")\n" + analysis_report+="$(printf '=%.0s' {1..50})\n\n" + cleanup + if [ ${#bridges[@]} -eq 0 ]; then + analysis_report+="ℹ️ $(translate "No bridges found in system")\n" + dialog --backtitle "ProxMenux" --title "$(translate "Bridge Analysis")" --msgbox "$analysis_report" 10 60 + return + fi + + # Analyze each bridge for bridge in "${bridges[@]}"; do + analysis_report+="πŸŒ‰ $(translate "Bridge"): $bridge\n" + + # Get current configuration local current_ports=$(grep -A5 "iface $bridge" /etc/network/interfaces 2>/dev/null | grep "bridge-ports" | cut -d' ' -f2-) + local bridge_ip=$(ip -4 addr show "$bridge" 2>/dev/null | grep -oP '(?<=inet\s)\d+(\.\d+){3}/\d+' | head -1) + local bridge_status=$(ip link show "$bridge" 2>/dev/null | grep -o "state [A-Z]*" | cut -d' ' -f2) + + analysis_report+=" πŸ“ $(translate "Status"): ${bridge_status:-UNKNOWN}\n" + analysis_report+=" 🌐 $(translate "IP"): ${bridge_ip:-$(translate "No IP assigned")}\n" + analysis_report+=" πŸ”Œ $(translate "Configured Ports"): ${current_ports:-$(translate "None")}\n" if [ -n "$current_ports" ]; then local invalid_ports="" local valid_ports="" + # Check each configured port for port in $current_ports; do if ip link show "$port" >/dev/null 2>&1; then valid_ports+="$port " + analysis_report+=" βœ… $(translate "Port") $port: $(translate "EXISTS")\n" else invalid_ports+="$port " + analysis_report+=" ❌ $(translate "Port") $port: $(translate "NOT FOUND")\n" + ((issues_found++)) fi done + # Generate suggestions for invalid ports if [ -n "$invalid_ports" ]; then - issues_found+="$(translate "Bridge") $bridge: $(translate "Invalid ports") - $invalid_ports\n" - if [ -z "$valid_ports" ] && [ ${#physical_interfaces[@]} -gt 0 ]; then - proposed_changes+="$(translate "Assign") ${physical_interfaces[0]} $(translate "to") $bridge\n" + suggestions+="πŸ”§ $(translate "SUGGESTION FOR") $bridge:\n" + if [ ${#physical_interfaces[@]} -gt 0 ]; then + suggestions+=" $(translate "Replace invalid port(s)") '$invalid_ports' $(translate "with"): ${physical_interfaces[0]}\n" + suggestions+=" $(translate "Command"): sed -i 's/bridge-ports.*/bridge-ports ${physical_interfaces[0]}/' /etc/network/interfaces\n" else - proposed_changes+="$(translate "Remove invalid ports from") $bridge\n" + suggestions+=" $(translate "Remove invalid port(s)") '$invalid_ports'\n" + suggestions+=" $(translate "Command"): sed -i 's/bridge-ports.*/bridge-ports none/' /etc/network/interfaces\n" fi + suggestions+="\n" + fi + else + analysis_report+=" ⚠️ $(translate "No ports configured")\n" + if [ ${#physical_interfaces[@]} -gt 0 ]; then + suggestions+="πŸ”§ $(translate "SUGGESTION FOR") $bridge:\n" + suggestions+=" $(translate "Consider adding physical interface"): ${physical_interfaces[0]}\n" + suggestions+=" $(translate "Command"): sed -i '/iface $bridge/a\\ bridge-ports ${physical_interfaces[0]}' /etc/network/interfaces\n\n" fi fi + analysis_report+="\n" done - cleanup - if [ -z "$issues_found" ]; then - dialog --title "$(translate "Bridge Analysis")" \ - --msgbox "\n$(translate "No bridge configuration issues found.")" 8 60 - return + + # Summary + analysis_report+="πŸ“Š $(translate "ANALYSIS SUMMARY")\n" + analysis_report+="$(printf '=%.0s' {1..25})\n" + analysis_report+="$(translate "Bridges analyzed"): ${#bridges[@]}\n" + analysis_report+="$(translate "Issues found"): $issues_found\n" + + + local auto_only=$(grep "^auto" /etc/network/interfaces | awk '{print $2}' | while read i; do + grep -q "^iface $i" /etc/network/interfaces || echo "$i" + done) + + if [ -n "$auto_only" ]; then + analysis_report+="⚠️ $(translate "Interfaces defined with 'auto' but no 'iface' block"): $auto_only\n" + ((issues_found++)) + fi + + analysis_report+="$(translate "Physical interfaces available"): ${#physical_interfaces[@]}\n\n" + + if [ $issues_found -gt 0 ]; then + analysis_report+="$suggestions" + analysis_report+="⚠️ $(translate "IMPORTANT"): $(translate "No changes have been made to your system")\n" + analysis_report+="$(translate "Use the Guided Repair option to fix issues safely")\n" + else + analysis_report+="βœ… $(translate "No bridge configuration issues found")\n" fi + # Show analysis in scrollable dialog + local temp_file=$(mktemp) + echo -e "$analysis_report" > "$temp_file" + dialog --backtitle "ProxMenux" --title "$(translate "Bridge Configuration Analysis")" \ + --textbox "$temp_file" 25 80 + rm -f "$temp_file" + + # Offer guided repair if issues found + if [ $issues_found -gt 0 ]; then + if dialog --backtitle "ProxMenux" --title "$(translate "Guided Repair Available")" \ + --yesno "$(translate "Issues were found. Would you like to use the Guided Repair Assistant?")" 8 60; then + guided_bridge_repair + fi + fi +} - local confirmation_text="" - confirmation_text+="$(translate "Bridge Configuration Issues Found"):\n\n" - confirmation_text+="$issues_found\n" - confirmation_text+="$(translate "Proposed Changes"):\n\n" - confirmation_text+="$proposed_changes\n" - confirmation_text+="$(translate "A backup will be created before making changes.")\n\n" - confirmation_text+="$(translate "Do you want to proceed with these repairs?")" - - if ! dialog --title "$(translate "Confirm Bridge Repair")" \ - --yesno "$confirmation_text" 18 70; then +guided_bridge_repair() { + local step=1 + local total_steps=5 + + + local timestamp=$(date +"%Y%m%d_%H%M%S") + local preview_backup_file="$BACKUP_DIR/interfaces_backup_$timestamp" + + + if ! dialog --backtitle "ProxMenux" --title "$(translate "Step") $step/$total_steps: $(translate "Safety Backup")" \ + --yesno "$(translate "Before making any changes, we'll create a safety backup.")\n\n$(translate "Backup location"): $preview_backup_file\n\n$(translate "Continue?")" 12 70; then return fi - + ((step++)) + show_proxmenux_logo - echo -e - backup_network_config + local backup_file=$(backup_network_config) sleep 1 + + dialog --backtitle "ProxMenux" --title "$(translate "Backup Created")" \ + --msgbox "$(translate "Safety backup created"): $backup_file\n\n$(translate "You can restore it anytime with"):\ncp $backup_file /etc/network/interfaces" 10 70 - local repair_log="" - repair_log+="$(translate "Bridge Repair Process")\n" - repair_log+="$(printf '=%.0s' {1..30})\n\n" + # Step 2: Show current configuration + if ! dialog --backtitle "ProxMenux" --title "$(translate "Step") $step/$total_steps: $(translate "Current Configuration")" \ + --yesno "$(translate "Let's review your current network configuration.")\n\n$(translate "Would you like to see the current") /etc/network/interfaces $(translate "file?")" 10 70; then + return + fi + ((step++)) + + # Show current config + local temp_config=$(mktemp) + cat /etc/network/interfaces > "$temp_config" + dialog --backtitle "ProxMenux" --title "$(translate "Current Network Configuration")" \ + --textbox "$temp_config" 20 80 + rm -f "$temp_config" + + # Step 3: Identify specific changes needed + local physical_interfaces=($(detect_physical_interfaces)) + local bridges=($(detect_bridge_interfaces)) + local changes_needed="" for bridge in "${bridges[@]}"; do local current_ports=$(grep -A5 "iface $bridge" /etc/network/interfaces 2>/dev/null | grep "bridge-ports" | cut -d' ' -f2-) if [ -n "$current_ports" ]; then - local valid_ports="" + for port in $current_ports; do + if ! ip link show "$port" >/dev/null 2>&1; then + if [ ${#physical_interfaces[@]} -gt 0 ]; then + changes_needed+="$(translate "Bridge") $bridge: $(translate "Replace") '$port' $(translate "with") '${physical_interfaces[0]}'\n" + else + changes_needed+="$(translate "Bridge") $bridge: $(translate "Remove invalid port") '$port'\n" + fi + fi + done + fi + done + + if [ -z "$changes_needed" ]; then + dialog --backtitle "ProxMenux" --title "$(translate "No Changes Needed")" \ + --msgbox "$(translate "After detailed analysis, no changes are needed.")" 8 50 + return + fi + + if ! dialog --backtitle "ProxMenux" --title "$(translate "Step") $step/$total_steps: $(translate "Proposed Changes")" \ + --yesno "$(translate "These are the changes that will be made"):\n\n$changes_needed\n$(translate "Do you want to proceed?")" 15 70; then + return + fi + ((step++)) + + # Step 4: Apply changes with verification + dialog --backtitle "ProxMenux" --title "$(translate "Step") $step/$total_steps: $(translate "Applying Changes")" \ + --infobox "$(translate "Applying changes safely...")\n\n$(translate "This may take a few seconds...")" 8 50 + + # Apply the changes + for bridge in "${bridges[@]}"; do + local current_ports=$(grep -A5 "iface $bridge" /etc/network/interfaces 2>/dev/null | grep "bridge-ports" | cut -d' ' -f2-) + + if [ -n "$current_ports" ]; then + local new_ports="" for port in $current_ports; do if ip link show "$port" >/dev/null 2>&1; then - valid_ports+="$port " - else - repair_log+="⚠ $(translate "Removed invalid port"): $port $(translate "from") $bridge\n" + new_ports+="$port " fi done - if [ -z "$valid_ports" ] && [ ${#physical_interfaces[@]} -gt 0 ]; then - valid_ports="${physical_interfaces[0]}" - repair_log+="βœ“ $(translate "Assigned port"): ${physical_interfaces[0]} $(translate "to") $bridge\n" + # If no valid ports and we have physical interfaces, use the first one + if [ -z "$new_ports" ] && [ ${#physical_interfaces[@]} -gt 0 ]; then + new_ports="${physical_interfaces[0]}" fi - if [ "$valid_ports" != "$current_ports" ]; then - sed -i "/iface $bridge/,/bridge-ports/ s/bridge-ports.*/bridge-ports $valid_ports/" /etc/network/interfaces - repair_log+="βœ“ $(translate "Updated bridge"): $bridge\n" - else - repair_log+="βœ“ $(translate "Bridge OK"): $bridge\n" + # Apply the change + if [ "$new_ports" != "$current_ports" ]; then + sed -i "/iface $bridge/,/bridge-ports/ s/bridge-ports.*/bridge-ports $new_ports/" /etc/network/interfaces fi fi done + ((step++)) - dialog --title "$(translate "Bridge Repair Complete")" \ - --msgbox "$repair_log" 15 70 -} - -clean_network_configuration() { - - show_proxmenux_logo - msg_info "$(translate "Analyzing Network Configuration")" - sleep 1 + # Step 5: Verification + local verification_report="" + verification_report+="βœ… $(translate "CHANGES APPLIED SUCCESSFULLY")\n\n" + verification_report+="$(translate "Verification"):\n" - - local configured_interfaces=($(grep "^iface" /etc/network/interfaces | awk '{print $2}' | grep -v "lo")) - local interfaces_to_remove="" - - for iface in "${configured_interfaces[@]}"; do - if [[ ! $iface =~ ^(vmbr|bond) ]] && ! ip link show "$iface" >/dev/null 2>&1; then - interfaces_to_remove+="$iface " - fi - done - cleanup - if [ -z "$interfaces_to_remove" ]; then - dialog --title "$(translate "Configuration Analysis")" \ - --msgbox "\n$(translate "No invalid interface configurations found.")" 8 60 - return - fi - - - local confirmation_text="" - confirmation_text+="$(translate "Invalid Interface Configurations Found"):\n\n" - confirmation_text+="$(translate "The following interfaces are configured but don't exist"):\n" - confirmation_text+="$interfaces_to_remove\n\n" - confirmation_text+="$(translate "These configurations will be removed from") /etc/network/interfaces\n" - confirmation_text+="$(translate "A backup will be created before making changes.")\n\n" - confirmation_text+="$(translate "Do you want to proceed with cleanup?")" - - if ! dialog --title "$(translate "Confirm Configuration Cleanup")" \ - --yesno "$confirmation_text" 16 70; then - return - fi - - show_proxmenux_logo - echo -e - backup_network_config - sleep 1 - - local cleanup_log="" - cleanup_log+="$(translate "Network Configuration Cleanup")\n" - cleanup_log+="$(printf '=%.0s' {1..35})\n\n" - - for iface in "${configured_interfaces[@]}"; do - if [[ ! $iface =~ ^(vmbr|bond) ]] && ! ip link show "$iface" >/dev/null 2>&1; then - sed -i "/iface $iface/,/^$/d" /etc/network/interfaces - cleanup_log+="βœ“ $(translate "Removed configuration for"): $iface\n" - fi + for bridge in "${bridges[@]}"; do + local new_ports=$(grep -A5 "iface $bridge" /etc/network/interfaces 2>/dev/null | grep "bridge-ports" | cut -d' ' -f2-) + verification_report+="$(translate "Bridge") $bridge: $new_ports\n" + + # Verify each port exists + for port in $new_ports; do + if ip link show "$port" >/dev/null 2>&1; then + verification_report+=" βœ… $port: $(translate "EXISTS")\n" + else + verification_report+=" ❌ $port: $(translate "NOT FOUND")\n" + fi + done done - cleanup_log+="$(translate "Cleanup completed")\n" + verification_report+="\n$(translate "Backup available at"): $backup_file\n" + verification_report+="$(translate "To restore"): cp $backup_file /etc/network/interfaces" - dialog --title "$(translate "Configuration Cleanup Complete")" \ - --msgbox "$cleanup_log" 12 60 -} - -restart_network_service() { - if dialog --title "$(translate "Restart Network")" \ - --yesno "$(translate "This will restart the network service and may cause a brief disconnection. Continue?")" 10 60; then + dialog --backtitle "ProxMenux" --title "$(translate "Step") $step/$total_steps: $(translate "Repair Complete")" \ + --msgbox "$verification_report" 18 70 + + # Ask about network restart + if dialog --backtitle "ProxMenux" --title "$(translate "Network Restart")" \ + --yesno "$(translate "Changes have been applied to the configuration file.")\n\n$(translate "Do you want to restart the network service to apply changes?")\n\n$(translate "WARNING: This may cause a brief disconnection.")" 12 70; then clear msg_info "$(translate "Restarting network service...")" @@ -383,6 +512,7 @@ restart_network_service() { msg_ok "$(translate "Network service restarted successfully")" else msg_error "$(translate "Failed to restart network service")" + msg_warn "$(translate "You can restore the backup with"): cp $backup_file /etc/network/interfaces" fi msg_success "$(translate "Press ENTER to continue...")" @@ -390,8 +520,205 @@ restart_network_service() { fi } -# ========================================================== +analyze_network_configuration() { + show_proxmenux_logo + msg_info "$(translate "Analyzing Network Configuration - READ ONLY MODE")" + sleep 1 + + local configured_interfaces=($(grep "^iface" /etc/network/interfaces | awk '{print $2}' | grep -v "lo")) + local analysis_report="" + local issues_found=0 + local suggestions="" + + analysis_report+="πŸ” $(translate "NETWORK CONFIGURATION ANALYSIS")\n" + analysis_report+="$(printf '=%.0s' {1..50})\n\n" + + cleanup + if [ ${#configured_interfaces[@]} -eq 0 ]; then + analysis_report+="ℹ️ $(translate "No network interfaces configured (besides loopback)")\n" + dialog --title "$(translate "Configuration Analysis")" --msgbox "$analysis_report" 10 60 + return + fi + + analysis_report+="πŸ“‹ $(translate "CONFIGURED INTERFACES")\n" + analysis_report+="$(printf '=%.0s' {1..30})\n" + + # Analyze each configured interface + for iface in "${configured_interfaces[@]}"; do + analysis_report+="πŸ”Œ $(translate "Interface"): $iface\n" + + # Check if interface exists physically + if ip link show "$iface" >/dev/null 2>&1; then + local status=$(ip link show "$iface" 2>/dev/null | grep -o "state [A-Z]*" | cut -d' ' -f2) + local ip=$(ip -4 addr show "$iface" 2>/dev/null | grep -oP '(?<=inet\s)\d+(\.\d+){3}/\d+' | head -1) + + analysis_report+=" βœ… $(translate "Status"): $(translate "EXISTS") ($status)\n" + analysis_report+=" 🌐 $(translate "IP"): ${ip:-$(translate "No IP assigned")}\n" + + # Check if it's a bridge or bond (these are virtual, so it's normal they exist) + if [[ $iface =~ ^(vmbr|bond) ]]; then + analysis_report+=" ℹ️ $(translate "Type"): $(translate "Virtual interface (normal)")\n" + else + analysis_report+=" ℹ️ $(translate "Type"): $(translate "Physical interface")\n" + fi + else + analysis_report+=" ❌ $(translate "Status"): $(translate "NOT FOUND")\n" + analysis_report+=" ⚠️ $(translate "Issue"): $(translate "Configured but doesn't exist")\n" + ((issues_found++)) + + # Only suggest removal for non-virtual interfaces + if [[ ! $iface =~ ^(vmbr|bond) ]]; then + suggestions+="πŸ”§ $(translate "SUGGESTION FOR") $iface:\n" + suggestions+=" $(translate "This interface is configured but doesn't exist physically")\n" + suggestions+=" $(translate "Consider removing its configuration")\n" + suggestions+=" $(translate "Command"): sed -i '/iface $iface/,/^$/d' /etc/network/interfaces\n\n" + fi + fi + analysis_report+="\n" + done + + # Summary + analysis_report+="πŸ“Š $(translate "ANALYSIS SUMMARY")\n" + analysis_report+="$(printf '=%.0s' {1..25})\n" + analysis_report+="$(translate "Interfaces configured"): ${#configured_interfaces[@]}\n" + analysis_report+="$(translate "Issues found"): $issues_found\n\n" + + if [ $issues_found -gt 0 ]; then + analysis_report+="$suggestions" + analysis_report+="⚠️ $(translate "IMPORTANT"): $(translate "No changes have been made to your system")\n" + analysis_report+="$(translate "Use the Guided Cleanup option to fix issues safely")\n" + else + analysis_report+="βœ… $(translate "No configuration issues found")\n" + fi + + # Show analysis in scrollable dialog + local temp_file=$(mktemp) + echo -e "$analysis_report" > "$temp_file" + dialog --backtitle "ProxMenux" --title "$(translate "Network Configuration Analysis")" \ + --textbox "$temp_file" 25 80 + rm -f "$temp_file" + + # Offer guided cleanup if issues found + if [ $issues_found -gt 0 ]; then + if dialog --backtitle "ProxMenux" --title "$(translate "Guided Cleanup Available")" \ + --yesno "$(translate "Issues were found. Would you like to use the Guided Cleanup Assistant?")" 8 60; then + guided_configuration_cleanup + fi + fi +} +guided_configuration_cleanup() { + local step=1 + local total_steps=5 + + local timestamp=$(date +"%Y%m%d_%H%M%S") + local preview_backup_file="$BACKUP_DIR/interfaces_backup_$timestamp" + + + if ! dialog --backtitle "ProxMenux" --title "$(translate "Step") $step/$total_steps: $(translate "Safety Backup")" \ + --yesno "$(translate "Before making any changes, we'll create a safety backup.")\n\n$(translate "Backup location"): $preview_backup_file\n\n$(translate "Continue?")" 12 70; then + return + fi + ((step++)) + + + show_proxmenux_logo + local backup_file=$(backup_network_config) + sleep 1 + + dialog --backtitle "ProxMenux" --title "$(translate "Backup Created")" \ + --msgbox "$(translate "Safety backup created"): $backup_file\n\n$(translate "You can restore it anytime with"):\ncp $backup_file /etc/network/interfaces" 10 70 + + # Step 2: Identify interfaces to remove + local configured_interfaces=($(grep "^iface" /etc/network/interfaces | awk '{print $2}' | grep -v "lo")) + local interfaces_to_remove="" + local removal_list="" + + for iface in "${configured_interfaces[@]}"; do + if [[ ! $iface =~ ^(vmbr|bond) ]] && ! ip link show "$iface" >/dev/null 2>&1; then + interfaces_to_remove+="$iface " + removal_list+="❌ $iface: $(translate "Configured but doesn't exist")\n" + fi + done + + if [ -z "$interfaces_to_remove" ]; then + dialog --backtitle "ProxMenux" --title "$(translate "No Cleanup Needed")" \ + --msgbox "$(translate "After detailed analysis, no cleanup is needed.")" 8 50 + return + fi + + if ! dialog --backtitle "ProxMenux" --title "$(translate "Step") $step/$total_steps: $(translate "Interfaces to Remove")" \ + --yesno "$(translate "These interface configurations will be removed"):\n\n$removal_list\n$(translate "Do you want to proceed?")" 15 70; then + return + fi + ((step++)) + + # Step 3: Show what will be removed + local temp_preview=$(mktemp) + echo "$(translate "Configuration sections that will be REMOVED"):" > "$temp_preview" + echo "=================================================" >> "$temp_preview" + echo "" >> "$temp_preview" + + for iface in $interfaces_to_remove; do + echo "# Interface: $iface" >> "$temp_preview" + sed -n "/^iface $iface/,/^$/p" /etc/network/interfaces >> "$temp_preview" + echo "" >> "$temp_preview" + done + + if ! dialog --backtitle "ProxMenux" --title "$(translate "Step") $step/$total_steps: $(translate "Preview Changes")" \ + --yesno "$(translate "Review what will be removed"):\n\n$(translate "Press OK to see the preview, then confirm")" 10 60; then + rm -f "$temp_preview" + return + fi + + dialog --backtitle "ProxMenux" --title "$(translate "Configuration to be Removed")" \ + --textbox "$temp_preview" 20 80 + rm -f "$temp_preview" + + if ! dialog --backtitle "ProxMenux" --title "$(translate "Final Confirmation")" \ + --yesno "$(translate "Are you sure you want to remove these configurations?")" 8 60; then + return + fi + ((step++)) + + # Step 4: Apply changes + dialog --backtitle "ProxMenux" --title "$(translate "Step") $step/$total_steps: $(translate "Applying Changes")" \ + --infobox "$(translate "Removing invalid configurations...")\n\n$(translate "This may take a few seconds...")" 8 50 + + for iface in $interfaces_to_remove; do + sed -i "/^iface $iface/,/^$/d" /etc/network/interfaces + done + ((step++)) + + # Step 5: Verification + local verification_report="" + verification_report+="βœ… $(translate "CLEANUP COMPLETED SUCCESSFULLY")\n\n" + verification_report+="$(translate "Removed configurations for"):\n" + + for iface in $interfaces_to_remove; do + verification_report+="❌ $iface\n" + done + + verification_report+="\n$(translate "Verification"): $(translate "Checking remaining interfaces")\n" + local remaining_interfaces=($(grep "^iface" /etc/network/interfaces | awk '{print $2}' | grep -v "lo")) + + for iface in "${remaining_interfaces[@]}"; do + if ip link show "$iface" >/dev/null 2>&1; then + verification_report+="βœ… $iface: $(translate "OK")\n" + else + verification_report+="⚠️ $iface: $(translate "Still has issues")\n" + fi + done + + verification_report+="\n$(translate "Backup available at"): $backup_file\n" + verification_report+="$(translate "To restore"): cp $backup_file /etc/network/interfaces" + + dialog --backtitle "ProxMenux" --title "$(translate "Step") $step/$total_steps: $(translate "Cleanup Complete")" \ + --msgbox "$verification_report" 18 70 +} + +# ========================================================== +# Configuration Management show_network_config() { local config_content config_content=$(cat /etc/network/interfaces) @@ -406,63 +733,99 @@ show_network_config() { read -r } + +create_network_backup_manual() { + + show_proxmenux_logo + echo -e + msg_info "$(translate "Creating backup of network interfaces configuration...")" + sleep 3 + backup_network_config + echo -e + msg_success "$(translate "Press Enter to continue...")" + read -r + +} + + + restore_network_backup() { local backups=($(ls -1 "$BACKUP_DIR"/interfaces_backup_* 2>/dev/null | sort -r)) if [ ${#backups[@]} -eq 0 ]; then - dialog --title "$(translate "No Backups")" \ - --msgbox "$(translate "No network configuration backups found.")" 8 50 + dialog --backtitle "ProxMenux" --title "$(translate "No Backups")" \ + --msgbox "\n$(translate "No network configuration backups found.")" 14 60 return fi - + local menu_items=() local counter=1 - + for backup in "${backups[@]}"; do local filename=$(basename "$backup") - local timestamp=$(echo "$filename" | sed 's/interfaces_backup_//' | sed 's/_/ /') + local timestamp=$(basename "$backup" | sed 's/interfaces_backup_//') menu_items+=("$counter" "$timestamp") ((counter++)) done - - local selection=$(dialog --title "$(translate "Restore Backup")" \ + + local selection=$(dialog --backtitle "ProxMenux" --title "$(translate "Restore Backup")" \ --menu "$(translate "Select backup to restore:"):" 15 60 8 \ "${menu_items[@]}" 3>&1 1>&2 2>&3) - + if [ -n "$selection" ] && [ "$selection" -ge 1 ] && [ "$selection" -le ${#backups[@]} ]; then local selected_backup="${backups[$((selection-1))]}" - - if dialog --title "$(translate "Confirm Restore")" \ - --yesno "$(translate "Are you sure you want to restore this backup? Current configuration will be overwritten.")" 10 60; then - + + + if dialog --backtitle "ProxMenux" --title "$(translate "Preview Backup")" \ + --yesno "\n$(translate "Do you want to view the selected backup before restoring?")" 8 60; then + dialog --backtitle "ProxMenux" --title "$(translate "Backup Preview")" \ + --textbox "$selected_backup" 22 80 + fi + + if dialog --backtitle "ProxMenux" --title "$(translate "Confirm Restore")" \ + --yesno "\n$(translate "Are you sure you want to restore this backup?\nCurrent configuration will be overwritten.")\n\n$(translate "For your safety, a backup of the current configuration will be created automatically before restoring.")" 14 70; then + + local pre_restore_backup=$(backup_network_config) cp "$selected_backup" /etc/network/interfaces - dialog --title "$(translate "Backup Restored")" \ - --msgbox "$(translate "Network configuration has been restored from backup.")" 8 60 + + + dialog --backtitle "ProxMenux" --title "$(translate "Backup Restored")" \ + --msgbox "\n$(translate "Network configuration has been restored from backup.")" 8 60 + + + if dialog --backtitle "ProxMenux" --title "$(translate "Restart Network")" \ + --yesno "\n$(translate "Do you want to restart the network service now to apply changes?")" 8 60; then + if systemctl restart networking; then + dialog --backtitle "ProxMenux" --title "$(translate "Network Restarted")" \ + --msgbox "\n$(translate "Network service restarted successfully.")" 8 50 + fi + fi fi fi } -# ========================================================== +# ========================================================== +# Main Menu show_main_menu() { while true; do local selection=$(dialog --clear \ --backtitle "ProxMenux" \ - --title "$(translate "Network Management")" \ + --title "$(translate "Network Management - SAFE MODE")" \ --menu "$(translate "Select an option:"):" 20 70 12 \ "1" "$(translate "Show Interface Details")" \ "2" "$(translate "Show Bridge Status")" \ "3" "$(translate "Show Routing Table")" \ "4" "$(translate "Test Connectivity")" \ "5" "$(translate "Advanced Diagnostics")" \ + "6" "$(translate "Analyze Bridge Configuration")" \ + "7" "$(translate "Analyze Network Configuration")" \ "8" "$(translate "Restart Network Service")" \ "9" "$(translate "Show Network Config File")" \ - "10" "$(translate "Restore Network Backup")" \ + "10" "$(translate "Create Network Backup")" \ + "11" "$(translate "Restore Network Backup")" \ "0" "$(translate "Return to Main Menu")" \ 3>&1 1>&2 2>&3) - - # "6" "$(translate "Repair Bridge Configuration")" \ - # "7" "$(translate "Clean Network Configuration")" \ case $selection in 1) show_interface_details ;; @@ -470,15 +833,16 @@ show_main_menu() { 3) show_routing_table ;; 4) test_connectivity ;; 5) advanced_network_diagnostics ;; - 6) repair_bridge_configuration ;; - 7) clean_network_configuration ;; + 6) analyze_bridge_configuration ;; + 7) analyze_network_configuration ;; 8) restart_network_service ;; 9) show_network_config ;; - 10) restore_network_backup ;; + 10) create_network_backup_manual ;; + 11) restore_network_backup ;; 0|"") exec bash <(curl -s "$REPO_URL/scripts/menus/main_menu.sh") ;; esac done } # ========================================================== -show_main_menu \ No newline at end of file +show_main_menu