iptables
iptables 是一个用于配置 Linux 内核防火墙的命令行工具,该防火墙在 Netfilter 项目中实现。术语 iptables 也常被用来指代这种内核级防火墙。它可以直接通过 iptables 进行配置,或者通过使用许多 控制台 和 图形化 前端进行配置。iptables 用于 IPv4,而 ip6tables 用于 IPv6。iptables 和 ip6tables 具有相同的语法,但某些选项仅适用于 IPv4 或 IPv6。
安装
iptables 软件包是一个兼容层,用于在使用 nftables 后端时使用类似于 iptables 的配置。它是 base 元软件包 的间接依赖项,因此应该默认安装在您的系统上。
Arch Linux 的标准内核仍然编译了 iptables 支持。遗留的用户空间工具可以通过 iptables-legacy 软件包安装,它将替换 iptables。
前端
控制台
- Arno's firewall — 适用于单宿主和多宿主机器的安全防火墙。配置非常容易,管理方便且高度可定制。支持:NAT 和 SNAT、端口转发、带有静态和动态分配 IP 的 ADSL 以太网调制解调器、MAC 地址过滤、隐蔽端口扫描检测、DMZ 和 DMZ-2-LAN 转发、防止 SYN/ICMP 洪水攻击、具有速率限制的可扩展用户自定义日志记录(防止日志洪水),以及所有 IP 协议和 VPN(如 IPsec),并支持插件以添加额外功能。
- ferm — 用于维护复杂防火墙的工具,无需反复重写复杂的规则。它允许将整个防火墙规则集存储在一个单独的文件中,并使用一个命令加载。防火墙配置类似于结构化编程语言,可以包含级别和列表。
- FireHOL — 一种用于表达防火墙规则的语言,而不仅仅是生成某种防火墙的脚本。它使构建即使是复杂的防火墙也变得容易——以您想要的方式。
- Firetable — 用于维护 IPtables 防火墙的工具。每个接口都可以通过其自己的配置文件单独配置,该文件具有简单且易于阅读的语法。
- firewalld (firewall-cmd) — 用于配置网络和防火墙区域以及设置和配置防火墙规则的守护进程和控制台接口。
- Shorewall — 用于配置 Netfilter 的高级工具。您可以使用一组配置文件中的条目来描述您的防火墙/网关需求。
- Uncomplicated Firewall (UFW) — iptables 的简单前端。
- PeerGuardian (pglcmd) — 面向隐私的防火墙应用程序。它会阻止与巨大阻止列表(成千上万或数百万个 IP 范围)中指定的主机之间的连接。
- Vuurmuur — 功能强大的防火墙管理器。它具有简单且易于学习的配置,允许进行简单和复杂的配置。配置可以通过 ncurses 图形界面完全配置,这允许通过 SSH 或在控制台上进行安全的远程管理。Vuurmuur 支持流量整形,具有强大的监控功能,允许管理员实时查看日志、连接和带宽使用情况。
图形界面
- Firewall Builder — 图形界面防火墙配置和管理工具,支持 iptables (netfilter)、ipfilter、pf、ipfw、Cisco PIX (FWSM, ASA) 和 Cisco 路由器扩展访问列表。该程序在 Linux、FreeBSD、OpenBSD、Windows 和 macOS 上运行,可以管理本地和远程防火墙。
- firewalld (firewall-config) — 用于配置网络和防火墙区域以及设置和配置防火墙规则的守护进程和图形界面。
- PeerGuardian GUI (pglgui) — 面向隐私的防火墙应用程序。它会阻止与巨大阻止列表(成千上万或数百万个 IP 范围)中指定的主机之间的连接。
- Portmaster — Portmaster 是一个免费且开源的应用程序防火墙,其默认设置旨在提高您的隐私。
基本概念
iptables 用于检查、修改、转发、重定向和/或丢弃 IP 数据包。用于过滤 IP 数据包的代码已经内置于内核中,并组织成一组 表 (tables),每个表都有特定的用途。这些表由一组预定义的 链 (chains) 组成,链包含规则,这些规则按顺序遍历。每条规则由潜在匹配的谓词和相应的动作(称为 目标 (target))组成,如果谓词为真,即满足条件,则执行该动作。如果 IP 数据包到达内置链的末尾,包括空链,则链的 策略 (policy) 目标决定了 IP 数据包的最终目的地。iptables 是允许您处理这些链/规则的用户工具。大多数新用户会发现 Linux IP 路由的复杂性非常令人畏惧,但在实践中,最常见的用例(NAT 和/或基础互联网防火墙)要简单得多。
理解 iptables 工作原理的关键是 这张图表。顶部的词是表,下方的词是链。进入 任何网络接口 的每个 IP 数据包都会从上到下通过此流程图。一个常见的误区是认为从内部接口进入的数据包与从面向互联网的接口进入的数据包处理方式不同。所有接口的处理方式相同;由您定义以不同方式处理它们的规则。当然,有些数据包旨在用于本地进程,因此它们从图表顶部进入并在 <Local Process> 处停止,而其他数据包由本地进程生成;因此它们从 <Local Process> 开始并向下穿过流程图。关于此流程图工作原理的详细说明可以在 此处 找到。
在绝大多数用例中,您根本不需要使用 raw、mangle 或 security 表。因此,下表描述了通过 iptables 的简化网络数据包流
XXXXXXXXXXXXXXXXXX
XXX Network XXX
XXXXXXXXXXXXXXXXXX
+
|
v
+-------------+ +------------------+
|table: filter| <---+ | table: nat |
|chain: INPUT | | | chain: PREROUTING|
+-----+-------+ | +--------+---------+
| | |
v | v
[local process] | **************** +--------------+
| +---------+ Routing decision +------> |table: filter |
v **************** |chain: FORWARD|
**************** +------+-------+
Routing decision |
**************** |
| |
v **************** |
+-------------+ +------> Routing decision <---------------+
|table: nat | | ****************
|chain: OUTPUT| | +
+-----+-------+ | |
| | v
v | +-------------------+
+--------------+ | | table: nat |
|table: filter | +----+ | chain: POSTROUTING|
|chain: OUTPUT | +--------+----------+
+--------------+ |
v
XXXXXXXXXXXXXXXXXX
XXX Network XXX
XXXXXXXXXXXXXXXXXX
表格
iptables 包含五个表
raw仅用于配置数据包,使其免于连接跟踪。filter是默认表,通常与防火墙相关联的所有操作都在此进行。nat用于 网络地址转换(例如端口转发)。mangle用于专门的数据包修改。security用于 强制访问控制 网络规则(例如 SELinux——请参阅 此文章 了解更多详细信息)。
在最常见的用例中,您只会使用这两个:filter 和 nat。其他表旨在处理涉及多个路由器和路由决策的复杂配置,无论如何,它们都超出了这些介绍性说明的范围。
链 (Chains)
表由 链 组成,它们是按顺序遵循的规则列表。默认表 filter 包含三个内置链:INPUT、OUTPUT 和 FORWARD,它们在数据包过滤过程的不同点激活,如 流程图 所示。nat 表包括 PREROUTING、POSTROUTING 和 OUTPUT 链。
有关其他表中内置链的描述,请参阅 iptables(8)。
默认情况下,没有任何链包含任何规则。由您决定将规则附加到您想要使用的链上。链 确实 具有默认策略,通常设置为 ACCEPT,但如果您想确保没有任何东西溜过您的规则集,可以将其重置为 DROP。默认策略始终仅在链的末尾应用。因此,数据包必须通过链中的所有现有规则,然后才能应用默认策略。
可以添加用户定义的链,以使规则集更有效或更容易修改。有关如何使用用户定义链的示例,请参阅 简单状态防火墙。
规则
数据包过滤基于 规则,这些规则由多个 匹配项(数据包必须满足以便应用规则的条件)和一个 目标(当数据包满足所有条件时采取的动作)指定。规则可能匹配的典型事物是数据包进入的接口(例如 eth0 或 eth1)、数据包的类型(ICMP、TCP 或 UDP)或数据包的目标端口。
目标使用 -j 或 --jump 选项指定。目标可以是用户定义的链(即如果满足这些条件,则跳转到以下用户定义的链并在那里继续处理)、特殊的内置目标之一,或目标扩展。内置目标是 ACCEPT、DROP、QUEUE 和 RETURN;目标扩展例如有 REJECT 和 LOG。如果目标是内置目标,则立即决定数据包的命运,并停止当前表中数据包的处理。如果目标是用户定义的链且数据包的命运未由第二个链决定,则它将根据原始链的剩余规则进行过滤。目标扩展可以是 终结的(如内置目标)或 非终结的(如用户定义的链),详情请参阅 iptables-extensions(8)。
遍历链
在任何接口上接收到的网络数据包会按 流程图 所示的顺序遍历表的流量控制链。第一个路由决策涉及决定数据包的最终目的地是本地机器(在这种情况下,数据包遍历 INPUT 链)还是其他地方(在这种情况下,数据包遍历 FORWARD 链)。随后的路由决策涉及决定为传出数据包分配什么接口。在路径中的每个链上,该链中的每条规则都会按顺序评估,每当规则匹配时,就会执行相应的目标/跳转操作。3 个最常用的目标是 ACCEPT、DROP 和跳转到用户定义的链。虽然内置链可以有默认策略,但用户定义的链不能。如果跳转到的链中的每条规则都未能提供完整匹配,则数据包被丢回调用链;请参阅以下 插图。如果在任何时候为具有 DROP 目标的规则实现了完整匹配,则丢弃数据包且不再进行进一步处理。如果数据包到达跳转到 ACCEPT 目标的规则,它将不再遍历链的任何后续规则以及该表的后续链。其处理将跳转到顺序中下一个表的第一条链。另请参阅 frozentux 教程的 遍历表和链 以及 接受目标。
模块
有许多模块可用于扩展 iptables,例如 connlimit、conntrack、limit 和 recent。这些模块添加了额外的功能,以允许复杂的过滤规则。
配置和使用
默认情况下,iptables 在 /etc/iptables/iptables.rules 中提供一组空的规则。为了能够在引导时自动加载 iptables 规则,您可以 启用 iptables 提供的 iptables.service 单元,或者 启动 systemd 服务单元以立即加载 iptables 规则。
同样,IPv6 的 iptables 规则默认存储在 /etc/iptables/ip6tables.rules 中,由 ip6tables.service 读取。您可以以与上述相同的方式启动它。
通过以下章节所示的命令行添加规则后,配置文件不会自动更改——您必须手动保存它
# iptables-save -f /etc/iptables/iptables.rules
如果您手动编辑配置文件,则必须 重新加载 iptables。
或者您可以直接通过 iptables 加载它
# iptables-restore /etc/iptables/iptables.rules
从命令行
显示当前规则
列出当前规则的基本命令是 --list-rules (-S),其输出格式类似于 iptables-save 工具。两者的主要区别在于,后者默认输出所有表的规则,而所有 iptables 命令默认仅针对 filter 表。
在命令行上使用 iptables 时,--list (-L) 命令接受更多修饰符并显示更多信息。例如,您可以使用以下命令检查当前规则集和每条规则的命中次数
# iptables -nvL
Chain INPUT (policy ACCEPT 0 packets, 0 bytes) pkts bytes target prot opt in out source destination 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
如果输出看起来像上面这样,那么默认 filter 表中没有任何规则(即没有阻止任何内容)。可以使用 -t 选项指定其他表。
要在列出规则时显示行号,请将 --line-numbers 附加到该输入中。当在命令行上 #编辑规则 时,行号是有用的缩写。
重置规则
您可以使用这些命令清空并重置 iptables 为默认值
# iptables -F # iptables -X # iptables -t nat -F # iptables -t nat -X # iptables -t mangle -F # iptables -t mangle -X # iptables -t raw -F # iptables -t raw -X # iptables -t security -F # iptables -t security -X # iptables -P INPUT ACCEPT # iptables -P FORWARD ACCEPT # iptables -P OUTPUT ACCEPT
不带参数的 -F 命令会清空其当前表中的所有链。同样,-X 会删除表中所有空的非默认链。
可以通过在 -F 和 -X 后面加上 [chain] 参数来清空或删除各个链。
编辑规则
可以通过将规则附加 -A 到链、在链的特定位置插入 -I、替换 -R 现有规则或删除 -D 来编辑规则。前三个命令在以下内容中进行了举例说明。
首先,我们的计算机不是路由器(除非它 就是路由器)。我们想将 FORWARD 链上的默认策略从 ACCEPT 更改为 DROP。
# iptables -P FORWARD DROP
Dropbox LAN 同步功能 每 30 秒向它能看到的所有计算机广播数据包。如果我们恰好与 Dropbox 客户端处于同一个局域网中且不使用此功能,那么我们可能希望拒绝这些数据包。
# iptables -A INPUT -p tcp --dport 17500 -j REJECT --reject-with icmp-port-unreachable
# iptables -nvL --line-numbers
Chain INPUT (policy ACCEPT 0 packets, 0 bytes) num pkts bytes target prot opt in out source destination 1 0 0 REJECT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:17500 reject-with icmp-port-unreachable Chain FORWARD (policy DROP 0 packets, 0 bytes) num pkts bytes target prot opt in out source destination Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes) num pkts bytes target prot opt in out source destination
REJECT 而不是 DROP,因为 RFC 1122 要求主机在可能的情况下返回 ICMP 错误,而不是丢弃数据包。此页面 解释了为什么 REJECT 数据包几乎总是比 DROP 更好。现在,假设我们改变了关于 Dropbox 的想法,并决定在我们的计算机上安装它。我们也想进行 LAN 同步,但只与我们网络上的一个特定 IP 同步。所以我们应该使用 -R 来替换我们的旧规则。其中 10.0.0.85 是我们的另一个 IP
# iptables -R INPUT 1 -p tcp --dport 17500 ! -s 10.0.0.85 -j REJECT --reject-with icmp-port-unreachable
# iptables -nvL --line-numbers
Chain INPUT (policy ACCEPT 0 packets, 0 bytes) num pkts bytes target prot opt in out source destination 1 0 0 REJECT tcp -- * * !10.0.0.85 0.0.0.0/0 tcp dpt:17500 reject-with icmp-port-unreachable Chain FORWARD (policy DROP 0 packets, 0 bytes) num pkts bytes target prot opt in out source destination Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes) num pkts bytes target prot opt in out source destination
我们现在已经用一条允许 10.0.0.85 访问我们计算机上 17500 端口的规则替换了我们的原始规则。但现在我们意识到这不可扩展。如果我们的友好 Dropbox 用户试图访问我们设备上的 17500 端口,我们应该立即允许他们,而不是让他们接受可能出现在后面的任何防火墙规则的测试!
因此,我们编写了一条新规则来立即允许我们的受信任用户。使用 -I 在我们的旧规则之前插入新规则
# iptables -I INPUT -p tcp --dport 17500 -s 10.0.0.85 -j ACCEPT -m comment --comment "Friendly Dropbox"
# iptables -nvL --line-numbers
Chain INPUT (policy ACCEPT 0 packets, 0 bytes) num pkts bytes target prot opt in out source destination 1 0 0 ACCEPT tcp -- * * 10.0.0.85 0.0.0.0/0 tcp dpt:17500 /* Friendly Dropbox */ 2 0 0 REJECT tcp -- * * !10.0.0.85 0.0.0.0/0 tcp dpt:17500 reject-with icmp-port-unreachable Chain FORWARD (policy DROP 0 packets, 0 bytes) num pkts bytes target prot opt in out source destination Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes) num pkts bytes target prot opt in out source destination
并用一条拒绝 17500 端口上所有内容的规则替换我们的第二条规则
# iptables -R INPUT 2 -p tcp --dport 17500 -j REJECT --reject-with icmp-port-unreachable
我们的最终规则列表现在看起来像这样
# iptables -nvL --line-numbers
Chain INPUT (policy ACCEPT 0 packets, 0 bytes) num pkts bytes target prot opt in out source destination 1 0 0 ACCEPT tcp -- * * 10.0.0.85 0.0.0.0/0 tcp dpt:17500 /* Friendly Dropbox */ 2 0 0 REJECT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:17500 reject-with icmp-port-unreachable Chain FORWARD (policy DROP 0 packets, 0 bytes) num pkts bytes target prot opt in out source destination Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes) num pkts bytes target prot opt in out source destination
允许组播流量
使用组播识别的协议(例如 SANE 搜索网络扫描仪)会将流量发送到网络的广播 IP,并且响应将来自特定客户端的 IP。由于这些 IP 地址不同,iptables 不会将响应识别为 RELATED 或 ESTABLISHED,并且它将阻止响应。请参阅 [1] 了解如何在不创建过度宽松的防火墙的情况下接受组播流量。
首先,创建一个 ipset 哈希容器。超时是接受客户端响应的时间窗口。
# ipset create upnp hash:ip,port timeout 3
其次,创建一个规则将传出的组播流量添加到 ipset 哈希中。
# iptables -A OUTPUT -d 239.255.255.250/32 -p udp -m udp -j SET --add-set upnp src,src --exist
第三,创建一个规则以允许与 ipset 哈希匹配的传入流量。
# iptables -A INPUT -p udp -m set --match-set upnp dst,dst -j ACCEPT
最后,记得保存新规则(请参阅 #配置与使用 和 ipset#使 ipset 持久化),并确保 启用 iptables.service 和 ipset.service,以便在系统启动时加载规则。
指南
日志记录
LOG 目标可用于记录命中规则的数据包。与其他目标(如 ACCEPT 或 DROP)不同,数据包在命中 LOG 目标后将继续在链中移动。这意味着为了启用所有丢弃数据包的日志记录,您必须在每个 DROP 规则之前添加一个重复的 LOG 规则。由于这降低了效率并使事情变得不够简单,因此可以改为创建一个 logdrop 链。
创建链
# iptables -N logdrop
并向新创建的链添加以下规则
# iptables -A logdrop -m limit --limit 5/m --limit-burst 10 -j LOG # iptables -A logdrop -j DROP
limit 和 limit-burst 选项的解释见 下文。
现在,每当我们想要丢弃数据包并记录此事件时,我们只需跳转到 logdrop 链,例如
# iptables -A INPUT -m conntrack --ctstate INVALID -j logdrop
限制日志速率
上面的 logdrop 链使用 limit 模块来防止 iptables 日志变得太大或导致不必要的硬盘写入。如果不进行限制,配置错误试图连接的服务,或者攻击者,可能会通过导致 iptables 日志写入来填满驱动器(或者至少是 /var 分区)。
limit 模块使用 -m limit 调用。然后,您可以使用 --limit 设置平均速率,并使用 --limit-burst 设置初始突发速率。在上面的 logdrop 示例中
iptables -A logdrop -m limit --limit 5/m --limit-burst 10 -j LOG
附加一条规则,该规则将记录通过它的所有数据包。前 10 个连续数据包将被记录,此后每分钟仅记录 5 个数据包。“限制突发”计数在每次未违反“限制速率”时重置,即日志记录活动自动恢复正常。
查看记录的数据包
记录的数据包在 systemd journal 中作为内核消息可见。
要查看自机器上次引导以来记录的所有数据包
# journalctl -k --grep="IN=.*OUT=.*"
syslog-ng
假设您正在使用 syslog-ng,您可以在 syslog-ng.conf 中控制 iptables 的日志输出去向。替换
filter f_everything { level(debug..emerg) and not facility(auth, authpriv); };
更改为
filter f_everything { level(debug..emerg) and not facility(auth, authpriv) and not filter(f_iptables); };
这将停止将 iptables 输出记录到 /var/log/everything.log。
如果您还希望 iptables 记录到不同于 /var/log/iptables.log 的文件,您可以简单地在此处(仍在 syslog-ng.conf 中)更改目标 d_iptables 的文件值
destination d_iptables { file("/var/log/iptables.log"); };
ulogd
ulogd 是一个专用的用户空间数据包记录守护进程,用于 netfilter,可以替换默认的 LOG 目标。
参见
- 维基百科文章
- 端口敲击
- 官方 iptables 网站
- iptables 教程 1.2.2 作者:Oskar Andreasson
- Debian Wiki - iptables
- 安全使用连接跟踪助手