STUN内网穿透原理
🧑💻 User
nat stun是啥 为啥能行?
🤖 Assistant
你感到困惑是非常正常的。因为光看这几步,你可能会想:“我知道了自己的公网 IP 又怎样?外面的数据包想进来,NAT 路由器不是依然会拦住它吗?”
要理解 STUN 为什么有用,我们需要跳出这张图,看一看后续发生了什么。
我们可以把 STUN 的作用拆解为三个阶段:照镜子、打招呼、钻洞。
1. 照镜子(Discovery:发现自己是谁)
这是你图中显示的部分。
- 问题: 你的电脑只知道自己的私网 IP(比如
192.168.1.5),它不知道自己在互联网上“长什么样”。 - STUN 的作用: 它像一面镜子。你给 STUN 服务器发个包,服务器回信说:“嘿,我看你穿的衣服(公网IP)是
120.70.39.4,你的纽扣(端口)是5001。” - 结果: 你的电脑现在知道自己的“公网外壳”了。
2. 打招呼(Signaling:告诉对方我在哪)
这一步是图中没画出来,但至关重要的。
假设你想和你的朋友(Device B)进行视频通话:
- 你通过一个第三方服务器(比如微信服务器、Zoom 服务器,这叫信令服务器)发个消息给朋友。
- 消息内容是:“喂,我想跟你连线,我的公网地址是
120.70.39.4:5001,你直接往这个地址发数据吧!”
3. 钻洞(Hole Punching:核心原理)
这是最神奇的地方。为什么对方发数据到这个地址,NAT 路由器就会放行呢?
NAT 的特性: 当你的电脑给 STUN 服务器发送请求时,你的 NAT 路由器会在它的“记录本”上记下一行:
“本地
192.168.1.5:8888的人 刚才通过公网120.70.39.4:5001给外面发了数据,如果有回信传到这个公网端口,我就把它转交给那个人。”维持“洞口”: 虽然这个记录原本是为 STUN 服务器准备的,但在大多数常见的 NAT 类型(比如锥形 NAT)中,这个“洞”一旦打好,任何外网的人(包括你的朋友)只要往这个公网端口发数据,NAT 路由器都会认为这是“回信”,从而准许通过。
用一个生活中的类比
想象你在一个管理很严的大公司上班,公司有围墙(NAT),外人进不来。
- STUN(查号码): 你给外面的一个“查询台”打电话。查询台的来电显示看出了你的分机转接出去后的外线号码是
010-8888。 - 告知对方: 你发短信给你的客户(朋友):“你要找我就打
010-8888,我现在正守在电话旁。” - 钻洞: 因为你刚刚才用这个外线打过电话,公司的总机房(NAT 路由器)在短时间内会保持这个线路处于“激活”状态。
- 通话: 客户打过来,总机房一看:“哦,这个外线刚才那个小王用过,可能是客户回电”,于是就把电话转接给了你。
这就是 P2P(点对点)连接成功的关键。
但是!STUN 不是万能的
如果你的 NAT 路由器非常死板(叫做 对称型 NAT / Symmetric NAT,常见于大型企业内网):
- 它会规定:你刚才打给 STUN 服务器的洞,只能由 STUN 服务器回信。如果别人(你的朋友)想从这个洞进来,NAT 会直接拒绝。
在这种情况下,STUN 就失效了。这时就需要 Workaround 2:TURN(中继服务器)。TURN 就相当于:“算了,洞钻不开,我们找个中间人,我把数据发给中间人,中间人再转交给你。”
总结
STUN 之所以行得通,是因为它利用了 NAT 允许“回信”通过的机制。它先帮你探测出这个“回信通道”的公网坐标,然后你把这个坐标告诉朋友,让朋友伪装成“回信的人”把数据发给你。
🧑💻 User
所以就是故意暴露个公网Port任何人都能暂时发这个Port?
🤖 Assistant
你的理解已经非常接近核心了!但关于“任何人”这一点,取决于你家路由器的“脾气”(即 NAT 的类型)。
我们可以把这个过程细化为三个关键点:
1. 是的,你在路由器上“骗”出了一个洞
正常情况下,NAT 像一堵墙,外面的人主动敲门,它是不会开的。
但是,当你通过 STUN 给服务器发包时,路由器会想:“由于里屋的人(你的设备)主动给外面发了消息,我得在墙上开个临时的小窗口(Port),万一外面有回信,我好传回来。”
STUN 的精髓就是:利用这个“回信窗口”来做点对点(P2P)通信。
2. 真的是“任何人”都能发吗?(这是关键)
这就是 NAT 复杂的地方。根据安全级别,路由器对这个“小窗口”有不同的限制:
最宽松的情况(全圆锥型 NAT):
确实如你所说,只要你的电脑通过 STUN 测出了公网 IP 和端口,世界上任何一个人只要往这个端口发包,你的电脑都能收到。这种最容易实现 P2P。稍微严格一点(受限圆锥型 NAT)—— 最常见:
路由器会看一眼来信人的 IP。它会想:“里屋的人刚才只给 STUN 服务器(IP_A)发过信,如果现在有个陌生人(IP_B,也就是你的朋友)发信进来,我要不要拦住?”
解决方法: 你不仅要用 STUN 测地址,你还得主动给你朋友的 IP 发一个包(哪怕这个包会被对方的防火墙拦截也没关系)。一旦你主动发过包,你的路由器就会把你的朋友列入“白名单”,他发进来的包就能通过那个 Port 进来了。最严格的情况(对称型 NAT):
这种路由器非常死板。你给 STUN 服务器发包时,它开一个 Port;当你给朋友发包时,它会另外开一个全新的、不同的 Port。
这时候 STUN 就彻底没戏了,因为你告诉朋友的那个 Port,仅仅是给 STUN 服务器专用的。
3. “暂时”是多久?(Keep-alive)
你说得对,这个 Port 是临时的。如果长时间没有数据往来,路由器为了节省资源,会把这个映射关系删掉,洞就“堵上”了。
所以,为了让这个洞一直开着,应用程序(比如微信、腾讯会议)会每隔几十秒发一个极其微小的包(俗称 “心跳包” / Heartbeat),其目的就是告诉路由器:“这个洞我还在用,别把它关了。”
总结一下你的疑问
- 故意暴露: 是的,为了让对方能连上你,必须在 NAT 墙上凿开一个公网可见的端口。
- 任何人: 在多数家用路由器上,经过“打洞”操作后,确实允许特定的对方(或者任何人)访问。
- 暂时: 是的,必须通过持续的“心跳”来维持这个映射。
这就是为什么 P2P 下载(如迅雷、BitTorrent)或者腾讯会议、Zoom 能够不通过昂贵的服务器中转,直接让两台电脑互传数据的原因。
