Domain-Name-System

同一 IPv4 地址上的多個權威 DNS 伺服器

  • February 22, 2021

我想在 example.com 上的自託管伺服器上維護 DNS 隧道。我還有一個 DNS 伺服器,它為 example.com 提供所有服務。我目前在域 tunnel.example.com 上使用dns2tcp進行 DNS 隧道。 NSD3用於為權威區域提供服務,因為它既簡單又安全。

但是,我只有一個公共 IPv4 地址,這意味著 NSD 和 dns2tcp 無法偵聽同一 IP/埠。

所以我目前正在使用PowerDNS Recursor使用如下forward-zones參數:

forward-zones-recurse=tunnel.example.com=1.2.3.4:5354
forward-zones=example.com=1.2.3.4:5353

這使得對權威區域的請求能夠被請求到正確的伺服器,以及對隧道請求。NSD 在埠 5353 上監聽,dns2tcp 在埠 5354 上監聽。

但是,這很糟糕,因為需要打開遞歸器。它實際上回答了任何遞歸查詢。

你有什麼解決辦法嗎?我真的更喜歡不涉及設置 BIND 的解決方案,但如果您有心情說服我,請不要猶豫;)


編輯:我將標題更改為更清晰。

2021 年更新

來自(見下文)的string模組的解決方案不能用 翻譯,所以我不得不找到另一個解決方案。iptables``nftables

我現在使用的是 DNS 負載均衡器dnsdist 。它使用更多的 CPU 和 RAM,但它顯然更強大。我喜歡它專注於這項任務,無需重寫 DNS 答案,除非有要求。這是我的配置文件的摘錄:

-- dnsdist configuration file, an example can be found in /usr/share/doc/dnsdist/examples/

-- disable security status polling via DNS
setSecurityPollSuffix("")

setLocal('<PUBLIC_IP4>:53', {reusePort=true, interface="eth_adsl"})
addLocal('[<PUBLIC_IP6>]:53', {reusePort=true, interface="eth_adsl"})
setACL({'0.0.0.0/0', '::/0'})

controlSocket('127.0.0.1')
setKey("SECRET_KEY")

-- Declare NSD authoritative server. It could also listen to localhost, but I let it answer on public addresses, using port 5300
newServer({address="[<PUBLIC_IP6>]:5300", checkInterval=60, pool="root"})
newServer({address="<PUBLIC_IP4>:5300", checkInterval=60, pool="root"})

-- Declare DNS Tunnel (iodine), on port 5354
newServer({address="127.0.0.1:5354", pool="tunnel"})
-- This is using socket activation, so disable dnsdist checks to avoid waking up the tunnel
getServer(2):setUp()

-- Forward to tunnel, skipping cache
tunnelRule = makeRule("t.antipoul.fr")
addAction(tunnelRule, SkipCacheAction())
addAction(tunnelRule, PoolAction("tunnel"))

-- Allow Zone transfer from secondary only
-- See https://dnsdist.org/advanced/axfr.html
addAction(AndRule({OrRule({QTypeRule(DNSQType.AXFR), QTypeRule(DNSQType.IXFR)}), NotRule(makeRule("<SECONDARY_IP4>/32"))}), RCodeAction(DNSRCode.REFUSED))

-- All remaining traffic goes to NSD
addAction(AllRule(), PoolAction("root"))

2012 年原始解決方案

我找到了解決我的問題的方法。但是,這不是該問題的通用解決方案。

就我而言,我依賴 dns2tcp 使用的協議,它使用 tunnel.example.com 上的子域請求進行通信。所以想法是匹配包含此類請求的數據包,並建構一個 netfilter 規則:

iptables -t nat -I PREROUTING -p udp --dport 53 -m string --algo bm --from 42 --hex-string "|0674756e6e656c076578616d706c6503636f6d00|" -j REDIRECT -to-ports 5354
  • hex-string參數是對應於 tunnel.example.com在 DNS 數據包中看到的字元串。
  • from 42確保只有子請求被重定向到 dns2tcp,而不是對域本身的正常請求,例如 SOA 或 NS 請求。
  • NSD 現在監聽埠 53,這比以前好多了。
  • 沒有更多的公共遞歸伺服器,這就更好了。

這並不完美,但它使用的軟體確實比以前少得多。

兩台伺服器不能同時監聽同一個 IP+埠組合。

你所做的任何事情都是為了讓這樣一個有兩個背部的野獸成為黑客——它是壞的和錯誤的,不應該做。痛苦、悲傷、瘋狂和死亡都在這條路上躺著——現在轉身,否則你會被一頭小豬吃掉。


正確的解決方案

獲取另一個IP。理想情況下完全獲得另一台伺服器,並且不要在與您的權威伺服器相同的機器上執行您的遞歸 DNS。


簡單的解決方案

克服對 BIND 的恐懼/不信任/仇恨(獲取DNS 和 BIND的副本並做好準備),並使用該allow-recursion{…};指令來限制誰可以進行遞歸查詢。

這個簡單的解決方案可能仍然會讓您面臨記憶體中毒和其他討厭的事情。如果您真的想要權威 DNS 伺服器的安全性,您需要執行一個單獨的名稱伺服器程序,偵聽單獨的 IP 地址,最好是在單獨的主機(或監獄、VM 等)上。

引用自:https://serverfault.com/questions/397835