因為項目的原因需要在客戶端啟動DNS服務,攔截本機DNS請求,考察了一下開源的DNS Server項目,適合在Windows下使用的只有CoreDNS。
說明
CoreDNS的項目地址
https://coredns.io
https://github.com/coredns/coredns
這是go語言寫的,所以默認支持大部分平台,在windows下有一些瑕疵(下面會說),但是總體已經是功能比較完整的一個DNS服務端實現。
使用
CoreDNS的使用很簡單,coredns.exe配合一個Corefile配置文件直接就可以運行。配置文件的格式類似於
# 監聽默認端口(53), .表示所有域名
. {
# 綁定lo網口,這樣啟動是靜默的,否則默認綁定0.0.0.0會彈出windows防火牆
bind 127.0.0.1
# hosts插件,自定義域名的解析,解析的域名少就直接用hosts插件完成需求,如果有大量自定義域名解析建議用file插件使用 符合RFC 1035規范的DNS解析配置文件
hosts {
10.6.6.2 somewhere.com
10.6.6.3 ip.com
10.10.0.2 m.baidu.com
# ttl
ttl 60
# 繼續執行
fallthrough
}
# 將走到這一步的所有解析請求轉發給192.168.10.1,這里可以配置多個地址,轉發時會同時對多個地址發起轉發
forward . 192.168.10.1:53
# 重載hosts配置 windows下不支持
# reload 10s
# 輸出錯誤
errors
# 輸出日志
#log . "{remote}:{port} - {>id} \"{proto} Request: {name} {type} {rsize} {rcode}\""
}
在命令行執行下面的命令啟動服務
coredns.exe -conf path\to\Corefile
然后新開一個窗口,驗證dns服務是否正常。注意這里第二個參數就是DNS服務器地址,要用127.0.0.1不能用localhost
nslookup www.baidu.com 127.0.0.1
編譯和定制
在Goland里可以直接通過go mod tidy && go build
編譯,在clone的代碼上直接編譯,產生的coredns.exe文件有60M。如果要減小文件尺寸,可以去掉一些不必要的插件。
插件的配置文件在plugin.cfg,可以將其中和k8s, aws相關的插件屏蔽,以下是我屏蔽插件后的列表
metadata:metadata
cancel:cancel
tls:tls
reload:reload
nsid:nsid
bufsize:bufsize
root:root
bind:bind
debug:debug
trace:trace
ready:ready
health:health
pprof:pprof
#prometheus:metrics
errors:errors
log:log
dnstap:dnstap
local:local
dns64:dns64
acl:acl
any:any
chaos:chaos
loadbalance:loadbalance
cache:cache
rewrite:rewrite
dnssec:dnssec
autopath:autopath
template:template
transfer:transfer
hosts:hosts
#route53:route53
#azure:azure
#clouddns:clouddns
#k8s_external:k8s_external
#kubernetes:kubernetes
file:file
auto:auto
secondary:secondary
etcd:etcd
loop:loop
forward:forward
grpc:grpc
#erratic:erratic
whoami:whoami
on:github.com/coredns/caddy/onevent
sign:sign
然后執行下面的命令就可以重新編譯
# 根據plugin.cfg更新插件配置
go generate
# 編譯
go build
這樣產生的coredns.exe只有25M大小
通過coredns.exe -plugins
命令可以看到包含插件的情況
coredns.exe -plugins
Server types:
dns
Caddyfile loaders:
flag
default
Other plugins:
dns.acl
dns.any
dns.auto
dns.autopath
dns.bind
dns.bufsize
dns.cache
dns.cancel
dns.chaos
dns.debug
dns.dns64
dns.dnssec
dns.dnstap
dns.errors
dns.etcd
dns.file
dns.forward
dns.grpc
dns.health
dns.hosts
dns.loadbalance
dns.local
dns.log
dns.loop
dns.metadata
dns.nsid
dns.pprof
dns.prometheus
dns.ready
dns.reload
dns.rewrite
dns.root
dns.secondary
dns.sign
dns.template
dns.tls
dns.trace
dns.transfer
dns.whoami
on
修改
因為要記錄解析結果,但是CoreDNS的日志輸出不包含解析結果,需要自己動手修改。這個修改在forward.go
在 ServeDNS() 方法下,在下面兩行之前
w.WriteMsg(ret)
return 0, nil
增加
for _, a := range ret.Answer {
if a.Header().Rrtype == dns.TypeA {
for _, b := range ret.Question {
log.Printf("%v ", b.Name)
}
log.Printf("IP: %v\n", a.(*dns.A).A.String())
} else if a.Header().Rrtype == dns.TypeAAAA {
for _, b := range ret.Question {
log.Printf("%v ", b.Name)
}
log.Printf("IP: %v\n", a.(*dns.AAAA).AAAA.String())
} else if a.Header().Rrtype == dns.TypeCNAME {
for _, b := range ret.Question {
log.Printf("%v ", b.Name)
}
log.Printf("CNAME: %v\n", a.(*dns.CNAME).Target)
} else if a.Header().Rrtype == dns.TypePTR {
log.Printf("PTR: %v\n", a.(*dns.PTR).Ptr)
} else {
log.Printf("Type: %v\n", a.Header().Rrtype)
}
}