今天因为某些原因需要操作一个处于远端的数据库,但是又不想 ssh 上去用 CLI 界面操作,所以便下载了 DBeaver 准备远程连接。
但是 DBeaver 一直连接不上,提示:

没有办法连接上。
于是就来排查原因了。
可能的原因
在网上搜索原因以及询问 AI 后,总结出以下几个可能的原因:
数据库配置

MariaDB 有几个连接相关的选项,其中比较重要的是 bind-address
和 skip-networking
。
如果 bind-address
被设定成了 127.0.0.1
,说明只允许本地连接,允许所有连接的地址是 0.0.0.0
。
skip-networking
默认是 0,如果为 1 则只允许本地连接。
我看了一下我的配置,bind-address
设定成了 127.0.0.1
,说明确实只监听了本地连接,于是改成 0.0.0.0
。
但还是连不上。
哪里的网络问题
既然数据库配置没问题,那就只能是网络的问题了。
要么就是在客户端没发出去,要么就是在服务端被拦截了。一个一个排查就好。
首先 ping 一下目标主机,是有响应的,说明远端主机在网络上是可达的,有可能是端口没有开或者被拦截了。
使用 ss 查看远端主机的端口情况:

可以看到,数据库的 3306 端口是开着的。
再看看客户端的情况。
在客户端可以使用 telnet 来与远端主机的特定端口进行沟通(我也是现在才知道 telnet 还有这个用法):

可以看到,telnet 成功连接上了数据库的端口,但是没多久就被远端断开连接了。

DBeaver 的报错也是一样的,还没有读取到内容就被远端断开服务了。
也就是说,请求在服务端被拦截了。
被什么拦截了?
根据 AI 的说法,可以用 ufw
或者 nftables
或者 iptables
查看防火墙设置。
但是我的远端主机并没有安装 ufw
,还好 nftables
是可以使用的。于是用 nftables
查看防火墙规则:

结果是空的,什么都没有
再用 iptables
试试:

同样也是什么规则都没有。
也就是说,远端机器内部根本就没有做任何的防火墙拦截,但连接就是被远端机器断掉了。
没办法,只能通过两头抓包来看看是什么情况了。
两头抓包
在客户端使用 wireshark,在远端主机使用 tcpdump,再用 telnet 访问远端主机,有以下结果:

客户端这边一直在进行 TCP 重传

远端主机则是什么都没收到。
这只能说明一个问题:有什么东西阻拦了客户端和远程主机上的连接,而且这个东西没有运行在远程主机上。
破案
这个小主机是跑在阿里云上的,既然问题不出现在客户端,也不出现在远端主机自身,那就只可能是阿里云做了什么,于是上阿里云控制台看看有没有控制端口相关的操作,结果:

还真有!
在阿里云控制台打开数据库的端口后,就可以正常连接远端机器上的数据库了。
至此,已经结束了……吗?
复盘
其实这是一个非常简单的问题,但是为什么花了我这么多时间呢?
因为有东西把我的思路引到了错误的方向。
还记得 DBeaver 和 telnet 报的是什么错吗?
DBeaver 是「连接上了远端主机,但是被远端主机主动断开了连接,所以读不到数据」。
telnet 是「连接上了远端主机,但是一秒后就被远端主机断开了连接」。
都是「先连接上了远端机器,但是被断开了连接」。
于是这便把我的思路转移到:连接已经建立了。
连接已经建立了,但是因为有什么问题所以被主动断开了。有可能是没有使用 TLS,有可能是用于登录数据库的用户有问题,有可能是没通过一些远端数据库默认打开的验证。
所以我就没有再想防火墙的事情。
直到与黑豹哥聊天后,黑豹哥说他连接同一个远端主机的情况和我完全不一样,他是直接无法建立连接。
这就让我觉得很奇怪,于是才进行了网络抓包。
Wireshark 网络抓包的结果是:
客户端一直在向远端主机发送 TCP 连接请求,但是一直在重发,没有得到远端主机的响应。
在远端机器上用 tcpdump 网络抓包的结果是:
一直没有从任何网络请求。
抓包结果说明,到远端的连接完全没有建立成功过。
客户端连接行为和抓包结果明显是相互矛盾的,只有一个是真实发生的情况。那么哪一个才是真的呢?
答案是:Wireshark 抓包和远端机器上的 tcpdump 抓包才是真实发生的结果。到远端的连接完全没有建立成功过。
详解
为什么会这样呢?在此请出黑豹哥的金句:

这句话让我醍醐灌顶。因为我正在开着代理软件的 tun 模式。也就是说,我的所有网络请求都是被代理软件托管的。
于是乎我关闭了代理软件重新试了一下,确实没有办法建立连接。
所以「先连接上了远端机器,但是被断开了连接」是代理软件模拟「连接不上」的行为,并不代表真实发生的情况。
感觉这可能成为以后一个潜在的坑,于是在这先记录一下。