iptables - Arch Linux 中文维基

跳至內容

# iptables

出自 Arch Linux 中文维基

翻譯狀態：

- 本文（或部分內容）譯自 Iptables，最近一次同步於 2021-11-24，若英文版本有所更改，則您可以幫助同步與翻譯更改的內容。
- 您可以在 ArchWiki 的對應頁面找到本文翻譯的原始修訂歷史。
- 本文可能與英文原文存在出入。

相關文章

- nftables
- Fail2ban
- sshguard
- Simple stateful firewall
- Sysctl#TCP/IP stack hardening
- Uncomplicated Firewall

iptables 是一個配置 Linux 內核防火牆的命令行工具，是 Netfilter 項目的一部分。術語 iptables 也經常代指該內核級防火牆。iptables 可以直接配置，也可以通過許多控制台和圖形化前端配置。iptables 用於 ipv4，ip6tables 用於 IPv6。iptables和ip6tables 擁有相同的語法，但是有些特別的選項，對 IPv4 和 IPv6 有些不同的。

注意：iptables是一個遺留的框架，nftables 致力於提供一個現代化的替代產品，包括一個兼容層。

## 安裝

Arch Linux 內核已經編譯了 iptables 支持。只需要安裝用戶層工具 iptables包 包即可。iptables包是base包meta package的間接依賴，因此系統中已經默認安裝了 iptables 包。

### 前端

#### 控制台

- Arno's firewall — 可用於單機器和多連接機器的安全防火牆。配置簡單，管理方便，高度定製化。支持：NAT和SNAT, 埠轉發，擁有靜態和動態IP分配的ADSL網絡數據機，MAC地址過濾，隱身埠掃描檢測，DMZ和DMZ-2-LAN轉發，保護免SYN/ICMP洪範攻擊，使用限速的可自定義的用戶日誌防禦日誌洪範攻擊，所有IP協議和VPN(如IPsec)，插件支持額外添加功能。

  https://rocky.eld.leidenuniv.nl/ || arno-iptables-firewallAUR

- ferm — 維護複雜防火牆的工具，無需一遍遍的向防火牆寫入複雜的規則。它允許將整個防火牆規則儲存在一個單獨的文件中，之後使用一個單獨的命令進行加載。 防火牆配置類似於結構變成語言，可以包含levels和lists。

  http://ferm.foo-projects.org/ || ferm包

- FireHOL — 用來表達防火牆規則的語言，不僅僅是生成某種防火牆的腳本。它可以以一種你想要的方式，使構建一個很複雜的防火牆變得簡單。

  http://firehol.sourceforge.net/ || fireholAUR

- Firetable — 維護IPtables防火牆的工具。每個接口可以通過其自己的配置文件單獨配置，配置文件是以一種簡單且人類可讀的語法書寫的。

  https://gitlab.com/hsleisink/firetable || firetableAUR

- firewalld (firewall-cmd) — 守護進程和控制台接口，以用來配置網絡和防火牆保護區域，和設置與配置防火牆規則一樣。

  https://firewalld.org/ || firewalld包

- Shorewall — 配置Netfilter的高級工具。您可以使用一組配置文件中的條目描述防火牆/網關的需求。

  http://www.shorewall.net/ || shorewallAUR

- Uncomplicated Firewall — iptables的簡單前端。

  https://launchpad.net/ufw || ufw包

- PeerGuardian (pglcmd) — 面向隱私的防火牆應用。它使用一個指定的巨大的阻塞鍊表（包含數千或數百萬的IP的範圍）來阻止主機的出站和入站連接。

  https://sourceforge.net/projects/peerguardian/ || pglAUR

- Vuurmuur — 強大的防火牆管理器。它擁有一個簡單易學配置方式，並且支持簡單或複雜的配置。配置完全可以使用ncurses包GUI進行，並且該GUI支持通過SSH或控制台進行的安全遠程管理。Vuurmuur支持流量整形，擁有一個強大的監控功能，它允許管理員實時查看日誌，連結和帶寬使用。

  https://www.vuurmuur.org/ || vuurmuurAUR

- Servicewall — 簡單的自定義的iptables前端，使你可以定義在連接到特定領域時允許的服務，並且在需要時自動的切換配置文件。它的服務定義通過jhansonxi提供，通過ufw使用。它依賴於ulogd來向日誌文件提供丟棄的包的日誌，並且提供了一個注重日誌訪問限制的日誌檢查框架。

  https://github.com/lafleurdeboum/servicewall || servicewall-gitAUR[損壞的連結：package not found]

#### 圖形化

- Firewall Builder — GUI防火牆配置管理工具，支持iptables (netfilter), ipfilter, pf, ipfw, 思科 PIX (FWSM, ASA) 和思科路由拓展訪問鍊表。程序可以運行在Linux，FreeBSD，OpenBSD，Windows和macOS上，並且可以管理本地和遠程的防火牆。

  https://fwbuilder.sourceforge.net/ || fwbuilder包

- firewalld (firewall-config) — 用於配置網絡和防火牆區域，以及設置和配置防火牆規則的守護進程和圖形界面。

  https://firewalld.org/ || firewalld包

- Gufw — 用於ufw包的基於GTK的前端，這正好是一個十分簡單好用的對於iptables(gufw->ufw->iptables)的用戶前端。

  https://gufw.org/ || gufw包

- PeerGuardian GUI (pglgui) — 面向隱私的防火牆應用。它使用一個指定的巨大的阻塞鍊表（包含數千或數百萬的IP的範圍）來阻止主機的出站和入站連接。

  https://sourceforge.net/projects/peerguardian/ || pglAUR

## 基本概念

iptables 可以檢測、修改、轉發、重定向和丟棄 IPv4 數據包。過濾 IPv4 數據包的代碼已經內置於內核中，並且按照不同的目的被組織成表的集合。表由一組預先定義的鏈組成，鏈包含遍歷順序規則。每一條規則包含一個謂詞的潛在匹配和相應的動作（稱為目標），如果謂詞為真，該動作會被執行。也就是說條件匹配。iptables 是用戶工具，允許用戶使用鏈和規則。很多新手面對複雜的 linux IP 路由時總是感到氣餒，但是，實際上最常用的一些應用案例（NAT 或者基本的網絡防火牆）並不是很複雜。

