天天看點

如何突破DNS封包的512位元組限制

“DNS協定大家都應該很熟悉,最近有同學問到如何獲得UDP承載的超過512位元組的DNS封包,借此機會,我們一起了解下DNS協定與封包長度有關的一些細節。”

本文将讨論的是DNS協定在UDP承載時超過512位元組的這一細節。

在之前的文章裡,對DNS協定進行了介紹:

使用Wireshark進行DNS協定解析

Windows下的DNS指令用法

看完這兩篇文章,大家應該對DNS協定有一些初步的了解。對DNS協定而言,在IETF網站上,能夠很容易地擷取到相關的RFC文檔及擴充資訊。

在大部分講解DNS協定的文章裡,都會這樣描述DNS協定的特性:

當封裝的DNS響應的長度超過512位元組時,協定應采用TCP傳輸,而不是UDP。

根據協定标準文檔RFC1035,這當然是對的,實際使用DNS協定的過程中,抓取的封包也确實是這樣的,但是,不要忘記這份RFC文檔産生于三十年前,這麼多年,随着網絡環境的變化,協定是會發展的,大家想想,網絡上是不是到處都是超過512位元組的UDP資料呀,那超過512位元組的UDP DNS又有何不可?

RFC 6891這份标準文檔,對DNS進行了擴充,描述了超過512位元組的DNS的情況,即EDNS0。

本文将首先描述DNS協定的長度限制情況,然後對EDNS0進行說明,接着用示例說明DNS工具在超過512位元組時的通常情況,最後将介紹如何友善地産生超過512位元組的UDP承載的DNS封包。大家可以根據需要,跳到對應章節查閱。

01

DNS的512位元組限制

根據協定标準,DNS協定同時占用UDP和TCP的53端口,這是為什麼呢?

翻閱DNS資料,可以發現,DNS協定預設按UDP傳輸,為優化傳輸性能,DNS協定有一個512位元組的限制,當資料長度超過了512位元組時,DNS協定會改用TCP進行傳輸。

DNS協定從UDP切換到TCP的過程如下:

1、用戶端向伺服器發起UDP DNS請求;

2、如果伺服器發現DNS響應資料超過512位元組,則傳回UDP DNS響應中置truncated位,告知用戶端改用TCP進行重新請求;

3、用戶端向伺服器發起TCP DNS請求;

4、伺服器傳回TCP DNS響應。

那為什麼限制是512位元組呢?

一個說法是:IPV4标準規定了各個主機必須能夠重組576位元組或更少位元組的資料包。具有512位元組内容的DNS封包加上IP頭和UDP頭,将小于576位元組。

02

EDNS0

EDNS0:即Extension Mechanisms for DNS (EDNS(0)),詳細情況可參考RFC 6891這份文檔。

EDNS0是随着網絡的發展,在DNS消息格式和它支援的消息内容已不足以滿足一些DNS伺服器的需求的情況下被提出的,它用于傳遞包大小,擴充了DNS協定。

EDNS0是在遵循已有的DNS消息格式的基礎上增加一些字段,來支援更多的DNS請求業務。當然,具備向後相容性,未支援EDNS0的舊的DNS伺服器仍然能夠很好地處理EDNS0。

EDNS0特征如下:

擴充DNS使用UDP傳輸時的最大封包限制,可以超過512位元組 

擴充RCODE,由4為增加到12位 

建議利用域名标簽類型的剩餘兩個

我們在這裡關注的是ENDS0突破DNS 512位元組限制的能力。

DNS協定在發起請求時,通過在Additional部分增加OPT RR字段,告知伺服器能處理的最大UDP封包長度,當伺服器準備進行回應時,如果響應資料大于該值,則在DNS協定中置truncated位,否則,可發送小于該值大小的封包。這相當于突破了512位元組的長度限制。

在ENDS0标準文檔中,很容易找到OPT RR字段的格式:

各字段如下:

NAME:目前為空

TYPE:OPT RR的類型編号,41

CLASS:最大UDP封包長度

TTL:擴充的DNS消息頭部

RDLEN:緊接着的RDATA的長度

RDATA:可變部分資料。

RDATA格式如下:

說明如下:

OPTION-CODE:由IANA配置設定

OPTION-LENGTH:OPTION-DATA的長度

OPTION-DATA:具體内容

而TTL則是用來存儲擴充消息頭部中的RCODE和flags,格式如下:

EXTENDED-RCODE:擴充RCODE(傳回狀态碼),這8個bit加上DNS頭部的4bit總共有12bit(8bit在高位),這樣就可以表示更多的傳回類型

VERSOION:EDNS的版本

DO:DNSSEC OK,見相關RFC文檔定義

Z:一般被發送者設定為0,接收方可以忽略它

是以,隻要在進行DNS請求時,設定了OPT RR的CLASS值,則當響應超過了512位元組,但未超過該值時,會仍然使用UDP進行傳輸。

03

DNS超過512位元組時正常互動

在進行示例之前,我們首先要找到能夠産生超過512位元組DNS封包的域名及DNS伺服器。這是由于大部分的DNS響應都不會很長,而同時,不同的DNS伺服器緩存的DNS資料是有差異的。

經過搜集,我們選取了微軟的DNS伺服器之一:208.84.2.53,同時,選取了進行示例的域名:outlook.com。

正常的DNS請求,不會設定OPT RR的CLASS值,是以會預設在DNS封包大于512位元組時,換用TCP傳輸。

正常DNS互動的實力,選擇使用windows自帶的nslookup服務進行,指令如下:

nslookup -qt=ANY outlook.com 208.84.2.53

使用Wireshark抓包可看到封包如下:

可以看到,DNS在UDP傳輸之後自動進行了TCP DNS請求,響應體長度達到1010位元組。

自動進行的關鍵是UDP的DNS響應封包裡給truncated進行了置位:

是以,我們隻需要找到超過512位元組DNS響應的域名及DNS伺服器,就能很容易擷取到DNS TCP的封包。

04

DNS突破UDP 512位元組限制

對于超過512位元組的DNS UDP封包,就不是那麼容易獲得的。一個簡單的辦法是,到骨幹網絡上去抓包,抓取DNS伺服器之間的DNS同步封包。當然,對很多分析DNS協定的朋友,這不現實。

這裡,将介紹一種在PC上産生超過512位元組的UDP DNS封包的辦法。

使用的仍然是前一節的DNS域名和伺服器。

這裡,需要找到設定DNS協定的OPT RR的CLASS值的方法,很幸運,有這樣的工具存在,即dig這個小工具,一款Linux下用于檢視域名詳情的小工具,類似于nslookup,但功能更強大。dig也存在Windows版,它包含在BIND工具包中,BIND工具包可以在BIND官網下載下傳,位址如下:https://www.isc.org/downloads/

在頁面下方即可找到BIND各個版本的下載下傳按鈕。

下載下傳好bind包,解壓後,直接指令行進入解壓目錄,即可使用dig進行DNS請求,為構造UDP的DNS大包,設定了參數+notcp以及+bufsize=1400:

dig.exe @208.84.2.53 outlook.com ANY IN +notcp +bufsize=1400

wireshark擷取到封包如下:

沒有從UDP跳轉為TCP進行DNS請求,而是直接在UDP中傳回了完整的DNS資料。

其中請求如下:

在OPT RR中,設定了UDP的payload size 1400。

響應如下:

響應體達1031位元組。

很容易地,就設定了DNS協定的OPT RR的CLASS值。進而獲得了超過512位元組的UDP承載的DNS協定封包。

05

總結