<acronym id="s8ci2"><small id="s8ci2"></small></acronym>
<rt id="s8ci2"></rt><rt id="s8ci2"><optgroup id="s8ci2"></optgroup></rt>
<acronym id="s8ci2"></acronym>
<acronym id="s8ci2"><center id="s8ci2"></center></acronym>
0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

Go的 DNS Lookup 的接口語義

Linux愛好者 ? 來源:Linux愛好者 ? 作者:Linux愛好者 ? 2022-10-25 16:28 ? 次閱讀

背景分享

遇到過這么一個問題,有童鞋的 Go 程序用 DNS 解析做服務發現(內網用的 CoreDNS 做的域名解析服務器)。比如,內網有個服務域名,對應 7 個后端節點。為了做服務發現,故障的剔除等服務,在 Client 端對一個給定的域名調用 Go 標準庫的 Resolver.LookupHost 方法來解析 ip 列表。如果解析得到的 ip 列表有變化,那么在 Client 內對相應的對后端節點的鏈接做創建和銷毀。

addrs,err:=resolver.LookupHost(ctx,/*某服務域名A*/)

//addrs的結果會變化,一會返回6個ip,一會返回7個ip

就是這么一個典型的服務發現的應用場景,還是精準踩坑。那什么坑?

坑就是:解析得到的 ip 列表反復變化,導致反復創、刪連接和對應的結構體。讓人誤以為 DNS 的后端節點一直在故障,從而導致一系列的問題。

還遇到另一個有趣的問題:同一份業務代碼,Go 1.15 編譯的版本總會頻繁截斷成 6 個 ip ,Go 1.16 以上的版本則非常穩定,一直返回 7 個 ip ? 這又是為啥呢。

這個問題很簡單,但其實也很隱蔽。因為很少人會這么用,也很少人會注意到這個問題。

Go 的 DNS Lookup 的接口語義

先看下 Go 標準庫的接口語義,看下 Resolver.LookupHost 在 Go 的注釋怎么說的。文件在 Go 的標準庫 net/lookup.go :

//LookupHostlooksupthegivenhostusingthelocalresolver.
//Itreturnsasliceofthathost'saddresses.
func(r*Resolver)LookupHost(ctxcontext.Context,hoststring)(addrs[]string,errerror){
//...
}

LookupHost 查詢一個給定的域名,返回值是一個地址列表。注意:它并沒有保證,要返回該域名的所有 ip 列表。 所以啊,這本來就是用法不對,Go 的接口沒聲明說要返回全部的 ip 。哪怕有域名對應有 100 個 ip ,這個接口只返回 1 個也是對的。

Go 1.15 和 Go 1.16之上的區別 ?

域名對應 7 個 ip ,同一份解析代碼, Go 1.15 編譯的程序時而返回 6 個?但 Go 1.16 之上的版本編譯則總是 7 個,感覺非常穩定。為什么呢?

筆者還真翻了一下 Go 1.15 和 Go 1.16 的區別,DNS 解析的代碼幾乎一致,只在 dnsPacketRoundTrip 函數中,改了一個 buffer 的大小。

Go 1.15 是這樣的( 文件:src/net/dnsclient_unix.go ):

funcdnsPacketRoundTrip(cConn,iduint16,querydnsmessage.Question,b[]byte)(dnsmessage.Parser,dnsmessage.Header,error){
//發送請求
if_,err:=c.Write(b);err!=nil{
}

//創建一個裝響應包的buffer
b=make([]byte,512)//seeRFC1035
for{
//讀取dns響應
n,err:=c.Read(b)
//...
returnp,h,nil
}
}

Go 1.16 是這樣的( 文件:src/net/dnsclient_unix.go ):

const(
//MaximumDNSpacketsize.
//Valuetakenfromhttps://dnsflagday.net/2020/.
maxDNSPacketSize=1232
)

funcdnsPacketRoundTrip(cConn,iduint16,querydnsmessage.Question,b[]byte)(dnsmessage.Parser,dnsmessage.Header,error){
//發送請求
if_,err:=c.Write(b);err!=nil{
}

//創建一個裝響應包的buffer
b=make([]byte,maxDNSPacketSize)
for{
//讀取dns響應
n,err:=c.Read(b)
//...
returnp,h,nil
}
}

