複製鏈接
請複製以下鏈接發送給好友

PF防火牆

鎖定
[1]  ( 全稱:Packet Filter ) 是 UNIX LIKE 系統上進行 TCP/IP 流量過濾和網絡地址轉換的軟件系統。PF 同樣也能提供 TCP/IP 流量的整形和控制,並且提供帶寬控制和數據包優先集控制。
中文名
PF防火牆
類    別
網絡名詞
使用平台
UNIX LIKE
目的端口
80

PF防火牆基本配置

基本配置圖片 基本配置圖片
重定向規則: rdr on tl0 proto tcp from 192.0.2.1 to 24.65.1.13 port 80 \
-> 192.168.1.5 port 8000</strong>
數據包在經過rdr規則前的模樣:
* 源地址: 192.0.2.1
* 源端口: 4028 (由操作系統任意選擇)
* 目的地址: 24.65.1.13
* 目的端口: 80
數據包經過rdr規則後的模樣:
* 源地址: 192.0.2.1
* 源端口: 4028
* 目的地址: 192.168.1.5
* 目的: 8000
過濾引擎看見的IP數據包時轉換髮生之後的情況。
安全隱患
重定向確實存在安全隱患。在防火牆上開了一個允許流量進入內部網絡的洞,被保護的網絡安全潛在的受到了威脅。例如,如果流量被轉發到了內部的web服務器,而web服務器上允許的守護程序或者CGI腳本程序存在漏洞,則這台服務器存在會被因特網網上的入侵者攻擊危險。如果入侵者控制了這台機器,就有了進入內部網絡的通道,僅僅是因為這種流量是允許通過防火牆的。
這種風險可以通過將允許外部網絡訪問的系統限制在一個單獨的網段中來減小。這個網段通常也被稱為非軍事化區域(DMZ)或者私有服務網絡(PSN)。通過這個方法,如果web服務器被控制,通過嚴格的過濾進出DMZ/PSN的流量,受影響的系統僅限於DMZ/PSN網段。
重定向和反射
通常,重定向規則是用來將因特網上到來的連接轉發到一個內部網絡或者局域網的私有地址。例如:
server = 192.168.1.40
rdr on $ext_if proto tcp from any to $ext_if port 80 -> $server \
port 80</strong>
但是,當一個重定向規則被從局域網上的客户端進行測試時,它不會正常工作。這是因為重定向規則僅適用於通過指定端口($ext_if,外部接口,在上面的例子中)的數據包。從局域網上的主機連接防火牆的外部地址,並不意味着數據包會實際的通過外部接口。防火牆上的TCP/IP棧會把到來的數據包的目的地址在通過內部接口時與它自己的IP地址或者別名進行對比檢測。那樣的數據包不會真的通過外部接口,棧在任何情況下也不會建立那樣的通道。因而,PF永遠也不會在外部接口上看到那些數據包,過濾規則由於指定了外部接口也不會起作用。
指定第二條針對內部接口的也達不到預想的效果。當本地的客户端連接防火牆的外部地址時,初始化的TCP握手數據包是通過內部接口到達防火牆的。重定向規則確實起作用了,目標地址被替換成了內部服務器,數據包通過內部接口轉發到了內部的服務器。但源地址沒有進行轉換,仍然包含的是本地客户端的IP地址,因此服務器把它的迴應直接發送給了客户端。防火牆永遠收不到應答不可能返回客户端信息,客户端收到的應答不是來自它期望的源(防火牆)會被丟棄,TCP握手失敗,不能建立連接。
當然,局域網裏的客户端仍然會希望象外部客户一樣透明的訪問這台內部服務器。有如下的方法解決這個問題:
水平分割 DNS
存在這樣的可能性,即配置DNS服務器使得它回答內部主機的查詢和回答外部主機的查詢不一樣,因此內部客户端在進行名稱解析時會收到內部服務器的地址。它們直接連接到內部服務器,防火牆根本不牽扯。這會降低本地流量,因為數據包不會被送到防火牆。
將服務器移到獨立的本地網絡
增加單獨的網絡接口卡到防火牆,把本地的服務器從和客户端同一個網段移動到專用的網段(DMZ)可以讓本地客户端按照外部重定向連接的方法一樣重定向。使用單獨的網段有幾個優點,包括和保留的內部主機隔離增加了安全性;服務器(我們的案例中可以從因特網訪問)一旦被控制,它不能直接存取本地網絡因為所有的連接都必須通過防火牆。
TCP 代理
一般而言,TCP代理可以在防火牆上設置,監聽要轉發的端口或者將內部接口上到來的連接重定向到它監聽的端口。當本地客户端連接防火牆時,代理接受連接,建立到內部服務器的第二條連接,在通信雙方間進行數據轉發。
簡單的代理可以使用inetd和nc建立。下面的/etc/inetd.conf中的條目建立一個監聽套接字綁定到lookback地址(127.0.0.1)和端口5000。連接被轉發到服務器192.168.1.10的80端口。
127.0.0.1:5000 stream tcp nowait nobody /usr/bin/nc nc -w \
20 192.168.1.10 80</strong>
下面的重定向規則轉發內部接口的80端口到代理:
rdr on $int_if proto tcp from $int_net to $ext_if port 80 -> \
127.0.0.1 port 5000</strong>
RDR 和 NAT 結合
通過對內部接口增加NAT規則,上面説的轉換後源地址不變的問題可以解決。
rdr on $int_if proto tcp from $int_net to $ext_if port 80 -> \
$server
no nat on $int_if proto tcp from $int_if to $int_net
nat on $int_if proto tcp from $int_net to $server port 80 -> \
$int_if</strong>
這會導致由客户端發起的初始化連接在收到內部接口的返回數據包時轉換回來,客户端的源ip地址被防火牆的內部接口地址代替。內部服務器會迴應防火牆的內部接口地址,在轉發給本地客户端時可以反轉NAT和RDR。這個結構是非常複雜的,因為它為每個反射連接產生了2個單獨的狀態。必須小心配置防止NAT規則應用到了其他流量,例如連接由外部發起(通過其他的重定向)或者防火牆自己。注意上面的rdr規則會導致TCP/IP棧看到來自內部接口帶有目的地址是內部網絡的數據包。

