iptables网络防火墙、SNAT、DNAT原理及端口重定向实战
网络防火墙
iptables/netfilter网络防火墙:
(1) 充当网关 (2) 使用filter表的FORWARD链
注意的问题:
(1) 请求-响应报文均会经由FORWARD链,要注意规则的方向性 (2) 如果要启用conntrack机制,建议将双方向的状态为ESTABLISHED的报文直接放行
实现内网ping通外网,外网无法ping通内网
第一种实现方法:
环境准备:
A主机:192.168.37.6(NAT模式,做内网)
B主机:192.168.37.7(NAT模式),172.16.0.7(桥接模式)B主机作为防火墙
C主机:172.16.0.17(桥接模式,做外网)
(1)在A主机修改IP地址
[root@centos7network-scripts]#cat ifcfg-ens33 DEVICE=ens33 BOOTPROTO=static IPADDR=192.168.37.6 PREFIX=24 GATEWAY=192.168.37.7 #指定防火墙左侧的IP地址 ONBOOT=yes
(2)修改B主机的NAT模式IP地址配置文件
[root@centos7network-scripts]#cat ifcfg-ens33 DEVICE=ens33 BOOTPROTO=none IPADDR=192.168.37.7 PREFIX=24 ONBOOT=yes GATEWAY=192.168.34.2 DNS1=114.114.114.114
修改B主机桥接模式IP地址配置文件
[root@centos7network-scripts]#cat ifcfg-ens37 DEVICE=ens37 BOOTPROTO=none IPADDR=172.16.0.7 PREFIX=16 ONBOOT=yes DNS1=114.114.114.114
(3)在C主机修改IP地址
[root@centos777network-scripts]#cat ifcfg-ens37 DEVICE=ens37 BOOTPROTO=dhcp IPADDR=172.16.0.17 PREFIX=16 GATEWAY=172.16.0.7 # 指定防火墙右侧的IP地址 ONBOOT=yes
(4)在B主机修改路由规则,将A主机和C主机跨网段ping通
[root@centos7~]#vim /etc/sysctl.conf net.ipv4.ip_forward=1 [root@centos7~]#sysctl -p 使配置文件生效 net.ipv4.ip_forward = 1
(5)在B主机设置(防火墙)设置FORWARD请求与响应防火墙策略,实现A主机ping通C主机策略,但是C主机无法ping通A主机
[root@centos7~]#iptables -A FORWARD -j REJECT 在B主机(防火墙)设置一个FORWARD拒绝策略 [root@centos7~]#iptales -vnL --line-numbers [root@centos7~]#iptables -vnL --line-numbers Chain INPUT (policy ACCEPT 85 packets, 6520 bytes) num pkts bytes target prot opt in out source destination Chain FORWARD (policy ACCEPT 0 packets, 0 bytes) num pkts bytes target prot opt in out source destination 1 0 0 REJECT all -- * * 0.0.0.0/0 0.0.0.0/0 reject-with icmp-port-unreachable Chain OUTPUT (policy ACCEPT 63 packets, 5876 bytes) num pkts bytes target prot opt in out source destination [root@centos7 ~]# iptables -I FORWARD 1 -s 192.168.37.0/24 -p icmp --icmp-type 8 -j ACCEPT # 设置A主机请求允许的策略 [root@centos7 ~]# iptables -I FORWARD 1 -d 192.168.37.0/24 -p icmp --icmp-type 0 -j ACCEPT # 设置A主机响应允许的策略
第二种实现方法:
也可以删除内网的响应允许IP,添加一个state模块,进行状态跟踪,ping通出去,回来就成为老的状态,也可以成功,此方法也可以
[root@centos7~]#iptables -D FORWARD 2 [root@centos7~]#iptables -I FORWARD 1 -m state --state ESTABLISHED,RELATED -j ACCEPT [root@centos7~]#iptables -vnL --line-numbers Chain INPUT (policy ACCEPT 49 packets, 3608 bytes) num pkts bytes target prot opt in out source destination Chain FORWARD (policy ACCEPT 0 packets, 0 bytes) num pkts bytes target prot opt in out source destination 1 5 420 ACCEPT all -- * * 0.0.0.0/0 0.0.0.0/0 state RELATED,ESTABLISHED 2 3 252 ACCEPT icmp -- * * 192.168.37.6 0.0.0.0/0 icmptype 8 3 0 0 REJECT all -- * * 0.0.0.0/0 0.0.0.0/0 reject-with icmp-port-unreachable Chain OUTPUT (policy ACCEPT 34 packets, 3040 bytes) num pkts bytes target prot opt in out source destination
实现内网访问外网httpd服务
(1)在C主机安装httpd服务
[root@centos777~]#yum install httpd [root@centos777~]#systemctl start httpd [root@centos777~]#echo internet server > /var/www/html/index.html
(2)在B主机设置防火墙策略,允许内网访问外网的httpd服务,但外网不能访问内网的服务
[root@centos7~]#iptables -I FORWARD 2 -s 192.168.37.0/24 -p tcp --dport 80 -j ACCEPT
(3)此时在A主机就可以访问C主机(外网)httpd服务
[root@centos7network-scripts]#curl 172.16.0.17 internet server
(4)C主机也可以对外网的httpd进行加密httpd服务
[root@centos777~]#yum install mod_ssl -y [root@centos777~]#systemctl restart httpd
(5)在B主机设置一个加密443和httpd端口80的防火墙规则
[root@centos7~]#iptables -I FORWARD 2 -s 192.168.37.0/24 -p tcp -m multiport --dport 80,443 -j ACCEPT
(6)此时在A主机就可以进行加密访问外网httpd服务
[root@centos7network-scripts]#curl -k https://172.16.0.17 加上-k不需要进行证书检测 internet server
实现外网访问内网HTTP服务
也可以在B主机实现外网访问内网的httpd服务
[root@centos7~]#iptables -I FORWARD 2 -d 192.168.37.6 -p tcp -m multiport --dport 80,443 -j ACCEPT [root@centos7~]#iptables -vnL Chain INPUT (policy ACCEPT 20 packets, 1528 bytes) pkts bytes target prot opt in out source destination Chain FORWARD (policy ACCEPT 0 packets, 0 bytes) pkts bytes target prot opt in out source destination 34 4644 ACCEPT all -- * * 0.0.0.0/0 0.0.0.0/0 state RELATED,ESTABLISHED 0 0 ACCEPT tcp -- * * 0.0.0.0/0 192.168.37.6 multiport dports 80,443 4 240 ACCEPT tcp -- * * 192.168.37.0/24 0.0.0.0/0 multiport dports 80,443 4 336 ACCEPT icmp -- * * 192.168.37.6 0.0.0.0/0 icmptype 8 84 4889 REJECT all -- * * 0.0.0.0/0 0.0.0.0/0 reject-with icmp-port-unreachable Chain OUTPUT (policy ACCEPT 14 packets, 1304 bytes) pkts bytes target prot opt in out source destination
(8)在C主机访问A主机的HTTPD服务
[root@centos777~]#curl 192.168.37.6 lan server
链管理:
-N:new, 自定义一条新的规则链 -X:delete,删除自定义的空的规则链 -P:Policy,设置默认策略;对filter表中的链而言,其默认策略有: ACCEPT:接受 DROP:丢弃 -E:重命名自定义链;引用计数不为0的自定义链不能够被重命名,也不能被删除
实战演示:创建自定义链,进行模块化(实现内网访问外网)
(1)以上实验的基础上,将B主机创建一个新链,方便管理模块化
[root@centos7~]#iptables -N TOINTERNET 创建一个新模块链 [root@centos7~]#iptables -A TOINTERNET -s 192.168.37.0/24 -p tcp -m multiport --dports 80,443,22 -j ACCEPT 将内网访问外网的规则添加到新链上 [root@centos7~]#iptables -A TOINTERNET -s 192.168.37.0/24 -p icmp --icmp-type 8 -j ACCEPT [root@centos7~]#iptables -I FORWARD 2 -j TOINTERNET 将新自定义的链加入到FORWARD链中 [root@centos7 ~]# iptables -vnL Chain INPUT (policy ACCEPT 14 packets, 960 bytes) pkts bytes target prot opt in out source destination Chain FORWARD (policy ACCEPT 0 packets, 0 bytes) pkts bytes target prot opt in out source destination 0 0 TOINTERNET all -- * * 0.0.0.0/0 0.0.0.0/0 # 将链名加入到规则中 0 0 REJECT all -- * * 0.0.0.0/0 0.0.0.0/0 reject-with icmp-port-unreachable Chain OUTPUT (policy ACCEPT 10 packets, 1888 bytes) pkts bytes target prot opt in out source destination Chain TOINTERNET (1 references) # 自定义的链 pkts bytes target prot opt in out source destination 0 0 ACCEPT tcp -- * * 192.168.37.0/24 0.0.0.0/0 multiport dports 80,443,22 0 0 ACCEPT icmp -- * * 192.168.37.0/24 0.0.0.0/0 icmptype 8
(2)此时就可以从内网访问外网,创建的自定义链规则,方便管理,条理清晰
[root@centos7html]#curl -k https://172.16.0.17 internet server [root@centos7html]#curl 172.16.0.17 internet server [root@centos7html]#ssh 172.16.0.17 The authenticity of host '172.16.0.17 (172.16.0.17)' can't be established. ECDSA key fingerprint is SHA256:nl4GdONb/BsSo/TpR+UHsM/gFo4+tLpD40NhCklkf7M. ECDSA key fingerprint is MD5:55:a8:61:99:c3:52:fd:25:80:95:21:88:2b:98:1b:87. Are you sure you want to continue connecting (yes/no)? yes Warning: Permanently added '172.16.0.17' (ECDSA) to the list of known hosts. Last login: Fri Dec 6 12:15:40 2019 from lpj-pc [root@centos777~]#
(3)删除自定义链
[root@centos7~]#iptables -vnL Chain INPUT (policy ACCEPT 77 packets, 5948 bytes) pkts bytes target prot opt in out source destination Chain FORWARD (policy ACCEPT 0 packets, 0 bytes) pkts bytes target prot opt in out source destination 143 24925 ACCEPT all -- * * 0.0.0.0/0 0.0.0.0/0 state RELATED,ESTABLISHED 3 180 TOINTERNET all -- * * 0.0.0.0/0 0.0.0.0/0 删除第二条链表 316 19254 REJECT all -- * * 0.0.0.0/0 0.0.0.0/0 reject-with icmp-port-unreachable Chain OUTPUT (policy ACCEPT 50 packets, 4452 bytes) pkts bytes target prot opt in out source destination Chain TOINTERNET (1 references) pkts bytes target prot opt in out source destination 3 180 ACCEPT tcp -- * * 192.168.37.0/24 0.0.0.0/0 multiport dports 80,443,22 0 0 ACCEPT icmp -- * * 192.168.37.0/24 0.0.0.0/0 icmptype 8 [root@centos7~]#iptables -D FORWARD 2 删除第二条新建的链表 [root@centos7~]#iptables -F TOINTERNET 先清空链表内容 [root@centos7~]#iptables -X TOINTERNET 删除空链表
NAT
NAT概念
NAT(Network Address Translation)是一种地址转换技术,可以将IPv4报文头中的地址转换为另一个地址。通常情况下,利用NAT技术将IPv4报文头中的私网地址转换为公网地址,可以实现位于私网的多个用户使用少量的公网地址同时访问Internet。因此,NAT技术常用来解决随着Internet规模的日益扩大而带来的IPv4公网地址短缺的问题。
NAT原理
NAT的基本工作原理是,当私有网主机和公共网主机通信的IP包经过NAT网关时,将IP包中的源IP或目的IP在私有IP和NAT的公共IP之间进行转换。
如下图所示,NAT网关有2个网络端口,其中公共网络端口的IP地址是统一分配的公共 IP,为202.20.65.5;私有网络端口的IP地址是保留地址为192.168.1.1。私有网中的主机192.168.1.2向公共网中的主机202.20.65.4发送了1个IP包(Dst=202.20.65.4,Src=192.168.1.2)。
当IP包经过NAT网关时,NAT Gateway会将IP包的源IP转换为NAT Gateway的公共IP并转发到公共网,此时IP包(Dst=202.20.65.4,Src=202.20.65.5)中已经不含任何私有网IP的信息。由于IP包的源IP已经被转换成NAT Gateway的公共IP,Web Server发出的响应IP包(Dst= 202.20.65.5,Src=202.20.65.4)将被发送到NAT Gateway。
这时,NAT Gateway会将IP包的目的IP转换成私有网中主机的IP,然后将IP包(Des=192.168.1.2,Src=202.20.65.4)转发到私有网。对于通信双方而言,这种地址的转换过程是完全透明的。转换示意图如下。
如果内网主机发出的请求包未经过NAT,那么当Web Server收到请求包,回复的响应包中的目的地址就是私有网络IP地址,在Internet上无法正确送达,导致连接失败。
NAT: network address translation
PREROUTING,INPUT,OUTPUT,POSTROUTING 请求报文:修改源/目标IP,由定义如何修改 响应报文:修改源/目标IP,根据跟踪机制自动实现
SNAT:source NAT POSTROUTING, INPUT
让本地网络中的主机通过某一特定地址访问外部网络,实现地址伪装 请求报文:修改源IP
DNAT:destination NAT PREROUTING , OUTPUT
把本地网络中的主机上的某服务开放给外部网络访问(发布服务和端口映射),但隐藏真实IP 请求报文:修改目标IP
PNAT: port nat,端口和IP都进行修改
注意:局域网内的IP地址要规范,尽量配置公有地址,如果不配置规范地址,和访问的外网地址一致时,就会冲突,无法连接到外网;
SNAT:请求报文替换源地址。
DNAT:请求报文替换目标地址。
nat表的target:
SNAT:固定IP --to-source [ipaddr[-ipaddr]][:port[-port]] --random
MASQUERADE:动态IP,如拨号网络
--to-ports port[-port] --random
实战演练:SNAT
实现原理:在防火墙上设置SNAT表和POSTROUTING链上,将源地址(也就是内网的IP地址)替换为防火墙访问的公网地址,此方法设置的是固定的IP地址,最终通过内网的IP地址访问外网的地址。
A主机:192.168.37.6(NAT模式,作为内网)
B主机:192.168.37.7,172.16.0.7(NAT和桥接模式,作为防火墙)
C主机:172.16.0.17 (桥接模式,作为外网)
(1)在C主机将网关删掉,暂时不配置172.16.0.7网关,此时A主机去访问C主机,无法返回信息,就无法上网,其他配置与前面的IP地址配置不变。
[root@centos777network-scripts]#cat ifcfg-ens37 DEVICE=ens37 BOOTPROTO=dhcp PREFIX=24 IPADDR=172.16.0.17 ONBOOT=yes DNS1=114.114.114.114
(2)在B主机进行设置SNAT防火墙策略,因为我们可能是本机的地址出去到公网或者是本地局域网的地址出去到公网,我们都可以在POSTROUTING链上将所有的IP地址汇总转发到公网上。
[root@centos7network-scripts]#iptables -t nat -A POSTROUTING -s 192.168.37.0/24 -j SNAT --to-source 172.16.0.7 # 将192.168.37.0出去的IP网段都替换成172.16.0.7的源地址 [root@centos7network-scripts]#iptables -vnL -t nat Chain PREROUTING (policy ACCEPT 0 packets, 0 bytes) pkts bytes target prot opt in out source destination Chain INPUT (policy ACCEPT 0 packets, 0 bytes) pkts bytes target prot opt in out source destination Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes) pkts bytes target prot opt in out source destination Chain POSTROUTING (policy ACCEPT 0 packets, 0 bytes) pkts bytes target prot opt in out source destination 0 0 SNAT all -- * * 192.168.37.0/24 0.0.0.0/0 to:172.16.0.7
(3)此时在A主机就可以访问C主机
[root@centos7~]#ping 172.16.0.17 PING 172.16.0.17 (172.16.0.17) 56(84) bytes of data. 64 bytes from 172.16.0.17: icmp_seq=1 ttl=63 time=2.23 ms 64 bytes from 172.16.0.17: icmp_seq=2 ttl=63 time=0.688 ms 64 bytes from 172.16.0.17: icmp_seq=3 ttl=63 time=0.919 ms
(4)此时在C主机查看,以为是172.16.0.7地址在访问,实际是内网的192.168.37.6在访问C主机信息。
[root@centos777~]#tcpdump -i ens37 -nn host 172.16.0.7 tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on ens37, link-type EN10MB (Ethernet), capture size 262144 bytes 17:17:17.505943 IP 172.16.0.7 > 172.16.0.17: ICMP echo request, id 12095, seq 13, length 64 17:17:17.506055 IP 172.16.0.17 > 172.16.0.7: ICMP echo reply, id 12095, seq 13, length 64 17:17:18.502328 IP 172.16.0.7 > 172.16.0.17: ICMP echo request, id 12095, seq 14, length 64 17:17:18.502438 IP 172.16.0.17 > 172.16.0.7: ICMP echo reply, id 12095, seq 14, length 64 17:17:19.519997 IP 172.16.0.7 > 172.16.0.17: ICMP echo request, id 12095, seq 15, length 64
MASQUERADE:动态IP,如拨号网络,也可以实现替换源地址功能
直接在B主机外网重新设置一个防火墙策略,设置不固定的IP地址,就可以在A主机访问C主机
[root@centos7network-scripts]#iptables -F -t nat [root@centos7network-scripts]#iptables -t nat -A POSTROUTING -s 192.168.37.0/24 -j MASQUERADE
DNAT
--to-destination [ipaddr[-ipaddr]][:port[-port]] iptables -t nat -A PREROUTING -d ExtIP -p tcp|udp --dport PORT -j DNAT --to-destination InterSeverIP[:PORT]
实战演练:外部用户访问防火墙公网地址转发到内网地址
实现原理:使用DNAT表,以及PREROUTING链,当外部用户访问防火墙公网的IP地址,防火墙的公网IP地址转发到后端内网的IP地址和端口上,表面上用户访问的是防火墙的公网IP地址和端口,实际访问的是后端内网的IP地址和端口。
如果用户访问内网的http服务,经过postrouting,此时已经经过了input output,以及postrouting三个链,在经过input链时,就会访问防火墙的http服务,此时防火墙内部无http服务,就无法再继续往下传递到下一个链,此postrouting无法实现IP地址转发,因此只能在prerouting链进行转发IP地址。
(1)在B主机设置防火墙策略,将防火墙外网的IP地址映射为企业内网的IP地址及端口(即目标地址和80端口映射成企业内部的(192.168.37.6)IP地址和8080端口)
[root@centos7network-scripts]#iptables -t nat -A PREROUTING -d 172.16.0.7 -p tcp --dport 80 -j DNAT --to-destination 192.168.37.6:8080(端口号也可以默认为80端口)
(2)修改A主机的httpd端口,并重启httpd服务
[root@centos7~]#vim /etc/httpd/conf/httpd.conf Listen 8080 [root@centos7~]#systemctl restart httpd
(3)C主机进行访问A主机
[root@centos777~]#curl 172.16.0.7 lan server
(4)在A主机查看log日志,此时由于改的是目标地址,未改本地源地址(172.16.0.17),因此日志中查看到的就是外网地址访问信息
端口重定向(转发)
REDIRECT:
NAT表
可用于:PREROUTING OUTPUT 自定义链 通过改变目标IP和端口,将接受的包转发至不同端口 --to-ports port[-port]
实战演练:将企业服务器端口转发
实现原理:将公司内网的端口重定向到指定的端口,比如8080端口,重定向到80端口,然后在防火墙上定义转发规则,将防火墙公网的IP地址和端口映射到内网的IP地址和重定向的端口号80。
(1)在A主机设置防火墙策略,将本地目标的80端口映射为8080端口,即访问80端口时,直接转发到8080端口。
[root@centos7~]#iptables -t nat -A PREROUTING -d 192.168.37.6 -p tcp --dport 80 -j REDIRECT --to-ports 8080
(2)在B主机将公网的IP(172.16.0.7)地址和端口(80),映射为192.168.37.6和80端口
[root@centos7network-scripts]#iptables -t nat -A PREROUTING -d 172.16.0.7 -p tcp --dport 80 -j DNAT --to-destination 192.168.37.6:80
(3)最后C主机还是可以访问A主机的httpd服务,虽然访问的是映射的172.16.0.7的IP地址,实则访问的是内网地址
[root@centos777~]#curl 172.16.0.7 lan server
(4)此时A主机监听的httpd服务端口号就是本机的8080端口,用户访问的80端口全部转发至8080端口上。