分析访问谷歌却返回百度的原因
我在某个办公网络中没挂代理的情况下访问 www.google.com,结果会被跳转到百度首页,如下是 curl 结果:
$ curl www.google.com -v * Rebuilt URL to: www.google.com/ * Trying 14.215.177.38... * Connected to www.google.com (14.215.177.38) port 80 (#0) > GET / HTTP/1.1 > Host: www.google.com > User-Agent: curl/7.47.0 > Accept: */* > < HTTP/1.1 302 Found < Location: https://www.baidu.com/error.html < Server: bfe < Date: Sun, 07 Oct 2018 09:44:17 GMT < Content-Length: 0 < Content-Type: text/plain; charset=utf-8 < * Connection #0 to host www.google.com left intact
从 curl 输出可看出:
1、www.google.com 解析出来的 IP 为 14.215.177.38,这不是 Google 的 IP;
2、服务端被 302 跳转到了百度的页面。
所以我怀疑是内部 DNS 服务器的问题,于是本地抓 DNS 的数据包:
tshark -w dns.pcap -f 'tcp port 53 || udp port 53' -i enp0s25
关键包如下:
3 2.462437548 10.8.250.222 10.8.2.1 DNS 74 Standard query 0xc451 A www.google.com 4 2.462449011 10.8.250.222 10.8.2.1 DNS 74 Standard query 0x1e72 AAAA www.google.com 5 2.462589097 10.8.2.1 10.8.250.222 DNS 102 Standard query response 0xc451 A www.google.com A 14.215.177.38 [ETHERNET FRAME CHECK SEQUENCE INCORRECT] 6 2.462619342 10.8.2.1 10.8.250.222 DNS 102 Standard query response 0x1e72 AAAA www.google.com A 14.215.177.38 [ETHERNET FRAME CHECK SEQUENCE INCORRECT]
3号、4号包是我机器发出的 DNS 查询请求;5号、6号包是 DNS 的响应,从5号、6号包的摘要里可以看到有“[ETHERNET FRAME CHECK SEQUENCE INCORRECT]”字样,意味着包的 FCS 校验失败。
标准的 Ethernet II 帧的最后4字节是校验码,一般来说网卡驱动会去校验 FCS,对于校验失败的帧则会被直接丢弃,而不会被传到协议栈中;正常的帧传到协议栈中后,会去掉 FCS 字段的。所以,理论上如果这条帧的 FCS 校验失败,是会被丢弃的,而不该被 Wireshark 抓到。
我选取校验失败的5号包,如下:
Frame 5: 102 bytes on wire (816 bits), 102 bytes captured (816 bits) on interface 0 Ethernet II, Src: Hangzhou_72:41:82 (60:0b:03:72:41:82), Dst: Dell_42:7c:28 (78:45:c4:42:7c:28) Destination: Dell_42:7c:28 (78:45:c4:42:7c:28) Source: Hangzhou_72:41:82 (60:0b:03:72:41:82) Type: IPv4 (0x0800) Trailer: 8c709a4284f86b10 Frame check sequence: 0x18bf0f4a incorrect, should be 0xe10c60dc [Expert Info (Error/Checksum): Bad checksum [should be 0xe10c60dc]] [Bad checksum [should be 0xe10c60dc]] [Severity level: Error] [Group: Checksum] [FCS Status: Bad] Internet Protocol Version 4, Src: 10.8.2.1, Dst: 10.8.250.222 User Datagram Protocol, Src Port: 53, Dst Port: 52466 Source Port: 53 Destination Port: 52466 Length: 56 [Checksum: [missing]] [Checksum Status: Not present] [Stream index: 1] Domain Name System (response) Transaction ID: 0xc451 Flags: 0x8180 Standard query response, No error Questions: 1 Answer RRs: 1 Authority RRs: 0 Additional RRs: 0 Queries Answers [Request In: 3] [Time: 0.000151549 seconds]
包的16进制原始数据如下:
0000 78 45 c4 42 7c 28 60 0b 03 72 41 82 08 00 45 00 0010 00 4c 58 26 40 00 7f 11 92 8b 0a 08 02 01 0a 08 0020 fa de 00 35 cc f2 00 38 00 00 c4 51 81 80 00 01 0030 00 01 00 00 00 00 03 77 77 77 06 67 6f 6f 67 6c 0040 65 03 63 6f 6d 00 00 01 00 01 c0 0c 00 01 00 01 0050 00 00 0e 10 00 04 0e d7 b1 26 8c 70 9a 42 84 f8 0060 6b 10 18 bf 0f 4a
仔细看这句提示“Frame check sequence: 0x18bf0f4a incorrect”,意思是 Wireshark 认为 0x18bf0f4a 是 FCS 字段的数据,是错误的 FCS 值;其实对照16进制的内容可以看出这是最后的4个字节。但是按之前说的理论,FCS 字段已在驱动层就被丢弃了,最后的字段当属于传输的数据内容,为何 Wireshark 会把它当作了 FCS 了呢?我们先计算下包应有的大小:
以太网头:14字节 IP 头:20字节 UDP 头 + DNS 包:56字节
14 + 20 + 56 = 90,包的总大小应当是90字节,但根据提示(102 bytes captured),这个帧总共有102字节,比预计的多出了12个字节,由于 Ethernet II 帧的最后4字节是 FCS,所以那多出的12字节中,最后4字节被 Wireshark 误认为是 FCS,这也就是理论上不会捕捉到 FCS 错误的包,却被 Wireshark 捕获到的原因。
其实说白了,帧数据错乱这种现象的根本原因就是 DNS 服务器返回给客户端的数据在途中被某个设备强行篡改了,导致的数据畸形,之前我还误认为是故意在 DNS 服务器上加的 google.com 的解析。