2014年8月19日星期二

重新理解GFW的DNS污染和劫持策略

一直以来我都只在关注GFW对境外DNS的劫持,直到发现GFW对国内DNS的境内劫持,我才觉得有必要重新研究一下GFW对境内DNS的污染策略.在开始之前,需要纠正一个很多人都有错误概念:Dig命令+trace参数不是要求DNS服务器做递归查询.

事实上,Dig+trace不是要求DNS服务器做递归查询,而是通过DNS服务器进行迭代查询.从Dig的Manpage可以看到,Dig默认就是要求DNS服务器做递归查询的,我们操作系统的解析器默认也是会发出解析请求的,可是当我们加上了trace参数之后,递归请求反而是被禁用了的.



+[no]recurse
    Toggle the setting of the RD (recursion desired) bit in the query. This bit is set by default, which means dig normally sends recursive queries. Recursion is automatically disabled when the +nssearch or +trace query options are used.
而trace参数的解释是:


+[no]trace
    Toggle tracing of the delegation path from the root name servers for the name being looked up. Tracing is disabled by default. When tracing is enabled, dig makes iterative queries to resolve the name being looked up. It will follow referrals from the root servers, showing the answer from each server that was used to resolve the lookup.
很明显这就是一个明显的迭代请求的描述,也就是说,实际上DNS服务器只返回一个根域服务器列表给你,然后你就自己从根域服务器开始一级级往下查,DNS’服务器就不再参与了,这个过程能否得到正确的解析,就完全取决于你和各级Name Server的网络连接是否安全了.如果想验证这个也很容易,抓包就行了,你会看到除了第一次的根域服务器列表是DNS返回的,后面的查询过程完全就是你本机和各级名称服务器的交互,和DNS服务器就不再有关系了.

对境内DNS的分析,我们选择了两个污染样本,分别是114DNS和阿里DNS,一个未污染样本,就是Google DNS,分别从上海联通网路和美国的VPS发起查询请求.

Case 1:我们先看看从美国VPS查询GoogleDNS +trace的返回数据,这是一个最标准的且肯定正确的查询流程:

root@Pipe:~# dig twitter.com @8.8.8.8 +trace

; <<>> DiG 9.7.0-P1 <<>> twitter.com @8.8.8.8 +trace
;; global options: +cmd
.                       20014   IN      NS      d.root-servers.net.
.                       20014   IN      NS      g.root-servers.net.
.                       20014   IN      NS      b.root-servers.net.
.                       20014   IN      NS      l.root-servers.net.
.                       20014   IN      NS      m.root-servers.net.
.                       20014   IN      NS      a.root-servers.net.
.                       20014   IN      NS      k.root-servers.net.
.                       20014   IN      NS      j.root-servers.net.
.                       20014   IN      NS      c.root-servers.net.
.                       20014   IN      NS      h.root-servers.net.
.                       20014   IN      NS      e.root-servers.net.
.                       20014   IN      NS      i.root-servers.net.
.                       20014   IN      NS      f.root-servers.net.
;; Received 228 bytes from 8.8.8.8#53(8.8.8.8) in 7 ms

com.                    172800  IN      NS      a.gtld-servers.net.
com.                    172800  IN      NS      b.gtld-servers.net.
com.                    172800  IN      NS      c.gtld-servers.net.
com.                    172800  IN      NS      d.gtld-servers.net.
com.                    172800  IN      NS      e.gtld-servers.net.
com.                    172800  IN      NS      f.gtld-servers.net.
com.                    172800  IN      NS      g.gtld-servers.net.
com.                    172800  IN      NS      h.gtld-servers.net.
com.                    172800  IN      NS      i.gtld-servers.net.
com.                    172800  IN      NS      j.gtld-servers.net.
com.                    172800  IN      NS      k.gtld-servers.net.
com.                    172800  IN      NS      l.gtld-servers.net.
com.                    172800  IN      NS      m.gtld-servers.net.
;; Received 489 bytes from 192.203.230.10#53(e.root-servers.net) in 2 ms

