- 添加 DNS 全局配置脚本(含 IPv6 禁用、有线网卡静态 IP) - 添加 UFW 防火墙配置脚本(默认拒绝入站、允许出站) - 添加 Claude Code 本地权限与记忆配置
403 lines
16 KiB
Bash
Executable File
403 lines
16 KiB
Bash
Executable File
#!/usr/bin/env bash
|
||
# ============================================================
|
||
# DNS 全局配置脚本(含 IPv6 禁用 + 有线网卡静态 IP)
|
||
# 功能:
|
||
# 1. 全局固定 DNS(深圳电信)
|
||
# 2. 全局禁用 IPv6(sysctl + GRUB + NM)
|
||
# 3. 有线网卡支持用户输入静态 IP
|
||
# 用法: sudo bash dns_setup.sh
|
||
# ============================================================
|
||
|
||
set -euo pipefail
|
||
|
||
RED='\033[0;31m'
|
||
GREEN='\033[0;32m'
|
||
YELLOW='\033[1;33m'
|
||
NC='\033[0m'
|
||
|
||
DNS_SERVERS="202.96.128.143 202.96.128.68 202.96.134.133 202.96.128.86 202.96.128.166"
|
||
GRUB_FILE="/etc/default/grub"
|
||
TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S')
|
||
NOW_TS=$(date +%Y%m%d%H%M%S)
|
||
|
||
echo "========================================"
|
||
echo " DNS 全局配置 + IPv6 禁用脚本"
|
||
echo "========================================"
|
||
echo ""
|
||
|
||
# 检查 root
|
||
if [[ $EUID -ne 0 ]]; then
|
||
echo -e "${RED}[错误] 请使用 sudo 运行此脚本${NC}"
|
||
exit 1
|
||
fi
|
||
|
||
# ──────────────────────────────────────────
|
||
# 步骤 1: 配置 systemd-resolved 全局 DNS
|
||
# ──────────────────────────────────────────
|
||
echo "==> 步骤 1/6: 配置 systemd-resolved 全局 DNS"
|
||
|
||
if [[ ! -f /etc/systemd/resolved.conf.bak ]]; then
|
||
cp /etc/systemd/resolved.conf /etc/systemd/resolved.conf.bak
|
||
echo -e "${GREEN}[备份] /etc/systemd/resolved.conf → resolved.conf.bak${NC}"
|
||
fi
|
||
|
||
cat > /etc/systemd/resolved.conf <<EOF
|
||
# systemd-resolved 配置文件
|
||
# 由 dns_setup.sh 生成 (${TIMESTAMP})
|
||
# 备份: /etc/systemd/resolved.conf.bak
|
||
|
||
[Resolve]
|
||
DNS=${DNS_SERVERS}
|
||
LLMNR=no
|
||
MulticastDNS=no
|
||
DNSSEC=no
|
||
DNSOverTLS=no
|
||
Cache=yes
|
||
EOF
|
||
|
||
echo -e "${GREEN}[完成] 全局 DNS: ${DNS_SERVERS}${NC}"
|
||
|
||
# ──────────────────────────────────────────
|
||
# 步骤 2: sysctl 全局禁用 IPv6
|
||
# ──────────────────────────────────────────
|
||
echo ""
|
||
echo "==> 步骤 2/6: sysctl 全局禁用 IPv6"
|
||
|
||
cat > /etc/sysctl.d/99-disable-ipv6.conf <<EOF
|
||
# 全局禁用 IPv6
|
||
# 由 dns_setup.sh 生成 (${TIMESTAMP})
|
||
net.ipv6.conf.all.disable_ipv6 = 1
|
||
net.ipv6.conf.default.disable_ipv6 = 1
|
||
net.ipv6.conf.lo.disable_ipv6 = 1
|
||
EOF
|
||
|
||
sysctl --system &>/dev/null
|
||
echo -e "${GREEN}[完成] IPv6 已全局禁用 (sysctl)${NC}"
|
||
|
||
if [[ "$(cat /proc/sys/net/ipv6/conf/all/disable_ipv6)" == "1" ]]; then
|
||
echo -e "${GREEN}[验证] /proc/sys/net/ipv6/conf/all/disable_ipv6 = 1 ✓${NC}"
|
||
fi
|
||
|
||
# ──────────────────────────────────────────
|
||
# 步骤 3: GRUB 内核参数禁用 IPv6
|
||
# ──────────────────────────────────────────
|
||
echo ""
|
||
echo "==> 步骤 3/6: GRUB 内核参数禁用 IPv6"
|
||
|
||
if grep -q "ipv6.disable=1" "$GRUB_FILE" 2>/dev/null; then
|
||
echo "[跳过] GRUB 已包含 ipv6.disable=1"
|
||
else
|
||
cp "$GRUB_FILE" "${GRUB_FILE}.bak.${NOW_TS}"
|
||
sed -i 's/^GRUB_CMDLINE_LINUX_DEFAULT="\(.*\)"/GRUB_CMDLINE_LINUX_DEFAULT="\1 ipv6.disable=1"/' "$GRUB_FILE"
|
||
sed -i 's/^GRUB_CMDLINE_LINUX="\(.*\)"/GRUB_CMDLINE_LINUX="\1 ipv6.disable=1"/' "$GRUB_FILE"
|
||
update-grub &>/dev/null || grub2-mkconfig -o /boot/grub2/grub.cfg &>/dev/null
|
||
echo -e "${GREEN}[完成] GRUB 内核参数已添加 ipv6.disable=1${NC}"
|
||
echo -e "${YELLOW}[提示] GRUB 修改需重启后生效${NC}"
|
||
fi
|
||
|
||
# ──────────────────────────────────────────
|
||
# 步骤 4: 有线网卡静态 IP 配置(含重复检测与清理)
|
||
# ──────────────────────────────────────────
|
||
echo ""
|
||
echo "==> 步骤 4/6: 有线网卡检测与静态 IP 配置"
|
||
echo ""
|
||
|
||
# 收集所有有线网卡连接,按接口分组
|
||
declare -A IFACE_CONNS # 接口 -> "uuid|cname|uuid|cname|..." (用换行分隔多个)
|
||
while IFS= read -r uuid; do
|
||
ctype=$(nmcli -t -f connection.type connection show uuid "$uuid" 2>/dev/null | cut -d: -f2-)
|
||
cname=$(nmcli -t -f connection.id connection show uuid "$uuid" 2>/dev/null | cut -d: -f2-)
|
||
iface=$(nmcli -t -f connection.interface-name connection show uuid "$uuid" 2>/dev/null | cut -d: -f2-)
|
||
if [[ "$ctype" == "802-3-ethernet" ]]; then
|
||
if [[ -n "${IFACE_CONNS[$iface]:-}" ]]; then
|
||
IFACE_CONNS[$iface]="${IFACE_CONNS[$iface]}
|
||
$uuid|$cname"
|
||
else
|
||
IFACE_CONNS[$iface]="$uuid|$cname"
|
||
fi
|
||
fi
|
||
done < <(nmcli -t -f UUID connection show 2>/dev/null)
|
||
|
||
if [[ ${#IFACE_CONNS[@]} -eq 0 ]]; then
|
||
echo " 未检测到有线网卡连接,跳过。"
|
||
else
|
||
NETPLAN_DIR="/etc/netplan"
|
||
|
||
for iface in "${!IFACE_CONNS[@]}"; do
|
||
# 解析该接口的所有连接
|
||
mapfile -t entries <<< "${IFACE_CONNS[$iface]}"
|
||
|
||
if [[ ${#entries[@]} -gt 1 ]]; then
|
||
echo ""
|
||
echo -e " ${YELLOW}══════════════════════════════════════${NC}"
|
||
echo -e " ${YELLOW} 检测到接口 [$iface] 有 ${#entries[@]} 个重复连接${NC}"
|
||
echo -e " ${YELLOW}══════════════════════════════════════${NC}"
|
||
|
||
# 找出活跃连接(有 IP 的)
|
||
active_entry=""
|
||
stale_uuids=()
|
||
for e in "${entries[@]}"; do
|
||
IFS='|' read -r euuid ecname <<< "$e"
|
||
eip=$(ip -4 addr show "$iface" 2>/dev/null | grep -oP 'inet \K[\d.]+/[\d]+' | head -1)
|
||
estate=$(nmcli -t -f GENERAL.STATE connection show uuid "$euuid" 2>/dev/null | cut -d: -f2-)
|
||
|
||
echo ""
|
||
echo " [$ecname] UUID: $euuid"
|
||
echo " 当前 NM 状态: ${estate:-未知}"
|
||
|
||
if [[ -n "$eip" ]]; then
|
||
# 检查该连接的 IP 是否匹配接口 IP
|
||
conn_ip=$(nmcli -t -f IP4.ADDRESS connection show uuid "$euuid" 2>/dev/null | cut -d: -f2- | head -1 | cut -d'/' -f1 | cut -d' ' -f1)
|
||
iface_ip=$(echo "$eip" | cut -d'/' -f1)
|
||
if [[ "$conn_ip" == "$iface_ip" ]] || [[ "$estate" == "activated" ]]; then
|
||
active_entry="$e"
|
||
echo -e " ${GREEN}◎ 活跃(当前使用中)${NC}"
|
||
else
|
||
stale_uuids+=("$euuid")
|
||
echo -e " ${YELLOW}⊙ 残留/非活跃${NC}"
|
||
fi
|
||
else
|
||
stale_uuids+=("$euuid")
|
||
echo -e " ${YELLOW}⊙ 无 IP,疑似残留${NC}"
|
||
fi
|
||
done
|
||
|
||
# 若未明确找到活跃连接,保留第一个,其余标记为残留
|
||
if [[ -z "$active_entry" ]]; then
|
||
active_entry="${entries[0]}"
|
||
stale_uuids=()
|
||
for ((i=1; i<${#entries[@]}; i++)); do
|
||
IFS='|' read -r suuid scname <<< "${entries[$i]}"
|
||
stale_uuids+=("$suuid")
|
||
done
|
||
fi
|
||
|
||
# 清理残留连接
|
||
if [[ ${#stale_uuids[@]} -gt 0 ]]; then
|
||
echo ""
|
||
echo -e " ${YELLOW}将自动清理 ${#stale_uuids[@]} 个残留连接:${NC}"
|
||
for suuid in "${stale_uuids[@]}"; do
|
||
sname=$(nmcli -t -f connection.id connection show uuid "$suuid" 2>/dev/null | cut -d: -f2-)
|
||
echo " - $sname ($suuid)"
|
||
done
|
||
|
||
read -r -p " 确认清理?[Y/n] " do_clean
|
||
if [[ ! "$do_clean" =~ ^[Nn]$ ]]; then
|
||
for suuid in "${stale_uuids[@]}"; do
|
||
sname=$(nmcli -t -f connection.id connection show uuid "$suuid" 2>/dev/null | cut -d: -f2-)
|
||
nmcli connection delete "$suuid" 2>/dev/null || true
|
||
rm -f "${NETPLAN_DIR}/90-NM-${suuid}.yaml"
|
||
echo -e " ${GREEN}✓ 已删除: $sname${NC}"
|
||
done
|
||
else
|
||
echo " 已跳过清理。"
|
||
fi
|
||
fi
|
||
|
||
# 更新 entries 为仅保留活跃连接
|
||
entries=("$active_entry")
|
||
fi
|
||
|
||
# 对每个保留的有线连接,配置静态 IP
|
||
for e in "${entries[@]}"; do
|
||
IFS='|' read -r uuid cname <<< "$e"
|
||
|
||
echo ""
|
||
echo "────────────────────────────────────────"
|
||
echo " 有线网卡: $cname"
|
||
echo " 接口名: $iface"
|
||
echo " UUID: $uuid"
|
||
echo ""
|
||
|
||
# 获取当前 IP 信息
|
||
cur_ip=""
|
||
cur_gw=""
|
||
if [[ -n "$iface" ]] && ip addr show "$iface" &>/dev/null; then
|
||
cur_ip=$(ip -4 addr show "$iface" 2>/dev/null | grep -oP 'inet \K[\d.]+/[\d]+' | head -1)
|
||
cur_gw=$(ip -4 route show default dev "$iface" 2>/dev/null | awk '{print $3}' | head -1)
|
||
fi
|
||
|
||
echo " 当前状态:"
|
||
echo " IP 地址: ${cur_ip:-未获取}"
|
||
echo " 网关: ${cur_gw:-未获取}"
|
||
echo ""
|
||
|
||
# 询问用户
|
||
read -r -p " 是否为此网卡设置静态 IP?[y/N] " set_static
|
||
if [[ ! "$set_static" =~ ^[Yy]$ ]]; then
|
||
echo -e " ${YELLOW}⊙ 跳过静态 IP,仅固定 DNS${NC}"
|
||
|
||
cur_method=$(nmcli -t -f ipv4.method connection show uuid "$uuid" 2>/dev/null | cut -d: -f2-)
|
||
if [[ "$cur_method" == "link-local" ]]; then
|
||
echo -e " ${YELLOW}⊙ method=link-local,切换到 auto 以支持 DNS${NC}"
|
||
nmcli connection modify "$uuid" ipv4.method auto
|
||
fi
|
||
nmcli connection modify "$uuid" ipv4.ignore-auto-dns yes
|
||
nmcli connection modify "$uuid" ipv4.dns "${DNS_SERVERS// /,}"
|
||
nmcli connection modify "$uuid" ipv6.method disabled
|
||
continue
|
||
fi
|
||
|
||
# 输入静态 IP
|
||
while true; do
|
||
read -r -p " 请输入静态 IP 地址 (格式: x.x.x.x/yy): " static_ip
|
||
if [[ "$static_ip" =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/[0-9]+$ ]]; then
|
||
break
|
||
fi
|
||
echo -e " ${RED}格式错误,示例: 192.168.1.90/24${NC}"
|
||
done
|
||
|
||
# 输入网关
|
||
read -r -p " 请输入网关地址 (回车使用检测值 ${cur_gw:-无}): " static_gw
|
||
if [[ -z "$static_gw" ]]; then
|
||
static_gw="$cur_gw"
|
||
fi
|
||
if [[ -z "$static_gw" ]]; then
|
||
echo -e " ${RED}[错误] 网关不能为空${NC}"
|
||
continue
|
||
fi
|
||
|
||
echo ""
|
||
echo " 即将应用以下配置:"
|
||
echo " 连接名: $cname"
|
||
echo " 接口: $iface"
|
||
echo " IP: $static_ip"
|
||
echo " 网关: $static_gw"
|
||
echo " DNS: $(echo "$DNS_SERVERS" | tr ' ' ',')"
|
||
echo " IPv6: 禁用"
|
||
echo ""
|
||
|
||
read -r -p " 确认应用?[Y/n] " confirm
|
||
if [[ "$confirm" =~ ^[Nn]$ ]]; then
|
||
echo -e " ${YELLOW}⊙ 已取消${NC}"
|
||
continue
|
||
fi
|
||
|
||
# ── 应用 NM 配置 ──
|
||
nmcli connection modify "$uuid" \
|
||
ipv4.method manual \
|
||
ipv4.addresses "$static_ip" \
|
||
ipv4.gateway "$static_gw" \
|
||
ipv4.dns "${DNS_SERVERS// /,}" \
|
||
ipv6.method disabled
|
||
|
||
echo -e " ${GREEN}✓ NM 配置已写入${NC}"
|
||
|
||
# ── 同步 netplan ──
|
||
NETPLAN_FILE="${NETPLAN_DIR}/90-NM-${uuid}.yaml"
|
||
|
||
if [[ -d "$NETPLAN_DIR" ]]; then
|
||
[[ ! -d "${NETPLAN_DIR}.bak" ]] && cp -r "$NETPLAN_DIR" "${NETPLAN_DIR}.bak"
|
||
|
||
cat > "$NETPLAN_FILE" <<NETEOF
|
||
network:
|
||
version: 2
|
||
ethernets:
|
||
${iface}:
|
||
renderer: NetworkManager
|
||
match: {}
|
||
dhcp4: false
|
||
addresses:
|
||
- "${static_ip}"
|
||
routes:
|
||
- to: "0.0.0.0/0"
|
||
via: "${static_gw}"
|
||
nameservers:
|
||
addresses:
|
||
$(for dns in $DNS_SERVERS; do echo " - ${dns}"; done)
|
||
networkmanager:
|
||
uuid: "${uuid}"
|
||
name: "${cname}"
|
||
passthrough:
|
||
ipv6.method: "disabled"
|
||
NETEOF
|
||
|
||
echo -e " ${GREEN}✓ netplan 配置已同步 → ${NETPLAN_FILE}${NC}"
|
||
|
||
if netplan generate 2>/dev/null; then
|
||
echo -e " ${GREEN}✓ netplan 语法检查通过${NC}"
|
||
else
|
||
echo -e " ${YELLOW}⚠ netplan 语法检查有警告,请手动确认${NC}"
|
||
fi
|
||
fi
|
||
|
||
echo ""
|
||
done
|
||
done
|
||
fi
|
||
|
||
# ──────────────────────────────────────────
|
||
# 步骤 5: 配置 NetworkManager 其余连接
|
||
# ──────────────────────────────────────────
|
||
echo ""
|
||
echo "==> 步骤 5/6: 配置其余 NetworkManager 连接 (WiFi 等)"
|
||
|
||
for conn in $(nmcli -t -f UUID connection show 2>/dev/null); do
|
||
ctype=$(nmcli -t -f connection.type connection show uuid "$conn" 2>/dev/null | cut -d: -f2-)
|
||
cname=$(nmcli -t -f connection.id connection show uuid "$conn" 2>/dev/null | cut -d: -f2-)
|
||
|
||
# 跳过回环
|
||
if [[ "$ctype" == "loopback" ]]; then
|
||
nmcli connection modify "$conn" ipv6.method auto 2>/dev/null || true
|
||
echo " $cname → ${YELLOW}⊙ 回环,跳过${NC}"
|
||
continue
|
||
fi
|
||
|
||
# 有线网卡已在步骤 4 处理
|
||
if [[ "$ctype" == "802-3-ethernet" ]]; then
|
||
echo " $cname → ${YELLOW}⊙ 有线网卡,已在步骤 4 处理${NC}"
|
||
continue
|
||
fi
|
||
|
||
# WiFi 等:固定 DNS + 禁用 IPv6
|
||
cur_method=$(nmcli -t -f ipv4.method connection show uuid "$conn" 2>/dev/null | cut -d: -f2-)
|
||
if [[ "$cur_method" == "link-local" ]]; then
|
||
nmcli connection modify "$conn" ipv4.method auto
|
||
fi
|
||
|
||
nmcli connection modify "$conn" ipv4.ignore-auto-dns yes
|
||
nmcli connection modify "$conn" ipv4.dns "${DNS_SERVERS// /,}"
|
||
nmcli connection modify "$conn" ipv6.method disabled
|
||
|
||
echo " $cname (类型: $ctype) → ${GREEN}✓ DNS 固定 / IPv6 禁用${NC}"
|
||
done
|
||
|
||
# ──────────────────────────────────────────
|
||
# 步骤 6: 重启服务
|
||
# ──────────────────────────────────────────
|
||
echo ""
|
||
echo "==> 步骤 6/6: 重启服务"
|
||
|
||
systemctl restart systemd-resolved
|
||
echo -e "${GREEN}[完成] systemd-resolved 已重启${NC}"
|
||
|
||
# ──────────────────────────────────────────
|
||
# 状态汇总
|
||
# ──────────────────────────────────────────
|
||
echo ""
|
||
echo "========================================"
|
||
echo " 当前状态汇总"
|
||
echo "========================================"
|
||
|
||
echo ""
|
||
echo "--- DNS 状态 ---"
|
||
resolvectl status 2>&1 || true
|
||
|
||
echo ""
|
||
echo "--- IPv6 状态 ---"
|
||
echo "sysctl disable_ipv6: $(cat /proc/sys/net/ipv6/conf/all/disable_ipv6 2>/dev/null || echo 'unknown')"
|
||
ip -6 addr show 2>/dev/null | grep "inet6" || echo "(无 IPv6 地址)"
|
||
|
||
echo ""
|
||
echo "--- DNS 解析验证 ---"
|
||
for domain in baidu.com qq.com; do
|
||
result=$(resolvectl query "$domain" 2>&1 || true)
|
||
echo " $domain → $(echo "$result" | head -3)"
|
||
done
|
||
|
||
echo ""
|
||
echo -e "${GREEN}全部配置完成!${NC}"
|
||
echo ""
|
||
echo -e "${YELLOW}提示: GRUB 修改需重启后完全生效。${NC}"
|
||
echo -e "${YELLOW} DNS / IPv6 变动需重连网络后生效。${NC}"
|