Stun协议(Rfc3489、详见http://www.ietf.org/rfc/rfc3489.txt ) 提出了4种NAT类型的定义及其分类,
并给出了如何检测在用的NAT究竟属于哪种分类的标准。
但是,
具体到P2P程序如何应用Stun协议及其分类法穿越NAT,
则是仁者见仁、智者见智。
(因为Stun协议并没有给出也没有必要给出如何穿越NAT的标准)
在拙作“iptables与stun”一文中,
笔者花大幅精力阐述了iptables理论上属于Symmetric NAT而非Port Restricted Cone。
对此,
很多人(包括笔者最初学习Stun协议时)心中都有一个疑惑,
即仅就Stun协议本身来说,
Port Restricted Cone和Symmetric NAT的区别似乎不大,
虽然两者的映射机制是有点不同,
但他们都具有端口受限的属性。
初看起来,
这两者在穿越NAT方面的特性也差不多,
尤其是对于外部地址欲往NAT内部地址发包的情况。
既然如此,
又为何有必要把iptables分得这么清呢,
本文顺带解决了读者在这一方面的疑惑。
网站http://midcom-p2p.sourceforge.net/ 给出了P2P程序具体如何穿越NAT的一个思路,
并提供了一个P2P协议穿越NAT兼容性的测试工具natcheck。
让我们仍旧用实例(例1)来说明这一思路吧!
A机器在私网(192.168.0.4)
A侧NAT服务器(210.21.12.140)
B机器在另一个私网(192.168.0.5)
B侧NAT服务器(210.15.27.140)
C机器在公网(210.15.27.166)作为A和B之间的中介
A机器连接过C机器,
假使是 A(192.168.0.4:5000)-> A侧NAT(转换后210.21.12.140:8000)-> C(210.15.27.166:2000)
B机器也连接过C机器,
假使是 B(192.168.0.5:5000)-> B侧NAT(转换后210.15.27.140:8000)-> C(210.15.27.166:2000)
A机器连接过C机器后,
A向C报告了自己的内部地址(192.168.0.4:5000),
此时C不仅知道了A的外部地址(C通过自己看到的210.21.12.140:8000)、也知道了A的内部地址。
同理C也知道了B的外部地址(210.15.27.140:8000)和内部地址(192.168.0.5:5000)。
之后,
C作为中介,
把A的两个地址告诉了B,
同时也把B的两个地址告诉了A。
假设A先知道了B的两个地址,
则A从192.168.0.4:5000处同时向B的两个地址192.168.0.5:5000和210.15.27.140:8000发包,
由于A和B在两个不同的NAT后面,
故从A(192.168.0.4:5000)到B(192.168.0.5:5000)的包肯定不通,
现在看A(192.168.0.4:5000)到B(210.15.27.140:8000)的包,
分如下两种情况:
1、B侧NAT属于Full Cone NAT
则无论A侧NAT属于Cone NAT还是Symmetric NAT,
包都能顺利到达B。
如果P2P程序设计得好,
使得B主动到A的包也能借用A主动发起建立的通道的话,
则即使A侧NAT属于Symmetric NAT,
B发出的包也能顺利到达A。
结论1:只要单侧NAT属于Full Cone NAT,
即可实现双向通信。
2、B侧NAT属于Restricted Cone或Port Restricted Cone
则包不能到达B。
再细分两种情况
(1)、A侧NAT属于Restricted Cone或Port Restricted Cone
虽然先前那个初始包不曾到达B,
但该发包过程已经在A侧NAT上留下了足够的记录:A(192.168.0.4:5000)->(210.21.12.140:8000)->B(210.15.27.140:8000)。
如果在这个记录没有超时之前,
B也重复和A一样的动作,
即向A(210.21.12.140:8000)发包,
虽然A侧NAT属于Restricted Cone或Port Restricted Cone,
但先前A侧NAT已经认为A已经向B(210.15.27.140:8000)发过包,
故B向A(210.21.12.140:8000)发包能够顺利到达A。
同理,
此后A到B的包,
也能顺利到达。
结论2:只要两侧NAT都不属于Symmetric NAT,
也可双向通信。
换种说法,
只要两侧NAT都属于Cone NAT,
即可双向通信。
(2)、A侧NAT属于Symmetric NAT
因为A侧NAT属于Symmetric NAT,
且最初A到C发包的过程在A侧NAT留下了如下记录:A(192.168.0.4:5000)->(210.21.12.140:8000)-> C(210.15.27.166:2000),
故A到B发包过程在A侧NAT上留下的记录为:A(192.168.0.4:5000)->(210.21.12.140:8001)->B(210.15.27.140:8000)(注意,
转换后端口产生了变化)。
而B向A的发包,
只能根据C给他的关于A的信息,
发往A(210.21.12.140:8000),
因为A端口受限,
故此路不通。
再来看B侧NAT,
由于B也向A发过了包,
且B侧NAT属于Restricted Cone或Port Restricted Cone,
故在B侧NAT上留下的记录为:B(192.168.0.5:5000)->(210.15.27.140:8000)->A(210.21.12.140:8000),
此后,
如果A还继续向B发包的话(因为同一目标,
故仍然使用前面的映射),
如果B侧NAT属于Restricted Cone,
则从A(210.21.12.140:8001)来的包能够顺利到达B;如果B侧NAT属于Port Restricted Cone,
则包永远无法到达B。
结论3:一侧NAT属于Symmetric NAT,
另一侧NAT属于Restricted Cone,
也可双向通信。
显然,
还可得出另一个不幸的结论4,
两个都是Symmetric NAT或者一个是Symmetric NAT、另一个是Port Restricted Cone,
则不能双向通信。
上面的例子虽然只是分析了最初发包是从A到B的情况,
但是,
鉴于两者的对称性,
并且如果P2P程序设计得足够科学,
则前面得出的几条结论都是没有方向性,
双向都适用的。
通过上述分析,
我们得知,
在穿越NAT方面,
Symmetric NAT和Port Restricted Cone是有本质区别的,
尽管他们表面上看起来相似。
我们上面得出了四条结论,
而natcheck网站则把他归结为一条:只要两侧NAT都属于Cone NAT(含Full Cone、Restricted Cone和Port Restricted Cone三者),
即可双向通信。
而且natcheck网站还建议尽量使用Port Restricted Cone,
以充分利用其端口受限的属性确保安全性。
目前,
国内充分利用了上述思路的具有代表性的P2P软件是“E话通”(www.et66.com )。
在对natcheck提供的思路进行详细分析后,
开始探讨本文主题:iptables与natcheck。
Natcheck脱胎于Stun协议,
由拙作“iptables与stun”一文可知,
其对iptables进行的穿越NAT兼容性测试结果必然是GOOD。
此外,
我在该文中还提到一句,
如果在每个NAT后面仅有一个客户端这种特殊情况下,
iptables就是一个标准的Port restricted Cone。
根据前面natcheck的结论,
这样两个iptables后面的客户端应该可以互相穿越对方的NAT。
让我们来看一下实际情况(例2)呢?
仍然参考前例,
只是两侧都使用iptables来进行地址转换。
(因为采用了iptables,
故此处和前例稍有点区别,
即转换后源端口不变)
A与B通过C交换对方地址的初始化环节此处略去,
我们从A(192.168.0.4:5000)向B(210.15.27.140:5000)(注意因使用iptables而导致端口和前例不一样)发包开始分析,
因为在本例中,
两侧均只有一个客户端,
我们姑且把iptables简化成Port restricted Cone看待。
如前例一样,
从A(192.168.0.4:5000)到B(210.15.27.140: 5000)的第一个包必不能到达B,
但其会在A侧iptables上留下记录,
在这条记录没有超时之前(iptables下默认30秒),
如果B也向A(210.21.12.140:5000)发包,
如前所述,
按理该包应该能够到达A,
但事实上却是永远到不了。
难道是natcheck的结论错了,
或者是特殊情况下iptables并不是Port restricted Cone(即仍然是Symmetric NAT),
我们还是别忙着再下结论,
先来看看来两侧iptables上留下的记录吧:
A侧:cat /proc/net/ip_conntrack | grep 192.168.0.4 | grep udp
udp 17 18 src=192.168.0.4 dst=210.15.27.140 sport=5000 dport=5000 [UNREPLIED] src=210.15.27.140 dst=210.21.12.140 sport=5000 dport=5000 use=1
B侧:cat /proc/net/ip_conntrack | grep 192.168.0.5 | grep udp
udp 17 26 src=192.168.0.5 dst=210.21.12.140 sport=5000 dport=5000 [UNREPLIED] src=210.21.12.140 dst=210.15.27.140 sport=5000 dport=1026 use=1
把两条记录翻译如下:(关于ip_conntrack文件的分析,
请见http://www.sns.ias.edu/~jns/security/iptables/iptables_conntrack.html )
A(192.168.0.4:5000)-> A侧NAT(转换后210.21.12.140:5000)-> B(210.15.27.140:5000)
B(192.168.0.5:5000)-> B侧NAT(转换后210.15.27.140:1026)-> A(210.21.12.140:5000)
奇怪,
B到A的包在映射后源端口号怎么变了呢,
按理不应该呀?因为按照iptables转换原则(详见“iptables与stun”),
要求尽量保持源端口号不变,
除非socket有重复。
难道B侧NAT上还有重复记录,
再cat一下呢?
B侧:cat /proc/net/ip_conntrack | grep 210.21.12.140 | grep udp
udp 17 10 src=210.21.12.140 dst=210.15.27.140 sport=5000 dport=5000 [UNREPLIED] src=210.15.27.140 dst=210.21.12.140 sport=5000 dport=5000 use=1
udp 17 16 src=192.168.0.5 dst=210.21.12.140 sport=5000 dport=5000 [UNREPLIED] src=210.21.12.140 dst=210.15.27.140 sport=5000 dport=1026 use=1
操!还果真有两条差不多的记录,
第一条与NAT无关,
是A到B的包在B侧iptables上留下的记录,
产生时间上略早于第二条记录,
其构成的socket是(210.21.12.140:5000,
210.15.27.140:5000)。
第二条即B到A的包产生的记录,
其构成的socket是(210.15.27.140:1026,
210.21.12.140:5000),
如果其源端口不改动,
即是(210.15.27.140:5000,
210.21.12.140:5000),
还真和第一条记录重复了呢,
怪不得转换后需要修改源端口,
也怪不得B发包到不了A。
为什么是这样的结果呢?我们知道,
iptables是一个有状态的防火墙,
他通过连接跟踪模块来实现状态检测的功能,
该模块检查所有到来的数据包,
也就是说,
该模块不仅对NAT起作用,
而且对普通的包过滤也起作用。
显然,
在上述例子里,
A到B的包就是作为普通的包过滤而被记载在B侧iptables的连接跟踪表里,
导致后来B到A的包为避免socket重复而不得不改换端口号,
从而导致无法实现双向通信。
看来,
natcheck的结论并没有错,
只是由于iptables具有状态检测的新特性导致即使在特殊情况下iptables又从Port restricted Cone变成了Symmetric NAT而已。
那么,
有办法解决这一问题吗?根据连接跟踪的特性,
在iptables下,
只要启用了NAT,
就肯定要启用连接跟踪功能,
而只要启用了连接跟踪功能,
就必然顺带跟踪普通包过滤(启用连接跟踪后,
似乎无法控制不让跟踪普通包过滤),
也就是说,
只要用NAT,
就无法避免上述情况,
真残酷!然而,
这却是事实,
即只要两端都采用了iptables作为NAT,
则尽管两侧都通过了natcheck的兼容性测试,
但iptables两侧永远也不能互相穿越。
在“iptables与stun”一文中曾经附带提到,
Win2000下的ics或nat在Stun协议下的表现和iptables是完全一样的。
那么,
在natcheck下,
表现是否还一致呢?答案是否定的,
虽然Win2000下的ics或nat也具有状态检测的功能,
但该状态检测,
仅对NAT起作用,
不对普通包过滤起作用。
所以在两侧都是Win2000下的ics或nat可以作为Port restricted Cone的特殊情况下,
是允许被穿越的。
另外,
在一侧使用iptables,
另一侧使用Win2000下的ics或nat,
但两者都表现为Port restricted Cone的特殊情况下,
从某个方向发起,
最终是允许互相穿越的,
但是这种穿越不具有对称性,
即从另一个方向发起,
则永远无法穿越,
具体原理,
读者可以参考例2自行分析。
iptables下udp穿越实用篇:iptables与natcheck
最新推荐文章于 2024-03-27 19:49:09 发布