简介:深信服ACSG v12.0.41版本的DNS代理功能测试实施指导书,是一份面向企业网络管理员与IT运维人员的专项部署手册,主要解决多链路场景下DNS请求分配不均、非法域名访问难以管控等问题。文档按照重定向至DNS服务器、解析为指定IP、丢弃非法请求、重定向至指定线路四种代理方式展开,每部分均包含测试条件、预期效果与详细配置步骤,方便运维人员结合实际网络环境直接对照操作。资源为单个PDF文件,大小约1.74MB,内容精炼、目录结构完整,适合正在部署或优化深信服上网行为管理设备DNS策略的中级运维人员参考学习。目前已有102人学习下载,其中还涉及负载均衡原理与链路利用率优化思路,能够帮助读者在完成功能配置的同时理解流量调度逻辑,有效缩短排错与调优时间。
1. 拿到《SANGFOR_ACSG_v12.0.41版本_DNS代理功能测试实施指导书》,先别急着点用例
很多运维拿到这类 PDF 的第一反应是照着步骤一条条点,点完就算“测过了”。但 DNS 代理恰恰是 ACSG 上最容易被误判的功能:内网上不了网、网页打开慢、部分系统解析到错误 IP,客户第一反应都怪设备,等你跑过去抓包才发现根本不是它的问题。这份指导书的核心不是教你“怎么点按钮”,而是给你一套验证“DNS 代理行为是否符合预期”的方法——客户端请求有没有到设备、设备有没有正确转发到上游、缓存到底有没有生效、域名分流有没有按策略走。适合做版本升级回归、首次验收,以及刚接手深信服设备、想自己搭环境跑一遍的网络工程师。
2. DNS 代理在 ACSG v12.0.41 里的角色:转发、缓存、分流三个测试维度
2.1 为什么网关要替终端做 DNS 解析,而不是让终端直连公共 DNS
终端直连公共 DNS 表面上简单,但对一台有上网行为管理诉求的网关来说,等于把域名解析这块彻底放进黑匣子:管理员看不到谁在解析什么,没法按域名做封堵、审计,也没法在某个上游 DNS 故障时统一切换。ACSG 做 DNS 代理以后,客户端的 DNS 配置指向设备 LAN 口,设备统一收包,再按策略转发给预先设定的上游 DNS。这样一来,域名解析路径上多了一个可以“插一脚”的位置:日志、缓存、域名策略都在这层生效,这层就是测试要盯住的对象。
ACSG 上的 DNS 代理一般有两种收包方式。一种是显式代理,客户端网卡里 DNS 直接填写设备 LAN 口地址,请求本身就以设备为目的;另一种是透明方式,客户端 DNS 还填运营商的地址,但设备在接口上拦截去往 53 端口的流量并交给本地模块处理。实施指导书里的测试通常默认前者,因为行为可预期、排错简单。如果你在现场发现客户端请求根本没出现在设备上,先确认是不是 DHCP 又把 DNS 推成了别的地址。这个细节我在第 5 章会单独展开。
顺带说一句,DNS 代理的日志功能经常被忽略。开启后,设备能记录内部 IP 解析了哪些域名,这对事后溯源很重要,但日志会占存储。测试环境里如果磁盘紧张,先把日志级别调低,免得测试中途把盘写满,那才是真的耽误事。被测对象不是协议本身,而是“代理这个动作”,所以测试要回答三件事:请求是否真的到了 ACSG,ACSG 是否按配置转给了指定上游,回包是否带着正确结果回来。抓包里同时看到客户端到设备、设备到上游的两段流量,才算把链路看全。
2.2 把功能测试拆成三条主链路:转发、缓存、分流
一份实施指导书的用例再多,拆到底层也只有三条主链路。转发链路验证“解析正确性”;缓存链路验证“性能与回源策略”;分流链路验证“策略匹配与故障转移”。我习惯先列一张表,把用例归档到这三列里,再决定抓包的位置和预期结果。
| 功能模块 | 验证点 | 关注指标 |
|---|---|---|
| 转发 | 返回记录类型与内容是否和上游一致 | 结果一致性、响应耗时 |
| 缓存 | 二次查询是否回源、TTL 是否刷新 | 缓存命中率、过期时间 |
| 分流 | 指定域名是否走指定上游或出口 | 策略匹配率、切换耗时 |
这张表最大的用处是防止“点完就忘”。比如有的用例表面在测“域名解析失败”,实际是在验证故障转移,那就要把重点从“解析结果”挪到“切换时间”上。v12.0.41 这种迭代版本,功能测试的重点不在“能不能解析”,而在“这些行为跟上一个版本比有没有变化”。所以在定通过标准时,我会把每条用例的预期写得足够具体:返回什么 IP、TTL 是多少、抓包能不能看到第二次回源。没有这些硬指标,测试结论很容易变成“好像没问题”。
三条链路对应的抓包位置也不一样。转发链路要看两段流量,缓存链路要看上游侧的重复请求,分流链路要看设备从哪个 WAN 口发出查询。同样一条 dig 命令,配合不同的抓包位置,验证的是完全不同的功能点。这也是为什么我不建议只拿客户端结果来判断设备行为——客户端看到的是一个合并后的结果,中间发生了什么,只有抓包和日志知道。
2.3 版本差异与测试边界:v12.0.41 回归要看哪些菜单
ACSG 的控制台里,DNS 相关配置一般集中在“网络配置”下,有些小版本菜单叫“DNS 代理”,有些叫“DNS 转发”,菜单位置会随版本微调。测试前先到“系统状态-版本信息”页确认设备已经升到 v12.0.41,再通过界面搜索 DNS 关键词定位入口,这个顺序不能反。常见配置项包括:DNS 代理总开关、上游 DNS 服务器列表、缓存开关、域名分流策略,以及日志审计开关,挨个过一遍能覆盖大部分回归点。
测试边界要划清楚:DNS 代理只处理域名到 IP 的映射,不处理后面的 TCP 连接建立和网页加载。所以“网页打开慢”这种用例不能只测代理,还要配合网页访问测试一起看;而“部分域名解析错误”则可以完全限定在代理功能内排查。我一般在测试方案里明确写一句:本批次只验证 v12.0.41 的 DNS 代理功能,不覆盖同版本其他模块,避免回归范围被无限扩大。
如果是集中管理平台下发的设备,还要多确认一步:当前生效配置是本地配置还是平台模板下发的。有些测试环境里,你刚改完上游 DNS,几分钟后被平台策略刷新覆盖,测试结果直接翻车。确认方法很简单,改完配置后再回到界面刷新一次,看配置是否还在。这个动作花不了十秒钟,但能省掉后面一小时的排查。
3. 搭一个最小可复现的 DNS 代理测试环境:拓扑、域名数据与抓包基线
3.1 测试拓扑与接口配置
最小环境只需要四部分:一台 ACSG、一台充当上游 DNS 的 Linux 服务器、一台客户端、一个能抓包的交换机镜像口。拓扑如下:客户端接入 ACSG 的 LAN 口,ACSG 的 WAN 口接到测试网络,上游 DNS 服务器放在 WAN 侧;管理口单独接出来用于登录控制台。客户端网卡 DNS 手动填写 ACSG LAN 口地址,不要从 DHCP 获取,避免环境干扰。
| 角色 | 接口/地址 | 说明 |
|---|---|---|
| ACSG | LAN 口 192.168.10.1 | 客户端 DNS 指向这里 |
| ACSG | WAN 口 10.0.0.2 | 连接测试上游 DNS |
| 上游 DNS | 10.0.0.253 | dnsmasq 或 BIND 模拟现网 DNS |
| 客户端 | 192.168.10.100 | Windows/Linux 均可 |
为什么要用可控上游而不是现网公共 DNS?因为缓存和分流用例需要你确切知道“上游返回了什么”。如果用公共 DNS,你无法判断设备回的是缓存还是上游真实结果,测试结论就站不住。上游 DNS 用 dnsmasq 最省事,配置几行 address 记录就能模拟多种解析结果。另外,建议准备一台带镜像口的交换机,把 ACSG 的 LAN 口和 WAN 口流量都镜像到一台笔记本上抓包,现场排查会方便很多。
3.2 准备一套覆盖正常、异常、长尾的测试域名清单
测试域名不要从生产环境里挑,风险大且预期不明。我习惯在现场建一套专用测试域名,全部挂在上游 DNS 服务器上。下面的清单可以覆盖大多数用例:
| 域名 | 记录类型 | 预期返回值 | 用途 |
|---|---|---|---|
| a.test.local | A | 10.10.10.1 | 正常解析 |
| alias.test.local | CNAME | a.test.local | CNAME 跟随 |
| v6.test.local | AAAA | fd00::1 | AAAA 记录转发 |
| ttl5.test.local | A | 10.10.10.2,TTL 5 | 缓存过期 |
| nx.test.local | 无记录 | NXDOMAIN | 异常解析 |
| split.test.local | A | 10.20.0.5 | 分流用例 |
这里注意两点:TTL 要特意设置成短值,这样测缓存过期不用干等;NXDOMAIN 一定要测,很多代理实现会把上游的“不存在”结果也缓存下来,第二次查询的表现会不一样。在 dnsmasq 配置里,这类记录可以写成 address=/a.test.local/10.10.10.1 这样的格式,TTL 通过 dnsmasq 的 --max-ttl 或 local-ttl 控制,具体看你的版本。
3.3 先打基线:不开 DNS 代理时上游的解析行为
在改 ACSG 任何配置之前,先直接在客户端用 dig 指向上游 DNS 打一轮基线。基线的意义是记录“上游本来就返回什么、耗时多少”,后面所有对比都以这组数据为参照。Linux 客户端可以直接用 dig,批量脚本如下:
#!/bin/bash # 基线测试:客户端直连上游 DNS,记录每个域名的答案与耗时 UPSTREAM="10.0.0.253" for domain in a.test.local alias.test.local v6.test.local ttl5.test.local nx.test.local split.test.local; do start=$(date +%s%N) result=$(dig @$UPSTREAM "$domain" +noall +answer +time=3 +tries=1 2>&1) end=$(date +%s%N) cost_ms=$(( (end - start) / 1000000 )) echo "$domain|$cost_ms|$result" >> baseline.txt done脚本逻辑很简单:对每个测试域名发起一次查询,禁用额外尝试(tries=1),把域名、耗时、答案一起写进 baseline.txt。date +%s%N 拿到纳秒时间戳,相减转成毫秒。+time=3 表示上游无响应时最多等 3 秒,避免单个坏域名拖住整个测试。Windows 客户端可以换成 PowerShell 的 Resolve-DnsName -Server 10.0.0.253 -Name $domain,效果一样。
baseline.txt 建好后,再在 ACSG 的 WAN 口和上游 DNS 服务器上各起一轮抓包,命令如下:
# 上游 DNS 服务器上抓包,抓满 20 个 DNS 报文就停 tcpdump -i eth0 -nn -c 20 port 53 -w upstream_baseline.pcap加上 -c 20 是为了控制抓包时长,测试环境里 20 个请求足够看出规律。pcap 文件先留着,后面验证缓存是否命中时,要回放对比上游到底收到几次请求。基线做完,设备配置才动,这个顺序能保证后面所有异常都能回到基线对比定位。
4. 按指导书执行功能测试:正向转发、缓存命中、故障转移的用例与命令
4.1 正向转发用例:验证客户端解析请求确实经过 ACSG
第一个用例不是看结果对不对,而是看流量路径对不对。客户端执行:
# 客户端把 DNS 指向 ACSG LAN 口,查询测试域名 nslookup a.test.local 192.168.10.1正常结果应返回 10.10.10.1,跟基线上游返回值一致。如果结果不一致,先别改 ACSG,回到客户端确认 DNS 配置确实指向了 192.168.10.1,再用抓包验证请求到底去了哪。在 ACSG 的 LAN 口和 WAN 口各开一路抓包,LAN 口应该看到客户端 192.168.10.100 到 192.168.10.1 的 53 端口请求,WAN 口应该看到设备 10.0.0.2 到 10.0.0.253 的转发请求。两段流量都出现,才算“代理”成立。
# 在 ACSG 上抓取 DNS 请求,打印源和目的 IP tcpdump -i any -nn -c 10 port 53这里用 -i any 是因为不确定报文会出现在哪个接口,实际测试中看到两条记录:一条 src=192.168.10.100 dst=192.168.10.1,一条 src=10.0.0.2 dst=10.0.0.253,链路就通了。注意参数顺序:-nn 表示不解析主机名和端口号,-c 10 是抓满 10 个包退出,适合现场快速验证。只看到 LAN 口那段,说明设备可能直接回了缓存;只看到 WAN 口那段,说明客户端请求没走设备,多半是 DHCP 又把 DNS 改回去了。
4.2 缓存命中与 TTL:用上游抓包区分“命中”和“碰巧”
缓存用例最容易自欺欺人:第二次查询快了一点,就以为缓存生效,其实只是网络抖动。最可靠的判断依据是看上游有没有再次收到请求。先在客户端连着查两次同一个域名,同时在上游 DNS 服务器抓包:
# 上游 DNS 上抓包,观察 ttl5.test.local 是否出现多次 tcpdump -i eth0 -nn port 53 -w cache_test.pcap然后客户端跑一个小循环,记录每次查询耗时:
# 客户端循环查询 3 次,间隔 1 秒,打印耗时 for i in 1 2 3; do start=$(date +%s%N) dig @192.168.10.1 ttl5.test.local +noall +answer +time=3 +tries=1 > /dev/null 2>&1 end=$(date +%s%N) echo "第 ${i} 次查询耗时:$(( (end - start) / 1000000 )) 毫秒" sleep 1 done如果第一次耗时几十毫秒、第二次变成一两毫秒,并且 cache_test.pcap 里 ttl5.test.local 的请求只出现一次,缓存就是真命中了。如果抓包里第二次请求又出现,说明缓存没生效,按顺序排查:设备缓存开关是否打开、该域名的 TTL 是否被上游设成了 0、是不是命中了“不缓存 NXDOMAIN”的策略。这里有个血泪经验:TTL 为 0 的域名永远不会被缓存,测缓存用例前先 dig 一下确认上游 TTL 不是 0。我曾拿一个 TTL=0 的接口域名测缓存,折腾半天,抓包才发现上游每次都不告诉设备“可以缓存”,设备自然选择不缓存。
4.3 域名分流与故障转移:多上游、按域名走不同出口的验证方法
分流用例的配置分两步。第一步在 ACSG 的上游 DNS 列表里配两个地址:主用 10.0.0.253,备用 10.0.0.254。第二步配置域名策略,把 split.test.local 指定走主用,其余域名走另一个上游。保存配置后,客户端分别解析 split.test.local 和其他域名,然后在设备会话列表或日志里确认这两类查询走了不同上游。注意,ACSG 里访问控制策略的线路分流和 DNS 代理的域名分流是两套逻辑,别在测试时把两者混为一个功能。
故障转移测试的方法:先确认 split.test.local 当前正常解析,然后在主上游服务器上停掉 DNS 服务:
# 上游 DNS 服务器上停掉 dnsmasq,制造故障 systemctl stop dnsmasq客户端立刻换一个新测试域名(比如 failover.test.local)再次解析。预期的行为是:ACSG 发现主上游不可用后,在下一个查询周期切到备用上游并正常返回。这里要记录两个时间:故障注入时间、设备实际切换到备用上游的时间。有些版本每次查询都做健康探测,切换是秒级的;有些版本依赖定时探测,切换可能要等下一个探测周期。这两个行为都算“符合设计”,但指导书必须写明你的设备属于哪一种,否则验收时容易被当成缺陷。故障恢复测试同理,重启 dnsmasq 后再查一次,确认解析可以回切。客户端本地 DNS 缓存会干扰结果,每次切换验证都用新测试域名,或者执行 ipconfig /flushdns 清掉缓存。
4.4 并发与压测:用脚本把代理压一压
单条查询正常不代表经得起现网流量。v12.0.41 回归时,我建议加一轮轻量并发测试,不需要专业压测工具,Python 标准库就能做。脚本逻辑是开多个线程,每个线程从测试域名池里随机选域名持续查询,统计成功率与耗时分布:
import concurrent.futures import random import subprocess import time # 参数区:按测试设备性能调整 DNS_SERVER = "192.168.10.1" # ACSG LAN 口地址 DOMAINS = ["a.test.local", "alias.test.local", "ttl5.test.local"] THREADS = 20 # 并发线程数 REQUESTS_PER_THREAD = 50 # 每个线程查询次数 TIMEOUT = 3 # 单次查询超时,秒 def query_once(domain): start = time.time() try: subprocess.run( ["dig", "@" + DNS_SERVER, domain, "+time=2", "+tries=1"], capture_output=True, timeout=TIMEOUT, check=False ) return time.time() - start, True except subprocess.TimeoutExpired: return TIMEOUT, False pool = [] with concurrent.futures.ThreadPoolExecutor(max_workers=THREADS) as executor: for worker in range(THREADS): for _ in range(REQUESTS_PER_THREAD): pool.append(executor.submit(query_once, random.choice(DOMAINS))) elapsed = [f.result() for f in concurrent.futures.as_completed(pool)] costs = [e[0] for e in elapsed] ok = sum(1 for e in elapsed if e[1]) costs.sort() p95 = costs[int(len(costs) * 0.95)] print(f"总请求数: {len(elapsed)} 成功率: {ok / len(elapsed):.2%} P95耗时: {p95:.3f}s")并发数我一般从 20 线程开始,每线程 50 次,总共 1000 个查询,对多数 ACSG 硬件不至于造成压力。如果设备 CPU 高或日志丢失,就降到 5 线程;如果成功率低但单条查询正常,优先怀疑设备会话表或安全策略把测试源 IP 当成了扫描攻击。脚本输出的 P95 耗时不要跟公共 DNS 比绝对数值,要跟第 3 章打好的基线比——开启代理后的 P95 比基线多出的部分,就是代理本身的开销。
5. 功能测试避坑:5 个常见问题与排查顺序
DNS 代理测试的翻车现场,多数不是设备坏了,而是环境里存在一个比 ACSG 更隐蔽的 DNS 源。下面 5 条都按“现象 → 原因 → 解决”写,命中现象就顺着原因往下查,基本能定位到具体环节。
5.1 现象:客户端明明填了设备地址,解析还是失败
原因:最常见的是 DHCP 又下发了一个 DNS 地址,客户端网卡实际生效的不是 ACSG;其次是 ACSG 对应接口的 DNS 代理开关没打开,或者开关配置在另一个接口上。测试环境里 DHCP 和静态地址混用最容易踩这个坑,因为客户端显示的是手动配置,实际生效却是 DHCP 下发的优先级更高。
解决:第一步在客户端查生效地址,Windows 用 ipconfig /all,Linux 用 cat /etc/resolv.conf,确认 DNS 是不是 192.168.10.1。第二步抓包看请求的目的 IP,只有请求真到了设备,才轮到查设备配置。抓包命令用 tcpdump -i any -nn host 192.168.10.1 and port 53。如果请求确实到了设备但没回应,检查接口归属和 DNS 代理总开关。不要急着重启设备,重启通常只掩盖问题,不会暴露根因。
5.2 现象:改完上游 DNS,解析结果纹丝不动
原因:设备缓存命中了。DNS 代理把上游结果按 TTL 缓存,TTL 没到期前,同一域名不会再向上游发查询。所以用旧域名验证配置变更,看到的永远是旧结果。这个坑在版本升级回归里特别常见,因为前面几轮测试已经把这些域名解析过一遍,设备里全是缓存。
解决:变更验证必须换新域名。如果手头没有新域名,可以在上游加一条刚创建的测试记录。不要用 TTL 大的生产域名做这类测试。反过来,TTL=0 的域名适合验证配置变更,因为它每次都会回源,结果即时可见。验证缓存是否命中时,不要只看客户端计时,要以上游抓包有没有再次出现请求为准,这才是区分“碰巧快”和“真命中”的唯一证据。
5.3 现象:分流域名没按策略走,全部落到默认上游
原因:通常三种:策略写的是精确匹配,而请求带子域;更宽泛的策略排在前面抢先命中;上游本身返回了结果,设备认为不需要分流。前两种是策略配置问题,第三种是测试数据设计问题。我在现场排查时发现,大多数“分流不生效”根因不是设备坏了,而是压根没有设计出可观察的差异。
解决:先在策略列表里核对匹配类型和顺序,确认动作是“走指定 DNS”而不是“允许”。再到两个上游分别 dig 同一个域名,确认两个上游返回的 IP 是否不同。如果两个上游返回一模一样,分流从解析结果上根本看不出来,测试就没有意义。建议给分流域名在两个上游配不同 IP,让结果可观察。另外注意匹配范围,带子域的场景要用后缀匹配,否则 www.split.test.local 永远命不中策略。
5.4 现象:内网 OA 域名被解析到公网 IP 或者 NXDOMAIN
原因:ACSG 的 DNS 代理把内网域名也当成普通域名向上游转发,上游没有这些记录,自然返回不了内网 IP。设备内置域名库或全局代理策略会放大这个问题,甚至把内网域名强行匹配到公网地址。很多第一次接触 ACSG 的同事都会在这上面耗掉半天,看着日志里一串奇怪的公网 IP,不知道从哪下手。
解决:在 DNS 代理的例外或分流策略里加入内网域名,转发到内网 DNS 服务器。规划测试域名时,把内网域名和公网域名分成两批,互不混用。测试前还要确认内置域名库有没有把测试域名也截走,很多“莫名失败”是库里预设的系统域名在起作用。如果设备有“域名识别库”这类开关,测试期间可以考虑暂时关闭,减少变量。
5.5 现象:测试机装了 SANGFOR 终端组件,结果“莫名其妙失败”
原因:一些测试机之前装过 SANGFOR 的终端管理或 SSL 插件,这类组件会接管本机 DNS 或劫持部分解析请求,流量根本没到 ACSG。很多人第一次发现“sangfor 文件夹删不掉”,问 sangfor 是什么软件、能不能卸载,指的多半就是这类常驻组件。它不在设备日志里留痕,所有异常都发生在客户端本地,所以容易让人怀疑是 ACSG 的问题。
解决:测试前在服务列表和网络适配器属性里检查相关项,能退出的退出,能卸载的卸载,不行就换一台干净测试机,或者直接在虚拟机上做功能测试。这个坑最隐蔽,因为它完全绕过了被测设备,抓包也只能看到本机进程在自问自答。判断方法很简单:把 ACSG 的 LAN 口网线拔掉,如果客户端还能“正常解析”测试域名,那解析一定发生在本地,跟设备无关。
6. 测试收尾的进阶做法:把指导书变成可重复执行的自动回归脚本
一次功能测试做完,留下 pcap 和 baseline.txt 还不够。v12.0.41 不是终点,下个版本还会回来。我现在拿到这类实施指导书,会先抽出核心用例,转成一个可重复执行的回归脚本,跑完自动输出 CSV,下次新版本回来直接对比差异。
import csv import subprocess import time DNS_SERVER = "192.168.10.1" CASES = [ ("a.test.local", "10.10.10.1"), ("alias.test.local", "a.test.local"), ("v6.test.local", "fd00::1"), ("nx.test.local", "NXDOMAIN"), ] rows = [] for domain, expected in CASES: start = time.time() result = subprocess.run( ["dig", "@" + DNS_SERVER, domain, "+noall", "+answer"], capture_output=True, text=True, timeout=5 ) cost_ms = int((time.time() - start) * 1000) passed = str(expected) in result.stdout rows.append({"domain": domain, "expected": expected, "cost_ms": cost_ms, "passed": passed}) with open("regression.csv", "w", newline="") as f: writer = csv.DictWriter(f, fieldnames=["domain", "expected", "cost_ms", "passed"]) writer.writeheader() writer.writerows(rows)这里的预期结果来自第 3 章的基线,自动化只做一件事:把“实际结果 vs 基线预期”变成一行 CSV。下次升级版本,重跑一遍,用 diff 对比 CSV,哪条用例行为变了一目了然。缓存的用例没办法完全自动化,因为它依赖 TTL 的计时,但转发和故障转移这类稳定行为非常适合做成回归项。我现在的习惯是,拿到任何网络设备的功能测试 PDF,先搭抓包基线,再写回归脚本,最后才点界面。DNS 这类功能太容易受环境干扰,眼见为实,数据说话,希望这些方法能帮你在 v12.0.41 的测试上少走弯路。
本文还有配套的精品资源,点击获取