# Iptables (简体中文)

相关文章

- Firewalls
- Sysctl#TCP/IP stack hardening

翻译状态： 本文是英文页面 Iptables 的翻译，最后翻译时间：2015-01-31，点击这里可以查看翻译后英文页面的改动。

iptables 是一个配置 Linux 内核 防火墙 的命令行工具，是 netfilter 项目的一部分。术语 iptables 也经常代指该内核级防火墙。iptables 可以直接配置，也可以通过许多 前端 和 图形界面 配置。iptables 用于 ipv4，ip6tables 用于 ipv6。

nftables 已经包含在 Linux kernel 3.13 中，以后会取代 iptables 成为主要的 Linux 防火墙工具。

## 安装

The stock Arch Linux kernel is compiled with iptables support. You will only need to install the userland utilities, which are provided by the package iptables in the official repositories. (The iproute2 package from the base group depends on iptables, so the iptables package should be installed on your system by default.)

## 基本概念

iptables 可以检测、修改、转发、重定向和丢弃 IPv4 数据包。过滤 IPv4 数据包的代码已经内置于内核中，并且按照不同的目的被组织成 表 的集合。表 由一组预先定义的 链 组成，链 包含遍历顺序规则。每一条规则包含一个谓词的潜在匹配和相应的动作（称为 目标），如果谓词为真，该动作会被执行。也就是说条件匹配。iptables 是用户工具，允许用户使用 链 和 规则。很多新手面对复杂的 linux IP 路由时总是感到气馁，但是，实际上最常用的一些应用案例（NAT 或者基本的网络防火墙）并不是很复杂。

理解 iptables 如何工作的关键是这张图。图中在上面的小写字母代表 表，在下面的大写字母代表 链。从任何网络端口 进来的每一个 IP 数据包都要从上到下的穿过这张图。一种常见的困扰是认为 iptables 对从内部端口进入的数据包和从面向互联网端口进入的数据包采取不同的处理方式，相反，iptabales 对从任何端口进入的数据包都会采取相同的处理方式。可以定义规则使 iptables 采取不同的方式对待从不同端口进入的数据包。当然一些数据包是用于本地进程的，因此在图中表现为从顶端进入，到 <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

### 表（Tables）

iptables 包含 5 张表（tables）:

1. `raw` is used only for configuring packets so that they are exempt from connection tracking.
2. `filter` is the default table, and is where all the actions typically associated with a firewall take place.
3. `nat` is used for network address translation (e.g. port forwarding).
4. `mangle` is used for specialized packet alterations (see Mangled packet).
5. `security` is used for Mandatory Access Control networking rules (e.g. SELinux -- see this article for more details).

1. `raw` 用于配置数据包，`raw` 中的数据包不会被系统跟踪。
2. `filter` 是用于存放所有与防火墙相关操作的默认表。
3. `nat` 用于 网络地址转换（例如：端口转发）。
4. `mangle` 用于对特定数据包的修改（参考 损坏数据包）。
5. `security` 用于 强制访问控制 网络规则（例如： SELinux -- 详细信息参考 该文章）。

In most common use cases you will only use two of these: filter and nat. The other tables are aimed at complex configurations involving multiple routers and routing decisions and are in any case beyond the scope of these introductory remarks.

大部分情况仅需要使用 filter 和 nat。其他表用于更复杂的情况——包括多路由和路由判定——已经超出了本文介绍的范围。

### 链 （Chains）

Tables consist of chains, which are lists of rules which are followed in order. The default table, `filter`, contains three built-in chains: `INPUT`, `OUTPUT` and `FORWARD` which are activated at different points of the packet filtering process, as illustrated in the flow chart. The nat table includes `PREROUTING`, `POSTROUTING`, and `OUTPUT` chains.

表由链组成，链是一些按顺序排列的规则的列表。默认的 `filter` 表包含 `INPUT`， `OUTPUT` 和 `FORWARD` 3条内建的链，这3条链作用于数据包过滤过程中的不同时间点，如该流程图所示。`nat` 表包含`PREROUTING`， `POSTROUTING` 和 `OUTPUT` 链。

