ipfw介绍

功能

根据文档可知, iptables实际上就是一个ip包过滤管理器, 结合之前做过的防火墙经验(modsecurity), 实际上就是一个本地防火墙, 认真研究iptables命令文档, 你会发现它的实际逻辑和防火墙是真的非常像.

  1. 通过定义一系列的规则链条来进行数据的防护, 每一种类型的链条处理不同的数据
  2. input(入包), forword(通过包), output(本地生成包), 类似waf上请求响应的规则处理
  3. 在完成基本包过滤基础上增加一个额外的包修改, 包转发等功能

iptables本身仅仅是一个客户端代理, 一个命令行工具, 只有将一些安全设置指定到对应的安全框架中, 此时其和安全框架共同组成了防火墙, 这个安全框架叫netfilter. netfilter算是主机防火墙或者软件防火墙, 而waf等是网络防火墙硬件防火墙, 前者主要实现下面三个功能:

  1. 网络地址转发
  2. 数据包内容修改
  3. 数据包过滤

iptables通过链概念, 表分类, 规则等概念, 并结合前两者实现了数据的处理, 这些概念会在后面提及, 这里先简单的介绍下表, 链, 规则的关系:

  1. 每一个表包含内部链, 也可以包含用户自定义链
  2. 每一个链是一个规则列表, 对相应包进行pattern(模式匹配)和action
  3. 每条规则定义了如何处理相匹配的包, 这被称为target(action)
  4. 每一条链可以被多个表关联.

让我们将功能和上面术语结合在一起:

  • 涉及包内容过滤时: 使用INPUT/OUTPUT 链来进行ACCEPT, REJEST, DROP.
  • 涉及包转发时: 使用PREROUTING, FORWARD, POSTROUTING链来进行包转发

注意, 并非所有的链组合成一个串行结构, 可能是条件结构, 并行结构等, 例如:

  • 进入本机报文经过链: PREROUTING->INPUT
  • 经由本机转发报文: PREROUTING -> FORWARD -> POSTROUTING
  • 本机发出的报文: OUTPUT -> POSTROUTING

命令

iptables命令格式如下:

1
2
3
4
5
6
7
8
iptables -[ACD] chain rule-specification [options], [A-append D-删除 C-check]
iptables -I chain [rulenum] rule-specification [options] (I-插入)
iptables -R chain rulenum rule-specification [options] (替换)
iptables -D chain rulenum [options] (Delete, 可以将删除的规则指定为链中的序号)
iptables -LFZ 链名 [选项] (L-显示所有链规则, 默认所有链所有规则, F-清空, Z-清空链中所有计数器)
iptables -[NX] 指定链 (N-new chain, 创建新链, X-delete chain, 删除用户自定义链, 被引用无法删除)
iptables -P chain target [options] (P-设置链目标规则)
iptables -E old-chain-name new-chain-name (E-rename chain, 重命名链)

整体命令格式可以总结如下: iptables [CMD] rulenum [options], 其中CMD就是上面所述, 其本身也归属于options, 下面简单的介绍一下options.

options

  1. commands: 这些选项指定执行明确的动作, 一般而言, 只能指定一个选项
  2. paramater: 使用参数指定一个特定的规则, 常常用于add, delete, replace, append, check等命令中.
  3. other: 其他特殊选项信息

这里简单的介绍下参数选项信息:

1
2
3
4
5
6
7
-p [!] protocol  指定规则或包检查准备处理的协议类型, 可以是协议号或者协议名, !表示相反规则, 0 表示所有
-s [!] address[/mask] 指定source address, 可以是主机,网络名,IP 名
-d [!] address[/mask] 指定目标address
-j target 指定规则target(类似action, 见下文介绍)
-i [!] name 指定包进入或转发的网络接口名, 指定后包从该接口进入
-o [!] name 指定包出口
[!] -f 处理分片包时, 只处理第二以及之后的片

其他选项信息:

1
2
3
4
-v      详细输出
-n 数字形式输出
-x 显示包和字节计数器的精确值
--line-numbers 当列表显示规则时, 在每个规则的前面加上行号(规则在链中位置)

安装配置

  1. 重启, 停止, 打开防火墙: /etc/init.d/iptables start/stop/restart
  2. 永久性关闭/打开防火墙
1
2
3
4
5
6
7
8
# 关闭
chkconfig --level 35 iptables off
/etc/init.d/iptables stop
iptables -P INPUT DROP

# 开启
chkconfig --list
chkconfig --level 235 iptables on
  1. centos下iptables操作
