4表5链。
4表
- raw
- mangle
- filter
- nat
5链
- prerouting
- input
- output
- forward
- postrouting
- filter表
- INPUT:对访问本机的数据包进行过滤
- FORWARD:对途经本机的数据包进行过滤
- OUTPUT:对本机发出的访问其他网络的包进行过滤
- 总结:根据规则来处理数据包,如转或者丢,实现主机型防火墙的主要表,内核模块 iptable_filter。
- nat 表
- PREROUTIBNG:修改目的地址
- POSTROUTING:修改源地址
- OUTPUT:主要是控制内部发出的数据包,POSTROUTING中的数据包有可能是直接FORWARD过来的
- 总结:转换地址的表(改IP、改端口),内核模块 iptable_nat
- mangle 表
- PREROPUTING、INPUT、OUTPUT、FORWARD、POSTROUTING
- 流量整形的表,路由标记用的表,改TOS,TTL,Mark标记策略路由等,iptable_mangle
- raw
- PREROUTING、OUTPUT
- 新表,数据包跟踪,iptable_raw
同时有多张表生效时的一个先后顺序。表的应用顺序:raw-->mangle-->nat-->filter
同样的,链之间也有先后顺序:入站-->转发-->出站
规则也有顺序:ACL逐条匹配,匹配到即停止。
命令语法
iptables -t 表名 管理选项 [链名][匹配条件][-j 控制类型]
- -t 表名:raw、mangle、nat、filter,不写默认为 filter表
- 管理选项:操作方式,如添加(A)、插入(I)、查看(L)、删除(D)等
- 添加:Add,在链的末尾追加一条规则
- 插入:Insert,在链的开头(或指定位置)插入一条规则
- 删除:Delete
- 查看:List
- 链名:PREROPUTING、INPUT、OUTPUT、FORWARD、POSTROUTING
- 匹配条件:数据包特征 ip、端口等
- 控制类型:数据包处理方式
- ACCEPT:允许
- REJECT:拒绝,会返回一个拒绝数据包作为回应
- DROP:丢弃,直接丢弃,不做任何回复
- LOG:日志
需求:禁止当前机器被ping
具体实现:在 filter 表的 INPUT 链插入一个丢弃 icmp 的规则。
# 添加
iptables -t filter -A INPUT -p icmp -j REJECT
# 查看
iptables -t filter -L
# 删除
iptables -t filter -D INPUT -p icmp -j REJECT
-
添加规则
- -A:在链的末尾追加一条规则
- -I:在链的开头(或指定位置)插入一条规则
-
查看规则
- -L:列出所有规则条目
- -n:以数字形式显示地址、端口等信息
- -v:以更详细的方式显示规则信息
- --line-numbers:查看规则时,显示规则的序号,后续可以直接通过序号进行删除,或者插入到具体位置
-
删除、清空规则
- -D:删除链内指定序号(或内容)的一条规则
- -F:清空所有的规则(-X 是清理自定义的链,用的少,-Z 清零规则序号)
-
设置默认规则
- -P:为指定的链设置默认规则,默认规则优先级最低,如果其他规则都匹配不上才会进默认规则
- 示例:
iptables -t filter -P INPUT DROP
# 追加一条规则
iptables -t filter -A INPUT -p tcp -j ACCEPT
# 插入到第一行
iptables -t filter -I INPUT -p udp -j ACCEPT
# 插入到第二行
iptables -t filter -I INPUT 2 -p icmp -j ACCEPT
# 查看
iptables -t filter -L
# 删除第三条骨子额
iptables -t filter -D INPUT 3
# 清空所有规则(清不了默认规则)
iptables -t filter -F
# 修改默认规则
iptables -t filter -P INTPUT ACCEPT
# 丢弃icmp的包,不让别人ping自己
iptables -t filter -I INPUT -p icmp -j DROP
#禁止源122.1的主机进来(换其他主机是可以进来的)
iptables -t filter -I INPUT -s 192.168.122.1 -j REJECT
#禁止源10网段的数据包
iptables -t filter -I INPUT -s 192.168.122.0/24 -j DROP
#谁也连不上
iptables -t filter -I INPUT -o eth0 -j DROP
端口匹配
--sprot/--dport,需要协议的前提
#允许个别端口
iptables -t filter -I INPUT -s 192.168.100.254/24 -p tcp --dport 80 -j ACCEPT
#这是一片端口,表示范围20~21,24500~24600
iptables -t filter -I INPUT -p tcp --dport 20:21 -j ACCEPT
iptables -t filter -I INPUT -p tcp --dport 24500:24600 -j ACCEPT
标记位匹配(SYN、ACK、RST)
iptables -t filter -I INPUT -i eth0 -p tcp --tcp-flags SYNC,RST,ACK SYN -j DROP
ICMP类型匹配
ICMP 类型:请求为8,应答为0.
#自己ping别人可以,反过来不行 icmp-type 8 就是指定把icmp的请求包丢弃了,所以别人不能ping我
# 但是应答包是可以接收的,所以我可以ping别人(前提是ping的那个机器没有禁止ping)
iptables -t filter -I INPUT -p icmp --icmp-type 8 -j DROP
通过调用模块,lsmod|grep xt_ 来加载内核扩展模块,如端口匹配,IP范围,MAC地址,状态等特殊匹配。
多端口匹配
- -m multiport --sprot:源端口
- -m multiport --dport:目的端口
iptables -t filter -A INPUT -p tcp -m multiport --dport 80,21,22,24 -j DROP
IP范围匹配
- -m iprange --src-range
iptables -t filter -I INPUT -p tcp -m iprange --src-range 192.168.100.21-192.168.100.28 -j ACCEPT
MAC地址匹配
- -m mac --mac-source
iptables -t filter -I INPUT -m mac --mac-source 00:0C:29:64:E3:8D -j ACCEPT
TCP 状态匹配
- -m state --state
iptables -t filter -I INPUT -p tcp -m state --state ESTABLISHED,RELATED -j ACCEPT
网络型iptables主要有两个作用:
- filter表主要做服务器流量控制
- nat表主要做网关路由器,网络地址转换SNAT和DNAT
SNAT:源地址转换,主要用于内网访问外网。
具体步骤:
- 1)配置IP,将同一网段打通,注意配置网关地址
- 2)启动机器B的路由转发功能,然后测试内外网互通,成功
- 3)删除机器C的网关,模拟私有IP没有路由的情况,尝试通信失败
- 4)在机器B(即中转路由设备)建立SNAT,通信成功
- 5)通过机器C的web访问日志,可以看出来访者
开启机器的路由转发功能
/usr/lib/sysctl.d/50-default.conf
文件中增加以下内容,然后重启。
net.ipv4.ip_forward = 1
不想重启也可以,执行以下命令,直接更改以下内存中的数据
echo 1 >/proc/sys/net/ipv4/ip_forward
然后使用以下命令查看是否生效:
sysctl -a |grep ip_forward
iptables 配置 nat
iptables -t nat -A POSTROUTING -s 192.168.100.0/24 -o ens33 -j SNAT --to-source 192.168.200.10
把 192.168.100.0/24 出站的数据的源地址全部换成 192.168.200.10。
实际生活源地址会被换成我们的公网IP。
MASQUERADE:地址伪装,也是NAT的一种,也是用于内网访问外网且外网IP地址非固定的情祝。
一般家庭带宽的公网IP都是动态分配的,SNAT无法使用。因为使用SNAT的时候需要指定一个固定的IP。
对于ADSL拨号连接,接口通常为ppp0、ppp1
iptables -t nat -A POSTROUTING -s 192.168.100.0/24 -o ens33 -j SNAT --to-source 192.168.200.10
--to-source 这个参数,但我们的IP是固定的,这个就没法用了。 将SNAT规则改为MASQUERADE即可,使动态地址作为SNAT的目标地址,效果和SNAT一致。
iptables -t nat -A POSTROUTING -s 192.168.100.0/24 -o ens33 -j MASQUERADE
DNAT:目的地址转换,适用于外网访问内网的场景。
在用于路由的机器上配置以下 iptables规则。
iptables -t nat -A PREROUTING -i ens33 -d 192.168.200.10 -p tcp --dport 80 -j DNAT --to-destination 192.168.100.10
PNAT:端口转换(映射),安全性更高,比如内网服务器的SSH程序22端口,发布时SSH使用2345端口。
iptables -t nat -A PREROUTING -i ens33 -d 192.168.200.10 -p tcp --dport 2345 -j DNAT --to-destination 192.168.100.10:22
和 DNAT 命令也基本一致,只是最后--to-destination 192.168.100.10:22
,带上了端口号。
具体流程如下图所示:
- 1)首先我们发出去的包 源地址是 100.10,目的地址为200.20,不在同一个网段所以这个包会被发送到网关
- 2)网关收到这个包的时候源地址还是 100.10,目的地址还是200.20
- 3)最重要的一步来了,SNAT功能,由于上面配置了 iptables规则的(把 192.168.100.0/24 出站的数据的源地址全部换成 192.168.200.10),,所以到这里的时候源地址就变成了 200.10,目的地址没变还是200.20
- 4)等Server3收到包的时候 源地址是 200.10,目的地址为200.20,成功收到这个包了,
- 5)然后Server3处理完成也要回复一个包,此时回复包的目的地址就是之前收到那个包的源地址,即200.10,然后当前回复包的源地址就是200.20
- 6)Server2成功收到了这个包,源地址200.20,目的地址200.10
- 7)Server2此时会根据自己的NAT转换记录找到,之前这个200.10是100.10在用,所以这个包会进行一个DNAT,将目的地址从200.10转成100.10
- 8)最终Server1就收到了这个包,目的地址100.10,源地址200.20
经过一个SNAT和DNAT就完成了一次数据交换。
iptables 添加规则时没有做重复校验,因此会出现同一条规则添加多次的情况,为了避免重复添加,我们需要在添加之前使用 iptables -C
进行校验。
如果时旧版本 iptables 没有 -C 参数的话可以使用
iptables-save | grep -- "-A INPUT -p tcp -m tcp --dport 8080 -j ACCEPT"
$ iptables -C INPUT -p tcp --dport 8080 --jump ACCEPT
# 如果不存在的话会报错,提示信息如下,并且 exitcode 为 1
iptables: Bad rule (does a matching rule exist in that chain?).
$ echo $?
1
$ iptables -A INPUT -p tcp --dport 8080 --jump ACCEPT
$ iptables -C INPUT -p tcp --dport 8080 --jump ACCEPT
# 如果脚本存在的话 exitcode 为 0
$ echo $?
0
因此可以根据 exitcode 来做判断,脚本如下:
# 最后 iptables 丢弃 53 端口的请求,保证外部无法访问本机 coredns
# 添加规则之前先判断是否存在,避免重复添加
if iptables -C INPUT -p tcp --dport 53 -j DROP
then # 进入 then 表示退出码为 0,说明规则已经存在了,不在重复添加
echo "tcp规则已经存在"
else # else 则表示退出码不为 0,规则不存在,则添加
echo "tcp规则不存在,添加"
iptables -I INPUT -p tcp --dport 53 -j DROP
fi
if iptables -C INPUT -p udp --dport 53 -j DROP
then # 进入 then 表示退出码为 0,说明规则已经存在了,不在重复添加
echo "udp规则已经存在"
else # else 则表示退出码不为 0,规则不存在,则添加
echo "udp规则不存在,添加"
iptables -I INPUT -p udp --dport 53 -j DROP
fi
同样的,删除规则之后也可以判断一下是否删除干净
# 删除 iptables 规则,允许外部访问本机 coredns
# 因为 iptables 规则可以重复添加多次,因此 使用 while 循环,保证删除干净
rule_tcp=1
while [ "${rule_tcp}" == 1 ]
do
if iptables -C INPUT -p tcp --dport 53 -j DROP
then # 进入 then 表示退出码为 0,说明规则已经存在了,需要移除
echo "tcp规则存在"
iptables -D INPUT -p tcp --dport 53 -j DROP
else # else 则表示退出码不为 0,规则不存在,不需要移除
echo "tcp规则已移除"
rule_tcp=0
fi
done
rule_udp=1
while [ "${rule_udp}" == 1 ]
do
if iptables -C INPUT -p udp --dport 53 -j DROP
then # 进入 then 表示退出码为 0,说明规则已经存在了,需要移除
echo "tcp规则存在"
iptables -D INPUT -p udp --dport 53 -j DROP
else # else 则表示退出码不为 0,规则不存在,不需要移除
echo "udp规则已移除"
rule_udp=0
fi
done