Skip to main content

5. Mechanism Definitions (机制定义)

5. Mechanism Definitions (机制定义)

本节定义了两种类型的机制: 基本语言框架机制和指定发件人机制。

基本机制有助于语言框架。它们不指定特定类型的授权方案。基本机制如下:

all
include

指定发件人机制用于将一组 <ip> 地址标识为被允许或不被允许使用 <domain> 发送邮件。指定发件人机制如下:

a
mx
ptr (do not use)
ip4
ip6
exists

以下约定适用于在任何时候执行 <target-name> 和 IP 地址之间比较的所有机制:

如果指令中没有给出 CIDR 前缀长度, 则比较 <target-name> 和 IP 地址的相等性。(这里, CIDR 是无类别域间路由, 在 [RFC4632] 中描述。)

如果指定了 CIDR 前缀长度, 则仅比较 <target-name> 和 IP 地址的指定数量的高位是否相等。

当任何机制获取主机地址以与 <ip> 进行比较时, 当 <ip> 是 IPv4 时, 获取 "A" 记录; 当 <ip> 是 IPv6 地址时, 获取 "AAAA" 记录。IPv6 服务器上的 SPF 实现需要处理 "AAAA" 和 "A" 记录, 以用于 IPv4 映射的 IPv6 地址上的客户端 [RFC4291]。IPv4 地址仅使用 "ip4" 机制列在 SPF 记录中。

几个机制依赖于从 DNS 获取的信息。对于这些 DNS 查询, 除非另有说明, 如果 DNS 服务器返回错误(RCODE 不是 0 或 3)或查询超时, 则机制停止并且最顶层的 check_host() 返回 "temperror"。如果服务器返回 "Name Error"(RCODE 3), 则机制的评估继续进行, 就像服务器返回无错误(RCODE 0)和零应答记录一样。

5.1 "all"

all = "all"

"all" 机制是一个总是匹配的测试。它用作记录中最右边的机制以提供明确的默认值。

例如:

v=spf1 a mx -all

"all" 之后的机制永远不会被测试。"all" 之后列出的机制必须被忽略。当记录中有 "all" 机制时, 任何 "redirect" 修饰符(第 6.1 节)必须被忽略, 无论术语的相对顺序如何。

5.2 "include"

include = "include" ":" domain-spec

"include" 机制触发 check_host() 的递归评估。

  1. <domain-spec> 按照第 7 节扩展。

  2. 使用生成的字符串作为 <domain> 评估 check_host()。<ip><sender> 参数与 check_host() 的当前评估中保持相同。

  3. 递归评估返回匹配, 不匹配, 或错误。

  4. 如果它返回匹配, 则 "include" 机制使用适当的结果(例如, include 或 +include 产生 "pass" 结果, -include 产生 "fail")。

  5. 如果它返回不匹配或错误, 则父 check_host() 按照下表恢复处理, 并恢复之前的 <domain> 值。

事后看来, 名称 "include" 选择得很糟糕。仅使用引用的 SPF 记录的评估结果, 而不是字面上包含第一个记录中引用的记录的机制。例如, 评估引用记录中的 "-all" 指令不会终止总体处理, 也不一定导致总体 "fail"。(这个机制更好的名称应该是 "if-match", "on-match" 等。)

"include" 机制使一个域可以指定多个管理上独立的域。例如, 虚荣域 "example.net" 可能使用管理上独立的域 example.com 和 example.org 的服务器发送邮件。

Example.net 可以说

IN TXT "v=spf1 include:example.com include:example.org -all"

这将指示 check_host() 有效地检查 example.com 和 example.org 的记录以获取 "pass" 结果。只有当主机不被这两个域中的任何一个允许时, 结果才会是 "fail"。

此机制是否匹配, 不匹配, 或返回异常取决于 check_host() 的递归评估的结果:

+---------------------------------+---------------------------------+
| A recursive check_host() result | Causes the "include" mechanism |
| of: | to: |
+---------------------------------+---------------------------------+
| pass | match |
| | |
| fail | not match |
| | |
| softfail | not match |
| | |
| neutral | not match |
| | |
| temperror | return temperror |
| | |
| permerror | return permerror |
| | |
| none | return permerror |
+---------------------------------+---------------------------------+

"include" 机制旨在跨越管理边界。当保持在一个管理机构内时, "include" 通常不是最佳选择。例如, 如果 example.com 和 example.org 由同一实体管理, 并且如果两个域的允许主机集合是 "mx:example.com", 则 example.org 可能指定 "include:example.com", 但最好指定 "redirect=example.com" 或甚至 "mx:example.com"。

使用 "include" 机制, 可以授权管理上外部的一组主机, 但发件人策略的确定仍然是原始域的 SPF 记录的功能(由该记录中的 "all" 机制确定)。"redirect" 修饰符更适合将授权和策略合并到要在 ADMD 内共享的通用集合中。Redirect 更像是要在单个 ADMD 内的记录之间共享的通用代码元素。可以从单个记录控制任意数量的域的授权主机和策略。

5.3 "a"

此机制在 <ip><target-name> 的 IP 地址之一时匹配。为了清楚起见, 这意味着 "a" 机制也匹配 AAAA 记录。

a = "a" [ ":" domain-spec ] [ dual-cidr-length ]

<target-name> 进行地址查询, 使用适合连接类型(IPv4 或 IPv6)的查询类型(A 或 AAAA)。将 <ip> 与返回的地址进行比较。如果任何地址匹配, 则机制匹配。

5.4 "mx"

此机制在 <ip> 是域名的 MX 主机之一时匹配。

mx = "mx" [ ":" domain-spec ] [ dual-cidr-length ]

check_host() 首先对 <target-name> 执行 MX 查询。然后它对返回的每个 MX 名称执行地址查询。将 <ip> 与每个返回的 IP 地址进行比较。为了防止拒绝服务(DoS)攻击, 必须遵循第 4.6.4 节中定义的处理限制。如果超过 MX 查询限制, 则返回 "permerror" 并终止评估。如果任何地址匹配, 则机制匹配。

关于隐式 MX 的注意事项: 如果 <target-name> 没有 MX 记录, 则 check_host() 绝对不能应用 [RFC5321] 的隐式 MX 规则, 即为相同名称查询 A 或 AAAA 记录。

5.5 "ptr" (do not use) ("ptr" (不使用))

此机制测试 <ip> 的 DNS 反向映射是否存在并正确指向特定域内的域名。此机制不应该被发布。有关更多信息, 请参见本节末尾的注释。

ptr = "ptr" [ ":" domain-spec ]

使用以下过程查找 <ip> 的名称:

  • <ip> 执行 DNS 反向映射: 如果地址是 IPv4 地址, 则在 "in-addr.arpa." 中查找相应的 PTR 记录, 如果是 IPv6 地址, 则在 "ip6.arpa." 中查找。

  • 对于返回的每个记录, 通过查找其 IP 地址来验证域名。为了防止 DoS 攻击, 必须应用第 4.6.4 节中定义的 PTR 处理限制。如果超过限制, 则终止处理, 并且机制不匹配。

  • 如果 <ip> 在返回的 IP 地址中, 则该域名被验证。

检查所有验证的域名以查看它们是否匹配 <target-name> 或是 <target-name> 的子域。如果有任何匹配, 则此机制匹配。如果找不到验证的域名, 或者没有验证的域名匹配或是 <target-name> 的子域, 则此机制无法匹配。如果在执行 PTR RR 查询时发生 DNS 错误, 则此机制无法匹配。如果在执行 A RR 查询时发生 DNS 错误, 则跳过该域名并继续搜索。

此机制在以下情况下匹配:

  • <target-name> 是验证域名的子域, 或

  • <target-name> 和验证域名相同。

例如, "mail.example.com" 在域 "example.com" 内, 但 "mail.bad-example.com" 不在。

注意: 此机制速度慢, 在 DNS 错误的情况下不如其他机制可靠, 并且对 .arpa 名称服务器造成很大负担。如果使用, 必须为域的主机设置适当的 PTR 记录, 并且 "ptr" 机制应该是最后检查的机制之一。经过多年的 SPF 部署经验, 已经得出结论认为它是不必要的, 应该使用更可靠的替代方案。然而, 它仍然作为 SPF 协议的一部分使用, 因此符合标准的 check_host() 实现必须支持它。

5.6 "ip4" and "ip6" ("ip4" 和 "ip6")

这些机制测试 <ip> 是否包含在给定的 IP 网络中。

ip4 = "ip4" ":" ip4-network [ ip4-cidr-length ]
ip6 = "ip6" ":" ip6-network [ ip6-cidr-length ]

ip4-cidr-length = "/" ("0" / %x31-39 0*1DIGIT) ; value range 0-32
ip6-cidr-length = "/" ("0" / %x31-39 0*2DIGIT) ; value range 0-128
dual-cidr-length = [ ip4-cidr-length ] [ "/" ip6-cidr-length ]

ip4-network = qnum "." qnum "." qnum "." qnum
qnum = DIGIT ; 0-9
/ %x31-39 DIGIT ; 10-99
/ "1" 2DIGIT ; 100-199
/ "2" %x30-34 DIGIT ; 200-249
/ "25" %x30-35 ; 250-255
; as per conventional dotted-quad notation, e.g., 192.0.2.0

ip6-network = <as per [RFC5952], Section 4>
; e.g., 2001:db8::cd30

<ip> 与给定网络进行比较。如果 CIDR 前缀长度的高位匹配, 则机制匹配。

如果省略 ip4-cidr-length, 则将其视为 "/32"。如果省略 ip6-cidr-length, 则将其视为 "/128"。不允许省略 IP 地址的部分而使用 CIDR 表示法。也就是说, 使用 192.0.2.0/24 而不是 192.0.2。

5.7 "exists"

此机制用于构造用于 DNS A 记录查询的任意域名。它允许涉及邮件信封的任意部分的复杂方案来确定允许的内容。

exists = "exists" ":" domain-spec

<domain-spec> 按照第 7 节扩展。生成的域名用于 DNS A RR 查询(即使连接类型是 IPv6)。如果返回任何 A 记录, 则此机制匹配。

域可以使用此机制来指定任意复杂的查询。例如, 假设 example.com 发布记录:

v=spf1 exists:%{ir}.%{l1r+-}._spf.%{d} -all

<target-name> 可能扩展为 "1.2.0.192.someuser._spf.example.com"。这使得可以在用户和客户端 IP 地址级别做出细粒度的决策。