# Iptables 防火墙实战
# 1.Iptables 基本介绍
# 1.1 什么是防火墙
- 过去,很长一段时期里,房屋都是草屋结构,如果一家失火,四邻也会跟着遭殃,所以为安全起见,古人就在自己居住地周围修筑搞搞的围墙,以阻挡外来的火势,保护自身的安全,这种墙就叫 “防火墙”。
- 如今,“英特网” 把世界各地的计算机都紧密地连接在一起。如果不严加防卫,一旦网络被侵害,可能会出现不可预计的损失。那么互联网上,我们会采用类似防火墙的方法,来保护我们的网络不受侵害,为此我们需要设定防火墙规则,确定哪些类型的数据包允许通过,哪些不允许通过。
- 那么具备这种功能的 “设备或软件” 就可以称之为 “防火墙”
# 1.2 防火墙的种类
从逻辑上讲,防火墙可以大体分为主机防火墙和网络防火墙:
- 主机防火墙:针对于单个主机进行防护,比如 Windowns。
- 网络防火墙:往往处理网络入口,针对于网络入口进行防护, 服务于防火墙背后的服务器集群。
从物理上讲,防火墙可以分为硬件防火墙和软件防火墙:
- 硬件防火墙:在硬件级别实现部分防火墙功能,另外一部分功能基于软件实现,性能高、成本高。
- 软件防火墙:以软件的方式模拟防火墙功能,运行在操作系统上,性能不高,成本低。
# 1.3 什么是 iptables
- iptables 其实不是真正的防火墙,就是一个代理程序,用户通过 iptables 这个代理程序,将安全规则执行到对应的 “安全框架” 中,这个 “安全框架” 才是真正的防火墙,这个安全框架叫 netfilter,是内核代码中不可缺少的一部分;
- iptables 位于操作系统的用户空间,我们后期是通过 iptables 命令工具操作 netfilter 内核框架;
- 所以 iptables 的完整叫法应该是 netfilter/iptables,它是 linux 平台下的 “包过滤型防火墙”,这个包过滤防火墙是免费的,它可以替代昂贵的商业防火墙解决方案,完成数据包的过滤、连接追踪、限速、网络地址转换(NAT)等功能。

# 1.4 什么是包过滤防火墙
包过滤防火墙它工作在 OSI 七层模型中的网络层,用来匹配网络数据包的 Header:
- 1. 将 Head 与预先定义好的防火墙规则进行比对;
- 2. 与规则相匹配的包会被放行;
- 3. 与规则不匹配的包则可能会被丢弃,也可能执行更复杂的动作;
由于包过滤防火墙工作在网络层,故也称 “网络层防火墙”,它通过检查每一个数据包的:
- 源地址、目的地址;
- 源端口、目的端口;
- 协议类型 TCP、UDP、ICMP,等状态信息来判断是否符合规则;
# 1.5 包过滤防火墙如何实现
包过滤防火墙是由 Netfilter 来实现,它是内核的一部分,如果我们想要防火墙能够达到 “防火” 的目的,则需要在内核中设置关卡,所有进出的数据报文都要经过这些关卡进行检查:
- 将如何条件的放行;
- 不符合条件的阻止;
- 而这些关卡在 iptables 中不被称为 “关卡”,而是被称为 “链”;
# 2. Iptables 链的概念
# 2.1 什么是链
在 iptables 中的关卡为什么被称为 “链” 呢?
防火墙的作用就在于对经过的数据报文进行 "规则" 匹配,然后执行规则对应的 “动作”,所以当报文经过这些关卡的时候,则必须匹配这个关卡上的规则,但是这个关卡上可能不止一条规则,而是有很多条规则,当我们把这些规则串到一起的时候,就形成了 “链”。
所以,每个经过这个 “关卡” 的报文,都要讲这条 “链” 上的所有规则匹配一遍,如果有如何条件的规则,则执行规则对应的动作,如果没有则执行默认链的动作。

# 2.2 iptables 有哪些链链
当我们启动了防火墙功能时,报文需要经过很多关卡,也就是说,根据实际情况的不同,报文经过 “链” 可能不同,大体分为如下三类:
- 1. 请求到达本机: PREROUTING --> INPUT --> Local Process
- 2. 请求经过本机: PREROUTING --> FORWARD --> POSTROUTING
- 3. 请求从本机发出:Process --> OUTPUT --> POSTROUTING
了解 iptables 链的数据包流向,后期在设定规则时,能很清楚的知道将规则设定在哪个链上。

