普通视图

发现新文章,点击刷新页面。
昨天以前HiFeng'Blog

PowerDNS 权威服务器基于 LUA Records 实现 CNAME Flattening

2026年3月4日 12:14

1. 背景与问题

在 DNS 中,CNAME 记录不能设置在 zone apex(根域名)上,例如 example.com 本身不能是 CNAME,只有子域名如 www.example.com 可以。这是 DNS 标准的限制。

CNAME Flattening 是一种技术手段,允许在根域名上实现类似 CNAME 的效果,即将根域名指向另一个域名,并动态解析出真实 IP 返回给客户端。

PowerDNS 提供了 ALIAS 记录类型来解决这个问题,但 ALIAS 类型存在一个缺陷:不支持 DNSSEC live-signing(实时签名)。

使用 LUA Records 可以同时解决 CNAME Flattening 和 DNSSEC 签名两个问题

2. 环境要求

在开始之前,请确认以下条件:

•PowerDNS Authoritative Server 4.x 及以上版本

•编译时包含 lua-records 支持(运行 pdns_server --version 确认 Features 中包含 lua-records)

•使用 gmysql 或其他数据库后端

•DNSSEC 使用 live-signing 模式(不是预签名模式)

验证 LUA records 支持:

pdns_server --version

输出的 Features 字段中应包含 lua-records。

3. PowerDNS 配置

3.1 启用 LUA Records

编辑 PowerDNS 配置文件(通常是 /etc/powerdns/pdns.conf 或 /etc/powerdns/pdns.d/ 目录下的配置文件),添加以下配置:

enable-lua-records=yes

同时确保配置了 resolver,LUA records 解析目标域名时需要用到:

resolver=8.8.8.8:53

重启 PowerDNS 使配置生效:

systemctl restart pdns

3.2 完整配置示例

以下是一份包含 LUA records 的完整配置示例:

launch=gmysql
gmysql-host=localhost
gmysql-user=root
gmysql-dbname=powerdns
gmysql-password=yourpassword
gmysql-dnssec=yes
enable-lua-records=yes
resolver=8.8.8.8:53
local-address=0.0.0.0 ::
local-port=53

4. 创建 Zone 并添加 LUA 记录

4.1 创建 Zone

使用 pdnsutil 创建 zone(如果已存在可跳过):

pdnsutil create-zone example.com ns1.example.com

4.2 添加 LUA CNAME 记录

使用 pdnsutil 在根域名上添加 LUA 类型的 CNAME 记录:

pdnsutil add-record example.com @ LUA "CNAME \";return 'target.example.net.'\""

实际命令示例(将 example.com 指向 hicairo.com):

pdnsutil add-record example.com @ LUA "CNAME \";return 'hicairo.com.'\""

注意:LUA 记录中的域名需要用单引号包裹,作为 Lua 字符串返回。末尾的点(.)表示绝对域名,建议保留。

4.3 验证记录

查看 zone 中的所有记录:

pdnsutil list-zone example.com

预期输出应包含:

example.com  3600  IN  LUA  CNAME ";return 'hicairo.com.'"

5. 启用 DNSSEC

5.1 对 Zone 签名

使用 pdnsutil 对 zone 启用 DNSSEC:

pdnsutil secure-zone example.com

更新 NSEC 排序信息:

pdnsutil rectify-zone example.com

5.2 查看签名信息

查看 zone 的 DNSSEC 详情,包括 DS 记录(需要提交到上级域):

pdnsutil show-zone example.com

输出示例:

ID = 1 (CSK), flags = 257, tag = 52822, algo = 13, bits = 256  Active  Published
DS = example.com. IN DS 52822 13 2 99ebc97b...

注意:需要将 DS 记录提交到域名注册商,才能完成 DNSSEC 信任链的建立。

6. 测试验证

6.1 测试 CNAME 查询

直接查询权威服务器:

dig @127.0.0.1 example.com CNAME

预期返回:

example.com.  3600  IN  CNAME  hicairo.com.

6.2 测试 A 记录查询

查询 A 记录,递归解析器会自动跟随 CNAME 解析出 IP:

dig @8.8.8.8 example.com A

预期返回 CNAME 记录以及目标域名的 A 记录(IP 地址)。

6.3 测试 DNSSEC 签名

使用 +dnssec 参数验证签名:

dig @127.0.0.1 example.com CNAME +dnssec

预期返回中应包含 RRSIG 记录:

example.com.  3600  IN  CNAME  hicairo.com.
example.com.  3600  IN  RRSIG  CNAME 13 2 3600 ...

通过公网 DNS(如 8.8.8.8)验证,响应 flags 中应包含 ad(Authenticated Data)标志,表示 DNSSEC 验证通过:

dig @8.8.8.8 example.com CNAME +dnssec
;; flags: qr rd ra ad;

7. LUA Records 语法说明

7.1 基本格式

LUA records 的存储格式为:

LUA  <DNS类型>  "<Lua代码>"

其中 Lua 代码需要用双引号包裹,代码本身返回一个字符串作为 DNS 记录的内容。

7.2 固定 CNAME 示例

将域名固定指向另一个域名:

LUA  CNAME  ";return 'target.example.net.'"

7.3 与 ALIAS 类型的区别

特性

ALIAS 类型

LUA 类型

CNAME Flattening

支持

支持

DNSSEC live-signing

不支持

支持

zone apex 使用

支持

支持

灵活性

固定指向

可编程,支持条件逻辑

PowerDNS 版本要求

4.x+

4.x+

8. 常见问题

8.1 查询返回 SERVFAIL

检查 LUA 代码语法是否正确,查看 PowerDNS 日志:

journalctl -fu pdns.service

日志中会显示 Lua record reported 错误信息,根据提示修正 Lua 代码。

8.2 A 记录查询只返回 CNAME 不返回 IP

这是正常行为。PowerDNS 作为权威服务器返回 CNAME,客户端的递归解析器会自动继续解析目标域名的 A 记录。使用 8.8.8.8 等公共递归解析器测试可以看到完整结果。

8.3 DNSSEC 验证失败

确认已执行以下步骤:

•pdnsutil secure-zone 对 zone 签名

•pdnsutil rectify-zone 更新 NSEC 排序

•DS 记录已提交到域名注册商

•等待 DS 记录在全球 DNS 传播(通常需要几小时到 24 小时)

9. 总结

使用 LUA Records 实现 CNAME Flattening 的优势:

•完全支持 DNSSEC live-signing,解决了 ALIAS 类型的历史遗留问题

•只需要 gmysql 单后端,无需额外的 HTTP 后端服务

•配置简单,只需一条 LUA 记录即可实现

•支持复杂的条件逻辑(如按地理位置返回不同的目标域名)

关键命令速查:

# 添加 LUA CNAME 记录
pdnsutil add-record example.com @ LUA "CNAME \";return 'target.example.net.'\""

# 启用 DNSSEC
pdnsutil secure-zone example.com
pdnsutil rectify-zone example.com

# 验证
dig @127.0.0.1 example.com CNAME +dnssec



本文出处:HiFeng's Blog
本文链接:https://www.hicairo.com/post/83.html
版权声明:本博客所有文章除特别声明外,均采用CC BY-NC-SA许可协议。转载请注明出处!

❌
❌