-
Notifications
You must be signed in to change notification settings - Fork 176
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Openwrt中运行一段时间后,chinadns-ng会出现大概率返回超时的情况 #125
Comments
补充:这段时间内没有断网换过ip。 |
为什么你们老是遇到这么多“超时” 😂 我建议tcpdump抓包看下chinadns-ng到底有没有转发dns请求给上游。或者使用strace跟踪chinadns-ng,看上游返回没有。 因为我真的反复看过转发那块代码,那个逻辑真的不能再简单了,我想不出什么地方会出问题。。。 |
首先verbose日志是别想了,因为确实很难开着verbose来跑。所以只能借助strace,或者tcpdump抓包研究。 没有这些信息,说真的,我也帮不了什么 |
问题在于你的 -p5, 上游觉得你在 DDOS 它的 dns, 每个 dns 都有请求数量的 rate limit 的. 如果你设置 -p5, 那么当你一次打开多个网站的时候, dns 请求数量是巨大的, 9.9.9.9 1.1.1.1 甚至 8.8.8.8 这类服务商会阻断你的请求. |
我觉得 -p 这个参数的设计可以稍微修改一下. |
有点道理,而且我看到你使用了tcp查询,服务器对于tcp查询确实会谨慎许多,毕竟tcp需要维护连接信息,udp开销就小的多 |
等下次再出现这个情况的时候,我试试tcpdump。 如果是上游服务器拒绝服务的话,我连续手工执行测试脚本的时候,就不会出现上游服务器均返回正确结果,但是chinadns-ng超时了。 单纯看有时超时有时又正常这个表现的话,感觉更像是chinadns-ng内部塞住了。 解决不了也没关系,我定时重启就是了,只是昨天才提到今天就遇到了,所以就过来说一声… |
文档中好像是说,默认是p3,那我先改成p3试试? |
你可以去掉 -p 参数, 再观察下. 就是完全不用 -p |
解决肯定是希望帮你们解决。 问题关键在于找到问题原因。。 这个我觉得真得strace跟踪一下chinadns-ng的系统调用,看看哪里的问题,不然光我们在这猜,也是无济于事,你说对吧 |
issue先开着,cattyhouse说的没毛病,先把p参数去了。或者改为p1,跑几天看看情况,另外就是遇到问题,先尽量收集下现场,top看看进程状态,strace跟踪下系统调用,或者tcpdump抓包看看。先别急着重启,不然真的很难找到原因,主要是我自己一直在rpi3b上跑chinadns-ng,也没遇到这种情况(我基本不重启的,除非节点挂了才会restart |
-p5 尤其在你打开一个复杂的网站的时候, 会触发dns服务商的 rate limit. 假设你打开一个网站,除了这个网站自身的域名需要解析之外, 网站的内容可能涉及到加载多个 其他的 cdn 域名. 假设你开这个网站需要解析的域名数量是 10, 那么, 你这一秒的 dns 请求就是 10x5 = 50 reqs/sec, 然后你再看看 cloudflare 的 issue: 1 2 如果你一次性从 浏览器打开多个网站, 那么很容易触发. 9.9.9.9 我不知道, 但也肯定有 limit, 毕竟他们的规模比 1.1.1.1 小很多. 8.8.8.8 是宽容度最大的. EDIT: 我曾经设置过 -p3, 然后浏览器全选打开100+个收藏夹网站, 就会有部分网站无法打开. 后来才知道是触发了 1.1.1.1 的 rate limit |
我改成p1了,tcmpdump和strace也提前装好了,等收集到啥数据了再来补充。 |
我感觉改为你说的这种策略,效果不行 假设超时时长是5秒 重试一次这体验就够呛了,想象一下,你打开网页,加载了十秒钟还没出来。。。。 |
而且就算用户愿意等,浏览器这些也不会等待这么久的dns解析时长,估计早就抛出错误,不会傻傻的在那等dns服务器返回的 |
一般 5秒还没解析出来, 那么就是梯子丢包了. 其实改为重试也没意义. 好像 dnsmasq 本身就会重试 --fast-dns-retry=? |
是的,我是觉得retry的意义不大,dnsmasq确实默认会重试,有一次我发现网络出异常了,然后看到dnsmasq疯狂重试老早以前请求的域名。震惊到我了说实话,感觉没必要,因为客户端早就不关心你的结果了 |
毕竟这玩意是udp,要是客户端通过tcp来请求域名解析,在tcp连接还存在时,重试确实是有意义的,udp就没得搞,因为没法知道客户端是不是还在等你的结果,只能依赖于一个大致的超时时间。 |
上游 dns 服务器拒绝的形式不是说直接把你的IP地址加入到他们的黑名单, 而是说, 当你每秒请求数量超过一定数值(具体是多少他们 dns 服务商都没有公开), 那么 |
为了防止下次出现问题没有获取到足够信息,我先把相关步骤简要地说下,尽早发现并解决问题。 首选还是strace(调试必备神器),当然如果可以,测试期间tcpdump抓个包辅助下最好不过。 当你发现问题时,执行
然后另一个终端,执行 dig 或其它会触发dns查询的操作(比如curl),为避免其它查询干扰测试,测试期间尽量减少其它dns查询 先别急着重启chinadns-ng,如果确实是上面说的-p参数导致rate-limit,那么你应该稍等一会,再次尝试dns查询,观察strace输出。 在测试chinadns-ng的同时,也测试一下chinadns-ng的国内、可信上游,看到底是哪里的问题。 最后,将 a.log 文件发出来,我看看到底是啥情况。 对于tcpdump抓包,一样的道理,使用 tcpdump -w 选项保存文件即可(可以适当过滤下,只抓udp的包)。为防止遗漏,建议 然后描述下当时的测试情况。 |
刚才打游戏去了,想说等等再去找找资料strace怎么用,结果就发现你这都写好了,感动。 等会我就去测试一下,看看工具是不是都正常,希望最后能找到问题所在吧。 |
更新一下进度,虽然其实没啥进度。 因为路由器是新换的,之前发现有些设备会频繁掉WIFI。为了找问题所以总是在重启,最近就不太能维持一个长时间运行的状态。 提交issue之后,有遇到过一次主楼描述的情况。不过等我把WiFi设备都禁用了,不相关的设备网线都拔掉之后再测试,超时的情况又消失了。 另外我最近还修改了一些跟DNS相关的设置,也一并列在这里:
如果遇到了跟我类似情况,可以试试看是否有效果。 |
又遇到主楼提到的问题了,这次抓到了一些信息。 chinadns的参数是这样的: 进程有两个,所以两个我都抓了: 测试方法是在Windows上用dig v9.16.30: 该命令应该是执行了三次吧,前两次都超时,最后一次返回了正确的结果。 我尝试用Wireshark打开抓包文件看了下,filter是这样的: 不知道是我理解有误还是方法不对,怎么看起来好像是opendns和adg都返回了正确的结果,反而是114跟阿里的服务器没有响应。 于是我尝试手工执行如下脚本,按顺序向114、阿里和chinadns发起查询:
结果是114和阿里都能正常返回数据,chinadns还是会超时。(进行这个部分测试的时候,tcpdump已经关掉了, 另外,今天发现该问题的时候,我刚从外面回家,手机连上家里wifi的时候就发现不对劲。当时家里连上网的有一些智能家电,还有手机平板一类的东西,PC没有开机,应该也就没有打开浏览器这种瞬间会发起很多查询请求的操作。 (节日快乐,什么时候有空了再说也成的。 |
过两天再看。。 |
过节要紧( 补充一点大概没啥用处的信息。我写完上边内容的时候,chinadns依然处于会间歇性超时的状态。 然后我把dnsmasq的上游dns改成了114并重启,chinadns放那里没管。等吃饭回来再试了一下,chinadns超时的情况又消失了。 |
我看了下,查询 bnu.edu.cn 时,判定为 tag:none,然后转发给 china 和 trust 上游; 根据 strace 和 tcpdump 结果,可以知道 china 上游没有返回,trust 上游倒是正常返回。 然后你说在 chinadns-ng 发生 china 上游超时期间,尝试 dig 直接访问 china 上游,正常返回,没有超时。 我猜应该是 china 上游临时封禁了 chinadns-ng 与 china 上游通信的那个 udp 源端口,chinadns-ng 启动时,会创建 N 个 udp socket(N 是上游数量), 用于与 china、trust 上游通信。这些源端口在启动后不会再改变(除非源ip发生变动,比如发生 pppoe 重新拨号)。 后面你说到,没有操作 chinadns-ng(重启),然后等一段时间,又恢复正常,应该就是解封了,符合上述猜想。 而且也很符合你之前说的,通常运行一天左右,就会发生此情况,应该就是触发某种机制,被 china 上游临时封禁了相关 udp src port。重启 chinadns-ng 后问题消失(因为会重新选择端口,通常不会与之前的端口一样)。 当初这么设计是为了减少 socket 创建/销毁的开销,所以进程启动后,只创建一次,之后只是 send、recv 数据。 要解决此问题,我的初步想法是,给这些 socket 设置一个最大生存时长,比如 60 秒,这样既能兼顾性能(减少系统调用开销),也顺便解决上述问题(如果确实是我猜的这个原因)。 |
按照你这个解释, 那么上游如果是 DoT/DoH proxy, 其实没啥影响对吧, 只是本地的连接了. |
是的,这种通常只出现在 路由器上(也就是主机本身有 公网ip),其他基本没影响,比如你说的套了 doh,这种 chinadns-ng 只与本地 proxy 通信。像路由器这种,因为 src ip 就是公网 ip,没有中间 proxy/nat,直接访问 china 上游,持续使用同一个端口,是很有可能发生上述情况的。 这好像也能解释,为什么我从未遇到上述超时问题,因为我的 rpi 没有直连公网,我是作为 旁路由 用的。 |
也不一定是公网ip吧,可能某些 nat 针对相同源端口,也会映射为相同的公网源端口。 |
我明两天先改一下(dev分支,或者新建一个分支),然后你这边用那个版本继续跑一段时间,观察下是否还能重现 |
好的,那等你改了,我再继续用114和阿里观察一下。 说不定我之前提到的大量upstream dns server reply timeout问题也是因为这个。两个china上游正好都超时的时候,客户端这边就出问题了。 |
现在的机制比较像 dnsmasq 的这个:
为何只有 udp 呢? tcp 是不是 rcode: tc 了才会用? |
基于tcp的dns,通常每个query,都是新建一个tcp连接的,没有复用,虽然协议层面支持,但很少能见到这种实现。 |
|
嗯,单个tcp连接多个dns查询,除了客户端支持(如coredns),还得看server支不支持,有些激进的公共dns,查询完就给你close连接了(我没测试有哪些,只是看rfc文档是这样说的,毕竟维护tcp连接是有开销的 |
我想了一下,你要不要考虑扩充一下log功能,给定个级。verbose之下给个level 2之类的,把哪个上游查询哪个域名超时了的记录写进去。 假如你的猜想正确的话,只有在两个china上游都限流,并且那个时间段我在家并且在上网的时候,才会被发现。即便修改以后60s重开一个端口,我这里也稳定跑了一两个星期,也很难说问题就解决了。 如果有了更有针对性的log,我家里那些智能家居也会没完没了的连接服务器,要是我不在家的时候出了问题,回来看看也就知道了。openwrt的system log大概能存个5、600条信息,应该也够了。 |
测试下 05.08 版本,应该是可以解决此问题了。 |
日志这块先不动吧,感觉没什么必要. |
好的,我等看看这位大佬的日更ipk:https://github.com/kiddin9/openwrt-packages 要是明天他那没更新,我就自己编译一下。 |
明白了,感谢大佬解惑 😄 |
回报一下进度,虽然也还是没啥进度。
我弄了个shell脚本,crontab设置10分钟执行一次。(希望没写错 其实更新0508之前这个脚本就挂了两天,到目前为看起来都没出什么差错。 #!/bin/sh
result=""
__nslookup() {
nslookup www.njtu.edu.cn 114.114.114.114 >> /dev/null 2>&1
result="${?}"
nslookup www.njtu.edu.cn 223.5.5.5 >> /dev/null 2>&1
result="${result} ${?}"
nslookup www.njtu.edu.cn 208.67.220.220 >> /dev/null 2>&1
result="${result} ${?}"
nslookup www.njtu.edu.cn 94.140.14.140 >> /dev/null 2>&1
result="${result} ${?}"
nslookup www.njtu.edu.cn 192.168.1.1 >> /dev/null 2>&1
result="${result} ${?}"
}
__nslookup
__err=$?
[ $__err -gt 0 ] && {
echo "$(date +%Y-%m-%d_%H:%M:%S) ${result}" >> /tmp/dns_rec.log
__nslookup
echo "$(date +%Y-%m-%d_%H:%M:%S) ${result}" >> /tmp/dns_rec.log
__nslookup
echo "$(date +%Y-%m-%d_%H:%M:%S) ${result}" >> /tmp/dns_rec.log
} |
话说 |
改为这样试试 #!/bin/sh
result=""
__nslookup() {
nslookup www.njtu.edu.cn 114.114.114.114 >> /dev/null 2>&1
result="$?"
nslookup www.njtu.edu.cn 223.5.5.5 >> /dev/null 2>&1
result="${result} $?"
nslookup www.njtu.edu.cn 208.67.220.220 >> /dev/null 2>&1
result="${result} $?"
nslookup www.njtu.edu.cn 94.140.14.140 >> /dev/null 2>&1
result="${result} $?"
nslookup www.njtu.edu.cn 192.168.1.1 >> /dev/null 2>&1
result="${result} $?"
}
__nslookup
[ "$result" != "0 0 0 0 0" ] && {
echo "$(date +%Y-%m-%d_%H:%M:%S) ${result}" >> /tmp/dns_rec.log
#这里sleep几秒?
sleep 2
__nslookup
echo "$(date +%Y-%m-%d_%H:%M:%S) ${result}" >> /tmp/dns_rec.log
sleep 2
__nslookup
echo "$(date +%Y-%m-%d_%H:%M:%S) ${result}" >> /tmp/dns_rec.log
} |
建议手动模拟下错误,看看是否按预期执行。 比如手动将 192.168.1.1(这个应该是chinadns-ng监听吧)给关了,测试下。 |
楼主是想探测 : 别的 DNS ok , 但是 chinadns-ng 却不行 的时候? EDIT: typo #!/bin/sh
c=223.5.5.5
t=208.67.220.220
ng=192.168.1.1
name=www.njtu.edu.cn
_check () {
nslookup $name $1 >/dev/null 2>&1
}
_log () {
echo "$(date +%Y-%m-%d_%H:%M:%S) $@" >> /tmp/dns_rec.log
}
if _check $c && _check $t ; then
# direct query ok
if ! _check $ng ; then
# chinadns-ng error
_log "chinadns-ng query error"
fi
else
# direct query error
_log "direct query error"
fi |
这个看起来更清晰,不过有个地方你忘记改了, 另外,可以在加个重试 if _check $c && _check $t ; then
# direct query ok
for i in 1 2 3; do
if _check $ng ; then
break
else
# chinadns-ng error
_log "chinadns-ng query error ($i)"
fi
done
else
# direct query error
_log "direct query error"
fi |
另外, 你这个 所以根据情况改一改吧:
|
哈,刻在DNA里的结构化。(然后我果然是写错了 我原意是当chinadns查询失败时,就把所有上游以及chinandns的查询结果,都记录到日志里。(chinadns成功了就不记录 没写注释是因为官方编译的openwrt的shell里不支持中文。 一个循环都没有是因为我记得openwrt的ash跟bash语法不太一样,比如 没用dig是因为那个东西的依赖有点多,openwrt的nslookup其实都是busybox,我上一个路由器的flash甚至只有8M,抠抠搜搜成习惯了。( #!/bin/sh
_servers="114.114.114.114 223.5.5.5 208.67.220.220 94.140.14.140 192.168.1.1"
_domain="www.njtu.edu.cn"
_result=""
_err=0
# 向所有上游发送查询
# $_result保存所有查询结果,都成功应该是0 0 0 0 0这样
# 函数执行完毕后,$_err还保存了chinadns的查询结果
__nslookup() {
_result=""
for s in $_servers;
do
nslookup $_domain $s >> /dev/null 2>&1
_err=$?
_result="${_result} ${_err}"
done
}
__log() {
echo "$(date +%Y-%m-%d_%H:%M:%S) ${@}" >> /tmp/dns_rec.log
}
# 首次查询
__nslookup
# 不管其他上游查询结果如何,只有chinadns查询出错才记录
[ $_err -ne 0 ] && {
__log $_result
# 多执行两轮查询,无论结果如何都写入记录
for i in 1 2
do
sleep 5
__nslookup
__log $_result
done
} |
如果你想先测 chinadns-ng, 那么这样 #!/bin/sh
c=223.5.5.5
t=208.67.220.220
ng=192.168.1.1
name=www.njtu.edu.cn
_check () {
nslookup $name $1 >/dev/null 2>&1
}
_log () {
echo "$(date +%Y-%m-%d_%H:%M:%S) $@" >> /tmp/dns_rec.log
}
# check chinadns-ng 3 times
# mark as fail if error in any round
fail=0
for i in 1 2 3 ; do
_check $ng || fail=1
sleep 5
done
if [ $fail = 1 ] ; then
# chinadns-ng query error
if _check $c && _check $t ; then
# but direct query ok
_log "chinadns-ng : NO. direct : YES (chinadns-ng BUG)"
else
# both error, log this as well
_log "chinadns-ng : NO. direct : NO (network error)"
fi
fi
# do nothing if chinadns-ng query ok |
如果你想确保3次 chinadns-ng 都失败的情况下再去尝试直接query fail=0
for i in 1 2 3 ; do
_check $ng || fail=$((fail + 1))
sleep 5
done
if [ $fail = 3 ] ; then
... |
来汇报一下,更新以后也挺长时间了,最近chinadns-ng工作一切正常。 问题看起来已经解决,我觉着这个issue可以暂时关掉了。 非常感谢~ |
root@OpenWrt:~# chinadns-ng --version
ChinaDNS-NG 2023.04.17 https://github.com/zfl9/chinadns-ng
昨天晚上更新的chinadns-ng,大概运行了20个小时左右,然后就发现了DNS解析异常的情况。
我用如下脚本在Windows上进行测试:
即把上游DNS都挨个dig一次,然后再查询chinadns-ng。
我试了baidu.com和sina.com.cn,结果发现上游DNS均正常。
但连续测试若干次时,chinadns-ng有可能会返回正确的结果,但也有可能会超时(;; connection timed out; no servers could be reached),超时和返回结果看不出有什么规律,并且会交替出现。
重启chinadns-ng,该问题消失。
系统日志中chinadns-ng没有输出任何信息。
当时忘记用top看一下chinadns-ng负载情况了。
之前的路由器是mips的,用的是chinadns,现在的是arm,chinadns-ng,都出现了类似的情况。
暂时就是这样。
The text was updated successfully, but these errors were encountered: