Try   HackMD

iptables 基本介紹

以下紀錄自己學習 iptables 的筆記~

資料透過網路傳輸時,會被切割成一個一個的封包,封包裡面除了含有要傳送的 data,也含有這個封包的資訊,像是 souce address、protocol 等等資訊。

而說到 Linux 的防火牆,就會提到 iptables。當封包進到 iptables 裡面,iptables 就會查看這個封包的資訊,並依據我們設定的防火牆規則對這個封包做處理。

以下簡單介紹 iptables 和它的指令~

Linux Firewall

linux firewall

netfilter 是運行在 kernel space 的,所以使用者沒辦法直接對他做操作;而 iptables 則是運行在 user space 的工具,使用者可以透過 iptablesnetfilter 做設定。

從上面那張圖可以看到 iptables 其實是比較舊版的,且 iptables 是專門負責 IPv4 的 packet filtering 和 network address translation(NAT);IPv6 的部分則由 ip6tables 負責,另外還有 ebtablesarptables 分別負責 ethernet bridge frame table 和 address resolution protocol table。

而 Linux kernel 自 3.13 版開始,就改成使用 nftables。一個 nftables 的功能就涵蓋了舊版的四個工具的功能。

而 OpenWRT 則是自 22.03 版以後,預設上改成使用 nftables

iptables 組成

Table、Chain、以及 Rule

tables, chains, rules in iptables

上圖是一個很簡單的示意圖,iptables 裡面會有一個一個的 tables,每個 table 則會由多個 chains 所組成,而這些 chains 則由多個 rules 所構成。

  • 依據對封包做的操作的不同,會有不同的 table,像是負責 network address translation 的 nat table、或負責封包過濾的 filter table
  • Chain 則是依據封包處理流程的不同階段所命名,像是在做 routing 之前(PREROUTING chain)、或者是處理完 routing 之後(POSTROUTING chain)。
  • Rule 就是我們所設定的防火牆規則。
    • 每個 rule 都會有 target,target 就是要對這個封包做什麼「操作」。
    • 當封包進入一個 chain,就會開始從該 chain 的第一條 rule 開始依序比對,假如該封包符合了第一個 rule,那就會對這個封包執行第一個 rule 所指定的「操作」,然後可能就會到下一個 chain 或被丟棄。
      假如前面的 rule 都沒有符合,那就會去比對下一條 rule,依此類推。
  • 最後,可以看到 chain 裡面不一定要有 rule,但一定要有 policy。Policy 跟 rule 一樣都會有 taget。前面有提到,封包一旦進入一個 chain,就會開始依序從第一個 rule 做比對,若有符合某個 rule,那就執行該 rule 的 target。但萬一全部的 rule 都比對過了,但都沒符合,或者是該 chain 裡面沒有半條 rule,那該怎麼處理這封包呢?這時候就是看該 chain 的 policy 的 target 為何,就會對封包執行 policy 的 target。

以 NAT table 為例,這個 table 的功能是對封包做 network address translation,那這個 table 有 PREROUTING chain 和 POSTROUTING chain,所以封包在 PREROUTINGPOSTROUTING 階段會進入 NAT table 的 PREROUTING chain 和 POSTROUTING chain,並且依序比對這些 chain 裡面的 rule,

packets and iptables

上圖是個簡單的示意圖說明若一個封包進到 iptables 的處理流程。

封包的處理流程主要依據不同的階段劃分,這裡簡單的用 Stage I、Stage II、以及 Stage III 作說明(後面會提到確切的流程)。

前面有提到,chain 的命名是依據封包處理的階段所命名,所以 stage I 會由某些 table 的 chain I 所組成,而 stage II 則由另一些 table 的 chain II 所組成,依此類推。

封包在每個 stage 會依序去執行不同 table 的 chain。一旦符合該 chain 的某個 rule,就執行該 rule 的 target。上圖列出了兩個最常見的 target:ACCEPTDROPACCEPT 就是讓這封包通過,DROP 則是丟掉這個封包。

所以在上面的示意圖可看到,一旦封包符合了 rule,且該 rule 的 target 是 ACCEPT,那這個封包就會到下一個 chain,而不會繼續比對同一個 chain 後面的 rule所以 rule 的順序在 iptables 是很重要的一件事!倘若 target 是 DROP,就會丟棄該封包、不再對它做處理。

Rule 的順序很重要!

rule order is important

前面有提到,封包一旦進入一個 chain,就會依序去比對該 chain 的 rule,倘若符合某個 rule,就會執行該 rule 指定的 target。

所以再提醒一次~rule 的順序在 iptables 是很重要的~若順序錯誤,可能就達不到自己想要的效果!

此外,依據封包執行的結果,大致可將 target 分成兩類:terminating target 和 non-terminating target。

  • Terminating target:
    • 大部分的 target 都屬於這類,像是最常見的 ACCEPTDROP。執行了這類的 target 後,封包就不會繼續比對同一個 chain 後續的 rule。例如,若是 ACCEPT,那封包就會到下一個 chain。
  • Non-terminating target:
    • 這類型的 target 執行後,還是會繼續比對後面的 rule,像是 LOG,顧名思義就是會記錄到 log。

iptables 的 Tables 和 Chains

Slide41

目前 iptables 內有這五個 tables,但可能會因 kernel 的 configuration 不同而有些許差異:

  • filter table
    • 最主要負責防火牆功能的 table,也是預設的 table,負責封包過濾的功能,像是 ACCEPT(接受)封包,或 DROP(丟掉)封包。
  • nat table
    • 主要負責處理 network address translation(NAT),像是更改封包的 source address(SNAT)、或是更改封包的 destination address(DNAT)。
  • mangle table
    • 此 table 的功能主要是修改封包的 header,像是修改 Time-To-Live(TTL)欄位、Quality of Service(QoS)欄位。此外,也能藉由 MARK target 對封包做標記。
  • raw table
    • raw table 的主要功能是將不需要做 connection tracking(連線追蹤)的封包做 NOTRACK,這樣這些封包就不會被 connection tracking,而可以減少 netfilter 的負擔。
    • 由於若要將封包設定為 NOTRACK,就必須要在封包進到 iptables 時盡早對其做處理,所以在封包的 PREROUTINGOUTPUT 階段第一個經過的 table 就是 raw table(後面會有張整個流程的示意圖)。
  • security table
    • 此 table 是用在 Mandatory Access Control(MAC)networking rules。通常是 kernel 有啟用 Linux Security Modules(LSM),這個 table 才會有作用。有用到 LSM 的包括 Security Enhanced Linux(SELinux)。
    • MAC 會透過對封包標示 Security Label 來控制是否可存取系統資源,所以此 table 主要的 target 就是對封包做 SECMARKCONNSECMARK 標示,後續再由像是 SELinux 決定是否允許此封包存取系統。
    • filter table 的 chain 比對完之後,就會馬上比對 security table 的 chain。

Slide42

如果是使用 OpenWRT 的話,OpenWRT 預設使用的 table 是 filter table、nat table、以及 mangle table。

若想要使用 raw table 的話,記得在編譯 kernel 前就要做好設定~
像是用 make menuconfig

  • Kernel modules
    • Netfilter Extensions
      • <*> kmod-ipt-raw

Slide44
內建的 chain 總共有五個,分別代表封包處理的五個階段:

  • PREROUTING
    • 封包從 network interface 進入,並且在做 routing decision 之前的階段。
    • 做完 routing decision 之後會決定這個封包其目的地是本機、還是只是經過本機。
      • 若封包的目的地是本機,那就會進入 INPUT chain。
      • 若封包只是經過本機、目的地不是本機,那就會進入 FORWARD chain。
  • INPUT
    • 當封包通過 PREROUTING chain,且路由決策判斷其目的地是本機,就會進入 INPUT chain,可以在這裡決定本機是否要接受此封包。
  • FORWARD
    • 只是經過本機的封包、目的地不是本機。
    • 通過 FORWARD chain 後會進入 POSTROUTING
  • OUTPUT
    • 由本機發出的封包,進入 iptables 的第一個階段就是 OUTPUT chain。
    • 通過 OUTPUT chain 後會進入 POSTROUTING chain。
  • POSTROUTING
    • 若只是經過本機而目的地非本機的封包、以及由本機發出的封包,在離開 network interface 之前的最後一個階段就是 POSTROUTING chain。
    • 可以在這個階段修改封包的 source address(SNATMASQUERADE)。

Slide40

每個 table 所內建的 chain。

封包處理流程

Slide45

上圖是 iptables 的封包處理流程的簡單示意圖~

假如封包從某個 network interface 進來(incoming packet),且目的地是本機(local processing),那這個封包就會經過

  1. raw table 的 PREROUTING chain
    • 決定此封包是否要做 connection tracking
  2. mangle table 的 PREROUTING chain
  3. nat table 的 PREROUTING chain
    • PREROUTING 的 nat table 有可能會做 destination NAT、以變更目的地 address
  4. 做 routing decision 判斷此封包目的地是本機(送往 INPUT chain)、或者是要被轉發到某個 network interface(送往 FORWARD chain)
  5. mangle table 的 INPUT chain
  6. filter table 的 INPUT chain
    • 決定哪些封包可以進入本機
  7. security table 的 INPUT chain
  8. 送到本機(local procession)

假如某個封包從 network interface 進來(incoming packet),但他的目的地不是本機、只是經過,最終會由某個 interface 出去(outgoing packet),那這個封包就會經過

  1. raw table 的 PREROUTING chain
  2. mangle table 的 PREROUTING chain
  3. nat table 的 PREROUTING chain
    • PREROUTING 的 nat table 有可能會做 destination NAT、以變更目的地 address
  4. 做 routing decision 判斷此封包目的地是本機(送往 INPUT chain)、或者是要被轉發到某個 network interface(送往 FORWARD chain)
  5. mangle table 的 FORWARD chain
  6. filter table 的 FORWARD chain
  7. security table 的 FORWARD chain
  8. mangle table 的 POSTROUTING chain
  9. nat table 的 POSTROUTING chain
    • POSTROUTING chain 的 nat table 可能會做 SNATMASQUERADE 以變更封包的 source address
      • SNAT 是將封包的 source address 修改成固定的 IP address。
      • MASQUERADE 則是將封包的 source address 修改成他要出去的 network interface 的 IP address。
  10. 由 network interface 出去(outgoing packet)

假如某個封包是由本機產生(locally generated packet),然後經由 network interface 出去(outgoing packet),那這個封包就會經過

  1. 本機產生的封包會先進行 routing decision,以決定走哪條路由,之後才進入 OUTPUT chain
  2. raw table 的 OUTPUT chain
    • 決定本機發出的封包是否要做 connection tracking
  3. mangle table 的 OUTPUT chain
  4. nat table 的 OUTPUT chain
    • OUTPUT chain 的 nat table 有可能會做 destination nat,更改封包的目的地。
  5. filter table 的 OUTPUT chain
  6. security table 的 OUTPUT chain
  7. 在經過 OUTPUT chain,準備進入 POSTROUTING chain 之前,會先進行 re-route check,再重新計算一次路由
    • 由於 OUTPUT chain 的 nat table 有可能會更改 destination address,所以才會需要再重新計算一次路由

    PS. 若封包是由 FORWARD chain 到 POSTROUTING chain,那就不會做 re-route check。
    因為這樣子的封包,其流程是 PREROUTING -> routing decision -> FORWARD -> POSTROUTING
    這樣的封包只有可能在 PREROUTING chain 的 nat table 才有可能做 destination nat 更改目的地 address,當他結束 PREROUTING chain 後就會做 routing decision,而 FORWARD chain 裡面並沒有 nat table,不可能更改目的地 address,所以在進入 POSTROUTING chain 前就不用做 re-route check。

  8. mangle table 的 POSTROUTING chain
  9. nat table 的 POSTROUTING chain
    • POSTROUTING chain 的 nat table 可能會做 SNATMASQUERADE 以變更封包的 source address
      • SNAT 是將封包的 source address 修改成固定的 IP address。
      • MASQUERADE 則是將封包的 source address 修改成他要出去的 network interface 的 IP address。
  10. 由 network interface 出去(outgoing packet)

一些常用的 iptables 指令

Slide46

接下來簡單介紹一些比較常見的 iptables 指令~若要看更詳細的內容可以用 man iptables 指令查看。

上圖中第一類的指令是在指定的 table 中指定的 chain 做添加(A ppend)、刪除(D elete)、插入(I nsert)規則的指令。

  • -A:新添加的規則會放在指定的 table 的指定的 chain 的最後面
  • -D:刪除某個規則,
  • -I:將新的規則插入指定的 table 的指定的 chain 的指定的位子,

第二類的指令則可以新增(-N)或刪除(-X)使用者自訂義的 chain。

第三個指令則是可以設定指定的 table 的指定的 chain 的 policy。

最後一個則是可以列出指定的 table 的規則。

在設定 iptables 的時候都要有 root user 的權限,所以若是一般使用者的話記得指令前面都要加個 sudo

以上幾個指令,若沒有指定 table 的話,預設都會是對 filter table 做設定喔~

Slide47

這張 slide 簡單介紹怎麼設定一個規則(後面會介紹幾個我自己有用過的規則~看例子應該會更好懂~)

首先~我們可以指定這條規則的參數,像是:

  • -p [!]protocol_name:指定某個 protocol 的封包。若有加 ! 則會變成指定「非」某某 protocol 的封包。
  • -s [!]address[/mask]:source address 是某某 address 的封包。
  • -d [!]address[/mask]:destination address 是某某 address 的封包。
  • -j target:符合這條規則的封包,要對他做的操作。
  • -g chain:符合這條規則的封包,跳到指定的 chain。
  • -i [!]interface_name:從某個 interface 進來的封包。
  • -o [!]interface_name:要從某個 interface 出去的封包。

我們也要設定若某個封包符合規則,那要對這個封包做什麼操作(Target),像是:

  • ACCEPT:讓這個封包通過
  • DROP:把這個封包丟掉,不處理它
  • REJECT:類似 DROP,但還會送封包回去說這個封包被拒絕
  • MASQUERADE:將封包的 source address 改成他要出去的 interface 的 IP address
  • SNAT:跟 MASQUERADE 一樣都會修改封包的 souce address,但 SNAT 是設定固定的 IP,MASQUERADE 則是依據指定的 network interface 的 IP 做設定。

接下來介紹幾個自己有設定過的 iptables 指令~

Slide48

這個指令的功能是:

  • 添加一個規則到 nat table 的 POSTROUTING chain 的最後一個位子
  • 這個規則是說,只要是從 enp1s0 這個 network interface 出去的封包,都對他們做 MASQUERADE,也就將他們的 source address 改成 enp1s0 network interface 的 IP address

Slide49

這個指令的功能是:

  • 添加一個規則到 filter table 的 INPUT chain 的最後一個位子
    • PS. 若沒有指定 table 的話~都是對 filter table 做操作喔
  • 這個規則是說,只要是 ICMP protocol 的封包,都讓他們通過

Slide50

這個指令的功能是:

  • 添加一個規則到 filter table 的 FORWARD chain 的最後一個位子
  • 這個規則是說,只要是從 enx256e 這個 network interface 進來、且會從 enp1s0 這個 network interface 出去的封包,都讓他們通過

Slide51

這個指令的功能是:

  • 添加一個規則到 filter table 的 FORWARD chain 的最後一個位子
  • 這個規則是說,只要是從 enp1s0 這個 network interface 進來、且會從 enx256e 這個 network interface 出去的封包,且若這些封包的狀態(state)是已建立(ESTABLISHED)連線的狀態,就讓這些封包通過

Slide51

前面用 iptables 指令所設定的規則,在每次重開機後都不會存在,若希望能保留每次設定的規則,可以用 iptables-persistent 這個工具。

安裝 iptables-persistent

$ sudo apt install iptables-persistent

每次設定完規則後就用以下指令儲存規則:

$ sudo netfilter-persistent save

這樣的話規則就會被儲存在以下檔案,並且在每次開機時都將其載入:

/etc/iptables/rules.v4
/etc/iptables/rules.v6

此外,順便介紹另一個與 iptables -L -n 類似的指令,會將 iptables 的規則依序印出來:

$ sudo iptables-save

iptables 設定接受/拒絕 ssh 連線

若想簡單練習 iptables 的話,可以練習設定是否要接受/拒絕 ssh 連線~

