1 序章#
前段时间,坐飞机从加拿大飞回香港,全程大概12个小时,坐的是加拿大航空(Air Canada)的飞机。
有趣的是,飞机上竟然有 Wifi:
但是 Wifi 做了限制,对于Aeroplan的会员,如果未付费,就只提供 Free Texting 的功能,即只能使用即时通信软件,比如 Whatsapp, Snapchat,微信发送文本信息,但无法访问其他网站。
如果想要无限制地访问其他网站,那么就是付 30.75 加元;
如果想要在飞机上看视频,那么就是付 39 加元;
我就在想,对于 Free Texting 服务,我是否可以绕过只能使用即时软件的限制,无限制地访问其他网站呢?
即相当于还是免费会员,但是可以享受30.75加元付费用户的服务,反正长途漫漫,总要找点有趣的事情消磨一下12个小时的时间。
又因为可以使用微信的文字聊天服务,那么我还可以在天上呼叫外援来帮忙一起处理,而我的室友恰好是个安全+网络专家,
当时在家休假,我一提这个想法,他觉得好玩就一拍即合,我们就直接地空连线开搞。
2 流程#
在飞机上选择完 acwifi.com 这个唯一的 wifi 后,就像其他需要登录的Wifi一样,会弹出一个 acwifi.com 的网页,要求验证我的 Aeroplan 会员的身份,验证通过之后即可上网。
有个非常经典的软件开发面试题:在浏览器输入一个网址之后,按下回车键之后,会发生什么事情。
比如输入的是 https://acwifi.com, 如果只关注的网络请求部分,整个过程大概是:DNS查询 -> TCP连接 -> TLS握手 -> HTTP请求与响应
我们把需要访问的目标网站当作是 github.com, 现在就来看下要怎么才能突破网络的限制,成功访问 github.com
3 思路1: 伪装域名#
既然 acwifi.com 可以访问,而 github.com 不可以访问,那么是否有可能是网络在DNS服务器做了限制,只解析白名单内的域名(即时通信的域名)
如果是这种情况的话,那么我是否可以修改 =/etc/host=,把我的服务器伪装成 acwifi.com, 所有的请求流量都经过我的服务器,再去请求目标网站(github.com) 如:
想法大概是我修改DNS记录,把我们的代理服务器的IP 137.184.231.87
绑定到 acwifi.com
上,因为本地的 /etc/host
的优先级是高于DNS服务器的,然后再用证书进行自签名,告诉浏览器,这个IP 和这个域名是绑定的,你要相信它。
我先验证下一个想法:
1
2
3
4
5
6
7
8
9
10
| > ping 137.184.231.87
PING 137.184.231.87 (137.184.231.87): 56 data bytes
Request timeout for icmp_seq 0
Request timeout for icmp_seq 1
Request timeout for icmp_seq 2
Request timeout for icmp_seq 3
Request timeout for icmp_seq 4
^C
--- 137.184.231.87 ping statistics ---
6 packets transmitted, 0 packets received, 100.0% packet loss
|
只是没想到,IP直接 ping
不通,相当于是IP大概率直接就连不上了。
试了下其他的著名IP,比如 Cloudflare 的CDN IP, 也是连不通:
1
2
3
4
5
6
7
8
9
10
| > ping 172.67.133.121
PING 172.67.133.121 (172.67.133.121): 56 data bytes
Request timeout for icmp_seq 0
Request timeout for icmp_seq 1
Request timeout for icmp_seq 2
Request timeout for icmp_seq 3
Request timeout for icmp_seq 4
^C
--- 172.67.133.121 ping statistics ---
6 packets transmitted, 0 packets received, 100.0% packet loss
|
看来这条路子是走不通的,这个思路只有满足两个条件才能走得通:
- texting only 的限制是在DNS 解析时做的,只有特定的域名(比如WhatsApp, 微信的域名)才会被解析 (这样的维护成本比较低)
- 网关允许任意的IP发起网络请求
但实际是IP都直接拦截了,怎么伪装都没有用了,这个网络大概率维护了某个IP白名单(比如WhatsApp,微信的出口IP),
只有在白名单的IP才可以访问。
4 思路2: 53端口伪装DNS#
在第一条路子走不通的时候,室友提供了第二条路子:尝试利用DNS服务作为突破口:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
| > dig http418.org
; <<>> DiG 9.10.6 <<>> http418.org
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 64160
;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;http418.org. IN A
;; ANSWER SECTION:
http418.org. 300 IN A 172.67.133.121
http418.org. 300 IN A 104.21.5.131
;; Query time: 3288 msec
;; SERVER: 172.19.207.1#53(172.19.207.1)
;; WHEN: Sat Oct 04 14:18:24 PDT 2025
;; MSG SIZE rcvd: 94
|
这是个好消息,说明还是有路子可以请求到外部网络的,DNS就是其中一个路子。
看上面的记录,说明我们查询 http418.org
这个网站的DNS 纪录成功,也就意味着DNS请求是成功的。
4.1 任意DNS服务器#
室友再随意找了个 DNS 服务器,看下这个网络是否对DNS服务器有白名单:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| > dig @40.115.144.198 http418.org
; <<>> DiG 9.10.6 <<>> @40.115.144.198 http418.org
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 58958
;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1224
;; QUESTION SECTION:
;http418.org. IN A
;; ANSWER SECTION:
http418.org. 275 IN A 104.21.5.131
http418.org. 275 IN A 172.67.133.121
;; Query time: 1169 msec
;; SERVER: 40.115.144.198#53(40.115.144.198)
;; WHEN: Sat Oct 04 14:24:25 PDT 2025
;; MSG SIZE rcvd: 72
|
竟然可以使用任意的DNS服务器,机会又大了不少
4.2 TCP查询#
任意的DNS服务器都能请求成功, 这就是个非常好的消息, DNS 默认是走的UDP 协议,那么走TCP 协议的DNS请求是否会被拦截呢?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| > dig @40.115.144.198 http418.org +tcp
; <<>> DiG 9.10.6 <<>> @40.115.144.198 http418.org +tcp
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 30355
;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1224
;; QUESTION SECTION:
;http418.org. IN A
;; ANSWER SECTION:
http418.org. 36 IN A 172.67.133.121
http418.org. 36 IN A 104.21.5.131
;; Query time: 4679 msec
;; SERVER: 40.115.144.198#53(40.115.144.198)
;; WHEN: Sat Oct 04 14:28:24 PDT 2025
;; MSG SIZE rcvd: 72
|
DNS TCP查询也能通过!这说明飞机网络的过滤策略相对宽松,为我们后续的DNS隧道方案提供了可能性。
4.3 53端口的代理服务#
说明飞机网络限制也不是完全密不透风的,我们发现这堵墙上有个「狗洞」。
那么我们就有了个巧妙的想法:既然飞机网关对DNS请求没有拦截,那么理论上我们可以把代理服务器伪装成DNS服务器,
暴露DNS服务的53端口,所有的请求都经过代理服务器,伪装成 DNS 请求,那么就可以绕过拦截了。
舍友就用 xray 服务花费了一个小时,架设了一个暴露 53 端口的代理服务器,把配置信息通过微信发给我:
室友用Xray搭建的代理服务器配置包含了如下的示意配置:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
| {
"outbounds": [
{
"tag": "proxy",
"protocol": "vless",
"settings": {
"vnext": [
{
"address": "our-proxy-server-domain",
"port": 53,
"users": [
{
"id": "some-uuid",
"flow": "xtls-rprx-vision",
"encryption": "none",
"level": 0
}
]
}
]
},
"streamSettings": {
"network": "tcp",
"security": "tls",
"tlsSettings": {
"allowInsecure": false,
"allowInsecureCiphers": false,
"alpn": [
"h2"
]
}
}
},
{
"tag": "direct",
"protocol": "freedom"
},
{
"tag": "block",
"protocol": "blackhole"
}
]
}
|
而我电脑上就有个 xray 的客户端,不需要额外的软件就能建立连接。
万事具备,激动人力的时刻到了,按下回车,访问 github.com
:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
| /Users/ramsayleung [ramsayleung@ramsayleungs-Laptop] [18:28]
> curl -v github.com -x socks5://127.0.0.1:10810
* Trying 127.0.0.1:10810...
* Connected to 127.0.0.1 (127.0.0.1) port 10810
* SOCKS5 connect to 172.19.1.1:80 (locally resolved)
* SOCKS5 request granted.
* Connected to 127.0.0.1 (127.0.0.1) port 10810
> GET / HTTP/1.1
> Host: github.com
> User-Agent: curl/8.4.0
> Accept: */*
>
< HTTP/1.1 301 Moved Permanently
< Content-Length: 0
< Location: https://github.com/
<
* Connection #0 to host 127.0.0.1 left intact
/Users/ramsayleung [ramsayleung@ramsayleungs-Laptop] [18:28]
> curl -v github.com -x socks5://127.0.0.1:10810
* Trying 127.0.0.1:10810...
* Connected to 127.0.0.1 (127.0.0.1) port 10810
* SOCKS5 connect to 172.19.1.1:80 (locally resolved)
* SOCKS5 request granted.
* Connected to 127.0.0.1 (127.0.0.1) port 10810
> GET / HTTP/1.1
> Host: github.com
> User-Agent: curl/8.4.0
> Accept: */*
>
< HTTP/1.1 301 Moved Permanently
< Content-Length: 0
< Location: https://github.com/
<
* Connection #0 to host 127.0.0.1 left intact
|
竟然请求成功了,github.com返回成功结果啦!
这意味着我们真的破解网络的限制,可以访问任意的网站啦!
此次,我们之前并没有意识到 xray 还有此种妙用 :)
这里我们就利用了一个简单的思维惯性:不是所有使用53端口的服务都是DNS查询请求。
5 终极思路: DNS Tunnel#
如果思路2还是无法成功,我们还有一个终极大招可以用。
现在网关是只通过端口是否是53来判断是否是DNS请求,
但是如果网关更严格一些,比如检查DNS请求包的内容,就会发现我们的请求是「伪装」成DNS查询请求,而非真正的DNS查询请求:
既然伪装的DNS请求会被拦截掉,那么我们就把所有请求都塞成DNS请求包里面,做成DNS TXT query,我真的是要查 DNS 了,只是还在里面加了些料:
但是这个终极方案需要有一个DNS Tunnel 的客户端来把所有的请求都封装起来,我电脑里面没有这样的软件,所以这个就变成理论上的终极方案,实际也无法验证。
6 结语#
长途漫漫,我和室友花费了大概4个小时的时间远程把网络限制给破解了,玩得不亦乐乎,证明我们解决问题的思路着实是可行的。
方案能最后实施成功,主要是归功于我室友这个网络专家,远程连线提供技术和思路支持。
美中不足的是,虽然我们破解了网络限制,可以访问任意网站,但是飞机上的带宽实在是太小的,
打开网页实在是费劲,所以我也没有花太多时间上网冲浪。
剩下的几个小时时间,我是重温了一下八十年代的经典穿越科幻电影:《回到未来(Back to Future)》三部曲,相当好看.
最后,我在此严正声明:
这种技术探索仅限于学习和研究目的,我们严格遵守相关规定和服务条款。
推荐阅读#

公号同步更新,欢迎关注👻