iptables實用知識 ,一文學會配置linux防火牆

wyf368發表於2020-09-08

iptables實用知識 ,一文學會配置linux防火牆, 以自己實際使用情況來總結了iptables常用知識點

iptables 官方man文件: https://linux.die.net/man/8/iptables

iptables中文指南: https://www.frozentux.net/iptables-tutorial/cn/iptables-tutorial-cn-1.1.19.html
(比較詳細,講了一些技術的實現原理, 版本舊,和centos7有點差異,我知道的是NAT時指定IP範圍,centos7不再支援自動迴圈使用指定的IP範圍,猜測只會使用第一個IP,沒做實驗)

說明:

本文測試基於系統環境: centOS 7

本文以實用的角度理解防火牆,不是官方文件的知識點羅列。

1.防火牆的概念

計算機領域中防火牆一般指的是網路(特指TCP/IP網路)防火牆,根據TCP/IP網路模型,防火牆可以處在不同的層,主要兩種:普通的網路層防火牆,上層的應用防火牆,如WAF。

linux和windows作業系統中的防火牆,我們叫網路層防火牆,準確的說應該是傳輸層的,因為會處理TCP, UDP埠號,而不僅僅是IP。

網路層防火牆的作用: 包過濾,根據源IP,埠,目標IP埠,過濾資料包,允許通行或者禁止通行。

2. linux防火牆

linux防火牆由核心netfiter實現,使用者不能直接操作核心,提供了防火牆配置工具iptables和現在centos 7版本開始的firewalld工具,這兩個工具只是防火牆的配置介面,核心都是netfiter。

iptables配置命令複雜,原始,難度較大,但支援配置全部的功能。

而firewalld做了更高階的封裝,配置命令簡單,但無法實現複雜的配置,要實現複雜的配置需要用rich-rule(富規則),以及更高階的direct命令(和iptables命令幾乎一模一樣了)。

iptables的功能:

  1. iptables是網路層防火牆,必然支援基於ip和埠的過濾規則;

  2. 預設包過濾是沒有狀態的,即每個進出的資料包均視為一個獨立的資料包。

  3. 支援擴充套件模組,通過擴充套件模組可以實現許多高階的功能 ,常用如下:

    • 支援基於狀態的,
    • 連續ip
    • 一條命令匹配多埠
    • 連線數
    • 速率限制
    • 基於時間的規則
    • 應用層資料過濾 ( 只的簡單的字串匹配)
  4. iptables防火牆的功能上還增加了修改資料包的功能,修改資料包最廣泛的應用應該是NAT了, iptables支援DNAT, SNAT , 如果同時使用DNAT, SNAT可以實現埠轉發的功能(後面有例項說明)。

    iptables 的NAT是有狀態的NAT ,只需要配置發起請求時的轉換規則,而返回的資料會自動對應轉換回來。

  5. 其它更高階的修改資料包的應用沒研究過。

3.linux資料包處理流程

任何一個網路主機處理資料必須有以下流程:

​ 1.接收到資料:網路卡接收到資料--> 路由判斷資料是否是本機->1,本機:轉給相應的上層應用 ->2, 目標不是本機, 再路由判斷通過哪個網路卡轉發出去-->發出去

如果不允許資料轉發,資料目標不是本機則直接丟棄。

​ 2.本機上層應用要傳送資料出去: 應用資料轉給核心--> 路由判斷從哪個網口傳送出去-->發出去

3.1 linux 防火牆將以上流程,固定區分為5個流程節點

  1. prerouting: 網路卡收到資料
  2. input : 轉發資料給本機上層應用
  3. forward: 目標非本機資料進入轉發流程
  4. output: 本機應用發出的資料
  5. postrouting: 資料從網路卡流出

3.2 資料流程

  1. 接收到目標為本機的資料: prerouting--> input
  2. 接收到目標不是本機的資料 ,prerouting--> forward --> postrouting
  3. 本機發出的資料:output --> postrouting

4 linux防火牆的實現機制

實現原理:在不同資料流程節點掛勾子函式,過濾資料, 符合的放回資料包流中,不符合條件的資料包從流程移除。

4.1 iptables五鏈

iptables將資料轉發的5個流程節點勾子依次對應為5個鏈,全部為大寫字母:

  1. PREROUTING
  2. INPUT
  3. FORWARD
  4. OUTPUT
  5. POSTROUTING

4.2 iptables四表

iptables將功能分為4類,即為iptables四表 :

實際有5個表,而不是我們常說的4表,還有一個表是security,本文不討論這個表。

  1. filter : 包過濾防火牆
  2. nat : 地址和埠轉換
  3. mangle : 資料包修改
  4. raw : 不帶連線狀態的nat

4.3 iptables 4表5鏈的關係

不同的表可以應用到不同的鏈上,

  1. filter: INPUT 、FORWARD 、OUTPUT

    • 過濾目標或本地為源的資料:接收-INPUT 、發出-OUTPUT

    • 過濾經本機轉發的資料: FORWARD

  2. nat : PREROUTING 、INPUT 、OUTPUT 、 POSTROUTING

    • 修改本機上層應用發出去的資料: OUTPUT

    2.1 SNAT: INPUT、 POSTROUTING

    必須先路由, 所以不能在PREROUTING 做,在從本機發出前的最後一步再修改源IP為本機出介面IP,如果在路由前即剛接收到資料就修改源埠為出介面的IP是不合理的:

    1. 主機自己出介面IP的資料,從另一個網口接收到,網路環路才會出現這種情況;
    2. 源IP變為出介面的IP,之後的處理流程看不到真實的源埠IP, 防火牆策略無法設定;
    3. 之後的流程,比如forward 看到源埠是自身的介面 ,按照核心資料轉發流程,本機應用發出的資料不應該進入forward流程。

    2.2 DNAT: OUTPUT 、 PREROUTING

    必須在路由前做DNAT, 這個好理解,只有DNAT修改資料包為真實的目標IP ,後面的路由才能正確選擇,因為源IP埠沒有修改,也不會影響之後流程處理。

    2.3 總結: 一般 SNAT在POSTROUTING做,SNAT在PREROUTING 做 , OUTPUT是本機發出的資料,沒怎麼見過需要用到NAT的場景。

    2.4 同時進行SNAT和DNAT

  3. mangle : 5鏈均適用, 沒用過,不討論

  4. raw :PREROUTING 、 OUTPUT,沒用過,不討論

4.4 表的優先順序

同一鏈上,如果有多個表的配置規則,優先處理次序依次為raw --> mangle --> nat --> filter

5. iptables 命令

iptables 【-t 表名 】 操作 鏈名 【規則編號】 匹配規則 -j 處理動作

5.1 表 名

可選,不配置預設是 filter,

  • filter
  • nat
  • mangle
  • raw

5.2 操作

  • -A 鏈中末尾新增規則
  • -I 鏈名【規則編號】 如果沒有規則編號,插入到第一條的位置,有規則編號,插入到指定編號位置,原編號及之後的規則依次下移
  • -R 鏈名 規則編號 必須輸入規則編號,替換該編號的規則
  • -D 鏈名 規則編號 必須輸入規則編號,刪除該編號的規則

5.3 鏈名

不同表只能使用允許的鏈名

  1. PREROUTING
  2. INPUT
  3. FORWARD
  4. OUTPUT
  5. POSTROUTING

5.4 匹配條件

iptables命令最複雜的部分就在匹配條件這部分

一級條件引數形式 -option , 一級引數可能包含二級引數, 二級引數必須緊跟在主引數後寫, 形式為 --option 兩個 “--”

  1. TCP/IP匹配條件,IP 和埠號

    • -s 源IP IP可以是單個IP , 也加掩碼 配置網段 如192.168.1.1/24, 但不能是連續ip, 如 192.168.1.1-192.168.1.20 (連續ip需要擴充套件模組)

    • -d 目標IP IP可以是單個IP , 也加掩碼 配置網段 如192.168.1.1/24, 但不能是連續ip, 如 192.168.1.1-192.168.1.20

  2. -i 網路卡名 資料進入的網路卡

  3. -0 網路卡名 資料流出的網路卡

  4. -p [!]協議名 tcp 、udp、icmp 等等, 指定協議名後才能進一步指定埠號,其實-p 會自動載入相應協議的擴充套件模組,指定埠號是擴充套件模組的功能。

    • --dport 源埠號 [!]port[:port] ,--source-port 的簡寫,可以是埠範圍

    • --sport 目標埠號 port[:port] --destination-port的簡寫, 可以是埠範圍

    • --tcp-flags [!] mask comp

    • mask comp 例 SYN,ACK,FIN,RST SYN 匹配 SYN標誌必須為1, ACK,FIN,RST必須為0, 其它標誌不檢查的資料包。

  5. -m 擴充套件模組

    1. state 基於狀態的匹配規則, 與特定的協議沒有關係,可以是TCP, UDP , 狀態也不是指TCP協議連線狀態。

      **對於TCP來說,第一個連線請求SYN包狀態為 NEW , 之後的全部為 ESTABLISHED 。 這個簡單的規則是非常有用的,用於區分連線發起的方向,是從內到外還是從外到內,而其它的匹配規則都無法識別連線的發起方向 **

      這個模組我認為是最有用的,關於核心如何跟蹤、標識各個協議的連結狀態,這個地址裡有詳細的介紹:https://www.frozentux.net/iptables-tutorial/cn/iptables-tutorial-cn-1.1.19.html

      • --state 狀態
        • NEW 新發起的連線請求,第一次講求的資料包為NEW狀態
        • ESTABLISHED 同一連線第一次請求之後的資料包均是該狀態
        • RELATED 第一請求,但是該請求是由已建立的其它連線發起的,典型應用 FTP的資料傳輸,資料傳輸連線是由已建立的FTP控制連線發起的新連線,使用這個需要載入
        • INVALID 無效資料包,資料包不合法
    2. connlimit 連線資料限制,可以限制匹配規則的連線數量,比如限制SSH連線資料只能為3

      • --connlimit-upto n 連線數小於等於n
      • --connlimit-above n 連線數大於等於n
    3. multiport 埠使用集合指定 ,最多15個,

      • --sports port,port,port 或者 port:port 連續範圍的port
      • --dports port,port,port 或者 port:port 連續範圍的port
    4. iprange 指定ip地址範圍

      • --src-range ip1-ip2
      • --dst-range ip1-ip2
    5. time 時間匹配

      • --timestart 開始日期 yyyy-mm-ddThh:mm:ss 例 1990-01-01T11:30:00 注意J日期和時間中間有個大寫T,預設 1970-01-01T00:00:00
      • --timestop 結束日期 yyyy-mm-ddThh:mm:ss 例 1990-01-01T11:30:00 注意J日期和時間中間有個大寫T,預設 2038-01-19T04:17:07
      • --datestart 結束時間 hh:mm:ss 例 11:30:00, 預設00:00:00
      • --datestop 結束時間 hh:mm:ss 例 11:30:00, 預設23:59:59
      • --monthdays 日期 1-31, 可以是集合,如 1,2,5,9
      • --weekdays 星期,1-7 , 可以是集合,如 1,3,5 1是星期一
    6. limit 速率匹配 ,

      使用令牌桶的演算法,每個要轉發的資料包要獲取一個令牌才能轉發,沒有獲取令牌的包,不匹配該規則,會轉由下一條匹配,如果限速,緊跟後面要有一條規則丟棄資料。

      • --limit rate n[/second|/minute/hour/day] 速率限制 , 單位時間允許生成的令牌資料,也即允許轉發的資料包數量, 注意: 不是頻寬,不是頻寬,當然通過限制包的資料也會間接限制了頻寬速率,包大小*包數=頻寬數。 預設3/hour
      • --limit-burst n 初始令牌資料, 即初始允許不受限制傳送的資料量,初始令牌用完,後面要等--limit 指定的單位時間生成的新令牌填充。
    7. string 匹配應用層資料中的字串, 只是簡單以字串形式匹配應用層資料,不會識別應用協議,如果是加密的也不會解密,只能是應該層協議沒有加密時有用,比如http

      --string pattern

5.5 處理動作 -j

​ 處理動作全部用大寫字母

5.5.1 filter表動作

  • ACCEPT 允許
  • DROP 直接丟棄
  • REJECT 拒絕 ,丟棄同時返回ICMP訊息
  • LOG 日誌記錄 , 不會終止規則匹配,也就是說該動作只記錄日誌,至於資料包是否被轉發,會繼續匹配後續規則

