一次 Anki 登录不上的找 bug 经历

From 清冽之泉
Jump to navigation Jump to search

本文记录我的一次找 bug 经历。

之前,因为服务器被刷流量,导致宕机。所以我需要写一些防爆破规则。

在整理各类规则时,我没管 Anki。有空再用 Anki 时,Anki 死活无法登录了。

报错不一定可靠

报错越大越含混,越不可靠。报错越细节,越可靠。

账密有错

表面上,报错:Email or password was incorrect. please try again.

这就有以下几个怀疑方向。

怀疑 证据 结果
我的 AnkiWeb 账密有误 但我明明在 AnkiWeb 上真实地登录着,它不可能有误 排除
Anki 不支持自定义账密,必须使用 AnkiWeb 账密 但很多网贴都清楚地记载着,AnkiWeb 账密和自定义账密,两者完全分开,可以不同。Anki 很支持自定义账密 排除
我出现了 typo 错误 但以我的细心程度,以及多番检查,以及不使用 copy and paste,没有误字漏字 排除

请求地址有错

表面上,报错:

  1. Connection timed out. Please try again. If you see frequent timeouts, please try a different network connection.
  2. Error details: error sending request for url ()

ChatGPT 和论坛许多人都认为是请求地址不对,认为是代理或恶意软件拦截了请求。殊不知这报错太宽泛,最终的实用价值很低。

Issue 和论坛不一定可靠

怀疑 证据 结论
发版出了问题 但本 Anki 版本已经发出来七个月了,要有问题早就引发热烈讨论了,GitHub Issue 里没人提 我没有理性排除发版问题,还怀疑别人都用的老版。有点傻乎乎,以后软件问题还是不要首先怀疑原作者的发版有问题
遭遇了恶意封禁 论坛里许多人提到因恶意软件导致无法登录。十几个相同案例让我非常怀疑自己遇到了相同情况 无法排除,耗费了大量时间查找线索

控制台不一定可靠

控制台 证据 结论
服务端控制台 错误显示得少。正确时显示得多 用处不大
客户端控制台 Windows Anki 可以用 anki_conselo.bat 运行。Linux Debian Anki 可以在 Terminal 里运行。同样是错误显示得少。正确时显示得多 用处不大
Ctrl Shift ; 调试窗口在插件开发过程中,应该比较有用 对此次排错用处不大

版本问题应该最早排查

Anki 有不同平台,所以我换了 Windows 端、Android 端、Linux Debian 端,皆报错一致,无法登录。此时第一时间应该怀疑不是客户端问题,而是服务端问题。但我没这种直觉,还是按部就班,怀疑是新版问题,于是接着用了三四个旧版,均报同样的错误。

抓包比较有效

抓包有两种思路:流量出站没?流量入站没?

out

最有效的命令,非在服务器之外运行curl -vk 1.2.3.4:12345莫属,它可以初步判定,有没有流量出去,对方有没有反应,哪怕是拒绝。

netstat -ano | findstr :443 在 Windows 里能很方便判断,有没有流量出去。

在 Windows 里,按住梅花键,再输入“资源监视器”,在“资源监视器”里勾选想监视的程序,也能看见它有没有使用磁盘、网络、内存,用处不大,但有点。优点是最简单方便。

in

tcpdump -i any port 29595 这条命令可以监测,任何尝试访问 29595 端口的流量。

who

除了出站、进站流量,有时还要关注下我主动开启的进程。

# 查看
ps aux | grep anki

# 关闭
kill pid

查日志才是最实用手段

日志,是服务器上的宝藏。看懂日志,就能解决一切问题。关于日志的详解,请见:Apache 日志详解

开启日志

LogLevel warn proxy:trace3 proxy_http:trace3
ErrorLog ${APACHE_LOG_DIR}/error.log

自造日志

SetEnvIfNoCase User-Agent "^$" ua_empty

LogFormat "%h %l %u %t \"%r\" %>s %b ua=\"%{User-Agent}i\" empty=%{ua_empty}e" anki_debug
CustomLog /var/log/apache2/anki_debug.log anki_debug

过滤日志

tail 的 -f 选项,简直是查报错的神器,客户端点击一次,服务端的日志就出现一次。有没有连上,连上是什么反应,一清二楚。在 error.log 里过滤 ip,也相当有用。

tail -f /var/log/apache2/access.log | grep 1.2.3.4
cat /var/log/apache2/error.log | grep 1.2.3.4 | tail -n 100

通过第二行命令,成功抓到以下日志:

[proxy:trace1]  mod_proxy.c(969): [client 1.2.3.4:42691] AH03464: URI path '/hi/sync/hostKey' matches proxy handler 'proxy:...
[authz_core:error] [client 1.2.3.4:42691] AH01630: client denied by server configuration: proxy:...
[proxy:trace2] mod_proxy.c(848): [client 1.2.3.4:42691] AH03461: attempting to match URI path '...' against prefix '/.../' for proxying

看到 denied 基本可以确定是服务器的 apache 配置在背后拒绝了。

最小化测试是最佳手段

改了 apache 配置,记得要systemctl restart apache2重启。

如果只有一行配置可能有毛病,那可以考虑把别的配置都注释掉,去掉所有别的配置的影响,只留怀疑的那一行。如果只留它,还出了毛病,那肯定就是它的毛病。如果只留它,没出毛病,那证明不是它的毛病。

最后,通过过滤日志、自造日志、最小化测试,成功查出原因:我在服务器里设置了拒绝无头 UA 访问。重新开启,就解决了问题。