iptables详解之filter
iptables令很多小伙伴脑阔疼,下面我们来说说如何使用iptables。
一、iptables格式
1.1、iptables 帮助
通过iptables --help
查看一下iptables用法
[root@note1 ~]# iptables --help iptables v1.4.21 Usage: iptables -[ACD] chain rule-specification [options] iptables -I chain [rulenum] rule-specification [options] iptables -R chain rulenum rule-specification [options] iptables -D chain rulenum [options] iptables -[LS] [chain [rulenum]] [options] iptables -[FZ] [chain] [options] iptables -[NX] chain iptables -E old-chain-name new-chain-name iptables -P chain target [options] iptables -h (print this help information)
1.2、iptables 格式
iptables [-t table] COMMAND chain [-m matchname [per-match-options]] -j targetname [per-target-options]
iptables命令由 表 + 命令 + 链 + 匹配条件 + 处理动作
组成
二、iptables表
iptables由四表五链组成。每个表分别实现不同的功能,每个表拥有不同的链,链代表规则实现的位置。
四表分别为:
- filter :过滤,防火墙;
- nat :用于源地址转换或目标地址转换;
- mangle :拆解报文,做出修改,并重新封装起来;
- raw :关闭nat表上启用的连接追踪机制;
五链分别为:PREROUTING,INPUT,FORWARD,OUTPUT,POSTROUTING。
不同表支持的链:
- filter :INPUT,FORWARD,OUTPUT
- nat :PREROUTING,INPUT,OUTPUT,POSTROUTING
- mangle :PREROUTING,INPUT,FORWARD,OUTPUT,POSTROUTING
- raw :OUTPUT,PREROUTING
添加规则时的考量点:
- 要实现哪种功能:判断添加到哪个表上;
- 报文流经的路径:判断添加到哪个链上;
链:链上的规则次序,即为检查的次序;因此,隐含一定的应用法则:
- 同类规则(访问同一应用),匹配范围小的放上面;
- 不同类的规则(访问不同应用),匹配到报文频率较大的放在上面;
- 将那些可由一条规则描述的多个规则合并起来;
- 设置默认策略;
使用iptables命令时若不使用-t
指明操作哪张表,默认操作filter表。
三、iptables命令
iptables命令有三大类,查看,链管理,规则管理
3.1、查看iptables规则
-t : 查看的表
-n :不进行 IP 与 HOSTNAME 的反解
-v :列出更多的信息,包括通过该规则的封包总位数、相关的网络接口等.
-L :列出目前的 table 的规则.
-S :查看规则定义,
--line-number用于查看规则号.
#使用iptables查看规则 [root@note1 ~]# iptables -vnL --line-number Chain INPUT (policy ACCEPT 0 packets, 0 bytes) num pkts bytes target prot opt in out source destination 1 467 29128 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:22 2 0 0 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:80 Chain FORWARD (policy ACCEPT 0 packets, 0 bytes) num pkts bytes target prot opt in out source destination Chain OUTPUT (policy ACCEPT 41 packets, 4276 bytes) num pkts bytes target prot opt in out source destination [root@note1 ~]# [root@note1 ~]# iptables -vnL INPUT --line-number Chain INPUT (policy ACCEPT 0 packets, 0 bytes) num pkts bytes target prot opt in out source destination 1 502 31476 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:22 2 0 0 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:80 [root@note1 ~]# #使用-S选项查看iptables的规则定义 [root@note1 ~]# iptables -S -P INPUT ACCEPT -P FORWARD ACCEPT -P OUTPUT ACCEPT -A INPUT -p tcp -m tcp --dport 22 -j ACCEPT -A INPUT -p tcp -m tcp --dport 80 -j ACCEPT
3.2、链管理
3.2.1、-N 新建链
-N:new, 自定义一条新的规则链;
iptables -N test
3.2.2、-X 删除链
-X:delete,删除自定义的规则链;
注意:仅能删除用户自定义的引用计数为0的空的链;
iptables -X test
3.2.3、-E 重命名
-E:重命名自定义链;引用计数不为0的自定义链不能够被重命名,也不能被删除;
iptables -N testrn iptables -E testrn testrename
3.2.4、-P 默认策略
-P:Policy,设置默认策略;对filter表中的链而言,其默认策略有:
- ACCEPT:接受
- DROP:丢弃
- REJECT:拒绝
使用需谨慎,由于我测试时,没有先增加一条放行ssh的规则,所以在我将filter的INPUT链默认策略改为DROP后,我已经无法通过Xshell链接虚拟机了,需要进入VMware放行ssh。
iptables -P INPUT DROP
增加了放行规则后,我们已经成功使用Xshell重新连上了主机
iptables -A INPUT -p tcp --dport 22 -j ACCEPT
使用命令添加默认策略
iptables -A INPUT -d 176.16.128.1 -j REJECT iptables -A OUTPUT -s 176.16.128.1 -j REJECT iptables -P INPUT ACCEPT iptables -P OUTPUT ACCEPT
3.3、规则管理
3.3.1、-A 追加规则
-A:append,在已有规则后追加规则;
# 在note1节点增加一条拒绝80端口的规则 [root@note1 local]# iptables -A INPUT -p tcp --dport 80 -j REJECT # 我们可以看到由于是使用追加命令追加的规则,这条规则的位置为2 [root@note1 local]# iptables -vnL --line-numbers Chain INPUT (policy ACCEPT 0 packets, 0 bytes) num pkts bytes target prot opt in out source destination 1 4208 225K ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:22 2 2 120 REJECT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:80 reject-with icmp-port-unreachable # 在主机点访问note1节点的80端口 [root@master ~]# curl note1:80 curl: (7) Failed connect to note1:80; 拒绝连接 [root@master ~]#
3.3.2、-R 替换规则
-R:replace,替换指定链上的指定规则;
# 使用-R命令修改拒绝80端口的规则为接受访问 [root@note1 local]# iptables -R INPUT 2 -p tcp --dport 80 -j ACCEPT # 查看iptables [root@note1 local]# iptables -vnL --line-numbers Chain INPUT (policy ACCEPT 0 packets, 0 bytes) num pkts bytes target prot opt in out source destination 1 4881 271K ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:22 2 0 0 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:80 # 在master节点访问80端口,可以看到网页的内容了。 [root@master ~]# curl note1:80 <h1>I'm Note1</h1> [root@master ~]#
3.3.3、-I 插入规则
-I:insert, 插入,要指明位置,省略时表示第一条;
# 使用iptables -I不指定位置插入规则。 [root@note1 ~]# iptables -I INPUT -p tcp --dport 3306 -j ACCEPT # 查看iptables,显示新增加的规则为第一条。 [root@note1 ~]# iptables -vnL INPUT --line-number Chain INPUT (policy ACCEPT 0 packets, 0 bytes) num pkts bytes target prot opt in out source destination 1 0 0 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:3306 2 616 38140 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:22 3 0 0 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:80 [root@note1 ~]# #使用iptables -I指定在第二条插入规则。 [root@note1 ~]# iptables -I INPUT 2 -p tcp --dport 443 -j ACCEPT [root@note1 ~]# iptables -vnL INPUT --line-number Chain INPUT (policy ACCEPT 0 packets, 0 bytes) num pkts bytes target prot opt in out source destination 1 0 0 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:3306 2 0 0 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:443 3 810 50540 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:22 4 0 0 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:80 [root@note1 ~]#
3.3.4、-D 删除规则
-D:delete,删除规则按照规则序号或规则本身
3.3.4.1、指明规则序号
[root@note1 ~]# iptables -vnL INPUT --line-number Chain INPUT (policy ACCEPT 0 packets, 0 bytes) num pkts bytes target prot opt in out source destination 1 0 0 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:3306 2 0 0 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:443 3 835 52340 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:22 4 0 0 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:80 [root@note1 ~]# iptables -D INPUT 2 [root@note1 ~]# iptables -vnL INPUT --line-number Chain INPUT (policy ACCEPT 0 packets, 0 bytes) num pkts bytes target prot opt in out source destination 1 0 0 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:3306 2 882 55100 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:22 3 0 0 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:80 [root@note1 ~]#
3.3.4.2、 指明规则本身
[root@note1 ~]# iptables -vnL INPUT --line-number Chain INPUT (policy ACCEPT 0 packets, 0 bytes) num pkts bytes target prot opt in out source destination 1 0 0 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:3306 2 882 55100 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:22 3 0 0 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:80 [root@note1 ~]# iptables -D INPUT -p tcp --dport 3306 -j ACCEPT [root@note1 ~]# iptables -vnL INPUT --line-number Chain INPUT (policy ACCEPT 0 packets, 0 bytes) num pkts bytes target prot opt in out source destination 1 1016 62940 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:22 2 0 0 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:80 [root@note1 ~]#
3.3.5、-Z 置零
iptables的每条规则都有两个计数器:
- (1) 匹配到的报文的个数;pkts
- (2) 匹配到的所有报文的大小之和;bytes
[root@note1 ~]# iptables -vnL INPUT --line-number Chain INPUT (policy ACCEPT 11 packets, 774 bytes) num pkts bytes target prot opt in out source destination 1 1028 63752 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:22 2 0 0 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:80 [root@note1 ~]# iptables -Z INPUT [root@note1 ~]# iptables -vnL INPUT --line-number Chain INPUT (policy ACCEPT 0 packets, 0 bytes) num pkts bytes target prot opt in out source destination 1 6 364 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:22 2 0 0 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:80 [root@note1 ~]#
3.3.6、-F 清空规则链
[root@note1 ~]# iptables -vnL INPUT --line-number Chain INPUT (policy ACCEPT 5 packets, 180 bytes) num pkts bytes target prot opt in out source destination 1 46 2728 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:22 2 0 0 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:80 [root@note1 ~]# iptables -F INPUT [root@note1 ~]# iptables -vnL INPUT --line-number Chain INPUT (policy ACCEPT 6 packets, 364 bytes) num pkts bytes target prot opt in out source destination [root@note1 ~]#
四、iptables匹配条件
4.1、基本匹配条件
无需加载任何模块,由iptables/netfilter自行提供;
[!] -s, --source
address[/mask][,...]:检查报文中的源IP地址是否符合此处指定的地址或范围;
[!] -d, --destination
address[/mask][,...]:检查报文中的目标IP地址是否符合此处指定的地址或范围;所有地址:0.0.0.0/0
[!] -p, --protocol
protocol: tcp, udp, udplite, icmp, icmpv6,esp, ah, sctp, mh or "all"
最常用的协议tcp、udp、icmp;[!] -i, --in-interface
数据报文流入的接口;只能应用于数据报文流入的环节,只能应用于PREROUTING,INPUT和FORWARD链;
[!] -o, --out-interface
数据报文流出的接口;只能应用于数据报文流出的环节,只能应用于FORWARD、OUTPUT和POSTROUTING链;
4.2、扩展匹配条件
4.2.1、隐式扩展
隐式扩展:不需要手动加载扩展模块;因为它们是对协议的扩展,所以在使用-p选项指明了特定的协议时,就表示已经指明了要扩展的模块,无需再同时使用-m选项指明扩展模块的扩展机制。
4.2.1.1、tcp
- [!] --source-port, --sport port[:port]:匹配报文的源端口;可以是端口范围;
- [!] --destination-port,--dport port[:port]:匹配报文的目标端口;可以是端口范围;
- [!] --tcp-flags mask comp
mask是我们应该检查的标志,以逗号分隔,例如 SYN,ACK,FIN,RST
comp是必须设置的标志,例如SYN
例如:“--tcp-flags SYN,ACK,FIN,RST SYN”表示,要检查的标志位为SYN,ACK,FIN,RST四个,其中SYN必须为1,余下的必须为0; [!] --syn:用于匹配第一次握手,相当于”--tcp-flags SYN,ACK,FIN,RST SYN“;
4.2.1.2、udp
- [!] --source-port, --sport port[:port]:匹配报文的源端口;可以是端口范围;
[!] --destination-port,--dport port[:port]:匹配报文的目标端口;可以是端口范围;
4.2.1.3、icmp
- [!] --icmp-type {type[/code]|typename}
icmp type
类型为8:请求回送echo-request(Ping 请求)
类型为0:回送应答echo-reply(Ping 应答)
我们设置INPUT放行icmp-type类型为0的报文,OUTPUT放行icmp-type类型为8的报文,默认规则设置为拒绝,这样就可以只允许我们ping其他主机,不允许其他主机ping我们。
#因为要增加默认拒绝规则,所以先放行ssh [root@note1 ~]# iptables -A INPUT -d 176.16.128.1 -p tcp --dport 22 -j ACCEPT [root@note1 ~]# iptables -A OUTPUT -s 176.16.128.1 -p tcp --sport 22 -j ACCEPT #增加默认拒绝规则 [root@note1 ~]# iptables -A INPUT -d 176.16.128.1 -j REJECT [root@note1 ~]# iptables -A OUTPUT -s 176.16.128.1 -j REJECT [root@note1 ~]# iptables -vnL Chain INPUT (policy ACCEPT 0 packets, 0 bytes) pkts bytes target prot opt in out source destination 299 19206 ACCEPT tcp -- * * 0.0.0.0/0 176.16.128.1 tcp dpt:22 0 0 REJECT all -- * * 0.0.0.0/0 176.16.128.1 reject-with icmp-port-unreachable Chain FORWARD (policy ACCEPT 0 packets, 0 bytes) pkts bytes target prot opt in out source destination Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes) pkts bytes target prot opt in out source destination 165 15559 ACCEPT tcp -- * * 176.16.128.1 0.0.0.0/0 tcp spt:22 0 0 REJECT all -- * * 176.16.128.1 0.0.0.0/0 reject-with icmp-port-unreachable #现在我们尝试ping,由于ping未在iptables中设置所以ping请求无法发送。 [root@note1 ~]# ping 176.16.128.8 PING 176.16.128.8 (176.16.128.8) 56(84) bytes of data. ping: sendmsg: 不允许的操作 ping: sendmsg: 不允许的操作 ping: sendmsg: 不允许的操作 ^C --- 176.16.128.8 ping statistics --- 3 packets transmitted, 0 received, 100% packet loss, time 1999ms #现在我们在OUTPUT链上增加一条允许发送ping请求的规则 [root@note1 ~]# iptables -I OUTPUT 2 -s 176.16.128.1 -p icmp --icmp-type 8 -j ACCEPT #尝试ping,发现请求可以发送了,但是未有响应回来 [root@note1 ~]# ping 176.16.128.8 PING 176.16.128.8 (176.16.128.8) 56(84) bytes of data. #我们使用tcpdump抓包,发现ping请求是有响应回来的。是INPUT链没有放行。 [root@note1 ~]# tcpdump -i eno16777736 icmp tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on eno16777736, link-type EN10MB (Ethernet), capture size 262144 bytes 20:45:00.605683 IP note1 > master: ICMP echo request, id 4276, seq 64, length 64 20:45:00.605962 IP master > note1: ICMP echo reply, id 4276, seq 64, length 64 20:45:01.606935 IP note1 > master: ICMP echo request, id 4276, seq 65, length 64 20:45:01.607533 IP master > note1: ICMP echo reply, id 4276, seq 65, length 64 ^C 8 packets captured 8 packets received by filter 0 packets dropped by kernel [root@note1 ~]# #我们在iptables的INPUT链放行ping请求的响应。 [root@note1 ~]# iptables -I INPUT 2 -d 176.16.128.1 -p icmp --icmp-type 0 -j ACCEPT #至此我们已经ping通了其他主机。 [root@note1 ~]# ping 176.16.128.8 PING 176.16.128.8 (176.16.128.8) 56(84) bytes of data. 64 bytes from 176.16.128.8: icmp_seq=228 ttl=64 time=0.687 ms 64 bytes from 176.16.128.8: icmp_seq=229 ttl=64 time=0.432 ms ^C --- 176.16.128.8 ping statistics --- 231 packets transmitted, 4 received, 98% packet loss, time 230101ms rtt min/avg/max/mdev = 0.432/0.804/1.443/0.382 ms [root@note1 ~]#
若要允许其他主机也能ping我们。在INPUT链中追加一条放行icmp-type类型为8的报文,OUTPUT放行icmp-type类型为0的报文,这样就都可以ping通了。
4.2.2、显式扩展
显式扩展:必须使用-m选项指明要调用的扩展模块的扩展机制;
4.2.2.1、multiport
This module matches a set of source or destination ports. Up to 15 ports can be specified. A port range (port:port) counts as two ports. It can only be used in conjunction with one of the following protocols: tcp, udp, udplite, dccp and sctp.
以离散或连续的 方式定义多端口匹配条件,最多15个;
[!] --source-ports,--sports port[,port|,port:port]...:指定多个源端口;
[!] --destination-ports,--dports port[,port|,port:port]...:指定多个目标端口;
iptables -I INPUT -d 172.16.0.7 -p tcp -m multiport --dports 22,80,139,445,3306 -j ACCEPT
4.2.2.2、iprange
以连续地址块的方式来指明多IP地址匹配条件;
[!] --src-range from[-to]
[!] --dst-range from[-to]
iptables -I INPUT -d 172.16.0.7 -p tcp -m multiport --dports 22,80,139,445,3306 -m iprange --src-range 172.16.0.61-172.16.0.70 -j REJECT
4.2.2.3、time
This matches if the packet arrival time/date is within a given range.
--timestart hh:mm[:ss]
--timestop hh:mm[:ss]
[!] --weekdays day[,day...]
[!] --monthdays day[,day...]
--datestart YYYY[-MM[-DD[Thh[:mm[:ss]]]]]
--datestop YYYY[-MM[-DD[Thh[:mm[:ss]]]]]
--kerneltz:使用内核配置的时区而非默认的UTC;
4.2.2.4、string
This modules matches a given string by using some pattern matching strategy.
--algo {bm|kmp}
[!] --string pattern
[!] --hex-string pattern
--from offset
--to offset
~]# iptables -I OUTPUT -m string --algo bm --string "gay" -j REJECT
4.2.2.5、connlimit
Allows you to restrict the number of parallel connections to a server per client IP address (or client address block).
--connlimit-upto n
--connlimit-above n
~]# iptables -I INPUT -d 172.16.0.7 -p tcp --syn --dport 22 -m connlimit --connlimit-above 2 -j REJECT
4.2.2.6、limit
This module matches at a limited rate using a token bucket filter.
--limit rate[/second|/minute|/hour|/day]
--limit-burst number
~]# iptables -I OUTPUT -s 172.16.0.7 -p icmp --icmp-type 0 -j ACCEPT
限制本机某tcp服务接收新请求的速率:--syn, -m limit
4.2.2.7、state
The "state" extension is a subset of the "conntrack" module. "state" allows access to the connection tracking state for this packet.
[!] --state state
INVALID, ESTABLISHED, NEW, RELATED or UNTRACKED.
NEW: 新连接请求;
ESTABLISHED:已建立的连接;
INVALID:无法识别的连接;
RELATED:相关联的连接,当前连接是一个新请求,但附属于某个已存在的连接;
UNTRACKED:未追踪的连接;
state扩展:
内核模块装载:
nf_conntrack
nf_conntrack_ipv4
手动装载:
nf_conntrack_ftp
追踪到的连接:
/proc/net/nf_conntrack
调整可记录的连接数量最大值:
/proc/sys/net/nf_conntrack_max
超时时长:
/proc/sys/net/netfilter/timeout