1
2
3
4
5
6
7
8
9
10
11
12
13
# 1. 启动和关闭
systemctl stop firewalld.service
systemctl disable firewalld.service
yum install iptables-services
systemctl enable iptables

# 停止iptables
systemctl status iptables.service
systemctl stop iptables.service
systemctl status iptables.service

# 重启iptables:
service iptables restart

开启端口: vim /etc/sysconfig/iptables, 之后增加端口到相应文件中

链和表

链包含内部定义链和用户自定义链, 每个链都是一系列的规则, 不同的链在不同的关卡中进行着不同的包过滤检查机制, 内部定义链:

  • prerouting (经由路由, 公网进入当前内网时)
  • input
  • output
  • forward
  • postrouting (经由路由, 内网通往外网时)

自定义链条不能单独使用, 其需要被某个默认的链条当做target调用之后才能作为默认链的某一个补充来进行包处理.

将具有相同功能的规则聚集在一起, 形成table, 这是一个逻辑概念, 从而高效的进行表的管理, 实际进行包过滤的时候还是基于链来完成, 当然链中的每一条规则则归属于不同的table. 目前有四种功能的表:

  1. filter表: 负责包过滤, 实现防护墙机制
  2. nat表: 网络地址转发
  3. mangle表: 包修改和重新封装
  4. raw表: 关闭nat表上启用的连接追踪机制

其中过滤功能有:

  • 哪些 IP 可访问
  • 哪些 IP 不能访问
  • 允许哪些端口
  • 禁止访问特定端口

一般而言, 用户自定义链中的规则在特定的table

  • prerouting: raw, mangle, nat表, 路由上也一般不做包过滤, 仅做包转发
  • input: mangle, filter, nat表
  • output: mangle, filter, nat, raw表
  • forward: mangle, filter表
  • postrouting: mangle, nat表

另外, 默认情况下, 每一个链中的不同表规则存在优先级问题, 一般来说: raw > mangle > nat > filter. 默认情况下, 查询规则时都是基于表去查找当前拥有的链路和规则信息的, 即上面信息的相反对应关系.

数据流

数据经过防火墙的数据流图如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

┌────────────────────────────┐
│ protocol stack │
└─▲────────────────────────┬─┘
│ │
│ │
│ │
┌──┴──┐ ┌───▼──┐ raw
mangle │input│ │output│ mangle
nat └──▲──┘ └───┬──┘ nat
filter │ │ filter
│ │
│ │
│ │
│ │
┌───────────┐ │ ┌───────┐ │ ┌───────────┐
─────►prerouting ├────┴─────────►forward├──────┴────────►postrouting├─────►
└───────────┘ route └───────┘ └───────────┘
raw mangle mangle
mangle filter nat
nat
───────────────────────────────────────────────────────────────────►

另外, 如果在 LINUX 上想要主机支持转发功能, 需要内核开启IP_FORWARD 功能.

规则结构

类似modsecurity防护策略一样, 链表内的规则也是由patternaction组成.

  1. 匹配条件: 分为基本匹配条件和扩展匹配条件
  • 基本匹配条件: 源地址Source IP, 目标地址Destination IP
  • 扩展匹配条件: 例如源端口, 目的端口等
  1. 处理动作: 在iptables中称为target, 动作称为基本动作和扩展动作
  • ACCEPT: 允许数据包通过
  • DROP: 丢包
  • REJECT: 拒绝
  • SNAT: 源地址转换, 解决内网用户用同一个公网地址上网的问题
  • MASQUERADE: SNAT的一种特殊形式, 用于动态,临时 IP 上
  • DNAT: 目标地址转换
  • REDIRECT: 本地端口映射
  • LOG: 记录日志并传递给下一条规则

3. 命令

查询命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 指定表信息, 获取表中所有链路
iptables -t filter -L
iptables -t raw -L
iptables -t mangle -L
iptables -t nat -L
# 列出所有表中的所有规则
iptables -L

# 3. 查询指定链中的规则
iptables -L INPUT
# 4. 列出详细信息(报文个数, 报文总大小等)
iptables -vL INPUT
# 5. 不适用名称解析, 提高速度
iptables -nvL INPUT

# 6. 显示每条规则的序号, 便于后续进行规则的中间插入
iptables --line-number -nvL INPUT

# 7. 清空某个链上所有规则
iptables -F INPUT

输出项

