歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Unix知識 >> 關於Unix >> 用IPFW實現BSD防火牆

用IPFW實現BSD防火牆

日期:2017/2/28 11:14:16   编辑:關於Unix


FreeBSD操作系統本身帶有二種內置的IP信息包檢查機制:ipfw和ipfilter。在創建決定允許哪些信息包進入系統、哪些信息包會被拒之系統門外的規則集方面,二種機制各有自己獨特的語法。在這裡,我們將討論如何使用ipfw配置系統的防火牆。
在能夠使用ipfw防火牆機制之前,我們需要在FreeBSD的內核配置文件中添加一些選項,並重新編譯內核。如果不太清楚如何編譯FreeBSD的內核,請參閱相關的手冊。
可供ipfw使用的選項有好幾個,我們首先從討論LINT開始。在這裡,我通過使用“/”符號進行搜索,以便能夠快速地發現恰當的小節:
cd /usr/src/sys/i386/conf
more LINT
/IPFIREWALL
# IPFIREWALL和ipfw軟件,這二者就可以支持IP防火牆的構建。IPFIREWALL_VERBOSE向
# 系統的注冊程序發送注冊信息包,IPFIREWALL_VERBOSE_LIMIT限制一台機器注冊的次
# 數。注意:如果沒有在啟動時添加任何允許IP訪問的規則,IPFIREWALL的缺省配置是
# 禁止任何IP數據包進出系統的,這時你甚至不能訪問網絡中的其他機器。建議首次使
# 再在/etc/rc.firewall仔細地調整防火牆的設置。IPFIREWALL_DEFAULT_TO_ACCEPT使
# 得缺省的規則允許所有形式的訪問。在使用這一變量時應該非常小心,如果黑客能夠
# 突破防火牆,就能任意訪問你的系統。
要啟用ipfw,必須設置IPFIREWALL選項,它將通知操作系統的內核檢查每個IP數據包,將它們與規則集進行比較,通過添加IPFIREWALL_VERBOSE選項包括注冊支持是一個好主意,還應該通過添加IPFIREWALL_VERBOSE_LIMIT選項來限制內核注冊的數據包的數量。
除非在規則集中進行了特別的說明,缺省情況下ipfw將阻塞所有的IP數據包。由於缺省設置可以仔細地控制哪些數據包會被接受,因此我非常喜歡它。我不喜歡內核會接受自己都不清楚內容的數據包,如果需要的數據沒有被系統接受,會得到系統的提示,並修改規則集使系統可以接受它們。這時,如果有沒有預料到的數據包通過系統也不會知道。因此,我不會通過包括IPFIREWALL_DEFAULT_TO_ACCEPT選項來繞過缺省的設置。
# IPDIVERT啟用由ipfw divert使用的轉向IP套接字。這一選項需要與natd聯合使用。由
# 於在本例中建立的防火牆僅用於保護一台機器,因此不需要這個選項。
# IPSTEALTH啟動支持秘密轉發的代碼,這一選項在使防火牆不被traceroute和類似工具發現時很有用。
這是一個非常有趣的選項,因此我將在防火牆中包含這一選項,並在對防火牆進行測試時看看它的工作原理。
# 接受過濾器中的靜態連接
# options ACCEPT_FILTER_DATA
# options ACCEPT_FILTER_HTTP
在這台計算機上運行的不是互聯網服務器,因此無需在編譯時包括這二個選項。
# 下面的選項和系統級變量控制系統如何處理適當的TCP數據包。
#
# TCP_DROP_SYNFIN可以支持包含有SYN+FIN的TCP數據包,它使nmap不能識別TCP/IP棧,# 但可以破壞對RFC1644擴展的支持,建議不要在互聯網服務器中使用。
#
# TCP_RESTRICT_RST支持阻止TCP RST棧的洩出,對於需要大量SYN的系統或者不希望被簡單地掃描到端口的系統非常有用。
我將在防火牆中包括這些選項,在測試防火牆時,仔細看看它們有什麼作用。
# ICMP_BANDLIM根據帶寬限制產生icmp錯誤。一般情況下我們需要這個選項,它有助於
# 你的系統免受D.O.S.攻擊。
#
options ICMP_BANDLIM
FreeBSD內核缺省支持這一選項。
# DUMMYNET啟動“dummynet”帶寬限制軟件。還需要有IPFIREWALL選項的支持
# BRIDGE啟動以太網卡之間的橋接功能
在本例中我不會選這二個選項,因為在獨立的計算機系統上無需對流量進行控制。
在重新編譯FreeBSD內核之前,我將在內核配置文件中添加下面的內容:
#以缺省的、拒絕所有數據包方式啟動IPFW
options IPFIREWALL
options IPFIREWALL_VERBOSE
options IPFIREWALL_VERBOSE_LIMIT=10
#隱藏防火牆
options IPSTEALTH
#使不被nmap發現,如果是互聯網服務器則去掉該選項。
options TCP_DROP_SYNFIN
#防止端口掃描
options TCP_RESTRICT_RST
/firewall
firewall_enable
(布爾型)如果不想在系統啟動時加載防火牆規則集,將其值設置為NO;否則,將其設置為YES。如果它被設置為YES,而內核在編譯時沒有使用IPFIREWALL選項,ipfw內核模塊將自動被加載。
firewall_script
(字符串型)如果要運行一段防火牆腳本程序,而不是/etc/rc.firewall,將這一變量設置為腳本程序的路徑全名。
firewall_type
(字符串型)從/etc/rc.firewall或包含規則集的文件中的防火牆類型中指定防火牆類型。/etc/rc.firewall中可選的防火牆類型為:open-不限制IP訪問;closed-禁止除通過lo0進行的之外的所有IP服務;client-對工作站的基本保護;simple-對LAN的基本保護。如果給的是一個指定的文件名,則必須使用全路徑名。
由於我希望系統啟動時加載防火牆規則,因此將把firewall_enable變量的值設置為YES。由於要使用自己的規則集,需要指定使用firewall_type創建的文件的全路徑名。
firewall_quiet
(布爾型)如果設置為YES,則系統在啟動時,不會在控制台上顯示ipfw規則。
由於會顯示加載的各條規則,將這個變量設置為YES是一個好主意。如果相關規則中出現了錯誤,則在這個錯誤之後的所有規則都不會被加載。如果在啟動時看著屏幕,就會在成功加載的最後一條規則之後看到一個ipfw語法消息。這樣就可以在規則集中發現出現的錯誤,然後重新啟動機器,使所有的規則都能夠被成功地加載。
firewall_logging
(布爾型)設置為YES會啟動ipfw事件日志功能,與IPFIREWALL_VERBOSE內核選項的功能相同。
tcp_extensions
(布爾型)缺省狀態下被設置為NO。設置為YES可以啟動由RFC 1323定義的一些TCP選項。如果連接有隨機的問題出現,將其重新設置為NO,看是否能夠解決問題,因為一些軟、硬件問題都與這個選項有關。
log_in_vain
(布爾型)缺省狀態下設置為NO。設置為YES將把對端口的連接嘗試記入日志中。
tcp_keepalive
(布爾型)缺省狀態下設置為YES。設置為NO會禁止對空閒的TCP連接的探查。
tcp_drop_synfin
(布爾型)缺省狀態下設置為NO。設置為YES會使內核忽略有SYN和FIN標志的TCP幀。 雖然這樣會提供操作系統的指紋,但會使一些正常的應用軟件出毛病。只有在編譯內核時使用了TCP_DROP_SYNFIN選項,該選項才有效。
由於在內核中添加了TCP_DROP_SYNFIN選項,我將這一變量的值設置為YES。如果在計算機上運行互聯網服務器軟件,應該去掉這一選項。
tcp_restrict_rst
(布爾型)缺省狀態下設置為NO。設置為YES將使內核在響應無效的TCP數據包時不能輸出TCP RST幀。只有在編譯內核時使用了TCP_RESTRICT_RST選項,這一選項才有效。
icmp_drop_redirect
(布爾型)缺省狀態下設置為NO。設置為YES將使內核忽略ICMP REDIRECT信息包。
icmp_log_redirect
(布爾型)缺省狀態下設置為NO。設置為YES將使內核在日志中記錄ICMP REDIRECT信息包。由於日志是沒有什麼限制的,因此只有在對網絡維護時才會使用這一選項。
#用於支持ipfw的選項
firewall_enable="YES"
firewall_script="/etc/rc.firewall"
firewall_type="/etc/ipfw.rules"
firewall_quiet="NO" #對現有的規則滿意後將其值改為YES
firewall_logging_enable="YES"
#附加的防火牆選項
log_in_vain="YES"
tcp_drop_synfin="YES" #如果要創建互聯網服務器,將其值改為NO。
tcp_restrict_rst="YES"
icmp_drop_redirect="YES"
在重新啟動機器運行新的內核之前,有一點需要注意。如果LINT文件顯示出“YOU WILL LOCK YOURSELF OUT”(你將封鎖自己),說明新的規則已經起作用了。在重新創建允許所需的IP數據包進入系統之前,所有的IP數據包都不能進入或傳出計算機。如果想從互聯網上收發電子郵件和下載資料,就需要在重新啟動系統之前完成這些工作。
創建一個好的規則集是一件技術性很強固的工作。如果是第一次創建防火牆,需要有大量的時間進行練習,就會發現ipfw所使用的邏輯與你認為的邏輯不完全相同。
此外,防火牆並非是安裝後就一勞永逸了,需要花些時間對它進行優化,在它不能完成你預期的任務時多想想這是為什麼。一旦用有防火牆的新內核啟動機器後,你可能希望完成下面的三項工作。
▲系統地在規則集中添加新的規則,測試每條規則的作用,確保只有你需要的數據包才能夠出入你的系統。
▲決定你要將哪些IP數據包記入日志並查看日志文件,隨著不斷發現你禁止或允許的一些數據包出入系統,會不斷地修改規則。
▲一旦對防火牆允許或不允許通過哪些數據包滿意了,就需要測試防火牆的性能是否能夠令人滿意。
好了,下面我要重新啟動機器加載新的內核。在啟動時盯著屏幕,在NIC加載後會看到下面的信息:
Flushed all rules.
00100 allow ip from any to any via lo0
00200 deny ip from any to any to 127.0.0.0/8
Firewall rules loaded, starting divert daemons:.
Additional routing options: tcp extensions=NO ignore ICMP redirect=YES TCP keepalive=YES restrict TCP reset=YES drop SYN+FIN packets=YES.
Additional TCP options: log_in_vain=YES.
firewall_script="/etc/rc.firewall"
在啟動時系統會讀取/etc/rc.firewall文件,該文件包含下面的內容:
############
# Flush out the list before we begin.
#
${fwcmd} -f flush
############
# 只有在極少數的情況下才需要改變這些規則
#
${fwcmd} add 100 pass all from any to any via lo0
${fwcmd} add 200 deny all from any to 127.0.0.0/8
由於規則100和規則200在啟動時會用到,因此在創建規則時應該從規則300開始。在創建規則之前,我會用下面的方法分二次檢查ipfw是否缺省地禁止所有的信息包出入我的計算機系統。可以通過運行ipfw show命令來進行檢查:
ipfw show
ipfw: socket: Operation not permitted
似乎只有超級用戶才有查看防火牆規則的權限,因此我將再次以超級用戶再身份次進行檢查:
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
65535 115 14092 deny ip from any to any
確實已經禁止所有的信息包出入計算機系統,我再來試著使用一下網絡連接。
Alert!: Unable to access document.
好了,名字解析也無效,我們再試試ping吧:
ping 24.141.116.1
PING 24.141.116.1 (24.141.116.1): 56 data bytes
ping: sendto: Permission denied
ping: sendto: Permission denied
^C
--- 24.141.116.1 ping statistics ---
2 packets transmitted, 0 packets received, 100% packet loss
由於我是以超級用戶的身份運行最後一個ping的,因此ipfw確實已經禁止所有信息包的出入,我已經完全不能使用網絡連接了。現在我們來創建一個允許收發我需要的IP信息包的規則集。
有二種方式可以創建被ipfw讀取的規則:
如果已經在使用ipfw,不用重啟動機器就能使規則生效。但是,如果重新啟動機器後,添加的規則就會丟了。
你還可以在讓ipfw讀取的文件中添加一條規則,這樣只有機器重新啟動後,新添加的規則才能生效。
firewall_type="/etc/ipfw.rules"
因此,我將創建一個名字為/etc/ipfw.rules的文件。
我們已經通過安裝帶缺省的禁止所有數據包出入的策略的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
kern_securelevel="3"
然後重新執行killall init命令。
重新登錄後,我將嘗試能否向外發送IP數據包並收到相應的應答數據包:
Alert!. Unable to access document.
也許是我的系統上沒有安裝DNA域名解析功能的緣故,我再使用IP地址試一下:
lynx 216.136.204.21
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
這裡我來解釋一下這一奇怪的現象吧。很明顯的是,一些數據包進入或發出了計算機系統,但一些則沒有。我們來仔細發分析一下我在上面的每個例子中使用的協議。
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)
現在,我們來試試這個選項:
;; ->;>;HEADER<<- opcode: QUERY, status: NOERROR, id: 39772
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 5, ADDITIONAL: 5
在我們使用TCP連接發出一個DNS請求時,名字解析過程運行得很好。我們再在沒有帶s選項的情況下看使用UDP時的情況如何:
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
你也許還注意到了標號為00302和65535的規則後面都跟有數字,其中第一個數字為數據包的數量,第二個數字為符合每條規則的字節數。被規則65535拒之門外的數據包都是失敗的UDP和ICMP數據包。
向規則集中添加新規則時,需要使用ipfw中的zero命令將這些計數器清零,這樣,當對新添加的規則進行測試時,就能知道哪些規則後面又出現了新的統計數字。
#允許 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命令重新加載規則集,看名字解析是否已經可以成功地運行了:
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命令重新再試一次:
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連接的條目。
我們已經建立了一個可以運行的網絡連接,但這個規則集仍然有很大的改進余地,下面我們將就這方面的問題進行更詳細的討論。
上面我們已經創建了一個規則集,使ipfw能夠允許對發出的互聯網請求進行響應,並能進行DNS名字解析。下面我們將仔細調節已經創建的規則集的性能,並通過內置的登錄工具對它進行測試。
創建的規則集已經可以起作用了,因此可以在DHCP規定的時間用完之前使用互聯網連接了。時間用完後,互聯網連接就不能再使用了。要搞清楚是哪條規則實現互聯網連接的,對DHCP的基本工作原理有一定的了解是很有必要的。
DHCP使用UDP數據包,意味著動態規則和狀態表在這裡是不起作用的。因此必須允許在我的計算機和ISP的DHCP服務器之間傳輸UDP數據包。DHCP需要二個端口:DHCP客戶端使用端口68,ISP的DHCP服務器使用端口67。
為了搞明白DHCP的工作原理,我們來看一下我的計算機的DHCP“租用”文件:
more /var/db/dhclient.leases
lease {
interface "ed0";
fixed-address 24.141.119.162;
option subnet-mask 255.255.252.0;
option time-offset -18000;
option routers 24.141.116.1;
option domain-name-servers 24.226.1.90,24.226.1.20,24.2.9.34;
option host-name "my_hostname";
option domain-name "my_domainname";
option broadcast-address 255.255.255.255;
option dhcp-lease-time 604800;
option dhcp-message-type 5;
option dhcp-server-identifier 24.226.1.41;
renew 2 2001/5/15 13:12:11;
rebind 5 2001/5/18 04:12:11;
expire 6 2001/5/19 01:12:11;
}
DHCP服務器提供了一個IP地址、子網掩碼、缺省的網關地址、三個DNS服務器的IP地址、我的主機名和提供服務的DHCP服務器的IP地址。由於DHCP“租用”契約是一種真正的“契約”,這意味著我必須保存好這些信息,最後三行內容與我的DHCP客戶端如何重新修改“租用”契約有關。
以renew開頭的這一行向我的DHCP客戶端表明它何時應該結束,並更新其“租用”契約,這一時間要早於expire行中列出的時間。在2001年5月15日13時12分11秒,我的計算機將會向IP地址為24.226.1.41的DHCP服務器上的端口67發送UDP數據包,因此需要添加一條規則允許向外發送UDP數據包。如果DHCP服務器收到了我的計算機發送的UDP數據包,它應該對要求更新“租用”契約的要求作出響應,並且以UDP數據包形式將此信息發回到我的計算機上的68端口。因此,我另外還需要在規則集中添加一規則,允許ipfw對此信息作出反應。
如果不在規則集中添加這些規則,或者由於其他原因DCHP服務器沒有對我的計算機發出的更新“租用”契約的要求作出響應,rebind行將在2001年5月18日4時12分11秒啟動,這時,我的DCHP客戶端就會開始擔心“租用”期滿,將會向DHCP服務器發出更多的UDP數據包,只是這次將不再向特定的DHCP服務器發送數據包,而是會向255.255.255.255發送數據包,任何服務器都可以響應發出的請求。
如果沒有DHCP服務器進行響應,我的計算機的契約會在2001年5月19日1時12分11秒結束,這意味著我的DCHP客戶端不能保證還可以繼續使用這些租用信息。這時,會有幾種情況出現。客戶端將繼續試圖與DHCP服務器聯系,向端口67發送UDP數據包。它將繼續試圖用ping與缺省的網關聯系,檢查其IP地址是否仍然有效。在最壞的情況下,我的客戶端的IP地址已經無效,DHCP服務器的應答將作為廣播被IP地址為255.255.255.255的機器的68端口接收。
既然已經明白了其工作原理,我們就清楚應該在規則集中添加什麼樣的規則了。在添加規則前,應該對規則進行仔細的檢查,因為規則的順序已經越來越重要了。規則集中的規則越多,前面的規則覆蓋後面新添加的規則的可能性也就越大。設計一個好的規則集的訣竅是讓你希望的數據包使用盡可能少的規則,如果添加的規則過多,盡管防火牆仍然會起作用,但這樣會加重ipfw不必要的負擔,因為在找出一個數據包適應的規則前它需要讀取更多的規則。此外,在你希望搞清楚到底是哪一條規則使系統不能按你的意願運行時,規則太多了會相當的麻煩。
我將以超級用戶的身份運行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
00403 0 0 allow udp from any to any out
65535 0 0 deny ip from any to any
由於我需要向外發送UDP數據包,因此需要指明DHCP端口號和DHCP服務器的IP地址,作為超級用戶,我將考慮在/etc/ipfw.rules文件中添加下面的內容:
#allow DHCP
add 00500 allow udp from any 68 to 24.226.1.41 67 out via ed0
add 00501 allow udp from 24.226.1.41 67 to any 68 in via ed0
這些規則可以說是使DHCP客戶端更新其“租用”契約所需要的最少的規則了,是否需要添加更多的規則會因DHCP服務器可靠性的不同而有所不同。如果DHCP服務器總是能夠響應我的更新請求,我也就無需采用發送UDP廣播、ping缺省的網關或者接收UDP廣播這些方式了。如果DHCP服務器的可靠性不高,那就還需要添加下面的規則:
add 00502 allow udp from any 68 to 255.255.255.255 67 out via ed0
add 00503 allow udp from any 67 to 255.255.255.255 68 in via ed0
由於我使用的DHCP服務器是相當可靠的,因此不需要立即添加00502和00503這二條規則。我只是反復提醒自己,在ISP的DHCP服務器出了問題或其IP地址有變化的時候就需要考慮這二條規則了。
在保存修改之前,我將把00500和00501二條規則與其余的規則進行比較,以確保它們之間沒有任何沖突和重復之處,結果00403和00500之間確實存在著部分重復:
add 00403 allow udp from any to any out
add 00500 allow udp from any 68 to 24.226.1.41 67 out via ed0
因為規則00403允許我的計算機發出任何的UDP數據包,ipfw就不會讀取其他的只從端口68發送UDP數據包的規則,在這裡,就需要在使用數量最少的規則還是使用把各種可能都考慮在內的數量最多的規則之間進行選擇了。
規則00403是在創建允許DNS解析時添加的,如果刪除了它,就需要添加三條規則才能實現向三個DNS服務器發送UDP數據包的功能。另外,如果還需要向其他的服務器發送UDP數據包,我就必須再添加規則。因此,如果不使用這樣一條“通用”的規則,ipfw規則集中就會包含一些多余的規則,使系統負擔不必要的負荷。
這樣作也不符合使用最少數量規則的原則,但我們必須仔細審查一下“通用”規則帶來的潛在後果。如果我限制系統接受UDP數據包,向外發送UDP數據包是不會有什麼危險的。例如,規則00403允許我的計算機向外發送任何數據包,但規則00400、00401、0402和00501保證我的計算機只能接受我的ISP的3台DNS和一台DHCP服務器發送的UDP數據包。因此,對於我的單獨運行的FreeBSD計算機而言,這個規則集還是比較合理的。
如果我在FreeBSD防火牆後面添加新的客戶端機器,就需要重新考慮這個規則集。例如,微軟的客戶端會發送數量不等的UDP數據包通報其共享資源,讓這些數據包通過防火牆發送出去,對我而言是不負責任並具有一定安全風險的。在本例中,我將使用只能發出我需要發出的UDP數據包的規則,而刪除可以發出任意UDP數據包的規則。
由於我現在保護的只是一台單獨的FreeBSD計算機,因此我將保留規則00403,刪除規則00500,因為系統永遠都不會讀取到它。我將對規則進行如下的改變:
#允許DHCP 操作
add 00501 allow udp from 24.226.1.41 67 to any 68 in via ed0
保存所作的改變,並通過使用killall init命令進行測試,以超級用戶身份重新登錄,看看所作改變的效果。
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 8 1322 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 8 469 allow udp from any to any out
00501 4 1592 allow udp from 24.226.1.41 67 to any 68 in recv ed0
65535 29 8591 deny ip from any to any
我好象從IP地址為24.226.1.90的DNS服務器收到了8個UDP數據包,從IP地址為24.226.1.41的DHCP服務器收到了4個UDP數據包。現在,我們再來看看DHCP的“租用”時間問題。
more /var/db/dhclient.leases
renew 3 2001/5/16 07:46:25;
rebind 5 2001/5/18 08:50:46;
expire 6 2001/5/19 01:12:14;
在執行killall init命令時,我成功地找到了DHCP服務器並更新了其“租用”時間,因此,我的DHCP規則是比較成功的。
由於我的規則集還拒絕收發所有的ICMP數據包,下面我們再來研究一下允許ICMP數據包收發的問題。阻止收發ICMP數據包並不是一件好事,因為它會破壞Path-MTU發現並阻止Source Quench信息。另外,ICMP使用types和codes來指定真正的ICMP信息。
在創建與ICMP有關的規則時,只能指定ICMP數據包的type而不能指定它的code。我將以超級用戶的身份登錄,在/etc/ipfw.rules文件中添加下面的內容:
#允許接受一些ICMP types (不支持codes)
###########允許雙向的path-mtu
add 00600 allow icmp from any to any icmptypes 3
add 00601 allow icmp from any to any icmptypes 4
我需要考慮是否需要ping我的網絡之外的主機或運行traceroute命令,由於二者都需要,並希望收到相應的應答,但我並不希望互聯網上的所有用戶都可以對我運行ping 或traceroute命令,因此,我需要添加下面的規則:
###########允許我對外部的主機運行ping命令,並得到相應的應答
add 00602 allow icmp from any to any icmptypes 8 out
add 00603 allow icmp from any to any icmptypes 0 in
###########允許我運行traceroute命令
add 00604 allow icmp from any to any icmptypes 11 in
ICMP type 8是一個重復的請求,ICMP type 0是反復的應答。由於我只允許反復地發出請求並接受應答,從而我可以ping別人而別人不能ping我。
在運行traceroute命令時,就會向外發出UDP數據包,這一點在規則00403中已經得到了保證。如果希望能夠獲得所有應答信息,我還必須允許系統接受所有的CMP type 11數據包。
好了,我們現在保存所作的修改,並使用ipfw zero命令對ipfw計數器重新復位。然後運行killall init命令,並試運行ping和traceroute命令:
64 bytes from 216.136.204.21: icmp_seq=0 ttl=239 time=85.250 ms
64 bytes from 216.136.204.21: icmp_seq=1 ttl=239 time=88.338 ms
64 bytes from 216.136.204.21: icmp_seq=2 ttl=239 time=83.757 ms
^C
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max/stddev = 83.757/85.782/88.338/1.908 ms
1 10.69.4.1 (10.69.4.1) 8.678 ms 8.739 ms 10.055 ms
6 216.197.153.65 (216.197.153.65) 14.112 ms 13.544 ms 42.612 ms
13 216.34.183.66 (216.34.183.66) 37.624 ms 39.455 ms 40.243 ms
15 64.15.192.34 (64.15.192.34) 79.431 ms 80.981 ms 115.289 ms
一切正常。現在我將以超級用戶的身份來看看系統使用了哪些規則。
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 29 5847 allow udp from 24.226.1.90 53 to any in recv ed0
00401 2 163 allow udp from 24.226.1.20 53 to any in recv ed0
00402 3 397 allow udp from 24.2.9.34 53 to any in recv ed0
00403 93 4712 allow udp from any to any out
00501 0 0 allow udp from 24.226.1.41 67 to any 68 in recv ed0
00600 3 168 allow icmp from any to any icmptype 3
00601 0 0 allow icmp from any to any icmptype 4
00602 3 252 allow icmp from any to any out icmptype 8
00603 3 252 allow icmp from any to any in icmptype 0
00604 53 2968 allow icmp from any to any in icmptype 11
65535 29 8591 deny ip from any to any
我們可以發現,運行ping命令時使用了三個反復的請求數據包(規則00602)和三個反復的應答數據包(規則00603)。此外,有53個ICMP type 11數據包響應traceroute命令(規則00604),然而,由於我不能夠在規則中指定具體的code,因此我不能說出為什麼會接收到三個“找不到目標”的信息。
通過上述的三篇文章,我簡要地介紹了如何使用FreeBSD操作系統自帶的IPIW實現防火牆,希望能夠起到拋磚引玉的作用,使大家充分認識FreeBSD中的網絡安全機制。
Copyright © Linux教程網 All Rights Reserved