### 概念簡介 **名稱** Netfilter/iptables模組有兩部分組成: Netfilter框架以及iptables,iptables又分為iptables(核心空間)和iptables命令列工具(使用者空間); Netfilter/iptables模組 在一般使用者眼裡簡稱為iptables,但其實在相關開發者眼裡更傾向於叫作Netfilter,從專案官網地址也看得出來: https://netfilter.org/ **作用** 用於資料包處理,比如:報文的轉發、過濾、修改,網路地址轉換等功能,是一種軟體防火牆。 ### iptables基本原理 #### 基本工作流程 **基本工作流程圖** ![](https://img2020.cnblogs.com/blog/2144409/202011/2144409-20201105144929336-1442042192.png) 資料包沿著鏈傳輸,iptables有5個鏈:PREROUTING, INPUT, FORWORD, OUTPUT, POSTROUTING,可以想象成5個關卡,每個關卡都有很多規則,也可能沒有規則。 工作流程如下: 1、當一個數據包進入網絡卡後,它會先進入PREROUTING,然後根據目的地址進行路由決策,如果目的地址是本機,則走INPUT,不是本機則走FORWARD,然後再走POSTROUTING轉出去。 2、進入INPUT的資料包會轉給本地程序,程序處理後,會發送新的資料包,走OUTPUT,然後經過POSTROUTING轉出去。 3、當然上面的過程每經過一個鏈,都要按照鏈中的規則順序來匹配鏈中的規則,只要遇到一個匹配的規則就按照這個規則進行處理,後面的規則對這個資料就不再起作用。 #### 簡單的規則新增 只有本地socket是使用者態,其餘都是核心處理。平時我們加iptables規則,就是加到各個鏈中的,我們建立一個容器進行測試,容器中我已經安裝好了iptables,直接使用iptables命令即可: ```shell #首先啟動一個容器 [
[email protected] ~]# docker run -itd --name "cos8_test" --cap-add=NET_ADMIN centos:base /bin/bash bd0c29186387b01ae64514050b3b4b804babc988f3dbc52c0cfe6eeac115d1b2 ``` >注:要修改容器網路,容器啟動時需加上 --cap-add=NET_ADMIN,不然容器中執行iptables命令會報錯: > >(nf_tables): Could not fetch rule set generation id: Permission denied (you must be root) 檢視iptables規則,可以看到當前沒有任何策略 ```shell [
[email protected] ~]# docker ps | grep cos8 bd0c29186387 centos:base "/bin/bash" 21 hours ago Up 21 hours cos8_test [
[email protected] ~]# docker exec -it bd0 bash [
[email protected] /]# [
[email protected] /]# iptables -nL Chain INPUT (policy ACCEPT) target prot opt source destination Chain FORWARD (policy ACCEPT) target prot opt source destination Chain OUTPUT (policy ACCEPT) target prot opt source destination ``` 建立一個規則:拒絕所有訪問本機80埠的tcp資料包。 ```shell [
[email protected] /]# iptables -A INPUT -p tcp --dport 80 -j DROP [
[email protected] /]# [
[email protected] /]# iptables -nL Chain INPUT (policy ACCEPT) target prot opt source destination DROP tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:80 Chain FORWARD (policy ACCEPT) target prot opt source destination DROP tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:80 Chain OUTPUT (policy ACCEPT) target prot opt source destination DROP tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:80 ``` 這裡有個小插曲:可以看到我只在INPUT鏈中添加了規則,但是怎麼FORWARD和OUTPUT鏈中也有這條規則,隨後我手動刪了INPUT鏈中的規則,然後FORWARD和OUTPUT鏈中的規則也隨之消失了,此容器的OS版本和核心資訊如下 ```shell [
[email protected] /]# cat /etc/redhat-release CentOS Linux release 8.2.2004 (Core) [
[email protected] /]# [
[email protected] /]# uname -a Linux bd0c29186387 3.10.0-1127.13.1.el7.x86_64 #1 SMP Tue Jun 23 15:46:38 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux ``` 之前沒用過centos8,考慮到可能是OS更新了netfilter模組,於是換成了一個centos7.8.2003的容器測試了一下,發現新增規則是符合預期的,如下 ```shell [
[email protected] /]# docker run -itd --name "cos7" --cap-add=NET_ADMIN centos7:base /bin/bash c951c0a9d34d8e43a56e43872294ab5ab6a1504b365721238178de134e8d3bde [
[email protected] /]# [
[email protected] /]# docker exec -it cos7 bash [
[email protected] /]# [
[email protected] /]# iptables -nL Chain INPUT (policy ACCEPT) target prot opt source destination Chain FORWARD (policy ACCEPT) target prot opt source destination Chain OUTPUT (policy ACCEPT) target prot opt source destination [
[email protected] /]# [
[email protected] /]# iptables -A INPUT -p tcp --dport 80 -j DROP [
[email protected] /]# [
[email protected] /]# iptables -nL Chain INPUT (policy ACCEPT) target prot opt source destination DROP tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:80 Chain FORWARD (policy ACCEPT) target prot opt source destination Chain OUTPUT (policy ACCEPT) target prot opt source destination ``` >拒絕可以使用DROP,也可以使用REJECT關鍵字,DROP不會給客戶端返回任何資訊,所以客戶端看到的情況就是連線超時,很難判斷是防火牆原因還是網路裝置故障等原因。 > >而REJECT則明確返回給客戶端一個拒絕的資訊,客戶端會知道我是被防火牆拒絕了。 > >可根據場景使用,REJECT更適合除錯,DROP抗攻擊上面更安全些。 後面使用centos7的容器作為測試,先不管centos8更新了啥。 #### 四表五鏈 上面我新增的規則命令如下: ```shell iptables -A INPUT -p tcp --dport 80 -j DROP ``` 但這只是簡寫後的,稍微寫全些如下,其實還可以更全些,暫不說明。 ```shell iptables -t filter -A INPUT -s 0.0.0.0/0 -p tcp -d 0.0.0.0/0 --dport 80 -j DROP ``` -t : 指定表,這裡是filter表,規則會新增到filter表中。 -s : 指定源地址,0.0.0.0/0是指所有IP。 -d : 指定目的地址。 --dport : 指定目的埠。 -j : 指定處理動作,這裡是DROP,也就是丟棄。 **表的概念** 上面提到了filter表,那什麼是表呢? 我們加規則,加到每個鏈中,每個鏈中的規則有很多,有一部分規則是相似的,比如,有一部分都是埠的過濾,有一部分都是報文的修改,根據這些規則的型別,把相似的規則放在一起,這些放在一起的規則的集合稱為表。 那不同的規則的集合就放在了不同的表中,總共有4種表,也就是4種規則: filter表:負責過濾功能; nat表:network address translation,網路地址轉換功能; mangle表:拆解、修改、並重新封裝報文; raw表:關閉nat表上啟用的連線追蹤機制; 因為每個鏈中都有不同規則,所以表存在於每一個鏈中,但不是每個鏈都有這4種表, PREROUTING 的規則可以存在於:raw表,mangle表,nat表。 INPUT 的規則可以存在於:mangle表,filter表,nat表(centos7中有nat表,centos6中沒有)。 FORWARD 的規則可以存在於:mangle表,filter表。 OUTPUT 的規則可以存在於:raw表mangle表,nat表,filter表。 POSTROUTING 的規則可以存在於:mangle表,nat表。 表的處理優先順序如下: raw --> mangle --> nat --> filter 所以我們一開始iptables的基本工作流程圖可以更詳細些 ![](https://img2020.cnblogs.com/blog/2144409/202011/2144409-20201105145148107-293486647.png) 其實還可以再詳細些,我們單獨拿一個鏈出來,比如PREROUTING鏈,大概是如下情況,這些規則組和在了一起便成了一條鏈。 ![](https://img2020.cnblogs.com/blog/2144409/202011/2144409-20201105145234302-288024359.png) 所以,我們上面加的禁止訪問本機80埠的規則是存放在filter表中的,我們來檢視下filter表中的規則,可以看到我們新增的規則,netfilter預設把80埠繫結為http。 ```shell [
[email protected] /]# iptables -L -t filter Chain INPUT (policy ACCEPT) target prot opt source destination DROP tcp -- anywhere anywhere tcp dpt:http Chain FORWARD (policy ACCEPT) target prot opt source destination Chain OUTPUT (policy ACCEPT) target prot opt source destination ``` #### iptables常用命令舉例 **檢視規則** ```shell 按表檢視: iptables -L -t table 按照鏈檢視: iptables -nL INPUT ``` **設定鏈的預設規則** ```shell #INPUT鏈預設拒絕所有資料包 iptables -P INPUT DROP #OUTPUT預設允許所有資料包出去 iptables -P INPUT ACCEPT ``` **清空表中的規則** ```shell #清空nat表中PREROUTING鏈的規則 iptables -t nat -F PREROUTING #清空filter表中所有鏈的規則 iptables -t filter -F #清空使用者自定義的表規則 iptables -X ``` **刪除某一條規則** ```shell #可以通過編號來刪除 #--line-number在規則前面顯示了編號 [
[email protected] /]# iptables -nL --line-number Chain INPUT (policy ACCEPT) num target prot opt source destination 1 DROP tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:80 Chain FORWARD (policy ACCEPT) num target prot opt source destination Chain OUTPUT (policy ACCEPT) num target prot opt source destination [
[email protected] /]# [
[email protected] /]# iptables -D INPUT 1 #也可以直接刪除規則 #下面命令中,-D後面的全是匹配條件,凡是某條規則中全部匹配這些的就刪除 [
[email protected] /]# iptables -D INPUT -p tcp --dport 80 -j DROP ``` **禁ping** ```shell #禁止別人ping自己,但是自己可以ping別人 #type 8: 表示ping包請求流量 #type 0: 表示ping包響應流量 iptables -A INPUT -p icmp --icmp-type 0 -j DROP iptables -A OUTPUT -p icmp --icmp-type 8 -j DROP #禁止別人ping自己,也禁止自己ping別人 iptables -A INPUT -p icmp -m icmp --icmp-type any -j DROP #也可以改引數實現禁ping echo "1" > /proc/sys/net/ipv4/icmp_echo_ignore_all ``` **轉發** ```shell #開啟轉發功能 echo 1 > /proc/sys/net/ipv4/ip_forward #對於外部訪問自己80埠的流量全部轉到172.17.0.4的80埠, #xxx.xxx.xxx.xx代表本機的IP iptables -t nat -I PREROUTING -d xxx.xxx.xxx.xx -p tcp --dport 80 -j DNAT --to-destination 172.17.0.4:80 #對於從本機出去的流量,源ip全部轉換為172.17.0.4 iptables -t nat -A POSTROUTING -p tcp -j SNAT --to-source 172.17.0.4 ``` **針對連結狀態作規則** ```shell #NEW 使用者發起一個全新的請求 #ESTABLISHED 對一個全新的請求進行迴應 #RELATED 兩個完整連線之間的相互關係,一個完整的連線,需要依賴於另一個完整的連線。 #INVALID 無法識別的狀態。 iptables -A INPUT -m state –state ESTABLISHED,RELATED -j ACCEPT ``` 先這