当命令中包含-v时会输出详细的规则信息:

  • pkts: 该规则匹配到的包数量
  • bytes: 该规则匹配到的报文总大小
  • target: 规则对应的动作
  • prot: 规则对应的协议
  • opt: 规则对应的选项
  • in: 数据包由哪个网卡流入
  • out: 数据包由哪个网卡流
  • source: 规则对应的源地址, 例如 IP, 网段, 默认显示anywhere, 名称解析
  • destination: 规则对应的目的地址, 例如 IP, 网段, 默认为anywhere

处理这些输出信息之外, 在头部还有一些计数信息, 表示策略, 所有包统计信息

  • policy ACCEPT: 当前链的默认策略, 这里表示通过
  • packets: 当前链默认策略匹配到的包的数量
  • bytes: 当前链默认策略匹配到的所有包的大小总和

工作场景 1: 禁止某个IP地址访问我们的主机
配置: 需要在 INPUT 链上定义规则, 根据 2.3 的数据流可以知道进入本机的数据
包流量会经过 PREROUTING和INPUT 链处理, 但是PREROUTING链不存在filter表中的
规则, 即天生不支持过滤, 所以只能在 INPUT 中定义.

规则操作

  1. 增加规则命令, 具体例子可见4.1节中的ping命令规则添加
1
2
3
4
5
6
# 1. 链首插入一条 ACCEPT 命令
iptables -t filter -I INPUT -p icmp -s 192.168.0.100 -j ACCEPT
# 2. 链尾插入一条 DROP 命令(TELNET, 指定端口)
iptables -t filter -A INPUT -p tcp --dport 23 -s 192.168.0.100 -j DROP
# 3. 插入链第二行
iptables -t filter -I INPUT 2 -p telnet -s 192.168.0.100 -j ACCEPT
  1. 删除规则命令, 指定序号或者根据匹配条件/动作进行删除
1
2
3
4
5
6
# 1. 根据序号删除
iptables -t filter -D INPUT 2
# 2. 根据匹配条件和动作删除特定规则
iptables -t filter -D INPUT -s 192.168.0.100 -j DROP -p tcp -dport 23
# 3. 删除所有规则(指定表), 危险操作
iptables -t filter -F
  1. 更改规则
1
2
3
4
# 1. 根据序号进行更改(规则原本的匹配条件也必须填写)
iptables -t filter -R INPUT 1 -s 192.168.0.100 -p tcp --dport 23 -j REJECT
# 2. 更改链上的默认规则, -P表示设置链规则
iptables -t filter -P FORWARD DROP
  1. 保存规则, 默认情况下上面的命令在重启iptables或者重启服务器之后都会重置
1
2
3
4
5
6
# 1. centos6保存iptables规则, 默认保存到/etc/sysconfig/iptables
service iptables save
# 2. ubuntu(必须超级用户), centos中也可以使用iptables-save
iptables-save > /etc/iptables.rules
# 3. 加载
iptables-restore < /etc/sysconfig/iptables

匹配条件

上面规则命令中都涉及到包的匹配逻辑, 那么匹配条件都有哪些呢? 除了源地址还有哪些匹配条件?

  1. 指定源地址(单个或者多个)
1
2
3
4
5
6
7
8
9
10
# 1. 单 IP
iptables -t filter -I INPUT -s 192.168.0.100 -j DROP
# 2. 多 IP(逗号不能有空格)
iptables -t filter -I INPUT -s 192.168.0.10,192.168.0.101 -j DROP
# 3. 指定网段
iptables -t filter -I INPUT -s 192.168.0.0/16 -j DROP

# 4. 取反操作, 非指定源地址, 这并非表明如果原地址是192.168.0.100就 DROP,
# 取反并不是直接说明反向条件成立
iptables -t filter -I INPUT ! -s 192.168.0.100 -j ACCEPT
  1. 目标地址(适用于多网卡, 多 IP 情况)
1
2
# 1. 指定入口网卡 IP
iptables -t filter -I INPUT -d 192.168.0.103 -p icmp -j DROP
  1. 协议类型
1
2
3
4
5
# 1. tcp所有端口(该操作会将所有连接关闭)
iptables -t filter -I INPUT -s 192.168.0.100 -p tcp -j REJECT
# 2. 其他协议类型: tcp, udp, udplite, icmp, icmpv6,esp, ah, sctp, mh
# 默认情况下, 所有协议
iptables -t filter -I INPUT -d 192.168.0.103 -j DROP
  1. 网卡接口
