NAT,全称Network Address Translation,网络地址转换。
是一种使得内网的计算机可以访问外网的技术。
这个本来是写在Net9 Wiki上的,现在这里也弄一份……
基础
是在网关上进行的一种过程,是在转发数据包的过程中干的。
因此,依赖于网关的功能。
样例与分析
环境
- 有某内网,网段192.168.1.0,网络掩码255.255.255.0。
- 其中有某机,IP 192.168.137.3。
- 网关对内IP 192.168.137.1。
- 网关对外IP 59.66.132.114。
- 网关对外环境下的默认路由IP 59.66.132.1。
目的
某机想上网,访问ibm.com的80端口。
常量定义
A: ibm.com 的IP地址 B: 某机IP(192.168.137.3) C: 网关对外IP(59.66.132.114) D: 网关IP(192.168.137.1)
a: 网关内网接口的MAC地址(对应192.168.137.1) b: 网关外网上默认路由的MAC地址(对应59.66.132.1) c: 某机MAC地址(对应192.168.137.3) d: 网关外网接口MAC地址(对应59.66.132.114)
x: 某机认为的源端口 y: 经过NAT变换之后的源端口
m: ibm.com 域名
数据包
某机发出的开始连接TCP数据包:
MAC头 | IP头 | TCP头 |
---|---|---|
a<-c | A<-B | 80<-x |
于是这个包被网关收到,经过篡改,当它在外网出现的时候,成了这样:
MAC头 | IP头 | TCP头 |
---|---|---|
b<-d | A<-C | 80<-y |
对面收到之后发了回复,回复抵达网关的外网接口的时候,是这样:
MAC头 | IP头 | TCP头 |
---|---|---|
d<-b | C<-A | y<-80 |
然后又被篡改,当某机收到的时候,是这样:
MAC头 | IP头 | TCP头 |
---|---|---|
c<-a | B<-A | x<-80 |
对某机来说,看上去就有了一条A:80 <-> B:x的连接。 但是对对面来说,看上去其实是有一条A:80 <-> C:y的连接。
分析
为啥要篡改?因为如果在外网出现了一个192.168.137.3的数据包,谁知道这个包是干啥的,因为外网的网段是59.66.132.0/24,不应该有这种包。所以就会被扔掉,即使没有扔掉,回复也发不回来。
所以,要伪造成网关发出去的包才有人管。所以,首先要把IP篡改成网关的对外IP。
当对面收到并且发了回复回来的时候,还需要改回去。问题是,如何区分哪些包是应该改的?对于TCP/UDP包,有个很好的依据:端口号。
所以,只要在之前篡改的时候,记录下源端口号,和源IP,那么当收到数据包的时候,如果目的端口号就是记下的这个,那就篡改回去,并且发给记下来的来源地址。
简单来说,这样就可以了。MAC地址那边的变化,只是为了数据包能够抵达目的地而已。这方面可以参考基础的网关转发数据包的过程。
那么为啥有时候还要篡改端口号?因为可能,网关对外出口上,已经有一个程序在用这个端口号了。比如有一个人listen在1025端口上,而内网的一个机子发给外网一个数据包,源端口号也是1025。那么,当有一个新的数据包到来,并且其目的端口号是1025的时候,我们要不要篡改呢?我们怎么知道,这个是到那个listen的人的一个新连接,还是对原来内网那个数据包的回应呢?
所以,有时候要篡改一下端口号,同时记录下源IP和源端口号,以及篡改后的端口号。这样,当收到向篡改后的端口号发送的数据包的时候,我们就要把目的地址和目的端口都篡改回去,再发给原来的发送者。