speaker新!iShredder™ iOS 和 Android 商业版现已面向企业用户开放。了解更多

OpenBSD 7.7 作为稳健的防火墙基础:一份能为你兜底的 pf.conf 与 sysctl.conf

OpenBSD 7.7 作为稳健的防火墙基础:一份能为你兜底的 pf.conf 与 sysctl.conf
October 09, 2025

多年来,OpenBSD 以其毫不妥协的安全理念著称:健全的默认值、干净的代码,把 “secure by default(默认安全)” 当成行动准则而不是宣传口号。若你在寻找一台在日常使用中既可靠又可解释的防火墙,OpenBSD 提供了坚实的基石。同时也要承认:强劲的默认值固然可贵,但再拧动几颗关键“微调螺丝”,就能在不把系统弄成“脆弱实验室”的前提下,显著提升安全性与可预测性。
本文旨在给出一套可落地的基线,既能稳妥保护小型网络、家庭实验环境与诸多中小企业场景,又保持可读、易维护。

我们不提供冗长的清单,也不给含混的“调优秘籍”,而是给出有理有据的选择清晰的理由:为什么要设这个选项、它解决哪些风险、会带来哪些副作用。目标不是覆盖每一个理论上的攻击场景,而是给你可靠的起点:精简的规则、少量的特例、明确的行为。

本指南遵循一条清晰的主线:明确允许,其余一律阻断。从外到内,只允许路由器自身所需;从内到外,只放行你确实想要的流量。我们让 DNS 保持可见且可控。不给 DoH、DoT、DoQ 与 QUIC 任何“静默小通道”,避免出现“隐形”路径。状态(state)刻意绑定到接口,让连接待在它们起始之处。这使系统更可预测、故障排查更可承受。因为透明胜过十个“小聪明”,所有关键路径都带有标签(label):上线后你会立刻看到哪些在用、哪些被挡、哪里需要收紧。

为让方案更具操作性,我们提供两套 pf 配置可选:一套是适用于经典 LAN‑到‑互联网场景的仅路由(router‑only)变体;另一套是路由 + DMZ 变体,适合需要隔离服务的环境。我们强制客户端 DNS 只指向 1.1.1.1(可选备用 1.0.0.1)。这不是咬文嚼字,而是刻意的架构设计:你因此重获可见性与控制权。若某个应用想绕路,它会被“亮出来”,你便能有意识地决定是否、以及在何处例外放行。

sysctl.conf 在内核层面呼应了这种取向。OpenBSD 自带的默认值已相当不错,但一些开关能带来可测量的稳健性提升:更“硬”的 malloc 配置,让经典内存错误更早、更响亮地失败;在侧信道风险无收益时,干脆关闭 SMT/超线程;启用 W^X,在可疑时宁可终止进程,也不让其在危险的灰区继续运行;禁用重定向与冗余的隧道协议;启用现代 TCP 选项与适度速率限制,在不破坏合法功能的前提下抑制“网络噪声”。这不是搏眼球的“黑科技”,而是持续的卫生学:更小攻击面、更少惊喜、在压力下更稳定。

不在本文范围的,是高度定制的定向攻击,或完整的 IDS/IPS 体系。如果你想引入分层监控、深度协议检查或威胁情报订阅,这套配置不会成为阻碍;它是地基,你可以在其上有序加砖。我们也刻意不覆盖复杂的多 WAN 策略、繁复的端口转发表或奇异的 overlay 网络。这些都能实现,但难免稀释基线的清晰度

追求可读性,也意味着我们更信任机械可解释的机制而不是“魔法”。需要实时性的地方使用静态 NAT 端口,其他地方则高段动态端口封掉 QUIC,以免 DNS 藏身于 TLS 流;默认阻断 IPv6,避免“半开 IPv6”(客户端偏好 v6,而你的防火墙并未控制 v6)——如果你需要 v6,文中会给正确开启的清晰步骤。凡是对运维有帮助的边界情形,我们都加上标签——不是为了让日志“更花”,而是为了得到答案:谁尝试了 DoT?哪些主机撞上了 anti‑rebind?是什么触发了 egress 封堵?

