iptables详解——SNAT和DNAT
书接上回,咳咳,这次是回来填坑的。(虽然已经快过去三个月了,哈哈)。下面进入正文
前言
本篇文章主要介绍NAT技术(NAT,Network Address Translation,网络地址转换),以及iptables相关的实操。想了解iptables的小伙伴可以去看我之前的文章:Linux防火墙——iptables详解。
NAT简介
NAT技术的提出是为了解决IPv4地址不够用的问题。在互联网中,为了定位主机,需要给每一台联网的主机设置一个IP地址。IPv4地址是由4 * 8位二进制数组成,只够分配给约43亿主机使用,而现在全球网民已经有51.6亿多人(来自2023年全球数字报告),显然不够用。为了解决这个问题,提出了NAT技术。
NAT原理
NAT技术的原理是将内部网络中的多个私有 IP 地址转换为一个或多个公共 IP 地址。这样,局域网中的多个设备可以共享同一个公共 IP 地址与互联网进行通信,从而减少IP地址的消耗。
工作步骤
- 内部设备发送数据包:当内部网络中的设备向外部网络发送数据包时,数据包的源 IP 地址是设备的私有 IP 地址,目标 IP 地址是外部服务器的公共 IP 地址。
- NAT 路由器接收数据包:NAT 路由器是内部网络与外部网络之间的边界设备。它接收到数据包后,检查目标 IP 地址。
- 地址映射查找:NAT 路由器在其地址映射表中查找与源 IP 地址相对应的公共 IP 地址和端口号。这个映射关系指示了内部设备与外部设备之间的对应关系。
- 地址转换:如果找到了匹配的映射关系,NAT 路由器将源 IP 地址和端口号修改为映射表中的公共 IP 地址和端口号。这样,在数据包进入外部网络时,数据包的源 IP 地址就变成了 NAT 路由器的公共 IP 地址。
- 数据包转发:NAT 路由器将修改后的数据包转发到外部网络中的目标服务器。
- 响应数据包返回:当外部服务器向 NAT 路由器返回响应数据包时,NAT 路由器查找地址映射表以确定目标设备,并将目标 IP 地址和端口号转换回内部设备的私有 IP 地址和端口号。然后,NAT 路由器将响应数据包转发给正确的内部设备。
优点和缺点
基于这些工作原理NAT有如下几个优点:
- 地址共享:通过 NAT,多个设备可以使用相同的公共 IP 地址与互联网通信,节省了 IPv4 地址资源。
- 安全性增强:内部设备使用私有 IP 地址进行通信,对外部网络来说不可见,提高了网络的安全性。
- IP 地址隐藏:由于内部设备使用的是私有 IP 地址,外部用户无法直接访问这些设备,可以增加对攻击的防御。
但是NAT有两个致命的缺点:NAT会使网络产生额外的网络延迟和复杂性。NAT产生额外的网络延迟是由于每进行一次数据交换,NAT就要转换一次IP地址(这个操作需要时间),这就产生了完全不必要的时间损耗。NAT增加网络复杂性则是因为NAT屏蔽了主机与主机之间的直接通信,两者之间必须通过网关,然后为了保证主机能够顺利访问外网,网关还必须要维护一张映射表,除此之外,多种映射关系会导致网络调试更加困难,这些会导致网络的复杂性大大加强。
总的来说,NAT确实存在着很好的优点,但是NAT是为了解决ipv4地址不足而提出的,这其实治标不治本,最好的解决办法应该是更快的普及ipv6地址,ipv6地址不仅有着ipv4没有的优点,还不存在NAT的这些问题,希望全网使用ipv6地址的那一天早日到来。
SNAT和DNAT
上文提到的NAT技术是一个广义的概念,而SNAT(源地址转换,Source Network Address Translaiton)和DNAT(目的地址转换, Destination Network Address Translation)则是NAT具体细分的概念。
概念
SNAT:SNAT(Source Network Address Translation),也称为出口NAT,用于将源IP地址从内部私有地址转换为公共地址。当内部主机发送数据包到外部网络时,NAT设备(如路由器或防火墙)会修改数据包的源IP地址为NAT设备的公共IP地址,以便与外部网络通信(使内部机器能够上网)。这样可以隐藏内部网络的真实IP地址。
DNAT:DNAT(Destination Network Address Translation),也称为入口NAT,用于将目标IP地址从公共地址转换为内部私有地址。当外部网络上的数据包发送到经过NAT的网络时,NAT设备会根据转换规则将数据包的目标IP地址修改为内部主机的私有IP地址,以便将数据包正确地转发给内部主机。
iptables实践
到现在为止,和NAT有关的概念已经介绍完毕,那么NAT和Linux中的防火墙又有什么关系呢?在Linux中,iptables提供了NAT相关的实现,通过在Linux中使用相关的命令,就可以将Linux主机模拟成NAT设备,对NAT相关技术进行模拟验证。
实例
这里将用到iptables相关的概念和命令参数,没学过的小伙伴可以去看我的另一篇文章:Linux防火墙——iptables详解。
其实相关的实现很简单,在iptables中,提供了相关的-j
动作(SNAT和DNAT动作)
- NAT的配置均是在网关服务器上进行
SNAT实现
一般常用配置SNAT的命令格式
iptables -t nat -A POSTROUTING -s 源ipv4地址 -o 网卡名称 -j SNAT --to-source 公网ipv4地址
SNAT用于将源IP地址从内部私有地址转换为公共地址,从而使内部主机能够连接公网上的主机。这条命令中-A
指定添加到的规则链,-s
代表了数据交换的源地址,-j SNAT
表示使用SNAT动作, --to-source
将-s
的ip地址转换为相关的公网ip地址。
举例:
模拟情景:假设有两台Linux主机,一台是内网的Linux主机,然后一台模拟网关设备,网关设备具有公网IP地址,通过设置,使只有私网地址的Linux主机能够上网。假设内网主机称为host1,模拟网关设备称为host2。(为了模拟路由网关,在host2上打开路由转发功能,echo 1> /proc/sys/net/ipv4/ip_forward
,host2还需配置两张网卡分别负责处理公网和私网的数据交换)
- 这里设置host1桥接模式IP地址为192.168.70.70(只要是在本地局域网无法上网的IP地址就行),host2使用可以上网的局域网地址(使用这个地址模拟公网地址)
-
由于host1只有私有IP地址,使用ping命令发现无法上网。
-
查看host1主机IP地址,在host2进行相关配置。
iptables -t nat -A POSTROUTING -s 192.168.70.70 -o ens37 -j SNAT --to-source 192.168.x.x
-
配置成功之后,再次使用
ping
命令,发现能够上网。
DNAT实现
一般常用配置DNAT的命令格式
iptables -t nat -A PREROUTING -d 公网ipv4地址 -i 网卡名称 -p 指定协议 [--dport 端口号] -j DNAT --to-destination 实际目标ipv4地址
DNAT这条命令和SNAT相差不大,而DNAT是将目标IP地址从公共地址转换为内部私有地址,这里-A
指定添加到哪个规则链,使用-d
指定了外网访问的ipv4地址,然后将使用-j DNAT
配置DNAT动作用于完成DNAT规则,--to-destination
指定内网IP地址。
举例:
模拟情景:假设有两台Linux主机,一台是内网的Linux主机,然后一台模拟网关设备,网关设备具有公网IP地址,通过设置,使外部的主机能够连接内网Linux主机。假设内网主机称为host1,模拟网关设备称为host2。(为了模拟路由网关,在host2上打开路由转发功能,echo 1> /proc/sys/net/ipv4/ip_forward
,还需配置两张网卡分别负责处理公网和私网的数据交换)
- 这里设置host1桥接模式IP地址为192.168.70.1(只要是在本地局域网无法上网的IP地址就行),host2使用可以上网的局域网地址(使用这个地址模拟公网地址)
-
使用一台与网关同级的机器
ping
(这里使windows)Linux主机,发现无法ping通。 -
在host2上进行相关配置。
iptables -t nat -A PREROUTING -d 192.168.x.x -i ens33 -p icmp -j DNAT --to-destination 192.168.70.70
-
再次使用
ping
命令,发现外部主机能够连接。
- 这里与网关同级的主机的ping的是网关服务器的IP地址,然后在host1上使用tcpdump抓包icmp,能够发现抓到的源目IP都是host2和外部主机的,但是这条命令指定抓包网卡是host1的ens33,这是因为通过DNAT,所有ping网关的指令都被转发转发到了host1上,而在host2上tcpdump抓包,可以发现真正的通信IP地址。
总结
NAT相较于iptables的实操,概念的理解更加重要,命令中为什么SNAT规则需要添加在nat表的POSTROUTING链上,然后为什么DNAT规则需要添加在nat表的PREROUTING链上,这都需要详细的理解iptables和nat相关的概念,NAT的实际使用更多的是对概念的实践验证。
最后,上述的准备模拟情景准备步骤没有描述的很详细,情景准备涉及到LinuxIP的设置以及如何给Linux虚拟机增加一张网卡(变成两张网卡),设置IP地址可以看我的博客K8s安装–超级详细(无坑)第二步有讲到,增加网卡得大家自己寻找一下方法了。
关于永久保存iptables规则的命令。
# 导出iptables规则,默认导出在/etc/iptables/
iptables-save > filename.txt
# 导入iptables规则,开机不会自动导入
iptables-restore < /etc/iptables/filename.txt
最后,如果博客哪里有问题,欢迎大家在评论区中指出,谢谢大家。
计划的下一篇文章:利用iptables实现内网服务器发布(SNAT+DNAT+docker),希望不会让大家等太久,哈哈。