概述
本文件涵盖以下主题:
- Postfix 查找表模型
- Postfix 列表与表的区别
- 为 LDAP 或 SQL 查找准备 Postfix
- 维护 Postfix 查找表文件
- 安全更新 Berkeley DB 文件
- Postfix 查找表类型
Postfix 查找表模型
Postfix 使用查找表来存储和查找用于访问控制、地址重写甚至内容过滤的信息。所有 Postfix 查找表均指定为 "type:table",其中 "type" 是本文末尾 "Postfix 查找表类型" 中描述的数据库类型之一,而 "table" 是查找表名称。Postfix 文档中使用 "数据库" 和 "查找表" 表示同一概念。
Postfix 文档中常见的查找表示例:
/etc/postfix/main.cf: alias_maps = hash:/etc/postfix/aliases (本地别名映射) header_checks = regexp:/etc/postfix/header_checks (内容过滤) transport_maps = hash:/etc/postfix/transport (路由表) 虚拟别名映射表 = hash:/etc/postfix/virtual (虚拟别名)
所有 Postfix 查找表都以 (键, 值) 对的形式存储信息。这个接口初看可能显得简单,但实际上非常强大。(键, 值) 查询接口完全隐藏了 LDAP 或 SQL 的复杂性。这是将复杂系统与简单接口连接的良好示例。
Postfix (键,值) 查询接口的优势:
- 您可以先使用本地 Berkeley DB 文件实现 Postfix 查找表,然后在不影响 Postfix 配置本身的情况下切换到 LDAP 或 MySQL,具体请参见下文的 "为 LDAP 或 SQL 查找准备 Postfix" 部分。
- 您可以使用 Berkeley DB 文件和固定查找字符串进行简单的地址重写操作,同时使用正则表达式表处理更复杂的工作。换言之,您无需将所有内容都放入同一张表中。
Postfix 列表与表的对比
大多数 Postfix 查找表用于查找信息。例如地址重写(查找字符串是旧地址,结果是新地址)或访问控制(查找字符串是客户端、发件人或收件人,结果是操作如"拒绝")。
然而,对于某些表,Postfix只需知道查找键是否存在。在此处,任何非空的查找结果值均可使用:查找结果本身不会被使用。示例包括用于确定 Postfix 在网络邮件中接受哪些本地收件人的 local_recipient_maps,以及用于指定 Postfix 本地投递哪些域的 mydestination 参数,该参数指定 Postfix 用于本地投递的域名,或 mynetworks 参数,该参数指定受信任客户端或客户端网络的 IP 地址。从技术上讲,这些是列表,而非表格。尽管存在差异,Postfix 列表在此处被描述,因为它们与 Postfix 查找表使用相同的底层基础设施。
为 LDAP 或 SQL 查找准备 Postfix
LDAP 和 SQL 是复杂的系统。同时配置 Postfix 和 LDAP 或 SQL 绝非明智之举。您可以通过先使用本地文件(如 Berkeley DB)实现 Postfix 来节省大量时间。本地文件出错较少,且可通过 postmap(1) 命令轻松调试:
% postmap -q [email protected] hash:/etc/postfix/virtual
一旦本地文件正常工作,您可以按照ldap_table(5)、mysql_table(5)、pgsql_table(5) 或 sqlite_table(5),并将本地文件查找替换为 LDAP 或 SQL 查找。执行此操作后,应再次使用 postmap(1) 命令,以验证数据库查找仍与本地文件查找产生完全相同的结果:
% postmap -q [email protected] ldap:/etc/postfix/virtual.cf
请确保测试所有在相关手册页"表搜索顺序"部分中记录的 partial address 或父域查询:access(5), canonical(5)、virtual(5)、transport(5),或在相关配置参数下: mynetworks、relay_domains,parent_domain_matches_subdomains。
维护 Postfix 查找表文件
当邮件系统运行时对数据库进行修改,希望 Postfix 在信息被修改期间避免读取相关信息。此外,若能无需执行 "postfix reload" 即可使用新信息,将更为理想。每次执行 "postfix reload" 都会导致 Postfix 性能大幅下降。
- 如果您修改了 LDAP、NIS 或 SQL 等网络数据库,无需执行 "postfix reload"。LDAP、NIS 或 SQL 服务器会处理读写访问冲突,并在数据可用时将新数据提供给 Postfix。
- 如果您修改了 regexp:、pcre: 或 cidr: 或 texthash: 文件,Postfix 可能不会立即检测到文件更改。这是因为 Postfix 进程会将整个文件一次性加载到内存中,之后不再检查该文件。
- 如果文件被短暂运行的进程(如 smtpd(8))使用,cleanup(8) 或 local(8) 时,无需在修改后执行 "postfix reload"。
- 如果文件正在被一个长时间运行的进程(如trivial-rewrite(8))在繁忙的服务器上使用,可能需要执行 "postfix reload"。
- 如果您修改了基于本地文件的数据库(如 DBM 或 Berkeley DB),无需执行 "postfix reload"。Postfix 使用文件锁定机制避免读写冲突,当 Postfix 守护进程检测到文件发生更改时,会终止当前进程并等待新进程初始化后再处理下一个客户端请求。
安全更新 Berkeley DB 文件
Postfix 使用文件锁定机制避免在更新 Berkeley DB 或其他本地数据库文件时发生访问冲突。此机制曾被认为是安全的,但随着 Berkeley DB 采用更激进的缓存机制,文件锁定可能不再足够。
此外,文件锁定无法防止因磁盘空间不足或其他原因导致数据库更新失败的情况。特别是,postmap(1) 或 postalias(1) 等命令会覆盖现有文件。如果覆盖操作中途失败,则数据库将无法使用,Postfix 也会停止工作。此问题不适用于 Postfix 2.2 及后续版本中提供的 CDB 数据库类型:CDB 会创建一个新文件,并在操作成功完成后重命名该文件。
对于 Berkeley DB 和其他"单文件"数据库,可以通过使用"mv"命令替换现有数据库文件而非覆盖它来增加一些额外健壮性:
# postmap access.in && mv access.in.db access.db
这将输入文件 "access.in" 转换为输出文件 "access.in.db",并且仅在 postmap(1) 命令成功时替换文件 "access.db"。当然,手动输入这些命令很快会变得枯燥,因此人们通常使用 "make" 代替,如下所示。用户输入以粗体字显示。
# cat Makefile all: aliases.db access.db virtual.db ...etcetera... # 注释 1:命令在制表符后指定。 # 注释 2:使用 postalias(1) 用于本地别名,postmap(1) 用于其他情况。 aliases.db: aliases.in postalias aliases.in mv aliases.in.db aliases.db access.db: access.in postmap access.in mv access.in.db access.db virtual.db: virtual.in postmap virtual.in mv virtual.in.db virtual.db ...等等... # vi access.in ...编辑会话未显示... # make postmap access.in mv access.in.db access.db #
"make" 命令仅更新已更改的文件。如果出现错误,"make" 命令将停止并不会调用 "mv" 命令,因此 Postfix 将继续使用现有数据库文件,仿佛什么都没发生。
Postfix 查找表类型
要查看 Postfix 系统支持的数据库类型,请使用 "postconf -m" 命令。以下是常见的数据库类型列表:
btree
一种排序、平衡的树结构。仅在支持 Berkeley DB 数据库的系统上可用。数据库文件通过 postmap(1) 或 postalias(1) 命令创建。在 "btree:table" 中使用的查找表名称是数据库文件名去除 ".db" 后缀的部分。
cdb
一种读取优化结构,不支持增量更新。数据库文件通过 postmap(1) 或 postalias(1) 命令创建。在 "cdb:table" 中使用的查找表名称是数据库文件名去除 ".cdb" 后缀的部分。此功能在 Postfix 2.2 及更高版本中可用。
cidr
一个将值与无类域间路由(CIDR)模式关联的表。表格式在cidr_table(5)中描述。
dbm
基于哈希的索引文件类型。仅在支持 DBM 数据库的系统上可用。公共数据库文件通过 postmap(1) 或 postalias(1) 命令创建,而私有数据库由 Postfix 守护进程维护。在 "dbm:table" 中使用的查找表名称是数据库文件名,不包含 ".dir" 或 ".pag" 后缀。
environ
UNIX 进程环境数组。查找键是变量名称。在 "environ:table" 中,查找表名称被忽略。
fail
一个可靠地拒绝所有请求的表。查找表名称仅用于日志记录。此表存在是为了简化 Postfix 错误测试。
hash
基于哈希的索引文件类型。此类型仅在支持 Berkeley DB 数据库的系统上可用。公共数据库文件通过 postmap(1) 或 postalias(1) 命令创建,而私有数据库由 Postfix 守护进程维护。在 "hash:table" 中使用的数据库名称是数据库文件名去除 ".db" 后缀的部分。
inline (只读)
一个非共享的内存查找表。示例:"inline:{ key=value, { key = 包含空格或逗号的文本 }}"。键值对由空格或逗号分隔;当键值对位于 "{}" 之间时,开头 "{" 后的空格、键与值之间的 "=" 周围的空格,以及闭合 "}" 前的空格将被忽略。内联表消除了仅为少量固定元素创建数据库文件的必要性。参见 static: map 类型。
内部
一个非共享的内存哈希表。其内容在进程终止时丢失。
lmdb
OpenLDAP LMDB 数据库。此选项仅在支持 LMDB 数据库的系统上可用。公共数据库文件由 postmap(1) 或 postalias(1) 命令创建,而私有数据库由 Postfix 守护进程维护。在 "lmdb:table" 中使用的数据库名称是数据库文件名去除 ".lmdb" 后缀的部分。详细信息请参阅 lmdb_table(5)。
ldap (只读)
LDAP 数据库客户端。配置细节请参阅 ldap_table(5)。
memcache
Memcache 数据库客户端。配置详情请参阅 memcache_table(5)。
mongodb(只读)
MongoDB 数据库客户端。配置详情请参阅 mongodb_table(5),示例请参阅 MONGODB_README。
mysql (只读)
MySQL 数据库客户端。配置详细信息请参阅 mysql_table(5)。
netinfo (只读)
Netinfo 数据库客户端。
nis (只读)
NIS 数据库客户端。
nisplus (只读)
NIS+ 数据库客户端。配置详细信息请参阅 nisplus_table(5)。
pcre (只读)
基于 Perl 兼容正则表达式的查找表。文件格式在 pcre_table(5) 中描述。在 "pcre:table" 中使用的查找表名称是正则表达式文件的名称。
pipemap (只读)
查找表管道。示例:"pipemap:{type1:name1, ..., typen:namen}"。每个 "pipemap:" 查询都会传递给第一个表。每个查找结果成为管道中下一张表的查询,最后一张表生成最终结果。当任何表查找未返回结果时,管道不返回结果。 "pipemap:" 表名的首尾字符必须为 "{" 和 "}"。在此范围内,各映射用逗号或空格分隔。
pgsql (只读)
PostgreSQL 数据库客户端。配置细节请参阅 pgsql_table(5)。
代理
Postfix proxymap(8) 客户端,用于共享访问 Postfix 数据库。查找表名称的语法为"proxy:type:table"。
randmap(只读)
一个内存表,用于随机选择。示例:"randmap:{result1, ..., resultn}"。每个表查询从指定的结果中返回一个随机选择。表名 "randmap:" 的第一个和最后一个字符必须是 "{" 和 "}"。在此范围内,各个映射用逗号或空格分隔。要为特定结果赋予更高权重,请多次指定该结果。
regexp(只读)
基于正则表达式的查找表。文件格式在regexp_table(5)中描述。在"regexp:table"中使用的查找表名称是正则表达式文件的名称。
sdbm
基于哈希的索引文件类型。此类型仅在支持 SDBM 数据库的系统上可用。公共数据库文件通过 postmap(1) 或 postalias(1) 命令创建,而私有数据库由 Postfix 守护进程维护。在 "sdbm:table" 中使用的查找表名称是数据库文件名,不带 ".dir" 或 ".pag" 后缀。
socketmap (只读)
Sendmail 风格的 socketmap 客户端。表的名称对于 TCP/IP 服务器为 inet:主机:端口:名称,对于 UNIX 域服务器为 unix:路径名:名称。详细信息请参阅 socketmap_table(5)。
sqlite(只读)
SQLite 数据库。配置详细信息请参阅 sqlite_table(5)。
static (只读)
一个始终将自身名称作为查找结果返回的表。例如,"static:foobar" 始终返回字符串 "foobar" 作为查找结果。当结果包含空格时,请指定 "static:{ 包含空格的文本 }";此形式会忽略开头 "{" 后的空格和结尾 "}" 前的空格。参见 inline: 映射类型。
tcp
TCP/IP 客户端。协议在 tcp_table(5) 中描述。查找表名称为"tcp:host:port",其中"host"指定符号主机名或数值 IP 地址,"port"指定符号服务名称或数值端口号。
texthash(只读)
一个与 hash: files 类似的表,但无需在使用文件前运行 postmap(1) 命令,且 texthash: 不会检测文件读取后的更改。查找表名称为"texthash:filename",其中文件名被直接使用,不添加后缀。
unionmap(只读)
一个将每个查询发送到多个查找表并以逗号分隔所有找到的结果的表。表名语法与 pipemap 表相同。
unix (只读)
UNIX 身份验证数据库的有限视图。以下表已实现:
unix:passwd.byname
该表是 UNIX 密码数据库。键是登录名。结果是 passwd(5) 格式中的密码文件条目。
unix:group.byname
该表是 UNIX 组数据库。键是组名。结果是 group(5) 格式中的组文件条目。
根据 Postfix 的构建方式,可能还可用其他查找表类型。在某些 Postfix 发行版中,列表可动态扩展,因为查找表支持已动态链接到 Postfix 中。