Skip to content
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

Closed
oTnTh opened this issue Apr 18, 2023 · 54 comments

Comments

@oTnTh
Copy link

oTnTh commented Apr 18, 2023

root@OpenWrt:~# chinadns-ng --version
ChinaDNS-NG 2023.04.17 https://github.com/zfl9/chinadns-ng

/usr/bin/chinadns-ng -b 0.0.0.0 -l 5353 -c 114.114.114.114,223.5.5.5 -t 94.140.14.140#5353,127.0.0.1#5300 -g /etc/chinadns-ng/gfwlist.txt -m /etc/chinadns-ng/chinalist.txt -o 15 -p 5 -r

/usr/bin/dns2tcp -L 0.0.0.0#5300 -R 9.9.9.9#9953

昨天晚上更新的chinadns-ng,大概运行了20个小时左右,然后就发现了DNS解析异常的情况。

我用如下脚本在Windows上进行测试:

echo 114:
dig "@114.114.114.114" +short $args[0]
echo 223
dig "@223.5.5.5" +short $args[0]
echo dns2tcp:
dig "@192.168.1.1" -p 5300 +short $args[0]
echo adg:
dig "@94.140.14.140" -p 5353 +short $args[0]
echo chinadns:
dig "@192.168.1.1" -p 5353 +short $args[0]

即把上游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,都出现了类似的情况。

暂时就是这样。

@oTnTh
Copy link
Author

oTnTh commented Apr 18, 2023

补充:这段时间内没有断网换过ip。

@zfl9
Copy link
Owner

zfl9 commented Apr 18, 2023

为什么你们老是遇到这么多“超时” 😂
我也日常使用chinadns-ng,没发现此问题。


我建议tcpdump抓包看下chinadns-ng到底有没有转发dns请求给上游。或者使用strace跟踪chinadns-ng,看上游返回没有。

因为我真的反复看过转发那块代码,那个逻辑真的不能再简单了,我想不出什么地方会出问题。。。

@zfl9
Copy link
Owner

zfl9 commented Apr 18, 2023

首先verbose日志是别想了,因为确实很难开着verbose来跑。所以只能借助strace,或者tcpdump抓包研究。

没有这些信息,说真的,我也帮不了什么

@cattyhouse
Copy link

问题在于你的 -p5, 上游觉得你在 DDOS 它的 dns, 每个 dns 都有请求数量的 rate limit 的. 如果你设置 -p5, 那么当你一次打开多个网站的时候, dns 请求数量是巨大的, 9.9.9.9 1.1.1.1 甚至 8.8.8.8 这类服务商会阻断你的请求.

@cattyhouse
Copy link

我觉得 -p 这个参数的设计可以稍微修改一下. 重复发包 -> 超时重试次数.

@zfl9
Copy link
Owner

zfl9 commented Apr 18, 2023

问题在于你的 -p5, 上游觉得你在 DDOS 它的 dns, 每个 dns 都有请求数量的 rate limit 的. 如果你设置 -p5, 那么当你一次打开多个网站的时候, dns 请求数量是巨大的, 9.9.9.9 1.1.1.1 甚至 8.8.8.8 这类服务商会阻断你的请求.

有点道理,而且我看到你使用了tcp查询,服务器对于tcp查询确实会谨慎许多,毕竟tcp需要维护连接信息,udp开销就小的多

@oTnTh
Copy link
Author

oTnTh commented Apr 18, 2023

等下次再出现这个情况的时候,我试试tcpdump。

如果是上游服务器拒绝服务的话,我连续手工执行测试脚本的时候,就不会出现上游服务器均返回正确结果,但是chinadns-ng超时了。

单纯看有时超时有时又正常这个表现的话,感觉更像是chinadns-ng内部塞住了。

解决不了也没关系,我定时重启就是了,只是昨天才提到今天就遇到了,所以就过来说一声…

@oTnTh
Copy link
Author

oTnTh commented Apr 18, 2023

问题在于你的 -p5, 上游觉得你在 DDOS 它的 dns, 每个 dns 都有请求数量的 rate limit 的. 如果你设置 -p5, 那么当你一次打开多个网站的时候, dns 请求数量是巨大的, 9.9.9.9 1.1.1.1 甚至 8.8.8.8 这类服务商会阻断你的请求.

