3个实操案例一文搞懂dns被篡改原理与排查
3个实操案例一文搞懂dns被篡改原理与排查 官方文档里关于 DNS 解析的章节动辄几十页,参数配置、协议交互、缓存机制堆砌在一起,新手根本抓不住重点,更别提遇到线上域名突然解析到错误 IP 时如何快速定位是 DNS 被篡改还是本地缓存问题。很多开发者在掘金技术社区提问“为什么我的域名突然打不开了”,回复往往只给出一句“检查 DNS”,却没人讲清楚底层到底发生了什么。今天这篇文章不抄文档,直接拆解 DNS 解析链路中的关键源码片段,带你从代码层面看清 DNS 被篡改的常见手法,一文搞懂如何从源头拦截和排查。 入口定位:从系统调用到内核解析器 要搞懂 DNS 被篡改,先得知道程序是怎么发起 DNS 查询的。大多数语言库(如 Python 的 socket 模块、Java 的 InetAddress)最终都会调用操作系统的 getaddrinfo() 函数。这个函数是用户态与内核态 DNS 解析的边界,也是篡改者最爱动手脚的地方。 在 Linux 系统中,getaddrinfo() 的行为由 /etc/nsswitch.conf 文件控制。默认情况下,系统会先查本地 hosts 文件,再查 DNS 服务器。如果攻击者修改了 hosts 文件,或者劫持了 DNS 服务器返回的应答包,解析结果就会出错。更隐蔽的手段是修改系统库函数,比如通过 LD_PRELOAD 注入恶意 .so 文件,直接拦截 getaddrinfo() 的调用,返回伪造的 IP 地址。 核心片段:Go 标准库的 DNS 解析逻辑 Go 语言的 net 包对 DNS 解析做了深度封装,其源码中有一段关键逻辑,揭示了如何绕过系统 resolver 直接进行 UDP 查询。这段代码位于 net/lookup_unix.go,展示了 Go 如何构造 DNS 报文并发送。 // 文件: net/lookup_unix.go (简化版核心逻辑) func (r *Resolver) lookupIPAddr(ctx context.Context, net string, host string) (addrs []ipAddr, err error) {// 1. 构造 DNS 查询报文,设置查询类型为 A 记录msg, err := dns.NewMsgWithQuestion(host, dns.TypeA, dns.ClassINET)if err != nil {return nil, err}// 2. 获取配置的 DNS 服务器地址(来自 /etc/resolv.conf)servers := r.servers()// 3. 遍历 DNS 服务器,发送 UDP 请求for _, server := range servers {conn, err := net.DialTimeout(udp, server, r.timeout)if err != nil {continue}// 4. 序列化报文并发送if err := conn.SetDeadline(time.Now().Add(r.timeout)); err != nil {conn.Close()continue}_, err = conn.Write(msg.Pack())if err != nil {conn.Close()continue}// 5. 接收响应并解析 IP 地址buf := make([]byte, 1500)n, err := conn.Read(buf)conn.Close()if err != nil {continue}// 6. 解析 DNS 响应,提取 A 记录中的 IPresp := new(dns.Msg)resp.Unpack(buf[:n])for _, ans := range resp.Answer {if a, ok := ans.(*dns.A); ok {addrs = append(addrs, ipAddr{ip: a.A})}}if len(addrs) 0 {return addrs, nil}}return nil, DNSError{Err: no answer, Name: host} }逐行注释如下:第1行:构造标准 DNS 查询报文,dns.TypeA 表示查询 IPv4 地址。 第4行:从系统配置读取 DNS 服务器列表,这是被篡改的高危点。 第7行:使用 UDP 协议连接 DNS 服务器,设置超时防止阻塞。 第12行:将报文序列化为字节流并发送,UDP 无连接特性使其易被中间人篡改。 第16行:接收响应数据,缓冲区大小设为 1500 字节,符合 DNS 报文最大长度。 第21行:解析响应报文,遍历 Answer 段提取 A 记录中的 IP 地址。 第25行:如果任一服务器返回有效 IP,立即返回,体现 DNS 查询的容错机制。这段代码的关键在于,Go 绕过了系统 getaddrinfo(),直接进行 DNS 查询。这意味着即使 hosts 文件被篡改,Go 程序可能不受影响,但 DNS 服务器返回的应答包仍可被中间人修改。 设计思想:为什么 DNS 解析如此脆弱 DNS 协议在设计之初未考虑安全性,这导致其极易被篡改。RFC 1035 规范中明确指出,DNS 应答不携带任何认证信息,客户端无法验证应答来源是否合法。攻击者只需在网络上监听 DNS 查询包,就能伪造应答,将域名指向恶意 IP。 现代系统引入了 DNSSEC(DNS Security Extensions)机制,通过数字签名验证应答的真实性。但 DNSSEC 部署率极低,尤其在企业内网和移动网络中,大多数 DNS 查询仍是“裸奔”状态。此外,DNS over HTTPS(DoH)和 DNS over TLS(DoT)协议通过加密通道传输查询,可有效防止中间人篡改,但需要客户端和服务器双方支持。 从源码角度看,DNS 解析的脆弱性源于三个层面:一是协议本身缺乏认证,二是传输层未加密,三是客户端缓存机制可能被利用。攻击者不仅可篡改网络传输中的应答,还可污染本地 DNS 缓存,使后续查询直接返回恶意 IP。 手写简化版:模拟 DNS 应答篡改过程 为了更直观理解 DNS 被篡改的原理,我们用 Python 手写一个简化版 DNS 应答伪造器。该脚本监听指定网段的 DNS 查询包,当查询特定域名时,返回预设的恶意 IP。 import socket import struct import timedef parse_dns_query(data):# 解析 DNS 查询报文头部trans_id = struct.unpack(!H, data[:2])[0]flags = struct.unpack(!H, data[2:4])[0]qdcount = struct.unpack(!H, data[4:6])[0]ancount = struct.unpack(!H, data[6:8])[0]nscount = struct.unpack(!H, data[8:10])[0]arcount = struct.unpack(!H, data[10:12])[0]# 解析查询名称offset = 12labels = []while data[offset] != 0:length = data[offset]labels.append(data[offset+1:offset+1+length].decode())offset += length + 1offset += 1 # 跳过末尾的 0qtype = struct.unpack(!H, data[offset:offset+2])[0]qclass = struct.unpack(!H, data[offset+2:offset+4])[0]return trans_id, ..join(labels), qtype, qclassdef build_dns_response(trans_id, domain, ip):# 构造 DNS 应答报文header = struct.pack(!HHHHHH, trans_id, 0x8180, 1, 1, 0, 0)# 构造名称部分(直接复制查询名称)name = bfor label in domain.split(.):name += struct.pack(!B, len(label)) + label.encode()name += b\x00# 构造资源记录rdata = socket.inet_aton(ip)rr = name + struct.pack(!HHHH, 1, 1, 300, len(rdata)) + rdatareturn header + name + struct.pack(!HHHH, 1, 1, 300, 4) + rdata# 主程序:监听 UDP 53 端口 sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) sock.bind((0.0.0.0, 53)) print(监听 DNS 查询...)while True:data, addr = sock.recvfrom(1500)trans_id, domain, qtype, qclass = parse_dns_query(data)# 如果查询目标域名是 evil.com,返回恶意 IPif domain == evil.com:response = build_dns_response(trans_id, domain, 1.2.3.4)sock.sendto(response, addr)print(f篡改查询: {domain} - 1.2.3.4)else:# 正常查询转发到真实 DNS 服务器(此处省略)pass逐行注释如下:第1行:导入 socket 模块用于网络通信,struct 模块用于二进制数据打包解包。 第14行:解析查询名称,DNS 域名采用标签长度前缀编码,循环读取直到遇到 0 字节。 第17行:提取查询类型和类别,qtype=1 表示 A 记录查询。 第21行:构造应答头部,0x8180 表示应答标志位(QR=1, AA=0, TC=0, RD=1, RA=1)。 第25行:构造名称部分,将点分域名转换为 DNS 二进制格式。 第29行:构造资源记录,TTL 设为 300 秒,RDATA 为恶意 IP 的二进制表示。 第35行:绑定 UDP 53 端口,这是 DNS 服务的标准端口。 第41行:判断查询域名,如果是目标域名则返回伪造应答,否则正常处理。这个简化版脚本展示了 DNS 应答篡改的核心原理:监听查询、解析域名、构造伪造应答。在实际攻击中,攻击者通常不会硬编码域名,而是维护一个恶意域名列表,动态匹配查询。 应用场景:企业内网 DNS 安全加固 在企业内网环境中,DNS 被篡改的风险尤为突出。攻击者一旦入侵内网,可通过 ARP 欺骗、路由器配置篡改或内部服务器入侵等方式劫持 DNS 流量。根据掘金技术社区多位安全工程师的实战经验,内网 DNS 篡改常见于供应链攻击和内部威胁场景。 应对策略包括:一是部署 DNSSEC,对关键域名启用签名验证;二是采用 DNS over TLS 或 DNS over HTTPS,加密查询和应答;三是实施 DNS 流量监控,异常应答立即告警;四是使用可信的公共 DNS 服务(如 1.1.1.1、8.8.8.8),避免依赖单一内网 DNS 服务器。 对于开发人员而言,在应用层可增加 DNS 解析结果校验逻辑。例如,对关键域名进行二次解析,比对不同 DNS 服务器返回的 IP 是否一致;或者使用 HTTPS 连接时校验证书 CN/SAN 字段与域名匹配,防止 DNS 劫持导致的中间人攻击。 你公司项目里是怎么处理 DNS 解析安全的?是用过 DoH 还是部署了 DNSSEC?或者遇到过 DNS 被篡改的案例?欢迎在评论区分享你的实战经验,一起避坑。

