😭事情起因:
我原本以为DD后系统会很干净,直到有一天,我DD完照例用同样的脚本,客户端timeout,直接ping ip是通的,查看程序运行状态Activating,配置文件完整无误,奇怪了,以前从没遇到这种情况。查看运行日志,发现了问题,程序在出站DNS走的不是8.8.8.8,1.1.1.1,而是主机上游的 xxxxx.com,从而导致的timeout,我查看resolv.conf,发现配置是这样的,前面竟然莫名奇妙的多了search xxxxx.com
search xxxxx.com
nameserver 8.8.8.8
nameserver 1.1.1.1
随后遍历互联网,不了解还真不知道,了解以后才发现主机商家的小动作还真不少
👿主机商家的动机:
他们添加额外的DNS配置,通常并非出于恶意,而是源于两个主要原因:
- 为了提供便捷的内部服务网络:
- 动机: 大型云服务商通常拥有一个庞大的内部网络,提供诸如对象存储、内网数据库、软件源镜像等服务。他们希望你能通过简单的主机名(如
storage-server或db-cluster-1)而不是复杂的私有IP来访问这些服务。 - 实现方式: 他们会在你的VPS上自动添加一个
search搜索域,通常是他们自己的域名(例如search my-provider.internal)。这样,当你尝试访问storage-server时,系统会自动将其补全为storage-server.my-provider.internal并进行查询。 - “污染”的副作用: 这个看似“便捷”的功能,却带来了巨大的隐患。当你的服务器查询任何一个不存在的内部域名时,这个查询会被发送到公网,无意中暴露了你的内部网络架构和应用命名习惯。这就是我们所说的 DNS 泄漏。
- 动机: 大型云服务商通常拥有一个庞大的内部网络,提供诸如对象存储、内网数据库、软件源镜像等服务。他们希望你能通过简单的主机名(如
- 为了优化网络性能与管理:
- 动机: 主机商会在他们的网络中部署自己的DNS解析服务器。他们认为,让你的VPS使用这些“就近”的DNS服务器,可以获得更低的解析延迟。同时,这也便于他们进行网络流量分析、故障排查,甚至在某些情况下用于安全防护(例如,拦截对已知恶意网站的访问)。
- 实现方式: 他们通过DHCP协议,在你获取IP地址的同时,强制推送他们自己的DNS服务器地址。这就是为什么我们常常在
resolvectl status的Link部分看到厂商的DNS。 - “污染”的副作用: 这让你完全受制于主机商。你无法控制他们是否记录了你的每一次DNS查询(从而了解你服务器的所有网络活动);你也无法保证他们不会因为错误配置、审查要求或被攻击而提供错误的、被劫持的DNS结果;最重要的是,这些DNS查询几乎总是未经加密的,在传输路径上任何一个节点都可以被窃听和篡改。
😀这个脚本命令能做什么:
1. 直接修改etc/resolv.conf的弊端是无法持久化,反复被污染,我们的目的是永久斩断厂商控制,夺回DNS控制权
- 驯服DHCP:通过修改DHCP客户端配置,强制忽略并拒绝接受任何由VPS提供商推送的DNS服务器和搜索域,从动态源头上根除DNS污染。
- 净化静态配置:自动扫描并禁用所有在网络配置文件(如
/etc/network/interfaces)中由厂商预设的、残留的DNS指令。 - 移除冲突软件:在Debian 11等存在兼容性问题的系统上,自动卸载与我们现代化方案冲突的旧有软件包(如
resolvconf),确保配置的唯一权威。
2. 构建坚不可摧的DNS安全堡垒
- 强制端到端加密 (DoT):部署并配置
systemd-resolved,强制所有出站的DNS查询,都必须通过加密的DNS-over-TLS (DoT) 通道进行。这使得任何第三方(包括你的主机商)都无法窃听、篡改或劫持你的DNS流量。 - 启用DNSSEC验证:开启DNSSEC校验,确保你的服务器获取到的每一个IP地址都是真实、未经篡改的,从根本上防御DNS缓存投毒攻击。
- 收缩攻击面:自动禁用
LLMNR和mDNS等在服务器上毫无用处且有潜在安全风险的本地网络发现协议。
3. 确保极致的可靠性与性能
- 高可用DNS池: Google (
8.8.8.8) 和 Cloudflare (1.1.1.1) - 本地缓存加速:通过
systemd-resolved提供的本地DNS缓存,重复的DNS查询将从内存中毫秒级响应,极大地提升了你服务器上应用程序的性能。
🛠️失败挽救:
一般不会出现问题,如果出现问题导致VPS无法解析,可手动修改/etc/resolv.conf
nameserver 8.8.8.8
nameserver 1.1.1.1
📖使用方法(命令本体):
- 不支持Alpine,ipv6 only小鸡慎用,Debian11/12测试没问题,其他系统自行测试。
- 保证你VPS是root登录状态,直接全部复制代码,回车。
sudo bash << 'SCRIPT_END'
#!/usr/bin/env bash
set -euo pipefail
readonly TARGET_DNS="8.8.8.8#dns.google 1.1.1.1#cloudflare-dns.com"
readonly SECURE_RESOLVED_CONFIG="[Resolve]
DNS=${TARGET_DNS}
LLMNR=no
MulticastDNS=no
DNSSEC=allow-downgrade
DNSOverTLS=yes
"
readonly GREEN="\033[0;32m"
readonly YELLOW="\033[1;33m"
readonly RED="\033[0;31m"
readonly NC="\033[0m"
log() { echo -e "${GREEN}--> $1${NC}"; }
log_warn() { echo -e "${YELLOW}--> $1${NC}"; }
log_error() { echo -e "${RED}--> $1${NC}" >&2; }
purify_and_harden_dns() {
echo -e "\n--- 开始执行DNS净化与安全加固流程 ---"
local debian_version
debian_version=$(grep "VERSION_ID" /etc/os-release | cut -d'=' -f2 | tr -d '"' || echo "unknown")
log "阶段一:正在清除所有潜在的DNS冲突源..."
local dhclient_conf="/etc/dhcp/dhclient.conf"
if [[ -f "$dhclient_conf" ]]; then
if ! grep -q "ignore domain-name-servers;" "$dhclient_conf" || ! grep -q "ignore domain-search;" "$dhclient_conf"; then
log "正在驯服 DHCP 客户端 (dhclient)..."
echo "" >> "$dhclient_conf"
echo "ignore domain-name-servers;" >> "$dhclient_conf"
echo "ignore domain-search;" >> "$dhclient_conf"
log "${GREEN}✅ 已确保 'ignore' 指令存在于 ${dhclient_conf}${NC}"
fi
fi
local ifup_script="/etc/network/if-up.d/resolved"
if [[ -f "$ifup_script" ]] && [[ -x "$ifup_script" ]]; then
log "正在禁用有冲突的 if-up.d 兼容性脚本..."
chmod -x "$ifup_script"
log "${GREEN}✅ 已移除 ${ifup_script} 的可执行权限。${NC}"
fi
local interfaces_file="/etc/network/interfaces"
if [[ -f "$interfaces_file" ]] && grep -qE '^[[:space:]]*dns-(nameservers|search|domain)' "$interfaces_file"; then
log "正在净化 /etc/network/interfaces 中的厂商残留DNS配置..."
sed -i -E 's/^[[:space:]]*(dns-(nameservers|search|domain).*)/# \1/' "$interfaces_file"
log "${GREEN}✅ 旧有DNS配置已成功注释禁用。${NC}"
fi
log "阶段二:正在配置 systemd-resolved..."
if ! command -v resolvectl &> /dev/null; then
log "正在安装 systemd-resolved..."
apt-get update -y > /dev/null
apt-get install -y systemd-resolved > /dev/null
fi
if [[ "$debian_version" == "11" ]] && dpkg -s resolvconf &> /dev/null; then
log "检测到 Debian 11 上的 'resolvconf',正在卸载..."
apt-get remove -y resolvconf > /dev/null
rm -f /etc/resolv.conf
log "${GREEN}✅ 'resolvconf' 已成功卸载。${NC}"
fi
log "正在启用并启动 systemd-resolved 服务..."
systemctl enable systemd-resolved
systemctl start systemd-resolved
log "正在应用最终的DNS安全配置 (DoT, DNSSEC...)"
echo -e "${SECURE_RESOLVED_CONFIG}" > /etc/systemd/resolved.conf
ln -sf /run/systemd/resolve/stub-resolv.conf /etc/resolv.conf
systemctl restart systemd-resolved
sleep 1
log "阶段三:正在安全地重启网络服务以应用所有更改..."
if systemctl is-enabled --quiet networking.service; then
systemctl restart networking.service
log "${GREEN}✅ networking.service 已安全重启。${NC}"
fi
echo -e "\n${GREEN}✅ 全部操作完成!以下是最终的 DNS 配置状态:${NC}"
echo "===================================================="
resolvectl status
echo "===================================================="
echo -e "\n${GREEN}DNS净化脚本执行完成${NC}"
echo -e "贡献者:NSdesk"
echo -e "更多信息:https://www.nodeseek.com/space/23129/"
echo "===================================================="
}
main() {
if [[ $EUID -ne 0 ]]; then
log_error "错误: 此脚本必须以 root 用户身份运行。请使用 'sudo'。"
exit 1
fi
echo "--- 开始执行全面系统DNS健康检查 ---"
local is_perfect=true
echo -n "1. 检查 systemd-resolved 实时状态... "
if ! command -v resolvectl &> /dev/null || ! resolvectl status &> /dev/null; then
echo -e "${YELLOW}服务未运行或无响应。${NC}"
is_perfect=false
else
local status_output
status_output=$(resolvectl status)
local current_dns
current_dns=$(echo "${status_output}" | sed -n '/Global/,/^\s*$/{/DNS Servers:/s/.*DNS Servers:[[:space:]]*//p}' | tr -d '\r\n' | xargs)
if [[ "${current_dns}" != "${TARGET_DNS}" ]] || ! echo "${status_output}" | grep -q -- "-LLMNR" || ! echo "${status_output}" | grep -q -- "-mDNS" || ! echo "${status_output}" | grep -q -- "+DNSOverTLS" || ! echo "${status_output}" | grep -q "DNSSEC=allow-downgrade"; then
echo -e "${YELLOW}实时配置与安全目标不符。${NC}"
is_perfect=false
else
echo -e "${GREEN}配置正确。${NC}"
fi
fi
echo -n "2. 检查 dhclient.conf 配置... "
local dhclient_conf="/etc/dhcp/dhclient.conf"
if [[ -f "$dhclient_conf" ]]; then
if grep -q "ignore domain-name-servers;" "$dhclient_conf" && grep -q "ignore domain-search;" "$dhclient_conf"; then
echo -e "${GREEN}已净化。${NC}"
else
echo -e "${YELLOW}未发现 'ignore' 净化参数。${NC}"
is_perfect=false
fi
else
echo -e "${GREEN}文件不存在,无需净化。${NC}"
fi
echo -n "3. 检查 if-up.d 冲突脚本... "
local ifup_script="/etc/network/if-up.d/resolved"
if [[ ! -f "$ifup_script" ]] || [[ ! -x "$ifup_script" ]]; then
echo -e "${GREEN}已禁用或不存在。${NC}"
else
echo -e "${YELLOW}脚本存在且可执行。${NC}"
is_perfect=false
fi
if [[ "$is_perfect" == true ]]; then
echo -e "\n${GREEN}✅ 全面检查通过!系统DNS配置稳定且安全。无需任何操作。${NC}"
echo -e "贡献者:NSdesk"
echo -e "更多信息:https://www.nodeseek.com/space/23129/"
exit 0
else
echo -e "\n${YELLOW}--> 一项或多项检查未通过。为了确保系统的长期稳定,将执行完整的净化与加固流程...${NC}"
purify_and_harden_dns
fi
}
main "$@"
SCRIPT_END
🤣最后:
- 为什么用DOT而不是DOH,是因为DOT更适合服务器体质,DOH更适合客户端体质
- 脚本代码由gemini,grok轮番打磨完成,由于本人对代码一窍不通,免不了被gemini,grok带了不少弯路,最后用了不少精力和时间将这两头倔驴拉到正轨完成任务,试用一段时候后DNS效果良好,无不良反应,后交由claude转译成全部代码复制粘贴直接执行的版本,claude更倔,框框一顿输出...
- 抛砖引玉,佬友们有其他更好的方法可以一起沟通讨论,大家添砖加瓦,
- 为什么不做成shell脚本放在github?小弟我github上还有其他好玩的脚本,不方便泄露,以后择机分享给大家
