generated from zj/archlinux-pkg
508 lines
16 KiB
Bash
508 lines
16 KiB
Bash
#!/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
|
||
|