欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

利用Java實(shí)現(xiàn)輕松解析DNS報(bào)文

 更新時(shí)間:2023年11月10日 08:25:48   作者:半夏之沫  
這篇文章主要為大家詳細(xì)介紹了如何利用Java實(shí)現(xiàn)輕松解析DNS報(bào)文,文中的示例代碼講解詳細(xì),具有一定的學(xué)習(xí)價(jià)值,感興趣的小伙伴可以跟隨小編一起了解一下

前言

最近在做網(wǎng)絡(luò)包分析的一個(gè)功能,其中有一點(diǎn)就是要判斷抓包期間應(yīng)用是否有存在異常的DNS解析行為,并且要寫在一個(gè)使用Java語言的后端服務(wù)中,由于之前使用Go語言做過類似的事情,所以我第一反應(yīng)就是這個(gè)應(yīng)該實(shí)現(xiàn)起來比較簡單,但是實(shí)際上手后,發(fā)現(xiàn)在Java中要拿到DNS報(bào)文還沒那么容易,當(dāng)然也有可能是我沒有找到正確的工具,如果有方便的工具,歡迎在評論區(qū)留言。那么本文就結(jié)合我如何從網(wǎng)絡(luò)包中拿到DNS報(bào)文,進(jìn)行一個(gè)簡單介紹。

一. DNS報(bào)文格式簡析

DNS報(bào)文本質(zhì)是UDP報(bào)文,UDP報(bào)文的格式如下所示。

DNS相關(guān)內(nèi)容,就體現(xiàn)在UDP報(bào)文載荷中。DNS報(bào)文分為DNS請求報(bào)文和DNS響應(yīng)報(bào)文,兩種報(bào)文結(jié)構(gòu)一樣,只是內(nèi)容稍有差別,如下是DNS報(bào)文的格式。

DNS報(bào)文內(nèi)容包含如下三個(gè)部分。

第一部分是基礎(chǔ)結(jié)構(gòu)部分,解釋如下。

  • Transaction ID。DNS報(bào)文的事務(wù)ID標(biāo)識,DNS請求報(bào)文和DNS響應(yīng)報(bào)文的Transaction ID是一樣的,故可以通過這個(gè)ID關(guān)聯(lián)DNS請求和響應(yīng)報(bào)文;
  • Flags。DNS報(bào)文的標(biāo)志,標(biāo)志由若干個(gè)含義不同的字段組成,較為常用的是第0位可以表示當(dāng)前是請求DNS報(bào)文還是響應(yīng)DNS報(bào)文,第12-15位可以表示響應(yīng)DNS報(bào)文的Reply Code;
  • Questions。問題數(shù),表示后面Queries的數(shù)量;
  • Answer RRs。回答資源記錄數(shù),表示后面Answers的數(shù)量;
  • Authority RRs。授權(quán)資源記錄數(shù),表示后面Authoritative nameservers的數(shù)量;
  • Additional RRs。附加資源記錄數(shù),表示后面Additional records的數(shù)量。

第二部分是問題部分,對應(yīng)Queries,該部分表示DNS查詢請求的問題信息,包含查詢的域名Name,查詢的類型Type和查詢的類Class,解釋如下。

Name。就是請求DNS解析的域名地址,這里的Name是一個(gè)不定長的字段,格式示意如下。

Type。表示DNS查詢的資源類型,Name字段結(jié)束后的兩個(gè)字節(jié)就是Type,通常關(guān)注較多的有0x0001,助記符是A,表示通過域名查詢IPv4地址,以及0x001C,助記符是AAAA,表示通過域名查詢IPv6地址;

Class。表示地址類型,通常為0x0001,表示互聯(lián)網(wǎng)地址。

第三部分是資源記錄部分,解釋如下。

  • Answers。記錄域名解析出來的地址信息;
  • Authoritative nameservers。記錄解析該域名對應(yīng)的權(quán)威名稱服務(wù)器信息;
  • Additional records。記錄解析該域名對應(yīng)的一些附加信息。

二. DNS報(bào)文解析實(shí)現(xiàn)

先回顧一下需求,就是需要得到應(yīng)用是否存在異常的DNS解析,那么結(jié)合上面的DNS報(bào)文格式,我們的判斷邏輯可以像下面這樣。

  • 先找到只有請求DNS報(bào)文但沒有響應(yīng)DNS報(bào)文的DNS解析,這是一種異常的DNS解析情況,即DNS服務(wù)器沒有響應(yīng)解析請求;
  • 拿到響應(yīng)DNS報(bào)文的Reply Code,然后根據(jù)Reply Code得到異常的DNS解析情況,Reply Code的枚舉如下所示。
Reply Code說明
0正常
1報(bào)文格式錯誤
2域名服務(wù)器異常
3域名不存在
4解析類型Type不支持
5域名服務(wù)器拒絕請求

計(jì)算DNS解析的請求和響應(yīng)報(bào)文的時(shí)間差,得到解析耗時(shí)過長的異常情況。

