歡迎您光臨本站 註冊首頁

用IPIW實現BSD防火牆(中)

←手機掃碼閱讀     火星人 @ 2014-03-12 , reply:0
  我們已經通過安裝帶預設的禁止所有數據包出入的策略的ipfw,使所有的IP信息包都不能出入我的計算機系統,下面,我們再創建一個能被ipfw讀取的規則集,使所需要的信息包能夠出入計算機系統。

由於在創建規則集方面沒有所謂「最合適」的方法,因此我不能說明如何在規則集中添加「萬能」的規則,而只能說明一下在創建規則集時需要遵循的原則。在這裡,我假設你已經掌握了ipfw的語法,能夠理解我創建的規則。如果對這些知識不大理解,請參閱相關的資料。

在創建規則集時需要注意的是,規則是按給定數字行號的順序被系統讀取的,直到信息包符合一條規則,ipfw才會停止讀取規則,也就是說,如果規則400和規則800都適用於一個信息包,系統總是會用到規則400而不會讀取規則800。因此,在添加新的規則之前,需要仔細地審查原來的規則,確保新的規則不會被原來的規則所覆蓋。

此外,規則對所有的連接-也就是在ifconfig -a的輸出中所列出的所有連接都是適用的。如果在象我這樣只有一個連接的計算機上自然不會有什麼問題,但如果在有多個連接的計算機上,就會有所不同。例如,你的機器上可能有二個連接,一個是互聯網連接,一個是內部區域網連接,每個不同的連接需要不同的安全規則,這一點可以通過在ipfw的規則中指定連接的名字來實現。

我的機器是一台運行FreeBSD 4.2、配置有互聯網連接的單台計算機。由於這是我在家裡使用的計算機,因此可以對向互聯網上發送的信息包的類型不作任何限制,而只需要它能夠接收是對我發出的信息包有效響應的信息包。

要完成這一任務最好的方法之一是利用ipfw的動態功能。如果你對這一概念還不太熟悉,下面我將對它作一番詳盡的解釋。

如果使用「動態」的規則,當我向互聯網上發送一個信息包時,ipfw將在其狀態表中添加一個記錄,其中包括有發送的信息包的目標計算機的IP地址和使用的目標計算機的埠。當有信息包從互聯網上返回時,如果其IP地址、埠號與在狀態表中記錄得不一致,計算機就不會接收這一信息包。動態規則只適用於TCP信息包,而不適用於UDP信息包,原因是UDP不創建一個虛擬的連接,它被稱作是「無狀態」協議,也就不能使用「狀態表」。

ipfw手冊中的例子部分給出了三條用來創建這個動態信息包過濾裝置的規則。由於我決定在/etc/ipfw.rules中創建自己的規則,因此,需要以超級用戶的身份創建包含下面內容的文件:

# 只允許向外發送信息包
add 00300 check-state
add 00301 deny tcp from any to any in established
add 00302 allow tcp from any to any out setup keep-state

由於規則100和規則200是預先包含在/etc/rc.firewall中的,因此,我自己添加的規則將從行號300開始。我將給相關的規則以300、301、302等行號,等規則越來越多或創建不相關的規則時,我就會把行號跳到400。不過,從理論上說你可以任意給規則指定行號,只要該行號沒有在該規則集文件中出現過就行。

你可能已經注意到規則集出現了幾個在ipfw手冊中定義的關健字:

check-state:檢查信息包是否與動態規則集匹配。如果匹配則搜索中止,否則繼續搜索下一條規則。
keep-state:根據匹配情況,防火牆將創建一條動態規則,其功能是在源、目的IP地址/埠之間使用同一協議的流量,這一規則是具有一定的生命周期的(由一系列sysctl(8)變數控制),每當發現匹配協議時其生命周期都會刷新。
established:只適用於TCP信息包,與有RST或ACK位的信息包進行匹配。
setup:只適用於TCP信息包,與有SYN位但不具有ACK位的信息包進行匹配。

換句話說,當有信息包到達網路連接后,ipfw將首先檢查它是否在狀態表中,如果在狀態表中,則允許它進入系統(行號為300的規則執行這一檢查工作)。如果它不在狀態表中,而且設置了RST或ACK位,ipfw將不允許它進入系統,因為它不是我創建的連接的有效響應(規則301完成這一工作)。只有當ACK標誌沒有設置,(這意味著它要初始化連接)並且這一信息包是由系統向外發送的時,才允許它向外發送;如果有信息包符合這一規則,則它被加入狀態表中。

我們來看看添加上這些規則后對系統有什麼影響。對規則集進行檢查沒有錯誤后,保存文件,然後輸入下面的命令:

killall init

敲Enter鍵,然後輸入:

exit

然後仔細觀察啟動信息,確保規則在載入時沒有出現出錯信息。如果在規則載入過程中出現了錯誤信息,那麼可能是系統的安全級別被設置為3或更高了,必須首先在/etc/rc.conf文件中找到下面的這行內容,將kern_securelevel改為較小的值:

kern_securelevel="3"

然後重新執行killall init命令。

重新登錄后,我將嘗試能否向外發送IP數據包並收到相應的應答數據包:

ping www.freebsd.org
ping: cannot resolve www.freebsd.org: Host name lookup failure

lynx www.freebsd.org
Alert!. Unable to access document.

也許是我的系統上沒有安裝DNA域名解析功能的緣故,我再使用IP地址試一下:

lynx 216.136.204.21

這次我發現自己在www.freebsd.org的主頁上了。我們再來試著ping一下這個IP地址吧:

ping 216.136.204.21
PING 216.136.204.21 (216.136.204.21): 56 data bytes
ping: sendto: Permission denied
ping: sendto: Permission denied
ping: sendto: Permission denied
^C
--- 216.136.204.21 ping statistics ---
3 packets transmitted, 0 packets received, 100% packet loss

這裡我來解釋一下這一奇怪的現象吧。很明顯的是,一些數據包進入或發出了計算機系統,但一些則沒有。我們來仔細發分析一下我在上面的每個例子中使用的協議。

由於我只能使用其IP地址訪問www.freebsd.org的網站,因此域名解析沒有成功。當我使用DNS服務時,我會向我的ISP的DNS伺服器發送域名查找請求,該DNS伺服器應該向我的機器發送響應數據包。這些操作都是符合我們的規則的,由於我是在53埠發送請求的,也應該在埠53上接收到響應數據包。我將複查我發送請求的DNS伺服器:

more /etc/resolv.conf
search kico1.on.home.com
nameserver 24.226.1.90
nameserver 24.226.1.20
nameserver 24.2.9.34

似乎問題不是出在這兒,因此應該仔細地搞清楚域名解析的工作原理。我們來看一下能否從在線手冊上得到一點幫助:

apropos resolve
dnsquery(1) - 使用解析器查詢域名伺服器
res_query(3), res_search(3), res_mkquery(3), res_send(3), res_init(3), dn_comp(3), dn_expand(3) - 解析器常式
resolver(5) - 解析器配置文件
man resolver

通過多次查看,下面的內容引起了我的興趣:RES_USEVC 在查詢中使用TCP而不是UDP連接;RES_STAYOPEN RES_USEVC用它來在多次查詢期間保持TCP連接。它只在需要進行多個查詢的的軟體中有用,UDP是最常用的模式。

我可能已經發現問題出在哪了。如果DNS使用的是UDP而不是TCP,而我的規則只允許TCP協議的數據包響應我的TCP連接,域名解析就會失敗。

man dnsquery
<只顯示我們感興趣的部分>
-s 使用流格式而非信息包。它使用一個帶名字伺服器的TCP流式連接而不是UDP,這一選項會設置解析軟體選項欄位的RES_USEVC位。(預設狀態下使用UDP)

現在,我們來試試這個選項:

dnsquery -s www.freebsd.org
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 39772
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 5, ADDITIONAL: 5
;; www.freebsd.org, type = ANY, class = IN
www.freebsd.org. 49m21s IN CNAME freefall.freebsd.org.
freebsd.org. 22m43s IN NS ns1.iafrica.com.
freebsd.org. 22m43s IN NS ns2.iafrica.com.
freebsd.org. 22m43s IN NS ns.gnome.co.uk.
freebsd.org. 22m43s IN NS ns0.freebsd.org.
freebsd.org. 22m43s IN NS ns1.root.com.
ns1.iafrica.com. 1h1m3s IN A 196.7.0.139
ns2.iafrica.com. 1h1m3s IN A 196.7.142.133
ns.gnome.co.uk. 12m37s IN A 193.243.228.142
ns0.freebsd.org. 11h9m9s IN A 216.136.204.126
ns1.root.com. 1h8m12s IN A 209.102.106.178

在我們使用TCP連接發出一個DNS請求時,名字解析過程運行得很好。我們再在沒有帶s選項的情況下看使用UDP時的情況如何:

dnsquery www.freebsd.org
Query failed (h_errno=2) : Host name lookup failure

現在我們明白了,DNS使用的是UDP數據包。由於我沒有在規則集中允許使用UDP數據包,因此DNS名字解析過程不能完成。

現在既然已經解決了這個問題,我們再來看看即使在使用IP地址時也ping不通的原因何在。我們知道,ping在其數據包中使用的是ICMP而非TCP協議。如果用ping發送ICMP數據包,不在防火牆的規則面前碰一鼻子灰才怪呢。

在向規則集中添加任何新的規則前,必須以超級用戶身份重新登錄。我們來看看ipfw的輸出:

