简介
本文档描述了 Postfix 3.6 及更高版本中可用的新功能。有关 Postfix 2.8 至 3.5 版本的信息,请参阅 POSTSCREEN_3_5_README.html。
Postfix 的 postscreen(8) 守护进程提供了额外的保护,防止邮件服务器过载。一个 postscreen(8) 进程处理多个传入的 SMTP 连接,并决定哪些客户端可以与 Postfix SMTP 服务器进程通信。通过阻止垃圾邮件机器人,postscreen(8) 为合法客户端保留更多 SMTP 服务器进程,并延迟 服务器过载 条件触发。
postscreen(8) 不应用于接收来自最终用户客户端(MUAs)邮件的 SMTP 端口。在典型部署中,postscreen(8) 处理 TCP 端口 25 上的 MX 服务,而 MUA 客户端通过 TCP 端口 587 上的提交服务发送邮件,该服务需要客户端认证。Alternatively, a site could set up a dedicated, non-postscreen, "port 25" server that provides submission service and client authentication, but no MX service.
postscreen(8) 维护一个临时允许列表,用于通过其测试的客户端;通过允许列表中的客户端跳过测试,postscreen(8) 最大限度地减少对合法邮件流的影响。
postscreen(8) 是多层防御体系的一部分。
- 作为第一层,postscreen(8) 阻止来自僵尸网络和其他垃圾邮件机器人(约占所有垃圾邮件的 90%)的连接。它以单进程形式实现,以尽可能降低防御成本。
- 第二层通过Postfix SMTP服务器、策略守护进程,以及Milter应用程序。
- 第三层使用 Postfix 内置的 header_checks 和 body_checks 进行轻量级内容检查。这可以阻止不可接受的附件,如可执行程序,以及具有易于识别的签名的蠕虫或病毒。
- 第四层通过外部内容过滤器提供高级内容检测。典型示例包括 Amavisd-new、SpamAssassin 和 Milter 应用程序。
每层都会减少垃圾邮件的数量。一般策略是先使用成本较低的防御措施,仅对剩余的垃圾邮件使用成本较高的防御措施。
本文件中的主题:
- 简介
- postscreen(8) 的基本原理
- 一般操作
- 在进行其他操作前的快速测试
- 220 SMTP 服务器问候语前的测试
- 220 SMTP 服务器问候语后的测试
- 其他错误
- 当所有测试成功时
- 配置 postscreen(8) 服务
- 历史注释和致谢
postscreen(8) 的基本原理
大多数电子邮件是垃圾邮件,而大多数垃圾邮件是由僵尸程序(受感染终端用户计算机上的恶意软件)发送的。Wietse预计,僵尸程序问题在情况好转之前会进一步恶化,甚至可能永远不会好转。如果没有像postscreen(8)这样的工具来阻止僵尸程序,Postfix将不得不消耗大部分资源来处理垃圾邮件,而非正常接收邮件。
postscreen(8) 的主要挑战是基于单一指标判断一个进程是否为僵尸程序。这是必要的,因为许多僵尸进程试图躲避检测并避免反复向同一网站发送垃圾邮件。一旦postscreen(8)确定某个客户端不是僵尸进程,它会暂时将其加入白名单,以避免合法邮件的进一步延迟。
僵尸也有挑战:它们在 IP 地址被列入黑名单前只有有限的时间来发送垃圾邮件。为了加快垃圾邮件发送速度,僵尸会在 SMTP 协议实现中做出妥协。例如,它们会在轮到自己之前发送数据,或忽略 SMTP 服务器的响应并继续发送命令,即使服务器已指示其停止发送。
postscreen(8) 通过多种测量方法识别僵尸。首先,postscreen(8) 判断远程 SMTP 客户端 IP 地址是否被列入黑名单。其次,postscreen(8) 会查找为加快投递而做出的协议妥协。这些是基于单一测量值判断是否为僵尸进程的良好指标。
postscreen(8) 不检查消息内容。消息内容可能因交付而异,尤其是在同时发送合法邮件的客户端情况下。内容并非基于单次测量判断是否为僵尸邮件的良好指标,而这就是postscreen(8)专注解决的问题。
一般操作
对于来自 SMTP 客户端的每个连接,postscreen(8) 会按以下顺序执行一系列测试。部分测试会引入几秒钟的延迟。postscreen(8) 维护一个临时允许列表,用于存储通过其测试的客户端;通过允许允许列表中的客户端跳过测试,postscreen(8) 最大限度地减少了对合法电子邮件流量的影响。
默认情况下,postscreen(8) 会将所有连接转发给 Postfix SMTP 服务器进程,并在记录检测结果后完成处理。此模式适用于非破坏性测试。
在典型的生产环境中,postscreen(8) 配置为在记录 HELO、发件人和收件人信息后,拒绝来自通过一项或多项测试的客户端的邮件。
注意:postscreen(8) 不是 SMTP 代理;这是有意为之。其目的是在不增加合法客户端开销的情况下,防止僵尸进程影响 Postfix。
在进行其他操作前进行快速测试
在进行 SMTP 级测试之前,postscreen(8) 会查询多个本地拒绝列表和允许列表。这些测试可加快已知客户端的处理速度。
永久允许/拒绝列表测试
postscreen_access_list 参数(默认值: permit_mynetworks)指定了 SMTP 客户端 IP 地址的永久访问列表。通常会先指定允许本地网络的规则, followed by a CIDR 表用于选择性允许或拒绝访问。
示例:
/etc/postfix/main.cf: postscreen_access_list = permit_mynetworks, cidr:/etc/postfix/postscreen_access.cidr /etc/postfix/postscreen_access.cidr: # 规则按指定顺序进行评估。 # 拒绝列表:192.168.*,除 192.168.0.1 外。 192.168.0.1 允许 192.168.0.0/16 拒绝
请参阅 postscreen_access_list 手册页文档以获取更多详细信息。
当 SMTP 客户端地址与"允许"操作匹配时,postscreen(8) 会以客户端地址和端口号的形式记录此信息:
ALLOWLISTED [地址]:端口
使用 respectful_logging 配置参数选择此日志记录的过时形式。
允许列表操作不可配置:立即将连接转发给 Postfix SMTP 服务器进程。
当 SMTP 客户端地址与"拒绝"操作匹配时,postscreen(8) 会以客户端地址和端口号的形式记录此信息:
DENYLISTED [地址]:端口
使用 respectful_logging 配置参数选择此日志记录的过时形式。
postscreen_denylist_action 参数指定接下来要执行的操作。请参阅下文的"当测试在 220 SMTP 服务器问候语之前失败时"。
临时允许列表测试
postscreen(8) 守护进程维护一个 临时 允许列表,用于存储通过以下所有测试的 SMTP 客户端 IP 地址。postscreen_cache_map 参数指定临时允许列表的位置。临时允许列表不适用于出现在 永久 访问列表中的 SMTP 客户端地址。
默认情况下,临时允许列表不会与其他 postscreen(8) 守护进程共享。请参阅下文的 共享临时允许列表 以获取替代方案。
当 SMTP 客户端地址出现在临时允许列表中时,postscreen(8) 会以以下格式记录该地址及端口号:
PASS OLD [地址]:端口
操作不可配置:立即将连接转发给 Postfix SMTP 服务器进程。客户端将被排除在进一步测试之外,直至其临时允许列表条目过期,具体由 postscreen_*_ttl 参数控制。过期条目在可能的情况下会静默续期。
MX 策略测试
当远程 SMTP 客户端不在静态访问列表或临时允许列表中时,postscreen(8) 可在授予客户端临时允许列表状态(允许其与 Postfix SMTP 服务器进程通信)之前,实施一系列允许列表测试。
当postscreen(8)配置为监控所有主MX地址和备用MX地址时,它可以拒绝将仅连接到备用MX地址的客户端加入允许列表(这是旧式垃圾邮件发送者利用备用MX主机比主MX主机反垃圾邮件策略更弱的漏洞的常见技巧)。
注意:以下解决方案适用于小型站点。大型站点需要在主和备用 MTA 之间共享 postscreen(8) 缓存,这会引入单点故障。
首先,配置主机监听主和备用 MX 地址。使用本地操作系统的相应 ifconfig 或 ip 命令,或更新相应配置文件并"刷新"网络协议栈。
其次,配置 Postfix 监听新 IP 地址(此步骤在 inet_interfaces 在 main.cf 中指定时需要执行)。
然后,配置 postscreen(8) 以拒绝备份 MX 地址的临时允许列表状态。Wietse 服务器的示例为:
/etc/postfix/main.cf: postscreen_allowlist_interfaces = ! 168.100.189.8 static:all
翻译:允许客户端在所有服务器 IP 地址上获取临时允许列表状态,但 168.100.189.8(备用 MX 地址)除外。
当未列入允许列表的客户端连接到备用 MX 地址时,postscreen(8) 会以客户端地址和端口号的形式记录此事件:
CONNECT from [地址]:端口 to [168.100.189.8]:25 ALLOWLIST VETO [地址]:端口
使用 respectful_logging 配置参数选择此日志记录的过时形式。
翻译:客户端在 [地址]:端口 连接到备用 MX 地址 168.100.189.8 时未被列入允许列表。即使该客户端通过了下面描述的所有允许列表测试,也不会被授予临时允许列表状态。
220 SMTP 服务器问候前的测试
postscreen_greet_wait 参数指定在 "220 text..." 服务器问候语之前的一个短时间间隔,在此期间 postscreen(8) 可以并行运行多个测试。
当客户端通过这些测试且未配置 "深度协议测试" 时,postscreen(8) 将客户端添加到临时允许列表,并将 "实时" 连接转交至 Postfix SMTP 服务器进程。客户端随后可继续运行,仿佛postscreen(8)从未存在过(当然除了短暂的postscreen_greet_wait延迟)。
预问候测试
SMTP 协议是一个典型的协议示例,其中服务器在客户端之前发送消息。postscreen(8) 检测那些急于发送消息的僵尸进程。此测试默认启用。
postscreen_greet_banner 参数指定 "220-文本..." 提示信息中的 文本 部分(默认值: $smtpd_banner)。请注意,这将成为多行服务器问候语的第一部分。postscreen(8) 守护进程会在 postscreen_greet_wait 定时器启动前发送此内容。该提示横幅的目的是迷惑僵尸用户,使其在轮到自己之前发言。它对正确实现协议的 SMTP 客户端没有影响。
为避免网络设备或网络测试工具中实现不佳的 SMTP 引擎引发问题,可通过以下方式处理:使用 postscreen_access_list 功能将它们排除在所有测试之外,或设置一个空的提示横幅:
/etc/postfix/main.cf: # 通过白名单排除故障客户端。mynetworks # 中的客户端应始终被允许。 postscreen_access_list = permit_mynetworks, cidr:/etc/postfix/postscreen_access.cidr /etc/postfix/postscreen_access.cidr: 192.168.254.0/24 允许
/etc/postfix/main.cf: # 禁用提示横幅(建议先尝试使用白名单)。 postscreen_greet_banner =
当 SMTP 客户端在 postscreen_greet_wait 时间未到之前发送命令时,postscreen(8) 会将此记录为:
PREGREET count after time from [地址]:端口 文本...
翻译:客户端在 [地址]:端口 发送了 计数 字节,但在其轮到发言前被中断。此事件发生在 时间 秒后,即 postscreen_greet_wait 定时器启动后。文本是客户端发送的内容(截断为 100 字节,并用 C 风格转义序列替换不可打印字符,如 \r 表示换行符,\n 表示换行)。
postscreen_greet_action 参数指定接下来要执行的操作。请参阅下文的"当在 220 SMTP 服务器问候前测试失败时"。
DNS 允许/拒绝列表测试
postscreen_dnsbl_sites 参数(默认值为空)指定了一组 DNS 阻止列表服务器,可选的过滤器和权重因子(正权重用于阻止列表,负权重用于允许列表)。这些服务器将与反向客户端 IP 地址并行查询。此测试默认禁用。
注意:当 postscreen 拒绝邮件时,其 SMTP 回复中包含 DNSBL 域名。使用 postscreen_dnsbl_reply_map 功能来隐藏 DNSBL 域名中的"密码"信息。
当 postscreen_greet_wait 时间已过,且 DNSBL 评分总和等于或大于 postscreen_dnsbl_threshold 参数值时,postscreen(8) 会记录如下:
DNSBL 排名 计数 针对 [地址]:端口
翻译:SMTP 客户端在 [地址]:端口 上的 DNSBL 总评分为 计数。
postscreen_dnsbl_action 参数指定当综合 DNSBL 评分等于或大于阈值时执行的操作。参见下文的"当测试在 220 SMTP 服务器问候语前失败时"。
当测试在 220 SMTP 服务器问候前失败时
当客户端地址与永久拒绝列表匹配,或客户端在预问候或 DNSBL 测试中失败时,操作由 postscreen_denylist_action,postscreen_greet_action 或 postscreen_dnsbl_action,分别对应相应操作。
忽略(默认)
忽略此测试的失败。允许其他测试继续执行。当客户端下次连接时重复此测试。此选项适用于测试和收集统计信息而不阻塞邮件。
强制执行
允许其他测试完成。拒绝发送邮件并返回 550 SMTP 响应,同时记录 HELO/发件人/收件人信息。下次客户端连接时重复此测试。
drop
立即断开连接并返回 521 SMTP 响应。在客户端下次连接时重复此测试。
220 SMTP 服务器问候后的测试
在此协议阶段,postscreen(8) 实现了一系列"深度协议"测试。这些测试使用内置于 postscreen(8) 服务器中的 SMTP 协议引擎。
重要说明:这些协议测试默认处于禁用状态。它们比 pregreet 和 DNSBL 测试更具侵入性,并且存在如下讨论的限制。
- "220 之后的问候"测试的主要限制是,新客户端在通过这些测试后必须断开连接(原因:postscreen 不是代理)。然后客户端必须从同一 IP 地址重新连接才能发送邮件。以下措施可帮助避免邮件延迟:
- 允许"良好"客户端跳过测试,使用postscreen_dnsbl_allowlist_threshold功能。这对于通常不会从同一IP地址重试的大型提供商特别有效。
- 小型站点:配置 postscreen(8) 以监听多个 IP 地址,并在 DNS 中将这些地址作为同一 MX 主机名的不同 IP 地址或不同 MX 主机名的 IP 地址进行发布。这可避免来自同一 IP 地址立即重新连接的客户端出现邮件投递延迟。
- 大型站点:通过足够大的 memcache_table(5),在不同 Postfix MTA 之间共享 postscreen(8) 缓存。同样,这避免了从同一 IP 地址立即重新连接的客户端出现邮件投递延迟。
- postscreen(8) 的内置 SMTP 引擎不支持 AUTH、XCLIENT 和 XFORWARD 功能。如果您需要在端口 25 上提供这些服务,则不要在 220 服务器问候语后启用这些测试。
- 最终用户客户端应直接连接到提交服务,以免它们需要处理 postscreen(8) 的测试。
以下"220 问候语后"测试可用:
命令管道测试
默认情况下,SMTP 是一种半双工协议:发送方和接收方一次只发送一个命令和一个响应。与 Postfix SMTP 服务器不同,postscreen(8) 不支持 ESMTP 命令管道化。因此,客户端不允许发送多个命令。postscreen(8) 的 深度协议测试 默认处于禁用状态。
通过设置 "postscreen_pipelining_enable = yes",postscreen(8) 会检测发送多个命令的僵尸进程,而非发送一个命令后等待服务器响应。
此测试会在 postscreen(8) 必须使用内置 SMTP 引擎时自动启用。此举旨在使 postscreen(8) 的日志记录更具信息量。
当客户端发送多个命令时,postscreen(8) 会记录为:
命令管道传输来自 [地址]:端口 在 命令: 文本
翻译:SMTP 客户端在 [地址]:端口 发送了多个 SMTP 命令,而不是发送一个命令后等待服务器响应。这发生在客户端发送 命令 之后。文本 显示了过早发送的部分输入;在 Postfix 2.8 中未记录此内容。
postscreen_pipelining_action 参数指定接下来要执行的操作。请参阅下文的"当在 220 SMTP 服务器问候后测试失败时"。
非 SMTP 命令测试
部分垃圾邮件机器人通过开放代理发送邮件。此类行为的特征是使用 CONNECT 等非 SMTP 命令。与 Postfix SMTP 服务器的 smtpd_forbidden_commands 功能类似,postscreen(8) 提供了等效的 postscreen_forbidden_commands 功能,用于阻止这些客户端。postscreen(8) 的 深度协议测试 默认处于禁用状态。
通过设置 "postscreen_non_smtp_command_enable = yes",postscreen(8) 会检测发送了由 postscreen_forbidden_commands 参数指定的命令的僵尸进程。这也会检测具有消息头标签语法的命令。后者是客户端在忽略所有来自 postscreen(8) 的拒绝邮件响应后,仍发送消息内容的症状。
此测试会在 postscreen(8) 必须使用内置 SMTP 引擎时自动启用。此举旨在使 postscreen(8) 的日志记录更具信息量。
当客户端发送非 SMTP 命令时,postscreen(8) 会记录为:
非 SMTP 命令来自 [地址]:端口 在 命令后:文本
翻译:SMTP 客户端在 [地址]:端口 发送了一个与 postscreen_forbidden_commands 参数匹配的命令,或具有消息头标签语法(文本后跟可选空格和 ":")。"after command"部分在 Postfix 2.10 及更高版本中会被记录。
postscreen_non_smtp_command_action 参数指定接下来要执行的操作。参见下文的"当 SMTP 服务器响应 220 后测试失败时"。
空行测试
SMTP 是一种基于行的协议:行长度有限,并以 <CR><LF> 结束。以"裸" <LF>(即未被换行符前置的换行符)结尾的行在 SMTP 中不被允许。postscreen(8) 的 深度协议测试 默认处于禁用状态。
通过设置 "postscreen_bare_newline_enable = yes",postscreen(8) 将检测发送以裸换行符结尾的行。
此测试会在 postscreen(8) 必须使用内置 SMTP 引擎时自动启用。此举旨在使 postscreen(8) 的日志记录更加详细。
当客户端发送裸换行符时,postscreen(8) 会记录为:
裸换行符来自 [地址]:端口 在 命令后
翻译:SMTP 客户端在 [地址]:端口 发送了一个裸换行字符,即未被换行符(carriage return)前置的换行符。 "after 命令" 部分在 Postfix 2.10 及更高版本中被记录。
postscreen_bare_newline_action 参数指定接下来要执行的操作。请参阅下文的 "当测试在 220 SMTP 服务器问候后失败时"。
当测试在 220 SMTP 服务器问候后失败时
当客户端在管道传输、非 SMTP 命令或空行测试中失败时,操作由 postscreen_pipelining_action,postscreen_non_smtp_command_action 或 postscreen_bare_newline_action,分别对应上述情况。
忽略(默认值为空行)
忽略此测试的失败。允许其他测试继续执行。在其他测试结果过期前,不要重复执行此测试。此选项适用于测试和收集统计信息,而不会永久阻塞邮件。
强制执行(默认用于管道传输)
允许其他测试继续执行。拒绝使用 550 SMTP 响应尝试发送邮件,并记录 HELO/发件人/收件人信息。当客户端下次连接时重复此测试。
drop(非 SMTP 命令的默认值)
立即断开连接并返回 521 SMTP 响应。当客户端下次连接时重复此测试。此操作与 Postfix SMTP 服务器的 smtpd_forbidden_commands 功能兼容。
其他错误
当 SMTP 客户端意外挂断时,postscreen(8) 会记录为:
HANGUP after time from [地址]:端口 in 测试名称
翻译:SMTP 客户端在 [地址]:端口 意外断开连接,在名为 测试名称 的测试开始后 时间 秒。
挂断不会受到惩罚。未发送 QUIT 命令就挂断的客户端仍可通过所有 postscreen(8) 测试。
以下错误由内置 SMTP 引擎报告。该引擎从不接受邮件,因此对每个会话的命令数量和会话时长设有限制。
命令时间限制 来自 [地址]:端口 在 命令 之后
翻译:SMTP 客户端在 [地址]:端口 达到由 postscreen_command_time_limit 参数指定的每命令时间限制。会话立即终止。"after command"部分在 Postfix 2.10 及更高版本中会被记录。
COMMAND COUNT LIMIT from [地址]:端口 after command
翻译:SMTP 客户端在 [地址]:端口 达到由 postscreen_command_count_limit 参数指定的每会话命令计数限制。会话立即终止。"after command"部分在 Postfix 2.10 及更高版本中会被记录。
COMMAND LENGTH LIMIT from [地址]:端口 after command
翻译:SMTP 客户端在 [地址]:端口 达到每命令长度限制,该限制由 line_length_limit 参数指定。会话立即终止。"after command"部分在 Postfix 2.10 及更高版本中会被记录。
当 SMTP 客户端同时建立过多连接时,postscreen(8) 将以 421 状态码拒绝连接并记录日志:
NOQUEUE: 拒绝: CONNECT from [地址]:端口: 连接过多
postscreen_client_connection_count_limit 参数控制此限制。
当 SMTP 客户端在 postscreen(8) 达到连接数限制后连接,postscreen(8) 将以 421 状态码拒绝连接并记录日志:
NOQUEUE: 拒绝:CONNECT 来自 [地址]:端口: 所有筛选端口繁忙 NOQUEUE: 拒绝:CONNECT 来自 [地址]:端口: 所有服务器端口繁忙
postscreen_pre_queue_limit 和 postscreen_post_queue_limit 参数控制这些限制。
当所有测试通过时
当一个新的 SMTP 客户端通过所有测试(即未通过某种机制被允许列表)时,postscreen(8) 会记录为:
PASS NEW [地址]:端口
其中 [地址]:端口 表示客户端的 IP 地址和端口。随后,postscreen(8) 会创建一个临时允许列表条目,将客户端 IP 地址从后续测试中排除,直至该临时允许列表条目过期,具体过期时间由 postscreen_*_ttl 参数控制。
当未配置 "深度协议测试" 时,postscreen(8) 将 "实时" 连接转交给 Postfix SMTP 服务器进程。客户端随后可继续运行,仿佛postscreen(8)从未存在过(除短暂的postscreen_greet_wait延迟外)。
当配置了任何"深度协议测试"时,postscreen(8) 无法在会话过程中将"活跃"连接交由 Postfix SMTP 服务器进程处理。相反,postscreen(8) 会以 4XX 状态码推迟邮件投递尝试,记录 HELO/发件人/收件人信息,并等待客户端断开连接。下次客户端连接时,将允许其与 Postfix SMTP 服务器进程通信以投递邮件。postscreen(8) 通过为 深度协议测试 设置较长的过期时间,减轻了此限制的影响。
配置 postscreen(8) 服务
postscreen(8) 已在 FreeBSD [4-8]、Linux 2.[4-6] 和 Solaris 9 系统上进行过测试。
启用 postscreen(8) 而不阻塞邮件
要启用 postscreen(8) 服务并记录客户端信息而不阻塞邮件:
确保本地客户端和使用非标准 SMTP 实现的系统被排除在任何 postscreen(8) 测试之外。默认情况下,所有在 mynetworks 中列出的客户端都会被排除。要排除其他客户端(例如第三方性能监控工具,这些工具通常具有损坏的 SMTP 实现):
/etc/postfix/main.cf: # 通过白名单排除有问题的客户端。mynetworks # 中的客户端应始终被允许。 postscreen_access_list = permit_mynetworks, cidr:/etc/postfix/postscreen_access.cidr /etc/postfix/postscreen_access.cidr: 192.168.254.0/24 允许
在master.cf中注释掉"smtp inet ... smtpd"服务,包括其后所有"-o parameter=value"条目。
/etc/postfix/master.cf: #smtp inet n - n - - smtpd # -o parameter=value ...
取消注释master.cf中的新"smtpd pass ... smtpd"服务,并将上一步中注释掉的smtpd服务中的任何"-o parameter=value"条目复制到此处。
/etc/postfix/master.cf: smtpd pass - - n - - smtpd -o parameter=value ...
取消注释master.cf中的新"smtp inet ... postscreen"服务。
/etc/postfix/master.cf: smtp inet n - n - 1 postscreen
取消注释新的 "tlsproxy unix ... tlsproxy" 服务在 master.cf 中。此服务为 postscreen(8) 实现 STARTTLS 支持。
/etc/postfix/master.cf: tlsproxy unix - - n - 0 tlsproxy
在 master.cf 中取消注释新的 "dnsblog unix ... dnsblog" 服务。该服务为 postscreen(8) 进行 DNSBL 查询并记录结果。
/etc/postfix/master.cf: dnsblog unix - - n - 0 dnsblog
要启用 DNSBL 查询,请在 main.cf 中列出一些 DNS 阻止列表网站,用空格分隔。不同网站可以有不同的权重。例如:
/etc/postfix/main.cf: postscreen_dnsbl_threshold = 2 postscreen_dnsbl_sites = zen.spamhaus.org*2 bl.spamcop.net*1 b.barracudacentral.org*1
注意:如果您的 DNSBL 查询中包含域名中的"秘密"信息,您必须在 postscreen(8) SMTP 响应中屏蔽此信息。例如:
/etc/postfix/main.cf: postscreen_dnsbl_reply_map = texthash:/etc/postfix/dnsbl_reply
/etc/postfix/dnsbl_reply: # 秘密 DNSBL 名称 在 postscreen(8) 响应中的名称 secret.zen.dq.spamhaus.net zen.spamhaus.org
texthash: 格式与 hash: 格式类似于,但无需在使用文件前运行postmap(1),且不会检测文件读取后的更改。该格式自Postfix 2.8版本起新增。
- 使用 "postfix reload" 重新加载新配置。
注意事项:
- 部分 postscreen(8) 配置参数实现了压力依赖行为。此功能仅在默认值为压力依赖型时受支持(即 "postconf -d parametername" 输出显示 "parametername = ${stress?something} ${stress:something}" 或 "parametername = ${stress?{something}:{something}}")。其他参数始终被视为压力值为空字符串。
- 请参阅"220 SMTP 服务器问候语之前的测试"以获取有关这些 postscreen(8) 测试的日志详细信息。
- 如果您使用 Postfix 2.6 或更早版本,必须停止并重新启动主守护进程("postfix stop; postfix start")。这是因为 Postfix 的 "pass" 主服务类型在所有系统上均无法可靠工作。
postscreen(8) TLS 配置
postscreen(8) TLS 支持适用于未列入白名单的远程 SMTP 客户端,包括需要刷新临时白名单状态的客户端。当远程 SMTP 客户端请求 TLS 服务时,postscreen(8) 会将连接无缝地转交给 tlsproxy(8) 进程。然后,tlsproxy(8) 对postscreen(8) 与远程 SMTP 客户端之间的流量进行加密和解密。一个 tlsproxy(8) 进程可以处理多个 SMTP 会话。tlsproxy(8) 进程的数量会随着服务器负载缓慢增加,但应始终远小于 postscreen(8) TLS 会话的数量。
TLS 支持用于 postscreen(8) 和 tlsproxy(8) 使用与 smtpd(8) 相同的参数。我们建议您将相关配置参数保存在 main.cf 中。如果您必须在 master.cf 中为受 postscreen 保护的 smtpd(8) 服务,则应为 postscreen(8) 和 tlsproxy(8) 服务指定相同的参数覆盖设置。
使用 postscreen(8) 阻止邮件
为了与 smtpd(8) 兼容,postscreen(8) 实现了 soft_bounce 安全功能。这会导致 Postfix 拒绝带有"请重试"响应代码的邮件。
- 要为整个 Postfix 启用此功能,请在 main.cf 中。
要仅对 postscreen(8) 启用此功能,请在 postscreen.8.html 的 postscreen 条目中添加 "-o soft_bounce=yes"(注意:'='两侧不要有空格)到 master.cf 中的 postscreen 条目。
执行 "postfix reload" 以使更改生效。
测试完成后,请务必删除soft_bounce功能,否则发件人将无法在数天后收到未送达通知。
要使用postscreen(8)服务来阻止邮件,请编辑main.cf并指定以下一项或多项:
- "postscreen_dnsbl_action = enforce", 以拒绝处于 DNS 阻止列表中的客户端,并记录 HELO/发件人/收件人信息。使用良好的 DNSBL,这将显著减少 Postfix SMTP 服务器的负载。
- "postscreen_greet_action = enforce", 以拒绝在轮到自己之前发送请求的客户端,并记录 HELO/发件人/收件人信息。这阻止了超过一半已知非法连接到 Wietse 的邮件服务器。这是针对尚未被列入黑名单的僵尸客户端的备份保护。
您还可以启用 "深度协议测试",但这些测试比 pregreet 或 DNSBL 测试更侵入性。
当一个合法客户端通过"深度协议测试"时,postscreen(8)会将该客户端添加到临时允许列表中,但无法在会话过程中将"活跃"连接转交至Postfix SMTP服务器进程。相反,postscreen(8) 会以 4XX 状态码推迟邮件投递尝试,记录 HELO/发件人/收件人信息,并等待客户端断开连接。
当良好客户端在后续会话中返回时,它被允许直接与 Postfix SMTP 服务器通信。有关 AUTH 及其他客户端可能需要的特性限制,请参阅上文的 "220 SMTP 服务器问候后的测试"。
"深度协议测试"的意外好处是,部分"良好"客户端在收到 4XX 响应后不会返回;这些客户端实际上并不算"良好"。
遗憾的是,部分发送者会从不同 IP 地址重新发送请求,可能永远无法被加入白名单。因此,Wietse 在其面向互联网的邮件服务器上停止使用 "深度协议测试"。
- 还支持永久拒绝列表和允许列表;请参阅postscreen_access_list参数的描述以获取详细信息。
关闭 postscreen(8)
要关闭 postscreen(8) 并直接通过 Postfix SMTP 服务器处理邮件:
在 master.cf 中注释掉 "smtp inet ... postscreen" 服务,包括其后所有 "-o parameter=value" 条目。
/etc/postfix/master.cf: #smtp inet n - n - 1 postscreen # -o parameter=value ...
注释掉 master.cf 中的 "dnsblog unix ... dnsblog" 服务。
/etc/postfix/master.cf: #dnsblog unix - - n - 0 dnsblog
注释掉 master.cf 文件中的 "smtpd pass ... smtpd" 服务,包括其后所有 "-o parameter=value" 参数。
/etc/postfix/master.cf: #smtpd pass - - n - - smtpd # -o parameter=value ...
注释掉master.cf中的"tlsproxy unix ... tlsproxy"服务,包括其后任何"-o 参数=值"条目。
/etc/postfix/master.cf: #tlsproxy unix - - n - 0 tlsproxy # -o parameter=value ...
取消注释master.cf中的"smtp inet ... smtpd"服务,包括其后可能出现的任何"-o 参数=值"条目。
/etc/postfix/master.cf: smtp inet n - n - - smtpd -o parameter=value ...
- 使用 "postfix reload" 重新加载新配置。
共享临时允许列表
默认情况下,临时允许列表不会在多个 postscreen(8) 守护进程之间共享。要启用共享,请选择以下选项之一:
非持久化 memcache:临时允许列表可在同一主机或不同主机上的 postscreen(8) 守护进程之间共享。禁用缓存清理(postscreen_cache_cleanup_interval = 0)在所有postscreen(8) 守护进程,因为 memcache 没有 first-next API(但请参见下文示例 4 中带持久备份的 memcache 配置)。这需要 Postfix 2.9 或更高版本。
# 示例 1:非持久化 memcache:allowlist。 /etc/postfix/main.cf: postscreen_cache_map = memcache:/etc/postfix/postscreen_cache postscreen_cache_cleanup_interval = 0 /etc/postfix/postscreen_cache: memcache = inet:127.0.0.1:11211 key_format = postscreen:%s
一个持久的 lmdb:临时白名单可以在 postscreen(8) 守护进程之间共享,这些守护进程在同一 master(8) 守护进程下运行,或在同一主机上不同 master(8) 守护进程下运行。禁用缓存清理(postscreen_cache_cleanup_interval = 0)在所有 postscreen(8) 守护进程,仅保留负责缓存清理的守护进程。此操作需要 Postfix 2.11 或更高版本。
# 示例 2:持久化 lmdb:允许列表。 /etc/postfix/main.cf: postscreen_cache_map = lmdb:$data_directory/postscreen_cache # 参见下文注释 1。 # postscreen_cache_cleanup_interval = 0
其他类型的持久临时允许列表只能在运行于同一 postscreen(8) 守护进程下的 master(8) 守护进程之间共享。在这种情况下,临时允许列表的访问必须通过proxymap(8)守护进程共享。这需要 Postfix 2.9 或更高版本。
# 示例 3:通过代理的 btree:allowlist。 /etc/postfix/main.cf: postscreen_cache_map = proxy:btree:/var/lib/postfix/postscreen_cache # 参见下文注释 1。 # postscreen_cache_cleanup_interval = 0 # 示例 4:通过代理的 btree:使用 memcache 作为加速器。 /etc/postfix/main.cf: postscreen_cache_map = memcache:/etc/postfix/postscreen_cache proxy_write_maps = proxy:btree:/var/lib/postfix/postscreen_cache... 其他代理表 ... # 参见下文注释 1。 # postscreen_cache_cleanup_interval = 0 /etc/postfix/postscreen_cache: # 注意:$data_directory 宏在此上下文中未定义。 memcache = inet:127.0.0.1:11211 backup = proxy:btree:/var/lib/postfix/postscreen_cache key_format = postscreen:%s
注释 1:禁用缓存清理(postscreen_cache_cleanup_interval = 0)在所有 postscreen(8) 守护进程中禁用缓存清理(
注释 2:postscreen(8) 通过 proxymap(8) 需要 Postfix 2.9 或更高版本;较早的 proxymap(8) 实现不支持缓存清理。
历史注释和致谢
postscreen(8) 中许多想法最初由 Michael Tokarev 在 OpenBSD spamd 及 MailChannels Traffic Control 中探索。
Wietse 于 2009 年 6 月快速开发了一个粗糙的原型,支持 pregreet 和 dnsbl,因为他需要为 7 月的邮件服务器会议演示准备新内容。Ralf Hildebrandt 在多台服务器上运行此代码以收集实际使用统计数据。该版本使用了 dnsblog(8) 临时 DNS 客户端程序。
Wietse 需要为 2010 年 11 月的 LISA 会议演讲准备新材料,因此他在 8 月添加了对 DNSBL 权重和过滤器的支持,随后在 9 月进行了重大代码重写、深度协议测试、helo/发件人/收件人日志记录以及压力自适应行为的实现。Ralf Hildebrandt 在多台服务器上运行此代码以收集实际使用统计数据。此版本仍使用令人尴尬的 dnsblog(8) 临时 DNS 客户端程序。
Wietse 于 2010 年 12 月添加了 STARTTLS 支持。这使得 postscreen(8) 可用于需要 TLS 支持的站点。该实现引入了tlsproxy(8)事件驱动的 TLS 代理,用于为多个 SMTP 客户端解密/加密会话。
tlsproxy(8) 的实现导致发现了一类新的漏洞(CVE-2011-0411),该漏洞影响了多个实现的 SMTP、POP、IMAP、NNTP 和 FTP 通过 TLS 的协议。
postscreen(8) 于 2011 年 1 月作为 Postfix 2.8 稳定版本的一部分正式发布。
Noel Jones 协助了 Postfix 3.6 向尊重文档的过渡。