︿
Top

1、前言

以下介紹為引用 FreeBSD 使用手冊 第26章 防火牆 26.4 OpenBSD Packet Filter (PF) 和 ALTQ

2003 年 7 月, OpenBSD 的防火牆, 也就是常說的 PF 被成功地移植到了 FreeBSD 上, 並可以通過 FreeBSD Ports Collection 來安裝了; 第一個將 PF 集成到基本系統中的版本是 2004 年 11 月發行的 FreeBSD 5.3。 PF 是一個完整的提供了大量功能的防火牆軟件, 並提供了可選的 ALTQ (交錯隊列, Alternate Queuing) 功能。

ALTQ 提供了服務品質 (QoS) 帶寬整形功能, 這個功能能夠以基於過濾規則的方式來保障不同服務的帶寬。 OpenBSD Project 在維護 PF 用戶指南方面已經做了非常卓越的工作,因此我們不打算在這本使用手冊中進行更進一步的闡述, 以避免不必要的重複勞動。

警告: 在瀏覽 pf 用戶手冊時,請時刻注意,在 FreeBSD 中所包含的 pf 的版本和 OpenBSD 中是不一樣的。 在 FreeBSD 5.X 中 pf 相當於 OpenBSD 3.5 中的版本, 而 FreeBSD 6.X 中則相當於 OpenBSD 3.7。更多的詳細信息, 可以在  FreeBSD 版本的 PF 網站 上找到。



文章目錄

1、前言
2、實作環境
3、安裝及設定
          步驟1.修改核心啟用 PF
          步驟2.修改/etc/rc.conf
          步驟3.修改 PF 設定檔 (pf.conf)
          步驟4.PF 常用指令
4、參考
5、Me FAQ
          Q1. pfctl: /dev/pf: No such file or directory?
          Q2. 所設定的 PF 都無法生效?
          Q3. 設定 route-to 時語法錯誤?



2、實作環境

  • FreeBSD 6.x 



3、安裝及設定

若您需要 PF ALTQ 功能則可不用透過修改核心來支援 PF,請直接在 /etc/rc.conf 內加入 pf_enable="YES" 即可,並跳到步驟 3 繼續,不過前提是您必須要確定你的核心檔內下列三個選項沒有註解掉。
 options INET
 options INET6
 device  bpf




步驟 1. 修改核心啟用 PF

修改核心加入如下項目來啟用 Packet Filter 防火牆。
 device      pf         //啟動 Packet Filter 防火牆
 device      pflog      //啟動 pflog0 網卡並以 bpf 格式來記錄網路流量
 device      pfsync     //啟動 pfsync0 網卡用來監控「狀態的改變」
 options     ALTQ       //啟動 ALTQ 功能 (注意不是所有網卡皆支援 ALTQ 功能)
 options     ALTQ_CBQ   //啟動 Class Bases Queuing (CBQ) 功能




步驟 2. 修改 /etc/rc.conf

修改 /etc/rc.conf 中加入下列的設定以便在系統重新開機時時會啟動 PF 服務。
 pf_enable="YES"         //啟動 PF (如果需要的話載入模組)
 pflog_enable="YES"      //啟動 pflogd 功能
 gateway_enable="YES"    //啟動 LAN Gateway (若要做 NAT 的話)




步驟 3. 修改 PF 設定檔 (pf.conf)

PF,Packet Filter 防火牆特性為 Default Pass ALL、Last Match Rules 當撰寫適合自已的 pf.conf 時記得 pf.conf 語法順序如下:
  • 巨集 Macro: 包含 IP 位址、介面名稱等自定變數
  • 表格 Tables: 包含 IP 位址列表的表格
  • 選項 Options: 各種控制 PF 運作的選項
  • 清理 Traffic Normalization: 正規化與重組分段封包等再處理
  • 佇列 Queueing: 提供頻寬控制與封包優先順序
  • 轉譯 Translation: 控制網路位址轉譯與封包轉向
  • 過濾規則 Packet Filtering: 當封包通過任何網路介面時允許選擇性的過濾或阻擋封包

遠端操作 PF 注意事項
當您在遠端操作 PF 若是沒有十足的把握最好不要亂動,因為可能動一動之後把自已擋掉了在 #bsdchat 上看到順便就記下來吧。
 16:01 <@f0rth> pf -f 的時候不忘加上 ;sleep 10; pf -d
 16:02 <@priv> f0rth: "pf設定已經變更,請問是否確認,二十秒鐘後恢復原設定值(Y/N)"
 16:03 <@priv> 要這樣?


