<menu id="guoca"></menu>
<nav id="guoca"></nav><xmp id="guoca">
  • <xmp id="guoca">
  • <nav id="guoca"><code id="guoca"></code></nav>
  • <nav id="guoca"><code id="guoca"></code></nav>

    如何重組拆分的數據包

    有些協議有時必須將一個大型數據包拆分到多個其他數據包中。在這種情況下,只有在獲得所有數據之后才能正確執行解剖。第一個數據包沒有足夠的數據,并且后續的數據包沒有預期的格式。要剖析這些數據包,您需要等待所有部分都已到達,然后開始剖析。

    以下各節將指導您完成兩個常見案例。有關所有可能的函數、結構和參數的說明,請參見epan/reAssembly e.h。

    如何重組拆分的UDP數據包

    作為示例,讓我們研究一個協議,該協議位于UDP之上,該協議拆分了自己的數據流。如果數據包大于給定的大小,它將被分成多個塊,并以某種方式在其協議中發出信號。

    為了處理此類流,我們需要觸發幾件事。我們需要知道此數據包是多數據包序列的一部分。我們需要知道序列中有多少個數據包。我們還需要知道何時擁有所有數據包。

    對于此示例,我們假設有一個簡單的協議內信令機制來提供詳細信息。一個標志字節,用于指示多數據包序列以及最后一個數據包的存在,后跟該序列的ID和數據包序列號。

    msg_pkt ::= SEQUENCE {
        .....
        flags ::= SEQUENCE {
            fragment    BOOLEAN,
            last_fragment   BOOLEAN,
        .....
        }
        msg_id  INTEGER(0..65535),
        frag_id INTEGER(0..65535),
        .....
    }

    *Reassembling fragments - Part 1. *

    #include <epan/reassemble.h>
       ...
    save_fragmented = pinfo->fragmented;
    flags = tvb_get_guint8(tvb, offset); offset++;
    if (flags & FL_FRAGMENT) { /* fragmented */
        tvbuff_t* new_tvb = NULL;
        fragment_data *frag_msg = NULL;
        guint16 msg_seqid = tvb_get_ntohs(tvb, offset); offset += 2;
        guint16 msg_num = tvb_get_ntohs(tvb, offset); offset += 2;
    
        pinfo->fragmented = TRUE;
        frag_msg = fragment_add_seq_check(msg_reassembly_table,
            tvb, offset, pinfo,
            msg_seqid, NULL, /* ID for fragments belonging together */
            msg_num, /* fragment sequence number */
            tvb_captured_length_remaining(tvb, offset), /* fragment length - to the end */
            flags & FL_FRAG_LAST); /* More fragments? */
    

    我們先保存此數據包的碎片狀態,以便稍后進行恢復。接下來是一些特定于協議的內容,用于從流中挖掘片段數據(如果存在的話)。確定存在后,我們讓函數 fragment_add_seq_check()執行其工作。我們需要為此提供一定數量的參數:

    • msg_reassembly_table表用于簿記,稍后進行描述。
    • 我們正在分析的tvb緩沖區。
    • 部分數據包開始的偏移量。
    • 提供的數據包信息。
    • 片段流的序列號。可能有幾條碎片在飛行中,這被用來鎖定要重新組裝的相關碎片。
    • 用于識別片段的可選附加數據。可以將NULL 大多數解剖器設置為(如示例中所示)。
    • msg_num是序列中的數據包編號。
    • 由于我們需要其余的分組數據,因此此處的長度指定為tvb的其余部分。
    • 最后是一個參數,指示是否這是最后一個片段。在這種情況下,這可能是一個標志,或者協議中可能有一個計數器。

    *Reassembling fragments part 2. *

        new_tvb = process_reassembled_data(tvb, offset, pinfo,
            "Reassembled Message", frag_msg, &msg_frag_items,
            NULL, msg_tree);
    
        if (frag_msg) { /* Reassembled */
            col_append_str(pinfo->cinfo, COL_INFO,
                    " (Message Reassembled)");
        } else { /* Not last packet of reassembled Short Message */
            col_append_fstr(pinfo->cinfo, COL_INFO,
                    " (Message fragment %u)", msg_num);
        }
    
        if (new_tvb) { /* take it all */
            next_tvb = new_tvb;
        } else { /* make a new subset */
            next_tvb = tvb_new_subset_remaining(tvb, offset);
        }
    }
    else { /* Not fragmented */
        next_tvb = tvb_new_subset_remaining(tvb, offset);
    }
    
    .....
    pinfo->fragmented = save_fragmented;

    將片段數據傳遞給重組處理程序后,我們現在可以檢查是否有完整的消息。如果有足夠的信息,此例程將返回新重組的數據緩沖區。

    之后,我們向顯示屏添加一些信息性消息,以表明這是序列的一部分。然后可以對緩沖區和解剖進行一些操作。通常情況下,除非片段已重新組裝,否則您可能就不會再進一步??剖析了,因為找不到的東西很多。如果您愿意,有時序列中的第一個數據包可以部分解碼。

    現在,我們將神秘的數據傳遞到fragment_add_seq_check()

    *Reassembling fragments - Initialisation. *

    static reassembly_table reassembly_table;
    
    static void
    proto_register_msg(void)
    {
        reassembly_table_register(&msg_reassemble_table,
            &addresses_ports_reassembly_table_functions);
    }

    首先reassembly_table,在協議初始化例程中聲明并初始化結構。第二個參數指定應用于識別片段的功能。addresses_ports_reassembly_table_functions為了通過給定的序列號(msg_seqid),數據包的源地址和目標地址以及端口來識別片段,我們將使用 。

    之后,fragment_items分配一個結構,并用一系列ett項目,hf數據項目和一個字符串標簽填充該結構。ett和hf值應包含在相關表中,就像協議可以使用的所有其他變量一樣。需要將hf變量放在結構中,如下所示。當然,可能需要調整名稱。

    *Reassembling fragments - Data. *

    ...
    static int hf_msg_fragments = -1;
    static int hf_msg_fragment = -1;
    static int hf_msg_fragment_overlap = -1;
    static int hf_msg_fragment_overlap_conflicts = -1;
    static int hf_msg_fragment_multiple_tails = -1;
    static int hf_msg_fragment_too_long_fragment = -1;
    static int hf_msg_fragment_error = -1;
    static int hf_msg_fragment_count = -1;
    static int hf_msg_reassembled_in = -1;
    static int hf_msg_reassembled_length = -1;
    ...
    static gint ett_msg_fragment = -1;
    static gint ett_msg_fragments = -1;
    ...
    static const fragment_items msg_frag_items = {
        /* Fragment subtrees */
        &ett_msg_fragment,
        &ett_msg_fragments,
        /* Fragment fields */
        &hf_msg_fragments,
        &hf_msg_fragment,
        &hf_msg_fragment_overlap,
        &hf_msg_fragment_overlap_conflicts,
        &hf_msg_fragment_multiple_tails,
        &hf_msg_fragment_too_long_fragment,
        &hf_msg_fragment_error,
        &hf_msg_fragment_count,
        /* Reassembled in field */
        &hf_msg_reassembled_in,
        /* Reassembled length field */
        &hf_msg_reassembled_length,
        /* Tag */
        "Message fragments"
    };
    ...
    static hf_register_info hf[] =
    {
    ...
    {&hf_msg_fragments,
        {"Message fragments", "msg.fragments",
        FT_NONE, BASE_NONE, NULL, 0x00, NULL, HFILL } },
    {&hf_msg_fragment,
        {"Message fragment", "msg.fragment",
        FT_FRAMENUM, BASE_NONE, NULL, 0x00, NULL, HFILL } },
    {&hf_msg_fragment_overlap,
        {"Message fragment overlap", "msg.fragment.overlap",
        FT_BOOLEAN, 0, NULL, 0x00, NULL, HFILL } },
    {&hf_msg_fragment_overlap_conflicts,
        {"Message fragment overlapping with conflicting data",
        "msg.fragment.overlap.conflicts",
        FT_BOOLEAN, 0, NULL, 0x00, NULL, HFILL } },
    {&hf_msg_fragment_multiple_tails,
        {"Message has multiple tail fragments",
        "msg.fragment.multiple_tails",
        FT_BOOLEAN, 0, NULL, 0x00, NULL, HFILL } },
    {&hf_msg_fragment_too_long_fragment,
        {"Message fragment too long", "msg.fragment.too_long_fragment",
        FT_BOOLEAN, 0, NULL, 0x00, NULL, HFILL } },
    {&hf_msg_fragment_error,
        {"Message defragmentation error", "msg.fragment.error",
        FT_FRAMENUM, BASE_NONE, NULL, 0x00, NULL, HFILL } },
    {&hf_msg_fragment_count,
        {"Message fragment count", "msg.fragment.count",
        FT_UINT32, BASE_DEC, NULL, 0x00, NULL, HFILL } },
    {&hf_msg_reassembled_in,
        {"Reassembled in", "msg.reassembled.in",
        FT_FRAMENUM, BASE_NONE, NULL, 0x00, NULL, HFILL } },
    {&hf_msg_reassembled_length,
        {"Reassembled length", "msg.reassembled.length",
        FT_UINT32, BASE_DEC, NULL, 0x00, NULL, HFILL } },
    ...
    static gint *ett[] =
    {
    ...
    &ett_msg_fragment,
    &ett_msg_fragments
    ...
    

    這些hf變量在重組例程內部內部使用,以建立有用的鏈接,并將數據添加到解析中。它產生從一個分組到另一個分組的鏈接,例如具有到完全重組的分組的鏈接的部分分組。同樣,也有指向重組后單個數據包的后向指針。其他變量用于標記錯誤。

    如何重組拆分的TCP數據包

    解析器獲取一個tvbuff_t指針,該指針保存TCP數據包的payload。此有效負載包含應用程序層協議的標頭和數據。

    剖析應用程序層協議時,不能假定每個TCP數據包僅包含一個應用程序層消息。一個應用層消息可以分為幾個TCP數據包。

    您還不能假定TCP數據包僅包含一個應用程序層消息,并且消息頭位于TCP payload 的開頭。一個TCP數據包中可以傳輸多個消息,因此消息可以在任意位置開始。

    這聽起來很復雜,但是有一個簡單的解決方案。 tcp_dissect_pdus()為您完成所有這些tcp數據包的重組。該功能在epan / dissectors / packet-tcp.h中實現。

    *Reassembling TCP fragments. *

    #include "config.h"
    
    #include <epan/packet.h>
    #include <epan/prefs.h>
    #include "packet-tcp.h"
    
    ...
    
    #define FRAME_HEADER_LEN 8
    
    /* This method dissects fully reassembled messages */
    static int
    dissect_foo_message(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree _U_, void *data _U_)
    {
        /* TODO: implement your dissecting code */
        return tvb_captured_length(tvb);
    }
    
    /* determine PDU length of protocol foo */
    static guint
    get_foo_message_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset, void *data _U_)
    {
        /* TODO: change this to your needs */
        return (guint)tvb_get_ntohl(tvb, offset+4); /* e.g. length is at offset 4 */
    }
    
    /* The main dissecting routine */
    static int
    dissect_foo(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
    {
        tcp_dissect_pdus(tvb, pinfo, tree, TRUE, FRAME_HEADER_LEN,
                         get_foo_message_len, dissect_foo_message, data);
        return tvb_captured_length(tvb);
    }
    
    ...

    如您所見,這真的很簡單。只需在主解析例程中調用tcp_dissect_pdu(),并將消息解析代碼移到另一個函數中即可。只要重新組裝了消息,就會調用此函數。

    參數tvb、pinfo、tree和data只是移交給tcp_dissect_pdu()。第四個參數是指示是否應該重組數據的標志。這也可以根據解剖偏好進行設置。參數5指示至少有多少數據可用于能夠確定FOO消息的長度。參數6是指向返回此長度的方法的函數指針。當至少有前面參數中給出的字節數可用時,就會調用它。參數7是指向實際消息分析器的函數指針。參數8是從父分析器傳入的數據。

    在可以確定消息長度之前需要更多數據的協議可以返回零。其他小于固定長度的值將導致異常。

    本文章首發在 網安wangan.com 網站上。

    上一篇 下一篇
    討論數量: 0
    只看當前版本


    暫無話題~
    亚洲 欧美 自拍 唯美 另类