相关新闻

近红外光谱深度学习回归:ConvNet与SpectFormer实战指南

近红外光谱深度学习回归:ConvNet与SpectFormer实战指南

简介:本资源是一套面向科研人员与工程实践者的近红外光谱(NIR)数据回归建模工具包,聚焦深度学习在化学分析、食品检测及农业成分定量等非破坏性检测场景中的落地应用。针对传统统计方法难以处理高维、强噪声光谱数据的痛点&#x…

2026/9/23 20:47:04 阅读更多 →
传送带异物检测数据集实战:从COCO JSON到YOLO训练

传送带异物检测数据集实战:从COCO JSON到YOLO训练

简介:这是一套面向工业传送带异物检测任务的目标检测数据集,适合计算机视觉算法工程师、科研人员及高校相关专业学生用于模型训练与效果验证。数据集标注了铁棍、垃圾两类异物,全部采用COCO JSON格式,能直接接入主流检测框架。zip…

2026/9/23 20:46:04 阅读更多 →
异步电动机工作原理新手避坑指南

异步电动机工作原理新手避坑指南

异步电动机工作原理新手避坑指南 刚接触电机控制时,你是不是也被那些旋转磁场公式绕晕了?配置环境就卡半天,连个简单的启停都搞不定,这种挫败感我太懂了。很多新手在学异步电动机工作原理时,容易陷入“只看公式不看物理过程”的误区,结果代码写了一堆,…

2026/9/23 20:46:04 阅读更多 →

最新新闻

论文写作流程怎么安排?一份从开题到提交的指南

论文写作流程怎么安排?一份从开题到提交的指南

论文写作流程怎么安排?一份从开题到提交的指南 工具不是越多越好,关键是放在正确环节。每位学弟学妹在撰写论文时,都会经历从选题、资料收集、写作到最终提交的各个阶段。在这些环节中,合理利用工具和方法,可以大大提…

2026/9/23 21:29:24 阅读更多 →
毕业设计任务书怎么填?研究内容、进度和目标示例

毕业设计任务书怎么填?研究内容、进度和目标示例

毕业设计任务书怎么填?研究内容、进度和目标示例 在毕业设计的过程中,很多同学可能都会遇到开题报告、毕业设计任务书和论文选题表的填写难题。尤其是截止日期临近时,任务书的字段空白、开题报告的展开困难等情况,真的会让人头大…

2026/9/23 21:29:24 阅读更多 →
Kubernetes 迁移传统分布式应用实战:以 Hadoop YARN 为例的完整指南

Kubernetes 迁移传统分布式应用实战:以 Hadoop YARN 为例的完整指南

教程云原生容器编排 【免费下载链接】kubernetes-handbook Kubernetes 架构与生态:从云原生到 AI 原生基础设施的构建指南 项目地址: https://gitcode.com/gh_mirrors/ku/kubernetes-handbook 点击查看 免费下载 本文是 Kubernetes Handbook 中面向&quo…

2026/9/23 21:29:24 阅读更多 →
Swift 非穷尽枚举(Non-Exhaustive Enums)深度解析:SE-0192 的 frozen 与 @unknown 机制

Swift 非穷尽枚举(Non-Exhaustive Enums)深度解析:SE-0192 的 frozen 与 @unknown 机制

Swift 非穷尽枚举(Non-Exhaustive Enums)深度解析:SE-0192 的 frozen 与 unknown 机制 【免费下载链接】swift-evolution This maintains proposals for changes and user-visible enhancements to the Swift Programming Language. 项目地…

2026/9/23 21:29:24 阅读更多 →
Apache Druid 空间索引与空间过滤器(Spatial Filter)实战指南

Apache Druid 空间索引与空间过滤器(Spatial Filter)实战指南

数据库OLAP大数据后端 【免费下载链接】druid Apache Druid: a high performance real-time analytics database. 项目地址: https://gitcode.com/gh_mirrors/druid6/druid 点击查看 免费下载 本文围绕 Apache Druid 原生查询语言中的空间过滤能力展开,…

2026/9/23 21:29:24 阅读更多 →
在 EOSIO 中使用 `cleos wallet import` 导入密钥对:完整操作指南与源码原理剖析

在 EOSIO 中使用 `cleos wallet import` 导入密钥对:完整操作指南与源码原理剖析

区块链 【免费下载链接】eos An open source smart contract platform 项目地址: https://gitcode.com/gh_mirrors/eo/eos 点击查看 免费下载 本篇指南聚焦 EOSIO 智能合约平台(当前仓库 eo/eos)中最常用的密钥管理操作——使用 cleos wall…

2026/9/23 21:28:23 阅读更多 →

日新闻

3招搞定手机怎么下载微信面试难题实战项目解析

3招搞定手机怎么下载微信面试难题实战项目解析

3招搞定手机怎么下载微信面试难题实战项目解析 面试被问“手机怎么下载微信”背后的原理,90%的人答不上来。别笑,这看似弱智的问题,实则是考察你对移动应用分发机制、安全校验及网络协议理解的试金石。我带过不少校招新人,他们背了八股文,却连一个A…

2026/9/23 0:00:23 阅读更多 →
2k显示屏性能优化踩坑:版本升级后API全变了,这份源码解析救了我

2k显示屏性能优化踩坑:版本升级后API全变了,这份源码解析救了我

2k显示屏性能优化踩坑:版本升级后API全变了,这份源码解析救了我 刚把开发环境的显示器从1080P换到2K,跑老项目直接报错,版本升级后 API…

2026/9/23 0:01:25 阅读更多 →
3步搞定美眉图实战项目,告别官方文档抓不住重点

3步搞定美眉图实战项目,告别官方文档抓不住重点

3步搞定美眉图实战项目,告别官方文档抓不住重点 官方文档翻了三遍还是云里雾里?别急,美眉图在实战项目中常被用来做数据可视化,但它的原理比你想的简单。今天咱们直接上手,用一个完整的小项目把美眉图跑通,不再死磕那些冗长的理论说明。…

2026/9/23 0:01:25 阅读更多 →

周新闻

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

直接铺开项目本身吧。这几个月我一直在折腾一件事:用Flutter给OpenHarmony做一款游戏集合类的App,说白了就是把若干小游戏塞进一个壳里,用统一入口分发。这个方向本身不算新鲜,真正让我花了不少心思的,是首页那堆游戏卡…

2026/9/23 4:55:02 阅读更多 →
Word表格编号全攻略:从列表编号到题注交叉引用

Word表格编号全攻略:从列表编号到题注交叉引用

写Word文档,最让人头疼的往往是那些“看起来不起眼”的小问题。比如表格编号这事:今天在表后面多加了两个空白行,明天给客户交稿前发现整个章节的编号全部错位,光是挨个改序号就能耗掉大半个下午。我前阵子帮人整理一份上百页的技…

2026/9/23 4:49:06 阅读更多 →
从第一个站到第二个站:独立开发者的静态网站选型与落地实践

从第一个站到第二个站:独立开发者的静态网站选型与落地实践

1. 项目概述1.1 核心需求解析做独立开发者这几年,说实话,第一个网站上线的那天晚上我兴奋得没睡着。但等它跑了半年,流量惨淡、功能臃肿、代码自己都懒得看第二遍之后,我才慢慢琢磨明白一个道理:第一个网站是练手&…

2026/9/23 9:53:41 阅读更多 →

月新闻

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

2026/9/23 9:53:40 阅读更多 →
容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…

2026/9/23 9:53:40 阅读更多 →
容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步分类:[工程技术]细分主题:Docker 容器化技术与镜像安全管理:核心链路的逐步实现与关键代码取舍面对一个积累了五六年历史包袱的单体架构应用(包含 Web 接口、后台…

2026/9/23 9:53:40 阅读更多 →