通过UDP打洞实现NAT穿越是一种在处于使用了NAT的私有网络中的Internet主机之间建立双向UDP连接的方法。由于NAT的行为是非标准化的,因此它并不能应用于所有类型的NAT。
其基本思想是这样的:让位于NAT后的两台主机都与处于公共地址空间的、众所周知的第三台服务器相连,然后,一旦NAT设备建立好UDP状态信息就转为直接通信,并寄希望于NAT设备会在分组其实是从另外一个主机传送过来的情况下仍然保持当前状态。
这项技术需要一个圆锥型NAT设备才能够正常工作。对称型NAT不能使用这项技术。
这项技术在P2P软件和VoIP电话领域被广泛采用。它是Skype用以绕过防火墙和NAT设备的技术之一。
相同的技术有时还被用于TCP连接——尽管远没有UDP成功。
UDP打洞的过程大体上如下:
主机A和主机B都是通过NAT设备访问互联网,主机S位于互联网上。
1. A和B都与S之间通过UDP进行心跳连接
2. A通知S,要与B通信
3. S把B的公网IP、port告诉A,同时把A的公网IP、port告诉B
4. A向B的公网IP、port发送数据(这个数据包应该会被丢弃,但是打开了B回来的窗户)
5. B向A的公网IP、port发送数据(这个数据包就会被A接受,之后A和B就建立起了连接)
上述能够正常工作的前提的,A连接S和连接B的时候,NAT设备对A做地址转换的时候,需要选择相同的IP、port。
比如:A--->NATA--->S
A--->NATA--->NATB-->B
那么NATA对A进行NAT的时候,需要选择相同的IP和port进行SNAT。
如果使用Linux作为防火墙,那么非常幸运,Linux就是这么搞的
现在我们来看看linux是如何实现的:
linux通过SNAT netfilter target 进行源地址转换,源码位于net/ipv4/netfilter/nf_nat_rule.c
点击(此处)折叠或打开
/* Source NAT */
static unsigned int
ipt_snat_target(struct sk_buff *skb, const struct xt_target_param *par)
{
struct nf_conn *ct;
enum ip_conntrack_info ctinfo;
const struct nf_nat_multi_range_compat *mr = par->targinfo;
NF_CT_ASSERT(par->hooknum == NF_INET_POST_ROUTING);
ct = nf_ct