关于DNS反向代理根据CNAME源域名返回对应TXT记录的可行性及实现方法问询
关于DNS反向代理根据CNAME源域名返回对应TXT记录的可行性及实现方法问询
首先明确说:这种需求是可以实现的,但得绕开DNS标准里的一些限制,或者调整下实现思路——毕竟CNAME记录本身有个硬性规则:设置了CNAME的域名不能同时存在其他记录(比如TXT),所以直接给sample.somedomain.com设CNAME再绑TXT是不符合标准的,递归DNS服务器只会去查CNAME指向的mydomain.example.com的记录。
下面分两种可行的实现路径给你讲:
一、推荐方案:放弃CNAME,直接用自定义DNS代理托管目标域名
这是最符合DNS标准、也最容易实现的方式:
- 把
sample.somedomain.com和test.anotherdomain.com的权威DNS服务器指向你搭建的自定义DNS代理 - 代理服务器收到TXT查询请求时,直接根据原始查询域名返回对应的TXT内容
举个具体的实现例子,用Python的dnspython库写个轻量代理:
- 先安装依赖:
pip install dnspython - 写个简单的代理脚本:
import dns from dns import resolver, message from dns.query import udp, tcp import socket UPSTREAM_DNS = '8.8.8.8' # 上游公共DNS服务器 LISTEN_PORT = 53 # 自定义TXT记录映射,末尾要加域名根点"." TXT_RECORDS = { 'sample.somedomain.com.': ['"sample-specific-TXT-content"'], 'test.anotherdomain.com.': ['"test-specific-TXT-content"'] } def handle_dns_request(data, addr, sock): try: request = message.from_wire(data) response = message.make_response(request) response.flags |= message.AA # 标记为权威应答 qname = request.question[0].name.to_text() qtype = request.question[0].rdtype if qtype == dns.rdatatype.TXT and qname in TXT_RECORDS: # 返回预设的自定义TXT记录 for txt_content in TXT_RECORDS[qname]: response.answer.append(dns.rrset.from_text(qname, 300, dns.rdataclass.IN, 'TXT', txt_content)) else: # 非目标域名的请求转发到上游DNS处理 if request.flags & message.TC: upstream_response = tcp(request, UPSTREAM_DNS) else: upstream_response = udp(request, UPSTREAM_DNS) response = upstream_response sock.sendto(response.to_wire(), addr) except Exception as e: print(f"Error handling request: {e}") def main(): sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) sock.bind(('0.0.0.0', LISTEN_PORT)) print(f"DNS proxy running on port {LISTEN_PORT}") while True: data, addr = sock.recvfrom(512) handle_dns_request(data, addr, sock) if __name__ == '__main__': main()
- 启动脚本后,把
sample.somedomain.com和test.anotherdomain.com的NS记录指向运行这个代理的服务器IP,这样所有针对这两个域名的TXT查询都会返回你预设的内容。
二、基于CNAME的特殊实现(不推荐,需自定义扩展)
如果你一定要保留CNAME指向mydomain.example.com的结构,那需要你的DNS代理服务器能追踪原始查询的域名——但这里有个问题:标准DNS递归查询中,当递归服务器发现sample.somedomain.com是CNAME后,会直接查询mydomain.example.com的TXT,这时候你的代理收到的查询请求域名是mydomain.example.com,根本不知道原始请求是来自sample还是test。
要解决这个,只能做特殊处理:
- 让所有客户端直接使用你的代理作为递归DNS服务器,这样代理能看到原始的查询域名(比如客户端直接查
sample.somedomain.com的TXT) - 在代理中添加逻辑:当收到
sample.somedomain.com的TXT查询时,忽略它的CNAME记录,直接返回对应的TXT内容(相当于“绕过”CNAME跳转)
比如用PowerDNS的Lua脚本后端实现这个逻辑:
function pdns_records(dq) -- 只处理TXT类型查询 if dq.qtype == pdns.TXT then local qname = dq.qname:toString() -- 根据原始查询域名返回对应TXT记录 if qname == "sample.somedomain.com." then return { { content = '"sample-TXT-content"', qtype = pdns.TXT, ttl = 300 } } elseif qname == "test.anotherdomain.com." then return { { content = '"test-TXT-content"', qtype = pdns.TXT, ttl = 300 } } end end -- 其他类型/域名的查询,返回nil让PowerDNS用默认逻辑处理 return nil end
然后配置PowerDNS使用这个Lua后端,同时确保客户端的DNS设置指向你的PowerDNS服务器。
你之前尝试失败可能的原因
- 没有捕获到原始查询域名:如果你的代理只是作为
mydomain.example.com的权威DNS,那收到的查询都是针对mydomain的,根本不知道是哪个CNAME跳转过来的 - 违反了CNAME和其他记录共存的规则:你可能尝试给设了CNAME的域名同时加TXT记录,这在DNS标准里是不允许的,递归服务器会直接忽略TXT记录
备注:内容来源于stack exchange,提问作者venkat S
相关产品推荐
相关产品推荐