# 3. Iptables 表的概念
# 3.1 什么是表
我们对每个 “链” 上都放置了一串规则,但是这些规则有些很相似,比如:
- A 类规则都是对 IP 或者端口的过滤;
- B 类规则都是对报文进行修改的;
- C 类规则都是进行地址转换的;
当我们把具有相同功能的规则集合在一起叫作 “表”,所以说,不同功能的规则,我们可以放置在不同的表中进行管理,二 iptables 已经为我们定义了 4 种表,每种表对应不同的功能。
# 3.2 表的功能
| 表名 | 用途 | 常用链 |
|---|---|---|
| filter | 默认表,用于数据包过滤(允许 / 拒绝流量) | INPUT, FORWARD, OUTPUT |
| nat | 网络地址转换(如端口转发、共享上网) | PREROUTING,INPUT, OUTPUT, POSTROUTING |
| mangle | 修改数据包内容(如 TTL、QoS 标记) | PREROUTING, POSTROUTING,INPUT, FORWARD, OUTPUT |
| raw | 关闭 nat 表上启用的连接追踪机制 | PREROUTING, OUTPUT |
# 3.3 表与链的关系
raw-->mangle-->nat-->filter

- 问题 1:来自
10.0.0.1的地址,访问本机的 WEB 服务请求不允许,应该在哪个表的哪个链上设定规则?
答案一:很多同学会觉得是 PREROUTING 链,但其实是 INPUT 链,因为我们要做的是过滤,而 PREROUTING 不能做过滤,所以应该在 filter 表中的 INPUT 规则链上设定规则。 - 问题 2:所有由本机发往
10.0.0.0/24网段的TCP服务都不允许?
答案二:由本地发出会经过 OUTPUT、POSTROUTING,但由于 POSTROUTING 不支持做过滤,所以应该在 filter 表中的 OUTPUT 规则链上配置。 - 问题 3:所有来自己本地内部网络的主机,向互联网发送 WEB 服务器请求都允许?
答案三:由本地发出会经过 PREROUTING,、FORWARD、POSTROUTING ,但由于 PREROUTING,POSTROUTING 不支持做过滤,所以应该在 filter 表中的 FORWARD 链上设定规则。
# 4. Iptables 规则管理
# 4.1 什么是规则
- 数据包的过滤基于规则,而规则是由匹配条件 + 动作组成,那我们对规则的操作无非就是增删改查。
- 操作规则的语法:iptables -t <表名> < 选项 > < 链名 > [规则] -j < 动作 >
- 操作规则之前我们需要考量如下两个问题:
- 1)要实现什么功能:判断添加到哪个表上;
- 2}报文流经的路线:判断添加到哪个链上;
| iptables 选项 | 含义 | 示例 |
|---|---|---|
| -t,--table | 指定要操作的表(默认 filter) | iptables -t filter |
| -A,--append | 最佳一条规则至链的末尾 | iptables -t filter -A INPUT |
| -I,--insert | 追加一条规则至链的首部 | iptables -t filter -I INPUT |
| -D,--delete | 指定删除一条规则 | iptables -t filter -D INPUT 1 |
| -R,--replace | 替换选定链中的规则 | iptables -t filter -R INPUT |
| -S,--list-rules | 打印选定链中的所有规则 | iptables -t filter -S |
| -Z,--zero | 将所有链中的数据包和字节计数器归零 | iptables -t filter -Z |
| -N,--new-chain | 创建自定义名称规则链 | iptables -N New_Rules |
| -E,--rename-chain | 给自定义链修改名称 | iptables -E Old_Rules New_Rules |
| -X,--delete-chain | 删除自定义链 | iptables -X Rules_Name |
| -P,--policy | 给链设定默认策略 | iptables -t filter -P DROP |
# 4.2 如何查看规则
#1. 如何查看 | |
[root@route ~]# iptables -t filter -L -n -v --line-numbers | |
-t 指定表明 | |
-L 查看详情 | |
-n 不反解 | |
-v 详细信息 | |
-line-numbers 显示规则编号 | |
#2. 如何添加规则: 禁止 10.0.0.10 ping 10.0.0.200 | |
[root@route ~]# iptables -t filter -I INPUT -p icmp -s 10.0.0.10 -j drop | |
#3. 如何修改规则 | |
-R:修改 需要指定规则的编号 | |
[root@route ~]# iptables -t filter -R INPUT 1 -p icmp -s 10.0.0.10 -j REJECT | |
#4. 如何清空计数器 | |
[root@route ~]# iptables -t filter -Z | |
#5. 备份规则 | |
[root@route ~]# iptables-save > /etc/iptables.rule | |
#6. 清空规则 | |
[root@route ~]# iptables -F # 只操作 filter | |
[root@route ~]# iptables -t nat -F # 清空 nat 表 | |
#7. 恢复规则 | |
[root@route ~]# iptables-restore < /etc/iptables.rule | |
#8. 永久生效 | |
命令: iptables-restore < /etc/iptables.rule | |
加入开机自启动 /etc/rc.local |
# 5.Iptables 基本匹配
# 5.1 iptables 匹配参数
| 条件参数 | 含义 |
|---|---|
| [!] -p, --protocol protocol | 指明需要匹配的协议,如 icmp、udp、tcp |
| [!] -s, --source address[/mask][,...] | 指定匹配源地址,如有多个可以逗号分隔 |
| [!] -d, --destination address[/mask][,...] | 指定匹配目标地址,如有多个可以逗号分隔 |
| [!] --source-port,--sport port[:port] | 指定源端口 |
| [!] --destination-port,--dport port[:port] | 指定目标端口 |
| [!] -i, --in-interface name | 接收数据包的接口名称 |
| [!] -o, --out-interface name | 发送数据包的接口名称 |
| -m, --match match | 执行需要使用的匹配项,属于扩展匹配 |
| -j, --jump target | 执行匹配规则后的动作、ACCEPT、DROP、REJECT 等 |
# 5.2 iptables 匹配示例
1.仅允许`10.0.0.1` 访问 `10.0.0.200` 服务器的`22`端口、其他地址全部拒绝; | |
[root@route ~]# iptables -t filter -I INPUT -s 10.0.0.1 -d 10.0.0.200 -p tcp --dport 22 -j ACCEPT | |
[root@route ~]# iptables -t filter -A INPUT -d 10.0.0.200 -p tcp --dport 22 -j DROP | |
2.所有来访问本机的协议,属于TCP协议的我们通通都放行; | |
[root@route ~]# iptables -t filter -I INPUT -p tcp -j ACCEPT | |
[root@route ~]# iptables -t filter -I INPUT -j DROP | |
3.凡是由本机发出的TCP协议报文,都允许出去,其他协议不行; | |
[root@route ~]# iptables -t filter -I OUTPUT -p tcp -j ACCEPT | |
[root@route ~]# iptables -t filter -I OUTPUT -j DROP | |
4.禁止其他主机从eth0向本机发送ping请求 | |
[root@route ~]# iptables -t filter -I INPUT -i eth0 -p icmp -j DROP | |
5.允许从本机发送`ping`请求,其他任何协议都不允许; 【ssh也会掉线】 | |
[root@route ~]# iptables -t filter -I OUTPUT -p icmp -j ACCEPT | |
[root@route ~]# iptables -t filter -A OUTPUT -j DROP |
# 6. Iptables 扩展匹配
# 6.1 multiport 模块
使用 multiport 模块可以添加多个不连续的端口;-m multiport <--sports|--dports|--ports> 端口 1 [, 端口 2,.., 端口 n]
示例 : 10.0.0.10 访问本机 20、21、80、443 允许通过;
[root@route ~]# iptables -t filter -I INPUT -s 10.0.0.10 -d 10.0.0.200 -p tcp -m multiport --dport 20:22,80,443 -j ACCEPT | |
[root@route ~]# iptables -t filter -A INPUT -j DROP |
# 6.2 iprange 模块
使用 iprange 模块可以指定 "一段连续的 IP 地址范围",用于匹配报文的源地址或者目标地址, iprange 扩展模块中有两个扩展匹配条件可以使用。
[!] --src-range from [-to]: 原地址范围
[!] --dst-range from [-to]: 目标地址范围
示例: 10.0.0.5-10.0.0.10 地址段 ping 本机,则丢弃
[root@route ~]# iptables -t filter -I INPUT -p icmp -m iprange --src-range 10.0.0.5-10.0.0.10 --dst-range 10.0.0.200 -j DROP |
# 6.3 String 模块
使用 string 扩展模块,可以指定要匹配的字符串,如果报文中包含对应的字符串,则符合匹配条件。
- --algo {bm|kmp} :字符匹配的查询算法;
- [!] --string pattern :字符匹配的字符串;
示例:应用返回的报文中包含字符 "hello" ,我们就丢弃当前报文,其余正常通过。
#1. 安装 HTTPd 服务并准备两个页面 | |
[root@route ~]# yum install httpd -y | |
[root@route ~]# systemctl start httpd | |
[root@route ~]# echo "hello" > /var/www/html/index.html | |
[root@route ~]# echo "video" > /var/www/html/test.html | |
[root@redis ~]# curl 192.168.40.200/index.html | |
hello | |
[root@redis ~]# curl 192.168.40.200/test.html | |
video | |
#2. 配置 iptables 规则 (响应做规则匹配) | |
[root@route ~]# iptables -t filter -I OUTPUT -p tcp -m string --algo kmp --string "video" -j DROP | |
[root@redis ~]# curl 192.168.40.200/index.html | |
hello | |
[root@redis ~]# curl 192.168.40.200/test.html #被拦截 |
示例:用户请求后端节点,如果包含 “web.hmallleasing.com” 则拒绝。
[root@route ~]# iptables -t filter -I FORWARD -p tcp -m sting --algo kmp --string "web.hmallleasing.com" -j DROP |
# 6.4 time 模块
使用 time 扩展模块,根据时间段区匹配报文,如果报文到达的时间在指定的时间范围以内,则符合匹配条件。
- --timestart hh:mm [:ss] :开始时间
- --timestop hh:mm [:ss] :结束时间
- [!] --monthdays day [,day...] :指定一个月的某一天
- [!] --weekdays day [,day...] :指定周一到周天
- --kerneltz :使用内核时区而不是 UTC 时间
示例一:拒绝每天 8:00 ~ 12:00 (00:00-04:00)、14:00 ~ 18:00 (06:00-10:00),任何主机发送 icmp 协议。
#utc 时间与本地时间快 8 小时,所以需要 - 8 小时 | |
[root@route ~]# iptables -t filter -I INPUT -p icmp -m time --timestar 00:00 --timestop 04:00 -j DROP | |
[root@route ~]# iptables -t filter -I INPUT -p icmp -m time --timestar 06:00 --timestop 10:00 -j DROP |
示例二:限制用户在上班时间 (每天 8:00 ~ 12:00 (00:00-04:00)、14:00 ~ 18:00 (06:00-10:00)) 禁止访问优酷、爱奇艺等资源,其他时间可以正常访问;
#网络策略 | |
iptables -t filter -I FORWARD -p tcp -m string --algo kmp --string "youku" -m time --timestar 00:00 --timestop 04:00 -j DROP | |
iptables -t filter -I FORWARD -p tcp -m string --algo kmp --string "iqyi" -m time --timestar 00:00 --timestop 04:00 -j DROP | |
iptables -t filter -I FORWARD -p tcp -m string --algo kmp --string "taobao" -m time --timestar 00:00 --timestop 04:00 -j DROP | |
iptables -t filter -I FORWARD -p tcp -m string --algo kmp --string "jd" -m time --timestar 00:00 --timestop 04:00 -j DROP | |
iptables -t filter -I FORWARD -p tcp -m string --algo kmp --string "youku" -m time --timestar 06:00 --timestop 10:00 -j DROP | |
iptables -t filter -I FORWARD -p tcp -m string --algo kmp --string "iqyi" -m time --timestar 06:00 --timestop 10:00 -j DROP | |
iptables -t filter -I FORWARD -p tcp -m string --algo kmp --string "taobao" -m time --timestar 06:00 --timestop 10:00 -j DROP | |
iptables -t filter -I FORWARD -p tcp -m string --algo kmp --string "jd" -m time --timestar 06:00 --timestop 10:00 -j DROP | |
#主机策略 | |
iptables -t filter -I INPUT -p tcp -m string --algo kmp --string "youku" -m time --timestar 00:00 --timestop 04:00 -j DROP | |
iptables -t filter -I INPUT -p tcp -m string --algo kmp --string "iqyi" -m time --timestar 00:00 --timestop 04:00 -j DROP | |
iptables -t filter -I INPUT -p tcp -m string --algo kmp --string "taobao" -m time --timestar 00:00 --timestop 04:00 -j DROP | |
iptables -t filter -I INPUT -p tcp -m string --algo kmp --string "jd" -m time --timestar 00:00 --timestop 04:00 -j DROP | |
iptables -t filter -I INPUT -p tcp -m string --algo kmp --string "youku" -m time --timestar 06:00 --timestop 10:00 -j DROP | |
iptables -t filter -I INPUT -p tcp -m string --algo kmp --string "iqyi" -m time --timestar 06:00 --timestop 10:00 -j DROP | |
iptables -t filter -I INPUT -p tcp -m string --algo kmp --string "taobao" -m time --timestar 06:00 --timestop 10:00 -j DROP | |
iptables -t filter -I INPUT -p tcp -m string --algo kmp --string "jd" -m time --timestar 06:00 --timestop 10:00 -j DROP | |
#验证测试 | |
[root@redis ~]# curl -HHost:youku.hmallleasing.com http://172.16.1.200/index.html #被限制访问 |
# 6.5 icmp 模块
icmp 扩展模块:默认情况当禁止 ping 后,其他主机无法 ping 通本主机,本主机也无法 ping 通其他主机。
假设现在的需求是本主机可以 ping 通其他主机,而其他主机依然无法 ping 同本主机。
- [!] --icmp-type
- 指定 ICMP 类型: echo-request(8 请求)、echo-reply(0 回应)
#1. 禁用 icmp 无法满足需求 | |
[root@route ~]# iptables -t filter -I INPUT -p icmp -j DROP | |
#2. 通过抓包可以发现 ping 会发送 echo request(请求)、echo-reply(回应)报文 | |
[root@route ~]# tcpdump -p icmp -v | |
tcpdump: listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes | |
20:39:58.467850 IP (tos 0x0, ttl 64, id 25799, offset 0, flags [DF], proto ICMP (1), length 84) | |
192.168.40.41 > route: ICMP echo request, id 1770, seq 1, length 64 | |
20:39:58.467878 IP (tos 0x0, ttl 64, id 48604, offset 0, flags [none], proto ICMP (1), length 84) | |
route > 192.168.40.41: ICMP echo reply, id 1770, seq 1, length 64 | |
#3. 使用 icmp 模块 | |
[root@route ~]# iptables -t filter -I INPUT -p icmp -m icmp --icmp-type "echo-request" -j DROP |
# 6.6 connlimit 模块
connlimit 扩展模块,限制每个客户端 IP 地址到服务器的并行连接数。
- --connlimit-upto n :如果现有连接数小于或等于 n,则匹配。
- --connlimit-above n :如果现有连接数大于 n,则匹配。
DDOS 攻击脚本程序,模拟大量的并发数连接
[root@redis ~]# ll flood_connect.c |
示例:使用脚本模拟 DDOS 攻击,然后检查网站是否异常,如果异常,则使用 iptables 限制并发连接数。
#1. 模拟 DDOS 攻击 | |
[root@route ~]# yum install httpd -y | |
[root@route ~]# echo "hello" > /var/www/html/test.html | |
[root@route ~]# echo "index-xuyong" > /var/www/html/index.html | |
[root@route ~]# systemctl restart httpd | |
[root@redis ~]# gcc flood_connect.c | |
[root@redis ~]# ./a.out 192.168.40.200 | |
#2 通过 netstat 会发现大量的 ESTABLISHED 状态,从而造成正常用户请求异常,开启并发限制,然后测试 | |
[root@route ~]# netstat -ntp |wc -l | |
1013 | |
[root@route ~]# netstat -ntp | grep ESTABLISHED | wc -l | |
384 | |
[root@route ~]# netstat -ntp | grep SYN_RECV | wc -l | |
72 | |
#3. 限制同一 IP 的并发连接数为 10 | |
[root@route ~]# iptables -t filter -I INPUT -p tcp --dport 80 -m connlimit --connlimit-above 10 -j DROP |
# 6.7 limit 模块
limit 扩展模块:限制单位时间内流入包的数量。
可以以秒为单位进行限制,也可以以分钟、小时、天作为单位进行限制。
- --limit rate [second|minute|hour|day] :平均匹配的速率
- --limit-burst number :超过限制速率的包,允许超过 burst 所设定值,默认可超出 5 个
示例一:限制主机每分钟接收 10 个 icmp 数据包,差不多 6s 会接收客户端一个数据包
[root@route ~]# iptables -t filter -I INPUT -p icmp -m limit --limit 10/minute -j ACCEPT | |
[root@route ~]# iptables -t filter -A INPUT -p icmp -j REJECT |
示例二:允许 icmp 瞬间通过 10 个数据包通过,超过的数据包每分钟仅能通过一个
[root@route ~]# iptables -A INPUT -p icmp -m limit --limit 1/m --limit-burst 10 -j ACCEPT | |
[root@route ~]# iptables -A INPUT -p icmp -j REJECT |
示例三:限制主机传输时的带宽每秒不超过 500k
#(500k * 1000=500000 字节 / 1500=333 个包) | |
# 主机防护: | |
[root@route ~]# iptables -t filter -I OUTPUT -p tcp -m limit --limit 300/second -j ACCEPT | |
[root@route ~]# iptables -t filter -A OUTPUT -p tcp -j DROP | |
[root@route ~]# dd if=/dev/zero of=/var/www/html/bigdata bs=300M count=3 | |
[root@redis ~]# wget http://192.168.40.200/bigdata | |
# 网络防护: | |
[root@route ~]# iptables -t filter -I FORWARD -p tcp -m limit --limit 300/second -j ACCEPT | |
[root@route ~]# iptables -t filter -A FORWARD -p tcp -j DROP |
# 6.8 tcp-flags 模块
使用 tcp 扩展模块的 "--tcp-flags" 选项,即可对 TCP 的标志位进行匹配,匹配指定标志位的值是否为 "1",在 tcp 协议建立连接的过程中,需要先进行三次握手,而三次握手就要依靠 tcp 头中的标记位进行。
- 第一次:客户端向服务端发起第一次 TCP 连接时,在 TCP 的 flag 标志位中,SYN、RST、ACK、,FIN 等标记位仅有 SYN 为 1,其他标记位为 0。
- 第二次:服务端向客户端返回 ACK,在 TCP 的 flag 标志位中,SYN、RST、ACK,FIN 等标记位 SYN、ACK 为 1,其他标记位为 0。
- 第三次:客户端向服务端返回 ACK,在 TCP 的 flag 标志位中,SYN、RST、ACK,FIN 等标记位 ACK 为 1,其他标记位为 0。
我们可以通过 --tcp-flag 指明需要匹配哪些标志位,然后再指明这些标志位中,哪些必须为 1,剩余的都必须为 0。
所以当服务器接收新请求时,SYN 标志位必须 1,其他的标志位为 0,服务端响应这个连接时, SYN、ACK 标志位必须为 1,其他的标志位为 0。(这样可以避免木马程序通过端口主动向外发送新连接。)
示例:客户端连接服务端 22 端口第一次握手必须是客户端发起的,所以 SYN 必须为 1,剩下全部为 0。然后服务端可以通过 22 端口返回对应的报文 SYN、ACK 为 1。
# 使用 "--syn" 选项相当于使用 "--tcp-flags SYN,RST,ACK,FIN SYN" | |
iptables -t filter -I INPUT -p tcp --dport 22 -m tcp --tcp-flags SYN,ACK,FIN,RST SYN -j ACCEPT | |
iptables -t filter -A INPUT -p tcp --dport 22 -m tcp --tcp-flags SYN,ACK,FIN,RST ACK -j ACCEPT | |
iptables -t filter -A INPUT -j DROP | |
iptables -t filter -I OUTPUT -p tcp --sport 22 -m tcp --tcp-flags SYN,ACK,FIN,RST SYN,ACK -j ACCEPT | |
iptables -t filter -A OUTPUT -p tcp --sport 22 -m tcp --tcp-flags SYN,ACK,FIN,RST ACK -j ACCEPT | |
iptables -t filter -A OUTPUT -j DROP |
# 7. Iptables 连接追踪 state
# 7.1 什么是连接追踪
state(conntrack) 连接跟踪,顾名思义,就是跟踪(并记录)连接的状态。
如上图:是一台 IP 地址为 10.1.1.2 的 Linux 机器,我们能看到这台机器上有三条连接:
机器访问外部 HTTP 服务的连接(目的端口 80)
外部访问机器内 FTP 服务的连接(目的端口 21)
机器访问外部 DNS 服务的连接(目的端口 53)
连接跟踪所做的事情就是发现并跟踪这些连接的状态,但这个追踪状态与 TCP 协议没有关系。它是由内核 nefilter 在 IP 层实现,可 IP 层是无连接、无追踪的,那是如何知道这个 IP 是否存在?当用户发送请求时,会将用户的请求存储在内核开辟的内存空间中,对应在 /proc/net/nf_conntrack
文件会记录源 IP、目标 IP、协议、时间、状态等信息;
当下次在有用户发起请求,就可以通过内存空间中获取该用户是否来过,以此来实现连接追踪机制;
注意:该文件能存储的条目是受 /proc/sys/net/nf_conntrack_max 设定大小所限;