1
2
3
4
# 1. 指定网卡而非 IP, -i 仅仅判断包流入, 仅仅用于INPUT, FORWARD, PREROUTING
iptables -t filter -I INPUT -i eth0 -p icmp -j DROP
# 2. 指定出口网卡, -o 用于OUTPUT, FORWARD, POSTROUTING
iptables -t filter -O OUTPUT -o eth0 -p icmp -j DROP
  1. 指定源端口和目的端口(扩展匹配条件)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 1. 使用扩展匹配条件需要指定扩展模块名称, -m指定扩展模块名称
iptables -t filter -I INPUT -s 192.168.0.100 -p tcp -m tcp --dport 23 -j REJECT
# 2. 默认情况下, 省略-m, 则会将-p指定的名称作为扩展模块名称
iptables -t filter -I INPUT -s 192.168.0.100 -p tcp --dport 23 -j REJECT

# 3. 源端口
iptables -t filter -I INPUT -s 192.168.0.100 -p tcp --sport 22 -j REJECT

# 4. 设置端口范围
iptables -t filter -I INPUT -s 192.168.0.100 -p tcp --dport 22:25 -j REJECT
# 5. 设置80~65535端口范围(类似python的切片)
iptables -t filter -I INPUT -s 192.168.0.100 -p tcp --dport 80: -j REJECT

# 6, 离散端口, 借助multiport扩展模块
iptables -t filter -I INPUT -s 192.168.0.100 -p tcp -m multiport --dport 22,36,80 -j REJECT

扩展模块

除了上面讲解的基本扩展模块用于扩展匹配条件, 还有很多其他扩展模块极大的丰富了iptables的功能.

  1. iprange: 一段连续的ip地址范围, 用于匹配源地址, 目标地址
1
2
3
4
# 1. 源匹配条件(--src-range)
iptables -t filter -I INPUT -m iprange --src-range 192.168.0.100-192.168.0.105 -j DROP
# 2. 目标匹配条件(--dst-range)
iptables -t filter -I INPUT -m iprange --dst-range 192.168.0.100-192.168.0.105 -j DROP
  1. string: 指定匹配的字符串, 用于报文全文匹配, 需要指定匹配算法
1
2
# 1. 对 HTTP 请求内容的过滤
iptables -t filter -I INPUT -m string --algo bm --string "bifeng" -j REJECT
  1. time: 根据时间段匹配报文, 报文如果在该时间段内达到或者发出, 则设置规则
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 1. 例如, 约束指定时间不能浏览网页
iptables -t filter -I OUTPUT -p tcp --dport 80 -m time --timestart 09:00:00 \
--timestop 12:00:00 -i REJECT
# 2. 指定星期几
iptables -t filter -I OUTPUT -p tcp --dport 80 -m time --weekdays 6,7 -j REJECT
# 3. 使用字符串形式的星期
iptables -t filter -I OUTPUT -p tcp --dport 80 -m time --weekdays Mon,Tue -j REJECT

# 4. 星期几, 具体时间点
iptables -t filter -I OUTPUT -p tcp --dport 80 -m time --timestart 09:00:00 \
--timestop 12:00:00 --weekdays 6,7 -i REJECT

# 5. 几号
iptables -t filter -I OUTPUT -p tcp --dport 80 -m time --monthdays 22,23 -j REJECT
# 6. 日期范围
iptables -t filter -I OUTPUT -p tcp --dport 80 -m time --datestart 2021-05-01 \
--datestart 2021-05-05 -j REJECT
  1. connlimit: 限制每一个 IP地址同时连接到server端的数量, 默认所有客户端 IP, 单 IP 连接限制
1
2
3
4
# 1. 限制ssh连接
iptables -t filter -I INPUT -p tcp --dport 22 -m connlimit --connlimit-above 2 -j REJECT
# 2. 限制网段(24表示 C 类网段)
iptables -t filter -I INPUT -p tcp --dport 22 -m connlimit --connlimit-mask 24 -j REJECT
  1. limit: 类似connlimit, 对报文到达速率进行限制, 限制单位时间内流入包数量
1
2
3
# 1. 每分钟限制数量为10(限制ping), 通过两条规则达到条件
iptables -t filter -I INPUT -p icmp -m limit --limit 10/minute -j ACCEPT
iptables -t filter -A INPUT -p icmp -j REJECT

配置和实例

阻止ping

有如下两台机器:

1
2
3
4
5
# 1. 其中, 通过mac ping Ubuntu
mac(192.168.0.100) --> ubuntu(192.168.0.103)
# 2. 查看ubuntu防火墙上的收到的包信息(iptables -nvL INPUT)
Chain INPUT (policy ACCEPT 1854 packets, 992K bytes)
pkts bytes target prot opt in out source destination

