CentOS上通过iptables实现NAT功能
时间:2014-10-28 12:18 来源:51cto.com 作者:it
实验:如下模型,node1为内网主机,IP地址为192.168.10.2;node3为外网主机,IP地址为10.72.37.177(假设此地址为公网地址),node3上提供web server和FTP Server的功能;内网主机node2主机有2块网卡,地址分别为eth0:192.168.10.1和eth2:10.72.37.91(假设此地址为公网地址);
现要求在node2上通过iptables配置实现SNAT功能,并做如下限制:
1、node1可以访问node3提供的web服务和ftp服务
2、node1只可以ping连接、ssh连接node3
SNAT实现的过程:
node1与node2都是内网主机处于同一网段,所以node1是默认直接可以ping通node2主机上eth1的地址192.168.10.1;将node1主机的网关指向192.168.10.1后,node1就可以直接ping通node2的eth0上的外网地址10.72.37.91;
但此时内网主机node1肯定是无法ping通外网主机node3的地址,此时开启node2主机的路由转发功能,即可实现将node1的请求报文,经由node2转发送到node3主机上,但是node3响应此报文时,发现源地址为192.168.10.1,与自己不在同一网段内,便会交由网关去转发,而node3的网关默认也是无法识别此网络,所以响应报文也就无法返回到node2;
所以即可以配置,node2把node1的请求报文转发出去之前,将请求报文的源地址由192.168.10.2转换为10.72.37.91后再送至node3主机上,此过程中node2同时会自动生成一张NAT会话表,记录下经由node2被转发的每一条记录;
node3封装响应报文时,发现源地址为10.72.37.91,所以响应报文的目标地址就会是10.72.37.91,响应报文即会被返回给node2,此时node2上就会查询NAT会话表,自动再做目标地址转换,将响应报文送至node1,此即实现了内网主机node1与外网主机node3通信了;iptables的SNAT即是实现此功能;
此过程中报文在node1、node2和node3之间传输路径如下图:
一个请求报文经由node2主机路由判断后,需要被转发出去的话,此请求报文则会经过node2主机上netfilter的链的顺序为PREROUTING--> FORWARD-->OUTROUTING,所以SNAT的规则需配置在OUTROUTING链上,而filter的规则就需要在FORWARD链上配置了(此路径中只有在FORWARD链上有filter功能表,PREROUTING和OUTROUTING链上不做filter);
总结:为了实现node1可以与node3通信需做的配置有:
1、node1主机的默认网关指向node2的eth1的地址
1、node2主机上的开启路由转发功能
2、node2主机上配置SNAT功能
配置过程:
node1上:
#ping 192.168.10.1 ##是可以直接ping通的
#route add default gw192.168.10.1 ##添加路由指向192.168.10.1
#ping 10.72.37.91 ##即可ping通node2主机上的另一个地址
node2上:
#sysctl -wnet.ipv4.ip_forward=1 ##开启node2主机上的路由转发功能
node1上:
#ping 10.72.37.177 ##此时,node1上暂且是无法ping通node3的,但是此时ping的请求包是已经可以发送到node3的
node3上:
#iptables -t filter -A INPUT -j LOG ##在node3主机的INPUT链上添加LOG功能
#tail /var/log/messages ##即可看到,已记录到来自192.168.10.2即node1的ICMP请求报文
… … kernel: IN=eth0OUT= MAC=1c:6f:65:03:1b:9a:00:0c:29:fa:ea:2d:08:00 SRC=192.168.10.2DST=10.72.37.177 LEN=84 TOS=0x00 PREC=0x00 TTL=63 ID=0 DF PROTO=ICMP TYPE=8CODE=0 ID=4876 SEQ=9
##如果此时在OUTPUT链上也记录LOG的话,也是可以看到SRC=10.72.37.177DST=192.168.10.2的响应报文,只不过是这个响应报文最终无法送达node1
node2上
#iptables -t nat -APOSTROUTING -s 192.168.10.0/24 -j SNAT --to-source 10.72.37.91
##在node2主机上的的POSTROUTING链上向NAT表中添加,定义来自192.168.10.0的主机,无论是使用何种协议,无论访问哪个网络,通通代理出去,将源地址转换成10.72.37.91
#iptables -t nat -L POSTROUTING -nv ##在nat表的POSTROUTING链上即可看到我们添加的规则
此时,node1即可以ping通node3,而在node3主机上的log中可以看到ICMP的请求报文SRC=10.72.37.91DST=10.72.37.177和响应报文SRC=10.72.37.177DST=10.72.37.91;注意此时的与node3通信的IP地址已被SANT转换为10.72.37.91了;
node1上
#curl -I http://10.72.37.177 ##测试连接node3的web服务
#tail /var/log/nginx/access.log ##node3上查看访问日志中,客户端源地址的已是被转换后的10.72.37.91
按照要求node1只可以向node3发起ping、shh、web访问请求,所以在node2上的filter表的FORWARD链上添加如下规则:
#iptables -t filter -P FORWARD DROP
#iptables -t filter -I FORWARD 1 -s192.168.10.0/24 -p icmp --icmp-type 8 -j ACCEPT
##转发来自192.168.10.0/24的ICMP协议的请求报文
#iptables -t filter -I FORWARD 1 -s10.72.37.0/24 -p icmp --icmp-type 0 -j ACCEPT
##转发来自10.72.37.0/24的ICMP协议的响应报文
#iptables -t filter-A FORWAORD -s 192.168.10.0/24 -p tcp -m state --state NEW -m multiport --destination-ports 21,22,80 -j ACCEPT
##转发来自192.168.10.0/24的状态为NEW,访问ftp,ssh,web的请求
#iptables -t filter -A FORWARD -m state--state ESTABLISHED,RELATED -j ACCEPT
##转发所有状态为ESTABLISHED和RELATED(for ftp)状态的请求
node1通过node3上的21端口和ftp server建立命令连接后,因为ftp server默认是工作在被动模式,所以node1还需访问node3上的一个大于1024的随机端口来建立数据连接,即需要node2上将所有所有大于1024的端口都转发至node3;但是本实验又要求只允许转发21,22,80端口;
此时要求node3主机上需已装载内核模块nf_contrack_ftp;这个模块可以监控ftp控制流,能够事先知道将要建立的ftp数据连接所使用的端口,从而可以允许相应的数据包通过,即使防火墙没有开放这个端口:
#modprobe nf_contrack_ftp ##手动装载此内核模块
#lsmod | grep ftp ##此时即可看到已装载
##或者写到配置文件/etc/sysconfig/iptables-config,即可不需每次去手动装载,即使重启后也会自动装载,添加一行:IPTABLES_MOUDLES=”nf_contrack_ftp”
假若node3没有装载内核模块nf_conntrack_ftp,在node1上连接node3上的ftp服务时,就会有如下报错信息:无法建立数据连接到(10.72.37.177) 端口 29814
lftp user2@10.72.37.177:~> debug
lftp user2@10.72.37.177:~> ls
---- 正在连接到 10.72.37.177(10.72.37.177) 端口 21
<--- 220 (vsFTPd 2.2.2)
---> FEAT
<--- 211-Features:
<--- EPRT
<--- EPSV
<--- MDTM
<--- PASV
<--- REST STREAM
<--- SIZE
<--- TVFS
<--- UTF8
<--- 211 End
---> OPTS UTF8 ON
<--- 200 Always in UTF8 mode.
---> USER user2
<--- 331 Please specify the password.
---> PASS XXXX
<--- 230 Login successful.
---> PASV
<--- 227 Entering Passive Mode(10,72,37,177,116,118).
---- 正在建立数据连接到(10.72.37.177) 端口 29814
`ls' at 0 [正在建立数据连接...]
...
以上,即基于node2主机上的FORWARD链实现了网络防火墙,内网主机通过node2访问外网时,通过FORWARD链实现了访问控制。
(责任编辑:IT)
实验:如下模型,node1为内网主机,IP地址为192.168.10.2;node3为外网主机,IP地址为10.72.37.177(假设此地址为公网地址),node3上提供web server和FTP Server的功能;内网主机node2主机有2块网卡,地址分别为eth0:192.168.10.1和eth2:10.72.37.91(假设此地址为公网地址); 现要求在node2上通过iptables配置实现SNAT功能,并做如下限制: 1、node1可以访问node3提供的web服务和ftp服务 2、node1只可以ping连接、ssh连接node3
SNAT实现的过程: node1与node2都是内网主机处于同一网段,所以node1是默认直接可以ping通node2主机上eth1的地址192.168.10.1;将node1主机的网关指向192.168.10.1后,node1就可以直接ping通node2的eth0上的外网地址10.72.37.91; 但此时内网主机node1肯定是无法ping通外网主机node3的地址,此时开启node2主机的路由转发功能,即可实现将node1的请求报文,经由node2转发送到node3主机上,但是node3响应此报文时,发现源地址为192.168.10.1,与自己不在同一网段内,便会交由网关去转发,而node3的网关默认也是无法识别此网络,所以响应报文也就无法返回到node2; 所以即可以配置,node2把node1的请求报文转发出去之前,将请求报文的源地址由192.168.10.2转换为10.72.37.91后再送至node3主机上,此过程中node2同时会自动生成一张NAT会话表,记录下经由node2被转发的每一条记录; node3封装响应报文时,发现源地址为10.72.37.91,所以响应报文的目标地址就会是10.72.37.91,响应报文即会被返回给node2,此时node2上就会查询NAT会话表,自动再做目标地址转换,将响应报文送至node1,此即实现了内网主机node1与外网主机node3通信了;iptables的SNAT即是实现此功能; 此过程中报文在node1、node2和node3之间传输路径如下图:
一个请求报文经由node2主机路由判断后,需要被转发出去的话,此请求报文则会经过node2主机上netfilter的链的顺序为PREROUTING--> FORWARD-->OUTROUTING,所以SNAT的规则需配置在OUTROUTING链上,而filter的规则就需要在FORWARD链上配置了(此路径中只有在FORWARD链上有filter功能表,PREROUTING和OUTROUTING链上不做filter);
总结:为了实现node1可以与node3通信需做的配置有: 1、node1主机的默认网关指向node2的eth1的地址 1、node2主机上的开启路由转发功能 2、node2主机上配置SNAT功能
配置过程: node1上: #ping 192.168.10.1 ##是可以直接ping通的 #route add default gw192.168.10.1 ##添加路由指向192.168.10.1 #ping 10.72.37.91 ##即可ping通node2主机上的另一个地址
node2上: #sysctl -wnet.ipv4.ip_forward=1 ##开启node2主机上的路由转发功能
node1上: #ping 10.72.37.177 ##此时,node1上暂且是无法ping通node3的,但是此时ping的请求包是已经可以发送到node3的
node3上: #iptables -t filter -A INPUT -j LOG ##在node3主机的INPUT链上添加LOG功能 #tail /var/log/messages ##即可看到,已记录到来自192.168.10.2即node1的ICMP请求报文 … … kernel: IN=eth0OUT= MAC=1c:6f:65:03:1b:9a:00:0c:29:fa:ea:2d:08:00 SRC=192.168.10.2DST=10.72.37.177 LEN=84 TOS=0x00 PREC=0x00 TTL=63 ID=0 DF PROTO=ICMP TYPE=8CODE=0 ID=4876 SEQ=9 ##如果此时在OUTPUT链上也记录LOG的话,也是可以看到SRC=10.72.37.177DST=192.168.10.2的响应报文,只不过是这个响应报文最终无法送达node1
node2上 #iptables -t nat -APOSTROUTING -s 192.168.10.0/24 -j SNAT --to-source 10.72.37.91 ##在node2主机上的的POSTROUTING链上向NAT表中添加,定义来自192.168.10.0的主机,无论是使用何种协议,无论访问哪个网络,通通代理出去,将源地址转换成10.72.37.91 #iptables -t nat -L POSTROUTING -nv ##在nat表的POSTROUTING链上即可看到我们添加的规则
此时,node1即可以ping通node3,而在node3主机上的log中可以看到ICMP的请求报文SRC=10.72.37.91DST=10.72.37.177和响应报文SRC=10.72.37.177DST=10.72.37.91;注意此时的与node3通信的IP地址已被SANT转换为10.72.37.91了;
node1上 #curl -I http://10.72.37.177 ##测试连接node3的web服务 #tail /var/log/nginx/access.log ##node3上查看访问日志中,客户端源地址的已是被转换后的10.72.37.91
按照要求node1只可以向node3发起ping、shh、web访问请求,所以在node2上的filter表的FORWARD链上添加如下规则:
node1通过node3上的21端口和ftp server建立命令连接后,因为ftp server默认是工作在被动模式,所以node1还需访问node3上的一个大于1024的随机端口来建立数据连接,即需要node2上将所有所有大于1024的端口都转发至node3;但是本实验又要求只允许转发21,22,80端口; 此时要求node3主机上需已装载内核模块nf_contrack_ftp;这个模块可以监控ftp控制流,能够事先知道将要建立的ftp数据连接所使用的端口,从而可以允许相应的数据包通过,即使防火墙没有开放这个端口: #modprobe nf_contrack_ftp ##手动装载此内核模块 #lsmod | grep ftp ##此时即可看到已装载 ##或者写到配置文件/etc/sysconfig/iptables-config,即可不需每次去手动装载,即使重启后也会自动装载,添加一行:IPTABLES_MOUDLES=”nf_contrack_ftp”
假若node3没有装载内核模块nf_conntrack_ftp,在node1上连接node3上的ftp服务时,就会有如下报错信息:无法建立数据连接到(10.72.37.177) 端口 29814 lftp user2@10.72.37.177:~> debug lftp user2@10.72.37.177:~> ls ---- 正在连接到 10.72.37.177(10.72.37.177) 端口 21 <--- 220 (vsFTPd 2.2.2) ---> FEAT <--- 211-Features: <--- EPRT <--- EPSV <--- MDTM <--- PASV <--- REST STREAM <--- SIZE <--- TVFS <--- UTF8 <--- 211 End ---> OPTS UTF8 ON <--- 200 Always in UTF8 mode. ---> USER user2 <--- 331 Please specify the password. ---> PASS XXXX <--- 230 Login successful. ---> PASV <--- 227 Entering Passive Mode(10,72,37,177,116,118). ---- 正在建立数据连接到(10.72.37.177) 端口 29814 `ls' at 0 [正在建立数据连接...] ... 以上,即基于node2主机上的FORWARD链实现了网络防火墙,内网主机通过node2访问外网时,通过FORWARD链实现了访问控制。 (责任编辑:IT) |