适合谁? 如果你把运维当成手艺,愿意花一小时打好干净的底子,胜过花三周追逐古怪副作用;如果你想理解你的网络,而不是被默认放行所惊到;如果你“夹在中间”——规模不足以搞 SOC/蓝队,但要求又高于“商超路由器”——那么这套基线不是魔法,而是合情合理的标准:小到可掌控,稳到可长用。

威胁模型:我们防什么,不防什么

这套基线面向没有专职蓝队、却希望遵循可靠标准的环境。它拦住每天砸向你边界的常见噪音:大范围扫描、机会主义利用、像“DNS over 一切”这样的协议滥用、错误的共享与宽松的 egress 策略(它们往往才是数据外泄的温床)。它将可选服务器纳入 DMZ,阻断横向移动入 LAN。不在聚焦范围的:高度定向攻击或完整 IDS/IPS 堆栈——这些可以在此基线上再往上加

设计原则:小攻击面,职责清晰

这份配置遵循几条也便于未来演进的准则:

Fail‑closed(失败即关闭)。 未被明确允许的,一律不通——无论入站还是出站。测试阶段你会很快发现应用真正需要什么,并保持主动权。

确定性的状态。 if-bound 让连接绑定在其产生的接口上。对单 WAN 路由器而言,这终结了对“漂浮状态”的苦寻,使故障排查更简单。

最小化出站(egress)。 从内到外只放必要的:经典 Web、邮件提交(submission)、为 VoIP/WebRTC 明确的 UDP 端口段——以及只向你指定的地方发送 DNS。

透明胜于猜谜。 封掉 QUIC,同时也封 DoH/DoT/DoQ。这也许会让某些应用不便,但换来的是清晰:DNS 就是 DNS,TLS 就是 TLS。谁需要“影子 DNS”,会立刻显形。

强健默认。 报文净化(scrub)、MSS 限定、随机 IP‑ID、bogon 过滤、反欺骗(anti‑spoofing)、TCP 标志卫生、对 ICMP 与 RST 的合理速率限制。单看都不惊艳,组合起来就是稳健卫生学。

IPv6 有意为之。 默认关闭 IPv6。若要开启,文中给出整洁流程。我们始终避免“半开 IPv6”。

sysctl.conf —— 在内核层真正有用的安全杠杆

OpenBSD 默认值已很强,但少量开关就能显著提升安全与可预测性。重点如下——不搞清单轰炸,只讲清楚理由

内存加固(vm.malloc_conf=CFGJRS)。 Guard page、垃圾填充(junk pattern)、Red‑Zone、金丝雀(canary)让经典内存漏洞更难被利用,并使进程“大声失败”而非“默默腐化”。这点开销在几乎所有路由器场景都值得。

CPU/硬件:关 SMT,封 aperture。 hw.smt=0 降低超线程的侧信道风险;在路由器上性能损失往往很小。machdep.allowaperture=0 封住类似 /dev/mem 的直通访问——对无头路由器正合适。若你需要 X11/KMS,你自然知道怎么做;否则保持关闭

路由与协议:开 IPv4,刻意关 IPv6。 net.inet.ip.forwarding=1 让设备成为 IPv4 路由器。net.inet6.ip6.forwarding=0 阻止“意外的” IPv6 转发。同时关闭不必要的隧道(IP‑in‑IP、GRE、ESP/AH、EtherIP)。更少的加密/封装机械,意味着更小攻击面、更少意外。

拆掉“古董陷阱”。 关闭定向广播、忽略重定向(IPv4/IPv6)。ICMP 重定向是经典“坑”;真要改路径,请在路由或 PF 中明确做,而不是旁门左道。

有分寸的 ICMP。 不回 broadcast echo,不回 timestamp/netmask;错误报文施加合理速率限制。这样既抑制 DDoS 噪音,又不破坏正当功能。ICMP 不是敌人,但需要护栏。

不搞玄学的 UDP/TCP 加固。 强制 UDP 校验;合理的 socket 缓冲防掉包。TCP 保持现代特性(窗口扩展、时间戳、SACK)开启以提升稳定性;ECN 开启,在现代网络很少出问题、在拥塞时更有帮助。SYN 缓存/桶限额与 RST 速率限制能吸收典型扫描浪潮。

