使用Mac OS X已經半年多了,很炫是真的,很懸也不假!Mac有太多太多的特性值得讓你花大量的時間仔細琢磨,用起來讓你自豪的找不著北,最終你會深信自己是一個很時尚的人...我承認自己很土,也不是什么果粉,更不是什么達人,因此我除了使用Mac最基本的功能外,幾乎沒有去深究其它。突然間,我發現Mac居然是一個BSD,雖然這個事實我早就知道,但是也只有在我在命令行敲入man ipfw的時候,我才真的想深究一下這個手邊的Unix,于是乎,不再覺得Unix很遙遠,它居然就在手邊,于是乎,我的MacBook也就成了我的Unix試驗機了。
偉大的Unix初看很龐大,然而用起來還真的比Linux簡單,Cisco IOS這樣的網絡操作系統內核也是基于BSD的,在BSD之上出現了兩個ios,一個是Cisco的IOS,一個是Apple的iOS,足見其偉大!
一.防火墻軟件學習歷程
關于防火墻,最開始學習的是華為VRP系統的命令,那是2004年,聽講師說和Cisco命令差不多,當時我們都一準認為有抄襲的內幕,于是自學了Cisco,發現還真的很像,幾乎是一模一樣...2006年參加工作第一次看到有人在Linux終端前敲命令,我開口就給同事說,我們配路由器配防火墻就是那樣的...太丟人了,其實那是Linux而已,于是就自學了Linux,學習iptables是08年的事了。
現在想想,但凡命令行,差別都不大,如果你在windows命令行輸入netsh,結果也差不多。因此我不認為那是抄襲了,充其量是拿來主義,共同點的底層一定是相同的組件,這種組件其實就是BSD內核。最終如果你比較一下各種包過濾機制,就會發現,Cisco,H3C,Windows的都差不多,只有Linux的Netfilter是個例外。Mac OS基于BSD,因此只要懂得Cisco,Mac OS上的命令行防火墻命令也就很容易駕馭了。
二.ipfw簡介以及與Netfilter的異同
想要簡介,最好就是man一下ipfw,這里就不列舉了。最關鍵的是一個章節,那就是“PACKET FLOW”這一章節。只有你知道數據包在協議棧的哪些地方被過濾,你才能設計好良好的規則集。
相比于Netfilter的5個HOOK點,這幅圖看起來清爽多了,一個包最多經過4個HOOK點,而Netfilter則復雜的多,按照路由前,路由后以及路由結果三個要素將HOOK點劃分為5個,任何點的規則都需要你仔細考慮路由的結果以及是否可以過濾,ip_conntrack機制以及由于conntrack機制內置的動態規則加重了事情的復雜度。
現摘錄一段ipfw命令的man手冊內容:
Also note that each packet is always checked against the complete ruleset, irrespective of the place where the check occurs, or the source of the packet. If a rule contains some match patterns or actions which are not valid for the place of invocation (e.g. trying to match a MAC header within ip_input() ), the match pattern will not match, but a not operator in front of such patterns will cause the pattern to always match on those packets. It is thus the responsibility of the programmer, if necessary, to write a suit-able ruleset to differentiate among the possible places.這段話說了兩個意思,第一個意思就是ruleset是全局的,不區分HOOK點的,每一個HOOK點都要遍歷所有的ruleset中的rule;另一個意思是說需要配置者來完成一切。我們看一個簡單的規則,禁掉icmp:
ipfw add deny icmp from any to any是不是和Cisco的很像,然而卻和iptables的一點都不像。
三.ipfw的動態規則
Netfilter有ip_conntrack機制可以追蹤每一個流。這個ip_conntrack機制讓人歡喜讓人愁,于是可以在PREROUTING的raw表上配置notrack。ipfw就不一樣了,它可以在任意地方針對任意流進行track,這就是其state機制,ipfw通過keep-state來追蹤一個流,并且建立針對該包反向包的動態規則,通過check-state來匹配keep-state建立的動態規則,ipfw的state可以在任意匹配的地方被keep,所謂的keep就是建立一條動態規則,其動作就是keep-state的動作,這個比較類似Netfilter的ip_conntrack和state match的聯動機制。以下是一個man手冊中的實例,我在前面加上了注釋:
對每一個包check所有的動態創建的rule:
ipfw add check-state對本地子網始發的TCP流量放行且保持連接,創建動態rule:
ipfw add allow tcp from my-subnet to any setup keep-state禁用其它地方始發的TCP連接:
ipfw add deny tcp from any to any上述實例的分析:
內網始發一個TCP,由于沒有任何動態rule,因此直接匹配到第二個rule并且保持了這個conntrack創建了反向動態rule,該連接的返回包到達這個Box時,由于匹配到了動態rule,因此通過。如果是外網始發的TCP到達內網,將直接匹配到第三條rule。如果使用iptables的話,則如下配置:
iptables -t raw -A PREROUTING -p tcp -s ! my-subbet -j NOTRACK
iptables -A FORWARD -p tcp -m state --state ESTABLISHED -j ACCEPT
iptables -A FORWARD -p tcp -s my-subnet -j ACCEPT
iptables -A FORWARD -p tcp -j DROP使用ipfw,就不用非要在特定的HOOK點來進行track了,它可以隨時進行track,隨時進行check。ipfw可以將track和target結合在一條rule中,可以針對特定的filter rule進行track,而Netfilte的iptables卻必須將這些關聯解除。
四.ipfw和natd
使用iptables,我們可以使用nat表來配置NAT,然而使用ipfw卻不能做到這一點,在BSD中,nat只是一個target,存在用戶態的natd進程來進行nat,也可以使用ipnat來完成,不管哪種方式,都使用了divert這個動作,所謂divert,其實就是其字面含義,將控制轉發到其它的邏輯,對于nat,很常見的就是將控制轉發到natd進程。我在Mac OS上,配置以下的nat:
ipfw add divert natd all from any to any via en1
natd -interface en1其中divert natd將匹配的數據包“路由”到natd進程。至于natd進程,也可以man一下,有下列關鍵的敘述:
The natd normally runs in the background as a daemon. It is passed raw IP packets as they travel into and out of the machine, and will possibly change these before re-injecting them back into the IP packet stream.
It changes all packets destined for another host so that their source IP number is that of the current machine. For each packet changed in this manner,an internal table entry is created to record this fact. The source port number is also changed to indicate the table entry applying to the packet. Packets that are received with a target IP of the current host are checked against this internal table. If an entry is found, it is used to determine the correct target IP number and port to place in the packet.可見natd本身就是保持狀態的,不需要keep-state和check-state,然而如果你想小實驗一把keep-state和check-state,那么你可能會注意到ipfw有一via/recv/xmit系列match,上例中是使用via,如果使用xmit的話,那么只能適用于out方向的數據包,man ipfw中有下述:
The recv interface can be tested on either incoming or outgoing packets, while the xmit interface can only be tested on outgoing packets. So out is required (and in is invalid) whenever xmit is used.注意,in/out匹配的是數據包方向,而via/recv/xmit匹配的是接口。xmit時已經確定了接口,對于in方向的數據包,由于還沒有路由,所以不能確定出口設備,進而不能用于xmit。如果我們創建以下的rule:
ipfw add divert natd all from any to any xmit en1
natd -interface en1如此一來,對于返回的數據包將全部放過,雖然natd是保持狀態的,然而并沒有rule將數據包divert到natd,所以僅僅為了將數據包divert到natd,需要使用keep-state:
ipfw add check-state
ipfw add divert natd all from any to any xmit en1 keep-state這樣就可以對付返回的數據包了。然而問題是,內核保持的state狀態可能會和natd中的狀態相沖突,因此對于有狀態的協議比如TCP,此方式工作的很好,對于UDP和ICMP會有不穩定的問題。
五.最后再來點比較
ipfw和Cisco一樣,畢竟都是BSD的緣故,都是將數據包分為了in和out兩個方向,并且都可以認為應用于接口,雖然ipfw在內核中保存了一份全局的ruleset。不管怎樣,Netfilter絕不是這樣,另外,Netfilter的iptables區分了INPUT和FORWARD,所以FORWARD的數據包無需經過INPUT鏈,而ipfw則是全局的rule。ipfw和natd可以在任意位置相互插入,任意動作包括divert natd都可以和state聯動,實現了動作的stateful,也就是說,ipfw的機制可以記住一個流的頭包或者任意包的第一次匹配的動作,而Netfilter的conntrack和rule則是分離的,conntrack僅僅追蹤了連接,filter動作需要自己去匹配,沒有filter的動態rule。最后,ipfw保存一份ruleset,在man ipfw所示的圖的一路最多4個HOOK點重復check。
網站題目:初探BSD的ipfw防火墻
網頁路徑:
http://www.xueling.net.cn/article/igphig.html