netflix 通过 linux iptables nat 停转,tcp 校验和错误(含解决方法)

netflix 通过 linux iptables nat 停转,tcp 校验和错误(含解决方法)

我已经尝试追踪这个问题好几天了。我仍然不知道发生了什么,或者如何正确修复它,但我有一个解决方法。

问题摘要

在我的内部网络的任何机器上观看 Netflix 时,通过充当 nat 路由器和 adsl 的 linux 机器访问互联网,Netflix 都会停顿。在连接到互联网的 linux 机器上直接观看时,Netflix 运行正常。

细节

我的 Linux 服务器机箱“chimp”通过一个网卡 (eth0) 连接到房屋内部网络,并通过另一个网卡 (eth3) 连接到 adsl 调制解调器。它正在运行 pppoe 到 adsl 调制解调器,互联网链接工作正常,下载速度为 15Mb/s,上传速度为 1Mb/s。Chimp 正在运行 debian jessie 8.6.0(内核 3.16.0-4-amd64),尽管在我将其升级为调查此问题的一部分之前,它是 debian wheezy 7.1.0。

家庭网络上的其他计算机通过 chimp 上的 iptables 规则访问互联网,这些规则使用伪装(我也尝试了 snat)从 eth0 转发到 ppp0。

在 chimp 上观看 Netflix 本身没有问题。在网络上的任何计算机上观看 BBC iplayer(我在英国)都没有问题。在 chimp 以外的任何计算机上观看 Netflix 都会卡住,尽管我相信它在 2016 年 11 月初左右可以正常工作。出现问题的计算机包括几台 Mac(Safari)和另一台 Debian Jessie Box(Chrome)。

查看“/sbin/ifconfig ppp0”中的“RX 字节”数字显示它正在下载几秒钟,然后几乎停止了。

我在互联网上发现一些东西,说我的 iptables 规则应该丢弃 conntrack 标记为“无效”的数据包。我添加了丢弃无效数据包的规则,但这并没有改善情况。我也尝试了日志记录,我发现我从 Netflix 收到了一堆这样的数据包,但只有在使用 Chimp 以外的机器观看时才会出现这种情况。

我尝试了“echo 255 >/proc/sys/net/netfilter/nf_conntrack_log_invalid”,发现无效数据包是由于 TCP 校验和错误造成的:

Dec 30 20:16:40 chimp kernel: [185803.594182] nf_ct_tcp: bad TCP checksum IN= OUT= SRC=78.146.119.61 DST=<my_public_ip_address> LEN=1500 TOS=0x00 PREC=0x00 TTL=59 ID=0 PROTO=TCP SPT=443 DPT=56711 SEQ=92431783 ACK=3940029300 WINDOW=2050 RES=0x00 ACK URGP=0 OPT (0101080AC67B959B27E48AC7) 
Dec 30 20:16:40 chimp kernel: [185803.594200] input invalid: IN=ppp0 OUT= MAC= SRC=78.146.119.61 DST=<my_public_ip_address> LEN=1500 TOS=0x00 PREC=0x00 TTL=59 ID=0 PROTO=TCP SPT=443 DPT=56711 WINDOW=2050 RES=0x00 ACK URGP=0

(“输入无效”前缀表明它来自我的 iptables 规则,用于在丢弃无效数据包之前在输入链中记录它。)

我尝试使用“sysctl -w net.netfilter.nf_conntrack_checksum=0”禁用 conntrack 中的校验和检查。这让上述日志行停止,但并没有解决问题。

所以我最好的猜测是:

  • 我向 Netflix 流发送的上游出现了问题,因此收到 TCP 校验和错误。
  • 当在 chimp 上观看 Netflix 时,一个错误的数据包到达 chimp 的 tcp 层,它能够恢复,也许是通过再次请求数据包。
  • 在另一台机器上观察时,即使禁用了 tcp 校验和检查,conntrack 也无法将数据包与连接关联起来,因此它永远不会到达客户端机器的 tcp 层。客户端的 tcp 层会以更激烈的方式恢复,可能是超时时间更长或整个连接出错。

最后才是真正的问题

对于比我更了解 tcp、conntrack 和 nat 的人来说,这有意义吗?还是我可能做错了什么?

解决方法

我已经有点精疲力竭了,无法再调查这个问题。但也许这个解决方法对遇到同样问题的人有用。

解决方法是使用在 chimp(连接到互联网的机器)上运行的 http/https 代理设置整个房屋网络。我使用 chimp 上的 wpad.dat 自动配置其他机器,并将其设置为仅代理 *.netflix.com 和 *.nflxvideo.net。

每台客户端机器都需要进行一些配置才能使用代理自动发现,只需在 mac 和 gnome 上的网络设置中选中一个复选框即可(我猜 windows 上也是一样)。

iptables -L -xvn 的输出