twitter.com.            172800  IN      NS      ns1.p34.dynect.net.
twitter.com.            172800  IN      NS      ns2.p34.dynect.net.
twitter.com.            172800  IN      NS      ns3.p34.dynect.net.
twitter.com.            172800  IN      NS      ns4.p34.dynect.net.
;; Received 179 bytes from 192.55.83.30#53(m.gtld-servers.net) in 82 ms

twitter.com.            30      IN      A       199.59.148.82
twitter.com.            30      IN      A       199.59.149.198
twitter.com.            30      IN      A       199.59.148.10
twitter.com.            30      IN      A       199.59.150.39
twitter.com.            86400   IN      NS      ns2.p34.dynect.net.
twitter.com.            86400   IN      NS      ns3.p34.dynect.net.
twitter.com.            86400   IN      NS      ns4.p34.dynect.net.
twitter.com.            86400   IN      NS      ns1.p34.dynect.net.
;; Received 179 bytes from 204.13.251.34#53(ns4.p34.dynect.net) in 59 ms



可以看到,作为对迭代请求的响应,Google DNS先返回了根服务器的列表(root-servers.net),然后Dig自身选择一个root-server,请求并获得了.com顶级域名的名称服务器,从.com顶级域名的名称服务器那里,dig又获得了twitter.com的权威名称服务器,最终Dig直接查询twitter.com的权威名称服务器获得了正确的twitter.com的A记录.

root@Pipe:~# dig twitter.com @223.5.5.5 +trace

; <<>> DiG 9.7.0-P1 <<>> twitter.com @223.5.5.5 +trace
;; global options: +cmd
.                       518398  IN      NS      l.root-servers.net.
.                       518398  IN      NS      m.root-servers.net.
.                       518398  IN      NS      h.root-servers.net.
.                       518398  IN      NS      f.root-servers.net.
.                       518398  IN      NS      b.root-servers.net.
.                       518398  IN      NS      a.root-servers.net.
.                       518398  IN      NS      c.root-servers.net.
.                       518398  IN      NS      e.root-servers.net.
.                       518398  IN      NS      k.root-servers.net.
.                       518398  IN      NS      j.root-servers.net.
.                       518398  IN      NS      d.root-servers.net.
.                       518398  IN      NS      g.root-servers.net.
.                       518398  IN      NS      i.root-servers.net.
;; Received 228 bytes from 223.5.5.5#53(223.5.5.5) in 281 ms

com.                    172800  IN      NS      l.gtld-servers.net.
com.                    172800  IN      NS      m.gtld-servers.net.
com.                    172800  IN      NS      a.gtld-servers.net.
com.                    172800  IN      NS      d.gtld-servers.net.
com.                    172800  IN      NS      i.gtld-servers.net.
com.                    172800  IN      NS      c.gtld-servers.net.
com.                    172800  IN      NS      f.gtld-servers.net.
com.                    172800  IN      NS      e.gtld-servers.net.
com.                    172800  IN      NS      k.gtld-servers.net.
com.                    172800  IN      NS      j.gtld-servers.net.
com.                    172800  IN      NS      g.gtld-servers.net.
com.                    172800  IN      NS      b.gtld-servers.net.
com.                    172800  IN      NS      h.gtld-servers.net.
;; Received 489 bytes from 192.112.36.4#53(g.root-servers.net) in 57 ms

twitter.com.            172800  IN      NS      ns1.p34.dynect.net.
twitter.com.            172800  IN      NS      ns2.p34.dynect.net.
twitter.com.            172800  IN      NS      ns3.p34.dynect.net.
twitter.com.            172800  IN      NS      ns4.p34.dynect.net.
;; Received 179 bytes from 192.12.94.30#53(e.gtld-servers.net) in 179 ms

twitter.com.            30      IN      A       199.59.149.198
twitter.com.            30      IN      A       199.59.149.230
twitter.com.            30      IN      A       199.59.148.10
twitter.com.            30      IN      A       199.59.150.7
twitter.com.            86400   IN      NS      ns1.p34.dynect.net.
twitter.com.            86400   IN      NS      ns2.p34.dynect.net.
twitter.com.            86400   IN      NS      ns3.p34.dynect.net.
twitter.com.            86400   IN      NS      ns4.p34.dynect.net.
;; Received 179 bytes from 208.78.71.34#53(ns3.p34.dynect.net) in 2 ms


