龙之介大人

iptables的SNAT与DNAT使用详解
iptables的NAT,DNAT使用示例环境模拟主机规划#公网主机:192.168.1.102 #路由器wan:...
扫描右侧二维码阅读全文
15
2020/02

iptables的SNAT与DNAT使用详解

iptables的NAT,DNAT使用示例

环境模拟

  • 主机规划
#公网主机:192.168.1.102
#路由器wan:192.168.106;lan:10.10.2.1
#内网主机:10.10.2.2
模拟拓扑:

  • NAT之间的区别
# SNAT: 只修改请求报文的源地址;
# DNAT: 只修改请求报文的目标地址;

#NAT 表
PREROUTING: DNAT
OUTPUT
POSTROUTING: SNAT

SNAT模拟过程示例

#公网主机配置路由
[root@public-ser ~]# route add -net 10.10.2.0/24 gw 192.168.1.106  #测试SNAT时删除这条路由

#网关地址配置及路由配置
[root@gateway ~]# ip addr add 10.10.2.1/24 dev eth1
[root@gateway ~]# route add -net 10.10.2.0/24 gw 10.10.2.1

#内网主机配置IP及路由
[root@node1 ~]# ip addr add 10.10.2.2/24 dev eth1
[root@node1 ~]# route add -net 192.168.1.0/24 gw 10.10.2.1

#网络连通测试
[root@node1 ~]# ping -c 2 192.168.1.102
PING 192.168.1.102 (192.168.1.102) 56(84) bytes of data.
64 bytes from 192.168.1.102: icmp_seq=1 ttl=63 time=0.397 ms
64 bytes from 192.168.1.102: icmp_seq=2 ttl=63 time=0.748 ms
[root@public-ser ~]# ping -c 2 10.10.2.2
PING 10.10.2.2 (10.10.2.2) 56(84) bytes of data.
64 bytes from 10.10.2.2: icmp_seq=1 ttl=63 time=1.50 ms
64 bytes from 10.10.2.2: icmp_seq=2 ttl=63 time=0.745 ms

##1. 网关开启内核转发及清除默认规则
[root@gateway ~]# sysctl -w net.ipv4.ip_forward=1
net.ipv4.ip_forward = 1