有点道理,而且我看到你使用了tcp查询,服务器对于tcp查询确实会谨慎许多,毕竟tcp需要维护连接信息,udp开销就小的多

文档中好像是说,默认是p3,那我先改成p3试试?

@cattyhouse
Copy link

你可以去掉 -p 参数, 再观察下. 就是完全不用 -p

@zfl9
Copy link
Owner

zfl9 commented Apr 18, 2023

等下次再出现这个情况的时候,我试试tcpdump。

如果是上游服务器拒绝服务的话,我连续手工执行测试脚本的时候,就不会出现上游服务器均返回正确结果,但是chinadns-ng超时了。

单纯看有时超时有时又正常这个表现的话,感觉更像是chinadns-ng内部塞住了。

解决不了也没关系,我定时重启就是了,只是昨天才提到今天就遇到了,所以就过来说一声…

解决肯定是希望帮你们解决。

问题关键在于找到问题原因。。

这个我觉得真得strace跟踪一下chinadns-ng的系统调用,看看哪里的问题,不然光我们在这猜,也是无济于事,你说对吧

@zfl9
Copy link
Owner

zfl9 commented Apr 18, 2023

issue先开着,cattyhouse说的没毛病,先把p参数去了。或者改为p1,跑几天看看情况,另外就是遇到问题,先尽量收集下现场,top看看进程状态,strace跟踪下系统调用,或者tcpdump抓包看看。先别急着重启,不然真的很难找到原因,主要是我自己一直在rpi3b上跑chinadns-ng,也没遇到这种情况(我基本不重启的,除非节点挂了才会restart

@cattyhouse
Copy link

cattyhouse commented Apr 18, 2023

-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

@oTnTh
Copy link
Author

oTnTh commented Apr 18, 2023

Tue Apr 18 21:38:27 2023 daemon.info chinadns-ng[19919]: [opt_parse] invalid trustdns repeat times: 0

我改成p1了,tcmpdump和strace也提前装好了,等收集到啥数据了再来补充。

@zfl9
Copy link
Owner

zfl9 commented Apr 18, 2023

我觉得 -p 这个参数的设计可以稍微修改一下. 重复发包 -> 超时重试次数.

我感觉改为你说的这种策略,效果不行

假设超时时长是5秒

重试一次这体验就够呛了,想象一下,你打开网页,加载了十秒钟还没出来。。。。

@zfl9
Copy link
Owner

zfl9 commented Apr 18, 2023

而且就算用户愿意等,浏览器这些也不会等待这么久的dns解析时长,估计早就抛出错误,不会傻傻的在那等dns服务器返回的

@cattyhouse
Copy link

我觉得 -p 这个参数的设计可以稍微修改一下. 重复发包 -> 超时重试次数.

我感觉改为你说的这种策略,效果不行

假设超时时长是5秒

重试一次这体验就够呛了,想象一下,你打开网页,加载了十秒钟还没出来。。。。

一般 5秒还没解析出来, 那么就是梯子丢包了. 其实改为重试也没意义. 好像 dnsmasq 本身就会重试 --fast-dns-retry=?

@zfl9
Copy link
Owner

zfl9 commented Apr 18, 2023

是的,我是觉得retry的意义不大,dnsmasq确实默认会重试,有一次我发现网络出异常了,然后看到dnsmasq疯狂重试老早以前请求的域名。震惊到我了说实话,感觉没必要,因为客户端早就不关心你的结果了

@zfl9
Copy link
Owner

zfl9 commented Apr 18, 2023

毕竟这玩意是udp,要是客户端通过tcp来请求域名解析,在tcp连接还存在时,重试确实是有意义的,udp就没得搞,因为没法知道客户端是不是还在等你的结果,只能依赖于一个大致的超时时间。

@cattyhouse
Copy link

等下次再出现这个情况的时候,我试试tcpdump。

如果是上游服务器拒绝服务的话,我连续手工执行测试脚本的时候,就不会出现上游服务器均返回正确结果,但是chinadns-ng超时了。

单纯看有时超时有时又正常这个表现的话,感觉更像是chinadns-ng内部塞住了。

解决不了也没关系,我定时重启就是了,只是昨天才提到今天就遇到了,所以就过来说一声…

上游 dns 服务器拒绝的形式不是说直接把你的IP地址加入到他们的黑名单, 而是说, 当你每秒请求数量超过一定数值(具体是多少他们 dns 服务商都没有公开), 那么这次的请求就会被丢弃,而你的ip依然可以进行下一次的请求, 只要不超过他们的每秒请求数量上限.

@zfl9
Copy link
Owner

zfl9 commented Apr 18, 2023

为了防止下次出现问题没有获取到足够信息,我先把相关步骤简要地说下,尽早发现并解决问题。

首选还是strace(调试必备神器),当然如果可以,测试期间tcpdump抓个包辅助下最好不过。

当你发现问题时,执行 strace -ttv -xx -s65535 -p `pidof chinadns-ng` |& tee -a a.log

或者 strace -ttv -xx -s65535 -p `pidof chinadns-ng` -Ao a.log,不借助 tee

然后另一个终端,执行 dig 或其它会触发dns查询的操作(比如curl),为避免其它查询干扰测试,测试期间尽量减少其它dns查询

先别急着重启chinadns-ng,如果确实是上面说的-p参数导致rate-limit,那么你应该稍等一会,再次尝试dns查询,观察strace输出。

在测试chinadns-ng的同时,也测试一下chinadns-ng的国内、可信上游,看到底是哪里的问题。

最后,将 a.log 文件发出来,我看看到底是啥情况。

对于tcpdump抓包,一样的道理,使用 tcpdump -w 选项保存文件即可(可以适当过滤下,只抓udp的包)。为防止遗漏,建议 -i any 抓所有网卡。

然后描述下当时的测试情况。

@oTnTh
Copy link
Author

oTnTh commented Apr 18, 2023

为了防止下次出现问题没有获取到足够信息,我先把相关步骤简要地说下,尽早发现并解决问题。

首选还是strace(调试必备神器),当然如果可以,测试期间tcpdump抓个包辅助下最好不过。

当你发现问题时,执行 strace -ttv -xx -s65535 -p `pidof chinadns-ng` |& tee -a a.log

或者 strace -ttv -xx -s65535 -p `pidof chinadns-ng` -Ao a.log,不借助 tee

然后另一个终端,执行 dig 或其它会触发dns查询的操作(比如curl),为避免其它查询干扰测试,测试期间尽量减少其它dns查询

先别急着重启chinadns-ng,如果确实是上面说的-p参数导致rate-limit,那么你应该稍等一会,再次尝试dns查询,观察strace输出。

在测试chinadns-ng的同时,也测试一下chinadns-ng的国内、可信上游,看到底是哪里的问题。

最后,将 a.log 文件发出来,我看看到底是啥情况。

对于tcpdump抓包,一样的道理,使用 tcpdump -w 选项保存文件即可(可以适当过滤下,只抓udp的包)。为防止遗漏,建议 -i any 抓所有网卡。

然后描述下当时的测试情况。

刚才打游戏去了,想说等等再去找找资料strace怎么用,结果就发现你这都写好了,感动。

等会我就去测试一下,看看工具是不是都正常,希望最后能找到问题所在吧。

@oTnTh
Copy link
Author

oTnTh commented Apr 28, 2023

更新一下进度,虽然其实没啥进度。

因为路由器是新换的,之前发现有些设备会频繁掉WIFI。为了找问题所以总是在重启,最近就不太能维持一个长时间运行的状态。

提交issue之后,有遇到过一次主楼描述的情况。不过等我把WiFi设备都禁用了,不相关的设备网线都拔掉之后再测试,超时的情况又消失了。

另外我最近还修改了一些跟DNS相关的设置,也一并列在这里:

/etc/config/dhcp

config dnsmasq
        option cachesize '5120'
        option dnsforwardmax '5120'
        option dhcpleasemax '5120'

如果遇到了跟我类似情况,可以试试看是否有效果。

@oTnTh
Copy link
Author

oTnTh commented May 3, 2023

又遇到主楼提到的问题了,这次抓到了一些信息。

report.zip

chinadns的参数是这样的:/usr/bin/chinadns-ng -b 0.0.0.0 -l 5353 -c 114.114.114.114,223.5.5.5 -t 208.67.220.220#5353,94.140.14.140#5353 -g /etc/chinadns-ng/gfwlist.txt -m /etc/chinadns-ng/chinalist.txt -o 6 -r

进程有两个,所以两个我都抓了:strace -ttv -xx -s65535 -p 5153 -p 5154

测试方法是在Windows上用dig v9.16.30:dig "@192.168.1.1" -p 5353 +short www.bnu.edu.cn

该命令应该是执行了三次吧,前两次都超时,最后一次返回了正确的结果。

我尝试用Wireshark打开抓包文件看了下,filter是这样的:dns.qry.name contains "bnu.edu.cn"

2023-05-03 174057

不知道是我理解有误还是方法不对,怎么看起来好像是opendns和adg都返回了正确的结果,反而是114跟阿里的服务器没有响应。

于是我尝试手工执行如下脚本,按顺序向114、阿里和chinadns发起查询:

echo 114:
Get-Date -Format yyyy-MM-dd_HH:mm:ss.ffff
dig "@114.114.114.114" +short www.njtu.edu.cn
echo 223
Get-Date -Format yyyy-MM-dd_HH:mm:ss.ffff
dig "@223.5.5.5" +short www.njtu.edu.cn
echo chinadns:
Get-Date -Format yyyy-MM-dd_HH:mm:ss.ffff
dig "@192.168.1.1" -p 5353 +short www.njtu.edu.cn

结果是114和阿里都能正常返回数据,chinadns还是会超时。(进行这个部分测试的时候,tcpdump已经关掉了,dump.cap里没有相关数据。)

另外,今天发现该问题的时候,我刚从外面回家,手机连上家里wifi的时候就发现不对劲。当时家里连上网的有一些智能家电,还有手机平板一类的东西,PC没有开机,应该也就没有打开浏览器这种瞬间会发起很多查询请求的操作。

(节日快乐,什么时候有空了再说也成的。

@zfl9
Copy link
Owner

zfl9 commented May 3, 2023

过两天再看。。

@oTnTh
Copy link
Author

oTnTh commented May 3, 2023

过节要紧(

补充一点大概没啥用处的信息。我写完上边内容的时候,chinadns依然处于会间歇性超时的状态。

然后我把dnsmasq的上游dns改成了114并重启,chinadns放那里没管。等吃饭回来再试了一下,chinadns超时的情况又消失了。

@zfl9
Copy link
Owner

zfl9 commented May 5, 2023

我看了下,查询 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 秒,这样既能兼顾性能(减少系统调用开销),也顺便解决上述问题(如果确实是我猜的这个原因)。

@oTnTh

@cattyhouse
Copy link

按照你这个解释, 那么上游如果是 DoT/DoH proxy, 其实没啥影响对吧, 只是本地的连接了.

@zfl9
Copy link
Owner

zfl9 commented May 5, 2023

按照你这个解释, 那么上游如果是 DoT/DoH proxy, 其实没啥影响对吧, 只是本地的连接了.

是的,这种通常只出现在 路由器上(也就是主机本身有 公网ip),其他基本没影响,比如你说的套了 doh,这种 chinadns-ng 只与本地 proxy 通信。像路由器这种,因为 src ip 就是公网 ip,没有中间 proxy/nat,直接访问 china 上游,持续使用同一个端口,是很有可能发生上述情况的。

这好像也能解释,为什么我从未遇到上述超时问题,因为我的 rpi 没有直连公网,我是作为 旁路由 用的。

@zfl9
Copy link
Owner

zfl9 commented May 5, 2023

也不一定是公网ip吧,可能某些 nat 针对相同源端口,也会映射为相同的公网源端口。

@zfl9
Copy link
Owner

zfl9 commented May 5, 2023

我明两天先改一下(dev分支,或者新建一个分支),然后你这边用那个版本继续跑一段时间,观察下是否还能重现

@oTnTh
Copy link
Author

oTnTh commented May 5, 2023

好的,那等你改了,我再继续用114和阿里观察一下。

说不定我之前提到的大量upstream dns server reply timeout问题也是因为这个。两个china上游正好都超时的时候,客户端这边就出问题了。

@cattyhouse
Copy link

现在的机制比较像 dnsmasq 的这个:

-Q, --query-port=<query_port>
              Send outbound DNS queries from, and listen for their replies on, the specific UDP port <query_port> instead of using random ports. NOTE that using this option will make dnsmasq less secure against DNS spoofing at‐
              tacks but it may be faster and use less resources.  Setting this option to zero makes dnsmasq use a single port allocated to it by the OS: this was the default behaviour in versions prior to 2.43.

为何只有 udp 呢? tcp 是不是 rcode: tc 了才会用?

@zfl9
Copy link
Owner

zfl9 commented May 5, 2023

基于tcp的dns,通常每个query,都是新建一个tcp连接的,没有复用,虽然协议层面支持,但很少能见到这种实现。

@cattyhouse
Copy link

基于tcp的dns,通常每个query,都是新建一个tcp连接的,没有复用,虽然协议层面支持,但很少能见到这种实现。

有倒是有 : https://github.com/coredns/coredns/blob/47d8ff6d915eb9ee13b71f68c0ce4b8342e6d5aa/plugin/forward/README.md?plain=1#L66

@zfl9
Copy link
Owner

zfl9 commented May 5, 2023

嗯,单个tcp连接多个dns查询,除了客户端支持(如coredns),还得看server支不支持,有些激进的公共dns,查询完就给你close连接了(我没测试有哪些,只是看rfc文档是这样说的,毕竟维护tcp连接是有开销的

@oTnTh
Copy link
Author

oTnTh commented May 5, 2023

我想了一下,你要不要考虑扩充一下log功能,给定个级。verbose之下给个level 2之类的,把哪个上游查询哪个域名超时了的记录写进去。

假如你的猜想正确的话,只有在两个china上游都限流,并且那个时间段我在家并且在上网的时候,才会被发现。即便修改以后60s重开一个端口,我这里也稳定跑了一两个星期,也很难说问题就解决了。

如果有了更有针对性的log,我家里那些智能家居也会没完没了的连接服务器,要是我不在家的时候出了问题,回来看看也就知道了。openwrt的system log大概能存个5、600条信息,应该也够了。

@zfl9
Copy link
Owner

zfl9 commented May 8, 2023

测试下 05.08 版本,应该是可以解决此问题了。
@oTnTh

@zfl9
Copy link
Owner

zfl9 commented May 8, 2023

我想了一下,你要不要考虑扩充一下log功能,给定个级。verbose之下给个level 2之类的,把哪个上游查询哪个域名超时了的记录写进去。

假如你的猜想正确的话,只有在两个china上游都限流,并且那个时间段我在家并且在上网的时候,才会被发现。即便修改以后60s重开一个端口,我这里也稳定跑了一两个星期,也很难说问题就解决了。

如果有了更有针对性的log,我家里那些智能家居也会没完没了的连接服务器,要是我不在家的时候出了问题,回来看看也就知道了。openwrt的system log大概能存个5、600条信息,应该也够了。

日志这块先不动吧,感觉没什么必要.

@zfl9 zfl9 closed this as completed in 1e607e5 May 8, 2023
@zfl9 zfl9 reopened this May 8, 2023
@oTnTh
Copy link
Author

oTnTh commented May 8, 2023

好的,我等看看这位大佬的日更ipk:https://github.com/kiddin9/openwrt-packages

要是明天他那没更新,我就自己编译一下。

@jdnt
Copy link

jdnt commented May 8, 2023

我有类似的日志,不过不影响使用
image
May 08 21:14:35 Home-Root-DNS chinadns-ng[1542]: 2023-05-08 21:14:35 E [dns.c:193 foreach_ip] remaining length is less than sizeof(record): 287 < 11278 May 08 21:19:45 Home-Root-DNS chinadns-ng[1542]: 2023-05-08 21:19:45 E [dns.c:193 foreach_ip] remaining length is less than sizeof(record): 262 < 11278 May 08 21:32:29 Home-Root-DNS chinadns-ng[1542]: 2023-05-08 21:32:29 E [dns.c:193 foreach_ip] remaining length is less than sizeof(record): 255 < 11287 May 08 21:32:29 Home-Root-DNS chinadns-ng[1542]: 2023-05-08 21:32:29 E [dns.c:193 foreach_ip] remaining length is less than sizeof(record): 76 < 11287
上一个版本也会这种提示。
很早以前的版本好像有出现过和楼主一样的超时问题,之后就很少发现了。

@zfl9
Copy link
Owner

zfl9 commented May 8, 2023

我有类似的日志,不过不影响使用 image May 08 21:14:35 Home-Root-DNS chinadns-ng[1542]: 2023-05-08 21:14:35 E [dns.c:193 foreach_ip] remaining length is less than sizeof(record): 287 < 11278 May 08 21:19:45 Home-Root-DNS chinadns-ng[1542]: 2023-05-08 21:19:45 E [dns.c:193 foreach_ip] remaining length is less than sizeof(record): 262 < 11278 May 08 21:32:29 Home-Root-DNS chinadns-ng[1542]: 2023-05-08 21:32:29 E [dns.c:193 foreach_ip] remaining length is less than sizeof(record): 255 < 11287 May 08 21:32:29 Home-Root-DNS chinadns-ng[1542]: 2023-05-08 21:32:29 E [dns.c:193 foreach_ip] remaining length is less than sizeof(record): 76 < 11287 上一个版本也会这种提示。 很早以前的版本好像有出现过和楼主一样的超时问题,之后就很少发现了。

你这个应该是收到了错误的dns回复包。忽略即可

因为那个长度明显不对。。。

@jdnt
Copy link

jdnt commented May 8, 2023

你这个应该是收到了错误的dns回复包。忽略即可

因为那个长度明显不对。。。

明白了,感谢大佬解惑 😄

@oTnTh
Copy link
Author

oTnTh commented May 11, 2023

回报一下进度,虽然也还是没啥进度。

ChinaDNS-NG 2023.05.08 <https://github.com/zfl9/chinadns-ng>

我弄了个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
}

@zfl9
Copy link
Owner

zfl9 commented May 11, 2023

话说result="${result} $?"这行,应该会把错误码重置掉吧,估计永远不会进$__err -gt 0这个判断。

@zfl9
Copy link
Owner

zfl9 commented May 11, 2023

改为这样试试

#!/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
}

@zfl9
Copy link
Owner

zfl9 commented May 11, 2023

建议手动模拟下错误,看看是否按预期执行。

比如手动将 192.168.1.1(这个应该是chinadns-ng监听吧)给关了,测试下。

@cattyhouse
Copy link

cattyhouse commented May 11, 2023

楼主是想探测 : 别的 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

@zfl9
Copy link
Owner

zfl9 commented May 11, 2023

楼主是想探测 : 别的 DNS ok , 但是 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
}

if _check $c && _nslookup $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

这个看起来更清晰,不过有个地方你忘记改了,&& _nslookup,应该是 && _check

另外,可以在加个重试

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

@cattyhouse
Copy link

另外, 你这个 nslookup 也不是很好的选择, 指定端口比较麻烦. 如果 chinadns-ng 不是监听在 192.168.1.1:53, 这个测试没有意义了. 我看一楼你的 chinadns-ng 监听是 5353

所以根据情况改一改吧:

  1. 用 dig 比较好, 可以方便指定端口
  2. 注意缓存的影响, chinadns-ng 是没有缓存, 但是如果是别的程序监听 53, 然后把 chinadns-ng 做上游, 这个测试也会被缓存影响, 从而出现误判. 最好是直接 dig chinadns 的端口 @127.0.0.1 -p 5353 这样.

@oTnTh
Copy link
Author

oTnTh commented May 11, 2023

哈,刻在DNA里的结构化。(然后我果然是写错了

我原意是当chinadns查询失败时,就把所有上游以及chinandns的查询结果,都记录到日志里。(chinadns成功了就不记录

没写注释是因为官方编译的openwrt的shell里不支持中文。

一个循环都没有是因为我记得openwrt的ash跟bash语法不太一样,比如for i in {1..2}是不行的,得写for i in 1 2。(sh语法本来就不熟悉,为了犯懒都展开了,结果还是写错了

没用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
}

@cattyhouse
Copy link

如果你想先测 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

@cattyhouse
Copy link

如果你想确保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
...

@oTnTh
Copy link
Author

oTnTh commented Jun 1, 2023

来汇报一下,更新以后也挺长时间了,最近chinadns-ng工作一切正常。

问题看起来已经解决,我觉着这个issue可以暂时关掉了。

非常感谢~

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants