Linux防火墻詳解
本文參考了《Linux就該這么學》、《鳥哥的Linux私房菜》、《RHCSA/RHCE紅帽Linux認證學習指南》、《iptables零基礎快速入門系列》、《Firewalld詳解》、《Firewalld Rich Rules Explained with Examples》、《Firewalld – Understanding Rich Rules on CentOS/RHEL 7》
Linux中防火墻的實現主要是依托于Netfilter框架,通過該框架,其他內核模塊才能夠實現諸如包過濾、網絡地址轉換(NAT)以及負載均衡等功能。其中iptables就是最著名的命令行工具,主要實現了包過濾以及NAT。在RHEL7中,又提供了一種新的服務——firewalld,與iptables不同的是,firewalld不是基于“規則鏈”,而是基于區域。
1. iptables
1.1 iptables的基本概念
iptables會按照從上到下的順序,依次檢查規則鏈,因此應該將優先級較高的規則放在前面。
既然叫做iptables,說明其中是有一個基本的概念,叫做表(table)。所謂表就是具有相同功能的規則的集合,在iptables中默認有四種表:
- filter:用于對數據包進行過濾
- nat:用于進行網絡地址轉換
- mangle:拆解報文、做出修改、重新封裝
- raw:關閉NAT表上啟用的連接追蹤功能
前面,我們又提到了iptables是一種基于“規則鏈”的應用,因此還需要明確,在iptables中存在鏈的概念,所謂鏈可以簡單理解為計算機系統中的關卡,由于每個關卡下面有一串的規則(需要從上至下以此執行),因此每個關卡可以看作一條鏈狀結構。其中默認有五種鏈,分別是:
- PREROUTING
- INPUT
- OUTPUT
- FORWARD
- POSTROUTING
具體的內容可以參考朱雙印的技術博客,里面介紹的非常清楚了。以上就是我們經常聽到的iptables中“四表五鏈”。
iptables中的動作主要包括以下幾類:
- ACCEPT:允許數據包通過
- DROP:丟棄掉數據包,且不做任何響應
- REJECT:拒絕數據包,且在必要時給出響應
- LOG:記錄日志信息到/var/log/message中
- REDIRECT:本機做端口映射
- SNAT:源地址轉換
- DNAT:目的地址轉換
1.2 iptables的基本操作
前面我們提到了表的概念,容易讓人想到的就是關系型數據庫中的表,對于這些表而言,最常見的操作就是“增刪改查”(有點像相聲里的說學逗唱哈)。讓我們首先來看看iptables的查。
1.2.1 查
要想查看iptables中的規則內容,主要使用-L
參數。在前面我們也提到了所謂的“四表五鏈”,如果想要查看這些具體的“表”和“鏈”的內容,就需要添加額外的參數。
查看表
如果要想查看(或者說的更準確些是操作)指定的表,可以使用-t <tabletype>
參數,如果沒有指定改參數,那么默認操作的是filter表。
查看鏈
要想查看鏈的內容,需要在-L
參數后面添加具體的鏈名(比如INPUT、PREROUTING等)
其他查看的參數
- --line-numbers:可以顯示出規則的序號
- -v:可以顯示出更為詳細的信息
- -n:不對規則中的IP和端口等進行反解析(即顯示IP地址和具體的端口號,沒有該參數時會顯示DNS的解析信息和服務名稱)
1.2.2 增
在iptable中增加規則,主要有三個參數,分別是:
- -I
- -A
- -P
默認規則
-P
參數主要用于設置默認參數,其語法為:
iptables -t <表名> -P <鏈名> <動作>
其中表名部分可以省略,默認為filter表。下面我們來簡單的看一個實例:
iptables -P INPUT ACCEPT
在這個例子中,沒有指定-t參數,說明操作的是filter表。-P參數后面跟了INPUT鏈,說明該命令就是將filter表中的INPUT鏈的默認動作設置為ACCEPT,即在沒有其他規則的情況下,將接受一切數據包
規則鏈尾部添加
-A
參數的全拼是append,即在規則鏈的尾部進行追加(即優先級最低的規則),其標準語法為:
iptables -t <表名> -A <鏈名> <匹配條件> -j <動作>
其中<表名>、<鏈名>和<動作>我們已經做了很多次說明了,此處就不再贅述了,我們重點來看一下匹配條件。所謂匹配條件是指當這個條件滿足以后,我們就會執行-j后面的動作。那么匹配條件有哪些呢?常見的主要有以下幾個:
- -s <地址>:源地址,可以用IP/MASK來表示,如果
-S
前面加了!
,則表示不匹配這個IP的時候滿足條件,多個ip地址時,使用,
進行分割 - -d <地址>:目的地址(與
-s
參數相同) - -p <協議名稱>:協議名稱,比如tcp、udp、icmp等,不指定該參數時,默認為
all
- -i <網卡名稱>:從這塊網卡流入的數據
- -o <網卡名稱>:從這塊網卡流出的數據
- --dport <端口號>:匹配目標端口號,可以寫為1000:1024,表示禁用1000-1024之間的所有端口
- --sport <端口號>:匹配源端口號
需要說明的是,當使用
--dport
和--sport
時,可以使用-m
參數來指定該規則針對的是哪個協議,例如:iptables -A INPUT -p tcp -s 192.168.10.0/24 -m tcp --sport 22 -j DROP
如果沒有指定該參數,則會跟隨
-p
參數指定的協議
規則鏈首部/指定位置添加
要想在規則鏈首部添加,就需要使用-I
參數,其標準語法為:
iptables -t <表名> -I <鏈名> <規則序號> <匹配條件> -j <動作>
除了優先級的差別外,-I
參數與-A
參數基本一致,唯一的差別在于-I
參數可以在<鏈名>后面添加<規則序號>
,即-I
不僅可以在鏈的首部添加規則,還可以在指定位置添加規則。
1.2.3 刪
在iptables中,要想刪除規則,有兩個參數可供選擇:
- -F
- -D
清空iptables
可以使用-F
參數來清空iptables規則庫,其命令語法為:
iptables -t <表名> -F <鏈名>
如果不置頂鏈名則刪除該表下的所有規則
刪除滿足特定條件的規則
要想刪掉某一條規則,則需要使用-D
參數,使用時有兩種語法,比較簡單的是直接指定規則序號,即:
iptables -t <表名> -D <鏈名> <規則序號>
如果要想實現更靈活的刪除,則可以使用帶有匹配條件的語法:
iptables -t <表名> -D <鏈名> <匹配條件> -j <動作>
這種方法的靈活性比較強,可以一次刪掉多條規則,但是其殺傷力比較大,建議操作之前一定要慎重
1.2.4 改
要想對規則進行修改,需要使用-R
參數,其具體語法命令為:
iptables -t <表名> -R <鏈名> <規則序號> <規則原本的匹配條件> -j <動作>
所謂<規則原本的匹配條件>是指不需要進行修改的規則,例如iptables詳解(3)中給出了一個例子:
iptables -t filter -R INPUT 3 -s 192.168.1.146 -j ACCEPT
該命令表示修改filter表中INPUT鏈中的第3條規則,將這條規則的動作改為放行(ACCEPT),-s 192.168.1.146
表示這條規則中原本的匹配條件,如果此處不寫這個條件的話,那么修改后的規則的源地址就有可能變為0.0.0.0/0(即anywhere)。所以在執行改命令時一定要慎之又慎?。。?/p>
1.3 保存
最后需要說明的是,執行上述命令后制定的各項規則,會在Linux重啟后消失,所以要想讓這些命令永久生效,就自然需要保存,即使用如下命令:
services iptables save
iptables會將最終的規則保存到
/etc/sysconfig/iptables
文件中
2 Firewall
在RedHat7.3中以后就不再支持iptables了,我個人猜測這可能是為了更好的推廣新的防火墻firewall。firewall對應的服務名稱是firewalld,其中又支持兩個工具,其中一個是命令行的,一個是GUI的窗口:
- firewall-cmd
- firewall-config
在firewall中,引入了一個區域(zone)的概念,我們可以將區域理解為不同的套餐,以適應不同的場景。firewall中內置的區域主要包括:
區域 | 默認策略規則 |
---|---|
trusted | 允許所有的數據包 |
home | 適用于家庭場景,拒絕流入的流量(除非與流出流量有關);允許ssh、mdns、ipp-client、samba-client、dhcpv6-client服務的流量 |
internal | 適用于內部網絡,與home區域一樣 |
work | 適用于工作區域,拒絕流入的流量(除非與流出流量有關);允許ssh、ipp-client、dhcpv6-client服務的流量 |
public | 適用于公共區域,允許ssh和dhcpv6-client服務的流量,是firewall默認區域 |
external | 拒絕流入的流量(除非與流出流量有關),僅允許ssh服務的流量 |
dmz | 拒絕流入的流量(除非與流出流量有關),僅允許ssh服務的流量 |
block | 拒絕流入的流量(除非與流出流量有關) |
drop | 拒絕流入的流量(除非與流出流量有關),沒有任何回復 |
在firewall中有兩種運行模式,分別是:
- runtime:當前生效,重啟無效
- permanent:當前無效,重啟生效
要想配置permanent模式,需要使用--permanent
參數,使用之后還必須手動執行下面的命令:
firewall-cmd --reload
才能確保配置的策略立即生效!?。?/p>
2.1 區域管理
對于區域的管理,firewall可以使用的參數包括:
- --get-default-zone:查看默認的區域
- --set-default-zone:設置默認的區域
- --get-activate-zones:顯示當前正在使用的區域與網卡名稱
- --get-zones:查看可用的區域
- --list-all:查看當前區域的信息(包括:網卡配置參數、資源、端口、服務等信息)
- --list-all-zones:查看所有區域的信息
所謂“默認區域”是指當不指定操作的區域時(即不使用--zone
參數時),所有操作所作用的區域;而“激活區域”(即activate zones)則是指正在使用的區域,例如我們的電腦上只有一塊網卡,那么如果我們把該網卡掛在public
區域,則激活區即為public
,如果服務器上有兩塊網卡,一塊掛在public
,一塊掛在dmz
,那么激活區就有兩個,分別為public
和dmz
。
2.2 規則管理
對于規則的管理,和iptables非常類似,也涉及到規則的“增刪查”。在firewall中,如果將一個服務/端口/協議添加(使用帶有add的參數)到規則中,則會放行該服務/端口/協議,如果移除(使用帶有remove的參數)一個服務/端口/協議,則會拒絕改改服務/端口/協議。
2.2.1 服務管理
在服務管理中,主要使用到以下幾個參數
- --add-service=<服務名>:添加一個服務到放行列表中
- --remove-service=<服務名>:從放行列表中刪除一個服務
- --query-service=<服務名>:查詢服務是否在放行列表中
- --list-services:列出所有放行的服務
2.2.2 端口管理
在端口管理中,主要使用到以下幾個參數:
- --add-port=<端口號>/<協議>:添加一個端口到放行列表中
- --remove-port=<端口號>/<協議>:從放行列表中移除一個端口
- --query-port=<端口號>/<協議>:查詢某個端口是否放行
- --list-ports:列出所有的放行端口
如果已經放行/禁用了某個服務,而該服務使用的是默認端口號(比如http使用80端口),則使用--list-ports
和--query-port
是無法查詢到的。
所有的服務和端口/協議的對應關系,都存儲在/etc/lib/firewalld/services
下的xml文件中
2.2.3 源地址管理
在firewall中,將源地址作為source,其常用的參數主要有:
- --add-source=<源地址>:將此地址/網段的流量引入某個zone
- --remove-source=<源地址>:拒絕此地址/網段的流量進入某個zone
- --query-source=<源地址>:查詢該地址/網段是否列入了放行列表
- --list-sources:列出所有放行的地址
需要注意的是,如果--add-source
添加了一個網段,比如192.168.20.0/24
那么,當使用--query-source=192.168.20.1
來查詢具體的某個地址是否加入放行列表時,得到的結論仍然是no
2.2.4 網卡管理
常用的參數主要有如下幾個:
- --add-interface=<網卡名稱>:將網卡綁定到某個zone
- --remove-interface=<網卡名稱>:將網卡與該zone進行解綁
- --query-interface=<網卡名稱>:查詢某網卡是否綁定到某個zone
- --list-interfaces:查看所有綁定到某個zone的網卡
2.2.5 一鍵斷網/恢復
要想一鍵斷網/恢復,需要使用下面兩個參數:
- --panic-on:一鍵斷網
- --panic-off:一鍵恢復
2.2.6 流量轉發
要想進行流量轉發,首先要打開masquerade
功能,我查了一下這個詞,原意是“偽裝、冒充”的意思,如果仔細看了前面的內容,不難猜出要打開這個功能,必然要使用帶有add
的參數,因此可知打開masquerade的命令為(關閉自然是使用--remove-masquerade
)
firewall-cmd --permanent --add-masquerade
此處,我們沒有指定域,因此操作的是默認域public
,而且我們又使用了--permanent
參數,因此如果要立即生效,必然是需要--reload
的。
打開masquerade
后,就可以進行流量的端口轉發了,其命令格式為:
firewall-cmd --permanent -zone=<區域> --add-forward-port=port=<源端口號>:proto=<協議>:toport=<目的端口號>:toaddr=<目的ip地址>
例如,如果我們要將本地端口888端口的TCP協議的數據轉發到22端口,即可以使用如下命令:
firewall-cmd --add-forward-port=port=888:proto=tcp:toport=22
2.2.7 富規則(Rich Rules)
如果想查看更詳細的富規則的內容,可以使用如下命令(無法用tab補全):
man firewalld.richlanguage
我把富規則理解為一種更加簡單的但是卻可以制定更加靈活防火墻規則的腳本語言。在firewall中,仍然是使用add、remove、query、list來實現富規則的“增刪改查”,其具體的含義就不做過多的說明了,前面的例子看多了,這里基本就水到渠成了。
- --add-rich-rule='<富規則>'
- --remove-rich-rule='<富規則>'
- --query-rich-rule='<富規則>'
- --list-rich-rule='<富規則>'
富規則的語法為:
rule
[source]
[destination]
service|port|protocol|icmp-block|masquerade|forward-port
[log]
[audit]
[accept|reject|drop]
其中:
- [source]:表示本條規則所關注的源IP地址/網段,可以寫為
source address="192.168.20.0/24"
- [destination]:本條規則所關注的目的IP地址/網段,可以寫為
destination address="192.168.20.0/24"
- service:是指firewall中提供的服務名稱,其命令格式為
service name=<服務名稱>
- port:端口號,命令格式為
port port=<端口/端口范圍>
- protocal:協議名稱,命令格式為
protocal value=<協議名稱>
- Imp-block:用于阻斷一個或多個ICMP類型。可以用
firewall-cmd --get-icmptypes
來獲得支持的ICMP類型,icmp-block在內部使用 reject 動作,因此不允許指定動作。命令格式為icmp-block name=<icmptype_name>
- masquerade:
- forward-port:進行流量轉發,命令格式為:
forward-port port=<源端口/端口范圍> protocol=<協議名稱> to-port=<目的端口> to-addr=<目的地址>
- log:
- audit: