一次不走心的寻路:DNS放大攻击到底在干什么?——DNS RRL
我的处理经验
折腾DNS RRL时,我发现最麻烦的往往不是安装,而是配置。想象一个场景:你在小区门口大喊一声“喂,3号楼在哪里?”保安立刻用对讲机吼出“3号楼在东边20米!”结果你这句话被隔壁一群捣蛋鬼听到,他们同时假扮你,在每栋楼门口都喊同一句话,保安则不停对讲各个方向,把整个小区吵翻天。这就是DNS放大攻击的缩影。
DNS(域名系统)本身是无辜的——它负责把“example.com”翻译成IP地址。问题出在一种特性:一个极小的查询请求(几十字节),可以触发一个巨大的响应(几百倍甚至上千倍)。攻击者通过伪造源IP地址(把源IP改成受害者的IP),向开放且未做限制的权威DNS服务器发送大量此类请求。服务器“好心”地将巨型响应一股脑发往受害者,最终耗尽受害者的带宽,使其无法正常服务。受害者甚至都不知道自己为什么被“群殴”。
这种攻击之所以“放大”,是因为响应/请求比非常高。例如,一个针对“isc.org”的ANY查询响应可以放大150倍以上。攻击者只需要很小的上游带宽,就能制造几百Gbps的洪流。长期以来,很多权威DNS服务器默认不设限制,成为DDoS的帮凶。
RRL:给DNS服务器装一个“限流阀”
先看关键判断
RRL(Response Rate Limiting,响应速率限制)就是用来解决这个问题的。它由ISC在BIND 9.9.x中引入,后来被其他实现(如Unbound、PowerDNS)采纳。核心思想很简单:当来自同一个源IP(伪造的源IP实际上就是受害者的IP)的DNS查询触发过多响应时,服务器开始选择性丢弃或延迟部分响应,从而防止放大流量产生。
注意:RRL不会限制正常查询,只会限制那些触发频繁、异常模式的流量。它通过维护一个桶(bucket)的滑动窗口机制,统计每个目标IP在单位时间内获得的响应数量,一旦超过阈值,就启动降级处理:比如丢弃、截断(TC=1强制客户端重试)、或者缓慢响应。这样,即使攻击者伪造了源IP,到达受害者IP的流量也会被服务器主动削减,放大效应被遏制。
RRL配置前必须知道的三件事——DNS RRL
故障定位思路
在动手之前,请理解以下三点,避免配置翻车:
- RRL只工作在权威DNS服务器上:递归DNS服务器(如公共DNS)通常不直接开放给外部递归查询,RRL主要针对权威服务器暴露的递归或开放端口。
- RRL有一定误杀风险:如果配置过于激进,可能会误伤来自共享网络(如NAT出口、CDN边缘节点)的正常用户。建议从较宽松阈值开始,观察日志再收紧。
- RRL不能替代整体DDoS防护:它是降低放大因子的有效手段,但若攻击流量来自大量真实IP(而非伪装),仍需要上游清洗或CDN防护。
想继续深入:此处可内链到“DNS RRL优化清单”文章。
一步一步配置BIND RRL(以Debian/Ubuntu为例)
步骤1:检查BIND版本
RRL自BIND 9.9.0起正式支持。首先确认版本:
named -v | grep "BIND 9"
如果版本低于9.9,建议升级到稳定版本,如BIND 9.16 LTS。安装命令:
sudo apt update && sudo apt install bind9
步骤2:编辑named.conf配置
RRL配置只能在options块或view块中启用。在/etc/bind/named.conf.options中添加如下内容:
options {
directory "/var/cache/bind";
// 启用速率限制
rate-limit {
// 每个目标IP每秒允许的最大响应次数
responses-per-second 50;
// 滑动窗口大小(秒),与responses-per-second配合
window 15;
// 超过限制后,丢弃的请求比例(0~1)
// 0.5表示丢弃一半超出的响应,1表示全部丢弃
slip 0;
// 可选:记录被限制的查询到日志
log-only yes;
};
// 其他配置...
};
参数解释:
responses-per-second:关键阈值。设为50表示每个目标IP在window时间内最多收到50个响应。一般建议从50开始,误报率低的公共权威服务器可设到100甚至更高。window:统计窗口,通常设为5~15秒。如果窗口太小,容易受突发正常流量影响;太大则限制过于宽松。slip:当限制生效时,是否“泄露”一部分响应。0表示直接丢弃,1表示全部丢弃;大于1则允许一定比例通过(如slip 2表示每两个限制触发一次返回NOTIMP或截断)。建议设0或者2。log-only:强烈建议第一次设为yes。这样RRL只会记录日志而不会实际丢弃响应,方便你观察误报情况,确认无误后再改为no。
步骤3:验证配置并启动
sudo named-checkconf
sudo systemctl restart bind9
检查日志:
tail -f /var/log/syslog | grep "rate-limit"
如果看到类似 client 203.0.113.1#12345: rate limit drop 的日志,说明RRL正在工作。但因为你设置了log-only,它不会真的丢弃。
步骤4:观察并调整参数
建议至少观察一周。你需要关注:
- 正常用户是否被限制:如果某个运营商的出口IP(如114.114.114.114)频繁出现在日志中,可能是正常递归查询被误伤。可以适当提高responses-per-second或window。
- 是否有明显的攻击源IP:如果某个IP每秒请求量是正常值的几十倍,那它就是可疑攻击源。你可以通过配置ACL单独放行或封禁。
- 日志量是否激增:当将log-only设为no后,控制台会安静很多,但也要防止日志被攻击性写入填满磁盘。
步骤5:正式启用丢弃
确认无异常后,将log-only改为no:
rate-limit {
responses-per-second 50;
window 15;
slip 2;
log-only no;
};
重载配置:
sudo rndc reload
验证RRL效果最简单的方法
配置前的检查
你可以在外部机器上模拟DNS放大请求,但注意不要攻击他人。最安全的测试是使用dnsamplifier测试工具(在自家网络内合法测试),观察响应是否被限制。更直观的方式是查看服务器的流量监控:启用RRL后,服务器出口流量应该显著下降,尤其是来自未知名查询的突发流量。
相关阅读:此处可内链到“DNS RRL常见问题”专题。
延伸阅读:此处可内链到“DNS RRL配置案例”相关文章。
常见问题与回滚
配置前的检查
- 配置错误导致BIND无法启动? 将rate-limit块整体注释掉,重启即可恢复。
- 误伤正常用户后怎么回滚? 同样先注释rate-limit块,或者增大responses-per-second到200+并设slip为0.5,让限制更宽松。然后逐一排查日志中的出现频率。
- RRL对权威服务器自身性能有影响吗? 极小。每个响应都需经过计数检查,但计算开销可忽略不计。在超大规模部署中,建议使用硬件加速或专用的DNS防火墙。
总结:让DNS服务器不再是DDoS帮凶
实际操作要点
RRL是一种轻量级、零成本的防御手段,尤其适合中小型权威DNS服务器。它不能替代专业的DDoS清洗设备,但可以从攻击源头削弱放大因子。配置起来并不复杂,只需十分钟就能让服务器从“有求必应”变成“理性限速”。开始行动前,先打开log-only观望几天,确认配置不会“伤及无辜”,再正式启用。如果你使用的是非BIND服务器(如PowerDNS、Unbound),原理一致,只需查阅对应文档调整参数即可。
DNS透明且脆弱——我们无法阻止攻击者伪造IP,但可以通过RRL让他们借力不成。保护自己,也保护他人。后续只要定期检查关键指标,DNS RRL就不会变成维护负担。
延伸阅读