理解 iptables 如何工作的關鍵是這張圖。圖中在上面的小寫字母代表表，在下面的大寫字母代表鏈。從任何網絡埠進來的每一個 IP 數據包都要從上到下的穿過這張圖。一種常見的錯誤認知是認為 iptables 對從內部埠進入的數據包和從面向網際網路埠進入的數據包採取不同的處理方式，相反，iptables 對從任何埠進入的數據包都會採取相同的處理方式。可以定義規則使 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` 用於配置數據包，`raw` 中的數據包不會被系統跟蹤。
2. `filter` 是用於存放所有與防火牆相關操作的默認表。
3. `nat` 用於網絡地址轉換（例如：埠轉發）。
4. `mangle` 用於對特定數據包的修改（參考損壞數據包）。
5. `security` 用於強制訪問控制網絡規則（例如： SELinux -- 詳細信息參考該文章）。

大部分情況僅需要使用 filter 和 nat。其他表用於更複雜的情況——包括多路由和路由判定——已經超出了本文介紹的範圍。

### 鏈 （Chains）

表由鏈組成，鏈是一些按順序排列的規則的列表。默認的 `filter` 表包含 `INPUT`， `OUTPUT` 和 `FORWARD` 3條內建的鏈，這3條鏈作用於數據包過濾過程中的不同時間點，如該流程圖所示。`nat` 表包含`PREROUTING`， `POSTROUTING` 和 `OUTPUT` 鏈。

使用 iptables(8) 查看其他表中內建鏈的描述。

默認情況下，任何鏈中都沒有規則。可以向鏈中添加自己想用的規則。鏈的默認規則通常設置為 `ACCEPT`，如果想確保任何包都不能通過規則集，那麼可以重置為 `DROP`。默認的規則總是在一條鏈的最後生效，所以在默認規則生效前數據包需要通過所有存在的規則。

用戶可以加入自己定義的鏈，從而使規則集更有效並且易於修改。如何使用自定義鏈請參考 Simple stateful firewall。

### 規則 （Rules）

數據包的過濾基於規則。規則由一個目標（數據包匹配所有條件後的動作）和很多匹配（導致該規則可以應用的數據包所滿足的條件）指定。一個規則的典型匹配事項是數據包進入的埠（例如：eth0 或者 eth1）、數據包的類型（ICMP, TCP, 或者 UDP）和數據包的目的埠。

目標使用 `-j` 或者 `--jump` 選項指定。目標可以是用戶定義的鏈（例如，如果條件匹配，跳轉到之後的用戶定義的鏈，繼續處理）、一個內置的特定目標或者是一個目標擴展。內置目標是 `ACCEPT`， `DROP`， `QUEUE` 和 `RETURN`，目標擴展是 `REJECT` and `LOG`。如果目標是內置目標，數據包的命運會立刻被決定並且在當前表的數據包的處理過程會停止。如果目標是用戶定義的鏈，並且數據包成功穿過第二條鏈，目標將移動到原始鏈中的下一個規則。目標擴展可以被終止（像內置目標一樣）或者不終止（像用戶定義鏈一樣）。詳細信息參閱 iptables-extensions(8)。

### 遍歷鏈 （Traversing Chains）

該流程圖描述了鏈在任何接口上收到的網絡數據包是按照怎樣的順序穿過表的交通管制鏈。第一個路由策略包括決定數據包的目的地是本地主機（這種情況下，數據包穿過 `INPUT` 鏈），還是其他主機（數據包穿過 `FORWARD` 鏈）；中間的路由策略包括決定給傳出的數據包使用哪個源地址、分配哪個接口；最後一個路由策略存在是因為先前的 mangle 與 nat 鏈可能會改變數據包的路由信息。數據包通過路徑上的每一條鏈時，鏈中的每一條規則按順序匹配；無論何時匹配了一條規則，相應的 target/jump 動作將會執行。最常用的3個 target 是 `ACCEPT`, `DROP` ,或者 jump 到用戶自定義的鏈。內置的鏈有默認的策略，但是用戶自定義的鏈沒有默認的策略。在 jump 到的鏈中，若每一條規則都不能提供完全匹配，那麼數據包像這張圖片描述的一樣返回到調用鏈。在任何時候，若 `DROP` target 的規則實現完全匹配，那麼被匹配的數據包會被丟棄，不會進行進一步處理。如果一個數據包在鏈中被 `ACCEPT`，那麼它也會被所有的父鏈 `ACCEPT`，並且不再遍歷其他父鏈。然而，要注意的是，數據包還會以正常的方式繼續遍歷其他表中的其他鏈。

### 模塊 （Modules）

有許多模塊可以用來擴展 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

上面的結果表明還沒有配置規則。沒有數據包被阻止。

在輸入中添加 `--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` 命令刪除表中所有非默認鏈。

用下面的帶 `[chain]` 參數的 `-F` 和 `-X` 命令刷新或刪除單獨的鏈。

#### 編輯規則

有兩種方式添加規則，一種是在鏈上附加規則，另一種是將規則插入到鏈上某個特定位置。這裡將講解這兩種方式。

首先，由於電腦不是路由器(unless, of course, it is a router)，因此將 `FORWARD` 鏈默認的規則由 `ACCEPT` 改成 `DROP`。

    # iptables -P FORWARD DROP

警告：本章節其餘部分主要講解 iptables 規則的語法和其背後的思想，而不是作為一種保護伺服器的手段，如果想要提高系統的安全性，參考 Simple stateful firewall 來獲得一個最低限度的 iptables 安全配置，參考 Security 來提高 Arch Linux 的安全性。

Dropbox 的區域網同步特性——每30秒廣播數據包[失效連結 2022-09-18 ⓘ]到所有可視的計算機，如果我們碰巧在一個擁有 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 3.3.8 要求主機儘可能返回 ICMP 錯誤而不是丟棄數據包。這裡 介紹了為什麼傾向於 REJECT 而不是 DROP 數據包。

現在，我們改變對 Dropbox 的看法，並且決定安裝其到我們的計算機，我們也希望區域網同步，但是我們的網絡只有一個特定的 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

### 配置文件

在 Arch Linux 中， Iptables 規則默認存放在 `/etc/iptables/iptables.rules` 文件中，它們不會被自動加載，因此需要啟用 `iptables.service`，服務會在啟動時讀取文件並且加載規則，或者直接啟動服務：

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

ipv6 規則默認保存在 `/etc/iptables/ip6tables.rules`,`ip6tables.service` 服務會使用這個規則，可以用類似的方式啟動服務。

注意：iptables 1.4.21-1 包中的 `iptables.service` 和 `ip6tables.service` 文件已經過期了。因為安全原因，自 systemd 214 起推薦防火牆在 `network-pre.target` 目標之前啟動，這樣防火牆就可以在任何網絡配置之前運行。等待 iptables 數據包更新，創建深層目錄 `/etc/systemd/system/iptables.service.d`，創建 `00-pre-network.conf` 文件，添加如下片段：

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

如果系統使用 `ip6tables.service`，那麼在 `/etc/systemd/system/ip6tables.service.d` 目錄中做同樣的配置。更多細節參考 systemd bug report，systemd release announcement 和 FS#33478

通過命令行添加規則，配置文件不會自動改變，所以必須手動保存：

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

修改配置文件後，需要重新加載服務：

    # systemctl reload iptables

或者通過 iptables 直接加載：

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

### 指南

- Simple stateful firewall
- Router

## 日誌

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

下文會給出 `limit` 和 `limit-burst` 選項的解釋。

現在任何時候想要丟棄數據包並且記錄該事件，只要跳轉到 `logdrop` 鏈，例如：

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

### 限制日誌級別

上述 `logdrop` 鏈使用限制（limit）模式來防止 iptables 日誌來過大或者造成不必要的硬碟讀寫。沒有限制的話，一個試圖連結的錯誤配置服務、或者一個攻擊者，都會使 iptables 日誌寫滿整個硬碟（或者至少是 `/var` 分區）。

限制模式使用 `-m limit`，可以使用 `--limit` 來設置平均速率或者使用 `--limit-burst` 來設置起始觸發速率。在上述 `logdrop` 例子中：

    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.

添加一條記錄所有通過其的數據包的規則。開始的連續10個數據包將會被記錄，之後每分鐘只會記錄5個數據包。The "limit burst" count is reset every time the "limit rate" is not broken，例如，日誌記錄活動自動恢復到正常。

### 查看記錄的數據包

記錄的數據包作為內核信息，可以在 systemd journal 看到。

使用以下命令查看所有最近一次啟動後所記錄的數據包：

    # 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

分類：​

- 防火牆
- 包含損壞的軟體包連結的頁面
- 包含失效連結的頁面

iptables
新增話題