從零認(rèn)識 iptables
原文:https://morven.life/notes/the_knowledge_of_iptables/
在使用Linux的過程中,很多人和我一樣經(jīng)常接觸iptables,但卻只知道它是用來設(shè)置Linux防火墻的工具,不知道它具體是怎么工作的。今天,我們就從零開始認(rèn)識一下Linux下iptables的具體工作原理。
iptables是Linux上常用的防火墻軟件netfilter項目的一部分,所以要講清楚iptables,我們先理一理什么是防火墻?
什么是防火墻
簡單來說,防火墻是一種網(wǎng)絡(luò)隔離工具,部署于主機(jī)或者網(wǎng)絡(luò)的邊緣,目標(biāo)是對于進(jìn)出主機(jī)或者本地網(wǎng)絡(luò)的網(wǎng)絡(luò)報文根據(jù)事先定義好的規(guī)則做匹配檢測,規(guī)則匹配成功則對相應(yīng)的網(wǎng)絡(luò)報文做定義好的處理(允許,拒絕,轉(zhuǎn)發(fā),丟棄等)。防火墻根據(jù)其管理的范圍來分可以將其劃分為主機(jī)防火墻和網(wǎng)絡(luò)防火墻;根據(jù)其工作機(jī)制來區(qū)分又可分為包過濾型防火墻(netfilter)和代理服務(wù)器(Proxy)。我們接下來在這篇筆記中主要說說**包過濾型防火墻(netfilter)。
Note: 也有人將tcp_warrpers也劃分為防火墻的一種,它是根據(jù)服務(wù)程序軟件的名稱來處理網(wǎng)絡(luò)數(shù)據(jù)包的工具。
包過濾型防火墻的工作原理
包過濾型防火墻主要依賴于Linux內(nèi)核軟件netfilter,它是一個Linux內(nèi)核“安全框架”,而iptables是內(nèi)核軟件netfilter的配置工具,工作于用戶空間。iptables/netfilter組合就是Linux平臺下的過濾型防火墻,并且這個防火墻軟件是免費的,可以用來替代商業(yè)防火墻軟件,來完成網(wǎng)絡(luò)數(shù)據(jù)包的過濾,修改,重定向以及網(wǎng)絡(luò)地址轉(zhuǎn)換(nat)等功能。
Note: 在有些Linux發(fā)行版上,我們可以使用
systemctl start iptables來啟動iptables服務(wù),但需要指出的是,iptables 并不是也不依賴于守護(hù)進(jìn)程,它只是利用Linux內(nèi)核提供的功能。
Linux網(wǎng)絡(luò)管理員通過配置iptables規(guī)則以及對應(yīng)的網(wǎng)路數(shù)據(jù)包處理邏輯,當(dāng)網(wǎng)絡(luò)數(shù)據(jù)包符合這樣的規(guī)則時,就做執(zhí)行預(yù)先定義好的相應(yīng)的處理邏輯??梢院唵蔚目偨Y(jié)為:
IF network_pkg match rule; THEN
handler
FI
其中規(guī)則可以包括匹配數(shù)據(jù)報文的源地址,目的地址,傳輸層協(xié)議(TCP/UDP/ICMP/..)以及應(yīng)用層協(xié)議(HTTP/FTP/SMTP/..)等,處理邏輯就是根據(jù)規(guī)則所定義的方法來處理這些數(shù)據(jù)包,如放行(accept),拒絕(reject),丟棄(drop)等。
而netfilter是工作于內(nèi)核空間當(dāng)中的一系列網(wǎng)絡(luò)(TCP/IP)協(xié)議棧的鉤子(hook),為內(nèi)核模塊在網(wǎng)絡(luò)協(xié)議棧中的不同位置注冊回調(diào)函數(shù)(callback)。也就是說,在數(shù)據(jù)包經(jīng)過網(wǎng)絡(luò)協(xié)議棧的不同位置時做相應(yīng)的由iptables配置好的處理邏輯。netfilter中的五個鉤子(這里也稱為五個關(guān)卡)PRE_ROUTING,INPUT,F(xiàn)ORWARD,OUTPUT,POST_ROUTING,網(wǎng)絡(luò)數(shù)據(jù)包的流向圖如下圖所示:

當(dāng)主機(jī)/網(wǎng)絡(luò)服務(wù)器網(wǎng)卡收到一個數(shù)據(jù)包之后進(jìn)入內(nèi)核空間的TCP/IP協(xié)議棧進(jìn)行層層解封裝
剛剛進(jìn)入網(wǎng)絡(luò)層的數(shù)據(jù)包通過PRE_ROUTING關(guān)卡時,要進(jìn)行一次路由選擇,當(dāng)目標(biāo)地址為本機(jī)地址時,數(shù)據(jù)進(jìn)入INPUT,非本地的目標(biāo)地址進(jìn)入FORWARD(需要本機(jī)內(nèi)核支持IP_FORWARD),所以目標(biāo)地址轉(zhuǎn)換通常在這個關(guān)卡進(jìn)行
INPUT:經(jīng)過路由之后送往本地的數(shù)據(jù)包經(jīng)過此關(guān)卡,所以過濾INPUT包在此點關(guān)卡進(jìn)行
FORWARD:經(jīng)過路由選擇之后要轉(zhuǎn)發(fā)的數(shù)據(jù)包經(jīng)過此關(guān)卡,所以網(wǎng)絡(luò)防火墻通常在此關(guān)卡配置
OUTPUT:由本地用戶空間應(yīng)用進(jìn)程產(chǎn)生的數(shù)據(jù)包過此關(guān)卡,所以O(shè)UTPUT包過濾在此關(guān)卡進(jìn)行
POST_ROUTING:剛剛通過FORWARD和OUTPUT關(guān)卡的數(shù)據(jù)包要通過一次路由選擇由哪個接口送往網(wǎng)絡(luò)中,經(jīng)過路由之后的數(shù)據(jù)包要通過POST_ROUTING此關(guān)卡,源地址轉(zhuǎn)換通常在此點進(jìn)行
上面提到的這些處于網(wǎng)絡(luò)(TCP/IP)協(xié)議棧的“關(guān)卡”,在iptables的術(shù)語里叫做“鏈(chain)”,內(nèi)置的鏈包括上面提到的5個:
PreRouting
Forward
Input
Output
PostRouting
一般的場景里面,數(shù)據(jù)包的流向基本是:
到本主機(jī)某進(jìn)程的報文:PreRouting -> Input -> Process -> Output -> PostRouting
由本主機(jī)轉(zhuǎn)發(fā)的報文:PreRouting -> Forward -> PostRouting
iptables的四表五鏈
iptables默認(rèn)有五條鏈(chain),分別對應(yīng)上面提到的五個關(guān)卡,PRE_ROUTING,INPUT,F(xiàn)ORWARD,OUTPUT,POST_ROUTING,這五個關(guān)卡分別由netfilter的五個鉤子函數(shù)來觸發(fā)。但是,為什么叫做“鏈”呢?我們知道,iptables/netfilter防火墻對經(jīng)過的數(shù)據(jù)包進(jìn)行“規(guī)則”匹配,然后執(zhí)行相應(yīng)的“處理”。當(dāng)報文經(jīng)過某一個關(guān)卡時,這個關(guān)卡上的“規(guī)則”不止一條,很多條規(guī)則會按照順序逐條匹配,將在此關(guān)卡的所有規(guī)則組織稱“鏈”就很適合,對于經(jīng)過的數(shù)據(jù)包按照順序逐條匹配“規(guī)則”。

