在互联网业务中,时常遇到客户端无法正常解析域名的情况,而获取客户端dns服务器配置有助于及时分析问题进而保障客户体验。
对于技术人员来说,获取客户端服务器地址的方法大概有以下几种:
- 打开终端,使用命令ipconfig /all获取
- 对于将路由器地址(比如192.168.0.1)作为客户端DNS服务器地址的情况,可以登录路由器检查配置情况
- 也可以通过已有的网站,例如https://ip.skk.moe/,查看“DNS”出口查询栏目获得。
那么,我们是否有方法可以搞一搞一个方案,可以获取终端的DNS服务器地址呢?
就这个问题,咨询了GPT,其给了一段代码,可以直接返回当前来解析DNS的客户端的地址。代码如下:
#!/bin/env python3
import socket
import dnslib
def handle_dns_request(data, client_address):
"""
Handle the DNS request and return a response with the client's IP address as A record.
"""
try:
# Parse the DNS request
request = dnslib.DNSRecord.parse(data)
# Get the client's IP address
client_ip = client_address[0]
# Create a DNS response
response = dnslib.DNSRecord(
dnslib.DNSHeader(id=request.header.id, qr=1, aa=1, ra=1),
q=request.q
)
# Add the A record with the client's IP
response.add_answer(dnslib.RR(
rname=request.q.qname,
rtype=dnslib.QTYPE.A,
rclass=dnslib.CLASS.IN,
ttl=1,
rdata=dnslib.A(client_ip)
))
with open("./getdnsserver.log","w") as f:
f.write(client_ip)
return response.pack()
except Exception as e:
print(f"Error handling request: {e}")
return None
def start_dns_server(address='0.0.0.0', port=53):
"""
Start a simple DNS server that returns the client's IP address in A records.
"""
with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as server_socket:
server_socket.bind((address, port))
print(f"DNS Server started on {address}:{port}")
try:
while True:
data, client_address = server_socket.recvfrom(512)
print(f"Received request from {client_address}")
response = handle_dns_request(data, client_address)
if response:
server_socket.sendto(response, client_address)
except KeyboardInterrupt:
print("DNS Server stopped")
# Start the DNS server (Note: This requires root privileges for port 53)
start_dns_server()
# The above line is commented out to prevent the server from starting automatically in this environment.
# You can uncomment it and run in your local environment with appropriate permissions.
打包软件
pyinstaller -F main.py
打包容器
#Dockerfile
#FROM alpine:3.14
FROM ubuntu:22.04
WORKDIR /app
COPY ./dist/main /app/main
ENTRYPOINT ["./main"]
version: '3'
services:
getdnsserver:
image: zzlyzq/getdnsserver:1.0
volumes:
- ./getdnsserver.log:/app/getdnsserver.log
build:
context: ./
dockerfile: Dockerfile
container_name: getdnsserver
restart: always
ports:
- "53:53/udp"
networks:
getdnsserver-network:
ipv4_address: 172.18.26.31
# entrypoint:
# - sh
# - -euc
# - sleep 600
networks:
getdnsserver-network:
driver: bridge
ipam:
config:
- subnet: 172.18.26.0/24
测试效果
使用本地直接测试,无论测试什么域名,总会返回返回访问该程序的SRC IP地址。
将程序部署到公网服务器
对于我的域名sddts.cn
设置一个A记录,将dnscheck.sddts.cn CNAME hk.hlab.sddts.cn
设置一个NS记录,将check.sddts.cn NS dnscheck.sddts.cn
这样,当用户解析所有xx.check.sddts.cn 都会去dnscheck.sddts.cn服务器去进行DNS解析,而会得到终端DNS服务器地址。
当然,这个地方虽然我们本地配置的可能是119.29.29.29,但是去获取xx.check.sddts.cn的SRC IP不一定是119.29.29.29,而是其周围相关的IP地址。
另外,经过一段时间测试,使用公共的DNS服务器119.29.29.29解析xx.check.sddts.cn后,陆续还会有一批地址去解析,而这些地址可能是北京、上海、广州的腾讯云(移动)相关的地址。