範例 1. 簡單 Web Server PF 設定檔

一個 Web Server 的基本 PF 設定內容如下 (Service FTP、SSH、DNS、HTTP),以下僅為範例實際請依個人網路環境自行調整:
vi /etc/pf.conf
### Macros: define common values, so they can be referenced and changed easily.
 ext_if="em0"
 private_addr="{192.168.0.0/16, 192.168.0.0/16, 10.0.0.0/8, 127.0.0.0/8, 0.0.0.0/8, 169.254.0.0/16, 192.0.2.0/24,
 204.152.64.0/23, 224.0.0.0/3}"
 pass_in_service="{53 80}"
### Normalization: reassemble fragments and resolve or reduce traffic ambiguities.
 scrub in all
### Filtering: the implicit first two rules are
### Pass Loopback
 pass in quick on lo0 all
 pass out quick on lo0 all
### Block the ftp ssh bruteforce bastards
 block drop in quick on $ext_if from <ssh-bruteforce>
### Pass Ping
 pass in quick on $ext_if proto icmp all
### Special rule for FTP/SSH
 pass in quick on $ext_if proto tcp from any to ($ext_if) port { ftp ssh } flags S/SA keep state (max-src-conn-rate 3/90,
 overload <ssh-bruteforce> flush global)
### Pass FTP
 pass in quick on $ext_if proto tcp from any to $ext_if port > 49151 keep state
### Pass IN Service DNS HTTP
 pass in quick on $ext_if proto { tcp, udp } from any to $ext_if port $pass_in_service keep state
### Pass Localhost to Any
#pass out quick on $ext_if all keep state
### Block Internet Private Address to Me
 block in quick on $ext_if from $private_addr to any
### Block Another all
 block return-rst in quick on $ext_if proto tcp all
 block return-icmp(net-unr) in quick on $ext_if proto udp all
 block in quick on $ext_if all


範例 2. 阻擋惡意 Try SSH/FTP 的 PF 設定檔

上面範例中可能只有一個地方比較不容易看懂,就是有關於會自動阻擋惡意嘗試連結您主機 SSH 及 FTP 服務的 IP 部份,詳細內容可參考 阻擋惡意 Try SSH/FTP IP
### special rule for ssh/ftp
 pass in on $ext_if proto tcp from any to ($ext_if) port { ftp ssh } flags S/SA keep state (max-src-conn-rate 3/30,
 overload <ssh-bruteforce> flush global)
### block the ssh bruteforce bastards
 block drop in quick on $ext_if from <ssh-bruteforce>

上面二條 PF 規則運作流程大概是這樣:
  1. 首先 Pass 對外進來的流量
  2. 記錄連結 Port {ftp ssh} 30 秒內 3 次 (max-src-conn-rate 指定時間內允許連結次數)
  3. 若有符合這樣條件的 IP 就將該 IP 加入 Table <ssh-bruteforce> 內
  4. 阻擋 (Block) 該 Table <ssh-bruteforce> 內列表的 IP

如何查看惡意嘗試 IP 列表? 執行如下指令即可查詢目前在 ssh-bruteforce table 內的 IP List
pfctl -t ssh-bruteforce -Tshow   //可看到惡意 IP 已加入 table 內
   61.95.172.140
   61.177.147.97
   62.29.248.240
   203.129.254.212
   210.192.98.99
   222.122.60.205

如何手動把惡意 IP 加入 table 內? 若想將已經的惡意 IP 加入 Table ssh-bruteforce 內請執行如下指令
pfctl -t ssh-bruteforce -T add 218.70.0.0/16   //將 218.70.x.x 網段加入阻擋的 table 內
定期清除 Table <ssh-bruteforce> 內列表的 IP方法? 下列方式請依個人喜好擇一即可

定期清除 Table 內 IP 列表 (方式一)
 /usr/ports/security/expiretable   //安裝 expiretable
 */5   *   *   *   *   /usr/local/sbin/expiretable -t 3600 ssh-bruteforce  //定期清除 Table <ssh-bruteforce>

手動清除 Table 內 IP 列表 (方式二)
pfctl -t ssh-bruteforce -T delete 218.70.0.0/16

範例 3. Gateway Server PF 設定檔

下列範例為使用 PF 當成 Gateway,負責的服務有 NAT (2 Routing)、WAN to DMZ 及 LAN to DMZ 的 Port Forwarding、Block Bad User IP,以下僅為範例實際請依個人網路環境自行調整。

/etc/rc.conf 內容
### TFN FTTB ###
 defaultrouter="219.20.230.254"       #TFN
 ifconfig_em0="inet 219.22.22.222  netmask 255.255.255.0"
### Hinet ADSL ###
 ifconfig_bge0="inet 202.60.43.111  netmask 255.255.255.0"        
### DMZ Interface ###
 ifconfig_em1="inet 192.168.10.1  netmask 255.255.255.0"
### LAN Interface ###
 ifconfig_em2="inet 192.168.20.1  netmask 255.255.255.0"
 ifconfig_em2_alias0="inet 192.168.10.2  netmask 255.255.255.255" # DMZ Mail
 ifconfig_em2_alias1="inet 192.168.10.8  netmask 255.255.255.255" # DMZ FTP
 ifconfig_em2_alias2="inet 192.168.10.9  netmask 255.255.255.255" # DMZ LDAP
#NAT
 gateway_enable="YES"
#PF
 pf_enable="YES"
 pflog_enable="YES"


/etc/pf.conf 內容
###Macros###
 ext_if1="em0"                        #TFN
 ext_if2="bge0"                       #Hinet
 dmz_if="em1"                         #DMZ
 lan_if="em2"                         #LAN
 dmz_net="192.168.10.0/24"            #DMZ Subnet
 lan_net="192.168.20.0/24"            #LAN Subnet
 weithenn_home="61.60.59.58/32"       #Weithenn Home IP
 hinet_gw="202.60.43.254/32"          #Routing to Hinet Gateway
 Allow_ftp_ip="{ 61.60.59.58/32 }"    #Allow FTP IP List
 icmp_types = "echoreq"               #ICMP
 lan_use_icmp="{ 192.168.20.137/32 }" #Allow Lan User Use ICMP List
 lan_bt="{ 192.168.20.171/32 }"       #Lan User Use BT ? Block it
###Tables###
 table <ssh-bruteforce> persist
###Options###
 set skip on lo0
 set block-policy return
###Scrub###
 scrub in all
###NAT/RDR###
###1.Lan User Default Routing go TFN
###2.If Lan User will Change Routing go Hinet Please Remark 41,85
###3.If Lan User will Change Routing go KBT Please Remark 82
#NAT on TFN (Primary Gateway)
 nat on $ext_if1 from { $dmz_net $lan_net } to any -> ($ext_if1)
#NAT on Hinet (Backup Gateway)
 nat on $ext_if2 from $lan_net to any -> ($ext_if2)
#RDR Outside to DMZ Hosts
 rdr on $ext_if1 proto tcp from any to $ext_if1/32 port { 25 80 110 } -> 192.168.10.2       #outside to MAIL pub ip
 rdr on $ext_if2 proto tcp from $Allow_ftp_ip to $ext_if2 port 21 -> 192.168.10.8 port 21   #outside to FTP
#RDP from weithenn
 rdr on $ext_if1 proto tcp from $weithenn_home to $ext_if1/32 port 3389 -> 192.168.79.10 port 3389
#RDR LAN to DMZ Hosts
 rdr on $lan_if proto { tcp, udp } from $lan_net to 192.168.88.2/32 port { 22 25 53 80 110 } -> 192.168.10.2 #to MAIL
 rdr on $lan_if proto { tcp, udp } from $lan_net to 192.168.88.8/32 port { 21 22 80 137 138 139 389 443 2355 } -> 192.168.10.8   #to ftp
 rdr on $lan_if proto { tcp, udp } from $lan_net to 192.168.88.9/32 port { 22 25 53 80 110 137 138 139 389 443 465 995 } -> 192.168.10.9 #to ldap
#RDR LAN outgoing FTP requests to the ftp-proxy
 rdr on $lan_if proto tcp from any to any port ftp -> 127.0.0.1 port 8021
###Filter###
 pass quick on lo0 all
#AntiSpoof
 antispoof quick for $lan_if