函數邏輯是發送請求給 DNS Server ,并等待它的響應。兩個版本完全一致,只有 buffer 的大小不一樣,Go 1.16 之上用了 1232 這個大小。請注意,這個大小其實是有講究的,這個值是在盡量避免 IP 包分片又能盡量多裝數據而拍的一個值。詳細看 DNS FLAG DAY 2020[1] 。

這就是 Go 1.15 ,Go 1.16 版本在內網域名解析中的差異。DNS 服務端雖然發了 7 個 ip 過來,但是 Go 1.15 編譯的版本用 512 個字節 buffer 裝不下,只解析到 6 個有效 ip,Go 1.16 版本則好點,客戶端用的 1232 個字節的 buffer 大一點,差別就在這個地方。

這里有個細節提一下:

DNS 的協議,Message 的 Header 有四個字段 QDCOUNT,ANCOUNT,NSCOUNT,ARCOUNT,是指明了數據包里各個 Record 有多少個,Answer 有多少個的。但是在協議實現的時候,往往不依賴于這幾個字段,因為它們可能被偽造攻擊。所以解析的 ip 列表都是按照實際解析結果來的,解析到多少個就多少個,而不是 Header 里聲明了多少個。

//Qdcount,Ancount,Nscount,Arcountcan'tbetrusted,astheyare
//attackercontrolled.

簡單說下 DNS

DNS 協議默認使用 UDP 協議作為其傳輸層協議。UDP 的數據包是有限制的,DNS 的消息大小也是有限制的,基本大小限制為 512 字節,長消息會被截斷并且設置標記位。

所以,DNS 協議本身就從來沒承諾過,給你解析完整的 IP 列表。它這個名字對應的 IP 而已,至于全不全,它從沒承諾過。

本文并不詳細介紹 DNS 協議的原理。詳細見 RFC 1035[2] 和相關的文檔。為了突破數據包大小,或者其他的限制,也有擴展協議 EDNS ,可以參考 RFC 6891[3] 。

總之,用 DNS 解析 ip 這種方式來替代 consul 這種服務發現。感覺還是有欠缺的,或者說它的使用場景是不一樣的。

總結

Go 默認的解析方式其實有兩種,一種是 cgo 的方式調用 libc 庫的函數去解析,一種是 Go 自己的實現。本文討論的是默認的 Go 的方式。

DNS 做服務發現好像并不合適,和 consul 等組件不同。它有自己特定的協議約束著,如果一定要用 DNS 來做服務發現,那么請千萬要注意本文提到的知識點。

DNS 解析的 ip 列表,并不承諾它是全的。如果業務想用來做服務發現和剔除的功能,請千萬牢記。

DNS 服務端和客戶端的行為配合缺一不可,服務端會不會發全部?客戶端能不能收全部?各種差異都會導致解析出來的 ip 可能不一樣。

審核編輯:彭靜
聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 接口
    +關注

    關注

    33

    文章

    7737

    瀏覽量

    148699
  • 服務器
    +關注

    關注

    12

    文章

    8178

    瀏覽量

    82720
  • 編譯
    +關注

    關注

    0

    文章

    622

    瀏覽量

    32417

原文標題:DNS 做服務發現,是坑嗎 ?