因为在trace过程中,DNS仅仅是返回了根域服务器的地址,后面的解析过程完全是美国VPS自己和各级名称服务器互动进行的,这个通信过程完全不受GFW干扰,自然就获得了正确的地址.如果我们直接查询这些DNS上的缓存的记录呢?这就有了两个很有趣的区别:


Case 3: 美国VPS+阿里DNS+notrace


root@Pipe:~# dig twitter.com @223.5.5.5

; <<>> DiG 9.7.0-P1 <<>> twitter.com @223.5.5.5
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 14535
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0

;; QUESTION SECTION:
;twitter.com.                   IN      A

;; ANSWER SECTION:
twitter.com.            4913    IN      A       59.24.3.173

;; Query time: 277 msec
;; SERVER: 223.5.5.5#53(223.5.5.5)
;; WHEN: Sat Jul 26 00:51:09 2014
;; MSG SIZE  rcvd: 45


结果一点都不出人意料,在默认的递归查询中,阿里的DNS返回了一个被污染(其实是劫持,后面会解释)的IP,这说明在阿里DNS做递归查询的过程中出了问题.


Case 4: 美国VPS+114+notrace


root@Pipe:~# dig twitter.com @114.114.114.114

; <<>> DiG 9.7.0-P1 <<>> twitter.com @114.114.114.114
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 41290
;; flags: qr rd ra; QUERY: 1, ANSWER: 4, AUTHORITY: 0, ADDITIONAL: 0

;; QUESTION SECTION:
;twitter.com.                   IN      A

;; ANSWER SECTION:
twitter.com.            30      IN      A       199.16.156.6
twitter.com.            30      IN      A       199.16.156.198
twitter.com.            30      IN      A       199.16.156.70
twitter.com.            30      IN      A       199.16.156.38

;; Query time: 42 msec
;; SERVER: 114.114.114.114#53(114.114.114.114)
;; WHEN: Sat Jul 26 00:53:57 2014
;; MSG SIZE  rcvd: 93


这个结果非常有趣,从境内查询一直是污染状态的114,从美国查询的时候竟然返回了正确的A记录.可能的原因是什么呢?我只能猜测是114的智能节点选择在工作,从114官方的介绍来看,114DNS对来自美国的访问有一个独立的逻辑区.毫无疑问的是,114.114.114.114这个IP对应的绝对不是一台服务器,甚至不是单一数据中心的服务器,通过GSLB技术,完全可以让一个IP对应的服务器分布到全球各地.看起来是114为来自美国的请求分配了一个位于境外的服务器,这个境外服务器的递归查询是不受GFW干扰的,使得这次的查询结果完全正常.

现在我们回国看看GFW的劫持是如何工作的,因为GFW对114和阿里DNS的污染机制几乎一样,我们只拿114做例子:

Case 5:国内网络+114+notrace


leavi_000@Cartman-Asus /home/leavi_000
$ dig twitter.com  @114.114.114.114

; <<>> DiG 9.9.5 <<>> twitter.com @114.114.114.114
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 54667
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;twitter.com.                   IN      A

;; ANSWER SECTION:
twitter.com.            25564   IN      A       59.24.3.173

;; Query time: 32 msec
;; SERVER: 114.114.114.114#53(114.114.114.114)
;; WHEN: 周六 7月 26 13:01:39     2014
;; MSG SIZE  rcvd: 56


这几乎就是我们所有人所最有可能经历的实际情况了,在境内查询114,返回一个被污染的IP,那么这个被污染的IP是如何进入114的缓存的呢?嗯,或许我们要先确认这个IP真的是从114的缓存中返回的,而不是GFW劫持了我们和114的通讯过程.

Case 6:国内网络+114DNS+notrace+iptables过滤

我们在路由上应用这篇文章中提到的方法,把可能的GFW劫持包过滤掉,剩下的就是完全有DNS服务器返回的数据了.


leavi_000@Cartman-Asus /home/leavi_000
$ dig twitter.com  @114.114.114.114

; <<>> DiG 9.9.5 <<>> twitter.com @114.114.114.114
;; global options: +cmd
;; connection timed out; no servers could be reached