另外一個問題是,每一條“鏈”上的一串規(guī)則里面有些功能是相似的,比如,A類規(guī)則都是對IP或者端口進(jìn)行過濾,B類規(guī)則都是修改報文,我們考慮能否將這些功能相似的規(guī)則放到一起,這樣管理iptables規(guī)則會更方便。iptables把具有相同功能的規(guī)則集合叫做“表”,并且定一個四種表:
filter:負(fù)責(zé)過濾功能;與之對應(yīng)的內(nèi)核模塊是iptables_filter
nat:Network Address Translation,網(wǎng)絡(luò)地址轉(zhuǎn)換功能,典型的比如SNAT,DNAT;與之對應(yīng)的內(nèi)核模塊是iptables_nat
mangle:解包報文,修改并封包;與之對應(yīng)的內(nèi)核模塊是iptables_mangle
raw:關(guān)閉nat表上啟用的連接追蹤機(jī)制;與之對應(yīng)的內(nèi)核模塊是iptables_raw
這樣,Linux網(wǎng)絡(luò)管理員所定義的iptables“規(guī)則”都存在于這四張表中。
但是,需要注意的是,并不是所有的“鏈”都具有所有類型的“規(guī)則”,也就是說,某個特定表中的“規(guī)則”注定不能應(yīng)用到某些“鏈”中,比如,用作地址轉(zhuǎn)換功能的nat表里面的“規(guī)則”據(jù)不能存在于FORWARD“鏈”中。下面,我們就詳細(xì)的列舉iptables的“鏈表”關(guān)系:
我們先說一下,每個“鏈”(關(guān)卡)都擁有那些功能的規(guī)則:
| 鏈 | 表 |
|---|---|
| PreRouting | raw, mangle, nat |
| Forward | mangle, filter |
| Input | mangle, filter, nat |
| Output | raw, mangle, filter, nat |
| PostRouting | mangle, nat |
在實際使用iptables配置規(guī)則時,我們往往是以“表”為入口制定“規(guī)則”,所以我們將“鏈表”關(guān)系轉(zhuǎn)化成“表鏈”關(guān)系:
| 表 | 鏈 |
|---|---|
| raw | PreRouting, Output |
| mangle | PreRouting, Forward, Input, Output, PostRouting |
| filter | Forward, Input, Output |
| nat | PreRouting, Input, Output, PostRouting |
還需要注意的一點兒是,因為數(shù)據(jù)包經(jīng)過一個關(guān)卡的時候,會將“鏈”中所有的“規(guī)則”都按照順序逐條匹配,為相同功能的“規(guī)則”屬于同一個“表”。那么,哪些“表”中的規(guī)則會放到“鏈”的最前面執(zhí)行呢?這時候就涉及一個優(yōu)先級的問題。iptables為我們提供了四張“表”,當(dāng)它們處于同一條“鏈”的時候,它們的執(zhí)行優(yōu)先級關(guān)系如下:
raw -> mangle -> nat -> filter
實際上,網(wǎng)絡(luò)管理員還可以使用iptables創(chuàng)建自定義的鏈,將針對某個應(yīng)用層序所設(shè)置的規(guī)則放到這個自定義鏈中,但是自定義的鏈不能直接使用,只能被某個默認(rèn)的鏈當(dāng)作Action去調(diào)用。可以這樣說,自定義鏈?zhǔn)恰岸獭辨?,這些“短”鏈并不能直接使用,而是需要和iptables上的內(nèi)置鏈一起配合,被內(nèi)置鏈“引用”。
數(shù)據(jù)包經(jīng)過過濾型防火墻的流程
有了前面的介紹我們可以總結(jié)出如下圖所示的數(shù)據(jù)包在經(jīng)過過濾型防火墻的流程圖:

