规则的顺序很重要,一旦有一个规则匹配成功了,后面的规则将会被忽略
- -I: 指定一个链,表示要加入一条规则在链中,放在所有规则的首部
- -A:指定一个链,追加一条规则,放在所有规则尾部
10.10.28.18的网关是10.10.28.1
root@ubuntu:/home/devuser# ping 8.8.8.8 PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data. 64 bytes from 8.8.8.8: icmp_seq=1 ttl=251 time=2.84 ms 64 bytes from 8.8.8.8: icmp_seq=2 ttl=251 time=2.67 ms ^C --- 8.8.8.8 ping statistics --- 2 packets transmitted, 2 received, 0% packet loss, time 1001ms rtt min/avg/max/mdev = 2.677/2.759/2.842/0.097 ms root@ubuntu:/home/devuser#
root@ubuntu:/home/devuser# tcpdump -i enp1s0 icmp and host 10.10.28.18 tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on enp1s0, link-type EN10MB (Ethernet), capture size 262144 bytes 16:55:13.696084 IP 10.10.28.18 > dns.google: ICMP echo request, id 2943, seq 1, length 64 16:55:13.698672 IP dns.google > 10.10.28.18: ICMP echo reply, id 2943, seq 1, length 64 16:55:14.697137 IP 10.10.28.18 > dns.google: ICMP echo request, id 2943, seq 2, length 64 16:55:14.699610 IP dns.google > 10.10.28.18: ICMP echo reply, id 2943, seq 2, length 64 16:55:15.699053 IP 10.10.28.18 > dns.google: ICMP echo request, id 2943, seq 3, length 64 16:55:15.701513 IP dns.google > 10.10.28.18: ICMP echo reply, id 2943, seq 3, length 64 16:55:16.700986 IP 10.10.28.18 > dns.google: ICMP echo request, id 2943, seq 4, length 64 16:55:16.703475 IP dns.google > 10.10.28.18: ICMP echo reply, id 2943, seq 4, length 64
10.10.28.18 经过10.10.18.1时 下述规则生效
19 3 252 MASQUERADE all -- * * 10.10.28.18 !10.10.28.0/24
8.8.8-->10.10.18.1 回包时
3189 167K MASQUERADE all -- * * !10.10.28.1 10.10.28.0/24
抓包应该看不到dns.google ,实际上看到了
root@PORT:~# conntrack -L | grep 10.10.28.18 tcp 6 115 SYN_SENT src=10.10.28.18 dst=8.8.8.8 sport=48352 dport=22 [UNREPLIED] src=8.8.8.8 dst=210.xx.xx.151 sport=22 dport=48352 mark=0 use=1 icmp 1 15 src=10.10.28.18 dst=8.8.8.8 type=8 code=0 id=2958 src=8.8.8.8 dst=210.xx.xx.151 type=0 code=0 id=2958 mark=0 use=1 conntrack v1.4.3 (conntrack-tools): 113 flow entries have been shown. tcp 6 431996 ESTABLISHED src=10.10.28.1 dst=10.10.28.18 sport=35230 dport=22 src=10.10.28.18 dst=10.10.28.1 sport=22 dport=35230 [ASSURED] mark=0 use=1 root@PORT:~#
root@ubuntu:/home/devuser# ping 10.10.16.82 PING 10.10.16.82 (10.10.16.82) 56(84) bytes of data. 64 bytes from 10.10.16.82: icmp_seq=1 ttl=63 time=0.236 ms 64 bytes from 10.10.16.82: icmp_seq=2 ttl=63 time=0.122 ms 64 bytes from 10.10.16.82: icmp_seq=3 ttl=63 time=0.123 ms ^C --- 10.10.16.82 ping statistics --- 3 packets transmitted, 3 received, 0% packet loss, time 2055ms rtt min/avg/max/mdev = 0.122/0.160/0.236/0.054 ms root@ubuntu:/home/devuser#
root@PORT:~# conntrack -L | grep 10.10.28.18 icmp 1 24 src=10.10.28.18 dst=10.10.16.82 type=8 code=0 id=2965 src=10.10.16.82 dst=10.10.16.1 type=0 code=0 id=2965 mark=0 use=1 conntrack v1.4.3 (conntrack-tools): 115 flow entries have been shown. tcp 6 431994 ESTABLISHED src=10.10.28.1 dst=10.10.28.18 sport=35230 dport=22 src=10.10.28.18 dst=10.10.28.1 sport=22 dport=35230 [ASSURED] mark=0 use=1
iptables nat&conntrack的特殊之处
问题与解释
我在PREROUTING上做了一个REDIRECT端口改写,相应的服务处理请求后会返回应答。
按照我以往的认识,认为回包的流量应该先后经过OUTPUT和POSTROUTING,所以我利用iptables -t nat -nvL去查看NAT表在OUTPUT链和POSTROUTING链上的packge计数器,结果发现没有上涨,这让我陷入了沉思。
经过谷歌后找到了完美的解释:linux-netfilter-how-does-connection-tracking-track-connections-changed-by-nat。
实际上我是知道OUTPUT链会先过conntrack表恢复原始IP关系的,但是超出我理解的是NAT表压根就不会再执行。
上述URL中给出了解释:NAT表只在连接状态是NEW的时候(也就是TCP的第一个握手包)才会执行计算,一旦改写关系存入了conntrack,那么这条连接后续的通讯就不会再过POSTROUTING和OUTPUT上面的NAT表了,而是直接换成了匹配conntrack来复原连接之前的改写状态。
因此,如果我们想看到回包的package计数器增长,就应该去看OUTPUT或者POSTROUTING上面的filter表计数,一定会看到上涨。
再次梳理流程
如果我们是服务端,那么SYN包到达的时候,在POSTROUTING链的NAT表执行过之后(可能做DNAT或者REDIRECT),路由表将决定是FORWARD还是INPUT:
- 如果INPUT,那么conntrack记录就此生成,当回包的时候会首先根据conntrack作地址复原,并且是不会经过OUTPUT/POSTROUTING链NAT表(但是会经过filter表)的。
- 如果FORWARD,那么conntrack记录不会立即生成,需要经过POSTROUTING之后才知道是否做了SNAT/MASQUERADE,此时才会生成conntrack记录。当收到上游回包的时候,不会过PREROUTING的NAT表,而是直接根据conntrack复原为原始IP地址,然后直接FORWARD->POSTROUTING(不会过NAT表)送回原始客户端。