#Lan User Routing Change to Hinet
#pass in quick on $lan_if route-to ($ext_if2 $hinet_gw) from $lan_net to ! 192.168.0.0/16
#special rule for ssh/ftp
 pass in on $ext_if1 proto tcp from any to ($ext_if1) port { ftp ssh } flags S/SA keep state (max-src-conn-rate 3/30, overload <ssh-bruteforce> flush global)
 pass in on $ext_if2 proto tcp from any to ($ext_if2) port { ftp ssh } flags S/SA keep state (max-src-conn-rate 3/30, overload <ssh-bruteforce> flush global)
#block the ssh bruteforce bastards
 block drop in quick on $ext_if1 from <ssh-bruteforce>
 block drop in quick on $ext_if2 from <ssh-bruteforce>
#LAN use ICMP
 pass in quick on $lan_if proto icmp from $lan_use_icmp to any icmp-type $icmp_types
 block in quick on $lan_if proto icmp from $lan_net to any icmp-type $icmp_types
#Block Bad User
 block in quick on $lan_if from $lan_bt to any keep state queue bt




步驟 4. PF 常用指令

修改完 PF 設定檔 (pf.conf) 後,常使用以下指令來控制 PF 更詳細的用法請參考 Man Page pf.conf
# pfctl -f /etc/pf.conf           //重新載入 pf.conf 設定檔
# pfctl -nf /etc/pf.conf          //檢查 PF 語法是否正確 (未載入)
# pfctl -e                        //啟用 PF (開啟 Packet Filter 功能)
# pfctl -d                        //禁用 PF (關閉 Packet Filter 功能)
# pfctl -Nf /etc/pf.conf          //僅載入 NAT 的設定檔
# pfctl -Rf /etc/pf.conf          //僅載入防火牆的過濾設定檔
# pfctl -sn                       //顯示現階段 NAT 的規則
# pfctl -sr                       //顯示現階段過濾的規則
# pfctl -ss                       //顯示現階段封包運作狀態
# pfctl -si                       //顯示現階段過濾封包的統計資料
# pfctl -sa                       //顯示現階段所有統計的資料
# pfctl -vsr                      //顯示現階段過濾封包的統計資料
# pfctl -t ssh-bruteforce -Tshow  //顯示 table 內資料
# pfctl -Fa -e -f /etc/pf.conf    //清除所有規則、啟用 PF、載入 pf.conf 設定檔




4、參考




5、Me FAQ

Q1. pfctl: /dev/pf: No such file or directory?

Error Message:
執行 pfctl 指令欲載入 PF 規則時出現如下錯誤訊息
pfctl -f /etc/pf.conf
 pfctl: /dev/pf: No such file or directory

Ans:
原因使用 PF 時未修改核心 (Kernel) 且也尚未載入模組所導致,請鍵入下列指令手動載入 pf.ko 模組。
kldload pf.ko        //載入 pf.ko 模組
kldstat              //查詢目前系統載入的模組
 Id Refs Address    Size     Name
  1    4 0xc0400000 6a743c   kernel
  2    1 0xc0aa8000 6a45c    acpi.ko
  3    1 0xc470e000 33000    pf.ko      //pf.ko 已載入

此時再次執行 pfctl 指令便可順利執行
pfctl -f /etc/pf.conf
 No ALTQ support in kernel
 ALTQ related functions disabled




Q2. 所設定的 PF 都無法生效?

Error Message:
執行 pfctl 指令載入 PF 規則成功,但測試 PF 功能時卻發現所設定的規則都未生效 (ex. 禁止 Ping)。

Ans:
若是未修改核心 (Kernel) 方式來使用 PF 建議重新開機使系統完全載入相關模組及檔案,在重開機前請先確定於 rc.conf 內加入此行
vi /etc/rc.conf
 pf_enable="YES"




Q3. 設定 route-to 時語法錯誤?

Error Message:
當備份線路的 NAT 規則設定為這樣時使用 pfctl -nf /etc/pf.conf 會顯示語法有問題無法套用 PF 規則
 nat on $wan2_if from $lan_net to any -> ($wan2_if)
 pass in quick on $lan_if route-to ($wan2_if $backup_gw) from $lan_net to ! 10.0.0.0/13

Ans:
將其中的 $backup_gw 不要使用參數,改為使用 IP 位址表示即可順利生效!!
 nat on $wan2_if from $lan_net to any -> ($wan2_if)
 pass in quick on $lan_if route-to ($wan2_if 61.60.59.254) from $lan_net to ! 10.0.0.0/13
文章標籤: