iptables
iptables 是一个命令行实用程序,用于配置 Linux 内核 防火墙,该防火墙在 Netfilter 项目中实现。术语 iptables 也常用于指代此内核级防火墙。它可以直接使用 iptables 进行配置,也可以使用许多 控制台 和 图形界面 前端之一进行配置。iptables 用于 IPv4,而 ip6tables 用于 IPv6。iptables 和 ip6tables 都具有相同的语法,但某些选项特定于 IPv4 或 IPv6。
安装
标准的 Arch Linux 内核在编译时已包含 iptables 支持。您只需 安装 用户空间实用程序,这些实用程序由软件包 iptables 提供。iptables 软件包是 base 元软件包 的间接依赖项,因此默认情况下应已安装在您的系统上。
前端
控制台
- 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 — iptables 的简单前端。
- PeerGuardian (pglcmd) — 面向隐私的防火墙应用程序。它阻止与巨型阻止列表(数千或数百万个 IP 范围)中指定的主机的连接。
- Vuurmuur — 强大的防火墙管理器。它具有简单易学的配置,允许简单和复杂的配置。可以通过 ncurses GUI 完全配置,该 GUI 允许通过 SSH 或在控制台上进行安全的远程管理。Vuurmuur 支持流量整形,具有强大的监控功能,使管理员可以实时查看日志、连接和带宽使用情况。
图形界面
- Firewall Builder — GUI 防火墙配置和管理工具,支持 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 数据包的代码已内置于内核中,并组织成 表 的集合,每个表都有特定的用途。这些表由一组预定义的链组成,这些链包含按顺序遍历的规则。每个规则都包含潜在匹配的谓词和相应的操作(称为目标),如果谓词为真,即条件匹配,则执行该操作。如果 IP 数据包到达内置链的末尾(包括空链),则链的策略目标确定 IP 数据包的最终目的地。iptables 是用户实用程序,允许您使用这些链/规则。大多数新用户发现 Linux IP 路由的复杂性令人望而生畏,但实际上,最常见的用例(NAT 和/或基本 Internet 防火墙)要简单得多。
理解 iptables 工作原理的关键是此图表。顶部的单词是小写的表名,下面的大写单词是链名。在任何网络接口上传入的每个 IP 数据包都从上到下遍历此流程图。一个常见的误解是,从内部接口进入的数据包与从面向 Internet 的接口进入的数据包的处理方式不同。所有接口的处理方式都相同;如何区别对待它们取决于您定义的规则。当然,有些数据包旨在用于本地进程,因此它们从图表的顶部进入并在“<本地进程>”处停止,而另一些数据包由本地进程生成;因此它们从“<本地进程>”开始并向下遍历流程图。有关此流程图工作原理的详细说明,请参见此处。
在绝大多数用例中,您根本不需要使用 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。其他表旨在用于涉及多个路由器和路由决策的复杂配置,并且无论如何都超出了这些入门级说明的范围。
链
表由链组成,链是按顺序遵循的规则列表。默认表 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 教程的遍历表和链和Accept 目标。
模块
有许多模块可用于扩展 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 客户端的 LAN 上,并且不使用此功能,那么我们可能希望拒绝这些数据包。
# 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 个数据包。“limit burst”计数在每次“limit rate”未被打破时重置,即日志记录活动自动恢复正常。
查看已记录的数据包
记录的数据包在 systemd 日志中作为内核消息可见。
要查看自上次机器启动以来记录的所有数据包
# 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
不同的文件,则只需在此处更改目标 d_iptables
的文件值(仍在 syslog-ng.conf
中)
destination d_iptables { file("/var/log/iptables.log"); };
ulogd
ulogd 是一个专门的用户空间数据包日志记录守护程序,用于 netfilter,可以替换默认的 LOG
目标。