可以看到,过滤掉了污染IP之后查询是失败的,也就是说114返回的结果就是污染的IP,而不是(或者说,不只是)GFW在中间劫持造成的.下面我们开始正式分析114DNS被污染的可能原因:

Case 7:国内网络+114DNS+trace

这里我们得到了两种不同的返回包,但大致机理都一样:


$ dig twitter.com @114.114.114.114 +trace

; <<>> DiG 9.9.5 <<>> twitter.com @114.114.114.114 +trace
;; global options: +cmd
.                       186609  IN      NS      c.root-servers.net.
.                       186609  IN      NS      j.root-servers.net.
.                       186609  IN      NS      b.root-servers.net.
.                       186609  IN      NS      i.root-servers.net.
.                       186609  IN      NS      a.root-servers.net.
.                       186609  IN      NS      d.root-servers.net.
.                       186609  IN      NS      l.root-servers.net.
.                       186609  IN      NS      k.root-servers.net.
.                       186609  IN      NS      h.root-servers.net.
.                       186609  IN      NS      e.root-servers.net.
.                       186609  IN      NS      g.root-servers.net.
.                       186609  IN      NS      f.root-servers.net.
.                       186609  IN      NS      m.root-servers.net.
;; Received 239 bytes from 114.114.114.114#53(114.114.114.114) in 37 ms

com.                    172800  IN      NS      a.gtld-servers.net.
com.                    172800  IN      NS      b.gtld-servers.net.
com.                    172800  IN      NS      c.gtld-servers.net.
com.                    172800  IN      NS      d.gtld-servers.net.
com.                    172800  IN      NS      e.gtld-servers.net.
com.                    172800  IN      NS      f.gtld-servers.net.
com.                    172800  IN      NS      g.gtld-servers.net.
com.                    172800  IN      NS      h.gtld-servers.net.
com.                    172800  IN      NS      i.gtld-servers.net.
com.                    172800  IN      NS      j.gtld-servers.net.
com.                    172800  IN      NS      k.gtld-servers.net.
com.                    172800  IN      NS      l.gtld-servers.net.
com.                    172800  IN      NS      m.gtld-servers.net.
com.                    86400   IN      DS      30909 8 2 E2D3C916F6DEEAC73294E8268FB5885044A833FC5459588F4A9184CF C41A5766
com.                    86400   IN      RRSIG   DS 8 1 86400 20140801000000 20140724230000 8230 . bbA/MlsqggckMvCojgBBoTUao4+bqEX3PE6wo4Vbttp9Sfk92XkTZmRd f9Ae70pfM4VDMXVpfTFnybqfXVv6IdJCT+v06M3GLXGGI5qeOh4fGpu5 dujmX9r4mhG4lGOH+dLJt7MvGZ4BvloHSNhOci2/qFDq4lVpdE8I5OHu SHg=
;; Received 735 bytes from 193.0.14.129#53(k.root-servers.net) in 420 ms

twitter.com.            300     IN      A       37.61.54.158
;; Received 56 bytes from 192.5.6.30#53(a.gtld-servers.net) in 32 ms


$ dig twitter.com  @114.114.114.114 +trace

; <<>> DiG 9.9.5 <<>> twitter.com @114.114.114.114 +trace
;; global options: +cmd
.                       188046  IN      NS      h.root-servers.net.
.                       188046  IN      NS      d.root-servers.net.
.                       188046  IN      NS      a.root-servers.net.
.                       188046  IN      NS      g.root-servers.net.
.                       188046  IN      NS      i.root-servers.net.
.                       188046  IN      NS      f.root-servers.net.
.                       188046  IN      NS      m.root-servers.net.
.                       188046  IN      NS      b.root-servers.net.
.                       188046  IN      NS      l.root-servers.net.
.                       188046  IN      NS      j.root-servers.net.
.                       188046  IN      NS      k.root-servers.net.
.                       188046  IN      NS      e.root-servers.net.
.                       188046  IN      NS      c.root-servers.net.
;; Received 239 bytes from 114.114.114.114#53(114.114.114.114) in 78 ms

twitter.com.            300     IN      A       37.61.54.158
;; Received 56 bytes from 202.12.27.33#53(m.root-servers.net) in 31 ms


