因为IPv4地址有限,最大42亿个。为了更好的利用这有限的IP数量,网络分为局域网和广域网,将IP分为了私有IP和公网IP,一个局域网里的N多台机器都可以共用一个公网IP,从而大大增加了"可用IP数量"。
当我们需要发送网络包的时候,在IP层,需要填入源IP地址,和目的IP地址,也就是对应快递的发货地址和收货地址。
但是我们家里的局域网内,基本上都用192.168.xx.xx
这样的私有IP。
如果我们在发送网络包的时候,这么填。对方在回数据包的时候该怎么回?毕竟千家万户人用的都是192.168.0.1
,网络怎么知道该发给谁?
所以肯定需要将这个192.168.xx
私有IP转换成公有IP。
局域网内用的是私有IP,公网用的都是公有IP。一个局域网里的私有IP想访问局域网外的公有IP,必然要做个IP转换,这是在哪里做的转换呢?
答案是NAT设备,全称Network Address Translation,网络地址转换。基本上家用路由器都支持这功能。
我们来聊下它是怎么工作的。
NAT的工作原理
假设你家里分到了一个公网IP地址 20.20.20.20
,对应配到了你家自带NAT功能的家用路由器上,你家里需要上网的设备有很多,比如你的手机,电脑都需要上网,他们构成了一个局域网,用的都是私有IP,比如192.168.xx
。 你要访问的公网IP地址是30.30.30.30
。
于是就有下面这样一张图
当你准备发送数据包的时候,你的电脑内核协议栈就会构造一个IP数据包。这个IP数据包报头里的发送端IP地址填的就是192.168.30.5
,接收端IP地址就是30.30.30.30
。将数据包发到NAT路由器中。
此时NAT路由器会将IP数据包里的源IP地址修改一下,私有IP地址192.168.30.5
改写为公网IP地址20.20.20.20
,这叫SNAT(Source Network Address Translation,源地址转换)。并且还会在NAT路由器内部留下一条 192.168.30.5 -> 20.20.20.20
的映射记录,这个信息会在后面用到。之后IP数据包经过公网里各个路由器的转发,发到了接收端30.30.30.30
,到这里发送流程结束。
如果接收端处理完数据了,需要发一个响应给你的电脑,那就需要将发送端IP地址填上自己的30.30.30.30
,将接收端地址填为你的公网IP地址20.20.20.20
,发往NAT路由器。NAT路由器收到公网来的消息之后,会检查下自己之前留下的映射信息,发现之前留下了这么一条 192.168.30.5 -> 20.20.20.20
记录,就会将这个数据包的目的IP地址修改一下,变成内网IP地址192.168.30.5
, 这也叫DNAT
(Destination Network Address Translation,目的地址转换)。 之后将其转发给你的电脑上。
整个过程下来,NAT悄悄的改了IP数据包的发送和接收端IP地址,但对真正的发送方和接收方来说,他们却对这件事情,一无所知。
这就是NAT的工作原理。
NAPT的原理
到这里,相信大家都有一个很大的疑问。
局域网里并不只有一台机器,局域网内 每台机器都在NAT下留下的映射信息都会是 192.168.xx.xx -> 20.20.20.20
,发送消息是没啥事,但接收消息的时候就不知道该回给谁了。
这问题相当致命,因此实际上大部分时候不会使用普通的NAT。
那怎么办呢?
问题出在我们没办法区分内网里的多个网络连接。
我们可以加入其他信息去区分内网里的各个网络连接,很自然就能想到端口。
但IP数据包(网络层)本身是没有端口信息的。常见的传输层协议TCP和UDP数据报文里才有端口的信息。
于是流程就变成了下面这样子。
当你准备发送数据包的时候,你的电脑内核协议栈就会先构造一个TCP或者UDP数据报头,里面写入端口号,比如发送端口是5000
,接收端口是3000
,然后在这个基础上,加入IP数据报头,填入发送端和接收端的IP地址。
那数据包长这样。
假设,发送端IP地址填的就是192.168.30.5
,接收端IP地址就是30.30.30.30
。
将数据包发到NAT路由器中。
此时NAT路由器会将IP数据包里的源IP地址和端口号修改一下,从192.168.30.5:5000
改写成20.20.20.20:6000
。并且还会在NAT路由器内部留下一条 192.168.30.5:5000 -> 20.20.20.20:6000
的映射记录。之后数据包经过公网里各个路由器的转发,发到了接收端30.30.30.30:3000
,到这里发送流程结束。
接收端响应时,就会在数据包里填入发送端地址是30.30.30.30:3000
,将接收端地址20.20.20.20:6000
,发往NAT路由器。NAT路由器发现下自己之前留下过这么一条 192.168.30.5:5000 -> 20.20.20.20:6000
的记录,就会将这个数据包的目的IP地址和端口修改一下,变回原来的192.168.30.5:5000
。 之后将其转发给你的电脑上。
如果局域网内有多个设备,他们就会映射到不同的公网端口上,毕竟端口最大可达65535,完全够用。这样大家都可以相安无事。
像这种同时转换IP和端口的技术,就是NAPT(Network Address Port Transfer , 网络地址端口转换 )。
那这么说只有用到端口的网络协议才能被NAT识别出来并转发?
但这怎么解释ping
命令?ping基于ICMP协议,而ICMP协议报文里并不带端口
信息。我依然可以正常的ping通公网机器并收到回包。
事实上针对ICMP协议,NAT路由器做了特殊处理。ping报文头里有个Identifier
的信息,它其实指的是放出ping命令的进程id。
对NAT路由器来说,这个Identifier
的作用就跟端口
一样。
内网穿透是什么
看到这里,我们大概也发现了。使用了NAT上网的话,前提得内网机器主动请求公网IP,这样NAT才能将内网的IP端口转成外网IP端口。
反过来公网的机器想主动请求内网机器,就会被拦在NAT路由器上,此时由于NAT路由器并没有任何相关的IP端口的映射记录,因此也就不会转发数据给内网里的任何一台机器。
举个现实中的场景就是,你在你家里的电脑上启动了一个HTTP服务,地址是192.168.30.5:5000,此时你在公司办公室里想通过手机去访问一下,却发现访问不了。
那问题就来了,有没有办法让外网机器访问到内网的服务?
有。
大家应该听过一句话叫,“没有什么是加中间层不能解决的,如果有,那就再加一层”。
放在这里,依然适用。
说到底,因为NAT的存在,我们只能从内网主动发起连接,否则NAT设备不会记录相应的映射关系,没有映射关系也就不能转发数据。
所以我们就在公网上加一台服务器x,并暴露一个访问域名,再让内网的服务主动连接服务器x,这样NAT路由器上就有对应的映射关系。接着,所有人都去访问服务器x,服务器x将数据转发给内网机器,再原路返回响应,这样数据就都通了。这就是所谓的内网穿透。
像上面提到的服务器x,你也不需要自己去搭,已经有很多现成的方案,花钱就完事了,比如花某壳。
到这里,我们就可以回答文章标题的问题。
为什么我在公司里访问不了家里的电脑?
那是因为家里的电脑在局域网内,局域网和广域网之间有个NAT路由器。由于NAT路由器的存在,外网服务无法主动连通局域网内的电脑。
NAT和路由,谁先谁后
结论:
出站的:先路由,数据走到对应出口上再nat
入站的:先nat,再路由
继NAT解决IP地址枯竭问题后,推广IPv6的有哪些意义?
总结
IPV4地址有限,但通过NAT路由器,可以使得整个内网N多台机器,对外只使用一个公网IP,大大节省了IP资源。
内网机子主动连接公网IP,中间的NAT会将内网机子的内网IP转换为公网IP,从而实现内网和外网的数据交互。
普通的NAT技术,只会修改网络包中的发送端和接收端IP地址,当内网设备较多时,将有可能导致冲突。因此一般都会使用NAPT技术,同时修改发送端和接收端的IP地址和端口。
由于NAT的存在,公网IP是无法访问内网服务的,但通过内网穿透技术,就可以让公网IP访问内网服务。一波操作下来,就可以在公司的网络里访问家里的电脑。