队列、BPF 与 W^X。 更长的 if‑queue 能在突发时减少丢包。更大的 BPF 缓冲是未来排障时送给自己的礼物。kern.wxabort=1 严格执行 W^X:代码要么可写要么可执行,绝不两者兼得;违规就终止——fail‑closed,正合初心。交换分区加密保持开启,避免敏感残留以明文落盘。

这份 sysctl 选择刻意不花哨。它让系统从“多数情况下可用”转向“在压力下也一致”。用 sysctl -f 干净加载,抽查几个计数器(如 sysctl -n net.inet6.icmp6.errppslimit、netstat -m、pfctl -s memory)。若你调整了 mbuf/cluster 预算,记得相应调节 PF 的 set limit frags 等限额。

pf.conf:你看得懂、说得清的规则

pf 能做的事无穷多。我们的基线只取恰到好处的一撮,足以形成稳健标准,不多不少。

宏、表与标签——结构是成功的一半。 先清晰定义接口与网段:WAN、LAN,以及(在变体中)DMZ。配以 bogonabusersscanners 与可疑 DoH 终端的观察表(watchlist)。这些不是装饰:有了 persist 它们能跨重载存活,配合 overload 则会把“吵闹源”自动塞进去。全程标签化能让你不用重 pcap 也拥有一流可见性:pfctl -vvsr 或 systat pf 会告诉你哪里“在跳”。

全局选项——要的就是可预测。 set block-policy drop 与 “aggressive” 优化是稳健的保守默认。set state-policy if-bound 把连接锚定在进入的接口上。定义状态、分片与源节点的限额,开启自适应超时,并自适应启用 syncookies——当洪水来临时它们很有用。loginterface 提供 WAN 统计;set skip on lo0 防止自伤。
pf 默认阻断 IPv6,与 sysctl 呼应,避免“半开 IPv6”。若要启用,请自觉且可见地放开。

WAN 入站 ICMP:开放到足以维持健康。 在 WAN 接口上仅允许 echo 与 “unreachable”,且带状态与速率限制。这样便于诊断(否则 MTU/路径问题怎么可靠定位?),同时抵御 ping 洪泛。重定向等其余类型保持关闭。

报文净化(scrub):更少碎片,更少挫败。 进出双向 scrub:随机 IP‑ID、保守的最小 TTL、MSS 限定在 1440(实践中很稳)、TCP 重组。这既避免可疑碎片塞满状态表,也明显减少 PMTU 抽风。有此在前,几乎不必用 sysctl 调 MSS。

NAT:实时要静,其他可动。UDP 使用静态端口——对 VoIP/WebRTC、游戏等实时协议堪称金牌。其他协议走高段短暂端口:抓包时更易溯源,冲突概率也低。NAT 覆盖一切,唯独明确定义的管理目标除外——杜绝“意外小路”。

反欺骗、bogon 与“零端口”。 antispoof 盯紧所有关键接口。带坏源路由的包在 WAN 入口就被早抛。bogon 既挡进也挡出;例如从 10/8 或 127/8 往公网走,往往意味着别的配置问题。同时清理端口 0 与离谱的 TCP 标志——不是黑科技,却能省下被“创意扫描器”折磨的时间。

默认拒绝:一把大扫帚。 做完卫生,来个硬切:block all。从这里开始,只有明确的例外

WAN 入站:只让路由器自身需要的通过。 若上游要求,只放行入站 DHCP。到此为止。本文基线并不面向“公网可达的 DMZ”,如需暴露端口,请克制地做明确端口转发。

QUIC:HTTP/3 留在外面。 在 WAN 上阻断 UDP 80/443,QUIC 自然“断氧”。为何如此严格?因为 QUIC 是个天生的隧道——也常被 DoH 变体与“一切走一条流”的把戏借道。若你后来确实需要面向特定目标的 HTTP/3(且你知道为什么),请外科式放开之。基线优先级是:透明 > 速度

