moneyslow.com

tinc接口能ping通但是tcp不能建连故障处理

tinc国内服务器访问国外

tinc国内服务器访问国外

在国内服务器A:
# ping -I tinc0 8.8.8.8 
PING 8.8.8.8 (8.8.8.8) from 192.168.2.1 tinc0: 56(84) bytes of data.
64 bytes from 8.8.8.8: icmp_seq=1 ttl=116 time=161 ms
64 bytes from 8.8.8.8: icmp_seq=2 ttl=116 time=161 ms

但是下面的执行没有反应:
curl --interface tinc0 https://api.ipify.org?format=text -vv
*   Trying 172.67.74.152:443...

排查与解决:
用 telnet 测试 TCP 443 端口是否能连通,正常是这样:
# telnet -b 192.168.2.1 172.67.74.152 443
Trying 172.67.74.152...
Connected to 172.67.74.152.
Escape character is '^]'.

不通的话,在服务器B上抓包:
tcpdump -i tinc0 port 443

通过抓包可以看到:
# tcpdump -i tinc0 port 443
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on tinc0, link-type RAW (Raw IP), snapshot length 262144 bytes
05:42:35.483689 IP 192.168.2.1.44327 > 172.67.74.152.https: Flags [S], seq 731388620, win 64240, options [mss 1397,sackOK,TS val 3979035144 ecr 0,nop,wscale 7], length 0
05:42:36.507046 IP 192.168.2.1.44327 > 172.67.74.152.https: Flags [S], seq 731388620, win 64240, options [mss 1397,sackOK,TS val 3979036168 ecr 0,nop,wscale 7], length 0
05:42:38.523019 IP 192.168.2.1.44327 > 172.67.74.152.https: Flags [S], seq 731388620, win 64240, options [mss 1397,sackOK,TS val 3979038184 ecr 0,nop,wscale 7], length 0

从现象来看,核心问题是 服务器 A 通过 tinc0 发送的 TCP SYN 包能到达服务器 B,但没有收到任何回应(服务器 B 未返回 SYN-ACK,导致三次握手失败)。结合排查信息,问题出在 服务器 B 的流量转发或出站规则 上。
服务器 A 的 tinc0 接口能正常发送 SYN 包(服务器 B 的 tcpdump 已捕获),但服务器 B 未回应,说明:
tinc 隧道双向连通性正常(A→B 的包能到达);
问题出在 服务器 B 未能将 A 的流量转发到公网,或 公网回应的包未能通过 B 返回 A。

服务器B上执行:

# iptables -L FORWARD -v -n
Chain FORWARD (policy ACCEPT 2482 packets, 125K bytes)
 pkts bytes target     prot opt in     out     source               destination         
  17M 8909M ufw-before-logging-forward  all  --  *      *       0.0.0.0/0            0.0.0.0/0           
  17M 8909M ufw-before-forward  all  --  *      *       0.0.0.0/0            0.0.0.0/0           
  10M  620M ufw-after-forward  all  --  *      *       0.0.0.0/0            0.0.0.0/0           
  10M  620M ufw-after-logging-forward  all  --  *      *       0.0.0.0/0            0.0.0.0/0           
  10M  620M ufw-reject-forward  all  --  *      *       0.0.0.0/0            0.0.0.0/0           
  10M  620M ufw-track-forward  all  --  *      *       0.0.0.0/0            0.0.0.0/0         

必须保持是policy ACCEPT状态。(这里就是直接原因了,不能是DROP)

如果是DROP状态:
# iptables -L FORWARD -v -n
Chain FORWARD (policy DROP 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         
17884 1148K ufw-before-logging-forward  all  --  *      *       0.0.0.0/0            0.0.0.0/0           
17884 1148K ufw-before-forward  all  --  *      *       0.0.0.0/0            0.0.0.0/0           
16339 1023K ufw-after-forward  all  --  *      *       0.0.0.0/0            0.0.0.0/0           
16339 1023K ufw-after-logging-forward  all  --  *      *       0.0.0.0/0            0.0.0.0/0           
16339 1023K ufw-reject-forward  all  --  *      *       0.0.0.0/0            0.0.0.0/0           
16339 1023K ufw-track-forward  all  --  *      *       0.0.0.0/0            0.0.0.0/0  

而且防火墙不能改,那么要
# 允许从 tinc0 接口进入,从 eth0 接口转发出去(服务器A→公网方向)
ufw route allow in on tinc0 out on eth0

一般保障这条在就没问题:
# ufw show added | grep route
ufw route allow in on tinc0 out on eth0

# 允许从 eth0 接口进入的回应流量,从 tinc0 接口转发出去(公网→服务器A方向,仅允许已建立的连接)
ufw route allow in on eth0 out on tinc0 match state related,established
这个命令如果报参数错误,那就用iptables代替:
iptables -A FORWARD -i eth0 -o tinc0 -m state --state ESTABLISHED,RELATED -j ACCEPT


总结:最简单办法,国外服务器B不要启动防火墙,只加一条混杂规则即可:
iptables -t nat -A POSTROUTING -j MASQUERADE

--------------------- 以下是用到的排错命令 ----------------
# 测试通过Tinc访问互联网
curl --interface tinc0 https://api.ipify.org?format=text
# 上述命令应返回服务器B的公网IP


# 测试HTTPS连接(通过tinc0接口)
curl --interface tinc0 https://8.8.8.8 -vv

# 以接口地址访问服务
telnet -b 192.168.2.1 172.67.74.152 443
Exit mobile version