# 7.2 连接追踪的状态分类
New:新请求,内存中不存在此连接的相关条目,因此识别为第一次请求,状态为 NEW。
ESTABLISHED:NEW 状态之后,再次建立连接,由于此前的连接还没有失效,所以追踪后被视为已连接通讯状态,状态为 ESTABLISHED。
RELATED:相关的连接。比如 ftp 有两个连接,命令连接和数据连接。命令连接有来有往是一个独立的循环,数据连接有来有往又是另外一个独立的循环,但是两者之间有关系,如果没有命令连接就不可能有数据连接,所以我们将这种称为” 相关联的连接 “。
INVALID:无效的连接。
# 7.3 连接追踪应用场景
正常情况下服务器的 80 端口不会主动连接其他服务器,如果出现了 80 端口连接其他服务器,那么说明出现了异常行为,或者可以理解为中了木马程序病毒。反弹端口型木马如果关闭 80 端口的响应报文,但那样就会造成请求进来无法响应;如果开放 80 端口,则又会出现异常行为。所以我们需要从 80 端口做连接追踪限制,凡事从 80 端口出去的就必须是对某个请求的响应,也就是说通过 80 端口出去的状态必须是 ESTABLISHED,不能是 NEW。
# 7.4 连接追踪配置场景
需求:允许接收远程主机的 SSH 与 HTTP 请求 (NEW、ESTABLISHED) ,同时仅允许本机回应 SSH 以及 HTTP 的响应(ESTABLISHED),但不允许本机通过 22、80 端口主动向外发起连接。
# 进站,允许状态:NEW,ESTABLISHED | |
iptables -t filter -I INPUT -p tcp -m multiport --dport 80,443,22 -m state --state NEW,ESTABLISHED -j ACCEPT | |
iptables -t filter -A INPUT -j DROP | |
# 出站,允许状态:ESTABLISHED | |
iptables -t filter -I OUTPUT -p tcp -m multiport --sport 80,443,22 -m state --state ESTABLISHED -j ACCEPT | |
iptables -t filter -A OUTPUT -j DROP |
需求:如果服务器也需要使用 SSH 连接其他远程主机,则还需要增加以下配置(但不建议)
iptables -t filter -I OUTPUT 2 -p tcp --dport 22 -m state --state NEW,ESTABLISHED -j ACCEPT | |
iptables -t filter -I INPUT 2 -p tcp --sport 22 -m state --state NEW,ESTABLISHED -j ACCEPT |
# 8. Iptables 地址转换
# 8.1 什么是 NAT
网络地址转换 (NAT) ,意思也比较清楚:对(数据包的)网络地址 (IP +Port) 进行转换。
例如,机器自己的 IP 10.1.1.2 是能与外部正常通信的,但 192.168.1 网段是私有 IP 段,无法与外界通信,因此当源地址为 192.168。1 网段的包要出去时,机器会先将源 IP 换成机器自己的 10.1.1.2 再发送出去;收到应答包时,再进行相反的转换。这就是 NAT 的基本过程。