若是 Ubuntu Desktop,需要先安裝 ssh server 這樣才能讓別人用 ssh 連進來,在 Ubuntu 的話主要都是安裝 openssh-server

$ sudo apt update
$ sudo apt install openssh-server

用以下指令確認確認 openssh-serveractive (running)

$ systemctl status ssh

image

如果 Ubuntu 是虛擬機,且是 VirtualBox 虛擬機的話,記得要先對Ubuntu 虛擬機設定 Bridged Adaptor,且 Name 選擇 MacBook 連到 Wi-Fi 的 interface en0,這樣我的 Ubuntu 虛擬機就會跟我的 MacBook 在同一個 LAN 內:

image

首先,我的 MacBook 透過 Wi-Fi 介面被分配到的 IP 是 192.168.50.180:

image

Ubuntu 虛擬機被分配到的則是 192.168.50.241:

image

設定 iptables 允許/拒絕 ssh 連線

由於 ssh 通常都是用 Transmission Control Protocol (TCP),且 ssh server 是監聽 port 22。所以若要允許/拒絕別人用 ssh 連過來,就要對 iptablesfilter table 的 INPUT chain 設定說,若有封包是用 TCP protocol、且該封包的 destination port 是 22,我們就接受/拒絕。

如果是要接受所有 ssh 連線,就做以下設定:

iptables -t filter -A INPUT -p tcp --dport 22 -j ACCEPT
  • -t filter -A INPUT:在 filter table 的 INPUT chain 添加(A ppend)新的規則
  • -p tcp --dport 22 -j ACCEPT:對於使用 tcp protocol 且 destination port 是 22 的封包,允許這樣的封包通過

若要拒絕所有 ssh 連線,可以做以下設定:

sudo iptables -t filter -A INPUT -p tcp --dport 22 -j DROP

sudo iptables -t filter -A INPUT -p tcp --dport 22 -j REJECT
  • DROP 就是丟掉這封包不理他,發送 ssh 連線請求的 client 端會過一陣子得到 timed out 的訊息
  • REJECT 則會發送一個拒絕的封包,讓發出 ssh 連線請求的 client 知道被拒絕了

Test 1 - DROP ssh 連線

若用 iptables 將 ssh 連線請求的封包設定為 DROP,並且用 tcpdump 查看是否有封包進來:

image

可以看到 MacBook 嘗試連過去時,並沒有收到被拒絕的訊息,而是過一段時間後出現 Operation timed out 的訊息,因為 Ubuntu 虛擬機的防火牆把這個封包丟掉而不處理它:

image

Test 2 - REJECT ssh 連線

若用 iptables 將 ssh 連線請求的封包設定為 REJECT

image

可以看到 MacBook 發送 ssh 連線請求後,會收到 Connection refused 的訊息:

image

Test 3 - 只允許特定 IP 的 ssh 連線

接下來,在 LAN 裡面多加一個新的裝置,也就是我的 Marvell ESPRESSObin v7 開發板~他被分配到的 IP 是 192.168.50.141:

image

假設要設定只允許我的開發板的 IP 可以 ssh 連到 Ubuntu 虛擬機,不允許其他的 IP 來進來,就需要依序對 Ubuntu 虛擬機做以下設定:

  1. 允許 192.168.50.141 的 ssh 連線請求:
    ​​​​iptables -t filter -A INPUT -p tcp --dport 22 -s 192.168.50.141 -j ACCEPT
    
  2. 其他的 ssh 連線請求全部都拒絕:
    ​​​​iptables -t filter -A INPUT -p tcp --dport 22 -j REJECT
    

這時候 rule 的順序就很重要!如果這兩條規則設定的順序反了,那封包一進到 INPUT chain 的 filter table 就會先比對到「拒絕所有 ssh 連線請求的規則」,所以會連來自 192.168.50.141 的連線請求都一併拒絕喔~

以下是測試的結果~左上角的視窗是對 Ubuntu 虛擬機做 iptables 的設定,右下角的視窗則是開發板可以 ssh 連過去:

image

我的 MacBook 被拒絕,無法 ssh 連過去~

image

若將這兩條規則的順序設反了,那就會連開發板都沒辦法連過去喔:

image
image

其他 iptables 相關設定

References