文章出處:【微信號:LinuxHub,微信公眾號:Linux愛好者】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    基于OWL屬性特征的語義檢索研究

    【來源】:《電子設計工程》2010年02期【摘要】:在文獻檢索中,概念的語義相似度計算直接影響查準率和查全率指標。將本體描述語言OWL(Web Ontology Language)的屬性特征有機結合
    發表于 04-24 09:48

    什么是域名DNS

    什么是域名DNS為什么要注冊DNS呢,申請了DNS后,客戶可以自己為域名作解析,或增設子域名.客戶申請DNS時,建議客戶一次性申請兩個。 在國際域名網網站上注冊域名,一般都是
    發表于 07-19 00:13

    語義機器人

    人工智能將迎來語義理解新時代。打破了傳統人工智能在語言交互方面反射式的應答方式,成功地通過獨創的中文語義理解算法,讓計算機可以準確理解語言環境,進行上下文處理、口語處理、省略處理。該平臺可用于構建
    發表于 03-10 16:52

    使用JavaScript代碼在Rapid板子上實現DNS解析域名得到IP地址操作分享!

    function key_cb(name){print(name);dns.lookup(“bbs.o2ee.com”, dns_cb);}key.on(key_cb);function loop
    發表于 08-15 04:17

    為什么編譯時有Warning說這個函數有定義未聲明?

    在LWIP1.3里面dns.c里面有定義了一個static u32_t dns_lookup(const char *name){。。。。}并且在dns.h里面進行了聲明static u32_t
    發表于 10-30 22:29

    DNS錯誤

    嗨,我試著使用DNS,但是總是會遇到DNS錯誤。我總是收到“DNS錯誤發生”消息。使用TCP/IP棧v5.41我有什么問題嗎?問候彼得
    發表于 04-20 06:14

    什么是DNS

    什么是DNS  英文縮寫: DNS 中文譯名: 域名系統 分  類: IP與多媒體 解  釋: 遍布于因特網的數據庫。它
    發表于 02-22 17:25 ?1053次閱讀

    DNS是什么DNS原理入門指南資料概述

    DNS 是互聯網核心協議之一。不管是上網瀏覽,還是編程開發,都需要了解一點它的知識。本文詳細介紹DNS的原理,以及如何運用工具軟件觀察它的運作。我的目標是,讀完此文后,你就能完全理解DNS。
    的頭像 發表于 02-03 08:58 ?5042次閱讀

    DNS服務器和DNS服務器地址是什么

    今日就來同大家分享什么是DNS服務器地址,DNS服務器地址怎么找,幫助大家更了解DNS服務器。首先,我們一起來聊聊什么是DNS服務器,什么是DNS
    的頭像 發表于 03-30 15:57 ?7956次閱讀

    DNS污染是是什么,DNS污染怎么解決

    DNS污染是指有意或無意進行的域名服務器分組,將域名指向錯誤的IP地址。 什么是DNS污染? DNS污染有哪些處理方法 一般而言,網站通常在Internet上具有可靠的域名服務器,但是為了減少
    發表于 04-19 09:43 ?1w次閱讀

    Tcp-DNS-proxy TCP DNS代理

    Tcp-DNS-proxy.zip
    發表于 04-29 10:44 ?2次下載
    Tcp-<b class='flag-5'>DNS</b>-proxy TCP <b class='flag-5'>DNS</b>代理

    DNS基本概述

    與 HTTP、FTP 和 SMTP 一樣,DNS 協議也是一種應用層的協議,DNS 使用客戶-服務器模式運行在通信的端系統之間,在通信的端系統之間通過 UDP 運輸層協議來傳送 DNS 報文。
    的頭像 發表于 05-25 10:49 ?2488次閱讀

    dns是什么意思 dns作用是什么介紹

    dns是什么意思 dns作用是什么介紹
    發表于 10-17 14:44 ?0次下載

    介紹時序分析的基本概念lookup table

    今天要介紹的時序分析基本概念是lookup table。中文全稱時序查找表。
    的頭像 發表于 07-03 14:30 ?800次閱讀
    介紹時序分析的基本概念<b class='flag-5'>lookup</b> table

    DNS服務器是什么?有哪些類型?

    每當我們單擊網站上的鏈接時,我們的計算機都會搜索其DNS信息。DNS是互聯網地址的數據庫。在互聯網上搜索信息時,我們會提交DNS請求。DNS只是與IP相對應的名稱列表,計算機通過IP進
    的頭像 發表于 08-14 17:40 ?1559次閱讀
    亚洲欧美日韩精品久久_久久精品AⅤ无码中文_日本中文字幕有码在线播放_亚洲视频高清不卡在线观看
    <acronym id="s8ci2"><small id="s8ci2"></small></acronym>
    <rt id="s8ci2"></rt><rt id="s8ci2"><optgroup id="s8ci2"></optgroup></rt>
    <acronym id="s8ci2"></acronym>
    <acronym id="s8ci2"><center id="s8ci2"></center></acronym>