Go语言网络编程: 模拟实现DNS服务器
环境: 两台虚拟机,不限系统
写在前面
DNS服务器是干什么的?DNS服务器(Domain Name Server,域名服务器)是进行域名和与之相对应的IP地址进行转换的服务器,保存了一张域名和与之相对应的IP地址 的表,以解析消息的域名。
在Linux上使用nslookup可以查询域名对应的IP
$ nslookup google.com Server: 114.114.114.114 Address: 114.114.114.114#53 Non-authoritative answer: Name: google.com Address: 142.251.43.14
初步环境搭建
目前有一台ubuntu虚拟机将作为DNS服务器,在ubuntu中执行命令 sudo lsof -i:53
,查看占用53端口的进程,强行关掉该进程,解除对UDP 53端口的占用。
另一台虚拟机系统为Linux Lite,后续将用来发送DNS请求。在ubuntu的终端中输入ifconfig
查看IP地址。
ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 inet 192.168.53.129 netmask 255.255.255.0 broadcast 192.168.53.255 inet6 fe80::f60:737c:cda6:87b2 prefixlen 64 scopeid 0x20<link> ether 00:0c:29:92:bc:64 txqueuelen 1000 (Ethernet)
于是ubuntu的IP地址为192.168.53.129
,将该地址作为Linux Lite的DNS服务器地址。
在Linux Lite的终端中输入sudo vim /etc/resolv.conf
,用管理员权限修改该文件,将nameserver
对应的IP修改为ubuntu的IP地址。
# Dynamic resolv.conf(5) file for glibc resolver(3) generated by resolvconf(8) # DO NOT EDIT THIS FILE BY HAND -- YOUR CHANGES WILL BE OVERWRITTEN # 127.0.0.53 is the systemd-resolved stub resolver. # run "systemd-resolve --status" to see details about the actual nameservers. nameserver 192.168.53.129 search localdomain
修改后的文件内容如上,这样Linux Lite的DNS查询会发到ubuntu上。
编写DNS服务器
使用github.com/miekg/dns
,可通过go get下载
DNS服务器将处理到来的DNS请求,并返回应答。
代码如下
package main import ( "github.com/miekg/dns" "log" "net" ) // 处理到来的请求 func handler(writer dns.ResponseWriter, req *dns.Msg) { var resp dns.Msg resp.SetReply(req) // 创建应答 for _, question := range req.Question { recordA := dns.A{ Hdr: dns.RR_Header{ Name: question.Name, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: 0, }, A: net.ParseIP("127.0.0.1").To4(), // 全部解析为127.0.0.1 } resp.Answer = append(resp.Answer, &recordA) // 写入应答 } err := writer.WriteMsg(&resp) // 回写信息 if err != nil { return } } func main() { dns.HandleFunc(".", handler) // 绑定函数 err := dns.ListenAndServe(":53", "udp", nil) // 启动 if err != nil { log.Println(err) } }
如上代码所示,首先调用HandleFunc,该函数的第一个参数是匹配的查询模式,第二个参数是处理函数。查询模式指示了处理函数将处理哪些请求,使用"."意味着handler
将处理所有请求。handler函数负责处理到来的请求,具有两个参数: ResponseWriter和请求本身。在该函数内部,首先要使用SetReply
创建响应消息并进行设置。
使用for 循环遍历请求中的每一个询问,使用A记录为每一个询问创建应答。使用append函数将指向A记录的指针添加到应答中,然后使用WriteMsg函数将消息写回客户端。
最后调用ListenAndServe启动DNS服务器,将所有的请求解析为127.0.0.1
测试
用管理员权限在ubuntu上运行程序,然后在Linux Lite的终端输入nslookup google.com
,即查询google.com的IP地址。
输出结果
Server: 192.168.53.129 Address: 192.168.53.129#53 Non-authoritative answer: Name: google.com Address: 127.0.0.1 Name: google.com Address: 127.0.0.1
被解析为了127.0.0.1
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!