分析访问谷歌却返回百度的原因

我在某个办公网络中没挂代理的情况下访问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的解析。