小技巧:使用 DNS 请求查询公网 IP 地址

发现了一个小技巧:通过谷歌域名服务器查询公网 IP 地址。

虽然没有什么实用性,还是写下来了。


具体命令如下:

dig TXT o-o.myaddr.l.google.com @ns1.google.com

这条命令调用digns1.google.com查询o-o.myaddr.l.google.com域名的 TXT 记录。


命令执行结果如下:

$ dig TXT o-o.myaddr.l.google.com @ns1.google.com

; <<>> DiG 9.10.3-P4-Ubuntu <<>> TXT o-o.myaddr.l.google.com @ns1.google.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 28162
;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
;; WARNING: recursion requested but not available

;; QUESTION SECTION:
;o-o.myaddr.l.google.com.	IN	TXT

;; ANSWER SECTION:
o-o.myaddr.l.google.com. 60	IN	TXT	"183.4x.xxx.xxx"

;; Query time: 47 msec
;; SERVER: 216.239.32.10#53(216.239.32.10)
;; WHEN: Fri May 18 13:50:14 CST 2018
;; MSG SIZE  rcvd: 68

添加+short参数可以简短地显示结果:

$ dig +short TXT o-o.myaddr.l.google.com @ns1.google.com
"183.4x.xxx.xxx"

上面的"183.4x.xxx.xxx"就是本机的公网 IP 地址:

$ curl ip.cn
IP:183.4x.xxx.xxx 来自:广东省 电信

同时支持 IPv6:

$ dig TXT o-o.myaddr.l.google.com @ns1.google.com

; <<>> DiG 9.10.3-P4-Ubuntu <<>> TXT o-o.myaddr.l.google.com @ns1.google.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 18097
;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
;; WARNING: recursion requested but not available

;; QUESTION SECTION:
;o-o.myaddr.l.google.com.	IN	TXT

;; ANSWER SECTION:
o-o.myaddr.l.google.com. 60	IN	TXT	"2001:da8:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx"

;; Query time: 113 msec
;; SERVER: 2001:4860:4802:32::a#53(2001:4860:4802:32::a)
;; WHEN: Fri May 18 14:03:10 CST 2018
;; MSG SIZE  rcvd: 92


o-o.myaddr.l.google.com是一个特殊的域名,该域名的 DNS 记录不是固定的。负责解析该域名的谷歌域名服务器将请求者的公网 IP 地址放入 TXT 记录中,请求者可以向谷歌域名服务器查询该记录,因而获取自己的 IP 地址。(注意,这里请求的是TXT 记录,而不是常见的 A 记录或者 AAAA 记录)

这里的“谷歌域名服务器”是指专门负责解析各种谷歌域名(如.google.com.youtube.com等)的 DNS 服务器,不是Google Public DNS(即8.8.8.88.8.4.4):

$ dig +short NS google.com @8.8.8.8
ns4.google.com.
ns3.google.com.
ns2.google.com.
ns1.google.com.

可以用公共 DNS 服务器解析域名。这时结果不是本机公网 IP,而是发起解析请求的 DNS 服务器节点 IP:

$ dig TXT o-o.myaddr.l.google.com @114.114.114.114

; <<>> DiG 9.10.3-P4-Ubuntu <<>> TXT o-o.myaddr.l.google.com @114.114.114.114
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 36600
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0

;; QUESTION SECTION:
;o-o.myaddr.l.google.com.	IN	TXT

;; ANSWER SECTION:
o-o.myaddr.l.google.com. 60	IN	TXT	"61.140.11.97"

;; Query time: 140 msec
;; SERVER: 114.114.114.114#53(114.114.114.114)
;; WHEN: Fri May 18 14:04:43 CST 2018
;; MSG SIZE  rcvd: 66

上面使用的是114DNS。其中61.140.11.97114DNS电信节点的 IP 地址。

如果公共 DNS 服务器支持ECS(即edns-client-subnet)协议,返回的结果包含ECS信息。

使用支持ECS协议的Google Public DNS的查询结果:

$ dig TXT o-o.myaddr.l.google.com @8.8.8.8

; <<>> DiG 9.10.3-P4-Ubuntu <<>> TXT o-o.myaddr.l.google.com @8.8.8.8
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 46029
;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 512
;; QUESTION SECTION:
;o-o.myaddr.l.google.com.	IN	TXT

;; ANSWER SECTION:
o-o.myaddr.l.google.com. 59	IN	TXT	"173.194.171.14"
o-o.myaddr.l.google.com. 59	IN	TXT	"edns0-client-subnet 183.4x.xxx.0/24"

;; Query time: 95 msec
;; SERVER: 8.8.8.8#53(8.8.8.8)
;; WHEN: Fri May 18 14:06:01 CST 2018
;; MSG SIZE  rcvd: 135

edns0-client-subnet 183.4x.xxx.0/24即是dig查询记录时,向Google Public DNS发送的ECS信息。

可以使用dig+subnet参数手动设置ECS信息:

$ dig +subnet=114.114.114.114/32 TXT o-o.myaddr.l.google.com @8.8.8.8

; <<>> DiG 9.10.3-P4-Ubuntu <<>> +subnet=114.114.114.114 TXT o-o.myaddr.l.google.com @8.8.8.8
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 61831
;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 512
; CLIENT-SUBNET: 114.114.114.114/32/0
;; QUESTION SECTION:
;o-o.myaddr.l.google.com.	IN	TXT

;; ANSWER SECTION:
o-o.myaddr.l.google.com. 59	IN	TXT	"173.194.171.14"
o-o.myaddr.l.google.com. 59	IN	TXT	"edns0-client-subnet 114.114.114.0/24"

;; Query time: 194 msec
;; SERVER: 8.8.8.8#53(8.8.8.8)
;; WHEN: Fri May 18 14:09:45 CST 2018
;; MSG SIZE  rcvd: 139


另外,OpenDNS也有一个有类似作用的域名:

dig myip.opendns.com @resolver1.opendns.com

结果如下:

$ dig myip.opendns.com @resolver1.opendns.com

; <<>> DiG 9.10.3-P4-Ubuntu <<>> myip.opendns.com @resolver1.opendns.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 8498
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

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

;; ANSWER SECTION:
myip.opendns.com.	0	IN	A	183.4x.xxx.xxx

;; Query time: 45 msec
;; SERVER: 208.67.222.222#53(208.67.222.222)
;; WHEN: Fri May 18 14:16:33 CST 2018
;; MSG SIZE  rcvd: 61

这个域名会将 IP 地址直接放入 A 记录中,所以只允许OpenDNS的域名服务器解析该域名。