现在, 如果希望仅仅mac所在 IP 访问当前机器, 可以在ubuntu上设置如下信息:

1
2
3
4
5
6
7
8
9
10
# 1. 增加规则(指定规则类型-表, 指定链-INPUT)
# -s 指定source, -j 指定规则动作信息
# 当然, 最好不要这样做, 这样会被ssh也禁止了
iptables -t filter -I INPUT -s 192.168.0.100 -j DROP

# 2. 增加特定协议类型的包
iptables -t filter -I INPUT -p ICMP -s 192.168.0.100 -j DROP

# 3. 此时查看INPUT 链上的规则包统计信息
iptables -nvL INPUT

输出如下:

1
2
3
Chain INPUT (policy ACCEPT 92 packets, 6584 bytes)
pkts bytes target prot opt in out source destination
76 6384 DROP icmp -- * * 192.168.0.100 0.0.0.0/0

链顺序

在 4.1 中我们增加了一个DROP动作的规则, 那么如果我们在该规则的后面再添加一条ACCEPT
的规则, 那么是否可以ping通目标主机呢?

1
2
3
4
# 1. 默认情况下表类型都是filter, -A表示append
iptables -A INPUT -p icmp -s 192.168.0.100 -j ACCEPT
# 2. 查看链上规则, 并查看输出
iptables -nvL INPUT

输出如下:

1
2
3
4
Chain INPUT (policy ACCEPT 62 packets, 4483 bytes)
pkts bytes target prot opt in out source destination
6476 544K DROP icmp -- * * 192.168.0.100 0.0.0.0/0
0 0 ACCEPT icmp -- * * 192.168.0.100 0.0.0.0/0

让我们再次增加一条新规则, 现在将规则插入到链首部

1
2
3
4
5
6
# 1. -I 表示insert
iptables -I INPUT -p icmp -s 192.168.0.100 -j ACCEPT
# 2. 查看规则顺序(输出序号)
iptables --line-number -nvL INPUT
# 3. 查看输出
iptables -nvL INPUT

输出如下:

1
2
3
4
5
Chain INPUT (policy ACCEPT 102 packets, 6504 bytes)
pkts bytes target prot opt in out source destination
12 1008 ACCEPT icmp -- * * 192.168.0.100 0.0.0.0/0
6581 553K DROP icmp -- * * 192.168.0.100 0.0.0.0/0
0 0 ACCEPT icmp -- * * 192.168.0.100 0.0.0.0/0

所以规则的顺序非常重要, 可以使用--line-number查看链上各个规则的顺序, 如果希望新增加的
规则在中间插入, 只需要指定序号即可:

1
2
# 1. 新增加一个规则, 指定序号为 1(类似 -I INPUT)
iptables -t filter -I INPUT 1 -p icmp -s 192.168.0.100 -j DROP

白名单机制

默认情况下, 所有链的策略都是ACCEPT, 新增加的链规则都是 DROP, REJECT, 这就是黑名单机制,这导致上面的频率限制等会出现问题, 未匹配的规则实际上默认还是走了 ACCEPT, 所以上面所有命令的!操作都有点怪.
我们可以设置白名单方式, 将所有链的默认规则设置为DROP, 在一个个增加相应规则, 确保所有流量都在自己的控制范围之内, 但是如果直接将所有链规则设置为DROP, 有时候可能导致一个问题, 当不小心清除所有链规则时, 好了, 管理员自己无法连接远程服务器了, 所以最好的白名单方式:

  • 最好在每一个链的末尾增加一个REJECT 规则即可

业务场景

1
2
3
4
# 1. 限制指定的IP可以访问, ip段,此时其他IP无法访问
iptables -I INPUT -s 192.168.199.0/24 -p tcp -dport 8989 -j Accept
# 2. 封禁某一个ip信息
iptables -I INPUT -s 192.168.199.3/16 -j Drop

查看当前防火墙允许接受的所有协议(或者端口号)

1
2
3
4
5
6
7
8
# 命令
/etc/init.d/iptables status
或者
iptables -L

# 输出
-> 如果没有显示防火墙规则,则表示没有设置防火墙策略;
-> 即使服务器运行,如果防火墙规则没有设置,则iptables处于"无效状态"

临时打开指定的端口: iptables -A INPUT -p tcp --dport 21 -j ACCEPT

引用