如何判断域名是否被污染

日期: 08 月 24日, 2014
标签:

Update 2017-11-15: 修复脚本

DNS 污染是指一些伪造的 DNS 请求,把域名指往不正确的 IP 地址。DNS 污染是国内某知名互联网服务的主要手段之一(其他手段包括 IP 封锁,端口封锁,TCP 连接重置等)。那么,如何判断一个域名是否被污染了呢?

DNS 污染的原理

DNS 设计是有缺陷的:

  1. 数据都是明文的,可以轻松嗅探
  2. 缺乏验证机制,无法识别虚假的 DNS 回应

只要做关键字匹配,发送虚假 DNS 查询结果即可。

dig twitter.com

; <<>> DiG 9.9.2-P2 <<>> twitter.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 3709
;; 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.		300	IN	A	37.61.54.158

;; Query time: 38 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: Wed Aug 27 00:13:43 2014
;; MSG SIZE  rcvd: 56

判断域名是否被污染

墙在做 DNS 污染时是很粗暴的,只要关键字匹配,一律发送虚假的 A 记录。例如,thisisnottwitter.com 这个域名并不存在,但依然被污染了:

dig @a.root-servers.net. thisisnottwitter.com

; <<>> DiG 9.9.2-P2 <<>> @a.root-servers.net. thisisnottwitter.com
; (2 servers found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 28008
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0

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

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

;; Query time: 128 msec
;; SERVER: 198.41.0.4#53(198.41.0.4)
;; WHEN: Wed Aug 27 00:14:47 2014
;; MSG SIZE  rcvd: 74

事实上,根据 DNS 协议,根 DNS 服务器应该返回的是 com. 的权威域,不可能返回 A 记录。正确的回应应该是这样的:

dig @a.root-servers.net. thisisnottwitter.com

; <<>> DiG 9.8.2rc1-RedHat-9.8.2-0.23.rc1.el6_5.1 <<>> @a.root-servers.net. thisisnottwitter.com
; (2 servers found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 23058
;; flags: qr rd; QUERY: 1, ANSWER: 0, AUTHORITY: 13, ADDITIONAL: 14
;; WARNING: recursion requested but not available

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

;; AUTHORITY SECTION:
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.

;; ADDITIONAL SECTION:
a.gtld-servers.net.	172800	IN	A	192.5.6.30
b.gtld-servers.net.	172800	IN	A	192.33.14.30
c.gtld-servers.net.	172800	IN	A	192.26.92.30
d.gtld-servers.net.	172800	IN	A	192.31.80.30
e.gtld-servers.net.	172800	IN	A	192.12.94.30
f.gtld-servers.net.	172800	IN	A	192.35.51.30
g.gtld-servers.net.	172800	IN	A	192.42.93.30
h.gtld-servers.net.	172800	IN	A	192.54.112.30
i.gtld-servers.net.	172800	IN	A	192.43.172.30
j.gtld-servers.net.	172800	IN	A	192.48.79.30
k.gtld-servers.net.	172800	IN	A	192.52.178.30
l.gtld-servers.net.	172800	IN	A	192.41.162.30
m.gtld-servers.net.	172800	IN	A	192.55.83.30
a.gtld-servers.net.	172800	IN	AAAA	2001:503:a83e::2:30

;; Query time: 122 msec
;; SERVER: 2001:503:ba3e::2:30#53(2001:503:ba3e::2:30)
;; WHEN: Wed Aug 27 00:15:38 2014
;; MSG SIZE  rcvd: 498

根据这一点即可判断某个域名是否被污染。写成 Bash 脚本如下:

#!/usr/bin/env bash

set -e

usage() {
    echo "Usage: $(basename $0) domain"
    echo "  -h, --help    Show this help"
}

isblocked() {
    if [[ $(dig @a.root-servers.net. ${1} | grep 'ANSWER SECTION') ]]; then
        return 0
    else
        return 1
    fi
}

set -e

[[ "$#" -eq 0 ]] && usage && exit 0


domain=$1

if isblocked "${domain}"; then
    echo "${domain} is polluted."
else
    echo "${domain} is not polluted."
fi