Linux 系统在内核中提供了对报文数据包过滤和修改的官方项目名为 Netfilter,它指的是 Linux 内核中的一个框架,它可以用于在不同阶段将某些钩子函数(hook)作用域网络协议栈。Netfilter 本身并不对数据包进行过滤,它只是允许可以过滤数据包或修改数据包的函数挂接到内核网络协议栈中的适当位置。这些函数是可以自定义的。

iptables 是用户层的工具,它提供命令行接口,能够向 Netfilter 中添加规则策略,从而实现报文过滤,修改等功能。Linux 系统中并不止有 iptables 能够生成防火墙规则,其他的工具如 firewalld 等也能实现类似的功能。

结构

首先介绍iptables的结构:iptables -> Tables -> Chains -> Rules. 简单地讲,tables由chains组成,而chains又由rules组成。如下图所示。
此处输入图片的描述

iptables具有Filter, NAT, Mangle, Raw四种内建表,filter 表主要实现过滤功能,nat 表实现 NAT 功能,mangle 表用于修改分组数据,raw 表用于修改俩节追踪的功能。

每个表都有一组内置链,用户还可以添加自定义的链。最重要的内置链是 filter 表中的 INPUT、OUTPUT 和 FORWARD 链。

Filter表

Filter表示iptables的默认表,因此如果你没有自定义表,那么就默认使用filter表,它具有以下三种内建链:

  • INPUT链 – 处理来自外部的数据
  • OUTPUT链 – 处理向外发送的数据。
  • FORWARD链 – 将数据转发到本机的其他网卡设备上

此处输入图片的描述

NAT表

  • PREROUTING链 – 处理刚到达本机并在路由转发前的数据包。它会转换数据包中的目标IP地址(destination ip address),通常用于DNAT(destination NAT)
  • POSTROUTING链 – 处理即将离开本机的数据包。它会转换数据包中的源IP地址(source ip address),通常用于SNAT(source NAT)
  • OUTPUT链 – 处理本机产生的数据包

Mangle表

Mangle表用于指定如何处理数据包。它能改变TCP头中的QoS位。Mangle表具有5个内建链:

  • PREROUTING 链 – 处理刚到达本机并在路由转发前的数据包
  • OUTPUT链 – 处理本机产生的数据包
  • FORWARD链 – 将数据转发到本机的其他网卡设备上
  • INPUT链 – 处理来自外部的数据
  • POSTROUTING 链 – 处理即将离开本机的数据包

Raw表

Raw表用于处理异常,它具有2个内建链:

  • PREROUTING 链 – 处理刚到达本机并在路由转发前的数据包
  • OUTPUT 链 – 处理本机产生的数据包

下图是一个数据包的过程
此处输入图片的描述

常用命令

查看链和规则

参数

1
2
3
4
5
iptables [-t tables] [-L] [-nv]
-t :后面接 table ,例如 nat 或 filter ,若省略此项目,则使用默认的 filter
-L :列出目前的 table 的规则
-n :不进行 IP 与 HOSTNAME 的反查,显示讯息的速度会快很多!
-v :列出更多的信息,包括通过该规则的封包总位数、相关的网络接口等

举例
iptables -L
输出

1
2
3
4
5
6
7
8
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

iptables -L -n -v -t nat
输出

1
2
3
4
5
6
7
8
9
10
11
Chain PREROUTING (policy ACCEPT 11 packets, 2597 bytes)
pkts bytes target prot opt in out source destination
Chain INPUT (policy ACCEPT 11 packets, 2597 bytes)
pkts bytes target prot opt in out source destination
Chain OUTPUT (policy ACCEPT 1917 packets, 125K bytes)
pkts bytes target prot opt in out source destination
Chain POSTROUTING (policy ACCEPT 1917 packets, 125K bytes)
pkts bytes target prot opt in out source destination

