[轉]自定義go的http client 的DNS解析服務器地址,Custom DNS resolver for the default HTTP client in Go


原文:https://koraygocmen.com/blog/custom-dns-resolver-for-the-default-http-client-in-go

https://koraygocmen.medium.com/custom-dns-resolver-for-the-default-http-client-in-go-a1420db38a5d

 

 

 

 

 

 將8.8.8.8:53改成某個不可以的ip, 則會失敗!!

 

 

 

 注釋掉這行,就會用系統默認的dns設置。 也是可以訪問網頁“https://www.violetnorth.com” 成功的

 

 

 

 

 

 

__________________________________________________________________________

 

 

 

客戶端發起http請求,基本的經歷過程如下:

域名解析 -> TCP三次握手 -> 建立TCP連接后發起HTTP請求 -> Nginx反向代理 -> 應用層 -> 服務層 -> 緩存/數據庫

一、域名解析

首先Chrome瀏覽器會解析 www.linux178.com 這個域名(准確的叫法應該是主機名)對應的IP地址。怎么解析到對應的IP地址?

① Chrome瀏覽器 會首先搜索瀏覽器自身的DNS緩存(緩存時間比較短,大概只有1分鍾,且只能容納1000條緩存),看自身的緩存中是否有www.linux178.com 對應的條目,而且沒有過期,如果有且沒有過期則解析到此結束。

    注:我們怎么查看Chrome自身的緩存?可以使用 chrome://net-internals/#dns 來進行查看

② 如果瀏覽器自身的緩存里面沒有找到對應的條目,那么Chrome會搜索操作系統自身的DNS緩存,如果找到且沒有過期則停止搜索解析到此結束.

     注:怎么查看操作系統自身的DNS緩存,以Windows系統為例,可以在命令行下使用 ipconfig /displaydns 來進行查看  

③ 如果在Windows系統的DNS緩存也沒有找到,那么嘗試讀取hosts文件(位於C:\Windows\System32\drivers\etc),看看這里面有沒有該域名對應的IP地址,如果有則解析成功。

④ 如果在hosts文件中也沒有找到對應的條目,瀏覽器就會發起一個DNS的系統調用,就會向本地配置的首選DNS服務器(一般是電信運營商提供的,也可以使用像Google提供的DNS服務器)發起域名解析請求(通過的是UDP協議向DNS的53端口發起請求,這個請求是遞歸的請求,也就是運營商的DNS服務器必須得提供給我們該域名的IP地址),運營商的DNS服務器首先查找自身的緩存,找到對應的條目,且沒有過期,則解析成功。如果沒有找到對應的條目,則有運營商的DNS代我們的瀏覽器發起迭代DNS解析請求,它首先是會找根域的DNS的IP地址(這個DNS服務器都內置13台根域的DNS的IP地址),找打根域的DNS地址,就會向其發起請求(請問www.linux178.com這個域名的IP地址是多少啊?),根域發現這是一個頂級域com域的一個域名,於是就告訴運營商的DNS我不知道這個域名的IP地址,但是我知道com域的IP地址,你去找它去,於是運營商的DNS就得到了com域的IP地址,又向com域的IP地址發起了請求(請問www.linux178.com這個域名的IP地址是多少?),com域這台服務器告訴運營商的DNS我不知道www.linux178.com這個域名的IP地址,但是我知道linux178.com這個域的DNS地址,你去找它去,於是運營商的DNS又向linux178.com這個域名的DNS地址(這個一般就是由域名注冊商提供的,像萬網,新網等)發起請求(請問www.linux178.com這個域名的IP地址是多少?),這個時候linux178.com域的DNS服務器一查,誒,果真在我這里,於是就把找到的結果發送給運營商的DNS服務器,這個時候運營商的DNS服務器就拿到了www.linux178.com這個域名對應的IP地址,並返回給Windows系統內核,內核又把結果返回給瀏覽器,終於瀏覽器拿到了www.linux178.com  對應的IP地址,該進行一步的動作了。

注:一般情況下是不會進行以下步驟的

如果經過以上的4個步驟,還沒有解析成功,那么會進行如下步驟(以下是針對Windows操作系統):

⑤ 操作系統就會查找NetBIOS name Cache(NetBIOS名稱緩存,就存在客戶端電腦中的),那這個緩存有什么東西呢?凡是最近一段時間內和我成功通訊的計算機的計算機名和Ip地址,就都會存在這個緩存里面。什么情況下該步能解析成功呢?就是該名稱正好是幾分鍾前和我成功通信過,那么這一步就可以成功解析。

⑥ 如果第⑤步也沒有成功,那會查詢WINS 服務器(是NETBIOS名稱和IP地址對應的服務器)

⑦ 如果第⑥步也沒有查詢成功,那么客戶端就要進行廣播查找

⑧ 如果第⑦步也沒有成功,那么客戶端就讀取LMHOSTS文件(和HOSTS文件同一個目錄下,寫法也一樣)

如果第八步還沒有解析成功,那么就宣告這次解析失敗,那就無法跟目標計算機進行通信。只要這八步中有一步可以解析成功,那就可以成功和目標計算機進行通信。

 

————————————————————————————————————

Custom DNS resolver for the default HTTP client in Go

 

The default HTTP client in Go uses the default DNS resolver available on the machine. There are some cases where you might want to use a different DNS resolver.
I want to quickly show how you can change the DNS resolver for the default HTTP client. We are using this same method for our custom DNS resolver in my company: Violetnorth

 

 

Changing DNS resolver
package main import ( "context" "io/ioutil" "log" "net" "net/http" "time" ) func main() { var ( dnsResolverIP = "8.8.8.8:53" // Google DNS resolver. dnsResolverProto = "udp" // Protocol to use for the DNS resolver dnsResolverTimeoutMs = 5000 // Timeout (ms) for the DNS resolver (optional) ) dialer := &net.Dialer{ Resolver: &net.Resolver{ PreferGo: true, Dial: func(ctx context.Context, network, address string) (net.Conn, error) { d := net.Dialer{ Timeout: time.Duration(dnsResolverTimeoutMs) * time.Millisecond, } return d.DialContext(ctx, dnsResolverProto, dnsResolverIP) }, }, } dialContext := func(ctx context.Context, network, addr string) (net.Conn, error) { return dialer.DialContext(ctx, network, addr) } http.DefaultTransport.(*http.Transport).DialContext = dialContext httpClient := &http.Client{} // Testing the new HTTP client with the custom DNS resolver. resp, err := httpClient.Get("https://www.violetnorth.com") if err != nil { log.Fatalln(err) } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { log.Fatalln(err) } log.Println(string(body)) } 
It only takes a few lines but you have to overwrite the Dial function in the Resolver which is inside the Dialer which is inside the Transport function. It might seem weird but it actually makes a lot of sense, follow the functions from top to bottom, DefaultTransport -> DialContext -> Dialer -> Resolver -> Dial We are changing the Dial function which dials the DNS server to resolve the request, so it should be inside the Resolver. But this whole thing is in the DialContext of the actual HTTP request. You have to dial the DNS resolver first, resolve the IP, then dial that resolved IP to make the HTTP request.
Anyways that's pretty much it. Changing the DNS resolver in the default HTTP client.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM