- 論壇徽章:
- 0
|
PF防火墻
![]()
PF ( 全稱:Packet Filter ) --- 包過濾
是
UNIX
LIKE系統(tǒng)上進(jìn)行
TCP
/
IP
流量過濾和
網(wǎng)絡(luò)地址轉(zhuǎn)換
的軟件系統(tǒng)。PF同樣也能提供TCP/IP流量的整形和控制,并且提供帶寬控制和數(shù)據(jù)包優(yōu)先集控制。
PF最早是由
Daniel Hartmeier
開發(fā)的,現(xiàn)在的開發(fā)和維護(hù)由
Daniel
和
openbsd
小組的其他成員負(fù)責(zé)。
目錄
•
基本配置
•
列表和宏
•
表
•
包過濾
•
網(wǎng)絡(luò)地址轉(zhuǎn)換(NAT)
•
基本配置
•
列表和宏
•
表
•
包過濾
•
網(wǎng)絡(luò)地址轉(zhuǎn)換(NAT)
•
重定向 (端口轉(zhuǎn)發(fā))
•
規(guī)則生成捷徑
•
高級配置
•
流量整形
•
錨定和命名規(guī)則集
•
地址池和負(fù)載均衡
•
數(shù)據(jù)包標(biāo)記
•
日志
•
性能
•
研究 FTP
•
驗(yàn)證: 用Shell 進(jìn)行網(wǎng)關(guān)驗(yàn)證
•
實(shí)例:家庭和小型辦公室防火墻
•
參考資料
[顯示全部]
編輯本段
回目錄
PF防火墻 - 基本配置
![]()
激活
要激活pf并且使它在啟動(dòng)時(shí)調(diào)用配置文件,編輯/etc/rc.conf文件,修改配置pf的一行:
pf=YES
重啟
操作系統(tǒng)
讓配置生效。
也可以通過
pfctl
程序啟動(dòng)和停止pf
# pfctl -e
# pfctl -d
注意這僅僅是啟動(dòng)和關(guān)閉PF,實(shí)際它不會載入規(guī)則集,規(guī)則集要么在系統(tǒng)啟動(dòng)時(shí)載入,要在PF啟動(dòng)后通過命令單獨(dú)載入。
配置
系統(tǒng)引導(dǎo)到在
rc腳本
文件運(yùn)行PF時(shí)PF從/etc/pf.conf文件載入配置規(guī)則。注意當(dāng)/etc/pf.conf文件是默認(rèn)配置文件,在系統(tǒng)調(diào)用rc腳本文件時(shí),它僅僅是作為文本文件由pfctl裝入并解釋和插入pf的。對于一些應(yīng)用來說,其他的規(guī)則集可以在系統(tǒng)引導(dǎo)后由其他文件載入。對于一些設(shè)計(jì)的非常好的unix程序,PF提供了足夠的靈活性。
pf.conf 文件有7個(gè)部分:
* 宏: 用戶定義的
變量
,包括
IP
地址,接口名稱等等
* 表: 一種用來保存IP地址列表的結(jié)構(gòu)
* 選項(xiàng): 控制PF如何工作的變量
* 整形: 重新處理
數(shù)據(jù)包
,進(jìn)行正;
碎片整理
* 排隊(duì): 提供帶寬控制和數(shù)據(jù)包優(yōu)先級控制.
* 轉(zhuǎn)換: 控制網(wǎng)絡(luò)地址轉(zhuǎn)換和數(shù)據(jù)包重定向.
* 過濾規(guī)則: 在數(shù)據(jù)包通過接口時(shí)允許進(jìn)行選擇性的過濾和阻止
除去宏和表,其他的段在配置文件中也應(yīng)該按照這個(gè)順序出現(xiàn),盡管對于一些特定的應(yīng)用并不是所有的段都是必須的。
空行會被忽略,以#開頭的行被認(rèn)為是注釋.
![]()
# pfctl -sa控制
引導(dǎo)之后,PF可以通過pfctl程序進(jìn)行操作,以下是一些例子:
# pfctl -f /etc/pf.conf 載入 pf.conf 文件
# pfctl -nf /etc/pf.conf 解析文件,但不載入
# pfctl -Nf /etc/pf.conf 只載入文件中的
NAT
規(guī)則
# pfctl -Rf /etc/pf.conf 只載入文件中的過濾規(guī)則
# pfctl -sn 顯示當(dāng)前的NAT規(guī)則
# pfctl -sr 顯示當(dāng)前的過濾規(guī)則
# pfctl -ss 顯示當(dāng)前的狀態(tài)表
# pfctl -si 顯示過濾狀態(tài)和計(jì)數(shù)
# pfctl -sa 顯示任何可顯示的
完整的命令列表,請參閱pfctl的man手冊頁。
編輯本段
回目錄
PF防火墻 - 列表和宏
列表
一個(gè)列表允許一個(gè)規(guī)則集中指定多個(gè)相似的標(biāo)準(zhǔn)。例如,多個(gè)
協(xié)議
,
端口號
,
網(wǎng)絡(luò)地址
等等。因此,不需要為每一個(gè)需要阻止的IP地址編寫一個(gè)過濾規(guī)則,一條規(guī)則可以在列表中指定多個(gè)IP地址。列表的定義是將要指定的條目放在{ }大括號中。
當(dāng)pfctl在載入規(guī)則集碰到列表時(shí),它產(chǎn)生多個(gè)規(guī)則,每條規(guī)則對于列表中的一個(gè)條目。例如:
block out on fxp0 from { 192.168.0.1, 10.5.32.6 } to any
展開后:
block out on fxp0 from 192.168.0.1 to any
block out on fxp0 from 10.5.32.6 to any
多種列表可以在規(guī)則中使用,并不僅僅限于過濾規(guī)則:
rdr on fxp0 proto tcp from any to any port { 22 80 } -> \
192.168.0.6
block out on fxp0 proto { tcp udp } from { 192.168.0.1, \
10.5.32.6 } to any port { ssh telnet }
注意逗號在列表?xiàng)l目之間是可有可無的。
宏
宏
是用戶定義變量用來指定IP地址,端口號,接口名稱等等。宏可以降低PF規(guī)則集的復(fù)雜度并且使得維護(hù)規(guī)則集變得容易。
宏名稱必須以字母開頭,可以包括字母,數(shù)字和下劃線。宏名稱不能包括保留關(guān)鍵字如:
pass, out, 以及 queue.
ext_if = "fxp0"
block in on $ext_if from any to any
這生成了一個(gè)宏名稱為ext_if. 當(dāng)一個(gè)宏在它產(chǎn)生以后被引用時(shí),它的名稱前面以$字符開頭。
宏也可以展開成列表,如:
friends = "{ 192.168.1.1, 10.0.2.5, 192.168.43.53 }"
宏能夠被重復(fù)定義,由于宏不能在引號內(nèi)被擴(kuò)展,因此必須使用下面得語法:
host1 = "192.168.1.1"
host2 = "192.168.1.2"
all_hosts = "{" $host1 $host2 "}"
宏 $all_hosts 現(xiàn)在會展開成 192.168.1.1, 192.168.1.2.
編輯本段
回目錄
PF防火墻 - 表
![]()
簡介
表是用來保存一組
IPv4
或者
IPv6
地址。在表中進(jìn)行查詢是非?斓模⑶冶攘斜硐母俚
內(nèi)存
和
cpu
時(shí)間。由于這個(gè)原因,表是保存大量地址的最好方法,在50,000個(gè)地址中查詢僅比在50個(gè)地址中查詢稍微多一點(diǎn)時(shí)間。表可以用于下列用途:
* 過濾,整形,NAT和重定向中的源或者目的地址.
* NAT規(guī)則中的轉(zhuǎn)換地址.
* 重定向規(guī)則中的重定向地址.
* 過濾規(guī)則選項(xiàng)中 route-to, reply-to, 和 dup-to的目的地址.
表可以通過在pf.conf里配置和使用pfctl生成。
配置
在pf.conf文件中, 表是使用table
關(guān)鍵字
創(chuàng)建出來的。下面的關(guān)鍵字必須在創(chuàng)建表時(shí)指定。
* constant - 這類表的內(nèi)容一旦創(chuàng)建出來就不能被改變。如果這個(gè)屬性沒有指定,可以使用pfctl添加和刪除表里的地址,即使系統(tǒng)是運(yùn)行在2或者更高得安全級別上。
* persist - 即使沒有規(guī)則引用這類表,內(nèi)核也會把它保留在內(nèi)存中。如果這個(gè)屬性沒有指定,當(dāng)最后引用它的規(guī)則被取消后內(nèi)核自動(dòng)把它移出內(nèi)存。
實(shí)例:
table { 192.0.2.0/24 }
table const { 192.168.0.0/16, 172.16.0.0/12, 10.0.0.0/8 }
table persist
block in on fxp0 from { , } to any
pass in on fxp0 from to any
地址也可以用“非”來進(jìn)行修改,如:
table { 192.0.2.0/24, !192.0.2.5 }
goodguys表將匹配除192.0.2.5外192.0.2.0/24網(wǎng)段得所有地址。
注意表名總是在符號得里面。
表也可以由包含IP地址和網(wǎng)絡(luò)地址的文本文件中輸入:
table persist file "/etc/spammers"
block in on fxp0 from to any
文件 /etc/spammers 應(yīng)該包含被阻塞的IP地址或者
CIDR
網(wǎng)絡(luò)地址,每個(gè)條目一行。以#開頭的行被認(rèn)為是注釋會被忽略。
用 pfctl 進(jìn)行操作
表可以使用pfctl進(jìn)行靈活的操作。例如,在上面產(chǎn)生的表中增加條目可以這樣寫:
# pfctl -t spammers -T add 218.70.0.0/16
如果這個(gè)表不存在,這樣會創(chuàng)建出這個(gè)表來。列出表中的內(nèi)容可以這樣:
# pfctl -t spammers -T show
-v 參數(shù)也可以使用-Tshow 來顯示每個(gè)表的條目內(nèi)容統(tǒng)計(jì)。要從表中刪除條目,可以這樣:
# pfctl -t spammers -T delete 218.70.0.0/16
指定地址
除了使用IP地址來指定主機(jī)外,也可以使用主機(jī)名。當(dāng)主機(jī)名被解析成IP地址時(shí),IPv4和IPv6地址都被插進(jìn)規(guī)則中。IP地址也可以通過合法的接口名稱或者self關(guān)鍵字輸入表中,這樣的表會分別包含接口或者機(jī)器上(包括
loopback地址
)上配置的所有IP地址。
一個(gè)限制時(shí)指定地址0.0.0.0/0 以及 0/0在表中不能工作。替代方法是明確輸入該地址或者使用宏。
地址匹配
表中的地址查詢會匹配最接近的規(guī)則,比如:
table { 172.16.0.0/16, !172.16.1.0/24, 172.16.1.100 }
block in on dc0 all
pass in on dc0 from to any
任何自dc0上數(shù)據(jù)包都會把它的源地址和goodguys表中的地址進(jìn)行匹配:
* 172.16.50.5 - 精確匹配172.16.0.0/16; 數(shù)據(jù)包符合可以通過
* 172.16.1.25 - 精確匹配!172.16.1.0/24; 數(shù)據(jù)包匹配表中的一條規(guī)則,但規(guī)則是“非”(使用“!”進(jìn)行了修改);數(shù)據(jù)包不匹配表會被阻塞。
* 172.16.1.100 - 準(zhǔn)確匹配172.16.1.100; 數(shù)據(jù)包匹配表,運(yùn)行通過
* 10.1.4.55 - 不匹配表,阻塞。
編輯本段
回目錄
PF防火墻 - 包過濾
![]()
簡介
包過濾是在數(shù)據(jù)包通過網(wǎng)絡(luò)接口時(shí)進(jìn)行選擇性的運(yùn)行通過或者阻塞。pf檢查包時(shí)使用的標(biāo)準(zhǔn)是基于的3層(IPV4或者IPV6)和4層(
TCP
,
UDP
,
ICMP
,
ICMPv6
)包頭。最常用的標(biāo)準(zhǔn)是
源和目的地址
,
源和目的端口
,以及
協(xié)議
。
過濾規(guī)則集指定了數(shù)據(jù)包必須匹配的標(biāo)準(zhǔn)和規(guī)則集作用后的結(jié)果,在規(guī)則集匹配時(shí)通過或者阻塞。規(guī)則集由開始到結(jié)束順序執(zhí)行。除非數(shù)據(jù)包匹配的規(guī)則包含quick關(guān)鍵字,否則數(shù)據(jù)包在最終執(zhí)行動(dòng)作前會通過所有的規(guī)則檢驗(yàn)。最后匹配的規(guī)則具有決定性,決定了數(shù)據(jù)包最終的執(zhí)行結(jié)果。存在一條潛在的規(guī)則是如果數(shù)據(jù)包和規(guī)則集中的所有規(guī)則都不匹配,則它會被通過。
規(guī)則語法
一般而言,最簡單的過濾規(guī)則語法是這樣的:
action direction [log] [quick] on interface [af] [proto protocol] \
from src_addr [port src_port] to dst_addr [port dst_port] \
[tcp_flags] [state]
action
數(shù)據(jù)包匹配規(guī)則時(shí)執(zhí)行的動(dòng)作,放行或者阻塞。放行動(dòng)作把數(shù)據(jù)包傳遞給核心進(jìn)行進(jìn)一步出來,阻塞動(dòng)作根據(jù)block-policy 選項(xiàng)指定的方法進(jìn)行處理。默認(rèn)的動(dòng)作可以修改為阻塞丟棄或者阻塞返回。
direction
數(shù)據(jù)包傳遞的方向,進(jìn)或者出
log
指定數(shù)據(jù)包被pflogd( 進(jìn)行日志記錄。如果規(guī)則指定了keep state, modulate state, or synproxy state 選項(xiàng),則只有建立了連接的狀態(tài)被日志。要記錄所有的日志,使用log-all
quick
如果數(shù)據(jù)包匹配的規(guī)則指定了quick關(guān)鍵字,則這條規(guī)則被認(rèn)為時(shí)最終的匹配規(guī)則,指定的動(dòng)作會立即執(zhí)行。
interface
數(shù)據(jù)包通過的網(wǎng)絡(luò)接口的名稱或組。組是接口的名稱但沒有最后的整數(shù)。比如
ppp
或
fxp
,會使得規(guī)則分別匹配任何ppp或者fxp接口上的任意數(shù)據(jù)包。
af
數(shù)據(jù)包的地址類型,
inet
代表Ipv4,
inet6
代表Ipv6。通常PF能夠根據(jù)源或者目標(biāo)地址自動(dòng)確定這個(gè)參數(shù)。
protocol
數(shù)據(jù)包的4層協(xié)議:
tcp
udp
icmp
icmp6
/etc/protocols中的協(xié)議名稱
0~255之間的協(xié)議號
使用列表的一系列協(xié)議.
src_addr, dst_addr
IP頭中的源/目標(biāo)地址。地址可以指定為:
單個(gè)的Ipv4或者Ipv6地址.
CIDR 網(wǎng)絡(luò)地址.
能夠在規(guī)則集載入時(shí)通過DNS解析到的合法的域名,IP地址會替代規(guī)則中的域名。
網(wǎng)絡(luò)接口名稱。網(wǎng)絡(luò)接口上配置的所有ip地址會替代進(jìn)規(guī)則中。
帶有/掩碼(例如/24)的網(wǎng)絡(luò)接口的名稱。每個(gè)根據(jù)掩碼確定的CIDR網(wǎng)絡(luò)地址都會被替代進(jìn)規(guī)則中。.
帶有()的網(wǎng)絡(luò)接口名稱。這告訴PF如果網(wǎng)絡(luò)接口的IP地址改變了,就更新規(guī)則集。這個(gè)對于使用
DHCP
或者撥號來獲得IP地址的接口特別有用,IP地址改變時(shí)不需要重新載入規(guī)則集。
帶有如下的修飾詞的網(wǎng)絡(luò)接口名稱:
o :network - 替代CIDR網(wǎng)絡(luò)地址段 (例如:192.168.0.0/24)
o :broadcast - 替代
網(wǎng)絡(luò)廣播地址
(例如:192.168.0.255)
o :peer - 替代點(diǎn)到點(diǎn)鏈路上的ip地址。
另外,:0修飾詞可以附加到接口名稱或者上面的修飾詞后面指示PF在替代時(shí)不包括網(wǎng)絡(luò)接口的其余附加(alias)地址。這些修飾詞也可以在接口名稱在括號()內(nèi)時(shí)使用。例如:fxp0:network:0
表.
上面的所有項(xiàng)但使用。ǚ牵┬揎椩~
使用列表的一系列地址.
關(guān)鍵字 any 代表所有地址
關(guān)鍵字 all 是 from any to any的縮寫。
src_port, dst_port
4層數(shù)據(jù)包頭中的源/目標(biāo)端口。端口可以指定為:
1 到 65535之間的整數(shù)
/etc/services中的合法服務(wù)名稱
使用列表的一系列端口
一個(gè)范圍:
o != (不等于)
o (大于)
o = (大于等于)
o > (反轉(zhuǎn)范圍)
最后2個(gè)是二元操作符(他們需要2個(gè)參數(shù)),在范圍內(nèi)不包括參數(shù)。
o : (inclusive range)
inclusive range 也是二元操作符但范圍內(nèi)包括參數(shù)。
tcp_flags
指定使用TCP協(xié)議時(shí)TCP頭中必須設(shè)定的標(biāo)記。 標(biāo)記指定的格式是: flags check/mask. 例如: flags S/SA -這指引PF只檢查S和A(SYN and ACK)標(biāo)記,如果SYN標(biāo)記是“on”則匹配。
state
指定狀態(tài)信息在規(guī)則匹配時(shí)是否保持。
keep state - 對 TCP, UDP, ICMP起作用
modulate state - 只對 TCP起作用. PF會為匹配規(guī)則的數(shù)據(jù)包產(chǎn)生強(qiáng)壯的初始化序列號。
synproxy state - 代理外來的TCP連接以保護(hù)服務(wù)器不受TCP SYN FLOODs欺騙。這個(gè)選項(xiàng)包含了keep state 和 modulate state 的功能。
默認(rèn)拒絕
按照慣例建立
防火墻
時(shí)推薦執(zhí)行的是默認(rèn)拒絕的方法。也就是說先拒絕所有的東西,然后有選擇的允許某些特定的流量通過防火墻。這個(gè)方法之所以是推薦的是因?yàn)樗鼘幙墒е^于謹(jǐn)慎(也不放過任何風(fēng)險(xiǎn)),而且使得編寫規(guī)則集變得簡單。
產(chǎn)生一個(gè)默認(rèn)拒絕的過濾規(guī)則,開始2行過濾規(guī)則必須是:
block in all
block out all
這會阻塞任何通信方在任何方向上進(jìn)入任意接口的所有流量。
通過流量
流量必須被明確的允許通過防火墻或者被默認(rèn)拒絕的策略丟棄。這是數(shù)據(jù)包標(biāo)準(zhǔn)如源/目的端口,源/目的地址和協(xié)議開始活動(dòng)的地方。無論何時(shí)數(shù)據(jù)包在被允許通過防火墻時(shí)規(guī)則都要設(shè)計(jì)的盡可能嚴(yán)厲。這是為了保證設(shè)計(jì)中的流量,也只有設(shè)計(jì)中的流量可以被允許通過。
實(shí)例:
# 允許本地網(wǎng)絡(luò)192.168.0.0/24流量通過dc0接口進(jìn)入訪問openbsd機(jī)器的IP地址
#192.168.0.1,同時(shí)也允許返回的數(shù)據(jù)包從dc0接口出去。
pass in on dc0 from 192.168.0.0/24 to 192.168.0.1
pass out on dc0 from 192.168.0.1 to 192.168.0.0/24
# Pass TCP traffic in on fxp0 to the web server running on the
# OpenBSD machine. The interface name, fxp0, is used as the
# destination address so that packets will only match this rule if
# they‘re destined for the OpenBSD machine.
pass in on fxp0 proto tcp from any to fxp0 port www
quick 關(guān)鍵字
每個(gè)數(shù)據(jù)包都要按自上至下的順序按規(guī)則進(jìn)行過濾。默認(rèn)情況下,數(shù)據(jù)包被標(biāo)記為通過,這個(gè)可以被任一規(guī)則改變,在到達(dá)最后一條規(guī)則前可以被來回改變多次,最后的匹配規(guī)則是“獲勝者”。存在一個(gè)例外是:過濾規(guī)則中的quick關(guān)鍵字具有取消進(jìn)一步往下處理的作用,使得規(guī)則指定的動(dòng)作馬上執(zhí)行?匆幌孪旅娴睦樱
錯(cuò)誤:
block in on fxp0 proto tcp from any to any port ssh
pass in all
在這樣的條件下,block行會被檢測,但永遠(yuǎn)也不會有效果,因?yàn)樗竺娴囊恍性试S所有的流量通過。
正確:
block in quick on fxp0 proto tcp from any to any port ssh
pass in all
這些規(guī)則執(zhí)行的結(jié)果稍有不同,如果block行被匹配,由于quick選項(xiàng)的原因,數(shù)據(jù)包會被阻塞,而且剩下的規(guī)則也會被忽略。
狀態(tài)保持
PF一個(gè)非常重要的功能是“狀態(tài)保持”或者“
狀態(tài)檢測
”。狀態(tài)檢測指PF跟蹤或者處理網(wǎng)絡(luò)連接狀態(tài)的能力。通過存貯每個(gè)連接的信息到一個(gè)狀態(tài)表中,PF能夠快速確定一個(gè)通過防火墻的數(shù)據(jù)包是否屬于已經(jīng)建立的連接。如果是,它會直接通過防火墻而不用再進(jìn)行規(guī)則檢驗(yàn)。
狀態(tài)保持有許多的優(yōu)點(diǎn),包括簡單的規(guī)則集和優(yōu)良的數(shù)據(jù)包處理性能。
PF is able to match packets moving in either direction to state table entries meaning that filter rules which pass returning trafficdon‘t need to be written.
并且,由于數(shù)據(jù)包匹配狀態(tài)連接時(shí)不再進(jìn)行規(guī)則集的匹配檢測,PF用于處理這些數(shù)據(jù)包的時(shí)間大為減少。
當(dāng)一條規(guī)則使用了keep state選項(xiàng),第一個(gè)匹配這條規(guī)則的數(shù)據(jù)包在收發(fā)雙方之間建立了一個(gè)狀態(tài)。現(xiàn)在,不僅發(fā)送者到接收者之間的數(shù)據(jù)包匹配這個(gè)狀態(tài)繞過規(guī)則檢驗(yàn),而且接收者回復(fù)發(fā)送者的數(shù)據(jù)包也是同樣的。例如:
pass out on fxp0 proto tcp from any to any keep state
這允許fxp0接口上的任何TCP流量通過,并且允許返回的流量通過防火墻。狀態(tài)保持是一個(gè)非常有用的特性,由于狀態(tài)查詢比使用規(guī)則進(jìn)行數(shù)據(jù)包檢驗(yàn)快的多,因此它可以大幅度提高防火墻的性能。
狀態(tài)調(diào)整選項(xiàng)和狀態(tài)保持的功能在除了僅適用于TCP數(shù)據(jù)包以為完全相同。在使用狀態(tài)調(diào)整時(shí),輸入連接的初始化序列號(
ISN
)是隨機(jī)的,這對于保護(hù)某些選擇ISN存在問題的操作系統(tǒng)的連接初始化非常有用。從openbsd 3.5開始,狀態(tài)調(diào)整選項(xiàng)可以應(yīng)用于包含非TCP的協(xié)議規(guī)則。
對輸出的TCP, UDP, ICMP數(shù)據(jù)包保持狀態(tài),并且調(diào)整
TCP ISN
。
pass out on fxp0 proto { tcp, udp, icmp } from any to any modulate state
狀態(tài)保持的另一個(gè)優(yōu)點(diǎn)是
ICMP
通信流量可以直接通過防火墻。例如,如果一個(gè)TCP連接使用了狀態(tài)保持,當(dāng)和這個(gè)TCP連接相關(guān)的ICMP數(shù)據(jù)包到來時(shí),它會自動(dòng)找到合適的狀態(tài)記錄,直接通過防火墻。
狀態(tài)記錄的范圍被state-policy runtime選項(xiàng)總體控制,也能基于單條規(guī)則由if-bound, group-bound, 和 floating state選項(xiàng)關(guān)鍵字設(shè)定。這些針對單條規(guī)則的關(guān)鍵字在使用時(shí)具有和state-policy選項(xiàng)同樣的意義。例如:
pass out on fxp0 proto { tcp, udp, icmp } from any to any modulate state (if-bound)
狀態(tài)規(guī)則指示為了使數(shù)據(jù)包匹配狀態(tài)條目,它們必須通過fxp0網(wǎng)絡(luò)接口傳遞。
需要注意的是,nat,binat,rdr規(guī)則隱含在連接通過過濾規(guī)則集審核的過程中產(chǎn)生匹配連接的狀態(tài)。
UDP狀態(tài)保持
“不能為UDP產(chǎn)生狀態(tài),因?yàn)閁DP是無狀態(tài)的協(xié)議”。確實(shí),UDP通信會話沒有狀態(tài)的概念(明確的開始和結(jié)束通信),這絲毫不影響PF為 UDP會話產(chǎn)生狀態(tài)的能力。對于沒有開始和結(jié)束數(shù)據(jù)包的協(xié)議,PF僅簡單追蹤匹配的數(shù)據(jù)部通過的時(shí)間。如果到達(dá)超時(shí)限制,狀態(tài)被清除,超時(shí)的時(shí)間值可以在pf.conf配置文件中設(shè)定。
TCP 標(biāo)記
基于標(biāo)記的TCP包匹配經(jīng)常被用于過濾試圖打開新連接的TCP數(shù)據(jù)包。TCP標(biāo)記和他們的意義如下所列:
* F :
FIN
- 結(jié)束; 結(jié)束會話
* S :
SYN
- 同步; 表示開始會話請求
* R :
RST
- 復(fù)位;中斷一個(gè)連接
* P : PUSH - 推送; 數(shù)據(jù)包立即發(fā)送
* A :
ACK
- 應(yīng)答
* U :
URG
- 緊急
* E :
ECE
- 顯式擁塞提醒回應(yīng)
* W :
CWR
- 擁塞窗口減少
要使PF在規(guī)則檢查過程中檢查TCP標(biāo)記,flag關(guān)鍵需按如下語法設(shè)置。
flags check/mask
mask部分告訴PF僅檢查指定的標(biāo)記,check部分說明在數(shù)據(jù)包頭中哪個(gè)標(biāo)記設(shè)置為“on”才算匹配。
pass in on fxp0 proto tcp from any to any port ssh flags S/SA
上面的規(guī)則通過的帶SYN標(biāo)記的TCP流量僅查看SYN和ACK標(biāo)記。帶有SYN和ECE標(biāo)記的數(shù)據(jù)包會匹配上面的規(guī)則,而帶有SYN和ACK的數(shù)據(jù)包或者僅帶有ACK的數(shù)據(jù)包不會匹配。
注意:在前面的openbsd版本中,下面的語法是支持的:
. . . flags S
現(xiàn)在,這個(gè)不再支持,mask必須被說明。
標(biāo)記常常和狀態(tài)保持規(guī)則聯(lián)合使用來控制創(chuàng)建狀態(tài)條目:
pass out on fxp0 proto tcp all flags S/SA keep state
這條規(guī)則允許為所有輸出中帶SYN和ACK標(biāo)記的數(shù)據(jù)包中的僅帶有SYN標(biāo)記的TCP數(shù)據(jù)包創(chuàng)建狀態(tài)。
使用標(biāo)記時(shí)必須小心,理解在做什么和為什么這樣做。小心聽取建議,因?yàn)橄喈?dāng)多的建議時(shí)不好的。一些人建議創(chuàng)建狀態(tài)“只有當(dāng)SYN標(biāo)記設(shè)定而沒有其他標(biāo)記”時(shí),這樣的規(guī)則如下:
. . . flags S/FSRPAUEW 糟糕的主意!!
這個(gè)理論是,僅為TCP開始會話時(shí)創(chuàng)建狀態(tài),會話會以SYN標(biāo)記開始,而沒有其他標(biāo)記。問題在于一些站點(diǎn)使用ECN標(biāo)記開始會話,而任何使用ECN連接你的會話都會被那樣的規(guī)則拒絕。比較好的規(guī)則是:
. . . flags S/SAFR
這個(gè)經(jīng)過實(shí)踐是安全的,如果流量進(jìn)行了整形也沒有必要檢查FIN和RST標(biāo)記。整形過程會讓PF丟棄帶有非法TCP標(biāo)記的進(jìn)入數(shù)據(jù)包(例如SYN和FIN以及SYN和RST)。強(qiáng)烈推薦總是進(jìn)行流量整形:
scrub in on fxp0
.
.
.
pass in on fxp0 proto tcp from any to any port ssh flags S/SA \
keep state
TCP SYN 代理
通過,當(dāng)客戶端向服務(wù)器初始化一個(gè)TCP連接時(shí),PF會在二者直接傳遞握手?jǐn)?shù)據(jù)包。然而,PF具有這樣的能力,就是代理握手。使用握手代理,PF自己會和客戶端完成握手,初始化和服務(wù)器的握手,然后在二者之間傳遞數(shù)據(jù)。這樣做的優(yōu)點(diǎn)是在客戶端完成握手之前,沒有數(shù)據(jù)包到達(dá)服務(wù)器。這樣就消沉了TCP SYN FLOOD欺騙影響服務(wù)器的問題,因?yàn)檫M(jìn)行欺騙的客戶端不會完成握手。
TCP SYN 代理在規(guī)則中使用synproxy state關(guān)鍵字打開。例如:
pass in on $ext_if proto tcp from any to $web_server port www \
flags S/SA synproxy state
這樣, web服務(wù)器的連接由PF進(jìn)行TCP代理。
由于synproxy state工作的方式,它具有keep state 和 modulate state一樣的功能。
如果PF工作在橋模式下,SYN代理不會起作用。
阻塞欺騙數(shù)據(jù)包
地址欺騙是惡意用戶為了隱藏他們的真實(shí)地址或者假冒網(wǎng)絡(luò)上的其他節(jié)點(diǎn)而在他們傳遞的數(shù)據(jù)包中使用虛假的地址。一旦實(shí)施了地址欺騙,他們可以隱蔽真實(shí)地址實(shí)施網(wǎng)絡(luò)攻擊或者獲得僅限于某些地址的網(wǎng)絡(luò)訪問服務(wù)。
PF通過antispoof關(guān)鍵字提供一些防止地址欺騙的保護(hù)。
antispoof [log] [quick] for interface [af]
log
指定匹配的數(shù)據(jù)包應(yīng)該被pflogd進(jìn)行日志記錄
quick
如果數(shù)據(jù)包匹配這條規(guī)則,則這是最終的規(guī)則,不再進(jìn)行其他規(guī)則集的檢查。
interface
激活要進(jìn)行欺騙保護(hù)的網(wǎng)絡(luò)接口。也可以是接口的列表。
af
激活進(jìn)行欺騙保護(hù)的地址族,inet代表Ipv4,inet6代表Ipv6。
實(shí)例:
antispoof for fxp0 inet
當(dāng)規(guī)則集載入時(shí),任何出現(xiàn)了antispoof關(guān)鍵字的規(guī)則都會擴(kuò)展成2條規(guī)則。假定接口fxp0具有ip地址10.0.0.1和子網(wǎng)掩碼255.255.255.0(或者/24),上面的規(guī)則會擴(kuò)展成:
block in on ! fxp0 inet from 10.0.0.0/24 to any
block in inet from 10.0.0.1 to any
這些規(guī)則實(shí)現(xiàn)下面的2個(gè)目的:
* 阻塞任何不是由fxp0接口進(jìn)入的10.0.0.0/24網(wǎng)絡(luò)的流量。由于10.0.0.0/24的網(wǎng)絡(luò)是在fxp0接口,具有這樣的源網(wǎng)絡(luò)地址的數(shù)據(jù)包絕不應(yīng)該從其他接口上出現(xiàn)。
* 阻塞任何由10.0.0.1即fxp0接口的IP地址的進(jìn)入流量。主機(jī)絕對不會通過外面的接口給自己發(fā)送數(shù)據(jù)包,因此任何進(jìn)入的流量源中帶有主機(jī)自己的IP地址都可以認(rèn)為是惡意的!
注意:antispoof規(guī)則擴(kuò)展出來的過濾規(guī)則會阻塞loopback接口上發(fā)送到本地地址的數(shù)據(jù)包。這些數(shù)據(jù)包應(yīng)該明確的配置為允許通過。例如:
pass quick on lo0 all
antispoof for fxp0 inet
使用antispoof應(yīng)該僅限于已經(jīng)分配了IP地址的網(wǎng)絡(luò)接口,如果在沒有分配IP地址的網(wǎng)絡(luò)接口上使用,過濾規(guī)則會擴(kuò)展成:
block drop in on ! fxp0 inet all
block drop in inet all
這樣的規(guī)則會存在阻塞所有接口上進(jìn)入的所有流量的危險(xiǎn)。
被動(dòng)操作系統(tǒng)識別
被動(dòng)操作系統(tǒng)識別是通過基于遠(yuǎn)端主機(jī)TCP SYN數(shù)據(jù)包中某些特征進(jìn)行操作系統(tǒng)被動(dòng)檢測的技術(shù)。這些信息可以作為標(biāo)準(zhǔn)在過濾規(guī)則中使用。
PF檢測遠(yuǎn)端操作系統(tǒng)是通過比較TCP SYN數(shù)據(jù)包中的特征和已知的特征文件對照來確定的,特征文件默認(rèn)是/etc/pf.os。如果PF起作用,可是使用下面的命令查看當(dāng)前的特征列表。
# pfctl -s osfp
在規(guī)則集中,特征可以指定為OS類型,版本,或者子類型/補(bǔ)丁級別。這些條目在上面的pfctl命令中有列表。要在過濾規(guī)則中指定特征,需使用os關(guān)鍵字:
pass in on $ext_if any os OpenBSD keep state
block in on $ext_if any os "Windows 2000"
block in on $ext_if any os "Linux 2.4 ts"
block in on $ext_if any os unknown
指定的操作系統(tǒng)類型unknow允許匹配操作系統(tǒng)未知的數(shù)據(jù)包。
注意以下的內(nèi)容::
*操作系統(tǒng)識別偶爾會出錯(cuò),因?yàn)榇嬖谄垓_或者修改過的使得看起來象某個(gè)操作系統(tǒng)得數(shù)據(jù)包。
* 某些修改或者打過補(bǔ)丁得操作系統(tǒng)會改變棧得行為,導(dǎo)致它或者和特征文件不符,或者符合了另外得操作系統(tǒng)特征。
* OSFP 僅對TCP SYN數(shù)據(jù)包起作用,它不會對其他協(xié)議或者已經(jīng)建立得連接起作用。
IP 選項(xiàng)
默認(rèn)情況下,PF阻塞帶有IP選項(xiàng)得數(shù)據(jù)包。這可以使得類似nmap得操作系統(tǒng)識別軟件工作困難。如果應(yīng)用程序需要通過這樣的數(shù)據(jù)包,例如多播或者
IGMP
,可以使用allow-opts關(guān)鍵字
pass in quick on fxp0 all allow-opts
過濾規(guī)則實(shí)例
下面是過濾規(guī)則得實(shí)例。運(yùn)行PF的機(jī)器充當(dāng)防火墻,在一個(gè)小得內(nèi)部網(wǎng)絡(luò)和因特網(wǎng)之間。只列出了過濾規(guī)則,queueing, nat, rdr,等等沒有在實(shí)例中列出。
ext_if = "fxp0"
int_if = "dc0"
lan_net = "192.168.0.0/24"
# scrub incoming packets
scrub in all
# setup a default deny policy
block in all
block out all
# pass traffic on the loopback interface in either direction
pass quick on lo0 all
# activate spoofing protection for the internal interface.
antispoof quick for $int_if inet
# only allow ssh connections from the local network if it‘s from the
# trusted computer, 192.168.0.15. use "block return" so that a TCP RST is
# sent to close blocked connections right away. use "quick" so that this
# rule is not overridden by the "pass" rules below.
block return in quick on $int_if proto tcp from ! 192.168.0.15 \
to $int_if port ssh flags S/SA
# pass all traffic to and from the local network
pass in on $int_if from $lan_net to any
pass out on $int_if from any to $lan_net
# pass tcp, udp, and icmp out on the external (Internet) interface.
# keep state on udp and icmp and modulate state on tcp.
pass out on $ext_if proto tcp all modulate state flags S/SA
pass out on $ext_if proto { udp, icmp } all keep state
# allow ssh connections in on the external interface as long as they‘re
# NOT destined for the firewall (i.e., they‘re destined for a machine on
# the local network). log the initial packet so that we can later tell
# who is trying to connect. use the tcp syn proxy to proxy the connection.
pass in log on $ext_if proto tcp from any to { !$ext_if, !$int_if } \
port ssh flags S/SA synproxy state
編輯本段
回目錄
PF防火墻 - 網(wǎng)絡(luò)地址轉(zhuǎn)換(NAT)
![]()
簡介
網(wǎng)絡(luò)地址轉(zhuǎn)換
是映射整個(gè)網(wǎng)絡(luò)(或者多個(gè)網(wǎng)絡(luò))到單個(gè)IP地址的方法。當(dāng)ISP分配的IP地址數(shù)目少于要連上互聯(lián)網(wǎng)的計(jì)算機(jī)數(shù)目時(shí),
NAT
是必需的。NAT在
RFC1631
中描述。
NAT允許使用
RFC1918
中定義的保留地址族。典型情況下,內(nèi)部網(wǎng)絡(luò)可以下面的地址族:
10.0.0.0/8 (10.0.0.0 - 10.255.255.255)
172.16.0.0/12 (172.16.0.0 - 172.31.255.255)
192.168.0.0/16 (192.168.0.0 - 192.168.255.255)
擔(dān)任NAT任務(wù)的操作系統(tǒng)必須至少要2塊網(wǎng)卡,一塊連接到因特網(wǎng),另一塊連接內(nèi)部網(wǎng)絡(luò)。NAT會轉(zhuǎn)換內(nèi)部網(wǎng)絡(luò)的所有請求,使它們看起來象是來自進(jìn)行NAT工作的主機(jī)系統(tǒng)。
NAT如何工作
當(dāng)內(nèi)部網(wǎng)絡(luò)的一個(gè)客戶端連接因特網(wǎng)上的主機(jī)時(shí),它發(fā)送目的是那臺主機(jī)的IP數(shù)據(jù)包。這些數(shù)據(jù)包包含了達(dá)到連接目的的所有信息。NAT的作用和這些信息相關(guān)。
* 源 IP 地址 (例如, 192.168.1.35)
* 源 TCP 或者 UDP 端口 (例如, 2132)
當(dāng)數(shù)據(jù)包通過NAT
網(wǎng)關(guān)
時(shí),它們會被修改,使得數(shù)據(jù)包看起來象是從NAT網(wǎng)關(guān)自己發(fā)出的。NAT網(wǎng)關(guān)會在它的狀態(tài)表中記錄這個(gè)改變,以便:
a)將返回的數(shù)據(jù)包反向轉(zhuǎn)換
b)確保返回的數(shù)據(jù)包能通過防火墻而不會被阻塞。
例如,會發(fā)生下面的改變:
* 源 IP: 被網(wǎng)關(guān)的外部地址所替換(例如, 24.5.0.5)
* 源端口:被隨機(jī)選擇的網(wǎng)關(guān)沒有在用的端口替換 (例如, 53136)
內(nèi)部主機(jī)和因特網(wǎng)上的主機(jī)都不會意識到發(fā)生了這個(gè)轉(zhuǎn)變步驟。對于內(nèi)部主機(jī),NAT系統(tǒng)僅僅是個(gè)因特網(wǎng)網(wǎng)關(guān),對于因特網(wǎng)上的主機(jī),數(shù)據(jù)包看起來直接來自NAT系統(tǒng),它完全不會意識到內(nèi)部工作站的存在。
當(dāng)因特網(wǎng)網(wǎng)上的主機(jī)回應(yīng)內(nèi)部主機(jī)的數(shù)據(jù)包時(shí),它會使用NAT網(wǎng)關(guān)機(jī)器的外部地址和轉(zhuǎn)換后的端口。然后NAT網(wǎng)關(guān)會查詢狀態(tài)表來確定返回的數(shù)據(jù)包是否匹配某個(gè)已經(jīng)建立的連接;贗P地址和端口的聯(lián)合找到唯一匹配的記錄告訴PF這個(gè)返回的數(shù)據(jù)包屬于內(nèi)部主機(jī)192.168.1.35。然后PF會進(jìn)行和出去的數(shù)據(jù)包相反的轉(zhuǎn)換過程,將返回的數(shù)據(jù)包傳遞給內(nèi)部主機(jī)。
ICMP數(shù)據(jù)包的轉(zhuǎn)換也是類似的,只是不進(jìn)行源端口的修改。
![]()
NAT和包過濾
注意:轉(zhuǎn)換后的數(shù)據(jù)包仍然會通過
過濾引擎
,根據(jù)定義的過濾規(guī)則進(jìn)行阻塞或者通過。唯一的例外是如果nat規(guī)則中使用了pass關(guān)鍵字,會使得經(jīng)過nat的數(shù)據(jù)包直接通過過濾引擎。
還要注意由于轉(zhuǎn)換是在過濾之前進(jìn)行,過濾引擎所看到的是上面“nat如何工作”中所說的經(jīng)過轉(zhuǎn)換后的ip地址和端口的數(shù)據(jù)包。
IP 轉(zhuǎn)發(fā)
由于NAT經(jīng)常在路由器和網(wǎng)關(guān)上使用,因此IP轉(zhuǎn)發(fā)是需要的,使得數(shù)據(jù)包可以在UNIX機(jī)器的不同網(wǎng)絡(luò)接口間傳遞。IP轉(zhuǎn)發(fā)可以通過sysctl命令打開:
# sysctl -w net.inet.ip.forwarding=1
# sysctl -w net.inet6.ip6.forwarding=1 (if using IPv6)
要使這個(gè)變化永久生效,可以增加如下行到/etc/sysctl.conf文件中:
net.inet.ip.forwarding=1
net.inet6.ip6.forwarding=1
這些行是本來就存在的,但默認(rèn)安裝中被#前綴注釋掉了。刪除#,保存文件,IP轉(zhuǎn)發(fā)在機(jī)器重啟后就會發(fā)生作用。
配置NAT
一般的NAT規(guī)則格式在pf.conf文件中是這個(gè)樣子:
nat [pass] on interface [af] from src_addr [port src_port] to \
dst_addr [port dst_port] -> ext_addr [pool_type] [static-port]
nat
開始NAT規(guī)則的關(guān)鍵字。
pass
使得轉(zhuǎn)換后的數(shù)據(jù)包完全繞過過濾規(guī)則。
interface
進(jìn)行數(shù)據(jù)包轉(zhuǎn)換的網(wǎng)絡(luò)接口。
af
地址類型,inet代表Ipv4,inet6代表Ipv6。PF通常能根據(jù)源/目標(biāo)地址自動(dòng)確定這個(gè)參數(shù)。
src_addr
被進(jìn)行轉(zhuǎn)換的IP頭中的源(內(nèi)部)地址。源地址可以指定為:
單個(gè)的Ipv4或者Ipv6地址.
CIDR 網(wǎng)絡(luò)地址.
能夠在規(guī)則集載入時(shí)通過DNS解析到的合法的域名,IP地址會替代規(guī)則中的域名。
網(wǎng)絡(luò)接口名稱。網(wǎng)絡(luò)接口上配置的所有ip地址會替代進(jìn)規(guī)則中。
帶有/掩碼(例如/24)的網(wǎng)絡(luò)接口的名稱。每個(gè)根據(jù)掩碼確定的CIDR網(wǎng)絡(luò)地址都會被替代進(jìn)規(guī)則中。.
帶有()的網(wǎng)絡(luò)接口名稱。這告訴PF如果網(wǎng)絡(luò)接口的IP地址改變了,就更新規(guī)則集。這個(gè)對于使用DHCP或者撥號來獲得IP地址的接口特別有用,IP地址改變時(shí)不需要重新載入規(guī)則集。
帶有如下的修飾詞的網(wǎng)絡(luò)接口名稱:
o :network - 替代CIDR網(wǎng)絡(luò)地址段 (例如, 192.168.0.0/24)
o :broadcast - 替代網(wǎng)絡(luò)廣播地址(例如, 192.168.0.255)
o :peer - 替代點(diǎn)到點(diǎn)鏈路上的ip地址。
另外,:0修飾詞可以附加到接口名稱或者上面的修飾詞后面指示PF在替代時(shí)不包括網(wǎng)絡(luò)接口的其余附加(alias)地址。這些修飾詞也可以在接口名稱在括號()內(nèi)時(shí)使用。例如:fxp0:network:0
表.
上面的所有項(xiàng)但使用。ǚ牵┬揎椩~
使用列表的一系列地址.
關(guān)鍵字 any 代表所有地址
關(guān)鍵字 all 是 from any to any的縮寫。
src_port
4層數(shù)據(jù)包頭中的源端口。端口可以指定為:
1 到 65535之間的整數(shù)
/etc/services中的合法服務(wù)名稱
使用列表的一系列端口
一個(gè)范圍:
o != (不等于)
o (大于)
o = (大于等于)
o > (反轉(zhuǎn)范圍)
最后2個(gè)是二元操作符(他們需要2個(gè)參數(shù)),在范圍內(nèi)不包括參數(shù)。
o : (inclusive range)
inclusive range 也是二元操作符但范圍內(nèi)包括參數(shù)。
Port選項(xiàng)在NAT規(guī)則中通常不使用,因?yàn)槟繕?biāo)通常會NAT所有的流量而不過端口是否在使用。
dst_addr
被轉(zhuǎn)換數(shù)據(jù)包中的目的地址。目的地址類型和源地址相似。
dst_port
4層數(shù)據(jù)包頭中的目的目的端口,目的端口類型和源端口類型相似。
ext_addr
NAT網(wǎng)關(guān)上數(shù)據(jù)包被轉(zhuǎn)換后的外部地址。外部地址可以是:
單個(gè)的Ipv4或者Ipv6地址.
CIDR 網(wǎng)絡(luò)地址.
能夠在規(guī)則集載入時(shí)通過DNS解析到的合法的域名,IP地址會替代規(guī)則中的域名。
網(wǎng)絡(luò)接口名稱。網(wǎng)絡(luò)接口上配置的所有ip地址會替代進(jìn)規(guī)則中。
帶有/掩碼(例如/24)的網(wǎng)絡(luò)接口的名稱。每個(gè)根據(jù)掩碼確定的CIDR網(wǎng)絡(luò)地址都會被替代進(jìn)規(guī)則中。.
帶有()的網(wǎng)絡(luò)接口名稱。這告訴PF如果網(wǎng)絡(luò)接口的IP地址改變了,就更新規(guī)則集。這個(gè)對于使用DHCP或者撥號來獲得IP地址的接口特別有用,IP地址改變時(shí)不需要重新載入規(guī)則集。
帶有如下的修飾詞的網(wǎng)絡(luò)接口名稱:
o :network - 替代CIDR網(wǎng)絡(luò)地址段 (例如, 192.168.0.0/24)
o :broadcast - 替代網(wǎng)絡(luò)廣播地址(例如, 192.168.0.255)
o :peer - 替代點(diǎn)到點(diǎn)鏈路上的ip地址。
另外,:0修飾詞可以附加到接口名稱或者上面的修飾詞后面指示PF在替代時(shí)不包括網(wǎng)絡(luò)接口的其余附加(alias)地址。這些修飾詞也可以在接口名稱在括號()內(nèi)時(shí)使用。例如:fxp0:network:0
使用列表的一系列地址.
pool_type
指定轉(zhuǎn)換后的地址池的類型
static-port
告訴PF不要轉(zhuǎn)換TCP和UDP數(shù)據(jù)包中的源端口
這條規(guī)則最簡單的形式如下:
nat on tl0 from 192.168.1.0/24 to any -> 24.5.0.5
這條規(guī)則是說對從tl0網(wǎng)絡(luò)接口上到來的所有192.168.1.0/24網(wǎng)絡(luò)的數(shù)據(jù)包進(jìn)行NAT,將源地址轉(zhuǎn)換為24.5.0.5。
盡管上面的規(guī)則是正確的,但卻不是推薦的形式。因?yàn)榫S護(hù)起來有困難,當(dāng)內(nèi)部或者外部網(wǎng)絡(luò)有變化時(shí)都要修改這一行。比較一下下面這條比較容易維護(hù)的規(guī)則:(tl0時(shí)外部,dc0是內(nèi)部):
nat on tl0 from dc0:network to any -> tl0
優(yōu)點(diǎn)是相當(dāng)明顯的,可以任意改變2個(gè)接口的IP地址而不用改變這條規(guī)則。
象上面這樣在地址轉(zhuǎn)換中使用接口名稱時(shí),IP地址在pf.conf文件載入時(shí)確定,并不是憑空的。如果使用DHCP還配置外部地址,這會存在問題。如果分配的IP地址改變了,NAT仍然會使用舊的IP地址轉(zhuǎn)換出去的數(shù)據(jù)包。這會導(dǎo)致對外的連接停止工作。為解決這個(gè)問題,應(yīng)該給接口名稱加上括號,告訴PF自動(dòng)更新轉(zhuǎn)換地址。
nat on tl0 from dc0:network to any -> (tl0)
這個(gè)方法對IPv4 和 IPv6地址都用效。
![]()
雙向映射 (1:1 映射)
雙向映射
可以通過使用
binat
規(guī)則建立。Binat規(guī)則建立一個(gè)內(nèi)部地址和外部地址一對一的映射。這會很有用,比如,使用獨(dú)立的外部IP地址用內(nèi)部網(wǎng)絡(luò)里的機(jī)器提供web服務(wù)。從因特網(wǎng)到來連接外部地址的請求被轉(zhuǎn)換到內(nèi)部地址,同時(shí)由(內(nèi)部)web服務(wù)器發(fā)起的連接(例如DNS查詢)被轉(zhuǎn)換為外部地址。和NAT規(guī)則不過,binat規(guī)則中的tcp和udp端口不會被修改。
例如:
web_serv_int = "192.168.1.100"
web_serv_ext = "24.5.0.6"
binat on tl0 from $web_serv_int to any -> $web_serv_ext
轉(zhuǎn)換規(guī)則例外設(shè)置
使用no關(guān)鍵字可以在轉(zhuǎn)換規(guī)則中設(shè)置例外。例如,如果上面的轉(zhuǎn)換規(guī)則修改成這樣:
no nat on tl0 from 192.168.1.10 to any
nat on tl0 from 192.168.1.0/24 to any -> 24.2.74.79
則除了192.168.1.10以外,整個(gè)192.168.1.0/24網(wǎng)絡(luò)地址的數(shù)據(jù)包都會轉(zhuǎn)換為外部地址24.2.74.79。
注意第一條匹配的規(guī)則起了決定作用,如果是匹配有no的規(guī)則,數(shù)據(jù)包不會被轉(zhuǎn)換。No關(guān)鍵字也可以在binat和rdr規(guī)則中使用。
檢查 NAT 狀態(tài)
要檢查活動(dòng)的NAT轉(zhuǎn)換可以使用pfctl帶-s state 選項(xiàng)。這個(gè)選項(xiàng)列出所有當(dāng)前的NAT會話。
# pfctl -s state
fxp0 TCP 192.168.1.35:2132 -> 24.5.0.5:53136 -> 65.42.33.245:22 TIME_WAIT:TIME_WAIT
fxp0 UDP 192.168.1.35:2491 -> 24.5.0.5:60527 -> 24.2.68.33:53 MULTIPLE:SINGLE
解釋 (對第一行):
fxp0
顯示狀態(tài)綁定的接口。如果狀態(tài)是浮動(dòng)的,會出現(xiàn)self字樣。
TCP
連接使用的協(xié)議。
192.168.1.35:2132
內(nèi)部網(wǎng)絡(luò)中機(jī)器的IP地址 (192.168.1.35),源端口(2132)在地址后顯示,這個(gè)也是被替換的IP頭中的地址。 of the machine on the internal network. The
source port (2132) is shown after the address. This is also the address
that is replaced in the IP header.
24.5.0.5:53136
IP 地址 (24.5.0.5) 和端口 (53136) 是網(wǎng)關(guān)上數(shù)據(jù)包被轉(zhuǎn)換后的地址和端口。
65.42.33.245:22
IP 地址 (65.42.33.245) 和端口 (22) 是內(nèi)部機(jī)器要連接的地址和端口。
TIME_WAIT:TIME_WAIT
這表明PF認(rèn)為的目前這個(gè)TCP連接的狀態(tài)。
編輯本段
回目錄
PF防火墻 - 重定向 (端口轉(zhuǎn)發(fā))
![]()
簡介
如果在辦公地點(diǎn)應(yīng)用了NAT,內(nèi)部網(wǎng)所有的機(jī)器都可以訪問因特網(wǎng)。但如何讓NAT網(wǎng)關(guān)后面的機(jī)器能夠被從外部訪問?這就是重定向的來源。重定向允許外來的流量發(fā)送到NAT網(wǎng)關(guān)后面的機(jī)器。
看個(gè)例子:
rdr on tl0 proto tcp from any to any port 80 -> 192.168.1.20
這一行重定向了TCP端口80(
web服務(wù)器
)流量到內(nèi)部網(wǎng)絡(luò)地址192.168.1.20。因此,即使192.168.1.20在網(wǎng)關(guān)后面的內(nèi)部網(wǎng)絡(luò),外部仍然能夠訪問它。
上面rdr行中from any to any部分非常有用。如果明確知道哪些地址或者子網(wǎng)被允許訪問web服務(wù)器的80端口,可以在這部分嚴(yán)格限制:
rdr on tl0 proto tcp from 27.146.49.0/24 to any port 80 -> 192.168.1.20
這樣只會重定向指定的子網(wǎng)。注意這表明可以重定向外部不同的訪問主機(jī)到網(wǎng)關(guān)后面不同的機(jī)器上。這非常有用。例如,如果知道遠(yuǎn)端的用戶連接上來時(shí)使用的IP地址,可以讓他們使用網(wǎng)關(guān)的IP地址和端口訪問他們各自的桌面計(jì)算機(jī)。
rdr on tl0 proto tcp from 27.146.49.14 to any port 80 -> \
192.168.1.20
rdr on tl0 proto tcp from 16.114.4.89 to any port 80 -> \
192.168.1.22
rdr on tl0 proto tcp from 24.2.74.178 to any port 80 -> \
192.168.1.23
重定向和包過濾
注意:轉(zhuǎn)換后的數(shù)據(jù)包仍然會通過過濾引擎,根據(jù)定義的過濾規(guī)則進(jìn)行阻塞或者通過。唯一的例外是如果rdr規(guī)則中使用了pass關(guān)鍵字,會使得重定向的數(shù)據(jù)包直接通過過濾引擎。
還要注意由于轉(zhuǎn)換是在過濾之前進(jìn)行,過濾引擎所看到的是在匹配rdr規(guī)則經(jīng)過轉(zhuǎn)換后的目標(biāo)ip地址和端口的數(shù)據(jù)包。
* 192.0.2.1 - 因特網(wǎng)上的主機(jī)
* 24.65.1.13 - openbsd路由器的外部地址
* 192.168.1.5 - web服務(wù)器的內(nèi)部IP地址
![]()
重定向規(guī)則:
rdr on tl0 proto tcp from 192.0.2.1 to 24.65.1.13 port 80 \
-> 192.168.1.5 port 8000
數(shù)據(jù)包在經(jīng)過rdr規(guī)則前的模樣:
* 源地址: 192.0.2.1
* 源端口: 4028 (由操作系統(tǒng)任意選擇)
* 目的地址: 24.65.1.13
* 目的端口: 80
數(shù)據(jù)包經(jīng)過rdr規(guī)則后的模樣:
* 源地址: 192.0.2.1
* 源端口: 4028
* 目的地址: 192.168.1.5
* 目的: 8000
過濾引擎看見的IP數(shù)據(jù)包時(shí)轉(zhuǎn)換發(fā)生之后的情況。
安全隱患
重定向確實(shí)存在安全隱患。在防火墻上開了一個(gè)允許流量進(jìn)入內(nèi)部網(wǎng)絡(luò)的洞,被保護(hù)的網(wǎng)絡(luò)安全潛在的受到了威脅!例如,如果流量被轉(zhuǎn)發(fā)到了內(nèi)部的web服務(wù)器,而web服務(wù)器上允許的守護(hù)程序或者CGI腳本程序存在漏洞,則這臺服務(wù)器存在會被因特網(wǎng)網(wǎng)上的入侵者攻擊危險(xiǎn)。如果入侵者控制了這臺機(jī)器,就有了進(jìn)入內(nèi)部網(wǎng)絡(luò)的通道,僅僅是因?yàn)檫@種流量是允許通過防火墻的。
這種風(fēng)險(xiǎn)可以通過將允許外部網(wǎng)絡(luò)訪問的系統(tǒng)限制在一個(gè)單獨(dú)的網(wǎng)段中來減小。這個(gè)網(wǎng)段通常也被稱為非軍事化區(qū)域(
DMZ
)或者私有服務(wù)網(wǎng)絡(luò)(
PSN
)。通過這個(gè)方法,如果web服務(wù)器被控制,通過嚴(yán)格的過濾進(jìn)出DMZ/PSN的流量,受影響的系統(tǒng)僅限于DMZ/PSN網(wǎng)段。
重定向和反射
通常,重定向規(guī)則是用來將因特網(wǎng)上到來的連接轉(zhuǎn)發(fā)到一個(gè)內(nèi)部網(wǎng)絡(luò)或者局域網(wǎng)的私有地址。例如:
server = 192.168.1.40
rdr on $ext_if proto tcp from any to $ext_if port 80 -> $server \
port 80
但是,當(dāng)一個(gè)重定向規(guī)則被從局域網(wǎng)上的客戶端進(jìn)行測試時(shí),它不會正常工作。這是因?yàn)橹囟ㄏ蛞?guī)則僅適用于通過指定端口($ext_if,外部接口,在上面的例子中)的數(shù)據(jù)包。從局域網(wǎng)上的主機(jī)連接防火墻的外部地址,并不意味著數(shù)據(jù)包會實(shí)際的通過外部接口。防火墻上的TCP/IP棧會把到來的數(shù)據(jù)包的目的地址在通過內(nèi)部接口時(shí)與它自己的IP地址或者別名進(jìn)行對比檢測。那樣的數(shù)據(jù)包不會真的通過外部接口,棧在任何情況下也不會建立那樣的通道。因而,PF永遠(yuǎn)也不會在外部接口上看到那些數(shù)據(jù)包,過濾規(guī)則由于指定了外部接口也不會起作用。
指定第二條針對內(nèi)部接口的也達(dá)不到預(yù)想的效果。當(dāng)本地的客戶端連接防火墻的外部地址時(shí),初始化的TCP握手?jǐn)?shù)據(jù)包是通過內(nèi)部接口到達(dá)防火墻的。重定向規(guī)則確實(shí)起作用了,目標(biāo)地址被替換成了內(nèi)部服務(wù)器,數(shù)據(jù)包通過內(nèi)部接口轉(zhuǎn)發(fā)到了內(nèi)部的服務(wù)器。但源地址沒有進(jìn)行轉(zhuǎn)換,仍然包含的是本地客戶端的IP地址,因此服務(wù)器把它的回應(yīng)直接發(fā)送給了客戶端。防火墻永遠(yuǎn)收不到應(yīng)答不可能返回客戶端信息,客戶端收到的應(yīng)答不是來自它期望的源(防火墻)會被丟棄,TCP握手失敗,不能建立連接。
當(dāng)然,局域網(wǎng)里的客戶端仍然會希望象外部客戶一樣透明的訪問這臺內(nèi)部服務(wù)器。有如下的方法解決這個(gè)問題:
水平分割 DNS
存在這樣的可能性,即配置DNS服務(wù)器使得它回答內(nèi)部主機(jī)的查詢和回答外部主機(jī)的查詢不一樣,因此內(nèi)部客戶端在進(jìn)行名稱解析時(shí)會收到內(nèi)部服務(wù)器的地址。它們直接連接到內(nèi)部服務(wù)器,防火墻根本不牽扯。這會降低本地流量,因?yàn)閿?shù)據(jù)包不會被送到防火墻。
將服務(wù)器移到獨(dú)立的本地網(wǎng)絡(luò)
增加單獨(dú)的網(wǎng)絡(luò)接口卡到防火墻,把本地的服務(wù)器從和客戶端同一個(gè)網(wǎng)段移動(dòng)到專用的網(wǎng)段(DMZ)可以讓本地客戶端按照外部重定向連接的方法一樣重定向。使用單獨(dú)的網(wǎng)段有幾個(gè)優(yōu)點(diǎn),包括和保留的內(nèi)部主機(jī)隔離增加了安全性;服務(wù)器(我們的案例中可以從因特網(wǎng)訪問)一旦被控制,它不能直接存取本地網(wǎng)絡(luò)因?yàn)樗械倪B接都必須通過防火墻。
TCP 代理
一般而言,TCP代理可以在防火墻上設(shè)置,監(jiān)聽要轉(zhuǎn)發(fā)的端口或者將內(nèi)部接口上到來的連接重定向到它監(jiān)聽的端口。當(dāng)本地客戶端連接防火墻時(shí),代理接受連接,建立到內(nèi)部服務(wù)器的第二條連接,在通信雙方間進(jìn)行數(shù)據(jù)轉(zhuǎn)發(fā)。
簡單的代理可以使用
inetd
和
nc
建立。下面的/etc/inetd.conf中的條目建立一個(gè)監(jiān)聽套接字綁定到lookback地址(127.0.0.1)和端口5000。連接被轉(zhuǎn)發(fā)到服務(wù)器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
下面的重定向規(guī)則轉(zhuǎn)發(fā)內(nèi)部接口的80端口到代理:
rdr on $int_if proto tcp from $int_net to $ext_if port 80 -> \
127.0.0.1 port 5000
RDR 和 NAT 結(jié)合
通過對內(nèi)部接口增加NAT規(guī)則,上面說的轉(zhuǎn)換后源地址不變的問題可以解決。
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
這會導(dǎo)致由客戶端發(fā)起的初始化連接在收到內(nèi)部接口的返回?cái)?shù)據(jù)包時(shí)轉(zhuǎn)換回來,客戶端的源ip地址被防火墻的內(nèi)部接口地址代替。內(nèi)部服務(wù)器會回應(yīng)防火墻的內(nèi)部接口地址,在轉(zhuǎn)發(fā)給本地客戶端時(shí)可以反轉(zhuǎn)NAT和RDR。這個(gè)結(jié)構(gòu)是非常復(fù)雜的,因?yàn)樗鼮槊總(gè)反射連接產(chǎn)生了2個(gè)單獨(dú)的狀態(tài)。必須小心配置防止NAT規(guī)則應(yīng)用到了其他流量,例如連接由外部發(fā)起(通過其他的重定向)或者防火墻自己。注意上面的rdr規(guī)則會導(dǎo)致TCP/IP棧看到來自內(nèi)部接口帶有目的地址是內(nèi)部網(wǎng)絡(luò)的數(shù)據(jù)包。
編輯本段
回目錄
PF防火墻 - 規(guī)則生成捷徑
簡介
PF提供了許多方法來進(jìn)行規(guī)則集的簡化。一些好的例子是使用宏和列表。另外,規(guī)則集的語言或者語法也提供了一些使規(guī)則集簡化的捷徑。首要的規(guī)則是,規(guī)則集越簡單,就越容易理解和維護(hù)。
使用宏
宏是非常有用的,因?yàn)樗峁┝?br />
硬編碼地址
,端口號,接口名稱等的可選替代。在一個(gè)規(guī)則集中,服務(wù)器的IP地址改變了?沒問題,僅僅更新一下宏,不需要弄亂花費(fèi)了大量時(shí)間和精力建立的規(guī)則集。
通常的慣例是在PF規(guī)則集中定義每個(gè)網(wǎng)絡(luò)接口的宏。如果網(wǎng)卡需要被使用不同驅(qū)動(dòng)的卡取代,例如,用
intel
代替
3com
,可以更新宏,過濾規(guī)則集會和以前功能一樣。另一個(gè)優(yōu)點(diǎn)是,如果在多臺機(jī)器上安裝同樣的規(guī)則集,某些機(jī)器會有不同的網(wǎng)卡,使用宏定義網(wǎng)卡可以使的安裝的規(guī)則集進(jìn)行最少的修改。使用宏來定義規(guī)則集中經(jīng)常改變的信息,例如端口號,IP地址,接口名稱等等,建議多多實(shí)踐!
# define macros for each network interface
IntIF = "dc0"
ExtIF = "fxp0"
DmzIF = "fxp1"
另一個(gè)慣例是使用宏來定義IP地址和網(wǎng)絡(luò),這可以大大減輕在IP地址改變時(shí)對規(guī)則集的維護(hù)。
# define our networks
IntNet = "192.168.0.0/24"
ExtAdd = "24.65.13.4"
DmzNet = "10.0.0.0/24"
如果內(nèi)部地址擴(kuò)展了或者改到了一個(gè)不同的IP段,可以更新宏為:
IntNet = "{ 192.168.0.0/24, 192.168.1.0/24 }"
當(dāng)這個(gè)規(guī)則集重新載入時(shí),任何東西都跟以前一樣。
使用列表
來看一下一個(gè)規(guī)則集中比較好的例子使得
RFC1918
定義的內(nèi)部地址不會傳送到因特網(wǎng)上,如果發(fā)生傳送的事情,可能導(dǎo)致問題。
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
看看下面更簡單的例子:
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 }
這個(gè)規(guī)則集從8行減少到2行。如果聯(lián)合使用宏,還會變得更好:
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
注意雖然宏和列表簡化了pf.conf文件,但是實(shí)際是這些行會被pfctl(8)擴(kuò)展成多行,因此,上面的例子實(shí)際擴(kuò)展成下面的規(guī)則:
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
可以看到,PF擴(kuò)展僅僅是簡化了編寫和維護(hù)pf.conf文件,實(shí)際并不簡化pf(4)對于規(guī)則的處理過程。
宏不僅僅用來定義地址和端口,它們在PF的規(guī)則文件中到處都可以用:
pre = "pass in quick on ep0 inet proto tcp from "
post = "to any port { 80, 6667 } keep state"
# David‘s classroom
$pre 21.14.24.80 $post
# Nick‘s home
$pre 24.2.74.79 $post
$pre 24.2.74.178 $post
擴(kuò)展后:
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
PF 語法
PF的語法相當(dāng)靈活,因此,允許編寫非常靈活的規(guī)則集。PF能夠自動(dòng)插入某些關(guān)鍵字因此它們不必在規(guī)則中明確寫出,關(guān)鍵字的順序也是隨意的,因此不需要記憶嚴(yán)格的語法限制。
減少關(guān)鍵字
要定義全部拒絕的策略,使用下面2條規(guī)則:
block in all
block out all
這可以簡化為:
block all
如果沒有指定方向,PF會認(rèn)為規(guī)則適用于數(shù)據(jù)包傳遞的進(jìn)、出2個(gè)方向。
同樣的, "from any to any" 和 "all" 子句可以在規(guī)則中省略,例如
block in on rl0 all
pass in quick log on rl0 proto tcp from any to any port 22 keep state
可以簡化為:
block in on rl0
pass in quick log on rl0 proto tcp to port 22 keep state
第一條規(guī)則阻塞rl0上從任意到任意的進(jìn)入數(shù)據(jù)包,第二條規(guī)則允許rl0上端口22的TCP流量通過。
Return 簡化
用于阻塞數(shù)據(jù)包,回應(yīng)TCP RST或者ICMP不可到達(dá)的規(guī)則集可以這么寫:
block in all
block return-rst in proto tcp all
block return-icmp in proto udp all
block out all
block return-rst out proto tcp all
block return-icmp out proto udp all
可以簡化為::
block return
當(dāng)PF看到return關(guān)鍵字,PF可以智能回復(fù)合適應(yīng)答,或者完全不回復(fù),取決于要阻塞的數(shù)據(jù)包使用的協(xié)議。W
關(guān)鍵字順序
在大多數(shù)情況下,關(guān)鍵字的順序是非常靈活的。例如,規(guī)則可以這么寫:
pass in log quick on rl0 proto tcp to port 22 \
flags S/SA keep state queue ssh label ssh
也可以這么寫:
pass in quick log on rl0 proto tcp to port 22 \
queue ssh keep state label ssh flags S/SA
其他類似的順序也能夠正常工作。
編輯本段
回目錄
PF防火墻 - 高級配置
運(yùn)行選項(xiàng)
運(yùn)行選項(xiàng)是控制pf操作的選擇。這些選項(xiàng)在pf.conf中使用set指定。
set block-policy
設(shè)定過濾規(guī)則中指定的block動(dòng)作的默認(rèn)行為。
drop - 數(shù)據(jù)包悄然丟棄.
return - TCP RST 數(shù)據(jù)包返回給遭阻塞的TCP數(shù)據(jù)包,ICMP不可到達(dá)數(shù)據(jù)包返回給其他。
注意單獨(dú)的過濾規(guī)則可以重寫默認(rèn)的響應(yīng)。
set debug
設(shè)定pf的調(diào)試級別。
none - 不顯示任何調(diào)試信息。
urgent - 為嚴(yán)重錯(cuò)誤產(chǎn)生調(diào)試信息,這是默認(rèn)選擇。
misc - 為多種錯(cuò)誤產(chǎn)生調(diào)試信息。(例如,收到標(biāo)準(zhǔn)化/整形的數(shù)據(jù)包的狀態(tài),和產(chǎn)生失敗的狀態(tài))。.
loud - 為普通條件產(chǎn)生調(diào)試信息(例如,收到被動(dòng)操作系統(tǒng)檢測信息狀態(tài))。
set fingerprints file
設(shè)定應(yīng)該裝入的進(jìn)行操作系統(tǒng)識別的操作系統(tǒng)特征文件來,默認(rèn)是 /etc/pf.os.
set limit
frags - 在內(nèi)存池中進(jìn)行數(shù)據(jù)包重組的最大數(shù)目。默認(rèn)是5000。
src-nodes - 在內(nèi)存池中用于追蹤源地址(由stick-address 和 source-track選項(xiàng)產(chǎn)生)的最大數(shù)目,默認(rèn)是10000。
states - 在內(nèi)存池中用于狀態(tài)表(過濾規(guī)則中的keep state)的最大數(shù)目,默認(rèn)是10000。
set loginterface int
設(shè)定PF要統(tǒng)計(jì)進(jìn)/出流量和放行/阻塞的數(shù)據(jù)包的數(shù)目的接口卡。統(tǒng)計(jì)數(shù)目一次只能用于一張卡。注意 match, bad-offset, 等計(jì)數(shù)器和狀態(tài)表計(jì)數(shù)器不管 loginterface是否設(shè)置都會被記錄。
set optimization
為以下的網(wǎng)絡(luò)環(huán)境優(yōu)化PF:
normal - 適用于絕大多數(shù)網(wǎng)絡(luò),這是默認(rèn)項(xiàng)。
high-latency - 高延時(shí)網(wǎng)絡(luò),例如衛(wèi)星連接。
aggressive - 自狀態(tài)表中主動(dòng)終止連接。這可以大大減少繁忙防火墻的內(nèi)存需求,但要冒空閑連接被過早斷開的風(fēng)險(xiǎn)。
conservative - 特別保守的設(shè)置。這可以避免在內(nèi)存需求過大時(shí)斷開空閑連接,會稍微增加CPU的利用率。
set state-policy
設(shè)定 PF在狀態(tài)保持時(shí)的行為。這種行為可以被單條規(guī)則所改變。見狀態(tài)保持章節(jié)。
if-bound - 狀態(tài)綁定到產(chǎn)生它們的接口。如果流量匹配狀態(tài)表種條目但不是由條目中記錄的接口通過,這個(gè)匹配會失敗。數(shù)據(jù)包要么匹配一條過濾規(guī)則,或者被丟棄/拒絕。
group-bound - 行為基本和if-bound相同,除了數(shù)據(jù)包允許由同一組接口通過,例如所有的ppp接口等。
floating - 狀態(tài)可以匹配任何接口上的流量。只要數(shù)據(jù)包匹配狀態(tài)表?xiàng)l目,不管是否匹配它通過的接口,都會放行。這是默認(rèn)的規(guī)則。
set timeout
interval - 丟棄過期的狀態(tài)和數(shù)據(jù)包碎片的秒數(shù)。
frag - 不能重組的碎片過期的秒數(shù)。
例如:
set timeout interval 10
set timeout frag 30
set limit { frags 5000, states 2500 }
set optimization high-latency
set block-policy return
set loginterface dc0
set fingerprints /etc/pf.os.test
set state-policy if-bound
編輯本段
回目錄
PF防火墻 - 流量整形
簡介
流量整形是將數(shù)據(jù)包標(biāo)準(zhǔn)化避免最終的數(shù)據(jù)包出現(xiàn)非法的目的。流量整形指引同時(shí)也會重組數(shù)據(jù)包碎片,保護(hù)某些操作系統(tǒng)免受某些攻擊,丟棄某些帶有非法聯(lián)合標(biāo)記的TCP數(shù)據(jù)包。流量整形指引的簡單形式是:
scrub in all
這會對所有接口上到來的數(shù)據(jù)包進(jìn)行流量整形。
一個(gè)不在接口上進(jìn)行流量整形的原因是要透過PF使用NFS。一些非openbsd的平臺發(fā)送(和等待)奇怪的數(shù)據(jù)包,對設(shè)置不分片位的數(shù)據(jù)包進(jìn)行分片。這會被流量整形(正確的)拒絕。這個(gè)問題可以通過設(shè)置no-df選項(xiàng)解決。另一個(gè)原因是某些多用戶的游戲在進(jìn)行流量整形通過PF時(shí)存在連接問題。除了這些極其罕見的案例,對所有的數(shù)據(jù)包進(jìn)行流量整形時(shí)強(qiáng)烈推薦的設(shè)置。
流量整形指引語法相對過濾語法是非常簡單的,它可以非常容易的選擇特定的數(shù)據(jù)包進(jìn)行整形而不對沒指定的數(shù)據(jù)包起作用。
選項(xiàng)
流量整形有下面的選項(xiàng):
no-df
在IP數(shù)據(jù)包頭中清除不分片位的設(shè)置。某些操作系統(tǒng)已知產(chǎn)生設(shè)置不分片位的分片數(shù)據(jù)包。尤其是對于
NFS
。流量整形(
scrub
)會丟棄這類數(shù)據(jù)包除非設(shè)置了no-df選項(xiàng)。某些操作系統(tǒng)產(chǎn)生帶有不分片位和用0填寫IP包頭中分類域,推薦使用no-df和random-id 聯(lián)合使用解決。
random-id
用隨機(jī)值替換某些操作系統(tǒng)輸出數(shù)據(jù)包中使用的可預(yù)測
IP分類域
的值這個(gè)選項(xiàng)僅適用于在選擇的數(shù)據(jù)包重組后不進(jìn)行分片的輸入數(shù)據(jù)包。
min-ttl num
增加IP包頭中的最小存活時(shí)間(TTL)。
max-mss num
增加在TCP數(shù)據(jù)包頭中最大分段值(MSS)。
fragment reassemble
在傳遞數(shù)據(jù)包到過濾引擎前緩沖收到的數(shù)據(jù)包碎片,重組它們成完整的數(shù)據(jù)包。優(yōu)點(diǎn)是過濾規(guī)則僅處理完整的數(shù)據(jù)包,忽略碎片。缺點(diǎn)是需要內(nèi)存緩沖數(shù)據(jù)包碎片。這是沒有設(shè)置分片選項(xiàng)時(shí)的默認(rèn)行為。這也是能和NAT一起工作的唯一分片選項(xiàng)。
fragment crop
導(dǎo)致重復(fù)的碎片被丟棄,重疊的被裁剪。與碎片重組不同,碎片不會被緩沖,而是一到達(dá)就直接傳遞。
fragment drop-ovl
跟 fragment crop 相似,除了所有重復(fù)和重疊的碎片和其他更多的通信碎片一樣被丟棄。
reassemble tcp
TCP連接狀態(tài)標(biāo)準(zhǔn)化。當(dāng)使用了 scrub reassemble tcp時(shí),方向(進(jìn)/出)不用說明,會執(zhí)行下面的標(biāo)準(zhǔn)化過程:
連接雙方都不允許減少它們的IP TTL值。這樣做是為了防止攻擊者發(fā)送數(shù)據(jù)包到防火墻,影響防火墻保持的連接狀態(tài),使數(shù)據(jù)包在到達(dá)目的主機(jī)前就過期。所有數(shù)據(jù)包的TTL都為了這個(gè)連接加到了最大值。
用隨機(jī)數(shù)字調(diào)整TCP數(shù)據(jù)包頭中的 RFC1323 時(shí)間戳。這可以阻止竊聽者推斷主機(jī)在線的時(shí)間和猜測NAT網(wǎng)關(guān)后面有多少主機(jī)。
實(shí)例:
scrub in on fxp0 all fragment reassemble min-ttl 15 max-mss 1400
scrub in on fxp0 all no-df
scrub on fxp0 all reassemble tcp
編輯本段
回目錄
PF防火墻 - 錨定和命名規(guī)則集
簡介
除了主要的規(guī)則集,PF還可以載入子規(guī)則
該網(wǎng)絡(luò)的隊(duì)列策略:
* 為Bob保留玩在線游戲的80Kbps下行帶寬,以減少另外兩人對他的影響,并且總帶寬富余的情況下可以超出該限制。
* 交互的SSH和即時(shí)信息流量要有高于其他流量的優(yōu)先級。
* DNS請求和反饋數(shù)據(jù)流要有第二高的優(yōu)先級。
* 流出的TCP ACK 數(shù)據(jù)包的優(yōu)先級要高于其他流出數(shù)據(jù)包的優(yōu)先級。
下面是對應(yīng)的策略(省略了其他部分策略,如rdr、nat等):
# enable queueing on the external interface to control traffic going to
# the Internet. use the priq scheduler to control only priorities. set
# the bandwidth to 610Kbps to get the best performance out of the TCP
# ACK queue.
altq on fxp0 priq bandwidth 610Kb queue { std_out, ssh_im_out, dns_out, \
tcp_ack_out }
# define the parameters for the child queues.
# std_out - the standard queue. any filter rule below that does not
# explicitly specify a queue will have its traffic added
# to this queue.
# ssh_im_out - interactive SSH and various instant message traffic.
# dns_out - DNS queries.
# tcp_ack_out - TCP ACK packets with no data payload.
queue std_out priq(default)
queue ssh_im_out priority 4 priq(red)
queue dns_out priority 5
queue tcp_ack_out priority 6
# enable queueing on the internal interface to control traffic coming in
# from the Internet. use the cbq scheduler to control bandwidth. max
# bandwidth is 2Mbps.
altq on dc0 cbq bandwidth 2Mb queue { std_in, ssh_im_in, dns_in, bob_in }
# define the parameters for the child queues.
# std_in - the standard queue. any filter rule below that does not
# explicitly specify a queue will have its traffic added
# to this queue.
# ssh_im_in - interactive SSH and various instant message traffic.
# dns_in - DNS replies.
# bob_in - bandwidth reserved for Bob‘s workstation. allow him to
# borrow.
queue std_in cbq(default)
queue ssh_im_in priority 4
queue dns_in priority 5
queue bob_in bandwidth 80Kb cbq(borrow)
# ... in the filtering section of pf.conf ...
alice = "192.168.0.2"
bob = "192.168.0.3"
charlie = "192.168.0.4"
local_net = "192.168.0.0/24"
ssh_ports = "{ 22 2022 }"
im_ports = "{ 1863 5190 5222 }"
# filter rules for fxp0 inbound
block in on fxp0 all
# filter rules for fxp0 outbound
block out on fxp0 all
pass out on fxp0 inet proto tcp from (fxp0) to any flags S/SA \
keep state queue(std_out, tcp_ack_out)
pass out on fxp0 inet proto { udp icmp } from (fxp0) to any keep state
pass out on fxp0 inet proto { tcp udp } from (fxp0) to any port domain \
keep state queue dns_out
pass out on fxp0 inet proto tcp from (fxp0) to any port $ssh_ports \
flags S/SA keep state queue(std_out, ssh_im_out)
pass out on fxp0 inet proto tcp from (fxp0) to any port $im_ports \
flags S/SA keep state queue(ssh_im_out, tcp_ack_out)
# filter rules for dc0 inbound
block in on dc0 all
pass in on dc0 from $local_net
# filter rules for dc0 outbound
block out on dc0 all
pass out on dc0 from any to $local_net
pass out on dc0 proto { tcp udp } from any port domain to $local_net \
queue dns_in
pass out on dc0 proto tcp from any port $ssh_ports to $local_net \
queue(std_in, ssh_im_in)
pass out on dc0 proto tcp from any port $im_ports to $local_net \
queue ssh_im_in
pass out on dc0 from any to $bob queue bob_in
實(shí)例 #2: 公司網(wǎng)絡(luò)
( IT Dept ) [ Boss‘s PC ]
| | T1
-- ---- ----- ---------- dc0 [ OpenBSD ] fxp0 -------- ( Internet )
| fxp1
[ COMP1 ] [ WWW ] /
| /
-- ----------‘
這個(gè)例子中OpenBSD作為公司網(wǎng)絡(luò)的防火墻,公司內(nèi)部在
DMZ
區(qū)運(yùn)行了
WWW服務(wù)器
,用戶通過FTP上傳他們的網(wǎng)站。IT部門有自己的子網(wǎng),老板的電腦主要用來收發(fā)電子郵件和網(wǎng)頁沖浪。防火墻通過1.5Mbps雙向帶寬的T1電路連接因特網(wǎng),其他網(wǎng)段均使用快速以太網(wǎng)(100Mbps)。
實(shí)現(xiàn)上述要求的策略如下:
* 限制WWW服務(wù)器到因特網(wǎng)之間的雙向流量――500Kbps。
* WWW服務(wù)器和內(nèi)部網(wǎng)絡(luò)之間沒有流量限制。
* 賦予WWW服務(wù)器和因特網(wǎng)間的流量高于其他流量的優(yōu)先級(例如FTP上傳流量)。
* 為IT部門保留500Kbps的帶寬使他們可以下載到最新的軟件,同時(shí)如果總帶寬富余,他們可以借用。
* 為老板訪問因特網(wǎng)的流量賦予比其他訪問因特網(wǎng)流量高的優(yōu)先級。
下面是對應(yīng)的策略(省略了其他部分策略,如rdr、nat等):
# enable queueing on the external interface to queue packets going out
# to the Internet. use the cbq scheduler so that the bandwidth use of
# each queue can be controlled. the max outgoing bandwidth is 1.5Mbps.
altq on fxp0 cbq bandwidth 1.5Mb queue { std_ext, www_ext, boss_ext }
# define the parameters for the child queues.
# std_ext - the standard queue. also the default queue for
# outgoing traffic on fxp0.
# www_ext - container queue for WWW server queues. limit to
# 500Kbps.
# www_ext_http - http traffic from the WWW server
# www_ext_misc - all non-http traffic from the WWW server
# boss_ext - traffic coming from the boss‘s computer
queue std_ext cbq(default)
queue www_ext bandwidth 500Kb { www_ext_http, www_ext_misc }
queue www_ext_http priority 3 cbq(red)
queue www_ext_misc priority 1
queue boss_ext priority 3
# enable queueing on the internal interface to control traffic coming
# from the Internet or the DMZ. use the cbq scheduler to control the
# bandwidth of each queue. bandwidth on this interface is set to the
# maximum. traffic coming from the DMZ will be able to use all of this
# bandwidth while traffic coming from the Internet will be limited to
# 1.0Mbps (because 0.5Mbps (500Kbps) is being allocated to fxp1).
altq on dc0 cbq bandwidth 100% queue { net_int, www_int }
# define the parameters for the child queues.
# net_int - container queue for traffic from the Internet. bandwidth
# is 1.0Mbps.
# std_int - the standard queue. also the default queue for outgoing
# traffic on dc0.
# it_int - traffic to the IT Dept network.
# boss_int - traffic to the boss‘s PC.
# www_int - traffic from the WWW server in the DMZ.
queue net_int bandwidth 1.0Mb { std_int, it_int, boss_int }
queue std_int cbq(default)
queue it_int bandwidth 500Kb cbq(borrow)
queue boss_int priority 3
queue www_int cbq(red)
# enable queueing on the DMZ interface to control traffic destined for
# the WWW server. cbq will be used on this interface since detailed
# control of bandwidth is necessary. bandwidth on this interface is set
# to the maximum. traffic from the internal network will be able to use
# all of this bandwidth while traffic from the Internet will be limited
# to 500Kbps.
altq on fxp1 cbq bandwidth 100% queue { internal_dmz, net_dmz }
# define the parameters for the child queues.
# internal_dmz - traffic from the internal network.
# net_dmz - container queue for traffic from the Internet.
# net_dmz_http - http traffic.
# net_dmz_misc - all non-http traffic. this is also the default queue.
queue internal_dmz # no special settings needed
queue net_dmz bandwidth 500Kb { net_dmz_http, net_dmz_misc }
queue net_dmz_http priority 3 cbq(red)
queue net_dmz_misc priority 1 cbq(default)
# ... in the filtering section of pf.conf ...
main_net = "192.168.0.0/24"
it_net = "192.168.1.0/24"
int_nets = "{ 192.168.0.0/24, 192.168.1.0/24 }"
dmz_net = "10.0.0.0/24"
boss = "192.168.0.200"
wwwserv = "10.0.0.100"
# default deny
block on { fxp0, fxp1, dc0 } all
# filter rules for fxp0 inbound
pass in on fxp0 proto tcp from any to $wwwserv port { 21, \
> 49151 } flags S/SA keep state queue www_ext_misc
pass in on fxp0 proto tcp from any to $wwwserv port 80 \
flags S/SA keep state queue www_ext_http
# filter rules for fxp0 outbound
pass out on fxp0 from $int_nets to any keep state
pass out on fxp0 from $boss to any keep state queue boss_ext
# filter rules for dc0 inbound
pass in on dc0 from $int_nets to any keep state
pass in on dc0 from $it_net to any queue it_int
pass in on dc0 from $boss to any queue boss_int
pass in on dc0 proto tcp from $int_nets to $wwwserv port { 21, 80, \
> 49151 } flags S/SA keep state queue www_int
# filter rules for dc0 outbound
pass out on dc0 from dc0 to $int_nets
# filter rules for fxp1 inbound
pass in on fxp1 proto { tcp, udp } from $wwwserv to any port 53 \
keep state
# filter rules for fxp1 outbound
pass out on fxp1 proto tcp from any to $wwwserv port { 21, \
> 49151 } flags S/SA keep state queue net_dmz_misc
pass out on fxp1 proto tcp from any to $wwwserv port 80 \
flags S/SA keep state queue net_dmz_http
pass out on fxp1 proto tcp from $int_nets to $wwwserv port { 80, \
21, > 49151 } flags S/SA keep state queue internal_dmz
編輯本段
回目錄
PF防火墻 - 地址池和負(fù)載均衡
簡介
地址池
是提供2個(gè)以上的地址供一組用戶共享的。地址池可以是rdr規(guī)則中的重定向地址;可以是nat規(guī)則中的轉(zhuǎn)換地址;也可以是route-to, reply-to, 和 dup-to filter選項(xiàng)中的目的地址。
有4種使用地址池的方法:
* bitmask - 截取被修改地址(nat規(guī)則的源地址;rdr規(guī)則的目標(biāo)地址)的最后部分和地址池地址的網(wǎng)絡(luò)部分組合。例如:如果地址池是192.0.2.1/24,而被修改地址是10.0.0.50,則結(jié)果地址是192.0.2.50。如果地址池是192.0.2.1/25,而被修改地址是10.0.0.130,這結(jié)果地址是192.0.2.2。
* random - 從地址池中隨機(jī)選擇地址.
* source-hash - 使用源地址 hash 來確定使用地址池中的哪個(gè)地址。這個(gè)方法保證給定的源地址總是被映射到同一個(gè)地址池。Hash算法的種子可以在source-hash關(guān)鍵字后通過16進(jìn)制字符或者字符串來指定。默認(rèn)情況下,pfctl(8)在規(guī)則集裝入時(shí)會隨機(jī)產(chǎn)生種子。
* round-robin - 在地址池中按順序循環(huán),這是默認(rèn)方法,也是表中定義的地址池唯一的方法。
除了round-robin方法,地址池的地址必須表達(dá)成CIDR(Classless Inter-Domain Routing )的網(wǎng)絡(luò)地址族。round-robin 方法可以接受多個(gè)使用列表和表的單獨(dú)地址。
sticky-address 選項(xiàng)可以在 random 和round-robin 池類型中使用,保證特定的源地址始終映射到同樣的重定向地址。
NAT 地址池
地址池在NAT規(guī)則中可以被用做轉(zhuǎn)換地址。連接的源地址會被轉(zhuǎn)換成使用指定的方法從地址池中選擇的地址。這對于PF負(fù)載一個(gè)非常大的網(wǎng)絡(luò)的NAT會非常有用。由于經(jīng)過NAT的連接對每個(gè)地址是有限的,增加附加的轉(zhuǎn)換地址允許NAT網(wǎng)關(guān)增大服務(wù)的用戶數(shù)量。
在這個(gè)例子中,2個(gè)地址被用來做輸出數(shù)據(jù)包的轉(zhuǎn)換地址。對于每一個(gè)輸出的連接,PF按照順序循環(huán)使用地址。
nat on $ext_if inet from any to any -> { 192.0.2.5, 192.0.2.10 }
這個(gè)方法的一個(gè)缺點(diǎn)是成功建立連接的同一個(gè)內(nèi)部地址不會總是轉(zhuǎn)換為同一個(gè)外部地址。這會導(dǎo)致沖突,例如:瀏覽根據(jù)用戶的ip地址跟蹤登錄的用戶的web站點(diǎn)。一個(gè)可選擇的替代方法是使用source-hash 方法,以便每一個(gè)內(nèi)部地址總是被轉(zhuǎn)換為同樣的外部地址。,要實(shí)現(xiàn)這個(gè)方法,地址池必須是CIDR網(wǎng)絡(luò)地址。
nat on $ext_if inet from any to any -> 192.0.2.4/31 source-hash
這條NAT規(guī)則使用地址池192.0.2.4/31 (192.0.2.4 - 192.0.2.5)做為輸出數(shù)據(jù)包的轉(zhuǎn)換地址。每一個(gè)內(nèi)部地址會被轉(zhuǎn)換為同樣的外部地址,由于source-hash關(guān)鍵字的緣故。
外來連接負(fù)載均衡
地址池也可以用來進(jìn)行外來連接
負(fù)載均衡
。例如,外來的web服務(wù)器連接可以分配到服務(wù)器群。
web_servers = "{ 10.0.0.10, 10.0.0.11, 10.0.0.13 }"
rdr on $ext_if proto tcp from any to any port 80 -> $web_servers \
round-robin sticky-address
成功的連接將按照順序重定向到web服務(wù)器,從同一個(gè)源到來的連接發(fā)送到同一個(gè)服務(wù)器。這個(gè)sticky connection會和指向這個(gè)連接的狀態(tài)一起存在。如果狀態(tài)過期,sticky
connection也過期。那個(gè)主機(jī)的更多連接被重定向到按順序的下一個(gè)web服務(wù)器。
輸出流量負(fù)載均衡
地址池可以和route-to過濾選項(xiàng)聯(lián)合使用,在多路徑路由協(xié)議(例如BGP4)不可用是負(fù)載均衡2個(gè)或者多個(gè)因特網(wǎng)連接。通過對round-robin地址池使用route-to,輸出連接可以平均分配到多個(gè)輸出路徑。
需要收集的附加的信息是鄰近的因特網(wǎng)路由器IP地址。這要加入到route-to選項(xiàng)后來控制輸入數(shù)據(jù)包的目的地址。
下面的例子通過2條到因特網(wǎng)的連接平衡輸出流量:
lan_net = "192.168.0.0/24"
int_if = "dc0"
ext_if1 = "fxp0"
ext_if2 = "fxp1"
ext_gw1 = "68.146.224.1"
ext_gw2 = "142.59.76.1"
pass in on $int_if route-to \
{ ($ext_if1 $ext_gw1), ($ext_if2 $ext_gw2) } round-robin \
from $lan_net to any keep state
route-to 選項(xiàng)用來在收到流量的內(nèi)部接口上指定平衡的流量經(jīng)過各自的網(wǎng)關(guān)到輸出的網(wǎng)絡(luò)接口。注意route-to 選項(xiàng)必須在每個(gè)需要均衡的過濾規(guī)則上出現(xiàn)。返回的數(shù)據(jù)包會路由到它們出去時(shí)的外部接口(這是由ISP做的),然后正常路由回內(nèi)部網(wǎng)絡(luò)。
要保證帶有屬于$ext_if1源地址的數(shù)據(jù)包總是路由到$ext_gw1($ext_if2 和 $ext_gw2也是同樣的),下面2行必須包括在規(guī)則集中:
pass out on $ext_if1 route-to ($ext_if2 $ext_gw2) from $ext_if2 \
to any
pass out on $ext_if2 route-to ($ext_if1 $ext_gw1) from $ext_if1 \
to any
最后,NAT也可以使用在輸出接口中:
nat on $ext_if1 from $lan_net to any -> ($ext_if1)
nat on $ext_if2 from $lan_net to any -> ($ext_if2)
一個(gè)完整的輸出負(fù)載均衡的例子應(yīng)該是這個(gè)樣子:
lan_net = "192.168.0.0/24"
int_if = "dc0"
ext_if1 = "fxp0"
ext_if2 = "fxp1"
ext_gw1 = "68.146.224.1"
ext_gw2 = "142.59.76.1"
# nat outgoing connections on each internet interface
nat on $ext_if1 from $lan_net to any -> ($ext_if1)
nat on $ext_if2 from $lan_net to any -> ($ext_if2)
# default deny
block in from any to any
block out from any to any
# pass all outgoing packets on internal interface
pass out on $int_if from any to $lan_net
# pass in quick any packets destined for the gateway itself
pass in quick on $int_if from $lan_net to $int_if
# load balance outgoing tcp traffic from internal network.
pass in on $int_if route-to \
{ ($ext_if1 $ext_gw1), ($ext_if2 $ext_gw2) } round-robin \
proto tcp from $lan_net to any flags S/SA modulate state
# load balance outgoing udp and icmp traffic from internal network
pass in on $int_if route-to \
{ ($ext_if1 $ext_gw1), ($ext_if2 $ext_gw2) } round-robin \
proto { udp, icmp } from $lan_net to any keep state
# general "pass out" rules for external interfaces
pass out on $ext_if1 proto tcp from any to any flags S/SA modulate state
pass out on $ext_if1 proto { udp, icmp } from any to any keep state
pass out on $ext_if2 proto tcp from any to any flags S/SA modulate state
pass out on $ext_if2 proto { udp, icmp } from any to any keep state
# route packets from any IPs on $ext_if1 to $ext_gw1 and the same for
# $ext_if2 and $ext_gw2
pass out on $ext_if1 route-to ($ext_if2 $ext_gw2) from $ext_if2 to any
pass out on $ext_if2 route-to ($ext_if1 $ext_gw1) from $ext_if1 to any
編輯本段
回目錄
PF防火墻 - 數(shù)據(jù)包標(biāo)記
簡介
數(shù)據(jù)包標(biāo)記是給數(shù)據(jù)包打內(nèi)部標(biāo)記的方法,以后可以在過濾和轉(zhuǎn)換規(guī)則中使用。使用標(biāo)記,有可能做這樣的事情,比如在接口間產(chǎn)生信任關(guān)系,或者確定數(shù)據(jù)包是否已經(jīng)經(jīng)過了轉(zhuǎn)換規(guī)則處理。也可能從基于規(guī)則的過濾中移出,開始執(zhí)行基于策略的過濾。
給數(shù)據(jù)包打標(biāo)記
要給數(shù)據(jù)包打標(biāo)記,使用tag 關(guān)鍵字:
pass in on $int_if all tag INTERNAL_NET keep state
標(biāo)記 INTERNAL_NET 會增加到任何匹配上述規(guī)則的數(shù)據(jù)包中。
注意keep state的使用; keep state (或者 modulate state/synproxy state) 在標(biāo)記數(shù)據(jù)包通過的規(guī)則中使用。
標(biāo)記也可以通過宏來打,比如:
name = "INTERNAL_NET"
pass in on $int_if all tag $name keep state
有一組預(yù)先定義的宏也可以被使用。
* $if - 接口
* $srcaddr - 源 IP 地址
* $dstaddr - 目的 IP 地址
* $srcport - 源端口
* $dstport - 目的端口
* $proto - 協(xié)議
* $nr - 規(guī)則號
這些宏在規(guī)則集裝入時(shí)擴(kuò)展,而不是運(yùn)行時(shí)。
標(biāo)記遵循以下規(guī)則:
* 標(biāo)記是粘性的。一旦一個(gè)標(biāo)記被匹配的規(guī)則打到一個(gè)數(shù)據(jù)包,就不能被刪除。但它可以被不同的標(biāo)記替換。
* 由于標(biāo)記的粘性,打了標(biāo)記的數(shù)據(jù)包會一直保持,即使所有的規(guī)則都沒有使用這個(gè)標(biāo)記。
* 一個(gè)數(shù)據(jù)包一次最多只能打一個(gè)標(biāo)記。
* 標(biāo)記是內(nèi)部標(biāo)識符,標(biāo)記不會被送到網(wǎng)上。
看看下面的例子:
(1) pass in on $int_if tag INT_NET keep state
(2) pass in quick on $int_if proto tcp to port 80 tag \
INT_NET_HTTP keep state
(3) pass in quick on $int_if from 192.168.1.5 keep state
* 按照規(guī)則1,$int_if 接口上收到的數(shù)據(jù)包會打上INT_NET 標(biāo)記。
* $int_if 接口上收到的目標(biāo)端口80的數(shù)據(jù)包根據(jù)規(guī)則1首先打上INT_NET 標(biāo)記,然后根據(jù)規(guī)則2,被INT_NET_HTTP 標(biāo)記替代。
* $int_if 接口上收到的來自192.168.1.5的數(shù)據(jù)包根據(jù)規(guī)則3會方向,由于這是最終匹配規(guī)則,因此如果它們的目標(biāo)端口是80,則標(biāo)記是INT_NET_HTTP ,否則標(biāo)記是INT_NET 。
標(biāo)記除了適用于過濾規(guī)則以外, nat, rdr, binat轉(zhuǎn)換規(guī)則也可以用tag關(guān)鍵字使用標(biāo)記。
檢查數(shù)據(jù)包標(biāo)記
要檢查先前已經(jīng)打的標(biāo)記,可以使用tagged關(guān)鍵字:
pass out on $ext_if tagged INT_NET keep state
在$ext_if輸出的數(shù)據(jù)包為了匹配上述規(guī)則必須打上INT_NET標(biāo)記。反轉(zhuǎn)匹配也可以使用!操作:
pass out on $ext_if tagged ! WIFI_NET keep state
策略過濾
過濾策略提供了編寫過濾規(guī)則集的不同方法。定義的策略設(shè)定規(guī)則,說明哪種流量放行,哪種流量阻塞。數(shù)據(jù)包被基于傳統(tǒng)的標(biāo)準(zhǔn)如源/目的IP地址,協(xié)議等等分配到不同的策略。例如,檢查下面的防火墻策略:
* 自內(nèi)部LAN到DMZ的流量是允許的 (LAN_DMZ)。
* 自因特網(wǎng)到DMZ的服務(wù)器流量是允許的。 (INET_DMZ)
* 自因特網(wǎng)被重定向到spamd(8)是允許的 (SPAMD)
* 其他所有流量阻塞。
注意策略是如何覆蓋所有通過防火墻的流量的。括號里面的項(xiàng)目指示這個(gè)策略項(xiàng)目將使用的標(biāo)記。
需要過濾和轉(zhuǎn)換規(guī)則來把數(shù)據(jù)包分配到不同的策略。
rdr on $ext_if proto tcp from to port smtp \
tag SPAMD -> 127.0.0.1 port 8025
block all
pass in on $int_if from $int_net tag LAN_INET keep state
pass in on $int_if from $int_net to $dmz_net tag LAN_DMZ keep state
pass in on $ext_if proto tcp to $www_server port 80 tag INET_DMZ keep
state
現(xiàn)在要設(shè)置定義策略的規(guī)則。
pass in quick on $ext_if tagged SPAMD keep state
pass out quick on $ext_if tagged LAN_INET keep state
pass out quick on $dmz_if tagged LAN_DMZ keep state
pass out quick on $dmz_if tagged INET_DMZ keep state
現(xiàn)在要建立整個(gè)規(guī)則集,修改分類規(guī)則。例如,如果pop3/SMTP服務(wù)器增加到了DMZ區(qū),就需要增加針對POP3和SMTP流量的分類,如下:
mail_server = "192.168.0.10"
...
pass in on $ext_if proto tcp to $mail_server port { smtp, pop3 } \
tag INET_DMZ keep state
Email 流量會作為INET-DMZ策略的條目被放行。t
完整的規(guī)則:
# macros
int_if = "dc0"
dmz_if = "dc1"
ext_if = "ep0"
int_net = "10.0.0.0/24"
dmz_net = "192.168.0.0/24"
www_server = "192.168.0.5"
mail_server = "192.168.0.10"
table persist file "/etc/spammers"
# classification -- classify packets based on the defined firewall
# policy.
rdr on $ext_if proto tcp from to port smtp \
tag SPAMD -> 127.0.0.1 port 8025
block all
pass in on $int_if from $int_net tag LAN_INET keep state
pass in on $int_if from $int_net to $dmz_net tag LAN_DMZ keep state
pass in on $ext_if proto tcp to $www_server port 80 tag INET_DMZ keep state
pass in on $ext_if proto tcp to $mail_server port { smtp, pop3 } \
tag INET_DMZ keep state
# policy enforcement -- pass/block based on the defined firewall policy.
pass in quick on $ext_if tagged SPAMD keep state
pass out quick on $ext_if tagged LAN_INET keep state
pass out quick on $dmz_if tagged LAN_DMZ keep state
pass out quick on $dmz_if tagged INET_DMZ keep state
標(biāo)記以太網(wǎng)幀
打標(biāo)記可以在以太網(wǎng)級別進(jìn)行,如果執(zhí)行標(biāo)記/過濾的機(jī)器同時(shí)做為網(wǎng)橋。通過創(chuàng)建使用tag關(guān)鍵字的網(wǎng)橋過濾規(guī)則,PF可以建立基于源/目的MAC地址的過濾規(guī)則。網(wǎng)橋規(guī)則可以由brconfig(8)命令產(chǎn)生,例如:
# brconfig bridge0 rule pass in on fxp0 src 0:de:ad:be:ef:0 \
tag USER1
然后在 pf.conf文件中:
pass in on fxp0 tagged USER1
編輯本段
回目錄
PF防火墻 - 日志
簡介
PF的包日志是由pflogd完成的,它通過監(jiān)聽pflog0接口然后將包以tcpdump二進(jìn)制格式寫入日志文件(一般在/val/log/pflog)。過濾規(guī)則定義的日志和log-all關(guān)鍵字所定義的日志都是以這種方式記錄的。
讀取日志文件
由pflogd生成的二進(jìn)制格式日志文件不能通過文本編輯器讀取,必須使用
Tcpdump
來查看日志。
使用如下格式查看日志信息:
# tcpdump -n -e -ttt -r /var/log/pflog
使用tcpdump( 查看日志文件并不是實(shí)時(shí)的,若要實(shí)時(shí)查詢?nèi)罩拘畔⑿杓由蟨flog0參數(shù):
# tcpdump -n -e -ttt -i pflog0
注意:當(dāng)查看日志時(shí)需要特別注意tcpdump的詳細(xì)協(xié)議解碼(通過在命令行增加-v參數(shù)實(shí)現(xiàn))。
Tcpdump的詳細(xì)協(xié)議解碼器并不具備完美的安全歷史,至少在理論上是這樣。日志記錄設(shè)備所記載的部分包信息可能會引發(fā)延時(shí)攻擊,因此推薦在查詢?nèi)罩疚募畔⒅跋葘⒃撊罩疚募䦶姆阑饓ι弦谱摺?br />
另外需要注意的是對日志文件的安全訪問。默認(rèn)情況下,pflogd 將在日志文件中記錄96字節(jié)的包信息。訪問日志文件將提供訪問部分敏感包信息的途徑(就像telnet(1)或者ftp(1)的用戶名和密碼)。
導(dǎo)出日志
由于pflogd以tcpdump二進(jìn)制格式記錄日志信息,因此當(dāng)回顧這些日志時(shí)可以使用tcpdump的很多特點(diǎn)。例如,只查看與特定端口匹配的包:
# tcpdump -n -e -ttt -r /var/log/pflog port 80
甚至可以限定具體的主機(jī)和端口:
# tcpdump -n -e -ttt -r /var/log/pflog port 80 and host 192.168.1.3
同樣的方法可以應(yīng)用到直接從pflog0接口讀取的信息:
# tcpdump -n -e -ttt -i pflog0 host 192.168.4.2
注意這與包被記錄到pflogd日志文件不相沖突;上述語句只以包被記錄的形式顯示。
除了使用標(biāo)準(zhǔn)的tcpdump(8)過濾規(guī)則外,OpenBSD的tcpdump過濾語言為讀取pflogd而被擴(kuò)展:
* ip -IPv4版本地址。
* ip6 - IPv6版本地址。
* on int - 包通過int接口。
* ifname int - 與 on int相同.
* rulenum num - 包匹配的過濾規(guī)則編號為num。
* action act - 對包的操作?赡苁莗ass(通過)或者block(阻斷)。
* reason res - 執(zhí)行對包操作的原因。可能的原因是match(匹配), bad-offset, fragment, short, normalize(規(guī)格化), memory(內(nèi)存)。
* inbound -入棧包。
* outbound - 出棧包。
舉例:
# tcpdump -n -e -ttt -i pflog0 inbound and action block and on wi0
這將以實(shí)時(shí)方式顯示被wi0接口阻斷的入棧包的日志信息。
通過Syslog記錄日志
很多情況下需要將防火墻的日志記錄以
ASCII
代碼格式存儲,或者(同時(shí))把這些日志存到遠(yuǎn)程的日志服務(wù)器上。這些可以通過兩個(gè)小的腳本文件實(shí)現(xiàn),是對 openbsd配置文件和syslogd,日志守護(hù)進(jìn)程的少許修改。Syslogd進(jìn)程以ASCII格式存儲日志,同時(shí)可以將日志存儲到遠(yuǎn)程日志服務(wù)器。
首先必須建立一個(gè)用戶,pflogger,使用 /sbin/nologin shell.最簡單的建立用戶的方法是使用adduser(8)。
完成后建立如下兩個(gè)腳本:
/etc/pflogrotate
FILE=/home/pflogger/pflog5min.$(date " %Y%m%d%H%M")
kill -ALRM $(cat /var/run/pflogd.pid)
if [ $(ls -l /var/log/pflog | cut -d " " -f -gt 24 ]; then
mv /var/log/pflog $FILE
chown pflogger $FILE
kill -HUP $(cat /var/run/pflogd.pid)
fi
/home/pflogger/pfl2sysl
for logfile in /home/pflogger/pflog5min* ; do
tcpdump -n -e -ttt -r $logfile | logger -t pf -p local0.info
rm $logfile
done
編輯root的cron 任務(wù):
# crontab -u root -e
增加如下兩行:
# rotate pf log file every 5 minutes
0-59/5 * * * * /bin/sh /etc/pflogrotate
為用戶pflogger建立一個(gè)cron任務(wù):
# crontab -u pflogger -e
增加如下兩行:
# feed rotated pflog file(s) to syslog
0-59/5 * * * * /bin/sh /home/pflogger/pfl2sysl
將下行增加到 /etc/syslog.conf:
local0.info /var/log/pflog.txt
如果需要日志記錄到遠(yuǎn)程日志服務(wù)器,增加:
local0.info @syslogger
確定主機(jī)syslogger已在hosts(5)中定義。
建立文件 /var/log/pflog.txt 使 syslog 可以向該文件寫入日志:
# touch /var/log/pflog.txt
重啟syslogd使變化生效:
# kill -HUP $(cat /var/run/syslog.pid)
所有符合標(biāo)準(zhǔn)的包將被寫入/var/log/pflog.txt. 如果增加了第二行,這些信息也將被存入遠(yuǎn)程日志服務(wù)器syslogger。
腳本 /etc/pflogrotate 將執(zhí)行,然后刪除 /var/log/pflog ,因此
rotation of pflog by newsyslog(Cool 不再必需可以被禁用。然而, /var/log/pflog.txt 替代 /var/log/pflog and rotation of it 要被啟用。 改變 /etc/newsyslog.conf 如下:
#/var/log/pflog 600 3 250 * ZB /var/run/pflogd.pid
/var/log/pflog.txt 600 7 * 24
PF 將日志以ASCII格式記錄到/var/log/pflog.txt. 如果這樣配置 /etc/syslog.conf, 系統(tǒng)將把日志存到遠(yuǎn)程服務(wù)器。存儲過程不會馬上發(fā)生,但是會在符合條件的包出現(xiàn)在文件中前5-6分鐘實(shí)現(xiàn)。
編輯本段
回目錄
PF防火墻 - 性能
“PF可以處理多少帶寬?”
“我需要多少臺計(jì)算機(jī)處理因特網(wǎng)連接?”
這個(gè)問題沒有簡單的答案。對于一些應(yīng)用程序來說,一臺486/66主機(jī),帶有2個(gè)比較好的ISA網(wǎng)卡在做過濾和NAT時(shí)接近5Mbps,但是對于其他應(yīng)用程序,一個(gè)更快的計(jì)算機(jī)加上更有效的PCI網(wǎng)卡也會顯得能力不足。真正的問題不是每秒處理的位數(shù)而是每秒處理的包數(shù)和規(guī)則集的復(fù)雜程度。
體現(xiàn)PF性能的幾個(gè)參數(shù):
* 每秒處理包的數(shù)量.
一個(gè)1500
字節(jié)
的包和一個(gè)只有1個(gè)字節(jié)的包所需要的處理過程的數(shù)目幾乎是一樣的。每秒處理包的數(shù)量標(biāo)志著狀態(tài)表和過濾規(guī)則集在每秒內(nèi)被評估的次數(shù) ,標(biāo)志著一個(gè)系統(tǒng)最有效的需求(在沒有匹配的情況下)。
* 系統(tǒng)總線性能.
ISA
總線最大帶寬 8MB/秒, 當(dāng)
處理器
訪問它時(shí), 它必須降速到80286的有效速度,不管處理器的真實(shí)處理速度如何,PCI總線有更有效的帶寬,與處理器的沖突更小。
* 網(wǎng)卡的效率.
一些網(wǎng)卡的工作效率要高于其他網(wǎng)卡。 基于
Realtek 8139
的網(wǎng)卡性能較低,而基于
Intel 21143
的網(wǎng)卡性能較好。為了取得更好的性能,建議使用千兆網(wǎng)卡,盡管所連接的網(wǎng)絡(luò)不是千兆網(wǎng),這些千兆網(wǎng)卡擁有高級的緩存,可以大幅提高性能。
* 規(guī)則集的設(shè)計(jì)和復(fù)雜性。
規(guī)則越復(fù)雜越慢。越多的包通過keep和quick方式過濾,性能越好。對每個(gè)包的策略越多,性能越差。
* 值得一提:
CPU 和內(nèi)存。由于PF是基于內(nèi)核的進(jìn)程,它不需要swap空間。所以,如果你有足夠的內(nèi)存,它將運(yùn)行很好,如果沒有,將受影響。不需要太大量的內(nèi)存。 32MB內(nèi)存對小型辦公室或者家庭應(yīng)用足夠,300MHz的cpu如果配置好網(wǎng)卡和規(guī)則集,足夠滿足要求。
人們經(jīng)常詢問PF的基準(zhǔn)點(diǎn)。唯一的基準(zhǔn)是在一個(gè)環(huán)境下系統(tǒng)的性能。不考慮環(huán)境因素將影響所設(shè)計(jì)的防火墻的系統(tǒng)性能。
PF 曾經(jīng)在非常大流量的系統(tǒng)中工作,同時(shí)PF的開發(fā)者也是它的忠實(shí)用戶。
編輯本段
回目錄
PF防火墻 - 研究 FTP
![]()
FTP 模式
FTP
是一種協(xié)議,它可以追溯到因特網(wǎng)發(fā)展初期,那時(shí)的因特網(wǎng)規(guī)模小,聯(lián)網(wǎng)的計(jì)算機(jī)彼此友好,過濾和嚴(yán)格安全性在那時(shí)不是必須的。FTP設(shè)計(jì)之初就沒有考慮包過濾、穿透防火墻和NAT。
FTP的工作模式分為被動(dòng)(passive)和主動(dòng)(active)兩種。通常這兩種選擇被用來確定哪邊有防火墻問題。實(shí)際上,為了方便用戶應(yīng)該全部支持這兩種模式。
在active模式下,當(dāng)用戶訪問遠(yuǎn)程FTP服務(wù)器并請求一個(gè)文件信息時(shí),那臺FTP服務(wù)器將與該用戶建立一個(gè)新的連接用來傳輸請求的數(shù)據(jù),這被稱為數(shù)據(jù)連接。具體過程為:客戶端隨機(jī)選擇一個(gè)端口號,在該端口監(jiān)聽的同時(shí)將端口號傳給服務(wù)器,由服務(wù)器向客戶端的該端口發(fā)起連接請求,然后傳遞數(shù)據(jù)。在 NAT后的用戶訪問FTP服務(wù)器的時(shí)候會出現(xiàn)問題,由于NAT的工作機(jī)制,服務(wù)器將向NAT網(wǎng)關(guān)的外部地址的所選端口發(fā)起連接,NAT網(wǎng)關(guān)收到該信息后將在自己的狀態(tài)表中查找該端口對應(yīng)的內(nèi)部主機(jī),由于狀態(tài)表中不存在這樣的記錄,因此該包被丟棄,導(dǎo)致無法建立連接。
在passive模式下(OpenBSD的ftp客戶端默認(rèn)模式),由客戶端請求服務(wù)器隨機(jī)選擇一個(gè)端口并在此端口監(jiān)聽,服務(wù)器通知客戶端它所選擇的端口號,等待客戶端連接。不幸的是,ftp服務(wù)器前的防火墻可能會阻斷客戶端發(fā)往服務(wù)器的請求信息。OpenBSD的ftp(1)默認(rèn)使用 passive模式;要強(qiáng)制改為active模式,使用-A參數(shù),或者在“ftp>”提示符下使用命令“passive off”關(guān)閉 passive模式。
工作在防火墻之后的FTP客戶端
如前所述,F(xiàn)TP對NAT和防火墻支持不好。
包過濾機(jī)制通過將FTP數(shù)據(jù)包重定向到一個(gè)FTP代理服務(wù)器解決這一問題。這一過程將引導(dǎo)FTP數(shù)據(jù)包通過NAT網(wǎng)關(guān)/防火墻。OpenBSD和PF使用的FTP代理是ftp-proxy(8),可以通過在pf.conf中的NAT章節(jié)增加下列信息激活該代理:
rdr on $int_if proto tcp from any to any port 21 -> 127.0.0.1 \
port 8021
這條語句的解釋為:在內(nèi)部接口上的ftp數(shù)據(jù)包被重定向到本機(jī)的8021端口
顯然該代理服務(wù)器應(yīng)該已在OpenBSD中啟動(dòng)并運(yùn)行。配置方法為在/etc/inetd.conf中增加下列信息:
127.0.0.1:8021 stream tcp nowait root /usr/libexec/ftp-proxy \
ftp-proxy
重啟系統(tǒng)或者通過下列命令發(fā)送一個(gè)‘HUP’標(biāo)記來生效:
kill -HUP `cat /var/run/inetd.pid`
ftp代理在8021端口監(jiān)聽,上面的rdr語句也是將數(shù)據(jù)包轉(zhuǎn)發(fā)到這一端口。這一端口號是可選的,因?yàn)?021端口沒有被其他應(yīng)用程序占用,因此不失為一個(gè)好的選擇。
請注意ftp-proxy(8)是用來幫助位于PF過濾器后的ftp客戶端傳遞信息;并不用于PF過濾器后的ftp服務(wù)器。
PF“自保護(hù)”FTP服務(wù)器
當(dāng)PF運(yùn)行在一個(gè)FTP服務(wù)器上,而不是單獨(dú)的一臺防火墻。這種情況下處理passive模式的FTP連接請求時(shí)FTP服務(wù)器將隨機(jī)取一個(gè)較大的 TCP端口接收數(shù)據(jù)。默認(rèn)情況下OpenBSD的本地FTP服務(wù)器ftpd(8)使用49152~65535范圍內(nèi)的端口,顯然,必須要有對應(yīng)的過濾規(guī)則放行這些端口的數(shù)據(jù):
pass in on $ext_if proto tcp from any to any port 21 keep state
pass in on $ext_if proto tcp from any to any port > 49151 \
keep state
如果需要可以調(diào)整上述端口范圍。在OpenBSD的ftpd(8)環(huán)境下,可以通過sysctl(8)進(jìn)行調(diào)整 net.inet.ip.porthifirst 和net.inet.ip.porthilast。
使用NAT外部 PF防火墻保護(hù)FTP服務(wù)器
這種情況下,防火墻必須將數(shù)據(jù)重定向到FTP服務(wù)器。為了討論方便,我們假設(shè)該FTP服務(wù)器使用標(biāo)準(zhǔn)的OpenBSD ftpd(8),并使用默認(rèn)端口范圍。
這里有個(gè)例子
ftp_server = "10.0.3.21"
rdr on $ext_if proto tcp from any to any port 21 -> $ftp_server \
port 21
rdr on $ext_if proto tcp from any to any port 49152:65535 -> \
$ftp_server port 49152:65535
# in on $ext_if
pass in quick on $ext_if proto tcp from any to $ftp_server \
port 21 keep state
pass in quick on $ext_if proto tcp from any to $ftp_server \
port > 49151 keep state
# out on $int_if
pass out quick on $int_if proto tcp from any to $ftp_server \
port 21 keep state
pass out quick on $int_if proto tcp from any to $ftp_server \
port > 49151 keep state
FTP的更多信息
過濾FTP和FTP如何工作的更多信息可以參考下面的白皮書。
編輯本段
回目錄
PF防火墻 - 驗(yàn)證: 用Shell 進(jìn)行網(wǎng)關(guān)驗(yàn)證
簡介
Authpf
(Cool是身份認(rèn)證網(wǎng)關(guān)的用戶shell。身份認(rèn)證網(wǎng)關(guān)類似于普通網(wǎng)關(guān),只不過用戶必須在網(wǎng)關(guān)上通過身份驗(yàn)證后才能使用該網(wǎng)關(guān)。當(dāng)用戶 shell被設(shè)置為/usr/sbin/authpf時(shí)(例如,代替了ksh(1),csh(1)等),并且用戶通過SSH登錄,authpf將對pf (4)策略集做必要的修改以便該用戶的數(shù)據(jù)包可以通過過濾器或者(和)使用NAT、重定向功能。一旦用戶退出登錄或者連接被斷開,authpf將移除加載到該用戶上的所有策略,同時(shí)關(guān)閉該用戶打開的所有會話。因此,只有當(dāng)用戶保持著他的SSH會話進(jìn)程時(shí)他才具備透過防火墻發(fā)送數(shù)據(jù)包的能力。
Authpf通過向附加到錨點(diǎn)的命名策略集增加策略來改變pf(4)的策略集。每次用戶進(jìn)行身份驗(yàn)證,authpf建立一個(gè)新的命名策略集,并將已經(jīng)配置好的filter、nat、binat和rdr規(guī)則加載上去。被authpf所加載的策略可以被配置為針對單獨(dú)的一個(gè)用戶相關(guān)或者針對總體。
Authpf可以應(yīng)用在:
* 在允許用戶訪問因特網(wǎng)之前進(jìn)行身份驗(yàn)證。
* 賦予特殊用戶訪問受限網(wǎng)絡(luò)的權(quán)利,例如管理員。
* 只允許特定的無線網(wǎng)絡(luò)用戶訪問特定的網(wǎng)絡(luò)。
* 允許公司員工在任何時(shí)候訪問公司網(wǎng)絡(luò),而公司之外的用戶不能訪問,并可以將這些用戶重定向到特定的基于用戶名的資源(例如他們自己的桌面)。
* 在類似圖書館這樣的地方通過PF限制guest用戶對因特網(wǎng)的訪問。Authpf可以用來向已注冊用戶開放完全的因特網(wǎng)連接。
Authpf通過syslogd(8)記錄每一個(gè)成功通過身份驗(yàn)證用戶的用戶名、IP地址、開始結(jié)束時(shí)間。通過這些信息,管理員可以確定誰在何時(shí)登陸,也使得用戶對其網(wǎng)絡(luò)流量負(fù)責(zé)。
配置
配置authpf的基本步驟大致描述如下。詳細(xì)的信息請查看man手冊。
將authpf連入主策略集
通過使用錨點(diǎn)策略將authpf連入主策略集:
nat-anchor authpf
rdr-anchor authpf
binat-anchor authpf
anchor authpf
錨點(diǎn)策略放入策略集的位置就是PF中斷執(zhí)行主策略集轉(zhuǎn)為執(zhí)行authpf策略的位置。上述4個(gè)錨點(diǎn)策略并不需要全部存在,例如,當(dāng)authpf沒有被設(shè)置加載任何nat策略時(shí),nat-anchor策略可被省略。
配置加載的策略
Authpf通過下面兩個(gè)文件之一加載策略:
* /etc/authpf/users/$USER/authpf.rules
* /etc/authpf/authpf.rules
第一個(gè)文件包含只有當(dāng)用戶$USER(將被替換為具體的用戶名)登錄時(shí)才被加載的策略。當(dāng)特殊用戶(例如管理員)需要一系列不同于其他默認(rèn)用戶的策略集時(shí)可以使用每用戶策略配置。第二個(gè)文件包含沒定義自己的authpf.rules文件的用戶所默認(rèn)加載的策略。如果用戶定義的文件存在,將覆蓋默認(rèn)文件。這兩個(gè)文件至少存在其一,否則authpf將不會工作。
過濾器和傳輸策略與其他的PF策略集語法一樣,但有一點(diǎn)不同:authpf允許使用預(yù)先定義的宏:
* $user_ip �C 登錄用戶的IP地址
* $user_id �C 登錄用戶的用戶名
推薦使用宏$user_ip,只賦予通過身份驗(yàn)證的計(jì)算機(jī)透過防火墻的權(quán)限。
訪問控制列表
可以通過在/etc/authpf/banned/目錄下建立以用戶名命名的文件來阻止該用戶使用authpf。文件的內(nèi)容將在authpf斷開與該用戶的連接之前顯示給他,這為通知該用戶被禁止訪問的原因并告知他解決問題聯(lián)系人提供了一個(gè)便捷的途徑。
相反,有可能只允許特定的用戶訪問,這時(shí)可以將這些用戶的用戶名寫入/etc/authpf/authpf.allow文件。如果該文件不存在或者文件中輸入了“*”,則authpf將允許任何成功通過SSH登錄的用戶進(jìn)行訪問(沒有被明確禁止的用戶)。
如果authpf不能斷定一個(gè)用戶名是被允許還是禁止,它將打印一個(gè)摘要信息并斷開該用戶的連接。明確禁止將會使明確允許失效。
將authpf配置為用戶shell
authpf必須作為用戶的登錄shell才能正常工作。當(dāng)用戶成功通過sshd(8)登錄后,authpf將被作為用戶的shell執(zhí)行。它將檢查該用戶是否有權(quán)使用authpf,并從適當(dāng)?shù)奈募屑虞d策略,等等。
有兩種途徑將authpf設(shè)置為用戶shell:
1.為每個(gè)用戶手動(dòng)使用chsh(1), vipw(Cool, useradd(Cool, usermod(Cool,等。
2.通過把一些用戶分配到一個(gè)登錄類,在文件/etc/login.conf中改變這個(gè)登錄類的shell屬性
查看登陸者
一旦用戶成功登錄,并且authpf調(diào)整了PF的策略,authpf將改變它的進(jìn)程名以顯示登錄者的用戶名和IP地址:
# ps -ax | grep authpf
23664 p0 Is 0:00.11 -authpf:
charlie@192.168
(authpf)
在這里用戶chalie從IP地址為192.168.1.3的主機(jī)登錄。用戶可以通過向authpf進(jìn)程發(fā)送SIGTERM信號退出登錄。Authpf也將移除加載到該用戶上的策略并關(guān)閉任何該用戶打開的會話連接。
# kill -TERM 23664
實(shí)例
OpenBSD網(wǎng)關(guān)通過authpf對一個(gè)大型校園無線網(wǎng)的用戶進(jìn)行身份驗(yàn)證。一旦某個(gè)用戶驗(yàn)證通過,假設(shè)他不在禁用列表中,他將被允許SSH并訪問網(wǎng)頁(包括安全網(wǎng)站https),也可以訪問該校園的任一個(gè)DNS服務(wù)器。
文件 /etc/authpf/authpf.rules包含下列策略:
wifi_if = "wi0"
dns_servers = "{ 10.0.1.56, 10.0.2.56 }"
pass in quick on $wifi_if proto udp from $user_ip to $dns_servers \
port domain keep state
pass in quick on $wifi_if proto tcp from $user_ip to port { ssh, http, \
https } flags S/SA keep state
管理員charlie除了網(wǎng)頁沖浪和使用SSH外還需要訪問校園網(wǎng)的SMTP和POP3服務(wù)器。下列策略被配置在/etc/authpf/users/charlie/authpf.rules 中:
wifi_if = "wi0"
smtp_server = "10.0.1.50"
pop3_server = "10.0.1.51"
dns_servers = "{ 10.0.1.56, 10.0.2.56 }"
pass in quick on $wifi_if proto udp from $user_ip to $dns_servers \
port domain keep state
pass in quick on $wifi_if proto tcp from $user_ip to $smtp_server \
port smtp flags S/SA keep state
pass in quick on $wifi_if proto tcp from $user_ip to $pop3_server \
port pop3 flags S/SA keep state
pass in quick on $wifi_if proto tcp from $user_ip to port { ssh, http, \
https } flags S/SA keep state
定義在/etc/pf.conf中的主策略集配置如下:
# macros
wifi_if = "wi0"
ext_if = "fxp0"
scrub in all
# filter
block drop all
pass out quick on $ext_if proto tcp from $wifi_if:network flags S/SA \
modulate state
pass out quick on $ext_if proto { udp, icmp } from $wifi_if:network \
keep state
pass in quick on $wifi_if proto tcp from $wifi_if:network to $wifi_if \
port ssh flags S/SA keep state
anchor authpf in on $wifi_if
該策略集非常簡單,作用如下:
* 阻斷所有(默認(rèn)拒絕)。
* 放行外部網(wǎng)卡接口上的來自無線網(wǎng)絡(luò)并流向外部的TCP,UDP和ICMP數(shù)據(jù)包。
* 放行來自無線網(wǎng)絡(luò),目的地址為網(wǎng)關(guān)本身的SSH數(shù)據(jù)包。該策略是用戶登錄所必須的。
* 在無線網(wǎng)絡(luò)接口上為流入數(shù)據(jù)建立錨點(diǎn)“authpf”。
設(shè)計(jì)主策略集的主導(dǎo)思想為:阻斷任何包并允許盡可能小的數(shù)據(jù)流通過。在外部接口上流出數(shù)據(jù)包是允許的,但是默認(rèn)否策略阻斷了由無線接口進(jìn)入的數(shù)據(jù)包。用戶一旦通過驗(yàn)證,他們的數(shù)據(jù)包被允許通過無線接口進(jìn)入并穿過網(wǎng)關(guān)到達(dá)其他網(wǎng)絡(luò)。
編輯本段
回目錄
PF防火墻 - 實(shí)例:家庭和小型辦公室防火墻
概況
在這個(gè)例子中,PF作為防火墻和NAT網(wǎng)關(guān)運(yùn)行在OpenBSD機(jī)器上,為家庭或辦公室的小型網(wǎng)絡(luò)提供服務(wù)。總的目標(biāo)是向內(nèi)部網(wǎng)提供因特網(wǎng)接入,允許從因特網(wǎng)到防火墻的限制訪問。下面將詳細(xì)描述:
網(wǎng)絡(luò)
網(wǎng)絡(luò)配置如下:
[ COMP1 ] [ COMP3 ]
| | ADSL
--- ------ ----- ------- fxp0 [ OpenBSD ] ep0 -------- ( 因特網(wǎng) )
|
[ COMP2 ]
內(nèi)部網(wǎng)有若干機(jī)器,圖中只劃出了3臺,這些機(jī)器除了COMP3之外主要進(jìn)行網(wǎng)頁沖浪、電子郵件、聊天等;COMP3運(yùn)行一個(gè)小型web服務(wù)器。內(nèi)部網(wǎng)使用192.168.0.0/24網(wǎng)段。
OpenBSD網(wǎng)關(guān)運(yùn)行在 Pentium 100計(jì)算機(jī)上,裝有兩塊網(wǎng)卡:一個(gè)3com 3c509B(ep0),另一個(gè) Intel EtherExpress Pro/100(fxp0)。該網(wǎng)關(guān)通過ADSL連接到因特網(wǎng),同時(shí)通過NAT向內(nèi)網(wǎng)共享因特網(wǎng)連接。外部網(wǎng)卡的 IP地址動(dòng)態(tài)分配。
目標(biāo)
* 向內(nèi)部網(wǎng)絡(luò)的每臺計(jì)算機(jī)提供無限制的因特網(wǎng)接入。
* 啟用一條“默認(rèn)拒絕”策略。
* 允許下列來自因特網(wǎng)的請求訪問防火墻:
SSH (TCP 端口 22): 用來遠(yuǎn)程維護(hù)防火墻。
Auth/Ident (TCP 端口 113): SMTP和IRC服務(wù)用到的端口。
ICMP Echo Requests: ping(8)用到的ICMP包類型。
* 重定向訪問80端口(訪問web的請求)的請求到計(jì)算機(jī)COMP3,同時(shí),允許指向COMP3計(jì)算機(jī)的80端口的數(shù)據(jù)流過防火墻。
* 記錄外部網(wǎng)卡接口上的過濾日志。
* 默認(rèn)為阻斷的包返回一個(gè) TCP RST 或者 ICMP Unreachable 信息。
* 盡量保持策略集簡單并易于維護(hù)。
準(zhǔn)備
這里假設(shè)作為網(wǎng)關(guān)的OpenBSD主機(jī)已經(jīng)配置完成,包括IP網(wǎng)絡(luò)配置,因特網(wǎng)連接和設(shè)置net.inet.ip.forwarding 的值為1。
規(guī)則集
下面將逐步建立策略集以滿足上訴要求。
宏
定義下列宏以增強(qiáng)策略集的可維護(hù)性和可讀性:
int_if = "fxp0"
ext_if = "ep0"
tcp_services = "{ 22, 113 }"
icmp_types = "echoreq"
priv_nets = "{ 127.0.0.0/8, 192.168.0.0/16, 172.16.0.0/12, 10.0.0.0/8 }"
comp3 = "192.168.0.3"
前兩行定義了發(fā)生過濾的網(wǎng)絡(luò)接口。第3、4行定義了向因特網(wǎng)開放的服務(wù)端口號(SSH和ident/auth)和允許訪問防火墻的ICMP包類型。第5行定義了回送地址段和RFC1918定義的私有地址段。最后一行定義了主機(jī)COMP3的IP地址。
注意:如果ADSL接入因特網(wǎng)需要PPPoE,則過濾和NAT將發(fā)生在tun0接口上而不是ep0接口。
選項(xiàng)
下列兩個(gè)選項(xiàng)用來設(shè)置阻斷后的默認(rèn)操作為反饋,并在外部接口設(shè)置開啟日志記錄:
set block-policy return
set loginterface $ext_if
流量整修
沒有理由不起用對所有進(jìn)入防火墻的所有包進(jìn)行規(guī)格化,因此只需要簡單的一行:
scrub in all
NAT(網(wǎng)絡(luò)地址轉(zhuǎn)換)
為所有內(nèi)部網(wǎng)啟用NAT可以通過下列策略:
nat on $ext_if from $int_if:network to any -> ($ext_if)
由于外部網(wǎng)卡的IP地址是動(dòng)態(tài)獲得的,因此在外部網(wǎng)卡接口處增加小括號以使當(dāng)IP地址發(fā)生變化時(shí)PF可以自適應(yīng)。
重定向
第一個(gè)需要重定向策略的是ftp-proxy(8),只有這樣內(nèi)部網(wǎng)上的FTP客戶端才可以訪問因特網(wǎng)上的FTP服務(wù)器。
rdr on $int_if proto tcp from any to any port 21 -> 127.0.0.1 port 8021
注意這條策略只捕獲到21端口的數(shù)據(jù)包,如果用戶通過其他端口訪問FTP服務(wù)器,則在定義目的端口時(shí)需要使用list(列表),例如: from any to any port { 21, 2121 }。
第二個(gè)重定向策略捕獲因特網(wǎng)上的用戶訪問防火墻80端口的數(shù)據(jù)包。用戶試圖訪問網(wǎng)絡(luò)的web服務(wù)器時(shí)將產(chǎn)生合法的訪問該端口的數(shù)據(jù)包,這些連接請求需要重定向到主機(jī)COMP3:
rdr on $ext_if proto tcp from any to any port 80 -> $comp3
過濾規(guī)則
過濾規(guī)則第一行是默認(rèn)否規(guī)則:
block all
這時(shí)沒有任何數(shù)據(jù)包可以流過防火墻,甚至來自內(nèi)部網(wǎng)絡(luò)的數(shù)據(jù)包。下面的規(guī)則將逐個(gè)依據(jù)上面提到的目標(biāo)開啟防火墻上的虛擬接口。
每個(gè)Unix系統(tǒng)都有一個(gè)“l(fā)oopback(回送)”接口,它是用于系統(tǒng)中應(yīng)用程序間通信的虛擬網(wǎng)絡(luò)接口。在OpenBSD中,回送接口是lo(4)。
pass quick on lo0 all
下一步,由RFC 1918定義的私有地址將在外部網(wǎng)卡接口的進(jìn)和出方向被阻斷。這些地址不應(yīng)該出現(xiàn)在公網(wǎng)上,通過阻斷這些地址可以保證防火墻不向外部網(wǎng)泄漏內(nèi)網(wǎng)地址,同時(shí)也阻斷了來自外部網(wǎng)中源地址為這些私有地址的數(shù)據(jù)包流入內(nèi)網(wǎng)。
block drop in quick on $ext_if from $priv_nets to any
block drop out quick on $ext_if from any to $priv_nets
這里block drop用來通知PF停止反饋TCP RST或者ICMP Unreachabel 數(shù)據(jù)包。因?yàn)镽FC 1918規(guī)定的地址不會存在于因特網(wǎng)上,發(fā)往那些地址的數(shù)據(jù)包將沒有意義。Quick 選項(xiàng)用來通知PF如果這條規(guī)則匹配則不再進(jìn)行其他規(guī)則的匹配操作,來自或流向$ priv_nets的數(shù)據(jù)包將被立即丟棄。
現(xiàn)在將打開因特網(wǎng)上的一些服務(wù)所用到的端口:
pass in on $ext_if inet proto tcp from any to ($ext_if) \
port $tcp_services flags S/SA keep state
通過在宏$tcp_services中定義服務(wù)端口可以更方便的進(jìn)行維護(hù)。開放UDP服務(wù)也可一模仿上述語句,只不過改為proto udp。
已經(jīng)有了一條rdr策略將web訪問請求轉(zhuǎn)發(fā)到主機(jī)COMP3上,我們必須建立另一條過濾規(guī)則使得這些訪問請求可以通過防火墻:
pass in on $ext_if proto tcp from any to $comp3 port 80 \
flags S/SA synproxy state
考慮到安全問題,我們使用
TCP SYN Proxy
保護(hù)web服務(wù)器――
synproxy state
。
現(xiàn)在將允許ICMP包通過防火墻:
pass in inet proto icmp all icmp-type $icmp_types keep state
類似于宏$tcp_services,當(dāng)需要增加允許進(jìn)入防火墻的ICMP數(shù)據(jù)包類型時(shí)可以容易地編輯宏$icmp_types。注意這條策略將應(yīng)用于所有網(wǎng)絡(luò)接口。
現(xiàn)在數(shù)據(jù)流必須可以正常出入內(nèi)部網(wǎng)絡(luò)。我們假設(shè)內(nèi)網(wǎng)的用戶清楚自己的所作所為并且確定不會導(dǎo)致麻煩。這并不是必然有效的假設(shè),在某些環(huán)境下更具限制性的策略集會更適合。
pass in on $int_if from $int_if:network to any keep state
上面的策略將允許內(nèi)網(wǎng)中的任何計(jì)算機(jī)發(fā)送數(shù)據(jù)包穿過防火墻;然而,這并沒有允許防火墻主動(dòng)與內(nèi)網(wǎng)的計(jì)算機(jī)建立連接。這是一種好的方法嗎?評價(jià)這些需要依靠網(wǎng)絡(luò)配置的一些細(xì)節(jié)。如果防火墻同時(shí)充當(dāng)DHCP服務(wù)器,它需要在分配一個(gè)地址之前ping一下該地址以確認(rèn)該地址沒有被占用。允許防火墻訪問內(nèi)部網(wǎng)絡(luò)同時(shí)也允許了在因特網(wǎng)上通過ssh控制防火墻的用戶訪問內(nèi)網(wǎng)。請注意禁止防火墻直接訪問內(nèi)網(wǎng)并不能帶來高安全性,因?yàn)槿绻粋(gè)用戶可以訪問防火墻,他也可以改變防火墻的策略。增加下列策略可以使防火墻具備訪問內(nèi)網(wǎng)的能力:
pass out on $int_if from any to $int_if:network keep state
如果這些策略同時(shí)存在,則keep state選項(xiàng)將不是必須的;所有的數(shù)據(jù)包都可以流經(jīng)內(nèi)網(wǎng)接口,因?yàn)橐粭l策略規(guī)定了雙向放行數(shù)據(jù)包。然而,如果沒有pass out這條策略時(shí),pass in策略必須要有keep state選項(xiàng)。這也是keep state的有點(diǎn)所在:在執(zhí)行策略匹配之前將先進(jìn)行state表檢查,如果state表中存在匹配記錄,數(shù)據(jù)包將直接放行而不比再進(jìn)行策略匹配。這將提高符合比較重的防火墻的效率。
最后,允許流出外部網(wǎng)卡接口的數(shù)據(jù)包通過防火墻
pass out on $ext_if proto tcp all modulate state flags S/SA
pass out on $ext_if proto { udp, icmp } all keep state
TCP, UDP, 和 ICMP數(shù)據(jù)包將被允許朝因特網(wǎng)的方向出防火墻。State信息將被保存,以保證反饋回來的數(shù)據(jù)包通過防火墻。
完整規(guī)則集
# macros
int_if = "fxp0"
ext_if = "ep0"
tcp_services = "{ 22, 113 }"
icmp_types = "echoreq"
priv_nets = "{ 127.0.0.0/8, 192.168.0.0/16, 172.16.0.0/12, 10.0.0.0/8 }"
comp3 = "192.168.0.3"
# options
set block-policy return
set loginterface $ext_if
# scrub
scrub in all
# nat/rdr
nat on $ext_if from $int_if:network to any -> ($ext_if)
rdr on $int_if proto tcp from any to any port 21 -> 127.0.0.1 \
port 8021
rdr on $ext_if proto tcp from any to any port 80 -> $comp3
# filter rules
block all
pass quick on lo0 all
block drop in quick on $ext_if from $priv_nets to any
block drop out quick on $ext_if from any to $priv_nets
pass in on $ext_if inet proto tcp from any to ($ext_if) \
port $tcp_services flags S/SA keep state
pass in on $ext_if proto tcp from any to $comp3 port 80 \
flags S/SA synproxy state
pass in inet proto icmp all icmp-type $icmp_types keep state
pass in on $int_if from $int_if:network to any keep state
pass out on $int_if from any to $int_if:network keep state
pass out on $ext_if proto tcp all modulate state flags S/SA
pass out on $ext_if proto { udp, icmp } all keep state
編輯本段
回目錄
PF防火墻 - 參考資料
http://www.freebsdchina.org/forum/topic_24641.html
http://www.google.com
轉(zhuǎn)自:http://www.hudong.com/wiki/PF%E9%98%B2%E7%81%AB%E5%A2%99
本文來自ChinaUnix博客,如果查看原文請點(diǎn):http://blog.chinaunix.net/u2/63141/showart_2145993.html |
|