站長新書 站長開講 首頁 最新文章 站長著作及審校 FreeBSD 筆記 Linux 筆記 Windows 筆記 虛擬化筆記 網管人雜誌 遊山玩水 關於本站
站長新書 VMware vSphere ICM 團購開跑了!!

PF-利用 PF 輕鬆達成 NAT

最後編輯

修改:

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

> === Q. pfctl: /dev/pf: No such file or directory? ===

修改:

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

> === Q. 所設定的 PF 都無法生效? ===

增加:

> === Q. 設定 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


前言

以下介紹為引用 [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 網站] 上找到

實作環境

安裝及設定

若您不需要 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 語法順序如下

  1. 巨集 Macro: 包含 IP 位址、介面名稱等自定變數
  2. 表格 Tables: 包含 IP 位址列表的表格
  3. 選項 Options: 各種控制 PF 運作的選項
  4. 清理 Traffic Normalization: 正規化與重組分段封包等再處理
  5. 佇列 Queueing: 提供頻寬控制與封包優先順序
  6. 轉譯 Translation: 控制網路位址轉譯與封包轉向
  7. 過濾規則 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
 #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
 #pfctl -t ssh-bruteforce -T add 218.70.0.0/16        //將 218.70.x.x 這個網段加入阻擋的 table 內
 /usr/ports/security/expiretable   //安裝 expiretable 
 */5   *   *   *   *   /usr/local/sbin/expiretable -t 3600 ssh-bruteforce  //定期清除 Table <ssh-bruteforce>
 #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,以下僅為範例實際請依個人網路環境自行調整。

 ### 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"
 ###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 設定檔

參考

[PF: The OpenBSD Packet Filter]

[PF: OpenBSD 封包過濾器]

[pf中文手冊(for openbsd,但同樣適用FREEBSD)]

[FreeBSD 使用手冊 第26章 防火牆 26.4 OpenBSD Packet Filter (PF) 和 ALTQ]

[Man Page pf.conf]

[Man Page altq(4)]

[FreeBSD packet filter Mail List]

[PF: The OpenBSD Packet Filter]

[PF: OpenBSD 封包過濾器]

[FreeBSD 5.3 Release PF 初體驗]

[ FreeBSD + PF + Shell Scritp + Load Sharing + Redundant ]

[FreeBSD NAT 上接兩條 ADSL 若斷線時自動偵測切換路由]

[PF 防火牆及 NAT 初次架設]

[ jail-pf memo]

[FreeBSD筆記:pf log]

[游志峰的網路架設筆記 pf 的紀錄檔]

[游志峰的網路架設筆記 pf設定]

[游志峰的網路架設筆記 pf 原廠範例]

[OpenBSD Taiwan openbsd & pf 的邂逅]

[Hi! I’m clsung » Blog Archive » pf 擋 ssh 惡意連線]

[Block ssh bruteforce attempts]

[FreeBSD PF 防火牆及 NAT 初次架設 < 月夜火]

[OpenBSD 超精簡版PF使用手冊]

[OpenBSD firewall using pf]

[openbsd+adsl+pf+qdns 配置过程 - fanqiang.com]

[OpenBSD下面自动block密码测试不法分子]

[FreeBSD with Packet Filter(PF) Firewall - (1) ]

[FreeBSD with Packet Filter(PF) Firewall - (2) ]

[FreeBSD with Packet Filter(PF) Firewall - (3) ]

[FreeBSD with Packet Filter(PF) Firewall - (4) ]

[FreeBSD with Packet Filter(PF) Firewall - (5) ]

[FreeBSD with Packet Filter(PF) Firewall - (6) ]

[Man Page expiretable -- removes PF table entries based on age]

Me FAQ

Q. 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

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

Error Message:

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

ANS:

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

 #vi /etc/rc.conf
 pf_enable="YES" 

Q. 設定 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
Go To Oddmuse OrgGo To FreeBSD OrgCreative Commons 2.5 Taiwansitestates.com