iptables & netfilter

1、簡介

netfilter/iptables(下文中簡稱為iptables)組成Linux核心下的包過濾防火牆,完成封包過濾、封包重定向和網路地址轉換(NAT)等功能。]

iptabels其實不是真正的防火牆,netfilter才是防火牆真正的安全框架(framework),netfilter位於核心空間。iptables其實是一個命令列工具,位於使用者空間,我們用這個工具操作真正的框架。

Netfilter是Linux作業系統核心層內部的一個數據包處理模組,它具有如下功能:

  • 網路地址轉換(Network Address Translate)
  • 資料包內容修改
  • 資料包過濾的防火牆功能

2、iptables基礎

iptatble是按規則來辦事的,當資料包與規則匹配時,iptables就根據規則所定義的方法來處理這些資料包,如放行(accept)、拒絕(reject)和丟棄(drop)等。配置防火牆的主要工作就是新增、修改和刪除這些規則。

netfilter才是真正的防火牆,它是核心的一部分,所以,如果我們想要防火牆能夠達到”防火”的目的,則需要在核心中設定關卡,所有進出的報文都要通過這些關卡,經過檢查後,符合放行條件的才能放行,符合阻攔條件的則需要被阻止,於是,就出現了input關卡和output關卡,而這些關卡在iptables中不被稱為”關卡”,而被稱為”鏈”。

iptatbles中不僅有inputoutput關卡,還有preroutingforwardpostrouting,當我們啟用了防火牆功能時,報文需要經過如下關卡,也就是說,根據實際情況的不同,報文經過”鏈”可能不同。如果報文需要轉發,那麼報文則不會經過input鏈發往使用者空間,而是直接在核心空間中經過forward鏈和postrouting鏈轉發出去的。

2.1、鏈

防火牆的作用就在於對經過的報文匹配”規則”,然後執行對應的”動作”,所以,當報文經過這些關卡的時候,則必須匹配這個關卡上的規則,但是,這個關卡上可能不止有一條規則,而是有很多條規則,當我們把這些規則串到一個鏈條上的時候,就形成了”鏈”。

這樣來說,把他們稱為”鏈”更為合適,每個經過這個”關卡”的報文,都要將這條”鏈”上的所有規則匹配一遍,如果有符合條件的規則,則執行規則對應的動作。

2.2、表

具有相同功能規則的集合叫做“表”,iptables定義來4種表,每種表對應了不同的功能,即我們定義的規則都逃脫不了這4種功能的範圍。

  • filter表:過濾功能,防火牆;核心模組:iptable_filter
  • nat表:網路地址轉換功能;核心模組:iptable_nat
  • mangle表:拆解報文,修改,並重新封裝功能;核心模組:iptable_mangle
  • raw表:關閉nat表上啟用的連線追蹤機制;核心模組:iptatble_raw

需要注意的是,某些“鏈”註定 不會包含“某類規則”,錶鏈的對應關係如下:

綜合上面描述,資料包經過防火牆的流程總結為下:

如果想要linux主機支援轉發,則需要開啟核心的IP_FORWARD功能,可以臨時修改對應檔案/proc/sys/net/ipv4/ip_forward。

在寫Iptables規則的時候,要時刻牢記這張路由次序圖,靈活配置規則。

2.3、規則

根據指定的匹配條件來嘗試匹配每個流經此處的報文,一旦匹配成功,則由規則後面指定的處理動作進行處理。

匹配條件分為

基本匹配條件:源IP、目的IP等

擴充套件匹配條件:源埠、目的埠等

處理動作(在iptatbles中被稱為target):

  • ACCEPT:允許資料包通過
  • DROP:丟棄資料包,不給任何迴應資訊
  • REJECT:拒絕資料包通過,必要時傳送一個響應資訊
  • SNAT:源地址轉換,解決內網使用者用同一個公網地址上網的問題
  • MASOUERADE:SNAT的一種特殊形式,適用於動態的、臨時會變的ip上
  • DNAT:目的地址轉換
  • REDIRECT:在本機做埠對映
  • LOG:在/var/log/messages檔案中記錄日誌資訊,然後將資料包傳遞給下一條規則。

3、使用

3.1、規則查詢

#檢視對應表所有規則,省略表名預設為filter表
iptables -t 表名 -L #指定鏈的規則,-v:詳細資訊 -n:直接顯示IP地址 --line-numbers:顯示規則序號 -x:顯示計數器的精確值
iptables --line-numbers -t 表名 -nvxL 鏈名

3.2、規則管理

新增規則

命令語法:iptables -t 表名 -A 鏈名 匹配條件 -j 動作
示例:iptables -t filter -A INPUT -s 192.168.1.146 -j DROP -I:在對應鏈開頭新增規則
-A:在末尾新增規則 規則是按照順序執行的,新增時候可以指定規則序號,這樣就可以在任意位置插入規則了. 命令語法:iptables -t 表名 -I 鏈名 規則序號 匹配條件 -j 動作
示例:iptables -t filter -I INPUT 5 -s 192.168.1.146 -j REJECT ---設定預設動作---
命令語法:iptables -t 表名 -P 鏈名 動作
示例:iptables -t filter -P FORWARD ACCEPT

刪除規則

命令語法:iptables -t 表名 -D 鏈名 規則序號
示例:iptables -t filter -D INPUT 3 ---按照具體匹配條件與動作刪除規則--
命令語法:iptables -t 表名 -D 鏈名 匹配條件 -j 動作
示例:iptables -t filter -D INPUT -s 192.168.1.146 -j DROP
-F:清空對應鏈的規則,如果省略鏈名錶示刪除表中所有規則

修改規則

---規則原本的匹配條件不可省略!如果省略,源地址會變成0.0.0.0/0,此時如果是拒絕動作,那麼ssh就斷掉了---
命令語法:iptables -t 表名 -R 鏈名 規則序號 規則原本的匹配條件 -j 動作
示例:iptables -t filter -R INPUT 3 -s 192.168.1.146 -j ACCEPT

儲存規則

---儲存在/etc/sysconfig/iptables檔案中
service iptables save 或
iptables-save > /etc/sysconfig/iptables ---從檔案中重新載入規則
iptatbles-restore < /etc/sysconfig/iptables

3.3、基本匹配條件

當規則中同時存在多個匹配條件時,多個條件之間預設存在“與”的關係.

  • -s: 指定源ip,多個ip用逗號隔開,也可以指定一個網段

    iptables -t filter -I INPUT -s 192.168.1.111,192.168.1.118 -j DROP
    iptables -t filter -I INPUT -s 192.168.1.0/24 -j ACCEPT
    iptables -t filter -I INPUT ! -s 192.168.1.0/24 -j ACCEPT
  • -d: 匹配目標地址,用法和-s一樣

  • -p: 匹配報文協議型別,可以匹配的協議型別tcp、udp、udplite、icmp、esp、ah、sctp等

  • -i: 匹配報文從哪個網絡卡介面流入本機,由於匹配條件只是用於匹配報文流入的網絡卡,所以在OUTPUT鏈與POSTROUTING鏈中不能使用此選項

  • -o: 匹配報文從哪個網絡卡介面流出本機

3.3、擴充套件匹配條件

  • tcp擴充套件模組

    常用的擴充套件匹配條件如下:

    -p tcp -m tcp –-sport 用於匹配tcp協議報文的源埠,可以使用冒號指定一個連續的埠範圍

    -p tcp -m tcp –-dport 用於匹配tcp協議報文的目標埠,可以使用冒號指定一個連續的埠範圍

    --tc-flages 用於匹配tcp頭部欄位標誌位,第一部分為需要匹配哪些標誌位,第二部分為哪些標誌位為1

    iptables -t filter -I INPUT -p tcp -m tcp --dport 22 --tcp-flags SYN,ACK,FIN,RST,URG,PSH SYN -j REJECT
    iptables -t filter -I INPUT -p tcp -m tcp --dport 22 --tcp-flags SYN,ACK,FIN,RST,URG,PSH SYN -j REJECT

    --syn 相當於使用”–tcp-flags SYN,RST,ACK,FIN SYN

  • udp模組

    當使用擴充套件匹配條件時,如果未指定擴充套件模組,iptables會預設呼叫與”-p”對應的協議名稱相同的模組,所以,當使用”-p udp”時,可以省略”-m udp”.udp只有sport和dport兩個匹配條件

  • mutiport擴充套件模組

    常用的擴充套件匹配條件如下:

    -p tcp -m multiport –-sports 用於匹配報文的源埠,可以指定離散的多個埠號,埠之間用”逗號”隔開

    -p udp -m multiport –-dports 用於匹配報文的目標埠,可以指定離散的多個埠號,埠之間用”逗號”隔開

  • iprange模組

    包含的擴充套件匹配條件如下

    -m iprange –-src-range:指定連續的源地址範圍,用-指定一個連續的範圍

    -m iprange -–dst-range:指定連續的目標地址範圍

  • string模組

    使用string擴充套件模組,可以指定要匹配的字串,如果報文中包含對應的字串,則符合匹配條件,常用擴充套件匹配條件如下

    –-algo:指定對應的匹配演算法,可用演算法為bm、kmp,此選項為必需選項。

    –-string:指定需要匹配的字串

  • time模組

    常用擴充套件匹配條件如下

    –-timestart:用於指定時間範圍的開始時間,不可取反

    –-timestop:用於指定時間範圍的結束時間,不可取反

    –-weekdays:用於指定”星期幾”,可取反

    –-monthdays:用於指定”幾號”,可取反

    –-datestart:用於指定日期範圍的開始日期,不可取反

    –-datestop:用於指定日期範圍的結束時間,不可取反

    iptables -t filter -I OUTPUT -p tcp --dport 80 -m time --timestart 09:00:00 --timestop 19:00:00 -j REJECT
    iptables -t filter -I OUTPUT -p tcp --dport 80 -m time --weekdays 6,7 -j REJECT
    iptables -t filter -I OUTPUT -p tcp --dport 80 -m time --monthdays 22,23 -j REJECT
    iptables -t filter -I OUTPUT -p tcp --dport 80 -m time --weekdays 5 --monthdays 22,23,24,25,26,27,28 -j REJECT
    iptables -t filter -I OUTPUT -p tcp --dport 80 -m time --datestart 2017-12-24 --datestop 2017-12-27 -j REJECT
  • connlimit模組

    使用connlimit擴充套件模組,可以限制每個IP地址同時連結到server端的連結數量,注意:我們不用指定IP,其預設就是針對”每個客戶端IP”,即對單IP的併發連線數限制

    –-connlimit-above:單獨使用此選項時,表示限制每個IP的連結數量。

    –-connlimit-mask:此選項不能單獨使用,在使用–connlimit-above選項時,配合此選項,則可以針對”某類IP段內的一定數量的IP”進行連線數量的限制

    iptables -I INPUT -p tcp --dport 22 -m connlimit --connlimit-above 2 -j REJECT
  • limit模組

    如果我想要限制單位時間內流入的包的數量,就能用limit模組,我們可以以秒為單位進行限制,也可以以分鐘、小時、天作為單位進行限制

    常用的擴充套件匹配條件如下

    –-limit-burst:類比”令牌桶”演算法,此選項用於指定令牌桶中令牌的最大數量

    –-limit:類比”令牌桶”演算法,此選項用於指定令牌桶中生成新令牌的頻率,可用時間單位有second、minute 、hour、day。

    iptables -t filter -I INPUT -p icmp -m limit --limit-burst 3 --limit 10/minute -j ACCEPT
  • icmp模組

    –-icmp-type:匹配icmp報文的具體型別,可以使用type/code和description兩種方式表示

  • state模組

    問題: 怎樣判斷這些報文是為了迴應我們之前發出的報文,還是主動向我們傳送的報文呢?

    state模組可以讓iptables實現”連線追蹤”機制,”連線”其中的報文可以分為5種狀態,報文狀態可以為NEW、ESTABLISHED、RELATED、INVALID、UNTRACKED.

    --state

3.4、黑白名單機制

前文中一直在強調一個概念:報文在經過iptables的鏈時,會匹配鏈中的規則,遇到匹配的規則時,就執行對應的動作,如果鏈中的規則都無法匹配到當前報文,則使用鏈的預設策略(預設動作),鏈的預設策略通常設定為ACCEPT或者DROP。

所以,當鏈的預設策略為ACCEPT時,鏈中的規則對應的動作應該為DROP或者REJECT,表示只有匹配到規則的報文才會被拒絕,沒有被規則匹配到的報文都會被預設接受,這就是”黑名單”機制。

同理,當鏈的預設策略為DROP時,鏈中的規則對應的動作應該為ACCEPT,表示只有匹配到規則的報文才會被放行,沒有被規則匹配到的報文都會被預設拒絕,這就是”白名單”機制。

在對應的鏈中沒有設定任何規則時,這樣使用預設策略為DROP是非常不明智的,因為管理員也會把自己拒之門外,即使對應的鏈中存在放行規則,當我們不小心使用”iptables -F”清空規則時,放行規則被刪除,則所有資料包都無法進入,這個時候就相當於給管理員挖了個坑,所以,我們如果想要使用”白名單”的機制,最好將鏈的預設策略保持為”ACCEPT”,然後將”拒絕所有請求”這條規則放在鏈的尾部,將”放行規則”放在前面,這樣做,既能實現”白名單”機制,又能保證在規則被清空時,管理員還有機會連線到主機

iptables -P INPUT ACCEPT
iptabels -I INPUT -p tcp --dport 22 -j ACCEPT
iptabels -I INPUT -p tcp --dport 80 -j ACCEPT
iptables -A INPUT -j ACCEPT

3.5、自定義鏈

當預設鏈中的規則非常多時,不方便我們管理。

想象一下,如果INPUT鏈中存放了200條規則,這200條規則有針對httpd服務的,有針對sshd服務的,有針對私網IP的,有針對公網IP的,假如,我們突然想要修改針對httpd服務的相關規則,難道我們還要從頭看一遍這200條規則,找出哪些規則是針對httpd的嗎?這顯然不合理。

但是需要注意的是,自定義鏈並不能直接使用,而是需要被預設鏈引用才能夠使用.

--建立自定義鏈
iptables -t filter -N IN_WEB --引用自定義鏈
iptables -t filter -I INPUT -p tcp --dport 80 -j IN_WEB --重新命名自定義鏈
iptables -E IN_WEB WEB --刪除自定義鏈
刪除自定義鏈需要滿足兩個條件
1、自定義鏈沒有被引用
2、自定義鏈中沒有任何規則 iptables -D INPUT 1
iptables -F WEB
iptables -X WEB

3.6、網路防火牆

防火牆從邏輯上講,可以分為主機防火牆與網路防火牆。

主機防火牆:針對於單個主機進行防護。

網路防火牆:往往處於網路入口或邊緣,針對於網路入口進行防護,服務於防火牆背後的本地區域網。

iptables都是作為主機防火牆的角色出現的,如果想要使用iptables充當網路防火牆,iptables所在的主機則需要處於網路入口處,網路防火牆主要職責就是“過濾並轉發”,所以規則只能定義在FORWARD鏈中.

上圖中把C主機的閘道器指向B主機網絡卡1的IP,A主機閘道器設為B網絡卡2的地址.

A ping 10.1.0.1 是ping不通的,A主機通過路由表得知,發往10.1.0.0/16網段的報文的閘道器為B主機,當報文達到B主機時,B主機發現A的目標為10.1.0.1,而自己的IP是10.1.0.3,這時,B主機則需要將這個報文轉發給10.1.0.1(也就是C主機),但是,Linux主機在預設情況下,並不會轉發報文,如果想要讓Linux主機能夠轉發報文,需要額外的設定,這就是為什麼10.1.0.1沒有迴應的原因.

A ping 10.1.0.3可以ping通: 當報文到達B時,B主機發現自己既是192.168.1.146又是10.1.0.3,所以,B主機就直接回應了A主機,並沒有將報文轉發給誰,所以A主機得到了10.1.0.3的迴應。

臨時生效:把/proc/sys/net/ipv4/ip_forward檔案內容設定為1表示支援轉發報文.

永久生效:/etc/sysctl.conf新增net.ipv4.ip_forward=1

此時就可以ping通了

#如果想要iptables作為網路防火牆,iptables所在主機開啟核心轉發功能,以便能夠轉發報文。
#使用如下命令檢視當前主機是否已經開啟了核心轉發,0表示為開啟,1表示已開啟
cat /proc/sys/net/ipv4/ip_forward
#使用如下兩種方法均可臨時開啟核心轉發,立即生效,但是重啟網路配置後會失效。
方法一:echo 1 > /proc/sys/net/ipv4/ip_forward
方法二:sysctl -w net.ipv4.ip_forward=1
#使用如下方法開啟核心轉發功能,重啟網路服務後永久生效。
配置/etc/sysctl.conf檔案(centos7中配置/usr/lib/sysctl.d/00-system.conf檔案),在配置檔案中將 net.ipv4.ip_forward設定為1 #由於iptables此時的角色為"網路防火牆",所以需要在filter表中的FORWARD鏈中設定規則。
#可以使用"白名單機制",先新增一條預設拒絕的規則,然後再為需要放行的報文設定規則。
#配置規則時需要考慮"方向問題",針對請求報文與迴應報文,考慮報文的源地址與目標地址,源埠與目標埠等。
#示例為允許網路內主機訪問網路外主機的web服務與sshd服務。
iptables -A FORWARD -j REJECT
iptables -I FORWARD -s 10.1.0.0/16 -p tcp --dport 80 -j ACCEPT
iptables -I FORWARD -d 10.1.0.0/16 -p tcp --sport 80 -j ACCEPT
iptables -I FORWARD -s 10.1.0.0/16 -p tcp --dport 22 -j ACCEPT
iptables -I FORWARD -d 10.1.0.0/16 -p tcp --sport 22 -j ACCEPT #可以使用state擴充套件模組,對上述規則進行優化,使用如下配置可以省略許多"迴應報文放行規則"。
iptables -A FORWARD -j REJECT
iptables -I FORWARD -s 10.1.0.0/16 -p tcp --dport 80 -j ACCEPT
iptables -I FORWARD -s 10.1.0.0/16 -p tcp --dport 22 -j ACCEPT
iptables -I FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT

3.7、動作總結

閘道器配置和上面一樣.

  • SNAT(服務在外網,內網主動訪問外網)

    #主機B
    iptables -t nat -A POSTROUTING -s 10.1.0.0/16 -j SNAT --to-source 192.168.1.146

    此時內網主機ping A主機就能ping通, iptables會自動維護NAT表,並將響應報文的目標地址轉換回來.

  • DNAT(服務在內網,外網主動訪問內網)

    #主機B
    iptables -t nat -F
    iptables -t nat -I PREROUTING -d 192.168.1.146 -p tcp --dport 3389 -j DNAT --to-destination 10.1.0.6:3389
    iptables -t nat -A POSTROUTING -s 10.1.0.0/16 -j SNAT --to-source 192.168.1.146

    表示報文目標地址為B公網IP,目標埠為3389的報文符合匹配條件,做DNAT轉換對映到10.1.0.6:3389上.

    注:理論上只配置DNAT規則即可,但是如果在測試時無法正常DNAT,可以嘗試配置對應的SNAT,此處按照配置SNAT的流程進行。

  • MASQUERADE

    MASQUERADE會動態的將源地址轉換為可用的IP地址,其實與SNAT實現的功能完全一致,都是修改源地址,只不過SNAT需要指明將報文的源地址改為哪個IP,而MASQUERADE則不用指定明確的IP,會動態的將報文的源地址修改為指定網絡卡上可用的IP地址.

    iptables -t nat -I POSTROUTING -s 10.1.0.0/16 -o eth0 -j MASQUERADE

    表示通過外網網絡卡出去的報文在經過POSTROUTING鏈時,會自動將報文的源地址修改為外網網絡卡上可用的IP地址,這時,即使外網網絡卡中的公網IP地址發生了改變,也能夠正常的、動態的將內部主機的報文的源IP對映為對應的公網IP,可以把MASQUERADE理解為動態的、自動化的SNAT,如果沒有動態SNAT的需求,沒有必要使用MASQUERADE,因為SNAT更加高效。

  • REDIRECT

    使用REDIRECT動作可以在本機上進行埠對映

    #將本機80埠對映到本機8080埠
    iptables -i nat -A PREROUTING -o tcp --dport 80 -j REDIRECT --to-ports 8080

4、總結

  1. 規則順序很重要

    如果報文已經被前面的規則匹配到,IPTABLES則會對報文執行對應的動作,通常是ACCEPT或者REJECT,報文被放行或拒絕以後,即使後面的規則也能匹配到剛才放行或拒絕的報文,也沒有機會再對報文執行相應的動作了(前面規則的動作為LOG時除外),所以,針對相同服務的規則,更嚴格的規則應該放在前面。

  2. 當規則中有多個匹配條件時,條件之間是“與”的關係

  3. 在不考慮1的情況下,應該將更容易被匹配的規則放在前面

    比如,你寫了兩條規則,一條針對sshd服務,一條針對web服務。假設,一天之內,有20000個請求訪問web服務,有200個請求訪問sshd服務,那麼,應該將針對web服務的規則放在前面,針對sshd的規則放在後面,因為訪問web服務的請求頻率更高。如果將sshd的規則放在前面,當報文是訪問web服務時,sshd的規則也要白白的驗證一遍,由於訪問web服務的頻率更高,白白耗費的資源就更多。

  4. 當IPTABLES所在主機作為網路防火牆時,在配置規則時,應著重考慮方向性,雙向都要考慮,從外到內,從內到外。

  5. 在配置IPTABLES白名單時,往往會將鏈的預設策略設定為ACCEPT,通過在鏈的最後設定REJECT規則實現白名單機制,而不是將鏈的預設策略設定為DROP,如果將鏈的預設策略設定為DROP,當鏈中的規則被清空時,管理員的請求也將會被DROP掉。