那么其實(shí)我們需要的DNS報(bào)文的內(nèi)容就很明確了,如下所示。

1. Transaction ID,事務(wù)ID

2. Reply Code,響應(yīng)碼;

3. Name,域名;

4. Type,解析類型。

現(xiàn)在就開始本文的正題,如何使用Java語言來解析網(wǎng)絡(luò)包并得到DNS報(bào)文。在Go語言中,可以使用google/gopacket來方便的拿到DNS報(bào)文,但是在Java中,要一步拿到DNS報(bào)文尚有點(diǎn)困難,但是可以基于如下步驟來操作。

  • 基于io.pkts的工具包來解析網(wǎng)絡(luò)包并拿到UDP報(bào)文;
  • 過濾出源或目標(biāo)端口號為53的UDP報(bào)文,這是因?yàn)橥ǔ?strong>DNS服務(wù)器會工作在53號端口上;
  • 拿到過濾后的UDP報(bào)文的載荷,按照DNS報(bào)文的格式解析得到Transaction IDReply Code,NameType。

現(xiàn)在進(jìn)行實(shí)操。先引入io.pkts的依賴,如下所示。

<dependency>  
    <groupId>io.pkts</groupId>  
    <artifactId>pkts-streams</artifactId>  
    <version>3.0.10</version>  
</dependency>  
<dependency>  
    <groupId>io.pkts</groupId>  
    <artifactId>pkts-core</artifactId>  
    <version>3.0.10</version>  
</dependency>  

然后基于SpringMultipartFile來上傳網(wǎng)絡(luò)包并使用io.pkts工具解析出UDP報(bào)文,實(shí)現(xiàn)如下所示。

@RestController
public class FileUpload {

    @PostMapping("/upload/udp")
    public void uploadUdp(MultipartFile uploadFile) throws IOException {
        try (InputStream inputStream = uploadFile.getInputStream()) {
            GZIPInputStream gzipInputStream = new GZIPInputStream(inputStream);
            Pcap pcap = Pcap.openStream(gzipInputStream);
            pcap.loop(packet -> {
                if (packet.hasProtocol(Protocol.UDP)) {
                    UDPPacket udpPacket = (UDPPacket) packet.getPacket(Protocol.UDP);
                    if (udpPacket.getSourcePort() == 53
                            || udpPacket.getDestinationPort() == 53) {
                        final byte[] payloadByteArray = udpPacket.getPayload().getArray();
                        // 在這里根據(jù)DNS報(bào)文格式解析數(shù)據(jù)
                        ......
                    }
                }
                return true;
            });
        }
    }

}

解析Transaction ID的邏輯如下所示。

private String parseTransactionId(byte[] array) {
    // 前兩字節(jié)是Transaction ID,表示會話標(biāo)識
    // DNS請求報(bào)文和響應(yīng)報(bào)文通過Transaction ID進(jìn)行匹配
    return HexUtils.toHexString(Arrays.copyOfRange(array, 0, 2));
}

解析請求或響應(yīng)報(bào)文類型的邏輯如下所示。

private int parseDnsPackageType(byte[] array) {
    // 第3和第4字節(jié)是Flags,表示標(biāo)志
    // Flags的第0位代表請求或響應(yīng)的類型
    // 0表示DNS請求報(bào)文,1表示DNS響應(yīng)報(bào)文
    String binaryString = String.format("%08d", Integer.parseInt(Integer.toBinaryString(array[2] & 0xFF)));
    return Integer.parseInt(binaryString.substring(0, 1), 2);
}

解析Reply Code的邏輯如下所示。

private int parseDnsRcode(byte[] array) {
    // 第3和第4字節(jié)是Flags,表示標(biāo)志
    // Flags的最后四位表示Reply Code
    String binaryString = String.format("%08d", Integer.parseInt(Integer.toBinaryString(array[3] & 0xFF)));
    return Integer.parseInt(binaryString.substring(4, 8), 2);
}

解析Type的邏輯如下所示。

private int parseDnsQueryType(byte[] array) {
    // 第13字節(jié)開始,是域名,域名以0x00結(jié)尾
    // 域名結(jié)束后的兩個(gè)字節(jié)就代表DNS查詢類型
    int domainEndIndex = -1;
    for (int i = 12; i < array.length; i++) {
        if ((array[i] & 0xFF) == 0) {
            domainEndIndex = i;
            break;
        }
    }
    String s = HexUtils.toHexString(Arrays.copyOfRange(array, domainEndIndex + 1, domainEndIndex + 3));
    return Integer.parseInt(s, 16);
}

解析Name的邏輯如下所示。

private String parseDnsQueryDomain(byte[] array) {
    // 從第13字節(jié)開始,遵循[域名長度][域名][域名長度][域名]...0x00的規(guī)律
    // 故按照上述規(guī)律,從第13字節(jié)開始,將域名的所有組成部分獲取出來并拼接
    List<String> domainParts = new ArrayList<>();
    int lengthIndex = 12;
    do {
        int partLength = array[lengthIndex] & 0xFF;
        String s = new String(Arrays.copyOfRange(array, lengthIndex + 1, lengthIndex + partLength + 2)).trim();
        domainParts.add(s);
        lengthIndex = lengthIndex + partLength + 1;
    } while ((array[lengthIndex] & 0xFF) != 0);
    return String.join(".", domainParts);
}