DoH/DoT/DoQ 的可见性——边界清晰。 DoT(853/TCP)与 DoQ(784/UDP)在出站被阻断,在入站被记录。在 LAN/DMZ 内,我们对指向已知 DoH 主机的 TLS 连接打标签——除非你选择更严格的变体,否则不改变策略。核心点:看见客户端尝试“隐身 DNS”。

防火墙的管理访问:窄且带节流。 允许从 LAN 到防火墙的 SSH,配合状态跟踪、标志卫生与温和的速率限制。上游管理路径(如前置调制解调器/路由器的 GUI)使用定点放行;适度的连接速率上限可缓冲误操作。标签让这些路径始终“在屏”。

没有本地解析器的 DNS 策略:靠强制,不靠祈祷。 关键一点:LAN(以及若存在的 DMZ)里的客户端只准1.1.1.1(可选 1.0.0.1)发起 53/TCP+UDP。其他指向 53 的流量一律阻断且记录。这不是“锦上添花”,而是可见性的根本。你会立刻看到它们尝试别的解析器——或 DoH/DoT/DoQ(它们被单独封)。你也可随时替换成其他外部解析器;机制完全相同。

DMZ:不留侧门,不走捷径。 在 DMZ 变体中,不允许任何 DMZ 内部互通、不允许回到 LAN,仅对驻留其上的服务放行定点出站(如经典 Web、邮件提交、VoIP/WebRTC 所需 UDP 段)。DMZ 到任何上游 GUI 的访问禁止;这样即便服务器沦陷,也碰不到你的管理网。其余统统阻断记录,以便迅速定位那颗“缺失螺丝”。

降低出站风险:先把“老毛病”关了。 对外我们封禁老面孔:SMB/NetBIOS、RPC/NFS、TFTP、SNMP、RDP/VNC/WinRM、以及“顺手就直投”的 SMTP。它们在内网明确路径上自有用武之地,但默认不该直面互联网。若确需例外,请有意识地放开,并打上标签

防火墙自身:可以上网,但要看得见。 防火墙可访问互联网——同样带状态、限额与标签。更新、装包与诊断都需要它。但请克制:它是路由器与看门犬,不是上网终端。

Anti‑rebind、LAN→DMZ 与总清理。 LAN 与 DMZ 之间只允许明确路径(如客户端到 DMZ 服务);回程保持关闭。Anti‑rebind 阻止客户端借 DNS 花招穿过防火墙去访问受保护的内部目标。其余地方,PF 给出明确的“不”——在合适处用 return,让错误更快暴露,便于排障。

仅路由 vs 路由 + DMZ:该选哪套?

只想把一个 LAN 接上互联网?选仅路由:简洁明晰且足够强硬。你会得到反欺骗、bogon 过滤、严格出站姿态、DNS 强制到 1.1.1.1/1.0.0.1、对 DoH/DoT/DoQ/QUIC 的控制、从 LAN 到防火墙的 SSH 管理、以及条理清楚的 scrub、state 与限额默认。

一旦你承载服务(哪怕只在内网用),路由 + DMZ 就有意义了。DMZ 能把故障圈在原地,减少“沦陷服务”成为跳板的概率。DMZ 内互通禁用;出站基于白名单,较 LAN 更窄。DNS 同样严格;NTP 默认不放,除非你确实需要。

正确开启 IPv6

基线默认阻断 IPv6,避免“半开半关”。若你需要 v6,请有计划且一致地启用:通过 sysctl 开路由、添加对应的 inet6 pf 规则、制定干净的出站方案(是的,v6 也要做 DNS 强制)、并明确 RA/DHCPv6 的取舍。把 v4 的好做法镜像到 v6:反欺骗、默认拒绝、QUIC/DoH/DoQ 管控、以及可见的例外——不多不少。最重要的提醒:别把 v6“悄悄塞进来”。要么一次到位,要么暂缓

运行、诊断与取证:宁测勿猜

严格的策略只有在看得懂的前提下才有价值。pf 通过三条路径帮你做到:

标签。 每条关键规则都有清晰的 label。在 pfctl -vvsr 里,你能看到哪些路径在用、哪些被挡、哪里在“响”。多数情况下这已足够定位问题。

