輕鬆在 Go 中使用 Dot 解析域名
前言
最近在家無聊翻到了 Dot 跟 Doh 的相關技術文章。所以就想著能否在 Go 中使用自帶的包無侵入性的使用,由於我感覺 Doh 太過於雞肋所以決定看下 Dot
閱讀過 Dot 的一些實現原始碼後知道 Dot 只是對普通的 TCP Dns 請求套上一層 TLS 加密,這大大降低了我的開發難度 (原本以為很複雜)
準備工作
由於 Go 的net
標準庫下的元件都有良好的擴充套件性,我決定尋找 Go 是否開放了相關的實現
眾所周知net.Resolver
是 Go 中把域名轉換成 IP 的一個元件,它定義了一個 Dial
屬性,通過介紹知道他的主要作用是 用於建立TCP和UDP連線到DNS伺服器
,這不就是我想要的嗎!
正式開始
得到了關鍵資訊我決定先寫個列子
net.DefaultResolver.Dial = func(ctx context.Context, network, address string) (net.Conn, error) {
fmt.Println(network,address)
return nil,io.EOF
}
ip, err := net.LookupIP("www.baidu.com")
if err != nil {
panic(err)
}
fmt.Println(ip)
按照我想的執行上面的程式碼他會把 DNS 伺服器列印了並且獲取不了www.baidu.com
任何 DNS 記錄,但是當我執行後發現Dial
中沒有任何輸出並且 DNS 記錄成功的獲取了。why?我帶著疑問翻閱了相關原始碼
func (r *Resolver) lookupIP(ctx context.Context, network, host string) (addrs []IPAddr, err error) {
if r.preferGo() {
return r.goLookupIP(ctx, network, host)
}
order := systemConf().hostLookupOrder(r, host)
if order == hostLookupCgo {
if addrs, err, ok := cgoLookupIP(ctx, network, host); ok {
return addrs, err
}
// cgo not available (or netgo); fall back to Go's DNS resolver
order = hostLookupFilesDNS
}
ips, _, err := r.goLookupIPCNAMEOrder(ctx, network, host, order)
return ips, err
}
從原始碼中可知如果 preferGo = false && order = hostLookupCgo
就會呼叫 C 函式去獲取 DNS 記錄。閱讀 preferGo
函式的原始碼可得知 net.Resolver
定義了一個 PreferGo
的屬性來讓開發者決定用不用 Go 自帶的解析器,預設值會根據系統自動配置具體程式碼在net/conf.go
下的initConfVal
函式中實現的,由於我是 macos 他會預設關閉,原因可以檢視具體備註
// Darwin pops up annoying dialog boxes if programs try to do
// their own DNS requests. So always use cgo instead, which
// avoids that.
if runtime.GOOS == "darwin" || runtime.GOOS == "ios" {
confVal.forceCgoLookupHost = true
return
}
macos 或者 IOS 會有彈窗出現,我把 PreferGo
設定為true
後並沒有出現描述的彈窗可能這個彈窗只會在 IOS 上出現。
開啟後再次執行上面的程式碼得到了預期的內容,通過Dial
的備註得知如果呼叫後返回的是PacketConn
他就會傳送 UDP 資料包其他的則會傳送 TCP 資料包。這裡意味著不需要對 DNS 資料包做任何修改 (UDP 請求中不包含長度,TCP 則會有) 就能達到目的。
這裡我們稍微封裝下就能讓 Go 使用 Dot 進行域名解析
func main() {
net.DefaultResolver.PreferGo = true
net.DefaultResolver.Dial = func(ctx context.Context, network, address string) (net.Conn, error) {
return NewDnsOverTLSAdopter("223.5.5.5:853", nil)
}
ip, err := net.LookupIP("www.baidu.com")
if err != nil {
panic(err)
}
fmt.Println(ip)
}
func NewDnsOverTLSAdopter(addr string, config *tls.Config) (net.Conn, error) {
conn, err := tls.Dial("tcp", addr, config)
if err != nil {
return nil, err
}
if err = conn.Handshake(); err != nil {
return nil, err
}
return conn, nil
}
執行上面的程式碼我們會得到www.baidu.com
的 IP[110.242.68.3 110.242.68.4]
注意事項
上面程式碼中的 Dot 伺服器我使用的是 alidns 其實他是個域名但是我沒有使用原因如下
1.會造成程式無限遞迴的去解析域名 2.即使解決了無限遞迴的問題也會造成效能浪費本來 Dot 就已經相比普通 DNS 解析慢了,每次解析一個域名的時候還需要解析另一個域名。
還有不建議像我示例程式碼中那樣對 DefaultResolver
做修改
- 加微信實戰群請加微信(註明:實戰群):gocnio
相關文章
- 在BCB中輕鬆使用ActiveX控制元件 (轉)控制元件
- 使用 mDNS 在區域網中輕鬆發現系統DNS
- Go語言輕鬆進階Go
- 《Go輕鬆學》、《Go示例學》和《Go入門指南》Go
- 選擇GoDaddy,輕鬆進行域名轉移Go
- 爬蟲解析庫:XPath 輕鬆上手爬蟲
- 利用同構JavaScript輕鬆解析URLJavaScript
- 輕鬆使用Aspire rabbitmq frameworkMQFramework
- 微信域名防紅防封系統,輕鬆微信推廣域名被遮蔽問題
- iota 在 Go 中的使用Go
- 在.NET Framework中輕鬆處理XML資料(一) (轉)FrameworkXML
- 在.NET Framework中輕鬆處理XML資料(五) (轉)FrameworkXML
- Go 指標,如此輕鬆掌握,希望有收穫Go指標
- 在 Linux 中輕鬆搜尋和安裝 Google Web 字型LinuxGoWeb
- 在 laravel 中輕鬆容易的輸出完整的 sql 語句LaravelSQL
- 在.NET中輕鬆獲取系統資訊(1) -WMI篇 (轉)
- 微信域名防紅防封系統,輕鬆解決微信推廣域名被遮蔽問題
- 技術乾貨| 如何在MongoDB中輕鬆使用GridFS?MongoDB
- Linux中輕鬆使用USB移動儲存器(轉)Linux
- 輕鬆搞懂Java中的自旋鎖Java
- 基於 go-zero 輕鬆實現 JWT 認證GoJWT
- 在 Linux 中安全且輕鬆地管理 Cron 定時任務Linux
- DNS直接解析域名與泛域名解析DNS
- 辦公室革命,教你輕鬆搞定輕鬆玩轉ExcelExcel
- 有了證件照大師 輕鬆在ps中做證件照
- 在ASP.NET開發中輕鬆讓網頁彈出視窗ASP.NET網頁
- 帶你十天輕鬆搞定 Go 微服務系列(五)Go微服務
- 帶你十天輕鬆搞定 Go 微服務系列(六)Go微服務
- 帶你十天輕鬆搞定 Go 微服務系列(七)Go微服務
- 帶你十天輕鬆搞定 Go 微服務系列(一)Go微服務
- 帶你十天輕鬆搞定 Go 微服務系列(二)Go微服務
- 帶你十天輕鬆搞定 Go 微服務系列(三)Go微服務
- 帶你十天輕鬆搞定 Go 微服務系列(四)Go微服務
- [譯] 如何輕鬆地在樹莓派上使用深度學習檢測物件樹莓派深度學習物件
- 輕鬆使用 Linux Equinox 桌面環境LinuxUI
- iOS 輕鬆使用 App 資料統計iOSAPP
- 使用 Eloquent 輕鬆搜尋多個模型模型
- Power BI整合Power Apps,輕鬆實現使用者在報告中任意輸入資訊APP