Files
tms-bbt-config-pkg/tms-bbt-config/nm_network_manager.sh
2025-12-17 01:30:41 +08:00

508 lines
16 KiB
Bash
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/bin/bash
#
# Arch Linux NetworkManager 管理脚本 - 修复版
# 功能: 检查网络、自动修复、可靠地备份和恢复配置
#
# --- 全局变量和配置 ---
BACKUP_BASE_DIR="/var/lib/network-manager-script"
LOG_FILE="/var/log/nm_manager.log"
ACTIVE_CONNS_LIST="active_connections.list"
CONNECTION_DETAILS_DIR="connection_details"
# --- 颜色定义 ---
C_RESET='\033[0m'
C_RED='\033[0;31m'
C_GREEN='\033[0;32m'
C_YELLOW='\033[0;33m'
C_BLUE='\033[0;34m'
# --- 基础函数 ---
log() { echo -e "$(date '+%Y-%m-%d %H:%M:%S') - $1" | tee -a "$LOG_FILE"; }
log_success() { log "${C_GREEN}$1${C_RESET}"; }
log_error() { log "${C_RED}$1${C_RESET}"; }
log_warn() { log "${C_YELLOW}$1${C_RESET}"; }
info() { echo -e "${C_BLUE} $1${C_RESET}"; }
# 检查root权限和NetworkManager服务
pre_check() {
if [ "$(id -u)" -ne 0 ]; then
log_error "此脚本需要root权限运行。请使用: sudo \$0"
exit 1
fi
if ! systemctl is-active --quiet NetworkManager; then
log_error "NetworkManager 服务未运行。请先启动: sudo systemctl start NetworkManager"
exit 1
fi
}
# --- 核心功能 ---
# 1. 检查当前网络状态
check_status() {
info "--- 当前网络状态 ---"
nmcli device status
info "\n--- 活动连接 ---"
nmcli connection show --active
log "正在检查外网连接..."
if ping -c 2 -W 3 8.8.8.8 >/dev/null 2>&1 || ping -c 2 -W 3 1.1.1.1 >/dev/null 2>&1; then
log_success "外网连接正常。"
return 0
else
log_error "外网连接失败。"
return 1
fi
}
# 2. 改进的备份网络配置
backup_config() {
local backup_dir="$BACKUP_BASE_DIR/$(date +%F_%H-%M-%S)"
mkdir -p "$backup_dir"
mkdir -p "$backup_dir/$CONNECTION_DETAILS_DIR"
log "开始备份网络配置到: $backup_dir"
# 记录当前活动的连接
nmcli -t -f NAME,TYPE,UUID,DEVICE connection show --active | grep -v ':loopback:' > "$backup_dir/$ACTIVE_CONNS_LIST"
# 备份所有非回环连接的详细配置
local backup_count=0
while IFS=: read -r conn_name conn_type conn_uuid conn_device; do
if [ -n "$conn_name" ] && [ "$conn_type" != "loopback" ]; then
local safe_name=$(echo "$conn_name" | tr ' /' '_-')
local detail_file="$backup_dir/$CONNECTION_DETAILS_DIR/${safe_name}_${conn_uuid}.conf"
# 导出连接的完整配置
if nmcli -f all connection show "$conn_uuid" > "$detail_file" 2>/dev/null; then
info "已备份连接: $conn_name (UUID: $conn_uuid)"
((backup_count++))
# 尝试导出为keyfile格式如果支持
local keyfile="$backup_dir/$CONNECTION_DETAILS_DIR/${safe_name}_${conn_uuid}.keyfile"
nmcli connection export "$conn_uuid" "$keyfile" 2>/dev/null || true
else
log_warn "备份连接 '$conn_name' 失败"
fi
fi
done < <(nmcli -t -f NAME,TYPE,UUID,DEVICE connection show | grep -v ':loopback:')
# 备份网络设备信息
nmcli device status > "$backup_dir/device_status.txt"
ip addr show > "$backup_dir/ip_addresses.txt"
ip route show > "$backup_dir/routes.txt"
# 尝试备份系统连接文件(如果存在)
local system_conn_dir="/etc/NetworkManager/system-connections"
if [ -d "$system_conn_dir" ] && [ "$(ls -A "$system_conn_dir" 2>/dev/null)" ]; then
local sys_backup_dir="$backup_dir/system-connections"
mkdir -p "$sys_backup_dir"
cp -r "$system_conn_dir"/* "$sys_backup_dir/" 2>/dev/null
info "已备份系统连接文件"
fi
if [ "$backup_count" -gt 0 ]; then
# 创建符号链接指向最新备份
ln -sfn "$backup_dir" "$BACKUP_BASE_DIR/latest"
log_success "备份完成!共备份 $backup_count 个连接配置。"
# 显示备份摘要
info "备份摘要:"
info "- 活动连接: $(wc -l < "$backup_dir/$ACTIVE_CONNS_LIST")"
info "- 详细配置: $backup_count"
info "- 备份位置: $backup_dir"
else
log_warn "未找到任何可备份的连接。"
rm -rf "$backup_dir"
return 1
fi
}
# 3. 自动修复网络
auto_fix() {
log "启动网络自动修复流程..."
if check_status; then
log_success "网络已连接,无需修复。"
return
fi
log_warn "网络连接中断,将尝试自动修复。"
# 修复前先执行备份
backup_config
log "正在尝试为所有物理网卡设置临时DHCP连接..."
# 获取所有物理网卡
while IFS=: read -r device device_type state connection; do
if [ "$device_type" = "ethernet" ] || [ "$device_type" = "wifi" ]; then
if [ -n "$device" ] && [ "$device" != "lo" ]; then
local temp_conn_name="temp-dhcp-$device"
log "处理设备: $device (类型: $device_type, 状态: $state)"
# 先停用设备上的所有现有连接
nmcli device disconnect "$device" 2>/dev/null
# 删除可能存在的旧临时连接
nmcli connection delete "$temp_conn_name" 2>/dev/null
# 根据设备类型创建连接
local conn_type="ethernet"
if [ "$device_type" = "wifi" ]; then
conn_type="wifi"
fi
# 添加并激活新的临时DHCP连接
if nmcli connection add type "$conn_type" ifname "$device" con-name "$temp_conn_name" autoconnect yes ipv4.method auto ipv6.method auto >/dev/null 2>&1; then
info "$device 创建了临时DHCP连接 '$temp_conn_name'"
# 激活连接
if nmcli connection up "$temp_conn_name" >/dev/null 2>&1; then
info "成功激活连接 '$temp_conn_name'"
else
log_warn "激活连接 '$temp_conn_name' 失败"
fi
else
log_error "$device 创建DHCP连接失败"
fi
fi
fi
done < <(nmcli -t -f DEVICE,TYPE,STATE,CONNECTION device status)
log "等待网络重新初始化 (10秒)..."
sleep 10
log "再次检查网络状态..."
check_status
}
# 4. 智能恢复网络配置
restore_config() {
local backup_dir="$BACKUP_BASE_DIR/latest"
if [ ! -d "$backup_dir" ] || [ ! -L "$backup_dir" ]; then
log_error "找不到备份目录。请先执行备份(选项2)或修复(选项3)操作。"
return 1
fi
local real_backup_dir=$(readlink -f "$backup_dir")
log "将从以下备份中恢复: $real_backup_dir"
# 显示备份信息
if [ -f "$real_backup_dir/$ACTIVE_CONNS_LIST" ]; then
info "备份中的活动连接:"
while IFS=: read -r name type uuid device; do
info " - $name ($type) -> $device"
done < "$real_backup_dir/$ACTIVE_CONNS_LIST"
fi
# 尝试从系统连接文件恢复
local sys_backup_dir="$real_backup_dir/system-connections"
if [ -d "$sys_backup_dir" ] && [ "$(ls -A "$sys_backup_dir" 2>/dev/null)" ]; then
log "发现系统连接文件备份,尝试恢复..."
restore_from_system_files "$sys_backup_dir"
else
log "未找到系统连接文件,尝试从详细配置恢复..."
restore_from_details "$real_backup_dir"
fi
# 重新激活之前的连接
log "正在重新激活之前的活动连接..."
if [ -f "$real_backup_dir/$ACTIVE_CONNS_LIST" ]; then
while IFS=: read -r conn_name conn_type conn_uuid conn_device; do
if [ -n "$conn_name" ]; then
info "尝试激活: $conn_name"
if nmcli connection up "$conn_name" >/dev/null 2>&1; then
info "✓ 成功激活: $conn_name"
else
log_warn "激活失败: $conn_name"
fi
fi
done < "$real_backup_dir/$ACTIVE_CONNS_LIST"
fi
log "等待网络重新连接 (8秒)..."
sleep 8
log_success "恢复过程完成!"
check_status
}
# 从系统文件恢复
restore_from_system_files() {
local sys_backup_dir="\$1"
local system_conn_dir="/etc/NetworkManager/system-connections"
# 停止NetworkManager
log "临时停止NetworkManager服务..."
systemctl stop NetworkManager
# 备份当前配置
local current_backup="/tmp/nm_current_backup_$(date +%s)"
mkdir -p "$current_backup"
if [ -d "$system_conn_dir" ]; then
cp -r "$system_conn_dir"/* "$current_backup/" 2>/dev/null || true
fi
# 恢复配置文件
mkdir -p "$system_conn_dir"
cp -r "$sys_backup_dir"/* "$system_conn_dir/" 2>/dev/null
chmod -R 600 "$system_conn_dir"/* 2>/dev/null
# 重启NetworkManager
log "重新启动NetworkManager服务..."
systemctl start NetworkManager
sleep 5
nmcli connection reload
sleep 3
rm -rf "$current_backup"
}
# 从详细配置恢复(显示信息供手动配置)
restore_from_details() {
local backup_dir="\$1"
local details_dir="$backup_dir/$CONNECTION_DETAILS_DIR"
if [ ! -d "$details_dir" ]; then
log_error "未找到详细配置备份"
return 1
fi
log_warn "系统连接文件备份不可用,显示配置信息供参考:"
for detail_file in "$details_dir"/*.conf; do
if [ -f "$detail_file" ]; then
local filename=$(basename "$detail_file" .conf)
info "连接配置: $filename"
echo "----------------------------------------"
# 提取关键配置信息
grep -E "^(connection\.|ipv4\.|ipv6\.|802-3-ethernet\.|wifi\.)" "$detail_file" | head -20
echo "----------------------------------------"
fi
done
}
# 5. 清理临时DHCP连接
cleanup_temp_connections() {
log "正在清理临时DHCP连接..."
local cleanup_count=0
while IFS= read -r conn_name; do
if [ -n "$conn_name" ]; then
if nmcli connection delete "$conn_name" >/dev/null 2>&1; then
info "已删除临时连接: $conn_name"
((cleanup_count++))
fi
fi
done < <(nmcli -t -f NAME connection show | grep "^temp-dhcp-")
if [ "$cleanup_count" -gt 0 ]; then
log_success "清理完成,共删除 $cleanup_count 个临时连接。"
else
log "没有找到需要清理的临时连接。"
fi
}
# 6. 显示备份信息
show_backup_info() {
info "--- 备份信息 ---"
if [ ! -d "$BACKUP_BASE_DIR" ]; then
log_warn "备份目录不存在: $BACKUP_BASE_DIR"
return
fi
local backup_count=0
for backup_dir in "$BACKUP_BASE_DIR"/20*; do
if [ -d "$backup_dir" ]; then
((backup_count++))
local dir_name=$(basename "$backup_dir")
local size=$(du -sh "$backup_dir" 2>/dev/null | cut -f1)
info "备份 #$backup_count: $dir_name (大小: $size)"
# 显示备份内容摘要
if [ -f "$backup_dir/$ACTIVE_CONNS_LIST" ]; then
local conn_count=$(wc -l < "$backup_dir/$ACTIVE_CONNS_LIST")
info " - 活动连接: $conn_count"
fi
if [ -d "$backup_dir/$CONNECTION_DETAILS_DIR" ]; then
local detail_count=$(ls -1 "$backup_dir/$CONNECTION_DETAILS_DIR"/*.conf 2>/dev/null | wc -l)
info " - 详细配置: $detail_count"
fi
fi
done
if [ "$backup_count" -eq 0 ]; then
log_warn "没有找到任何备份。"
else
info "总共找到 $backup_count 个备份。"
# 显示最新备份信息
if [ -L "$BACKUP_BASE_DIR/latest" ]; then
local latest_backup=$(readlink -f "$BACKUP_BASE_DIR/latest")
info "最新备份: $(basename "$latest_backup")"
fi
fi
}
# 7. 删除旧备份
cleanup_old_backups() {
local keep_days=7
log "正在清理超过 $keep_days 天的旧备份..."
if [ ! -d "$BACKUP_BASE_DIR" ]; then
log_warn "备份目录不存在,无需清理。"
return
fi
local deleted_count=0
find "$BACKUP_BASE_DIR" -maxdepth 1 -type d -name "20*" -mtime +$keep_days | while read -r old_backup; do
if [ -d "$old_backup" ]; then
local backup_name=$(basename "$old_backup")
rm -rf "$old_backup"
info "已删除旧备份: $backup_name"
((deleted_count++))
fi
done
if [ "$deleted_count" -gt 0 ]; then
log_success "清理完成,删除了 $deleted_count 个旧备份。"
else
log "没有找到需要清理的旧备份。"
fi
}
# 8. 高级网络诊断
advanced_diagnosis() {
info "--- 高级网络诊断 ---"
log "1. NetworkManager 服务状态:"
systemctl status NetworkManager --no-pager -l
log "\n2. 网络设备详细信息:"
nmcli device show
log "\n3. 所有连接配置:"
nmcli connection show
log "\n4. 路由表:"
ip route show table all
log "\n5. DNS 配置:"
cat /etc/resolv.conf
log "\n6. 防火墙状态:"
if command -v ufw >/dev/null 2>&1; then
ufw status verbose
elif command -v iptables >/dev/null 2>&1; then
iptables -L -n
else
info "未找到防火墙工具"
fi
log "\n7. 网络接口统计:"
cat /proc/net/dev
log "\n8. 系统网络配置文件:"
info "NetworkManager 主配置:"
[ -f /etc/NetworkManager/NetworkManager.conf ] && cat /etc/NetworkManager/NetworkManager.conf
log "\n9. 最近的网络日志:"
journalctl -u NetworkManager --no-pager -n 50
}
# --- 主菜单和程序入口 ---
show_menu() {
echo
echo "=============================================="
echo " Arch Linux NetworkManager 管理工具"
echo "=============================================="
echo "1. 检查网络状态"
echo "2. 备份网络配置"
echo "3. 自动修复网络"
echo "4. 恢复网络配置"
echo "5. 清理临时连接"
echo "6. 显示备份信息"
echo "7. 清理旧备份"
echo "8. 高级网络诊断"
echo "9. 退出"
echo "=============================================="
echo -n "请选择操作 (1-9): "
}
main() {
# 初始化
pre_check
mkdir -p "$BACKUP_BASE_DIR"
touch "$LOG_FILE"
log_success "NetworkManager 管理脚本启动成功"
while true; do
show_menu
read -r choice
case $choice in
1)
echo
log "执行选项 1: 检查网络状态"
check_status
;;
2)
echo
log "执行选项 2: 备份网络配置"
backup_config
;;
3)
echo
log "执行选项 3: 自动修复网络"
auto_fix
;;
4)
echo
log "执行选项 4: 恢复网络配置"
restore_config
;;
5)
echo
log "执行选项 5: 清理临时连接"
cleanup_temp_connections
;;
6)
echo
log "执行选项 6: 显示备份信息"
show_backup_info
;;
7)
echo
log "执行选项 7: 清理旧备份"
cleanup_old_backups
;;
8)
echo
log "执行选项 8: 高级网络诊断"
advanced_diagnosis
;;
9)
echo
log_success "感谢使用 NetworkManager 管理工具!"
exit 0
;;
*)
echo
log_error "无效选择,请输入 1-9 之间的数字。"
;;
esac
echo
echo "按 Enter 键继续..."
read -r
done
}
# 脚本入口点
if [ "${BASH_SOURCE[0]}" = "${0}" ]; then
main "$@"
fi