iptables其实就是通过表的形式对我们的数据包进行一些限制。
这里的话我们只实验常见的表和链,其他的暂先不实验,因为用的很少。
1. filter表:对进入宿主机和从宿主机发出去的数据包进行过滤
2. nat表:网络地址转换,DNAT,数据包到了当前宿主机的时候,我们把数据的目的地址/端口修改了,然后就可以转发到其他机器了。SNAT,反之。
我们先查看一下宿主当前的规则
[root@master1 ~]# iptables -t filter -nvL
Chain INPUT (policy ACCEPT 142 packets, 7804 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 DOCKER-USER all -- * * 0.0.0.0/0 0.0.0.0/0
0 0 DOCKER-ISOLATION-STAGE-1 all -- * * 0.0.0.0/0 0.0.0.0/0
0 0 ACCEPT all -- * docker0 0.0.0.0/0 0.0.0.0/0 ctstate RELATED,ESTABLISHED
0 0 DOCKER all -- * docker0 0.0.0.0/0 0.0.0.0/0
0 0 ACCEPT all -- docker0 !docker0 0.0.0.0/0 0.0.0.0/0
0 0 ACCEPT all -- docker0 docker0 0.0.0.0/0 0.0.0.0/0
0 0 ACCEPT all -- * br-acc96e30ac37 0.0.0.0/0 0.0.0.0/0 ctstate RELATED,ESTABLISHED
0 0 DOCKER all -- * br-acc96e30ac37 0.0.0.0/0 0.0.0.0/0
0 0 ACCEPT all -- br-acc96e30ac37 !br-acc96e30ac37 0.0.0.0/0 0.0.0.0/0
0 0 ACCEPT all -- br-acc96e30ac37 br-acc96e30ac37 0.0.0.0/0 0.0.0.0/0
0 0 ACCEPT all -- * br-3330b1262d6f 0.0.0.0/0 0.0.0.0/0 ctstate RELATED,ESTABLISHED
0 0 DOCKER all -- * br-3330b1262d6f 0.0.0.0/0 0.0.0.0/0
0 0 ACCEPT all -- br-3330b1262d6f !br-3330b1262d6f 0.0.0.0/0 0.0.0.0/0
0 0 ACCEPT all -- br-3330b1262d6f br-3330b1262d6f 0.0.0.0/0 0.0.0.0/0
0 0 ACCEPT all -- * docker_gwbridge 0.0.0.0/0 0.0.0.0/0 ctstate RELATED,ESTABLISHED
0 0 DOCKER all -- * docker_gwbridge 0.0.0.0/0 0.0.0.0/0
0 0 ACCEPT all -- docker_gwbridge !docker_gwbridge 0.0.0.0/0 0.0.0.0/0
0 0 DROP all -- docker_gwbridge docker_gwbridge 0.0.0.0/0 0.0.0.0/0
Chain OUTPUT (policy ACCEPT 135 packets, 8508 bytes)
pkts bytes target prot opt in out source destination
Chain DOCKER (4 references)
pkts bytes target prot opt in out source destination
Chain DOCKER-ISOLATION-STAGE-1 (1 references)
pkts bytes target prot opt in out source destination
0 0 DOCKER-ISOLATION-STAGE-2 all -- docker0 !docker0 0.0.0.0/0 0.0.0.0/0
0 0 DOCKER-ISOLATION-STAGE-2 all -- br-acc96e30ac37 !br-acc96e30ac37 0.0.0.0/0 0.0.0.0/0
0 0 DOCKER-ISOLATION-STAGE-2 all -- br-3330b1262d6f !br-3330b1262d6f 0.0.0.0/0 0.0.0.0/0
0 0 DOCKER-ISOLATION-STAGE-2 all -- docker_gwbridge !docker_gwbridge 0.0.0.0/0 0.0.0.0/0
0 0 RETURN all -- * * 0.0.0.0/0 0.0.0.0/0
Chain DOCKER-ISOLATION-STAGE-2 (4 references)
pkts bytes target prot opt in out source destination
0 0 DROP all -- * docker0 0.0.0.0/0 0.0.0.0/0
0 0 DROP all -- * br-acc96e30ac37 0.0.0.0/0 0.0.0.0/0
0 0 DROP all -- * br-3330b1262d6f 0.0.0.0/0 0.0.0.0/0
0 0 DROP all -- * docker_gwbridge 0.0.0.0/0 0.0.0.0/0
0 0 RETURN all -- * * 0.0.0.0/0 0.0.0.0/0
Chain DOCKER-USER (1 references)
pkts bytes target prot opt in out source destination
0 0 RETURN all -- * * 0.0.0.0/0 0.0.0.0/0
[root@master1 ~]#
关于DOCKER-xxx的一些规则先不管,这是docker创建的,后边有学习到这部分再细讲吧。
这里我们只关心INPUT ,FORWARD ,OUTPUT 这三个链,这里的话,网上有一个经典的图片来表示我们数据包进入本机和出去的过程
总的来说,我们的数据包就两条路,要么发送给本机,要么就发送给其他机器。发送给其他机器的话,就多了一个FORWARD链,这个我们下面有试验。
我们先试验INPUT和OUTPUT
关于INPUT和OUTPUT的字段这块可以参考另外的文章
我们直接开始试验filter表中的INPUT和OUTPUT
这里先试验INPUT,通过前面的命令,可以看到我们的INPUT和OUTPUT对于数据包的处理都是ACCEPT,这里我们在宿主机上启动一个nginx,然后访问
现在我们添加一条规则,让本机收到80端口的数据包,就直接丢弃
[root@master1 ~]# iptables -t filter -A INPUT -j DROP -p tcp --dport 80
然后再次访问,结果访问不了,证明规则生效
[root@master1 ~]# iptables -t filter -nvL
Chain INPUT (policy ACCEPT 542 packets, 30534 bytes)
pkts bytes target prot opt in out source destination
45 2340 DROP tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:80
..........
[root@master1 ~]# iptables -t filter -D INPUT 1
//因为我们就添加了一条规则,后边这个数字表示第几条
现在试验一下OUTPUT的规则
[root@master1 ~]# iptables -t filter -A OUTPUT -j DROP -p tcp --dport 22-d 192.168.64.151
上面的规则是,只要发送到192.168.64.151,并且端口是80的数据包都要被丢弃掉,80是sshd的默认端口,这个时候,我就无法远程连接151这台机器了。
[root@master1 ~]# ssh root@192.168.64.151
ssh: connect to host 192.168.64.151 port 22: Connection timed out
删除这条规则
[root@master1 ~]# iptables -t filter -D OUTPUT 1
[root@master1 ~]# ssh root@192.168.64.151
root@192.168.64.151's password:
现在试验FORWARD的规则,FORWARD是当收到需要通过防火中转发给其他地址的数据包时,将应用此链中的规则,所以这个时候需要nat表了
[root@master1 ~]# iptables -t nat -nvL
Chain PREROUTING (policy ACCEPT 148 packets, 8880 bytes)
pkts bytes target prot opt in out source destination
148 8880 DOCKER all -- * * 0.0.0.0/0 0.0.0.0/0 ADDRTYPE match dst-type LOCAL
Chain INPUT (policy ACCEPT 148 packets, 8880 bytes)
pkts bytes target prot opt in out source destination
Chain OUTPUT (policy ACCEPT 144 packets, 8688 bytes)
pkts bytes target prot opt in out source destination
213 12780 DOCKER all -- * * 0.0.0.0/0 !127.0.0.0/8 ADDRTYPE match dst-type LOCAL
Chain POSTROUTING (policy ACCEPT 144 packets, 8688 bytes)
pkts bytes target prot opt in out source destination
0 0 MASQUERADE all -- * !docker0 172.17.0.0/16 0.0.0.0/0
0 0 MASQUERADE all -- * !br-acc96e30ac37 172.19.0.0/16 0.0.0.0/0
0 0 MASQUERADE all -- * !br-3330b1262d6f 172.20.0.0/16 0.0.0.0/0
0 0 MASQUERADE all -- * !docker_gwbridge 172.18.0.0/16 0.0.0.0/0
Chain DOCKER (2 references)
pkts bytes target prot opt in out source destination
0 0 RETURN all -- docker0 * 0.0.0.0/0 0.0.0.0/0
0 0 RETURN all -- docker_gwbridge * 0.0.0.0/0 0.0.0.0/0
0 0 RETURN all -- br-acc96e30ac37 * 0.0.0.0/0 0.0.0.0/0
0 0 RETURN all -- br-3330b1262d6f * 0.0.0.0/0 0.0.0.0/0
[root@master1 ~]#
nat表中多了POSTROUTING 和PREROUTING 这两个链,它们的意思是
PREROUTING :在对数据包做路由选择之前,将应用此链中的规则,如果想要修改目的地址的话,因为目前是发往本机的,所以我们在这个时候把数据包的目的地址给改了,这样就跳转到其他机器上去了。
POSTROUTING :在对数据包做路由选择之后,将应用此链中的规则,这个是改源地址的。
我们现在有两台机器
master1 192.168.64.150,没有运行nginx
[root@master1 ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
[root@master1 ~]#
master2 192.168.64.151,运行着nginx
[root@master2 ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
75919ba70120 nginx "/docker-entrypoint.…" 18 minutes ago Up 18 minutes 0.0.0.0:7751->80/tcp zen_kowalevski
[root@master2 ~]#
我们要做的事情就是把发到192.168.64.150:7750的数据包发送到192.168.64.151:7751上。
把192.168.64.150:7750发送到192.168.64.151:7751的数据包源地址改成192.168.64.150
iptables -t nat -A PREROUTING -p tcp --dport 7750 -j DNAT --to 192.168.64.151:7751
我们数据包经过上面的转换,已经可以发送到192.168.64.151了,但是访问的是nginx服务器,这个时候有个响应的过程,响应的话需要添加下面的规则才可以。
iptables -t nat -A POSTROUTING -p tcp -d 192.168.64.151 --dport 7751 -j SNAT --to 192.168.64.150
【 -j SNAT --to 192.168.64.150 等价于 -j MASQUERADE】
补充一下我测试环境的规则