修改链和规则

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
iptables [-AIRD 链名] [-io 网络接口] [-p 协议] [-s 来源IP/网域] [-d 目标IP/网域] -j [ACCEPT|DROP|REJECT|LOG]
选项与参数:
-AIRD 链名
-I(插入到第一行)
-A(追加到最后一行)
-R(替换)
-D(删除
链 :有 INPUT, OUTPUT, FORWARD 等
-io 网络接口:设定封包进出的接口规范
-i :封包所进入的那个网络接口,例如 eth0, lo 等接口。需与 INPUT 链配合;
-o :封包所传出的那个网络接口,需与 OUTPUT 链配合
-p 协议:设定此规则适用于哪种封包格式
主要的封包格式有: tcp, udp, icmp 及 all
-s 来源 IP/网域:设定此规则之封包的来源项目,可指定单纯的 IP 或包括网域,例如:
IP :192.168.0.100
网域:192.168.0.0/24, 192.168.0.0/255.255.255.0 均可。
若规范为『不许』时,则加上 ! 即可,例如:
-s ! 192.168.100.0/24 表示不许 192.168.100.0/24 之封包来源
-d 目标 IP/网域:同 -s ,只不过这里指的是目标的 IP 或网域。
-j :后面接动作,主要的动作有接受(ACCEPT)、丢弃(DROP)、拒绝(REJECT)及记录(LOG)

其他参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# 端口
iptables [-AI 链] [-io 网络接口] [-p tcp,udp] [-s 来源IP/网域] [--sport 埠口范围] [-d 目标IP/网域] [--dport 端口范围] -j [ACCEPT|DROP|REJECT]
选项与参数:
--sport 埠口范围:限制来源的端口号码,端口号码可以是连续的,例如 1024:65535
--dport 埠口范围:限制目标的端口号码。
mac 与 state
iptables -A INPUT [-m state] [--state 状态]
选项与参数:
-m :一些 iptables 的外挂模块,主要常见的有:
state :状态模块
mac :网络卡硬件地址 (hardware address)
--state :一些封包的状态,主要有:
INVALID :无效的封包,例如数据破损的封包状态
ESTABLISHED:已经联机成功的联机状态;
NEW :想要新建立联机的封包状态;
RELATED :这个最常用!表示这个封包是与我们主机发送出去的封包有关
#ICMP 封包规则的比对:针对是否响应 ping 来设计
iptables -A INPUT [-p icmp] [--icmp-type 类型] -j ACCEPT
选项与参数:
--icmp-type :后面必须要接 ICMP 的封包类型,也可以使用代号,
例如 8 代表 echo request 的意思。

清除与保存

清除

1
2
3
4
5
iptables --flush
或者
iptables -F
这两条命令是等效的。但是并非执行后就万事大吉了。你仍然需要检查规则是不是真的清空了,因为有的linux发行版上这个命令不会清除NAT表中的规则,此时只能手动清除:
iptables -t NAT -F

  • Ubuntu
    首先,保存现有的规则:
    ptables-save > /etc/iptables.rules
    然后新建一个bash脚本,并保存到/etc/network/if-pre-up.d/目录下:
    #!/bin/bash iptables-restore < /etc/iptables.rules
    这样,每次系统重启后iptables规则都会被自动加载。

    注意:不要尝试在.bashrc或者.profile中执行以上命令,因为用户通常不是root,而且这只能在登录时加载iptables规则。

  • CentOS, RedHat
    1
    2
    3
    4
    5
    6
    7
    # 保存iptables规则
    service iptables save
    # 重启iptables服务
    service iptables stop
    service iptables start
    查看当前规则:
    cat /etc/sysconfig/iptables
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
使用扩展模块进行匹配
使用模块扩展进行匹配时,必须使用 -m 指明由哪个模块进行的扩展
多端口匹配
-m multiport
--sports [!] port[,port[,port:port...]] 匹配多个源端口
--dports [!] port[,port[,port:port...]] 匹配多个目标端口
--ports 匹配多个端口(无论源还是目标端口)
范围 IP 地址匹配
-m iprange
[!] --src-range IPADDR-IPADDR 匹配一个范围的源 IP 地址
[!] --dst-range IPADDR-IPADDR 匹配一个范围的目标 IP 地址
连接数限制
-m connlimit
[!] --connlimit-above N 限制同时连接数量
连接速率限制
-m limit
--limit RATE 单位时间连接控制,使用 '/second''/minute''/hour''/day' 等单位为后缀,默认是 3/hour
--limit-burst N 同一时间的连接的并发连接控制,默认为 5
报文内容字符串匹配
-m string
--algo {bm|kmp} 字符串匹配算法,可以选择 bm 或 kmp
--string "STRING" 匹配的字符串
--hex-string "STRING" 十六进制格式的字符串
基于时间的控制
-m time
--datestart YYYY[-MM[[-DD[Thh[:mm[:ss]]]]]
--datestop YYYY[-MM[-DD[Thh[:mm[:ss]]]]]
匹配起始时间与结束时间
--timestart hh:mm[:ss]
--timestop hh:mm[:ss]
[!] --monthdays day[,day...]
[!] --weekdays day[,day...]
根据时间和星期几来匹配

参考
http://liaoph.com/iptables/
http://xstarcd.github.io/wiki/Linux/iptables_forward_internetshare.html
https://wsgzao.github.io/post/iptables/
https://lesca.me/archives/iptables-tutorial-structures-configuratios-examples.html
http://www.cnblogs.com/JemBai/archive/2009/03/19/1416364.html