Sendmail+IDA

作者:Vince Skahan

作为 Linux(或 Unix)用户,您肯定熟悉您用来阅读电子邮件的程序。它可能是 mail、mailx、elm、mush 或 pine,但它的功能是让您以有序的方式访问您的邮箱。这个程序被称为邮件用户代理或 MUA。

但是,所有这些邮件是如何进入邮箱的呢?当您发送邮件时,它是如何正确路由的呢? 这是邮件传输代理或 MTA 的工作。

Sendmail+IDA 简介

有人说,除非你编辑过 sendmail.cf 文件,否则你还不是一个真正的 Unix 系统管理员。 也有人说,如果你尝试过两次这样做,那你就是个疯子 :-)

Sendmail 是一个功能极其强大的程序。 对于大多数人来说,它也极其难以学习和理解。 任何程序的权威参考(O'Reilly and Associates 出版的 Sendmail)长达 792 页,这完全有理由让大多数人望而却步。

Sendmail+IDA 则不同。 它消除了编辑总是晦涩难懂的 sendmail.cf 文件的需要,并允许管理员通过相对容易理解的“表”来定义特定于站点的路由和寻址配置。 切换到 sendmail+IDA 可以为您节省大量工作和压力。

与其他主要的邮件传输代理相比,我还没有发现任何您不能用 sendmail+IDA 更快更简单地完成的事情。 运行普通 UUCP 或 Internet 站点所需的典型事情绝对是微不足道的。 通常难以配置的配置也很容易创建和维护。

在撰写本文时,sendmail5.67b+IDA1.5 的当前版本可通过 ftp.uiuc.edu 上的匿名 ftp 获取。 它在 Linux 下编译时无需任何补丁。

获取 sendmail+IDA 源代码以在 Linux 下编译、安装和运行所需的所有配置文件都包含在 newspak-2.0.tar.gz 中,该文件可通过 sunsite.unc.edu 上的匿名 ftp 在目录 /pub/Linux/system/Mail 中获取。

Sendmail+IDA 配置文件 - 概述

传统的 sendmail 是通过系统配置文件设置的,通常是 /etc/sendmail.cf 或 /usr/lib/sendmail.cf,它与您以前见过的任何语言都不接近。 编辑 sendmail.cf 文件以提供自定义行为可能是一种令人沮丧的体验。

Sendmail+IDA 通过使所有配置选项都由表格驱动且具有相当容易理解的语法,基本上使这种痛苦成为过去。 这些选项通过在随源代码提供的 Makefile 上运行 m4(一个简单的宏处理器)或 dbm(一个简单的数据库处理器)来配置。

sendmail.cf 文件仅定义系统的默认行为。 几乎所有特殊定制都是通过许多可选的“表”而不是直接编辑 sendmail.cf 文件来完成的。

  • mailertable - 定义远程主机或域的特殊行为

  • uucpxtable - 强制通过 UUCP 传递邮件到域主机

  • pathtable - 定义到远程主机或域的 pathalias 风格的 UUCP 路径

  • uucprelays - 缩短到知名远程主机的 pathalias 路径

  • genericfrom - 将内部地址转换为外部世界可见的通用地址

  • xaliases - 将通用地址转换为/从有效的内部地址

  • decnetxtable - 将 SMTP 地址转换为 decnet 风格的地址

sendmail.cf 文件

描述

Sendmail+IDA 的 sendmail.cf 文件不是直接编辑的,而是基于管理员指定的 m4 配置文件生成的。 此文件创建了一些定义,否则指向“真正的工作”完成的表。 一般来说,只需要指定本地系统上使用的路径、站点用于电子邮件目的的名称以及所需的默认邮件程序(以及可能的智能中继主机)。

可以定义各种各样的参数来建立本地站点的行为或覆盖编译到配置项中的项目。 这些配置选项在源代码随附的文档 <IDA_SOURCE_DIR>/ida/cf/OPTIONS 文件中详细标识。

示例

最小配置(UUCP 或 SMTP,所有非本地邮件都中继到直接连接的智能主机)的 m4 文件可以短至 10 或 15 行,不包括注释。

下面显示了一个仅限 UUCP 站点且与 Internet 中继主机通信的典型 sendmail.m4 文件。

几乎所有系统都应设置 DEFAULT_HOST、DEFAULT_MAILER 和 PSEUDONYMS。

UUCP 主机可能还需要定义 UUCPNAME、RELAY_MAILER 和 RELAY_HOST 参数。

如果您的站点仅限 SMTP 且使用“域名服务”,您应将 DEFAULT_MAILER 更改为 TCP-A,并可能删除 RELAY_MAILER 和 RELAY_HOST 行。

见图 1

mailers.linux LOCAL_MAILER

大多数操作系统都提供一个程序来处理邮件的本地传递。 用于 Unix 主要变体的典型程序在 sendmail+IDA 二进制文件中具有默认值。 在 Linux 中,有必要显式定义适当的本地邮件程序,因为在您安装的发行版中不一定存在本地传递程序。 这是通过在 sendmail.m4 文件中指定 LOCAL_MAILER_DEF 来完成的。

以下示例说明了如何将本地邮件传递程序设置为常用(并移植到 Linux)的程序“deliver”以提供此功能。

Sendmail+IDA

示例

在 sendmail+IDA Sendmail.mc 文件中也内置了“deliver”的默认值,该文件包含在 sendmail.cf 文件中。 要指定它,您不需要 mailers.linux 文件,而是在 sendmail.m4 文件中定义以下内容

dnl -- (in sendmail.m4) --
define(LOCAL_MAILER_DEF, DELIVER)dnl
# mailer for local delivery

不幸的是,Sendmail.mc 假设 deliver 安装在 /bin 中,但 Slackware1.1.1 (将其安装在 /usr/bin 中) 并非如此。 在这种情况下,您需要使用链接来伪造它,或者从源代码重建 deliver,使其位于 /bin 中。

Sendmail+IDA dbm 表

Sendmail+IDA 提供了许多表,以便能够覆盖 sendmail 的默认行为(在 sendmail.m4 文件中指定)并为独特的情况、远程系统和网络定义特殊行为。 这些表使用提供的 Makefile 通过 dbm 进行后处理。

大多数站点只需要很少的表格,甚至不需要任何表格。 如果您的站点不需要这些表,那么最简单的事情可能是使它们成为零长度文件(使用“touch”),并使用 $LIBDIR 中的默认 Makefile,而不是编辑提供的 Makefile。

通用的 Internet 站点(使用域名服务)或仅限 UUCP 的站点(通过智能 RELAY_HOST 通过 UUCP 转发所有邮件)可能根本不需要任何特定的表条目。

mailertable

描述

mailertable 根据远程主机或网络名称定义特定主机或域的特殊处理。

它通常在 Internet 站点上用于使用特定协议 (uucp/smtp) 转发到中间邮件中继主机或网关,以便到达远程网络。

UUCP 站点通常不需要使用此文件。

顺序很重要。 条目基于规则集的自上而下的解释进行匹配,因此通常明智的做法是将最明确的规则放在文件顶部,而将更通用的规则放在下面。

示例

假设您要通过 UUCP 将所有发往神话般的 JoeUniversity 的邮件转发到中继主机“sysA”。 为此,您将有一个 mailertable 条目,如下所示

# (in mailertable)
#
# forward all mail for the domain .joe-u.edu via uucp to sysA

UUCP-A,sysA .joe-u.edu

假设您希望所有发往更大的 .edu 域的邮件都转到不同的中继主机“sysB”以进行地址解析和传递。 扩展后的 mailertable 条目看起来非常相似。

# (in mailertable)
#
# forward all mail for the domain .joe-u.edu via uucp to sysA

UUCP-A,sysA .joe-u.edu
#
# forward all mail for the domain .edu via uucp to sysB
UUCP-A,sysB .edu

如上所述,顺序很重要。 颠倒上面显示的两个规则的顺序将导致所有发往 joe-u.edu 的邮件都通过更通用的“sysB”路径,而不是真正需要的显式“sysA”路径。

# (in mailertable)
#
# forward all mail for the domain .edu via uucp to sysB

UUCP-A,sysB .edu

#
# no mail for joe-u will go through sysA because the above
# rule was matched and used by sendmail

UUCP-A,sysA .joe-u.edu

#
Mailertable 格式

在上面的 mailertable 示例中,UUCP-A 邮件程序意味着使用带有域头的 UUCP 传递。 邮件程序和远程系统之间的逗号告诉 sendmail 仅将消息转发到“sysA”以进行地址解析和传递。 Mailertable 条目的格式为

MAILER DELIMITER RELAYHOST HOST_OR_DOMAIN

有许多可能的邮件程序。 区别通常在于它们如何处理地址。

典型的邮件程序是 TCP-A(带有 Internet 风格地址的 tcp/ip)、TCP-U(带有 UUCP 风格地址的 tcp/ip)、UUCP-A(带有 Internet 风格地址的 uucp)。

选择将邮件程序与 mailertable 行左侧的主机部分分隔开的字符定义了地址如何被 mailertable 修改。

! - (感叹号)表示在转发到邮件程序之前剥离收件人主机名

, - (逗号)表示不要以任何方式更改地址。 仅通过指定的邮件程序转发到指定的中继主机

: - (冒号)表示仅当您和目的地之间存在中间主机时才删除收件人主机名

uucpxtable

通常,发往具有完全限定域名的主机的邮件通过基于域名服务器 (DNS) 配置的 Internet 风格 (SMTP) 传递进行传递。 uucpxtable 通过将域化的名称转换为 UUCP 风格的非域化远程主机名来强制通过 UUCP 路由传递。

当您是站点或(子)域的 MX 转发器时,或者当您希望通过直接可靠的 UUCP 链接而不是潜在的通过默认邮件程序和任何中间系统和网络的多跳发送邮件时,通常会使用它。

与使用域化邮件头的 UUCP 邻居通信的 UUCP 站点将使用此文件来强制邮件通过两个系统之间的直接 UUCP 点对点链路传递,而不是通过 RELAY_MAILER 和 RELAY_HOST 或通过 DEFAULT_MAILER 的不太直接的路由传递。

不使用 UUCP 的 Internet 站点可能不会使用 uucpxtable。

示例

假设您为 DNS 中名为“foo.bar.com”和 UUCP 映射中名为“foobarcom”的系统提供 MX 转发服务。 您将需要以下 uucpxtable 条目来强制发往其主机的传入邮件通过您的直接 UUCP 连接。

#======= /usr/local/lib/mail/uucpxtable  ==========
#Mail sent to joe@foo.bar.com is rewritten to foobarcom!joe and
#therefore delivered via UUCP
#
foobarcom foo.bar.com
#
#-------------------------
pathtable

描述

pathtable 用于定义到远程主机或网络的显式路由。 pathtable 文件应采用 pathalias 风格的语法,并按字母顺序排序。

大多数系统都不需要任何 pathtable 条目。

pathtable 示例

#======== /usr/local/lib/mail/pathtable ==========
#
# this is a pathalias-style paths file to let you kick mail to
# uucp neighbors to the direct uucp path so you don't have to
# go the long way through your smart host that takes other traffic
#
# you want real tabs on each line or m4 might complain...
#
# pathalias-style routing through a system
foo!bar!%s bar
#
# mixed mode address
foo!%s@bar.com foo
#
#
# all mail for a network to a gateway (see the leading '.' ?)

%s@gateway.host.name.domain .UUCP
relayhost!%s@othergate.domain .BITNET
#
#
#============ end of pathtable ===============
domaintable

描述

domaintable 通常用于强制在 DNS 查找发生后发生某些行为。 它允许管理员通过自动将速记名称替换为正确的名称,为常用的系统或域提供速记名称。 它也可以用于将不正确的 host.domain 信息替换为“正确”的信息。

大多数站点都不需要任何 domaintable 条目。

示例

#========= /usr/local/lib/mail/domaintable =======
#
#replace a wrong domain people are mailing to with the correct one
#
brokenhost.correct.domain brokenhost.wrong.domain
#
#
#============ end of domaintable =============
aliases

别名允许发生许多事情

  • 为邮件提供一个简写或众所周知的名称,以便发送给一个人或多个人

  • 使用邮件消息作为程序的输入来调用程序

  • 将邮件发送到文件

所有系统都需要 Postmaster 和 MAILER-DAEMON 的别名才能符合 RFC。 在定义调用程序或写入程序的别名时,始终要高度注意安全性,因为 sendmail 通常以 setuid-root 身份运行。

对别名文件的更改只有在执行“/usr/lib/sendmail -bi”命令以构建所需的 dbm 表后才会生效。 这也可以通过执行“newaliases”命令来完成,通常从 cron 完成。

有关邮件别名的详细信息,请参阅 aliases(5) 手册页。

不常用的表

以下表可用,但很少使用。 有关详细信息,请参阅 sendmail+IDA 源代码随附的文档。

uucprelays

uucprelays 文件用于“缩短”到特别知名的站点的 uucp 路径,而不是使用通过 pathalias 处理 UUCP 映射生成的多跳或不可靠路径。

genericfrom 和 xaliases

genericfrom 文件通过自动将内部用户名转换为与内部用户名不匹配的通用“From”地址,从而对外隐藏本地用户名和地址。

相关的“xalparse”实用程序自动化了 genericfrom 和别名文件的生成,以便从主 xaliases 文件发生传入和传出的用户名转换。

decnetxtable

decnetxtable 将域化地址重写为 decnet 风格的地址,就像 domaintable 将非域化地址重写为域化 SMTP 风格的地址一样。

在哪里获取更多信息

有很多地方(请参阅 comp.answers 或 rtfm.mit.edu 中的 Linux MAIL HOWTO 以获取列表),但权威的地方在 sendmail+IDA 源代码中。 在目录 <IDA_SRC_PATH>/ida/cf 中查找文件 DBM-GUIDE、OPTIONS 和 Sendmail.mc。

aliases 示例

致谢

感谢 Neil Rickert 和 Paul Pomes 多年来在 sendmail+IDA 的维护和管理方面提供的帮助,以及 Rich Braun 完成了 sendmail+IDA 到 Linux 的初始移植。

附录 A:典型问题

混合和匹配二进制发行版

电子邮件传输和传递代理没有“真正的标准配置”,也没有“一个真正的目录结构”。

因此,有必要确保系统的所有各个部分(Usenet 新闻、邮件、tcp/ip)在本地邮件传递程序(lmail、deliver 等)、远程邮件传递程序 (rmail) 和邮件传输程序(sendmail 或 smail)的位置上达成一致。 尽管使用“strings”命令可以帮助确定期望的文件和目录,但此类假设通常没有文档记录。 以下是我们过去在一些常见的 Linux 二进制发行版和源代码中看到的一些问题。

  • 某些版本的 NET-2 tcp/ip 发行版为名为“umail”的程序而不是 sendmail 定义了服务。

  • Elm 和 mailx 的各种端口都在查找 /usr/bin/smail 而不是 sendmail 的传递代理。

  • Sendmail+IDA 为“deliver”内置了本地邮件程序,但期望它位于 /bin 而不是更典型的 Linux 位置 /usr/bin。

与其费力从源代码构建所有邮件客户端,我们通常使用适当的软链接来伪造它...

附录 B:愚蠢的邮件技巧

定义智能主机和邮件程序

您可以通过 sendmail.m4 文件中的 RELAY_HOST 和 RELAY_MAILER 参数设置默认智能主机,该文件被处理为 sendmail.cf。

要将发往特定主机或域的邮件转发到指定的中继系统,通常使用 mailertable。

例如,要将发往 relayhost.com 的邮件转发到其 uucp 网关系统“uucpgate”。

(在 mailertable 中)UUCP-A,uucpgate relayhost.com

强制邮件进入配置错误的远程站点

通常,Internet 主机在将邮件发送到配置错误的远程站点时会遇到问题。 此问题有多种变体,但一般症状是邮件被远程系统退回或根本无法到达。

这些问题可能会使本地系统管理员处于不利地位,因为您的用户通常不在乎您是否亲自管理全球每个系统(或知道如何让远程管理员解决问题)。 他们只知道他们的邮件没有发送到另一端的预期收件人,而您很可能是他们抱怨的对象。

远程站点的配置是他们的问题,而不是您的问题。 在任何情况下,请务必不要为了与配置错误的远程站点通信而破坏您的站点。 如果您无法及时联系到远程站点的 Postmaster 以让他们修复其配置,您有两种选择。

通常可以成功地将邮件强制发送到远程系统,尽管由于远程系统配置错误,远程端的回复可能无法正常工作……但这又是远程管理员的问题了。

您可以通过为他们的主机/域放置一个 domaintable 条目来仅修复从您的站点发出的邮件信封中的错误标头,该条目会导致无效信息在邮件中得到纠正

# (in domaintable)
braindead_site.correct.domain.com braindead_site.wrong.domain.com

或者.....

将它们视为完全脑死亡,并剥离从您的站点发往他们的邮件信封中的所有 hostname.domain 信息。

以下内容中的“!”导致邮件被传递到他们的远程站点,并且(对于 sendmail 而言)看起来是本地发起的。 您的站点的返回地址不会更改,因此正确的返回地址仍将显示在消息中。

# (in mailertable)
TCP!braindead_site.correct.domain.com braindead_site.wrong.domain.com

无论如何,即使您将邮件发送到他们的系统,也不能保证他们可以回复您的消息(记住,他们坏了……),但那样他们的用户会向他们的管理员抱怨,而不是您的用户向您抱怨。

强制通过 UUCP 或 SMTP 传递到远程系统

在不使用任何可选 DBM 表的情况下,sendmail+IDA 通过用于生成 sendmail.cf 的 m4 文件中的 DEFAULT_MAILER(以及可能的 RELAY_HOST 和 RELAY_MAILER)传递邮件。 通过 domaintable 或 uucpxtable 中的条目很容易覆盖此行为。

强制邮件通过 UUCP 传输

在理想的世界(从 Internet 的角度来看)中,所有主机在域名服务 (DNS) 中都有记录,并将使用完全限定域名发送邮件。

如果您碰巧通过 UUCP 与此类站点通信,则可以通过 uucpxtable 从本质上“取消域化”其主机名,从而强制邮件通过点对点直接 UUCP 连接而不是通过默认邮件程序。 结果是 sendmail 然后将确定(通过 sendmail.cf m4 文件中的 UUCPNODES)您已直接连接到远程系统,并将邮件排队以使用 UUCP 传递。

# (in the uucpxtable)
# un-domainize sys2.com to force UUCP delivery
sys2 sys2.com

阻止邮件通过 UUCP 传递

相反的情况也会发生。 通常,系统可能具有许多不经常使用或不如默认邮件程序或中继主机可靠且始终可用的直接 UUCP 连接。

例如,在西雅图地区,当发布发行版时,有许多系统通过匿名 uucp 交换各种 Linux 发行版。 这些系统仅在必要时才通过 UUCP 通信,因此通常通过多个非常可靠的跃点和常见(且始终可用)的中继主机发送邮件比通过不可靠的直接点对点 UUCP 链接更快、更可靠。

很容易阻止通过 UUCP 将邮件传递到您直接连接的主机。 如果远程系统是域化的,您可以在 domaintable 中添加一个条目,该条目将完全域化主机名,并防止 sendmail.cf m4 文件中的 UUCPNODES 行匹配。 结果通常是邮件将通过 relay_mailer 和 relay_host(或 default_mailer)发送。

# (in domaintable)
# prevent mail delivery via uucp to a neighbor
uucp_neighbor.domain.com uucp_neighbor
按需运行 Sendmail 队列

要立即处理排队的消息,只需键入“/usr/lib/runq”,它将使用适当的选项调用 sendmail,以使 sendmail 立即运行完挂起的作业队列,而不是等待下一个计划运行。

构建和测试 sendmail.cf

  • cd 到 $LIBDIR/CF(通常是 /usr/local/lib/mail/CF)

  • 将 example.m4 文件复制到 yourhostname.m4

  • 编辑它以执行正确的操作(设置您的中继、主机名、别名等)

  • “make yourhostname.cf”

  • 测试那个家伙...

    /usr/lib/sendmail -bt -Cyourhostname.cf
    
    在“>”提示符下,尝试
    "3,0 me"
    "3,0 my-uucp-neighbor!foo"
    "3,0 me@mynode.mydomain"
    "3,0 mynode!me"
    "3,0 me@somenode.com"
    
    (所有都应该“做正确的事”,希望如此)
  • 将其放入 /etc/sendmail.cf 中

启动 sendmail 作为守护程序

/usr/lib/sendmail -bd -q1h

将上面的一行放在 /etc/rc.local 文件中,以便 sendmail 在系统启动时例行启动。

报告邮件统计信息

Sendmail 附带一个名为“mailstats”的实用程序,它读取一个名为 /usr/local/lib/mail/sendmail.st 的文件,并报告 senmail.cf 文件中使用的每个邮件程序传输的消息数和字节数。 此文件必须由本地管理员手动创建,才能进行 sendmail 日志记录。 通过删除和重新创建 sendmail.st 文件来清除运行总计。 一种方法是执行以下操作

cp /dev/null /usr/local/lib/mail/sendmail.st

关于谁使用邮件以及多少流量通过本地系统传入、传出和通过本地系统,进行高质量报告的最佳方法可能是使用 syslogd 打开邮件调试。 通常,这意味着从系统启动文件中运行 /etc/syslogd 守护程序,并在 /etc/syslog.conf 中包含如下行

mail.debug /usr/adm/syslog.mail

sendmail.st 文件不会增长到令人担忧的程度。 如果您使用 mail.debug 并获得任何中等到高邮件量,syslog 输出可能会变得非常大。 来自 syslogd 的输出文件通常需要从 cron 定期轮换或清除。

有许多常用的实用程序可以汇总 syslog 中邮件日志的输出。 更知名的实用程序之一是随 sendmail+IDA 源代码分发的 syslog-stat.pl 文件。

加载 Disqus 评论