Chain INPUT (policy DROP 0 packets, 0 bytes)
    pkts      bytes target     prot opt in     out     source               destination         
       0        0 LOG        all  --  *      *       0.0.0.0/0            0.0.0.0/0            state INVALID LOG flags 0 level 4 prefix "input invalid: "
       0        0 DROP       all  --  *      *       0.0.0.0/0            0.0.0.0/0            state INVALID
     347    19177 ACCEPT     all  --  lo     *       0.0.0.0/0            0.0.0.0/0           
     259    33840 ACCEPT     all  --  eth+   *       0.0.0.0/0            0.0.0.0/0           
       0        0 ACCEPT     icmp --  *      *       0.0.0.0/0            0.0.0.0/0           
       0        0 ACCEPT     udp  --  *      *       0.0.0.0/0            0.0.0.0/0            udp dpts:1024:5999
       0        0 ACCEPT     udp  --  *      *       0.0.0.0/0            0.0.0.0/0            udp dpts:6010:65535
       0        0 ACCEPT     udp  --  *      *       0.0.0.0/0            0.0.0.0/0            udp dpt:123
       0        0 ACCEPT     udp  --  *      *       0.0.0.0/0            0.0.0.0/0            udp dpt:500
       0        0 ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp dpt:25
       0        0 ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp dpt:143
       0        0 ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp dpt:993
       0        0 ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp dpt:80
       0        0 ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp dpt:22
       0        0 ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp dpt:443
       0        0 ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp dpt:8443
       0        0 ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp flags:!0x17/0x02
       0        0 ACCEPT     47   --  *      *       0.0.0.0/0            0.0.0.0/0           
       0        0 ACCEPT     esp  --  *      *       0.0.0.0/0            0.0.0.0/0           
       0        0 DROP       all  --  *      *       0.0.0.0/0            0.0.0.0/0           

Chain FORWARD (policy DROP 0 packets, 0 bytes)
    pkts      bytes target     prot opt in     out     source               destination         
       0        0 ACCEPT     all  --  lo     *       0.0.0.0/0            0.0.0.0/0           
       0        0 LOG        all  --  *      *       0.0.0.0/0            0.0.0.0/0            state INVALID LOG flags 0 level 4 prefix "forward invalid: "
       0        0 DROP       all  --  *      *       0.0.0.0/0            0.0.0.0/0            state INVALID
       0        0 ACCEPT     tcp  --  eth0   ppp+    0.0.0.0/0            0.0.0.0/0           
       0        0 ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp flags:!0x17/0x02
       0        0 ACCEPT     udp  --  eth0   *       0.0.0.0/0            0.0.0.0/0            udp dpt:53
       0        0 ACCEPT     udp  --  *      eth0    0.0.0.0/0            0.0.0.0/0            udp spt:53
       0        0 DROP       all  --  *      *       0.0.0.0/0            0.0.0.0/0           

Chain OUTPUT (policy ACCEPT 639 packets, 103120 bytes)
    pkts      bytes target     prot opt in     out     source               destination         

iptables-save 的输出

# Generated by iptables-save v1.4.21 on Mon Jan  2 13:24:22 2017
*nat
:PREROUTING ACCEPT [115:43215]
:INPUT ACCEPT [43:4146]
:OUTPUT ACCEPT [2:606]
:POSTROUTING ACCEPT [2:606]
-A POSTROUTING -o ppp+ -j MASQUERADE
COMMIT
# Completed on Mon Jan  2 13:24:22 2017
# Generated by iptables-save v1.4.21 on Mon Jan  2 13:24:22 2017
*filter
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [692:108312]
-A INPUT -m state --state INVALID -j LOG --log-prefix "input invalid: "
-A INPUT -m state --state INVALID -j DROP
-A INPUT -i lo -j ACCEPT
-A INPUT -i eth+ -j ACCEPT
-A INPUT -p icmp -j ACCEPT
-A INPUT -p udp -m udp --dport 1024:5999 -j ACCEPT
-A INPUT -p udp -m udp --dport 6010:65535 -j ACCEPT
-A INPUT -p udp -m udp --dport 123 -j ACCEPT
-A INPUT -p udp -m udp --dport 500 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 25 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 143 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 993 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 80 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 22 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 443 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 8443 -j ACCEPT
-A INPUT -p tcp -m tcp ! --tcp-flags FIN,SYN,RST,ACK SYN -j ACCEPT
-A INPUT -p gre -j ACCEPT
-A INPUT -p esp -j ACCEPT
-A INPUT -j DROP
-A FORWARD -i lo -j ACCEPT
-A FORWARD -m state --state INVALID -j LOG --log-prefix "forward invalid: "
-A FORWARD -m state --state INVALID -j DROP
-A FORWARD -i eth0 -o ppp+ -p tcp -j ACCEPT
-A FORWARD -p tcp -m tcp ! --tcp-flags FIN,SYN,RST,ACK SYN -j ACCEPT
-A FORWARD -i eth0 -p udp -m udp --dport 53 -j ACCEPT
-A FORWARD -o eth0 -p udp -m udp --sport 53 -j ACCEPT
-A FORWARD -j DROP
COMMIT
# Completed on Mon Jan  2 13:24:22 2017

相关内容