有專家見解:"支援ECS的 recursive DNS resolver 可將DNS請求來源(DNS request client)的IP subnet(網段即可,不一定要精準到IP)附加到DNS query內提交給ADNS (authoritative DNS server),以便ADNS判斷最佳回應"
2018/11月就告訴我,我到今天(1/30日)才看到...
得證:夠偷懶....
當時因為工作翻牆出來,從CDN的觀念查到這個
到今天新聞:一些google、IBM等等的DNS開始要支援EDNS
我又再度翻了一遍..
解釋:
在台灣,這沒啥用處
在大陸,這用處可大了
不過遇到電信、聯通自己不願意公開自己DNS給別人,那也沒啥用處
來源:http://noops.me/?p=653
DNS support edns-client-subnet
2,020 瀏覽看了2天RFC,終於讓DNS支持edns-client-subnet協議,通過google dns resolver的請求,可以獲取用戶的ip地址。
國內很多CDN和DNS提供商都已經實現了,但網上的中文資料比較少,所以在這裡分享一下,能力有限,錯誤之處還請諒解。
問題
- CDN使用DNS獲取查詢IP,根據IP對用戶進行地域調度。但這裡獲取的IP地址是DNS地址,而不是用戶真實的IP地址。
- 大多數情況下,我們假設用戶通過會使用離自己網絡最近的DNS resolver,CDN調度基本還是準確的。
- 但也有很多nameserver設置錯誤,或者用戶使用google public dns(nameserver 8.8.8.8/8.8.4.4)或opendns進行DNS resolver
- 國內用戶設置nameserver 8.8.8.8 (dig xxx.com @8.8.8.8)
- 我們得到的DNS query IP是74.125.16.208,判斷IP屬於美國,,,加利福尼亞州山景市谷歌公司
- 這個時候,我們的DNS會返回離美國加州最近的CDN節點IP給用戶。
- 國內用戶錯誤的調度到美國節點……
edns-client-subnet
- google提交了一份DNS擴展協議,允許DNS resolver傳遞用戶的ip地址給authoritative DNS server.
- CDN的DNS支持該協議,就可以獲取用戶真實的IP地址,進行準確的調度。
- OpenDNS和Google Public DNS已經支持了該協議,如果希望他們的query中帶有用戶IP,需要聯繫他們添加白名單。提供nameserver的hostname、ip以及可以 用來測試解析的域名即可,一般幾天就可以搞定。(註:我是晚上22:l00提交的申請,第二天10:00就已經生效了)
實現
一. 支持發送和接收edns-client-subnet的dig
注意上面的OPT PSEUDOSECTION
,已經可以發送和接收edns-client-subnet請求了二. 協議
- DNS協議
- DNS query會包含header和RR 2部分,這裡只介紹我們關注地方,網上可以搜到很多協議的介紹,比如這個http://archercai.blog.sohu.com/60779796.html
- header會描述本次請求中Questions、Answer RRs、Authority RRs和Additional RRs的數量,RR部分會詳細描述每個資源的內容,所有的RR格式是相同的,如下:
- 個人理解edns-client-subnet是對edns協議的擴展,附加在一個DNS請求的Additional RRs區域,這裡
重點描述edns-client-subnet的結構
- EDNS協議 Extension mechanisms for DNS (EDNS0):http://tools.ietf.org/html/draft-ietf-dnsind-edns0-01
- EDNS0每個字段的結構和描述如下:
- OPT 的值41,詳細的協議值如下:
- RDLENGTH描述RDATAD的長度,edns-client-subnet的詳細格式存在RDATA中,如下:
- OPTION-CODE: 2個字節
- OPTION-LENGTH: 2個字節,描述它之後的內容長度(BYTE)
- FAMILY: 2個字節,1表示ipv4, 2表示ipv6
- ADDRESS: 實際存放IP地址的地方,ipv4長度為4,google發送過來的長度一般為3,隱藏了ip地址最後一位
三. 開發
完成前2個步驟,就可以開搞了,邏輯很簡單:1. 判斷dns query是否包含Additional RRs,讀取NAME部分
2. 讀取10個字節(byte),判斷TYPE是否為41,rdlength > 8
3. 如果rdlength > 8,再讀取8個字節,對應OPTION-CODE(2)–>OPTION-LENGTH(2)–>FAMILY(2)–>SOURCE NETMASK(1)–>SCOPE NETMASK(1)
4. 讀取剩下的address,長度 rdlength – 8 或者 option-length – 4都行
註:讀取到的地址長度為4,可以用socket.inet_ntoa變成ip地址,如果不夠4個字節,需要後面補\x00
5. 獲取到的IP地址就可以用來進行判斷調度了
6. respond時也需要增加一個Additional RRs區域,直接把請求的Additional內容發過去就可以(
如果支持source netmask,將請求中的source netmask複製到scope netmask中
,OpenDNS要求必須支持scope netmask)四. 抓包
- 發包
- 發送dns query請求時,可以看到Questions:1, Additional RRs: 1
- Additional RRs中,type: 41(OPT), rdlength: 12 (google發過來的包,長度為11,沒有IP地址最後一位)
- 12 – OPTION-CODE(2) – OPTION-LENGTH(2) – FAMILY(2) – SOURCE NETMASK(1) – SCOPE NETMASK(1) = 4,IPV4 地址的大小
- 回包
- 發送dns query請求時,可以看到Questions:1, Answer RRs:1, Additional RRs: 1
- 發送dns query請求時,可以看到Questions:1, Answer RRs:1, Additional RRs: 1