SPF Toolbox v2.2.0 配置参数详解

SPF Toolbox v2.2.0 无配置文件,配置分散在 HTTP 查询参数、源码常量与 PHP 运行时三层:本文逐项给出默认值、修改方法与实测验证闭环,含 50 个 DNSBL 区域清单、端口/超时、DMARC 前缀、dnsmasq 离线复现与缓存行为实证。

SPF ToolboxSPF Toolbox邮件服务域名服务2026/10/26

SPF Toolbox v2.2.0 配置参数详解

目标:讲清 SPF Toolbox v2.2.0 的全部可配置项——应用无独立配置文件,配置分散在 HTTP 查询参数、源码常量与 PHP 运行时三层,本文逐层给出参数含义、默认值、修改方法与实测验证闭环,并覆盖缓存行为与超时项的实测结论。

一、环境信息

本文所有修改与验证均在以下真实服务器环境实测:

  • 操作系统:Ubuntu 22.04.5 LTS
  • Web 服务器:Apache 2.4.52(mod_php 形态,apache2 systemd 服务托管)
  • PHP:8.1.2(/etc/php/8.1/apache2/php.ini 为 Web 运行时配置)
  • 应用版本:SPF Toolbox v2.2.0,部署于 /var/www/html/spftoolbox,属主 www-data
  • 验证方式:每项配置修改后经 curl -s 'http://127.0.0.1/spftoolbox/operations/?domain=…&request=…' 调用查询端点核对结果变化
  • 辅助环境:本地 dnsmasq(自建 DNS 区域,用于验证解析器参数与离线复现)

部署过程见本专栏部署篇:《Ubuntu 22.04 安装 SPF Toolbox v2.2.0 指南》。

二、前置条件

  1. 已按部署篇完成 v2.2.0 安装并可通过 http://<服务器IP>/spftoolbox/ 正常访问;
  2. 修改源码常量前先备份原文件(本文示例统一备份到 /tmp);
  3. 修改 PHP 配置后需 systemctl restart apache2 才生效(mod_php 不热加载 php.ini);
  4. 修改 Blacklist.php/Port.php/Dmarc.php 等源码文件后无需重启 Apache(PHP 每次请求重新编译),curl 复测即生效。

三、参数查看与修改方式

关键认知:SPF Toolbox 没有配置文件。 v2.2.0 的全部可配置项分布在三个层面:

配置层位置修改后生效方式适合调什么
① HTTP 查询参数URL:operations/?domain=…&request=…&port=…立即(每次请求独立解析)查询目标、查询类型、端口
② 源码常量operations/Blacklist.php、operations/Port.php、operations/Dmarc.php立即(PHP 每请求重编译,无需重启)黑名单区域清单、默认端口数组、连接超时、DMARC 前缀
③ PHP 运行时/etc/php/8.1/apache2/php.ini + /etc/resolv.confsystemctl restart apache2(resolv.conf 立即)错误显示/日志、执行时限、内存、Socket 超时、DNS 上游

查看当前生效值的命令:

# ② 层常量值(Blacklist 区域数量)
php -r 'require "/var/www/html/spftoolbox/operations/OperationInterface.php"; require "/var/www/html/spftoolbox/operations/Blacklist.php"; echo count(Blacklist::LOOKUP_HOSTS), PHP_EOL;'

实测回显:

50
# ③ 层 PHP 运行时关键项
grep -E "^(max_execution_time|memory_limit|default_socket_timeout|display_errors|log_errors|error_reporting) " /etc/php/8.1/apache2/php.ini

实测回显:

max_execution_time = 30
memory_limit = 128M
display_errors = Off
log_errors = On
default_socket_timeout = 60
error_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT

四、参数总览

参数层位置默认值作用调整建议
domain①URL必填查询目标域名/IP传空返回空响应
request①URL必填查询类型,11 取值传非法值返回明确错误
port①URL仅 port 查询用指定端口空=按默认端口数组探测
LOOKUP_HOSTS②Blacklist.php50 个 DNSBL 区域黑名单反查清单按需增删区域
默认端口数组②Port.php[25, 53, 80, 443, 465, 587, 993]port 查询缺省探测集加自有服务端口
连接超时②Port.php5 秒fsockopen 超时慢链路可放宽
DMARC 前缀②Dmarc.php"_dmarc."DMARC 记录子域前缀一般不动
display_errors③php.iniOff错误是否进输出必须保持 Off
log_errors③php.iniOn错误是否进日志保持 On
max_execution_time③php.ini30脚本 CPU 时间上限一般不动(见 5.7)
default_socket_timeout③php.ini60未显式传超时的 Socket 默认超时一般不动
memory_limit③php.ini128M内存上限一般不动
DNS 上游③/etc/resolv.conf系统默认所有 DNS 查询的代发出口内网复现/隔离时调整

五、核心参数分类详解

5.1 查询入口 HTTP 参数(domain / request / port)

后端唯一入口是 operations/index.php,接收三个 GET 参数。request 的 11 个合法取值与功能对应关系如下(与界面下拉框一致):

request 值查询功能domain 传什么
a / aaaaIPv4 / IPv6 地址域名
mxMX 收信服务器域名
txtTXT 记录(含 SPF;DKIM 用选择器子域变通)域名或 选择器._domainkey.域名
dmarcDMARC 策略(自动拼 _dmarc.)裸域名
blacklist50 个 DNSBL 聚合反查域名(先解析出 IP)
whois注册信息(内置 phpwhois)域名
portTCP 端口探测域名或 IP,配 port 参数
hinfoHINFO 记录域名
all全部记录(DNS_ALL 优先回退 DNS_ANY)域名
reverseLookup反向解析(PTR)IP

三个参数的边界行为实测:

# 空 domain:整个 if 分支不成立,无任何输出
curl -s 'http://127.0.0.1/spftoolbox/operations/?domain=&request=mx'

实测回显(空响应):

# 非法 request:返回明确的错误 JSON
curl -s 'http://127.0.0.1/spftoolbox/operations/?domain=gmail.com&request=bogus'

实测回显:

[{"error": "Please check a valid DNS type"}]
# 不存在的域名:dns_get_record 返回空,序列化为 []
curl -s 'http://127.0.0.1/spftoolbox/operations/?domain=no-such-xyz-9x.com&request=mx'

实测回显:

[]

DKIM 变通验证:应用没有 DKIM 专用入口,把 选择器._domainkey.域名 整串当作 domain 走 txt 查询即可。实测 ebay 域名的 dkim 选择器:

curl -s 'http://127.0.0.1/spftoolbox/operations/?domain=dkim._domainkey.ebay.com&request=txt' | head -20

实测回显(完整 JSON):

[
    {
        "host": "dkim._domainkey.ebay.com",
        "class": "IN",
        "ttl": 3600,
        "type": "TXT",
        "txt": "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDLM0fpK\/rhklYDRJSBQ6bSyZKjQxTeEnZywzodwGAjAste2aOQzXJyZmZrjHZ0JL6Gy\/e351n1P0Yo0cVE4nEQ7WD9jo0cqVEmkf1SInnhN1FGX\/pOTjrjh7QU398YFxks\/rqnX6C1qdoeu7B4wwRhNEHUjlaH79afYqOtk0ta0wIDAQAB; n=1024;",
        "entries": [
            "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDLM0fpK\/rhklYDRJSBQ6bSyZKjQxTeEnZywzodwGAjAste2aOQzXJyZmZrjHZ0JL6Gy\/e351n1P0Yo0cVE4nEQ7WD9jo0cqVEmkf1SInnhN1FGX\/pOTjrjh7QU398YFxks\/rqnX6C1qdoeu7B4wwRhNEHUjlaH79afYqOtk0ta0wIDAQAB; n=1024;"
        ]
    }
]

选择器名称从发件方文档或邮件原始头(DKIM-Signature: ... s=<选择器> 字段)获取;选择器猜错时返回 []。

5.2 黑名单区域清单(Blacklist.php LOOKUP_HOSTS)

operations/Blacklist.php 的 LOOKUP_HOSTS 类常量定义黑名单反查区域清单,默认 50 个。查询逻辑:先把域名解析为 IP,反转后逐区域拼接反查(如 83.99.250.142.dnsrbl.org),checkdnsrr 有 A 记录即判 FAIL,无记录判 OK。

完整默认清单(50 项,php -r 反射导出,按源码顺序):

babl.rbl.webiron.net      cabl.rbl.webiron.net    stabl.rbl.webiron.net
all.rbl.webiron.net       crawler.rbl.webiron.net truncate.gbudb.net
dnsbl.sorbs.net           safe.dnsbl.sorbs.net    http.dnsbl.sorbs.net
socks.dnsbl.sorbs.net     misc.dnsbl.sorbs.net    smtp.dnsbl.sorbs.net
web.dnsbl.sorbs.net       new.spam.dnsbl.sorbs.net recent.spam.dnsbl.sorbs.net
old.spam.dnsbl.sorbs.net  spam.dnsbl.sorbs.net    escalations.dnsbl.sorbs.net
block.dnsbl.sorbs.net     zombie.dnsbl.sorbs.net  dul.dnsbl.sorbs.net
noservers.dnsbl.sorbs.net rhsbl.sorbs.net         badconf.rhsbl.sorbs.net
nomail.rhsbl.sorbs.net    sbl.spamhaus.org        xbl.spamhaus.org
pbl.spamhaus.org          sbl-xbl.spamhaus.org    zen.spamhaus.org
rbl.orbitrbl.com          dnsrbl.org              db.wpbl.info
bad.psky.me               bl.spamcop.net          noptr.spamrats.com
dyna.spamrats.com         spam.spamrats.com       auth.spamrats.com
spamtrap.drbl.drand.net   hostkarma.junkemailfilter.com blacklist.hostkarma.com
ix.dnsbl.manitu.net       dnsbl.inps.de           bl.blocklist.de
srnblack.surgate.net      all.s5h.net             rbl.realtimeblacklist.com
b.barracudacentral.org    virbl.dnsbl.bit.nl

其中 webiron 系 5 个、sorbs 系 16 个、spamhaus 系 5 个、spamrats 系 4 个为主力分组;zen.spamhaus.org 与 b.barracudacentral.org 是最常引用的两个综合区域。

增删闭环实测(改完即生效,无需重启):

# 1) 删除 virbl.dnsbl.bit.nl 区域
cd /var/www/html/spftoolbox/operations
cp Blacklist.php /tmp/Blacklist.php.bak
sed -i 's/"virbl.dnsbl.bit.nl"//' Blacklist.php
time curl -s -m 120 'http://127.0.0.1/spftoolbox/operations/?domain=gmail.com&request=blacklist' | tail -c 230

实测回显(输出尾部,virbl 条目已消失,最后一项变为 barracuda):

.com": "OK","ix.dnsbl.manitu.net": "OK","dnsbl.inps.de": "OK","bl.blocklist.de": "OK","srnblack.surgate.net": "OK","all.s5h.net": "OK","rbl.realtimeblacklist.com": "OK","b.barracudacentral.org": "OK","end of list": "end of list"}]
real	1m8.764s
user	0m0.005s
sys	0m0.001s
# 2) 还原后新增自定义区域 testbl.lab.internal 到清单头
cp /tmp/Blacklist.php.bak Blacklist.php
sed -i 's/const LOOKUP_HOSTS = \[/const LOOKUP_HOSTS = [\n        "testbl.lab.internal",/' Blacklist.php
curl -s -m 120 'http://127.0.0.1/spftoolbox/operations/?domain=gmail.com&request=blacklist' | head -c 140

实测回显(输出头部,新区域排第一;不存在的区域反查无记录判 OK):