这里可以很轻松的看到问题所在了:

1.第一步查询根域服务器地址,OK,这个114返回的很正常.因为根域服务器地址是一个支持递归的DNS服务器必须要内置的数据,否则他根本没法开始第一步的递归查询.

2.然后我们的dig命令开始向202.12.27.33#53(m.root-servers.net)这个根域查询,参考Case 1,正常情况根域服务器应该返回.com顶级域的名称服务器给我们,事实上呢?

3.第一个包里,根域直接返回了一个.com顶级域名称服务器的列表,在向.com顶级域名称服务器查询的时候,却返回了污染的twitter.com的A记录地址给我们.

4.第二个包里,根域甚至连.com顶级域名称服务器的列表都没给我们,直接返回了污染的A记录给我们.

4.很明显,我们向根域和.com顶级域的DNS查询过程被劫持了,在他们返回正确数据之前,GFW伪造了一个虚假数据给我们.因为无论是根域服务器,还是顶级域服务器,都不可能去记录并返回一个单独域名的 A记录,他们只返回下一级名称服务器的列表.

5.为什么会产生两种不同的劫持阶段,我猜测有以下几种可能:

A.GFW对根域服务器的查询相对劫持密度较低,有可能漏网,这个可能性似乎不大,因为劫持密度这种事很难控制.

B.根域服务器在中国是有镜像的,肯定也在同样的运用GSLB技术或其他类似的技术,因为根域服务器的负载是非常庞大的,而且基于全球网络速度的考虑,不做这种动态分配几乎不可能.那么在国内向一个美国IP发起的查询,实际上可能最终是被指向了位于中国的根镜像服务器,而GFW对境内的根域镜像查询是不会有劫持的.而查询根域服务器是,到底是被指向国内镜像还是国外镜像,这个过程是有随机性的

C.而.com顶级域名称服务器全部在国外,所以查询到这一步的时候劫持一定会发生.

按理说这个过程的逻辑有很明显的问题,但这个返回从DNS协议上并不违法,所以还是会被DNS服务器接受.我们可以继续做如下测试:

Case 8:国内网络+根域服务器(192.112.36.4#53(g.root-servers.net))

还是有两种包:


$ dig twitter.com +trace @192.112.36.4

; <<>> DiG 9.9.5 <<>> twitter.com +trace @192.112.36.4
;; global options: +cmd
.                       518400  IN      NS      j.root-servers.net.
.                       518400  IN      NS      e.root-servers.net.
.                       518400  IN      NS      f.root-servers.net.
.                       518400  IN      NS      i.root-servers.net.
.                       518400  IN      NS      b.root-servers.net.
.                       518400  IN      NS      a.root-servers.net.
.                       518400  IN      NS      d.root-servers.net.
.                       518400  IN      NS      h.root-servers.net.
.                       518400  IN      NS      c.root-servers.net.
.                       518400  IN      NS      l.root-servers.net.
.                       518400  IN      NS      m.root-servers.net.
.                       518400  IN      NS      g.root-servers.net.
.                       518400  IN      NS      k.root-servers.net.
.                       518400  IN      RRSIG   NS 8 0 518400 20140801000000 20140724230000 8230 . V2ec5SXGvaXaRofv9WZo5BnSHdy8dYoSxSDPcdqDWuuEcp7K0/32Myo/ DLHv8rfkqU2Z7ekKQr/jLXCHUhAJdtd5bT7hBF65nOaqgQ6ukn/mzRSz GySlpOMEgkq81ezEvx0u19omi1jUvTmb6qL2aNh92VY4qi9HWHIcS3s7 ssE=
;; Received 913 bytes from 192.112.36.4#53(192.112.36.4) in 235 ms

com.                    172800  IN      NS      g.gtld-servers.net.
com.                    172800  IN      NS      a.gtld-servers.net.
com.                    172800  IN      NS      e.gtld-servers.net.
com.                    172800  IN      NS      m.gtld-servers.net.
com.                    172800  IN      NS      b.gtld-servers.net.
com.                    172800  IN      NS      h.gtld-servers.net.
com.                    172800  IN      NS      j.gtld-servers.net.
com.                    172800  IN      NS      d.gtld-servers.net.
com.                    172800  IN      NS      k.gtld-servers.net.
com.                    172800  IN      NS      l.gtld-servers.net.
com.                    172800  IN      NS      f.gtld-servers.net.
com.                    172800  IN      NS      c.gtld-servers.net.
com.                    172800  IN      NS      i.gtld-servers.net.
com.                    86400   IN      DS      30909 8 2 E2D3C916F6DEEAC73294E8268FB5885044A833FC5459588F4A9184CF C41A5766
com.                    86400   IN      RRSIG   DS 8 1 86400 20140801000000 20140724230000 8230 . bbA/MlsqggckMvCojgBBoTUao4+bqEX3PE6wo4Vbttp9Sfk92XkTZmRd f9Ae70pfM4VDMXVpfTFnybqfXVv6IdJCT+v06M3GLXGGI5qeOh4fGpu5 dujmX9r4mhG4lGOH+dLJt7MvGZ4BvloHSNhOci2/qFDq4lVpdE8I5OHu SHg=
;; Received 735 bytes from 192.58.128.30#53(j.root-servers.net) in 35 ms

twitter.com.            35707   IN      A       59.24.3.173
;; Received 45 bytes from 192.55.83.30#53(m.gtld-servers.net) in 35 ms


劫持发生在对.com顶级域名称服务器的查询过程中.


$ dig twitter.com @192.112.36.4

; <<>> DiG 9.9.5 <<>> twitter.com @192.112.36.4
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 60646
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0

;; QUESTION SECTION:
;twitter.com.                   IN      A

;; ANSWER SECTION:
twitter.com.            300     IN      A       37.61.54.158

;; Query time: 53 msec
;; SERVER: 192.112.36.4#53(192.112.36.4)
;; WHEN: 周六 7月 26 13:16:56     2014
;; MSG SIZE  rcvd: 56


劫持发生在对根域服务器的查询过程中.

Case 9:国内网络+.com顶级域名称服务器(192.12.94.30#53(e.gtld-servers.net))


$ dig twitter.com @192.12.94.30

; <<>> DiG 9.9.5 <<>> twitter.com @192.12.94.30
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 7529
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0

;; QUESTION SECTION:
;twitter.com.                   IN      A

;; ANSWER SECTION:
twitter.com.            300     IN      A       37.61.54.158

;; Query time: 38 msec
;; SERVER: 192.12.94.30#53(192.12.94.30)
;; WHEN: 周六 7月 26 13:18:49     2014
;; MSG SIZE  rcvd: 56


直接返回劫持的IP.

Case 10:国内网络+twitter.com的权威服务器(208.78.71.34#53(ns3.p34.dynect.net)


$ dig twitter.com @208.78.71.34

; <<>> DiG 9.9.5 <<>> twitter.com @208.78.71.34
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 7729
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0

;; QUESTION SECTION:
;twitter.com.                   IN      A

;; ANSWER SECTION:
twitter.com.            31524   IN      A       59.24.3.173

;; Query time: 12 msec
;; SERVER: 208.78.71.34#53(208.78.71.34)
;; WHEN: 周六 7月 26 13:20:04     2014
;; MSG SIZE  rcvd: 45


直接返回劫持的IP.

如果我们用iptables挡掉劫持的数据包呢?

Case 11:国内网络+114DNS+trace+iptalbes过滤

使用iptables+trace的时候,请一定先禁用之前文章中提到的对付GFW空包劫持的iptables命令,否则会造成命令的阻塞.


$ dig +trace twitter.com @114.114.114.114

; <<>> DiG 9.9.5 <<>> +trace twitter.com @114.114.114.114
;; global options: +cmd
.                       178646  IN      NS      f.root-servers.net.
.                       178646  IN      NS      e.root-servers.net.
.                       178646  IN      NS      d.root-servers.net.
.                       178646  IN      NS      c.root-servers.net.
.                       178646  IN      NS      g.root-servers.net.
.                       178646  IN      NS      a.root-servers.net.
.                       178646  IN      NS      j.root-servers.net.
.                       178646  IN      NS      h.root-servers.net.
.                       178646  IN      NS      b.root-servers.net.
.                       178646  IN      NS      m.root-servers.net.
.                       178646  IN      NS      l.root-servers.net.
.                       178646  IN      NS      k.root-servers.net.
.                       178646  IN      NS      i.root-servers.net.
;; Received 239 bytes from 114.114.114.114#53(114.114.114.114) in 169 ms

com.                    172800  IN      NS      g.gtld-servers.net.
com.                    172800  IN      NS      b.gtld-servers.net.
com.                    172800  IN      NS      e.gtld-servers.net.
com.                    172800  IN      NS      c.gtld-servers.net.
com.                    172800  IN      NS      k.gtld-servers.net.
com.                    172800  IN      NS      i.gtld-servers.net.
com.                    172800  IN      NS      j.gtld-servers.net.
com.                    172800  IN      NS      l.gtld-servers.net.
com.                    172800  IN      NS      f.gtld-servers.net.
com.                    172800  IN      NS      h.gtld-servers.net.
com.                    172800  IN      NS      m.gtld-servers.net.
com.                    172800  IN      NS      d.gtld-servers.net.
com.                    172800  IN      NS      a.gtld-servers.net.
com.                    86400   IN      DS      30909 8 2 E2D3C916F6DEEAC73294E8268FB5885044A833FC5459588F4A9184CF C41A5766
com.                    86400   IN      RRSIG   DS 8 1 86400 20140802000000 20140725230000 8230 . HS07Hkll7EGhVOpSWr2/5l96vk+1Utt1jYFy1rk71LEH5TNN9VFGBQDh vXFBSj3qf5EaRySrZkp4DfSFUq56BXSbz+ng5i/fQ4YH/g4TtTltPa9Q pVgOzRYU6VkWKQPF18e5+gLaBtI+EWbMq2RKEaLTvYIhibmQJgp4IJ05 OrA=
;; Received 735 bytes from 192.58.128.30#53(j.root-servers.net) in 157 ms

twitter.com.            172800  IN      NS      ns1.p34.dynect.net.
twitter.com.            172800  IN      NS      ns2.p34.dynect.net.
twitter.com.            172800  IN      NS      ns3.p34.dynect.net.
twitter.com.            172800  IN      NS      ns4.p34.dynect.net.
CK0POJMG874LJREF7EFN8430QVIT8BSM.com. 86400 IN NSEC3 1 1 0 - CK0QFMDQRCSRU0651QLVA1JQB21IF7UR NS SOA RRSIG DNSKEY NSEC3PARAM
CK0POJMG874LJREF7EFN8430QVIT8BSM.com. 86400 IN RRSIG NSEC3 8 2 86400 20140801044838 20140725033838 6122 com. e+3YxNuU3CxSkKOcFCwFr6MlzBuwGOB8/1+8/VNIV3JIbNdH1cospOxy MfxwJiY/LVL1tpeH+lSIybBcLtR9KdVawVMDRndQINNCYFK8nDRSJNdL c1PCpk7FF6gm+bGrTEXEpPvgvlklc/+ClFCtQFywiIFiBr5ea7chYZkV iIg=
7T78ED4VO4I3CTH3UHB6FITOQRR1DO4J.com. 86400 IN NSEC3 1 1 0 - 7T7E58K6BTE54RNTMBLJPP0BU6Q7D68C NS DS RRSIG
7T78ED4VO4I3CTH3UHB6FITOQRR1DO4J.com. 86400 IN RRSIG NSEC3 8 2 86400 20140731043311 20140724032311 6122 com. 1Rng0qrC511J/mnyfsq27KA47ciAOFKoWo+fiYrWyjXoGoxnE6bY/lbR 8La9yoIdtoEJix5CIciSYASWPYbw5tUkNbW2GcEvZZh1bclulHTC3D/m PR8SxPjzi4O/grjDne0SxDDUhl80XE2Tf86w0wCcNaRZrHlXd12cqN0e Tp0=
;; Received 675 bytes from 192.55.83.30#53(m.gtld-servers.net) in 287 ms

twitter.com.            30      IN      A       199.59.148.10
twitter.com.            30      IN      A       199.59.148.82
twitter.com.            30      IN      A       199.59.150.39
twitter.com.            30      IN      A       199.59.149.230
twitter.com.            86400   IN      NS      ns4.p34.dynect.net.
twitter.com.            86400   IN      NS      ns3.p34.dynect.net.
twitter.com.            86400   IN      NS      ns2.p34.dynect.net.
twitter.com.            86400   IN      NS      ns1.p34.dynect.net.
;; Received 190 bytes from 204.13.250.34#53(ns2.p34.dynect.net) in 205 ms


可以看到,只要挡掉了劫持包,从本地发起的一级级迭代查询是完全可以获得正确的数据的.在必要的时刻,我们仅凭借iptables过滤规则+根域服务器+dig+trace就可以获得任何一个域名的正确IP,而不需要依赖任何DNS服务器,因为我们的机器自己做迭代查询的时候就是一台DNS服务器.

那么,GFW对境外DNS的查询劫持,是针对某台服务器进行的吗?

Case 12:国内环境+其他境外IP

我在一个美国的VPS上随便搭了个Dnsmasq的DNS服务器(其实应该叫转发器),在国内查询看看:


$ dig twitter.com @23.29.125.143

; <<>> DiG 9.9.5 <<>> twitter.com @23.29.125.143
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 53217
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0

;; QUESTION SECTION:
;twitter.com.                   IN      A

;; ANSWER SECTION:
twitter.com.            300     IN      A       37.61.54.158

;; Query time: 4 msec
;; SERVER: 23.29.125.143#53(23.29.125.143)
;; WHEN: 周六 7月 26 14:36:01     2014
;; MSG SIZE  rcvd: 56


很牛逼,在你们看到这篇文章之前没人知道我在这个IP上有DNS服务,难道GFW有这么智能,是个DNS都能发现?更奇葩的是,在我关闭了服务器上的Dnsmasq服务器之后,别的域名都查询不到了,在查询twitter.com这些污染域名的时候还是会返回污染的IP.

然后我随便挑了个可能根本没有服务器在运作的国外IP,结果也是会返回污染IP:


$ dig twitter.com @4.8.8.18

; <<>> DiG 9.9.5 <<>> twitter.com @4.8.8.18
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 10926
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0

;; QUESTION SECTION:
;twitter.com.                   IN      A

;; ANSWER SECTION:
twitter.com.            300     IN      A       37.61.54.158

;; Query time: 87 msec
;; SERVER: 4.8.8.18#53(4.8.8.18)
;; WHEN: 周六 7月 26 14:43:44     2014
;; MSG SIZE  rcvd: 56


leavi_000@Cartman-Asus /home/leavi_000
$ dig taobao.com @4.8.8.18

; <<>> DiG 9.9.5 <<>> taobao.com @4.8.8.18
;; global options: +cmd
;; connection timed out; no servers could be reached



总结
1.对于国内很多ISP的不支持递归查询的DNS服务器,因为无法跟踪其记录的来源,我只能猜测是政策性的投毒污染.例如指定他们从特定的DNS服务器进行Zone Transfer取得数据,而这些数据就是已经被污染的数据.因为这些DNS的数据取得,依赖于定期的从上级DNS进行ZoneTransfer而不是递归查询,所以一个很明显的特征是,当域名的A记录变化时,他们的更新往往都是非常慢的.

2.对于114和阿里DNS这类支持递归查询的DNS,GFW对付的方法和对付普通网民使用境外DNS的方法是一样的,也就是对所有向境外服务器发起的针对特定域名的DNS解析请求全部劫持.虽然我觉得他们肯定有更高级的设备,但如果真的要用iptables来干这个活也挺容易的.

这样114之类的DNS就和普通网民一样无法获得正确的解析结果了,一旦GFW劫持的结果进入114DNS的缓存里(而且几乎肯定会进入),对普通网民来说就是一个DNS缓存投毒了.

3.114这类DNS如果真的想避免劫持,可以类似的采用iptables过滤,或者对特定域名的解析交给他们在海外的节点去处理,然后通过相对安全的走TCP的ZoneTransfer交回到国内节点,不过他们未必有这样的动机.毕竟国内干净的私人DNS也不少,他们要真想做早就可以实现了.

没有评论:

发表评论