# 8.2 NAT 的几种模式
SNAT :源地址转换
DNAT :目标地址转换
PNAT :端口转换
# 8.3 NAT 环境搭建图

# 8.4 SNAT - 示例
需求:实现内网主机通过防火墙进行上网,需要使用 SNAT(源地址转换 POSTROUTING)
172.16.1.7 --> 172.16.1.200 -- POSTROUTING --> 10.0.0.200 --> baidu.com
#1. 将 172.16.1.7 的网关指向 172.16.1.200,关闭 eth0 | |
[root@web01 ~]# echo "GATEWAY=172.16.1.200" >> /etc/sysconfig/network-scripts/ifcfg-eth1 | |
[root@web01 ~]# echo "DNS1=223.5.5.5" >> /etc/sysconfig/network-scripts/ifcfg-eth1 | |
[root@web01 ~]# ifdown eth1 && ifup eth1 | |
[root@web01 ~]# ifdown eth0 | |
#2. 开启 iptables 防火墙的 forward 转发 | |
[root@route ~]# echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf | |
[root@route ~]# sysctl -p | |
#3. 配置 iptables 的 SNAT 转发规则 | |
#3.1 指定从哪个 ip 地址转换出去(静态公网地址) | |
[root@route ~]# iptables -t nat -I POSTROUTING -s 172.16.1.0/24 -j SNAT --to 10.0.0.200 | |
[root@route ~]# iptables -t nat -L | |
#3.2 当外网源地址为动态获取的地址时,MASQUERADE 可自行判断要转换为的外网地址 | |
[root@route ~]# iptables -t nat -A POSTROUTING -s 172.16.1.0/24 -j MASQUERADE |
# 8.5 DNAT - 示例
需求:实现外网主机通过防火墙访问内部主机 80 端口,需要通过 DNAT(目标地址转换 PREROUTING)
#端口映射 DNAT | |
[root@route ~]# iptables -t nat -I PREROUTING -d 10.0.0.200 -p tcp --dport 80 -j DNAT --to 172.16.1.7:80 | |
[root@route ~]# iptables -t nat -L -n | |
#地址映射 DNAT | |
[root@route ~]# iptables -t nat -I PREROUTING -d 10.0.0.200 -j DNAT --to 172.16.1.7 |
# 9. Iptables - 自定义链
# 9.1 为什么要使用自定义链
此前我们一直在 iptables 的默认链中定义规则,那么此处,我们就来了解一下自定义链。这里可能有疑问,iptables 的默认链就已经能够满足我们了,为什么还需要自定义链呢?
当默认链中的规则非常多时,不便于管理。
- 假设 INPUT 链中存放了 200 条规则,这 200 条规则有针对 80 端口的,有针对 22 端口的,有针对私网 IP 的,等等。
- 假如想修改针对 80 端口的规则,可能需要从头到尾看一遍 200 条规则,找出哪些规则是针对 80 端口。这显然不合理。
所以,我们需要使用自定义链,通过自定义链即可解决上述问题。
假设,我们自定义一条链,链名叫 IN_HTTP ,我们可以将所有针对 80 端口入站规则都写入到这条自定义链中,当以后想要修改针对 80 端口入站规则时,就直接修改 IN_HTTP 链中的规则就可以了。
即使默认链中有再多的规则,也没有关系,因为所有针对 80 端口的入站规则都存放在 IN_HTTP 链中。
同理,我们可以将针对 22 端口的出站规则放入到 OUT_SSH 自定义链中,这样,我们就能快速定位到想修改的规则在哪里。
# 9.2 自定义链基本应用
1、在 filter 表中,添加一个自定义链
[root@route ~]# iptables -t filter -N IN_SSHD | |
[root@route ~]# iptables -L -n |
2、给自定义链配置对应的规则:禁止 10.0.0.10 访问 10.0.0.200 的 22 端口
[root@route ~]# iptables -t filter -I IN_SSHD -s 192.168.40.10 -d 192.168.40.200 -p tcp --dport 22 -j DROP |
3、测试后发现,规则没有生效,因为自定义的链需要被默认的链调用才会生效
# 既然 IN_HTTP 链是为了针对 22 端口的入站规则而创建的,那么这些规则应该去匹配入站的报文,所以应该用 INPUT 链去引用它。 | |
[root@route ~]# iptables -t filter -I INPUT -p tcp --dport 22 -j IN_SSHD | |
[root@route ~]# iptables -L -n | |
Chain INPUT (policy ACCEPT) | |
target prot opt source destination | |
IN_SSHD tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:22 | |
Chain FORWARD (policy ACCEPT) | |
target prot opt source destination | |
Chain OUTPUT (policy ACCEPT) | |
target prot opt source destination | |
Chain IN_SSHD (1 references) | |
target prot opt source destination | |
DROP tcp -- 192.168.40.10 192.168.40.200 tcp dpt:22 |
# 9.3 自定义链执行顺序

