Physical Address:
ChongQing,China.
WebSite:
Iptables是Linux平台下通用的包过滤防火墙,可以完成封包过滤、封包重定向和网络地址转换(NAT)等功能。Iptables本身是对内核netfilter模块的封装,便于用户态程序操作防火墙。
四表指的是:filter、nat、mangle、raw,其中filter表负责过滤功能,也就是防火墙配置;nat表,也就是network address translation,网络地址转换;mangle表负责拆解报文,做出修改(如TTL,Qos配置等信息)并重新封装;raw表,负责关闭nat表上启用的连接追踪机制。
五链指的是:PREROUTING、INPUT、FORWARD、OUTPUT、POSTROUTING
表与链之间的关系,我们可以简单理解为表是一个一个面,而链则是穿越这些面将面连接。在表与链中,真正起到作用的则是规则。我们在表中可以修改TCP/IP包头的不同位置,在链中执行为包被路由转换的不同阶段。规则是具体的行为逻辑。
并不是所有的链都贯穿了上述四表,某些表中只能包含特定的某些链,下面简单作个列表归纳:
链 | 表 |
PREROUTING | raw,mangle,nat |
INPUT | mangle,filter,nat |
FORWARD | mangle,filter |
OUTPUT | raw,mangle,filter,nat |
POSTROUTING | mangle,nat |
关于规则,具体的动作包括:ACCEPT(接受)、REJECT(拒绝但会回复被拒绝的原因)、DROP(直接丢弃无响应)、REDIRECT(端口重定向)、MASQUERADE(源地址动态伪装)、LOG(记录日志而后向下匹配规则)、DNAT(目的IP转换)、SNAT(源IP转换)等。以下是规则匹配中的一些常用参数表:
参数 | 用途 |
-i | 指定入站的network interface |
-o | 指定出站的network interface |
-p | 指定匹配的协议,如tcp/udp/icmp |
-s | 指定源IP |
-d | 指定目标IP |
数据包经过防火墙时的数据流向可以参考下图:
如果数据包需要经过上层处理:流量->PREROUTING->INPUT->Application->OUTPUT->POSTROUTING;如果数据不需要经过上层处理,单纯转发:流量->PREROUTING->FORWARD->POSTROUTING.
Iptables命令配置参数中遵守“表->链->规则“。如果我们需要查看所有的iptables配置,如下所示:
root@bstcd-OptiPlex-7090:~# iptables --list -n
Chain INPUT (policy ACCEPT)
target prot opt source destination
Chain FORWARD (policy ACCEPT)
target prot opt source destination
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
root@bstcd-OptiPlex-7090:~#
列出某个表上的规则:iptables -t +表名 -L,表名在缺省情况下默认为filter表
trout_x86:/ # iptables -t filter -L
Chain INPUT (policy ACCEPT)
target prot opt source destination
bw_INPUT all -- anywhere anywhere
fw_INPUT all -- anywhere anywhere
Chain FORWARD (policy ACCEPT)
target prot opt source destination
oem_fwd all -- anywhere anywhere
fw_FORWARD all -- anywhere anywhere
bw_FORWARD all -- anywhere anywhere
tetherctrl_FORWARD all -- anywhere anywhere
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
oem_out all -- anywhere anywhere
fw_OUTPUT all -- anywhere anywhere
st_OUTPUT all -- anywhere anywhere
bw_OUTPUT all -- anywhere anywhere
列出某个表上某个链的所有规则:iptables -t +表名 -L +链名
trout_x86:/ # iptables -t filter -L INPUT
Chain INPUT (policy ACCEPT)
target prot opt source destination
bw_INPUT all -- anywhere anywhere
fw_INPUT all -- anywhere anywhere
trout_x86:/ # iptables -t filter -L OUTPUT
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
oem_out all -- anywhere anywhere
fw_OUTPUT all -- anywhere anywhere
st_OUTPUT all -- anywhere anywhere
bw_OUTPUT all -- anywhere anywhere
trout_x86:/ #
同时我们可以使用-v参数查看完整信息:
trout_x86:/ # iptables -t filter -L OUTPUT
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
oem_out all -- anywhere anywhere
fw_OUTPUT all -- anywhere anywhere
st_OUTPUT all -- anywhere anywhere
bw_OUTPUT all -- anywhere anywhere
trout_x86:/ # iptables -t filter -vL OUTPUT
Chain OUTPUT (policy ACCEPT 33733 packets, 6488K bytes)
pkts bytes target prot opt in out source destination
33749 6490K oem_out all -- any any anywhere anywhere
33749 6490K fw_OUTPUT all -- any any anywhere anywhere
33749 6490K st_OUTPUT all -- any any anywhere anywhere
33749 6490K bw_OUTPUT all -- any any anywhere anywhere
trout_x86:/ #
每一列的内容:
pkts:对应规则匹配到的报文的个数
bytes:对应匹配到的报文包的大小总和
target:规则对应的target,往往表示规则对应的动作
prot:表示规则对应的协议,是否仅针对某些协议应用此规则
opt:表示规则对应的选项
in:表示数据包由哪个网卡流入
out:表示数据包从哪个网卡流出
source:表示规则对应的源地址,可以是IP也可以一个网段
destination:表示规则对应的目标地址,可以是IP也可以是一个网段
在这些列的最上方,Chain OUTPUT意味着这是属于OUTPUT链的规则,policy drop意味着默认的规则为ACCEPT.
上面的内容为查看iptables的规则,实际上是通过-L来列出。接下来我们讲讲如何添加规则。这里添加规则分为两种类型:insert与append。其中insert可以指定规则顺序,未指定的情况下将会将规则至于链开头;而append则是在链末尾进行追加。由于规则判断是自上而下进行的,所以链头的规则具有更高的优先级,这一点需要注意。
示例如下:
iptables -t filter -I INPUT -s 192.168.1.146 -j DROP
在这个示例中,-t用于指定哪个表,-t filter表明用于指定filter表,-I用于insert插入,-I INPUT表明在INPUT链中进行插入,-s表明适用于该规则的源地址,-j表示该规则具体的动作,一般常用的动作有ACCEPT,REJECT,DROP等。
在此处未指定位置顺序,所以是在INPUT链头添加规则。下面我们看一个追加规则的例子:
iptables -t filter -A INPUT -s 192.168.1.146 -j ACCEPT
在这个示例中,-A INPUT表示在INPUT链中append添加,需要说明的是,-A添加的规则是在链的尾部,而-I添加的规则是在链的首部,而规则的顺序是很重要的,对同一个目标制定好的规则,规则靠前满足就会优先处理,这可能会导致后续的规则无法生效。
如何确定规则的顺序呢,在列出规则时使用–line参数即可,如下图所示:
trout_x86:/ # iptables -t filter -vL OUTPUT
Chain OUTPUT (policy ACCEPT 33733 packets, 6488K bytes)
pkts bytes target prot opt in out source destination
33749 6490K oem_out all -- any any anywhere anywhere
33749 6490K fw_OUTPUT all -- any any anywhere anywhere
33749 6490K st_OUTPUT all -- any any anywhere anywhere
33749 6490K bw_OUTPUT all -- any any anywhere anywhere
trout_x86:/ # iptables -t filter --line -vL OUTPUT
Chain OUTPUT (policy ACCEPT 34237 packets, 6623K bytes)
num pkts bytes target prot opt in out source destination
1 34253 6625K oem_out all -- any any anywhere anywhere
2 34253 6625K fw_OUTPUT all -- any any anywhere anywhere
3 34253 6625K st_OUTPUT all -- any any anywhere anywhere
4 34253 6625K bw_OUTPUT all -- any any anywhere anywhere
trout_x86:/ #
如果我们想要指定插入的规则序号,可以使用如下示例来进行添加:
iptables -t filter -I INPUT 2 -s 192.168.1.146 -j ACCEPT
该示例表示插入规则且序号为2。
有些时候我们可能会需要删除某些规则,删除规则一般可以有两种方式,一是通过序号来进行删除,二是直接删除对应的动作,如下所示:
iptables -t filter -D INPUT 2
表明删除filter表INPUT链的第二条规则。
iptables -t filter -D INPUT -s 192.168.1.146 -j ACCEPT
表明删除filter表中INPUT链对应的规则。
除了上述两种方式,iptables还提供了直接清除链中所有规则的方式,如下所示:
iptables -t filter -F INPUT
表明删除filter表中INPUT链上所有的规则。
一般情况下不建议修改规则,比较推荐的是删除规则后重新添加对应的规则,但如果我们不得不修改规则时,iptables也提供了相应的能力。这里我们使用-R选项来修改。
使用示例:
iptables -t filter -R INPUT 1 -s 192.168.1.110 -j REJECT
在该示例中,-R选项表示指定要修改的链(Replace),1代表INPUT链的第一条规则,-s指定源地址,-j REJECT表明修改为REJECT。
除了修改某个具体的规则,我们可能还会修改某些链的默认规则,关于链的默认规则我们已经在上面提到过,这里讲如何修改默认规则:
iptables -t filter -P FORWARD DROP
在该示例中,我们将filter表中的FORWARD链默认规则改为DROP。
iptables提供了一些额外的拓展来帮助我们更好的制定规则,通过这些拓展我们可以更好地来制定规则。
确认当前支持的拓展,我们可以使用如下命令进行确认:
root@bwg29cn2:~# ls /lib/modules/`uname -r`/kernel/net/netfilter/
ipset nf_dup_netdev.ko nfnetlink_osf.ko nft_hash.ko nft_tunnel.ko xt_conntrack.ko xt_iprange.ko xt_osf.ko xt_statistic.ko
ipvs nf_flow_table_inet.ko nfnetlink_queue.ko nft_limit.ko nft_xfrm.ko xt_cpu.ko xt_ipvs.ko xt_owner.ko xt_string.ko
nf_conncount.ko nf_flow_table.ko nf_synproxy_core.ko nft_log.ko x_tables.ko xt_CT.ko xt_l2tp.ko xt_physdev.ko xt_tcpmss.ko
nf_conntrack_amanda.ko nf_log_common.ko nf_tables.ko nft_masq.ko xt_addrtype.ko xt_dccp.ko xt_LED.ko xt_pkttype.ko xt_TCPMSS.ko
nf_conntrack_broadcast.ko nf_log_netdev.ko nf_tables_set.ko nft_nat.ko xt_AUDIT.ko xt_devgroup.ko xt_length.ko xt_policy.ko xt_TCPOPTSTRIP.ko
nf_conntrack_ftp.ko nf_nat_amanda.ko nft_chain_nat.ko nft_numgen.ko xt_bpf.ko xt_dscp.ko xt_limit.ko xt_quota.ko xt_tcpudp.ko
nf_conntrack_h323.ko nf_nat_ftp.ko nft_compat.ko nft_objref.ko xt_cgroup.ko xt_DSCP.ko xt_LOG.ko xt_rateest.ko xt_TEE.ko
nf_conntrack_irc.ko nf_nat_irc.ko nft_connlimit.ko nft_osf.ko xt_CHECKSUM.ko xt_ecn.ko xt_mac.ko xt_RATEEST.ko xt_time.ko
nf_conntrack.ko nf_nat.ko nft_counter.ko nft_queue.ko xt_CLASSIFY.ko xt_esp.ko xt_mark.ko xt_realm.ko xt_TPROXY.ko
nf_conntrack_netbios_ns.ko nf_nat_sip.ko nft_ct.ko nft_quota.ko xt_cluster.ko xt_hashlimit.ko xt_MASQUERADE.ko xt_recent.ko xt_TRACE.ko
nf_conntrack_netlink.ko nf_nat_tftp.ko nft_dup_netdev.ko nft_redir.ko xt_comment.ko xt_helper.ko xt_multiport.ko xt_REDIRECT.ko xt_u32.ko
nf_conntrack_pptp.ko nfnetlink_acct.ko nft_fib_inet.ko nft_reject_inet.ko xt_connbytes.ko xt_hl.ko xt_nat.ko xt_sctp.ko
nf_conntrack_sane.ko nfnetlink_cthelper.ko nft_fib.ko nft_reject.ko xt_connlabel.ko xt_HL.ko xt_NETMAP.ko xt_SECMARK.ko
nf_conntrack_sip.ko nfnetlink_cttimeout.ko nft_fib_netdev.ko nft_socket.ko xt_connlimit.ko xt_HMARK.ko xt_nfacct.ko xt_set.ko
nf_conntrack_snmp.ko nfnetlink.ko nft_flow_offload.ko nft_synproxy.ko xt_connmark.ko xt_IDLETIMER.ko xt_NFLOG.ko xt_socket.ko
nf_conntrack_tftp.ko nfnetlink_log.ko nft_fwd_netdev.ko nft_tproxy.ko xt_CONNSECMARK.ko xt_ipcomp.ko xt_NFQUEUE.ko xt_state.ko
root@bwg29cn2:~#
这些*.ko都是内核驱动模块,当iptables使用相应的拓展时就会load对应的模块。
确认已经loaded的拓展,我们可以使用如下命令:
root@Franz:/home/FranzKafka# cat /proc/net/ip_tables_matches
time
comment
limit
addrtype
conntrack
conntrack
conntrack
recent
recent
ttl
addrtype
udplite
udp
tcp
icmp
iprange模块:可以指定连续的IP地址,启用该模块后使用–src-range和—dst-range来指定,如下所示:
iptables -t filter -I INPUT -m iprange --src-range 192.168.1.1-192.168.1.146 -j DROP
iptables -t filter -I INPUT -m iprange --dst-range 192.168.1.1-192.168.1.146 -j DROP
string模块:使用string扩展模块,可以指定要匹配的字符串,如果报文中包含对应的字符串,则符合匹配条件
time模块:可以根据时间段来匹配报文,如果报文到达的时间在指定的时间范围内,则符合匹配条件,可用参数包括–timestart和—timestop,–weekdays,–monthdays
iptables -t filter -I INPUT -p tcp --sport 443 -m time --timestart 09:00:00 -j DROP
iptables -t filter -I OUTPUT -p tcp -d taobao.com --dport 80 -m time --timestart 00:00 --timestop 10:00 --weekdays 1,2,3,4,5 -j DROP
需要说明的是,time模块使用的时间为UTC时间,与服务器的系统时间可能是存在差异的,这可能会导致规则无法匹配;不过我们可以通过–kerneltz参数来设置其采用与内核一致的时区。如下所示:
iptables -t filter -I INPUT -s 112.165.10.4 -p tcp --dport 43162 -m time --kerneltz --timestop 12:57:28 -j DROP
connlimit模块:可以限制IP的连接数量
iptables -t filter -I INPUT -m connlimit –connlimit-above 3 -j REJECT
该示例限制单IP连接数超过3则REJECT拒绝连接。
limit模块:limit模块可以用于限制速率
查看某个拓展模块的帮助,可以使用如下命令:iptables -m 模块名 –help
如我们需要查看time模块的使用帮助,如下所示:
root@FranzKafka:/home/FranzKafka# iptables -m time --help
iptables v1.8.4
time match options:
--datestart time Start and stop time, to be given in ISO 8601
--datestop time (YYYY[-MM[-DD[Thh[:mm[:ss]]]]])
--timestart time Start and stop daytime (hh:mm[:ss])
--timestop time (between 00:00:00 and 23:59:59)
[!] --monthdays value List of days on which to match, separated by comma
(Possible days: 1 to 31; defaults to all)
[!] --weekdays value List of weekdays on which to match, sep. by comma
(Possible days: Mon,Tue,Wed,Thu,Fri,Sat,Sun or 1 to 7
Defaults to all weekdays.)
--kerneltz Work with the kernel timezone instead of UTC
除了默认的四表五链,我们也可以增加自己的链,也就是自定义的链。一般来讲我们可以不用增加自己的链,在默认的五链中进行规则的添加即可。但有些时候为了规则的集中管理,我们不方便在默认的链中进行操作,此时就可以使用自定义链,对自定义链进行管理。
创建自定义链:
iptables -t filter -N OWN_CHAIN //表明在filter表创建名为OWN_CHAIN的链,-N代表new
这里需要说明的是,创建自定义创建后需要在默认的链中进行引用才能使规则生效。
引用自定义链:
iptables -t filter -I INPUT -p tcp -j OWN_CHAIN //在INPUT链中引用OWN_CHAIN链
重命名自定义链:
iptables -E OWN_CHAIN OWN_CHAIN1 //将OWN_CHAIN重命名为OWN_CHAIN1
删除自定义链:
iptables -X OWN_CHAIN
需要说明的是,在删除自定义链之前,需要先清除该自定义链在默认五链中的引用,并且确保无任何规则,否则无法进行删除。
清除自定义链:
iptables -t filter -F OWN_CHAIN
Iptables中的动作除了ACCEPT、DROP、REJECT、RETURN,还有LOG,其中LOG动作即是记录满足规则的数据包,如下示例:
iptables -A INPUT -p tcp --dport 80 -j LOG --log-prefix "INPUT" --log-level 4 --log-ip-options --log-tcp-sequence
--log-level #错误级别,可以使用0到7之间的数字。0是emerg,1是alert,2是crit,3是err,4是warning,5是notice,6是info,7是debug
--log-prefix "INPUT" #描述前缀,日志中的tag
--log-ip-options #记录IP信息
--log-tcp-sequence #记录TCP序列号
该规则表明以Append的形式将tcp访问端口80的数据包进行记录,默认会将日志记录到kernel日志中,我们可以直接使用dmesg命令进行查看。