那么至此我們期望得到的DNS報(bào)文的數(shù)據(jù),我們就拿到了,后續(xù)就是將這些數(shù)據(jù)組裝為一個(gè)Entity來方便我們在程序中使用和處理,這里就不再演示了。

總結(jié)

我使用Java語言從網(wǎng)絡(luò)包中解析出DNS報(bào)文的步驟總結(jié)如下。

  • 使用io.pkts解開網(wǎng)絡(luò)包并過濾得到UDP報(bào)文;
  • 過濾出源或目標(biāo)端口號為53的UDP報(bào)文;
  • 拿到過濾后的UDP報(bào)文的載荷,按照DNS報(bào)文的格式解析得到想要的DNS數(shù)據(jù)。

以上就是利用Java實(shí)現(xiàn)輕松解析DNS報(bào)文的詳細(xì)內(nèi)容,更多關(guān)于Java解析DNS報(bào)文的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Java使用正則表達(dá)式提取XML節(jié)點(diǎn)內(nèi)容的方法示例

    Java使用正則表達(dá)式提取XML節(jié)點(diǎn)內(nèi)容的方法示例

    這篇文章主要介紹了Java使用正則表達(dá)式提取XML節(jié)點(diǎn)內(nèi)容的方法,結(jié)合具體實(shí)例形式分析了java針對xml格式字符串的正則匹配相關(guān)操作技巧,需要的朋友可以參考下
    2017-08-08
  • 淺談Springboot之于Spring的優(yōu)勢

    淺談Springboot之于Spring的優(yōu)勢

    這篇文章主要介紹了淺談Springboot之于Spring的優(yōu)勢,簡述了在Java EE開發(fā)中遇到的問題,言簡意賅,需要的朋友可以參考下。
    2017-09-09
  • java實(shí)現(xiàn)ip地址與十進(jìn)制數(shù)相互轉(zhuǎn)換

    java實(shí)現(xiàn)ip地址與十進(jìn)制數(shù)相互轉(zhuǎn)換

    本文介紹在java中IP地址轉(zhuǎn)換十進(jìn)制數(shù)及把10進(jìn)制再轉(zhuǎn)換成IP地址的方法及實(shí)例參考,曬出來和大家分享一下
    2012-12-12
  • Netty分布式ByteBuf使用命中緩存的分配解析

    Netty分布式ByteBuf使用命中緩存的分配解析

    這篇文章主要為大家介紹了Netty分布式ByteBuf?使用命中緩存的分配解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-03-03
  • java8版本base64加密解密的實(shí)例

    java8版本base64加密解密的實(shí)例

    下面小編就為大家分享一篇java8版本base64加密解密的實(shí)例,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2017-12-12
  • springboot mybatis里localdatetime序列化問題的解決

    springboot mybatis里localdatetime序列化問題的解決

    這篇文章主要介紹了springboot mybatis里localdatetime序列化問題,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-10-10
  • Java多線程批量數(shù)據(jù)導(dǎo)入的方法詳解

    Java多線程批量數(shù)據(jù)導(dǎo)入的方法詳解

    這篇文章主要介紹了Java多線程批量數(shù)據(jù)導(dǎo)入的方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,下面小編和大家來一起學(xué)習(xí)下吧
    2019-06-06
  • Java數(shù)據(jù)結(jié)構(gòu)之LinkedList從鏈表到實(shí)現(xiàn)

    Java數(shù)據(jù)結(jié)構(gòu)之LinkedList從鏈表到實(shí)現(xiàn)

    LinkedList是Java中常用的數(shù)據(jù)結(jié)構(gòu)之一,實(shí)現(xiàn)了鏈表的特性,支持快速添加、刪除元素,可以用于實(shí)現(xiàn)隊(duì)列、棧、雙向隊(duì)列等數(shù)據(jù)結(jié)構(gòu)。LinkedList的內(nèi)部實(shí)現(xiàn)采用了雙向鏈表,其中每個(gè)節(jié)點(diǎn)都包含前驅(qū)節(jié)點(diǎn)和后繼節(jié)點(diǎn)的引用,可以直接訪問鏈表的頭尾元素
    2023-04-04
  • Java鎖之自旋鎖詳解

    Java鎖之自旋鎖詳解

    這篇文章主要介紹了Java鎖之自旋鎖詳解,本文是系列文章的第一篇,請持續(xù)關(guān)注腳本之家java欄目,需要的朋友可以參考下
    2014-09-09
  • java八大經(jīng)典書籍 你看過幾本?

    java八大經(jīng)典書籍 你看過幾本?

    java八大經(jīng)典書籍,你看過幾本?本文為大家分享了java學(xué)習(xí)書單,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-01-01

最新評論