# 9.4 如何删除自定义链
删除自定义链需要满足两个条件:
- 1、自定义链没有被引用
- 2、自定义链中没有任何规则
#1. 删除自定义规则 | |
iptables -t filter -D IN_SSHD 1 | |
#2. 删除 INPUT 引用 | |
iptables -t filter -D INPUT 1 | |
#3. 自定义链重命名 | |
iptables -E IN_SSHD SSHD | |
#4. 删除自定义链 | |
iptables -X SSHD |
# 10. Iptables 场景示例
# 10.1 场景示例 1
- 1. 对所有的地址开放本机的 tcp(80、22、8080-9090)端口的访问
- 2. 允许对所有的地址开放本机的基于 ICMP 协议的数据包访问
- 3. 其他未被允许的端口禁止访问
思路:先允许,后拒绝 | |
INPUT: | |
iptables -t filter -I INPUT -p tcp -m multiport --dport 22,443,80,8080:9090 -m state --state "NEW,ESTABLISHED,RELATED" -j ACCEPT | |
iptables -t filter -A INPUT -p icmp -j ACCEPT | |
iptables -t filter -A INPUT -j DROP | |
output: | |
iptables -t filter -I OUTPUT -p tcp -m multiport --sport 22,80,443,8080:9090 -m state --state "NEW,ESTABLISHED,RELATED" -j ACCEPT | |
iptables -t filter -A OUTPUT -p icmp -j ACCEPT | |
iptables -t filter -A OUTPUT -j DROP |
# 10.2 场景示例二
- 1. 员工在公司内部
(10.0.0.0/24、10.8.0.0/24)能访问服务器上任何服务 - 2. 当员工出差外地,通过
vpn连接到公司,也可以访问内部上的任何服务 - 3. 公司有门户网站需要允许公网用户访问
http 80/tcp、https 443/tcp
[root@route ~]# iptables -F | |
[root@route ~]# iptables -t filter -I INPUT -s 10.0.0.0/24 -j ACCEPT | |
[root@route ~]# iptables -t filter -I INPUT -s 10.8.0.0/24 -j ACCEPT | |
[root@route ~]# iptables -t filter -A INPUT -p tcp -m multiport --dport 80,443 -j ACCEPT | |
[root@route ~]# iptables -t filter -A INPUT -p tcp -j DROP |
# 10.3 ftp 主动模式规则配置
ftp 服务一般有主动和被动 l 两个个模式,那么针对这两个模式该如何配置 Iptables 规则呢?
通常 ftp 主动模式监听在 21 端口,然后由 20 端口作为数据传输端口,向客户端发送数据。
1.vsftp 服务端配置支持主动模式
[root@route ~]# yum install vsftpd -y | |
[root@route ~]# systemctl start vsftpd | |
[root@route ~]# systemctl enable vsftpd |
2. 客服端连接模式默认为被动模式,需要通过 passvie 命令切换到主动模式
[root@client ~]# yum install ftp -y | |
[root@client ~]# ftp 192.168.40.200 | |
Connected to 192.168.40.200 (192.168.40.200). | |
220 (vsFTPd 3.0.2) | |
Name (192.168.40.200:root): anonymous | |
ftp> passive |
3. 登录服务端查看客户端与服务端的连接状态。【服务端 20 端口主动向客户端随机端口发送数据】
[root@route pub]# netstat -antp | |
Active Internet connections (servers and established) | |
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name | |
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 1067/sshd | |
tcp6 0 0 192.168.40.200:21 192.168.40.1:51035 ESTABLISHED 2088/vsftpd | |
tcp6 0 0 192.168.40.200:20 192.168.40.1:51017 TIME_WAIT - |
4. 配置防火墙放行 21、20 端口,以及建立连接后的数据传输。
INPUT | |
[root@route ~]# iptables -F | |
[root@route ~]# iptables -I INPUT -p tcp --dport 22 -j ACCEPT | |
[root@route ~]# iptables -A INPUT -p tcp -m state --state "NEW,ESTABLISHED,RELATED" -j ACCEPT | |
[root@route ~]# iptables -A INPUT -p tcp -m multiport --dports 20,21 -j ACCEPT | |
[root@route ~]# iptables -A INPUT -j DROP | |
OUTPUT: | |
[root@route ~]# iptables -t filter -I OUTPUT -p tcp -m multiport --sport 22 -m state --state "ESTABLISHED" -j ACCEPT | |
[root@route ~]# iptables -t filter -I OUTPUT -p tcp -m multiport --sport 20,21 -m state --state "NEW,ESTABLISHED,RELATED" -j ACCEPT | |
[root@route ~]# iptables -t filter -A OUTPUT -j DROP |
# 10.4 ftp 被动模式规则配置
ftp 被动模式监听在 21 端口,然后由随机端口作为数据传输端口,向客户端回发数据。
由于是随机就法办法指定端口,所以可以配置 vsftpd 控制随机端口范围。
1. 修改 vsftpd 服务端传输数据时的随机端口
[root@route ~]# vim /etc/vsftpd/vsftpd.conf | |
pasv_min_port=50000 | |
pasv_max_port=60000 | |
[root@route ~]# systemctl restart vsftpd |
2. 配置 iptables 规则
# INPUT | |
[root@route ~]# iptables -I INPUT -p tcp --dport 22 -j ACCEPT | |
[root@route ~]# iptables -A INPUT -p tcp -m multiport --dports 21,50000:60000 -m state --state "NEW,ESTABLISHED,RELATED" -j ACCEPT | |
[root@route ~]# iptables -A INPUT -j DROP | |
# OUTPUT | |
[root@route ~]# iptables -I OUTPUT -p tcp --sport 22 -m state --state "ESTABLISHED" -j ACCEPT | |
[root@route ~]# iptables -A OUTPUT -p tcp -m multiport --sports 21,50000:60000 -m state --state "ESTABLISHED" -j ACCEPT | |
[root@route ~]# iptables -A OUTPUT -j DROP |
