前几天把 ss 服务器从 ConoHa 迁移到 Linode 的东京2节点,丢包情况有所改善。

迁移后为了安全我重新配置了防火墙,只允许需要的端口通过。但在配置 ss 梯子服务时遇到了坑。在放行 ss 端口的情况下,ss 的手机客户端发生无法解析地址的情况,关掉防火墙则服务恢复正常,电脑端也一切正常。

iptables 配置如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
-A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
-A OUTPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
-A INPUT -p icmp -j ACCEPT
-A OUTPUT -p icmp -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A OUTPUT -o lo -j ACCEPT

# DNS
-A OUTPUT -p udp --dport 53 -j ACCEPT
-A INPUT -p udp --sport 53 -j ACCEPT

# SSH is 23333
-A INPUT -p tcp -m multiport --dports 22,23333 -j ACCEPT
-A OUTPUT -p tcp -m multiport --sports 22,23333 -j ACCEPT

# http client
-A INPUT -p tcp -m multiport --sports 80,443 -j ACCEPT
-A OUTPUT -p tcp -m multiport --dports 80,443 -j ACCEPT

# http server
-A INPUT -p tcp -m multiport --dports 80,443 -j ACCEPT
-A OUTPUT -p tcp -m multiport --sports 80,443 -j ACCEPT

# shadowxxx
-A INPUT -p tcp -m multiport --dports 6666,7777 -j ACCEPT
-A INPUT -p udp -m multiport --dports 6666,7777 -j ACCEPT
-A OUTPUT -p tcp -m multiport --sports 6666,7777 -j ACCEPT
-A OUTPUT -p udp -m multiport --sports 6666,7777 -j ACCEPT

# kcptun
-A INPUT -p udp --dport 6677 -j ACCEPT
-A OUTPUT -p udp --sport 6677 -j ACCEPT
-A INPUT -p tcp --dport 6677 -j ACCEPT
-A OUTPUT -p tcp --sport 6677 -j ACCEPT

# drop
-P INPUT DROP
-P OUTPUT DROP
-P FORWARD ACCEPT

COMMIT

我百思不得其解,分析了各种可能性,最后只能开启日志找问题。

修改 /etc/rsyslog.conf ,添加一行:

kern.* /var/log/iptables.log

将内核日志重定向到 iptables.log 方便查看。

在 iptables 文件中最后的 drop 前添加了 -A OUTPUT -j LOG,把所有被 drop 的数据包记录下来。

然后用 tailf /var/log/iptables.log 滚动输出日志。

日志输出如图:

image-20210421175608972

可以看到有大量的53端口 DNS 查询被丢弃,但我已经在 iptables 中放行了 dns 查询啊?为什么呢???

image-20210421175636741

瞪了屏幕两分钟后发现这些查询都是 tcp 协议的,而我只放行了 udp 的 DNS包。

普通的 DNS 都是 udp 传输的,而手机端的 ss 似乎默认使用了 tcp 方式的 DNS 查询,导致数据包被丢弃。

在 iptables 中允许53端口 tcp 包后问题解决。