##2. SNAT方式;内网主机访问外网主机用SNAT方式进行
#内网访问外的httpd服务
[root@node1 ~]# curl 192.168.1.102  #在外网主机没有添加路由时时无法返回内容给客户机
^C
#在外网服务器抓包看看
[root@public-ser ~]# tcpdump -i eth0 host 10.10.2.2
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes
21:06:18.249530 IP 10.10.2.2.56372 > public-ser.http: Flags [S], seq 2423564944, win 29200, options [mss 1460,sackOK,TS val 45534429 ecr 0,nop,wscale 7], length 0
21:06:18.249572 IP public-ser.http > 10.10.2.2.56372: Flags [S.], seq 2009409078, ack 2423564945, win 28960, options [mss 1460,sackOK,TS val 32674544 ecr 45534429,nop,wscale 7], length 0
21:06:19.252394 IP 10.10.2.2.56372 > public-ser.http: Flags [S], seq 2423564944, win 29200, options [mss 1460,sackOK,TS val 45535432 ecr 0,nop,wscale 7], length 0
21:06:19.252433 IP public-ser.http > 10.10.2.2.56372: Flags [S.], seq 2009409078, ack 2423564945, win 28960, options [mss 1460,sackOK,TS val 32675547 ecr 45534429,nop,wscale 7], length 0
21:06:20.606057 IP public-ser.http > 10.10.2.2.56372: Flags [S.], seq 2009409078, ack 2423564945, win 28960, options [mss 1460,sackOK,TS val 32676901 ecr 45534429,nop,wscale 7], length 0
21:06:21.255958 IP 10.10.2.2.56372 > public-ser.http: Flags [S], seq 2423564944, win 29200, options [mss 
^C
#抓包可以看到内网10.10.2.2的主机访问成功了外网的httpd服务;但是外网主机没有办法回应内网的用户;

# 添加路由时访问测试和抓包数据
[root@public-ser ~]# route add -net 10.10.2.0/24 gw 192.168.1.106

[root@node1 ~]# curl 192.168.1.102
is public server!this IP:192.168.1.102
#外网主机抓包数据
[root@public-ser ~]# tcpdump -i eth0 host 10.10.2.2
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes
21:12:27.453658 IP 10.10.2.2.56378 > public-ser.http: Flags [S], seq 901322029, win 29200, options [mss 1460,sackOK,TS val 45903632 ecr 0,nop,wscale 7], length 0
21:12:27.453729 IP public-ser.http > 10.10.2.2.56378: Flags [S.], seq 2943397281, ack 901322030, win 28960, options [mss 1460,sackOK,TS val 33043748 ecr 45903632,nop,wscale 7], length 0
21:12:27.454099 IP 10.10.2.2.56378 > public-ser.http: Flags [.], ack 1, win 229, options [nop,nop,TS val 45903634 ecr 33043748], length 0
21:12:27.454196 IP 10.10.2.2.56378 > public-ser.http: Flags [P.], seq 1:78, ack 1, win 229, options [nop,nop,TS val 45903634 ecr 33043748], length 77: HTTP: GET / HTTP/1.1
21:12:27.454219 IP public-ser.http > 10.10.2.2.56378: Flags [.], ack 78, win 227, options [nop,nop,TS val 33043749 ecr 45903634], length 0
21:12:27.454643 IP public-ser.http > 10.10.2.2.56378: Flags [P.], seq 1:281, ack 78, win 227, options [nop,nop,TS val 33043749 ecr 45903634], length 280: HTTP: HTTP/1.1 200 OK
21:12:27.454992 IP 10.10.2.2.56378 > public-ser.http: Flags [.], ack 281, win 237, options [nop,nop,TS val 45903634 ecr 33043749], length 0
21:12:27.455099 IP 10.10.2.2.56378 > public-ser.http: Flags [F.], seq 78, ack 281, win 237, options [nop,nop,TS val 45903635 ecr 33043749], length 0
21:12:27.455134 IP public-ser.http > 10.10.2.2.56378: Flags [F.], seq 281, ack 79, win 227, options [nop,nop,TS val 33043750 ecr 45903635], length 0
21:12:27.455350 IP 10.10.2.2.56378 > public-ser.http: Flags [.], ack 282, win 237, options [nop,nop,TS val 45903635 ecr 33043750], length 0

#网关抓包数据
[root@gateway ~]# tcpdump -i eth0 host 192.168.1.102
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes
21:14:11.264985 ARP, Request who-has 192.168.1.101 tell 192.168.1.102, length 46
21:14:11.264997 ARP, Reply 192.168.1.101 is-at f8:94:c2:db:b5:be (oui Unknown), length 46
21:14:12.671193 IP 10.10.2.2.56380 > 192.168.1.102.http: Flags [S], seq 909170526, win 29200, options [mss 1460,sackOK,TS val 46008858 ecr 0,nop,wscale 7], length 0
21:14:12.671534 IP 192.168.1.102.http > 10.10.2.2.56380: Flags [S.], seq 773281030, ack 909170527, win 28960, options [mss 1460,sackOK,TS val 33148975 ecr 46008858,nop,wscale 7], length 0
21:14:12.671802 IP 192.168.1.102.ssh > 192.168.1.101.57963: Flags [P.], seq 3518080131:3518080519, ack 1566365748, win 252, length 388
21:14:12.671929 IP 10.10.2.2.56380 > 192.168.1.102.http: Flags [.], ack 1, win 229, options [nop,nop,TS val 46008860 ecr 33148975], length 0
21:14:12.672024 IP 10.10.2.2.56380 > 192.168.1.102.http: Flags [P.], seq 1:78, ack 1, win 229, options [nop,nop,TS val 46008860 ecr 33148975], length 77: HTTP: GET / HTTP/1.1
21:14:12.672162 IP 192.168.1.102.http > 10.10.2.2.56380: Flags [.], ack 78, win 227, options [nop,nop,TS val 33148975 ecr 46008860], length 0
21:14:12.672371 IP 192.168.1.102.http > 10.10.2.2.56380: Flags [P.], seq 1:281, ack 78, win 227, options [nop,nop,TS val 33148975 ecr 46008860], length 280: HTTP: HTTP/1.1 200 OK
21:14:12.672774 IP 192.168.1.102.ssh > 192.168.1.101.57963: Flags [P.], seq 388:1056, ack 1, win 252, length 668
21:14:12.672777 IP 192.168.1.101.57963 > 192.168.1.102.ssh: Flags [.], ack 1056, win 4102, length 0
21:14:12.672790 IP 10.10.2.2.56380 > 192.168.1.102.http: Flags [.], ack 281, win 237, options [nop,nop,TS val 46008860 ecr 33148975], length 0
  • SNAT 测试流程
#删除上面测试时在外网主机添加的路由信息
[root@public-ser ~]# route del -net 10.10.2.0/24 gw 192.168.1.106
[root@public-ser ~]# route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         192.168.1.1     0.0.0.0         UG    100    0        0 eth0
192.168.1.0     0.0.0.0         255.255.255.0   U     100    0        0 eth0
#内网在测试一下结果
[root@node1 ~]# curl 192.168.1.102
^C

##1. 在网关做SNAT 
#POSTROUTING链路
[root@gateway ~]# iptables -t nat -A POSTROUTING -s 10.10.2.0/24 ! -d 10.10.2.0/24 -j SNAT --to-source 192.168.1.106
# 在nat表的POSTROUTING链路上源地址是10.10.2.0/24的主机,目标是非10.10.2.0/24 的主机做SNAT到源 192.168.1.106主机
[root@gateway ~]# iptables -t nat -L POSTROUTING -n -v
Chain POSTROUTING (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 SNAT       all  --  *      *       10.10.2.0/24        !10.10.2.0/24         to:192.168.1.106
#内网主机测试结果
[root@node1 ~]# curl 192.168.1.102
is public server!this IP:192.168.1.102

#外网主机的日志及数据包文
[root@public-ser ~]# tail -n 1 /var/log/httpd/access_log  #外网主机的httpd日志显示的也是网关地址
192.168.1.106 - - [15/Feb/2020:21:24:36 +0800] "GET / HTTP/1.1" 200 39 "-" "curl/7.29.0"
#tcpdump报文
[root@public-ser ~]# tcpdump -i eth0 host 192.168.1.106
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes
21:27:24.216029 IP 192.168.1.106.56388 > public-ser.http: Flags [S], seq 2890427396, win 29200, options [mss 1460,sackOK,TS val 46800394 ecr 0,nop,wscale 7], length 0
21:27:24.216061 IP public-ser.http > 192.168.1.106.56388: Flags [S.], seq 4122664105, ack 2890427397, win 28960, options [mss 1460,sackOK,TS val 33940511 ecr 46800394,nop,wscale 7], length 0
21:27:24.216331 IP 192.168.1.106.56388 > public-ser.http: Flags [.], ack 1, win 229, options [nop,nop,TS val 46800395 ecr 33940511], length 0
21:27:24.216495 IP 192.168.1.106.56388 > public-ser.http: Flags [P.], seq 1:78, ack 1, win 229, options [nop,nop,TS val 46800395 ecr 33940511], length 77: HTTP: GET / HTTP/1.1
21:27:24.216512 IP public-ser.http > 192.168.1.106.56388: Flags [.], ack 78, win 227, options [nop,nop,TS val 33940511 ecr 46800395], length 0
21:27:24.216690 IP public-ser.http > 192.168.1.106.56388: Flags [P.], seq 1:281, ack 78, win 227, options [nop,nop,TS val 33940511 ecr 46800395], length 280: HTTP: HTTP/1.1 200 OK
21:27:24.216946 IP 192.168.1.106.56388 > public-ser.http: Flags [.], ack 281, win 237, options [nop,nop,TS val 46800395 ecr 33940511], length 0
21:27:24.217053 IP 192.168.1.106.56388 > public-ser.http: Flags [F.], seq 78, ack 281, win 237, options [nop,nop,TS val 46800395 ecr 33940511], length 0
21:27:24.217097 IP public-ser.http > 192.168.1.106.56388: Flags [F.], seq 281, ack 79, win 227, options [nop,nop,TS val 33940512 ecr 46800395], length 0

#网关iptables的匹配信息
[root@gateway ~]# iptables -t nat -L POSTROUTING -n -v
Chain POSTROUTING (policy ACCEPT 6 packets, 436 bytes)
 pkts bytes target     prot opt in     out     source               destination         
    3   180 SNAT       all  --  *      *       10.10.2.0/24        !10.10.2.0/24         to:192.168.1.106

DNAT 模拟示例

以上面的拓扑示例进行反正,外网主机变成内网主机;内网主机变成外网主机;
##1. 清空nat表规则
[root@gateway ~]# iptables -t nat -F
#网关测内网主机的httpd服务
[root@gateway ~]# curl 10.10.2.2
this is 10.10.2.2 server!
#外网主机访问内网测试
[root@public-ser ~]# curl 192.168.1.106
^C

##2. DNAT转换规则定义
[root@gateway ~]# iptables -t nat -A PREROUTING -d 192.168.1.106 -p tcp --dport 80 -j DNAT --to-destination 10.10.2.2
# 在PREROUTING链路添加规则,目标地址是192.168.1.106 协议是tcp 端口是80 做DNAT 转换为10.10.2.2内网主机的地址

[root@public-ser ~]# curl 192.168.1.106  #测试DNAT后可以正常访问
this is 10.10.2.2 server!

#httpd日志信息
[root@node1 ~]# tail -n 2 /var/log/httpd/access_log 
192.168.1.102 - - [15/Feb/2020:21:37:23 +0800] "GET / HTTP/1.1" 200 26 "-" "curl/7.29.0"


##2. 例如内网的httpd端口是8080 在做DNAT时候进行端口映射
[root@node1 ~]# netstat -luntp | grep 8080
tcp        0      0 0.0.0.0:8080            0.0.0.0:*               LISTEN      3498/httpd
#网关修改DNAT规则进行端口映射到内网的8080
[root@gateway ~]# iptables -t nat -R PREROUTING 1 -d 192.168.1.106 -p tcp --dport 80 -j DNAT --to-destination 10.10.2.2:8080
[root@gateway ~]# iptables -t nat -L PREROUTING -n -v
Chain PREROUTING (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 DNAT       tcp  --  *      *       0.0.0.0/0            192.168.1.106        tcp dpt:80 to:10.10.2.2:8080
#外网主机访问测试
[root@public-ser ~]# curl 192.168.1.106
this is 10.10.2.2 server!

ADSL动态地址策略

如果是ADSL拨号;那么IP会不停的变动,NAT的to-source地址也会变动;如何才能考录到NAT有不用频繁的变动--to-source地址呢?

可以是用MASQUERADE(地址伪装),自动找一个适合的外网地址进行转换
#例如:网关地址的IP:192.168.1.106会经常变换那个就没有办法使用--to-source进行转换
[root@gateway ~]# iptables -t nat -A POSTROUTING -s 10.10.2.2/24 ! -d 10.10.2.0/24 -j MASQUERADE
[root@gateway ~]# iptables -t nat -L POSTROUTING -n -v
Chain POSTROUTING (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 MASQUERADE  all  --  *      *       10.10.2.0/24        !10.10.2.0/24
#内网主机访问外网主机测试:
[root@node1 ~]# curl 192.168.1.102
is public server!this IP:192.168.1.102

总结

  • 规则使用总结:
#源地址转换:
iptables -t nat -A POSTROUTING -s LocalNET ! -d LocalNet -j SNAT --to-source ExtIP
iptables -t nat -A POSTROUTING -s LocalNET ! -d LocalNet -j MASQUERADE   #主要用于IP地址变化的情况

#目标地址转换:
iptables -t nat -A PREROUTING -d ExtIP -p tcp|udp --dport PORT -j DNAT --to-destination InterSeverIP[:PORT]

注意

iptables的链接跟踪表最大容量为/proc/sys/net/ipv4/ip_conntrack_max,链接碰到各种状态的超时后就会从表中删除。
  • 解决办法有两个:
#1. 加大 ip_conntrack_max 值
vim /etc/sysctl.conf
net.ipv4.ip_conntrack_max = 393216
net.ipv4.netfilter.ip_conntrack_max = 393216

#2. 降低 ip_conntrack timeout时间
vim /etc/sysctl.conf
net.ipv4.netfilter.ip_conntrack_tcp_timeout_established = 300
net.ipv4.netfilter.ip_conntrack_tcp_timeout_time_wait = 120
net.ipv4.netfilter.ip_conntrack_tcp_timeout_close_wait = 60
net.ipv4.netfilter.ip_conntrack_tcp_timeout_fin_wait = 120
最后修改:2020 年 02 月 15 日 10 : 07 PM

发表评论