表。 pfctl -t <table> -T show 可查看 abusers/scanners 记录。overload 会在客户端“开太多连接”时自动把它们塞进表里。这不是惩罚,而是安全带——失误不会把你直接抛出挡风玻璃。

最小化 pcap。 tcpdump 是朋友,但要用得巧。针对 DNS/DoH,很多时候像下面这样短促一瞥就够:
tcpdump -n -e -ttt -i $wan 'port 53 or port 853 or (udp and port 784)'
这叫“带计划的取证”,不是“Wireshark 到眼睛流泪”。

健康的测试仪式。 改规则时先只编译不加载:pfctl -nf /etc/pf.conf;随后 pfctl -f。若出错,labels 与 tables 会指引修复。验证 DNS 强制:drill @1.1.1.1 openbsd.org 应成功;drill @9.9.9.9 openbsd.org 应被阻断。验证 QUIC:curl -I --http3 https://example.com 不应走 UDP,应回落到 HTTP/2。验证 DoT/DoQ:对 1.1.1.1:853 与 UDP 784 的尝试应失败,且你能在带标签的规则上看到阻断计数增长。

出站变更小贴士。 当你放开某一出站项,临时给这条规则打一个非常醒目的标签,一周后再看是否真的被使用。若没人用,删掉它。基线就能一直清爽

性能考量:别信“传说”

这套方案不是“刀尖上跳舞”,而是瞄准稳定性。几个影响要记住:

封 QUIC 可能让某些网站略慢。这是有意识的取舍可见性优先于速度。若你有正当理由放开 HTTP/3,请外科式处理(目标纳入表、加标签、完事)。

ECN 开启在现代网络里通常没问题。若某个奇葩中间盒不喜欢,你会很快看到异常,对症关闭即可——基线不会跟你作对。

UDP 静态 NAT 端口 是实时协议的福音。追过 WebRTC 问题的人都懂它值千金。它几乎没有成本,只需要你明白“UDP 端口随机化”并不是安全功能。

if‑queue 与 BPF 缓冲 取值务实:有余量扛峰值,也让排障会话不被 4KB 缓冲扼住。真要跑到线速,请先测后调——而不是反过来。

常见坑与优雅化解

“我的应用只能用 DoH!” 那就要例外——或更好,先做诚实评估。DoH 本身无罪,但在家庭/企业网络管控中常常添堵。你可以把特定主机加入允许表;把它当成有意识的例外,而不是一把总钥匙。

“视频通话卡顿。” 先确认你是否覆盖了服务商(Zoom/Teams/WebRTC)所需的 UDP 端口段。静态 UDP 端口有帮助,但没有合适的出站走廊也白搭。请按需精调,不要一刀切。

“邮件客户端不能直接发。” 正确:出站 25 端口是关闭的。邮件应通过提交端口(465/587)送到你的服务商/服务器,而不是直投互联网。若需要,请明确放开提交端口——并打上标签

“IPv6 突然坏了。” 这套基线默认封 v6。若客户端偏好 v6 而防火墙不转 v6,自然会超时。要么正确开启 v6(配套规则齐备),要么通过 RA/ND 明确告诉客户端:暂不提供 v6

“改了规则后出现怪事。” 想想状态表。旧 state 默认仍存活。若你改变了基础策略(如开放了新的出站端口),请有针对性地清除相关 state(pfctl -k ...),或在必要时清空整个状态表(pfctl -F state)。随后世界就恢复一致了。

为什么这套基线“安全”——这里的安全意味着什么

安全从不绝对。但当目标清晰、路径可验时,它是可量化的。这份基线降低攻击面,因为它:

将一切入站暴露降到最低

让出站成为例外而非常态;

强制并保持可见 DNS;

封堵被掩饰的通道(QUIC/DoH/DoT/DoQ);

关闭伪功能(重定向、广播);

采用稳健的 TCP/ICMP 默认值

让状态处理确定化

并给你工具去观察日常使用。

同时,这份配置可维护。它不是因为“有 3000 行”而安全,而是因为每一行你都说得清

迁移:怎么做

若你已有一份 pf 配置,请分步推进

  1. 先上 sysctl。 加载不会影响可用性的内核加固。留意日志里是否出现异常的 ICMP/RST 噪音。
  2. 并行验证 pf 策略。 用 pfctl -nf 干编译,在实验网或维护窗口里测试。首次启用时,务必确认能从 LAN 通过 SSH 管理防火墙——把自己锁在门外很痛苦。
  3. 收紧出站。 先启用 DNS 强制并观察;然后逐步关闭经典高风险服务。持续 1–2 周的监控有助发现盲点。
  4. 需要的话加 DMZ。 迁移服务,保持 intra‑DMZ 与 DMZ→LAN 关闭。只开放确实必要的出站通道。观察并微调。
  5. 有意识地决定 IPv6。 要么按规范开启,要么继续关闭并明确告知客户端。

每一步都在不搞“爆炸式变更”的前提下提升安全。

后续可轻松扩展的内容

这套基线是地基,不是牢笼。常见扩展包括:

  • 若有经过验证的理由,为 QUIC/DoH 设置外科式例外——始终通过表与标签管理;
  • 站点到站点(Site‑to‑Site)VPN,以最小攻击面为目标;默认 sysctl 不会拦你,只要你明确放行协议;
  • 监控/告警。 pf 计数与 systat pf 足以覆盖基础指标;若需要更强,可将 pf 日志汇聚到中心系统;
  • IPv6,完整镜像 v4 的逻辑,而非“外接插件”。

升级与日常维护

OpenBSD 言出必行——但每次升级请阅读发行说明,尤其关注 pf 语法与内核默认值的变化。标签、表与清晰的宏会让跨版本校验变得迅速。保持为每个例外写下注释的纪律:它为什么存在、谁在用、你上次复查是什么时候。例外并非原罪;未注释的例外才是技术债。

结语:清晰,就是最好的加固

这套基线的目标很简单:清晰优先于复杂。你得到的是一台在日常中可预测的 OpenBSD 防火墙,攻击面小,通过标签合理默认随时让你看清到底发生了什么。我们更青睐明确的选择而非隐含的副作用:严格的出站政策、对指定解析器的 DNS 强制、不允许经由 QUIC 或 DoH/DoT/DoQ 的“静默通道”、确定性的状态处理与稳健的内核杠杆。结果不是学术展品,而是一块结实的起步石,让你能放心地继续构建。

需要强调:这套基线刻意不假定存在本地解析器本地 NTP 服务。它面向的是希望快速稳定、又不想先搭一堆新基础设施的场景。若你后来需要更强的本地化控制,完全可以无缝补上——架构已为此留好接口,无需背离基线立场。

为免你四处寻找:文末提供了完整的配置建议——两份 pf.conf(无 DMZ 的“仅路由”与含 DMZ 的“路由 + DMZ”)以及一份加固的 sysctl.conf。本文解释决策逻辑;下面的文件一比一实现这些决策。遵循 “验证 → 加载 → 度量” 的节奏,你将很快得到可复现的结果。

同样要对范围诚实:本文聚焦高定向攻击或完整 IDS/IPS 场景。这不意味着你要放弃它们——恰恰相反。地基已经打好,你可以有章法地把这些组件叠上去。实践中有三条常见扩展路径已被验证有效。

如果你在阅读中想到如何进一步收紧某些规则、有特殊需求,或愿意分享你的运行观察:欢迎联系。真实世界的反馈是推动有意义改进的最佳催化剂——也会纳入后续文章。安全是一个过程,不是短跑;有清晰的基线与愿意分享经验的社区,“良好”很快就会变成“优秀”。

下载 sysctl.conf:https://www.protectstar.com/download/blog/sysctl.txt
下载 pf.conf(含 DMZ):https://www.protectstar.com/download/blog/pf.conf_withDMZ.txt
下载 pf.conf(无 DMZ):https://www.protectstar.com/download/blog/pf.conf_noDMZ.txt

这篇文章对您有帮助吗?
1 共 1 人觉得这篇文章有帮助
取消 提交
Back 返回