su
Password:
ipfw show
00100 0 0 allow ip from any to any via lo0
00200 0 0 deny ip from any to 127.0.0.0/8
00300 0 0 check-state
00301 0 0 deny tcp from any to any in established
00302 21 15144 allow tcp from any to any out keep-state setup
65535 142 10531 deny ip from any to any
## 動態規則:
00302 19 15040 (T 0, # 147) ty 0 tcp, 24.141.119.162 2932 <-> 216.136.204.21 80

注意一下動態規則部分,這是一個狀態表。當運行lynx 216.136.204.21命令與www.freebsd.org站點上的http埠(埠 80)進行連接時,Rule 00302允許發出setup數據包,並在狀態表中添加一個條目。所有從216.136.204.21上的埠80發出或以它為目標地址的數據包都可以進入或者發出我的計算機。

你也許還注意到了標號為00302和65535的規則後面都跟有數字,其中第一個數字為數據包的數量,第二個數字為符合每條規則的位元組數。被規則65535拒之門外的數據包都是失敗的UDP和ICMP數據包。

向規則集中添加新規則時,需要使用ipfw中的zero命令將這些計數器清零,這樣,當對新添加的規則進行測試時,就能知道哪些規則後面又出現了新的統計數字。

下面,我將添加一些允許進行DNS名字解析的規則。由於DNS使用UDP,UDP不進行連接,我不能指定只允許對我的連接的有效的響應數據包進入系統。但是,我可以限制DNS使用的埠(埠 53)進出的數據包,選擇只接受來自我的ISP的DNS伺服器的IP地址發出的數據包。運行more /etc.resolv.conf命令就能發現這些IP地址。我將在/etc/ipfw.rules文件中添加下面的內容:

#允許 DNS
add 00400 allow udp from 24.226.1.90 53 to any in recv ed0
add 00401 allow udp from 24.226.1.20 53 to any in recv ed0
add 00402 allow udp from 24.2.9.34 53 to any in recv ed0

然後,通過運行killall init命令重新載入規則集,看名字解析是否已經可以成功地運行了:

lynx www.freebsd.org
Alert!. Unable to access document.

怎麼回事?我已經在規則集中添加了允許使用UDP數據包的規則,怎麼名字解析服務仍然不行呢?我們運行ipfw show命令來看看哪條規則的後面跟有數據包計數字:

su
Password:
ipfw show
00100 0 0 allow ip from any to any via lo0
00200 0 0 deny ip from any to 127.0.0.0/8
00300 0 0 check-state
00301 0 0 deny tcp from any to any in established
00302 0 0 allow tcp from any to any keep-state setup
00400 0 0 allow udp from 24.226.1.90 53 to any in recv ed0
00401 0 0 allow udp from 24.226.1.20 53 to any in recv ed0
00402 0 0 allow udp from 24.2.9.34 53 to any in recv ed0
65535 30 2196 deny ip from any to any
## Dynamic rules:

後面跟有統計數字的唯一的規則是最後一條拒絕服務的規則,說明添加的允許UDP數據包的規則沒有作用。現在我才明白,我還沒有允許向外發送UDP數據包,沒有UDP數據包返回來也就沒有什麼好奇怪的了。下面我們再往規則集中添加一行內容:

00403 allow udp from any to any out

這樣,我的計算機就可以向外發送UDP數據包了。然後用ipfw zero清除規則後面的統計數字,運行killall init命令重新再試一次:

lynx www.freebsd.org

FreeBSD的主頁終於出現了。如果我以超級用戶的身份運行ipfw show命令,就會得到更令人滿意的輸出:

ipfw show
00100 0 0 allow ip from any to any via lo0
00200 0 0 deny ip from any to 127.0.0.0/8
00300 0 0 check-state
00301 0 0 deny tcp from any to any in established
00302 20 15061 allow tcp from any to any keep-state setup
00400 10 1882 allow udp from 24.226.1.90 53 to any in recv ed0
00401 0 0 allow udp from 24.226.1.20 53 to any in recv ed0
00402 0 0 allow udp from 24.2.9.34 53 to any in recv ed0
00403 10 591 allow udp from any to any out
65535 31 2577 deny ip from any to any
## Dynamic rules:
00302 19 15017 (T 0, # 236) ty 0 tcp, 24.141.119.162 4363 <-> 216.136.204.21 80

規則00403允許我的計算機發出DNS請求,規則00400允許接受DNS應答,規則00302建立HTTP連接,而且,我在狀態表中有了一個與216.136.204.21之間HTTP連接的條目。

我們已經建立了一個可以運行的網路連接,但這個規則集仍然有很大的改進餘地,下面我們將就這方面的問題進行更詳細的討論。


[火星人 ] 用IPIW實現BSD防火牆(中)已經有587次圍觀

http://coctec.com/docs/security/show-post-72812.html