[{"testbl.lab.internal": "OK","babl.rbl.webiron.net": "OK","cabl.rbl.webiron.net": "OK","stabl.rbl.webiron.net": "OK","all.rbl.webiron.net":
# 3) 恢复原文件
cp /tmp/Blacklist.php.bak Blacklist.php
php -r 'require "/var/www/html/spftoolbox/operations/OperationInterface.php"; require "/var/www/html/spftoolbox/operations/Blacklist.php"; echo count(Blacklist::LOOKUP_HOSTS), PHP_EOL;'

实测回显:

50

FAIL 结果解读警示:判定逻辑不校验返回值是否为 127.0.0.x 网段。实测 gmail.com 解析出的 Google IP(142.250.99.83)在 dnsrbl.org 上反查有 A 记录而判 FAIL(其余 49 个区域全部 OK):

dig +short 83.99.250.142.dnsrbl.org

实测回显:

103.224.182.253

该返回值并非 127 网段命中编码,说明此区域把大量非垃圾 IP 也列出(对 Google 段如此),因此看到 FAIL 必须人工复核:确认反查返回值是否符合该 DNSBL 的编码规范,再决定处置。调整 5.2 清单时,可把这类误报率高的区域直接删掉。

5.3 端口探测参数(Port.php 端口数组与超时)

operations/Port.php 两个默认值:端口数组 private $ports = [25, 53, 80, 443, 465, 587, 993];、连接超时 fsockopen($hostname, $port[$i], $errno, $errstr, 5) 的 5 秒。不传 port 参数时按数组逐个探测:

curl -s 'http://127.0.0.1/spftoolbox/operations/?domain=127.0.0.1&request=port&port='

实测回显(7 个默认端口,本机 80 开放):

  [{
"25": "Is closed",
"53": "Is closed",
"80": "Is open",
"443": "Is closed",
"465": "Is closed",
"587": "Is closed",
"993": "Is closed"
}]

修改闭环 1——默认端口数组(新增 8080):

cd /var/www/html/spftoolbox/operations
cp Port.php /tmp/Port.php.bak
sed -i 's/private \$ports = \[25, 53, 80 , 443, 465, 587, 993\];/private \$ports = [25, 53, 80 , 443, 465, 587, 993, 8080];/' Port.php
curl -s 'http://127.0.0.1/spftoolbox/operations/?domain=127.0.0.1&request=port&port='

实测回显(8 个端口生效):

  [{
"25": "Is closed",
"53": "Is closed",
"80": "Is open",
"443": "Is closed",
"465": "Is closed",
"587": "Is closed",
"993": "Is closed",
"8080": "Is closed"
}]

修改闭环 2——连接超时 5s → 2s(对被出站防火墙拦截的公网地址,响应时长随超时值同步变化):

sed -i 's/fsockopen($hostname, $port[$i], $errno, $errstr, 5)/fsockopen($hostname, $port[$i], $errno, $errstr, 2)/' Port.php
time curl -s 'http://127.0.0.1/spftoolbox/operations/?domain=gmail.com&request=port&port=443'

实测回显(超时 2 秒生效):

[{"443": "Is closed"}]
real	0m2.044s
user	0m0.013s
sys	0m0.000s
# 还原 5 秒超时后同条件复测
cp /tmp/Port.php.bak Port.php
time curl -s 'http://127.0.0.1/spftoolbox/operations/?domain=gmail.com&request=port&port=443'

实测回显(恢复 5 秒):

[{"443": "Is closed"}]
real	0m5.030s
user	0m0.018s
sys	0m0.000s

结论:超时参数直接线性反映到响应时长(2.044s vs 5.030s),单地址单端口探测时长≈超时值。对被拦截环境调小超时可显著加快 port 查询返回。

5.4 DMARC 查询前缀(Dmarc.php _dmarc.)

operations/Dmarc.php 把 _dmarc. 前缀硬编码为变量 $dmarc = "_dmarc.";,用户只传裸域名。RFC 7489 规定 DMARC 记录固定在 _dmarc.<域名> 子域,因此该前缀一般不应修改;但组织若使用组织域 DMARC 分发(子域继承 _dmarc.example.com),可临时改前缀排查子域记录发布情况。

修改闭环实测(改为 _dmarctest.,验证查询目标随之改变):

cd /var/www/html/spftoolbox/operations
cp Dmarc.php /tmp/Dmarc.php.bak
php -r '$s=file_get_contents("Dmarc.php"); $s=str_replace("_dmarc.","_dmarctest.",$s); file_put_contents("Dmarc.php",$s);'
grep -n "_dmarctest" Dmarc.php
curl -s 'http://127.0.0.1/spftoolbox/operations/?domain=gmail.com&request=dmarc'

实测回显(查询目标变为 _dmarctest.gmail.com,该子域无记录返回 []):

12:$dmarc = "_dmarctest.";
[]
# 还原后复测,恢复真实 DMARC 记录
cp /tmp/Dmarc.php.bak Dmarc.php
curl -s 'http://127.0.0.1/spftoolbox/operations/?domain=gmail.com&request=dmarc' | head -5

实测回显:

[
    {
        "host": "_dmarc.gmail.com",

5.5 PHP 运行时参数(php.ini)

Web 侧生效文件是 /etc/php/8.1/apache2/php.ini(注意不是 cli/php.ini,两套互相独立),改完必须 systemctl restart apache2。

display_errors / log_errors(最关键两项):display_errors = Off 保证 JSON 输出纯净——一旦开启,任何 PHP 告警文本都会混进 JSON 导致前端 response.json() 解析失败。实测验证:把 display_errors 改为 On 并重启后,对不存在域名的 MX 查询仍返回纯 []、whois 查询输出依旧无告警前缀(v2.2.0 的 11 类查询路径在 PHP 8.1 下未触发输出级告警);但该防线必须保持,防止未来 PHP 升级引入弃用告警时污染输出。告警细节由 log_errors = On 落到 /var/log/apache2/error.log 排查:

tail -5 /var/log/apache2/error.log

实测回显(权限类故障示例,8.1 节场景):

[Mon Oct 26 05:09:28.376387 2026] [core:error] [pid 10066] (13)Permission denied: [client 127.0.0.1:43722] AH00035: access to /spftoolbox/index.htm denied (filesystem path '/var/www/html/spftoolbox/index.htm') because search permissions are missing on a component of the path
[Mon Oct 26 05:09:28.380530 2026] [core:error] [pid 10062] (13)Permission denied: [client 127.0.0.1:43728] AH00035: access to /spftoolbox/operations/ denied (filesystem path '/var/www/html/spftoolbox/operations') because search permissions are missing on a component of the path

max_execution_time = 30 的一个反直觉现象:黑名单查询对 50 个区域逐个 checkdnsrr,部分区域无响应时总耗时实测约 88 秒,远超 30 秒上限却未被打断——Linux 上该限值只累计 CPU 时间,DNS 等待(I/O 阻塞)不计入。因此调大它并不能解决黑名单慢,真正的缓解手段是删掉无响应的 DNSBL 区域(5.2)或降低各环节超时。

default_socket_timeout = 60:仅对未显式传超时的 socket 生效;Port 查询的 fsockopen 有自己的 5 秒超时(5.3),whois 的 phpwhois 走 fsockopen 自带超时,所以该项对 SPF Toolbox 常规查询几乎无影响,保持默认即可。

memory_limit = 128M:11 类查询均为小结果集,实测从未接近上限,保持默认。

5.6 DNS 解析器与本地记录复现(/etc/resolv.conf + dnsmasq)

应用自身不指定 DNS 服务器,dns_get_record/checkdnsrr 全部走系统解析器 /etc/resolv.conf。这意味着:换上游解析器 = 全局改变所有查询的数据源,也是内网/无外网环境复现查询能力的开关。

实测在服务器本地用 dnsmasq 建一个模拟区域,验证 SPF Toolbox 从本地 DNS 拿到自造记录(可离线复现):

# 1) 建 dnsmasq 本地区域(A/MX/TXT/DMARC 四类记录)
cat > /etc/dnsmasq.d/lab.conf <<'EOF'
listen-address=127.0.0.2
bind-interfaces
port=53
server=127.0.0.11
host-record=lab.example,10.10.10.10
mx-host=lab.example,mail.lab.example,10
txt-record=lab.example,"v=spf1 ip4:10.10.10.0/24 -all"
txt-record=_dmarc.lab.example,"v=DMARC1; p=reject; rua=mailto:dmarc@lab.example"
EOF
systemctl enable --now dnsmasq
systemctl is-active dnsmasq

# 2) 把系统解析器指向本地 dnsmasq
printf 'nameserver 127.0.0.2\nsearch .\noptions edns0 trust-ad ndots:0\n' > /etc/resolv.conf

# 3) 先用 dig 确认解析器侧记录就绪
dig +short lab.example MX
dig +short lab.example TXT

实测回显:

active
10 mail.lab.example
"v=spf1 ip4:10.10.10.0/24 -all"
# 4) SPF Toolbox 全链路实测本地记录
curl -s 'http://127.0.0.1/spftoolbox/operations/?domain=lab.example&request=mx'
curl -s 'http://127.0.0.1/spftoolbox/operations/?domain=lab.example&request=txt'
curl -s 'http://127.0.0.1/spftoolbox/operations/?domain=lab.example&request=dmarc'

实测回显(MX 与 DMARC,TXT 同理返回自造 SPF 记录):

[
    {
        "host": "lab.example",
        "class": "IN",
        "ttl": 0,
        "type": "MX",
        "pri": 10,
        "target": "mail.lab.example"
    }
]
[
    {
        "host": "_dmarc.lab.example",
        "class": "IN",
        "ttl": 0,
        "type": "TXT",
        "txt": "v=DMARC1; p=reject; rua=mailto:dmarc@lab.example"
    }
]

本地记录全部正确返回,且 ttl 显示 0(dnsmasq 对本地记录默认返回 TTL 0)——离线复现闭环成立。验证完毕后把 /etc/resolv.conf 恢复原 nameserver,公网查询立即回归。

⚠️ 注意:部分最小化部署里 /etc/resolv.conf 由部署底座挂载管理(本实测环境即如此,sed -i 重命名替换时报 Device or resource busy 即属这种情况),改用重定向覆写(printf ... > /etc/resolv.conf);常规物理服务器无此限制。

5.7 缓存与超时项(应用无缓存,实测证据)

应用层无结果缓存。证据一:后端入口显式输出禁缓存头(实测响应头):

curl -sI 'http://127.0.0.1/spftoolbox/operations/?domain=gmail.com&request=a'

实测回显:

HTTP/1.1 200 OK
Date: Mon, 26 Oct 2026 05:29:59 GMT
Server: Apache/2.4.52 (Ubuntu)
Access-Control-Allow-Origin: *
Access-Control-Allow-Headers: Content-Type
Access-Control-Allow-Methods: GET, POST, OPTIONS
Cache-Control: no-store, no-cache, must-revalidate
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Content-Type: text/html; charset=UTF-8

证据二:两次相同查询之间的 TTL 递减(来自解析器缓存倒计时)说明每次都是重新解析而非回放缓存。实测同一域名两次 TXT 查询 TTL 从 3600 递减:

第一次: "ttl": 3600
第二次: "ttl": 3586

超时项全景(汇总实测):

环节超时来源默认值实测表现
端口探测Port.php fsockopen 参数5 秒被拦截地址实测 5.030s(改 2s 后 2.044s)
DNS 查询系统解析器(resolv.conf + 上游)上游决定正常数十毫秒;无响应区域阻塞黑名单查询
whoisphpwhois 内部 fsockopen库内定值whois.verisign-grs.com 实测 1.8s 内返回
黑名单整体50 区域串行累加无总上限实测 1m28s(含无响应区域等待)
PHP 执行max_execution_time(仅 CPU 时间)3088s 的黑名单查询未被打断

TTL 显示值差异提示:实测同一域名 dig 显示 TTL 3600 而应用 JSON 显示 ttl: 5,原因是应用经系统解析器(glibc resolver → 递归链路)取得响应,递归链路上的解析器可对 TTL 做改写/压低;ttl: 0(如 dnsmasq 本地记录)表示不可缓存。解读时以「TTL>0 可缓存」定性即可,不建议跨工具直接对比 TTL 数值。

六、生产配置模板

以下为推荐的生产基线(Apache + mod_php 形态),逐项均在前文验证过:

; /etc/php/8.1/apache2/php.ini 关键项(Ubuntu 默认值,显式核对)
display_errors = Off          ; JSON 纯净的第一道防线(5.5)
log_errors = On               ; 告警落 /var/log/apache2/error.log
max_execution_time = 30       ; 保持默认:I/O 等待不计时,调大无益(5.5)
memory_limit = 128M           ; 保持默认
default_socket_timeout = 60   ; 保持默认
# /etc/apache2/sites-enabled/000-default.conf 关键段
# 1) 访问控制(防公网滥用,账号如 admin,强口令)
<Directory /var/www/html/spftoolbox>
    AuthType Basic
    AuthName "SPF Toolbox"
    AuthUserFile /etc/apache2/.htspf
    Require valid-user
</Directory>
# 2) 文件权限(403 故障的第一修复项,8.1)
chown -R www-data:www-data /var/www/html/spftoolbox
chmod -R 755 /var/www/html/spftoolbox

# 3) (可选)删除误报率高的 DNSBL 区域,缩短黑名单查询耗时(5.2)
# 4) 出站放行:UDP 53(DNS)、TCP 43(whois)、按需出站 TCP(port 查询)

适用场景:公网或内网均可;内网部署可省去 Basic Auth 但仍建议保留文件权限基线。配置完成后执行一轮回归:request=mx 与 request=blacklist 各查一次公网域名,输出结构与部署验收一致即为配置收敛。

七、常见问题(FAQ)

7.1 改了 Blacklist.php/Port.php 没生效

PHP 每次请求重新编译脚本,源码修改本应立即生效。若未生效,排查三点:改的文件路径是否为部署目录(/var/www/html/spftoolbox/operations/)而非解压残留目录;sed 语句是否真的匹配(grep -n 确认关键字已变);浏览器/中间层是否缓存(用 curl -s 直连验证)。

7.2 黑名单查询要一分多钟

正常现象(50 区域串行 + 部分区域无响应等待,实测 1m28s)。缓解:删减 5.2 清单中无响应或误报区域;不要试图调大 max_execution_time(CPU 时间不计 I/O,见 5.5)。

7.3 request=all 只返回一条 HINFO RFC8482

解析器按 RFC 8482 拒绝 ANY 查询的合成响应。All.php 优先走 DNS_ALL(逐类型查询)正常返回全量记录;仅当全类型无记录回退 DNS_ANY 时才会撞上占位响应。需要完整清单改用 a/mx/txt 单项查询。

7.4 黑名单 FAIL 一定是垃圾邮件源吗

不一定。判定逻辑是「反查有 A 记录即 FAIL」,实测 gmail.com 的 Google IP 被 dnsrbl.org 判 FAIL(返回 103.224.182.253,非 127 网段,见 5.2)。处置前先核对该 DNSBL 的返回值编码规范,再人工定性。

7.5 想离线演示/复现查询功能

按 5.6 用 dnsmasq 建本地模拟区域,把 /etc/resolv.conf 指向它即可——A/MX/TXT/DMARC 四类记录实测全链路可复现,验证完恢复原 nameserver。

八、参考链接