【PowerDNS】Lua Records
這是一份 PowerDNS 官方文件的完整中文翻譯。
它說明了 LUA Record(Lua 動態記錄) 的用途、語法、應用範例、進階用法與安全注意事項。
我保留了原文段落結構與技術名詞,方便你比對。
🧩 PowerDNS — Lua Records 中文說明文件
一、概述
為了提供動態行為(例如全球負載平衡 Global Server Load Balancing),
PowerDNS Authoritative Server 自 4.2 版起 支援 動態 DNS 記錄(LUA Records)。
這些記錄中包含了小段設定程式(Lua 程式碼),
可根據「查詢者 IP」、「EDNS Client Subnet」、「伺服器可用性」等因素,
動態決定要回應哪個 IP 或 CNAME。
功能範圍從簡單到複雜,
可實現多池(multi-pool)地理與權重負載平衡(Geo & Weighted Load Balancing)。
雖然使用者不必了解內部原理,
但 PowerDNS 的動態記錄本質上是 嵌入在 DNS 內的小型 Lua 腳本。
💡 注意:
這是 PowerDNS 專屬功能,目前尚未成為 IETF 或其他標準機構的標準。
PowerDNS 官方承諾會致力於互通性,並希望最終能成為被廣泛支持的標準。
要啟用此功能,可在設定檔中加入:
enable-lua-records=yes
或對單一 zone 設定 metadata:
ENABLE-LUA-RECORDS=1
若要使用地理位置功能,請確認 launch
設定中包含:
launch=gpgsql,geoip
⚠️ 警告:
使用 AXFR 傳輸包含長 Lua 記錄的 zone 時,請確保每筆記錄內容(TXT 型態傳輸)
不超過 255 bytes。超過時會被分割成多段,導致次伺服器解析錯誤。
二、範例說明
1️⃣ ifportup()
www IN LUA A "ifportup(443, {'192.0.2.1', '192.0.2.2'})"
這會讓 www
這個名稱隨機回應 192.0.2.1
或 192.0.2.2
,
前提是這些 IP 的 TCP 443 port 是開放的。
若其中一個 IP 不再回應 443,則僅回傳另一個。
若全部都不通,則全部地址會被回傳。
多組 IP 可分優先層級,例如:
www IN LUA A "ifportup(443, {{'192.0.2.1', '192.0.2.2'}, {'192.0.3.1'}})"
這表示:
-
若第一組中的任一 IP 可用 → 回第一組;
-
否則 → 試第二組。
因為 DNS 查詢要求極快回應,PowerDNS 不會即時檢查連線狀態,
而是由背景程序定期檢測這些 IP 是否可用。
2️⃣ pickclosest()
www IN LUA A "pickclosest({'192.0.2.1','192.0.2.2','198.51.100.1'})"
這會根據查詢者的地理位置(GeoIP),
選擇最靠近使用者的 IP 回覆。
也可以與 ifportup()
結合:
www IN LUA A ("ifportup(443, {'192.0.2.1', '192.0.2.2', '198.51.100.1'}, {selector='pickclosest'})")
這會在可用的 IP 中挑出距離使用者最近的一個。
3️⃣ 複雜 Lua 程式碼範例
www IN LUA A ";if country('US') then return {'192.0.2.1','192.0.2.2','198.51.100.1'} else return '192.0.2.2' end"
可同時回傳單一字串或多筆字串(array)。
4️⃣ 使用 qname 的例子
*.example.net 10 IN LUA TXT "; return 'Got a TXT query for ' .. qname:toString() .. '; First label is: ' .. qname:getRawLabels()[1]"
注意:
qtype
無法從 Lua 內直接取得(它是固定的)。
可使用預設變數(Preset Variables)取得其他查詢相關資訊。
三、在 SQL 後端使用 Lua Records
LUA Records 可與一般的 gmysql / gpgsql 通用 SQL 後端一起使用。
由於內容同時包含單引號與雙引號,
在 INSERT
或 UPDATE
時需特別轉義。
範例如下:
-- 建立 zone
INSERT INTO domains (id, name, type) VALUES (1, 'example.com', 'NATIVE');
-- 啟用 Lua 記錄功能
INSERT INTO domainmetadata (domain_id, kind, content)
VALUES (1, 'ENABLE-LUA-RECORDS', 1);
-- 建立 pickclosest() 記錄
INSERT INTO records (domain_id, name, type, content, ttl)
VALUES (
1,
'www.example.com',
'LUA',
'A "pickclosest({''192.0.2.1'',''192.0.2.2'',''198.51.100.1''})"',
600
);
這三筆 SQL:
-
建立
example.com
zone, -
啟用 Lua Records,
-
新增一筆
www.example.com
的動態 A 記錄。
四、LUA Record 格式
💡 名稱由來:
“Lua” 在葡萄牙文中意為「月亮」,不是縮寫。
但 DNS 慣例記錄類型一律大寫,因此用LUA
。
一筆 LUA Record 結構如下:
LUA <query_type> <Lua 程式>
例如:
www IN LUA A "pickclosest({'1.1.1.1','8.8.8.8'})"
-
可設定 TTL,PowerDNS 會照常套用;
-
可被 DNSSEC 簽章(需在同一伺服器即時簽署)。
五、更強大的範例
west IN LUA A ("ifurlup('https://www.lua.org/', {{'192.0.2.1', '192.0.2.2'}, {'198.51.100.1'}}, {stringmatch='Programming in Lua'})")
這會:
-
嘗試對
www.lua.org
發出 HTTPS; -
若回應內容包含
Programming in Lua
,則視為可用; -
第一組 IP 可用 → 回第一組;否則 → 回第二組。
與地理導向結合:
www IN LUA CNAME (";if(continent('EU')) then return 'west.powerdns.org' else return 'usa.powerdns.org' end")
對應的 usa
名稱配置如下:
usa IN LUA A ("ifurlup('https://www.lua.org/', {{'198.51.100.1'}, {'192.0.2.1', '192.0.2.2'}}, {stringmatch='Programming in Lua'})")
歐洲以外的訪客會優先使用 198.51.100.1
,
若失效則回到 192.0.2.1
/ 192.0.2.2
。
六、進階主題
(1) 語法模式
若記錄內容未以 ;
開頭,PDNS 會自動加上 return
。
若要撰寫完整 Lua 腳本,請以分號 ;
開頭。
(2) 可引用其他記錄的設定
可用 include()
引用共用設定:
config IN LUA LUA ("settings={stringmatch='Programming in Lua'} EUips={'192.0.2.1','192.0.2.2'} USAips={'198.51.100.1'}")
usa IN LUA A (";include('config') return ifurlup('https://www.lua.org/', {USAips, EUips}, settings)")
west IN LUA A (";include('config') return ifurlup('https://www.lua.org/', {EUips, USAips}, settings)")
七、安全與同步機制
-
LUA Record 是查詢時即時生成;
-
可透過 AXFR 同步至其他 PDNS 伺服器;
-
但無法直接查詢(防止外部洩露負載邏輯)。
⚠️ 警告:
絕對不要從不信任的來源匯入含 LUA Record 的 zone!
惡意 Lua 可能導致伺服器崩潰甚至被接管。即使是可信來源也請使用 TSIG 保護 AXFR 傳輸。
若有 DNSSEC 簽章需求,
LUA Record 必須由主伺服器即時簽署(無法預先簽署 zone)。
八、共享 Lua 狀態模式(shared mode)
預設情況下,PDNS 每次查詢都會建立新的 Lua 執行環境。
這樣每筆 LUA Record 彼此獨立,不會污染變數。
但建立 Lua state 很耗時。
可啟用共用模式:
enable-lua-records=shared
-
每個執行緒建立一個 Lua 狀態並重複使用;
-
約可提升 QPS 10 倍;
-
各執行緒 Lua 環境獨立(UDP 為多實例,TCP 共用一個)。
九、Reference(函式與物件類別)
PowerDNS 提供的 Lua 內建 API 包含:
預設變數(Preset Variables)
-
qname
,qtype
,remoteip
,ednssubnet
等
可用函式
-
getdns()
,ifportup()
,pickclosest()
,country()
,continent()
-
ifurlup()
,include()
,pdnslog()
, 等
物件類別
-
DNSName
,ComboAddress
,DNSResourceRecord
,DNSHeader
,QType
-
Netmask
,ComboAddressSet
,DNSRecord
, 及輔助函式群組
(這些內容在官方文件的「LUA Reference」章節中詳細列出)
🔚 總結
功能 | 說明 |
---|---|
LUA Record | PowerDNS 內建的動態 DNS 回覆機制 |
語言 | Lua |
用途 | 智能選址、健康檢查、地理導向、服務偵測 |
啟用方式 | enable-lua-records=yes 或 ENABLE-LUA-RECORDS=1 |
安全性 | 僅限信任 zone;建議使用 TSIG |
效能優化 | enable-lua-records=shared 可大幅提高 QPS |
是否要我幫你把這篇翻譯版整理成 可直接放進公司內部 Wiki 的 Markdown 版(含語法高亮與範例區塊)?
我可以自動加上標題層級、代碼框、注意區塊與翻譯對照欄位。