Go 解析 SPF 记录

背景知识:什么是 SPF?

SPF(Sender Policy Framework,发送方策略框架)是一种电子邮件验证协议,定义在 https://datatracker.ietf.org/doc/html/rfc7208 中。它的核心作用是让域名所有者声明:哪些 IP 地址或服务器被允许代表该域名发送邮件

接收方邮件服务器收到邮件后,会查询发件人域名的 SPF 记录(一条 DNS TXT 记录),检查连接 IP 是否在授权列表中。这能有效防止邮件伪造和钓鱼攻击。

一条典型的 SPF 记录长这样:

v=spf1 ip4:192.0.2.0/24 include:_spf.google.com ~all

Golang 解析

注意:这个库只有 12 次提交,已经 2 年多没有更新,肯定不完备,但是放在小工具中简单使用也没有什么问题。
UPDATE: 这个库太简陋了,不如自己写一个。

mileusna/spf 是一个轻量级的 Go 语言 SPF 检查库,提供了两个核心接口:

功能 函数 说明
SPF 校验 spf.CheckHost() 给定 IP、域名和发件人,返回完整的 SPF 判定结果
记录查询 spf.LookupSPF() 仅从 DNS 拉取原始 SPF TXT 字符串
package main

import (
    "net"

    "github.com/mileusna/spf"
)

func main() {
    // optional, set DNS server which will be used by resolver.
    // Default is Google's 8.8.8.8:53
    spf.DNSServer = "1.1.1.1:53"

    ip := net.ParseIP("123.123.123.123")
    r := spf.CheckHost(ip, "qq.com", "service@qq.com", "");
    // returns spf check result
    // "PASS" / "FAIL" / "SOFTFAIL" / "NEUTRAL" / "NONE" / "TEMPERROR" / "PERMERROR"

    // if you only need to retrive SPF record as string from DNS
    spfRecord, _ := spf.LookupSPF("qq.com")
    fmt.Println(spfRecord)
    // v=spf1 include:spf.mail.qq.com -all
}

spf.CheckHost() 返回以下 7 种字符串结果之一:

返回值 含义 邮件处理建议
"PASS" IP 被明确授权 正常接收
"FAIL" IP 不在授权列表中(-all-ip4 匹配失败) 建议拒收
"SOFTFAIL" 软失败(~all),IP 可能未授权但无法确定 接受但标记/放入垃圾箱
"NEUTRAL" 策略判定为中立(?all 按常规流程处理
"NONE" 域名无 SPF 记录或记录无法解析 建议拒收
"TEMPERROR" DNS 临时错误(超时、SERVFAIL 等) 可能是 DNS 抖动,稍后重试,暂不拒收
"PERMERROR" SPF 记录存在永久错误(语法错误、多重记录等) 配置异常,建议拒收
如果你有魔法,你可以看到一个评论框~