Files
tech/.claude/tools/dns_setup.sh
T
arno 919124af89 配置(工具): 添加 DNS 配置与防火墙脚本及本地权限设置
- 添加 DNS 全局配置脚本(含 IPv6 禁用、有线网卡静态 IP)
- 添加 UFW 防火墙配置脚本(默认拒绝入站、允许出站)
- 添加 Claude Code 本地权限与记忆配置
2026-06-08 14:59:16 +08:00

403 lines
16 KiB
Bash
Executable File
Raw 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.
#!/usr/bin/env bash
# ============================================================
# DNS 全局配置脚本(含 IPv6 禁用 + 有线网卡静态 IP)
# 功能:
# 1. 全局固定 DNS(深圳电信)
# 2. 全局禁用 IPv6sysctl + 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}"