本文以ubuntu 14.04為例,講講ufw防火牆規則順序問題。
--------------------------------此處應該優雅的使用分割線--------------------------------
先說原理再吐槽!
linux系統及其許多其他軟體中都有通路控制(access control)功能,比如系統中的防火牆,cisco ios中的acl(access control lists),web伺服器中的access module。在有些通路控制的實作中,有一些通路控制的功能跟順序有關,例如禁止所有其他主機通路本機端口但允許某一台主機通路本機端口,或者允許所有主機通路本機端口但禁止某一台主機通路本端口。這樣的例子在netfilter iptables和apache httpd 2.2版本中能很容易得到展現,這裡主要講講ubuntu的ufw。
首先要給大多數人糾正一下,ufw并不是一個防火牆,盡管它叫做ubuntu firewall,但它本身并沒有防火牆的功能,它隻是一個管理netfilter防火牆的工具,其核心還是netfilter的iptables。這一點在ufw的man中很容易發現,ufw是管理netfilter的一個程式而已,此工具的目的在于幫助使用者簡化iptables的複雜使用方法。
在說ubuntu ufw之前還是要說一下centos中的iptables,在centos中,iptables規則是從一個檔案(/etc/sysconfig/iptables)中,從上到下讀取配置的,後一條的規則能覆寫(override)前一條規則,例如預設規則下有2條拒絕規則:
-a input -j reject --reject-with icmp-host-prohibited
-a forward -j reject --reject-with icmp-host-prohibited
這兩條規則的含義是拒絕其他不符合規則的資料包,并且給被拒絕的主機發送一條icmp host prohibited的消息。并且這兩條規則可以認為是iptables對預設規則的補充,因為在這些預設規則之前,有:input accept [0:0]這樣的規則,這些規則表示預設全部允許。
那說了這麼多,到底要表達什麼呢?不知道有沒有這樣的印象,就是在centos中直接使用iptables指令插入一個規則,并沒有起作用,原因就是它預設被插入到了reject規則的下面?例如執行“iptables -a input -p tcp -m state --state new -m tcp --dport 8088 -j accept”卻發現不好用,原因是它插入到“-a input -j reject --reject-with icmp-host-prohibited”的下面,要想好用,那必須插入到它的前面,例如執行“iptables -i input -p tcp -m state --state new -m tcp --dport 8088 -j accept”,這樣它就會被添加到input鍊的最前端,也就起到預期的作用了。
現在再說ubuntu ufw。ubuntu ufw這個程式有點奇怪,它總是像ubuntu系統一樣,喜歡everything included,盡管ufw也不是簡單的included,ufw自己做了一些類似腳本的東西以及有一堆相關的檔案,它稱之為ufw-framework,可以通過man ufw-framework看到它的介紹資訊和相關檔案,可以看到它不當作普通服務運作而是當作腳本運作(例如man中提到的a standard sysv style initscript used by the ufw command),如果想深入研究一下的話可以自己慢慢看man page以及檢視相關的檔案和資料。
終于到了在這裡簡潔的介紹一下ufw到底如何去用的時候了。本文隻講順序問題不講文法問題,文法問題可以自己查詢man page或者其他網站的精彩文章。這裡隻說一些别的文章上不說的地方,從實際生産環境和多次測試得來經驗。
那iptables通過-a和-i區分插入還是添加,ufw也是有的,而且ufw的本質還是跟iptables風格一樣的配置檔案(這個檔案是/lib/ufw/user.rules,這個檔案就像centos下的/etc/sysconfig/iptables檔案一樣,記錄着使用者自定義的規則),具體什麼内容什麼文法自己可以去檢視。
此處以ssh預設端口22為例,列舉一下允許所有主機通路本機22端口但禁止某一台主機(10.20.0.1)通路22端口的例子。
如果是初次配置ufw防火牆,那麼可以這麼做:
sudo ufw reset#重置防火牆
sudo ufw enable#啟用防火牆
sudo ufw default reject#配置預設規則,拒絕
sudo ufw deny from 10.20.0.1#拒絕某ip通路,或執行sudo ufw deny from 10.20.0.1 to 10.20.0.130 port 22
sudo ufw allow 22/tcp#允許所有主機通路22端口
sudo ufw status#檢視ufw狀态
如果ufw已經被配置過,規則已經有了,那就這麼做:
sudo ufw status numbered#按照數字書序檢視ufw狀态,注意帶v6的不用管
sudo ufw insert 1 deny from 10.20.0.1#或者sudo ufw insert 1 deny from 10.20.0.1 to 10.20.0.130 port 22
sudo ufw allow 22/tcp
sudo ufw status
經過上述配置以後,如/lib/ufw/user.rules檔案會像下面顯示:
### tuple ### deny any 22 10.20.0.130 any 10.20.0.1 in
-a ufw-user-input -p tcp -d 10.20.0.130 --dport 22 -s 10.20.0.1 -j drop
-a ufw-user-input -p udp -d 10.20.0.130 --dport 22 -s 10.20.0.1 -j drop
### tuple ### allow tcp 22 0.0.0.0/0 any 0.0.0.0/0 in
-a ufw-user-input -p tcp --dport 22 -j accept
上面的###開始的注釋能使ufw正确識别通過ufw指令添加的規則,自己可以手動用iptables指令去改寫。是以通過指令也是可以添加這樣的規則的。
例如:
iptables -i ufw-user-input -p tcp -d 10.20.0.130 --dport 22 -s 10.20.0.1 -j drop
iptables -i ufw-user-input -p udp -d 10.20.0.130 --dport 22 -s 10.20.0.1 -j drop
iptables -i ufw-user-input -p tcp --dport 22 -j accept
為何能手動改寫?原因可以通過先啟用ufw後再用iptables-save指令檢視:
-a ufw-user-input -s 10.20.0.1/32 -d 10.20.0.130/32 -p tcp -m tcp --dport 22 -j drop
-a ufw-user-input -s 10.20.0.1/32 -d 10.20.0.130/32 -p udp -m udp --dport 22 -j drop
-a ufw-user-input -p tcp -m tcp --dport 22 -j accept
-a ufw-user-limit -m limit --limit 3/min -j log --log-prefix "[ufw limit block] "
-a ufw-user-limit -j reject --reject-with icmp-port-unreachable
-a ufw-user-limit-accept -j accept
通過這一段資訊可以發現,其實這跟/etc/sysconfig/iptables檔案真的一樣。
簡單一句話,就是先deny,後allow,deny規則插入到allow規則前面,這樣才能起到禁止的作用。
文中講的不是特别詳細,但絕對能有啟發作用,希望當你通過ufw設定deny規則不好用時,可以想起這篇文章,哈哈。
一些可用的參考或資料:
tag:ubuntu ufw用法,ufw規則無效,ubuntu配置防火牆,ubuntu ufw原理,ubuntu ufw規則順序
--end--