5.5.2 NAT 表動作

  • SNAT 源地址轉換

    • --to-source [ipaddr[-ipaddr]][:port[-port]][:port][-port] 可以指定埠範圍,如果不指定,預設儘可能不變更埠,但如果埠已經被其它連結佔用,會選用另一個埠替換,預設的埠轉換遵守以下規則:

      • 1 . 512以內的埠,會轉換成512以內的埠,保證不會大於512
      • 2 . 512-1023以內的埠,轉換為512-1024 ,保證不會大於1024
      • 3 . 1024以上的埠,轉換為1024以上的埠

      TCP/UDP標準將埠分為了0-511, 512-1024,1024以上這三個段,以上規則與之對應,不會出現源埠占用標準服務埠的情況:

      比如,訪問外部http服務,把源埠轉換成了21 , 佔用了FTP的埠,導致埠混亂(雖然技術上說也能通)

  • DNAT 目標地址轉換

    • --to-destination [ipaddr[-ipaddr]][:port[-port] 可以指定埠範圍,如果不指定,不變更埠,如果不指定IP, IP不會變更
    • --random 埠轉換會隨機進行

​ Later Kernels (>= 2.6.11-rc1) 不再支援IP範圍內的輪訓轉換,這個功能常做負載均衡用,也就是說centos7 開始不支援這一功能了, 不知道什麼原因。

5.6 儲存,恢復iptables配置

預設iptables配置規則只能當前生效,重啟就沒有了,需要用命令把規則放儲存到檔案,然後設定開機啟動指令碼載入配置檔案

  • 儲存 iptables-save > 檔名.rules
  • 恢復 iptables-restore <檔名.rules

5.7 iptables 命令例項

  1. 檢視當前規則

    • -vL 詳細資訊,可以-vvL 更詳細的資訊
    • --line-number 顯示規則編號
    [root@localhost ~]# iptables -vL --line-number
    Chain INPUT (policy ACCEPT 9639 packets, 806K bytes)
    num   pkts bytes target     prot opt in     out     source               destination         
    
    Chain FORWARD (policy ACCEPT 5388 packets, 2808K bytes)
    num   pkts bytes target     prot opt in     out     source               destination         
    
    Chain OUTPUT (policy ACCEPT 8262 packets, 1684K bytes)
    num   pkts bytes target     prot opt in     out     source               destination         
    [root@localhost ~]# 
    
    
    • 檢視nat表 , 沒有指定-t 預設filter表

      [root@localhost ~]# iptables -t nat  -vL --line-number
      Chain PREROUTING (policy ACCEPT 1281 packets, 105K bytes)
      num   pkts bytes target     prot opt in     out     source               destination         
      1        6   312 DNAT       tcp  --  any    any     anywhere             localhost.localdomain  tcp dpt:rtsps to:192.168.31.12:22
      
      Chain INPUT (policy ACCEPT 629 packets, 56218 bytes)
      num   pkts bytes target     prot opt in     out     source               destination         
      
      Chain OUTPUT (policy ACCEPT 296 packets, 22480 bytes)
      num   pkts bytes target     prot opt in     out     source               destination         
      
      Chain POSTROUTING (policy ACCEPT 296 packets, 22480 bytes)
      num   pkts bytes target     prot opt in     out     source               destination         
      1        1    52 SNAT       tcp  --  any    any     10.100.90.200        192.168.31.12        tcp dpt:ssh to:192.168.31.1:1023
      2      686 50843 SNAT       all  --  any    any     192.168.31.0/24      anywhere             to:10.100.93.202
      
      
  2. 清空規則

    • -F 清空規則
    [root@localhost ~]# iptables -t nat -F
    [root@localhost ~]# iptables -t nat  -vL --line-number
    Chain PREROUTING (policy ACCEPT 0 packets, 0 bytes)
    num   pkts bytes target     prot opt in     out     source               destination         
    
    Chain INPUT (policy ACCEPT 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         
    
    Chain POSTROUTING (policy ACCEPT 0 packets, 0 bytes)
    num   pkts bytes target     prot opt in     out     source               destination         
    [root@localhost ~]# 
    
    
  3. 開放本地埠80

    沒有用 -A 是因為表中已有其它規則,一般最後一條是預設規則,實際中往往是插入到第一條比較常見

    • 插入到第2條

      iptables -t filter -I INPUT  1  -p tcp --dport 80 -j ACCEPT
      
    • 插入到第2條

      iptables -t filter -I INPUT  2 -p tcp --dport 80 -j ACCEPT
      
    • 替換第2條

      iptables -t filter -R INPUT  2 -p tcp --dport 80 -j ACCEPT
      
    • 只允許指定源IP訪問

      iptables -t filter -R INPUT  2 -s 192.168.1.1 -p tcp --dport 80 -j ACCEPT
      
  4. 通過狀態匹配防火牆

    • 禁止本機主動發起的出站連線 (伺服器上可以這麼設定,因為伺服器是讓別人訪問自身 ,而自己本身不需要發起對外的連線,可以防止反彈木馬)

      iptables -t filter -I OUTPUT  -m multiport -m state --state NEW -j DROP
      
    • 允許(非本機主動發起的)外部主機主動發起的對本機的連線

      iptables -t filter -I OUTPUT  -m multiport -m state --state ESTABLISHED,RELATED -j DROP
      
  5. SNAT 代理上網, 允許源地址192.168.1.0/24 經本機上網 10.100.93.202為連通公網的IP

    iptables -t nat -I POSTROUTING -s 192.168.1.0/24 -j SNAT --to-source 10.100.93.202
    
  6. DNAT 將目標為本機IP 10.100.93.202 ,目標埠為 80 的資料轉發到後端真實伺服器 192.168.1.10的8000埠去

    iptables -t nat -I PREROUTING -d 192.168.1.0/24 -p tcp  --dport 80 -j DNAT --to-destination 192.168.1.0:8000
    
  7. 接合 SNAT和DNAT實現埠轉發

SNAT在資料發出時轉換IP為本機出介面,DNAT在接收到資料時轉換目標IP為後端真實伺服器IP ,組合這兩個特性,可以實現埠轉發的功能。

假如有如下場景:

在外網的使用者能訪問到防火牆外網IP 10.100.0.20

防火牆內網IP和內網伺服器可以互通,同時內網伺服器與外網隔離,不能通訊

使用者要想直接訪問內網伺服器的一個埠。

解決方法:

  1. 此場景不能只用DNAT, 因為內網伺服器與外網不通,返回給user的資料是無法出內網的。

  2. user只能與防火牆能,資料包的源地址必須是防火牆的,所以還需要SNAT, 在從防火牆內網口發出時轉換源地址為192.168.0.20 , 內網伺服器返回資料,自然目標地址也就是192.168.0.20。

  3. iptables nat是有連結狀態的,返回的資料會自動反向轉換,返回的資料經由以下過程:

  4. 防火牆內網口192.168.0.20 收到資料時,返向轉換目標IP為真實的USER , 經路由後,由公網口

  5. 10.100.0.20發出時,反向轉換源埠為防火牆自身埠 10.100.0.20.

  6. 通訊完成。

此過程即為埠轉發,當然有很多開源軟體可以實現埠轉發,但linux防火牆全部是在核心完成這些操作的,而使用其它軟體自然資料是要經過使用者空間,而且需要在公網埠建立tcp/udp監聽才可以。

​ 配置:

​ 內網伺服器埠22, 防火牆用埠 13322轉發:

# DNAT
iptables -t nat -I PREROUTING -d 10.100.0.20 -p tcp  --dport 13222 -j DNAT --to-destination 192.168.0.10:22
# SNAT
iptables -t nat -I POSTROUTING -d 192.168.0.10 --dport 22  -j SNAT --to-source 192.168.0.20

6 iptables防火牆配置最佳實踐

  1. 防火牆建議用白名單機制,即預設禁止所有,只明確放行需要放行的流量,

    • 不推薦 使用iptables 的 -P DROP 操作設定為預設禁止,
    • 推薦在鏈的最後一條規則設定為禁止所有

    原因:使用-P 設定為預設禁止,那麼除錯規則時不小心清空了防火牆,自己豈不是被關在了門外, 排查連線問題時,有時需要臨時清空規則,放行所有流量,來判斷是否因為防火牆阻止了連線。

  2. 被流量匹配到的頻率和可能性越大,規則越要往前面放,這樣能提高效率,防火牆的機制是從上向下順序匹配,配置到一條規則時,不再繼續向下匹配(此處說的是常規流量處理動作,如ACCEPT, DROP, REJECT, SNAT,DNAT, 像LOG還是會繼續向下匹配的)

  3. 建議使用擴充套件模組state設定有狀態的防火牆,安全性更高(因為能認識是誰主動發起的連線),配置規則更簡化。

    • 預設允許所有ESTABLISHEDRELATED、狀態連線,
    • 禁止所有INVALID 無效的資料包
    • 通過狀態NEW 控制資料發起的方向和IP,埠等。

相關文章