PF防火牆規則生成捷徑

簡介
PF提供了許多方法來進行規則集的簡化。一些好的例子是使用宏和列表。另外,規則集的語言或者語法也提供了一些使規則集簡化的捷徑。首要的規則是,規則集越簡單,就越容易理解和維護。
使用宏
宏是非常有用的,因為它提供了硬編碼地址,端口號,接口名稱等的可選替代。在一個規則集中,服務器的IP地址改變了。沒問題,僅僅更新一下宏,不需要弄亂花費了大量時間和精力建立的規則集。
通常的慣例是在PF規則集中定義每個網絡接口的宏。如果網卡需要被使用不同驅動的卡取代,例如,用intel代替3com,可以更新宏,過濾規則集會和以前功能一樣。另一個優點是,如果在多台機器上安裝同樣的規則集,某些機器會有不同的網卡,使用宏定義網卡可以使的安裝的規則集進行最少的修改。使用宏來定義規則集中經常改變的信息,例如端口號,IP地址,接口名稱等等,建議多多實踐!
# define macros for each network interface
IntIF = "dc0"
ExtIF = "fxp0"
DmzIF = "fxp1"</strong>
另一個慣例是使用宏來定義IP地址和網絡,這可以大大減輕在IP地址改變時對規則集的維護。
# define our networks
IntNet = "192.168.0.0/24"
ExtAdd = "24.65.13.4"
DmzNet = "10.0.0.0/24"</strong>
如果內部地址擴展了或者改到了一個不同的IP段,可以更新宏為:
IntNet = "{ 192.168.0.0/24, 192.168.1.0/24 }"
當這個規則集重新載入時,任何東西都跟以前一樣。
使用列表
來看一下一個規則集中比較好的例子使得RFC1918定義的內部地址不會傳送到因特網上,如果發生傳送的事情,可能導致問題。
block in quick on tl0 inet from 127.0.0.0/8 to any
block in quick on tl0 inet from 192.168.0.0/16 to any
block in quick on tl0 inet from 172.16.0.0/12 to any
block in quick on tl0 inet from 10.0.0.0/8 to any
block out quick on tl0 inet from any to 127.0.0.0/8
block out quick on tl0 inet from any to 192.168.0.0/16
block out quick on tl0 inet from any to 172.16.0.0/12
block out quick on tl0 inet from any to 10.0.0.0/8</strong>
看看下面更簡單的例子:
block in quick on tl0 inet from { 127.0.0.0/8, 192.168.0.0/16, \
172.16.0.0/12, 10.0.0.0/8 } to any
block out quick on tl0 inet from any to { 127.0.0.0/8, \
192.168.0.0/16, 172.16.0.0/12, 10.0.0.0/8 }</strong>
這個規則集從8行減少到2行。如果聯合使用宏,還會變得更好:
NoRouteIPs = "{ 127.0.0.0/8, 192.168.0.0/16, 172.16.0.0/12, \
10.0.0.0/8 }"
ExtIF = "tl0"
block in quick on $ExtIF from $NoRouteIPs to any
block out quick on $ExtIF from any to $NoRouteIPs</strong>
注意雖然宏和列表簡化了pf.conf文件,但是實際是這些行會被pfctl(8)擴展成多行,因此,上面的例子實際擴展成下面的規則:
block in quick on tl0 inet from 127.0.0.0/8 to any
block in quick on tl0 inet from 192.168.0.0/16 to any
block in quick on tl0 inet from 172.16.0.0/12 to any
block in quick on tl0 inet from 10.0.0.0/8 to any
block out quick on tl0 inet from any to 10.0.0.0/8
block out quick on tl0 inet from any to 172.16.0.0/12
block out quick on tl0 inet from any to 192.168.0.0/16
block out quick on tl0 inet from any to 127.0.0.0/8</strong>
可以看到,PF擴展僅僅是簡化了編寫和維護pf.conf文件,實際並不簡化pf(4)對於規則的處理過程。
宏不僅僅用來定義地址和端口,它們在PF的規則文件中到處都可以用:
pre = "pass in quick on ep0 inet proto tcp from "
post = "to any port { 80, 6667 } keep state"</strong>
# David‘s classroom
$pre 21.14.24.80 $post</strong>
# Nick‘s home
$pre 24.2.74.79 $post
$pre 24.2.74.178 $post</strong>
擴展後:
pass in quick on ep0 inet proto tcp from 21.14.24.80 to any \
port = 80 keep state
pass in quick on ep0 inet proto tcp from 21.14.24.80 to any \
port = 6667 keep state
pass in quick on ep0 inet proto tcp from 24.2.74.79 to any \
port = 80 keep state
pass in quick on ep0 inet proto tcp from 24.2.74.79 to any \
port = 6667 keep state
pass in quick on ep0 inet proto tcp from 24.2.74.178 to any \
port = 80 keep state
pass in quick on ep0 inet proto tcp from 24.2.74.178 to any \
port = 6667 keep state</strong>
PF 語法
PF的語法相當靈活,因此,允許編寫非常靈活的規則集。PF能夠自動插入某些關鍵字因此它們不必在規則中明確寫出,關鍵字的順序也是隨意的,因此不需要記憶嚴格的語法限制。
減少關鍵字
要定義全部拒絕的策略,使用下面2條規則:
block in all
block out all</strong>
這可以簡化為:
block all
如果沒有指定方向,PF會認為規則適用於數據包傳遞的進、出2個方向。
同樣的, "from any to any" 和 "all" 子句可以在規則中省略,例如
block in on rl0 all
pass in quick log on rl0 proto tcp from any to any port 22 keep state</strong>
可以簡化為:
block in on rl0
pass in quick log on rl0 proto tcp to port 22 keep state</strong>
第一條規則阻塞rl0上從任意到任意的進入數據包,第
參考資料