See `man 8 iptables` for a description of built-in chains in other tables.

使用 `man 8 iptables` 查看其他表中内建链的描述。

By default, none of the chains contain any rules. It is up to you to append rules to the chains that you want to use. Chains do have a default policy, which is generally set to `ACCEPT`, but can be reset to `DROP`, if you want to be sure that nothing slips through your ruleset. The default policy always applies at the end of a chain only. Hence, the packet has to pass through all existing rules in the chain before the default policy is applied.

默认情况下，任何链中都没有规则。可以向链中添加自己想用的规则。链的默认规则通常设置为 `ACCEPT`，如果想确保任何包都不能通过规则集，那么可以重置为 `DROP`。默认的规则总是在一条链的最后生效，所以在默认规则生效前数据包需要通过所有存在的规则。

User-defined chains can be added to make rulesets more efficient or more easily modifiable. See Simple stateful firewall for an example of how user-defined chains are used.

用户可以加入自己定义的链，从而使规则集更有效并且易于修改。如何使用自定义链请参考 Simple stateful firewall。

### 规则

Packet filtering is based on rules, which are specified by multiple matches (conditions the packet must satisfy so that the rule can be applied), and one target (action taken when the packet matches all conditions). The typical things a rule might match on are what interface the packet came in on (e.g eth0 or eth1), what type of packet it is (ICMP, TCP, or UDP), or the destination port of the packet.

数据包的过滤基于 规则。

Targets are specified using the `-j` or `--jump` option. Targets can be either user-defined chains (i.e. if these conditions are matched, jump to the following user-defined chain and continue processing there), one of the special built-in targets, or a target extension. Built-in targets are `ACCEPT`, `DROP`, `QUEUE` and `RETURN`, target extensions are, for example, `REJECT` and `LOG`. If the target is a built-in target, the fate of the packet is decided immediately and processing of the packet in current table is stopped. If the target is a user-defined chain and the packet passes successfully through this second chain, it will move to the next rule in the original chain. Target extensions can be either terminating (as built-in targets) or non-terminating (as user-defined chains), see `man 8 iptables-extensions` for details.

目标使用 `-j` 或者 `--jump` 选项指定。目标可以是用户定义的链（例如，如果条件匹配，跳转到之后的用户定义的链，继续处理）、一个内置的特定目标或者是一个目标扩展。内置目标是 `ACCEPT`， `DROP`， `QUEUE` 和 `RETURN`，目标扩展是 `REJECT` and `LOG`。

### 遍历链

A network packet received on any interface traverses the traffic control chains of tables in the order shown in the flow chart. The first routing decision involves deciding if the final destination of the packet is the local machine (in which case the packet traverses through the `INPUT` chains) or elsewhere (in which case the packet traverses through the `FORWARD` chains). Subsequent routing decisions involve deciding what interface to assign to an outgoing packet. At each chain in the path, every rule in that chain is evaluated in order and whenever a rule matches, the corresponding target/jump action is executed. The 3 most commonly used targets are `ACCEPT`, `DROP`, and jump to a user-defined chain. While built-in chains can have default policies, user-defined chains can not. If every rule in a chain that you jumped fails to provide a complete match, the packet is dropped back into the calling chain as illustrated here. If at any time a complete match is achieved for a rule with a `DROP` target, the packet is dropped and no further processing is done. If a packet is `ACCEPT`ed within a chain, it will be `ACCEPT`ed in all superset chains also and it will not traverse any of the superset chains any further. However, be aware that the packet will continue to traverse all other chains in other tables in the normal fashion.

### 模块

有许多模块可以用来扩展 iptables，例如 connlimit, conntrack, limit 和 recent。这些模块增添了功能，可以进行更复杂的过滤。

## 配置并运行 iptables

iptables 是一个 Systemd 服务，因此可以这样启动：

    # systemctl start iptables

但是，除非有 `/etc/iptables/iptables.rules` 文件，否则服务不会启动，Arch iptables 包不包含默认的 `iptables.rules` 文件。因此，第一次启动服务时使用以下命令：

    # touch /etc/iptables/iptables.rules
    # systemctl start iptables

或者

    # cp /etc/iptables/empty.rules /etc/iptables/iptables.rules
    # systemctl start iptables

和其他服务一样，如果希望启动时自动加载 iptables，必须启用该服务：

    # systemctl enable iptables

### 从命令行

#### 显示当前规则

使用以下命令查看当前规则和匹配数：

    # 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 0K packets, 0 bytes)
     pkts bytes target     prot opt in     out     source               destination

上面的结果表明还没有配置规则。没有数据包被阻止。

To show the line numbers when listing rules, append `--line-numbers` to that input. This is useful when deleting and adding individual rules.

在输入中添加 `--line-numbers` 选项，可以在列出规则的时候显示行号。这在添加单独的规则的时候很有用。

#### 重置规则

You can flush and reset iptables to default using these commands:

    # 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

The `-F` command with no arguments flushes all the chains in its current table. Similarly, `-X` deletes all empty non-default chains in a table.

Individual chains may be flushed or deleted by following `-F` and `-X` with a `[chain]` argument.

#### 编辑规则

Rules can be added either by appending a rule to a chain or inserting them at a specific position on the chain. We will explore both methods here.

有两种方式添加规则，一种是在链上附加规则，另一种是将规则插入到链上某个特定位置。这里将讲解这两种方式。

First of all, our computer is not a router (unless, of course, it is a router). We want to change the default policy on the `FORWARD` chain from `ACCEPT` to `DROP`.

首先，由于电脑不是路由器(unless, of course, it is a router)，因此将 `FORWARD` 链默认的规则由 `ACCEPT` 改成 `DROP`。

    # iptables -P FORWARD DROP

Warning: The rest of this section is meant to teach the syntax and concepts behind iptables rules. It is not intended as a means for securing servers. For improving the security of your system, see Simple stateful firewall for a minimally secure iptables configuration and Security for hardening Arch Linux in general.
警告: 本章节其余部分主要讲解 iptables 规则的语法和其背后的思想，而不是作为一种保护服务器的手段，如果想要提高系统的安全性，参考 Simple stateful firewall 来获得一个最低限度的 iptables 安全配置，参考 Security 来提高 Arch Linux 的安全性。

The Dropbox LAN sync feature broadcasts packets every 30 seconds to all computers it can see. If we happen to be on a LAN with Dropbox clients and do not use this feature, then we might wish to reject those packets.

    # 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

Note: We use `REJECT` rather than `DROP` here, because RFC 1122 3.3.8 requires hosts return ICMP errors whenever possible, instead of dropping packets. This page explains why it is almost always better to REJECT rather than DROP packets.
注意: 这里使用 `REJECT` 而不是 `DROP`，因为 RFC 1122 3.3.8 要求主机尽可能返回 ICMP 错误而不是丢弃数据包。这里 介绍了为什么倾向于 REJECT 而不是 DROP 数据包。

Now, say we change our mind about Dropbox and decide to install it on our computer. We also want to LAN sync, but only with one particular IP on our network. So we should use `-R` to replace our old rule. Where `10.0.0.85` is our other 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

We have now replaced our original rule with one that allows `10.0.0.85` to access port `17500` on our computer. But now we realize that this is not scalable. If our friendly Dropbox user is attempting to access port `17500` on our device, we should allow him immediately, not test him against any firewall rules that might come afterwards!

So we write a new rule to allow our trusted user immediately. Using `-I` to insert the new rule before our old one:

    # 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

And replace our second rule with one that rejects everything on port `17500`:

    # iptables -R INPUT 2 -p tcp --dport 17500 -j REJECT --reject-with icmp-port-unreachable

Our final rule list now looks like this:

    # 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

### 配置文件

Iptables rules are, by default in Arch Linux, stored in `/etc/iptables/iptables.rules`. They are, however, not loaded automatically, instead you can enable the `iptables.service` which reads this file and loads the rules at boot or when started:

    # systemctl enable iptables.service
    # systemctl start iptables.service

ipv6 规则默认保存在`/etc/iptables/ip6tables.rules`,`ip6tables.service`服务会使用这个规则，可以用类似的方式启动服务。

Note: The `iptables.service` and `ip6tables.service` files in the iptables 1.4.21-1 package are outdated. Since systemd 214 for security reasons it is recommended that firewalls be started before the `network-pre.target` target so that the firewall is running before any network is configured. Pending updating of the iptables package, create the dropin directory `/etc/systemd/system/iptables.service.d`, create the file `00-pre-network.conf` and include the following snippet:

    [Unit]
    Before=network-pre.target
    [Install]
    RequiredBy=network-pre.target

If the system uses the `ip6tables.service`, do the same via a `/etc/systemd/system/ip6tables.service.d` dropin directory. For more details see this systemd bug report, this systemd release announcement and FS#33478.

After adding rules via command-line, the configuration file is not changed automatically — you have to save it manually:

    # iptables-save > /etc/iptables/iptables.rules

修改配置文件后，需要重新加载服务：

    # systemctl reload iptables

Or you can load it directly through iptables:

    # iptables-restore < /etc/iptables/iptables.rules

### 指南

- Simple stateful firewall
- Router

## 日志

The `LOG` target can be used to log packets that hit a rule. Unlike other targets like `ACCEPT` or `DROP`, the packet will continue moving through the chain after hitting a `LOG` target. This means that in order to enable logging for all dropped packets, you would have to add a duplicate `LOG` rule before each DROP rule. Since this reduces efficiency and makes things less simple, a `logdrop` chain can be created instead.

LOG 目标可以用来记录匹配某个规则的数据包。和 ACCEPT 或 DROP 规则不同，进入 LOG 目标之后数据包会继续沿着链向下走。所以要记录所有丢弃的数据包，只需要在 DROP 规则前加上相应的 LOG 规则。但是这样会比较复杂，影响效率，所以应该创建一个`logdrop`链。

创建 logdrop 链：

    # iptables -N logdrop

定义规则：

    # iptables -A logdrop -m limit --limit 5/m --limit-burst 10 -j LOG
    # iptables -A logdrop -j DROP

Explanation for `limit` and `limit-burst` options is given below.

Now whenever we want to drop a packet and log this event, we just jump to the `logdrop` chain, for example:

    # iptables -A INPUT -m conntrack --ctstate INVALID -j logdrop

### 限制日志级别

The above `logdrop` chain uses the limit module to prevent the iptables log from growing too large or causing needless hard drive writes. Without limiting an erroneously configured service trying to connect, or an attacker, could fill the drive (or at least the `/var` partition) by causing writes to the iptables log.

The limit module is called with `-m limit`. You can then use `--limit` to set an average rate and `--limit-burst` to set an initial burst rate. In the `logdrop` example above:

    iptables -A logdrop -m limit --limit 5/m --limit-burst 10 -j LOG

appends a rule which will log all packets that pass through it. The first 10 consecutive packets will be logged, and from then on only 5 packets per minute will be logged. The "limit burst" count is reset every time the "limit rate" is not broken, i.e. logging activity returns to normal automatically.

### Viewing logged packets

Logged packets are visible as kernel messages in the systemd journal.

记录的数据包作为内核信息，可以在 systemd journal 看到。

To view all packets that were logged since the machine was last booted:

使用以下命令查看所有最近一次启动后所记录的数据包：

    # journalctl -k | grep "IN=.*OUT=.*" | less

### syslog-ng

使用 Arch 默认的 syslog-ng 可以控制 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 目标。软件包 ulogd 位于 `[community]` 源。

## 参见

Wikipedia:iptables

- Simple stateful firewall
- 官方网站
- Iptables 教程 1.2.2

Category:

- Firewalls (简体中文)