iptables規(guī)則
前面我們提到過,iptables規(guī)則由兩部分組成,報文的匹配條件和匹配到之后的處理動作。
匹配條件:根據(jù)協(xié)議報文特征指定匹配條件,基本匹配條件和擴(kuò)展匹配條件
處理動作:內(nèi)建處理機(jī)制由iptables自身提供的一些處理動作
同時,網(wǎng)絡(luò)管理員還可以使用iptables創(chuàng)建自定義的鏈,附加到iptables的四個內(nèi)置鏈。
Note: 報文不會經(jīng)過自定義鏈,只能在內(nèi)置鏈上通過規(guī)則進(jìn)行引用后生效,也就是說自定義鏈為規(guī)則的一個處理動作的集合。
設(shè)置iptables規(guī)則時需要考量的要點:
根據(jù)要實現(xiàn)哪種功能,判斷添加在那張“表”上
根據(jù)報文流經(jīng)的路徑,判斷添加在那個“鏈”上
到本主機(jī)某進(jìn)程的報文:PreRouting -> Input -> Process -> Output -> PostRouting
由本主機(jī)轉(zhuǎn)發(fā)的報文:PreRouting -> Forward -> PostRouting
對于每一條“鏈”上其“規(guī)則”的匹配順序,排列好檢查順序能有效的提高性能,因此隱含一定的法則:
同類規(guī)則(訪問同一應(yīng)用),匹配范圍小的放上面
不同類規(guī)則(訪問不同應(yīng)用),匹配到報文頻率大的放上面
將那些可由一條規(guī)則描述的多個規(guī)則合并為一個
設(shè)置默認(rèn)策略
同時,也一定要注意,在遠(yuǎn)程連接主機(jī)配置防火墻時注意:
不要把“鏈”的默認(rèn)策略修改為拒絕,因為有可能配置失敗或者清除所有策略后無法遠(yuǎn)程到服務(wù)器,而是盡量使用規(guī)則條目配置默認(rèn)策略
為防止配置失誤策略把自己也拒掉,可在配置策略時設(shè)置計劃任務(wù)定時清除策略,當(dāng)確定無誤后,關(guān)閉該計劃任務(wù)
iptables語法
iptables語法結(jié)構(gòu)如下所示:
iptables(選項)(參數(shù))
選項:
# 通用匹配:源地址目標(biāo)地址的匹配
-p:指定要匹配的數(shù)據(jù)包協(xié)議類型;
-s, --source [!] address[/mask] :把指定的一個/一組地址作為源地址,按此規(guī)則進(jìn)行過濾。當(dāng)后面沒有 mask 時,address 是一個地址,比如:192.168.1.1;當(dāng) mask 指定時,可以表示一組范圍內(nèi)的地址,比如:192.168.1.0/255.255.255.0。
-d, --destination [!] address[/mask] :地址格式同上,但這里是指定地址為目的地址,按此進(jìn)行過濾。
-i, --in-interface [!] <網(wǎng)絡(luò)接口name> :指定數(shù)據(jù)包的來自來自網(wǎng)絡(luò)接口,比如最常見的 eth0 。注意:它只對 INPUT,F(xiàn)ORWARD,PREROUTING 這三個鏈起作用。如果沒有指定此選項, 說明可以來自任何一個網(wǎng)絡(luò)接口。同前面類似,"!" 表示取反。
-o, --out-interface [!] <網(wǎng)絡(luò)接口name> :指定數(shù)據(jù)包出去的網(wǎng)絡(luò)接口。只對 OUTPUT,F(xiàn)ORWARD,POSTROUTING 三個鏈起作用。
# 查看管理命令
-L, --list [chain] 列出鏈 chain 上面的所有規(guī)則,如果沒有指定鏈,列出表上所有鏈的所有規(guī)則。
# 規(guī)則管理命令
-A, --append chain rule-specification 在指定鏈 chain 的末尾插入指定的規(guī)則,也就是說,這條規(guī)則會被放到最后,最后才會被執(zhí)行。規(guī)則是由后面的匹配來指定。
-I, --insert chain [rulenum] rule-specification 在鏈 chain 中的指定位置插入一條或多條規(guī)則。如果指定的規(guī)則號是1,則在鏈的頭部插入。這也是默認(rèn)的情況,如果沒有指定規(guī)則號。
-D, --delete chain rule-specification -D, --delete chain rulenum 在指定的鏈 chain 中刪除一個或多個指定規(guī)則。
-R num:Replays替換/修改第幾條規(guī)則
# 鏈管理命令(這都是立即生效的)
-P, --policy chain target :為指定的鏈 chain 設(shè)置策略 target。注意,只有內(nèi)置的鏈才允許有策略,用戶自定義的是不允許的。
-F, --flush [chain] 清空指定鏈 chain 上面的所有規(guī)則。如果沒有指定鏈,清空該表上所有鏈的所有規(guī)則。
-N, --new-chain chain 用指定的名字創(chuàng)建一個新的鏈。
-X, --delete-chain [chain] :刪除指定的鏈,這個鏈必須沒有被其它任何規(guī)則引用,而且這條上必須沒有任何規(guī)則。如果沒有指定鏈名,則會刪除該表中所有非內(nèi)置的鏈。
-E, --rename-chain old-chain new-chain :用指定的新名字去重命名指定的鏈。這并不會對鏈內(nèi)部照成任何影響。
-Z, --zero [chain] :把指定鏈,或者表中的所有鏈上的所有計數(shù)器清零。
-j, --jump target <指定目標(biāo)> :即滿足某條件時該執(zhí)行什么樣的動作。target 可以是內(nèi)置的目標(biāo),比如 ACCEPT,也可以是用戶自定義的鏈。
-h:顯示幫助信息;
參數(shù)
| 參數(shù) | 作用 |
|---|---|
| -P | 設(shè)置默認(rèn)策略:iptables -P INPUT (DROP) |
| -F | 清空規(guī)則鏈 |
| -L | 查看規(guī)則鏈 |
| -A | 在規(guī)則鏈的末尾加入新規(guī)則 |
| -I | num 在規(guī)則鏈的頭部加入新規(guī)則 |
| -D | num 刪除某一條規(guī)則 |
| -s | 匹配來源地址IP/MASK,加嘆號”!“表示除這個IP外 |
| -d | 匹配目標(biāo)地址 |
| -i | 網(wǎng)卡名稱 匹配從這塊網(wǎng)卡流入的數(shù)據(jù) |
| -o | 網(wǎng)卡名稱 匹配從這塊網(wǎng)卡流出的數(shù)據(jù) |
| -p | 匹配協(xié)議,如tcp,udp,icmp |
| –dport num | 匹配目標(biāo)端口號 |
| –sport num | 匹配來源端口號 |
命令選項輸入順序:
iptables -t 表名 <-A/I/D/R> 規(guī)則鏈名 [規(guī)則號] <-i/o 網(wǎng)卡名> -p 協(xié)議名 <-s 源IP/源子網(wǎng)> --sport 源端口 <-d 目標(biāo)IP/目標(biāo)子網(wǎng)> --dport 目標(biāo)端口 -j 動作
對于iptables命令的細(xì)節(jié),請參考:https://wangchujiang.com/linux-command/c/iptables.html
- END -
?推薦閱讀? 記一次線上商城系統(tǒng)高并發(fā)的優(yōu)化
部署一套完整的Kubernetes高可用集群(二進(jìn)制)
點亮,服務(wù)器三年不宕機(jī)

